[NUI] Add BorderCloseDelegate for closing the application by the border.
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Window / DefaultBorder.cs
1 /*
2  * Copyright(c) 2022 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.ComponentModel;
20 using Tizen.NUI.BaseComponents;
21
22 namespace Tizen.NUI
23 {
24     /// <summary>
25     /// This class creates a border UI.
26     /// </summary>
27     [EditorBrowsable(EditorBrowsableState.Never)]
28     public class DefaultBorder : IBorderInterface
29     {
30         #region Constant Fields
31         private static readonly string ResourcePath = FrameworkInformation.ResourcePath;
32         private static readonly string MinimalizeIcon = ResourcePath + "minimalize.png";
33         private static readonly string MaximalizeIcon = ResourcePath + "maximalize.png";
34         private static readonly string CloseIcon = ResourcePath + "close.png";
35         private static readonly string LeftCornerIcon = ResourcePath + "leftCorner.png";
36         private static readonly string RightCornerIcon = ResourcePath + "rightCorner.png";
37
38         private static readonly string DarkMinimalizeIcon = ResourcePath + "dark_minimalize.png";
39         private static readonly string DarkPreviousIcon = ResourcePath + "dark_smallwindow.png";
40         private static readonly string DarkCloseIcon = ResourcePath + "dark_close.png";
41         private static readonly string DarkLeftCornerIcon = ResourcePath + "dark_leftCorner.png";
42         private static readonly string DarkRightCornerIcon = ResourcePath + "dark_rightCorner.png";
43
44
45         private const uint DefaultHeight = 50;
46         private const uint DefaultLineThickness = 5;
47         private const uint DefaultTouchThickness = 20;
48         private static readonly Color DefaultBackgroundColor = new Color(1, 1, 1, 0.3f);
49         private static readonly Color DefaultClickedBackgroundColor = new Color(1, 1, 1, 0.4f);
50         private static readonly Size2D DefaultMinSize = new Size2D(100, 0);
51         #endregion //Constant Fields
52
53
54         #region Fields
55         private Color backgroundColor;
56         private View borderView;
57
58         private ImageView minimalizeIcon;
59         private ImageView maximalizeIcon;
60         private ImageView closeIcon;
61         private ImageView leftCornerIcon;
62         private ImageView rightCornerIcon;
63
64         private Window.BorderDirection direction = Window.BorderDirection.None;
65         private float preScale = 0;
66
67         private View windowView = null;
68         private bool isWinGestures = false;
69         private Timer timer;
70         private Timer overlayTimer;
71
72         private CurrentGesture currentGesture = CurrentGesture.None;
73         private bool disposed = false;
74         #endregion //Fields
75
76         #region Events
77         private PanGestureDetector borderPanGestureDetector;
78         private PinchGestureDetector borderPinchGestureDetector;
79         private PanGestureDetector winPanGestureDetector;
80         private TapGestureDetector winTapGestureDetector;
81         #endregion //Events
82
83         #region Enums
84         private enum CurrentGesture
85         {
86           None = 0,
87           TapGesture = 1,
88           PanGesture = 2,
89           PinchGesture = 3,
90         }
91         #endregion //Enums
92
93         #region Methods
94
95         /// <summary>
96         /// The thickness of the border.
97         /// </summary>
98         [EditorBrowsable(EditorBrowsableState.Never)]
99         public uint BorderLineThickness {get; set;}
100
101         /// <summary>
102         /// The thickness of the border's touch area.
103         /// </summary>
104         [EditorBrowsable(EditorBrowsableState.Never)]
105         public uint TouchThickness {get; set;}
106
107         /// <summary>
108         /// The height of the border.
109         /// </summary>
110         [EditorBrowsable(EditorBrowsableState.Never)]
111         public uint BorderHeight {get; set;}
112
113         /// <summary>
114         /// The minimum size by which the window will small.
115         /// </summary>
116         [EditorBrowsable(EditorBrowsableState.Never)]
117         public Size2D MinSize {get; set;}
118
119         /// <summary>
120         /// The maximum size by which the window will big.
121         /// </summary>
122         [EditorBrowsable(EditorBrowsableState.Never)]
123         public Size2D MaxSize {get; set;}
124
125         /// <summary>
126         /// The window with borders added.
127         /// </summary>
128         [EditorBrowsable(EditorBrowsableState.Never)]
129         public Window BorderWindow {get; set;}
130
131         /// <summary>
132         /// Whether overlay mode.
133         /// If overlay mode is true, the border area is hidden when the window is maximized.
134         /// And if you touched at screen, the border area is shown on the screen.
135         /// Default value is false;
136         /// </summary>
137         [EditorBrowsable(EditorBrowsableState.Never)]
138         public bool OverlayMode {get; set;}
139
140         /// <summary>
141         /// Set the window resizing policy.
142         /// Default value is BorderResizePolicyType.Free;
143         /// </summary>
144         [EditorBrowsable(EditorBrowsableState.Never)]
145         public Window.BorderResizePolicyType ResizePolicy {get; set;}
146
147
148         /// <summary>
149         /// Creates a default border
150         /// </summary>
151         [EditorBrowsable(EditorBrowsableState.Never)]
152         public DefaultBorder()
153         {
154             BorderLineThickness = DefaultLineThickness;
155             TouchThickness = DefaultTouchThickness;
156             BorderHeight = DefaultHeight;
157             MinSize = DefaultMinSize;
158             OverlayMode = false;
159             ResizePolicy = Window.BorderResizePolicyType.Free;
160         }
161
162         /// <summary>
163         /// Create top border UI. User can override this method to draw top border UI.
164         /// </summary>
165         /// <param name="topView">The top view on which the border.</param>
166         [EditorBrowsable(EditorBrowsableState.Never)]
167         public virtual bool CreateTopBorderView(View topView)
168         {
169             return false;
170         }
171
172         /// <summary>
173         /// Create bottom border UI. User can override this method to draw bottom border UI.
174         /// </summary>
175         /// <param name="bottomView">The bottom view on which the border.</param>
176         [EditorBrowsable(EditorBrowsableState.Never)]
177         public virtual bool CreateBottomBorderView(View bottomView)
178         {
179             if (bottomView == null)
180             {
181                 return false;
182             }
183             bottomView.Layout = new RelativeLayout();
184
185             minimalizeIcon = new ImageView()
186             {
187                 Focusable = true,
188                 ResourceUrl = MinimalizeIcon,
189                 AccessibilityHighlightable = true,
190             };
191
192             maximalizeIcon = new ImageView()
193             {
194                 Focusable = true,
195                 ResourceUrl = MaximalizeIcon,
196                 AccessibilityHighlightable = true,
197             };
198
199             closeIcon = new ImageView()
200             {
201                 Focusable = true,
202                 ResourceUrl = CloseIcon,
203                 AccessibilityHighlightable = true,
204             };
205
206             leftCornerIcon = new ImageView()
207             {
208                 Focusable = true,
209                 ResourceUrl = LeftCornerIcon,
210                 AccessibilityHighlightable = true,
211             };
212
213             rightCornerIcon = new ImageView()
214             {
215                 Focusable = true,
216                 ResourceUrl = RightCornerIcon,
217                 AccessibilityHighlightable = true,
218             };
219
220             RelativeLayout.SetRightTarget(minimalizeIcon, maximalizeIcon);
221             RelativeLayout.SetRightRelativeOffset(minimalizeIcon, 0.0f);
222             RelativeLayout.SetHorizontalAlignment(minimalizeIcon, RelativeLayout.Alignment.End);
223             RelativeLayout.SetRightTarget(maximalizeIcon, closeIcon);
224             RelativeLayout.SetRightRelativeOffset(maximalizeIcon, 0.0f);
225             RelativeLayout.SetHorizontalAlignment(maximalizeIcon, RelativeLayout.Alignment.End);
226             RelativeLayout.SetRightTarget(closeIcon, rightCornerIcon);
227             RelativeLayout.SetRightRelativeOffset(closeIcon, 0.0f);
228             RelativeLayout.SetHorizontalAlignment(closeIcon, RelativeLayout.Alignment.End);
229             RelativeLayout.SetRightRelativeOffset(rightCornerIcon, 1.0f);
230             RelativeLayout.SetHorizontalAlignment(rightCornerIcon, RelativeLayout.Alignment.End);
231             bottomView.Add(leftCornerIcon);
232             bottomView.Add(minimalizeIcon);
233             bottomView.Add(maximalizeIcon);
234             bottomView.Add(closeIcon);
235             bottomView.Add(rightCornerIcon);
236
237
238             minimalizeIcon.TouchEvent += OnMinimizeIconTouched;
239             maximalizeIcon.TouchEvent += OnMaximizeIconTouched;
240             closeIcon.TouchEvent += OnCloseIconTouched;
241             leftCornerIcon.TouchEvent += OnLeftBottomCornerIconTouched;
242             rightCornerIcon.TouchEvent += OnRightBottomCornerIconTouched;
243
244             minimalizeIcon.AccessibilityActivated += (s, e) =>
245             {
246                 MinimizeBorderWindow();
247             };
248             maximalizeIcon.AccessibilityActivated += (s, e) =>
249             {
250                 MaximizeBorderWindow();
251             };
252             closeIcon.AccessibilityActivated += (s, e) =>
253             {
254                 CloseBorderWindow();
255             };
256
257             minimalizeIcon.AccessibilityNameRequested += (s, e) =>
258             {
259                 e.Name = "Minimize";
260             };
261             maximalizeIcon.AccessibilityNameRequested += (s, e) =>
262             {
263                 e.Name = "Maximize";
264             };
265             closeIcon.AccessibilityNameRequested += (s, e) =>
266             {
267                 e.Name = "Close";
268             };
269             leftCornerIcon.AccessibilityNameRequested += (s, e) =>
270             {
271                 e.Name = "Resize";
272             };
273             rightCornerIcon.AccessibilityNameRequested += (s, e) =>
274             {
275                 e.Name = "Resize";
276             };
277
278             minimalizeIcon.SetAccessibilityReadingInfoTypes(Tizen.NUI.BaseComponents.AccessibilityReadingInfoTypes.Name);
279             maximalizeIcon.SetAccessibilityReadingInfoTypes(Tizen.NUI.BaseComponents.AccessibilityReadingInfoTypes.Name);
280             closeIcon.SetAccessibilityReadingInfoTypes(Tizen.NUI.BaseComponents.AccessibilityReadingInfoTypes.Name);
281             leftCornerIcon.SetAccessibilityReadingInfoTypes(Tizen.NUI.BaseComponents.AccessibilityReadingInfoTypes.Name);
282             rightCornerIcon.SetAccessibilityReadingInfoTypes(Tizen.NUI.BaseComponents.AccessibilityReadingInfoTypes.Name);
283
284             return true;
285         }
286
287
288         /// <summary>
289         /// Create border UI. User can override this method to draw border UI.
290         /// A top border and a bottom border are added to this view.
291         /// </summary>
292         /// <param name="borderView">The root view on which the border.</param>
293         [EditorBrowsable(EditorBrowsableState.Never)]
294         public virtual void CreateBorderView(View borderView)
295         {
296             if (borderView == null)
297             {
298                 return;
299             }
300             this.borderView = borderView;
301             borderView.BackgroundColor = DefaultBackgroundColor;
302             borderView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f);
303             borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
304         }
305
306         /// Determines the behavior of pinch gesture.
307         private void OnPinchGestureDetected(object source, PinchGestureDetector.DetectedEventArgs e)
308         {
309             if (e == null)
310             {
311                 return;
312             }
313             if (e.PinchGesture.State == Gesture.StateType.Started)
314             {
315                 preScale = e.PinchGesture.Scale;
316             }
317             else if (e.PinchGesture.State == Gesture.StateType.Finished || e.PinchGesture.State == Gesture.StateType.Cancelled)
318             {
319                 if (preScale > e.PinchGesture.Scale)
320                 {
321                     if (BorderWindow.IsMaximized())
322                     {
323                         BorderWindow.Maximize(false);
324                         OnMaximize(false);
325                     }
326                     else
327                     {
328                         BorderWindow.Minimize(true);
329                         OnMinimize(true);
330                     }
331                 }
332                 else
333                 {
334                     BorderWindow.Maximize(true);
335                     OnMaximize(true);
336                 }
337             }
338         }
339
340         /// Determines the behavior of borders.
341         private void OnPanGestureDetected(object source, PanGestureDetector.DetectedEventArgs e)
342         {
343             if (e == null)
344             {
345                 return;
346             }
347             PanGesture panGesture = e.PanGesture;
348
349             if (panGesture.State == Gesture.StateType.Started && panGesture.Position != null)
350             {
351                 direction = BorderWindow.GetDirection(panGesture.Position.X, panGesture.Position.Y);
352
353                 if (direction == Window.BorderDirection.Move)
354                 {
355                     if (BorderWindow.IsMaximized() == true)
356                     {
357                         BorderWindow.Maximize(false);
358                         OnMaximize(false);
359                     }
360                     else
361                     {
362                         BorderWindow.RequestMoveToServer();
363                     }
364                 }
365                 else if (direction != Window.BorderDirection.None && ResizePolicy != Window.BorderResizePolicyType.Fixed)
366                 {
367                     OnRequestResize();
368                     BorderWindow.RequestResizeToServer((Window.ResizeDirection)direction);
369                 }
370             }
371             else if (panGesture.State == Gesture.StateType.Finished || panGesture.State == Gesture.StateType.Cancelled)
372             {
373                 direction = Window.BorderDirection.None;
374                 ClearWindowGesture();
375             }
376         }
377
378         /// <summary>
379         /// This is an event callback when the left top corner icon is touched.
380         /// </summary>
381         [EditorBrowsable(EditorBrowsableState.Never)]
382         public virtual bool OnLeftTopCornerIconTouched(object sender, View.TouchEventArgs e)
383         {
384             if (e != null && e.Touch.GetState(0) == PointStateType.Down)
385             {
386               ClearWindowGesture();
387               if (ResizePolicy != Window.BorderResizePolicyType.Fixed)
388               {
389                 OnRequestResize();
390                 BorderWindow.RequestResizeToServer(Window.ResizeDirection.TopLeft);
391               }
392             }
393             return true;
394         }
395
396         /// <summary>
397         ///This is an event callback when the right bottom corner icon is touched.
398         /// </summary>
399         [EditorBrowsable(EditorBrowsableState.Never)]
400         public virtual bool OnRightTopCornerIconTouched(object sender, View.TouchEventArgs e)
401         {
402             if (e != null && e.Touch.GetState(0) == PointStateType.Down)
403             {
404               ClearWindowGesture();
405               if (ResizePolicy != Window.BorderResizePolicyType.Fixed)
406               {
407                 OnRequestResize();
408                 BorderWindow.RequestResizeToServer(Window.ResizeDirection.TopRight);
409               }
410             }
411             return true;
412         }
413
414
415         /// <summary>
416         /// This is an event callback when the left bottom corner icon is touched.
417         /// </summary>
418         [EditorBrowsable(EditorBrowsableState.Never)]
419         public virtual bool OnLeftBottomCornerIconTouched(object sender, View.TouchEventArgs e)
420         {
421             if (e != null && e.Touch.GetState(0) == PointStateType.Down)
422             {
423               ClearWindowGesture();
424               if (ResizePolicy != Window.BorderResizePolicyType.Fixed)
425               {
426                 OnRequestResize();
427                 BorderWindow.RequestResizeToServer(Window.ResizeDirection.BottomLeft);
428               }
429             }
430             return true;
431         }
432
433         /// <summary>
434         ///This is an event callback when the right bottom corner icon is touched.
435         /// </summary>
436         [EditorBrowsable(EditorBrowsableState.Never)]
437         public virtual bool OnRightBottomCornerIconTouched(object sender, View.TouchEventArgs e)
438         {
439             if (e != null && e.Touch.GetState(0) == PointStateType.Down)
440             {
441               ClearWindowGesture();
442               if (ResizePolicy != Window.BorderResizePolicyType.Fixed)
443               {
444                 OnRequestResize();
445                 BorderWindow.RequestResizeToServer(Window.ResizeDirection.BottomRight);
446               }
447             }
448             return true;
449         }
450
451
452         /// <summary>
453         /// Minimize border window.
454         /// </summary>
455         [EditorBrowsable(EditorBrowsableState.Never)]
456         protected void MinimizeBorderWindow()
457         {
458             ClearWindowGesture();
459             BorderWindow.Minimize(true);
460             OnMinimize(true);
461         }
462
463         /// <summary>
464         /// This is an event callback when the minimize icon is touched.
465         /// </summary>
466         [EditorBrowsable(EditorBrowsableState.Never)]
467         public virtual bool OnMinimizeIconTouched(object sender, View.TouchEventArgs e)
468         {
469             if (e != null && e.Touch.GetState(0) == PointStateType.Up)
470             {
471                 MinimizeBorderWindow();
472             }
473             return true;
474         }
475
476         /// <summary>
477         /// Maximize border window.
478         /// </summary>
479         [EditorBrowsable(EditorBrowsableState.Never)]
480         protected void MaximizeBorderWindow()
481         {
482             ClearWindowGesture();
483             if (BorderWindow.IsMaximized())
484             {
485               BorderWindow.Maximize(false);
486               OnMaximize(false);
487             }
488             else
489             {
490               BorderWindow.Maximize(true);
491               OnMaximize(true);
492             }
493         }
494
495         /// <summary>
496         /// This is an event callback when the maximum icon is touched.
497         /// </summary>
498         [EditorBrowsable(EditorBrowsableState.Never)]
499         public virtual bool OnMaximizeIconTouched(object sender, View.TouchEventArgs e)
500         {
501             if (e != null && e.Touch.GetState(0) == PointStateType.Up)
502             {
503                 MaximizeBorderWindow();
504             }
505             return true;
506         }
507
508         /// <summary>
509         /// Close border window.
510         /// </summary>
511         [EditorBrowsable(EditorBrowsableState.Never)]
512         protected void CloseBorderWindow()
513         {
514             BorderWindow.BorderDestroy();
515         }
516
517         /// <summary>
518         /// This is an event callback when the close icon is touched.
519         /// </summary>
520         [EditorBrowsable(EditorBrowsableState.Never)]
521         public virtual bool OnCloseIconTouched(object sender, View.TouchEventArgs e)
522         {
523             if (e != null && e.Touch.GetState(0) == PointStateType.Up)
524             {
525                 CloseBorderWindow();
526             }
527             return true;
528         }
529
530
531         private void UpdateIcons()
532         {
533             if (BorderWindow != null && borderView != null)
534             {
535                 if (BorderWindow.IsMaximized() == true)
536                 {
537                     if (maximalizeIcon != null)
538                     {
539                         maximalizeIcon.ResourceUrl = DarkPreviousIcon;
540                     }
541                     if (minimalizeIcon != null)
542                     {
543                         minimalizeIcon.ResourceUrl = DarkMinimalizeIcon;
544                     }
545                     if (closeIcon != null)
546                     {
547                         closeIcon.ResourceUrl = DarkCloseIcon;
548                     }
549                     if (leftCornerIcon != null)
550                     {
551                         leftCornerIcon.ResourceUrl = DarkLeftCornerIcon;
552                     }
553                     if (rightCornerIcon != null)
554                     {
555                         rightCornerIcon.ResourceUrl = DarkRightCornerIcon;
556                     }
557                     borderView.CornerRadius = new Vector4(0, 0, 0, 0);
558                     borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
559                     BorderWindow.SetTransparency(false);
560                 }
561                 else
562                 {
563                     if (maximalizeIcon != null)
564                     {
565                         maximalizeIcon.ResourceUrl = MaximalizeIcon;
566                     }
567                     if (minimalizeIcon != null)
568                     {
569                         minimalizeIcon.ResourceUrl = MinimalizeIcon;
570                     }
571                     if (closeIcon != null)
572                     {
573                         closeIcon.ResourceUrl = CloseIcon;
574                     }
575                     if (leftCornerIcon != null)
576                     {
577                         leftCornerIcon.ResourceUrl = LeftCornerIcon;
578                     }
579                     if (rightCornerIcon != null)
580                     {
581                         rightCornerIcon.ResourceUrl = RightCornerIcon;
582                     }
583                     borderView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f);
584                     borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
585                     BorderWindow.SetTransparency(true);
586                 }
587             }
588         }
589
590
591         /// <summary>
592         /// Called after the border UI is created.
593         /// </summary>
594         /// <param name="borderView">The border view on which the border.</param>
595         [EditorBrowsable(EditorBrowsableState.Never)]
596         public virtual void OnCreated(View borderView)
597         {
598             if (borderView == null)
599             {
600                 return;
601             }
602             this.borderView = borderView;
603             // Register to resize and move through pan gestures.
604             borderPanGestureDetector = new PanGestureDetector();
605             borderPanGestureDetector.Attach(borderView);
606             borderPanGestureDetector.Detected += OnPanGestureDetected;
607
608             // Register touch event for effect when border is touched.
609             borderView.LeaveRequired = true;
610             borderView.TouchEvent += (s, e) =>
611             {
612                 if (e.Touch.GetState(0) == PointStateType.Started)
613                 {
614                     if (BorderWindow.IsMaximized() == false)
615                     {
616                         BorderWindow.Raise();
617                     }
618                     backgroundColor = new Color(borderView.BackgroundColor);
619                     borderView.BackgroundColor = DefaultClickedBackgroundColor;
620                 }
621                 else if (e.Touch.GetState(0) == PointStateType.Finished ||
622                          e.Touch.GetState(0) == PointStateType.Leave ||
623                          e.Touch.GetState(0) == PointStateType.Interrupted)
624                 {
625                     borderView.BackgroundColor = backgroundColor;
626                 }
627                 return true;
628             };
629
630             borderPinchGestureDetector = new PinchGestureDetector();
631             borderPinchGestureDetector.Attach(borderView);
632             borderPinchGestureDetector.Detected += OnPinchGestureDetected;
633
634             AddInterceptGesture();
635
636             UpdateIcons();
637         }
638
639
640         // Register an intercept touch event on the window.
641         private void AddInterceptGesture()
642         {
643             isWinGestures = false;
644             BorderWindow.InterceptTouchEvent += OnWinInterceptedTouch;
645         }
646
647         // Intercept touch on window.
648         private bool OnWinInterceptedTouch(object sender, Window.TouchEventArgs e)
649         {
650             if (e.Touch.GetState(0) == PointStateType.Stationary && e.Touch.GetPointCount() == 2)
651             {
652                 if (isWinGestures == false && timer == null)
653                 {
654                     timer = new Timer(300);
655                     timer.Tick += OnTick;
656                     timer.Start();
657                 }
658             }
659             else
660             {
661                 currentGesture = CurrentGesture.None;
662                 if (timer != null)
663                 {
664                     timer.Stop();
665                     timer.Dispose();
666                     timer = null;
667                 }
668             }
669             return false;
670         }
671
672         // If two finger long press is done, create a windowView.
673         // then, Register a gesture on the windowView to do a resize or move.
674         private bool OnTick(object o, Timer.TickEventArgs e)
675         {
676             windowView = new View()
677             {
678                 WidthResizePolicy = ResizePolicyType.FillToParent,
679                 HeightResizePolicy = ResizePolicyType.FillToParent,
680                 BackgroundColor = new Color(1, 1, 1, 0.5f),
681             };
682             windowView.TouchEvent += (s, e) =>
683             {
684                 return true;
685             };
686             BorderWindow.Add(windowView);
687
688             winTapGestureDetector = new TapGestureDetector();
689             winTapGestureDetector.Attach(windowView);
690             winTapGestureDetector.SetMaximumTapsRequired(3);
691             winTapGestureDetector.Detected += OnWinTapGestureDetected;
692
693             winPanGestureDetector = new PanGestureDetector();
694             winPanGestureDetector.Attach(windowView);
695             winPanGestureDetector.Detected += OnWinPanGestureDetected;
696
697             BorderWindow.InterceptTouchEvent -= OnWinInterceptedTouch;
698             isWinGestures = true;
699             return false;
700         }
701
702         // Behavior when the window is tapped.
703         private void OnWinTapGestureDetected(object source, TapGestureDetector.DetectedEventArgs e)
704         {
705           if (currentGesture <= CurrentGesture.TapGesture)
706           {
707               currentGesture = CurrentGesture.TapGesture;
708               if (e.TapGesture.NumberOfTaps == 2)
709               {
710                   if (BorderWindow.IsMaximized() == false)
711                   {
712                     BorderWindow.Maximize(true);
713                     OnMaximize(true);
714                   }
715                   else
716                   {
717                     BorderWindow.Maximize(false);
718                     OnMaximize(false);
719                   }
720               }
721               else
722               {
723                   ClearWindowGesture();
724               }
725           }
726         }
727
728         // Window moves through pan gestures.
729         private void OnWinPanGestureDetected(object source, PanGestureDetector.DetectedEventArgs e)
730         {
731             if (currentGesture <= CurrentGesture.PanGesture /*&& panGesture.NumberOfTouches == 1*/)
732             {
733                 PanGesture panGesture = e.PanGesture;
734
735                 if (panGesture.State == Gesture.StateType.Started)
736                 {
737                     currentGesture = CurrentGesture.PanGesture;
738                     if (BorderWindow.IsMaximized() == true)
739                     {
740                         BorderWindow.Maximize(false);
741                         OnMaximize(false);
742                     }
743                     else
744                     {
745                         BorderWindow.RequestMoveToServer();
746                     }
747                 }
748                 else if (panGesture.State == Gesture.StateType.Finished || panGesture.State == Gesture.StateType.Cancelled)
749                 {
750                     currentGesture = CurrentGesture.None;
751                     ClearWindowGesture();
752                 }
753             }
754         }
755
756         private void ClearWindowGesture()
757         {
758             if (isWinGestures)
759             {
760                 winPanGestureDetector.Dispose();
761                 winTapGestureDetector.Dispose();
762
763                 isWinGestures = false;
764                 BorderWindow.Remove(windowView);
765                 BorderWindow.InterceptTouchEvent += OnWinInterceptedTouch;
766             }
767         }
768
769         /// <summary>
770         /// Called when requesting a resize
771         /// </summary>
772         [EditorBrowsable(EditorBrowsableState.Never)]
773         public virtual void OnRequestResize() {}
774
775         /// <summary>
776         /// Called when the window is resized.
777         /// </summary>
778         /// <param name="width">The width of the resized window</param>
779         /// <param name="height">The height of the resized window</param>
780         [EditorBrowsable(EditorBrowsableState.Never)]
781         public virtual void OnResized(int width, int height)
782         {
783             if (overlayTimer != null)
784             {
785                 overlayTimer.Stop();
786                 overlayTimer.Dispose();
787                 overlayTimer = null;
788                 BorderWindow?.GetBorderWindowBottomLayer().LowerToBottom();
789                 borderView?.Show();
790             }
791             UpdateIcons();
792         }
793
794         /// <summary>
795         /// Called when the window is maximized.
796         /// </summary>
797         /// <param name="isMaximized">If window is maximized or unmaximized.</param>
798         [EditorBrowsable(EditorBrowsableState.Never)]
799         public virtual void OnMaximize(bool isMaximized)
800         {
801             UpdateIcons();
802         }
803
804         /// <summary>
805         /// Called when the window is minimized.
806         /// </summary>
807         /// <param name="isMinimized">If window is mnimized or unminimized.</param>
808         [EditorBrowsable(EditorBrowsableState.Never)]
809         public virtual void OnMinimize(bool isMinimized)
810         {
811             UpdateIcons();
812         }
813
814         /// <summary>
815         /// Show the border when OverlayMode is true and the window is now Maximize.
816         /// </summary>
817         /// <param name="time">Time(ms) for borders to disappear again</param>
818         /// <returns>True if border became show, false otherwise</returns>
819         [EditorBrowsable(EditorBrowsableState.Never)]
820         public virtual bool OverlayBorderShow(uint time = 3000)
821         {
822             if (BorderWindow != null && BorderWindow.IsMaximized())
823             {
824                 if (overlayTimer == null)
825                 {
826                     overlayTimer = new Timer(time);
827                     overlayTimer.Tick += (s, e) =>
828                     {
829                         BorderWindow.GetBorderWindowBottomLayer().LowerToBottom();
830                         borderView?.Hide();
831                         overlayTimer?.Stop();
832                         overlayTimer?.Dispose();
833                         overlayTimer = null;
834                         return false;
835                     };
836                     overlayTimer.Start();
837                     BorderWindow.GetBorderWindowBottomLayer().RaiseToTop();
838                     borderView?.Show();
839                 }
840                 else
841                 {
842                     overlayTimer.Start();
843                 }
844                 return true;
845             }
846             return false;
847         }
848
849         /// <summary>
850         /// Hide the border when OverlayMode is true and the window is now Maximize.
851         /// </summary>
852         /// <returns>True if border became hide, false otherwise</returns>
853         [EditorBrowsable(EditorBrowsableState.Never)]
854         public virtual bool OverlayBorderHide()
855         {
856             if (BorderWindow != null && BorderWindow.IsMaximized())
857             {
858                 borderView?.Hide();
859                 return true;
860             }
861             return false;
862         }
863
864         [EditorBrowsable(EditorBrowsableState.Never)]
865         protected virtual void Dispose(bool disposing)
866         {
867             if (disposed)
868             {
869                 return;
870             }
871             if (disposing)
872             {
873                 ClearWindowGesture();
874
875                 if (BorderWindow != null)
876                 {
877                     BorderWindow.InterceptTouchEvent -= OnWinInterceptedTouch;
878                 }
879
880                 borderView?.Dispose();
881                 windowView?.Dispose();
882                 borderPanGestureDetector?.Dispose();
883                 borderPinchGestureDetector?.Dispose();
884                 backgroundColor?.Dispose();
885                 minimalizeIcon?.Dispose();
886                 maximalizeIcon?.Dispose();
887                 closeIcon?.Dispose();
888                 leftCornerIcon?.Dispose();
889                 rightCornerIcon?.Dispose();
890                 timer?.Dispose();
891                 overlayTimer?.Dispose();
892             }
893             disposed = true;
894         }
895
896         /// <summary>
897         /// Dispose
898         /// </summary>
899         [EditorBrowsable(EditorBrowsableState.Never)]
900         public void Dispose()
901         {
902             Dispose(true);
903             global::System.GC.SuppressFinalize(this);
904         }
905         #endregion //Methods
906
907     }
908 }