*/
using System;
-using System.Collections.Generic;
+using Tizen.NUI.BaseComponents;
namespace Tizen.NUI
{
- /// <summary>
- /// [Draft] This internal class houses the algorithm for computing the locations and size of cells.
- /// </summary>
- internal class GridLocations
+ public partial class GridLayout
{
+ private Node[] hEdgeList;
+ private Node[] vEdgeList;
+
+ private int maxRowCount;
+ private int maxColumnConut;
+ private float[] hLocations;
+ private float[] vLocations;
+ private int totalHorizontalExpand = 0;
+ private int totalVerticalExpand = 0;
+
+ private GridChild[] gridChildren;
+
/// <summary>
- /// A struct holding the 4 points which make up a cell.
+ /// The nested class to represent a node of DAG.
/// </summary>
- public struct Cell
+ private class Node
{
- public int Start;
- public int End;
- public int Top;
- public int Bottom;
-
- /// <summary>
- /// Initialize a cell with the given points.
- /// </summary>
- /// <param name="start">The start x coordinate.</param>
- /// <param name="end">The end x coordinate.</param>
- /// <param name="top">The top y coordinate.</param>
- /// <param name="bottom">The bottom y coordinate.</param>
-
- public Cell(int start, int end, int top, int bottom)
+ /// <summary>The start vertex with the same value as <c>Column/Row</c> child property.</summary>
+ public int Start { get; }
+
+ /// <summary>The end vertex with the same value as <c>Column+ColumnSpan/Row+RowSpan</c>.</summary>
+ public int End { get; }
+
+ /// <summary>The edge with the same value as measured width/height of child.</summary>
+ public float Edge { get; }
+
+ /// <summary>The stretch with the same value as <c>HorizontalStretch/VerticalStretch</c>.</summary>
+ public StretchFlags Stretch { get; }
+
+ /// <summary>The expanded size. It can be updated by expand calculation.</summary>
+ public float ExpandedSize { get; set; }
+
+ public Node(int vertex, int span, float edge, StretchFlags stretch)
{
- Start = start;
- End = end;
- Top = top;
- Bottom = bottom;
+ Start = vertex;
+ End = vertex + span;
+ Edge = edge;
+ Stretch = stretch;
+ ExpandedSize = 0;
}
- };
-
- private List<Cell> _locationsVector;
+ }
+ private class GridChild
+ {
+ public LayoutItem LayoutItem { get; }
+ public Node Column { get; }
+ public Node Row { get; }
+ public GridChild(LayoutItem layoutItem, Node column, Node row)
+ {
+ LayoutItem = layoutItem;
+ Column = column;
+ Row = row;
+ }
+ }
- /// <summary>
- /// [Draft]Constructor
- /// </summary>
- public GridLocations()
+ private void InitChildren(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
{
- _locationsVector = new List<Cell>();
+ InitChildrenData(widthMeasureSpec, heightMeasureSpec);
+
+ InitEdgeList(ref hEdgeList);
+ InitLocations(ref hLocations);
+
+ InitEdgeList(ref vEdgeList);
+ InitLocations(ref vLocations);
}
- /// <summary>
- /// Get locations vector with position of each cell and cell size.
- /// </summary>
- public List<Cell> GetLocations()
+ private void InitChildrenWithExpand(LayoutLength width, LayoutLength height)
{
- return _locationsVector;
+ if (totalHorizontalExpand > 0)
+ {
+ ReInitLocationsWithExpand(ref hLocations, width);
+ }
+ if (totalVerticalExpand > 0)
+ {
+ ReInitLocationsWithExpand(ref vLocations, height);
+ }
}
- /// <summary>
- /// [Draft] Uses the given parameters to calculate the x,y coordinates of each cell and cell size.
- /// </summary>
- public void CalculateLocations(int numberOfColumns, int availableWidth, int availableHeight, int numberOfCells)
+ private void ReInitLocationsWithExpand(ref float[] locations, LayoutLength parentSize)
{
- numberOfColumns = Math.Max(numberOfColumns, 1);
- _locationsVector.Clear();
+ bool isHorizontal = (locations == hLocations);
+ Node[] edgeList = isHorizontal ? hEdgeList : vEdgeList;
+ int maxIndex = isHorizontal ? maxColumnConut : maxRowCount;
+ float space = isHorizontal ? ColumnSpacing : RowSpacing;
+ float totalExpand = isHorizontal ? totalVerticalExpand : totalHorizontalExpand;
- // Calculate width and height of columns and rows.
+ float parentDecimalSize = parentSize.AsDecimal();
+ float maxExpandedSize = parentDecimalSize * LayoutChildren.Count;
+ float minExpandedSize = 0;
+ float newChildrenSize = locations[maxIndex] - locations[0] - space;
- // Calculate numbers of rows, round down result as later check for remainder.
- int remainder = 0;
- int numberOfRows = Math.DivRem(numberOfCells, numberOfColumns, out remainder);
- // If number of cells not cleanly dividable by columns, add another row to house remainder cells.
- numberOfRows += (remainder > 0) ? 1 : 0;
+ // No available sapce
+ if (newChildrenSize > parentDecimalSize)
+ return;
- // Rounding on column widths performed here,
- // if visually noticeable then can divide the space explicitly between columns.
- int columnWidth = availableWidth / numberOfColumns;
+ // binary search for finding maximum expanded size.
+ while ((int)(newChildrenSize + 0.5) != (int)parentDecimalSize)
+ {
+ float curExpandedSize = (maxExpandedSize + minExpandedSize) / 2;
+ for (int i = 0; i < edgeList.Length; i++)
+ {
+ Node node = edgeList[i];
+ // update expanded size.
+ if (node.Stretch.HasFlag(StretchFlags.Expand))
+ node.ExpandedSize = curExpandedSize / totalExpand;
+ }
- int rowHeight = availableHeight;
+ // re-init locations based on updated expanded size.
+ InitLocations(ref locations);
+ newChildrenSize = locations[maxIndex] - locations[0] - space;
- if (numberOfRows > 0)
- {
- // Column height supplied so use this unless exceeds available height.
- rowHeight = (availableHeight / numberOfRows);
+ // internal child size cannot exceed the Gridlayout size.
+ if (newChildrenSize > parentDecimalSize)
+ {
+ maxExpandedSize = curExpandedSize;
+ }
+ else
+ {
+ minExpandedSize = curExpandedSize;
+ }
}
+ }
- int y1 = 0;
- int y2 = y1 + rowHeight;
+ private void InitChildrenData(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
+ {
+ int childCount = LayoutChildren.Count;
+ bool isHorizontal = (GridOrientation == Orientation.Horizontal);
+ int mainPivot = 0, subPivot = 0;
+ int[] pivotStack = new int[isHorizontal ? Columns : Rows];
- // Calculate start, end, top and bottom coordinate of each cell.
+ vLocations = hLocations = null;
+ vEdgeList = hEdgeList = null;
+ gridChildren = new GridChild[childCount];
+ maxColumnConut = Columns;
+ maxRowCount = Rows;
- // Iterate rows
- for (var i = 0u; i < numberOfRows; i++)
+ totalVerticalExpand = 0;
+ totalHorizontalExpand = 0;
+
+ for (int i = 0; i < childCount; i++)
{
- int x1 = 0;
- int x2 = x1 + columnWidth;
+ LayoutItem item = LayoutChildren[i];
+ View view = item?.Owner;
+ if (view == null) continue;
+
+ int column, columnSpan, row, rowSpan;
+ StretchFlags verticalStretch, horizontalStretch;
- // Iterate columns
- for (var j = 0; j < numberOfColumns; j++)
+ column = GetColumn(view);
+ columnSpan = GetColumnSpan(view);
+ row = GetRow(view);
+ rowSpan = GetRowSpan(view);
+ verticalStretch = GetVerticalStretch(view);
+ horizontalStretch = GetHorizontalStretch(view);
+
+ if (column + columnSpan > Columns || row + rowSpan > Rows)
{
- Cell cell = new Cell(x1, x2, y1, y2);
- _locationsVector.Add(cell);
- // Calculate starting x and ending x position of each column
- x1 = x2;
- x2 = x2 + columnWidth;
+ if (column + columnSpan > Columns)
+ Tizen.Log.Error("NUI", "Column + ColumnSapn exceeds Grid Columns. Column + ColumnSpan (" + column + " + " + columnSpan + ") > Grid Columns(" + Columns + ")");
+ else
+ Tizen.Log.Error("NUI", "Row + RowSapn exceeds Grid Rows. Row + RowSapn (" + row + " + " + rowSpan + ") > Grid Rows(" + Rows + ")");
+
+ gridChildren[i] = new GridChild(null, new Node(0, 1, 0, 0), new Node(0, 1, 0, 0));
+
+ continue;
}
- // Calculate top y and bottom y position of each row.
- y1 = y2;
- y2 = y2 + rowHeight;
+ if (horizontalStretch.HasFlag(StretchFlags.Expand))
+ totalHorizontalExpand++;
+
+ if (verticalStretch.HasFlag(StretchFlags.Expand))
+ totalVerticalExpand++;
+
+ // assign column/row depending on GridOrientation. The main axis count(Columns on Horizontal, Rows otherwise) won't be exceeded
+ // explicit column(row) count which is assigned by Columns(Rows). but, cross axis count(Rows(Columns)) can be increased by sub axis count.
+ if (column == CellUndefined || row == CellUndefined)
+ {
+ (int point, int span) mainAxis = isHorizontal ? (column, columnSpan) : (row, rowSpan);
+ (int point, int span) subAxis = isHorizontal ? (row, rowSpan) : (column, columnSpan);
+
+ if (subAxis.point != CellUndefined)
+ subPivot = subAxis.point;
+ if (mainAxis.point != CellUndefined)
+ mainPivot = mainAxis.point;
+
+ if (mainPivot + mainAxis.span > pivotStack.Length)
+ {
+ mainPivot = 0;
+ subPivot++;
+ }
+
+ for (int n = mainPivot + mainAxis.span - 1; n >= mainPivot; n--)
+ {
+ if (pivotStack[n] > subPivot)
+ {
+ mainPivot = n + 1;
+ n = mainPivot + mainAxis.span;
+
+ if (n > pivotStack.Length)
+ {
+ if (mainAxis.point != CellUndefined)
+ mainPivot = mainAxis.point;
+ else
+ mainPivot = 0;
+
+ n = mainPivot + mainAxis.span;
+ subPivot++;
+ }
+ }
+ }
+
+ if (isHorizontal)
+ {
+ column = mainPivot;
+ row = subPivot;
+ }
+ else
+ {
+ column = subPivot;
+ row = mainPivot;
+ }
+
+ for (int start = mainPivot, end = mainPivot + mainAxis.span; start < end; start++)
+ {
+ pivotStack[start] = subPivot + subAxis.span;
+ }
+
+ mainPivot += mainAxis.span;
+ }
+
+ if (maxColumnConut < column + columnSpan)
+ maxColumnConut = column + columnSpan;
+ if (maxRowCount < row + rowSpan)
+ maxRowCount = row + rowSpan;
+
+ MeasureChildWithMargins(item, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
+ gridChildren[i] = new GridChild(item,
+ new Node(column, columnSpan, item.MeasuredWidth.Size.AsDecimal(), horizontalStretch),
+ new Node(row, rowSpan, item.MeasuredHeight.Size.AsDecimal(), verticalStretch));
}
}
-
- /// <summary>
- /// [Draft] Uses the given parameters to calculate the x,y coordinates of each cell and cell size.
- /// </summary>
- public void CalculateLocationsRow(int numberOfRows, int availableWidth, int availableHeight, int numberOfCells)
+ /// <summary> Initialize the edge list sorted by start vetex. </summary>
+ private void InitEdgeList(ref Node[] edgeList)
{
- numberOfRows = Math.Max(numberOfRows, 1);
- _locationsVector.Clear();
+ bool isHorizontal = (edgeList == hEdgeList);
+ int axisCount = isHorizontal ? Columns : Rows;
- int remainder = 0;
- int numberOfColumns = Math.DivRem(numberOfCells, numberOfRows, out remainder);
+ edgeList = new Node[gridChildren.Length + axisCount];
- numberOfColumns += (remainder > 0) ? 1 : 0;
+ for (int i = 0; i < gridChildren.Length; i++)
+ edgeList[i] = isHorizontal ? gridChildren[i].Column : gridChildren[i].Row;
- int rowHeight = availableHeight / numberOfRows;
- int columnWidth = availableHeight;
+ // Add virtual edge that have no edge for connecting adjacent cells.
+ for (int i = LayoutChildren.Count, end = LayoutChildren.Count + axisCount, v = 0; i < end; i++, v++)
+ edgeList[i] = new Node(v, 1, 0, 0);
- if (numberOfColumns > 0)
- {
- columnWidth = (availableWidth / numberOfColumns);
- }
+ Array.Sort(edgeList, (a, b) => a.Start.CompareTo(b.Start));
+ }
+
+ /// <summary>
+ /// Locations are longest path from zero-vertex. that means 'locations[MAX] - locations[0]' is maximun size of children.
+ /// Since GridLayout is Directed Acyclic Graph(DAG) which have no negative cycles, longest path can be found in linear time.
+ /// </summary>
+ private void InitLocations(ref float[] locations)
+ {
+ bool isHorizontal = (locations == hLocations);
+ int maxAxisCount = isHorizontal ? maxColumnConut : maxRowCount;
+ Node[] edgeList = isHorizontal ? hEdgeList : vEdgeList;
+ float space = isHorizontal ? ColumnSpacing : RowSpacing;
- int x1 = 0;
- int x2 = x1 + columnWidth;
+ locations = new float[maxAxisCount + 1];
- for (var i = 0u; i < numberOfColumns; i++)
+ for (int i = 0; i < edgeList.Length; i++)
{
- int y1 = 0;
- int y2 = y1 + rowHeight;
+ float newLocation = locations[edgeList[i].Start] + edgeList[i].Edge + edgeList[i].ExpandedSize;
+ if (edgeList[i].Edge + edgeList[i].ExpandedSize > 0)
+ newLocation += space;
- for (var j = 0; j < numberOfRows; j++)
+ if (locations[edgeList[i].End] < newLocation)
{
- Cell cell = new Cell(x1, x2, y1, y2);
- _locationsVector.Add(cell);
- y1 = y2;
- y2 = y2 + rowHeight;
+ locations[edgeList[i].End] = newLocation;
}
-
- x1 = x2;
- x2 = x2 + columnWidth;
}
}
}
-/* Copyright (c) 2019 Samsung Electronics Co., Ltd.
+/* Copyright (c) 2019 Samsung Electronics Co., Ltd.
.*
.* Licensed under the Apache License, Version 2.0 (the "License");
.* you may not use this file except in compliance with the License.
using System;
using System.ComponentModel;
-using System.Collections.Generic;
using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
namespace Tizen.NUI
{
/// <summary>
/// [Draft] This class implements a grid layout
/// </summary>
- public class GridLayout : LayoutGroup
+ public partial class GridLayout : LayoutGroup
{
/// <summary>
+ /// ColumnProperty
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static readonly BindableProperty ColumnProperty = BindableProperty.CreateAttached("Column", typeof(int), typeof(GridLayout), CellUndefined, validateValue: (bindable, value) => (int)value >= 0, propertyChanged: OnChildPropertyChanged);
+
+ /// <summary>
+ /// ColumnSpanProperty
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static readonly BindableProperty ColumnSpanProperty = BindableProperty.CreateAttached("ColumnSpan", typeof(int), typeof(GridLayout), 1, validateValue: (bindable, value) => (int)value >= 1, propertyChanged: OnChildPropertyChanged);
+
+ /// <summary>
+ /// RowProperty
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static readonly BindableProperty RowProperty = BindableProperty.CreateAttached("Row", typeof(int), typeof(GridLayout), CellUndefined, validateValue: (bindable, value) => (int)value >= 0, propertyChanged: OnChildPropertyChanged);
+
+ /// <summary>
+ /// RowSpanProperty
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static readonly BindableProperty RowSpanProperty = BindableProperty.CreateAttached("RowSpan", typeof(int), typeof(GridLayout), 1, validateValue: (bindable, value) => (int)value >= 1, propertyChanged: OnChildPropertyChanged);
+
+ /// <summary>
+ /// HorizontalStretchProperty
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static readonly BindableProperty HorizontalStretchProperty = BindableProperty.CreateAttached("HorizontalStretch", typeof(StretchFlags), typeof(GridLayout), StretchFlags.Fill, propertyChanged: OnChildPropertyChanged);
+
+ /// <summary>
+ /// VerticalStretchProperty
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static readonly BindableProperty VerticalStretchProperty = BindableProperty.CreateAttached("VerticalStretch", typeof(StretchFlags), typeof(GridLayout), StretchFlags.Fill, propertyChanged: OnChildPropertyChanged);
+
+ /// <summary>
+ /// HorizontalAlignmentProperty
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static readonly BindableProperty HorizontalAlignmentProperty = BindableProperty.CreateAttached("HorizontalAlignment", typeof(Alignment), typeof(GridLayout), Alignment.Start, propertyChanged: OnChildPropertyChanged);
+
+ /// <summary>
+ /// VerticalAlignmentProperty
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static readonly BindableProperty VerticalAlignmentProperty = BindableProperty.CreateAttached("VerticalAlignment", typeof(Alignment), typeof(GridLayout), Alignment.Start, propertyChanged: OnChildPropertyChanged);
+
+ private const int CellUndefined = int.MinValue;
+ private Orientation gridOrientation = Orientation.Vertical;
+ private int columns = 1;
+ private int rows = 1;
+ private float columnSpacing = 0;
+ private float rowSpacing = 0;
+
+ /// <summary>
/// [Draft] Enumeration for the direction in which the content is laid out
/// </summary>
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
Vertical
}
- private Orientation _GridOrientation = Orientation.Vertical;
- const int AUTO_FIT = -1;
- private int _columns = 1;
- private int _rows = 1;
- private int _totalWidth;
- private int _totalHeight;
- private int _requestedColumnWidth = 1;
- private int _numberOfRequestedColumns;
- private int _requestedRowHeight = 1;
- private int _numberOfRequestedRows;
- internal GridLocations _locations;
+ /// <summary>
+ /// Get the column index.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static int GetColumn(View view)
+ {
+ return (int)view.GetValue(ColumnProperty);
+ }
+ /// <summary>
+ /// Get the column span.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static int GetColumnSpan(View view)
+ {
+ return (int)view.GetValue(ColumnSpanProperty);
+ }
/// <summary>
- /// [Draft] Get/Set the orientation in the layout
+ /// Get the row index.
/// </summary>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
- public Orientation GridOrientation
+ public static int GetRow(View view)
{
- get
- {
- return _GridOrientation;
- }
- set
- {
- _GridOrientation = value;
- RequestLayout();
- }
+ return (int)view.GetValue(RowProperty);
}
/// <summary>
- /// [draft] GridLayout Constructor/>
+ /// Get the row span.
/// </summary>
- /// <returns> New Grid object.</returns>
- /// <since_tizen> 6 </since_tizen>
- public GridLayout()
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static int GetRowSpan(View view)
{
- _locations = new GridLocations();
+ return (int)view.GetValue(RowSpanProperty);
}
/// <summary>
- /// [Draft] Get/Set the number of columns in the grid
+ /// Get the value how child is resized within its horizontal space. <see cref="StretchFlags.Fill"/> by default.
/// </summary>
- /// <since_tizen> 6 </since_tizen>
- public int Columns
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static StretchFlags GetHorizontalStretch(View view)
{
- get
- {
- return GetColumns();
- }
- set
- {
- SetColumns(value);
- }
+ return (StretchFlags)view.GetValue(HorizontalStretchProperty);
}
/// <summary>
- /// [draft ] Sets the number of columns the GridLayout should have. />
+ /// Get the value how child is resized within its vertical space. <see cref="StretchFlags.Fill"/> by default.
/// </summary>
- /// <param name="columns">The number of columns.</param>
- internal void SetColumns(int columns)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static StretchFlags GetVerticalStretch(View view)
{
- _numberOfRequestedColumns = columns;
- if (columns != _columns)
- {
- _columns = Math.Max(1, _columns);
- _columns = columns;
- RequestLayout();
- }
+ return (StretchFlags)view.GetValue(VerticalStretchProperty);
}
/// <summary>
- /// [draft ] Gets the number of columns in the Grid />
+ /// Get the horizontal alignment of this child.
/// </summary>
- /// <returns>The number of columns in the Grid.</returns>
- internal int GetColumns()
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static Alignment GetHorizontalAlignment(View view)
{
- return _columns;
+ return (Alignment)view.GetValue(HorizontalAlignmentProperty);
}
/// <summary>
- /// [draft ]Get/Set the number of rows in the grid
+ /// Get the vertical alignment of this child.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static Alignment GetVerticalAlignment(View view)
+ {
+ return (Alignment)view.GetValue(VerticalAlignmentProperty);
+ }
+
+ /// <summary>
+ /// Set the column index.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetColumn(View view, int value)
+ {
+ SetChildValue(view, ColumnProperty, value);
+ }
+
+ /// <summary>
+ /// Set the column span.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetColumnSpan(View view, int value)
+ {
+ SetChildValue(view, ColumnSpanProperty, value);
+ }
+
+ /// <summary>
+ /// Set the row index.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetRow(View view, int value)
+ {
+ SetChildValue(view, RowProperty, value);
+ }
+
+ /// <summary>
+ /// Set the row span.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetRowSpan(View view, int value)
+ {
+ SetChildValue(view, RowSpanProperty, value);
+ }
+
+ /// <summary>
+ /// Set the value how child is resized within its horizontal space. <see cref="StretchFlags.Fill"/> by default.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetHorizontalStretch(View view, StretchFlags value)
+ {
+ SetChildValue(view, HorizontalStretchProperty, value);
+ }
+
+ /// <summary>
+ /// Set the value how child is resized within its vertical space. <see cref="StretchFlags.Fill"/> by default.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetVerticalStretch(View view, StretchFlags value)
+ {
+ SetChildValue(view, VerticalStretchProperty, value);
+ }
+
+ /// <summary>
+ /// Set the horizontal alignment of this child inside the cells.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetHorizontalAlignment(View view, Alignment value)
+ {
+ SetChildValue(view, HorizontalAlignmentProperty, value);
+ }
+
+ /// <summary>
+ /// Set the vertical alignment of this child inside the cells.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetVerticalAlignment(View view, Alignment value)
+ {
+ SetChildValue(view, VerticalAlignmentProperty, value);
+ }
+
+ /// <summary>
+ /// [Draft] The Distance between Column
/// </summary>
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
- public int Rows
+ public float ColumnSpacing
{
- get
+ get => columnSpacing;
+ set
{
- return GetRows();
+ if (columnSpacing == value) return;
+ if (columnSpacing < 0) columnSpacing = 0;
+ columnSpacing = value;
+
+ RequestLayout();
}
+ }
+
+ /// <summary>
+ /// [Draft] The Distance between Rows
+ /// </summary>
+ // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float RowSpacing
+ {
+ get => rowSpacing;
set
{
- SetRows(value);
+ if (rowSpacing == value) return;
+ if (rowSpacing < 0) rowSpacing = 0;
+ rowSpacing = value;
+
+ RequestLayout();
}
}
/// <summary>
- /// [draft ] Sets the number of rows the GridLayout should have. />
+ /// [Draft] Get/Set the orientation in the layout
/// </summary>
- /// <param name="rows">The number of rows.</param>
- internal void SetRows(int rows)
+ // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Orientation GridOrientation
{
- _numberOfRequestedRows = rows;
- if (rows != _rows)
+ get => gridOrientation;
+ set
{
- _rows = Math.Max(1, _rows);
- _rows = rows;
+ if (gridOrientation == value) return;
+ gridOrientation = value;
RequestLayout();
}
}
/// <summary>
- /// [draft ] Gets the number of rows in the Grid />
+ /// [draft] GridLayout Constructor/>
/// </summary>
- /// <returns>The number of rows in the Grid.</returns>
- internal int GetRows()
+ /// <returns> New Grid object.</returns>
+ /// <since_tizen> 6 </since_tizen>
+ public GridLayout()
{
- return _rows;
}
- void DetermineNumberOfColumns(int availableSpace)
+ /// <summary>
+ /// [Draft] Get/Set the number of columns in the GridLayout should have.
+ /// </summary>
+ /// <since_tizen> 6 </since_tizen>
+ public int Columns
{
- if (_numberOfRequestedColumns == AUTO_FIT)
+ get => columns;
+ set
{
- if (availableSpace > 0)
- {
- // Can only calculate number of columns if a column width has been set
- _columns = (_requestedColumnWidth > 0) ? (availableSpace / _requestedColumnWidth) : 1;
- }
+ if (value == columns) return;
+
+ if (value < 1) value = 1;
+ columns = value;
+ RequestLayout();
}
}
- void DetermineNumberOfRows(int availableSpace)
+ /// <summary>
+ /// [draft ]Get/Set the number of rows in the grid
+ /// </summary>
+ // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int Rows
{
- if (_numberOfRequestedRows == AUTO_FIT)
+ get => rows;
+ set
{
- if (availableSpace > 0)
- {
- // Can only calculate number of rows if a rows height has been set
- _rows = (_requestedRowHeight > 0) ? (availableSpace / _requestedRowHeight) : 1;
- }
+ if (value == rows) return;
+
+ if (value < 1) value = 1;
+ rows = value;
+ RequestLayout();
}
}
/// <since_tizen> 6 </since_tizen>
protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
{
- var gridWidthMode = widthMeasureSpec.Mode;
- var gridHeightMode = heightMeasureSpec.Mode;
-
- int widthSize = (int)widthMeasureSpec.Size.AsRoundedValue();
- int heightSize = (int)heightMeasureSpec.Size.AsRoundedValue();
-
- var childCount = LayoutChildren.Count;
+ int widthSize;
+ int heightSize;
+ var widthMode = widthMeasureSpec.Mode;
+ var heightMode = heightMeasureSpec.Mode;
- if (childCount > 0)
- {
- foreach (LayoutItem childLayout in LayoutChildren)
- {
- if (childLayout != null)
- {
- MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
- }
- }
+ InitChildren(widthMeasureSpec, heightMeasureSpec);
- if (_GridOrientation == Orientation.Horizontal)
- {
- widthSize = CalculateHorizontalSize(gridWidthMode, gridHeightMode, widthSize, heightSize);
- heightSize = gridWidthMode == MeasureSpecification.ModeType.Exactly?
- heightSize:
- (int)(LayoutChildren[0].MeasuredHeight.Size.AsDecimal() + LayoutChildren[0].Margin.Top + LayoutChildren[0].Margin.Bottom)*Rows;
- }
- else
- {
- widthSize = gridWidthMode == MeasureSpecification.ModeType.Exactly?
- heightSize:
- (int)(LayoutChildren[0].MeasuredWidth.Size.AsDecimal() + LayoutChildren[0].Margin.Start + LayoutChildren[0].Margin.End)*Columns;
- heightSize = CalculateVerticalSize(gridWidthMode, gridHeightMode, widthSize, heightSize);
- }
+ if (widthMode == MeasureSpecification.ModeType.Exactly)
+ widthSize = (int)widthMeasureSpec.Size.AsRoundedValue();
+ else
+ widthSize = (int)(hLocations[maxColumnConut] - hLocations[0] - columnSpacing);
- } // Children exists
+ if (heightMode == MeasureSpecification.ModeType.Exactly)
+ heightSize = (int)heightMeasureSpec.Size.AsRoundedValue();
else
- {
- if (_GridOrientation == Orientation.Horizontal)
- {
- widthSize = (gridWidthMode == MeasureSpecification.ModeType.Unspecified)?0:widthSize;
- }
- else
- {
- heightSize = (gridHeightMode == MeasureSpecification.ModeType.Unspecified)?0:heightSize;
- }
- }
+ heightSize = (int)(vLocations[maxRowCount] - vLocations[0] - rowSpacing);
LayoutLength widthLength = new LayoutLength(widthSize + Padding.Start + Padding.End);
LayoutLength heightLenght = new LayoutLength(heightSize + Padding.Top + Padding.Bottom);
SetMeasuredDimensions(widthMeasuredSize, heightMeasuredSize);
}
- private int CalculateHorizontalSize(MeasureSpecification.ModeType gridWidthMode, MeasureSpecification.ModeType gridHeightMode, int widthSize, int heightSize)
+ /// <summary>
+ /// Assign a size and position to each of its children.<br />
+ /// </summary>
+ /// <param name="changed">This is a new size or position for this layout.</param>
+ /// <param name="left">Left position, relative to parent.</param>
+ /// <param name="top"> Top position, relative to parent.</param>
+ /// <param name="right">Right position, relative to parent.</param>
+ /// <param name="bottom">Bottom position, relative to parent.</param>
+ /// <since_tizen> 6 </since_tizen>
+ protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
{
- int availableContentWidth;
- int availableContentHeight;
-
- int desiredChildHeight;
- int desiredChildWidth;
-
- Extents gridLayoutPadding = Padding;
- var childCount = LayoutChildren.Count;
+ InitChildrenWithExpand(MeasuredWidth.Size - Padding.Start - Padding.End, MeasuredHeight.Size - Padding.Top - Padding.Bottom);
- // Use first child's dimensions for layout measurement
- View childOwner = LayoutChildren[0].Owner;
-
- desiredChildHeight = (int)LayoutChildren[0].MeasuredHeight.Size.AsRoundedValue();
- desiredChildWidth = (int)LayoutChildren[0].MeasuredWidth.Size.AsRoundedValue();
-
- // If child has a margin then add it to desired size
- Extents childMargin = LayoutChildren[0].Margin;
- desiredChildHeight += childMargin.Top + childMargin.Bottom;
- desiredChildWidth += childMargin.Start + childMargin.End;
- _totalHeight = desiredChildHeight * _rows;
- _totalHeight += gridLayoutPadding.Top + gridLayoutPadding.Bottom;
- _totalHeight = Math.Max(_totalHeight, (int)SuggestedMinimumHeight.AsRoundedValue());
-
- if (gridHeightMode == MeasureSpecification.ModeType.Exactly || gridHeightMode == MeasureSpecification.ModeType.AtMost)
+ for (int i = 0; i < gridChildren.Length; i++)
{
- _totalHeight = Math.Min(_totalHeight, heightSize);
- }
+ GridChild child = gridChildren[i];
+ View view = child.LayoutItem?.Owner;
- availableContentHeight = _totalHeight - gridLayoutPadding.Top - gridLayoutPadding.Bottom;
- heightSize = _totalHeight;
+ if (view == null) continue;
- if (gridWidthMode == MeasureSpecification.ModeType.Exactly || gridWidthMode == MeasureSpecification.ModeType.AtMost)
- {
- if (childCount > 0)
- {
- _totalWidth = gridLayoutPadding.Start + gridLayoutPadding.End;
+ Alignment halign = GetHorizontalAlignment(view);
+ Alignment valign = GetVerticalAlignment(view);
- for (int i = 0; i < childCount; i += _rows)
- {
- _totalWidth += desiredChildWidth;
- }
+ int column = child.Column.Start;
+ int row = child.Row.Start;
+ int columnEnd = child.Column.End;
+ int rowEnd = child.Row.End;
+ float l = hLocations[column] + left.AsDecimal() + Padding.Start;
+ float t = vLocations[row] + top.AsDecimal() + Padding.Top;
+ float width = hLocations[columnEnd] - hLocations[column] - ColumnSpacing;
+ float height = vLocations[rowEnd] - vLocations[row] - RowSpacing;
- _totalWidth = Math.Min(_totalWidth, widthSize);
- _totalWidth = Math.Max(_totalWidth, (int)SuggestedMinimumWidth.AsRoundedValue());
-
- widthSize = _totalWidth;
- } // Child exists
+ if (!child.Column.Stretch.HasFlag(StretchFlags.Fill))
+ {
+ l += (width - child.LayoutItem.MeasuredWidth.Size.AsDecimal()) * halign.ToFloat();
+ width = child.LayoutItem.MeasuredWidth.Size.AsDecimal();
+ }
- // In the case of AT_MOST, availableContentHeight is the max limit.
- availableContentWidth = widthSize - gridLayoutPadding.Start - gridLayoutPadding.End;
- }
- else
- {
- _rows = (_rows > 0) ? _rows : 1;
- _columns = childCount / _rows;
- _columns += (childCount % _rows > 0) ? 1 : 0;
+ if (!child.Row.Stretch.HasFlag(StretchFlags.Fill))
+ {
+ t += (height - child.LayoutItem.MeasuredHeight.Size.AsDecimal()) * valign.ToFloat();
+ height = child.LayoutItem.MeasuredHeight.Size.AsDecimal();
+ }
- widthSize = desiredChildWidth * _columns + gridLayoutPadding.Start + gridLayoutPadding.End;
- availableContentWidth = widthSize - gridLayoutPadding.Start - gridLayoutPadding.End;
+ child.LayoutItem.Layout(new LayoutLength(l), new LayoutLength(t), new LayoutLength(l + width), new LayoutLength(t + height));
}
-
- // If number of rows not defined
- DetermineNumberOfRows(availableContentHeight);
-
- _locations.CalculateLocationsRow(_rows, availableContentWidth, availableContentHeight, childCount);
-
- return availableContentWidth;
}
- private int CalculateVerticalSize(MeasureSpecification.ModeType gridWidthMode, MeasureSpecification.ModeType gridHeightMode, int widthSize, int heightSize)
+ /// <summary>
+ /// The value how child is resized within its space.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ [Flags]
+ public enum StretchFlags
{
- int availableContentWidth;
- int availableContentHeight;
-
- int desiredChildHeight;
- int desiredChildWidth;
-
- Extents gridLayoutPadding = Padding;
- var childCount = LayoutChildren.Count;
-
- // Use first child's dimensions for layout measurement
- View childOwner = LayoutChildren[0].Owner;
-
- desiredChildHeight = (int)LayoutChildren[0].MeasuredHeight.Size.AsRoundedValue();
- desiredChildWidth = (int)LayoutChildren[0].MeasuredWidth.Size.AsRoundedValue();
-
- // If child has a margin then add it to desired size
- Extents childMargin = LayoutChildren[0].Margin;
- desiredChildHeight += childMargin.Top + childMargin.Bottom;
- desiredChildWidth += childMargin.Start + childMargin.End;
-
- _totalWidth = desiredChildWidth * _columns;
-
- // Include padding for max and min checks
- _totalWidth += gridLayoutPadding.Start + gridLayoutPadding.End;
-
- // Ensure width does not exceed specified at most width or less than mininum width
- _totalWidth = Math.Max(_totalWidth, (int)SuggestedMinimumWidth.AsRoundedValue());
-
- // widthMode EXACTLY so grid must be the given width
- if (gridWidthMode == MeasureSpecification.ModeType.Exactly || gridWidthMode == MeasureSpecification.ModeType.AtMost)
- {
- // In the case of AT_MOST, widthSize is the max limit.
- _totalWidth = Math.Min(_totalWidth, widthSize);
- }
-
- availableContentWidth = _totalWidth - gridLayoutPadding.Start - gridLayoutPadding.End;
- widthSize = _totalWidth;
-
- // HEIGHT SPECIFICATIONS
- // heightMode EXACTLY so grid must be the given height
- if (gridHeightMode == MeasureSpecification.ModeType.Exactly || gridHeightMode == MeasureSpecification.ModeType.AtMost)
- {
- if (childCount > 0)
- {
- _totalHeight = gridLayoutPadding.Top + gridLayoutPadding.Bottom;
-
- for (int i = 0; i < childCount; i += _columns)
- {
- _totalHeight += desiredChildHeight;
- }
-
- // Ensure ourHeight does not exceed specified at most height
- _totalHeight = Math.Min(_totalHeight, heightSize);
- _totalHeight = Math.Max(_totalHeight, (int)SuggestedMinimumHeight.AsRoundedValue());
-
- heightSize = _totalHeight;
- } // Child exists
-
- // In the case of AT_MOST, availableContentHeight is the max limit.
- availableContentHeight = heightSize - gridLayoutPadding.Top - gridLayoutPadding.Bottom;
- }
- else
- {
- // Grid expands to fit content
- // If number of columns AUTO_FIT then set to 1 column.
- _columns = (_columns > 0) ? _columns : 1;
- // Calculate numbers of rows, round down result as later check for remainder.
- _rows = childCount / _columns;
- // If number of cells not cleanly dividable by columns, add another row to house remainder cells.
- _rows += (childCount % _columns > 0) ? 1 : 0;
-
- heightSize = desiredChildHeight * _rows + gridLayoutPadding.Top + gridLayoutPadding.Bottom;
- availableContentHeight = heightSize - gridLayoutPadding.Top - gridLayoutPadding.Bottom;
- }
- // If number of columns not defined
- DetermineNumberOfColumns(availableContentWidth);
-
- // Locations define the start, end,top and bottom of each cell.
- _locations.CalculateLocations(_columns, availableContentWidth, availableContentHeight, childCount);
-
- return availableContentHeight;
+ /// <summary>
+ /// Respect mesured size of the child.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ None = 0,
+ /// <summary>
+ /// Resize to completely fill the space.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Fill = 1,
+ /// <summary>
+ /// Expand to share available space in GridLayout.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Expand = 2,
+ /// <summary>
+ /// Expand to share available space in GridLayout and fill the space.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ ExpandAndFill = Fill + Expand,
}
/// <summary>
- /// Assign a size and position to each of its children.<br />
+ /// The alignment of the grid layout child.
/// </summary>
- /// <param name="changed">This is a new size or position for this layout.</param>
- /// <param name="left">Left position, relative to parent.</param>
- /// <param name="top"> Top position, relative to parent.</param>
- /// <param name="right">Right position, relative to parent.</param>
- /// <param name="bottom">Bottom position, relative to parent.</param>
- /// <since_tizen> 6 </since_tizen>
- protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public enum Alignment
{
- List<GridLocations.Cell> locations = _locations.GetLocations();
-
- Extents gridLayoutPadding = Padding;
- Extents childMargins = new Extents();
-
- // Margin for all children dependant on if set on first child
- if (LayoutChildren.Count > 0)
- {
- childMargins = LayoutChildren[0]?.Margin;
- }
+ /// <summary>
+ /// At the start of the container.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Start = 0,
+ /// <summary>
+ /// At the center of the container
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Center = 1,
+ /// <summary>
+ /// At the end of the container.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ End = 2,
+ }
+ }
- int index = 0;
- foreach (LayoutItem childLayout in LayoutChildren)
- {
- // for each child
- if (childLayout != null)
- {
- // Get start and end position of child x1,x2
- int x1 = locations[index].Start;
- int x2 = locations[index].End;
-
- // Get top and bottom position of child y1,y2
- int y1 = locations[index].Top;
- int y2 = locations[index].Bottom;
-
- // Offset children by the grids padding if present
- x1 += gridLayoutPadding.Start;
- x2 += gridLayoutPadding.Start;
- y1 += gridLayoutPadding.Top;
- y2 += gridLayoutPadding.Top;
-
- // Offset children by the margin of the first child ( if required ).
- x1 += childMargins.Start;
- x2 -= childMargins.End;
- y1 += childMargins.Top;
- y2 -= childMargins.Bottom;
-
- childLayout.Layout(new LayoutLength(x1), new LayoutLength(y1),
- new LayoutLength(x2), new LayoutLength(y2));
- index++;
- //childLayout.Owner.RaiseToTop();
- }
- }
+ // Extension Method of GridLayout.Alignment.
+ internal static class AlignmentExtension
+ {
+ public static float ToFloat(this GridLayout.Alignment align)
+ {
+ return 0.5f * (float)align;
}
}
}