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/depth-layout.h>
23 #include <dali/public-api/animation/animation.h>
26 using namespace Dali::Toolkit;
28 namespace // unnamed namespace
31 const unsigned int DEFAULT_NUMBER_OF_COLUMNS = 3;
32 const float DEFAULT_NUMBER_OF_ROWS = 20.0f;
33 const float DEFAULT_ROW_SPACING = 55.0f;
34 const float DEFAULT_BOTTOM_MARGIN_FACTOR = 0.1f;
35 const Radian DEFAULT_TILT_ANGLE ( Math::PI*0.12f );
36 const Radian DEFAULT_ITEM_TILT_ANGLE ( -Math::PI*0.025f );
37 const float DEFAULT_SCROLL_SPEED_FACTOR = 0.02f;
38 const float DEFAULT_MAXIMUM_SWIPE_SPEED = 50.0f;
39 const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.03f;
41 static Vector3 GetItemSizeDefaultFunction(unsigned int numberOfColumns, float layoutWidth)
43 float width = layoutWidth / static_cast<float>(numberOfColumns + 1);
46 return Vector3(width, width, width);
49 static float GetBottomMarginDefaultFunction(float layoutHeight)
51 return layoutHeight * DEFAULT_BOTTOM_MARGIN_FACTOR;
54 struct GetColumnPositionDefaultFunction
56 float operator()(unsigned int numberOfColumns,
57 unsigned int columnNumber,
58 const Vector3& itemSize,
61 // Share the available space between margins & column spacings
62 float availableSpace = std::max(0.0f, (layoutWidth - itemSize.width*numberOfColumns));
64 float leftMargin = availableSpace/numberOfColumns * 0.5f;
66 float columnPosition = leftMargin + itemSize.width*0.5f + columnNumber*(itemSize.width + availableSpace/numberOfColumns);
68 return columnPosition - layoutWidth*0.5f;
72 struct DepthPositionConstraint0
74 DepthPositionConstraint0(unsigned int numberOfColumns,
75 unsigned int columnNumber,
76 DepthLayout::ItemSizeFunction itemSizeFunction,
77 DepthLayout::BottomMarginFunction bottomMarginFunction,
78 DepthLayout::ColumnPositionFunction columnPositionFunction,
81 : mNumberOfColumns(numberOfColumns),
82 mColumnNumber(columnNumber),
83 mItemSizeFunction(itemSizeFunction),
84 mBottomMarginFunction(bottomMarginFunction),
85 mColumnPositionFunction(columnPositionFunction),
86 mHeightScale(heightScale),
87 mDepthScale(depthScale)
91 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
93 Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.width);
95 float rowLayoutPositon = layoutPosition - static_cast<float>(mColumnNumber);
97 return Vector3( mColumnPositionFunction(mNumberOfColumns, mColumnNumber, itemSize, layoutSize.width),
98 rowLayoutPositon*mHeightScale + layoutSize.height*0.5f - mBottomMarginFunction(layoutSize.height) - itemSize.height * 0.5f,
99 -rowLayoutPositon*mDepthScale );
102 unsigned int mNumberOfColumns;
103 unsigned int mColumnNumber;
105 DepthLayout::ItemSizeFunction mItemSizeFunction;
106 DepthLayout::BottomMarginFunction mBottomMarginFunction;
107 DepthLayout::ColumnPositionFunction mColumnPositionFunction;
113 struct DepthPositionConstraint90
115 DepthPositionConstraint90(unsigned int numberOfColumns,
116 unsigned int columnNumber,
117 DepthLayout::ItemSizeFunction itemSizeFunction,
118 DepthLayout::BottomMarginFunction bottomMarginFunction,
119 DepthLayout::ColumnPositionFunction columnPositionFunction,
122 : mNumberOfColumns(numberOfColumns),
123 mColumnNumber(columnNumber),
124 mItemSizeFunction(itemSizeFunction),
125 mBottomMarginFunction(bottomMarginFunction),
126 mColumnPositionFunction(columnPositionFunction),
127 mHeightScale(heightScale),
128 mDepthScale(depthScale)
132 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
134 Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.height);
136 float rowLayoutPositon = layoutPosition - static_cast<float>(mColumnNumber) + mNumberOfColumns*0.5f;
138 return Vector3( rowLayoutPositon*mHeightScale + layoutSize.width*0.5f - mBottomMarginFunction(layoutSize.width) - itemSize.height * 0.5f,
139 -mColumnPositionFunction(mNumberOfColumns, mColumnNumber, itemSize, layoutSize.height),
140 -rowLayoutPositon*mDepthScale );
143 unsigned int mNumberOfColumns;
144 unsigned int mColumnNumber;
146 DepthLayout::ItemSizeFunction mItemSizeFunction;
147 DepthLayout::BottomMarginFunction mBottomMarginFunction;
148 DepthLayout::ColumnPositionFunction mColumnPositionFunction;
154 struct DepthPositionConstraint180
156 DepthPositionConstraint180(unsigned int numberOfColumns,
157 unsigned int columnNumber,
158 DepthLayout::ItemSizeFunction itemSizeFunction,
159 DepthLayout::BottomMarginFunction bottomMarginFunction,
160 DepthLayout::ColumnPositionFunction columnPositionFunction,
163 : mNumberOfColumns(numberOfColumns),
164 mColumnNumber(columnNumber),
165 mItemSizeFunction(itemSizeFunction),
166 mBottomMarginFunction(bottomMarginFunction),
167 mColumnPositionFunction(columnPositionFunction),
168 mHeightScale(heightScale),
169 mDepthScale(depthScale)
173 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
175 Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.width);
177 float rowLayoutPositon = layoutPosition - static_cast<float>(mColumnNumber);
179 return Vector3( -mColumnPositionFunction(mNumberOfColumns, mColumnNumber, itemSize, layoutSize.width),
180 -(rowLayoutPositon*mHeightScale + layoutSize.height*0.5f - mBottomMarginFunction(layoutSize.height) - itemSize.height * 0.5f),
181 -rowLayoutPositon*mDepthScale );
184 unsigned int mNumberOfColumns;
185 unsigned int mColumnNumber;
187 DepthLayout::ItemSizeFunction mItemSizeFunction;
188 DepthLayout::BottomMarginFunction mBottomMarginFunction;
189 DepthLayout::ColumnPositionFunction mColumnPositionFunction;
195 struct DepthPositionConstraint270
197 DepthPositionConstraint270(unsigned int numberOfColumns,
198 unsigned int columnNumber,
199 DepthLayout::ItemSizeFunction itemSizeFunction,
200 DepthLayout::BottomMarginFunction bottomMarginFunction,
201 DepthLayout::ColumnPositionFunction columnPositionFunction,
204 : mNumberOfColumns(numberOfColumns),
205 mColumnNumber(columnNumber),
206 mItemSizeFunction(itemSizeFunction),
207 mBottomMarginFunction(bottomMarginFunction),
208 mColumnPositionFunction(columnPositionFunction),
209 mHeightScale(heightScale),
210 mDepthScale(depthScale)
214 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
216 Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.height);
218 float rowLayoutPositon = layoutPosition - static_cast<float>(mColumnNumber) + mNumberOfColumns*0.5f;
220 return Vector3( -(rowLayoutPositon*mHeightScale + layoutSize.width*0.5f - mBottomMarginFunction(layoutSize.width) - itemSize.height * 0.5f),
221 mColumnPositionFunction(mNumberOfColumns, mColumnNumber, itemSize, layoutSize.height),
222 -rowLayoutPositon*mDepthScale );
225 unsigned int mNumberOfColumns;
226 unsigned int mColumnNumber;
228 DepthLayout::ItemSizeFunction mItemSizeFunction;
229 DepthLayout::BottomMarginFunction mBottomMarginFunction;
230 DepthLayout::ColumnPositionFunction mColumnPositionFunction;
236 struct DepthRotationConstraint0
238 DepthRotationConstraint0(float angleRadians)
239 : mTiltAngle(angleRadians)
243 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
245 return Quaternion(0.0f, Vector3::ZAXIS) * Quaternion(mTiltAngle, Vector3::XAXIS);
251 struct DepthRotationConstraint90
253 DepthRotationConstraint90(float angleRadians)
254 : mTiltAngle(angleRadians)
258 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
260 return Quaternion(1.5f * Math::PI, Vector3::ZAXIS) * Quaternion(mTiltAngle, Vector3::XAXIS);
266 struct DepthRotationConstraint180
268 DepthRotationConstraint180(float angleRadians)
269 : mTiltAngle(angleRadians)
273 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
275 return Quaternion(-Math::PI, Vector3::ZAXIS) * Quaternion(mTiltAngle, Vector3::XAXIS);
281 struct DepthRotationConstraint270
283 DepthRotationConstraint270(float angleRadians)
284 : mTiltAngle(angleRadians)
288 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
290 return Quaternion(0.5f * Math::PI, Vector3::ZAXIS) * Quaternion(mTiltAngle, Vector3::XAXIS);
296 struct DepthColorConstraint
298 DepthColorConstraint(unsigned int numberOfColumns, float numberOfRows, unsigned int columnNumber)
299 : mNumberOfColumns(numberOfColumns),
300 mNumberOfRows(numberOfRows),
301 mColumnNumber(columnNumber)
305 Vector4 operator()(const Vector4& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
307 float row = (layoutPosition - static_cast<float>(mColumnNumber)) / mNumberOfColumns;
309 float darkness(1.0f);
314 darkness = alpha = std::max(0.0f, 1.0f + row);
318 if (row > mNumberOfRows)
324 darkness = 1.0f - ( 1.0f * (row / mNumberOfRows) );
327 if (row > (mNumberOfRows-1.0f))
329 alpha = std::max(0.0f, 1.0f - (row-(mNumberOfRows-1.0f)));
333 return Vector4( darkness, darkness, darkness, current.a * alpha );
336 unsigned int mNumberOfColumns;
338 unsigned int mColumnNumber;
341 struct DepthVisibilityConstraint
343 DepthVisibilityConstraint(unsigned int numberOfColumns, float numberOfRows, unsigned int columnNumber)
344 : mNumberOfColumns(numberOfColumns),
345 mNumberOfRows(numberOfRows),
346 mColumnNumber(columnNumber)
350 bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
352 float row = (layoutPosition - static_cast<float>(mColumnNumber)) / mNumberOfColumns;
353 return (row > -1.0f) && (row < mNumberOfRows);
356 unsigned int mNumberOfColumns;
358 unsigned int mColumnNumber;
361 } // unnamed namespace
369 struct PositionConstraintSet
371 ItemLayout::Vector3Function mOrientation0;
372 ItemLayout::Vector3Function mOrientation90;
373 ItemLayout::Vector3Function mOrientation180;
374 ItemLayout::Vector3Function mOrientation270;
377 struct DepthLayout::Impl
380 : mNumberOfColumns(DEFAULT_NUMBER_OF_COLUMNS),
381 mNumberOfRows(DEFAULT_NUMBER_OF_ROWS),
382 mRowSpacing(DEFAULT_ROW_SPACING),
383 mTiltAngle(DEFAULT_TILT_ANGLE),
384 mItemTiltAngle(DEFAULT_ITEM_TILT_ANGLE),
385 mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
386 mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
387 mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION),
388 mItemSizeFunction(GetItemSizeDefaultFunction),
389 mBottomMarginFunction(GetBottomMarginDefaultFunction),
390 mColumnPositionFunction(GetColumnPositionDefaultFunction())
394 unsigned int mNumberOfColumns;
395 unsigned int mNumberOfRows;
400 Radian mItemTiltAngle;
402 float mScrollSpeedFactor;
403 float mMaximumSwipeSpeed;
404 float mItemFlickAnimationDuration;
406 ItemSizeFunction mItemSizeFunction;
407 BottomMarginFunction mBottomMarginFunction;
408 ColumnPositionFunction mColumnPositionFunction;
411 DepthLayoutPtr DepthLayout::New()
413 return DepthLayoutPtr(new DepthLayout());
416 DepthLayout::~DepthLayout()
421 void DepthLayout::SetNumberOfColumns(unsigned int columns)
423 mImpl->mNumberOfColumns = columns;
426 unsigned int DepthLayout::GetNumberOfColumns() const
428 return mImpl->mNumberOfColumns;
431 void DepthLayout::SetNumberOfRows(unsigned int rows)
433 mImpl->mNumberOfRows = rows;
436 unsigned int DepthLayout::GetNumberOfRows() const
438 return mImpl->mNumberOfRows;
441 void DepthLayout::SetRowSpacing(float spacing)
443 mImpl->mRowSpacing = spacing;
446 float DepthLayout::GetRowSpacing() const
448 return mImpl->mRowSpacing;
451 void DepthLayout::SetTiltAngle(Degree angle)
453 mImpl->mTiltAngle = Degree( Clamp<float>(angle, -45.0f, 45.0f) );
456 Degree DepthLayout::GetTiltAngle() const
458 return mImpl->mTiltAngle;
461 void DepthLayout::SetItemSizeFunction(ItemSizeFunction function)
463 mImpl->mItemSizeFunction = function;
466 DepthLayout::ItemSizeFunction DepthLayout::GetItemSizeFunction() const
468 return mImpl->mItemSizeFunction;
471 void DepthLayout::SetBottomMarginFunction(BottomMarginFunction function)
473 mImpl->mBottomMarginFunction = function;
476 DepthLayout::BottomMarginFunction DepthLayout::GetBottomMarginFunction() const
478 return mImpl->mBottomMarginFunction;
481 void DepthLayout::SetItemTiltAngle(Degree angle)
483 mImpl->mItemTiltAngle = angle;
486 Degree DepthLayout::GetItemTiltAngle() const
488 return mImpl->mItemTiltAngle;
491 void DepthLayout::SetColumnPositionFunction(ColumnPositionFunction function)
493 mImpl->mColumnPositionFunction = function;
496 DepthLayout::ColumnPositionFunction DepthLayout::GetColumnPositionFunction() const
498 return mImpl->mColumnPositionFunction;
501 void DepthLayout::SetScrollSpeedFactor(float scrollSpeed)
503 mImpl->mScrollSpeedFactor = scrollSpeed;
506 void DepthLayout::SetMaximumSwipeSpeed(float speed)
508 mImpl->mMaximumSwipeSpeed = speed;
511 void DepthLayout::SetItemFlickAnimationDuration(float durationSeconds)
513 mImpl->mItemFlickAnimationDuration = durationSeconds;
516 float DepthLayout::GetScrollSpeedFactor() const
518 return mImpl->mScrollSpeedFactor;
521 float DepthLayout::GetMaximumSwipeSpeed() const
523 return mImpl->mMaximumSwipeSpeed;
526 float DepthLayout::GetItemFlickAnimationDuration() const
528 return mImpl->mItemFlickAnimationDuration;
531 float DepthLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
533 return static_cast<float>(mImpl->mNumberOfColumns) - static_cast<float>(numberOfItems);
536 float DepthLayout::GetClosestAnchorPosition(float layoutPosition) const
538 float rowIndex = static_cast<float>(round(layoutPosition / mImpl->mNumberOfColumns));
539 return rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
542 float DepthLayout::GetItemScrollToPosition(unsigned int itemId) const
544 float rowIndex = static_cast<float>(itemId / mImpl->mNumberOfColumns);
545 return -rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
548 ItemRange DepthLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
550 float firstRow = -(firstItemPosition/mImpl->mNumberOfColumns);
551 float lastRow = firstRow + mImpl->mNumberOfRows * 0.5f;
553 unsigned int firstItem = static_cast<unsigned int>(std::max(0.0f, firstRow * mImpl->mNumberOfColumns));
554 unsigned int lastItem = static_cast<unsigned int>(std::max(0.0f, lastRow * mImpl->mNumberOfColumns));
556 return ItemRange(firstItem, lastItem+1);
559 unsigned int DepthLayout::GetReserveItemCount(Vector3 layoutSize) const
561 float itemsWithinLayout = (layoutSize.depth * mImpl->mNumberOfColumns) / (cosf(mImpl->mTiltAngle) * mImpl->mRowSpacing);
563 return static_cast<unsigned int>(itemsWithinLayout);
566 bool DepthLayout::GetItemSize(unsigned int itemId, Vector3 layoutSize, Vector3& itemSize) const
568 // Note: itemId is not checked, since every item has the same size
570 itemSize = mImpl->mItemSizeFunction( mImpl->mNumberOfColumns, (IsVertical(mOrientation) ? layoutSize.width : layoutSize.height) );
574 void DepthLayout::GetResizeAnimation(Animation& animation, Actor actor, Vector3 size, float durationSeconds) const
578 animation.Resize(actor, size);
582 bool DepthLayout::GetPositionConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
584 float heightScale = -sinf(mImpl->mTiltAngle) * mImpl->mRowSpacing;
585 float depthScale = cosf(mImpl->mTiltAngle) * mImpl->mRowSpacing;
587 if (mOrientation == ControlOrientation::Up)
589 constraint = DepthPositionConstraint0( mImpl->mNumberOfColumns,
590 itemId % mImpl->mNumberOfColumns,
591 mImpl->mItemSizeFunction,
592 mImpl->mBottomMarginFunction,
593 mImpl->mColumnPositionFunction,
597 else if (mOrientation == ControlOrientation::Left)
599 constraint = DepthPositionConstraint90( mImpl->mNumberOfColumns,
600 itemId % mImpl->mNumberOfColumns,
601 mImpl->mItemSizeFunction,
602 mImpl->mBottomMarginFunction,
603 mImpl->mColumnPositionFunction,
607 else if (mOrientation == ControlOrientation::Down)
609 constraint = DepthPositionConstraint180( mImpl->mNumberOfColumns,
610 itemId % mImpl->mNumberOfColumns,
611 mImpl->mItemSizeFunction,
612 mImpl->mBottomMarginFunction,
613 mImpl->mColumnPositionFunction,
617 else // mOrientation == ControlOrientation::Right
619 constraint = DepthPositionConstraint270( mImpl->mNumberOfColumns,
620 itemId % mImpl->mNumberOfColumns,
621 mImpl->mItemSizeFunction,
622 mImpl->mBottomMarginFunction,
623 mImpl->mColumnPositionFunction,
631 bool DepthLayout::GetRotationConstraint(unsigned int itemId, ItemLayout::QuaternionFunction& constraint) const
633 if (mOrientation == ControlOrientation::Up)
635 constraint = DepthRotationConstraint0(mImpl->mItemTiltAngle);
637 else if (mOrientation == ControlOrientation::Left)
639 constraint = DepthRotationConstraint90(mImpl->mItemTiltAngle);
641 else if (mOrientation == ControlOrientation::Down)
643 constraint = DepthRotationConstraint180(mImpl->mItemTiltAngle);
645 else // mOrientation == ControlOrientation::Right
647 constraint = DepthRotationConstraint270(mImpl->mItemTiltAngle);
653 bool DepthLayout::GetScaleConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
655 return false; // No scaling
658 bool DepthLayout::GetColorConstraint(unsigned int itemId, ItemLayout::Vector4Function& constraint) const
660 constraint = DepthColorConstraint(mImpl->mNumberOfColumns, mImpl->mNumberOfRows*0.5f, itemId % mImpl->mNumberOfColumns);
664 bool DepthLayout::GetVisibilityConstraint(unsigned int itemId, ItemLayout::BoolFunction& constraint) const
666 constraint = DepthVisibilityConstraint(mImpl->mNumberOfColumns, mImpl->mNumberOfRows*0.5f, itemId % mImpl->mNumberOfColumns);
670 Degree DepthLayout::GetScrollDirection() const
672 Degree scrollDirection(0.0f);
674 if (mOrientation == ControlOrientation::Up)
676 scrollDirection = 180.0f;
678 else if (mOrientation == ControlOrientation::Left)
680 scrollDirection = 270.0f;
682 else if (mOrientation == ControlOrientation::Down)
684 scrollDirection = 0.0f;
686 else // mOrientation == ControlOrientation::Right
688 scrollDirection = 90.0f;
691 return scrollDirection;
694 DepthLayout::DepthLayout()
700 float DepthLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
702 float scrollTo = currentLayoutPosition;
703 float row = (currentLayoutPosition + itemID - static_cast<float>(itemID % mImpl->mNumberOfColumns)) / mImpl->mNumberOfColumns;
705 // Check whether item is not within viewable area
708 scrollTo = GetItemScrollToPosition(itemID);
710 else if(row > mImpl->mNumberOfRows * 0.5f - 1.0f)
712 scrollTo = GetItemScrollToPosition(itemID) + (mImpl->mNumberOfRows - 1.0f) * 0.5f * mImpl->mNumberOfColumns;
718 int DepthLayout::GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
727 itemID = loopEnabled ? maxItems - 1 : 0;
733 itemID += mImpl->mNumberOfColumns;
734 if( itemID >= maxItems )
736 itemID = loopEnabled ? 0 : itemID - mImpl->mNumberOfColumns;
743 if( itemID >= maxItems )
745 itemID = loopEnabled ? 0 : maxItems - 1;
751 itemID -= mImpl->mNumberOfColumns;
754 itemID = loopEnabled ? itemID + maxItems : itemID + mImpl->mNumberOfColumns;
762 } // namespace Toolkit