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.
96 Dispose(DisposeTypes.Explicit);
100 /// Dispose Explict or Implicit
102 protected virtual void Dispose(DisposeTypes type)
109 if (type == DisposeTypes.Explicit)
111 //Called by User code
112 //Release your own managed resources here.
113 //You should release all of your own disposable objects here.
116 //Release your own unmanaged resources here.
117 //You should not access any managed member here except static instance.
118 //because the execution order of Finalizes is non-deterministic.
120 if (unmanagedLayoutController.Handle != global::System.IntPtr.Zero)
122 Interop.LayoutController.delete_LayoutController(unmanagedLayoutController);
123 unmanagedLayoutController = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
129 // Traverse through children from the provided root.
130 // If a child has no layout but is a pure View then assign a default layout and continue traversal.
131 // If child has no layout and not a pure View then assign a LayoutItem that terminates the layouting (leaf),
132 private void AutomaticallyAssignLayouts(View rootNode)
134 for (uint i = 0; i < rootNode.ChildCount; i++)
136 View view = rootNode.GetChildAt(i);
137 if (rootNode.Layout == null )
139 if (rootNode.GetType() == typeof(View))
141 rootNode.Layout = new LayoutGroup();
142 AutomaticallyAssignLayouts(rootNode);
146 rootNode.Layout = new LayoutItem();
152 // Traverse the tree looking for a root node that is a layout.
153 // Once found, it's children can be assigned Layouts and the Measure process started.
154 private void FindRootLayouts(View rootNode)
156 if (rootNode.Layout != null)
158 // rootNode has a layout, ensure all children have default layouts or layout items.
159 AutomaticallyAssignLayouts(rootNode);
160 // rootNode has a layout, start measuring and layouting from here.
161 MeasureAndLayout(rootNode);
165 // Search children of supplied node for a layout.
166 for (uint i = 0; i < rootNode.ChildCount; i++)
168 View view = rootNode.GetChildAt(i);
169 FindRootLayouts(view);
174 // Starts of the actual measuring and layouting from the given root node.
175 // Can be called from multiple starting roots but in series.
176 void MeasureAndLayout(View root)
180 // Get parent MeasureSpecification, this could be the Window or View with an exact size.
181 Container parentNode = root.GetParent();
183 Position2D rootPosition = root.Position2D;
184 View parentView = parentNode as View;
187 // Get parent View's Size. If using Legacy size negotiation then should have been set already.
188 rootSize = new Size2D(parentView.Size2D.Width, parentView.Size2D.Height);
192 // Parent not a View so assume it's a Layer which is the size of the window.
193 rootSize = new Size2D(_window.Size.Width, _window.Size.Height);
196 // Determine measure specification for root.
197 // The root layout policy could be an exact size, be match parent or wrap children.
198 // If wrap children then at most it can be the root parent size.
199 // If match parent then should be root parent size.
200 // If exact then should be that size limited by the root parent size.
202 LayoutLength width = new LayoutLength(rootSize.Width);
203 LayoutLength height = new LayoutLength(rootSize.Height);
204 MeasureSpecification.ModeType widthMode = MeasureSpecification.ModeType.AtMost;
205 MeasureSpecification.ModeType heightMode = MeasureSpecification.ModeType.AtMost;
207 if ( root.WidthSpecification >= 0 )
209 // exact size provided so match width exactly
210 width = new LayoutLength(root.WidthSpecification);
211 widthMode = MeasureSpecification.ModeType.Exactly;
213 else if (root.WidthSpecification == LayoutParamPolicies.MatchParent)
216 widthMode = MeasureSpecification.ModeType.Exactly;
219 if (root.HeightSpecification >= 0 )
221 // exact size provided so match height exactly
222 height = new LayoutLength(root.HeightSpecification);
223 heightMode = MeasureSpecification.ModeType.Exactly;
225 else if (root.HeightSpecification == LayoutParamPolicies.MatchParent)
227 heightMode = MeasureSpecification.ModeType.Exactly;
230 MeasureSpecification parentWidthSpecification =
231 new MeasureSpecification( width, widthMode);
233 MeasureSpecification parentHeightSpecification =
234 new MeasureSpecification( height, heightMode);
236 // Start at root with it's parent's widthSpecification and heightSpecification
237 MeasureHierarchy(root, parentWidthSpecification, parentHeightSpecification);
239 // Start at root which was just measured.
240 PerformLayout( root, new LayoutLength(rootPosition.X),
241 new LayoutLength(rootPosition.Y),
242 new LayoutLength(rootPosition.X) + root.Layout.MeasuredWidth.Size,
243 new LayoutLength(rootPosition.Y) + root.Layout.MeasuredHeight.Size );
248 /// Entry point into the C# Layouting that starts the Processing
250 private void Process(int id)
252 // First layer in the Window should be the default layer (index 0 )
253 uint numberOfLayers = _window.LayerCount;
254 for (uint layerIndex = 0; layerIndex < numberOfLayers; layerIndex++)
256 Layer layer = _window.GetLayer(layerIndex);
257 for (uint i = 0; i < layer.ChildCount; i++)
259 View view = layer.GetChildAt(i);
260 FindRootLayouts(view);
267 /// Starts measuring the tree, starting from the root layout.
269 private void MeasureHierarchy(View root, MeasureSpecification widthSpec, MeasureSpecification heightSpec)
271 // Does this View have a layout?
272 // Yes - measure the layout. It will call this method again for each of it's children.
273 // No - reached leaf or no layouts set
275 // If in a leaf View with no layout, it's natural size is bubbled back up.
277 if (root.Layout != null)
279 root.Layout.Measure(widthSpec, heightSpec);
284 /// Performs the layouting positioning
286 private void PerformLayout(View root, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
288 if(root.Layout != null)
290 root.Layout.Layout(left, top, right, bottom);
293 } // class LayoutController
295 } // namespace Tizen.NUI