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 Tizen.NUI.BaseComponents;
20 using Tizen.NUI.Binding;
25 /// GridLayout is a 2D grid pattern layout that consists of a set of rows and columns.
27 public partial class GridLayout : LayoutGroup
32 [EditorBrowsable(EditorBrowsableState.Never)]
33 public static readonly BindableProperty ColumnProperty = BindableProperty.CreateAttached("Column", typeof(int), typeof(GridLayout), AutoColumn, validateValue: (bindable, value) => (int)value >= 0 || (int)value == AutoColumn, propertyChanged: OnChildPropertyChanged);
36 /// ColumnSpanProperty
38 [EditorBrowsable(EditorBrowsableState.Never)]
39 public static readonly BindableProperty ColumnSpanProperty = BindableProperty.CreateAttached("ColumnSpan", typeof(int), typeof(GridLayout), 1, validateValue: (bindable, value) => (int)value >= 1, propertyChanged: OnChildPropertyChanged);
44 [EditorBrowsable(EditorBrowsableState.Never)]
45 public static readonly BindableProperty RowProperty = BindableProperty.CreateAttached("Row", typeof(int), typeof(GridLayout), AutoRow, validateValue: (bindable, value) => (int)value >= 0 || (int)value == AutoRow, propertyChanged: OnChildPropertyChanged);
50 [EditorBrowsable(EditorBrowsableState.Never)]
51 public static readonly BindableProperty RowSpanProperty = BindableProperty.CreateAttached("RowSpan", typeof(int), typeof(GridLayout), 1, validateValue: (bindable, value) => (int)value >= 1, propertyChanged: OnChildPropertyChanged);
54 /// HorizontalStretchProperty
56 [EditorBrowsable(EditorBrowsableState.Never)]
57 public static readonly BindableProperty HorizontalStretchProperty = BindableProperty.CreateAttached("HorizontalStretch", typeof(StretchFlags), typeof(GridLayout), default(StretchFlags), validateValue: ValidateEnum((int)StretchFlags.None, (int)StretchFlags.ExpandAndFill), propertyChanged: OnChildPropertyChanged);
60 /// VerticalStretchProperty
62 [EditorBrowsable(EditorBrowsableState.Never)]
63 public static readonly BindableProperty VerticalStretchProperty = BindableProperty.CreateAttached("VerticalStretch", typeof(StretchFlags), typeof(GridLayout), default(StretchFlags), validateValue: ValidateEnum((int)StretchFlags.None, (int)StretchFlags.ExpandAndFill), propertyChanged: OnChildPropertyChanged);
66 /// HorizontalAlignmentProperty
68 [EditorBrowsable(EditorBrowsableState.Never)]
69 public static readonly BindableProperty HorizontalAlignmentProperty = BindableProperty.CreateAttached("HorizontalAlignment", typeof(Alignment), typeof(GridLayout), Alignment.Start, validateValue: ValidateEnum((int)Alignment.Start, (int)Alignment.End), propertyChanged: OnChildPropertyChanged);
72 /// VerticalAlignmentProperty
74 [EditorBrowsable(EditorBrowsableState.Never)]
75 public static readonly BindableProperty VerticalAlignmentProperty = BindableProperty.CreateAttached("VerticalAlignment", typeof(Alignment), typeof(GridLayout), Alignment.Start, validateValue: ValidateEnum((int)Alignment.Start, (int)Alignment.End), propertyChanged: OnChildPropertyChanged);
78 [EditorBrowsable(EditorBrowsableState.Never)]
79 public const int AutoColumn = int.MinValue;
80 [EditorBrowsable(EditorBrowsableState.Never)]
81 public const int AutoRow = int.MinValue;
83 private Orientation gridOrientation = Orientation.Horizontal;
84 private int columns = 1;
86 private float columnSpacing = 0;
87 private float rowSpacing = 0;
90 /// Enumeration for the direction in which the content is laid out
92 /// <since_tizen> 8 </since_tizen>
93 public enum Orientation
100 /// Vertical (column)
106 /// Gets the column index.
108 /// <param name="view">The child view.</param>
109 /// <returns>The column index of <paramref name="view"/>.</returns>
110 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
111 /// <since_tizen> 8 </since_tizen>
112 public static int GetColumn(View view) => GetAttachedValue<int>(view, ColumnProperty);
115 /// Gets the column span.
117 /// <param name="view">The child view.</param>
118 /// <returns>The column span of <paramref name="view"/>.</returns>
119 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
120 /// <since_tizen> 8 </since_tizen>
121 public static int GetColumnSpan(View view) => GetAttachedValue<int>(view, ColumnSpanProperty);
124 /// Gets the row index.
126 /// <param name="view">The child view.</param>
127 /// <returns>The row index of <paramref name="view"/>.</returns>
128 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
129 /// <since_tizen> 8 </since_tizen>
130 public static int GetRow(View view) => GetAttachedValue<int>(view, RowProperty);
133 /// Gets the row span.
135 /// <param name="view">The child view.</param>
136 /// <returns>The row span of <paramref name="view"/>.</returns>
137 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
138 /// <since_tizen> 8 </since_tizen>
139 public static int GetRowSpan(View view) => GetAttachedValue<int>(view, RowSpanProperty);
142 /// Gets the value how child is resized within its horizontal space.
144 /// <param name="view">The child view.</param>
145 /// <returns>The horizontal stretch flag of <paramref name="view"/>.</returns>
146 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
147 /// <since_tizen> 8 </since_tizen>
148 public static StretchFlags GetHorizontalStretch(View view) => GetAttachedValue<StretchFlags>(view, HorizontalStretchProperty);
151 /// Gets the value how child is resized within its vertical space.
153 /// <param name="view">The child view.</param>
154 /// <returns>The vertical stretch flag of <paramref name="view"/>.</returns>
155 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
156 /// <since_tizen> 8 </since_tizen>
157 public static StretchFlags GetVerticalStretch(View view) => GetAttachedValue<StretchFlags>(view, VerticalStretchProperty);
160 /// Gets the horizontal alignment of this child.
162 /// <param name="view">The child view.</param>
163 /// <returns>The horizontal alignment of <paramref name="view"/>.</returns>
164 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
165 /// <since_tizen> 8 </since_tizen>
166 public static Alignment GetHorizontalAlignment(View view) => GetAttachedValue<Alignment>(view, HorizontalAlignmentProperty);
169 /// Gets the vertical alignment of this child.
171 /// <param name="view">The child view.</param>
172 /// <returns>The vertical alignment of <paramref name="view"/>.</returns>
173 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
174 /// <since_tizen> 8 </since_tizen>
175 public static Alignment GetVerticalAlignment(View view) => GetAttachedValue<Alignment>(view, VerticalAlignmentProperty);
178 /// Sets the column index the child occupies. A default column is <see cref="AutoColumn"/>.<br/>
179 /// If column is a <see cref="AutoColumn"/>, child will be automatically laid out depending on <see cref="GridOrientation"/>.
181 /// <param name="view">The child view.</param>
182 /// <param name="value">The column index of <paramref name="view"/>.</param>
183 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
184 /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be a negative value other than <see cref="AutoColumn"/>.</exception>
185 /// <since_tizen> 8 </since_tizen>
186 public static void SetColumn(View view, int value) => SetAttachedValue(view, ColumnProperty, value);
189 /// Sets the column span the child occupies. the default value is 1.
191 /// <param name="view">The child view.</param>
192 /// <param name="value">The column span of <paramref name="view"/>.</param>
193 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
194 /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than 1.</exception>
195 /// <since_tizen> 8 </since_tizen>
196 public static void SetColumnSpan(View view, int value) => SetAttachedValue(view, ColumnSpanProperty, value);
199 /// Sets the row index the child occupies. A default row index is <see cref="AutoRow"/>.<br/>
200 /// If row is a <see cref="AutoRow"/>, child will be automatically laid out depending on <see cref="GridOrientation"/>.
202 /// <param name="view">The child view.</param>
203 /// <param name="value">The row index of <paramref name="view"/>.</param>
204 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
205 /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be a negative value other than <see cref="AutoRow"/>.</exception>
206 /// <since_tizen> 8 </since_tizen>
207 public static void SetRow(View view, int value) => SetAttachedValue(view, RowProperty, value);
210 /// Sets the row span the child occupies. the default value is 1.
212 /// <param name="view">The child view.</param>
213 /// <param name="value">The row span of <paramref name="view"/>.</param>
214 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
215 /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than 1.</exception>
216 /// <since_tizen> 8 </since_tizen>
217 public static void SetRowSpan(View view, int value) => SetAttachedValue(view, RowSpanProperty, value);
220 /// Sets the value how child is resized within its horizontal space. <see cref="StretchFlags.None"/> by default.
222 /// <param name="view">The child view.</param>
223 /// <param name="value">The horizontal stretch flag of <paramref name="view"/>.</param>
224 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
225 /// <exception cref="ArgumentException">The <paramref name="value"/> should be <see cref="StretchFlags"/>.</exception>
226 /// <since_tizen> 8 </since_tizen>
227 public static void SetHorizontalStretch(View view, StretchFlags value) => SetAttachedValue(view, HorizontalStretchProperty, value);
230 /// Set the value how child is resized within its vertical space. <see cref="StretchFlags.None"/> by default.
232 /// <param name="view">The child view.</param>
233 /// <param name="value">The vertical stretch flag of <paramref name="view"/>.</param>
234 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
235 /// <exception cref="ArgumentException">The <paramref name="value"/> should be <see cref="StretchFlags"/>.</exception>
236 /// <since_tizen> 8 </since_tizen>
237 public static void SetVerticalStretch(View view, StretchFlags value) => SetAttachedValue(view, VerticalStretchProperty, value);
240 /// Set the horizontal alignment of this child inside the cells. <see cref="Alignment.Start"/> by default.
242 /// <param name="view">The child view.</param>
243 /// <param name="value">The horizontal alignment flag of <paramref name="view"/>.</param>
244 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
245 /// <exception cref="ArgumentException">The <paramref name="value"/> should be <see cref="Alignment"/>.</exception>
246 /// <since_tizen> 8 </since_tizen>
247 public static void SetHorizontalAlignment(View view, Alignment value) => SetAttachedValue(view, HorizontalAlignmentProperty, value);
250 /// Set the vertical alignment of this child inside the cells.
252 /// <param name="view">The child view.</param>
253 /// <param name="value">The vertical alignment flag of <paramref name="view"/>.</param>
254 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
255 /// <exception cref="ArgumentException">The <paramref name="value"/> should be <see cref="Alignment"/>.</exception>
256 /// <since_tizen> 8 </since_tizen>
257 public static void SetVerticalAlignment(View view, Alignment value) => SetAttachedValue(view, VerticalAlignmentProperty, value);
260 /// The distance between columns.
262 /// <since_tizen> 8 </since_tizen>
263 public float ColumnSpacing
265 get => columnSpacing;
268 if (columnSpacing == value) return;
269 columnSpacing = value > 0 ? value : 0;
276 /// The distance between rows.
278 /// <since_tizen> 8 </since_tizen>
279 public float RowSpacing
284 if (rowSpacing == value) return;
285 rowSpacing = value > 0 ? value : 0;
292 /// Get/Set the orientation in the layout
294 /// <exception cref="InvalidEnumArgumentException">Thrown when using invalid arguments that are enumerators.</exception>
295 /// <since_tizen> 8 </since_tizen>
296 public Orientation GridOrientation
298 get => gridOrientation;
301 if (gridOrientation == value) return;
302 if (value != Orientation.Horizontal && value != Orientation.Vertical)
303 throw new InvalidEnumArgumentException(nameof(GridOrientation));
305 gridOrientation = value;
311 /// GridLayout Constructor.
313 /// <returns> New Grid object.</returns>
314 /// <since_tizen> 6 </since_tizen>
320 /// Gets or Sets the number of columns in the grid.
322 /// <since_tizen> 6 </since_tizen>
328 if (value == columns) return;
330 if (value < 1) value = 1;
337 /// Gets or Sets the number of rows in the grid.
339 /// <since_tizen> 8 </since_tizen>
345 if (value == rows) return;
347 if (value < 1) value = 1;
354 /// Measure the layout and its content to determine the measured width and the measured height.<br />
356 /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
357 /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
358 /// <since_tizen> 6 </since_tizen>
359 protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
363 var widthMode = widthMeasureSpec.Mode;
364 var heightMode = heightMeasureSpec.Mode;
366 InitChildren(widthMeasureSpec, heightMeasureSpec);
368 if (widthMode == MeasureSpecification.ModeType.Exactly)
369 widthSize = (int)widthMeasureSpec.Size.AsRoundedValue();
371 widthSize = (int)(hLocations[maxColumnConut] - hLocations[0] - columnSpacing);
373 if (heightMode == MeasureSpecification.ModeType.Exactly)
374 heightSize = (int)heightMeasureSpec.Size.AsRoundedValue();
376 heightSize = (int)(vLocations[maxRowCount] - vLocations[0] - rowSpacing);
378 LayoutLength widthLength = new LayoutLength(widthSize + Padding.Start + Padding.End);
379 LayoutLength heightLenght = new LayoutLength(heightSize + Padding.Top + Padding.Bottom);
381 MeasuredSize widthMeasuredSize = ResolveSizeAndState(widthLength, widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
382 MeasuredSize heightMeasuredSize = ResolveSizeAndState(heightLenght, heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
384 SetMeasuredDimensions(widthMeasuredSize, heightMeasuredSize);
388 /// Assign a size and position to each of its children.<br />
390 /// <param name="changed">This is a new size or position for this layout.</param>
391 /// <param name="left">Left position, relative to parent.</param>
392 /// <param name="top"> Top position, relative to parent.</param>
393 /// <param name="right">Right position, relative to parent.</param>
394 /// <param name="bottom">Bottom position, relative to parent.</param>
395 /// <since_tizen> 6 </since_tizen>
396 protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
398 InitChildrenWithExpand(MeasuredWidth.Size - Padding.Start - Padding.End, MeasuredHeight.Size - Padding.Top - Padding.Bottom);
400 for (int i = 0; i < gridChildren.Length; i++)
402 GridChild child = gridChildren[i];
403 View view = child.LayoutItem?.Owner;
405 if (view == null) continue;
407 Alignment halign = GetHorizontalAlignment(view);
408 Alignment valign = GetVerticalAlignment(view);
410 int column = child.Column.Start;
411 int row = child.Row.Start;
412 int columnEnd = child.Column.End;
413 int rowEnd = child.Row.End;
414 float l = hLocations[column] + Padding.Start + view.Margin.Start;
415 float t = vLocations[row] + Padding.Top + view.Margin.Top;
416 float width = hLocations[columnEnd] - hLocations[column] - ColumnSpacing - view.Margin.Start - view.Margin.End;
417 float height = vLocations[rowEnd] - vLocations[row] - RowSpacing - view.Margin.Top - view.Margin.Bottom;
419 if (!child.Column.Stretch.HasFlag(StretchFlags.Fill))
421 l += (width - child.LayoutItem.MeasuredWidth.Size.AsDecimal()) * halign.ToFloat();
422 width = child.LayoutItem.MeasuredWidth.Size.AsDecimal();
425 if (!child.Row.Stretch.HasFlag(StretchFlags.Fill))
427 t += (height - child.LayoutItem.MeasuredHeight.Size.AsDecimal()) * valign.ToFloat();
428 height = child.LayoutItem.MeasuredHeight.Size.AsDecimal();
431 child.LayoutItem.Layout(new LayoutLength(l), new LayoutLength(t), new LayoutLength(l + width), new LayoutLength(t + height));
436 /// The value how child is resized within its space.
438 /// <since_tizen> 8 </since_tizen>
440 public enum StretchFlags
443 /// Respect mesured size of the child.
445 /// <since_tizen> 8 </since_tizen>
448 /// Resize to completely fill the space.
450 /// <since_tizen> 8 </since_tizen>
453 /// Expand to share available space in GridLayout.
455 /// <since_tizen> 8 </since_tizen>
458 /// Expand to share available space in GridLayout and fill the space.
460 /// <since_tizen> 8 </since_tizen>
461 ExpandAndFill = Fill + Expand,
465 /// The alignment of the grid layout child.
467 /// <since_tizen> 8 </since_tizen>
468 public enum Alignment
471 /// At the start of the container.
473 /// <since_tizen> 8 </since_tizen>
476 /// At the center of the container
478 /// <since_tizen> 8 </since_tizen>
481 /// At the end of the container.
483 /// <since_tizen> 8 </since_tizen>
488 // Extension Method of GridLayout.Alignment.
489 internal static class AlignmentExtension
491 public static float ToFloat(this GridLayout.Alignment align)
493 return 0.5f * (float)align;