2 * Copyright(c) 2022 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 using System.ComponentModel;
20 using Tizen.NUI.BaseComponents;
25 /// This class creates a border UI.
27 [EditorBrowsable(EditorBrowsableState.Never)]
28 public class DefaultBorder : IBorderInterface
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";
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";
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
55 private Color backgroundColor;
56 private View borderView;
58 private ImageView minimalizeIcon;
59 private ImageView maximalizeIcon;
60 private ImageView closeIcon;
61 private ImageView leftCornerIcon;
62 private ImageView rightCornerIcon;
64 private Window.BorderDirection direction = Window.BorderDirection.None;
65 private float preScale = 0;
67 private View windowView = null;
68 private bool isWinGestures = false;
71 private CurrentGesture currentGesture = CurrentGesture.None;
72 private bool disposed = false;
76 private PanGestureDetector borderPanGestureDetector;
77 private PinchGestureDetector borderPinchGestureDetector;
78 private PanGestureDetector winPanGestureDetector;
79 private TapGestureDetector winTapGestureDetector;
83 private enum CurrentGesture
95 /// The thickness of the border.
97 [EditorBrowsable(EditorBrowsableState.Never)]
98 public uint BorderLineThickness {get; set;}
101 /// The thickness of the border's touch area.
103 [EditorBrowsable(EditorBrowsableState.Never)]
104 public uint TouchThickness {get; set;}
107 /// The height of the border.
109 [EditorBrowsable(EditorBrowsableState.Never)]
110 public uint BorderHeight {get; set;}
113 /// The minimum size by which the window will small.
115 [EditorBrowsable(EditorBrowsableState.Never)]
116 public Size2D MinSize {get; set;}
119 /// The maximum size by which the window will big.
121 [EditorBrowsable(EditorBrowsableState.Never)]
122 public Size2D MaxSize {get; set;}
125 /// The window with borders added.
127 [EditorBrowsable(EditorBrowsableState.Never)]
128 public Window BorderWindow {get; set;}
131 /// Whether overlay mode.
132 /// If overlay mode is true, the border area is hidden when the window is maximized.
133 /// And if you touched at screen, the border area is shown on the screen.
134 /// Default value is false;
136 [EditorBrowsable(EditorBrowsableState.Never)]
137 public bool OverlayMode {get; set;}
141 /// Creates a default border
143 [EditorBrowsable(EditorBrowsableState.Never)]
144 public DefaultBorder()
146 BorderLineThickness = DefaultLineThickness;
147 TouchThickness = DefaultTouchThickness;
148 BorderHeight = DefaultHeight;
149 MinSize = DefaultMinSize;
154 /// Create top border UI. User can override this method to draw top border UI.
156 /// <param name="topView">The top view on which the border.</param>
157 [EditorBrowsable(EditorBrowsableState.Never)]
158 public virtual bool CreateTopBorderView(View topView)
164 /// Create bottom border UI. User can override this method to draw bottom border UI.
166 /// <param name="bottomView">The bottom view on which the border.</param>
167 [EditorBrowsable(EditorBrowsableState.Never)]
168 public virtual bool CreateBottomBorderView(View bottomView)
170 if (bottomView == null)
174 bottomView.Layout = new RelativeLayout();
176 minimalizeIcon = new ImageView()
178 ResourceUrl = MinimalizeIcon,
181 maximalizeIcon = new ImageView()
183 ResourceUrl = MaximalizeIcon,
186 closeIcon = new ImageView()
188 ResourceUrl = CloseIcon,
191 leftCornerIcon = new ImageView()
193 ResourceUrl = LeftCornerIcon,
196 rightCornerIcon = new ImageView()
198 ResourceUrl = RightCornerIcon,
201 RelativeLayout.SetRightTarget(minimalizeIcon, maximalizeIcon);
202 RelativeLayout.SetRightRelativeOffset(minimalizeIcon, 0.0f);
203 RelativeLayout.SetHorizontalAlignment(minimalizeIcon, RelativeLayout.Alignment.End);
204 RelativeLayout.SetRightTarget(maximalizeIcon, closeIcon);
205 RelativeLayout.SetRightRelativeOffset(maximalizeIcon, 0.0f);
206 RelativeLayout.SetHorizontalAlignment(maximalizeIcon, RelativeLayout.Alignment.End);
207 RelativeLayout.SetRightTarget(closeIcon, rightCornerIcon);
208 RelativeLayout.SetRightRelativeOffset(closeIcon, 0.0f);
209 RelativeLayout.SetHorizontalAlignment(closeIcon, RelativeLayout.Alignment.End);
210 RelativeLayout.SetRightRelativeOffset(rightCornerIcon, 1.0f);
211 RelativeLayout.SetHorizontalAlignment(rightCornerIcon, RelativeLayout.Alignment.End);
212 bottomView.Add(leftCornerIcon);
213 bottomView.Add(minimalizeIcon);
214 bottomView.Add(maximalizeIcon);
215 bottomView.Add(closeIcon);
216 bottomView.Add(rightCornerIcon);
219 minimalizeIcon.TouchEvent += OnMinimizeIconTouched;
220 maximalizeIcon.TouchEvent += OnMaximizeIconTouched;
221 closeIcon.TouchEvent += OnCloseIconTouched;
222 leftCornerIcon.TouchEvent += OnLeftBottomCornerIconTouched;
223 rightCornerIcon.TouchEvent += OnRightBottomCornerIconTouched;
229 /// Create border UI. User can override this method to draw border UI.
230 /// A top border and a bottom border are added to this view.
232 /// <param name="borderView">The root view on which the border.</param>
233 [EditorBrowsable(EditorBrowsableState.Never)]
234 public virtual void CreateBorderView(View borderView)
236 if (borderView == null)
240 this.borderView = borderView;
241 borderView.BackgroundColor = DefaultBackgroundColor;
242 borderView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f);
243 borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
246 /// Determines the behavior of pinch gesture.
247 private void OnPinchGestureDetected(object source, PinchGestureDetector.DetectedEventArgs e)
253 if (e.PinchGesture.State == Gesture.StateType.Started)
255 preScale = e.PinchGesture.Scale;
257 else if (e.PinchGesture.State == Gesture.StateType.Finished || e.PinchGesture.State == Gesture.StateType.Cancelled)
259 if (preScale > e.PinchGesture.Scale)
261 if (BorderWindow.IsMaximized())
263 BorderWindow.Maximize(false);
267 BorderWindow.Minimize(true);
272 BorderWindow.Maximize(true);
277 /// Determines the behavior of borders.
278 private void OnPanGestureDetected(object source, PanGestureDetector.DetectedEventArgs e)
284 PanGesture panGesture = e.PanGesture;
286 if (panGesture.State == Gesture.StateType.Started && panGesture.Position != null)
288 direction = BorderWindow.GetDirection(panGesture.Position.X, panGesture.Position.Y);
290 if (direction == Window.BorderDirection.Move)
292 if (BorderWindow.IsMaximized() == true)
294 BorderWindow.Maximize(false);
298 BorderWindow.RequestMoveToServer();
301 else if (direction != Window.BorderDirection.None)
304 BorderWindow.RequestResizeToServer((Window.ResizeDirection)direction);
307 else if (panGesture.State == Gesture.StateType.Finished || panGesture.State == Gesture.StateType.Cancelled)
309 direction = Window.BorderDirection.None;
310 ClearWindowGesture();
315 /// This is an event callback when the left top corner icon is touched.
317 [EditorBrowsable(EditorBrowsableState.Never)]
318 public virtual bool OnLeftTopCornerIconTouched(object sender, View.TouchEventArgs e)
324 if (e.Touch.GetState(0) == PointStateType.Down)
326 ClearWindowGesture();
328 BorderWindow.RequestResizeToServer(Window.ResizeDirection.TopLeft);
334 ///This is an event callback when the right bottom corner icon is touched.
336 [EditorBrowsable(EditorBrowsableState.Never)]
337 public virtual bool OnRightTopCornerIconTouched(object sender, View.TouchEventArgs e)
343 if (e.Touch.GetState(0) == PointStateType.Down)
345 ClearWindowGesture();
347 BorderWindow.RequestResizeToServer(Window.ResizeDirection.TopRight);
354 /// This is an event callback when the left bottom corner icon is touched.
356 [EditorBrowsable(EditorBrowsableState.Never)]
357 public virtual bool OnLeftBottomCornerIconTouched(object sender, View.TouchEventArgs e)
363 if (e.Touch.GetState(0) == PointStateType.Down)
365 ClearWindowGesture();
367 BorderWindow.RequestResizeToServer(Window.ResizeDirection.BottomLeft);
373 ///This is an event callback when the right bottom corner icon is touched.
375 [EditorBrowsable(EditorBrowsableState.Never)]
376 public virtual bool OnRightBottomCornerIconTouched(object sender, View.TouchEventArgs e)
382 if (e.Touch.GetState(0) == PointStateType.Down)
384 ClearWindowGesture();
386 BorderWindow.RequestResizeToServer(Window.ResizeDirection.BottomRight);
393 /// This is an event callback when the minimize icon is touched.
395 [EditorBrowsable(EditorBrowsableState.Never)]
396 public virtual bool OnMinimizeIconTouched(object sender, View.TouchEventArgs e)
402 if (e.Touch.GetState(0) == PointStateType.Up)
404 ClearWindowGesture();
405 BorderWindow.Minimize(true);
411 /// This is an event callback when the maximum icon is touched.
413 [EditorBrowsable(EditorBrowsableState.Never)]
414 public virtual bool OnMaximizeIconTouched(object sender, View.TouchEventArgs e)
420 if (e.Touch.GetState(0) == PointStateType.Up)
422 ClearWindowGesture();
423 if (BorderWindow.IsMaximized())
425 BorderWindow.Maximize(false);
429 BorderWindow.Maximize(true);
436 /// This is an event callback when the close icon is touched.
438 [EditorBrowsable(EditorBrowsableState.Never)]
439 public virtual bool OnCloseIconTouched(object sender, View.TouchEventArgs e)
445 if (e.Touch.GetState(0) == PointStateType.Up)
447 BorderWindow.Destroy();
454 private void UpdateIcons()
456 if (BorderWindow != null && borderView != null)
458 if (BorderWindow.IsMaximized() == true)
460 if (maximalizeIcon != null)
462 maximalizeIcon.ResourceUrl = DarkPreviousIcon;
464 if (minimalizeIcon != null)
466 minimalizeIcon.ResourceUrl = DarkMinimalizeIcon;
468 if (closeIcon != null)
470 closeIcon.ResourceUrl = DarkCloseIcon;
472 if (leftCornerIcon != null)
474 leftCornerIcon.ResourceUrl = DarkLeftCornerIcon;
476 if (rightCornerIcon != null)
478 rightCornerIcon.ResourceUrl = DarkRightCornerIcon;
480 borderView.CornerRadius = new Vector4(0, 0, 0, 0);
481 borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
482 BorderWindow.SetTransparency(false);
486 if (maximalizeIcon != null)
488 maximalizeIcon.ResourceUrl = MaximalizeIcon;
490 if (minimalizeIcon != null)
492 minimalizeIcon.ResourceUrl = MinimalizeIcon;
494 if (closeIcon != null)
496 closeIcon.ResourceUrl = CloseIcon;
498 if (leftCornerIcon != null)
500 leftCornerIcon.ResourceUrl = LeftCornerIcon;
502 if (rightCornerIcon != null)
504 rightCornerIcon.ResourceUrl = RightCornerIcon;
506 borderView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f);
507 borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
508 BorderWindow.SetTransparency(true);
515 /// Called after the border UI is created.
517 /// <param name="borderView">The border view on which the border.</param>
518 [EditorBrowsable(EditorBrowsableState.Never)]
519 public virtual void OnCreated(View borderView)
521 if (borderView == null)
525 // Register to resize and move through pan gestures.
526 borderPanGestureDetector = new PanGestureDetector();
527 borderPanGestureDetector.Attach(borderView);
528 borderPanGestureDetector.Detected += OnPanGestureDetected;
530 // Register touch event for effect when border is touched.
531 borderView.LeaveRequired = true;
532 borderView.TouchEvent += (s, e) =>
534 if (e.Touch.GetState(0) == PointStateType.Started)
536 if (BorderWindow.IsMaximized() == false)
538 BorderWindow.Raise();
540 backgroundColor = new Color(borderView.BackgroundColor);
541 borderView.BackgroundColor = DefaultClickedBackgroundColor;
543 else if (e.Touch.GetState(0) == PointStateType.Finished ||
544 e.Touch.GetState(0) == PointStateType.Leave ||
545 e.Touch.GetState(0) == PointStateType.Interrupted)
547 borderView.BackgroundColor = backgroundColor;
552 borderPinchGestureDetector = new PinchGestureDetector();
553 borderPinchGestureDetector.Attach(borderView);
554 borderPinchGestureDetector.Detected += OnPinchGestureDetected;
556 AddInterceptGesture();
562 // Register an intercept touch event on the window.
563 private void AddInterceptGesture()
565 isWinGestures = false;
566 BorderWindow.InterceptTouchEvent += OnWinInterceptedTouch;
569 // Intercept touch on window.
570 private bool OnWinInterceptedTouch(object sender, Window.TouchEventArgs e)
572 if (e.Touch.GetState(0) == PointStateType.Stationary && e.Touch.GetPointCount() == 2)
574 if (isWinGestures == false && timer == null)
576 timer = new Timer(300);
577 timer.Tick += OnTick;
583 currentGesture = CurrentGesture.None;
594 // If two finger long press is done, create a windowView.
595 // then, Register a gesture on the windowView to do a resize or move.
596 private bool OnTick(object o, Timer.TickEventArgs e)
598 windowView = new View()
600 WidthResizePolicy = ResizePolicyType.FillToParent,
601 HeightResizePolicy = ResizePolicyType.FillToParent,
602 BackgroundColor = new Color(1, 1, 1, 0.5f),
604 windowView.TouchEvent += (s, e) =>
608 BorderWindow.Add(windowView);
610 winTapGestureDetector = new TapGestureDetector();
611 winTapGestureDetector.Attach(windowView);
612 winTapGestureDetector.SetMaximumTapsRequired(3);
613 winTapGestureDetector.Detected += OnWinTapGestureDetected;
615 winPanGestureDetector = new PanGestureDetector();
616 winPanGestureDetector.Attach(windowView);
617 winPanGestureDetector.Detected += OnWinPanGestureDetected;
619 BorderWindow.InterceptTouchEvent -= OnWinInterceptedTouch;
620 isWinGestures = true;
624 // Behavior when the window is tapped.
625 private void OnWinTapGestureDetected(object source, TapGestureDetector.DetectedEventArgs e)
627 if (currentGesture <= CurrentGesture.TapGesture)
629 currentGesture = CurrentGesture.TapGesture;
630 if (e.TapGesture.NumberOfTaps == 2)
632 if (BorderWindow.IsMaximized() == false)
634 BorderWindow.Maximize(true);
638 BorderWindow.Maximize(false);
643 ClearWindowGesture();
648 // Window moves through pan gestures.
649 private void OnWinPanGestureDetected(object source, PanGestureDetector.DetectedEventArgs e)
651 if (currentGesture <= CurrentGesture.PanGesture /*&& panGesture.NumberOfTouches == 1*/)
653 PanGesture panGesture = e.PanGesture;
655 if (panGesture.State == Gesture.StateType.Started)
657 currentGesture = CurrentGesture.PanGesture;
658 if (BorderWindow.IsMaximized() == true)
660 BorderWindow.Maximize(false);
664 BorderWindow.RequestMoveToServer();
667 else if (panGesture.State == Gesture.StateType.Finished || panGesture.State == Gesture.StateType.Cancelled)
669 currentGesture = CurrentGesture.None;
670 ClearWindowGesture();
675 private void ClearWindowGesture()
679 winPanGestureDetector.Dispose();
680 winTapGestureDetector.Dispose();
682 isWinGestures = false;
683 BorderWindow.Remove(windowView);
684 BorderWindow.InterceptTouchEvent += OnWinInterceptedTouch;
689 /// Called when requesting a resize
691 [EditorBrowsable(EditorBrowsableState.Never)]
692 public virtual void OnRequestResize() {}
695 /// Called when the window is resized.
697 /// <param name="width">The width of the resized window</param>
698 /// <param name="height">The height of the resized window</param>
699 [EditorBrowsable(EditorBrowsableState.Never)]
700 public virtual void OnResized(int width, int height)
705 [EditorBrowsable(EditorBrowsableState.Never)]
706 protected virtual void Dispose(bool disposing)
714 ClearWindowGesture();
716 if (BorderWindow != null)
718 BorderWindow.InterceptTouchEvent -= OnWinInterceptedTouch;
721 borderPanGestureDetector?.Dispose();
722 borderPinchGestureDetector?.Dispose();
723 backgroundColor?.Dispose();
724 minimalizeIcon?.Dispose();
725 maximalizeIcon?.Dispose();
726 closeIcon?.Dispose();
727 leftCornerIcon?.Dispose();
728 rightCornerIcon?.Dispose();
730 windowView?.Dispose();
731 borderView?.Dispose();
739 [EditorBrowsable(EditorBrowsableState.Never)]
740 public void Dispose()
743 global::System.GC.SuppressFinalize(this);