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;
70 private Timer overlayTimer;
72 private CurrentGesture currentGesture = CurrentGesture.None;
73 private bool disposed = false;
77 private PanGestureDetector borderPanGestureDetector;
78 private PinchGestureDetector borderPinchGestureDetector;
79 private PanGestureDetector winPanGestureDetector;
80 private TapGestureDetector winTapGestureDetector;
84 private enum CurrentGesture
96 /// The thickness of the border.
98 [EditorBrowsable(EditorBrowsableState.Never)]
99 public uint BorderLineThickness {get; set;}
102 /// The thickness of the border's touch area.
104 [EditorBrowsable(EditorBrowsableState.Never)]
105 public uint TouchThickness {get; set;}
108 /// The height of the border.
110 [EditorBrowsable(EditorBrowsableState.Never)]
111 public uint BorderHeight {get; set;}
114 /// The minimum size by which the window will small.
116 [EditorBrowsable(EditorBrowsableState.Never)]
117 public Size2D MinSize {get; set;}
120 /// The maximum size by which the window will big.
122 [EditorBrowsable(EditorBrowsableState.Never)]
123 public Size2D MaxSize {get; set;}
126 /// The window with borders added.
128 [EditorBrowsable(EditorBrowsableState.Never)]
129 public Window BorderWindow {get; set;}
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;
137 [EditorBrowsable(EditorBrowsableState.Never)]
138 public bool OverlayMode {get; set;}
141 /// Set the window resizing policy.
142 /// Default value is BorderResizePolicyType.Free;
144 [EditorBrowsable(EditorBrowsableState.Never)]
145 public Window.BorderResizePolicyType ResizePolicy {get; set;}
149 /// Creates a default border
151 [EditorBrowsable(EditorBrowsableState.Never)]
152 public DefaultBorder()
154 BorderLineThickness = DefaultLineThickness;
155 TouchThickness = DefaultTouchThickness;
156 BorderHeight = DefaultHeight;
157 MinSize = DefaultMinSize;
159 ResizePolicy = Window.BorderResizePolicyType.Free;
163 /// Create top border UI. User can override this method to draw top border UI.
165 /// <param name="topView">The top view on which the border.</param>
166 [EditorBrowsable(EditorBrowsableState.Never)]
167 public virtual bool CreateTopBorderView(View topView)
173 /// Create bottom border UI. User can override this method to draw bottom border UI.
175 /// <param name="bottomView">The bottom view on which the border.</param>
176 [EditorBrowsable(EditorBrowsableState.Never)]
177 public virtual bool CreateBottomBorderView(View bottomView)
179 if (bottomView == null)
183 bottomView.Layout = new RelativeLayout();
185 minimalizeIcon = new ImageView()
188 ResourceUrl = MinimalizeIcon,
189 AccessibilityHighlightable = true,
192 maximalizeIcon = new ImageView()
195 ResourceUrl = MaximalizeIcon,
196 AccessibilityHighlightable = true,
199 closeIcon = new ImageView()
202 ResourceUrl = CloseIcon,
203 AccessibilityHighlightable = true,
206 leftCornerIcon = new ImageView()
209 ResourceUrl = LeftCornerIcon,
210 AccessibilityHighlightable = true,
213 rightCornerIcon = new ImageView()
216 ResourceUrl = RightCornerIcon,
217 AccessibilityHighlightable = true,
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);
238 minimalizeIcon.TouchEvent += OnMinimizeIconTouched;
239 maximalizeIcon.TouchEvent += OnMaximizeIconTouched;
240 closeIcon.TouchEvent += OnCloseIconTouched;
241 leftCornerIcon.TouchEvent += OnLeftBottomCornerIconTouched;
242 rightCornerIcon.TouchEvent += OnRightBottomCornerIconTouched;
244 minimalizeIcon.AccessibilityActivated += (s, e) =>
246 MinimizeBorderWindow();
248 maximalizeIcon.AccessibilityActivated += (s, e) =>
250 MaximizeBorderWindow();
252 closeIcon.AccessibilityActivated += (s, e) =>
257 minimalizeIcon.AccessibilityNameRequested += (s, e) =>
261 maximalizeIcon.AccessibilityNameRequested += (s, e) =>
265 closeIcon.AccessibilityNameRequested += (s, e) =>
269 leftCornerIcon.AccessibilityNameRequested += (s, e) =>
273 rightCornerIcon.AccessibilityNameRequested += (s, e) =>
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);
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.
292 /// <param name="borderView">The root view on which the border.</param>
293 [EditorBrowsable(EditorBrowsableState.Never)]
294 public virtual void CreateBorderView(View borderView)
296 if (borderView == null)
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;
306 /// Determines the behavior of pinch gesture.
307 private void OnPinchGestureDetected(object source, PinchGestureDetector.DetectedEventArgs e)
313 if (e.PinchGesture.State == Gesture.StateType.Started)
315 preScale = e.PinchGesture.Scale;
317 else if (e.PinchGesture.State == Gesture.StateType.Finished || e.PinchGesture.State == Gesture.StateType.Cancelled)
319 if (preScale > e.PinchGesture.Scale)
321 if (BorderWindow.IsMaximized())
323 BorderWindow.Maximize(false);
328 BorderWindow.Minimize(true);
334 BorderWindow.Maximize(true);
340 /// Determines the behavior of borders.
341 private void OnPanGestureDetected(object source, PanGestureDetector.DetectedEventArgs e)
347 PanGesture panGesture = e.PanGesture;
349 if (panGesture.State == Gesture.StateType.Started && panGesture.Position != null)
351 direction = BorderWindow.GetDirection(panGesture.Position.X, panGesture.Position.Y);
353 if (direction == Window.BorderDirection.Move)
355 if (BorderWindow.IsMaximized() == true)
357 BorderWindow.Maximize(false);
362 BorderWindow.RequestMoveToServer();
365 else if (direction != Window.BorderDirection.None && ResizePolicy != Window.BorderResizePolicyType.Fixed)
368 BorderWindow.RequestResizeToServer((Window.ResizeDirection)direction);
371 else if (panGesture.State == Gesture.StateType.Finished || panGesture.State == Gesture.StateType.Cancelled)
373 direction = Window.BorderDirection.None;
374 ClearWindowGesture();
379 /// This is an event callback when the left top corner icon is touched.
381 [EditorBrowsable(EditorBrowsableState.Never)]
382 public virtual bool OnLeftTopCornerIconTouched(object sender, View.TouchEventArgs e)
384 if (e != null && e.Touch.GetState(0) == PointStateType.Down)
386 ClearWindowGesture();
387 if (ResizePolicy != Window.BorderResizePolicyType.Fixed)
390 BorderWindow.RequestResizeToServer(Window.ResizeDirection.TopLeft);
397 ///This is an event callback when the right bottom corner icon is touched.
399 [EditorBrowsable(EditorBrowsableState.Never)]
400 public virtual bool OnRightTopCornerIconTouched(object sender, View.TouchEventArgs e)
402 if (e != null && e.Touch.GetState(0) == PointStateType.Down)
404 ClearWindowGesture();
405 if (ResizePolicy != Window.BorderResizePolicyType.Fixed)
408 BorderWindow.RequestResizeToServer(Window.ResizeDirection.TopRight);
416 /// This is an event callback when the left bottom corner icon is touched.
418 [EditorBrowsable(EditorBrowsableState.Never)]
419 public virtual bool OnLeftBottomCornerIconTouched(object sender, View.TouchEventArgs e)
421 if (e != null && e.Touch.GetState(0) == PointStateType.Down)
423 ClearWindowGesture();
424 if (ResizePolicy != Window.BorderResizePolicyType.Fixed)
427 BorderWindow.RequestResizeToServer(Window.ResizeDirection.BottomLeft);
434 ///This is an event callback when the right bottom corner icon is touched.
436 [EditorBrowsable(EditorBrowsableState.Never)]
437 public virtual bool OnRightBottomCornerIconTouched(object sender, View.TouchEventArgs e)
439 if (e != null && e.Touch.GetState(0) == PointStateType.Down)
441 ClearWindowGesture();
442 if (ResizePolicy != Window.BorderResizePolicyType.Fixed)
445 BorderWindow.RequestResizeToServer(Window.ResizeDirection.BottomRight);
453 /// Minimize border window.
455 [EditorBrowsable(EditorBrowsableState.Never)]
456 protected void MinimizeBorderWindow()
458 ClearWindowGesture();
459 BorderWindow.Minimize(true);
464 /// This is an event callback when the minimize icon is touched.
466 [EditorBrowsable(EditorBrowsableState.Never)]
467 public virtual bool OnMinimizeIconTouched(object sender, View.TouchEventArgs e)
469 if (e != null && e.Touch.GetState(0) == PointStateType.Up)
471 MinimizeBorderWindow();
477 /// Maximize border window.
479 [EditorBrowsable(EditorBrowsableState.Never)]
480 protected void MaximizeBorderWindow()
482 ClearWindowGesture();
483 if (BorderWindow.IsMaximized())
485 BorderWindow.Maximize(false);
490 BorderWindow.Maximize(true);
496 /// This is an event callback when the maximum icon is touched.
498 [EditorBrowsable(EditorBrowsableState.Never)]
499 public virtual bool OnMaximizeIconTouched(object sender, View.TouchEventArgs e)
501 if (e != null && e.Touch.GetState(0) == PointStateType.Up)
503 MaximizeBorderWindow();
509 /// Close border window.
511 [EditorBrowsable(EditorBrowsableState.Never)]
512 protected void CloseBorderWindow()
514 BorderWindow.Destroy();
519 /// This is an event callback when the close icon is touched.
521 [EditorBrowsable(EditorBrowsableState.Never)]
522 public virtual bool OnCloseIconTouched(object sender, View.TouchEventArgs e)
528 if (e != null && e.Touch.GetState(0) == PointStateType.Up)
536 private void UpdateIcons()
538 if (BorderWindow != null && borderView != null)
540 if (BorderWindow.IsMaximized() == true)
542 if (maximalizeIcon != null)
544 maximalizeIcon.ResourceUrl = DarkPreviousIcon;
546 if (minimalizeIcon != null)
548 minimalizeIcon.ResourceUrl = DarkMinimalizeIcon;
550 if (closeIcon != null)
552 closeIcon.ResourceUrl = DarkCloseIcon;
554 if (leftCornerIcon != null)
556 leftCornerIcon.ResourceUrl = DarkLeftCornerIcon;
558 if (rightCornerIcon != null)
560 rightCornerIcon.ResourceUrl = DarkRightCornerIcon;
562 borderView.CornerRadius = new Vector4(0, 0, 0, 0);
563 borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
564 BorderWindow.SetTransparency(false);
568 if (maximalizeIcon != null)
570 maximalizeIcon.ResourceUrl = MaximalizeIcon;
572 if (minimalizeIcon != null)
574 minimalizeIcon.ResourceUrl = MinimalizeIcon;
576 if (closeIcon != null)
578 closeIcon.ResourceUrl = CloseIcon;
580 if (leftCornerIcon != null)
582 leftCornerIcon.ResourceUrl = LeftCornerIcon;
584 if (rightCornerIcon != null)
586 rightCornerIcon.ResourceUrl = RightCornerIcon;
588 borderView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f);
589 borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
590 BorderWindow.SetTransparency(true);
597 /// Called after the border UI is created.
599 /// <param name="borderView">The border view on which the border.</param>
600 [EditorBrowsable(EditorBrowsableState.Never)]
601 public virtual void OnCreated(View borderView)
603 if (borderView == null)
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;
613 // Register touch event for effect when border is touched.
614 borderView.LeaveRequired = true;
615 borderView.TouchEvent += (s, e) =>
617 if (e.Touch.GetState(0) == PointStateType.Started)
619 if (BorderWindow.IsMaximized() == false)
621 BorderWindow.Raise();
623 backgroundColor = new Color(borderView.BackgroundColor);
624 borderView.BackgroundColor = DefaultClickedBackgroundColor;
626 else if (e.Touch.GetState(0) == PointStateType.Finished ||
627 e.Touch.GetState(0) == PointStateType.Leave ||
628 e.Touch.GetState(0) == PointStateType.Interrupted)
630 borderView.BackgroundColor = backgroundColor;
635 borderPinchGestureDetector = new PinchGestureDetector();
636 borderPinchGestureDetector.Attach(borderView);
637 borderPinchGestureDetector.Detected += OnPinchGestureDetected;
639 AddInterceptGesture();
645 // Register an intercept touch event on the window.
646 private void AddInterceptGesture()
648 isWinGestures = false;
649 BorderWindow.InterceptTouchEvent += OnWinInterceptedTouch;
652 // Intercept touch on window.
653 private bool OnWinInterceptedTouch(object sender, Window.TouchEventArgs e)
655 if (e.Touch.GetState(0) == PointStateType.Stationary && e.Touch.GetPointCount() == 2)
657 if (isWinGestures == false && timer == null)
659 timer = new Timer(300);
660 timer.Tick += OnTick;
666 currentGesture = CurrentGesture.None;
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)
681 windowView = new View()
683 WidthResizePolicy = ResizePolicyType.FillToParent,
684 HeightResizePolicy = ResizePolicyType.FillToParent,
685 BackgroundColor = new Color(1, 1, 1, 0.5f),
687 windowView.TouchEvent += (s, e) =>
691 BorderWindow.Add(windowView);
693 winTapGestureDetector = new TapGestureDetector();
694 winTapGestureDetector.Attach(windowView);
695 winTapGestureDetector.SetMaximumTapsRequired(3);
696 winTapGestureDetector.Detected += OnWinTapGestureDetected;
698 winPanGestureDetector = new PanGestureDetector();
699 winPanGestureDetector.Attach(windowView);
700 winPanGestureDetector.Detected += OnWinPanGestureDetected;
702 BorderWindow.InterceptTouchEvent -= OnWinInterceptedTouch;
703 isWinGestures = true;
707 // Behavior when the window is tapped.
708 private void OnWinTapGestureDetected(object source, TapGestureDetector.DetectedEventArgs e)
710 if (currentGesture <= CurrentGesture.TapGesture)
712 currentGesture = CurrentGesture.TapGesture;
713 if (e.TapGesture.NumberOfTaps == 2)
715 if (BorderWindow.IsMaximized() == false)
717 BorderWindow.Maximize(true);
722 BorderWindow.Maximize(false);
728 ClearWindowGesture();
733 // Window moves through pan gestures.
734 private void OnWinPanGestureDetected(object source, PanGestureDetector.DetectedEventArgs e)
736 if (currentGesture <= CurrentGesture.PanGesture /*&& panGesture.NumberOfTouches == 1*/)
738 PanGesture panGesture = e.PanGesture;
740 if (panGesture.State == Gesture.StateType.Started)
742 currentGesture = CurrentGesture.PanGesture;
743 if (BorderWindow.IsMaximized() == true)
745 BorderWindow.Maximize(false);
750 BorderWindow.RequestMoveToServer();
753 else if (panGesture.State == Gesture.StateType.Finished || panGesture.State == Gesture.StateType.Cancelled)
755 currentGesture = CurrentGesture.None;
756 ClearWindowGesture();
761 private void ClearWindowGesture()
765 winPanGestureDetector.Dispose();
766 winTapGestureDetector.Dispose();
768 isWinGestures = false;
769 BorderWindow.Remove(windowView);
770 BorderWindow.InterceptTouchEvent += OnWinInterceptedTouch;
775 /// Called when requesting a resize
777 [EditorBrowsable(EditorBrowsableState.Never)]
778 public virtual void OnRequestResize() {}
781 /// Called when the window is resized.
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)
788 if (overlayTimer != null)
791 overlayTimer.Dispose();
793 BorderWindow?.GetBorderWindowBottomLayer().LowerToBottom();
800 /// Called when the window is maximized.
802 /// <param name="isMaximized">If window is maximized or unmaximized.</param>
803 [EditorBrowsable(EditorBrowsableState.Never)]
804 public virtual void OnMaximize(bool isMaximized)
810 /// Called when the window is minimized.
812 /// <param name="isMinimized">If window is mnimized or unminimized.</param>
813 [EditorBrowsable(EditorBrowsableState.Never)]
814 public virtual void OnMinimize(bool isMinimized)
820 /// Show the border when OverlayMode is true and the window is now Maximize.
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)
827 if (BorderWindow != null && BorderWindow.IsMaximized())
829 if (overlayTimer == null)
831 overlayTimer = new Timer(time);
832 overlayTimer.Tick += (s, e) =>
834 BorderWindow.GetBorderWindowBottomLayer().LowerToBottom();
836 overlayTimer?.Stop();
837 overlayTimer?.Dispose();
841 overlayTimer.Start();
842 BorderWindow.GetBorderWindowBottomLayer().RaiseToTop();
847 overlayTimer.Start();
855 /// Hide the border when OverlayMode is true and the window is now Maximize.
857 /// <returns>True if border became hide, false otherwise</returns>
858 [EditorBrowsable(EditorBrowsableState.Never)]
859 public virtual bool OverlayBorderHide()
861 if (BorderWindow != null && BorderWindow.IsMaximized())
869 [EditorBrowsable(EditorBrowsableState.Never)]
870 protected virtual void Dispose(bool disposing)
878 ClearWindowGesture();
880 if (BorderWindow != null)
882 BorderWindow.InterceptTouchEvent -= OnWinInterceptedTouch;
885 borderPanGestureDetector?.Dispose();
886 borderPinchGestureDetector?.Dispose();
887 backgroundColor?.Dispose();
888 minimalizeIcon?.Dispose();
889 maximalizeIcon?.Dispose();
890 closeIcon?.Dispose();
891 leftCornerIcon?.Dispose();
892 rightCornerIcon?.Dispose();
894 overlayTimer?.Dispose();
895 windowView?.Dispose();
896 borderView?.Dispose();
904 [EditorBrowsable(EditorBrowsableState.Never)]
905 public void Dispose()
908 global::System.GC.SuppressFinalize(this);