[NUI] separate layouting logic of the independent children
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Layouting / FlexLayout.cs
1 /* Copyright (c) 2020 Samsung Electronics Co., Ltd.
2  *
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
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  *
15  */
16
17 using System;
18 using System.ComponentModel;
19 using Tizen.NUI.BaseComponents;
20 using System.Runtime.InteropServices;
21 using System.Diagnostics;
22 using Tizen.NUI.Binding;
23
24 namespace Tizen.NUI
25 {
26     /// <summary>
27     /// This class implements a flex layout.
28     /// The flex layout implementation is based on open source Facebook Yoga layout engine.
29     /// For more information about the flex layout API and how to use it please refer to https://yogalayout.com/docs/
30     /// We implement the subset of the API in the class below.
31     /// </summary>
32     public class FlexLayout : LayoutGroup, global::System.IDisposable
33     {
34         /// <summary>
35         /// FlexItemProperty
36         /// </summary>
37         [EditorBrowsable(EditorBrowsableState.Never)]
38         internal static readonly BindableProperty FlexItemProperty = BindableProperty.CreateAttached("FlexItem", typeof(HandleRef), typeof(FlexLayout), default(HandleRef));
39
40         /// <summary>
41         /// FlexAlignmentSelfProperty
42         /// </summary>
43         [EditorBrowsable(EditorBrowsableState.Never)]
44         public static readonly BindableProperty FlexAlignmentSelfProperty = BindableProperty.CreateAttached("FlexAlignmentSelf", typeof(AlignmentType), typeof(FlexLayout), AlignmentType.Auto, validateValue: ValidateEnum((int)AlignmentType.Auto, (int)AlignmentType.Stretch), propertyChanged: OnChildPropertyChanged);
45
46         /// <summary>
47         /// FlexPositionTypeProperty
48         /// </summary>
49         [EditorBrowsable(EditorBrowsableState.Never)]
50         public static readonly BindableProperty FlexPositionTypeProperty = BindableProperty.CreateAttached("FlexPositionType", typeof(PositionType), typeof(FlexLayout), PositionType.Relative, validateValue: ValidateEnum((int)PositionType.Relative, (int)PositionType.Absolute),
51         propertyChanged: (bindable, oldValue, newValue) =>
52         {
53             if (bindable is View view)
54             {
55                 view.ExcludeLayouting = (PositionType)newValue == PositionType.Absolute;
56             }
57         },
58         defaultValueCreator: (bindable) =>
59         {
60             var view = (View)bindable;
61             if (view.ExcludeLayouting)
62                 return PositionType.Absolute;
63
64             return PositionType.Relative;
65         });
66
67
68         /// <summary>
69         /// AspectRatioProperty
70         /// </summary>
71         [EditorBrowsable(EditorBrowsableState.Never)]
72         public static readonly BindableProperty FlexAspectRatioProperty = BindableProperty.CreateAttached("FlexAspectRatio", typeof(float), typeof(FlexLayout), FlexUndefined, validateValue: (bindable, value) => (float)value > 0, propertyChanged: OnChildPropertyChanged);
73
74         /// <summary>
75         /// FlexBasisProperty
76         /// </summary>
77         [EditorBrowsable(EditorBrowsableState.Never)]
78         public static readonly BindableProperty FlexBasisProperty = BindableProperty.CreateAttached("FlexBasis", typeof(float), typeof(FlexLayout), FlexUndefined, validateValue: (bindable, value) => (float)value >= 0, propertyChanged: OnChildPropertyChanged);
79
80         /// <summary>
81         /// FlexShrinkProperty
82         /// </summary>
83         [EditorBrowsable(EditorBrowsableState.Never)]
84         public static readonly BindableProperty FlexShrinkProperty = BindableProperty.CreateAttached("FlexShrink", typeof(float), typeof(FlexLayout), 1.0f, validateValue: (bindable, value) => (float)value >= 0, propertyChanged: OnChildPropertyChanged);
85
86         /// <summary>
87         /// FlexGrowProperty
88         /// </summary>
89         [EditorBrowsable(EditorBrowsableState.Never)]
90         public static readonly BindableProperty FlexGrowProperty = BindableProperty.CreateAttached("FlexGrow", typeof(float), typeof(FlexLayout), FlexUndefined, validateValue: (bindable, value) => (float)value >= 0, propertyChanged: OnChildPropertyChanged);
91
92         private static bool LayoutDebugFlex = false; // Debug flag
93
94         private global::System.Runtime.InteropServices.HandleRef swigCPtr;
95         private bool swigCMemOwn;
96         private bool disposed;
97         private bool isDisposeQueued = false;
98
99         private MeasureSpecification parentMeasureSpecificationWidth;
100         private MeasureSpecification parentMeasureSpecificationHeight;
101
102         private IntPtr _rootFlex;  // Pointer to the unmanged flex layout class.
103
104         internal const float FlexUndefined = 10E20F; // Auto setting which is equivalent to WrapContent.
105
106         internal struct MeasuredSize
107         {
108             public MeasuredSize(float x, float y)
109             {
110                 width = x;
111                 height = y;
112             }
113             public float width;
114             public float height;
115         };
116
117         /// <summary>
118         /// Gets the alignment self of the child view.
119         /// </summary>
120         /// <seealso cref="SetFlexAlignmentSelf(View, AlignmentType)"/>
121         /// <param name="view">The child view.</param>
122         /// <returns> The value of alignment self.</returns>
123         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
124         /// <since_tizen> 8 </since_tizen>
125         public static AlignmentType GetFlexAlignmentSelf(View view) => GetAttachedValue<AlignmentType>(view, FlexAlignmentSelfProperty);
126
127         /// <summary>
128         /// Gets the position type of the child view.
129         /// </summary>
130         /// <seealso cref="SetFlexPositionType(View, PositionType)"/>
131         /// <param name="view">The child view.</param>
132         /// <returns> The value of position type</returns>
133         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
134         /// <since_tizen> 8 </since_tizen>
135         public static PositionType GetFlexPositionType(View view) => GetAttachedValue<PositionType>(view, FlexPositionTypeProperty);
136
137         /// <summary>
138         /// Gets the aspect ratio of the child view.
139         /// </summary>
140         /// <seealso cref="SetFlexAspectRatio(View, float)"/>
141         /// <param name="view">The child view.</param>
142         /// <returns> The value of aspect ratio</returns>
143         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
144         /// <since_tizen> 8 </since_tizen>
145         public static float GetFlexAspectRatio(View view) => GetAttachedValue<float>(view, FlexAspectRatioProperty);
146
147         /// <summary>
148         /// Gets the basis of the child view.
149         /// </summary>
150         /// <seealso cref="SetFlexBasis(View, float)"/>
151         /// <param name="view">The child view.</param>
152         /// <returns> The value of basis</returns>
153         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
154         /// <since_tizen> 8 </since_tizen>
155         public static float GetFlexBasis(View view) => GetAttachedValue<float>(view, FlexBasisProperty);
156
157         /// <summary>
158         /// Gets the shrink of the child view.
159         /// </summary>
160         /// <seealso cref="SetFlexShrink(View, float)"/>
161         /// <param name="view">The child view.</param>
162         /// <returns> The value of shrink</returns>
163         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
164         /// <since_tizen> 8 </since_tizen>
165         public static float GetFlexShrink(View view) => GetAttachedValue<float>(view, FlexShrinkProperty);
166
167         /// <summary>
168         /// Gets the grow of the child view.
169         /// </summary>
170         /// <seealso cref="SetFlexGrow(View, float)"/>
171         /// <param name="view">The child view.</param>
172         /// <returns> The value of grow</returns>
173         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
174         /// <since_tizen> 8 </since_tizen>
175         public static float GetFlexGrow(View view) => GetAttachedValue<float>(view, FlexGrowProperty);
176
177         /// <summary>
178         /// Sets the alignment self of the child view.<br/>
179         /// Alignment self has the same options and effect as <see cref="ItemsAlignment"/> but instead of affecting the children within a container,
180         /// you can apply this property to a single child to change its alignment within its parent.<br/>
181         /// Alignment self overrides any option set by the parent with <see cref="ItemsAlignment"/>.
182         /// </summary>
183         /// <param name="view">The child view.</param>
184         /// <param name="value">The value of alignment self.</param>
185         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
186         /// <exception cref="ArgumentException">The <paramref name="value"/> should be <see cref="AlignmentType"/>.</exception>
187         /// <since_tizen> 8 </since_tizen>
188         public static void SetFlexAlignmentSelf(View view, AlignmentType value) => SetAttachedValue(view, FlexAlignmentSelfProperty, value);
189
190         /// <summary>
191         /// Sets the position type of the child view.<br/>
192         /// The position type of an element defines how it is positioned within its parent.
193         /// By default a child is positioned relatively. This means a child is positioned according to the normal flow of the layout,
194         /// and then offset relative to that position based on the values of <see cref="View.Margin"/>.<br/>
195         /// When positioned absolutely an element doesn't take part in the normal layout flow.
196         /// It is instead laid out independent of its siblings. The position is determined based on the <see cref="View.Margin"/>.
197         /// </summary>
198         /// <param name="view">The child view.</param>
199         /// <param name="value">The value of position type.</param>
200         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
201         /// <exception cref="ArgumentException">The <paramref name="value"/> should be <see cref="PositionType"/>.</exception>
202         /// <since_tizen> 8 </since_tizen>
203         public static void SetFlexPositionType(View view, PositionType value) => SetAttachedValue(view, FlexPositionTypeProperty, value);
204
205         /// <summary>
206         /// Sets the aspect ratio of the child view.
207         /// Aspect ratio Defines as the ratio between the width and the height of a node
208         /// e.g. if a node has an aspect ratio of 2 then its width is twice the size of its height.<br/>
209         /// Aspect ratio accepts any floating point value > 0. this has higher priority than flex grow.
210         /// </summary>
211         /// <param name="view">The child view.</param>
212         /// <param name="value">The value of aspect ratio</param>
213         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
214         /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than or equal to 0.0f.</exception>
215         /// <since_tizen> 8 </since_tizen>
216         public static void SetFlexAspectRatio(View view, float value) => SetAttachedValue(view, FlexAspectRatioProperty, value);
217
218         /// <summary>
219         /// Sets the flex basis of the child view.
220         /// Flex basis is an axis-independent way of providing the default size of an item along the main axis.<br/>
221         /// Setting the flex basis of a child is similar to setting the width of that child if its parent is a container with <see cref="FlexDirection.Row"/>
222         /// or setting the height of a child if its parent is a container with <see cref="FlexDirection.Column"/>.<br/>
223         /// The flex basis of an item is the default size of that item, the size of the item before any flex grow and flex shrink calculations are performed.
224         /// </summary>
225         /// <param name="view">The child view.</param>
226         /// <param name="value">The value of basis</param>
227         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
228         /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than 0.0f.</exception>
229         /// <since_tizen> 8 </since_tizen>
230         public static void SetFlexBasis(View view, float value) => SetAttachedValue(view, FlexBasisProperty, value);
231
232         /// <summary>
233         /// Sets the flex shrink of the child view.
234         /// Flex shrink describes how to shrink children along the main axis in the case that the total size of the children overflow the size of the container on the main axis.<br/>
235         /// Flex shrink is very similar to flex grow and can be thought of in the same way if any overflowing size is considered to be negative remaining space.
236         /// These two properties also work well together by allowing children to grow and shrink as needed.<br/>
237         /// Flex shrink accepts any floating point value >= 0, with 1 being the default value. A container will shrink its children weighted by the child's flex shrink value.
238         /// </summary>
239         /// <param name="view">The child view.</param>
240         /// <param name="value">The value of shrink</param>
241         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
242         /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than 0.0f.</exception>
243         /// <since_tizen> 8 </since_tizen>
244         public static void SetFlexShrink(View view, float value) => SetAttachedValue(view, FlexShrinkProperty, value);
245
246         /// <summary>
247         /// Sets the grow of the child view.
248         /// Flex grow describes how any space within a container should be distributed among its children along the main axis.
249         /// After laying out its children, a container will distribute any remaining space according to the flex grow values specified by its children.<br/>
250         /// Flex grow accepts any floating point value >= 0, with 0 being the default value.<br/>
251         /// A container will distribute any remaining space among its children weighted by the child's flex grow value.
252         /// </summary>
253         /// <param name="view">The child view.</param>
254         /// <param name="value">The value of flex</param>
255         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
256         /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than 0.0f.</exception>
257         /// <since_tizen> 8 </since_tizen>
258         public static void SetFlexGrow(View view, float value) => SetAttachedValue(view, FlexGrowProperty, value);
259
260         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
261         internal delegate void ChildMeasureCallback(global::System.IntPtr child, float width, int measureModeWidth, float height, int measureModeHeight, out MeasuredSize measureSize);
262
263         event ChildMeasureCallback measureChildDelegate; // Stores a delegate to the child measure callback. Used for all children of this FlexLayout.
264
265         internal FlexLayout(global::System.IntPtr cPtr, bool cMemoryOwn)
266         {
267             swigCMemOwn = cMemoryOwn;
268             swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
269             _rootFlex = Interop.FlexLayout.FlexLayout_New();
270             measureChildDelegate = new ChildMeasureCallback(measureChild);
271         }
272
273         internal static global::System.Runtime.InteropServices.HandleRef getCPtr(FlexLayout obj)
274         {
275             return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
276         }
277
278         /// <inheritdoc/>
279         /// <since_tizen> 6 </since_tizen>
280         public void Dispose()
281         {
282             // Throw exception if Dispose() is called in separate thread.
283             if (!Window.IsInstalled())
284             {
285                 throw new System.InvalidOperationException("This API called from separate thread. This API must be called from MainThread.");
286             }
287
288             if (isDisposeQueued)
289             {
290                 Dispose(DisposeTypes.Implicit);
291             }
292             else
293             {
294                 Dispose(DisposeTypes.Explicit);
295                 System.GC.SuppressFinalize(this);
296             }
297         }
298
299         /// <inheritdoc/>
300         /// <since_tizen> 6 </since_tizen>
301         protected virtual void Dispose(DisposeTypes type)
302         {
303             if (disposed)
304             {
305                 return;
306             }
307
308             if (type == DisposeTypes.Explicit)
309             {
310                 // Called by User
311                 // Release your own managed resources here.
312                 // You should release all of your own disposable objects here.
313
314             }
315
316             // Release your own unmanaged resources here.
317             // You should not access any managed member here except static instance.
318             // because the execution order of Finalizes is non-deterministic.
319             if (swigCPtr.Handle != global::System.IntPtr.Zero)
320             {
321                 if (swigCMemOwn)
322                 {
323                     swigCMemOwn = false;
324                     Interop.FlexLayout.delete_FlexLayout(swigCPtr);
325                 }
326                 swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
327             }
328             disposed = true;
329         }
330
331         /// <summary>
332         /// Creates a FlexLayout object.
333         /// </summary>
334         /// <since_tizen> 6 </since_tizen>
335         public FlexLayout() : this(Interop.FlexLayout.FlexLayout_New(), true)
336         {
337             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
338         }
339
340         internal static FlexLayout DownCast(BaseHandle handle)
341         {
342             FlexLayout ret = new FlexLayout(Interop.FlexLayout.FlexLayout_DownCast(BaseHandle.getCPtr(handle)), true);
343             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
344             return ret;
345         }
346
347         internal FlexLayout(FlexLayout other) : this(Interop.FlexLayout.new_FlexLayout__SWIG_1(FlexLayout.getCPtr(other)), true)
348         {
349             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
350         }
351
352         internal FlexLayout.AlignmentType GetFlexAlignment()
353         {
354             FlexLayout.AlignmentType ret = (FlexLayout.AlignmentType)Interop.FlexLayout.FlexLayout_GetFlexAlignment(swigCPtr);
355             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
356             return ret;
357         }
358
359         internal FlexLayout.AlignmentType GetFlexItemsAlignment()
360         {
361             FlexLayout.AlignmentType ret = (FlexLayout.AlignmentType)Interop.FlexLayout.FlexLayout_GetFlexItemsAlignment(swigCPtr);
362             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
363             return ret;
364         }
365
366         /// <summary>
367         /// Gets/Sets the flex direction in the layout.
368         /// The direction of the main-axis which determines the direction that flex items are laid out.
369         /// </summary>
370         /// <exception cref="InvalidEnumArgumentException">Thrown when using invalid arguments that are enumerators.</exception>
371         /// <since_tizen> 6 </since_tizen>
372         public FlexDirection Direction
373         {
374             get => (FlexDirection)Interop.FlexLayout.FlexLayout_GetFlexDirection(swigCPtr);
375             set
376             {
377                 if (value < FlexDirection.Column || value > FlexDirection.RowReverse)
378                     throw new InvalidEnumArgumentException(nameof(Direction));
379
380                 Interop.FlexLayout.FlexLayout_SetFlexDirection(swigCPtr, (int)value);
381                 RequestLayout();
382             }
383         }
384
385         /// <summary>
386         /// Gets/Sets the justification in the layout.
387         /// Justify content describes how to align children within the main axis of their container.<br/>
388         /// For example, you can use this property to center a child horizontally within a container with <see cref="Direction"/> set to <see cref="FlexDirection.Row"/>
389         /// or vertically within a container with <see cref="Direction"/> set to <see cref="FlexDirection.Column"/>.
390         /// </summary>
391         /// <exception cref="InvalidEnumArgumentException">Thrown when using invalid arguments that are enumerators.</exception>
392         /// <since_tizen> 6 </since_tizen>
393         public FlexJustification Justification
394         {
395             get => (FlexJustification)Interop.FlexLayout.FlexLayout_GetFlexJustification(swigCPtr);
396             set
397             {
398                 if (value < FlexJustification.FlexStart || value > FlexJustification.SpaceAround)
399                     throw new InvalidEnumArgumentException(nameof(Justification));
400
401                 Interop.FlexLayout.FlexLayout_SetFlexJustification(swigCPtr, (int)value);
402                 RequestLayout();
403             }
404         }
405
406         /// <summary>
407         /// Gets/Sets the wrap in the layout.
408         /// The flex wrap property is set on containers and controls what happens when children overflow the size of the container along the main axis.<br/>
409         /// By default children are forced into a single line (which can shrink elements).<br/>
410         /// If wrapping is allowed items are wrapped into multiple lines along the main axis if needed. wrap reverse behaves the same, but the order of the lines is reversed.<br/>
411         /// When wrapping lines <see cref="Alignment"/> can be used to specify how the lines are placed in the container.
412         /// </summary>
413         /// <exception cref="InvalidEnumArgumentException">Thrown when using invalid arguments that are enumerators.</exception>
414         /// <since_tizen> 6 </since_tizen>
415         public FlexWrapType WrapType
416         {
417             get => (FlexWrapType)Interop.FlexLayout.FlexLayout_GetFlexWrap(swigCPtr);
418             set
419             {
420                 if (value != FlexWrapType.NoWrap && value != FlexWrapType.Wrap)
421                     throw new InvalidEnumArgumentException(nameof(WrapType));
422
423                 Interop.FlexLayout.FlexLayout_SetFlexWrap(swigCPtr, (int)value);
424                 RequestLayout();
425
426             }
427         }
428
429         /// <summary>
430         /// Gets/Sets the alignment of the layout content.
431         /// Alignment defines the distribution of lines along the cross-axis.<br/>
432         /// This only has effect when items are wrapped to multiple lines using flex wrap.
433         /// </summary>
434         /// <exception cref="InvalidEnumArgumentException">Thrown when using invalid arguments that are enumerators.</exception>
435         /// <since_tizen> 6 </since_tizen>
436         public AlignmentType Alignment
437         {
438             get => GetFlexAlignment();
439             set
440             {
441                 if (value < AlignmentType.Auto || value > AlignmentType.Stretch)
442                     throw new InvalidEnumArgumentException(nameof(Alignment));
443
444                 Interop.FlexLayout.FlexLayout_SetFlexAlignment(swigCPtr, (int)value);
445                 RequestLayout();
446             }
447         }
448
449         /// <summary>
450         /// Gets/Sets the alignment of the layout items.
451         /// Items alignment describes how to align children along the cross axis of their container.<br/>
452         /// Align items is very similar to <see cref="Justification"/> but instead of applying to the main axis, align items applies to the cross axis.
453         /// </summary>
454         /// <exception cref="InvalidEnumArgumentException">Thrown when using invalid arguments that are enumerators.</exception>
455         /// <since_tizen> 6 </since_tizen>
456         public AlignmentType ItemsAlignment
457         {
458             get => GetFlexItemsAlignment();
459             set
460             {
461                 if (value < AlignmentType.Auto || value > AlignmentType.Stretch)
462                     throw new InvalidEnumArgumentException(nameof(ItemsAlignment));
463
464                 Interop.FlexLayout.FlexLayout_SetFlexItemsAlignment(swigCPtr, (int)value);
465                 RequestLayout();
466             }
467         }
468
469         /// <summary>
470         /// Enumeration for the direction of the main axis in the flex container.
471         /// This determines the direction that flex items are laid out in the flex container.
472         /// </summary>
473         /// <since_tizen> 6 </since_tizen>
474         public enum FlexDirection
475         {
476             /// <summary>
477             /// The flexible items are displayed vertically as a column
478             /// </summary>
479             Column,
480             /// <summary>
481             /// The flexible items are displayed vertically as a column, but in reverse order
482             /// </summary>
483             ColumnReverse,
484             /// <summary>
485             /// The flexible items are displayed horizontally as a row
486             /// </summary>
487             Row,
488             /// <summary>
489             /// The flexible items are displayed horizontally as a row, but in reverse order
490             /// </summary>
491             RowReverse
492         }
493
494         /// <summary>
495         /// Enumeration for the alignment of the flex items when the items do not use all available space on the main-axis.
496         /// </summary>
497         /// <since_tizen> 6 </since_tizen>
498         public enum FlexJustification
499         {
500             /// <summary>
501             /// Items are positioned at the beginning of the container.
502             /// </summary>
503             FlexStart,
504             /// <summary>
505             /// Items are positioned at the center of the container.
506             /// </summary>
507             Center,
508             /// <summary>
509             /// Items are positioned at the end of the container.
510             /// </summary>
511             FlexEnd,
512             /// <summary>
513             /// Items are positioned with equal space between the lines.
514             /// </summary>
515             SpaceBetween,
516             /// <summary>
517             /// Items are positioned with equal space before, between, and after the lines.<br/>
518             /// Compared to <see cref="FlexJustification.SpaceBetween"/> using <see cref="FlexJustification.SpaceAround"/>
519             /// will result in space being distributed to the beginning of the first child and end of the last child.
520             /// </summary>
521             SpaceAround
522         }
523
524         /// <summary>
525         /// Enumeration for the wrap type of the flex container when there is no enough room for all the items on one flex line.
526         /// </summary>
527         /// <since_tizen> 6 </since_tizen>
528         public enum FlexWrapType
529         {
530             /// <summary>
531             /// Flex items laid out in single line (shrunk to fit the flex container along the main axis)
532             /// </summary>
533             NoWrap,
534             /// <summary>
535             /// Flex items laid out in multiple lines if needed
536             /// </summary>
537             Wrap
538         }
539
540         /// <summary>
541         /// Enumeration for the alignment of the flex items or lines when the items or lines do not use all the available space on the cross-axis.
542         /// </summary>
543         /// <since_tizen> 6 </since_tizen>
544         public enum AlignmentType
545         {
546             /// <summary>
547             /// Inherits the same alignment from the parent
548             /// </summary>
549             Auto,
550             /// <summary>
551             /// At the beginning of the container
552             /// </summary>
553             FlexStart,
554             /// <summary>
555             /// At the center of the container
556             /// </summary>
557             Center,
558             /// <summary>
559             /// At the end of the container
560             /// </summary>
561             FlexEnd,
562             /// <summary>
563             /// Stretch to fit the container
564             /// </summary>
565             Stretch
566         }
567
568         /// <summary>
569         /// Enumeration for the position type of the flex item how it is positioned within its parent.
570         /// </summary>
571         /// <since_tizen> 8 </since_tizen>
572         public enum PositionType
573         {
574             /// <summary>
575             /// Flex items laid out relatively.
576             /// </summary>
577             Relative,
578             /// <summary>
579             /// Flex items laid out absolutely.
580             /// </summary>
581             Absolute
582         }
583
584         private void measureChild(global::System.IntPtr childPtr, float width, int measureModeWidth, float height, int measureModeHeight, out MeasuredSize measureSize)
585         {
586             // We need to measure child layout
587             View child = Registry.GetManagedBaseHandleFromNativePtr(childPtr) as View;
588             // independent child will be measured in LayoutGroup.OnMeasureIndependentChildren().
589             if (child?.ExcludeLayouting ?? true)
590             {
591                 measureSize.width = 0;
592                 measureSize.height = 0;
593                 return;
594             }
595
596             LayoutItem childLayout = child.Layout;
597
598             MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(
599                                     new MeasureSpecification(
600                                         new LayoutLength(parentMeasureSpecificationWidth.Size - (child.Margin.Start + child.Margin.End)),
601                                         parentMeasureSpecificationWidth.Mode),
602                                     new LayoutLength(Padding.Start + Padding.End),
603                                     new LayoutLength(child.WidthSpecification));
604
605             MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(
606                                     new MeasureSpecification(
607                                         new LayoutLength(parentMeasureSpecificationHeight.Size - (child.Margin.Top + child.Margin.Bottom)),
608                                         parentMeasureSpecificationHeight.Mode),
609                                     new LayoutLength(Padding.Top + Padding.Bottom),
610                                     new LayoutLength(child.HeightSpecification));
611
612             childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
613
614             measureSize.width = childLayout.MeasuredWidth.Size.AsRoundedValue();
615             measureSize.height = childLayout.MeasuredHeight.Size.AsRoundedValue();
616         }
617
618         void InsertChild(LayoutItem child)
619         {
620             // Store created node for child
621             IntPtr childPtr = Interop.FlexLayout.FlexLayout_AddChildWithMargin(swigCPtr, View.getCPtr(child.Owner), Extents.getCPtr(child.Owner.Margin), measureChildDelegate, LayoutChildren.Count - 1);
622             HandleRef childHandleRef = new HandleRef(child.Owner, childPtr);
623             SetAttachedValue(child.Owner, FlexItemProperty, childHandleRef);
624         }
625
626         /// <summary>
627         /// Callback when child is added to container.<br />
628         /// Derived classes can use this to set their own child properties on the child layout's owner.<br />
629         /// </summary>
630         /// <param name="child">The Layout child.</param>
631         /// <exception cref="ArgumentNullException"> Thrown when child is null. </exception>
632         /// <since_tizen> 6 </since_tizen>
633         protected override void OnChildAdd(LayoutItem child)
634         {
635             if (null == child)
636             {
637                 throw new ArgumentNullException(nameof(child));
638             }
639             InsertChild(child);
640         }
641
642         /// <summary>
643         /// Callback when child is removed from container.<br />
644         /// </summary>
645         /// <param name="child">The Layout child.</param>
646         /// <since_tizen> 6 </since_tizen>
647         protected override void OnChildRemove(LayoutItem child)
648         {
649             // When child View is removed from it's parent View (that is a Layout) then remove it from the layout too.
650             // FlexLayout refers to the child as a View not LayoutItem.
651             Interop.FlexLayout.FlexLayout_RemoveChild(swigCPtr, child);
652         }
653
654         /// <summary>
655         /// Measure the layout and its content to determine the measured width and the measured height.<br />
656         /// </summary>
657         /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
658         /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
659         /// <since_tizen> 6 </since_tizen>
660         protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
661         {
662             bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
663             Extents padding = Owner.Padding;
664
665             Interop.FlexLayout.FlexLayout_SetPadding(swigCPtr, Extents.getCPtr(padding));
666
667             float width = FlexUndefined; // Behaves as WrapContent (Flex Auto)
668             float height = FlexUndefined; // Behaves as WrapContent (Flex Auto)
669
670             if (widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly || widthMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost)
671             {
672                 width = widthMeasureSpec.Size.AsDecimal();
673             }
674
675             if (heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly || heightMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost)
676             {
677                 height = heightMeasureSpec.Size.AsDecimal();
678             }
679
680             // Save measureSpec to measure children.
681             // In other Layout, we can pass it as parameter to measuring child but in FlexLayout we can't
682             // because measurChild function is called by native callback.
683             parentMeasureSpecificationWidth = widthMeasureSpec;
684             parentMeasureSpecificationHeight = heightMeasureSpec;
685
686             Extents zeroMargin = new Extents();
687
688             // Assign child properties
689             for (int i = 0; i < LayoutChildren.Count; i++)
690             {
691                 LayoutItem layoutItem = LayoutChildren[i];
692                 View Child = layoutItem?.Owner;
693                 HandleRef childHandleRef = (HandleRef)Child.GetValue(FlexItemProperty);
694                 if (childHandleRef.Handle == IntPtr.Zero || Child == null)
695                     continue;
696
697                 AlignmentType flexAlignemnt = GetFlexAlignmentSelf(Child);
698                 PositionType positionType = GetFlexPositionType(Child);
699                 float flexAspectRatio = GetFlexAspectRatio(Child);
700                 float flexBasis = GetFlexBasis(Child);
701                 float flexShrink = GetFlexShrink(Child);
702                 float flexGrow = GetFlexGrow(Child);
703                 Extents childMargin = Child.ExcludeLayouting ? zeroMargin : layoutItem.Margin;
704
705                 Interop.FlexLayout.FlexLayout_SetMargin(childHandleRef, Extents.getCPtr(childMargin));
706                 Interop.FlexLayout.FlexLayout_SetFlexAlignmentSelf(childHandleRef, (int)flexAlignemnt);
707                 Interop.FlexLayout.FlexLayout_SetFlexPositionType(childHandleRef, (int)positionType);
708                 Interop.FlexLayout.FlexLayout_SetFlexAspectRatio(childHandleRef, flexAspectRatio);
709                 Interop.FlexLayout.FlexLayout_SetFlexBasis(childHandleRef, flexBasis);
710                 Interop.FlexLayout.FlexLayout_SetFlexShrink(childHandleRef, flexShrink);
711                 Interop.FlexLayout.FlexLayout_SetFlexGrow(childHandleRef, flexGrow);
712             }
713
714             Interop.FlexLayout.FlexLayout_CalculateLayout(swigCPtr, width, height, isLayoutRtl);
715             zeroMargin.Dispose();
716
717             LayoutLength flexLayoutWidth = new LayoutLength(Interop.FlexLayout.FlexLayout_GetWidth(swigCPtr));
718             LayoutLength flexLayoutHeight = new LayoutLength(Interop.FlexLayout.FlexLayout_GetHeight(swigCPtr));
719
720             Debug.WriteLineIf(LayoutDebugFlex, "FlexLayout OnMeasure width:" + flexLayoutWidth.AsRoundedValue()
721                                                 + " height:" + flexLayoutHeight.AsRoundedValue());
722
723             SetMeasuredDimensions(GetDefaultSize(flexLayoutWidth, widthMeasureSpec),
724                                    GetDefaultSize(flexLayoutHeight, heightMeasureSpec));
725         }
726
727         /// <summary>
728         /// Assign a size and position to each of its children.<br />
729         /// </summary>
730         /// <param name="changed">This is a new size or position for this layout.</param>
731         /// <param name="left">Left position, relative to parent.</param>
732         /// <param name="top"> Top position, relative to parent.</param>
733         /// <param name="right">Right position, relative to parent.</param>
734         /// <param name="bottom">Bottom position, relative to parent.</param>
735         /// <since_tizen> 6 </since_tizen>
736         protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
737         {
738
739             bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
740             LayoutLength width = right - left;
741             LayoutLength height = bottom - top;
742
743             // Call to FlexLayout implementation to calculate layout values for later retrieval.
744             Interop.FlexLayout.FlexLayout_CalculateLayout(swigCPtr, width.AsDecimal(), height.AsDecimal(), isLayoutRtl);
745
746             for (int childIndex = 0; childIndex < LayoutChildren.Count; childIndex++)
747             {
748                 LayoutItem childLayout = LayoutChildren[childIndex];
749                 if (!childLayout?.Owner?.ExcludeLayouting ?? false)
750                 {
751                     // Get the frame for the child, start, top, end, bottom.
752                     Vector4 frame = new Vector4(Interop.FlexLayout.FlexLayout_GetNodeFrame(swigCPtr, childIndex), true);
753                     childLayout.Layout(new LayoutLength(frame.X), new LayoutLength(frame.Y), new LayoutLength(frame.Z), new LayoutLength(frame.W));
754                 }
755             }
756         }
757     } // FLexlayout
758 } // namesspace Tizen.NUI