/* Copyright (c) 2019 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ using System; using System.ComponentModel; using Tizen.NUI.BaseComponents; using System.Runtime.InteropServices; namespace Tizen.NUI { /// /// [Draft] This class implements a flex layout. /// The flex layout implementation is based on open source Facebook Yoga layout engine. /// For more information about the flex layout API and how to use it please refer to https://yogalayout.com/docs/ /// We implement the subset of the API in the class below. /// public class FlexLayout : LayoutGroup, global::System.IDisposable { float Flex{ get; set;} int AlignSelf{get; set;} private global::System.Runtime.InteropServices.HandleRef swigCPtr; private bool swigCMemOwn; private bool disposed; private bool isDisposeQueued = false; private IntPtr _rootFlex; // Pointer to the unmanged flex layout class. internal struct MeasuredSize { public MeasuredSize(float x, float y) { width = x; height = y; } float width; float height; }; [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate MeasuredSize ChildMeasureCallback( global::System.IntPtr child, float width, int measureModeWidth, float height, int measureModeHeight ); event ChildMeasureCallback measureChildDelegate; // Stores a delegate to the child measure callback. Used for all children of this FlexLayout. internal FlexLayout(global::System.IntPtr cPtr, bool cMemoryOwn) { swigCMemOwn = cMemoryOwn; swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr); _rootFlex = Interop.FlexLayout.FlexLayout_New(); measureChildDelegate = new ChildMeasureCallback(measureChild); } internal static global::System.Runtime.InteropServices.HandleRef getCPtr(FlexLayout obj) { return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr; } /// /// Dispose. /// /// 6 public void Dispose() { // Throw exception if Dispose() is called in separate thread. if (!Window.IsInstalled()) { throw new System.InvalidOperationException("This API called from separate thread. This API must be called from MainThread."); } if (isDisposeQueued) { Dispose(DisposeTypes.Implicit); } else { Dispose(DisposeTypes.Explicit); System.GC.SuppressFinalize(this); } } /// /// Dispose. /// /// 6 protected virtual void Dispose(DisposeTypes type) { if (disposed) { return; } if (type == DisposeTypes.Explicit) { // Called by User // Release your own managed resources here. // You should release all of your own disposable objects here. } // Release your own unmanaged resources here. // You should not access any managed member here except static instance. // because the execution order of Finalizes is non-deterministic. if (swigCPtr.Handle != global::System.IntPtr.Zero) { if (swigCMemOwn) { swigCMemOwn = false; Interop.FlexLayout.delete_FlexLayout(swigCPtr); } swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero); } disposed = true; } /// /// [Draft] Creates a FlexLayout object. /// /// 6 public FlexLayout() : this(Interop.FlexLayout.FlexLayout_New(), true) { if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } internal static FlexLayout DownCast(BaseHandle handle) { FlexLayout ret = new FlexLayout(Interop.FlexLayout.FlexLayout_DownCast(BaseHandle.getCPtr(handle)), true); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return ret; } internal FlexLayout(FlexLayout other) : this(Interop.FlexLayout.new_FlexLayout__SWIG_1(FlexLayout.getCPtr(other)), true) { if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } internal FlexLayout Assign(FlexLayout other) { FlexLayout ret = new FlexLayout(Interop.FlexLayout.FlexLayout_Assign(swigCPtr, FlexLayout.getCPtr(other)), false); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return ret; } internal void SetFlexDirection(FlexLayout.FlexDirection flexDirection) { Interop.FlexLayout.FlexLayout_SetFlexDirection(swigCPtr, (int)flexDirection); RequestLayout(); } internal FlexLayout.FlexDirection GetFlexDirection() { FlexLayout.FlexDirection ret = (FlexLayout.FlexDirection)Interop.FlexLayout.FlexLayout_GetFlexDirection(swigCPtr); return ret; } internal void SetFlexJustification(FlexLayout.FlexJustification flexJustification) { Interop.FlexLayout.FlexLayout_SetFlexJustification(swigCPtr, (int)flexJustification); RequestLayout(); } internal FlexLayout.FlexJustification GetFlexJustification() { FlexLayout.FlexJustification ret = (FlexLayout.FlexJustification)Interop.FlexLayout.FlexLayout_GetFlexJustification(swigCPtr); return ret; } internal void SetFlexWrap(FlexLayout.FlexWrapType flexWrap) { Interop.FlexLayout.FlexLayout_SetFlexWrap(swigCPtr, (int)flexWrap); RequestLayout(); } internal FlexLayout.FlexWrapType GetFlexWrap() { FlexLayout.FlexWrapType ret = (FlexLayout.FlexWrapType)Interop.FlexLayout.FlexLayout_GetFlexWrap(swigCPtr); return ret; } internal void SetFlexAlignment(FlexLayout.AlignmentType flexAlignment) { Interop.FlexLayout.FlexLayout_SetFlexAlignment(swigCPtr, (int)flexAlignment); RequestLayout(); } internal FlexLayout.AlignmentType GetFlexAlignment() { FlexLayout.AlignmentType ret = (FlexLayout.AlignmentType)Interop.FlexLayout.FlexLayout_GetFlexAlignment(swigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return ret; } internal void SetFlexItemsAlignment(FlexLayout.AlignmentType flexAlignment) { Interop.FlexLayout.FlexLayout_SetFlexItemsAlignment(swigCPtr, (int)flexAlignment); RequestLayout(); } internal FlexLayout.AlignmentType GetFlexItemsAlignment() { FlexLayout.AlignmentType ret = (FlexLayout.AlignmentType)Interop.FlexLayout.FlexLayout_GetFlexItemsAlignment(swigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return ret; } /// /// [Draft] Get/Set the flex direction in the layout. /// The direction of the main-axis which determines the direction that flex items are laid out. /// /// 6 public FlexDirection Direction { get { return GetFlexDirection(); } set { SetFlexDirection(value); } } /// /// [Draft] Get/Set the justification in the layout. /// /// 6 public FlexJustification Justification { get { return GetFlexJustification(); } set { SetFlexJustification(value); } } /// /// [Draft] Get/Set the wrap in the layout. /// /// 6 public FlexWrapType WrapType { get { return GetFlexWrap(); } set { SetFlexWrap(value); } } /// /// [Draft] Get/Set the alignment of the layout content. /// /// 6 public AlignmentType Alignment { get { return GetFlexAlignment(); } set { SetFlexAlignment(value); } } /// /// [Draft] Get/Set the alignment of the layout items. /// /// 6 public AlignmentType ItemsAlignment { get { return GetFlexItemsAlignment(); } set { SetFlexItemsAlignment(value); } } /// /// [Draft] Enumeration for the direction of the main axis in the flex container. /// This determines the direction that flex items are laid out in the flex container. /// /// 6 public enum FlexDirection { /// /// The flexible items are displayed vertically as a column /// Column, /// /// The flexible items are displayed vertically as a column, but in reverse order /// ColumnReverse, /// /// The flexible items are displayed horizontally as a row /// Row, /// /// The flexible items are displayed horizontally as a row, but in reverse order /// RowReverse } /// /// [Draft] Enumeration for the alignment of the flex items when the items do not use all available space on the main-axis. /// /// 6 public enum FlexJustification { /// /// Items are positioned at the beginning of the container /// FlexStart, /// /// Items are positioned at the center of the container /// Center, /// /// Items are positioned at the end of the container /// FlexEnd, /// /// Items are positioned with equal space between the lines /// SpaceBetween, /// /// Items are positioned with equal space before, between, and after the lines /// SpaceAround } /// /// [Draft] Enumeration for the wrap type of the flex container when there is no enough room for all the items on one flex line. /// /// 6 public enum FlexWrapType { /// /// Flex items laid out in single line (shrunk to fit the flex container along the main axis) /// NoWrap, /// /// Flex items laid out in multiple lines if needed /// Wrap } /// /// [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. /// /// 6 public enum AlignmentType { /// /// Inherits the same alignment from the parent /// Auto, /// /// At the beginning of the container /// FlexStart, /// /// At the center of the container /// Center, /// /// At the end of the container /// FlexEnd, /// /// Stretch to fit the container /// Stretch } private MeasuredSize measureChild(global::System.IntPtr child, float width, int measureModeWidth, float height, int measureModeHeight) { View view = Registry.GetManagedBaseHandleFromNativePtr(child) as View; Size2D viewSize = new Size2D(8,8); if(view) { viewSize = view.NaturalSize2D; } return new MeasuredSize(viewSize.Width,viewSize.Height); } void InsertChild( LayoutItem child ) { // Store created node for child Interop.FlexLayout.FlexLayout_AddChild(swigCPtr, View.getCPtr(child.Owner), measureChildDelegate, LayoutChildren.Count-1); } /// /// Callback when child is added to container.
/// Derived classes can use this to set their own child properties on the child layout's owner.
///
/// The Layout child. /// 6 protected override void OnChildAdd(LayoutItem child) { InsertChild(child); } /// /// Callback when child is removed from container.
///
/// The Layout child. /// 6 protected override void OnChildRemove(LayoutItem child) { // When child View is removed from it's parent View (that is a Layout) then remove it from the layout too. // FlexLayout refers to the child as a View not LayoutItem. Interop.FlexLayout.FlexLayout_RemoveChild(swigCPtr, child); } /// /// Measure the layout and its content to determine the measured width and the measured height.
///
/// horizontal space requirements as imposed by the parent. /// vertical space requirements as imposed by the parent. /// 6 protected override void OnMeasure( MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec ) { bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL; Extents padding = Owner.Padding; Extents margin = Owner.Margin; Interop.FlexLayout.FlexLayout_SetMargin(swigCPtr, Extents.getCPtr(margin)); Interop.FlexLayout.FlexLayout_SetPadding(swigCPtr, Extents.getCPtr(padding)); float width = 0.0f; float height = 0.0f; if( widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly || widthMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost ) { width = widthMeasureSpec.Size.AsDecimal(); } if ( heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly || heightMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost ) { height = heightMeasureSpec.Size.AsDecimal(); } Interop.FlexLayout.FlexLayout_CalculateLayout( swigCPtr, width, height, isLayoutRtl ); SetMeasuredDimensions( GetDefaultSize( new LayoutLength( (float)Interop.FlexLayout.FlexLayout_GetWidth(swigCPtr) ), widthMeasureSpec ), GetDefaultSize( new LayoutLength( (float)Interop.FlexLayout.FlexLayout_GetHeight(swigCPtr) ), heightMeasureSpec ) ); } /// /// Assign a size and position to each of its children.
///
/// This is a new size or position for this layout. /// Left position, relative to parent. /// Top position, relative to parent. /// Right position, relative to parent. /// Bottom position, relative to parent. /// 6 protected override void OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom ) { bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL; LayoutLength width = right - left; LayoutLength height = bottom - top; // Call to FlexLayout implementation to calculate layout values for later retrieval. Interop.FlexLayout.FlexLayout_CalculateLayout( swigCPtr, width.AsDecimal(), height.AsDecimal(), isLayoutRtl ); int count = LayoutChildren.Count; for( int childIndex = 0; childIndex < count; childIndex++) { LayoutItem childLayout = LayoutChildren[childIndex]; if( childLayout != null ) { // Get the frame for the child, start, top, end, bottom. Vector4 frame = new Vector4(Interop.FlexLayout.FlexLayout_GetNodeFrame(swigCPtr, childIndex ), true); childLayout.Layout( new LayoutLength(frame.X), new LayoutLength(frame.Y), new LayoutLength(frame.Z), new LayoutLength(frame.W) ); } } } } // FLexlayout } // namesspace Tizen.NUI