[NUI] Remove useless API in FlexLayout
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Layouting / FlexLayout.cs
1 /* Copyright (c) 2021 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
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 global::System.Runtime.InteropServices.HandleRef swigCPtr;
93         private bool swigCMemOwn;
94         private bool disposed;
95         private bool isDisposeQueued = false;
96
97         private MeasureSpecification parentMeasureSpecificationWidth;
98         private MeasureSpecification parentMeasureSpecificationHeight;
99
100         private IntPtr _rootFlex;  // Pointer to the unmanaged flex layout class.
101
102         internal const float FlexUndefined = 10E20F; // Auto setting which is equivalent to WrapContent.
103
104         internal struct MeasuredSize
105         {
106             public MeasuredSize(float x, float y)
107             {
108                 width = x;
109                 height = y;
110             }
111             public float width;
112             public float height;
113         };
114
115         /// <summary>
116         /// Gets the alignment self of the child view.
117         /// </summary>
118         /// <seealso cref="SetFlexAlignmentSelf(View, AlignmentType)"/>
119         /// <param name="view">The child view.</param>
120         /// <returns> The value of alignment self.</returns>
121         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
122         /// <since_tizen> 8 </since_tizen>
123         public static AlignmentType GetFlexAlignmentSelf(View view) => GetAttachedValue<AlignmentType>(view, FlexAlignmentSelfProperty);
124
125         /// <summary>
126         /// Gets the position type of the child view.
127         /// </summary>
128         /// <seealso cref="SetFlexPositionType(View, PositionType)"/>
129         /// <param name="view">The child view.</param>
130         /// <returns> The value of position type</returns>
131         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
132         /// <since_tizen> 8 </since_tizen>
133         public static PositionType GetFlexPositionType(View view) => GetAttachedValue<PositionType>(view, FlexPositionTypeProperty);
134
135         /// <summary>
136         /// Gets the aspect ratio of the child view.
137         /// </summary>
138         /// <seealso cref="SetFlexAspectRatio(View, float)"/>
139         /// <param name="view">The child view.</param>
140         /// <returns> The value of aspect ratio</returns>
141         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
142         /// <since_tizen> 8 </since_tizen>
143         public static float GetFlexAspectRatio(View view) => GetAttachedValue<float>(view, FlexAspectRatioProperty);
144
145         /// <summary>
146         /// Gets the basis of the child view.
147         /// </summary>
148         /// <seealso cref="SetFlexBasis(View, float)"/>
149         /// <param name="view">The child view.</param>
150         /// <returns> The value of basis</returns>
151         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
152         /// <since_tizen> 8 </since_tizen>
153         public static float GetFlexBasis(View view) => GetAttachedValue<float>(view, FlexBasisProperty);
154
155         /// <summary>
156         /// Gets the shrink of the child view.
157         /// </summary>
158         /// <seealso cref="SetFlexShrink(View, float)"/>
159         /// <param name="view">The child view.</param>
160         /// <returns> The value of shrink</returns>
161         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
162         /// <since_tizen> 8 </since_tizen>
163         public static float GetFlexShrink(View view) => GetAttachedValue<float>(view, FlexShrinkProperty);
164
165         /// <summary>
166         /// Gets the grow of the child view.
167         /// </summary>
168         /// <seealso cref="SetFlexGrow(View, float)"/>
169         /// <param name="view">The child view.</param>
170         /// <returns> The value of grow</returns>
171         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
172         /// <since_tizen> 8 </since_tizen>
173         public static float GetFlexGrow(View view) => GetAttachedValue<float>(view, FlexGrowProperty);
174
175         /// <summary>
176         /// Sets the alignment self of the child view.<br/>
177         /// Alignment self has the same options and effect as <see cref="ItemsAlignment"/> but instead of affecting the children within a container,
178         /// you can apply this property to a single child to change its alignment within its parent.<br/>
179         /// Alignment self overrides any option set by the parent with <see cref="ItemsAlignment"/>.
180         /// </summary>
181         /// <param name="view">The child view.</param>
182         /// <param name="value">The value of alignment self.</param>
183         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
184         /// <exception cref="ArgumentException">The <paramref name="value"/> should be <see cref="AlignmentType"/>.</exception>
185         /// <since_tizen> 8 </since_tizen>
186         public static void SetFlexAlignmentSelf(View view, AlignmentType value) => SetAttachedValue(view, FlexAlignmentSelfProperty, value);
187
188         /// <summary>
189         /// Sets the position type of the child view.<br/>
190         /// The position type of an element defines how it is positioned within its parent.
191         /// By default a child is positioned relatively. This means a child is positioned according to the normal flow of the layout,
192         /// and then offset relative to that position based on the values of <see cref="View.Margin"/>.<br/>
193         /// When positioned absolutely an element doesn't take part in the normal layout flow.
194         /// It is instead laid out independent of its siblings. The position is determined based on the <see cref="View.Margin"/>.
195         /// </summary>
196         /// <param name="view">The child view.</param>
197         /// <param name="value">The value of position type.</param>
198         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
199         /// <exception cref="ArgumentException">The <paramref name="value"/> should be <see cref="PositionType"/>.</exception>
200         /// <since_tizen> 8 </since_tizen>
201         public static void SetFlexPositionType(View view, PositionType value) => SetAttachedValue(view, FlexPositionTypeProperty, value);
202
203         /// <summary>
204         /// Sets the aspect ratio of the child view.
205         /// Aspect ratio Defines as the ratio between the width and the height of a node
206         /// e.g. if a node has an aspect ratio of 2 then its width is twice the size of its height.<br/>
207         /// Aspect ratio accepts any floating point value > 0. this has higher priority than flex grow.
208         /// </summary>
209         /// <param name="view">The child view.</param>
210         /// <param name="value">The value of aspect ratio</param>
211         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
212         /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than or equal to 0.0f.</exception>
213         /// <since_tizen> 8 </since_tizen>
214         public static void SetFlexAspectRatio(View view, float value) => SetAttachedValue(view, FlexAspectRatioProperty, value);
215
216         /// <summary>
217         /// Sets the flex basis of the child view.
218         /// Flex basis is an axis-independent way of providing the default size of an item along the main axis.<br/>
219         /// 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"/>
220         /// or setting the height of a child if its parent is a container with <see cref="FlexDirection.Column"/>.<br/>
221         /// 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.
222         /// </summary>
223         /// <param name="view">The child view.</param>
224         /// <param name="value">The value of basis</param>
225         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
226         /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than 0.0f.</exception>
227         /// <since_tizen> 8 </since_tizen>
228         public static void SetFlexBasis(View view, float value) => SetAttachedValue(view, FlexBasisProperty, value);
229
230         /// <summary>
231         /// Sets the flex shrink of the child view.
232         /// 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/>
233         /// 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.
234         /// These two properties also work well together by allowing children to grow and shrink as needed.<br/>
235         /// 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.
236         /// </summary>
237         /// <param name="view">The child view.</param>
238         /// <param name="value">The value of shrink</param>
239         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
240         /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than 0.0f.</exception>
241         /// <since_tizen> 8 </since_tizen>
242         public static void SetFlexShrink(View view, float value) => SetAttachedValue(view, FlexShrinkProperty, value);
243
244         /// <summary>
245         /// Sets the grow of the child view.
246         /// Flex grow describes how any space within a container should be distributed among its children along the main axis.
247         /// After laying out its children, a container will distribute any remaining space according to the flex grow values specified by its children.<br/>
248         /// Flex grow accepts any floating point value >= 0, with 0 being the default value.<br/>
249         /// A container will distribute any remaining space among its children weighted by the child's flex grow value.
250         /// </summary>
251         /// <param name="view">The child view.</param>
252         /// <param name="value">The value of flex</param>
253         /// <exception cref="ArgumentNullException">The <paramref name="view"/> cannot be null.</exception>
254         /// <exception cref="ArgumentException">The <paramref name="value"/> cannot be less than 0.0f.</exception>
255         /// <since_tizen> 8 </since_tizen>
256         public static void SetFlexGrow(View view, float value) => SetAttachedValue(view, FlexGrowProperty, value);
257
258         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
259         internal delegate void ChildMeasureCallback(global::System.IntPtr child, float width, int measureModeWidth, float height, int measureModeHeight, out MeasuredSize measureSize);
260
261         event ChildMeasureCallback measureChildDelegate; // Stores a delegate to the child measure callback. Used for all children of this FlexLayout.
262
263         internal FlexLayout(global::System.IntPtr cPtr, bool cMemoryOwn)
264         {
265             swigCMemOwn = cMemoryOwn;
266             swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
267             _rootFlex = Interop.FlexLayout.New();
268             measureChildDelegate = new ChildMeasureCallback(measureChild);
269         }
270
271         internal static global::System.Runtime.InteropServices.HandleRef getCPtr(FlexLayout obj)
272         {
273             return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
274         }
275
276         /// <summary>
277         /// Hidden API (Inhouse API).
278         /// Destructor.
279         /// </summary>
280         [EditorBrowsable(EditorBrowsableState.Never)]
281         ~FlexLayout() => Dispose(false);
282
283         /// <inheritdoc/>
284         /// <since_tizen> 6 </since_tizen>
285         public new void Dispose()
286         {
287             Dispose(true);
288             System.GC.SuppressFinalize(this);
289         }
290
291         /// <summary>
292         /// Hidden API (Inhouse API).
293         /// Dispose. 
294         /// </summary>
295         /// <remarks>
296         /// Following the guide of https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose.
297         /// This will replace "protected virtual void Dispose(DisposeTypes type)" which is exactly same in functionality.
298         /// </remarks>
299         /// <param name="disposing">true in order to free managed objects</param>
300         // Protected implementation of Dispose pattern.
301         [EditorBrowsable(EditorBrowsableState.Never)]
302         protected override void Dispose(bool disposing)
303         {
304             if (disposed)
305             {
306                 return;
307             }
308
309             if (disposing)
310             {
311                 // TODO: dispose managed state (managed objects).
312                 // Explicit call. user calls Dispose()
313
314                 //Throw exception if Dispose() is called in separate thread.
315                 if (!Window.IsInstalled())
316                 {
317                     throw new System.InvalidOperationException("This API called from separate thread. This API must be called from MainThread.");
318                 }
319
320                 if (isDisposeQueued)
321                 {
322                     Dispose(DisposeTypes.Implicit);
323                 }
324                 else
325                 {
326                     Dispose(DisposeTypes.Explicit);
327                 }
328             }
329             else
330             {
331                 // Implicit call. user doesn't call Dispose(), so this object is added into DisposeQueue to be disposed automatically.
332                 if (!isDisposeQueued)
333                 {
334                     isDisposeQueued = true;
335                     DisposeQueue.Instance.Add(this);
336                 }
337             }
338
339             // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
340             // TODO: set large fields to null.
341             base.Dispose(disposing);
342         }
343
344         /// <inheritdoc/>
345         /// <since_tizen> 6 </since_tizen>
346         protected virtual void Dispose(DisposeTypes type)
347         {
348             if (disposed)
349             {
350                 return;
351             }
352
353             if (type == DisposeTypes.Explicit)
354             {
355                 //Called by User
356                 //Release your own managed resources here.
357                 //You should release all of your own disposable objects here.
358             }
359
360             //Release your own unmanaged resources here.
361             //You should not access any managed member here except static instance.
362             //because the execution order of Finalizes is non-deterministic.
363             if (swigCPtr.Handle != global::System.IntPtr.Zero)
364             {
365                 if (swigCMemOwn)
366                 {
367                     swigCMemOwn = false;
368                     ReleaseSwigCPtr(swigCPtr);
369                 }
370                 swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
371             }
372
373             disposed = true;
374         }
375
376         /// <summary>
377         /// Hidden API (Inhouse API).
378         /// Release swigCPtr.
379         /// </summary>
380         /// This will not be public opened.
381         [EditorBrowsable(EditorBrowsableState.Never)]
382         protected virtual void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
383         {
384             Interop.FlexLayout.DeleteFlexLayout(swigCPtr);
385         }
386
387         /// <summary>
388         /// Creates a FlexLayout object.
389         /// </summary>
390         /// <since_tizen> 6 </since_tizen>
391         public FlexLayout() : this(Interop.FlexLayout.New(), true)
392         {
393             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
394         }
395
396         internal FlexLayout.AlignmentType GetFlexAlignment()
397         {
398             FlexLayout.AlignmentType ret = (FlexLayout.AlignmentType)Interop.FlexLayout.GetFlexAlignment(swigCPtr);
399             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
400             return ret;
401         }
402
403         internal FlexLayout.AlignmentType GetFlexItemsAlignment()
404         {
405             FlexLayout.AlignmentType ret = (FlexLayout.AlignmentType)Interop.FlexLayout.GetFlexItemsAlignment(swigCPtr);
406             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
407             return ret;
408         }
409
410         /// <summary>
411         /// Gets/Sets the flex direction in the layout.
412         /// The direction of the main-axis which determines the direction that flex items are laid out.
413         /// </summary>
414         /// <exception cref="InvalidEnumArgumentException">Thrown when using invalid arguments that are enumerators.</exception>
415         /// <since_tizen> 6 </since_tizen>
416         public FlexDirection Direction
417         {
418             get => (FlexDirection)Interop.FlexLayout.GetFlexDirection(swigCPtr);
419             set
420             {
421                 if (value < FlexDirection.Column || value > FlexDirection.RowReverse)
422                     throw new InvalidEnumArgumentException(nameof(Direction));
423
424                 Interop.FlexLayout.SetFlexDirection(swigCPtr, (int)value);
425                 RequestLayout();
426             }
427         }
428
429         /// <summary>
430         /// Gets/Sets the justification in the layout.
431         /// Justify content describes how to align children within the main axis of their container.<br/>
432         /// 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"/>
433         /// or vertically within a container with <see cref="Direction"/> set to <see cref="FlexDirection.Column"/>.
434         /// </summary>
435         /// <exception cref="InvalidEnumArgumentException">Thrown when using invalid arguments that are enumerators.</exception>
436         /// <since_tizen> 6 </since_tizen>
437         public FlexJustification Justification
438         {
439             get => (FlexJustification)Interop.FlexLayout.GetFlexJustification(swigCPtr);
440             set
441             {
442                 if (value < FlexJustification.FlexStart || value > FlexJustification.SpaceEvenly)
443                     throw new InvalidEnumArgumentException(nameof(Justification));
444
445                 Interop.FlexLayout.SetFlexJustification(swigCPtr, (int)value);
446                 RequestLayout();
447             }
448         }
449
450         /// <summary>
451         /// Gets/Sets the wrap in the layout.
452         /// 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/>
453         /// By default children are forced into a single line (which can shrink elements).<br/>
454         /// 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/>
455         /// When wrapping lines <see cref="Alignment"/> can be used to specify how the lines are placed in the container.
456         /// </summary>
457         /// <exception cref="InvalidEnumArgumentException">Thrown when using invalid arguments that are enumerators.</exception>
458         /// <since_tizen> 6 </since_tizen>
459         public FlexWrapType WrapType
460         {
461             get => (FlexWrapType)Interop.FlexLayout.GetFlexWrap(swigCPtr);
462             set
463             {
464                 if (value != FlexWrapType.NoWrap && value != FlexWrapType.Wrap)
465                     throw new InvalidEnumArgumentException(nameof(WrapType));
466
467                 Interop.FlexLayout.SetFlexWrap(swigCPtr, (int)value);
468                 RequestLayout();
469
470             }
471         }
472
473         /// <summary>
474         /// Gets/Sets the alignment of the layout content.
475         /// Alignment defines the distribution of lines along the cross-axis.<br/>
476         /// This only has effect when items are wrapped to multiple lines using flex wrap.
477         /// </summary>
478         /// <exception cref="InvalidEnumArgumentException">Thrown when using invalid arguments that are enumerators.</exception>
479         /// <since_tizen> 6 </since_tizen>
480         public AlignmentType Alignment
481         {
482             get => GetFlexAlignment();
483             set
484             {
485                 if (value < AlignmentType.Auto || value > AlignmentType.Stretch)
486                     throw new InvalidEnumArgumentException(nameof(Alignment));
487
488                 Interop.FlexLayout.SetFlexAlignment(swigCPtr, (int)value);
489                 RequestLayout();
490             }
491         }
492
493         /// <summary>
494         /// Gets/Sets the alignment of the layout items.
495         /// Items alignment describes how to align children along the cross axis of their container.<br/>
496         /// Align items is very similar to <see cref="Justification"/> but instead of applying to the main axis, align items applies to the cross axis.
497         /// </summary>
498         /// <exception cref="InvalidEnumArgumentException">Thrown when using invalid arguments that are enumerators.</exception>
499         /// <since_tizen> 6 </since_tizen>
500         public AlignmentType ItemsAlignment
501         {
502             get => GetFlexItemsAlignment();
503             set
504             {
505                 if (value < AlignmentType.Auto || value > AlignmentType.Stretch)
506                     throw new InvalidEnumArgumentException(nameof(ItemsAlignment));
507
508                 Interop.FlexLayout.SetFlexItemsAlignment(swigCPtr, (int)value);
509                 RequestLayout();
510             }
511         }
512
513         /// <summary>
514         /// Enumeration for the direction of the main axis in the flex container.
515         /// This determines the direction that flex items are laid out in the flex container.
516         /// </summary>
517         /// <since_tizen> 6 </since_tizen>
518         public enum FlexDirection
519         {
520             /// <summary>
521             /// The flexible items are displayed vertically as a column
522             /// </summary>
523             Column,
524             /// <summary>
525             /// The flexible items are displayed vertically as a column, but in reverse order
526             /// </summary>
527             ColumnReverse,
528             /// <summary>
529             /// The flexible items are displayed horizontally as a row
530             /// </summary>
531             Row,
532             /// <summary>
533             /// The flexible items are displayed horizontally as a row, but in reverse order
534             /// </summary>
535             RowReverse
536         }
537
538         /// <summary>
539         /// Enumeration for the alignment of the flex items when the items do not use all available space on the main-axis.
540         /// </summary>
541         /// <since_tizen> 6 </since_tizen>
542         public enum FlexJustification
543         {
544             /// <summary>
545             /// Items are positioned at the beginning of the container.
546             /// </summary>
547             FlexStart,
548             /// <summary>
549             /// Items are positioned at the center of the container.
550             /// </summary>
551             Center,
552             /// <summary>
553             /// Items are positioned at the end of the container.
554             /// </summary>
555             FlexEnd,
556             /// <summary>
557             /// Items are positioned with equal space between the lines.
558             /// </summary>
559             SpaceBetween,
560             /// <summary>
561             /// Items are positioned with equal space before, and after the lines.<br/>
562             /// </summary>
563             SpaceAround,
564             /// <summary>
565             /// Items are positioned with equal space before, between, and after the lines.<br/>
566             /// Spaces are distributed equally to the beginning of the first child, between each child, and the end of the last child.
567             /// </summary>
568             /// <since_tizen> 9 </since_tizen>
569             SpaceEvenly
570         }
571
572         /// <summary>
573         /// Enumeration for the wrap type of the flex container when there is no enough room for all the items on one flex line.
574         /// </summary>
575         /// <since_tizen> 6 </since_tizen>
576         public enum FlexWrapType
577         {
578             /// <summary>
579             /// Flex items laid out in single line (shrunk to fit the flex container along the main axis)
580             /// </summary>
581             NoWrap,
582             /// <summary>
583             /// Flex items laid out in multiple lines if needed
584             /// </summary>
585             Wrap
586         }
587
588         /// <summary>
589         /// 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.
590         /// </summary>
591         /// <since_tizen> 6 </since_tizen>
592         public enum AlignmentType
593         {
594             /// <summary>
595             /// Inherits the same alignment from the parent
596             /// </summary>
597             Auto,
598             /// <summary>
599             /// At the beginning of the container
600             /// </summary>
601             FlexStart,
602             /// <summary>
603             /// At the center of the container
604             /// </summary>
605             Center,
606             /// <summary>
607             /// At the end of the container
608             /// </summary>
609             FlexEnd,
610             /// <summary>
611             /// Stretch to fit the container
612             /// </summary>
613             Stretch
614         }
615
616         /// <summary>
617         /// Enumeration for the position type of the flex item how it is positioned within its parent.
618         /// </summary>
619         /// <since_tizen> 8 </since_tizen>
620         public enum PositionType
621         {
622             /// <summary>
623             /// Flex items laid out relatively.
624             /// </summary>
625             Relative,
626             /// <summary>
627             /// Flex items laid out absolutely.
628             /// </summary>
629             Absolute
630         }
631
632         private void measureChild(global::System.IntPtr childPtr, float width, int measureModeWidth, float height, int measureModeHeight, out MeasuredSize measureSize)
633         {
634             // We need to measure child layout
635             View child = Registry.GetManagedBaseHandleFromNativePtr(childPtr) as View;
636             // independent child will be measured in LayoutGroup.OnMeasureIndependentChildren().
637             if ((child == null) || (child?.ExcludeLayouting ?? true))
638             {
639                 measureSize.width = 0;
640                 measureSize.height = 0;
641                 return;
642             }
643
644             LayoutItem childLayout = child.Layout;
645             Extents margin = child.Margin;
646
647             MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(
648                                     new MeasureSpecification(
649                                         new LayoutLength(parentMeasureSpecificationWidth.Size - (margin.Start + margin.End)),
650                                         parentMeasureSpecificationWidth.Mode),
651                                     new LayoutLength(Padding.Start + Padding.End),
652                                     new LayoutLength(child.WidthSpecification));
653
654             MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(
655                                     new MeasureSpecification(
656                                         new LayoutLength(parentMeasureSpecificationHeight.Size - (margin.Top + margin.Bottom)),
657                                         parentMeasureSpecificationHeight.Mode),
658                                     new LayoutLength(Padding.Top + Padding.Bottom),
659                                     new LayoutLength(child.HeightSpecification));
660
661             childLayout?.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
662
663             measureSize.width = (childLayout == null) ? 0 : childLayout.MeasuredWidth.Size.AsRoundedValue();
664             measureSize.height = (childLayout == null) ? 0 : childLayout.MeasuredHeight.Size.AsRoundedValue();
665         }
666
667         void InsertChild(LayoutItem child)
668         {
669             // Store created node for child
670             IntPtr childPtr = Interop.FlexLayout.AddChildWithMargin(swigCPtr, View.getCPtr(child.Owner), Extents.getCPtr(child.Owner.Margin), measureChildDelegate, LayoutChildren.Count - 1);
671             HandleRef childHandleRef = new HandleRef(child.Owner, childPtr);
672             SetAttachedValue(child.Owner, FlexItemProperty, childHandleRef);
673         }
674
675         /// <summary>
676         /// Callback when child is added to container.<br />
677         /// Derived classes can use this to set their own child properties on the child layout's owner.<br />
678         /// </summary>
679         /// <param name="child">The Layout child.</param>
680         /// <exception cref="ArgumentNullException"> Thrown when child is null. </exception>
681         /// <since_tizen> 6 </since_tizen>
682         protected override void OnChildAdd(LayoutItem child)
683         {
684             if (null == child)
685             {
686                 throw new ArgumentNullException(nameof(child));
687             }
688             InsertChild(child);
689         }
690
691         /// <summary>
692         /// Callback when child is removed from container.<br />
693         /// </summary>
694         /// <param name="child">The Layout child.</param>
695         /// <exception cref="ArgumentNullException"> Thrown when child is null. </exception>
696         /// <since_tizen> 6 </since_tizen>
697         protected override void OnChildRemove(LayoutItem child)
698         {
699             if (null == child)
700             {
701                 throw new ArgumentNullException(nameof(child));
702             }
703             // When child View is removed from it's parent View (that is a Layout) then remove it from the layout too.
704             // FlexLayout refers to the child as a View not LayoutItem.
705             Interop.FlexLayout.RemoveChild(swigCPtr, child.Owner.SwigCPtr);
706         }
707
708         /// <summary>
709         /// Measure the layout and its content to determine the measured width and the measured height.<br />
710         /// </summary>
711         /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
712         /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
713         /// <since_tizen> 6 </since_tizen>
714         protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
715         {
716             bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
717             Extents padding = Owner.Padding;
718
719             Interop.FlexLayout.SetPadding(swigCPtr, Extents.getCPtr(padding));
720
721             float width = FlexUndefined; // Behaves as WrapContent (Flex Auto)
722             float height = FlexUndefined; // Behaves as WrapContent (Flex Auto)
723
724             if (widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
725             {
726                 width = widthMeasureSpec.Size.AsDecimal();
727             }
728
729             if (heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
730             {
731                 height = heightMeasureSpec.Size.AsDecimal();
732             }
733
734             // Save measureSpec to measure children.
735             // In other Layout, we can pass it as parameter to measuring child but in FlexLayout we can't
736             // because measurChild function is called by native callback.
737             parentMeasureSpecificationWidth = widthMeasureSpec;
738             parentMeasureSpecificationHeight = heightMeasureSpec;
739
740             Extents zeroMargin = new Extents();
741
742             // Assign child properties
743             for (int i = 0; i < LayoutChildren.Count; i++)
744             {
745                 LayoutItem layoutItem = LayoutChildren[i];
746                 View Child = layoutItem?.Owner;
747                 HandleRef childHandleRef = (HandleRef)Child.GetValue(FlexItemProperty);
748                 if (childHandleRef.Handle == IntPtr.Zero || Child == null)
749                     continue;
750
751                 AlignmentType flexAlignemnt = GetFlexAlignmentSelf(Child);
752                 PositionType positionType = GetFlexPositionType(Child);
753                 float flexAspectRatio = GetFlexAspectRatio(Child);
754                 float flexBasis = GetFlexBasis(Child);
755                 float flexShrink = GetFlexShrink(Child);
756                 float flexGrow = GetFlexGrow(Child);
757                 Extents childMargin = Child.ExcludeLayouting ? zeroMargin : layoutItem.Margin;
758
759                 Interop.FlexLayout.SetMargin(childHandleRef, Extents.getCPtr(childMargin));
760                 Interop.FlexLayout.SetFlexAlignmentSelf(childHandleRef, (int)flexAlignemnt);
761                 Interop.FlexLayout.SetFlexPositionType(childHandleRef, (int)positionType);
762                 Interop.FlexLayout.SetFlexAspectRatio(childHandleRef, flexAspectRatio);
763                 Interop.FlexLayout.SetFlexBasis(childHandleRef, flexBasis);
764                 Interop.FlexLayout.SetFlexShrink(childHandleRef, flexShrink);
765                 Interop.FlexLayout.SetFlexGrow(childHandleRef, flexGrow);
766             }
767
768             Interop.FlexLayout.CalculateLayout(swigCPtr, width, height, isLayoutRtl);
769             zeroMargin.Dispose();
770
771             LayoutLength flexLayoutWidth = new LayoutLength(Interop.FlexLayout.GetWidth(swigCPtr));
772             LayoutLength flexLayoutHeight = new LayoutLength(Interop.FlexLayout.GetHeight(swigCPtr));
773
774             NUILog.Debug("FlexLayout OnMeasure width:" + flexLayoutWidth.AsRoundedValue() + " height:" + flexLayoutHeight.AsRoundedValue());
775
776             SetMeasuredDimensions(GetDefaultSize(flexLayoutWidth, widthMeasureSpec),
777                                    GetDefaultSize(flexLayoutHeight, heightMeasureSpec));
778         }
779
780         /// <summary>
781         /// Assign a size and position to each of its children.<br />
782         /// </summary>
783         /// <param name="changed">This is a new size or position for this layout.</param>
784         /// <param name="left">Left position, relative to parent.</param>
785         /// <param name="top"> Top position, relative to parent.</param>
786         /// <param name="right">Right position, relative to parent.</param>
787         /// <param name="bottom">Bottom position, relative to parent.</param>
788         /// <since_tizen> 6 </since_tizen>
789         protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
790         {
791
792             bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
793             LayoutLength width = right - left;
794             LayoutLength height = bottom - top;
795
796             // Call to FlexLayout implementation to calculate layout values for later retrieval.
797             Interop.FlexLayout.CalculateLayout(swigCPtr, width.AsDecimal(), height.AsDecimal(), isLayoutRtl);
798
799             for (int childIndex = 0; childIndex < LayoutChildren.Count; childIndex++)
800             {
801                 LayoutItem childLayout = LayoutChildren[childIndex];
802                 if (!childLayout?.Owner?.ExcludeLayouting ?? false)
803                 {
804                     // Get the frame for the child, start, top, end, bottom.
805                     Vector4 frame = new Vector4(Interop.FlexLayout.GetNodeFrame(swigCPtr, childIndex), true);
806
807                     // Child view's size is calculated in OnLayout() without considering child layout's measured size unlike other layouts' OnLayout().
808                     // This causes that the grand child view's size is calculated incorrectly if the child and grand child have MatchParent Specification.
809                     // e.g. Let parent view's width be 200 and parent has 2 children.
810                     //      Then, child layout's measured width becomes 200 and child view's width becomes 100. (by dali-toolkit's YOGA APIs)
811                     //      Then, grand child layout's measured width becomes 200 and grand child view's width becomes 200. (by NUI Layout)
812                     //
813                     // To resolve the above issue, child layout's measured size is set with the child view's size calculated by dali-toolkit's YOGA APIs.
814                     MeasureSpecification widthSpec = new MeasureSpecification(new LayoutLength(frame.Z - frame.X), MeasureSpecification.ModeType.Exactly);
815                     MeasureSpecification heightSpec = new MeasureSpecification(new LayoutLength(frame.W - frame.Y), MeasureSpecification.ModeType.Exactly);
816                     MeasureChildWithoutPadding(childLayout, widthSpec, heightSpec);
817
818                     childLayout.Layout(new LayoutLength(frame.X), new LayoutLength(frame.Y), new LayoutLength(frame.Z), new LayoutLength(frame.W));
819                     frame.Dispose();
820                 }
821             }
822         }
823     } // FLexlayout
824 } // namesspace Tizen.NUI