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