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/depth-layout.h>
22 using namespace Dali::Toolkit;
25 namespace // unnamed namespace
28 const unsigned int DEFAULT_NUMBER_OF_COLUMNS = 3;
29 const float DEFAULT_NUMBER_OF_ROWS = 20.0f;
30 const float DEFAULT_ROW_SPACING = 55.0f;
31 const float DEFAULT_BOTTOM_MARGIN_FACTOR = 0.1f;
32 const Radian DEFAULT_TILT_ANGLE ( Math::PI*0.12f );
33 const Radian DEFAULT_ITEM_TILT_ANGLE ( -Math::PI*0.025f );
34 const float DEFAULT_SCROLL_SPEED_FACTOR = 0.02f;
35 const float DEFAULT_MAXIMUM_SWIPE_SPEED = 50.0f;
36 const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.03f;
38 static Vector3 GetItemSizeDefaultFunction(unsigned int numberOfColumns, float layoutWidth)
40 float width = layoutWidth / static_cast<float>(numberOfColumns + 1);
43 return Vector3(width, width, width);
46 static float GetBottomMarginDefaultFunction(float layoutHeight)
48 return layoutHeight * DEFAULT_BOTTOM_MARGIN_FACTOR;
51 struct GetColumnPositionDefaultFunction
53 float operator()(unsigned int numberOfColumns,
54 unsigned int columnNumber,
55 const Vector3& itemSize,
58 // Share the available space between margins & column spacings
59 float availableSpace = max(0.0f, (layoutWidth - itemSize.width*numberOfColumns));
61 float leftMargin = availableSpace/numberOfColumns * 0.5f;
63 float columnPosition = leftMargin + itemSize.width*0.5f + columnNumber*(itemSize.width + availableSpace/numberOfColumns);
65 return columnPosition - layoutWidth*0.5f;
69 struct DepthPositionConstraint0
71 DepthPositionConstraint0(unsigned int numberOfColumns,
72 unsigned int columnNumber,
73 DepthLayout::ItemSizeFunction itemSizeFunction,
74 DepthLayout::BottomMarginFunction bottomMarginFunction,
75 DepthLayout::ColumnPositionFunction columnPositionFunction,
78 : mNumberOfColumns(numberOfColumns),
79 mColumnNumber(columnNumber),
80 mItemSizeFunction(itemSizeFunction),
81 mBottomMarginFunction(bottomMarginFunction),
82 mColumnPositionFunction(columnPositionFunction),
83 mHeightScale(heightScale),
84 mDepthScale(depthScale)
88 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
90 Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.width);
92 float rowLayoutPositon = layoutPosition - static_cast<float>(mColumnNumber);
94 return Vector3( mColumnPositionFunction(mNumberOfColumns, mColumnNumber, itemSize, layoutSize.width),
95 rowLayoutPositon*mHeightScale + layoutSize.height*0.5f - mBottomMarginFunction(layoutSize.height) - itemSize.height * 0.5f,
96 -rowLayoutPositon*mDepthScale );
99 unsigned int mNumberOfColumns;
100 unsigned int mColumnNumber;
102 DepthLayout::ItemSizeFunction mItemSizeFunction;
103 DepthLayout::BottomMarginFunction mBottomMarginFunction;
104 DepthLayout::ColumnPositionFunction mColumnPositionFunction;
110 struct DepthPositionConstraint90
112 DepthPositionConstraint90(unsigned int numberOfColumns,
113 unsigned int columnNumber,
114 DepthLayout::ItemSizeFunction itemSizeFunction,
115 DepthLayout::BottomMarginFunction bottomMarginFunction,
116 DepthLayout::ColumnPositionFunction columnPositionFunction,
119 : mNumberOfColumns(numberOfColumns),
120 mColumnNumber(columnNumber),
121 mItemSizeFunction(itemSizeFunction),
122 mBottomMarginFunction(bottomMarginFunction),
123 mColumnPositionFunction(columnPositionFunction),
124 mHeightScale(heightScale),
125 mDepthScale(depthScale)
129 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
131 Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.height);
133 float rowLayoutPositon = layoutPosition - static_cast<float>(mColumnNumber) + mNumberOfColumns*0.5f;
135 return Vector3( rowLayoutPositon*mHeightScale + layoutSize.width*0.5f - mBottomMarginFunction(layoutSize.width) - itemSize.height * 0.5f,
136 -mColumnPositionFunction(mNumberOfColumns, mColumnNumber, itemSize, layoutSize.height),
137 -rowLayoutPositon*mDepthScale );
140 unsigned int mNumberOfColumns;
141 unsigned int mColumnNumber;
143 DepthLayout::ItemSizeFunction mItemSizeFunction;
144 DepthLayout::BottomMarginFunction mBottomMarginFunction;
145 DepthLayout::ColumnPositionFunction mColumnPositionFunction;
151 struct DepthPositionConstraint180
153 DepthPositionConstraint180(unsigned int numberOfColumns,
154 unsigned int columnNumber,
155 DepthLayout::ItemSizeFunction itemSizeFunction,
156 DepthLayout::BottomMarginFunction bottomMarginFunction,
157 DepthLayout::ColumnPositionFunction columnPositionFunction,
160 : mNumberOfColumns(numberOfColumns),
161 mColumnNumber(columnNumber),
162 mItemSizeFunction(itemSizeFunction),
163 mBottomMarginFunction(bottomMarginFunction),
164 mColumnPositionFunction(columnPositionFunction),
165 mHeightScale(heightScale),
166 mDepthScale(depthScale)
170 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
172 Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.width);
174 float rowLayoutPositon = layoutPosition - static_cast<float>(mColumnNumber);
176 return Vector3( -mColumnPositionFunction(mNumberOfColumns, mColumnNumber, itemSize, layoutSize.width),
177 -(rowLayoutPositon*mHeightScale + layoutSize.height*0.5f - mBottomMarginFunction(layoutSize.height) - itemSize.height * 0.5f),
178 -rowLayoutPositon*mDepthScale );
181 unsigned int mNumberOfColumns;
182 unsigned int mColumnNumber;
184 DepthLayout::ItemSizeFunction mItemSizeFunction;
185 DepthLayout::BottomMarginFunction mBottomMarginFunction;
186 DepthLayout::ColumnPositionFunction mColumnPositionFunction;
192 struct DepthPositionConstraint270
194 DepthPositionConstraint270(unsigned int numberOfColumns,
195 unsigned int columnNumber,
196 DepthLayout::ItemSizeFunction itemSizeFunction,
197 DepthLayout::BottomMarginFunction bottomMarginFunction,
198 DepthLayout::ColumnPositionFunction columnPositionFunction,
201 : mNumberOfColumns(numberOfColumns),
202 mColumnNumber(columnNumber),
203 mItemSizeFunction(itemSizeFunction),
204 mBottomMarginFunction(bottomMarginFunction),
205 mColumnPositionFunction(columnPositionFunction),
206 mHeightScale(heightScale),
207 mDepthScale(depthScale)
211 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
213 Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.height);
215 float rowLayoutPositon = layoutPosition - static_cast<float>(mColumnNumber) + mNumberOfColumns*0.5f;
217 return Vector3( -(rowLayoutPositon*mHeightScale + layoutSize.width*0.5f - mBottomMarginFunction(layoutSize.width) - itemSize.height * 0.5f),
218 mColumnPositionFunction(mNumberOfColumns, mColumnNumber, itemSize, layoutSize.height),
219 -rowLayoutPositon*mDepthScale );
222 unsigned int mNumberOfColumns;
223 unsigned int mColumnNumber;
225 DepthLayout::ItemSizeFunction mItemSizeFunction;
226 DepthLayout::BottomMarginFunction mBottomMarginFunction;
227 DepthLayout::ColumnPositionFunction mColumnPositionFunction;
233 struct DepthRotationConstraint0
235 DepthRotationConstraint0(float angleRadians)
236 : mTiltAngle(angleRadians)
240 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
242 return Quaternion(0.0f, Vector3::ZAXIS) * Quaternion(mTiltAngle, Vector3::XAXIS);
248 struct DepthRotationConstraint90
250 DepthRotationConstraint90(float angleRadians)
251 : mTiltAngle(angleRadians)
255 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
257 return Quaternion(1.5f * Math::PI, Vector3::ZAXIS) * Quaternion(mTiltAngle, Vector3::XAXIS);
263 struct DepthRotationConstraint180
265 DepthRotationConstraint180(float angleRadians)
266 : mTiltAngle(angleRadians)
270 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
272 return Quaternion(-Math::PI, Vector3::ZAXIS) * Quaternion(mTiltAngle, Vector3::XAXIS);
278 struct DepthRotationConstraint270
280 DepthRotationConstraint270(float angleRadians)
281 : mTiltAngle(angleRadians)
285 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
287 return Quaternion(0.5f * Math::PI, Vector3::ZAXIS) * Quaternion(mTiltAngle, Vector3::XAXIS);
293 struct DepthColorConstraint
295 DepthColorConstraint(unsigned int numberOfColumns, float numberOfRows, unsigned int columnNumber)
296 : mNumberOfColumns(numberOfColumns),
297 mNumberOfRows(numberOfRows),
298 mColumnNumber(columnNumber)
302 Vector4 operator()(const Vector4& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
304 float row = (layoutPosition - static_cast<float>(mColumnNumber)) / mNumberOfColumns;
306 float darkness(1.0f);
311 darkness = alpha = max(0.0f, 1.0f + row);
315 if (row > mNumberOfRows)
321 darkness = 1.0f - ( 1.0f * (row / mNumberOfRows) );
324 if (row > (mNumberOfRows-1.0f))
326 alpha = max(0.0f, 1.0f - (row-(mNumberOfRows-1.0f)));
330 return Vector4( darkness, darkness, darkness, current.a * alpha );
333 unsigned int mNumberOfColumns;
335 unsigned int mColumnNumber;
338 struct DepthVisibilityConstraint
340 DepthVisibilityConstraint(unsigned int numberOfColumns, float numberOfRows, unsigned int columnNumber)
341 : mNumberOfColumns(numberOfColumns),
342 mNumberOfRows(numberOfRows),
343 mColumnNumber(columnNumber)
347 bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
349 float row = (layoutPosition - static_cast<float>(mColumnNumber)) / mNumberOfColumns;
350 return (row > -1.0f) && (row < mNumberOfRows);
353 unsigned int mNumberOfColumns;
355 unsigned int mColumnNumber;
358 } // unnamed namespace
366 struct PositionConstraintSet
368 ItemLayout::Vector3Function mOrientation0;
369 ItemLayout::Vector3Function mOrientation90;
370 ItemLayout::Vector3Function mOrientation180;
371 ItemLayout::Vector3Function mOrientation270;
374 struct DepthLayout::Impl
377 : mNumberOfColumns(DEFAULT_NUMBER_OF_COLUMNS),
378 mNumberOfRows(DEFAULT_NUMBER_OF_ROWS),
379 mRowSpacing(DEFAULT_ROW_SPACING),
380 mTiltAngle(DEFAULT_TILT_ANGLE),
381 mItemTiltAngle(DEFAULT_ITEM_TILT_ANGLE),
382 mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
383 mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
384 mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION),
385 mItemSizeFunction(GetItemSizeDefaultFunction),
386 mBottomMarginFunction(GetBottomMarginDefaultFunction),
387 mColumnPositionFunction(GetColumnPositionDefaultFunction())
391 unsigned int mNumberOfColumns;
392 unsigned int mNumberOfRows;
397 Radian mItemTiltAngle;
399 float mScrollSpeedFactor;
400 float mMaximumSwipeSpeed;
401 float mItemFlickAnimationDuration;
403 ItemSizeFunction mItemSizeFunction;
404 BottomMarginFunction mBottomMarginFunction;
405 ColumnPositionFunction mColumnPositionFunction;
408 DepthLayoutPtr DepthLayout::New()
410 return DepthLayoutPtr(new DepthLayout());
413 DepthLayout::~DepthLayout()
418 void DepthLayout::SetNumberOfColumns(unsigned int columns)
420 mImpl->mNumberOfColumns = columns;
423 unsigned int DepthLayout::GetNumberOfColumns() const
425 return mImpl->mNumberOfColumns;
428 void DepthLayout::SetNumberOfRows(unsigned int rows)
430 mImpl->mNumberOfRows = rows;
433 unsigned int DepthLayout::GetNumberOfRows() const
435 return mImpl->mNumberOfRows;
438 void DepthLayout::SetRowSpacing(float spacing)
440 mImpl->mRowSpacing = spacing;
443 float DepthLayout::GetRowSpacing() const
445 return mImpl->mRowSpacing;
448 void DepthLayout::SetTiltAngle(Degree angle)
450 mImpl->mTiltAngle = Degree( Clamp<float>(angle, -45.0f, 45.0f) );
453 Degree DepthLayout::GetTiltAngle() const
455 return mImpl->mTiltAngle;
458 void DepthLayout::SetItemSizeFunction(ItemSizeFunction function)
460 mImpl->mItemSizeFunction = function;
463 DepthLayout::ItemSizeFunction DepthLayout::GetItemSizeFunction() const
465 return mImpl->mItemSizeFunction;
468 void DepthLayout::SetBottomMarginFunction(BottomMarginFunction function)
470 mImpl->mBottomMarginFunction = function;
473 DepthLayout::BottomMarginFunction DepthLayout::GetBottomMarginFunction() const
475 return mImpl->mBottomMarginFunction;
478 void DepthLayout::SetItemTiltAngle(Degree angle)
480 mImpl->mItemTiltAngle = angle;
483 Degree DepthLayout::GetItemTiltAngle() const
485 return mImpl->mItemTiltAngle;
488 void DepthLayout::SetColumnPositionFunction(ColumnPositionFunction function)
490 mImpl->mColumnPositionFunction = function;
493 DepthLayout::ColumnPositionFunction DepthLayout::GetColumnPositionFunction() const
495 return mImpl->mColumnPositionFunction;
498 void DepthLayout::SetScrollSpeedFactor(float scrollSpeed)
500 mImpl->mScrollSpeedFactor = scrollSpeed;
503 void DepthLayout::SetMaximumSwipeSpeed(float speed)
505 mImpl->mMaximumSwipeSpeed = speed;
508 void DepthLayout::SetItemFlickAnimationDuration(float durationSeconds)
510 mImpl->mItemFlickAnimationDuration = durationSeconds;
513 float DepthLayout::GetScrollSpeedFactor() const
515 return mImpl->mScrollSpeedFactor;
518 float DepthLayout::GetMaximumSwipeSpeed() const
520 return mImpl->mMaximumSwipeSpeed;
523 float DepthLayout::GetItemFlickAnimationDuration() const
525 return mImpl->mItemFlickAnimationDuration;
528 float DepthLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
530 return static_cast<float>(mImpl->mNumberOfColumns) - static_cast<float>(numberOfItems);
533 float DepthLayout::GetClosestAnchorPosition(float layoutPosition) const
535 float rowIndex = static_cast<float>(round(layoutPosition / mImpl->mNumberOfColumns));
536 return rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
539 float DepthLayout::GetItemScrollToPosition(unsigned int itemId) const
541 float rowIndex = static_cast<float>(itemId / mImpl->mNumberOfColumns);
542 return -rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
545 ItemRange DepthLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
547 float firstRow = -(firstItemPosition/mImpl->mNumberOfColumns);
548 float lastRow = firstRow + mImpl->mNumberOfRows * 0.5f;
550 unsigned int firstItem = static_cast<unsigned int>(max(0.0f, firstRow * mImpl->mNumberOfColumns));
551 unsigned int lastItem = static_cast<unsigned int>(max(0.0f, lastRow * mImpl->mNumberOfColumns));
553 return ItemRange(firstItem, lastItem+1);
556 unsigned int DepthLayout::GetReserveItemCount(Vector3 layoutSize) const
558 float itemsWithinLayout = (layoutSize.depth * mImpl->mNumberOfColumns) / (cosf(mImpl->mTiltAngle) * mImpl->mRowSpacing);
560 return static_cast<unsigned int>(itemsWithinLayout);
563 bool DepthLayout::GetItemSize(unsigned int itemId, Vector3 layoutSize, Vector3& itemSize) const
565 // Note: itemId is not checked, since every item has the same size
567 itemSize = mImpl->mItemSizeFunction( mImpl->mNumberOfColumns, (IsVertical(mOrientation) ? layoutSize.width : layoutSize.height) );
571 void DepthLayout::GetResizeAnimation(Animation& animation, Actor actor, Vector3 size, float durationSeconds) const
575 animation.Resize(actor, size);
579 bool DepthLayout::GetPositionConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
581 float heightScale = -sinf(mImpl->mTiltAngle) * mImpl->mRowSpacing;
582 float depthScale = cosf(mImpl->mTiltAngle) * mImpl->mRowSpacing;
584 if (mOrientation == ControlOrientation::Up)
586 constraint = DepthPositionConstraint0( mImpl->mNumberOfColumns,
587 itemId % mImpl->mNumberOfColumns,
588 mImpl->mItemSizeFunction,
589 mImpl->mBottomMarginFunction,
590 mImpl->mColumnPositionFunction,
594 else if (mOrientation == ControlOrientation::Left)
596 constraint = DepthPositionConstraint90( mImpl->mNumberOfColumns,
597 itemId % mImpl->mNumberOfColumns,
598 mImpl->mItemSizeFunction,
599 mImpl->mBottomMarginFunction,
600 mImpl->mColumnPositionFunction,
604 else if (mOrientation == ControlOrientation::Down)
606 constraint = DepthPositionConstraint180( mImpl->mNumberOfColumns,
607 itemId % mImpl->mNumberOfColumns,
608 mImpl->mItemSizeFunction,
609 mImpl->mBottomMarginFunction,
610 mImpl->mColumnPositionFunction,
614 else // mOrientation == ControlOrientation::Right
616 constraint = DepthPositionConstraint270( mImpl->mNumberOfColumns,
617 itemId % mImpl->mNumberOfColumns,
618 mImpl->mItemSizeFunction,
619 mImpl->mBottomMarginFunction,
620 mImpl->mColumnPositionFunction,
628 bool DepthLayout::GetRotationConstraint(unsigned int itemId, ItemLayout::QuaternionFunction& constraint) const
630 if (mOrientation == ControlOrientation::Up)
632 constraint = DepthRotationConstraint0(mImpl->mItemTiltAngle);
634 else if (mOrientation == ControlOrientation::Left)
636 constraint = DepthRotationConstraint90(mImpl->mItemTiltAngle);
638 else if (mOrientation == ControlOrientation::Down)
640 constraint = DepthRotationConstraint180(mImpl->mItemTiltAngle);
642 else // mOrientation == ControlOrientation::Right
644 constraint = DepthRotationConstraint270(mImpl->mItemTiltAngle);
650 bool DepthLayout::GetScaleConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
652 return false; // No scaling
655 bool DepthLayout::GetColorConstraint(unsigned int itemId, ItemLayout::Vector4Function& constraint) const
657 constraint = DepthColorConstraint(mImpl->mNumberOfColumns, mImpl->mNumberOfRows*0.5f, itemId % mImpl->mNumberOfColumns);
661 bool DepthLayout::GetVisibilityConstraint(unsigned int itemId, ItemLayout::BoolFunction& constraint) const
663 constraint = DepthVisibilityConstraint(mImpl->mNumberOfColumns, mImpl->mNumberOfRows*0.5f, itemId % mImpl->mNumberOfColumns);
667 Degree DepthLayout::GetScrollDirection() const
669 Degree scrollDirection(0.0f);
671 if (mOrientation == ControlOrientation::Up)
673 scrollDirection = 180.0f;
675 else if (mOrientation == ControlOrientation::Left)
677 scrollDirection = 270.0f;
679 else if (mOrientation == ControlOrientation::Down)
681 scrollDirection = 0.0f;
683 else // mOrientation == ControlOrientation::Right
685 scrollDirection = 90.0f;
688 return scrollDirection;
691 DepthLayout::DepthLayout()
697 float DepthLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
699 float scrollTo = currentLayoutPosition;
700 float row = (currentLayoutPosition + itemID - static_cast<float>(itemID % mImpl->mNumberOfColumns)) / mImpl->mNumberOfColumns;
702 // Check whether item is not within viewable area
705 scrollTo = GetItemScrollToPosition(itemID);
707 else if(row > mImpl->mNumberOfRows * 0.5f - 1.0f)
709 scrollTo = GetItemScrollToPosition(itemID) + (mImpl->mNumberOfRows - 1.0f) * 0.5f * mImpl->mNumberOfColumns;
715 int DepthLayout::GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
724 itemID = loopEnabled ? maxItems - 1 : 0;
730 itemID += mImpl->mNumberOfColumns;
731 if( itemID >= maxItems )
733 itemID = loopEnabled ? 0 : itemID - mImpl->mNumberOfColumns;
740 if( itemID >= maxItems )
742 itemID = loopEnabled ? 0 : maxItems - 1;
748 itemID -= mImpl->mNumberOfColumns;
751 itemID = loopEnabled ? itemID + maxItems : itemID + mImpl->mNumberOfColumns;
759 } // namespace Toolkit