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-component/scroll-bar-internal-impl.h>
22 #include <dali/public-api/object/type-registry.h>
25 #include <dali-toolkit/public-api/enums.h>
34 * @param[in] x Input value to be squared
35 * @return Result (x*x)
43 const char* BAR_TAB_IMAGE_PATH = DALI_IMAGE_DIR "popup_scroll.png";
44 const Vector4 BAR_TAB_NINE_PATCH_BORDER(0.0f, 12.0f, 14.0f, 14.0f);
45 const Vector3 BAR_TAB_SIZE(18.0f, 72.0f, 0.0f);
46 const Vector3 BAR_TAB_OFFSET_V(-18.0f, 0.0f, 0.1f);
47 const Vector3 BAR_TAB_OFFSET_H(0.0f, -18.0f, 0.1f);
48 const float BAR_CONTRACT_DELAY(0.8f);
49 const float BAR_SHOW_TIME(0.4f);
50 const float BAR_HIDE_TIME(0.5f);
51 const int SECOND_UNIT(1000);
54 * ScrollBarInternal Visibility Constraint
55 * Returns whether scroll bar is visible
57 bool ScrollBarInternalVisibilityConstraint(const bool& current,
58 const PropertyInput& canScrollProperty)
60 bool canScroll = canScrollProperty.GetBoolean();
65 * ScrollBarInternal Size Constraint
66 * Resize ScrollBarInternal Size depends on both ScrollSize and DomainSize
68 struct ScrollBarInternalSizeConstraint
71 * @param[in] vertical Whether this constraint controls a vertical scrollbar (true)
72 * or a horizontal one (false)
74 ScrollBarInternalSizeConstraint(bool vertical)
81 * @param[in] current The current ScrollBarInternal size
82 * @param[in] scrollMinProperty The container's minimum position.
83 * @param[in] scrollMaxProperty The container's maximum position.
84 * @param[in] scrollDirectionProperty The container's scroll direction.
85 * @param[in] scrollSizeProperty The container's size of viewport.
86 * @return The new ScrollBarInternal position is returned.
88 Vector3 operator()(const Vector3& current,
89 const PropertyInput& scrollMinProperty,
90 const PropertyInput& scrollMaxProperty,
91 const PropertyInput& scrollDirectionProperty,
92 const PropertyInput& scrollSizeProperty)
94 const Vector3& min = scrollMinProperty.GetVector3();
95 const Vector3& max = scrollMaxProperty.GetVector3();
96 const Vector3& scrollDirection = scrollDirectionProperty.GetVector3();
97 const Toolkit::ControlOrientation::Type& orientation = static_cast<Toolkit::ControlOrientation::Type>(scrollDirection.z);
98 const Vector3& size = scrollSizeProperty.GetVector3();
99 const Vector3 domainSize = max - min;
101 if (mVertical && Toolkit::IsVertical(orientation))
103 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);
104 return Vector3( current.width, mod, current.depth );
108 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);
109 return Vector3( current.width, mod, current.depth );
113 bool mVertical; ///< Whether vertical or horizontal
117 * ScrollBarInternal rotation Constraint
118 * Rotate ScrollBarInternal depends on the scroll direction
120 struct ScrollBarInternalRotationConstraint
123 * @param[in] vertical Whether this constraint controls a vertical scrollbar (true)
124 * or a horizontal one (false)
126 ScrollBarInternalRotationConstraint(bool vertical)
127 : mVertical(vertical)
132 * Constraint operator
133 * @param[in] current The current ScrollBarInternal rotation
134 * @param[in] scrollDirectionProperty The container's scroll direction.
135 * @return The new ScrollBarInternal rotation is returned.
137 Quaternion operator()(const Quaternion& current,
138 const PropertyInput& scrollDirectionProperty)
140 const Vector3& scrollDirection = scrollDirectionProperty.GetVector3();
141 const Toolkit::ControlOrientation::Type& orientation = static_cast<Toolkit::ControlOrientation::Type>(scrollDirection.z);
143 if( (mVertical && Toolkit::IsVertical(orientation)) || (!mVertical && Toolkit::IsHorizontal(orientation)) )
145 return Quaternion(0.0f, Vector3::ZAXIS);
149 return Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
153 bool mVertical; ///< Whether vertical or horizontal
157 * ScrollBarInternal Position Constraint
158 * Positions the scroll bar to reflect the current scroll position
161 struct ScrollBarInternalPositionConstraint
164 * @param[in] vertical Whether this constraint controls a vertical scrollbar (true)
165 * or a horizontal one (false)
166 * @param[in] wrap Whether to base scrollbar on original position or wrapped position
168 ScrollBarInternalPositionConstraint(bool vertical, bool wrap = false)
169 : mVertical(vertical),
175 * Constraint operator
176 * @param[in] current The current ScrollBarInternal position
177 * @param[in] scrollBarSizeProperty ScrollBarInternal size
178 * @param[in] scrollRelativePositionProperty The container's relative position (from 0.0 -> 1.0 in each axis)
179 * @param[in] scrollMinProperty The container's minimum position.
180 * @param[in] scrollMaxProperty The container's maximum position.
181 * @param[in] scrollDirectionProperty The container's scroll direction.
182 * @param[in] scrollSizeProperty The container's size of viewport.
183 * @return The new ScrollBarInternal position is returned.
185 Vector3 operator()(const Vector3& current,
186 const PropertyInput& scrollBarSizeProperty,
187 const PropertyInput& scrollRelativePositionProperty,
188 const PropertyInput& scrollMinProperty,
189 const PropertyInput& scrollMaxProperty,
190 const PropertyInput& scrollDirectionProperty,
191 const PropertyInput& scrollSizeProperty)
193 Vector3 barSize = scrollBarSizeProperty.GetVector3();
194 Vector3 relativePosition = scrollRelativePositionProperty.GetVector3();
195 Vector3 size = scrollSizeProperty.GetVector3();
196 const Vector3& min = scrollMinProperty.GetVector3();
197 const Vector3& max = scrollMaxProperty.GetVector3();
198 const Vector3& scrollDirection = scrollDirectionProperty.GetVector3();
199 const Toolkit::ControlOrientation::Type& orientation = static_cast<Toolkit::ControlOrientation::Type>(scrollDirection.z);
201 Vector3 domainSize = max - min;
202 domainSize.x = fabsf(domainSize.x);
203 domainSize.y = fabsf(domainSize.y);
206 Vector3 mask; // Mask movement aspect of scroll bar
207 Vector3 relativeOffset; // base position of scroll bar in relation to the container
208 Vector3 absoluteOffset; // absolute offset position of scroll bar
214 case Toolkit::ControlOrientation::Up:
216 mask = Vector3::YAXIS;
217 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.
218 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 );
221 case Toolkit::ControlOrientation::Left:
223 mask = Vector3::XAXIS;
224 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.
225 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 );
228 case Toolkit::ControlOrientation::Down:
230 mask = Vector3::YAXIS;
231 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.
232 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 );
235 case Toolkit::ControlOrientation::Right:
237 mask = Vector3::XAXIS;
238 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.
239 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 );
246 mask = Vector3::XAXIS;
247 relativeOffset = Vector3(0.0f, 1.0f, 0.0f); // Bottom side of stage.
248 absoluteOffset = BAR_TAB_OFFSET_H + Vector3( barSize.height * 0.5f, barSize.width * 0.5f, 1.0f );
251 Vector3 maskedRelativePosition = Toolkit::IsVertical(orientation) ? Vector3(relativePosition.x * (size.x-barSize.y), relativePosition.y * (size.y-barSize.y), 0.0f) * mask
252 : Vector3(relativePosition.y * (size.x-barSize.y), relativePosition.x * (size.y-barSize.y), 0.0f) * mask;
254 Vector3 finalPosition = relativeOffset * size + absoluteOffset + maskedRelativePosition;
256 // If Wrapped Slider, then position 1 domain either before or after current slider.
259 if(finalPosition.x < 0.5f)
261 finalPosition.x += size.x;
265 finalPosition.x -= size.x;
268 if(finalPosition.y < 0.5f)
270 finalPosition.y += size.y;
274 finalPosition.y -= size.y;
278 return finalPosition;
281 bool mVertical; ///< Whether vertical or horizontal.
282 bool mWrap; ///< Whether to wrap this position.
286 * ScrollBarInternal HitSize Constraint
287 * Resizes HitArea to size of the container.
289 struct ScrollBarInternalHitSizeConstraint
292 * @param[in] vertical Whether this constraint controls a vertical scrollbar (true)
293 * or a horizontal one (false)
294 * @param[in] thickness The thickness of the scrollbar
296 ScrollBarInternalHitSizeConstraint(bool vertical,
298 : mVertical(vertical),
299 mThickness(thickness)
304 * Constraint operator
305 * @param[in] current The current HitSize
306 * @param[in] scrollDirectionProperty The container's scroll direction.
307 * @param[in] scrollSizeProperty The container's size of viewport.
308 * @return The new ScrollBarInternal Hit Area size is returned.
310 Vector3 operator()(const Vector3& current,
311 const PropertyInput& scrollDirectionProperty,
312 const PropertyInput& scrollSizeProperty)
314 const Vector3& scrollDirection = scrollDirectionProperty.GetVector3();
315 const Toolkit::ControlOrientation::Type& orientation = static_cast<Toolkit::ControlOrientation::Type>(scrollDirection.z);
316 Vector3 size = scrollSizeProperty.GetVector3();
318 Vector3 mask; // Mask size aspect of hit area.
319 Vector3 offset; // Add Offset size.
321 if( (mVertical && Toolkit::IsVertical(orientation)) || (!mVertical && Toolkit::IsHorizontal(orientation)) )
323 mask = Vector3::YAXIS;
324 offset = Vector3::XAXIS * mThickness;
328 mask = Vector3::XAXIS;
329 offset = Vector3::YAXIS * mThickness;
332 return size * mask + offset;
335 bool mVertical; ///< Whether vertical or horizontal.
336 float mThickness; ///< Thickness of the scroll bar
339 } // unnamed namespace
353 using namespace Dali;
360 TypeRegistration mType( typeid(Toolkit::ScrollBarInternal), typeid(Toolkit::ScrollComponent), Create );
364 ScrollBarInternal::ScrollBarInternal(Toolkit::Scrollable& container, bool vertical)
365 : mContainer(static_cast<Toolkit::Internal::Scrollable&>(container.GetImplementation())),
367 mAxisMask(vertical ? Vector3::YAXIS : Vector3::XAXIS),
370 Image sliderImage = Image::New( BAR_TAB_IMAGE_PATH );
372 mSlider = ImageActor::New( sliderImage );
373 mSlider.SetParentOrigin( ParentOrigin::TOP_LEFT );
374 mSlider.SetAnchorPoint( AnchorPoint::CENTER );
375 mSlider.SetSize( BAR_TAB_SIZE );
376 mSlider.SetStyle( ImageActor::STYLE_NINE_PATCH );
377 mSlider.SetNinePatchBorder( BAR_TAB_NINE_PATCH_BORDER );
379 // A duplicate Slider should appear 1 domain away from the original Slider
380 mSliderWrap = ImageActor::New( sliderImage );
381 mSliderWrap.SetParentOrigin( ParentOrigin::TOP_LEFT );
382 mSliderWrap.SetAnchorPoint( AnchorPoint::CENTER );
383 mSliderWrap.SetSize( BAR_TAB_SIZE );
384 mSliderWrap.SetStyle( ImageActor::STYLE_NINE_PATCH );
385 mSliderWrap.SetNinePatchBorder( BAR_TAB_NINE_PATCH_BORDER );
387 // target the container to observe for scrolling
388 Actor target = mContainer.Self();
389 Constraint constraint = Constraint::New<bool>( Actor::VISIBLE,
390 Source( target, vertical ? target.GetPropertyIndex(Scrollable::SCROLLABLE_CAN_SCROLL_VERTICAL) : target.GetPropertyIndex(Scrollable::SCROLLABLE_CAN_SCROLL_HORIZONTAL)),
391 ScrollBarInternalVisibilityConstraint );
392 mSlider.ApplyConstraint( constraint );
393 mSliderWrap.ApplyConstraint( constraint );
395 constraint = Constraint::New<Vector3>( Actor::SIZE,
396 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
397 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
398 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
399 Source( target, Actor::SIZE ),
400 ScrollBarInternalSizeConstraint( vertical ) );
401 mSlider.ApplyConstraint( constraint );
402 mSliderWrap.ApplyConstraint( constraint );
404 constraint = Constraint::New<Quaternion>( Actor::ROTATION,
405 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
406 ScrollBarInternalRotationConstraint( vertical ) );
407 mSlider.ApplyConstraint( constraint );
408 mSliderWrap.ApplyConstraint( constraint );
410 constraint = Constraint::New<Vector3>( Actor::POSITION,
411 Source( mSlider, Actor::SIZE),
412 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_RELATIVE_POSITION_PROPERTY_NAME ) ),
413 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
414 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
415 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
416 Source( target, Actor::SIZE ),
417 ScrollBarInternalPositionConstraint(vertical) );
419 mSlider.ApplyConstraint( constraint );
421 constraint = Constraint::New<Vector3>( Actor::POSITION,
422 Source( mSlider, Actor::SIZE),
423 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_RELATIVE_POSITION_PROPERTY_NAME ) ),
424 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
425 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
426 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
427 Source( target, Actor::SIZE ),
428 ScrollBarInternalPositionConstraint(vertical, true) );
429 mSliderWrap.ApplyConstraint( constraint );
431 // Add Sliders to internal Actor, to avoid mixing up with regular
432 // Actors added by user.
433 mContainer.AddOverlay( mSlider );
434 mContainer.AddOverlay( mSliderWrap );
435 mContainer.ScrollStartedSignal().Connect( this, &ScrollBarInternal::OnStarted );
436 mContainer.ScrollCompletedSignal().Connect( this, &ScrollBarInternal::OnCompleted );
438 // Hit Area for dragging slider /////////////////////////////////////////////
439 mHitArea = Actor::New();
440 mHitArea.SetPosition(0.0f, 0.0f, 0.2f);
442 mContainer.AddOverlay( mHitArea );
443 constraint = Constraint::New<Vector3>( Actor::SIZE,
444 Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
445 Source( target, Actor::SIZE ),
446 ScrollBarInternalHitSizeConstraint(vertical, BAR_TAB_SIZE.width) );
447 mHitArea.ApplyConstraint( constraint );
451 mHitArea.SetParentOrigin(ParentOrigin::CENTER_RIGHT);
452 mHitArea.SetAnchorPoint(AnchorPoint::CENTER_RIGHT);
456 mHitArea.SetParentOrigin(ParentOrigin::BOTTOM_CENTER);
457 mHitArea.SetAnchorPoint(AnchorPoint::BOTTOM_CENTER);
460 WaitingContractDelay();
463 ScrollBarInternal::~ScrollBarInternal()
468 void ScrollBarInternal::OnInitialize()
470 EnableGestureDetection(Gesture::Type(Gesture::Pan));
473 void ScrollBarInternal::OnDisconnect()
475 // Disconnect all connected callback functions.
476 mContainer.RemoveOverlay( mSlider );
477 mContainer.RemoveOverlay( mSliderWrap );
480 void ScrollBarInternal::OnPanGesture(Actor actor, PanGesture gesture)
482 switch(gesture.state)
484 case Gesture::Started:
488 mScrollStart = mContainer.GetCurrentScrollPosition();
489 mGestureDisplacement = Vector3::ZERO;
492 case Gesture::Continuing:
494 Vector3 delta(gesture.displacement.x, gesture.displacement.y, 0.0f);
495 mGestureDisplacement+=delta;
497 Vector3 size = mContainer.Self().GetCurrentSize();
498 Vector3 span = size - Vector3(BAR_TAB_SIZE.y, BAR_TAB_SIZE.y, 1.0f);
499 Vector3 domainSize = mContainer.GetDomainSize();
501 Vector3 position = mScrollStart + mGestureDisplacement * mAxisMask * domainSize / span;
502 mContainer.ScrollTo(position, 0.0f);
513 void ScrollBarInternal::OnStarted(const Vector3& position)
515 // TODO: Need to disable this for the scrollbar which isn't being scrolled.
523 void ScrollBarInternal::OnCompleted(const Vector3& position)
529 WaitingContractDelay();
533 bool ScrollBarInternal::OnContractDelayExpired()
545 void ScrollBarInternal::Show()
547 // Cancel any animation
554 mAnimation = Animation::New( BAR_SHOW_TIME );
555 mAnimation.OpacityTo( mSlider, 1.0f, AlphaFunctions::EaseIn );
556 mAnimation.OpacityTo( mSliderWrap, 1.0f, AlphaFunctions::EaseIn );
562 void ScrollBarInternal::Hide()
564 // Cancel any animation
571 mAnimation = Animation::New( BAR_HIDE_TIME );
572 mAnimation.OpacityTo( mSlider, 0.0f, AlphaFunctions::EaseIn );
573 mAnimation.OpacityTo( mSliderWrap, 0.0f, AlphaFunctions::EaseIn );
577 void ScrollBarInternal::CreateTimer()
581 // Create timer for contract delay
582 mTimer = Timer::New( BAR_CONTRACT_DELAY * SECOND_UNIT );
583 mTimer.TickSignal().Connect( this, &ScrollBarInternal::OnContractDelayExpired );
587 void ScrollBarInternal::DestructTimer()
592 mTimer.TickSignal().Disconnect( this, &ScrollBarInternal::OnContractDelayExpired );
597 void ScrollBarInternal::WaitingContractDelay()
603 Toolkit::ScrollBarInternal ScrollBarInternal::New(Toolkit::Scrollable& container, bool vertical)
605 // Create the implementation, temporarily owned by this handle on stack
606 IntrusivePtr< ScrollBarInternal > impl = new ScrollBarInternal( container, vertical );
608 // Pass ownership to CustomActor handle
609 Toolkit::ScrollBarInternal handle( *impl );
611 // Second-phase init of the implementation
612 // This can only be done after the CustomActor connection has been made...
618 } // namespace Internal
620 } // namespace Toolkit