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;
29 namespace // unnamed namespace
32 const unsigned int DEFAULT_NUMBER_OF_COLUMNS = 3;
33 const float DEFAULT_NUMBER_OF_ROWS = 20.0f;
34 const float DEFAULT_ROW_SPACING = 55.0f;
35 const float DEFAULT_BOTTOM_MARGIN_FACTOR = 0.1f;
36 const Radian DEFAULT_TILT_ANGLE ( Math::PI*0.12f );
37 const Radian DEFAULT_ITEM_TILT_ANGLE ( -Math::PI*0.025f );
38 const float DEFAULT_SCROLL_SPEED_FACTOR = 0.02f;
39 const float DEFAULT_MAXIMUM_SWIPE_SPEED = 50.0f;
40 const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.03f;
42 static Vector3 GetItemSizeDefaultFunction(unsigned int numberOfColumns, float layoutWidth)
44 float width = layoutWidth / static_cast<float>(numberOfColumns + 1);
47 return Vector3(width, width, width);
50 static float GetBottomMarginDefaultFunction(float layoutHeight)
52 return layoutHeight * DEFAULT_BOTTOM_MARGIN_FACTOR;
55 struct GetColumnPositionDefaultFunction
57 float operator()(unsigned int numberOfColumns,
58 unsigned int columnNumber,
59 const Vector3& itemSize,
62 // Share the available space between margins & column spacings
63 float availableSpace = max(0.0f, (layoutWidth - itemSize.width*numberOfColumns));
65 float leftMargin = availableSpace/numberOfColumns * 0.5f;
67 float columnPosition = leftMargin + itemSize.width*0.5f + columnNumber*(itemSize.width + availableSpace/numberOfColumns);
69 return columnPosition - layoutWidth*0.5f;
73 struct DepthPositionConstraint0
75 DepthPositionConstraint0(unsigned int numberOfColumns,
76 unsigned int columnNumber,
77 DepthLayout::ItemSizeFunction itemSizeFunction,
78 DepthLayout::BottomMarginFunction bottomMarginFunction,
79 DepthLayout::ColumnPositionFunction columnPositionFunction,
82 : mNumberOfColumns(numberOfColumns),
83 mColumnNumber(columnNumber),
84 mItemSizeFunction(itemSizeFunction),
85 mBottomMarginFunction(bottomMarginFunction),
86 mColumnPositionFunction(columnPositionFunction),
87 mHeightScale(heightScale),
88 mDepthScale(depthScale)
92 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
94 Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.width);
96 float rowLayoutPositon = layoutPosition - static_cast<float>(mColumnNumber);
98 return Vector3( mColumnPositionFunction(mNumberOfColumns, mColumnNumber, itemSize, layoutSize.width),
99 rowLayoutPositon*mHeightScale + layoutSize.height*0.5f - mBottomMarginFunction(layoutSize.height) - itemSize.height * 0.5f,
100 -rowLayoutPositon*mDepthScale );
103 unsigned int mNumberOfColumns;
104 unsigned int mColumnNumber;
106 DepthLayout::ItemSizeFunction mItemSizeFunction;
107 DepthLayout::BottomMarginFunction mBottomMarginFunction;
108 DepthLayout::ColumnPositionFunction mColumnPositionFunction;
114 struct DepthPositionConstraint90
116 DepthPositionConstraint90(unsigned int numberOfColumns,
117 unsigned int columnNumber,
118 DepthLayout::ItemSizeFunction itemSizeFunction,
119 DepthLayout::BottomMarginFunction bottomMarginFunction,
120 DepthLayout::ColumnPositionFunction columnPositionFunction,
123 : mNumberOfColumns(numberOfColumns),
124 mColumnNumber(columnNumber),
125 mItemSizeFunction(itemSizeFunction),
126 mBottomMarginFunction(bottomMarginFunction),
127 mColumnPositionFunction(columnPositionFunction),
128 mHeightScale(heightScale),
129 mDepthScale(depthScale)
133 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
135 Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.height);
137 float rowLayoutPositon = layoutPosition - static_cast<float>(mColumnNumber) + mNumberOfColumns*0.5f;
139 return Vector3( rowLayoutPositon*mHeightScale + layoutSize.width*0.5f - mBottomMarginFunction(layoutSize.width) - itemSize.height * 0.5f,
140 -mColumnPositionFunction(mNumberOfColumns, mColumnNumber, itemSize, layoutSize.height),
141 -rowLayoutPositon*mDepthScale );
144 unsigned int mNumberOfColumns;
145 unsigned int mColumnNumber;
147 DepthLayout::ItemSizeFunction mItemSizeFunction;
148 DepthLayout::BottomMarginFunction mBottomMarginFunction;
149 DepthLayout::ColumnPositionFunction mColumnPositionFunction;
155 struct DepthPositionConstraint180
157 DepthPositionConstraint180(unsigned int numberOfColumns,
158 unsigned int columnNumber,
159 DepthLayout::ItemSizeFunction itemSizeFunction,
160 DepthLayout::BottomMarginFunction bottomMarginFunction,
161 DepthLayout::ColumnPositionFunction columnPositionFunction,
164 : mNumberOfColumns(numberOfColumns),
165 mColumnNumber(columnNumber),
166 mItemSizeFunction(itemSizeFunction),
167 mBottomMarginFunction(bottomMarginFunction),
168 mColumnPositionFunction(columnPositionFunction),
169 mHeightScale(heightScale),
170 mDepthScale(depthScale)
174 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
176 Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.width);
178 float rowLayoutPositon = layoutPosition - static_cast<float>(mColumnNumber);
180 return Vector3( -mColumnPositionFunction(mNumberOfColumns, mColumnNumber, itemSize, layoutSize.width),
181 -(rowLayoutPositon*mHeightScale + layoutSize.height*0.5f - mBottomMarginFunction(layoutSize.height) - itemSize.height * 0.5f),
182 -rowLayoutPositon*mDepthScale );
185 unsigned int mNumberOfColumns;
186 unsigned int mColumnNumber;
188 DepthLayout::ItemSizeFunction mItemSizeFunction;
189 DepthLayout::BottomMarginFunction mBottomMarginFunction;
190 DepthLayout::ColumnPositionFunction mColumnPositionFunction;
196 struct DepthPositionConstraint270
198 DepthPositionConstraint270(unsigned int numberOfColumns,
199 unsigned int columnNumber,
200 DepthLayout::ItemSizeFunction itemSizeFunction,
201 DepthLayout::BottomMarginFunction bottomMarginFunction,
202 DepthLayout::ColumnPositionFunction columnPositionFunction,
205 : mNumberOfColumns(numberOfColumns),
206 mColumnNumber(columnNumber),
207 mItemSizeFunction(itemSizeFunction),
208 mBottomMarginFunction(bottomMarginFunction),
209 mColumnPositionFunction(columnPositionFunction),
210 mHeightScale(heightScale),
211 mDepthScale(depthScale)
215 Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
217 Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.height);
219 float rowLayoutPositon = layoutPosition - static_cast<float>(mColumnNumber) + mNumberOfColumns*0.5f;
221 return Vector3( -(rowLayoutPositon*mHeightScale + layoutSize.width*0.5f - mBottomMarginFunction(layoutSize.width) - itemSize.height * 0.5f),
222 mColumnPositionFunction(mNumberOfColumns, mColumnNumber, itemSize, layoutSize.height),
223 -rowLayoutPositon*mDepthScale );
226 unsigned int mNumberOfColumns;
227 unsigned int mColumnNumber;
229 DepthLayout::ItemSizeFunction mItemSizeFunction;
230 DepthLayout::BottomMarginFunction mBottomMarginFunction;
231 DepthLayout::ColumnPositionFunction mColumnPositionFunction;
237 struct DepthRotationConstraint0
239 DepthRotationConstraint0(float angleRadians)
240 : mTiltAngle(angleRadians)
244 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
246 return Quaternion(0.0f, Vector3::ZAXIS) * Quaternion(mTiltAngle, Vector3::XAXIS);
252 struct DepthRotationConstraint90
254 DepthRotationConstraint90(float angleRadians)
255 : mTiltAngle(angleRadians)
259 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
261 return Quaternion(1.5f * Math::PI, Vector3::ZAXIS) * Quaternion(mTiltAngle, Vector3::XAXIS);
267 struct DepthRotationConstraint180
269 DepthRotationConstraint180(float angleRadians)
270 : mTiltAngle(angleRadians)
274 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
276 return Quaternion(-Math::PI, Vector3::ZAXIS) * Quaternion(mTiltAngle, Vector3::XAXIS);
282 struct DepthRotationConstraint270
284 DepthRotationConstraint270(float angleRadians)
285 : mTiltAngle(angleRadians)
289 Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
291 return Quaternion(0.5f * Math::PI, Vector3::ZAXIS) * Quaternion(mTiltAngle, Vector3::XAXIS);
297 struct DepthColorConstraint
299 DepthColorConstraint(unsigned int numberOfColumns, float numberOfRows, unsigned int columnNumber)
300 : mNumberOfColumns(numberOfColumns),
301 mNumberOfRows(numberOfRows),
302 mColumnNumber(columnNumber)
306 Vector4 operator()(const Vector4& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
308 float row = (layoutPosition - static_cast<float>(mColumnNumber)) / mNumberOfColumns;
310 float darkness(1.0f);
315 darkness = alpha = max(0.0f, 1.0f + row);
319 if (row > mNumberOfRows)
325 darkness = 1.0f - ( 1.0f * (row / mNumberOfRows) );
328 if (row > (mNumberOfRows-1.0f))
330 alpha = max(0.0f, 1.0f - (row-(mNumberOfRows-1.0f)));
334 return Vector4( darkness, darkness, darkness, current.a * alpha );
337 unsigned int mNumberOfColumns;
339 unsigned int mColumnNumber;
342 struct DepthVisibilityConstraint
344 DepthVisibilityConstraint(unsigned int numberOfColumns, float numberOfRows, unsigned int columnNumber)
345 : mNumberOfColumns(numberOfColumns),
346 mNumberOfRows(numberOfRows),
347 mColumnNumber(columnNumber)
351 bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
353 float row = (layoutPosition - static_cast<float>(mColumnNumber)) / mNumberOfColumns;
354 return (row > -1.0f) && (row < mNumberOfRows);
357 unsigned int mNumberOfColumns;
359 unsigned int mColumnNumber;
362 } // unnamed namespace
370 struct PositionConstraintSet
372 ItemLayout::Vector3Function mOrientation0;
373 ItemLayout::Vector3Function mOrientation90;
374 ItemLayout::Vector3Function mOrientation180;
375 ItemLayout::Vector3Function mOrientation270;
378 struct DepthLayout::Impl
381 : mNumberOfColumns(DEFAULT_NUMBER_OF_COLUMNS),
382 mNumberOfRows(DEFAULT_NUMBER_OF_ROWS),
383 mRowSpacing(DEFAULT_ROW_SPACING),
384 mTiltAngle(DEFAULT_TILT_ANGLE),
385 mItemTiltAngle(DEFAULT_ITEM_TILT_ANGLE),
386 mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
387 mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
388 mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION),
389 mItemSizeFunction(GetItemSizeDefaultFunction),
390 mBottomMarginFunction(GetBottomMarginDefaultFunction),
391 mColumnPositionFunction(GetColumnPositionDefaultFunction())
395 unsigned int mNumberOfColumns;
396 unsigned int mNumberOfRows;
401 Radian mItemTiltAngle;
403 float mScrollSpeedFactor;
404 float mMaximumSwipeSpeed;
405 float mItemFlickAnimationDuration;
407 ItemSizeFunction mItemSizeFunction;
408 BottomMarginFunction mBottomMarginFunction;
409 ColumnPositionFunction mColumnPositionFunction;
412 DepthLayoutPtr DepthLayout::New()
414 return DepthLayoutPtr(new DepthLayout());
417 DepthLayout::~DepthLayout()
422 void DepthLayout::SetNumberOfColumns(unsigned int columns)
424 mImpl->mNumberOfColumns = columns;
427 unsigned int DepthLayout::GetNumberOfColumns() const
429 return mImpl->mNumberOfColumns;
432 void DepthLayout::SetNumberOfRows(unsigned int rows)
434 mImpl->mNumberOfRows = rows;
437 unsigned int DepthLayout::GetNumberOfRows() const
439 return mImpl->mNumberOfRows;
442 void DepthLayout::SetRowSpacing(float spacing)
444 mImpl->mRowSpacing = spacing;
447 float DepthLayout::GetRowSpacing() const
449 return mImpl->mRowSpacing;
452 void DepthLayout::SetTiltAngle(Degree angle)
454 mImpl->mTiltAngle = Degree( Clamp<float>(angle, -45.0f, 45.0f) );
457 Degree DepthLayout::GetTiltAngle() const
459 return mImpl->mTiltAngle;
462 void DepthLayout::SetItemSizeFunction(ItemSizeFunction function)
464 mImpl->mItemSizeFunction = function;
467 DepthLayout::ItemSizeFunction DepthLayout::GetItemSizeFunction() const
469 return mImpl->mItemSizeFunction;
472 void DepthLayout::SetBottomMarginFunction(BottomMarginFunction function)
474 mImpl->mBottomMarginFunction = function;
477 DepthLayout::BottomMarginFunction DepthLayout::GetBottomMarginFunction() const
479 return mImpl->mBottomMarginFunction;
482 void DepthLayout::SetItemTiltAngle(Degree angle)
484 mImpl->mItemTiltAngle = angle;
487 Degree DepthLayout::GetItemTiltAngle() const
489 return mImpl->mItemTiltAngle;
492 void DepthLayout::SetColumnPositionFunction(ColumnPositionFunction function)
494 mImpl->mColumnPositionFunction = function;
497 DepthLayout::ColumnPositionFunction DepthLayout::GetColumnPositionFunction() const
499 return mImpl->mColumnPositionFunction;
502 void DepthLayout::SetScrollSpeedFactor(float scrollSpeed)
504 mImpl->mScrollSpeedFactor = scrollSpeed;
507 void DepthLayout::SetMaximumSwipeSpeed(float speed)
509 mImpl->mMaximumSwipeSpeed = speed;
512 void DepthLayout::SetItemFlickAnimationDuration(float durationSeconds)
514 mImpl->mItemFlickAnimationDuration = durationSeconds;
517 float DepthLayout::GetScrollSpeedFactor() const
519 return mImpl->mScrollSpeedFactor;
522 float DepthLayout::GetMaximumSwipeSpeed() const
524 return mImpl->mMaximumSwipeSpeed;
527 float DepthLayout::GetItemFlickAnimationDuration() const
529 return mImpl->mItemFlickAnimationDuration;
532 float DepthLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
534 return static_cast<float>(mImpl->mNumberOfColumns) - static_cast<float>(numberOfItems);
537 float DepthLayout::GetClosestAnchorPosition(float layoutPosition) const
539 float rowIndex = static_cast<float>(round(layoutPosition / mImpl->mNumberOfColumns));
540 return rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
543 float DepthLayout::GetItemScrollToPosition(unsigned int itemId) const
545 float rowIndex = static_cast<float>(itemId / mImpl->mNumberOfColumns);
546 return -rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
549 ItemRange DepthLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
551 float firstRow = -(firstItemPosition/mImpl->mNumberOfColumns);
552 float lastRow = firstRow + mImpl->mNumberOfRows * 0.5f;
554 unsigned int firstItem = static_cast<unsigned int>(max(0.0f, firstRow * mImpl->mNumberOfColumns));
555 unsigned int lastItem = static_cast<unsigned int>(max(0.0f, lastRow * mImpl->mNumberOfColumns));
557 return ItemRange(firstItem, lastItem+1);
560 unsigned int DepthLayout::GetReserveItemCount(Vector3 layoutSize) const
562 float itemsWithinLayout = (layoutSize.depth * mImpl->mNumberOfColumns) / (cosf(mImpl->mTiltAngle) * mImpl->mRowSpacing);
564 return static_cast<unsigned int>(itemsWithinLayout);
567 bool DepthLayout::GetItemSize(unsigned int itemId, Vector3 layoutSize, Vector3& itemSize) const
569 // Note: itemId is not checked, since every item has the same size
571 itemSize = mImpl->mItemSizeFunction( mImpl->mNumberOfColumns, (IsVertical(mOrientation) ? layoutSize.width : layoutSize.height) );
575 void DepthLayout::GetResizeAnimation(Animation& animation, Actor actor, Vector3 size, float durationSeconds) const
579 animation.Resize(actor, size);
583 bool DepthLayout::GetPositionConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
585 float heightScale = -sinf(mImpl->mTiltAngle) * mImpl->mRowSpacing;
586 float depthScale = cosf(mImpl->mTiltAngle) * mImpl->mRowSpacing;
588 if (mOrientation == ControlOrientation::Up)
590 constraint = DepthPositionConstraint0( mImpl->mNumberOfColumns,
591 itemId % mImpl->mNumberOfColumns,
592 mImpl->mItemSizeFunction,
593 mImpl->mBottomMarginFunction,
594 mImpl->mColumnPositionFunction,
598 else if (mOrientation == ControlOrientation::Left)
600 constraint = DepthPositionConstraint90( mImpl->mNumberOfColumns,
601 itemId % mImpl->mNumberOfColumns,
602 mImpl->mItemSizeFunction,
603 mImpl->mBottomMarginFunction,
604 mImpl->mColumnPositionFunction,
608 else if (mOrientation == ControlOrientation::Down)
610 constraint = DepthPositionConstraint180( mImpl->mNumberOfColumns,
611 itemId % mImpl->mNumberOfColumns,
612 mImpl->mItemSizeFunction,
613 mImpl->mBottomMarginFunction,
614 mImpl->mColumnPositionFunction,
618 else // mOrientation == ControlOrientation::Right
620 constraint = DepthPositionConstraint270( mImpl->mNumberOfColumns,
621 itemId % mImpl->mNumberOfColumns,
622 mImpl->mItemSizeFunction,
623 mImpl->mBottomMarginFunction,
624 mImpl->mColumnPositionFunction,
632 bool DepthLayout::GetRotationConstraint(unsigned int itemId, ItemLayout::QuaternionFunction& constraint) const
634 if (mOrientation == ControlOrientation::Up)
636 constraint = DepthRotationConstraint0(mImpl->mItemTiltAngle);
638 else if (mOrientation == ControlOrientation::Left)
640 constraint = DepthRotationConstraint90(mImpl->mItemTiltAngle);
642 else if (mOrientation == ControlOrientation::Down)
644 constraint = DepthRotationConstraint180(mImpl->mItemTiltAngle);
646 else // mOrientation == ControlOrientation::Right
648 constraint = DepthRotationConstraint270(mImpl->mItemTiltAngle);
654 bool DepthLayout::GetScaleConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
656 return false; // No scaling
659 bool DepthLayout::GetColorConstraint(unsigned int itemId, ItemLayout::Vector4Function& constraint) const
661 constraint = DepthColorConstraint(mImpl->mNumberOfColumns, mImpl->mNumberOfRows*0.5f, itemId % mImpl->mNumberOfColumns);
665 bool DepthLayout::GetVisibilityConstraint(unsigned int itemId, ItemLayout::BoolFunction& constraint) const
667 constraint = DepthVisibilityConstraint(mImpl->mNumberOfColumns, mImpl->mNumberOfRows*0.5f, itemId % mImpl->mNumberOfColumns);
671 Degree DepthLayout::GetScrollDirection() const
673 Degree scrollDirection(0.0f);
675 if (mOrientation == ControlOrientation::Up)
677 scrollDirection = 180.0f;
679 else if (mOrientation == ControlOrientation::Left)
681 scrollDirection = 270.0f;
683 else if (mOrientation == ControlOrientation::Down)
685 scrollDirection = 0.0f;
687 else // mOrientation == ControlOrientation::Right
689 scrollDirection = 90.0f;
692 return scrollDirection;
695 DepthLayout::DepthLayout()
701 float DepthLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
703 float scrollTo = currentLayoutPosition;
704 float row = (currentLayoutPosition + itemID - static_cast<float>(itemID % mImpl->mNumberOfColumns)) / mImpl->mNumberOfColumns;
706 // Check whether item is not within viewable area
709 scrollTo = GetItemScrollToPosition(itemID);
711 else if(row > mImpl->mNumberOfRows * 0.5f - 1.0f)
713 scrollTo = GetItemScrollToPosition(itemID) + (mImpl->mNumberOfRows - 1.0f) * 0.5f * mImpl->mNumberOfColumns;
719 int DepthLayout::GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
728 itemID = loopEnabled ? maxItems - 1 : 0;
734 itemID += mImpl->mNumberOfColumns;
735 if( itemID >= maxItems )
737 itemID = loopEnabled ? 0 : itemID - mImpl->mNumberOfColumns;
744 if( itemID >= maxItems )
746 itemID = loopEnabled ? 0 : maxItems - 1;
752 itemID -= mImpl->mNumberOfColumns;
755 itemID = loopEnabled ? itemID + maxItems : itemID + mImpl->mNumberOfColumns;
763 } // namespace Toolkit