[NUI] Integreation from dalihub (#988)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Layouting / FlexLayout.cs
1 /* Copyright (c) 2019 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
22 namespace Tizen.NUI
23 {
24     /// <summary>
25     /// [Draft] This class implements a flex layout.
26     /// The flex layout implementation is based on open source Facebook Yoga layout engine.
27     /// For more information about the flex layout API and how to use it please refer to https://yogalayout.com/docs/
28     /// We implement the subset of the API in the class below.
29     /// </summary>
30     internal class FlexLayout : LayoutGroup,  global::System.IDisposable
31     {
32         float Flex{ get; set;}
33         int AlignSelf{get; set;}
34
35         private global::System.Runtime.InteropServices.HandleRef swigCPtr;
36         private bool swigCMemOwn;
37         private bool disposed;
38         private bool isDisposeQueued = false;
39
40         private IntPtr _rootFlex;  // Pointer to the unmanged flex layout class.
41
42         public struct MeasuredSize
43         {
44           public MeasuredSize(float x, float y)
45           {
46             width = x;
47             height = y;
48           }
49           float width;
50           float height;
51         };
52
53         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
54         internal delegate MeasuredSize ChildMeasureCallback( global::System.IntPtr child, float width, int measureModeWidth, float height, int measureModeHeight );
55
56         event ChildMeasureCallback measureChildDelegate; // Stores a delegate to the child measure callback. Used for all children of this FlexLayout.
57
58         internal FlexLayout(global::System.IntPtr cPtr, bool cMemoryOwn)
59         {
60             swigCMemOwn = cMemoryOwn;
61             swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
62             _rootFlex = Interop.FlexLayout.FlexLayout_New();
63             measureChildDelegate = new ChildMeasureCallback(measureChild);
64         }
65
66         internal static global::System.Runtime.InteropServices.HandleRef getCPtr(FlexLayout obj)
67         {
68             return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
69         }
70
71         public void Dispose()
72         {
73             // Throw exception if Dispose() is called in separate thread.
74             if (!Window.IsInstalled())
75             {
76                 throw new System.InvalidOperationException("This API called from separate thread. This API must be called from MainThread.");
77             }
78
79             if (isDisposeQueued)
80             {
81                 Dispose(DisposeTypes.Implicit);
82             }
83             else
84             {
85                 Dispose(DisposeTypes.Explicit);
86                 System.GC.SuppressFinalize(this);
87             }
88         }
89
90         protected virtual void Dispose(DisposeTypes type)
91         {
92             if (disposed)
93             {
94                 return;
95             }
96
97             if (type == DisposeTypes.Explicit)
98             {
99                 // Called by User
100                 // Release your own managed resources here.
101                 // You should release all of your own disposable objects here.
102
103             }
104
105             // Release your own unmanaged resources here.
106             // You should not access any managed member here except static instance.
107             // because the execution order of Finalizes is non-deterministic.
108             if (swigCPtr.Handle != global::System.IntPtr.Zero)
109             {
110                 if (swigCMemOwn)
111                 {
112                     swigCMemOwn = false;
113                     Interop.FlexLayout.delete_FlexLayout(swigCPtr);
114                 }
115                 swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
116             }
117             disposed = true;
118         }
119
120         /// <summary>
121         /// [Draft] Creates a FlexLayout object.
122         /// </summary>
123         public FlexLayout() : this(Interop.FlexLayout.FlexLayout_New(), true)
124         {
125             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
126         }
127
128         internal static FlexLayout DownCast(BaseHandle handle)
129         {
130             FlexLayout ret = new FlexLayout(Interop.FlexLayout.FlexLayout_DownCast(BaseHandle.getCPtr(handle)), true);
131             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
132             return ret;
133         }
134
135         internal FlexLayout(FlexLayout other) : this(Interop.FlexLayout.new_FlexLayout__SWIG_1(FlexLayout.getCPtr(other)), true)
136         {
137             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
138         }
139
140         internal FlexLayout Assign(FlexLayout other)
141         {
142             FlexLayout ret = new FlexLayout(Interop.FlexLayout.FlexLayout_Assign(swigCPtr, FlexLayout.getCPtr(other)), false);
143             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
144             return ret;
145         }
146
147         internal void SetFlexDirection(FlexLayout.FlexDirection flexDirection)
148         {
149             Interop.FlexLayout.FlexLayout_SetFlexDirection(swigCPtr, (int)flexDirection);
150             RequestLayout();
151         }
152
153         internal FlexLayout.FlexDirection GetFlexDirection()
154         {
155             FlexLayout.FlexDirection ret = (FlexLayout.FlexDirection)Interop.FlexLayout.FlexLayout_GetFlexDirection(swigCPtr);
156             return ret;
157
158         }
159
160         internal void SetFlexJustification(FlexLayout.FlexJustification flexJustification)
161         {
162             Interop.FlexLayout.FlexLayout_SetFlexJustification(swigCPtr, (int)flexJustification);
163             RequestLayout();
164         }
165
166         internal FlexLayout.FlexJustification GetFlexJustification()
167         {
168             FlexLayout.FlexJustification ret = (FlexLayout.FlexJustification)Interop.FlexLayout.FlexLayout_GetFlexJustification(swigCPtr);
169             return ret;
170         }
171
172         internal void SetFlexWrap(FlexLayout.FlexWrapType flexWrap)
173         {
174             Interop.FlexLayout.FlexLayout_SetFlexWrap(swigCPtr, (int)flexWrap);
175             RequestLayout();
176         }
177
178         internal FlexLayout.FlexWrapType GetFlexWrap()
179         {
180             FlexLayout.FlexWrapType ret = (FlexLayout.FlexWrapType)Interop.FlexLayout.FlexLayout_GetFlexWrap(swigCPtr);
181             return ret;
182         }
183
184         internal void SetFlexAlignment(FlexLayout.AlignmentType flexAlignment)
185         {
186             Interop.FlexLayout.FlexLayout_SetFlexAlignment(swigCPtr, (int)flexAlignment);
187             RequestLayout();
188         }
189
190         internal FlexLayout.AlignmentType GetFlexAlignment()
191         {
192             FlexLayout.AlignmentType ret = (FlexLayout.AlignmentType)Interop.FlexLayout.FlexLayout_GetFlexAlignment(swigCPtr);
193             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
194             return ret;
195         }
196
197         internal void SetFlexItemsAlignment(FlexLayout.AlignmentType flexAlignment)
198         {
199             Interop.FlexLayout.FlexLayout_SetFlexItemsAlignment(swigCPtr, (int)flexAlignment);
200             RequestLayout();
201         }
202
203         internal FlexLayout.AlignmentType GetFlexItemsAlignment()
204         {
205             FlexLayout.AlignmentType ret = (FlexLayout.AlignmentType)Interop.FlexLayout.FlexLayout_GetFlexItemsAlignment(swigCPtr);
206             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
207             return ret;
208         }
209
210         /// <summary>
211         /// [Draft] Get/Set the flex direction in the layout.
212         /// The direction of the main-axis which determines the direction that flex items are laid out.
213         /// </summary>
214         public FlexDirection Direction
215         {
216             get
217             {
218                 return GetFlexDirection();
219             }
220             set
221             {
222                 SetFlexDirection(value);
223             }
224         }
225
226         /// <summary>
227         /// [Draft] Get/Set the justification in the layout.
228         /// </summary>
229         public FlexJustification Justification
230         {
231             get
232             {
233                 return GetFlexJustification();
234             }
235             set
236             {
237                 SetFlexJustification(value);
238             }
239         }
240
241         /// <summary>
242         /// [Draft] Get/Set the wrap in the layout.
243         /// </summary>
244         public FlexWrapType WrapType
245         {
246             get
247             {
248                 return GetFlexWrap();
249             }
250             set
251             {
252                 SetFlexWrap(value);
253             }
254         }
255
256         /// <summary>
257         /// [Draft] Get/Set the alignment of the layout content.
258         /// </summary>
259         public AlignmentType Alignment
260         {
261             get
262             {
263                 return GetFlexAlignment();
264             }
265             set
266             {
267                 SetFlexAlignment(value);
268             }
269         }
270
271         /// <summary>
272         /// [Draft] Get/Set the alignment of the layout items.
273         /// </summary>
274         public AlignmentType ItemsAlignment
275         {
276             get
277             {
278                 return GetFlexItemsAlignment();
279             }
280             set
281             {
282                 SetFlexItemsAlignment(value);
283             }
284         }
285
286         /// <summary>
287         /// [Draft] Enumeration for the direction of the main axis in the flex container.
288         /// This determines the direction that flex items are laid out in the flex container.
289         /// </summary>
290         public enum FlexDirection
291         {
292             /// <summary>
293             /// The flexible items are displayed vertically as a column
294             /// </summary>
295             Column,
296             /// <summary>
297             /// The flexible items are displayed vertically as a column, but in reverse order
298             /// </summary>
299             ColumnReverse,
300             /// <summary>
301             /// The flexible items are displayed horizontally as a row
302             /// </summary>
303             Row,
304             /// <summary>
305             /// The flexible items are displayed horizontally as a row, but in reverse order
306             /// </summary>
307             RowReverse
308         }
309
310         /// <summary>
311         /// [Draft] Enumeration for the alignment of the flex items when the items do not use all available space on the main-axis.
312         /// </summary>
313         public enum FlexJustification
314         {
315             /// <summary>
316             /// Items are positioned at the beginning of the container
317             /// </summary>
318             FlexStart,
319             /// <summary>
320             /// Items are positioned at the center of the container
321             /// </summary>
322             Center,
323             /// <summary>
324             /// Items are positioned at the end of the container
325             /// </summary>
326             FlexEnd,
327             /// <summary>
328             /// Items are positioned with equal space between the lines
329             /// </summary>
330             SpaceBetween,
331             /// <summary>
332             /// Items are positioned with equal space before, between, and after the lines
333             /// </summary>
334             SpaceAround
335         }
336
337         /// <summary>
338         /// [Draft] Enumeration for the wrap type of the flex container when there is no enough room for all the items on one flex line.
339         /// </summary>
340         public enum FlexWrapType
341         {
342             /// <summary>
343             /// Flex items laid out in single line (shrunk to fit the flex container along the main axis)
344             /// </summary>
345             NoWrap,
346             /// <summary>
347             /// Flex items laid out in multiple lines if needed
348             /// </summary>
349             Wrap
350         }
351
352         /// <summary>
353         /// [Draft] 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.
354         /// </summary>
355         public enum AlignmentType
356         {
357             /// <summary>
358             /// Inherits the same alignment from the parent
359             /// </summary>
360             Auto,
361             /// <summary>
362             /// At the beginning of the container
363             /// </summary>
364             FlexStart,
365             /// <summary>
366             /// At the center of the container
367             /// </summary>
368             Center,
369             /// <summary>
370             /// At the end of the container
371             /// </summary>
372             FlexEnd,
373             /// <summary>
374             /// Stretch to fit the container
375             /// </summary>
376             Stretch
377         }
378
379         private MeasuredSize measureChild(global::System.IntPtr child, float width, int measureModeWidth, float height, int measureModeHeight)
380         {
381             View view = Registry.GetManagedBaseHandleFromNativePtr(child) as View;
382             Size2D viewSize = new Size2D(8,8);
383             if(view)
384             {
385               viewSize = view.NaturalSize2D;
386             }
387             return new MeasuredSize(viewSize.Width,viewSize.Height);
388         }
389
390         void InsertChild( LayoutItem child )
391         {
392             // Store created node for child
393             Interop.FlexLayout.FlexLayout_AddChild(swigCPtr, View.getCPtr(child.Owner), measureChildDelegate, _children.Count-1);
394         }
395
396         protected override void OnChildAdd(LayoutItem child)
397         {
398             InsertChild(child);
399         }
400
401         protected override void OnChildRemove(LayoutItem child)
402         {
403             // When child View is removed from it's parent View (that is a Layout) then remove it from the layout too.
404             // FlexLayout refers to the child as a View not LayoutItem.
405             Interop.FlexLayout.FlexLayout_RemoveChild(swigCPtr, child);
406         }
407
408         protected override void OnMeasure( MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec )
409         {
410             bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
411             Extents padding = Owner.Padding;
412             Extents margin = Owner.Margin;
413
414             Interop.FlexLayout.FlexLayout_SetMargin(swigCPtr, Extents.getCPtr(margin));
415             Interop.FlexLayout.FlexLayout_SetPadding(swigCPtr, Extents.getCPtr(padding));
416
417             float width = 0.0f;
418             float height = 0.0f;
419
420             if( widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly ||  widthMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost )
421             {
422                 width = widthMeasureSpec.Size.AsDecimal();
423             }
424
425             if ( heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly || heightMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost )
426             {
427                 height = heightMeasureSpec.Size.AsDecimal();
428             }
429
430             Interop.FlexLayout.FlexLayout_CalculateLayout( swigCPtr, width, height, isLayoutRtl );
431
432             SetMeasuredDimensions( GetDefaultSize( new LayoutLength( (float)Interop.FlexLayout.FlexLayout_GetWidth(swigCPtr) ), widthMeasureSpec ),
433                                    GetDefaultSize( new LayoutLength( (float)Interop.FlexLayout.FlexLayout_GetHeight(swigCPtr) ), heightMeasureSpec ) );
434         }
435
436         protected override void OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
437         {
438
439             bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
440             LayoutLength width = right - left;
441             LayoutLength height = bottom - top;
442
443             // Call to FlexLayout implementation to calculate layout values for later retrieval.
444             Interop.FlexLayout.FlexLayout_CalculateLayout( swigCPtr, width.AsDecimal(), height.AsDecimal(), isLayoutRtl );
445
446             int count = _children.Count;
447             for( int childIndex = 0; childIndex < count; childIndex++)
448             {
449                 LayoutItem childLayout = _children[childIndex];
450                 if( childLayout != null )
451                 {
452                     // Get the frame for the child, start, top, end, bottom.
453                     Vector4 frame = new Vector4(Interop.FlexLayout.FlexLayout_GetNodeFrame(swigCPtr, childIndex ), true);
454                     childLayout.Layout( new LayoutLength(frame.X), new LayoutLength(frame.Y), new LayoutLength(frame.Z), new LayoutLength(frame.W) );
455                 }
456             }
457         }
458
459     } // FLexlayout
460 } // namesspace Tizen.NUI