1 /* Copyright (c) 2019 Samsung Electronics Co., Ltd.
3 .* Licensed under the Apache License, Version 2.0 (the "License");
4 .* you may not use this file except in compliance with the License.
5 .* You may obtain a copy of the License at
7 .* http://www.apache.org/licenses/LICENSE-2.0
9 .* Unless required by applicable law or agreed to in writing, software
10 .* distributed under the License is distributed on an "AS IS" BASIS,
11 .* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 .* See the License for the specific language governing permissions and
13 .* limitations under the License.
18 using System.ComponentModel;
19 using System.Collections.Generic;
20 using Tizen.NUI.BaseComponents;
25 /// [Draft] This class implements a grid layout
27 public class GridLayout : LayoutGroup
29 const int AUTO_FIT = -1;
30 private int _columns = 1;
31 private int _rows = 1;
32 private int _totalWidth;
33 private int _totalHeight;
34 private int _requestedColumnWidth = 1;
35 private int _numberOfRequestedColumns;
36 private GridLocations _locations;
39 /// [draft] GridLayout Constructor/>
41 /// <returns> New Grid object.</returns>
42 /// <since_tizen> 6 </since_tizen>
45 _locations = new GridLocations();
49 /// [Draft] Get/Set the number of columns in the grid
51 /// <since_tizen> 6 </since_tizen>
66 /// [draft ] Sets the number of columns the GridLayout should have. />
68 /// <param name="columns">The number of columns.</param>
69 internal void SetColumns(int columns)
71 _numberOfRequestedColumns = columns;
72 if( columns != _columns)
74 _columns = Math.Max(1, _columns);
81 /// [draft ] Gets the number of columns in the Grid />
83 /// <returns>The number of columns in the Grid.</returns>
84 internal int GetColumns()
89 void DetermineNumberOfColumns( int availableSpace )
91 if( _numberOfRequestedColumns == AUTO_FIT )
93 if( availableSpace > 0 )
95 // Can only calculate number of columns if a column width has been set
96 _columns = ( _requestedColumnWidth > 0 ) ? ( availableSpace / _requestedColumnWidth ) : 1;
102 /// Measure the layout and its content to determine the measured width and the measured height.<br />
104 /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
105 /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
106 /// <since_tizen> 6 </since_tizen>
107 protected override void OnMeasure( MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec )
109 var gridWidthMode = widthMeasureSpec.Mode;
110 var gridHeightMode = heightMeasureSpec.Mode;
111 int widthSize = (int)widthMeasureSpec.Size.AsRoundedValue();
112 int heightSize = (int)heightMeasureSpec.Size.AsRoundedValue();
114 int availableContentWidth;
115 int availableContentHeight;
117 int desiredChildHeight;
118 int desiredChildWidth;
120 Extents gridLayoutPadding = Padding;
122 var childCount = LayoutChildren.Count;
124 // WIDTH SPECIFICATIONS
126 // measure first child and use it's dimensions for layout measurement
130 LayoutItem childLayoutItem = LayoutChildren[0];
131 View childOwner = childLayoutItem.Owner;
133 MeasureChild( childLayoutItem, widthMeasureSpec, heightMeasureSpec );
134 desiredChildHeight = (int)childLayoutItem.MeasuredHeight.Size.AsRoundedValue();
135 desiredChildWidth = (int)childLayoutItem.MeasuredWidth.Size.AsRoundedValue();
137 // If child has a margin then add it to desired size
138 Extents childMargin = childLayoutItem.Margin;
139 desiredChildHeight += childMargin.Top + childMargin.Bottom;
140 desiredChildWidth += childMargin.Start + childMargin.End;
142 _totalWidth = desiredChildWidth * _columns;
144 // Include padding for max and min checks
145 _totalWidth += gridLayoutPadding.Start + gridLayoutPadding.End;
147 // Ensure width does not exceed specified at most width or less than mininum width
148 _totalWidth = Math.Max( _totalWidth, (int)SuggestedMinimumWidth.AsRoundedValue() );
150 // widthMode EXACTLY so grid must be the given width
151 if( gridWidthMode == MeasureSpecification.ModeType.Exactly || gridWidthMode == MeasureSpecification.ModeType.AtMost )
153 // In the case of AT_MOST, widthSize is the max limit.
154 _totalWidth = Math.Min( _totalWidth, widthSize );
157 availableContentWidth = _totalWidth - gridLayoutPadding.Start - gridLayoutPadding.End;
158 widthSize = _totalWidth;
160 // HEIGHT SPECIFICATIONS
162 // heightMode EXACTLY so grid must be the given height
163 if( gridHeightMode == MeasureSpecification.ModeType.Exactly || gridHeightMode == MeasureSpecification.ModeType.AtMost )
167 _totalHeight = gridLayoutPadding.Top + gridLayoutPadding.Bottom;
169 for( int i = 0; i < childCount; i += _columns )
171 _totalHeight += desiredChildHeight;
174 // Ensure ourHeight does not exceed specified at most height
175 _totalHeight = Math.Min( _totalHeight, heightSize );
176 _totalHeight = Math.Max( _totalHeight, (int)SuggestedMinimumHeight.AsRoundedValue() );
178 heightSize = _totalHeight;
181 // In the case of AT_MOST, availableContentHeight 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.
189 _columns = ( _columns > 0 ) ? _columns : 1;
190 // Calculate numbers of rows, round down result as later check for remainder.
191 _rows = childCount / _columns;
192 // If number of cells not cleanly dividable by columns, add another row to house remainder cells.
193 _rows += ( childCount % _columns > 0 ) ? 1 : 0;
195 availableContentHeight = desiredChildHeight * _rows;
198 // If number of columns not defined
199 DetermineNumberOfColumns( availableContentWidth );
201 // Locations define the start, end,top and bottom of each cell.
202 _locations.CalculateLocations(_columns, availableContentWidth, availableContentHeight, childCount);
206 SetMeasuredDimensions( ResolveSizeAndState( new LayoutLength(widthSize), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK ),
207 ResolveSizeAndState( new LayoutLength(heightSize), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK ) );
211 /// Assign a size and position to each of its children.<br />
213 /// <param name="changed">This is a new size or position for this layout.</param>
214 /// <param name="left">Left position, relative to parent.</param>
215 /// <param name="top"> Top position, relative to parent.</param>
216 /// <param name="right">Right position, relative to parent.</param>
217 /// <param name="bottom">Bottom position, relative to parent.</param>
218 /// <since_tizen> 6 </since_tizen>
219 protected override void OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
221 List<GridLocations.Cell> locations = _locations.GetLocations();
223 Extents gridLayoutPadding = Padding;
224 Extents childMargins = new Extents();
226 // Margin for all children dependant on if set on first child
227 if( LayoutChildren.Count > 0 )
229 childMargins = LayoutChildren[0]?.Margin;
233 foreach( LayoutItem childLayout in LayoutChildren )
236 if( childLayout != null )
238 // Get start and end position of child x1,x2
239 int x1 = locations[ index ].Start;
240 int x2 = locations[ index ].End;
242 // Get top and bottom position of child y1,y2
243 int y1 = locations[ index ].Top;
244 int y2 = locations[ index ].Bottom;
246 // Offset children by the grids padding if present
247 x1 += gridLayoutPadding.Start;
248 x2 += gridLayoutPadding.Start;
249 y1 += gridLayoutPadding.Top;
250 y2 += gridLayoutPadding.Top;
252 // Offset children by the margin of the first child ( if required ).
253 x1 += childMargins.Start;
254 x2 -= childMargins.End;
255 y1 += childMargins.Top;
256 y2 -= childMargins.Bottom;
258 childLayout.Layout( new LayoutLength(x1), new LayoutLength(y1),
259 new LayoutLength(x2), new LayoutLength(y2) );