2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 // http://floralicense.org/license/
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/public-api/controls/scrollable/item-view/roll-layout.h>
22 using namespace Dali::Toolkit;
25 namespace // unnamed namespace
28 const float DEFAULT_ROW_SPACING = 20.0f;
29 const float DEFAULT_SCROLL_SPEED_FACTOR = 0.0015f;
30 const float DEFAULT_MAXIMUM_SWIPE_SPEED = 8.0f;
31 const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.4f;
33 // 4 orientations are supported
34 static const unsigned int ORIENTATION_COUNT = 4;
36 static Vector3 GetItemSizeDefaultFunction(float layoutWidth, float layoutHeight, float rowSpacing)
38 float height = (layoutHeight - rowSpacing) * 0.5f;
39 return Vector3(layoutWidth, height, height);
42 struct RollPositionConstraint0
44 RollPositionConstraint0(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
45 : mRowSpacing(rowSpacing),
46 mItemSizeFunction(itemSizeFunction)
50 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
52 Vector3 itemSize = mItemSizeFunction(layoutSize.width, layoutSize.height, mRowSpacing);
54 float adjustedLayoutPosition = layoutPosition;
55 float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed * scrollSpeed;
58 float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
60 if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
62 float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
63 adjustedLayoutPosition = adjustment * 2.0f;
64 y = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.height * 0.5f + itemSize.y * 0.5f;
68 float yStep = max(50.0f, min(itemSize.y, scrollSpeedFactor));
69 y = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * yStep : (layoutSize.height * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * yStep;
70 y += itemSize.y * 0.5f - layoutSize.height * 0.5f;
73 float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
74 z -= min(3000.0f, scrollSpeedFactor * 2.0f);
76 return Vector3(itemSize.x * 0.5f - layoutSize.x * 0.5f, y, z);
82 RollLayout::ItemSizeFunction mItemSizeFunction;
85 struct RollPositionConstraint90
87 RollPositionConstraint90(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
88 : mRowSpacing(rowSpacing),
89 mItemSizeFunction(itemSizeFunction)
93 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
95 Vector3 itemSize = mItemSizeFunction(layoutSize.height, layoutSize.width, mRowSpacing);
97 float adjustedLayoutPosition = layoutPosition;
98 float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed;
101 float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
103 if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
105 float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
106 adjustedLayoutPosition = adjustment * 2.0f;
107 x = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.width * 0.5f + itemSize.y * 0.5f;
111 float xStep = max(50.0f, min(itemSize.y, scrollSpeedFactor));
112 x = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * xStep : (layoutSize.width * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * xStep;
113 x += itemSize.y * 0.5f - layoutSize.width * 0.5f;
116 float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
117 z -= min(3000.0f, scrollSpeedFactor * 2.0f);
119 return Vector3(x, itemSize.x * 0.5f - layoutSize.y * 0.5f, z);
125 RollLayout::ItemSizeFunction mItemSizeFunction;
128 struct RollPositionConstraint180
130 RollPositionConstraint180(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
131 : mRowSpacing(rowSpacing),
132 mItemSizeFunction(itemSizeFunction)
136 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
138 Vector3 itemSize = mItemSizeFunction(layoutSize.width, layoutSize.height, mRowSpacing);
140 float adjustedLayoutPosition = layoutPosition;
141 float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed;
144 float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
146 if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
148 float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
149 adjustedLayoutPosition = adjustment * 2.0f;
150 y = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.height * 0.5f + itemSize.y * 0.5f;
154 float yStep = max(50.0f, min(itemSize.y, scrollSpeedFactor));
155 y = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * yStep : (layoutSize.height * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * yStep;
156 y += itemSize.y * 0.5f - layoutSize.height * 0.5f;
159 float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
160 z -= min(3000.0f, scrollSpeedFactor * 2.0f);
163 return Vector3(-(itemSize.x * 0.5f - layoutSize.x * 0.5f),
171 RollLayout::ItemSizeFunction mItemSizeFunction;
174 struct RollPositionConstraint270
176 RollPositionConstraint270(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
177 : mRowSpacing(rowSpacing),
178 mItemSizeFunction(itemSizeFunction)
182 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
184 Vector3 itemSize = mItemSizeFunction(layoutSize.height, layoutSize.width, mRowSpacing);
186 float adjustedLayoutPosition = layoutPosition;
187 float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed;
190 float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
192 if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
194 float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
195 adjustedLayoutPosition = adjustment * 2.0f;
196 x = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.width * 0.5f + itemSize.y * 0.5f;
200 float xStep = max(50.0f, min(itemSize.y, scrollSpeedFactor));
201 x = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * xStep : (layoutSize.width * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * xStep;
202 x += itemSize.y * 0.5f - layoutSize.width * 0.5f;
205 float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
206 z -= min(3000.0f, scrollSpeedFactor * 2.0f);
209 itemSize.x * 0.5f - layoutSize.y * 0.5f,
216 RollLayout::ItemSizeFunction mItemSizeFunction;
219 struct RollRotationConstraint0
221 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
223 return Quaternion(0.0f, Vector3::ZAXIS);
227 struct RollRotationConstraint90
229 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
231 return Quaternion(1.5f * Math::PI, Vector3::ZAXIS);
235 struct RollRotationConstraint180
237 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
239 return Quaternion(Math::PI, Vector3::ZAXIS);
243 struct RollRotationConstraint270
245 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
247 return Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
251 struct RollScaleConstraint
253 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
255 float adjustedLayoutPosition = layoutPosition;
257 if(adjustedLayoutPosition < Math::MACHINE_EPSILON_0)
259 factor = fabsf(adjustedLayoutPosition);
261 if(adjustedLayoutPosition - 1.0f > Math::MACHINE_EPSILON_0)
263 factor = adjustedLayoutPosition - 1.0f;
266 float scale = min(1.0f, max(0.1f, 1.0f - 0.1f * factor));
267 if(scrollSpeed > 0.0f)
269 scale *= min(1.0f, max(0.1f, 1.0f / (scrollSpeed * 0.05f)));
272 return Vector3(scale, scale, scale);
276 struct RollColorConstraint
278 Vector4 operator()(const Vector4& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
280 float adjustedLayoutPosition = layoutPosition;
283 if(adjustedLayoutPosition < Math::MACHINE_EPSILON_0)
285 factor = fabsf(adjustedLayoutPosition);
287 if(adjustedLayoutPosition - 1.0f > Math::MACHINE_EPSILON_0)
289 factor = adjustedLayoutPosition - 1.0f;
292 float darkness = min(1.0f, max(0.5f, 1.0f - 0.5f * factor));
293 float alpha = min(1.0f, max(0.0f, 1.0f - 0.9f * factor));
294 return Vector4(darkness, darkness, darkness, alpha);
298 struct RollVisibilityConstraintPortrait
300 RollVisibilityConstraintPortrait(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
301 : mRowSpacing(rowSpacing),
302 mItemSizeFunction(itemSizeFunction)
306 bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
308 Vector3 itemSize = mItemSizeFunction(layoutSize.width, layoutSize.height, mRowSpacing);
309 int rowsPerPage = ceil(layoutSize.height / (itemSize.y + mRowSpacing));
310 return (layoutPosition > -rowsPerPage) && (layoutPosition < rowsPerPage);
316 RollLayout::ItemSizeFunction mItemSizeFunction;
319 struct RollVisibilityConstraintLandscape
321 RollVisibilityConstraintLandscape(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
322 : mRowSpacing(rowSpacing),
323 mItemSizeFunction(itemSizeFunction)
327 bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
329 Vector3 itemSize = mItemSizeFunction(layoutSize.height, layoutSize.width, mRowSpacing);
330 int rowsPerPage = ceil(layoutSize.width / (itemSize.y + mRowSpacing));
331 return (layoutPosition + 2.0f > Math::MACHINE_EPSILON_0) && (layoutPosition < rowsPerPage);
337 RollLayout::ItemSizeFunction mItemSizeFunction;
340 } // unnamed namespace
348 struct RollLayout::Impl
351 : mRowSpacing(DEFAULT_ROW_SPACING),
352 mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
353 mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
354 mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION),
355 mItemSizeFunction(GetItemSizeDefaultFunction)
357 mScaleConstraint = RollScaleConstraint();
358 mColorConstraint = RollColorConstraint();
360 mRotationConstraint[0] = RollRotationConstraint0();
361 mRotationConstraint[1] = RollRotationConstraint90();
362 mRotationConstraint[2] = RollRotationConstraint180();
363 mRotationConstraint[3] = RollRotationConstraint270();
368 float mScrollSpeedFactor;
369 float mMaximumSwipeSpeed;
370 float mItemFlickAnimationDuration;
372 ItemLayout::QuaternionFunction mRotationConstraint[ORIENTATION_COUNT];
373 ItemLayout::Vector3Function mScaleConstraint;
374 ItemLayout::Vector4Function mColorConstraint;
376 ItemSizeFunction mItemSizeFunction;
379 RollLayoutPtr RollLayout::New()
381 return RollLayoutPtr(new RollLayout());
384 RollLayout::~RollLayout()
389 void RollLayout::SetRowSpacing(float spacing)
391 mImpl->mRowSpacing = spacing;
394 float RollLayout::GetRowSpacing() const
396 return mImpl->mRowSpacing;
399 void RollLayout::SetItemSizeFunction(ItemSizeFunction function)
401 mImpl->mItemSizeFunction = function;
404 RollLayout::ItemSizeFunction RollLayout::GetItemSizeFunction() const
406 return mImpl->mItemSizeFunction;
409 void RollLayout::SetScrollSpeedFactor(float scrollSpeed)
411 mImpl->mScrollSpeedFactor = scrollSpeed;
414 void RollLayout::SetMaximumSwipeSpeed(float speed)
416 mImpl->mMaximumSwipeSpeed = speed;
419 void RollLayout::SetItemFlickAnimationDuration(float durationSeconds)
421 mImpl->mItemFlickAnimationDuration = durationSeconds;
424 float RollLayout::GetScrollSpeedFactor() const
426 return mImpl->mScrollSpeedFactor;
429 float RollLayout::GetMaximumSwipeSpeed() const
431 return mImpl->mMaximumSwipeSpeed;
434 float RollLayout::GetItemFlickAnimationDuration() const
436 return mImpl->mItemFlickAnimationDuration;
439 float RollLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
441 return 2.0f - static_cast<float>(numberOfItems);
444 float RollLayout::GetClosestAnchorPosition(float layoutPosition) const
446 return static_cast<float>(round(layoutPosition));
449 float RollLayout::GetItemScrollToPosition(unsigned int itemId) const
451 return 0.0f - static_cast<float>(itemId);
454 ItemRange RollLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
456 float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
457 float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
459 Vector3 itemSize = mImpl->mItemSizeFunction( layoutWidth,layoutHeight, mImpl->mRowSpacing);
461 float itemsPerPage = (layoutHeight / (itemSize.y + mImpl->mRowSpacing));
462 if(firstItemPosition + 0.001f >= Math::MACHINE_EPSILON_0)
464 itemsPerPage = std::max(0.0f, itemsPerPage - 1.0f);
466 int firstVisibleItem = -(static_cast<int>(firstItemPosition));
468 int firstItemIndex = std::max(0, firstVisibleItem);
469 int lastItemIndex = std::max(0, static_cast<int>(ceil(firstVisibleItem + itemsPerPage - 1)));
470 return ItemRange(firstItemIndex, lastItemIndex);
473 unsigned int RollLayout::GetReserveItemCount(Vector3 layoutSize) const
475 float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
476 float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
478 Vector3 itemSize = mImpl->mItemSizeFunction(layoutWidth, layoutHeight, mImpl->mRowSpacing);
479 int itemsPerPage = ceil(layoutHeight / (itemSize.y + mImpl->mRowSpacing));
480 return itemsPerPage * 5;
483 bool RollLayout::GetItemSize(unsigned int itemId, Vector3 layoutSize, Vector3& itemSize) const
485 // Note: itemId is not checked, since every item has the same size
486 float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
487 float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
489 itemSize = mImpl->mItemSizeFunction(layoutWidth, layoutHeight, mImpl->mRowSpacing);
494 void RollLayout::GetResizeAnimation(Animation& animation, Actor actor, Vector3 size, float durationSeconds) const
498 animation.Resize(actor, size);
502 bool RollLayout::GetPositionConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
504 if (mOrientation == ControlOrientation::Up)
506 constraint = RollPositionConstraint0(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
508 else if (mOrientation == ControlOrientation::Left)
510 constraint = RollPositionConstraint90(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
512 else if (mOrientation == ControlOrientation::Down)
514 constraint = RollPositionConstraint180(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
516 else // mOrientation == ControlOrientation::Right
518 constraint = RollPositionConstraint270(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
524 bool RollLayout::GetRotationConstraint(unsigned int itemId, ItemLayout::QuaternionFunction& constraint) const
526 constraint = mImpl->mRotationConstraint[mOrientation];
530 bool RollLayout::GetScaleConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
532 constraint = mImpl->mScaleConstraint;
536 bool RollLayout::GetColorConstraint(unsigned int itemId, ItemLayout::Vector4Function& constraint) const
538 constraint = mImpl->mColorConstraint;
542 bool RollLayout::GetVisibilityConstraint(unsigned int itemId, ItemLayout::BoolFunction& constraint) const
544 if (IsVertical(mOrientation))
546 constraint = RollVisibilityConstraintPortrait(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
550 constraint = RollVisibilityConstraintLandscape(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
556 Degree RollLayout::GetScrollDirection() const
558 Degree scrollDirection(0.0f);
560 if (mOrientation == ControlOrientation::Up)
562 scrollDirection = 0.0f;
564 else if (mOrientation == ControlOrientation::Left)
566 scrollDirection = 90.0f;
568 else if (mOrientation == ControlOrientation::Down)
570 scrollDirection = 180.0f;
572 else // mOrientation == ControlOrientation::Right
574 scrollDirection = 270.0f;
577 return scrollDirection;
580 RollLayout::RollLayout()
586 } // namespace Toolkit