2 using System.Collections.Generic;
3 using System.Collections.ObjectModel;
4 using System.Collections.Specialized;
5 using System.ComponentModel;
7 using Tizen.NUI.Binding.Internals;
8 using Tizen.NUI.BaseComponents;
10 namespace Tizen.NUI.Binding
12 [ContentProperty("Children")]
13 internal abstract class Layout<T> : Layout, IViewContainer<T> where T : View
15 readonly ElementCollection<T> _children;
19 _children = new ElementCollection<T>(InternalChildren);
22 public new IList<T> Children
24 get { return _children; }
27 protected virtual void OnAdded(T view)
31 protected override void OnChildAdded(Element child)
33 base.OnChildAdded(child);
35 var typedChild = child as T;
36 if (typedChild != null)
40 protected override void OnChildRemoved(Element child)
42 base.OnChildRemoved(child);
44 var typedChild = child as T;
45 if (typedChild != null)
46 OnRemoved(typedChild);
49 protected virtual void OnRemoved(T view)
54 internal abstract class Layout : View, ILayout, ILayoutController, IPaddingElement
56 public static readonly BindableProperty IsClippedToBoundsProperty = BindableProperty.Create("IsClippedToBounds", typeof(bool), typeof(Layout), false);
58 public static readonly BindableProperty CascadeInputTransparentProperty = BindableProperty.Create(
59 nameof(CascadeInputTransparent), typeof(bool), typeof(Layout), true);
61 public static new readonly BindableProperty PaddingProperty = PaddingElement.PaddingProperty;
63 static IList<KeyValuePair<Layout, int>> s_resolutionList = new List<KeyValuePair<Layout, int>>();
64 static bool s_relayoutInProgress;
67 Size _lastLayoutSize = new Size(-1, -1, 0);
69 ReadOnlyCollection<Element> _logicalChildren;
73 //if things were added in base ctor (through implicit styles), the items added aren't properly parented
74 if (InternalChildren.Count > 0)
75 InternalChildrenOnCollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, InternalChildren));
77 InternalChildren.CollectionChanged += InternalChildrenOnCollectionChanged;
80 public bool IsClippedToBounds
82 get { return (bool)GetValue(IsClippedToBoundsProperty); }
83 set { SetValue(IsClippedToBoundsProperty, value); }
86 public new Thickness Padding
88 get { return (Thickness)GetValue(PaddingElement.PaddingProperty); }
89 set { SetValue(PaddingElement.PaddingProperty, value); }
92 public bool CascadeInputTransparent
94 get { return (bool)GetValue(CascadeInputTransparentProperty); }
95 set { SetValue(CascadeInputTransparentProperty, value); }
98 Thickness IPaddingElement.PaddingDefaultValueCreator()
100 return default(Thickness);
103 void IPaddingElement.OnPaddingPropertyChanged(Thickness oldValue, Thickness newValue)
105 UpdateChildrenLayout();
108 internal ObservableCollection<Element> InternalChildren { get; } = new ObservableCollection<Element>();
110 internal override ReadOnlyCollection<Element> LogicalChildrenInternal
112 get { return _logicalChildren ?? (_logicalChildren = new ReadOnlyCollection<Element>(InternalChildren)); }
116 /// Raised when the layout of the Page has changed.
118 public event EventHandler LayoutChanged;
120 [EditorBrowsable(EditorBrowsableState.Never)]
121 public new IReadOnlyList<Element> Children
123 get { return InternalChildren; }
126 public void ForceLayout()
131 public static void LayoutChildIntoBoundingRegion(BaseHandle child, Rectangle region)
133 var view = child as View;
140 public void LowerChild(View view)
142 if (!InternalChildren.Contains(view) || (InternalChildren.First() as BaseHandle) == view)
145 InternalChildren.Move(InternalChildren.IndexOf(view), 0);
148 public void RaiseChild(View view)
150 if (!InternalChildren.Contains(view) || (InternalChildren.Last() as BaseHandle) == view)
153 InternalChildren.Move(InternalChildren.IndexOf(view), InternalChildren.Count - 1);
156 protected virtual void InvalidateLayout()
158 _hasDoneLayout = false;
163 protected abstract void LayoutChildren(double x, double y, double width, double height);
165 protected void OnChildMeasureInvalidated(object sender, EventArgs e)
167 InvalidationTrigger trigger = (e as InvalidationEventArgs)?.Trigger ?? InvalidationTrigger.Undefined;
168 OnChildMeasureInvalidated((BaseHandle)sender, trigger);
169 OnChildMeasureInvalidated();
172 protected virtual void OnChildMeasureInvalidated()
176 protected virtual bool ShouldInvalidateOnChildAdded(View child)
181 protected virtual bool ShouldInvalidateOnChildRemoved(View child)
186 protected void UpdateChildrenLayout()
188 _hasDoneLayout = true;
190 if (!ShouldLayoutChildren())
193 LayoutChanged?.Invoke(this, EventArgs.Empty);
196 internal static void LayoutChildIntoBoundingRegion(View child, Rectangle region, SizeRequest childSizeRequest)
200 internal virtual void OnChildMeasureInvalidated(BaseHandle child, InvalidationTrigger trigger)
202 ReadOnlyCollection<Element> children = LogicalChildrenInternal;
203 int count = children.Count;
204 for (var index = 0; index < count; index++)
206 var v = LogicalChildrenInternal[index] as BaseHandle;
213 var view = child as View;
216 //we can ignore the request if we are either fully constrained or when the size request changes and we were already fully constrainted
217 if ((trigger == InvalidationTrigger.MeasureChanged) ||
218 (trigger == InvalidationTrigger.SizeRequestChanged))
224 s_resolutionList.Add(new KeyValuePair<Layout, int>(this, GetElementDepth(this)));
225 if (!s_relayoutInProgress)
227 s_relayoutInProgress = true;
228 Device.BeginInvokeOnMainThread(() =>
230 // if thread safety mattered we would need to lock this and compareexchange above
231 IList<KeyValuePair<Layout, int>> copy = s_resolutionList;
232 s_resolutionList = new List<KeyValuePair<Layout, int>>();
233 s_relayoutInProgress = false;
238 static int GetElementDepth(Element view)
241 while (view.Parent != null)
249 void InternalChildrenOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
251 if (e.Action == NotifyCollectionChangedAction.Move)
256 if (e.OldItems != null)
258 foreach (object item in e.OldItems)
260 var v = item as View;
264 OnInternalRemoved(v);
268 if (e.NewItems != null)
270 foreach (object item in e.NewItems)
272 var v = item as View;
276 if ((item as BaseHandle) == this)
277 throw new InvalidOperationException("Can not add self to own child collection.");
284 void OnInternalAdded(View view)
286 var parent = view.GetParent() as Layout;
287 parent?.InternalChildren.Remove(view);
290 if (ShouldInvalidateOnChildAdded(view))
294 void OnInternalRemoved(View view)
296 OnChildRemoved(view);
297 if (ShouldInvalidateOnChildRemoved(view))
301 bool ShouldLayoutChildren()
303 if ( !LogicalChildrenInternal.Any() )
308 foreach (Element element in VisibleDescendants())
310 var visual = element as BaseHandle;