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;
28 namespace // unnamed namespace
31 const float DEFAULT_ROW_SPACING = 20.0f;
32 const float DEFAULT_SCROLL_SPEED_FACTOR = 0.0015f;
33 const float DEFAULT_MAXIMUM_SWIPE_SPEED = 8.0f;
34 const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.4f;
36 // 4 orientations are supported
37 static const unsigned int ORIENTATION_COUNT = 4;
39 static Vector3 GetItemSizeDefaultFunction(float layoutWidth, float layoutHeight, float rowSpacing)
41 float height = (layoutHeight - rowSpacing) * 0.5f;
42 return Vector3(layoutWidth, height, height);
45 struct RollPositionConstraint0
47 RollPositionConstraint0(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
48 : mRowSpacing(rowSpacing),
49 mItemSizeFunction(itemSizeFunction)
53 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
55 Vector3 itemSize = mItemSizeFunction(layoutSize.width, layoutSize.height, mRowSpacing);
57 float adjustedLayoutPosition = layoutPosition;
58 float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed * scrollSpeed;
61 float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
63 if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
65 float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
66 adjustedLayoutPosition = adjustment * 2.0f;
67 y = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.height * 0.5f + itemSize.y * 0.5f;
71 float yStep = std::max(50.0f, std::min(itemSize.y, scrollSpeedFactor));
72 y = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * yStep : (layoutSize.height * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * yStep;
73 y += itemSize.y * 0.5f - layoutSize.height * 0.5f;
76 float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
77 z -= std::min(3000.0f, scrollSpeedFactor * 2.0f);
79 return Vector3(itemSize.x * 0.5f - layoutSize.x * 0.5f, y, z);
85 RollLayout::ItemSizeFunction mItemSizeFunction;
88 struct RollPositionConstraint90
90 RollPositionConstraint90(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
91 : mRowSpacing(rowSpacing),
92 mItemSizeFunction(itemSizeFunction)
96 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
98 Vector3 itemSize = mItemSizeFunction(layoutSize.height, layoutSize.width, mRowSpacing);
100 float adjustedLayoutPosition = layoutPosition;
101 float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed;
104 float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
106 if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
108 float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
109 adjustedLayoutPosition = adjustment * 2.0f;
110 x = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.width * 0.5f + itemSize.y * 0.5f;
114 float xStep = std::max(50.0f, std::min(itemSize.y, scrollSpeedFactor));
115 x = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * xStep : (layoutSize.width * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * xStep;
116 x += itemSize.y * 0.5f - layoutSize.width * 0.5f;
119 float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
120 z -= std::min(3000.0f, scrollSpeedFactor * 2.0f);
122 return Vector3(x, itemSize.x * 0.5f - layoutSize.y * 0.5f, z);
128 RollLayout::ItemSizeFunction mItemSizeFunction;
131 struct RollPositionConstraint180
133 RollPositionConstraint180(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
134 : mRowSpacing(rowSpacing),
135 mItemSizeFunction(itemSizeFunction)
139 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
141 Vector3 itemSize = mItemSizeFunction(layoutSize.width, layoutSize.height, mRowSpacing);
143 float adjustedLayoutPosition = layoutPosition;
144 float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed;
147 float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
149 if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
151 float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
152 adjustedLayoutPosition = adjustment * 2.0f;
153 y = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.height * 0.5f + itemSize.y * 0.5f;
157 float yStep = std::max(50.0f, std::min(itemSize.y, scrollSpeedFactor));
158 y = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * yStep : (layoutSize.height * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * yStep;
159 y += itemSize.y * 0.5f - layoutSize.height * 0.5f;
162 float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
163 z -= std::min(3000.0f, scrollSpeedFactor * 2.0f);
166 return Vector3(-(itemSize.x * 0.5f - layoutSize.x * 0.5f),
174 RollLayout::ItemSizeFunction mItemSizeFunction;
177 struct RollPositionConstraint270
179 RollPositionConstraint270(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
180 : mRowSpacing(rowSpacing),
181 mItemSizeFunction(itemSizeFunction)
185 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
187 Vector3 itemSize = mItemSizeFunction(layoutSize.height, layoutSize.width, mRowSpacing);
189 float adjustedLayoutPosition = layoutPosition;
190 float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed;
193 float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
195 if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
197 float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
198 adjustedLayoutPosition = adjustment * 2.0f;
199 x = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.width * 0.5f + itemSize.y * 0.5f;
203 float xStep = std::max(50.0f, std::min(itemSize.y, scrollSpeedFactor));
204 x = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * xStep : (layoutSize.width * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * xStep;
205 x += itemSize.y * 0.5f - layoutSize.width * 0.5f;
208 float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
209 z -= std::min(3000.0f, scrollSpeedFactor * 2.0f);
212 itemSize.x * 0.5f - layoutSize.y * 0.5f,
219 RollLayout::ItemSizeFunction mItemSizeFunction;
222 struct RollRotationConstraint0
224 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
226 return Quaternion(0.0f, Vector3::ZAXIS);
230 struct RollRotationConstraint90
232 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
234 return Quaternion(1.5f * Math::PI, Vector3::ZAXIS);
238 struct RollRotationConstraint180
240 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
242 return Quaternion(Math::PI, Vector3::ZAXIS);
246 struct RollRotationConstraint270
248 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
250 return Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
254 struct RollScaleConstraint
256 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
258 float adjustedLayoutPosition = layoutPosition;
260 if(adjustedLayoutPosition < Math::MACHINE_EPSILON_0)
262 factor = fabsf(adjustedLayoutPosition);
264 if(adjustedLayoutPosition - 1.0f > Math::MACHINE_EPSILON_0)
266 factor = adjustedLayoutPosition - 1.0f;
269 float scale = std::min(1.0f, std::max(0.1f, 1.0f - 0.1f * factor));
270 if(scrollSpeed > 0.0f)
272 scale *= std::min(1.0f, std::max(0.1f, 1.0f / (scrollSpeed * 0.05f)));
275 return Vector3(scale, scale, scale);
279 struct RollColorConstraint
281 Vector4 operator()(const Vector4& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
283 float adjustedLayoutPosition = layoutPosition;
286 if(adjustedLayoutPosition < Math::MACHINE_EPSILON_0)
288 factor = fabsf(adjustedLayoutPosition);
290 if(adjustedLayoutPosition - 1.0f > Math::MACHINE_EPSILON_0)
292 factor = adjustedLayoutPosition - 1.0f;
295 float darkness = std::min(1.0f, std::max(0.5f, 1.0f - 0.5f * factor));
296 float alpha = std::min(1.0f, std::max(0.0f, 1.0f - 0.9f * factor));
297 return Vector4(darkness, darkness, darkness, alpha);
301 struct RollVisibilityConstraintPortrait
303 RollVisibilityConstraintPortrait(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
304 : mRowSpacing(rowSpacing),
305 mItemSizeFunction(itemSizeFunction)
309 bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
311 Vector3 itemSize = mItemSizeFunction(layoutSize.width, layoutSize.height, mRowSpacing);
312 int rowsPerPage = ceil(layoutSize.height / (itemSize.y + mRowSpacing));
313 return (layoutPosition > -rowsPerPage) && (layoutPosition < rowsPerPage);
319 RollLayout::ItemSizeFunction mItemSizeFunction;
322 struct RollVisibilityConstraintLandscape
324 RollVisibilityConstraintLandscape(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
325 : mRowSpacing(rowSpacing),
326 mItemSizeFunction(itemSizeFunction)
330 bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
332 Vector3 itemSize = mItemSizeFunction(layoutSize.height, layoutSize.width, mRowSpacing);
333 int rowsPerPage = ceil(layoutSize.width / (itemSize.y + mRowSpacing));
334 return (layoutPosition + 2.0f > Math::MACHINE_EPSILON_0) && (layoutPosition < rowsPerPage);
340 RollLayout::ItemSizeFunction mItemSizeFunction;
343 } // unnamed namespace
351 struct RollLayout::Impl
354 : mRowSpacing(DEFAULT_ROW_SPACING),
355 mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
356 mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
357 mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION),
358 mItemSizeFunction(GetItemSizeDefaultFunction)
360 mScaleConstraint = RollScaleConstraint();
361 mColorConstraint = RollColorConstraint();
363 mRotationConstraint[0] = RollRotationConstraint0();
364 mRotationConstraint[1] = RollRotationConstraint90();
365 mRotationConstraint[2] = RollRotationConstraint180();
366 mRotationConstraint[3] = RollRotationConstraint270();
371 float mScrollSpeedFactor;
372 float mMaximumSwipeSpeed;
373 float mItemFlickAnimationDuration;
375 ItemLayout::QuaternionFunction mRotationConstraint[ORIENTATION_COUNT];
376 ItemLayout::Vector3Function mScaleConstraint;
377 ItemLayout::Vector4Function mColorConstraint;
379 ItemSizeFunction mItemSizeFunction;
382 RollLayoutPtr RollLayout::New()
384 return RollLayoutPtr(new RollLayout());
387 RollLayout::~RollLayout()
392 void RollLayout::SetRowSpacing(float spacing)
394 mImpl->mRowSpacing = spacing;
397 float RollLayout::GetRowSpacing() const
399 return mImpl->mRowSpacing;
402 void RollLayout::SetItemSizeFunction(ItemSizeFunction function)
404 mImpl->mItemSizeFunction = function;
407 RollLayout::ItemSizeFunction RollLayout::GetItemSizeFunction() const
409 return mImpl->mItemSizeFunction;
412 void RollLayout::SetScrollSpeedFactor(float scrollSpeed)
414 mImpl->mScrollSpeedFactor = scrollSpeed;
417 void RollLayout::SetMaximumSwipeSpeed(float speed)
419 mImpl->mMaximumSwipeSpeed = speed;
422 void RollLayout::SetItemFlickAnimationDuration(float durationSeconds)
424 mImpl->mItemFlickAnimationDuration = durationSeconds;
427 float RollLayout::GetScrollSpeedFactor() const
429 return mImpl->mScrollSpeedFactor;
432 float RollLayout::GetMaximumSwipeSpeed() const
434 return mImpl->mMaximumSwipeSpeed;
437 float RollLayout::GetItemFlickAnimationDuration() const
439 return mImpl->mItemFlickAnimationDuration;
442 float RollLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
444 return 2.0f - static_cast<float>(numberOfItems);
447 float RollLayout::GetClosestAnchorPosition(float layoutPosition) const
449 return static_cast<float>(round(layoutPosition));
452 float RollLayout::GetItemScrollToPosition(unsigned int itemId) const
454 return 0.0f - static_cast<float>(itemId);
457 ItemRange RollLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
459 float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
460 float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
462 Vector3 itemSize = mImpl->mItemSizeFunction( layoutWidth,layoutHeight, mImpl->mRowSpacing);
464 float itemsPerPage = (layoutHeight / (itemSize.y + mImpl->mRowSpacing));
465 if(firstItemPosition + 0.001f >= Math::MACHINE_EPSILON_0)
467 itemsPerPage = std::max(0.0f, itemsPerPage - 1.0f);
469 int firstVisibleItem = -(static_cast<int>(firstItemPosition));
471 int firstItemIndex = std::max(0, firstVisibleItem);
472 int lastItemIndex = std::max(0, static_cast<int>(ceil(firstVisibleItem + itemsPerPage - 1)));
473 return ItemRange(firstItemIndex, lastItemIndex);
476 unsigned int RollLayout::GetReserveItemCount(Vector3 layoutSize) const
478 float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
479 float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
481 Vector3 itemSize = mImpl->mItemSizeFunction(layoutWidth, layoutHeight, mImpl->mRowSpacing);
482 int itemsPerPage = ceil(layoutHeight / (itemSize.y + mImpl->mRowSpacing));
483 return itemsPerPage * 5;
486 bool RollLayout::GetItemSize(unsigned int itemId, Vector3 layoutSize, Vector3& itemSize) const
488 // Note: itemId is not checked, since every item has the same size
489 float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
490 float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
492 itemSize = mImpl->mItemSizeFunction(layoutWidth, layoutHeight, mImpl->mRowSpacing);
497 void RollLayout::GetResizeAnimation(Animation& animation, Actor actor, Vector3 size, float durationSeconds) const
501 animation.Resize(actor, size);
505 bool RollLayout::GetPositionConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
507 if (mOrientation == ControlOrientation::Up)
509 constraint = RollPositionConstraint0(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
511 else if (mOrientation == ControlOrientation::Left)
513 constraint = RollPositionConstraint90(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
515 else if (mOrientation == ControlOrientation::Down)
517 constraint = RollPositionConstraint180(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
519 else // mOrientation == ControlOrientation::Right
521 constraint = RollPositionConstraint270(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
527 bool RollLayout::GetRotationConstraint(unsigned int itemId, ItemLayout::QuaternionFunction& constraint) const
529 constraint = mImpl->mRotationConstraint[mOrientation];
533 bool RollLayout::GetScaleConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
535 constraint = mImpl->mScaleConstraint;
539 bool RollLayout::GetColorConstraint(unsigned int itemId, ItemLayout::Vector4Function& constraint) const
541 constraint = mImpl->mColorConstraint;
545 bool RollLayout::GetVisibilityConstraint(unsigned int itemId, ItemLayout::BoolFunction& constraint) const
547 if (IsVertical(mOrientation))
549 constraint = RollVisibilityConstraintPortrait(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
553 constraint = RollVisibilityConstraintLandscape(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
559 Degree RollLayout::GetScrollDirection() const
561 Degree scrollDirection(0.0f);
563 if (mOrientation == ControlOrientation::Up)
565 scrollDirection = 0.0f;
567 else if (mOrientation == ControlOrientation::Left)
569 scrollDirection = 90.0f;
571 else if (mOrientation == ControlOrientation::Down)
573 scrollDirection = 180.0f;
575 else // mOrientation == ControlOrientation::Right
577 scrollDirection = 270.0f;
580 return scrollDirection;
583 RollLayout::RollLayout()
589 } // namespace Toolkit