1 /* Copyright (c) 2020 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), CellUndefined, validateValue: (bindable, value) => (int)value >= 0, 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), CellUndefined, validateValue: (bindable, value) => (int)value >= 0, 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);
77 private const int CellUndefined = -1;
78 private Orientation gridOrientation = Orientation.Horizontal;
79 private int columns = 1;
81 private float columnSpacing = 0;
82 private float rowSpacing = 0;
85 /// Enumeration for the direction in which the content is laid out
87 /// <since_tizen> 8 </since_tizen>
88 public enum Orientation
101 /// Gets the column index.
103 /// <param name="view">The child view.</param>
104 /// <returns>The column index of <paramref name="view"/>.</returns>
105 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
106 /// <since_tizen> 8 </since_tizen>
107 public static int GetColumn(View view) => GetAttachedValue<int>(view, ColumnProperty);
110 /// Gets the column span.
112 /// <param name="view">The child view.</param>
113 /// <returns>The column span of <paramref name="view"/>.</returns>
114 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
115 /// <since_tizen> 8 </since_tizen>
116 public static int GetColumnSpan(View view) => GetAttachedValue<int>(view, ColumnSpanProperty);
119 /// Gets the row index.
121 /// <param name="view">The child view.</param>
122 /// <returns>The row index of <paramref name="view"/>.</returns>
123 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
124 /// <since_tizen> 8 </since_tizen>
125 public static int GetRow(View view) => GetAttachedValue<int>(view, RowProperty);
128 /// Gets the row span.
130 /// <param name="view">The child view.</param>
131 /// <returns>The row span of <paramref name="view"/>.</returns>
132 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
133 /// <since_tizen> 8 </since_tizen>
134 public static int GetRowSpan(View view) => GetAttachedValue<int>(view, RowSpanProperty);
137 /// Gets the value how child is resized within its horizontal space.
139 /// <param name="view">The child view.</param>
140 /// <returns>The horizontal stretch flag of <paramref name="view"/>.</returns>
141 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
142 /// <since_tizen> 8 </since_tizen>
143 public static StretchFlags GetHorizontalStretch(View view) => GetAttachedValue<StretchFlags>(view, HorizontalStretchProperty);
146 /// Gets the value how child is resized within its vertical space.
148 /// <param name="view">The child view.</param>
149 /// <returns>The vertical stretch flag of <paramref name="view"/>.</returns>
150 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
151 /// <since_tizen> 8 </since_tizen>
152 public static StretchFlags GetVerticalStretch(View view) => GetAttachedValue<StretchFlags>(view, VerticalStretchProperty);
155 /// Gets the horizontal alignment of this child.
157 /// <param name="view">The child view.</param>
158 /// <returns>The horizontal alignment of <paramref name="view"/>.</returns>
159 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
160 /// <since_tizen> 8 </since_tizen>
161 public static Alignment GetHorizontalAlignment(View view) => GetAttachedValue<Alignment>(view, HorizontalAlignmentProperty);
164 /// Gets the vertical alignment of this child.
166 /// <param name="view">The child view.</param>
167 /// <returns>The vertical alignment of <paramref name="view"/>.</returns>
168 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
169 /// <since_tizen> 8 </since_tizen>
170 public static Alignment GetVerticalAlignment(View view) => GetAttachedValue<Alignment>(view, VerticalAlignmentProperty);
173 /// Sets the column index the child occupies. the default value is -1.
175 /// <param name="view">The child view.</param>
176 /// <param name="value">The column index of <paramref name="view"/>.</param>
177 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
178 /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than 0.</exception>
179 /// <since_tizen> 8 </since_tizen>
180 public static void SetColumn(View view, int value) => SetAttachedValue(view, ColumnProperty, value);
183 /// Sets the column span the child occupies. the default value is 1.
185 /// <param name="view">The child view.</param>
186 /// <param name="value">The column span of <paramref name="view"/>.</param>
187 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
188 /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than 1.</exception>
189 /// <since_tizen> 8 </since_tizen>
190 public static void SetColumnSpan(View view, int value) => SetAttachedValue(view, ColumnSpanProperty, value);
193 /// Sets the row index the child occupies. the default value is -1.
195 /// <param name="view">The child view.</param>
196 /// <param name="value">The row index of <paramref name="view"/>.</param>
197 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
198 /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than 0.</exception>
199 /// <since_tizen> 8 </since_tizen>
200 public static void SetRow(View view, int value) => SetAttachedValue(view, RowProperty, value);
203 /// Sets the row span the child occupies. the default value is 1.
205 /// <param name="view">The child view.</param>
206 /// <param name="value">The row span of <paramref name="view"/>.</param>
207 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
208 /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than 1.</exception>
209 /// <since_tizen> 8 </since_tizen>
210 public static void SetRowSpan(View view, int value) => SetAttachedValue(view, RowSpanProperty, value);
213 /// Sets the value how child is resized within its horizontal space. <see cref="StretchFlags.None"/> by default.
215 /// <param name="view">The child view.</param>
216 /// <param name="value">The horizontal stretch flag of <paramref name="view"/>.</param>
217 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
218 /// <exception cref="ArgumentException">The <paramref name="value"/> should be <see cref="StretchFlags"/>.</exception>
219 /// <since_tizen> 8 </since_tizen>
220 public static void SetHorizontalStretch(View view, StretchFlags value) => SetAttachedValue(view, HorizontalStretchProperty, value);
223 /// Set the value how child is resized within its vertical space. <see cref="StretchFlags.None"/> by default.
225 /// <param name="view">The child view.</param>
226 /// <param name="value">The vertical stretch flag of <paramref name="view"/>.</param>
227 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
228 /// <exception cref="ArgumentException">The <paramref name="value"/> should be <see cref="StretchFlags"/>.</exception>
229 /// <since_tizen> 8 </since_tizen>
230 public static void SetVerticalStretch(View view, StretchFlags value) => SetAttachedValue(view, VerticalStretchProperty, value);
233 /// Set the horizontal alignment of this child inside the cells. <see cref="Alignment.Start"/> by default.
235 /// <param name="view">The child view.</param>
236 /// <param name="value">The horizontal alignment flag of <paramref name="view"/>.</param>
237 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
238 /// <exception cref="ArgumentException">The <paramref name="value"/> should be <see cref="Alignment"/>.</exception>
239 /// <since_tizen> 8 </since_tizen>
240 public static void SetHorizontalAlignment(View view, Alignment value) => SetAttachedValue(view, HorizontalAlignmentProperty, value);
243 /// Set the vertical alignment of this child inside the cells.
245 /// <param name="view">The child view.</param>
246 /// <param name="value">The vertical alignment flag of <paramref name="view"/>.</param>
247 /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
248 /// <exception cref="ArgumentException">The <paramref name="value"/> should be <see cref="Alignment"/>.</exception>
249 /// <since_tizen> 8 </since_tizen>
250 public static void SetVerticalAlignment(View view, Alignment value) => SetAttachedValue(view, VerticalAlignmentProperty, value);
253 /// The distance between columns.
255 /// <since_tizen> 8 </since_tizen>
256 public float ColumnSpacing
258 get => columnSpacing;
261 if (columnSpacing == value) return;
262 columnSpacing = value > 0 ? value : 0;
269 /// The distance between rows.
271 /// <since_tizen> 8 </since_tizen>
272 public float RowSpacing
277 if (rowSpacing == value) return;
278 rowSpacing = value > 0 ? value : 0;
285 /// Get/Set the orientation in the layout
287 /// <exception cref="InvalidEnumArgumentException">Thrown when using invalid arguments that are enumerators.</exception>
288 /// <since_tizen> 8 </since_tizen>
289 public Orientation GridOrientation
291 get => gridOrientation;
294 if (gridOrientation == value) return;
295 if (value != Orientation.Horizontal && value != Orientation.Vertical)
296 throw new InvalidEnumArgumentException(nameof(GridOrientation));
298 gridOrientation = value;
304 /// GridLayout Constructor.
306 /// <returns> New Grid object.</returns>
307 /// <since_tizen> 6 </since_tizen>
313 /// Gets or Sets the number of columns in the grid.
315 /// <since_tizen> 6 </since_tizen>
321 if (value == columns) return;
323 if (value < 1) value = 1;
330 /// Gets or Sets the number of rows in the grid.
332 /// <since_tizen> 8 </since_tizen>
338 if (value == rows) return;
340 if (value < 1) value = 1;
347 /// Measure the layout and its content to determine the measured width and the measured height.<br />
349 /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
350 /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
351 /// <since_tizen> 6 </since_tizen>
352 protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
356 var widthMode = widthMeasureSpec.Mode;
357 var heightMode = heightMeasureSpec.Mode;
359 InitChildren(widthMeasureSpec, heightMeasureSpec);
361 if (widthMode == MeasureSpecification.ModeType.Exactly)
362 widthSize = (int)widthMeasureSpec.Size.AsRoundedValue();
364 widthSize = (int)(hLocations[maxColumnConut] - hLocations[0] - columnSpacing);
366 if (heightMode == MeasureSpecification.ModeType.Exactly)
367 heightSize = (int)heightMeasureSpec.Size.AsRoundedValue();
369 heightSize = (int)(vLocations[maxRowCount] - vLocations[0] - rowSpacing);
371 LayoutLength widthLength = new LayoutLength(widthSize + Padding.Start + Padding.End);
372 LayoutLength heightLenght = new LayoutLength(heightSize + Padding.Top + Padding.Bottom);
374 MeasuredSize widthMeasuredSize = ResolveSizeAndState(widthLength, widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
375 MeasuredSize heightMeasuredSize = ResolveSizeAndState(heightLenght, heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
377 SetMeasuredDimensions(widthMeasuredSize, heightMeasuredSize);
381 /// Assign a size and position to each of its children.<br />
383 /// <param name="changed">This is a new size or position for this layout.</param>
384 /// <param name="left">Left position, relative to parent.</param>
385 /// <param name="top"> Top position, relative to parent.</param>
386 /// <param name="right">Right position, relative to parent.</param>
387 /// <param name="bottom">Bottom position, relative to parent.</param>
388 /// <since_tizen> 6 </since_tizen>
389 protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
391 InitChildrenWithExpand(MeasuredWidth.Size - Padding.Start - Padding.End, MeasuredHeight.Size - Padding.Top - Padding.Bottom);
393 for (int i = 0; i < gridChildren.Length; i++)
395 GridChild child = gridChildren[i];
396 View view = child.LayoutItem?.Owner;
398 if (view == null) continue;
400 Alignment halign = GetHorizontalAlignment(view);
401 Alignment valign = GetVerticalAlignment(view);
403 int column = child.Column.Start;
404 int row = child.Row.Start;
405 int columnEnd = child.Column.End;
406 int rowEnd = child.Row.End;
407 float l = hLocations[column] + Padding.Start + view.Margin.Start;
408 float t = vLocations[row] + Padding.Top + view.Margin.Top;
409 float width = hLocations[columnEnd] - hLocations[column] - ColumnSpacing - view.Margin.Start - view.Margin.End;
410 float height = vLocations[rowEnd] - vLocations[row] - RowSpacing - view.Margin.Top - view.Margin.Bottom;
412 if (!child.Column.Stretch.HasFlag(StretchFlags.Fill))
414 l += (width - child.LayoutItem.MeasuredWidth.Size.AsDecimal()) * halign.ToFloat();
415 width = child.LayoutItem.MeasuredWidth.Size.AsDecimal();
418 if (!child.Row.Stretch.HasFlag(StretchFlags.Fill))
420 t += (height - child.LayoutItem.MeasuredHeight.Size.AsDecimal()) * valign.ToFloat();
421 height = child.LayoutItem.MeasuredHeight.Size.AsDecimal();
424 child.LayoutItem.Layout(new LayoutLength(l), new LayoutLength(t), new LayoutLength(l + width), new LayoutLength(t + height));
427 LayoutForIndependentChild();
431 /// The value how child is resized within its space.
433 /// <since_tizen> 8 </since_tizen>
435 public enum StretchFlags
438 /// Respect mesured size of the child.
440 /// <since_tizen> 8 </since_tizen>
443 /// Resize to completely fill the space.
445 /// <since_tizen> 8 </since_tizen>
448 /// Expand to share available space in GridLayout.
450 /// <since_tizen> 8 </since_tizen>
453 /// Expand to share available space in GridLayout and fill the space.
455 /// <since_tizen> 8 </since_tizen>
456 ExpandAndFill = Fill + Expand,
460 /// The alignment of the grid layout child.
462 /// <since_tizen> 8 </since_tizen>
463 public enum Alignment
466 /// At the start of the container.
468 /// <since_tizen> 8 </since_tizen>
471 /// At the center of the container
473 /// <since_tizen> 8 </since_tizen>
476 /// At the end of the container.
478 /// <since_tizen> 8 </since_tizen>
483 // Extension Method of GridLayout.Alignment.
484 internal static class AlignmentExtension
486 public static float ToFloat(this GridLayout.Alignment align)
488 return 0.5f * (float)align;