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.BorderDestroy();
518 /// This is an event callback when the close icon is touched.
520 [EditorBrowsable(EditorBrowsableState.Never)]
521 public virtual bool OnCloseIconTouched(object sender, View.TouchEventArgs e)
523 if (e != null && e.Touch.GetState(0) == PointStateType.Up)
531 private void UpdateIcons()
533 if (BorderWindow != null && borderView != null)
535 if (BorderWindow.IsMaximized() == true)
537 if (maximalizeIcon != null)
539 maximalizeIcon.ResourceUrl = DarkPreviousIcon;
541 if (minimalizeIcon != null)
543 minimalizeIcon.ResourceUrl = DarkMinimalizeIcon;
545 if (closeIcon != null)
547 closeIcon.ResourceUrl = DarkCloseIcon;
549 if (leftCornerIcon != null)
551 leftCornerIcon.ResourceUrl = DarkLeftCornerIcon;
553 if (rightCornerIcon != null)
555 rightCornerIcon.ResourceUrl = DarkRightCornerIcon;
557 borderView.CornerRadius = new Vector4(0, 0, 0, 0);
558 borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
559 BorderWindow.SetTransparency(false);
563 if (maximalizeIcon != null)
565 maximalizeIcon.ResourceUrl = MaximalizeIcon;
567 if (minimalizeIcon != null)
569 minimalizeIcon.ResourceUrl = MinimalizeIcon;
571 if (closeIcon != null)
573 closeIcon.ResourceUrl = CloseIcon;
575 if (leftCornerIcon != null)
577 leftCornerIcon.ResourceUrl = LeftCornerIcon;
579 if (rightCornerIcon != null)
581 rightCornerIcon.ResourceUrl = RightCornerIcon;
583 borderView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f);
584 borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
585 BorderWindow.SetTransparency(true);
592 /// Called after the border UI is created.
594 /// <param name="borderView">The border view on which the border.</param>
595 [EditorBrowsable(EditorBrowsableState.Never)]
596 public virtual void OnCreated(View borderView)
598 if (borderView == null)
602 this.borderView = borderView;
603 // Register to resize and move through pan gestures.
604 borderPanGestureDetector = new PanGestureDetector();
605 borderPanGestureDetector.Attach(borderView);
606 borderPanGestureDetector.Detected += OnPanGestureDetected;
608 // Register touch event for effect when border is touched.
609 borderView.LeaveRequired = true;
610 borderView.TouchEvent += (s, e) =>
612 if (e.Touch.GetState(0) == PointStateType.Started)
614 if (BorderWindow.IsMaximized() == false)
616 BorderWindow.Raise();
618 backgroundColor = new Color(borderView.BackgroundColor);
619 borderView.BackgroundColor = DefaultClickedBackgroundColor;
621 else if (e.Touch.GetState(0) == PointStateType.Finished ||
622 e.Touch.GetState(0) == PointStateType.Leave ||
623 e.Touch.GetState(0) == PointStateType.Interrupted)
625 borderView.BackgroundColor = backgroundColor;
630 borderPinchGestureDetector = new PinchGestureDetector();
631 borderPinchGestureDetector.Attach(borderView);
632 borderPinchGestureDetector.Detected += OnPinchGestureDetected;
634 AddInterceptGesture();
640 // Register an intercept touch event on the window.
641 private void AddInterceptGesture()
643 isWinGestures = false;
644 BorderWindow.InterceptTouchEvent += OnWinInterceptedTouch;
647 // Intercept touch on window.
648 private bool OnWinInterceptedTouch(object sender, Window.TouchEventArgs e)
650 if (e.Touch.GetState(0) == PointStateType.Stationary && e.Touch.GetPointCount() == 2)
652 if (isWinGestures == false && timer == null)
654 timer = new Timer(300);
655 timer.Tick += OnTick;
661 currentGesture = CurrentGesture.None;
672 // If two finger long press is done, create a windowView.
673 // then, Register a gesture on the windowView to do a resize or move.
674 private bool OnTick(object o, Timer.TickEventArgs e)
676 windowView = new View()
678 WidthResizePolicy = ResizePolicyType.FillToParent,
679 HeightResizePolicy = ResizePolicyType.FillToParent,
680 BackgroundColor = new Color(1, 1, 1, 0.5f),
682 windowView.TouchEvent += (s, e) =>
686 BorderWindow.Add(windowView);
688 winTapGestureDetector = new TapGestureDetector();
689 winTapGestureDetector.Attach(windowView);
690 winTapGestureDetector.SetMaximumTapsRequired(3);
691 winTapGestureDetector.Detected += OnWinTapGestureDetected;
693 winPanGestureDetector = new PanGestureDetector();
694 winPanGestureDetector.Attach(windowView);
695 winPanGestureDetector.Detected += OnWinPanGestureDetected;
697 BorderWindow.InterceptTouchEvent -= OnWinInterceptedTouch;
698 isWinGestures = true;
702 // Behavior when the window is tapped.
703 private void OnWinTapGestureDetected(object source, TapGestureDetector.DetectedEventArgs e)
705 if (currentGesture <= CurrentGesture.TapGesture)
707 currentGesture = CurrentGesture.TapGesture;
708 if (e.TapGesture.NumberOfTaps == 2)
710 if (BorderWindow.IsMaximized() == false)
712 BorderWindow.Maximize(true);
717 BorderWindow.Maximize(false);
723 ClearWindowGesture();
728 // Window moves through pan gestures.
729 private void OnWinPanGestureDetected(object source, PanGestureDetector.DetectedEventArgs e)
731 if (currentGesture <= CurrentGesture.PanGesture /*&& panGesture.NumberOfTouches == 1*/)
733 PanGesture panGesture = e.PanGesture;
735 if (panGesture.State == Gesture.StateType.Started)
737 currentGesture = CurrentGesture.PanGesture;
738 if (BorderWindow.IsMaximized() == true)
740 BorderWindow.Maximize(false);
745 BorderWindow.RequestMoveToServer();
748 else if (panGesture.State == Gesture.StateType.Finished || panGesture.State == Gesture.StateType.Cancelled)
750 currentGesture = CurrentGesture.None;
751 ClearWindowGesture();
756 private void ClearWindowGesture()
760 winPanGestureDetector.Dispose();
761 winTapGestureDetector.Dispose();
763 isWinGestures = false;
764 BorderWindow.Remove(windowView);
765 BorderWindow.InterceptTouchEvent += OnWinInterceptedTouch;
770 /// Called when requesting a resize
772 [EditorBrowsable(EditorBrowsableState.Never)]
773 public virtual void OnRequestResize() {}
776 /// Called when the window is resized.
778 /// <param name="width">The width of the resized window</param>
779 /// <param name="height">The height of the resized window</param>
780 [EditorBrowsable(EditorBrowsableState.Never)]
781 public virtual void OnResized(int width, int height)
783 if (overlayTimer != null)
786 overlayTimer.Dispose();
788 BorderWindow?.GetBorderWindowBottomLayer().LowerToBottom();
795 /// Called when the window is maximized.
797 /// <param name="isMaximized">If window is maximized or unmaximized.</param>
798 [EditorBrowsable(EditorBrowsableState.Never)]
799 public virtual void OnMaximize(bool isMaximized)
805 /// Called when the window is minimized.
807 /// <param name="isMinimized">If window is mnimized or unminimized.</param>
808 [EditorBrowsable(EditorBrowsableState.Never)]
809 public virtual void OnMinimize(bool isMinimized)
815 /// Show the border when OverlayMode is true and the window is now Maximize.
817 /// <param name="time">Time(ms) for borders to disappear again</param>
818 /// <returns>True if border became show, false otherwise</returns>
819 [EditorBrowsable(EditorBrowsableState.Never)]
820 public virtual bool OverlayBorderShow(uint time = 3000)
822 if (BorderWindow != null && BorderWindow.IsMaximized())
824 if (overlayTimer == null)
826 overlayTimer = new Timer(time);
827 overlayTimer.Tick += (s, e) =>
829 BorderWindow.GetBorderWindowBottomLayer().LowerToBottom();
831 overlayTimer?.Stop();
832 overlayTimer?.Dispose();
836 overlayTimer.Start();
837 BorderWindow.GetBorderWindowBottomLayer().RaiseToTop();
842 overlayTimer.Start();
850 /// Hide the border when OverlayMode is true and the window is now Maximize.
852 /// <returns>True if border became hide, false otherwise</returns>
853 [EditorBrowsable(EditorBrowsableState.Never)]
854 public virtual bool OverlayBorderHide()
856 if (BorderWindow != null && BorderWindow.IsMaximized())
864 [EditorBrowsable(EditorBrowsableState.Never)]
865 protected virtual void Dispose(bool disposing)
873 ClearWindowGesture();
875 if (BorderWindow != null)
877 BorderWindow.InterceptTouchEvent -= OnWinInterceptedTouch;
880 borderView?.Dispose();
881 windowView?.Dispose();
882 borderPanGestureDetector?.Dispose();
883 borderPinchGestureDetector?.Dispose();
884 backgroundColor?.Dispose();
885 minimalizeIcon?.Dispose();
886 maximalizeIcon?.Dispose();
887 closeIcon?.Dispose();
888 leftCornerIcon?.Dispose();
889 rightCornerIcon?.Dispose();
891 overlayTimer?.Dispose();
899 [EditorBrowsable(EditorBrowsableState.Never)]
900 public void Dispose()
903 global::System.GC.SuppressFinalize(this);