2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h>
22 #include <cstring> // for strcmp
23 #include <dali/public-api/animation/constraint.h>
24 #include <dali/public-api/animation/constraints.h>
25 #include <dali/public-api/object/type-registry.h>
26 #include <dali/public-api/object/type-registry-helper.h>
27 #include <dali/public-api/images/resource-image.h>
30 #include <dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h>
37 const char* DEFAULT_INDICATOR_IMAGE_PATH = DALI_IMAGE_DIR "popup_scroll.png";
38 const Vector4 DEFAULT_INDICATOR_NINE_PATCH_BORDER(4.0f, 9.0f, 7.0f, 11.0f);
39 const float MINIMUM_INDICATOR_HEIGHT(20.0f); // The minimum indicator height for the nine patch border
40 const float DEFAULT_SLIDER_DEPTH(1.0f);
41 const float DEFAULT_INDICATOR_SHOW_DURATION(0.5f);
42 const float DEFAULT_INDICATOR_HIDE_DURATION(0.5f);
43 const float DEFAULT_PAN_GESTURE_PROCESS_TIME(16.7f); // 16.7 milliseconds, i.e. one frame
44 const float DEFAULT_INDICATOR_FIXED_HEIGHT(80.0f);
47 * Indicator size depends on both indicator's parent size and the scroll content size
49 Vector3 IndicatorSize( const Vector3& parentSize, float contentSize)
51 float height = contentSize > parentSize.height ?
52 parentSize.height * ( parentSize.height / contentSize ) :
53 parentSize.height * ( (parentSize.height - contentSize * 0.5f) / parentSize.height);
54 return Vector3( parentSize.width, std::max(MINIMUM_INDICATOR_HEIGHT, height), parentSize.depth );
58 * Indicator position constraint
59 * Positions the indicator to reflect the current scroll position within the scroll domain.
61 struct IndicatorPositionConstraint
64 * @param[in] minPosition The minimum limit of scroll position
65 * @param[in] maxPosition the maximum limit of scroll position
67 IndicatorPositionConstraint(float minPosition, float maxPosition)
68 : mMinPosition(minPosition),
69 mMaxPosition(maxPosition)
75 * @param[in,out] current The current indicator position
76 * @param[in] inputs Contains the size of indicator, the size of indicator's parent, and the scroll position of the scrollable container (from 0.0 -> 1.0 in each axis)
77 * @return The new indicator position is returned.
79 void operator()( Vector3& current, const PropertyInputContainer& inputs )
81 const Vector3& indicatorSize = inputs[0]->GetVector3();
82 const Vector3& parentSize = inputs[1]->GetVector3();
83 float scrollPosition = inputs[2]->GetFloat();
85 const float domainSize = fabs(mMaxPosition - mMinPosition);
86 float relativePosition = (mMaxPosition - scrollPosition) / domainSize;
88 current.y = relativePosition * ( parentSize.height - indicatorSize.height );
89 current.z = DEFAULT_SLIDER_DEPTH;
92 float mMinPosition; ///< The minimum scroll position
93 float mMaxPosition; ///< The maximum scroll position
96 } // unnamed namespace
110 using namespace Dali;
114 return Toolkit::ScrollBar::New();
117 // Setup properties, signals and actions using the type-registry.
118 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ScrollBar, Toolkit::ScrollComponent, Create );
120 DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicator-height-policy", STRING, INDICATOR_HEIGHT_POLICY )
121 DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicator-fixed-height", FLOAT, INDICATOR_FIXED_HEIGHT )
122 DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicator-show-duration", FLOAT, INDICATOR_SHOW_DURATION )
123 DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicator-hide-duration", FLOAT, INDICATOR_HIDE_DURATION )
125 DALI_SIGNAL_REGISTRATION( Toolkit, ScrollBar, "scroll-position-notified", SCROLL_POSITION_NOTIFIED_SIGNAL )
127 DALI_TYPE_REGISTRATION_END()
129 const char* INDICATOR_HEIGHT_POLICY_NAME[] = {"Variable", "Fixed"};
133 ScrollBar::ScrollBar()
134 : mIndicatorShowDuration(DEFAULT_INDICATOR_SHOW_DURATION),
135 mIndicatorHideDuration(DEFAULT_INDICATOR_HIDE_DURATION),
138 mCurrentScrollPosition(0.0f),
139 mIndicatorHeightPolicy(Toolkit::ScrollBar::Variable),
140 mIndicatorFixedHeight(DEFAULT_INDICATOR_FIXED_HEIGHT),
141 mPropertyIndicatorPosition(Property::INVALID_INDEX)
145 ScrollBar::~ScrollBar()
149 void ScrollBar::OnInitialize()
153 Image indicatorImage = ResourceImage::New( DEFAULT_INDICATOR_IMAGE_PATH );
154 mIndicator = ImageActor::New( indicatorImage );
155 mIndicator.SetNinePatchBorder( DEFAULT_INDICATOR_NINE_PATCH_BORDER );
156 mIndicator.SetStyle( ImageActor::STYLE_NINE_PATCH );
157 mIndicator.SetParentOrigin( ParentOrigin::TOP_LEFT );
158 mIndicator.SetAnchorPoint( AnchorPoint::TOP_LEFT );
159 self.Add(mIndicator);
161 self.SetDrawMode(DrawMode::OVERLAY);
163 // Enable the pan gesture which is attached to the control
164 EnableGestureDetection(Gesture::Type(Gesture::Pan));
167 void ScrollBar::OnScrollConnectorSet( Toolkit::ScrollConnector oldConnector )
171 oldConnector.DomainChangedSignal().Disconnect(this, &ScrollBar::OnScrollDomainChanged);
173 mScrollPositionObject.Reset();
176 if( mScrollConnector )
178 mScrollPositionObject = mScrollConnector.GetScrollPositionObject();
181 mScrollConnector.DomainChangedSignal().Connect(this, &ScrollBar::OnScrollDomainChanged);
185 void ScrollBar::SetIndicatorImage( Image image )
187 mIndicator.SetImage(image);
190 Actor ScrollBar::GetScrollIndicator()
195 void ScrollBar::ApplyConstraints()
197 if( mScrollConnector )
199 // Set indicator height according to the indicator's height policy
200 if(mIndicatorHeightPolicy == Toolkit::ScrollBar::Fixed)
202 mIndicator.SetSize(Self().GetCurrentSize().width, mIndicatorFixedHeight);
206 mIndicator.SetSize( IndicatorSize( Self().GetCurrentSize(), mScrollConnector.GetContentLength() ) );
209 if(mIndicatorPositionConstraint)
211 mIndicatorPositionConstraint.Remove();
214 mIndicatorPositionConstraint = Constraint::New<Vector3>( mIndicator, Actor::Property::POSITION, IndicatorPositionConstraint( mScrollConnector.GetMinLimit(), mScrollConnector.GetMaxLimit() ) );
215 mIndicatorPositionConstraint.AddSource( LocalSource( Actor::Property::SIZE ) );
216 mIndicatorPositionConstraint.AddSource( ParentSource( Actor::Property::SIZE ) );
217 mIndicatorPositionConstraint.AddSource( Source( mScrollPositionObject, Toolkit::ScrollConnector::SCROLL_POSITION ) );
218 mIndicatorPositionConstraint.Apply();
222 void ScrollBar::SetPositionNotifications( const std::vector<float>& positions )
224 if(mScrollPositionObject)
226 if(mPositionNotification)
228 mScrollPositionObject.RemovePropertyNotification(mPositionNotification);
230 mPositionNotification = mScrollPositionObject.AddPropertyNotification( Toolkit::ScrollConnector::SCROLL_POSITION, VariableStepCondition(positions) );
231 mPositionNotification.NotifySignal().Connect( this, &ScrollBar::OnScrollPositionNotified );
235 void ScrollBar::OnScrollPositionNotified(PropertyNotification& source)
237 // Emit the signal to notify the scroll position crossing
238 mScrollPositionNotifiedSignal.Emit(mScrollConnector.GetScrollPosition());
241 void ScrollBar::Show()
245 // Cancel any animation
252 if(mIndicatorShowDuration > 0.0f)
254 mAnimation = Animation::New( mIndicatorShowDuration );
255 mAnimation.AnimateTo( Property( self, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunctions::EaseIn );
260 self.SetOpacity(1.0f);
264 void ScrollBar::Hide()
268 // Cancel any animation
275 if(mIndicatorHideDuration > 0.0f)
277 mAnimation = Animation::New( mIndicatorHideDuration );
278 mAnimation.AnimateTo( Property( self, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunctions::EaseIn );
283 self.SetOpacity(0.0f);
287 bool ScrollBar::OnPanGestureProcessTick()
289 // Update the scroll position property.
290 if( mScrollConnector )
292 mScrollConnector.SetScrollPosition(mCurrentScrollPosition);
298 void ScrollBar::OnPan( PanGesture gesture )
302 Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast(Self().GetParent());
304 switch(gesture.state)
306 case Gesture::Started:
310 // Make sure the pan gesture is only being processed once per frame.
311 mTimer = Timer::New( DEFAULT_PAN_GESTURE_PROCESS_TIME );
312 mTimer.TickSignal().Connect( this, &ScrollBar::OnPanGestureProcessTick );
317 mScrollStart = mScrollConnector.GetScrollPosition();
318 mGestureDisplacement = Vector3::ZERO;
323 case Gesture::Continuing:
325 Vector3 delta(gesture.displacement.x, gesture.displacement.y, 0.0f);
326 mGestureDisplacement+=delta;
328 Vector3 span = Self().GetCurrentSize() - mIndicator.GetCurrentSize();
329 const float domainSize = fabs(mScrollConnector.GetMaxLimit() - mScrollConnector.GetMinLimit());
330 mCurrentScrollPosition = mScrollStart - mGestureDisplacement.y * domainSize / span.y;
331 mCurrentScrollPosition = std::min(mScrollConnector.GetMaxLimit(), std::max(mCurrentScrollPosition, mScrollConnector.GetMinLimit()));
341 // Destroy the timer when pan gesture is finished.
343 mTimer.TickSignal().Disconnect( this, &ScrollBar::OnPanGestureProcessTick );
349 // Refresh the ItemView cache with extra items
350 GetImpl(itemView).DoRefresh(mCurrentScrollPosition, true);
359 // Disable automatic refresh in ItemView during fast scrolling
360 GetImpl(itemView).SetRefreshEnabled(!mIsPanning);
365 void ScrollBar::OnControlSizeSet( const Vector3& size )
367 if(mIndicatorHeightPolicy != Toolkit::ScrollBar::Fixed && mScrollConnector)
369 mIndicator.SetSize( IndicatorSize( size, mScrollConnector.GetContentLength() ) );
373 void ScrollBar::OnScrollDomainChanged(float minPosition, float maxPosition, float contentSize)
375 // Reapply constraints when the scroll domain is changed
379 void ScrollBar::SetIndicatorHeightPolicy( Toolkit::ScrollBar::IndicatorHeightPolicy policy )
381 mIndicatorHeightPolicy = policy;
385 Toolkit::ScrollBar::IndicatorHeightPolicy ScrollBar::GetIndicatorHeightPolicy()
387 return mIndicatorHeightPolicy;
390 void ScrollBar::SetIndicatorFixedHeight( float height )
392 mIndicatorFixedHeight = height;
396 float ScrollBar::GetIndicatorFixedHeight()
398 return mIndicatorFixedHeight;
401 void ScrollBar::SetIndicatorShowDuration( float durationSeconds )
403 mIndicatorShowDuration = durationSeconds;
406 float ScrollBar::GetIndicatorShowDuration()
408 return mIndicatorShowDuration;
411 void ScrollBar::SetIndicatorHideDuration( float durationSeconds )
413 mIndicatorHideDuration = durationSeconds;
416 float ScrollBar::GetIndicatorHideDuration()
418 return mIndicatorHideDuration;
421 void ScrollBar::OnIndicatorHeightPolicyPropertySet( Property::Value propertyValue )
423 std::string policyName( propertyValue.Get<std::string>() );
424 if(policyName == "Variable")
426 SetIndicatorHeightPolicy(Toolkit::ScrollBar::Variable);
428 else if(policyName == "Fixed")
430 SetIndicatorHeightPolicy(Toolkit::ScrollBar::Fixed);
434 DALI_ASSERT_ALWAYS( !"ScrollBar::OnIndicatorHeightPolicyPropertySet(). Invalid Property value." );
438 bool ScrollBar::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
440 Dali::BaseHandle handle( object );
442 bool connected( true );
443 Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast( handle );
445 if( 0 == strcmp( signalName.c_str(), SCROLL_POSITION_NOTIFIED_SIGNAL ) )
447 scrollBar.ScrollPositionNotifiedSignal().Connect( tracker, functor );
451 // signalName does not match any signal
458 void ScrollBar::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
460 Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast( Dali::BaseHandle( object ) );
464 ScrollBar& scrollBarImpl( GetImpl( scrollBar ) );
467 case Toolkit::ScrollBar::Property::INDICATOR_HEIGHT_POLICY:
469 scrollBarImpl.OnIndicatorHeightPolicyPropertySet( value );
472 case Toolkit::ScrollBar::Property::INDICATOR_FIXED_HEIGHT:
474 scrollBarImpl.SetIndicatorFixedHeight(value.Get<float>());
477 case Toolkit::ScrollBar::Property::INDICATOR_SHOW_DURATION:
479 scrollBarImpl.SetIndicatorShowDuration(value.Get<float>());
482 case Toolkit::ScrollBar::Property::INDICATOR_HIDE_DURATION:
484 scrollBarImpl.SetIndicatorHideDuration(value.Get<float>());
491 Property::Value ScrollBar::GetProperty( BaseObject* object, Property::Index index )
493 Property::Value value;
495 Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast( Dali::BaseHandle( object ) );
499 ScrollBar& scrollBarImpl( GetImpl( scrollBar ) );
502 case Toolkit::ScrollBar::Property::INDICATOR_HEIGHT_POLICY:
504 value = INDICATOR_HEIGHT_POLICY_NAME[ scrollBarImpl.GetIndicatorHeightPolicy() ];
507 case Toolkit::ScrollBar::Property::INDICATOR_FIXED_HEIGHT:
509 value = scrollBarImpl.GetIndicatorFixedHeight();
512 case Toolkit::ScrollBar::Property::INDICATOR_SHOW_DURATION:
514 value = scrollBarImpl.GetIndicatorShowDuration();
517 case Toolkit::ScrollBar::Property::INDICATOR_HIDE_DURATION:
519 value = scrollBarImpl.GetIndicatorHideDuration();
527 Toolkit::ScrollBar ScrollBar::New()
529 // Create the implementation, temporarily owned by this handle on stack
530 IntrusivePtr< ScrollBar > impl = new ScrollBar();
532 // Pass ownership to CustomActor handle
533 Toolkit::ScrollBar handle( *impl );
535 // Second-phase init of the implementation
536 // This can only be done after the CustomActor connection has been made...
542 } // namespace Internal
544 } // namespace Toolkit