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 internal 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>
44 _locations = new GridLocations();
48 // [Draft] Get/Set the number of columns in the grid
64 /// [draft ] Sets the number of columns the GridLayout should have. />
66 /// <param name="columns">The number of columns.</param>
67 internal void SetColumns(int columns)
69 _numberOfRequestedColumns = columns;
70 if( columns != _columns)
72 _columns = Math.Max(1, _columns);
79 /// [draft ] Gets the number of columns in the Grid />
81 /// <returns>The number of columns in the Grid.</returns>
82 internal int GetColumns()
87 void DetermineNumberOfColumns( int availableSpace )
89 if( _numberOfRequestedColumns == AUTO_FIT )
91 if( availableSpace > 0 )
93 // Can only calculate number of columns if a column width has been set
94 _columns = ( _requestedColumnWidth > 0 ) ? ( availableSpace / _requestedColumnWidth ) : 1;
99 protected override void OnMeasure( MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec )
101 var gridWidthMode = widthMeasureSpec.Mode;
102 var gridHeightMode = heightMeasureSpec.Mode;
103 int widthSize = (int)widthMeasureSpec.Size.AsRoundedValue();
104 int heightSize = (int)heightMeasureSpec.Size.AsRoundedValue();
106 int availableContentWidth;
107 int availableContentHeight;
109 int desiredChildHeight;
110 int desiredChildWidth;
112 Extents gridLayoutPadding = Padding;
114 var childCount = _children.Count;
116 // WIDTH SPECIFICATIONS
118 // measure first child and use it's dimensions for layout measurement
122 LayoutItem childLayoutItem = _children[0];
123 View childOwner = childLayoutItem.Owner;
125 MeasureChild( childLayoutItem, widthMeasureSpec, heightMeasureSpec );
126 desiredChildHeight = (int)childLayoutItem.MeasuredHeight.Size.AsRoundedValue();
127 desiredChildWidth = (int)childLayoutItem.MeasuredWidth.Size.AsRoundedValue();
129 // If child has a margin then add it to desired size
130 Extents childMargin = childLayoutItem.Margin;
131 desiredChildHeight += childMargin.Top + childMargin.Bottom;
132 desiredChildWidth += childMargin.Start + childMargin.End;
134 _totalWidth = desiredChildWidth * _columns;
136 // Include padding for max and min checks
137 _totalWidth += gridLayoutPadding.Start + gridLayoutPadding.End;
139 // Ensure width does not exceed specified at most width or less than mininum width
140 _totalWidth = Math.Max( _totalWidth, (int)SuggestedMinimumWidth.AsRoundedValue() );
142 // widthMode EXACTLY so grid must be the given width
143 if( gridWidthMode == MeasureSpecification.ModeType.Exactly || gridWidthMode == MeasureSpecification.ModeType.AtMost )
145 // In the case of AT_MOST, widthSize is the max limit.
146 _totalWidth = Math.Min( _totalWidth, widthSize );
149 availableContentWidth = _totalWidth - gridLayoutPadding.Start - gridLayoutPadding.End;
150 widthSize = _totalWidth;
152 // HEIGHT SPECIFICATIONS
154 // heightMode EXACTLY so grid must be the given height
155 if( gridHeightMode == MeasureSpecification.ModeType.Exactly || gridHeightMode == MeasureSpecification.ModeType.AtMost )
159 _totalHeight = gridLayoutPadding.Top + gridLayoutPadding.Bottom;
161 for( int i = 0; i < childCount; i += _columns )
163 _totalHeight += desiredChildHeight;
166 // Ensure ourHeight does not exceed specified at most height
167 _totalHeight = Math.Min( _totalHeight, heightSize );
168 _totalHeight = Math.Max( _totalHeight, (int)SuggestedMinimumHeight.AsRoundedValue() );
170 heightSize = _totalHeight;
173 // In the case of AT_MOST, availableContentHeight is the max limit.
174 availableContentHeight = heightSize - gridLayoutPadding.Top - gridLayoutPadding.Bottom;
178 // Grid expands to fit content
180 // If number of columns AUTO_FIT then set to 1 column.
181 _columns = ( _columns > 0 ) ? _columns : 1;
182 // Calculate numbers of rows, round down result as later check for remainder.
183 _rows = childCount / _columns;
184 // If number of cells not cleanly dividable by columns, add another row to house remainder cells.
185 _rows += ( childCount % _columns > 0 ) ? 1 : 0;
187 availableContentHeight = desiredChildHeight * _rows;
190 // If number of columns not defined
191 DetermineNumberOfColumns( availableContentWidth );
193 // Locations define the start, end,top and bottom of each cell.
194 _locations.CalculateLocations(_columns, availableContentWidth, availableContentHeight, childCount);
198 SetMeasuredDimensions( ResolveSizeAndState( new LayoutLength(widthSize), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK ),
199 ResolveSizeAndState( new LayoutLength(heightSize), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK ) );
202 protected override void OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
204 List<GridLocations.Cell> locations = _locations.GetLocations();
206 Extents gridLayoutPadding = Padding;
207 Extents childMargins = new Extents();
209 // Margin for all children dependant on if set on first child
210 if( _children.Count > 0 )
212 childMargins = _children[0]?.Margin;
216 foreach( LayoutItem childLayout in _children )
219 if( childLayout != null )
221 // Get start and end position of child x1,x2
222 int x1 = locations[ index ].Start;
223 int x2 = locations[ index ].End;
225 // Get top and bottom position of child y1,y2
226 int y1 = locations[ index ].Top;
227 int y2 = locations[ index ].Bottom;
229 // Offset children by the grids padding if present
230 x1 += gridLayoutPadding.Start;
231 x2 += gridLayoutPadding.Start;
232 y1 += gridLayoutPadding.Top;
233 y2 += gridLayoutPadding.Top;
235 // Offset children by the margin of the first child ( if required ).
236 x1 += childMargins.Start;
237 x2 -= childMargins.End;
238 y1 += childMargins.Top;
239 y2 -= childMargins.Bottom;
241 childLayout.Layout( new LayoutLength(x1), new LayoutLength(y1),
242 new LayoutLength(x2), new LayoutLength(y2) );