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/public-api/controls/scrollable/item-view/roll-layout.h>
23 #include <dali/public-api/animation/animation.h>
26 using namespace Dali::Toolkit;
29 namespace // unnamed namespace
32 const float DEFAULT_ROW_SPACING = 20.0f;
33 const float DEFAULT_SCROLL_SPEED_FACTOR = 0.0015f;
34 const float DEFAULT_MAXIMUM_SWIPE_SPEED = 8.0f;
35 const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.4f;
37 // 4 orientations are supported
38 static const unsigned int ORIENTATION_COUNT = 4;
40 static Vector3 GetItemSizeDefaultFunction(float layoutWidth, float layoutHeight, float rowSpacing)
42 float height = (layoutHeight - rowSpacing) * 0.5f;
43 return Vector3(layoutWidth, height, height);
46 struct RollPositionConstraint0
48 RollPositionConstraint0(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
49 : mRowSpacing(rowSpacing),
50 mItemSizeFunction(itemSizeFunction)
54 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
56 Vector3 itemSize = mItemSizeFunction(layoutSize.width, layoutSize.height, mRowSpacing);
58 float adjustedLayoutPosition = layoutPosition;
59 float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed * scrollSpeed;
62 float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
64 if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
66 float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
67 adjustedLayoutPosition = adjustment * 2.0f;
68 y = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.height * 0.5f + itemSize.y * 0.5f;
72 float yStep = max(50.0f, min(itemSize.y, scrollSpeedFactor));
73 y = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * yStep : (layoutSize.height * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * yStep;
74 y += itemSize.y * 0.5f - layoutSize.height * 0.5f;
77 float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
78 z -= min(3000.0f, scrollSpeedFactor * 2.0f);
80 return Vector3(itemSize.x * 0.5f - layoutSize.x * 0.5f, y, z);
86 RollLayout::ItemSizeFunction mItemSizeFunction;
89 struct RollPositionConstraint90
91 RollPositionConstraint90(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
92 : mRowSpacing(rowSpacing),
93 mItemSizeFunction(itemSizeFunction)
97 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
99 Vector3 itemSize = mItemSizeFunction(layoutSize.height, layoutSize.width, mRowSpacing);
101 float adjustedLayoutPosition = layoutPosition;
102 float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed;
105 float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
107 if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
109 float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
110 adjustedLayoutPosition = adjustment * 2.0f;
111 x = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.width * 0.5f + itemSize.y * 0.5f;
115 float xStep = max(50.0f, min(itemSize.y, scrollSpeedFactor));
116 x = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * xStep : (layoutSize.width * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * xStep;
117 x += itemSize.y * 0.5f - layoutSize.width * 0.5f;
120 float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
121 z -= min(3000.0f, scrollSpeedFactor * 2.0f);
123 return Vector3(x, itemSize.x * 0.5f - layoutSize.y * 0.5f, z);
129 RollLayout::ItemSizeFunction mItemSizeFunction;
132 struct RollPositionConstraint180
134 RollPositionConstraint180(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
135 : mRowSpacing(rowSpacing),
136 mItemSizeFunction(itemSizeFunction)
140 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
142 Vector3 itemSize = mItemSizeFunction(layoutSize.width, layoutSize.height, mRowSpacing);
144 float adjustedLayoutPosition = layoutPosition;
145 float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed;
148 float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
150 if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
152 float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
153 adjustedLayoutPosition = adjustment * 2.0f;
154 y = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.height * 0.5f + itemSize.y * 0.5f;
158 float yStep = max(50.0f, min(itemSize.y, scrollSpeedFactor));
159 y = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * yStep : (layoutSize.height * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * yStep;
160 y += itemSize.y * 0.5f - layoutSize.height * 0.5f;
163 float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
164 z -= min(3000.0f, scrollSpeedFactor * 2.0f);
167 return Vector3(-(itemSize.x * 0.5f - layoutSize.x * 0.5f),
175 RollLayout::ItemSizeFunction mItemSizeFunction;
178 struct RollPositionConstraint270
180 RollPositionConstraint270(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
181 : mRowSpacing(rowSpacing),
182 mItemSizeFunction(itemSizeFunction)
186 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
188 Vector3 itemSize = mItemSizeFunction(layoutSize.height, layoutSize.width, mRowSpacing);
190 float adjustedLayoutPosition = layoutPosition;
191 float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed;
194 float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
196 if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
198 float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
199 adjustedLayoutPosition = adjustment * 2.0f;
200 x = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.width * 0.5f + itemSize.y * 0.5f;
204 float xStep = max(50.0f, min(itemSize.y, scrollSpeedFactor));
205 x = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * xStep : (layoutSize.width * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * xStep;
206 x += itemSize.y * 0.5f - layoutSize.width * 0.5f;
209 float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
210 z -= min(3000.0f, scrollSpeedFactor * 2.0f);
213 itemSize.x * 0.5f - layoutSize.y * 0.5f,
220 RollLayout::ItemSizeFunction mItemSizeFunction;
223 struct RollRotationConstraint0
225 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
227 return Quaternion(0.0f, Vector3::ZAXIS);
231 struct RollRotationConstraint90
233 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
235 return Quaternion(1.5f * Math::PI, Vector3::ZAXIS);
239 struct RollRotationConstraint180
241 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
243 return Quaternion(Math::PI, Vector3::ZAXIS);
247 struct RollRotationConstraint270
249 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
251 return Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
255 struct RollScaleConstraint
257 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
259 float adjustedLayoutPosition = layoutPosition;
261 if(adjustedLayoutPosition < Math::MACHINE_EPSILON_0)
263 factor = fabsf(adjustedLayoutPosition);
265 if(adjustedLayoutPosition - 1.0f > Math::MACHINE_EPSILON_0)
267 factor = adjustedLayoutPosition - 1.0f;
270 float scale = min(1.0f, max(0.1f, 1.0f - 0.1f * factor));
271 if(scrollSpeed > 0.0f)
273 scale *= min(1.0f, max(0.1f, 1.0f / (scrollSpeed * 0.05f)));
276 return Vector3(scale, scale, scale);
280 struct RollColorConstraint
282 Vector4 operator()(const Vector4& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
284 float adjustedLayoutPosition = layoutPosition;
287 if(adjustedLayoutPosition < Math::MACHINE_EPSILON_0)
289 factor = fabsf(adjustedLayoutPosition);
291 if(adjustedLayoutPosition - 1.0f > Math::MACHINE_EPSILON_0)
293 factor = adjustedLayoutPosition - 1.0f;
296 float darkness = min(1.0f, max(0.5f, 1.0f - 0.5f * factor));
297 float alpha = min(1.0f, max(0.0f, 1.0f - 0.9f * factor));
298 return Vector4(darkness, darkness, darkness, alpha);
302 struct RollVisibilityConstraintPortrait
304 RollVisibilityConstraintPortrait(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
305 : mRowSpacing(rowSpacing),
306 mItemSizeFunction(itemSizeFunction)
310 bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
312 Vector3 itemSize = mItemSizeFunction(layoutSize.width, layoutSize.height, mRowSpacing);
313 int rowsPerPage = ceil(layoutSize.height / (itemSize.y + mRowSpacing));
314 return (layoutPosition > -rowsPerPage) && (layoutPosition < rowsPerPage);
320 RollLayout::ItemSizeFunction mItemSizeFunction;
323 struct RollVisibilityConstraintLandscape
325 RollVisibilityConstraintLandscape(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
326 : mRowSpacing(rowSpacing),
327 mItemSizeFunction(itemSizeFunction)
331 bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
333 Vector3 itemSize = mItemSizeFunction(layoutSize.height, layoutSize.width, mRowSpacing);
334 int rowsPerPage = ceil(layoutSize.width / (itemSize.y + mRowSpacing));
335 return (layoutPosition + 2.0f > Math::MACHINE_EPSILON_0) && (layoutPosition < rowsPerPage);
341 RollLayout::ItemSizeFunction mItemSizeFunction;
344 } // unnamed namespace
352 struct RollLayout::Impl
355 : mRowSpacing(DEFAULT_ROW_SPACING),
356 mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
357 mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
358 mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION),
359 mItemSizeFunction(GetItemSizeDefaultFunction)
361 mScaleConstraint = RollScaleConstraint();
362 mColorConstraint = RollColorConstraint();
364 mRotationConstraint[0] = RollRotationConstraint0();
365 mRotationConstraint[1] = RollRotationConstraint90();
366 mRotationConstraint[2] = RollRotationConstraint180();
367 mRotationConstraint[3] = RollRotationConstraint270();
372 float mScrollSpeedFactor;
373 float mMaximumSwipeSpeed;
374 float mItemFlickAnimationDuration;
376 ItemLayout::QuaternionFunction mRotationConstraint[ORIENTATION_COUNT];
377 ItemLayout::Vector3Function mScaleConstraint;
378 ItemLayout::Vector4Function mColorConstraint;
380 ItemSizeFunction mItemSizeFunction;
383 RollLayoutPtr RollLayout::New()
385 return RollLayoutPtr(new RollLayout());
388 RollLayout::~RollLayout()
393 void RollLayout::SetRowSpacing(float spacing)
395 mImpl->mRowSpacing = spacing;
398 float RollLayout::GetRowSpacing() const
400 return mImpl->mRowSpacing;
403 void RollLayout::SetItemSizeFunction(ItemSizeFunction function)
405 mImpl->mItemSizeFunction = function;
408 RollLayout::ItemSizeFunction RollLayout::GetItemSizeFunction() const
410 return mImpl->mItemSizeFunction;
413 void RollLayout::SetScrollSpeedFactor(float scrollSpeed)
415 mImpl->mScrollSpeedFactor = scrollSpeed;
418 void RollLayout::SetMaximumSwipeSpeed(float speed)
420 mImpl->mMaximumSwipeSpeed = speed;
423 void RollLayout::SetItemFlickAnimationDuration(float durationSeconds)
425 mImpl->mItemFlickAnimationDuration = durationSeconds;
428 float RollLayout::GetScrollSpeedFactor() const
430 return mImpl->mScrollSpeedFactor;
433 float RollLayout::GetMaximumSwipeSpeed() const
435 return mImpl->mMaximumSwipeSpeed;
438 float RollLayout::GetItemFlickAnimationDuration() const
440 return mImpl->mItemFlickAnimationDuration;
443 float RollLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
445 return 2.0f - static_cast<float>(numberOfItems);
448 float RollLayout::GetClosestAnchorPosition(float layoutPosition) const
450 return static_cast<float>(round(layoutPosition));
453 float RollLayout::GetItemScrollToPosition(unsigned int itemId) const
455 return 0.0f - static_cast<float>(itemId);
458 ItemRange RollLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
460 float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
461 float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
463 Vector3 itemSize = mImpl->mItemSizeFunction( layoutWidth,layoutHeight, mImpl->mRowSpacing);
465 float itemsPerPage = (layoutHeight / (itemSize.y + mImpl->mRowSpacing));
466 if(firstItemPosition + 0.001f >= Math::MACHINE_EPSILON_0)
468 itemsPerPage = std::max(0.0f, itemsPerPage - 1.0f);
470 int firstVisibleItem = -(static_cast<int>(firstItemPosition));
472 int firstItemIndex = std::max(0, firstVisibleItem);
473 int lastItemIndex = std::max(0, static_cast<int>(ceil(firstVisibleItem + itemsPerPage - 1)));
474 return ItemRange(firstItemIndex, lastItemIndex);
477 unsigned int RollLayout::GetReserveItemCount(Vector3 layoutSize) const
479 float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
480 float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
482 Vector3 itemSize = mImpl->mItemSizeFunction(layoutWidth, layoutHeight, mImpl->mRowSpacing);
483 int itemsPerPage = ceil(layoutHeight / (itemSize.y + mImpl->mRowSpacing));
484 return itemsPerPage * 5;
487 bool RollLayout::GetItemSize(unsigned int itemId, Vector3 layoutSize, Vector3& itemSize) const
489 // Note: itemId is not checked, since every item has the same size
490 float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
491 float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
493 itemSize = mImpl->mItemSizeFunction(layoutWidth, layoutHeight, mImpl->mRowSpacing);
498 void RollLayout::GetResizeAnimation(Animation& animation, Actor actor, Vector3 size, float durationSeconds) const
502 animation.Resize(actor, size);
506 bool RollLayout::GetPositionConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
508 if (mOrientation == ControlOrientation::Up)
510 constraint = RollPositionConstraint0(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
512 else if (mOrientation == ControlOrientation::Left)
514 constraint = RollPositionConstraint90(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
516 else if (mOrientation == ControlOrientation::Down)
518 constraint = RollPositionConstraint180(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
520 else // mOrientation == ControlOrientation::Right
522 constraint = RollPositionConstraint270(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
528 bool RollLayout::GetRotationConstraint(unsigned int itemId, ItemLayout::QuaternionFunction& constraint) const
530 constraint = mImpl->mRotationConstraint[mOrientation];
534 bool RollLayout::GetScaleConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
536 constraint = mImpl->mScaleConstraint;
540 bool RollLayout::GetColorConstraint(unsigned int itemId, ItemLayout::Vector4Function& constraint) const
542 constraint = mImpl->mColorConstraint;
546 bool RollLayout::GetVisibilityConstraint(unsigned int itemId, ItemLayout::BoolFunction& constraint) const
548 if (IsVertical(mOrientation))
550 constraint = RollVisibilityConstraintPortrait(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
554 constraint = RollVisibilityConstraintLandscape(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
560 Degree RollLayout::GetScrollDirection() const
562 Degree scrollDirection(0.0f);
564 if (mOrientation == ControlOrientation::Up)
566 scrollDirection = 0.0f;
568 else if (mOrientation == ControlOrientation::Left)
570 scrollDirection = 90.0f;
572 else if (mOrientation == ControlOrientation::Down)
574 scrollDirection = 180.0f;
576 else // mOrientation == ControlOrientation::Right
578 scrollDirection = 270.0f;
581 return scrollDirection;
584 RollLayout::RollLayout()
590 } // namespace Toolkit