[NUI] Adjust directory (#903)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / XamlBinding / Page.cs
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17 using System;
18 using System.Collections.Generic;
19 using System.Collections.ObjectModel;
20 using System.Collections.Specialized;
21 using System.ComponentModel;
22 using System.Linq;
23 using System.Threading;
24 using System.Threading.Tasks;
25 using Tizen.NUI.Binding.Internals;
26 using Tizen.NUI.Binding;
27
28 namespace Tizen.NUI
29 {
30     /// <summary>
31     /// A BaseHandle that occupies the entire screen.
32     /// </summary>
33     // [RenderWith(typeof(_PageRenderer))]
34     [EditorBrowsable(EditorBrowsableState.Never)]
35     public class Page : BaseHandle, IPageController, IElementConfiguration<Page>
36     {
37         /// <summary>
38         /// For internal use.
39         /// </summary>
40         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
41         [EditorBrowsable(EditorBrowsableState.Never)]
42         public const string BusySetSignalName = "NUI.BusySet";
43
44         /// <summary>
45         /// For internal use.
46         /// </summary>
47         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
48         [EditorBrowsable(EditorBrowsableState.Never)]
49         public const string AlertSignalName = "NUI.SendAlert";
50
51         /// <summary>
52         /// For internal use.
53         /// </summary>
54         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
55         [EditorBrowsable(EditorBrowsableState.Never)]
56         public const string ActionSheetSignalName = "NUI.ShowActionSheet";
57
58         internal static readonly BindableProperty IgnoresContainerAreaProperty = BindableProperty.Create("IgnoresContainerArea", typeof(bool), typeof(Page), false);
59
60         /// <summary>
61         /// Identifies the IsBusy property.
62         /// </summary>
63         internal static readonly BindableProperty IsBusyProperty = BindableProperty.Create("IsBusy", typeof(bool), typeof(Page), false, propertyChanged: (bo, o, n) => ((Page)bo).OnPageBusyChanged());
64
65         Rectangle _containerArea;
66
67         bool _hasAppeared;
68
69         ReadOnlyCollection<Element> _logicalChildren;
70
71         /// <summary>
72         /// Creates a new Page element with default values.
73         /// </summary>
74         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
75         [EditorBrowsable(EditorBrowsableState.Never)]
76         public Page()
77         {
78             // ToolbarItems = toolbarItems;
79             InternalChildren.CollectionChanged += InternalChildrenOnCollectionChanged;
80         }
81
82         /// <summary>
83         /// Marks the Page as busy. This will cause the platform specific global activity indicator to show a busy state.
84         /// </summary>
85         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
86         [EditorBrowsable(EditorBrowsableState.Never)]
87         public bool IsBusy
88         {
89             get { return (bool)GetValue(IsBusyProperty); }
90             set { SetValue(IsBusyProperty, value); }
91         }
92
93         /// <summary>
94         /// For internal use.
95         /// </summary>
96         [EditorBrowsable(EditorBrowsableState.Never)]
97         public Rectangle ContainerArea
98         {
99             get { return _containerArea; }
100             set
101             {
102                 if (_containerArea == value)
103                     return;
104
105                 _containerArea = value;
106                 ForceLayout();
107             }
108         }
109
110         /// <summary>
111         /// For internal use.
112         /// </summary>
113         [EditorBrowsable(EditorBrowsableState.Never)]
114         public bool IgnoresContainerArea
115         {
116             get { return (bool)GetValue(IgnoresContainerAreaProperty); }
117             set { SetValue(IgnoresContainerAreaProperty, value); }
118         }
119
120         /// <summary>
121         /// For internal use.
122         /// </summary>
123         [EditorBrowsable(EditorBrowsableState.Never)]
124         public ObservableCollection<Element> InternalChildren { get; } = new ObservableCollection<Element>();
125
126         internal override ReadOnlyCollection<Element> LogicalChildrenInternal =>
127             _logicalChildren ?? (_logicalChildren = new ReadOnlyCollection<Element>(InternalChildren));
128
129         /// <summary>
130         /// ndicates that the Page is about to appear.
131         /// </summary>
132         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
133         [EditorBrowsable(EditorBrowsableState.Never)]
134         public event EventHandler Appearing;
135
136         /// <summary>
137         /// Indicates that the Page is about to cease displaying.
138         /// </summary>
139         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
140         [EditorBrowsable(EditorBrowsableState.Never)]
141         public event EventHandler Disappearing;
142
143         /// <summary>
144         /// Displays a native platform action sheet, allowing the application user to choose from several buttons.
145         /// </summary>
146         /// <param name="title">Title of the displayed action sheet. Must not be null.</param>
147         /// <param name="cancel">Text to be displayed in the 'Cancel' button. Can be null to hide the cancel action.</param>
148         /// <param name="destruction">Text to be displayed in the 'Destruct' button. Can be null to hide the destructive option.</param>
149         /// <param name="buttons">Text labels for additional buttons. Must not be null.</param>
150         /// <returns>An awaitable Task that displays an action sheet and returns the Text of the button pressed by the user.</returns>
151         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
152         [EditorBrowsable(EditorBrowsableState.Never)]
153         public Task<string> DisplayActionSheet(string title, string cancel, string destruction, params string[] buttons)
154         {
155             var args = new ActionSheetArguments(title, cancel, destruction, buttons);
156             MessagingCenter.Send(this, ActionSheetSignalName, args);
157             return args.Result.Task;
158         }
159
160         /// <summary>
161         /// Presents an alert dialog to the application user with a single cancel button.
162         /// </summary>
163         /// <param name="title">The title of the alert dialog.</param>
164         /// <param name="message">The body text of the alert dialog.</param>
165         /// <param name="cancel">Text to be displayed on the 'Cancel' button.</param>
166         /// <returns></returns>
167         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
168         [EditorBrowsable(EditorBrowsableState.Never)]
169         public Task DisplayAlert(string title, string message, string cancel)
170         {
171             return DisplayAlert(title, message, null, cancel);
172         }
173
174         /// <summary>
175         /// resents an alert dialog to the application user with an accept and a cancel button.
176         /// </summary>
177         /// <param name="title">The title of the alert dialog.</param>
178         /// <param name="message">The body text of the alert dialog.</param>
179         /// <param name="accept">Text to be displayed on the 'Accept' button.</param>
180         /// <param name="cancel">Text to be displayed on the 'Cancel' button.</param>
181         /// <returns></returns>
182         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
183         [EditorBrowsable(EditorBrowsableState.Never)]
184         public Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
185         {
186             if (string.IsNullOrEmpty(cancel))
187                 throw new ArgumentNullException("cancel");
188
189             var args = new AlertArguments(title, message, accept, cancel);
190             MessagingCenter.Send(this, AlertSignalName, args);
191             return args.Result.Task;
192         }
193
194         /// <summary>
195         /// Forces the Page to perform a layout pass.
196         /// </summary>
197         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
198         [EditorBrowsable(EditorBrowsableState.Never)]
199         public void ForceLayout()
200         {
201         }
202
203         /// <summary>
204         /// Calls OnBackButtonPressed().
205         /// </summary>
206         /// <returns></returns>
207         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
208         [EditorBrowsable(EditorBrowsableState.Never)]
209         public bool SendBackButtonPressed()
210         {
211             return OnBackButtonPressed();
212         }
213
214         /// <summary>
215         /// When overridden, allows application developers to customize behavior immediately prior to the Page becoming visible.
216         /// </summary>
217         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
218         [EditorBrowsable(EditorBrowsableState.Never)]
219         protected virtual void OnAppearing()
220         {
221         }
222
223         /// <summary>
224         /// Application developers can override this method to provide behavior when the back button is pressed.
225         /// </summary>
226         /// <returns>true if consumed</returns>
227         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
228         [EditorBrowsable(EditorBrowsableState.Never)]
229         protected virtual bool OnBackButtonPressed()
230         {
231             var application = RealParent as Application;
232
233             var canceled = false;
234             EventHandler handler = (sender, args) => { canceled = true; };
235
236             return !canceled;
237         }
238
239         /// <summary>
240         /// Invoked whenever the binding context of the Page changes. Override this method to add class handling for this event.
241         /// </summary>
242         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
243         [EditorBrowsable(EditorBrowsableState.Never)]
244         protected override void OnBindingContextChanged()
245         {
246             base.OnBindingContextChanged();
247         }
248
249         /// <summary>
250         /// Indicates that the preferred size of a child Element has changed.
251         /// </summary>
252         /// <param name="sender">The object that raised the event.</param>
253         /// <param name="e">The event arguments.</param>
254         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
255         [EditorBrowsable(EditorBrowsableState.Never)]
256         protected virtual void OnChildMeasureInvalidated(object sender, EventArgs e)
257         {
258             InvalidationTrigger trigger = (e as InvalidationEventArgs)?.Trigger ?? InvalidationTrigger.Undefined;
259             OnChildMeasureInvalidated((BaseHandle)sender, trigger);
260         }
261
262         /// <summary>
263         /// When overridden, allows the application developer to customize behavior as the Page disappears.
264         /// </summary>
265         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
266         [EditorBrowsable(EditorBrowsableState.Never)]
267         protected virtual void OnDisappearing()
268         {
269         }
270
271         /// <summary>
272         /// Called when the Page's Parent property has changed.
273         /// </summary>
274         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
275         [EditorBrowsable(EditorBrowsableState.Never)]
276         protected override void OnParentSet()
277         {
278             base.OnParentSet();
279         }
280
281         internal virtual void OnChildMeasureInvalidated(BaseHandle child, InvalidationTrigger trigger)
282         {
283             var container = this as IPageContainer<Page>;
284             if (container != null)
285             {
286                 Page page = container.CurrentPage;
287                 if (page != null)
288                 {
289                     return;
290                 }
291             }
292             else
293             {
294                 for (var i = 0; i < LogicalChildren.Count; i++)
295                 {
296                     var v = LogicalChildren[i] as BaseHandle;
297                     if (v != null)
298                     {
299                         return;
300                     }
301                 }
302             }
303         }
304
305         /// <summary>
306         /// For intarnal use.
307         /// </summary>
308         [EditorBrowsable(EditorBrowsableState.Never)]
309         public void SendAppearing()
310         {
311             if (_hasAppeared)
312                 return;
313
314             _hasAppeared = true;
315
316             if (IsBusy)
317                 MessagingCenter.Send(this, BusySetSignalName, true);
318
319             OnAppearing();
320             Appearing?.Invoke(this, EventArgs.Empty);
321
322             var pageContainer = this as IPageContainer<Page>;
323             pageContainer?.CurrentPage?.SendAppearing();
324         }
325
326         /// <summary>
327         /// For intarnal use.
328         /// </summary>
329         [EditorBrowsable(EditorBrowsableState.Never)]
330         public void SendDisappearing()
331         {
332             if (!_hasAppeared)
333                 return;
334
335             _hasAppeared = false;
336
337             if (IsBusy)
338                 MessagingCenter.Send(this, BusySetSignalName, false);
339
340             var pageContainer = this as IPageContainer<Page>;
341             pageContainer?.CurrentPage?.SendDisappearing();
342
343             OnDisappearing();
344             Disappearing?.Invoke(this, EventArgs.Empty);
345         }
346
347         Application FindApplication(Element element)
348         {
349             if (element == null)
350                 return null;
351
352             return (element.Parent is Application app) ? app : FindApplication(element.Parent);
353         }
354
355         void InternalChildrenOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
356         {
357             if (e.OldItems != null)
358             {
359                 foreach (BaseHandle item in e.OldItems.OfType<BaseHandle>())
360                 {
361                     OnInternalRemoved(item);
362                 }
363             }
364
365             if (e.NewItems != null)
366             {
367                 foreach (BaseHandle item in e.NewItems.OfType<BaseHandle>())
368                 {
369                     OnInternalAdded(item);
370                 }
371             }
372         }
373
374         private void OnInternalAdded(BaseHandle view)
375         {
376             OnChildAdded(view);
377         }
378
379         private void OnInternalRemoved(BaseHandle view)
380         {
381             OnChildRemoved(view);
382         }
383
384         void OnPageBusyChanged()
385         {
386             if (!_hasAppeared)
387                 return;
388
389             MessagingCenter.Send(this, BusySetSignalName, IsBusy);
390         }
391
392         void OnToolbarItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
393         {
394             if (args.Action != NotifyCollectionChangedAction.Add)
395                 return;
396             foreach (IElement item in args.NewItems)
397                 item.Parent = this;
398         }
399
400         bool ShouldLayoutChildren()
401         {
402             if (!LogicalChildren.Any())
403             {
404                 return false;
405             }
406
407             var container = this as IPageContainer<Page>;
408             if (container?.CurrentPage != null)
409             {
410                 return true;
411             }
412
413             var any = false;
414             for (var i = 0; i < LogicalChildren.Count; i++)
415             {
416                 var v = LogicalChildren[i] as BaseHandle;
417                 if (v != null)
418                 {
419                     any = true;
420                     break;
421                 }
422             }
423             return !any;
424         }
425     }
426 }