Remove the dependency between ScrollBar & ItemView
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scroll-bar / scroll-bar-impl.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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
7 //
8 //     http://floralicense.org/license/
9 //
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.
15 //
16
17 #include <dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h>
18
19 using namespace Dali;
20
21 namespace
22 {
23
24 const char* DEFAULT_INDICATOR_IMAGE_PATH = DALI_IMAGE_DIR "popup_scroll.png";
25 const Vector4 DEFAULT_INDICATOR_NINE_PATCH_BORDER(0.0f, 12.0f, 14.0f, 14.0f);
26 const float DEFAULT_SLIDER_DEPTH(1.0f);
27 const float INDICATOR_SHOW_TIME(0.5f);
28 const float INDICATOR_HIDE_TIME(0.5f);
29
30 /**
31  * Indicator size constraint
32  * Indicator size depends on both indicator's parent size and the scroll content size
33  */
34 struct IndicatorSizeConstraint
35 {
36   /**
37    * @param[in] contentSize The size of scrollable content
38    */
39   IndicatorSizeConstraint(float contentSize)
40   : mContentSize(contentSize)
41   {
42   }
43
44   /**
45    * Constraint operator
46    * @param[in] current The current indicator size
47    * @param[in] parentSizeProperty The parent size of scroll indicator.
48    * @return The new scroll indicator size.
49    */
50   Vector3 operator()(const Vector3& current,
51                      const PropertyInput& parentSizeProperty)
52   {
53     const Vector3& parentSize = parentSizeProperty.GetVector3();
54     float height = mContentSize > parentSize.height ? parentSize.height * ( parentSize.height / mContentSize ) : parentSize.height * ( (parentSize.height - mContentSize * 0.5f) / parentSize.height);
55     return Vector3( parentSize.width, height, parentSize.depth );
56   }
57
58   float mContentSize;  ///< The size of scrollable content
59 };
60
61 /**
62  * Indicator position constraint
63  * Positions the indicator to reflect the current scroll position within the scroll domain.
64  */
65 struct IndicatorPositionConstraint
66 {
67   /**
68    * @param[in] minPosition The minimum limit of scroll position
69    * @param[in] maxPosition the maximum limit of scroll position
70    */
71   IndicatorPositionConstraint(float minPosition, float maxPosition)
72   : mMinPosition(minPosition),
73     mMaxPosition(maxPosition)
74   {
75   }
76
77   /**
78    * Constraint operator
79    * @param[in] current The current indicator position
80    * @param[in] indicatorSizeProperty The size of indicator.
81    * @param[in] parentSizeProperty The parent size of indicator.
82    * @param[in] scrollPositionProperty The scroll position of the scrollable container // (from 0.0 -> 1.0 in each axis)
83    * @return The new indicator position is returned.
84    */
85   Vector3 operator()(const Vector3& current,
86                      const PropertyInput& indicatorSizeProperty,
87                      const PropertyInput& parentSizeProperty,
88                      const PropertyInput& scrollPositionProperty)
89   {
90     Vector3 indicatorSize = indicatorSizeProperty.GetVector3();
91     Vector3 parentSize = parentSizeProperty.GetVector3();
92     float scrollPosition = scrollPositionProperty.GetFloat();
93
94     const float domainSize = fabs(mMaxPosition - mMinPosition);
95     float relativePosition = (mMaxPosition - scrollPosition) / domainSize;
96     return Vector3(current.x, relativePosition * (parentSize.height - indicatorSize.height), DEFAULT_SLIDER_DEPTH);
97   }
98
99   float mMinPosition;  ///< The minimum scroll position
100   float mMaxPosition;  ///< The maximum scroll position
101 };
102
103 } // unnamed namespace
104
105 namespace Dali
106 {
107
108 namespace Toolkit
109 {
110
111 namespace Internal
112 {
113
114 namespace
115 {
116
117 using namespace Dali;
118
119 BaseHandle Create()
120 {
121   return BaseHandle();
122 }
123
124 TypeRegistration mType( typeid(Toolkit::ScrollBar), typeid(Toolkit::Control), Create );
125
126 }
127
128 ScrollBar::ScrollBar()
129 : mScrollStart(0.0f)
130 {
131 }
132
133 ScrollBar::~ScrollBar()
134 {
135 }
136
137 void ScrollBar::OnInitialize()
138 {
139   Actor self = Self();
140
141   Image indicatorImage = Image::New( DEFAULT_INDICATOR_IMAGE_PATH );
142   mIndicator = ImageActor::New( indicatorImage );
143   mIndicator.SetNinePatchBorder( DEFAULT_INDICATOR_NINE_PATCH_BORDER );
144   mIndicator.SetStyle( ImageActor::STYLE_NINE_PATCH );
145   mIndicator.SetParentOrigin( ParentOrigin::TOP_LEFT );
146   mIndicator.SetAnchorPoint( AnchorPoint::TOP_LEFT );
147   self.Add(mIndicator);
148
149   self.SetDrawMode(DrawMode::OVERLAY);
150
151   // Enable the pan gesture which is attached to the control
152   EnableGestureDetection(Gesture::Type(Gesture::Pan));
153 }
154
155 void ScrollBar::OnScrollConnectorSet( Toolkit::ScrollConnector oldConnector )
156 {
157   if( oldConnector )
158   {
159     oldConnector.DomainChangedSignal().Disconnect(this, &ScrollBar::OnScrollDomainChanged);
160
161     mScrollPositionObject.Reset();
162   }
163
164   if( mScrollConnector )
165   {
166     mScrollPositionObject = mScrollConnector.GetScrollPositionObject();
167
168     ApplyConstraints();
169     mScrollConnector.DomainChangedSignal().Connect(this, &ScrollBar::OnScrollDomainChanged);
170   }
171 }
172
173 void ScrollBar::SetBackgroundImage( Image image, const Vector4& border )
174 {
175   if (!mBackground )
176   {
177     mBackground = ImageActor::New( image );
178     mBackground.SetParentOrigin( ParentOrigin::TOP_LEFT );
179     mBackground.SetAnchorPoint( AnchorPoint::TOP_LEFT );
180     Self().Add(mBackground);
181   }
182   else
183   {
184     mBackground.SetImage(image);
185   }
186
187   mBackground.SetNinePatchBorder( border );
188   mBackground.SetStyle( ImageActor::STYLE_NINE_PATCH );
189 }
190
191 void ScrollBar::SetIndicatorImage( Image image, const Vector4& border )
192 {
193   mIndicator.SetImage(image);
194   mIndicator.SetNinePatchBorder( border );
195   mIndicator.SetStyle( ImageActor::STYLE_NINE_PATCH );
196 }
197
198 Actor ScrollBar::GetScrollIndicator()
199 {
200   return mIndicator;
201 }
202
203 void ScrollBar::ApplyConstraints()
204 {
205   mIndicator.RemoveConstraints();
206
207   Constraint constraint = Constraint::New<Vector3>( Actor::SIZE,
208                                                     ParentSource( Actor::SIZE ),
209                                                     IndicatorSizeConstraint( mScrollConnector.GetContentLength() ) );
210   mIndicator.ApplyConstraint( constraint );
211
212   constraint = Constraint::New<Vector3>( Actor::POSITION,
213                                          LocalSource( Actor::SIZE ),
214                                          ParentSource( Actor::SIZE ),
215                                          Source( mScrollPositionObject, Toolkit::ScrollConnector::SCROLL_POSITION ),
216                                          IndicatorPositionConstraint( mScrollConnector.GetMinLimit(), mScrollConnector.GetMaxLimit() ) );
217   mIndicator.ApplyConstraint( constraint );
218
219   if( mBackground )
220   {
221     mBackground.RemoveConstraints();
222
223     constraint = Constraint::New<Vector3>(Actor::SIZE,
224                                           ParentSource(Actor::SIZE),
225                                           EqualToConstraint());
226     mBackground.ApplyConstraint(constraint);
227   }
228 }
229
230 void ScrollBar::SetPositionNotifications( const std::vector<float>& positions )
231 {
232   if(mScrollPositionObject)
233   {
234     if(mPositionNotification)
235     {
236       mScrollPositionObject.RemovePropertyNotification(mPositionNotification);
237     }
238     mPositionNotification = mScrollPositionObject.AddPropertyNotification( Toolkit::ScrollConnector::SCROLL_POSITION, VariableStepCondition(positions) );
239     mPositionNotification.NotifySignal().Connect( this, &ScrollBar::OnScrollPositionNotified );
240   }
241 }
242
243 void ScrollBar::OnScrollPositionNotified(PropertyNotification& source)
244 {
245   // Emit the signal to notify the scroll position crossing
246   mScrollPositionNotifiedSignal.Emit(mScrollPositionObject.GetProperty<float>( Toolkit::ScrollConnector::SCROLL_POSITION ));
247 }
248
249 void ScrollBar::Show()
250 {
251   // Cancel any animation
252   if(mAnimation)
253   {
254     mAnimation.Clear();
255     mAnimation.Reset();
256   }
257
258   mAnimation = Animation::New( INDICATOR_SHOW_TIME );
259   mAnimation.OpacityTo( Self(), 1.0f, AlphaFunctions::EaseIn );
260   mAnimation.Play();
261 }
262
263 void ScrollBar::Hide()
264 {
265   // Cancel any animation
266   if(mAnimation)
267   {
268     mAnimation.Clear();
269     mAnimation.Reset();
270   }
271
272   mAnimation = Animation::New( INDICATOR_HIDE_TIME );
273   mAnimation.OpacityTo( Self(), 0.0f, AlphaFunctions::EaseIn );
274   mAnimation.Play();
275 }
276
277 void ScrollBar::OnPan( PanGesture gesture )
278 {
279   if(mScrollPositionObject)
280   {
281     switch(gesture.state)
282     {
283       case Gesture::Started:
284       {
285         Show();
286         mScrollStart = mScrollPositionObject.GetProperty<float>( Toolkit::ScrollConnector::SCROLL_POSITION );
287         mGestureDisplacement = Vector3::ZERO;
288         break;
289       }
290       case Gesture::Continuing:
291       {
292         Vector3 delta(gesture.displacement.x, gesture.displacement.y, 0.0f);
293         mGestureDisplacement+=delta;
294
295         Vector3 span = Self().GetCurrentSize() - mIndicator.GetCurrentSize();
296         const float domainSize = fabs(mScrollConnector.GetMaxLimit() - mScrollConnector.GetMinLimit());
297         float position = mScrollStart - mGestureDisplacement.y * domainSize / span.y;
298         position = std::min(mScrollConnector.GetMaxLimit(), std::max(position, mScrollConnector.GetMinLimit()));
299         mScrollPositionObject.SetProperty( Toolkit::ScrollConnector::SCROLL_POSITION, position );
300         break;
301       }
302       default:
303       {
304         break;
305       }
306     }
307   }
308 }
309
310 void ScrollBar::OnScrollDomainChanged(float minPosition, float maxPosition, float contentSize)
311 {
312   // Reapply constraints when the scroll domain is changed
313   ApplyConstraints();
314 }
315
316 Toolkit::ScrollBar ScrollBar::New()
317 {
318   // Create the implementation, temporarily owned by this handle on stack
319   IntrusivePtr< ScrollBar > impl = new ScrollBar();
320
321   // Pass ownership to CustomActor handle
322   Toolkit::ScrollBar handle( *impl );
323
324   // Second-phase init of the implementation
325   // This can only be done after the CustomActor connection has been made...
326   impl->Initialize();
327
328   return handle;
329 }
330
331 } // namespace Internal
332
333 } // namespace Toolkit
334
335 } // namespace Dali