(Clipping Example) Add a rotation effect around the X-axis as we scroll through the... 80/110880/1
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 18 Jan 2017 10:23:04 +0000 (10:23 +0000)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 18 Jan 2017 10:23:18 +0000 (10:23 +0000)
Change-Id: I4a485a758d54ca01c0bf5c2dc3d2162f27810241

examples/clipping/clipping-example.cpp
examples/clipping/item-view-orientation-constraint.h [new file with mode: 0644]

index 4db5147..6598b68 100644 (file)
@@ -24,6 +24,7 @@
 
 // INTERNAL INCLUDES
 #include "clipping-item-factory.h"
+#include "item-view-orientation-constraint.h"
 
 using namespace Dali;
 using namespace Dali::Toolkit;
@@ -32,8 +33,13 @@ namespace
 {
 const char * const APPLICATION_TITLE( "Clipping Controls" );
 const Vector3 APPLICATION_TITLE_PARENT_ORIGIN( 0.5f, 0.03f, 0.5f ); // Set the parent origin to a small percentage below the top (so the demo will scale for different resolutions).
+
 const Vector3 ITEM_VIEW_LAYOUT_SIZE_SCALE( 0.75f, 0.5f, 0.75f );
 const float ITEM_VIEW_BORDER_SIZE = 2.0f;
+const float ITEM_VIEW_MAXIMUM_ROTATION_IN_DEGREES = 20.0f;
+const float ITEM_VIEW_LAYOUT_POSITION_CHANGE_MULTIPLIER = 3.0f;
+const float ITEM_VIEW_ROTATION_ANIMATION_TIME = 0.2f;
+
 const char * const BUTTON_LABEL( "Toggle Clipping Mode" );
 } // unnamed namespace
 
@@ -44,6 +50,8 @@ const char * const BUTTON_LABEL( "Toggle Clipping Mode" );
  * need to clip to. UI Controls automate the creation of the renderers/visuals when they are set to clip their children.
  *
  * This example displays an item-view whose clipping mode is toggled without the need for adding any renderers to it.
+ *
+ * Additionally, a constraint is used to modify the item-view's orientation.
  */
 class ClippingExample : public ConnectionTracker
 {
@@ -100,6 +108,14 @@ private:
     const Vector3 itemViewLayoutSize( ITEM_VIEW_LAYOUT_SIZE_SCALE.x * stageSize.x, ITEM_VIEW_LAYOUT_SIZE_SCALE.y * stageSize.y, ITEM_VIEW_LAYOUT_SIZE_SCALE.z * stageSize.x );
     mItemView.ActivateLayout( 0, itemViewLayoutSize, 0.0f );
 
+    // Connect to the scroll started and completed signals to apply orientation constraints & animations.
+    mItemView.ScrollStartedSignal().Connect( this, &ClippingExample::ScrollStarted );
+    mItemView.ScrollCompletedSignal().Connect( this, &ClippingExample::ScrollCompleted );
+
+    // Create a constraint for the item-view which we apply when we start scrolling and remove when we stop.
+    mItemViewOrientationConstraint = Constraint::New< Quaternion >( mItemView, Actor::Property::ORIENTATION, ItemViewOrientationConstraint( ITEM_VIEW_MAXIMUM_ROTATION_IN_DEGREES, ITEM_VIEW_LAYOUT_POSITION_CHANGE_MULTIPLIER ) );
+    mItemViewOrientationConstraint.AddSource( LocalSource( ItemView::Property::LAYOUT_POSITION ) );
+
     // Create a border around item-view (as item-view is clipping its children, we should NOT add this as a child of item-view).
     Control border = Control::New();
     border.SetParentOrigin( ParentOrigin::CENTER );
@@ -107,10 +123,16 @@ private:
     border.SetProperty( Control::Property::BACKGROUND,
                         Property::Map().Add( Visual::Property::TYPE, Visual::BORDER )
                                        .Add( BorderVisual::Property::COLOR, Color::WHITE )
-                                       .Add( BorderVisual::Property::SIZE, 2.0f ) );
+                                       .Add( BorderVisual::Property::SIZE, 2.0f )
+                                       .Add( BorderVisual::Property::ANTI_ALIASING, true ) );
     border.SetSize( Vector3( itemViewLayoutSize.x + ITEM_VIEW_BORDER_SIZE * 2.0f, itemViewLayoutSize.y + ITEM_VIEW_BORDER_SIZE * 2.0f, itemViewLayoutSize.z + ITEM_VIEW_BORDER_SIZE * 2.0f ) );
     stage.Add( border );
 
+    // Constrain the border's orientation to the orientation of item-view.
+    Constraint constraint = Constraint::New< Quaternion >( border, Actor::Property::ORIENTATION, EqualToConstraint() );
+    constraint.AddSource( Source( mItemView, Actor::Property::ORIENTATION ) );
+    constraint.Apply();
+
     // Create a button to toggle the clipping mode
     PushButton button = Toolkit::PushButton::New();
     button.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
@@ -118,14 +140,36 @@ private:
     button.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
     button.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
     button.SetProperty( Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D );
-    button.SetProperty( Button::Property::LABEL,
-                        Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::TEXT )
-                                       .Add( Toolkit::TextVisual::Property::TEXT, BUTTON_LABEL ) );
+    button.SetProperty( Button::Property::LABEL, BUTTON_LABEL );
     button.ClickedSignal().Connect( this, &ClippingExample::OnButtonClicked );
     stage.Add( button );
   }
 
   /**
+   * @brief Called when the item-view starts to scroll.
+   *
+   * Here we want to apply the item-view constraint.
+   */
+  void ScrollStarted( const Vector2& /* currentScrollPosition */ )
+  {
+    mItemViewOrientationConstraint.Apply();
+  }
+
+  /**
+   * @brief Called when the item-view scrolling completes.
+   *
+   * Here we remove the item-view orientation constraint and perform an animation to return the item-view back to base-rotation.
+   */
+  void ScrollCompleted( const Vector2& /* currentScrollPosition */ )
+  {
+    Animation animation = Animation::New( ITEM_VIEW_ROTATION_ANIMATION_TIME );
+    animation.AnimateTo( Property( mItemView, Actor::Property::ORIENTATION ), Quaternion( Degree( 0.0f ), Vector3::XAXIS ), AlphaFunction::EASE_IN_SINE );
+    animation.Play();
+
+    mItemViewOrientationConstraint.Remove();
+  }
+
+  /**
    * @brief Called when any key event is received
    *
    * Will use this to quit the application if Back or the Escape key is received
@@ -163,6 +207,7 @@ private:
   Application& mApplication; ///< Reference to the application class.
   ItemView mItemView; ///< The item view which whose children we would like to clip.
   ClippingItemFactory mClippingItemFactory; ///< The ItemFactory used to create our items.
+  Constraint mItemViewOrientationConstraint; ///< The constraint used to control the orientation of item-view.
 };
 
 int DALI_EXPORT_API main( int argc, char **argv )
diff --git a/examples/clipping/item-view-orientation-constraint.h b/examples/clipping/item-view-orientation-constraint.h
new file mode 100644 (file)
index 0000000..0ff4bf9
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef ITEM_VIEW_ORIENTATION_CONSTRAINT_H
+#define ITEM_VIEW_ORIENTATION_CONSTRAINT_H
+
+/*
+ * Copyright (c) 2017 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/math/degree.h>
+#include <dali/public-api/math/math-utils.h>
+#include <dali/public-api/math/quaternion.h>
+#include <dali/public-api/math/radian.h>
+#include <dali/public-api/math/vector3.h>
+
+/**
+ * @brief Constraint used to constrain the orientation of the item-view depending on the position within the layout.
+ */
+class ItemViewOrientationConstraint
+{
+public:
+
+  /**
+   * @brief Constructor.
+   * @param[in] maximumRotationInDegrees       The maximum rotation (in degrees) that we should rotate the item-view by.
+   * @param[in] layoutPositionChangeMultiplier This value is used to multiply the change in layout position
+   *                                           (in order to exaggerate the amount moved so it's more visible).
+   */
+  ItemViewOrientationConstraint( float maximumRotationInDegrees, float layoutPositionChangeMultiplier )
+  : mMaximumRotationInDegrees( maximumRotationInDegrees ),
+    mLayoutPositionChangeMultiplier( layoutPositionChangeMultiplier ),
+    mStartingLayoutPosition( 0.0f ),
+    mStartingAngle( 0.0f ),
+    mFirstCall( true )
+  {
+  }
+
+  /**
+   * @brief Will be called by the Constraint.
+   *
+   * The first time this operator is called, it uses the values as it's base reference.
+   * Thereafter, the position in the layout is used to determine the rotation around the X-Axis.
+   *
+   * @param[in] rotation The rotation of the item-view.
+   * @param[in] inputs   The constraint inputs:
+   *                     [0] ItemView::Property::LAYOUT_POSITION, float
+   */
+  void operator()( Dali::Quaternion& rotation, const Dali::PropertyInputContainer& inputs )
+  {
+    const float& layoutPosition = inputs[ 0 ]->GetFloat();
+
+    // Store values for base reference when called the first call.
+    if( mFirstCall )
+    {
+      mStartingLayoutPosition = layoutPosition;
+
+      Dali::Vector3 axis;
+      Dali::Radian angleInRadians;
+      rotation.ToAxisAngle( axis, angleInRadians );
+      Dali::Degree angleInDegrees( angleInRadians ); // Convert to Degrees
+
+      mStartingAngle = angleInDegrees.degree;
+      if( axis.x < 0.0f ) // We only rotate round the X-Axis. So if the X-Axis is negative, then the angle is also a negative angle.
+      {
+        mStartingAngle = -mStartingAngle;
+      }
+
+      mFirstCall = false;
+    }
+    else
+    {
+      // All subsequent calls should tilt the orientation of the item-view around the X-Axis depending on how much our position has changed in the layout.
+
+      Dali::Degree angle( mStartingAngle + mLayoutPositionChangeMultiplier * ( mStartingLayoutPosition - layoutPosition ) );
+      Dali::ClampInPlace( angle.degree, -mMaximumRotationInDegrees, mMaximumRotationInDegrees ); // Ensure the angle does not exceed maximum specified (in both directions).
+      rotation = Dali::Quaternion( angle, Dali::Vector3::XAXIS );
+    }
+  }
+
+private:
+
+  const float mMaximumRotationInDegrees; ///< The maximum allowable rotation of the item-view.
+  const float mLayoutPositionChangeMultiplier; ///< This value is used to multiply the change in layout position.
+  float mStartingLayoutPosition; ///< The starting layout position.
+  float mStartingAngle; ///< The starting angle (in degrees) of the item-view.
+  bool mFirstCall; ///< A boolean to state whether this is the first time the operator() is called. Allows us to set the starting values.
+};
+
+#endif // ITEM_VIEW_ORIENTATION_CONSTRAINT_H