2 * Copyright (c) 2018 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.
18 #include <dali-toolkit/internal/layouting/grid-impl.h>
21 #include <dali/integration-api/debug.h>
22 #include <dali/public-api/common/extents.h>
23 #include <dali/public-api/actors/actor.h>
26 #include <dali-toolkit/devel-api/layouting/layout-item.h>
27 #include <dali-toolkit/public-api/controls/control-impl.h>
28 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
29 #include <dali-toolkit/devel-api/layouting/layout-length.h>
30 #include <dali-toolkit/internal/layouting/grid-locations.h>
32 #if defined(DEBUG_ENABLED)
33 static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_LAYOUT" );
45 GridPtr layout( new Grid() );
53 mNumColumns( AUTO_FIT ),
55 mRequestedColumnWidth( 0 ),
56 mRequestedNumColumns( AUTO_FIT )
58 mLocations = GridLocations::New();
63 void Grid::SetNumberOfColumns( int columns )
65 mRequestedNumColumns = columns;
66 // Store value and Relayout if changed.
67 if( columns != mNumColumns )
69 mNumColumns = columns;
74 int Grid::GetNumberOfColumns() const
79 void Grid::DetermineNumberOfColumns( int availableSpace )
81 if( mRequestedNumColumns == AUTO_FIT )
83 if( availableSpace > 0 )
85 // Can only calculate number of columns if a column width has been set
86 mNumColumns = ( mRequestedColumnWidth > 0 ) ? ( availableSpace / mRequestedColumnWidth ) : 1;
91 void Grid::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
93 DALI_LOG_STREAM( gLogFilter, Debug::Verbose,
94 "Grid::OnMeasure Actor Id:" << Actor::DownCast(GetOwner()).GetId() <<
95 " Owner:" << Actor::DownCast(GetOwner()).GetName() <<
96 " MeasureSpecs( width:"<<widthMeasureSpec<<", height:"<<heightMeasureSpec );
98 auto gridWidthMode = widthMeasureSpec.GetMode();
99 auto gridHeightMode = heightMeasureSpec.GetMode();
100 LayoutLength widthSize = widthMeasureSpec.GetSize();
101 LayoutLength heightSize = heightMeasureSpec.GetSize();
103 int availableContentWidth(0);
104 int availableContentHeight(0);
106 LayoutLength desiredChildHeight( 0 );
107 LayoutLength desiredChildWidth( 0 );
109 Extents gridLayoutPadding = GetPadding();
111 auto childCount = GetChildCount();
113 // WIDTH SPECIFICATIONS
115 // measure first child and use it's dimensions for layout measurement
116 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Grid::OnMeasure MeasureSpec::Mode::EXACTLY or MeasureSpec::Mode::AT_MOST \n" );
120 auto childLayoutItem = GetChildAt( 0 );
121 if( childLayoutItem )
123 auto childOwner = childLayoutItem->GetOwner();
125 MeasureChild( childLayoutItem, widthMeasureSpec, heightMeasureSpec );
126 desiredChildHeight = childLayoutItem->GetMeasuredHeight();
127 desiredChildWidth = childLayoutItem->GetMeasuredWidth();
129 // If child has a margin then add it to desired size
130 Extents childMargin = childOwner.GetProperty<Extents>( Toolkit::Control::Property::MARGIN );
131 desiredChildHeight += childMargin.top + childMargin.bottom;
132 desiredChildWidth += childMargin.start + childMargin.end;
134 mTotalWidth = desiredChildWidth * mNumColumns;
135 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Grid::OnMeasure TotalDesiredWidth(%d) \n", mTotalWidth.mValue );
136 } // Child is LayoutItem
139 // Include padding for max and min checks
140 mTotalWidth += gridLayoutPadding.start + gridLayoutPadding.end;
142 // Ensure width does not exceed specified atmost width or less than mininum width
143 mTotalWidth = std::max( mTotalWidth, GetSuggestedMinimumWidth() );
145 // widthMode EXACTLY so grid must be the given width
146 if( gridWidthMode == MeasureSpec::Mode::EXACTLY || gridWidthMode == MeasureSpec::Mode::AT_MOST )
148 // In the case of AT_MOST, widthSize is the max limit.
149 mTotalWidth = std::min( mTotalWidth, widthSize );
152 availableContentWidth = mTotalWidth - gridLayoutPadding.start - gridLayoutPadding.end;
153 widthSize = mTotalWidth;
155 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Grid::OnMeasure availableContentWidth(%d) mTotalWidth(%d) \n",
156 availableContentWidth,
157 mTotalWidth.mValue );
158 // HEIGHT SPECIFICATIONS
160 // heightMode EXACTLY so grid must be the given height
161 if( gridHeightMode == MeasureSpec::Mode::EXACTLY || gridHeightMode == MeasureSpec::Mode::AT_MOST )
165 mTotalHeight = gridLayoutPadding.top + gridLayoutPadding.bottom;
167 for( auto i = 0u; i < childCount; i += mNumColumns )
169 mTotalHeight += desiredChildHeight;
171 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Grid::OnMeasure TotalDesiredHeight(%d) \n",
172 mTotalHeight.mValue );
174 // Ensure ourHeight does not exceed specified atmost height
175 mTotalHeight = std::min( mTotalHeight, heightSize );
176 mTotalHeight = std::max( mTotalHeight, GetSuggestedMinimumHeight() );
178 heightSize = mTotalHeight;
181 // In the case of AT_MOST, availableContentHeigth is the max limit.
182 availableContentHeight = heightSize - gridLayoutPadding.top - gridLayoutPadding.bottom;
186 // Grid expands to fit content
188 // If number of columns AUTO_FIT then set to 1 column.
190 // Calculate numbers of rows, round down result as later check for remainder.
191 mNumRows = childCount / ( ( mNumColumns ) ? mNumColumns : 1 );
192 // If number of cells not cleanly dividable by colums, add another row to house remainder cells.
193 mNumRows += ( childCount % ( ( mNumColumns ) ? mNumColumns : 1 ) ) ? 1 : 0;
195 availableContentHeight = desiredChildHeight * mNumRows;
198 // If number of columns not defined
199 DetermineNumberOfColumns( availableContentWidth );
201 // Locations define the start, end,top and bottom of each cell.
202 mLocations->CalculateLocations( mNumColumns, availableContentWidth, availableContentHeight, childCount, 0, 0 );
205 SetMeasuredDimensions( ResolveSizeAndState( widthSize, widthMeasureSpec, MeasuredSize::State::MEASURED_SIZE_OK ),
206 ResolveSizeAndState( heightSize, heightMeasureSpec, MeasuredSize::State::MEASURED_SIZE_OK ) );
209 void Grid::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
211 auto owner = GetOwner();
212 auto actor = Actor::DownCast(owner);
213 auto count = GetChildCount();
215 GridLocations::LocationVector locations = mLocations->GetLocations();
217 Extents gridLayoutPadding = GetPadding();
218 Extents childMargins;
220 // Margin for all children dependant on if set on first child
223 LayoutItemPtr childLayout = GetChildAt( 0 );
226 auto childOwner = childLayout->GetOwner();
229 childMargins = childOwner.GetProperty<Extents>( Toolkit::Control::Property::MARGIN );
234 for( unsigned int i = 0; i < count; i++)
238 LayoutItemPtr childLayout = GetChildAt( childIndex );
239 if( childLayout != nullptr )
241 // Get start and end position of child x1,x2
242 auto x1 = locations[ i ].xStart;
243 auto x2 = locations[ i ].xEnd;
245 // Get top and bottom position of child y1,y2
246 auto y1 = locations[ i ].yTop;
247 auto y2 = locations[ i ].yBottom;
249 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Grid::OnLayout cellSize(%d,%d) \n", x2 - x1, y2 - y1);
251 // Offset children by the grids padding if present
252 x1 += gridLayoutPadding.start;
253 x2 += gridLayoutPadding.start;
254 y1 += gridLayoutPadding.top;
255 y2 += gridLayoutPadding.top;
257 // Offset children by the margin of the first child ( if required ).
258 x1 += childMargins.start;
259 x2 -= childMargins.end;
260 y1 += childMargins.top;
261 y2 -= childMargins.bottom;
263 childLayout->Layout( x1, y1, x2, y2 );
268 } // namespace Internal
269 } // namespace Toolkit