2 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.ComponentModel;
20 using Tizen.NUI.BaseComponents;
21 using System.Runtime.InteropServices;
26 /// [Draft] The class that initiates the Measuring and Layouting of the tree,
27 /// It sets a callback that becomes the entry point into the C# Layouting.
29 internal class LayoutController : global::System.IDisposable
31 private global::System.Runtime.InteropServices.HandleRef unmanagedLayoutController;
33 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
34 internal delegate void Callback(int id);
36 event Callback mInstance;
38 //A Flat to check if it is already disposed.
39 protected bool disposed = false;
41 private Window _window;
43 /// Constructs a LayoutController which controls the measuring and layouting.<br />
44 /// <param name="window">Window attach this LayoutController to.</param>
46 public LayoutController(Window window)
48 global::System.IntPtr cPtr = Interop.LayoutController.LayoutController_New();
50 // Wrap cPtr in a managed handle.
51 unmanagedLayoutController = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
53 mInstance = new Callback(Process);
54 Interop.LayoutController.LayoutController_SetCallback(unmanagedLayoutController, mInstance);
58 /// Get the unique id of the LayoutController
62 return Interop.LayoutController.LayoutController_GetId(unmanagedLayoutController);
66 /// Request relayout of a LayoutItem and it's parent tree.
68 /// <param name="layoutItem">LayoutItem that is required to be laid out again.</param>
69 public void RequestLayout(LayoutItem layoutItem)
71 // Go up the tree and mark all parents to relayout
72 ILayoutParent layoutParent = layoutItem.GetParent();
73 if (layoutParent != null)
75 LayoutGroup layoutGroup = layoutParent as LayoutGroup;
76 if(! layoutGroup.LayoutRequested)
78 layoutGroup.RequestLayout();
85 /// Destructor which adds LayoutController to the Dispose queue.
89 Dispose(DisposeTypes.Explicit);
97 Dispose(DisposeTypes.Explicit);
98 System.GC.SuppressFinalize(this);
102 /// Dispose Explict or Implicit
104 protected virtual void Dispose(DisposeTypes type)
111 if (type == DisposeTypes.Explicit)
113 //Called by User code
114 //Release your own managed resources here.
115 //You should release all of your own disposable objects here.
118 //Release your own unmanaged resources here.
119 //You should not access any managed member here except static instance.
120 //because the execution order of Finalizes is non-deterministic.
122 if (unmanagedLayoutController.Handle != global::System.IntPtr.Zero)
124 Interop.LayoutController.delete_LayoutController(unmanagedLayoutController);
125 unmanagedLayoutController = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
131 // Traverse through children from the provided root.
132 // If a child has no layout but is a pure View then assign a default layout and continue traversal.
133 // If child has no layout and not a pure View then assign a LayoutItem that terminates the layouting (leaf),
134 private void AutomaticallyAssignLayouts(View rootNode)
136 for (uint i = 0; i < rootNode.ChildCount; i++)
138 View view = rootNode.GetChildAt(i);
139 if (rootNode.Layout == null )
141 if (rootNode.GetType() == typeof(View))
143 rootNode.Layout = new LayoutGroup();
144 AutomaticallyAssignLayouts(rootNode);
148 rootNode.Layout = new LayoutItem();
154 // Traverse the tree looking for a root node that is a layout.
155 // Once found, it's children can be assigned Layouts and the Measure process started.
156 private void FindRootLayouts(View rootNode)
158 if (rootNode.Layout != null)
160 Log.Info("NUI", "Found root:" + rootNode.Name + "\n");
161 // rootNode has a layout, ensure all children have default layouts or layout items.
162 AutomaticallyAssignLayouts(rootNode);
163 // rootNode has a layout, start measuring and layouting from here.
164 MeasureAndLayout(rootNode);
168 // Search children of supplied node for a layout.
169 for (uint i = 0; i < rootNode.ChildCount; i++)
171 View view = rootNode.GetChildAt(i);
172 FindRootLayouts(view);
177 // Starts of the actual measuring and layouting from the given root node.
178 // Can be called from multiple starting roots but in series.
179 void MeasureAndLayout(View root)
183 // Get parent MeasureSpecification, this could be the Window or View with an exact size.
184 Container parentNode = root.GetParent();
186 Position2D rootPosition = root.Position2D;
187 View parentView = parentNode as View;
190 // Get parent View's Size. If using Legacy size negotiation then should have been set already.
191 rootSize = new Size2D(parentView.Size2D.Width, parentView.Size2D.Height);
195 // Parent not a View so assume it's a Layer which is the size of the window.
196 rootSize = new Size2D(_window.Size.Width, _window.Size.Height);
199 // Determine measure specification for root.
200 // The root layout policy could be an exact size, be match parent or wrap children.
201 // If wrap children then at most it can be the root parent size.
202 // If match parent then should be root parent size.
203 // If exact then should be that size limited by the root parent size.
205 LayoutLength width = new LayoutLength(rootSize.Width);
206 LayoutLength height = new LayoutLength(rootSize.Height);
207 MeasureSpecification.ModeType widthMode = MeasureSpecification.ModeType.AtMost;
208 MeasureSpecification.ModeType heightMode = MeasureSpecification.ModeType.AtMost;
210 if (root.WidthSpecification >= 0 )
212 // exact size provided so match width exactly
213 width = new LayoutLength(root.WidthSpecification);
214 widthMode = MeasureSpecification.ModeType.Exactly;
216 else if (root.WidthSpecification == LayoutParamPolicies.MatchParent)
218 widthMode = MeasureSpecification.ModeType.Exactly;
221 if (root.HeightSpecification >= 0 )
223 // exact size provided so match height exactly
224 height = new LayoutLength(root.HeightSpecification);
225 heightMode = MeasureSpecification.ModeType.Exactly;
227 else if (root.HeightSpecification == LayoutParamPolicies.MatchParent)
229 heightMode = MeasureSpecification.ModeType.Exactly;
232 MeasureSpecification parentWidthSpecification =
233 new MeasureSpecification( width, widthMode);
235 MeasureSpecification parentHeightSpecification =
236 new MeasureSpecification( height, heightMode);
238 // Start at root with it's parent's widthSpecification and heightSpecification
239 MeasureHierarchy(root, parentWidthSpecification, parentHeightSpecification);
241 // Start at root which was just measured.
242 PerformLayout( root, new LayoutLength(rootPosition.X),
243 new LayoutLength(rootPosition.Y),
244 new LayoutLength(rootPosition.X) + root.Layout.MeasuredWidth.Size,
245 new LayoutLength(rootPosition.Y) + root.Layout.MeasuredHeight.Size );
250 /// Entry point into the C# Layouting that starts the Processing
252 private void Process(int id)
254 Layer defaultLayer = _window.GetDefaultLayer();
255 for (uint i = 0; i < defaultLayer.ChildCount; i++)
257 View view = defaultLayer.GetChildAt(i);
258 FindRootLayouts(view);
264 /// Starts measuring the tree, starting from the root layout.
266 private void MeasureHierarchy(View root, MeasureSpecification widthSpec, MeasureSpecification heightSpec)
268 // Does this View have a layout?
269 // Yes - measure the layout. It will call this method again for each of it's children.
270 // No - reached leaf or no layouts set
272 // If in a leaf View with no layout, it's natural size is bubbled back up.
274 if (root.Layout != null)
276 root.Layout.Measure(widthSpec, heightSpec);
281 /// Performs the layouting positioning
283 private void PerformLayout(View root, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
285 if(root.Layout != null)
287 root.Layout.Layout(left, top, right, bottom);
290 } // class LayoutController
292 } // namespace Tizen.NUI