[NUI] Add border resizing policy and add api to show/hide border when OverlayMode...
[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 false;
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 false;
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 false;
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 false;
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 false;
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 false;
506         }
507
508         /// <summary>
509         /// Close border window.
510         /// </summary>
511         [EditorBrowsable(EditorBrowsableState.Never)]
512         protected void CloseBorderWindow()
513         {
514             BorderWindow.Destroy();
515             BorderWindow = null;
516         }
517
518         /// <summary>
519         /// This is an event callback when the close icon is touched.
520         /// </summary>
521         [EditorBrowsable(EditorBrowsableState.Never)]
522         public virtual bool OnCloseIconTouched(object sender, View.TouchEventArgs e)
523         {
524             if (e == null)
525             {
526                 return false;
527             }
528             if (e != null && e.Touch.GetState(0) == PointStateType.Up)
529             {
530                 CloseBorderWindow();
531             }
532             return false;
533         }
534
535
536         private void UpdateIcons()
537         {
538             if (BorderWindow != null && borderView != null)
539             {
540                 if (BorderWindow.IsMaximized() == true)
541                 {
542                     if (maximalizeIcon != null)
543                     {
544                         maximalizeIcon.ResourceUrl = DarkPreviousIcon;
545                     }
546                     if (minimalizeIcon != null)
547                     {
548                         minimalizeIcon.ResourceUrl = DarkMinimalizeIcon;
549                     }
550                     if (closeIcon != null)
551                     {
552                         closeIcon.ResourceUrl = DarkCloseIcon;
553                     }
554                     if (leftCornerIcon != null)
555                     {
556                         leftCornerIcon.ResourceUrl = DarkLeftCornerIcon;
557                     }
558                     if (rightCornerIcon != null)
559                     {
560                         rightCornerIcon.ResourceUrl = DarkRightCornerIcon;
561                     }
562                     borderView.CornerRadius = new Vector4(0, 0, 0, 0);
563                     borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
564                     BorderWindow.SetTransparency(false);
565                 }
566                 else
567                 {
568                     if (maximalizeIcon != null)
569                     {
570                         maximalizeIcon.ResourceUrl = MaximalizeIcon;
571                     }
572                     if (minimalizeIcon != null)
573                     {
574                         minimalizeIcon.ResourceUrl = MinimalizeIcon;
575                     }
576                     if (closeIcon != null)
577                     {
578                         closeIcon.ResourceUrl = CloseIcon;
579                     }
580                     if (leftCornerIcon != null)
581                     {
582                         leftCornerIcon.ResourceUrl = LeftCornerIcon;
583                     }
584                     if (rightCornerIcon != null)
585                     {
586                         rightCornerIcon.ResourceUrl = RightCornerIcon;
587                     }
588                     borderView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f);
589                     borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
590                     BorderWindow.SetTransparency(true);
591                 }
592             }
593         }
594
595
596         /// <summary>
597         /// Called after the border UI is created.
598         /// </summary>
599         /// <param name="borderView">The border view on which the border.</param>
600         [EditorBrowsable(EditorBrowsableState.Never)]
601         public virtual void OnCreated(View borderView)
602         {
603             if (borderView == null)
604             {
605                 return;
606             }
607             this.borderView = borderView;
608             // Register to resize and move through pan gestures.
609             borderPanGestureDetector = new PanGestureDetector();
610             borderPanGestureDetector.Attach(borderView);
611             borderPanGestureDetector.Detected += OnPanGestureDetected;
612
613             // Register touch event for effect when border is touched.
614             borderView.LeaveRequired = true;
615             borderView.TouchEvent += (s, e) =>
616             {
617                 if (e.Touch.GetState(0) == PointStateType.Started)
618                 {
619                     if (BorderWindow.IsMaximized() == false)
620                     {
621                         BorderWindow.Raise();
622                     }
623                     backgroundColor = new Color(borderView.BackgroundColor);
624                     borderView.BackgroundColor = DefaultClickedBackgroundColor;
625                 }
626                 else if (e.Touch.GetState(0) == PointStateType.Finished ||
627                          e.Touch.GetState(0) == PointStateType.Leave ||
628                          e.Touch.GetState(0) == PointStateType.Interrupted)
629                 {
630                     borderView.BackgroundColor = backgroundColor;
631                 }
632                 return true;
633             };
634
635             borderPinchGestureDetector = new PinchGestureDetector();
636             borderPinchGestureDetector.Attach(borderView);
637             borderPinchGestureDetector.Detected += OnPinchGestureDetected;
638
639             AddInterceptGesture();
640
641             UpdateIcons();
642         }
643
644
645         // Register an intercept touch event on the window.
646         private void AddInterceptGesture()
647         {
648             isWinGestures = false;
649             BorderWindow.InterceptTouchEvent += OnWinInterceptedTouch;
650         }
651
652         // Intercept touch on window.
653         private bool OnWinInterceptedTouch(object sender, Window.TouchEventArgs e)
654         {
655             if (e.Touch.GetState(0) == PointStateType.Stationary && e.Touch.GetPointCount() == 2)
656             {
657                 if (isWinGestures == false && timer == null)
658                 {
659                     timer = new Timer(300);
660                     timer.Tick += OnTick;
661                     timer.Start();
662                 }
663             }
664             else
665             {
666                 currentGesture = CurrentGesture.None;
667                 if (timer != null)
668                 {
669                     timer.Stop();
670                     timer.Dispose();
671                     timer = null;
672                 }
673             }
674             return false;
675         }
676
677         // If two finger long press is done, create a windowView.
678         // then, Register a gesture on the windowView to do a resize or move.
679         private bool OnTick(object o, Timer.TickEventArgs e)
680         {
681             windowView = new View()
682             {
683                 WidthResizePolicy = ResizePolicyType.FillToParent,
684                 HeightResizePolicy = ResizePolicyType.FillToParent,
685                 BackgroundColor = new Color(1, 1, 1, 0.5f),
686             };
687             windowView.TouchEvent += (s, e) =>
688             {
689                 return true;
690             };
691             BorderWindow.Add(windowView);
692
693             winTapGestureDetector = new TapGestureDetector();
694             winTapGestureDetector.Attach(windowView);
695             winTapGestureDetector.SetMaximumTapsRequired(3);
696             winTapGestureDetector.Detected += OnWinTapGestureDetected;
697
698             winPanGestureDetector = new PanGestureDetector();
699             winPanGestureDetector.Attach(windowView);
700             winPanGestureDetector.Detected += OnWinPanGestureDetected;
701
702             BorderWindow.InterceptTouchEvent -= OnWinInterceptedTouch;
703             isWinGestures = true;
704             return false;
705         }
706
707         // Behavior when the window is tapped.
708         private void OnWinTapGestureDetected(object source, TapGestureDetector.DetectedEventArgs e)
709         {
710           if (currentGesture <= CurrentGesture.TapGesture)
711           {
712               currentGesture = CurrentGesture.TapGesture;
713               if (e.TapGesture.NumberOfTaps == 2)
714               {
715                   if (BorderWindow.IsMaximized() == false)
716                   {
717                     BorderWindow.Maximize(true);
718                     OnMaximize(true);
719                   }
720                   else
721                   {
722                     BorderWindow.Maximize(false);
723                     OnMaximize(false);
724                   }
725               }
726               else
727               {
728                   ClearWindowGesture();
729               }
730           }
731         }
732
733         // Window moves through pan gestures.
734         private void OnWinPanGestureDetected(object source, PanGestureDetector.DetectedEventArgs e)
735         {
736             if (currentGesture <= CurrentGesture.PanGesture /*&& panGesture.NumberOfTouches == 1*/)
737             {
738                 PanGesture panGesture = e.PanGesture;
739
740                 if (panGesture.State == Gesture.StateType.Started)
741                 {
742                     currentGesture = CurrentGesture.PanGesture;
743                     if (BorderWindow.IsMaximized() == true)
744                     {
745                         BorderWindow.Maximize(false);
746                         OnMaximize(false);
747                     }
748                     else
749                     {
750                         BorderWindow.RequestMoveToServer();
751                     }
752                 }
753                 else if (panGesture.State == Gesture.StateType.Finished || panGesture.State == Gesture.StateType.Cancelled)
754                 {
755                     currentGesture = CurrentGesture.None;
756                     ClearWindowGesture();
757                 }
758             }
759         }
760
761         private void ClearWindowGesture()
762         {
763             if (isWinGestures)
764             {
765                 winPanGestureDetector.Dispose();
766                 winTapGestureDetector.Dispose();
767
768                 isWinGestures = false;
769                 BorderWindow.Remove(windowView);
770                 BorderWindow.InterceptTouchEvent += OnWinInterceptedTouch;
771             }
772         }
773
774         /// <summary>
775         /// Called when requesting a resize
776         /// </summary>
777         [EditorBrowsable(EditorBrowsableState.Never)]
778         public virtual void OnRequestResize() {}
779
780         /// <summary>
781         /// Called when the window is resized.
782         /// </summary>
783         /// <param name="width">The width of the resized window</param>
784         /// <param name="height">The height of the resized window</param>
785         [EditorBrowsable(EditorBrowsableState.Never)]
786         public virtual void OnResized(int width, int height)
787         {
788             if (overlayTimer != null)
789             {
790                 overlayTimer.Stop();
791                 overlayTimer.Dispose();
792                 overlayTimer = null;
793                 BorderWindow?.GetBorderWindowBottomLayer().LowerToBottom();
794                 borderView?.Show();
795             }
796             UpdateIcons();
797         }
798
799         /// <summary>
800         /// Called when the window is maximized.
801         /// </summary>
802         /// <param name="isMaximized">If window is maximized or unmaximized.</param>
803         [EditorBrowsable(EditorBrowsableState.Never)]
804         public virtual void OnMaximize(bool isMaximized) 
805         {
806             UpdateIcons();
807         }
808
809         /// <summary>
810         /// Called when the window is minimized.
811         /// </summary>
812         /// <param name="isMinimized">If window is mnimized or unminimized.</param>
813         [EditorBrowsable(EditorBrowsableState.Never)]
814         public virtual void OnMinimize(bool isMinimized)
815         {
816             UpdateIcons();
817         }
818
819         /// <summary>
820         /// Show the border when OverlayMode is true and the window is now Maximize.
821         /// </summary>
822         /// <param name="time">Time(ms) for borders to disappear again</param>
823         /// <returns>True if border became show, false otherwise</returns>
824         [EditorBrowsable(EditorBrowsableState.Never)]
825         public virtual bool OverlayBorderShow(uint time = 3000)
826         {
827             if (BorderWindow != null && BorderWindow.IsMaximized())
828             {
829                 if (overlayTimer == null)
830                 {
831                     overlayTimer = new Timer(time);
832                     overlayTimer.Tick += (s, e) =>
833                     {
834                         BorderWindow.GetBorderWindowBottomLayer().LowerToBottom();
835                         borderView?.Hide();
836                         overlayTimer?.Stop();
837                         overlayTimer?.Dispose();
838                         overlayTimer = null;
839                         return false;
840                     };
841                     overlayTimer.Start();
842                     BorderWindow.GetBorderWindowBottomLayer().RaiseToTop();
843                     borderView?.Show();
844                 }
845                 else
846                 {
847                     overlayTimer.Start();
848                 }
849                 return true;
850             }
851             return false;
852         }
853
854         /// <summary>
855         /// Hide the border when OverlayMode is true and the window is now Maximize.
856         /// </summary>
857         /// <returns>True if border became hide, false otherwise</returns>
858         [EditorBrowsable(EditorBrowsableState.Never)]
859         public virtual bool OverlayBorderHide()
860         {
861             if (BorderWindow != null && BorderWindow.IsMaximized())
862             {
863                 borderView?.Hide();
864                 return true;
865             }
866             return false;
867         }
868
869         [EditorBrowsable(EditorBrowsableState.Never)]
870         protected virtual void Dispose(bool disposing)
871         {
872             if (disposed)
873             {
874                 return;
875             }
876             if (disposing)
877             {
878                 ClearWindowGesture();
879
880                 if (BorderWindow != null)
881                 {
882                     BorderWindow.InterceptTouchEvent -= OnWinInterceptedTouch;
883                 }
884
885                 borderPanGestureDetector?.Dispose();
886                 borderPinchGestureDetector?.Dispose();
887                 backgroundColor?.Dispose();
888                 minimalizeIcon?.Dispose();
889                 maximalizeIcon?.Dispose();
890                 closeIcon?.Dispose();
891                 leftCornerIcon?.Dispose();
892                 rightCornerIcon?.Dispose();
893                 timer?.Dispose();
894                 overlayTimer?.Dispose();
895                 windowView?.Dispose();
896                 borderView?.Dispose();
897             }
898             disposed = true;
899         }
900
901         /// <summary>
902         /// Dispose
903         /// </summary>
904         [EditorBrowsable(EditorBrowsableState.Never)]
905         public void Dispose()
906         {
907             Dispose(true);
908             global::System.GC.SuppressFinalize(this);
909         }
910         #endregion //Methods
911
912     }
913 }