[NUI] Add Navigator and Page classes
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / Navigation / Navigator.cs
1 /*
2  * Copyright(c) 2020 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
18 using System;
19 using System.Collections.Generic;
20 using System.ComponentModel;
21 using System.Threading.Tasks;
22 using Tizen.NUI.BaseComponents;
23 using Tizen.NUI.Binding;
24
25 namespace Tizen.NUI.Components
26 {
27     /// <summary>
28     /// The Navigator is a class which navigates pages with stack methods such
29     /// as Push and Pop.
30     /// </summary>
31     [EditorBrowsable(EditorBrowsableState.Never)]
32     public class Navigator : Control
33     {
34         //This will be replaced with view transition class instance.
35         private Animation _curAnimation = null;
36
37         //This will be replaced with view transition class instance.
38         private Animation _newAnimation = null;
39
40         /// <summary>
41         /// Creates a new instance of a Navigator.
42         /// </summary>
43         [EditorBrowsable(EditorBrowsableState.Never)]
44         public Navigator() : base()
45         {
46         }
47
48         /// <summary>
49         /// List of pages of Navigator.
50         /// </summary>
51         [EditorBrowsable(EditorBrowsableState.Never)]
52         public List<Page> NavigationPages { get; } = new List<Page>();
53
54         /// <summary>
55         /// Pushes a page to Navigator.
56         /// If the page is already in Navigator, then it is not pushed.
57         /// </summary>
58         /// <param name="page">The page to push to Navigator.</param>
59         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
60         [EditorBrowsable(EditorBrowsableState.Never)]
61         public void Push(Page page)
62         {
63             if (page == null)
64             {
65                 throw new ArgumentNullException(nameof(page), "page should not be null.");
66             }
67
68             //Duplicate page is not pushed.
69             if (NavigationPages.Contains(page)) return;
70
71             var curTop = Peek();
72
73             if (!curTop)
74             {
75                 Insert(0, page);
76                 return;
77             }
78
79             NavigationPages.Add(page);
80             Add(page);
81
82             //Invoke Page events
83             page.InvokeAppearing();
84             curTop.InvokeDisappearing();
85
86             //TODO: The following transition codes will be replaced with view transition.
87             if (_curAnimation)
88             {
89                 _curAnimation.Stop();
90                 _curAnimation.Clear();
91             }
92
93             if (_newAnimation)
94             {
95                 _newAnimation.Stop();
96                 _newAnimation.Clear();
97             }
98
99             _curAnimation = new Animation(1000);
100             using (var scaleVec = new Vector3(0.0f, 0.0f, 1.0f))
101             {
102                 _curAnimation.AnimateTo(curTop, "Scale", scaleVec, 0, 1000);
103             }
104             _curAnimation.AnimateTo(curTop, "Opacity", 0.0f, 0, 1000);
105             _curAnimation.EndAction = Animation.EndActions.Discard;
106             _curAnimation.Play();
107
108             using (var scaleVec = new Vector3(0.0f, 0.0f, 1.0f))
109             {
110                 using (var scaleProp = new Tizen.NUI.PropertyValue(scaleVec))
111                 {
112                     Tizen.NUI.Object.SetProperty(page.SwigCPtr, Page.Property.SCALE, scaleProp);
113                 }
114             }
115             using (var scaleProp = new Tizen.NUI.PropertyValue(0.0f))
116             {
117                 Tizen.NUI.Object.SetProperty(page.SwigCPtr, Page.Property.OPACITY, scaleProp);
118             }
119             _newAnimation = new Animation(1000);
120             using (var scaleVec = new Vector3(1.0f, 1.0f, 1.0f))
121             {
122                 _newAnimation.AnimateTo(page, "Scale", scaleVec, 0, 1000);
123             }
124             _newAnimation.AnimateTo(page, "Opacity", 1.0f, 0, 1000);
125             _newAnimation.Play();
126         }
127
128         /// <summary>
129         /// Pops the top page from Navigator.
130         /// </summary>
131         /// <returns>The popped page.</returns>
132         /// <exception cref="InvalidOperationException">Thrown when there is no page in Navigator.</exception>
133         [EditorBrowsable(EditorBrowsableState.Never)]
134         public Page Pop()
135         {
136             if (NavigationPages.Count == 0)
137             {
138                 throw new InvalidOperationException("There is no page in Navigator.");
139             }
140
141             var curTop = Peek();
142
143             if (NavigationPages.Count == 1)
144             {
145                 Remove(curTop);
146                 return curTop;
147             }
148
149             var newTop = NavigationPages[NavigationPages.Count - 2];
150
151             //Invoke Page events
152             newTop.InvokeAppearing();
153             curTop.InvokeDisappearing();
154
155             //TODO: The following transition codes will be replaced with view transition.
156             if (_curAnimation)
157             {
158                 _curAnimation.Stop();
159                 _curAnimation.Clear();
160             }
161
162             if (_newAnimation)
163             {
164                 _newAnimation.Stop();
165                 _newAnimation.Clear();
166             }
167
168             _curAnimation = new Animation(1000);
169             using (var scaleVec = new Vector3(0.0f, 0.0f, 1.0f))
170             {
171                 _curAnimation.AnimateTo(curTop, "Scale", scaleVec, 0, 1000);
172             }
173             _curAnimation.AnimateTo(curTop, "Opacity", 0.0f, 0, 1000);
174             _curAnimation.Play();
175             _curAnimation.Finished += (object sender, EventArgs e) =>
176             {
177                 //Removes the current top page after transition is finished.
178                 Remove(curTop);
179             };
180
181             using (var scaleVec = new Vector3(0.0f, 0.0f, 1.0f))
182             {
183                 using (var scaleProp = new Tizen.NUI.PropertyValue(scaleVec))
184                 {
185                     Tizen.NUI.Object.SetProperty(newTop.SwigCPtr, Page.Property.SCALE, scaleProp);
186                 }
187             }
188             using (var opacityProp = new Tizen.NUI.PropertyValue(0.0f))
189             {
190                 Tizen.NUI.Object.SetProperty(newTop.SwigCPtr, Page.Property.OPACITY, opacityProp);
191             }
192             _newAnimation = new Animation(1000);
193             using (var scaleVec = new Vector3(1.0f, 1.0f, 1.0f))
194             {
195                 _newAnimation.AnimateTo(newTop, "Scale", scaleVec, 0, 1000);
196             }
197             _newAnimation.AnimateTo(newTop, "Opacity", 1.0f, 0, 1000);
198             _newAnimation.Play();
199
200             return curTop;
201         }
202
203         /// <summary>
204         /// Inserts a page at the specified index of Navigator.
205         /// If the page is already in Navigator, then it is not inserted.
206         /// </summary>
207         /// <param name="index">The index of Navigator where a page will be inserted.</param>
208         /// <param name="page">The page to insert to Navigator.</param>
209         /// <exception cref="ArgumentOutOfRangeException">Thrown when the argument index is less than 0, or greater than the number of pages.</exception>
210         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
211         [EditorBrowsable(EditorBrowsableState.Never)]
212         public void Insert(int index, Page page)
213         {
214             if ((index < 0) || (index > NavigationPages.Count))
215             {
216                 throw new ArgumentOutOfRangeException(nameof(index), "index should be greater than or equal to 0, and less than or equal to the number of pages.");
217             }
218
219             if (page == null)
220             {
221                 throw new ArgumentNullException(nameof(page), "page should not be null.");
222             }
223
224             //Duplicate page is not pushed.
225             if (NavigationPages.Contains(page)) return;
226
227             NavigationPages.Insert(index, page);
228             Add(page);
229         }
230
231         /// <summary>
232         /// Inserts a page to Navigator before an existing page.
233         /// If the page is already in Navigator, then it is not inserted.
234         /// </summary>
235         /// <param name="before">The existing page, before which a page will be inserted.</param>
236         /// <param name="page">The page to insert to Navigator.</param>
237         /// <exception cref="ArgumentNullException">Thrown when the argument before is null.</exception>
238         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
239         /// <exception cref="ArgumentException">Thrown when the argument before does not exist in Navigator.</exception>
240         [EditorBrowsable(EditorBrowsableState.Never)]
241         public void InsertBefore(Page before, Page page)
242         {
243             if (before == null)
244             {
245                 throw new ArgumentNullException(nameof(before), "before should not be null.");
246             }
247
248             if (page == null)
249             {
250                 throw new ArgumentNullException(nameof(page), "page should not be null.");
251             }
252
253             //Find the index of before page.
254             int beforeIndex = NavigationPages.FindIndex(x => x == before);
255
256             //before does not exist in Navigator.
257             if (beforeIndex == -1)
258             {
259                 throw new ArgumentException("before does not exist in Navigator.", nameof(before));
260             }
261
262             Insert(beforeIndex, page);
263         }
264
265         /// <summary>
266         /// Removes a page from Navigator.
267         /// </summary>
268         /// <param name="page">The page to remove from Navigator.</param>
269         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
270         [EditorBrowsable(EditorBrowsableState.Never)]
271         public void Remove(Page page)
272         {
273             if (page == null)
274             {
275                 throw new ArgumentNullException(nameof(page), "page should not be null.");
276             }
277
278             NavigationPages.Remove(page);
279             base.Remove(page);
280         }
281
282         /// <summary>
283         /// Removes a page at the specified index of Navigator.
284         /// </summary>
285         /// <param name="index">The index of Navigator where a page will be removed.</param>
286         /// <exception cref="ArgumentOutOfRangeException">Thrown when the index is less than 0, or greater than or equal to the number of pages.</exception>
287         [EditorBrowsable(EditorBrowsableState.Never)]
288         public void RemoveAt(int index)
289         {
290             if ((index < 0) || (index >= NavigationPages.Count))
291             {
292                 throw new ArgumentOutOfRangeException(nameof(index), "index should be greater than or equal to 0, and less than the number of pages.");
293             }
294
295             Remove(NavigationPages[index]);
296         }
297
298         /// <summary>
299         /// Returns the page at the top of Navigator.
300         /// </summary>
301         /// <returns>The page at the top of Navigator.</returns>
302         [EditorBrowsable(EditorBrowsableState.Never)]
303         public Page Peek()
304         {
305             if (NavigationPages.Count == 0) return null;
306
307             return NavigationPages[NavigationPages.Count - 1];
308         }
309     }
310 } //namespace Tizen.NUI