[NUI] GridLayout Refactoring to support column, row, spacing, weight, align (#1655)
authorYeongJong Lee <cleanlyj@naver.com>
Mon, 15 Jun 2020 03:04:15 +0000 (12:04 +0900)
committerGitHub <noreply@github.com>
Mon, 15 Jun 2020 03:04:15 +0000 (12:04 +0900)
* [NUI] LayoutGroup: Support child property

* [NUI] GridLayout Refactoring to support column, row, spacing, alignment

1) Add ColumnSpacing, RowSpacing(GridLayout Property)
This is GridLayout properties for the distance between columns, rows.

2) Add Column, ColumnSpan, Row, RowSpan(Child Property)
This is child properties for specific cell index to layout. `SetChildValue` is
added to support child property using Attached Bindable Property.

If the Column(Row) isn't defined, it is automatically assigned left to right or
top to bottom depending on `GridOrientation`(RTL is not supported yet).
The main axis count(Columns on Horizontal mode, Rows otherwise) won't be
exceeded explicit column(row) count which is assigned by
Property(`Columns`(`Rows`)). otherwise, cross axis count(row(column))
can be increased.
Children with automatically assigned Column(Row) don't overlap. but,
children with specific Column and Row can overlap with the other children.

To respect child width(height), each cell size is determined by the maximum
size among Columns(Rows) it belongs to. Greedy Algorithm is used to find
maximum size of each Columns(Rows) that is same problem to find longest path
in DAG(Directed Acyclic Graph).

3) Add HorizontalAlignment, VerticalAlignment(Child Property)
The child properties how child is laid out in the cell.(Start, End, Center)

src/Tizen.NUI/src/internal/Layouting/GridLocations.cs
src/Tizen.NUI/src/public/Layouting/GridLayout.cs
src/Tizen.NUI/src/public/Layouting/LayoutGroup.cs

index f36dcee..2a08c1b 100755 (executable)
  */
 
 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;
             }
         }
     }
index 1958e25..b18d01d 100755 (executable)
@@ -1,4 +1,4 @@
-/* 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)
@@ -43,149 +98,243 @@ namespace Tizen.NUI
             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();
             }
         }
 
@@ -197,51 +346,22 @@ namespace Tizen.NUI
         /// <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);
@@ -252,216 +372,113 @@ namespace Tizen.NUI
             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;
         }
     }
 }
index 7473c30..800cc1a 100755 (executable)
@@ -20,6 +20,8 @@ using System.ComponentModel;
 using System.Diagnostics;
 using Tizen.NUI.BaseComponents;
 using System.Linq;
+using Tizen.NUI.Binding.Internals;
+using static Tizen.NUI.Binding.BindableObject;
 
 namespace Tizen.NUI
 {
@@ -558,5 +560,15 @@ namespace Tizen.NUI
             child.Measure( childWidthMeasureSpec, childHeightMeasureSpec );
 
         }
+
+        internal static void SetChildValue(Binding.BindableObject bindable, Binding.BindableProperty property, object value)
+        {
+            bindable.SetValueCore(property, value, SetValueFlags.None, SetValuePrivateFlags.ManuallySet, false);
+        }
+        internal static void OnChildPropertyChanged(Binding.BindableObject bindable, object oldValue, object newValue)
+        {
+            View view = bindable as View;
+            view?.Layout?.RequestLayout();
+        }
     }
 }
\ No newline at end of file