2 * Copyright (c) 2017 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.Collections.Generic;
19 using System.Collections.ObjectModel;
20 using System.Collections.Specialized;
21 using System.ComponentModel;
23 using System.Threading;
24 using System.Threading.Tasks;
25 using Tizen.NUI.Internals;
26 using Tizen.NUI.Binding;
30 // [RenderWith(typeof(_PageRenderer))]
31 public class Page : /*VisualElement*/BaseHandle, ILayout, IPageController, IElementConfiguration<Page>, IPaddingElement
33 public const string BusySetSignalName = "Xamarin.BusySet";
35 public const string AlertSignalName = "Xamarin.SendAlert";
37 public const string ActionSheetSignalName = "Xamarin.ShowActionSheet";
39 internal static readonly BindableProperty IgnoresContainerAreaProperty = BindableProperty.Create("IgnoresContainerArea", typeof(bool), typeof(Page), false);
41 public static readonly BindableProperty BackgroundImageProperty = BindableProperty.Create("BackgroundImage", typeof(string), typeof(Page), default(string));
43 public static readonly BindableProperty IsBusyProperty = BindableProperty.Create("IsBusy", typeof(bool), typeof(Page), false, propertyChanged: (bo, o, n) => ((Page)bo).OnPageBusyChanged());
45 public static readonly BindableProperty PaddingProperty = PaddingElement.PaddingProperty;
47 public static readonly BindableProperty TitleProperty = BindableProperty.Create("Title", typeof(string), typeof(Page), null);
49 public static readonly BindableProperty IconProperty = BindableProperty.Create("Icon", typeof(FileImageSource), typeof(Page), default(FileImageSource));
51 readonly Lazy<PlatformConfigurationRegistry<Page>> _platformConfigurationRegistry;
54 Rectangle _containerArea;
56 bool _containerAreaSet;
60 ReadOnlyCollection<Element> _logicalChildren;
64 var toolbarItems = new ObservableCollection<ToolbarItem>();
65 toolbarItems.CollectionChanged += OnToolbarItemsCollectionChanged;
66 // ToolbarItems = toolbarItems;
67 InternalChildren.CollectionChanged += InternalChildrenOnCollectionChanged;
68 _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<Page>>(() => new PlatformConfigurationRegistry<Page>(this));
71 public string BackgroundImage
73 get { return (string)GetValue(BackgroundImageProperty); }
74 set { SetValue(BackgroundImageProperty, value); }
77 internal FileImageSource Icon
79 get { return (FileImageSource)GetValue(IconProperty); }
80 set { SetValue(IconProperty, value); }
85 get { return (bool)GetValue(IsBusyProperty); }
86 set { SetValue(IsBusyProperty, value); }
89 public Thickness Padding
91 get { return (Thickness)GetValue(PaddingElement.PaddingProperty); }
92 set { SetValue(PaddingElement.PaddingProperty, value); }
95 Thickness IPaddingElement.PaddingDefaultValueCreator()
97 return default(Thickness);
100 void IPaddingElement.OnPaddingPropertyChanged(Thickness oldValue, Thickness newValue)
102 UpdateChildrenLayout();
107 get { return (string)GetValue(TitleProperty); }
108 set { SetValue(TitleProperty, value); }
111 internal IList<ToolbarItem> ToolbarItems { get;/* internal set;*/ }
113 [EditorBrowsable(EditorBrowsableState.Never)]
114 public Rectangle ContainerArea
116 get { return _containerArea; }
119 if (_containerArea == value)
121 _containerAreaSet = true;
122 _containerArea = value;
127 [EditorBrowsable(EditorBrowsableState.Never)]
128 public bool IgnoresContainerArea
130 get { return (bool)GetValue(IgnoresContainerAreaProperty); }
131 set { SetValue(IgnoresContainerAreaProperty, value); }
134 [EditorBrowsable(EditorBrowsableState.Never)]
135 public ObservableCollection<Element> InternalChildren { get; } = new ObservableCollection<Element>();
137 internal override ReadOnlyCollection<Element> LogicalChildrenInternal =>
138 _logicalChildren ?? (_logicalChildren = new ReadOnlyCollection<Element>(InternalChildren));
140 public event EventHandler LayoutChanged;
142 public event EventHandler Appearing;
144 public event EventHandler Disappearing;
146 public Task<string> DisplayActionSheet(string title, string cancel, string destruction, params string[] buttons)
148 var args = new ActionSheetArguments(title, cancel, destruction, buttons);
149 MessagingCenter.Send(this, ActionSheetSignalName, args);
150 return args.Result.Task;
153 public Task DisplayAlert(string title, string message, string cancel)
155 return DisplayAlert(title, message, null, cancel);
158 public Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
160 if (string.IsNullOrEmpty(cancel))
161 throw new ArgumentNullException("cancel");
163 var args = new AlertArguments(title, message, accept, cancel);
164 MessagingCenter.Send(this, AlertSignalName, args);
165 return args.Result.Task;
168 public void ForceLayout()
170 // SizeAllocated(Width, Height);
173 public bool SendBackButtonPressed()
175 return OnBackButtonPressed();
178 protected virtual void LayoutChildren(double x, double y, double width, double height)
180 var area = new Rectangle((int)x, (int)y, (int)width, (int)height);
181 Rectangle originalArea = area;
182 if (_containerAreaSet)
184 area = ContainerArea;
185 area.X += (int)Padding.Left;
186 area.Y += (int)Padding.Right;
187 area.Width -= (int)Padding.HorizontalThickness;
188 area.Height -= (int)Padding.VerticalThickness;
189 area.Width = Math.Max(0, area.Width);
190 area.Height = Math.Max(0, area.Height);
193 List<Element> elements = LogicalChildren.ToList();
194 foreach (Element element in elements)
196 var child = element as /*VisualElement*/BaseHandle;
199 var page = child as Page;
200 // if (page != null && page.IgnoresContainerArea)
201 // Forms.Layout.LayoutChildIntoBoundingRegion(child, originalArea);
203 // Forms.Layout.LayoutChildIntoBoundingRegion(child, area);
207 protected virtual void OnAppearing()
211 protected virtual bool OnBackButtonPressed()
213 var application = RealParent as Application;
214 // if (application == null || this == application.MainPage)
217 var canceled = false;
218 EventHandler handler = (sender, args) => { canceled = true; };
219 // application.PopCanceled += handler;
220 Navigation.PopModalAsync().ContinueWith(t => { throw t.Exception; }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
222 // application.PopCanceled -= handler;
226 protected override void OnBindingContextChanged()
228 base.OnBindingContextChanged();
229 foreach (ToolbarItem toolbarItem in ToolbarItems)
231 SetInheritedBindingContext(toolbarItem, BindingContext);
235 protected virtual void OnChildMeasureInvalidated(object sender, EventArgs e)
237 InvalidationTrigger trigger = (e as InvalidationEventArgs)?.Trigger ?? InvalidationTrigger.Undefined;
238 OnChildMeasureInvalidated((/*VisualElement*/BaseHandle)sender, trigger);
241 protected virtual void OnDisappearing()
245 protected override void OnParentSet()
247 //if (!Application.IsApplicationOrNull(RealParent) && !(RealParent is Page))
248 // throw new InvalidOperationException("Parent of a Page must also be a Page");
252 // protected override void OnSizeAllocated(double width, double height)
254 // _allocatedFlag = true;
255 // //base.OnSizeAllocated(width, height);
256 // UpdateChildrenLayout();
259 protected void UpdateChildrenLayout()
261 if (!ShouldLayoutChildren())
264 var startingLayout = new List<Rectangle>(LogicalChildren.Count);
265 foreach (/*VisualElement*/BaseHandle c in LogicalChildren)
267 //startingLayout.Add(c.Bounds);
270 double x = Padding.Left;
271 double y = Padding.Top;
272 //double w = Math.Max(0, Width - Padding.HorizontalThickness);
273 //double h = Math.Max(0, Height - Padding.VerticalThickness);
275 //LayoutChildren(x, y, w, h);
277 for (var i = 0; i < LogicalChildren.Count; i++)
279 var c = (/*VisualElement*/BaseHandle)LogicalChildren[i];
281 // if (c.Bounds != startingLayout[i])
283 // LayoutChanged?.Invoke(this, EventArgs.Empty);
289 internal virtual void OnChildMeasureInvalidated(/*VisualElement*/BaseHandle child, InvalidationTrigger trigger)
291 var container = this as IPageContainer<Page>;
292 if (container != null)
294 Page page = container.CurrentPage;
295 if (page != null /*&& page.IsVisible && (!page.IsPlatformEnabled || !page.IsNativeStateConsistent)*/)
300 for (var i = 0; i < LogicalChildren.Count; i++)
302 var v = LogicalChildren[i] as /*VisualElement*/BaseHandle;
303 if (v != null /*&& v.IsVisible && (!v.IsPlatformEnabled || !v.IsNativeStateConsistent)*/)
308 _allocatedFlag = false;
309 // InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
310 if (!_allocatedFlag /*&& Width >= 0 && Height >= 0*/)
312 // SizeAllocated(Width, Height);
316 [EditorBrowsable(EditorBrowsableState.Never)]
317 public void SendAppearing()
325 MessagingCenter.Send(this, BusySetSignalName, true);
328 Appearing?.Invoke(this, EventArgs.Empty);
330 var pageContainer = this as IPageContainer<Page>;
331 pageContainer?.CurrentPage?.SendAppearing();
333 //FindApplication(this)?.OnPageAppearing(this);
336 [EditorBrowsable(EditorBrowsableState.Never)]
337 public void SendDisappearing()
342 _hasAppeared = false;
345 MessagingCenter.Send(this, BusySetSignalName, false);
347 var pageContainer = this as IPageContainer<Page>;
348 pageContainer?.CurrentPage?.SendDisappearing();
351 Disappearing?.Invoke(this, EventArgs.Empty);
353 //FindApplication(this)?.OnPageDisappearing(this);
356 Application FindApplication(Element element)
361 return (element.Parent is Application app) ? app : FindApplication(element.Parent);
364 void InternalChildrenOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
366 if (e.OldItems != null)
368 foreach (/*VisualElement*/BaseHandle item in e.OldItems.OfType</*VisualElement*/BaseHandle>())
369 OnInternalRemoved(item);
372 if (e.NewItems != null)
374 foreach (/*VisualElement*/BaseHandle item in e.NewItems.OfType</*VisualElement*/BaseHandle>())
375 OnInternalAdded(item);
379 void OnInternalAdded(/*VisualElement*/BaseHandle view)
381 // view.MeasureInvalidated += OnChildMeasureInvalidated;
384 // InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
387 void OnInternalRemoved(/*VisualElement*/BaseHandle view)
389 // view.MeasureInvalidated -= OnChildMeasureInvalidated;
391 OnChildRemoved(view);
394 void OnPageBusyChanged()
399 MessagingCenter.Send(this, BusySetSignalName, IsBusy);
402 void OnToolbarItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
404 if (args.Action != NotifyCollectionChangedAction.Add)
406 foreach (IElement item in args.NewItems)
410 bool ShouldLayoutChildren()
412 if (!LogicalChildren.Any()/* || Width <= 0 || Height <= 0 || !IsNativeStateConsistent*/)
415 var container = this as IPageContainer<Page>;
416 if (container?.CurrentPage != null)
418 // if (InternalChildren.Contains(container.CurrentPage))
419 // return container.CurrentPage.IsPlatformEnabled && container.CurrentPage.IsNativeStateConsistent;
424 for (var i = 0; i < LogicalChildren.Count; i++)
426 var v = LogicalChildren[i] as /*VisualElement*/BaseHandle;
427 if (v != null /*&& (!v.IsPlatformEnabled || !v.IsNativeStateConsistent)*/)
436 public IPlatformElementConfiguration<T, Page> On<T>() where T : IConfigPlatform
438 return _platformConfigurationRegistry.Value.On<T>();