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.
18 #include <dali-toolkit/internal/controls/scroll-component/scroll-bar-internal-impl.h>
19 #include <dali-toolkit/public-api/enums.h>
28 * @param[in] x Input value to be squared
29 * @return Result (x*x)
37 const char* BAR_TAB_IMAGE_PATH = DALI_IMAGE_DIR "popup_scroll.png";
38 const Vector4 BAR_TAB_NINE_PATCH_BORDER(0.0f, 12.0f, 14.0f, 14.0f);
39 const Vector3 BAR_TAB_SIZE(18.0f, 72.0f, 0.0f);
40 const Vector3 BAR_TAB_OFFSET_V(-18.0f, 0.0f, 0.1f);
41 const Vector3 BAR_TAB_OFFSET_H(0.0f, -18.0f, 0.1f);
42 const float BAR_CONTRACT_DELAY(0.8f);
43 const float BAR_SHOW_TIME(0.4f);
44 const float BAR_HIDE_TIME(0.5f);
45 const int SECOND_UNIT(1000);
48 * ScrollBarInternal Visibility Constraint
49 * Returns whether scroll bar is visible
51 bool ScrollBarInternalVisibilityConstraint(const bool& current,
52 const PropertyInput& canScrollProperty)
54 bool canScroll = canScrollProperty.GetBoolean();
59 * ScrollBarInternal Size Constraint
60 * Resize ScrollBarInternal Size depends on both ScrollSize and DomainSize
62 struct ScrollBarInternalSizeConstraint
65 * @param[in] vertical Whether this constraint controls a vertical scrollbar (true)
66 * or a horizontal one (false)
68 ScrollBarInternalSizeConstraint(bool vertical)
75 * @param[in] current The current ScrollBarInternal size
76 * @param[in] scrollMinProperty The container's minimum position.
77 * @param[in] scrollMaxProperty The container's maximum position.
78 * @param[in] scrollDirectionProperty The container's scroll direction.
79 * @param[in] scrollSizeProperty The container's size of viewport.
80 * @return The new ScrollBarInternal position is returned.
82 Vector3 operator()(const Vector3& current,
83 const PropertyInput& scrollMinProperty,
84 const PropertyInput& scrollMaxProperty,
85 const PropertyInput& scrollDirectionProperty,
86 const PropertyInput& scrollSizeProperty)
88 const Vector3& min = scrollMinProperty.GetVector3();
89 const Vector3& max = scrollMaxProperty.GetVector3();
90 const Vector3& scrollDirection = scrollDirectionProperty.GetVector3();
91 const Toolkit::ControlOrientation::Type& orientation = static_cast<Toolkit::ControlOrientation::Type>(scrollDirection.z);
92 const Vector3& size = scrollSizeProperty.GetVector3();
93 const Vector3 domainSize = max - min;
95 if (mVertical && Toolkit::IsVertical(orientation))
97 float mod = fabsf(domainSize.height) > size.height ? size.height * ( size.height / fabsf(domainSize.height) ) : size.height * ( (size.height - fabsf(domainSize.height * 0.5f)) / size.height);
98 return Vector3( current.width, mod, current.depth );
102 float mod = fabsf(domainSize.height) > size.width ? size.width * ( size.width / fabsf(domainSize.height) ) : size.width * ( (size.width - fabsf(domainSize.height * 0.5f)) / size.width);
103 return Vector3( current.width, mod, current.depth );
107 bool mVertical; ///< Whether vertical or horizontal
111 * ScrollBarInternal rotation Constraint
112 * Rotate ScrollBarInternal depends on the scroll direction
114 struct ScrollBarInternalRotationConstraint
117 * @param[in] vertical Whether this constraint controls a vertical scrollbar (true)
118 * or a horizontal one (false)
120 ScrollBarInternalRotationConstraint(bool vertical)
121 : mVertical(vertical)
126 * Constraint operator
127 * @param[in] current The current ScrollBarInternal rotation
128 * @param[in] scrollDirectionProperty The container's scroll direction.
129 * @return The new ScrollBarInternal rotation is returned.
131 Quaternion operator()(const Quaternion& current,
132 const PropertyInput& scrollDirectionProperty)
134 const Vector3& scrollDirection = scrollDirectionProperty.GetVector3();
135 const Toolkit::ControlOrientation::Type& orientation = static_cast<Toolkit::ControlOrientation::Type>(scrollDirection.z);
137 if( (mVertical && Toolkit::IsVertical(orientation)) || (!mVertical && Toolkit::IsHorizontal(orientation)) )
139 return Quaternion(0.0f, Vector3::ZAXIS);
143 return Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
147 bool mVertical; ///< Whether vertical or horizontal
151 * ScrollBarInternal Position Constraint
152 * Positions the scroll bar to reflect the current scroll position
155 struct ScrollBarInternalPositionConstraint
158 * @param[in] vertical Whether this constraint controls a vertical scrollbar (true)
159 * or a horizontal one (false)
160 * @param[in] wrap Whether to base scrollbar on original position or wrapped position
162 ScrollBarInternalPositionConstraint(bool vertical, bool wrap = false)
163 : mVertical(vertical),
169 * Constraint operator
170 * @param[in] current The current ScrollBarInternal position
171 * @param[in] scrollBarSizeProperty ScrollBarInternal size
172 * @param[in] scrollRelativePositionProperty The container's relative position (from 0.0 -> 1.0 in each axis)
173 * @param[in] scrollMinProperty The container's minimum position.
174 * @param[in] scrollMaxProperty The container's maximum position.
175 * @param[in] scrollDirectionProperty The container's scroll direction.
176 * @param[in] scrollSizeProperty The container's size of viewport.
177 * @return The new ScrollBarInternal position is returned.
179 Vector3 operator()(const Vector3& current,
180 const PropertyInput& scrollBarSizeProperty,
181 const PropertyInput& scrollRelativePositionProperty,
182 const PropertyInput& scrollMinProperty,
183 const PropertyInput& scrollMaxProperty,
184 const PropertyInput& scrollDirectionProperty,
185 const PropertyInput& scrollSizeProperty)
187 Vector3 barSize = scrollBarSizeProperty.GetVector3();
188 Vector3 relativePosition = scrollRelativePositionProperty.GetVector3();
189 Vector3 size = scrollSizeProperty.GetVector3();
190 const Vector3& min = scrollMinProperty.GetVector3();
191 const Vector3& max = scrollMaxProperty.GetVector3();
192 const Vector3& scrollDirection = scrollDirectionProperty.GetVector3();
193 const Toolkit::ControlOrientation::Type& orientation = static_cast<Toolkit::ControlOrientation::Type>(scrollDirection.z);
195 Vector3 domainSize = max - min;
196 domainSize.x = fabsf(domainSize.x);
197 domainSize.y = fabsf(domainSize.y);
200 Vector3 mask; // Mask movement aspect of scroll bar
201 Vector3 relativeOffset; // base position of scroll bar in relation to the container
202 Vector3 absoluteOffset; // absolute offset position of scroll bar
208 case Toolkit::ControlOrientation::Up:
210 mask = Vector3::YAXIS;
211 relativeOffset = (scrollDirection.y < 0.0f && relativePosition.y <= 0.0f) ? Vector3(1.0f, 1.0f, 0.0f) : Vector3(1.0f, 0.0f, 0.0f); // Right side of stage.
212 absoluteOffset = (scrollDirection.y < 0.0f && relativePosition.y <= 0.0f) ? BAR_TAB_OFFSET_V + Vector3( barSize.width * 0.5f, -barSize.height * 0.5f, 1.0f ) : BAR_TAB_OFFSET_V + Vector3( barSize.width * 0.5f, barSize.height * 0.5f, 1.0f );
215 case Toolkit::ControlOrientation::Left:
217 mask = Vector3::XAXIS;
218 relativeOffset = (scrollDirection.x <= 0.0f && relativePosition.y <= 0.0f) ? Vector3(1.0f, 0.0f, 0.0f) : Vector3(0.0f, 0.0f, 0.0f); // Bottom side of stage.
219 absoluteOffset = (scrollDirection.x <= 0.0f && relativePosition.y <= 0.0f) ? Vector3( -barSize.height * 0.5f, barSize.width * 0.5f, 1.0f ) : Vector3( barSize.height * 0.5f, barSize.width * 0.5f, 1.0f );
222 case Toolkit::ControlOrientation::Down:
224 mask = Vector3::YAXIS;
225 relativeOffset = (scrollDirection.y <= 0.0f && relativePosition.y <= 0.0f) ? Vector3(0.0f, 1.0f, 0.0f) : Vector3(0.0f, 0.0f, 0.0f); // Left side of stage.
226 absoluteOffset = (scrollDirection.y <= 0.0f && relativePosition.y <= 0.0f) ? Vector3( barSize.width * 0.5f, -barSize.height * 0.5f, 1.0f ) : Vector3( barSize.width * 0.5f, barSize.height * 0.5f, 1.0f );
229 case Toolkit::ControlOrientation::Right:
231 mask = Vector3::XAXIS;
232 relativeOffset = (scrollDirection.x <= 0.0f && relativePosition.y <= 0.0f) ? Vector3(1.0f, 1.0f, 0.0f) : Vector3(0.0f, 1.0f, 0.0f); // Up side of stage.
233 absoluteOffset = (scrollDirection.x <= 0.0f && relativePosition.y <= 0.0f) ? Vector3( -barSize.height * 0.5f, -barSize.width * 0.5f, 1.0f ) : Vector3( barSize.height * 0.5f, -barSize.width * 0.5f, 1.0f );
240 mask = Vector3::XAXIS;
241 relativeOffset = Vector3(0.0f, 1.0f, 0.0f); // Bottom side of stage.
242 absoluteOffset = BAR_TAB_OFFSET_H + Vector3( barSize.height * 0.5f, barSize.width * 0.5f, 1.0f );
245 Vector3 maskedRelativePosition = Toolkit::IsVertical(orientation) ? Vector3(relativePosition.x * (size.x-barSize.y), relativePosition.y * (size.y-barSize.y), 0.0f) * mask
246 : Vector3(relativePosition.y * (size.x-barSize.y), relativePosition.x * (size.y-barSize.y), 0.0f) * mask;
248 Vector3 finalPosition = relativeOffset * size + absoluteOffset + maskedRelativePosition;
250 // If Wrapped Slider, then position 1 domain either before or after current slider.
253 if(finalPosition.x < 0.5f)
255 finalPosition.x += size.x;
259 finalPosition.x -= size.x;
262 if(finalPosition.y < 0.5f)
264 finalPosition.y += size.y;
268 finalPosition.y -= size.y;
272 return finalPosition;
275 bool mVertical; ///< Whether vertical or horizontal.
276 bool mWrap; ///< Whether to wrap this position.
280 * ScrollBarInternal HitSize Constraint
281 * Resizes HitArea to size of the container.
283 struct ScrollBarInternalHitSizeConstraint
286 * @param[in] vertical Whether this constraint controls a vertical scrollbar (true)
287 * or a horizontal one (false)
288 * @param[in] thickness The thickness of the scrollbar
290 ScrollBarInternalHitSizeConstraint(bool vertical,
292 : mVertical(vertical),
293 mThickness(thickness)
298 * Constraint operator
299 * @param[in] current The current HitSize
300 * @param[in] scrollDirectionProperty The container's scroll direction.
301 * @param[in] scrollSizeProperty The container's size of viewport.
302 * @return The new ScrollBarInternal Hit Area size is returned.
304 Vector3 operator()(const Vector3& current,
305 const PropertyInput& scrollDirectionProperty,
306 const PropertyInput& scrollSizeProperty)
308 const Vector3& scrollDirection = scrollDirectionProperty.GetVector3();
309 const Toolkit::ControlOrientation::Type& orientation = static_cast<Toolkit::ControlOrientation::Type>(scrollDirection.z);
310 Vector3 size = scrollSizeProperty.GetVector3();
312 Vector3 mask; // Mask size aspect of hit area.
313 Vector3 offset; // Add Offset size.
315 if( (mVertical && Toolkit::IsVertical(orientation)) || (!mVertical && Toolkit::IsHorizontal(orientation)) )
317 mask = Vector3::YAXIS;
318 offset = Vector3::XAXIS * mThickness;
322 mask = Vector3::XAXIS;
323 offset = Vector3::YAXIS * mThickness;
326 return size * mask + offset;
329 bool mVertical; ///< Whether vertical or horizontal.
330 float mThickness; ///< Thickness of the scroll bar
333 } // unnamed namespace
347 using namespace Dali;
354 TypeRegistration mType( typeid(Toolkit::ScrollBarInternal), typeid(Toolkit::ScrollComponent), Create );
358 ScrollBarInternal::ScrollBarInternal(Toolkit::Scrollable& container, bool vertical)
359 : mContainer(static_cast<Toolkit::Internal::Scrollable&>(container.GetImplementation())),
361 mAxisMask(vertical ? Vector3::YAXIS : Vector3::XAXIS),
364 Image sliderImage = Image::New( BAR_TAB_IMAGE_PATH );
366 mSlider = ImageActor::New( sliderImage );
367 mSlider.SetParentOrigin( ParentOrigin::TOP_LEFT );
368 mSlider.SetAnchorPoint( AnchorPoint::CENTER );
369 mSlider.SetSize( BAR_TAB_SIZE );
370 mSlider.SetStyle( ImageActor::STYLE_NINE_PATCH );
371 mSlider.SetNinePatchBorder( BAR_TAB_NINE_PATCH_BORDER );
373 // A duplicate Slider should appear 1 domain away from the original Slider
374 mSliderWrap = ImageActor::New( sliderImage );
375 mSliderWrap.SetParentOrigin( ParentOrigin::TOP_LEFT );
376 mSliderWrap.SetAnchorPoint( AnchorPoint::CENTER );
377 mSliderWrap.SetSize( BAR_TAB_SIZE );
378 mSliderWrap.SetStyle( ImageActor::STYLE_NINE_PATCH );
379 mSliderWrap.SetNinePatchBorder( BAR_TAB_NINE_PATCH_BORDER );
381 // target the container to observe for scrolling
382 Actor target = mContainer.Self();
383 Constraint constraint = Constraint::New<bool>( Actor::VISIBLE,
384 Source( target, vertical ? target.GetPropertyIndex(Scrollable::SCROLLABLE_CAN_SCROLL_VERTICAL) : target.GetPropertyIndex(Scrollable::SCROLLABLE_CAN_SCROLL_HORIZONTAL)),
385 ScrollBarInternalVisibilityConstraint );
386 mSlider.ApplyConstraint( constraint );
387 mSliderWrap.ApplyConstraint( constraint );
389 constraint = Constraint::New<Vector3>( Actor::SIZE,
390 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
391 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
392 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
393 Source( target, Actor::SIZE ),
394 ScrollBarInternalSizeConstraint( vertical ) );
395 mSlider.ApplyConstraint( constraint );
396 mSliderWrap.ApplyConstraint( constraint );
398 constraint = Constraint::New<Quaternion>( Actor::ROTATION,
399 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
400 ScrollBarInternalRotationConstraint( vertical ) );
401 mSlider.ApplyConstraint( constraint );
402 mSliderWrap.ApplyConstraint( constraint );
404 constraint = Constraint::New<Vector3>( Actor::POSITION,
405 Source( mSlider, Actor::SIZE),
406 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_RELATIVE_POSITION_PROPERTY_NAME ) ),
407 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
408 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
409 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
410 Source( target, Actor::SIZE ),
411 ScrollBarInternalPositionConstraint(vertical) );
413 mSlider.ApplyConstraint( constraint );
415 constraint = Constraint::New<Vector3>( Actor::POSITION,
416 Source( mSlider, Actor::SIZE),
417 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_RELATIVE_POSITION_PROPERTY_NAME ) ),
418 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
419 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
420 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
421 Source( target, Actor::SIZE ),
422 ScrollBarInternalPositionConstraint(vertical, true) );
423 mSliderWrap.ApplyConstraint( constraint );
425 // Add Sliders to internal Actor, to avoid mixing up with regular
426 // Actors added by user.
427 mContainer.AddOverlay( mSlider );
428 mContainer.AddOverlay( mSliderWrap );
429 mContainer.ScrollStartedSignal().Connect( this, &ScrollBarInternal::OnStarted );
430 mContainer.ScrollCompletedSignal().Connect( this, &ScrollBarInternal::OnCompleted );
432 // Hit Area for dragging slider /////////////////////////////////////////////
433 mHitArea = Actor::New();
434 mHitArea.SetPosition(0.0f, 0.0f, 0.2f);
436 mContainer.AddOverlay( mHitArea );
437 constraint = Constraint::New<Vector3>( Actor::SIZE,
438 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
439 Source( target, Actor::SIZE ),
440 ScrollBarInternalHitSizeConstraint(vertical, BAR_TAB_SIZE.width) );
441 mHitArea.ApplyConstraint( constraint );
445 mHitArea.SetParentOrigin(ParentOrigin::CENTER_RIGHT);
446 mHitArea.SetAnchorPoint(AnchorPoint::CENTER_RIGHT);
450 mHitArea.SetParentOrigin(ParentOrigin::BOTTOM_CENTER);
451 mHitArea.SetAnchorPoint(AnchorPoint::BOTTOM_CENTER);
454 WaitingContractDelay();
457 ScrollBarInternal::~ScrollBarInternal()
462 void ScrollBarInternal::OnInitialize()
464 EnableGestureDetection(Gesture::Type(Gesture::Pan));
467 void ScrollBarInternal::OnDisconnect()
469 // Disconnect all connected callback functions.
470 mContainer.RemoveOverlay( mSlider );
471 mContainer.RemoveOverlay( mSliderWrap );
474 void ScrollBarInternal::OnPanGesture(Actor actor, PanGesture gesture)
476 switch(gesture.state)
478 case Gesture::Started:
482 mScrollStart = mContainer.GetCurrentScrollPosition();
483 mGestureDisplacement = Vector3::ZERO;
486 case Gesture::Continuing:
488 Vector3 delta(gesture.displacement.x, gesture.displacement.y, 0.0f);
489 mGestureDisplacement+=delta;
491 Vector3 size = mContainer.Self().GetCurrentSize();
492 Vector3 span = size - Vector3(BAR_TAB_SIZE.y, BAR_TAB_SIZE.y, 1.0f);
493 Vector3 domainSize = mContainer.GetDomainSize();
495 Vector3 position = mScrollStart + mGestureDisplacement * mAxisMask * domainSize / span;
496 mContainer.ScrollTo(position, 0.0f);
507 void ScrollBarInternal::OnStarted(const Vector3& position)
509 // TODO: Need to disable this for the scrollbar which isn't being scrolled.
517 void ScrollBarInternal::OnCompleted(const Vector3& position)
523 WaitingContractDelay();
527 bool ScrollBarInternal::OnContractDelayExpired()
539 void ScrollBarInternal::Show()
541 // Cancel any animation
548 mAnimation = Animation::New( BAR_SHOW_TIME );
549 mAnimation.OpacityTo( mSlider, 1.0f, AlphaFunctions::EaseIn );
550 mAnimation.OpacityTo( mSliderWrap, 1.0f, AlphaFunctions::EaseIn );
556 void ScrollBarInternal::Hide()
558 // Cancel any animation
565 mAnimation = Animation::New( BAR_HIDE_TIME );
566 mAnimation.OpacityTo( mSlider, 0.0f, AlphaFunctions::EaseIn );
567 mAnimation.OpacityTo( mSliderWrap, 0.0f, AlphaFunctions::EaseIn );
571 void ScrollBarInternal::CreateTimer()
575 // Create timer for contract delay
576 mTimer = Timer::New( BAR_CONTRACT_DELAY * SECOND_UNIT );
577 mTimer.TickSignal().Connect( this, &ScrollBarInternal::OnContractDelayExpired );
581 void ScrollBarInternal::DestructTimer()
586 mTimer.TickSignal().Disconnect( this, &ScrollBarInternal::OnContractDelayExpired );
591 void ScrollBarInternal::WaitingContractDelay()
597 Toolkit::ScrollBarInternal ScrollBarInternal::New(Toolkit::Scrollable& container, bool vertical)
599 // Create the implementation, temporarily owned by this handle on stack
600 IntrusivePtr< ScrollBarInternal > impl = new ScrollBarInternal( container, vertical );
602 // Pass ownership to CustomActor handle
603 Toolkit::ScrollBarInternal handle( *impl );
605 // Second-phase init of the implementation
606 // This can only be done after the CustomActor connection has been made...
612 } // namespace Internal
614 } // namespace Toolkit