[NUI] View Transition with page switching
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / Navigation / Navigator.cs
1 /*
2  * Copyright(c) 2021 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.Diagnostics.CodeAnalysis;
22 using Tizen.NUI.BaseComponents;
23
24 namespace Tizen.NUI.Components
25 {
26     /// <summary>
27     /// The Navigator is a class which navigates pages with stack methods such as Push and Pop.
28     ///
29     /// With Transition class, Navigator supports smooth transition of View pair between two Pages
30     /// by using PushWithTransition(Page) and PopWithTransition() methods.
31     /// If there is View pair of current top Page and next top Page those have same View.TransitionOptions.TransitionTag,
32     /// Navigator creates smooth transition motion for them.
33     /// Navigator.Transition property can be used to set properties of the Transition such as TimePeriod and AlphaFunction.
34     /// When all transitions are finished, Navigator calls a callback methods those connected on the "TransitionFinished" event.
35     /// 
36     /// <example>
37     /// <code>
38     /// Navigator.Transition = new Transition()
39     /// {
40     ///     TimePeriod = new TimePeriod(0.5),
41     ///     AlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseInOutSine)
42     /// }
43     ///
44     /// Navigator.PushWithTransition(newPage);
45     /// </code>
46     /// </example>
47     /// </summary>
48     [EditorBrowsable(EditorBrowsableState.Never)]
49     public class Navigator : Control
50     {
51         private static readonly float DefaultTransitionDuration = 0.5f;
52
53         //This will be replaced with view transition class instance.
54         private Animation curAnimation = null;
55
56         //This will be replaced with view transition class instance.
57         private Animation newAnimation = null;
58
59         private TransitionSet transitionSet = null;
60
61         private Transition transition = new Transition()
62         {
63             TimePeriod = new TimePeriod(DefaultTransitionDuration),
64             AlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.Default),
65         };
66
67         private bool transitionFinished = true;
68
69         //TODO: Needs to consider how to remove disposed window from dictionary.
70         //Two dictionaries are required to remove disposed navigator from dictionary.
71         private static Dictionary<Window, Navigator> windowNavigator = new Dictionary<Window, Navigator>();
72         private static Dictionary<Navigator, Window> navigatorWindow = new Dictionary<Navigator, Window>();
73
74         /// <summary>
75         /// Creates a new instance of a Navigator.
76         /// </summary>
77         [EditorBrowsable(EditorBrowsableState.Never)]
78         public Navigator() : base()
79         {
80             Layout = new AbsoluteLayout();
81         }
82         
83         /// <summary>
84         /// An event for the page disappearing signal which can be used to subscribe or unsubscribe the event handler provided by the user.
85         /// </summary>
86         [EditorBrowsable(EditorBrowsableState.Never)]
87         public event EventHandler<EventArgs> TransitionFinished;
88
89         /// <summary>
90         /// List of pages of Navigator.
91         /// </summary>
92         [EditorBrowsable(EditorBrowsableState.Never)]
93         public List<Page> NavigationPages { get; } = new List<Page>();
94
95         /// <summary>
96         /// Transition properties for the transition of View pair those have same transition tag.
97         /// </summary>
98         [EditorBrowsable(EditorBrowsableState.Never)]
99         public Transition Transition
100         {
101             set
102             {
103                 transition = value;
104             }
105             get
106             {
107                 return transition;
108             }
109         }
110
111         /// <summary>
112         /// Pushes a page to Navigator.
113         /// If the page is already in Navigator, then it is not pushed.
114         /// </summary>
115         /// <param name="page">The page to push to Navigator.</param>
116         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
117         [EditorBrowsable(EditorBrowsableState.Never)]
118         public void PushWithTransition(Page page)
119         {
120             if (!transitionFinished)
121             {
122                 Tizen.Log.Error("NUI", "Transition is still not finished.\n");
123                 return;
124             }
125
126             if (page == null)
127             {
128                 throw new ArgumentNullException(nameof(page), "page should not be null.");
129             }
130
131             //Duplicate page is not pushed.
132             if (NavigationPages.Contains(page)) return;
133
134             var topPage = Peek();
135
136             if (!topPage)
137             {
138                 Insert(0, page);
139                 return;
140             }
141
142             NavigationPages.Add(page);
143             Add(page);
144
145             //Invoke Page events
146             page.InvokeAppearing();
147             topPage.InvokeDisappearing();
148
149             transitionSet = CreateTransition(topPage, page, true);
150             transitionSet.Finished += (object sender, EventArgs e) =>
151             {
152                 topPage.SetVisible(false);
153             };
154             transitionFinished = false;
155         }
156
157         /// <summary>
158         /// Pops the top page from Navigator.
159         /// </summary>
160         /// <returns>The popped page.</returns>
161         /// <exception cref="InvalidOperationException">Thrown when there is no page in Navigator.</exception>
162         [EditorBrowsable(EditorBrowsableState.Never)]
163         public Page PopWithTransition()
164         {
165             if (!transitionFinished)
166             {
167                 Tizen.Log.Error("NUI", "Transition is still not finished.\n");
168                 return null;
169             }
170
171             if (NavigationPages.Count == 0)
172             {
173                 throw new InvalidOperationException("There is no page in Navigator.");
174             }
175
176             var topPage = Peek();
177
178             if (NavigationPages.Count == 1)
179             {
180                 Remove(topPage);
181                 return topPage;
182             }
183             var newTopPage = NavigationPages[NavigationPages.Count - 2];
184
185 //            newTopPage.RaiseAbove(topPage);
186
187             //Invoke Page events
188             newTopPage.InvokeAppearing();
189             topPage.InvokeDisappearing();
190
191             transitionSet = CreateTransition(topPage, newTopPage, false);
192             transitionSet.Finished += (object sender, EventArgs e) =>
193             {
194                 Remove(topPage);
195                 topPage.SetVisible(true);
196             };
197             transitionFinished = false;
198
199             return topPage;
200         }
201
202         /// <summary>
203         /// Pushes a page to Navigator.
204         /// If the page is already in Navigator, then it is not pushed.
205         /// </summary>
206         /// <param name="page">The page to push to Navigator.</param>
207         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
208         [EditorBrowsable(EditorBrowsableState.Never)]
209         public void Push(Page page)
210         {
211             if (!transitionFinished)
212             {
213                 Tizen.Log.Error("NUI", "Transition is still not finished.\n");
214                 return;
215             }
216
217             if (page == null)
218             {
219                 throw new ArgumentNullException(nameof(page), "page should not be null.");
220             }
221
222             //Duplicate page is not pushed.
223             if (NavigationPages.Contains(page)) return;
224
225             var curTop = Peek();
226
227             if (!curTop)
228             {
229                 Insert(0, page);
230                 return;
231             }
232
233             NavigationPages.Add(page);
234             Add(page);
235
236             //Invoke Page events
237             page.InvokeAppearing();
238             curTop.InvokeDisappearing();
239
240             //TODO: The following transition codes will be replaced with view transition.
241             if (curAnimation)
242             {
243                 curAnimation.Stop();
244                 curAnimation.Clear();
245             }
246
247             if (newAnimation)
248             {
249                 newAnimation.Stop();
250                 newAnimation.Clear();
251             }
252
253             curAnimation = new Animation(1000);
254             using (var scaleVec = new Vector3(0.0f, 0.0f, 1.0f))
255             {
256                 curAnimation.AnimateTo(curTop, "Scale", scaleVec, 0, 1000);
257             }
258             curAnimation.AnimateTo(curTop, "Opacity", 0.0f, 0, 1000);
259             curAnimation.EndAction = Animation.EndActions.Discard;
260             curAnimation.Play();
261
262             using (var scaleVec = new Vector3(0.0f, 0.0f, 1.0f))
263             {
264                 using (var scaleProp = new Tizen.NUI.PropertyValue(scaleVec))
265                 {
266                     Tizen.NUI.Object.SetProperty(page.SwigCPtr, Page.Property.SCALE, scaleProp);
267                 }
268             }
269             using (var scaleProp = new Tizen.NUI.PropertyValue(0.0f))
270             {
271                 Tizen.NUI.Object.SetProperty(page.SwigCPtr, Page.Property.OPACITY, scaleProp);
272             }
273             newAnimation = new Animation(1000);
274             using (var scaleVec = new Vector3(1.0f, 1.0f, 1.0f))
275             {
276                 newAnimation.AnimateTo(page, "Scale", scaleVec, 0, 1000);
277             }
278             newAnimation.AnimateTo(page, "Opacity", 1.0f, 0, 1000);
279             newAnimation.Play();
280         }
281
282         /// <summary>
283         /// Pops the top page from Navigator.
284         /// </summary>
285         /// <returns>The popped page.</returns>
286         /// <exception cref="InvalidOperationException">Thrown when there is no page in Navigator.</exception>
287         [EditorBrowsable(EditorBrowsableState.Never)]
288         public Page Pop()
289         {
290             if (!transitionFinished)
291             {
292                 Tizen.Log.Error("NUI", "Transition is still not finished.\n");
293                 return null;
294             }
295
296             if (NavigationPages.Count == 0)
297             {
298                 throw new InvalidOperationException("There is no page in Navigator.");
299             }
300
301             var curTop = Peek();
302
303             if (NavigationPages.Count == 1)
304             {
305                 Remove(curTop);
306                 return curTop;
307             }
308
309             var newTop = NavigationPages[NavigationPages.Count - 2];
310
311             //Invoke Page events
312             newTop.InvokeAppearing();
313             curTop.InvokeDisappearing();
314
315             //TODO: The following transition codes will be replaced with view transition.
316             if (curAnimation)
317             {
318                 curAnimation.Stop();
319                 curAnimation.Clear();
320             }
321
322             if (newAnimation)
323             {
324                 newAnimation.Stop();
325                 newAnimation.Clear();
326             }
327
328             curAnimation = new Animation(1000);
329             using (var scaleVec = new Vector3(0.0f, 0.0f, 1.0f))
330             {
331                 curAnimation.AnimateTo(curTop, "Scale", scaleVec, 0, 1000);
332             }
333             curAnimation.AnimateTo(curTop, "Opacity", 0.0f, 0, 1000);
334             curAnimation.Play();
335             curAnimation.Finished += (object sender, EventArgs e) =>
336             {
337                 //Removes the current top page after transition is finished.
338                 Remove(curTop);
339             };
340
341             using (var scaleVec = new Vector3(0.0f, 0.0f, 1.0f))
342             {
343                 using (var scaleProp = new Tizen.NUI.PropertyValue(scaleVec))
344                 {
345                     Tizen.NUI.Object.SetProperty(newTop.SwigCPtr, Page.Property.SCALE, scaleProp);
346                 }
347             }
348             using (var opacityProp = new Tizen.NUI.PropertyValue(0.0f))
349             {
350                 Tizen.NUI.Object.SetProperty(newTop.SwigCPtr, Page.Property.OPACITY, opacityProp);
351             }
352             newAnimation = new Animation(1000);
353             using (var scaleVec = new Vector3(1.0f, 1.0f, 1.0f))
354             {
355                 newAnimation.AnimateTo(newTop, "Scale", scaleVec, 0, 1000);
356             }
357             newAnimation.AnimateTo(newTop, "Opacity", 1.0f, 0, 1000);
358             newAnimation.Play();
359
360             return curTop;
361         }
362
363         /// <summary>
364         /// Inserts a page at the specified index of Navigator.
365         /// If the page is already in Navigator, then it is not inserted.
366         /// </summary>
367         /// <param name="index">The index of Navigator where a page will be inserted.</param>
368         /// <param name="page">The page to insert to Navigator.</param>
369         /// <exception cref="ArgumentOutOfRangeException">Thrown when the argument index is less than 0, or greater than the number of pages.</exception>
370         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
371         [EditorBrowsable(EditorBrowsableState.Never)]
372         public void Insert(int index, Page page)
373         {
374             if ((index < 0) || (index > NavigationPages.Count))
375             {
376                 throw new ArgumentOutOfRangeException(nameof(index), "index should be greater than or equal to 0, and less than or equal to the number of pages.");
377             }
378
379             if (page == null)
380             {
381                 throw new ArgumentNullException(nameof(page), "page should not be null.");
382             }
383
384             //Duplicate page is not pushed.
385             if (NavigationPages.Contains(page)) return;
386
387             NavigationPages.Insert(index, page);
388             Add(page);
389         }
390
391         /// <summary>
392         /// Inserts a page to Navigator before an existing page.
393         /// If the page is already in Navigator, then it is not inserted.
394         /// </summary>
395         /// <param name="before">The existing page, before which a page will be inserted.</param>
396         /// <param name="page">The page to insert to Navigator.</param>
397         /// <exception cref="ArgumentNullException">Thrown when the argument before is null.</exception>
398         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
399         /// <exception cref="ArgumentException">Thrown when the argument before does not exist in Navigator.</exception>
400         [EditorBrowsable(EditorBrowsableState.Never)]
401         public void InsertBefore(Page before, Page page)
402         {
403             if (before == null)
404             {
405                 throw new ArgumentNullException(nameof(before), "before should not be null.");
406             }
407
408             if (page == null)
409             {
410                 throw new ArgumentNullException(nameof(page), "page should not be null.");
411             }
412
413             //Find the index of before page.
414             int beforeIndex = NavigationPages.FindIndex(x => x == before);
415
416             //before does not exist in Navigator.
417             if (beforeIndex == -1)
418             {
419                 throw new ArgumentException("before does not exist in Navigator.", nameof(before));
420             }
421
422             Insert(beforeIndex, page);
423         }
424
425         /// <summary>
426         /// Removes a page from Navigator.
427         /// </summary>
428         /// <param name="page">The page to remove from Navigator.</param>
429         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
430         [EditorBrowsable(EditorBrowsableState.Never)]
431         public void Remove(Page page)
432         {
433             if (page == null)
434             {
435                 throw new ArgumentNullException(nameof(page), "page should not be null.");
436             }
437
438             NavigationPages.Remove(page);
439             base.Remove(page);
440         }
441
442         /// <summary>
443         /// Removes a page at the specified index of Navigator.
444         /// </summary>
445         /// <param name="index">The index of Navigator where a page will be removed.</param>
446         /// <exception cref="ArgumentOutOfRangeException">Thrown when the index is less than 0, or greater than or equal to the number of pages.</exception>
447         [EditorBrowsable(EditorBrowsableState.Never)]
448         public void RemoveAt(int index)
449         {
450             if ((index < 0) || (index >= NavigationPages.Count))
451             {
452                 throw new ArgumentOutOfRangeException(nameof(index), "index should be greater than or equal to 0, and less than the number of pages.");
453             }
454
455             Remove(NavigationPages[index]);
456         }
457
458         /// <summary>
459         /// Returns the page at the top of Navigator.
460         /// </summary>
461         /// <returns>The page at the top of Navigator.</returns>
462         [EditorBrowsable(EditorBrowsableState.Never)]
463         public Page Peek()
464         {
465             if (NavigationPages.Count == 0) return null;
466
467             return NavigationPages[NavigationPages.Count - 1];
468         }
469
470         /// <summary>
471         /// Disposes Navigator and all children on it.
472         /// </summary>
473         /// <param name="type">Dispose type.</param>
474         [EditorBrowsable(EditorBrowsableState.Never)]
475         protected override void Dispose(DisposeTypes type)
476         {
477             if (disposed)
478             {
479                 return;
480             }
481
482             if (type == DisposeTypes.Explicit)
483             {
484                 foreach (Page page in NavigationPages)
485                 {
486                     Utility.Dispose(page);
487                 }
488                 NavigationPages.Clear();
489
490                 Window window;
491
492                 if (navigatorWindow.TryGetValue(this, out window) == true)
493                 {
494                     navigatorWindow.Remove(this);
495                     windowNavigator.Remove(window);
496                 }
497             }
498
499             base.Dispose(type);
500         }
501
502         /// <summary>
503         /// Returns the default navigator of the given window.
504         /// </summary>
505         /// <returns>The default navigator of the given window.</returns>
506         /// <exception cref="ArgumentNullException">Thrown when the argument window is null.</exception>
507         [EditorBrowsable(EditorBrowsableState.Never)]
508         public static Navigator GetDefaultNavigator(Window window)
509         {
510             if (window == null)
511             {
512                 throw new ArgumentNullException(nameof(window), "window should not be null.");
513             }
514
515             if (windowNavigator.ContainsKey(window) == true)
516             {
517                 return windowNavigator[window];
518             }
519
520             var defaultNavigator = new Navigator();
521             defaultNavigator.WidthResizePolicy = ResizePolicyType.FillToParent;
522             defaultNavigator.HeightResizePolicy = ResizePolicyType.FillToParent;
523             window.Add(defaultNavigator);
524             windowNavigator.Add(window, defaultNavigator);
525             navigatorWindow.Add(defaultNavigator, window);
526
527             return defaultNavigator;
528         }
529
530         /// <summary>
531         /// Shows a dialog by pushing a page containing dialog to default navigator.
532         /// </summary>
533         /// <param name="content">The content of Dialog.</param>
534         [EditorBrowsable(EditorBrowsableState.Never)]
535         [SuppressMessage("Microsoft.Reliability",
536                          "CA2000:DisposeObjectsBeforeLosingScope",
537                          Justification = "The pushed views are added to NavigationPages and are disposed in Navigator.Dispose().")]
538         public static void ShowDialog(View content = null)
539         {
540             var window = NUIApplication.GetDefaultWindow();
541             var defaultNavigator = window.GetDefaultNavigator();
542
543             var dialog = new Dialog(content);
544             SetDialogScrim(dialog);
545
546             var dialogPage = new Page(dialog);
547             defaultNavigator.Push(dialogPage);
548         }
549
550         /// <summary>
551         /// Shows an alert dialog by pushing a page containing the alert dialog
552         /// to default navigator.
553         /// </summary>
554         /// <param name="titleContent">The title content of AlertDialog.</param>
555         /// <param name="content">The content of AlertDialog.</param>
556         /// <param name="actionContent">The action content of AlertDialog.</param>
557         [EditorBrowsable(EditorBrowsableState.Never)]
558         [SuppressMessage("Microsoft.Reliability",
559                          "CA2000:DisposeObjectsBeforeLosingScope",
560                          Justification = "The pushed views are added to NavigationPages and are disposed in Navigator.Dispose().")]
561         public static void ShowAlertDialog(View titleContent, View content, View actionContent)
562         {
563             var window = NUIApplication.GetDefaultWindow();
564             var defaultNavigator = window.GetDefaultNavigator();
565
566             var dialog = new AlertDialog(titleContent, content, actionContent);
567             SetDialogScrim(dialog);
568
569             var dialogPage = new Page(dialog);
570             defaultNavigator.Push(dialogPage);
571         }
572
573         /// <summary>
574         /// Shows an alert dialog by pushing a page containing the alert dialog
575         /// to default navigator.
576         /// </summary>
577         /// <param name="title">The title of AlertDialog.</param>
578         /// <param name="message">The message of AlertDialog.</param>
579         /// <param name="positiveButtonText">The positive button text in the action content of AlertDialog.</param>
580         /// <param name="positiveButtonClickedHandler">The clicked callback of the positive button in the action content of AlertDialog.</param>
581         /// <param name="negativeButtonText">The negative button text in the action content of AlertDialog.</param>
582         /// <param name="negativeButtonClickedHandler">The clicked callback of the negative button in the action content of AlertDialog.</param>
583         [EditorBrowsable(EditorBrowsableState.Never)]
584         [SuppressMessage("Microsoft.Reliability",
585                          "CA2000:DisposeObjectsBeforeLosingScope",
586                          Justification = "The pushed views are added to NavigationPages and are disposed in Navigator.Dispose().")]
587         public static void ShowAlertDialog(string title = null, string message = null, string positiveButtonText = null, EventHandler<ClickedEventArgs> positiveButtonClickedHandler = null, string negativeButtonText = null, EventHandler<ClickedEventArgs> negativeButtonClickedHandler = null)
588         {
589             var window = NUIApplication.GetDefaultWindow();
590             var defaultNavigator = window.GetDefaultNavigator();
591
592             var dialog = new AlertDialog(title, message, positiveButtonText, positiveButtonClickedHandler, negativeButtonText, negativeButtonClickedHandler);
593             SetDialogScrim(dialog);
594
595             var dialogPage = new Page(dialog);
596             defaultNavigator.Push(dialogPage);
597         }
598
599         /// <summary>
600         /// Create Transition between currentTopPage and newTopPage
601         /// </summary>
602         /// <param name="currentTopPage">The top page of Navigator.</param>
603         /// <param name="newTopPage">The new top page after transition.</param>
604         /// <param name="pushTransition">True if this transition is for push new page</param>
605         private TransitionSet CreateTransition(Page currentTopPage, Page newTopPage, bool pushTransition)
606         {
607             currentTopPage.SetVisible(true);
608             newTopPage.SetVisible(true);
609
610             List<View> taggedViewsInNewTopPage = new List<View>();
611             RetrieveTaggedViews(taggedViewsInNewTopPage, newTopPage.Content);
612             List<View> taggedViewsInCurrentTopPage = new List<View>();
613             RetrieveTaggedViews(taggedViewsInCurrentTopPage, currentTopPage.Content);
614
615             List<KeyValuePair<View, View>> sameTaggedViewPair = new List<KeyValuePair<View, View>>();
616             foreach(View currentTopPageView in taggedViewsInCurrentTopPage)
617             {
618                 bool findPair = false;
619                 foreach(View newTopPageView in taggedViewsInNewTopPage)
620                 {
621                     if((currentTopPageView.TransitionOptions != null) && (newTopPageView.TransitionOptions != null) &&
622                         currentTopPageView.TransitionOptions?.TransitionTag == newTopPageView.TransitionOptions?.TransitionTag)
623                     {
624                         sameTaggedViewPair.Add(new KeyValuePair<View, View>(currentTopPageView, newTopPageView));
625                         findPair = true;
626                         break;
627                     }
628                 }
629                 if(findPair)
630                 {
631                     taggedViewsInNewTopPage.Remove(sameTaggedViewPair[sameTaggedViewPair.Count - 1].Value);
632                 }
633             }
634             foreach(KeyValuePair<View, View> pair in sameTaggedViewPair)
635             {
636                 taggedViewsInCurrentTopPage.Remove(pair.Key);
637             }
638
639             TransitionSet newTransitionSet = new TransitionSet();
640             foreach(KeyValuePair<View, View> pair in sameTaggedViewPair)
641             {
642                 TransitionItem pairTransition = transition.CreateTransition(pair.Key, pair.Value);
643                 if(pair.Value.TransitionOptions?.TransitionWithChild ?? false)
644                 {
645                     pairTransition.TransitionWithChild = true;
646                 }
647                 newTransitionSet.AddTransition(pairTransition);
648             }
649             newTransitionSet.Play();
650
651             newTransitionSet.Finished += (object sender, EventArgs e) =>
652             {
653                 transitionFinished = true;
654                 InvokeTransitionFinished();
655                 transitionSet.Dispose();
656                 currentTopPage.Opacity = 1.0f;
657             };
658
659             // default entering/exit transition - fast fade (half duration compaired with that of view pair transition)
660             float duration = (transition.TimePeriod.DurationSeconds + transition.TimePeriod.DelaySeconds) * 0.8f;
661             Animation fade = new Animation(duration);
662             fade.AnimateTo(currentTopPage, "Opacity", 0.0f);
663             KeyFrames keyframes = new KeyFrames();
664             keyframes.Add(0.0f, 0.0f);
665             keyframes.Add(1.0f, 1.0f);
666             fade.AnimateBetween(newTopPage, "Opacity", keyframes);
667             fade.Play();
668
669             return newTransitionSet;
670         }
671
672         private static void SetDialogScrim(Dialog dialog)
673         {
674             if (dialog == null)
675             {
676                 return;
677             }
678
679             var window = NUIApplication.GetDefaultWindow();
680             var defaultNavigator = window.GetDefaultNavigator();
681             var defaultScrim = dialog.Scrim;
682
683             //Copies default scrim's GUI properties.
684             var scrim = new VisualView();
685             scrim.BackgroundColor = defaultScrim.BackgroundColor;
686             scrim.Size = defaultScrim.Size;
687             scrim.TouchEvent += (object source, View.TouchEventArgs e) =>
688             {
689                 if (e.Touch.GetState(0) == PointStateType.Up)
690                 {
691                     defaultNavigator.Pop();
692                 }
693
694                 return true;
695             };
696
697             dialog.Scrim = scrim;
698         }
699
700
701         /// <summary>
702         /// Retrieve Tagged Views in the view tree.
703         /// </summary>
704         /// <param name="taggedViews">Returned tagged view list..</param>
705         /// <param name="view">Root View to get tagged child View.</param>
706         private void RetrieveTaggedViews(List<View> taggedViews, View view)
707         {
708             if (!string.IsNullOrEmpty(view.TransitionOptions?.TransitionTag))
709             {
710                 taggedViews.Add((view as View));
711             }
712
713             if (view.ChildCount == 0)
714             {
715                 return;
716             }
717
718             if (view.TransitionOptions?.TransitionWithChild ?? false)
719             {
720                 return;
721             }
722
723             foreach (View child in view.Children)
724             {
725                 RetrieveTaggedViews(taggedViews, child);
726             }
727         }
728
729         internal void InvokeTransitionFinished()
730         {
731             TransitionFinished?.Invoke(this, new EventArgs());
732         }
733     }
734 } //namespace Tizen.NUI