Changes after Set/Get synchronous behaviour of registered animatable & custom properties
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scroll-bar / scroll-bar-impl.cpp
index 120dcb7..b59e6e0 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * 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.
 #include <dali/public-api/object/property-array.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/integration-api/debug.h>
-
+#include <dali/devel-api/object/property-helper-devel.h>
+#include <dali/devel-api/object/handle-devel.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h>
 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/devel-api/controls/scroll-bar/scroll-bar-devel.h>
 
 using namespace Dali;
 
@@ -39,12 +41,15 @@ namespace
 {
 
 const char* DEFAULT_INDICATOR_IMAGE_PATH = DALI_IMAGE_DIR "popup_scroll.9.png";
-const float MINIMUM_INDICATOR_HEIGHT(20.0f); // The minimum indicator height for the nine patch border
 const float DEFAULT_SLIDER_DEPTH(1.0f);
 const float DEFAULT_INDICATOR_SHOW_DURATION(0.5f);
 const float DEFAULT_INDICATOR_HIDE_DURATION(0.5f);
 const float DEFAULT_PAN_GESTURE_PROCESS_TIME(16.7f); // 16.7 milliseconds, i.e. one frame
 const float DEFAULT_INDICATOR_FIXED_HEIGHT(80.0f);
+const float DEFAULT_INDICATOR_MINIMUM_HEIGHT(0.0f);
+const float DEFAULT_INDICATOR_START_PADDING(0.0f);
+const float DEFAULT_INDICATOR_END_PADDING(0.0f);
+const float DEFAULT_INDICATOR_TRANSIENT_DURATION(1.0f);
 
 /**
  * Indicator size constraint
@@ -52,7 +57,13 @@ const float DEFAULT_INDICATOR_FIXED_HEIGHT(80.0f);
  */
 struct IndicatorSizeConstraint
 {
-  IndicatorSizeConstraint()
+  /**
+   * @param[in] minimumHeight The minimum height for the indicator
+   * @param[in] padding The sum of the padding at the start & end of the indicator
+   */
+  IndicatorSizeConstraint( float minimumHeight, float padding )
+  : mMinimumHeight( minimumHeight ),
+    mPadding( padding )
   {
   }
 
@@ -62,17 +73,23 @@ struct IndicatorSizeConstraint
    * @param[in] parentSizeProperty The parent size of scroll indicator.
    * @return The new scroll indicator size.
    */
-  void operator()(Vector3& current, const PropertyInputContainer& inputs )
+  void operator()( Vector3& current, const PropertyInputContainer& inputs )
   {
     const Vector3& parentSize = inputs[0]->GetVector3();
     const float contentSize = inputs[1]->GetFloat();
 
-    float height = contentSize > parentSize.height ?
-                   parentSize.height * ( parentSize.height / contentSize ) :
-                   parentSize.height * ( (parentSize.height - contentSize * 0.5f) / parentSize.height);
+    // Take into account padding that may exist at the beginning and end of the indicator.
+    const float parentHeightMinusPadding = parentSize.height - mPadding;
+
+    float height = contentSize > parentHeightMinusPadding ?
+                   parentHeightMinusPadding * ( parentHeightMinusPadding / contentSize ) :
+                   parentHeightMinusPadding * ( ( parentHeightMinusPadding - contentSize * 0.5f ) / parentHeightMinusPadding );
 
-    current.y = std::max(MINIMUM_INDICATOR_HEIGHT, height);
+    current.y = std::max( mMinimumHeight, height );
   }
+
+  float mMinimumHeight;
+  float mPadding;
 };
 
 /**
@@ -82,10 +99,12 @@ struct IndicatorSizeConstraint
 struct IndicatorPositionConstraint
 {
   /**
-   * @param[in] minPosition The minimum limit of scroll position
-   * @param[in] maxPosition the maximum limit of scroll position
+   * @param[in] startPadding The padding at the start of the indicator
+   * @param[in] endPadding The padding at the end of the indicator
    */
-  IndicatorPositionConstraint()
+  IndicatorPositionConstraint( float startPadding, float endPadding )
+  : mStartPadding( startPadding ),
+    mEndPadding( endPadding )
   {
   }
 
@@ -100,13 +119,19 @@ struct IndicatorPositionConstraint
     const Vector3& indicatorSize = inputs[0]->GetVector3();
     const Vector3& parentSize = inputs[1]->GetVector3();
     const float scrollPosition = -inputs[2]->GetFloat();
-    const float minScrollPosition = inputs[3]->GetFloat();
-    const float maxScrollPosition = inputs[4]->GetFloat();
+    const float minimumScrollPosition = inputs[3]->GetFloat();
+    const float maximumScrollPosition = inputs[4]->GetFloat();
+
+    // Take into account padding that may exist at the beginning and end of the indicator.
+    const float parentHeightMinusPadding = parentSize.height - ( mStartPadding + mEndPadding );
 
-    float relativePosition = std::max( 0.0f, std::min( 1.0f, (scrollPosition - minScrollPosition) / (maxScrollPosition - minScrollPosition) ) );
-    current.y = ( parentSize.height - indicatorSize.height ) * relativePosition;
+    float relativePosition = std::max( 0.0f, std::min( 1.0f, ( scrollPosition - minimumScrollPosition ) / ( maximumScrollPosition - minimumScrollPosition ) ) );
+    current.y = mStartPadding + ( parentHeightMinusPadding - indicatorSize.height ) * relativePosition;
     current.z = DEFAULT_SLIDER_DEPTH;
   }
+
+  float mStartPadding;
+  float mEndPadding;
 };
 
 } // unnamed namespace
@@ -133,16 +158,25 @@ BaseHandle Create()
 // Setup properties, signals and actions using the type-registry.
 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ScrollBar, Toolkit::Control, Create );
 
-DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "scrollDirection",                   STRING, SCROLL_DIRECTION          )
-DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorHeightPolicy",             STRING, INDICATOR_HEIGHT_POLICY   )
-DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorFixedHeight",              FLOAT,  INDICATOR_FIXED_HEIGHT    )
-DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorShowDuration",             FLOAT,  INDICATOR_SHOW_DURATION   )
-DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorHideDuration",             FLOAT,  INDICATOR_HIDE_DURATION   )
-DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "scrollPositionIntervals",           ARRAY,  SCROLL_POSITION_INTERVALS )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "scrollDirection",                   STRING, SCROLL_DIRECTION             )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorHeightPolicy",             STRING, INDICATOR_HEIGHT_POLICY      )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorFixedHeight",              FLOAT,  INDICATOR_FIXED_HEIGHT       )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorShowDuration",             FLOAT,  INDICATOR_SHOW_DURATION      )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorHideDuration",             FLOAT,  INDICATOR_HIDE_DURATION      )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "scrollPositionIntervals",           ARRAY,  SCROLL_POSITION_INTERVALS    )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorMinimumHeight",            FLOAT,  INDICATOR_MINIMUM_HEIGHT     )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorStartPadding",             FLOAT,  INDICATOR_START_PADDING      )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorEndPadding",               FLOAT,  INDICATOR_END_PADDING        )
 
-DALI_SIGNAL_REGISTRATION(   Toolkit, ScrollBar, "panFinished",                       PAN_FINISHED_SIGNAL )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorTransientDuration", FLOAT,  INDICATOR_TRANSIENT_DURATION )
+
+DALI_SIGNAL_REGISTRATION(   Toolkit, ScrollBar, "panFinished",                       PAN_FINISHED_SIGNAL                     )
 DALI_SIGNAL_REGISTRATION(   Toolkit, ScrollBar, "scrollPositionIntervalReached",     SCROLL_POSITION_INTERVAL_REACHED_SIGNAL )
 
+DALI_ACTION_REGISTRATION(   Toolkit, ScrollBar, "ShowIndicator",                     ACTION_SHOW_INDICATOR                   )
+DALI_ACTION_REGISTRATION(   Toolkit, ScrollBar, "HideIndicator",                     ACTION_HIDE_INDICATOR                   )
+DALI_ACTION_REGISTRATION(   Toolkit, ScrollBar, "ShowTransientIndicator",            ACTION_SHOW_TRANSIENT_INDICATOR         )
+
 DALI_TYPE_REGISTRATION_END()
 
 const char* SCROLL_DIRECTION_NAME[] = {"Vertical", "Horizontal"};
@@ -151,7 +185,7 @@ const char* INDICATOR_HEIGHT_POLICY_NAME[] = {"Variable", "Fixed"};
 }
 
 ScrollBar::ScrollBar(Toolkit::ScrollBar::Direction direction)
-: Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
   mIndicatorShowAlpha(1.0f),
   mDirection(direction),
   mScrollableObject(WeakHandleBase()),
@@ -161,10 +195,14 @@ ScrollBar::ScrollBar(Toolkit::ScrollBar::Direction direction)
   mPropertyScrollContentSize(Property::INVALID_INDEX),
   mIndicatorShowDuration(DEFAULT_INDICATOR_SHOW_DURATION),
   mIndicatorHideDuration(DEFAULT_INDICATOR_HIDE_DURATION),
+  mTransientIndicatorDuration(DEFAULT_INDICATOR_TRANSIENT_DURATION),
   mScrollStart(0.0f),
   mCurrentScrollPosition(0.0f),
   mIndicatorHeightPolicy(Toolkit::ScrollBar::Variable),
   mIndicatorFixedHeight(DEFAULT_INDICATOR_FIXED_HEIGHT),
+  mIndicatorMinimumHeight(DEFAULT_INDICATOR_MINIMUM_HEIGHT),
+  mIndicatorStartPadding(DEFAULT_INDICATOR_START_PADDING),
+  mIndicatorEndPadding(DEFAULT_INDICATOR_END_PADDING),
   mIsPanning(false),
   mIndicatorFirstShow(true)
 {
@@ -207,7 +245,8 @@ void ScrollBar::CreateDefaultIndicatorActor()
   Toolkit::ImageView indicator = Toolkit::ImageView::New( DEFAULT_INDICATOR_IMAGE_PATH );
   indicator.SetParentOrigin( ParentOrigin::TOP_LEFT );
   indicator.SetAnchorPoint( AnchorPoint::TOP_LEFT );
-
+  indicator.SetStyleName( "ScrollBarIndicator" );
+  indicator.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
   SetScrollIndicator(indicator);
 }
 
@@ -216,11 +255,17 @@ void ScrollBar::SetScrollIndicator( Actor indicator )
   // Don't allow empty handle
   if( indicator )
   {
+    // Remove current Indicator
+    if( mIndicator )
+    {
+      Self().Remove( mIndicator );
+    }
     mIndicator = indicator;
+
     mIndicatorFirstShow = true;
-    Self().Add(mIndicator);
+    Self().Add( mIndicator );
 
-    EnableGestureDetection(Gesture::Type(Gesture::Pan));
+    EnableGestureDetection( Gesture::Type( Gesture::Pan ) );
 
     PanGestureDetector detector( GetPanGestureDetector() );
     detector.DetachAll();
@@ -265,7 +310,8 @@ void ScrollBar::ApplyConstraints()
     }
     else
     {
-      mIndicatorSizeConstraint = Constraint::New<Vector3>( mIndicator, Actor::Property::SIZE, IndicatorSizeConstraint() );
+      mIndicatorSizeConstraint = Constraint::New<Vector3>( mIndicator, Actor::Property::SIZE,
+                                                           IndicatorSizeConstraint( mIndicatorMinimumHeight, mIndicatorStartPadding + mIndicatorEndPadding ) );
       mIndicatorSizeConstraint.AddSource( ParentSource( Actor::Property::SIZE ) );
       mIndicatorSizeConstraint.AddSource( Source( scrollableHandle, mPropertyScrollContentSize ) );
       mIndicatorSizeConstraint.Apply();
@@ -276,7 +322,8 @@ void ScrollBar::ApplyConstraints()
       mIndicatorPositionConstraint.Remove();
     }
 
-    mIndicatorPositionConstraint = Constraint::New<Vector3>( mIndicator, Actor::Property::POSITION, IndicatorPositionConstraint() );
+    mIndicatorPositionConstraint = Constraint::New<Vector3>( mIndicator, Actor::Property::POSITION,
+                                                             IndicatorPositionConstraint( mIndicatorStartPadding, mIndicatorEndPadding ) );
     mIndicatorPositionConstraint.AddSource( LocalSource( Actor::Property::SIZE ) );
     mIndicatorPositionConstraint.AddSource( ParentSource( Actor::Property::SIZE ) );
     mIndicatorPositionConstraint.AddSource( Source( scrollableHandle, mPropertyScrollPosition ) );
@@ -315,7 +362,7 @@ void ScrollBar::OnScrollPositionIntervalReached(PropertyNotification& source)
   Handle scrollableHandle = mScrollableObject.GetBaseHandle();
   if(scrollableHandle)
   {
-    mScrollPositionIntervalReachedSignal.Emit(scrollableHandle.GetProperty<float>(mPropertyScrollPosition));
+    mScrollPositionIntervalReachedSignal.Emit( DevelHandle::GetCurrentProperty< float >( scrollableHandle, mPropertyScrollPosition ) );
   }
 }
 
@@ -368,6 +415,30 @@ void ScrollBar::HideIndicator()
   }
 }
 
+void ScrollBar::ShowTransientIndicator()
+{
+  // Cancel any animation
+  if(mAnimation)
+  {
+    mAnimation.Clear();
+    mAnimation.Reset();
+  }
+
+  mAnimation = Animation::New( mIndicatorShowDuration + mTransientIndicatorDuration + mIndicatorHideDuration );
+  if(mIndicatorShowDuration > 0.0f)
+  {
+    mAnimation.AnimateTo( Property( mIndicator, Actor::Property::COLOR_ALPHA ),
+                          mIndicatorShowAlpha, AlphaFunction::EASE_IN, TimePeriod(0, mIndicatorShowDuration) );
+  }
+  else
+  {
+    mIndicator.SetOpacity(mIndicatorShowAlpha);
+  }
+  mAnimation.AnimateTo( Property( mIndicator, Actor::Property::COLOR_ALPHA ),
+                        0.0f, AlphaFunction::EASE_IN, TimePeriod((mIndicatorShowDuration + mTransientIndicatorDuration), mIndicatorHideDuration) );
+  mAnimation.Play();
+}
+
 bool ScrollBar::OnPanGestureProcessTick()
 {
   // Update the scroll position property.
@@ -401,7 +472,7 @@ void ScrollBar::OnPan( const PanGesture& gesture )
         }
 
         ShowIndicator();
-        mScrollStart = scrollableHandle.GetProperty<float>(mPropertyScrollPosition);
+        mScrollStart = DevelHandle::GetCurrentProperty< float >( scrollableHandle, mPropertyScrollPosition );
         mGestureDisplacement = Vector3::ZERO;
         mIsPanning = true;
 
@@ -409,16 +480,18 @@ void ScrollBar::OnPan( const PanGesture& gesture )
       }
       case Gesture::Continuing:
       {
-        Vector3 delta(gesture.displacement.x, gesture.displacement.y, 0.0f);
-        mGestureDisplacement+=delta;
+        mGestureDisplacement.x += gesture.displacement.x;
+        mGestureDisplacement.y += gesture.displacement.y;
+
+        float minScrollPosition = DevelHandle::GetCurrentProperty<float>( scrollableHandle, mPropertyMinScrollPosition );
+        float maxScrollPosition = DevelHandle::GetCurrentProperty<float>( scrollableHandle, mPropertyMaxScrollPosition );
 
-        Vector3 span = Self().GetCurrentSize() - mIndicator.GetCurrentSize();
-        float minScrollPosition = scrollableHandle.GetProperty<float>(mPropertyMinScrollPosition);
-        float maxScrollPosition = scrollableHandle.GetProperty<float>(mPropertyMaxScrollPosition);
+        // The domain size is the internal range
         float domainSize = maxScrollPosition - minScrollPosition;
+        float logicalSize = Self().GetCurrentSize().y - ( mIndicator.GetCurrentSize().y + mIndicatorStartPadding + mIndicatorEndPadding );
 
-        mCurrentScrollPosition = mScrollStart - mGestureDisplacement.y * domainSize / span.y;
-        mCurrentScrollPosition = 0.0f - std::min(maxScrollPosition, std::max(-mCurrentScrollPosition, minScrollPosition));
+        mCurrentScrollPosition = mScrollStart - ( ( mGestureDisplacement.y * domainSize ) / logicalSize );
+        mCurrentScrollPosition = -std::min( maxScrollPosition, std::max( -mCurrentScrollPosition, minScrollPosition ) );
 
         break;
       }
@@ -460,6 +533,8 @@ void ScrollBar::OnSizeSet( const Vector3& size )
   {
     mIndicator.SetSize(size.width, mIndicatorFixedHeight);
   }
+
+  Control::OnSizeSet( size );
 }
 
 void ScrollBar::SetScrollDirection( Toolkit::ScrollBar::Direction direction )
@@ -474,8 +549,11 @@ Toolkit::ScrollBar::Direction ScrollBar::GetScrollDirection() const
 
 void ScrollBar::SetIndicatorHeightPolicy( Toolkit::ScrollBar::IndicatorHeightPolicy policy )
 {
-  mIndicatorHeightPolicy = policy;
-  ApplyConstraints();
+  if( policy != mIndicatorHeightPolicy )
+  {
+    mIndicatorHeightPolicy = policy;
+    ApplyConstraints();
+  }
 }
 
 Toolkit::ScrollBar::IndicatorHeightPolicy ScrollBar::GetIndicatorHeightPolicy() const
@@ -627,6 +705,29 @@ void ScrollBar::SetProperty( BaseObject* object, Property::Index index, const Pr
         }
         break;
       }
+      case Toolkit::ScrollBar::Property::INDICATOR_MINIMUM_HEIGHT:
+      {
+        scrollBarImpl.mIndicatorMinimumHeight = value.Get<float>();
+        scrollBarImpl.ApplyConstraints();
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_START_PADDING:
+      {
+        scrollBarImpl.mIndicatorStartPadding = value.Get<float>();
+        scrollBarImpl.ApplyConstraints();
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_END_PADDING:
+      {
+        scrollBarImpl.mIndicatorEndPadding = value.Get<float>();
+        scrollBarImpl.ApplyConstraints();
+        break;
+      }
+      case Toolkit::DevelScrollBar::Property::INDICATOR_TRANSIENT_DURATION:
+      {
+        scrollBarImpl.mTransientIndicatorDuration = value.Get<float>();
+        break;
+      }
     }
   }
 }
@@ -683,11 +784,63 @@ Property::Value ScrollBar::GetProperty( BaseObject* object, Property::Index inde
         }
         break;
       }
+      case Toolkit::ScrollBar::Property::INDICATOR_MINIMUM_HEIGHT:
+      {
+        value = scrollBarImpl.mIndicatorMinimumHeight;
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_START_PADDING:
+      {
+        value = scrollBarImpl.mIndicatorStartPadding;
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_END_PADDING:
+      {
+        value = scrollBarImpl.mIndicatorEndPadding;
+        break;
+      }
+      case Toolkit::DevelScrollBar::Property::INDICATOR_TRANSIENT_DURATION:
+      {
+        value = scrollBarImpl.mTransientIndicatorDuration;
+        break;
+      }
     }
   }
   return value;
 }
 
+bool ScrollBar::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
+{
+  bool ret = false;
+
+  Dali::BaseHandle handle( object );
+
+  Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast( handle );
+
+  DALI_ASSERT_DEBUG( scrollBar );
+
+  if( scrollBar )
+  {
+    if( 0 == strcmp( actionName.c_str(), ACTION_SHOW_INDICATOR ) )
+    {
+      GetImpl( scrollBar ).ShowIndicator();
+      ret = true;
+    }
+    else if( 0 == strcmp( actionName.c_str(), ACTION_HIDE_INDICATOR ) )
+    {
+      GetImpl( scrollBar ).HideIndicator();
+      ret = true;
+    }
+    else if( 0 == strcmp( actionName.c_str(), ACTION_SHOW_TRANSIENT_INDICATOR ) )
+    {
+      GetImpl( scrollBar ).ShowTransientIndicator();
+      ret = true;
+    }
+  }
+
+  return ret;
+}
+
 Toolkit::ScrollBar ScrollBar::New(Toolkit::ScrollBar::Direction direction)
 {
   // Create the implementation, temporarily owned by this handle on stack