Support multiple transitions for a Control. 22/265822/6
authorseungho <sbsh.baek@samsung.com>
Fri, 29 Oct 2021 07:04:54 +0000 (16:04 +0900)
committerSeungho Baek <sbsh.baek@samsung.com>
Fri, 5 Nov 2021 11:05:28 +0000 (20:05 +0900)
 - If a Control has multiple transitions, the Control must be hidden durring only the minimum delay of the transitions.
 - During delay time, the transitioned property of the Control will be set to the source value.

Change-Id: If158d01511b373edaad59b5e288bc33e5adde9bb
Signed-off-by: seungho <sbsh.baek@samsung.com>
automated-tests/src/dali-toolkit/utc-Dali-Transition.cpp
dali-toolkit/internal/transition/transition-base-impl.cpp
dali-toolkit/internal/transition/transition-base-impl.h
dali-toolkit/internal/transition/transition-set-impl.cpp

index ef1eb2c..0ead710 100755 (executable)
@@ -24,6 +24,8 @@
 #include <dali-toolkit/public-api/transition/transition-set.h>
 #include <dali-toolkit/public-api/transition/transition-base.h>
 #include <dali-toolkit/public-api/transition/transition.h>
+#include <dali-toolkit/public-api/transition/fade-transition.h>
+#include <dali-toolkit/public-api/transition/slide-transition.h>
 
 using namespace Dali;
 using namespace Dali::Toolkit;
@@ -1186,3 +1188,82 @@ int UtcDaliTransitionBetweenControlPairWithTreeWithoutScaleInheritance(void)
 
   END_TEST;
 }
+
+
+int UtcDaliMultipleTransitionAppearing(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliMultipleTransitionAppearing");
+
+  Control control = Control::New();
+  control.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  control.SetProperty(Actor::Property::POSITION, Vector3(100, 200, 0));
+  control.SetProperty(Actor::Property::SIZE, Vector3(150, 150, 0));
+  Property::Map controlProperty;
+  controlProperty.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty);
+
+  application.GetScene().Add(control);
+
+  application.SendNotification();
+  application.Render(20);
+
+  DALI_TEST_EQUALS(1.0f, control.GetCurrentProperty<float>(Actor::Property::OPACITY), TEST_LOCATION);
+
+  TransitionSet transitionSet = TransitionSet::New();
+  FadeTransition fade = FadeTransition::New(control, 0.5, TimePeriod(1.0f, 1.0f));
+  fade.SetAppearingTransition(true); // set fade in
+  transitionSet.AddTransition(fade);
+  SlideTransition slide = SlideTransition::New(control, Dali::Toolkit::SlideTransitionDirection::BOTTOM, TimePeriod(0.5f, 1.0f));
+  slide.SetAppearingTransition(true); // set slide
+  transitionSet.AddTransition(slide);
+  transitionSet.Play();
+
+  bool signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  transitionSet.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(300);
+
+  float currentOpacity = control.GetCurrentProperty<float>(Actor::Property::OPACITY);
+  DALI_TEST_CHECK(currentOpacity == 0.0f);
+
+  application.SendNotification();
+  application.Render(400);
+
+  currentOpacity = control.GetCurrentProperty<float>(Actor::Property::OPACITY);
+  DALI_TEST_CHECK(currentOpacity == 0.5f);
+
+  application.SendNotification();
+  application.Render(500);
+
+  currentOpacity = control.GetCurrentProperty<float>(Actor::Property::OPACITY);
+  DALI_TEST_CHECK(currentOpacity > 0.5f && currentOpacity < 1.0f);
+
+  application.SendNotification();
+  application.Render(500);
+
+  currentOpacity = control.GetCurrentProperty<float>(Actor::Property::OPACITY);
+  DALI_TEST_CHECK(currentOpacity > 0.5f && currentOpacity < 1.0f);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalNotReceived();
+
+  application.SendNotification();
+  application.Render(500);
+
+  // We did expect the animation to finish
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  application.SendNotification();
+  application.Render(20);
+
+  DALI_TEST_EQUALS(1.0f, control.GetCurrentProperty<float>(Actor::Property::OPACITY), TEST_LOCATION);
+
+  END_TEST;
+}
index f8aed47..5ee926e 100644 (file)
@@ -208,22 +208,18 @@ void TransitionBase::SetAnimation()
     return;
   }
 
-  // If this transition is not a transition from a Control to another Control
-  // and a transition effect to appear with delay,
-  // the mTarget should not be shown until delay seconds.
-  if(!IsPairTransition() && mIsAppearingTransition && mAnimation && mTimePeriod.delaySeconds > Dali::Math::MACHINE_EPSILON_10)
-  {
-    Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
-    initialKeyframes.Add(0.0f, OPACITY_TRANSPARENT);
-    initialKeyframes.Add(1.0f, OPACITY_TRANSPARENT);
-    mAnimation.AnimateBetween(Property(mTarget, Dali::Actor::Property::OPACITY), initialKeyframes, TimePeriod(mTimePeriod.delaySeconds));
-  }
-
   for(uint32_t i = 0; i < mStartPropertyMap.Count(); ++i)
   {
     Property::Value* finishValue = mFinishPropertyMap.Find(mStartPropertyMap.GetKeyAt(i).indexKey);
     if(finishValue)
     {
+      // If this transition is appearing transition, this property keeps start value during delay.
+      // If multiple transitions are applied to this Control and others run before this transition,
+      // this property should keep start value until this transition starts.
+      if(!IsPairTransition() && IsAppearingTransition() && mTimePeriod.delaySeconds > Dali::Math::MACHINE_EPSILON_10)
+      {
+        mTarget.SetProperty(mStartPropertyMap.GetKeyAt(i).indexKey, mStartPropertyMap.GetValue(i));
+      }
       AnimateBetween(mTarget, mStartPropertyMap.GetKeyAt(i).indexKey, mStartPropertyMap.GetValue(i), *finishValue);
     }
   }
index 409eb60..b194e52 100644 (file)
@@ -101,6 +101,30 @@ public:
     mIsAppearingTransition = appearingTransition;
   }
 
+  /**
+   * @brief Returns whether this transition is appearing transition or not
+   */
+  bool IsAppearingTransition() const
+  {
+    return mIsAppearingTransition;
+  }
+
+  /**
+   * @brief Returns whether this transition is a transition from a Control to another Control or effect to appearing or disappearing.
+   */
+  bool IsPairTransition() const
+  {
+    return mIsPairTransition;
+  }
+
+  /**
+   * @brief Returns target which will be transition.
+   */
+  const Dali::Toolkit::Control GetTarget() const
+  {
+    return mTarget;
+  }
+
 protected:
 
   /**
@@ -159,14 +183,6 @@ protected:
   }
 
   /**
-   * @brief Returns whether this transition is appearing transition or not
-   */
-  bool IsAppearingTransition() const
-  {
-    return mIsAppearingTransition;
-  }
-
-  /**
    * @brief Set whether this transition is a transition from a Control to another Control or effect to appearing or disappearing.
    * @param[in] pairTransition True if this transition is appearing transition.
    */
@@ -175,14 +191,6 @@ protected:
     mIsPairTransition = pairTransition;
   }
 
-  /**
-   * @brief Returns whether this transition is a transition from a Control to another Control or effect to appearing or disappearing.
-   */
-  bool IsPairTransition() const
-  {
-    return mIsPairTransition;
-  }
-
 protected:
   /**
    * Construct a new TransitionBase.
index fd019b6..d1b16af 100644 (file)
@@ -37,6 +37,13 @@ namespace
 // Signals
 static constexpr std::string_view SIGNAL_FINISHED = "finished";
 
+static constexpr float OPACITY_TRANSPARENT = 0.0f;
+
+float CustomAlphaFunction(float progress)
+{
+  return (progress >= 1.0f) ? 1.0f : 0.0f;
+}
+
 BaseHandle Create()
 {
   return Dali::Toolkit::TransitionSet::New();
@@ -117,9 +124,46 @@ void TransitionSet::TransitionPreProcess()
 
 void TransitionSet::TransitionStart()
 {
+  std::vector<std::pair<Dali::Actor, float>> minimumDelays;
   for(auto&& transition : mTransitions)
   {
     transition->Play();
+
+    // If target Control has appearing transition, the target will not be rendered during delay.
+    // And if the Control has multiple transitions, the target will not be rendered during minimum delay of the transitions.
+    // Here we can find minimum delay of each target.
+    if(!transition->IsPairTransition() && transition->IsAppearingTransition())
+    {
+      bool found = false;
+      for(uint32_t index = 0; index < minimumDelays.size(); ++index)
+      {
+        if(minimumDelays[index].first == transition->GetTarget())
+        {
+          minimumDelays[index].second = std::min(minimumDelays[index].second, transition->GetTimePeriod().delaySeconds);
+          found = true;
+          break;
+        }
+      }
+      if(!found)
+      {
+        minimumDelays.push_back(std::pair<Dali::Actor, float>(transition->GetTarget(), transition->GetTimePeriod().delaySeconds));
+      }
+    }
+  }
+
+  // If the target has delay that is larger than 0, hide the target during minimum delay.
+  // The custom alpha function make the target hide just during delay.
+  for(auto&& delay : minimumDelays)
+  {
+    if(delay.second > Dali::Math::MACHINE_EPSILON_10)
+    {
+      Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
+      initialKeyframes.Add(0.0f, OPACITY_TRANSPARENT);
+      initialKeyframes.Add(1.0f, delay.first.GetProperty<float>(Dali::Actor::Property::OPACITY));
+
+      AlphaFunction alpha(&CustomAlphaFunction);
+      mAnimation.AnimateBetween(Property(delay.first, Dali::Actor::Property::OPACITY), initialKeyframes, alpha, TimePeriod(delay.second));
+    }
   }
 
   mAnimation.FinishedSignal().Connect(this, &TransitionSet::TransitionFinished);