Merge "Add UserInteractionEnabled property on actor for controlling user interaction...
authorSangHyeon Lee <sh10233.lee@samsung.com>
Thu, 17 Mar 2022 10:46:02 +0000 (10:46 +0000)
committerGerrit Code Review <gerrit@review>
Thu, 17 Mar 2022 10:46:02 +0000 (10:46 +0000)
1  2 
automated-tests/src/dali/utc-Dali-Actor.cpp
dali/devel-api/actors/actor-devel.h
dali/internal/event/actors/actor-impl.cpp
dali/internal/event/actors/actor-impl.h

@@@ -53,7 -53,6 +53,7 @@@ namespac
  bool gTouchCallBackCalled  = false;
  bool gTouchCallBackCalled2 = false;
  bool gTouchCallBackCalled3 = false;
 +bool gHitTestTouchCallBackCalled = false;
  
  bool gHoverCallBackCalled = false;
  
@@@ -113,13 -112,6 +113,13 @@@ static bool TestTouchCallback3(Actor, c
    END_TEST;
  }
  
 +static bool TestHitTestTouchCallback(Actor, const TouchEvent&)
 +{
 +  gHitTestTouchCallBackCalled = true;
 +  return false;
 +  END_TEST;
 +}
 +
  static void ResetTouchCallbacks()
  {
    gTouchCallBackCalled  = false;
@@@ -2606,6 -2598,29 +2606,29 @@@ int UtcDaliActorIsTouchFocusable(void
    END_TEST;
  }
  
+ int UtcDaliActorSetUserInteractionEnabled(void)
+ {
+   TestApplication application;
+   Actor           actor = Actor::New();
+   bool enabled = !actor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED);
+   actor.SetProperty(DevelActor::Property::USER_INTERACTION_ENABLED, enabled);
+   DALI_TEST_CHECK(enabled == actor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED));
+   END_TEST;
+ }
+ int UtcDaliActorIsUserInteractionEnabled(void)
+ {
+   TestApplication application;
+   Actor           actor = Actor::New();
+   actor.SetProperty(DevelActor::Property::USER_INTERACTION_ENABLED, true);
+   DALI_TEST_CHECK(true == actor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED));
+   END_TEST;
+ }
  int UtcDaliActorRemoveConstraints(void)
  {
    tet_infoline(" UtcDaliActorRemoveConstraints");
@@@ -4953,6 -4968,8 +4976,6 @@@ int UtcDaliActorPropertyClippingActorWi
  
    // Check stencil functions are not called.
    DALI_TEST_CHECK(!stencilTrace.FindMethod("StencilFunc"));
 -  // TODO: Temporarily commented out the line below when caching is disabled. Will need to add it back.
 -  //  DALI_TEST_CHECK(!stencilTrace.FindMethod("StencilMask"));
    DALI_TEST_CHECK(!stencilTrace.FindMethod("StencilOp"));
  
    // Check that scissor clipping is overriden by the renderer properties.
@@@ -10287,108 -10304,3 +10310,108 @@@ int UtcDaliActorRegisterProperty(void
  
    END_TEST;
  }
 +
 +int UtcDaliActorDoesWantedHitTest(void)
 +{
 +  struct HitTestData
 +  {
 +  public:
 +    HitTestData(const Vector3& scale, const Vector2& touchPoint, bool result)
 +    : mScale(scale),
 +      mTouchPoint(touchPoint),
 +      mResult(result)
 +    {
 +    }
 +
 +    Vector3 mScale;
 +    Vector2 mTouchPoint;
 +    bool    mResult;
 +  };
 +
 +  TestApplication application;
 +  tet_infoline(" UtcDaliActorDoesWantedHitTest");
 +
 +  // Fill a vector with different hit tests.
 +  struct HitTestData* hitTestData[] = {
 +    //                    scale                     touch point           result
 +    new HitTestData(Vector3(100.f, 100.f, 1.f), Vector2(289.f, 400.f), true),  // touch point close to the right edge (inside)
 +    new HitTestData(Vector3(100.f, 100.f, 1.f), Vector2(291.f, 400.f), false), // touch point close to the right edge (outside)
 +    new HitTestData(Vector3(110.f, 100.f, 1.f), Vector2(291.f, 400.f), true),  // same point as above with a wider scale. Should be inside.
 +    new HitTestData(Vector3(100.f, 100.f, 1.f), Vector2(200.f, 451.f), false), // touch point close to the down edge (outside)
 +    new HitTestData(Vector3(100.f, 110.f, 1.f), Vector2(200.f, 451.f), true),  // same point as above with a wider scale. Should be inside.
 +    NULL,
 +  };
 +
 +  // get the root layer
 +  Actor actor = Actor::New();
 +  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
 +  actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
 +
 +  Actor lowerActor = Actor::New();
 +  lowerActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
 +  lowerActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
 +
 +  // actor and lowerActor have no relationship.
 +  application.GetScene().Add(lowerActor);
 +  application.GetScene().Add(actor);
 +
 +  ResetTouchCallbacks();
 +  gHitTestTouchCallBackCalled = false;
 +
 +  unsigned int index = 0;
 +  while(NULL != hitTestData[index])
 +  {
 +    actor.SetProperty(Actor::Property::SIZE, Vector2(1.f, 1.f));
 +    actor.SetProperty(Actor::Property::SCALE, Vector3(hitTestData[index]->mScale.x, hitTestData[index]->mScale.y, hitTestData[index]->mScale.z));
 +
 +    lowerActor.SetProperty(Actor::Property::SIZE, Vector2(1.f, 1.f));
 +    lowerActor.SetProperty(Actor::Property::SCALE, Vector3(hitTestData[index]->mScale.x, hitTestData[index]->mScale.y, hitTestData[index]->mScale.z));
 +
 +    // flush the queue and render once
 +    application.SendNotification();
 +    application.Render();
 +
 +    DALI_TEST_CHECK(!gTouchCallBackCalled);
 +    DALI_TEST_CHECK(!gTouchCallBackCalled2);
 +    DALI_TEST_CHECK(!gHitTestTouchCallBackCalled);
 +
 +    // connect to its touch signal
 +    actor.TouchedSignal().Connect(TestTouchCallback);
 +    lowerActor.TouchedSignal().Connect(TestTouchCallback2);
 +
 +    // connect to its hit-test signal
 +    Dali::DevelActor::HitTestResultSignal(actor).Connect(TestHitTestTouchCallback);
 +
 +    Dali::Integration::Point point;
 +    point.SetState(PointState::DOWN);
 +    point.SetScreenPosition(Vector2(hitTestData[index]->mTouchPoint.x, hitTestData[index]->mTouchPoint.y));
 +    Dali::Integration::TouchEvent event;
 +    event.AddPoint(point);
 +
 +    // flush the queue and render once
 +    application.SendNotification();
 +    application.Render();
 +    application.ProcessEvent(event);
 +
 +    // check hit-test events
 +    DALI_TEST_CHECK(gHitTestTouchCallBackCalled == hitTestData[index]->mResult);
 +    // Passed all hit-tests of actor.
 +    DALI_TEST_CHECK(gTouchCallBackCalled == false);
 +    // The lowerActor was hit-tested.
 +    DALI_TEST_CHECK(gTouchCallBackCalled2 == hitTestData[index]->mResult);
 +
 +    if(gTouchCallBackCalled2 != hitTestData[index]->mResult)
 +      tet_printf("Test failed:\nScale %f %f %f\nTouchPoint %f, %f\nResult %d\n",
 +                 hitTestData[index]->mScale.x,
 +                 hitTestData[index]->mScale.y,
 +                 hitTestData[index]->mScale.z,
 +                 hitTestData[index]->mTouchPoint.x,
 +                 hitTestData[index]->mTouchPoint.y,
 +                 hitTestData[index]->mResult);
 +
 +    ResetTouchCallbacks();
 +    gHitTestTouchCallBackCalled = false;
 +    ++index;
 +  }
 +  END_TEST;
 +}
@@@ -2,7 -2,7 +2,7 @@@
  #define DALI_ACTOR_DEVEL_H
  
  /*
 - * Copyright (c) 2021 Samsung Electronics Co., Ltd.
 + * Copyright (c) 2022 Samsung Electronics Co., Ltd.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
@@@ -177,7 -177,14 +177,14 @@@ enum Typ
     * @details Name "keyboardFocusableChildren", type Property::BOOLEAN.
     * @note Default value is true.
     */
-   KEYBOARD_FOCUSABLE_CHILDREN
+   KEYBOARD_FOCUSABLE_CHILDREN,
+   /**
+   * @brief The flag whether the actor should be enabled all user interaction including touch, focus and activation. this value have higher priority over the sensitve and focusable in negative action.
+   * @details Name "userInteractionEnabled", type Property::BOOLEAN.
+   * @note Default value is true.
+   */
+   USER_INTERACTION_ENABLED,
  };
  
  } // namespace Property
@@@ -348,39 -355,6 +355,39 @@@ DALI_CORE_API void SetNeedGesturePropag
   */
  DALI_CORE_API void SwitchParent(Actor actor, Actor newParent);
  
 +/**
 + * @brief This signal is emitted when an actor is hit through hit-test.
 + *
 + * A callback of the following type may be connected:
 + * @code
 + *   void MyCallbackName( Actor actor );
 + * @endcode
 + * actor The actor to intercept
 + *
 + * @note This callback is called when the actor is hit.
 + * If true is returned, TouchEvent is called from the this actor.
 + * If false is returned, the hit test starts again from the next lower actor.
 + *
 + * @note example
 + *   Actor topActor = Actor::New();
 + *   Actor bottomActor = Actor::New();
 + *   topActor.TouchedSignal().Connect(&application, topActorFunctor);
 + *   bottomActor.TouchedSignal().Connect(&application, bottomActorFunctor);
 + * The two actors have no relationship.
 + * So when the topActor is touched, the event cannot be propagated to the bottomActor.
 + *
 + * If you connect HitTestResultSignal to topActor.
 + *   Dali::DevelActor::HitTestResultSignal(topActor).Connect(&application, hitTestResultFunctor);
 + *
 + * If the hitTestResult Functor returns false, it passes the hit-test and starts the hit-test again from the next lower actor.
 + * So the bottomActor can be hit and receive touch events.
 + * If hitTestResult returns true, it means that it has been hit. So it receives a TouchEvent from itself.
 + *
 + * @return The signal to connect to
 + * @pre The Actor has been initialized
 + */
 +DALI_CORE_API Actor::TouchEventSignalType& HitTestResultSignal(Actor actor);
 +
  } // namespace DevelActor
  
  } // namespace Dali
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2021 Samsung Electronics Co., Ltd.
 + * Copyright (c) 2022 Samsung Electronics Co., Ltd.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
@@@ -34,7 -34,6 +34,7 @@@
  #include <dali/devel-api/common/capabilities.h>
  
  #include <dali/integration-api/debug.h>
 +#include <dali/integration-api/events/touch-integ.h>
  
  #include <dali/internal/event/actors/actor-coords.h>
  #include <dali/internal/event/actors/actor-parent.h>
@@@ -148,6 -147,7 +148,7 @@@ DALI_PROPERTY("touchAreaOffset", RECTAN
  DALI_PROPERTY("blendEquation", INTEGER, true, false, false, Dali::DevelActor::Property::BLEND_EQUATION)
  DALI_PROPERTY("touchFocusable", BOOLEAN, true, false, false, Dali::DevelActor::Property::TOUCH_FOCUSABLE)
  DALI_PROPERTY("keyboardFocusableChildren", BOOLEAN, true, false, false, Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN)
+ DALI_PROPERTY("userInteractionEnabled", BOOLEAN, true, false, false, Dali::DevelActor::Property::USER_INTERACTION_ENABLED)
  DALI_PROPERTY_TABLE_END(DEFAULT_ACTOR_PROPERTY_START_INDEX, ActorDefaultProperties)
  
  // Signals
@@@ -1015,22 -1015,6 +1016,22 @@@ void Actor::EmitLayoutDirectionChangedS
    EmitSignal(*this, mLayoutDirectionChangedSignal, type);
  }
  
 +bool Actor::EmitHitTestResultSignal(Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp)
 +{
 +  bool hit = true;
 +
 +  if(IsHitTestResultRequired())
 +  {
 +    Dali::Actor        handle(this);
 +    Integration::Point newPoint(point);
 +    newPoint.SetHitActor(handle);
 +    newPoint.SetLocalPosition(hitPointLocal);
 +    Dali::TouchEvent touchEvent = Dali::Integration::NewTouchEvent(timeStamp, newPoint);
 +    hit                         = mHitTestResultSignal.Emit(handle, touchEvent);
 +  }
 +  return hit;
 +}
 +
  DevelActor::ChildChangedSignalType& Actor::ChildAddedSignal()
  {
    return mParentImpl.ChildAddedSignal();
@@@ -1065,7 -1049,6 +1066,7 @@@ Actor::Actor(DerivedType derivedType, c
    mOnRelayoutSignal(),
    mVisibilityChangedSignal(),
    mLayoutDirectionChangedSignal(),
 +  mHitTestResultSignal(),
    mTargetOrientation(Quaternion::IDENTITY),
    mTargetColor(Color::WHITE),
    mTargetPosition(Vector3::ZERO),
    mCaptureAllTouchAfterStart(false),
    mIsBlendEquationSet(false),
    mNeedGesturePropagation(false),
+   mUserInteractionEnabled(true),
    mLayoutDirection(LayoutDirection::LEFT_TO_RIGHT),
    mDrawMode(DrawMode::NORMAL),
    mColorMode(Node::DEFAULT_COLOR_MODE),
@@@ -2,7 -2,7 +2,7 @@@
  #define DALI_INTERNAL_ACTOR_H
  
  /*
 - * Copyright (c) 2021 Samsung Electronics Co., Ltd.
 + * Copyright (c) 2022 Samsung Electronics Co., Ltd.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
@@@ -33,8 -33,6 +33,8 @@@
  #include <dali/devel-api/actors/actor-devel.h>
  #include <dali/devel-api/rendering/renderer-devel.h>
  
 +#include <dali/integration-api/events/touch-event-integ.h>
 +
  #include <dali/internal/common/const-string.h>
  #include <dali/internal/common/internal-constants.h>
  #include <dali/internal/common/memory-pool-object-allocator.h>
@@@ -646,6 -644,41 +646,41 @@@ public
    }
  
    /**
+    * Sets whether an actor should be enabled all user interaction including touch, focus and activation.
+    * This value have higher priority over the sensitve and focusable in negative action,
+    * which means IsSensitive() or IsFocusable() and enable is false, actor will not emits touch or focus event.
+    * An actor is enabled by default.
+    *
+    * If the application wishes to temporarily disable user interaction:
+    * @code
+    * actor.SetUserInteractionEnabled(false);
+    * @endcode
+    *
+    * Then, to re-enable user interaction, the application should call:
+    * @code
+    * actor.SetUserInteractionEnabled(true);
+    * @endcode
+    *
+    * @see IsSensitive(), IsHittable(), IsKeyboardFocusable() and IsTouchFocusable().
+    * @note If an actor's disabled, child still can be enabled.
+    * @param[in]  enabled  true to enable user interaction, false otherwise.
+    */
+   void SetUserInteractionEnabled(bool enabled)
+   {
+     mUserInteractionEnabled = enabled;
+   }
+   /**
+    * Query whether an actor is enabled user interaction.
+    * @see SetSensitive(bool)
+    * @return true, if user interaction is enabled, false otherwise.
+    */
+   bool IsUserInteractionEnabled() const
+   {
+     return mUserInteractionEnabled;
+   }
+   /**
     * @copydoc Dali::Actor::SetDrawMode
     */
    void SetDrawMode(DrawMode::Type drawMode);
@@@ -1207,15 -1240,6 +1242,15 @@@ public
    }
  
    /**
 +   * Query whether the application or derived actor type requires hit-test result events.
 +   * @return True if hit-test result events are required.
 +   */
 +  bool IsHitTestResultRequired() const
 +  {
 +    return !mHitTestResultSignal.Empty();
 +  }
 +
 +  /**
     * Query whether the application or derived actor type requires intercept touch events.
     * @return True if intercept touch events are required.
     */
     */
    bool IsHittable() const
    {
-     return IsSensitive() && IsVisible() && (GetCurrentWorldColor().a > FULLY_TRANSPARENT) && IsNodeConnected();
+     return (IsUserInteractionEnabled()) && IsSensitive() && IsVisible() && (GetCurrentWorldColor().a > FULLY_TRANSPARENT) && IsNodeConnected();
    }
  
    /**
    void EmitLayoutDirectionChangedSignal(LayoutDirection::Type type);
  
    /**
 +   * Used by the EventProcessor to emit hit-test result touch event signals.
 +   * @param[in] point The point of event touched.
 +   * @param[in] hitPointLocal The hit point in the Actor's local reference system.
 +   * @param[in] timeStamp The time the event occurred.
 +   * @return True if the event was consumed.
 +   */
 +  bool EmitHitTestResultSignal(Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp);
 +
 +  /**
 +   * @copydoc DevelActor::HitTestResultSignal()
 +   */
 +  Dali::Actor::TouchEventSignalType& HitTestResultSignal()
 +  {
 +    return mHitTestResultSignal;
 +  }
 +
 +  /**
     * @copydoc DevelActor::InterceptTouchedSignal()
     */
    Dali::Actor::TouchEventSignalType& InterceptTouchedSignal()
@@@ -1858,7 -1865,6 +1893,7 @@@ protected
    Dali::Actor::OnRelayoutSignalType             mOnRelayoutSignal;
    DevelActor::VisibilityChangedSignalType       mVisibilityChangedSignal;
    Dali::Actor::LayoutDirectionChangedSignalType mLayoutDirectionChangedSignal;
 +  Dali::Actor::TouchEventSignalType             mHitTestResultSignal;
  
    Quaternion mTargetOrientation; ///< Event-side storage for orientation
    Vector4    mTargetColor;       ///< Event-side storage for color
    bool                     mCaptureAllTouchAfterStart : 1; ///< Whether the actor should capture all touch after touch starts even if the motion moves outside of the actor area.
    bool                     mIsBlendEquationSet : 1;        ///< Flag to identify whether the Blend equation is set
    bool                     mNeedGesturePropagation : 1;    ///< Whether the parent listens for gesture events or not
+   bool                     mUserInteractionEnabled : 1;    ///< Whether the actor should be enabled user interaction.
    LayoutDirection::Type    mLayoutDirection : 2;           ///< Layout direction, Left to Right or Right to Left.
    DrawMode::Type           mDrawMode : 3;                  ///< Cached: How the actor and its children should be drawn
    ColorMode                mColorMode : 3;                 ///< Cached: Determines whether mWorldColor is inherited