From 52684652fb66f4835a229b08f1f945244da3c46e Mon Sep 17 00:00:00 2001 From: "joogab.yun" Date: Tue, 10 May 2022 10:40:05 +0900 Subject: [PATCH] [NUI] Allows you to set the border to the top or bottom. If you return true after overriding CreateTopBorderView(), the border UI is displayed at the top. If you return true after overriding CreateBottomBorderView(), the border UI is displayed at the bottom. ```c# public override bool CreateTopBorderView(View topView) { // Decorate the top view return true; } public override bool CreateBottomBorderView(View bottomView) { // Decorate the bottom view return true; } ``` --- .../src/public/Application/NUIApplication.cs | 1 + src/Tizen.NUI/src/public/Window/BorderWindow.cs | 191 ++++++++----- src/Tizen.NUI/src/public/Window/DefaultBorder.cs | 213 +++++++++------ .../src/public/Window/IBorderInterface.cs | 22 +- .../Tizen.NUI.Samples/Samples/AllAppsSample.cs | 54 ---- .../Tizen.NUI.Samples/Samples/BorderWindowTest.cs | 297 ++++++++++++++------- .../Tizen.NUI.Samples/res/images/close.png | Bin 0 -> 216 bytes .../Tizen.NUI.Samples/res/images/leftCorner.png | Bin 0 -> 446 bytes .../Tizen.NUI.Samples/res/images/maximalize.png | Bin 0 -> 211 bytes .../Tizen.NUI.Samples/res/images/minimalize.png | Bin 0 -> 148 bytes .../Tizen.NUI.Samples/res/images/rightCorner.png | Bin 0 -> 434 bytes .../Tizen.NUI.Samples/res/images/smallwindow.png | Bin 0 -> 258 bytes 12 files changed, 462 insertions(+), 316 deletions(-) create mode 100644 test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/close.png create mode 100644 test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/leftCorner.png create mode 100644 test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/maximalize.png create mode 100644 test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/minimalize.png create mode 100644 test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/rightCorner.png create mode 100644 test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/smallwindow.png diff --git a/src/Tizen.NUI/src/public/Application/NUIApplication.cs b/src/Tizen.NUI/src/public/Application/NUIApplication.cs index 33c7898..17e0d3d 100755 --- a/src/Tizen.NUI/src/public/Application/NUIApplication.cs +++ b/src/Tizen.NUI/src/public/Application/NUIApplication.cs @@ -479,6 +479,7 @@ namespace Tizen.NUI if (borderEnabled) { GetDefaultWindow().EnableBorder(borderInterface); + GetDefaultWindow().EnableFloatingMode(false); } } diff --git a/src/Tizen.NUI/src/public/Window/BorderWindow.cs b/src/Tizen.NUI/src/public/Window/BorderWindow.cs index dd804d8..d78f91f 100755 --- a/src/Tizen.NUI/src/public/Window/BorderWindow.cs +++ b/src/Tizen.NUI/src/public/Window/BorderWindow.cs @@ -41,6 +41,13 @@ namespace Tizen.NUI // for border area private View rootView = null; + private View borderView = null; + private View topView = null; + private View contentsView = null; + private View bottomView = null; + private bool isTop = false; + private bool isBottom = false; + uint borderHeight = 0; #endregion //Fields #region Constructors @@ -114,42 +121,41 @@ namespace Tizen.NUI GetDefaultLayer().Name = "OriginalRootLayer"; - Resized += OnBorderWindowResized; - - isBorderWindow = true; - - // The current window is as below - // ***** - // ***** - // Increase the window size as much as the border area. - // +++++++ - // +*****+ - // +*****+ - // +=====+ - // +=====+ - // '+' is BorderLineThickness - // '=' is BorderHeight - WindowSize += new Size2D((int)borderInterface.BorderLineThickness * 2, (int)(borderInterface.BorderHeight + borderInterface.BorderLineThickness)); - - if (CreateBorder() == false) - { - WindowSize -= new Size2D((int)borderInterface.BorderLineThickness * 2, (int)(borderInterface.BorderHeight + borderInterface.BorderLineThickness)); - Resized -= OnBorderWindowResized; - isBorderWindow = false; - this.borderInterface = null; - return false; - } + if (CreateBorder() == true) + { + isBorderWindow = true; + Resized += OnBorderWindowResized; - SetTransparency(true); - BackgroundColor = Color.Transparent; - borderInterface.BorderWindow = this; + // Increase the window size as much as the border area. + if (isTop) borderHeight += borderInterface.BorderHeight; + if (isBottom) borderHeight += borderInterface.BorderHeight; + WindowSize += new Size2D((int)borderInterface.BorderLineThickness * 2, (int)(borderHeight + borderInterface.BorderLineThickness * 2)); - EnableFloatingMode(true); + if (borderInterface.OverlayMode == true) + { + rootView.InterceptTouchEvent += OverlayInterceptTouch; + } - borderInterface.OnCreated(rootView); + // Add a view to the border layer. + GetBorderWindowBottomLayer().Add(rootView); + + SetTransparency(true); + BackgroundColor = Color.Transparent; + borderInterface.BorderWindow = this; + + EnableFloatingMode(true); + + borderInterface.OnCreated(borderView); - return true; + + return true; + } + else + { + this.borderInterface.Dispose(); + return false; + } } /// Create the border UI. @@ -162,23 +168,55 @@ namespace Tizen.NUI BackgroundColor = Color.Transparent, }; - // Gets the Border's UI. - borderInterface.CreateBorderView(rootView); - if (rootView == null) + ushort padding = (ushort) borderInterface.BorderLineThickness; + borderView = new View() { - return false; - } - else + WidthResizePolicy = ResizePolicyType.FillToParent, + HeightResizePolicy = ResizePolicyType.FillToParent, + BackgroundColor = Color.Transparent, + Layout = new LinearLayout() { + LinearOrientation = LinearLayout.Orientation.Vertical, + LinearAlignment = LinearLayout.Alignment.Top + }, + Padding = new Extents(padding, padding, padding, padding), + }; + borderInterface.CreateBorderView(borderView); + + topView = new View() { - if (borderInterface.OverlayMode == true) - { - rootView.InterceptTouchEvent += OverlayInterceptTouch; - } - // Add a view to the border layer. - GetBorderWindowBottomLayer().Add(rootView); + WidthSpecification = LayoutParamPolicies.MatchParent, + SizeHeight = borderInterface.BorderHeight, + BackgroundColor = Color.Transparent, + }; - return true; + contentsView = new View() + { + BackgroundColor = Color.Transparent, + WidthSpecification = LayoutParamPolicies.MatchParent, + }; + + bottomView = new View() + { + WidthSpecification = LayoutParamPolicies.MatchParent, + SizeHeight = borderInterface.BorderHeight, + BackgroundColor = Color.Transparent, + }; + + // // Gets the Border's UI. + if (borderInterface.CreateTopBorderView(topView) == true && topView != null) + { + borderView.Add(topView); + isTop = true; + } + borderView.Add(contentsView); + if (borderInterface.CreateBottomBorderView(bottomView) == true && bottomView != null) + { + borderView.Add(bottomView); + isBottom = true; } + rootView.Add(borderView); + + return isTop || isBottom; } /// @@ -193,12 +231,12 @@ namespace Tizen.NUI BorderDirection direction = BorderDirection.None; // check bottom left corner - if (xPosition < borderInterface.TouchThickness && yPosition > WindowSize.Height + borderInterface.BorderHeight - borderInterface.TouchThickness) + if (xPosition < borderInterface.TouchThickness && yPosition > WindowSize.Height + borderHeight - borderInterface.TouchThickness) { direction = BorderDirection.BottomLeft; } // check bottom right corner - else if (xPosition > WindowSize.Width + borderInterface.BorderLineThickness * 2 - borderInterface.TouchThickness && yPosition > WindowSize.Height + borderInterface.BorderHeight - borderInterface.TouchThickness) + else if (xPosition > WindowSize.Width + borderInterface.BorderLineThickness * 2 - borderInterface.TouchThickness && yPosition > WindowSize.Height + borderHeight - borderInterface.TouchThickness) { direction = BorderDirection.BottomRight; } @@ -223,7 +261,7 @@ namespace Tizen.NUI direction = BorderDirection.Right; } // check bottom side - else if (yPosition > WindowSize.Height + borderInterface.BorderHeight + borderInterface.BorderLineThickness - borderInterface.TouchThickness) + else if (yPosition > WindowSize.Height + borderHeight + borderInterface.BorderLineThickness - borderInterface.TouchThickness) { direction = BorderDirection.Bottom; } @@ -233,7 +271,7 @@ namespace Tizen.NUI direction = BorderDirection.Top; } // check move - else if (yPosition > WindowSize.Height) + else if ((yPosition > WindowSize.Height) || (isTop == true && yPosition < borderInterface.BorderHeight)) { direction = BorderDirection.Move; } @@ -254,9 +292,9 @@ namespace Tizen.NUI private bool OnTick(object o, Timer.TickEventArgs e) { GetBorderWindowBottomLayer().LowerToBottom(); - if (rootView != null) + if (borderView != null) { - rootView.Hide(); + borderView.Hide(); } isInterceptTouch = false; @@ -277,9 +315,9 @@ namespace Tizen.NUI overlayTimer.Tick += OnTick; overlayTimer.Start(); GetBorderWindowBottomLayer().RaiseToTop(); - if (rootView != null) + if (borderView != null) { - rootView.Show(); + borderView.Show(); } isInterceptTouch = true; } @@ -294,11 +332,11 @@ namespace Tizen.NUI if (enable == true) { InterceptTouchEvent += OnWinInterceptTouch; - if (rootView != null) + if (borderView != null) { - overlayBackgroundColor = new Color(rootView.BackgroundColor); - rootView.BackgroundColor = new Color(1, 1, 1, 0.3f); - rootView.Hide(); + overlayBackgroundColor = new Color(borderView.BackgroundColor); + borderView.BackgroundColor = Color.Transparent; + borderView.Hide(); } } else @@ -312,10 +350,10 @@ namespace Tizen.NUI isInterceptTouch = false; InterceptTouchEvent -= OnWinInterceptTouch; GetBorderWindowBottomLayer().LowerToBottom(); - if (rootView != null) + if (borderView != null) { - rootView.BackgroundColor = overlayBackgroundColor; - rootView.Show(); + borderView.BackgroundColor = overlayBackgroundColor; + borderView.Show(); } } } @@ -345,21 +383,32 @@ namespace Tizen.NUI WindowSize = new Size2D(resizeWidth, resizeHeight); } + borderInterface.OnResized(resizeWidth, resizeHeight); + if (borderInterface.OverlayMode == true && IsMaximized() == true) { Interop.ActorInternal.SetSize(GetBorderWindowRootLayer().SwigCPtr, resizeWidth, resizeHeight); Interop.ActorInternal.SetSize(GetBorderWindowBottomLayer().SwigCPtr, resizeWidth, resizeHeight); + Interop.ActorInternal.SetPosition(GetBorderWindowRootLayer().SwigCPtr, 0, 0); + if (contentsView != null) + { + contentsView.SizeHeight = resizeHeight - borderHeight - borderInterface.BorderLineThickness * 2; + } OverlayMode(true); } else { + uint height = (isTop == true) ? borderInterface.BorderHeight : 0; Interop.ActorInternal.SetSize(GetBorderWindowRootLayer().SwigCPtr, resizeWidth, resizeHeight); - Interop.ActorInternal.SetSize(GetBorderWindowBottomLayer().SwigCPtr, resizeWidth + borderInterface.BorderLineThickness * 2, resizeHeight+borderInterface.BorderHeight + borderInterface.BorderLineThickness); + Interop.ActorInternal.SetSize(GetBorderWindowBottomLayer().SwigCPtr, resizeWidth + borderInterface.BorderLineThickness * 2, resizeHeight + borderHeight + borderInterface.BorderLineThickness * 2); + Interop.ActorInternal.SetPosition(GetBorderWindowRootLayer().SwigCPtr, 0, height + borderInterface.BorderLineThickness); + if (contentsView != null) + { + contentsView.SizeHeight = resizeHeight; + } OverlayMode(false); } - borderInterface.OnResized(resizeWidth, resizeHeight); - if (NDalicPINVOKE.SWIGPendingException.Pending) { throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } } @@ -373,7 +422,7 @@ namespace Tizen.NUI Interop.ActorInternal.SetParentOrigin(borderWindowBottomLayer.SwigCPtr, topCentor.SwigCPtr); Interop.Actor.SetAnchorPoint(borderWindowBottomLayer.SwigCPtr, topCentor.SwigCPtr); Interop.Actor.Add(rootLayer.SwigCPtr, borderWindowBottomLayer.SwigCPtr); - Interop.ActorInternal.SetSize(borderWindowBottomLayer.SwigCPtr, WindowSize.Width+borderInterface.BorderLineThickness * 2, WindowSize.Height + borderInterface.BorderLineThickness); + Interop.ActorInternal.SetSize(borderWindowBottomLayer.SwigCPtr, WindowSize.Width + borderInterface.BorderLineThickness * 2, WindowSize.Height + borderInterface.BorderLineThickness * 2); borderWindowBottomLayer.SetWindow(this); borderWindowBottomLayer.LowerToBottom(); @@ -392,9 +441,11 @@ namespace Tizen.NUI Interop.ActorInternal.SetParentOrigin(borderWindowRootLayer.SwigCPtr, topCentor.SwigCPtr); Interop.Actor.SetAnchorPoint(borderWindowRootLayer.SwigCPtr, topCentor.SwigCPtr); Interop.Actor.Add(rootLayer.SwigCPtr, borderWindowRootLayer.SwigCPtr); - Interop.ActorInternal.SetSize(borderWindowRootLayer.SwigCPtr, WindowSize.Width, WindowSize.Height-borderInterface.BorderHeight - borderInterface.BorderLineThickness); - Interop.ActorInternal.SetPosition(borderWindowRootLayer.SwigCPtr, 0, borderInterface.BorderLineThickness); - Tizen.NUI.Object.SetProperty(borderWindowRootLayer.SwigCPtr, Tizen.NUI.BaseComponents.View.Property.ClippingMode, new Tizen.NUI.PropertyValue((int)Tizen.NUI.ClippingModeType.ClipToBoundingBox)); + Interop.ActorInternal.SetSize(borderWindowRootLayer.SwigCPtr, WindowSize.Width, WindowSize.Height - borderHeight - borderInterface.BorderLineThickness * 2); + uint height = (isTop == true) ? borderInterface.BorderHeight : 0; + Interop.ActorInternal.SetPosition(borderWindowRootLayer.SwigCPtr, 0, height + borderInterface.BorderLineThickness); + using PropertyValue propertyValue = new Tizen.NUI.PropertyValue((int)Tizen.NUI.ClippingModeType.ClipToBoundingBox); + Tizen.NUI.Object.SetProperty(borderWindowRootLayer.SwigCPtr, Tizen.NUI.BaseComponents.View.Property.ClippingMode, propertyValue); if (NDalicPINVOKE.SWIGPendingException.Pending) { throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } } @@ -405,9 +456,9 @@ namespace Tizen.NUI internal void DisposeBorder() { Resized -= OnBorderWindowResized; - if (borderInterface.OverlayMode == true && rootView != null) + if (borderInterface.OverlayMode == true) { - rootView.InterceptTouchEvent -= OverlayInterceptTouch; + OverlayMode(false); } borderInterface.Dispose(); GetBorderWindowBottomLayer().Dispose(); @@ -417,7 +468,7 @@ namespace Tizen.NUI { if (isBorderWindow == true) { - var height = (ushort)(size.GetHeight() + borderInterface.BorderHeight + borderInterface.BorderLineThickness); + var height = (ushort)(size.GetHeight() + borderHeight + borderInterface.BorderLineThickness * 2); var width = (ushort)(size.GetWidth() + borderInterface.BorderLineThickness * 2); size.SetHeight(height); size.SetWidth(width); @@ -428,7 +479,7 @@ namespace Tizen.NUI { if (isBorderWindow == true && !(borderInterface.OverlayMode == true && IsMaximized() == true)) { - var height = (ushort)(size.GetHeight() - borderInterface.BorderHeight - borderInterface.BorderLineThickness); + var height = (ushort)(size.GetHeight() - borderHeight - borderInterface.BorderLineThickness * 2); var width = (ushort)(size.GetWidth() - borderInterface.BorderLineThickness * 2); size.SetHeight(height); size.SetWidth(width); diff --git a/src/Tizen.NUI/src/public/Window/DefaultBorder.cs b/src/Tizen.NUI/src/public/Window/DefaultBorder.cs index fa26f81..cfa2b7c 100755 --- a/src/Tizen.NUI/src/public/Window/DefaultBorder.cs +++ b/src/Tizen.NUI/src/public/Window/DefaultBorder.cs @@ -53,7 +53,6 @@ namespace Tizen.NUI #region Fields private Color backgroundColor; - private View rootView; private View borderView; private ImageView minimalizeIcon; @@ -137,6 +136,10 @@ namespace Tizen.NUI [EditorBrowsable(EditorBrowsableState.Never)] public bool OverlayMode {get; set;} + + /// + /// Creates a default border + /// [EditorBrowsable(EditorBrowsableState.Never)] public DefaultBorder() { @@ -147,85 +150,97 @@ namespace Tizen.NUI OverlayMode = false; } + /// + /// Create top border UI. User can override this method to draw top border UI. + /// + /// The top view on which the border. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual bool CreateTopBorderView(View topView) + { + return false; + } /// - /// Create border UI. Users can override this method to draw border UI. + /// Create bottom border UI. User can override this method to draw bottom border UI. /// + /// The bottom view on which the border. [EditorBrowsable(EditorBrowsableState.Never)] - public virtual void CreateBorderView(View rootView) + public virtual bool CreateBottomBorderView(View bottomView) { - if (rootView == null) + if (bottomView == null) { - return; + return false; } - this.rootView = rootView; - rootView.BackgroundColor = DefaultBackgroundColor; - rootView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f); - rootView.CornerRadiusPolicy = VisualTransformPolicyType.Relative; - - borderView = new View() - { - Layout = new LinearLayout() - { - LinearAlignment = LinearLayout.Alignment.End, - LinearOrientation = LinearLayout.Orientation.Horizontal, - }, - WidthSpecification = LayoutParamPolicies.MatchParent, - HeightSpecification = LayoutParamPolicies.MatchParent, - }; + bottomView.Layout = new RelativeLayout(); minimalizeIcon = new ImageView() { ResourceUrl = MinimalizeIcon, - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, }; maximalizeIcon = new ImageView() { ResourceUrl = MaximalizeIcon, - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, }; closeIcon = new ImageView() { ResourceUrl = CloseIcon, - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, }; leftCornerIcon = new ImageView() { ResourceUrl = LeftCornerIcon, - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, }; rightCornerIcon = new ImageView() { ResourceUrl = RightCornerIcon, - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, }; - rootView.Add(leftCornerIcon); - borderView.Add(minimalizeIcon); - borderView.Add(maximalizeIcon); - borderView.Add(closeIcon); - borderView.Add(rightCornerIcon); - rootView.Add(borderView); + RelativeLayout.SetRightTarget(minimalizeIcon, maximalizeIcon); + RelativeLayout.SetRightRelativeOffset(minimalizeIcon, 0.0f); + RelativeLayout.SetHorizontalAlignment(minimalizeIcon, RelativeLayout.Alignment.End); + RelativeLayout.SetRightTarget(maximalizeIcon, closeIcon); + RelativeLayout.SetRightRelativeOffset(maximalizeIcon, 0.0f); + RelativeLayout.SetHorizontalAlignment(maximalizeIcon, RelativeLayout.Alignment.End); + RelativeLayout.SetRightTarget(closeIcon, rightCornerIcon); + RelativeLayout.SetRightRelativeOffset(closeIcon, 0.0f); + RelativeLayout.SetHorizontalAlignment(closeIcon, RelativeLayout.Alignment.End); + RelativeLayout.SetRightRelativeOffset(rightCornerIcon, 1.0f); + RelativeLayout.SetHorizontalAlignment(rightCornerIcon, RelativeLayout.Alignment.End); + bottomView.Add(leftCornerIcon); + bottomView.Add(minimalizeIcon); + bottomView.Add(maximalizeIcon); + bottomView.Add(closeIcon); + bottomView.Add(rightCornerIcon); + minimalizeIcon.TouchEvent += OnMinimizeIconTouched; maximalizeIcon.TouchEvent += OnMaximizeIconTouched; closeIcon.TouchEvent += OnCloseIconTouched; - leftCornerIcon.TouchEvent += OnLeftCornerIconTouched; - rightCornerIcon.TouchEvent += OnRightCornerIconTouched; + leftCornerIcon.TouchEvent += OnLeftBottomCornerIconTouched; + rightCornerIcon.TouchEvent += OnRightBottomCornerIconTouched; + return true; + } + + + /// + /// Create border UI. User can override this method to draw border UI. + /// A top border and a bottom border are added to this view. + /// + /// The root view on which the border. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual void CreateBorderView(View borderView) + { + if (borderView == null) + { + return; + } + this.borderView = borderView; + borderView.BackgroundColor = DefaultBackgroundColor; + borderView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f); + borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative; } /// Determines the behavior of pinch gesture. @@ -271,6 +286,7 @@ namespace Tizen.NUI if (panGesture.State == Gesture.StateType.Started && panGesture.Position != null) { direction = BorderWindow.GetDirection(panGesture.Position.X, panGesture.Position.Y); + if (direction == Window.BorderDirection.Move) { if (BorderWindow.IsMaximized() == true) @@ -288,25 +304,6 @@ namespace Tizen.NUI BorderWindow.RequestResizeToServer((Window.ResizeDirection)direction); } } - else if (panGesture.State == Gesture.StateType.Continuing) - { - if (direction == Window.BorderDirection.BottomLeft || direction == Window.BorderDirection.BottomRight || direction == Window.BorderDirection.TopLeft || direction == Window.BorderDirection.TopRight) - { - BorderWindow.WindowSize += new Size2D((int)panGesture.ScreenDisplacement.X, (int)panGesture.ScreenDisplacement.Y); - } - else if (direction == Window.BorderDirection.Left || direction == Window.BorderDirection.Right) - { - BorderWindow.WindowSize += new Size2D((int)panGesture.ScreenDisplacement.X, 0); - } - else if (direction == Window.BorderDirection.Bottom || direction == Window.BorderDirection.Top) - { - BorderWindow.WindowSize += new Size2D(0, (int)panGesture.ScreenDisplacement.Y); - } - else if (direction == Window.BorderDirection.Move) - { - BorderWindow.WindowPosition += new Position2D((int)panGesture.ScreenDisplacement.X, (int)panGesture.ScreenDisplacement.Y); - } - } else if (panGesture.State == Gesture.StateType.Finished || panGesture.State == Gesture.StateType.Cancelled) { direction = Window.BorderDirection.None; @@ -314,12 +311,50 @@ namespace Tizen.NUI } } + /// + /// This is an event callback when the left top corner icon is touched. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual bool OnLeftTopCornerIconTouched(object sender, View.TouchEventArgs e) + { + if (e == null) + { + return false; + } + if (e.Touch.GetState(0) == PointStateType.Down) + { + ClearWindowGesture(); + OnRequestResize(); + BorderWindow.RequestResizeToServer(Window.ResizeDirection.TopLeft); + } + return true; + } /// - /// This is an event callback when the left corner icon is touched. + ///This is an event callback when the right bottom corner icon is touched. /// [EditorBrowsable(EditorBrowsableState.Never)] - public virtual bool OnLeftCornerIconTouched(object sender, View.TouchEventArgs e) + public virtual bool OnRightTopCornerIconTouched(object sender, View.TouchEventArgs e) + { + if (e == null) + { + return false; + } + if (e.Touch.GetState(0) == PointStateType.Down) + { + ClearWindowGesture(); + OnRequestResize(); + BorderWindow.RequestResizeToServer(Window.ResizeDirection.TopRight); + } + return true; + } + + + /// + /// This is an event callback when the left bottom corner icon is touched. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual bool OnLeftBottomCornerIconTouched(object sender, View.TouchEventArgs e) { if (e == null) { @@ -335,10 +370,10 @@ namespace Tizen.NUI } /// - ///This is an event callback when the right corner icon is touched. + ///This is an event callback when the right bottom corner icon is touched. /// [EditorBrowsable(EditorBrowsableState.Never)] - public virtual bool OnRightCornerIconTouched(object sender, View.TouchEventArgs e) + public virtual bool OnRightBottomCornerIconTouched(object sender, View.TouchEventArgs e) { if (e == null) { @@ -355,7 +390,7 @@ namespace Tizen.NUI /// - /// This is an event callback when the minimize button is touched. + /// This is an event callback when the minimize icon is touched. /// [EditorBrowsable(EditorBrowsableState.Never)] public virtual bool OnMinimizeIconTouched(object sender, View.TouchEventArgs e) @@ -373,7 +408,7 @@ namespace Tizen.NUI } /// - /// This is an event callback when the maximum button is touched. + /// This is an event callback when the maximum icon is touched. /// [EditorBrowsable(EditorBrowsableState.Never)] public virtual bool OnMaximizeIconTouched(object sender, View.TouchEventArgs e) @@ -398,7 +433,7 @@ namespace Tizen.NUI } /// - /// This is an event callback when the close button is touched. + /// This is an event callback when the close icon is touched. /// [EditorBrowsable(EditorBrowsableState.Never)] public virtual bool OnCloseIconTouched(object sender, View.TouchEventArgs e) @@ -418,7 +453,7 @@ namespace Tizen.NUI private void UpdateIcons() { - if (BorderWindow != null && rootView != null) + if (BorderWindow != null && borderView != null) { if (BorderWindow.IsMaximized() == true) { @@ -442,8 +477,8 @@ namespace Tizen.NUI { rightCornerIcon.ResourceUrl = DarkRightCornerIcon; } - rootView.CornerRadius = new Vector4(0, 0, 0, 0); - rootView.CornerRadiusPolicy = VisualTransformPolicyType.Relative; + borderView.CornerRadius = new Vector4(0, 0, 0, 0); + borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative; BorderWindow.SetTransparency(false); } else @@ -468,8 +503,8 @@ namespace Tizen.NUI { rightCornerIcon.ResourceUrl = RightCornerIcon; } - rootView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f); - rootView.CornerRadiusPolicy = VisualTransformPolicyType.Relative; + borderView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f); + borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative; BorderWindow.SetTransparency(true); } } @@ -479,39 +514,39 @@ namespace Tizen.NUI /// /// Called after the border UI is created. /// - /// The root view on which the border. + /// The border view on which the border. [EditorBrowsable(EditorBrowsableState.Never)] - public virtual void OnCreated(View rootView) + public virtual void OnCreated(View borderView) { - if (rootView == null) + if (borderView == null) { return; } // Register to resize and move through pan gestures. borderPanGestureDetector = new PanGestureDetector(); - borderPanGestureDetector.Attach(rootView); + borderPanGestureDetector.Attach(borderView); borderPanGestureDetector.Detected += OnPanGestureDetected; // Register touch event for effect when border is touched. - rootView.LeaveRequired = true; - rootView.TouchEvent += (s, e) => + borderView.LeaveRequired = true; + borderView.TouchEvent += (s, e) => { if (e.Touch.GetState(0) == PointStateType.Started) { - backgroundColor = new Color(rootView.BackgroundColor); - rootView.BackgroundColor = DefaultClickedBackgroundColor; + backgroundColor = new Color(borderView.BackgroundColor); + borderView.BackgroundColor = DefaultClickedBackgroundColor; } else if (e.Touch.GetState(0) == PointStateType.Finished || e.Touch.GetState(0) == PointStateType.Leave || e.Touch.GetState(0) == PointStateType.Interrupted) { - rootView.BackgroundColor = backgroundColor; + borderView.BackgroundColor = backgroundColor; } return true; }; borderPinchGestureDetector = new PinchGestureDetector(); - borderPinchGestureDetector.Attach(rootView); + borderPinchGestureDetector.Attach(borderView); borderPinchGestureDetector.Detected += OnPinchGestureDetected; AddInterceptGesture(); @@ -648,9 +683,7 @@ namespace Tizen.NUI /// Called when requesting a resize /// [EditorBrowsable(EditorBrowsableState.Never)] - public virtual void OnRequestResize() - { - } + public virtual void OnRequestResize() {} /// /// Called when the window is resized. @@ -674,7 +707,10 @@ namespace Tizen.NUI { ClearWindowGesture(); - BorderWindow.InterceptTouchEvent -= OnWinInterceptedTouch; + if (BorderWindow != null) + { + BorderWindow.InterceptTouchEvent -= OnWinInterceptedTouch; + } borderPanGestureDetector?.Dispose(); borderPinchGestureDetector?.Dispose(); @@ -687,7 +723,6 @@ namespace Tizen.NUI timer?.Dispose(); windowView?.Dispose(); borderView?.Dispose(); - rootView?.Dispose(); } disposed = true; } diff --git a/src/Tizen.NUI/src/public/Window/IBorderInterface.cs b/src/Tizen.NUI/src/public/Window/IBorderInterface.cs index 7abc23a..81bf50e 100755 --- a/src/Tizen.NUI/src/public/Window/IBorderInterface.cs +++ b/src/Tizen.NUI/src/public/Window/IBorderInterface.cs @@ -72,20 +72,34 @@ namespace Tizen.NUI [EditorBrowsable(EditorBrowsableState.Never)] public bool OverlayMode {get;} + /// + /// Create top border UI. User can override this method to draw top border UI. + /// + /// The top view on which the border. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool CreateTopBorderView(View topView); + + /// + /// Create bottom border UI. User can override this method to draw bottom border UI. + /// + /// The bottom view on which the border. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool CreateBottomBorderView(View bottomView); /// /// Create border UI. User can override this method to draw border UI. + /// A top border and a bottom border are added to this view. /// - /// The root view on which the border. + /// The border view on which the border. [EditorBrowsable(EditorBrowsableState.Never)] - public void CreateBorderView(View rootView); + public void CreateBorderView(View borderView); /// /// Called after the border UI is created. /// - /// The root view on which the border. + /// The border view on which the border. [EditorBrowsable(EditorBrowsableState.Never)] - public void OnCreated(View rootView); + public void OnCreated(View borderView); /// /// Called when requesting a resize diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/AllAppsSample.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/AllAppsSample.cs index 953c437..5b3c841 100644 --- a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/AllAppsSample.cs +++ b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/AllAppsSample.cs @@ -22,60 +22,6 @@ namespace Tizen.NUI.Samples "hbo", "linkedin", "youtube" }; - class TestWindow : DefaultBorder - { - public override void CreateBorderView(View rootView) - { - rootView.BackgroundColor = Color.Red; - rootView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f); - rootView.CornerRadiusPolicy = VisualTransformPolicyType.Relative; - - - View borderView = new View() - { - Layout = new LinearLayout() - { - LinearOrientation = LinearLayout.Orientation.Horizontal, - }, - WidthSpecification = LayoutParamPolicies.MatchParent, - HeightSpecification = LayoutParamPolicies.MatchParent, - }; - - var minimalizeIcon = new Button() - { - Text = "min", - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, - }; - - var maximalizeIcon = new Button() - { - Text = "Max", - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, - }; - - var closeIcon = new Button() - { - Text = "Close", - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, - }; - - borderView.Add(minimalizeIcon); - borderView.Add(maximalizeIcon); - borderView.Add(closeIcon); - rootView.Add(borderView); - - minimalizeIcon.TouchEvent += OnMinimizeIconTouched; - maximalizeIcon.TouchEvent += OnMaximizeIconTouched; - closeIcon.TouchEvent += OnCloseIconTouched; - } - } - View CreateItem(string file, string name) { var itemView = new View() diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/BorderWindowTest.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/BorderWindowTest.cs index ef42430..2a98d62 100755 --- a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/BorderWindowTest.cs +++ b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/BorderWindowTest.cs @@ -18,122 +18,152 @@ namespace Tizen.NUI.Samples class CustomBorder : DefaultBorder { + private static readonly string ResourcePath = Tizen.Applications.Application.Current.DirectoryInfo.Resource; + private static readonly string MinimalizeIcon = ResourcePath + "/images/minimalize.png"; + private static readonly string MaximalizeIcon = ResourcePath + "/images/maximalize.png"; + private static readonly string RestoreIcon = ResourcePath + "/images/smallwindow.png"; + private static readonly string CloseIcon = ResourcePath + "/images/close.png"; + private static readonly string LeftCornerIcon = ResourcePath + "/images/leftCorner.png"; + private static readonly string RightCornerIcon = ResourcePath + "/images/rightCorner.png"; + private int width = 500; private bool hide = false; - private View rootView; private View borderView; private TextLabel title; + private ImageView minimalizeIcon; + private ImageView maximalizeIcon; + private ImageView closeIcon; + private ImageView leftCornerIcon; + private ImageView rightCornerIcon; + + private Rectangle preWinPositonSize; + public CustomBorder() : base() { - BorderHeight = 60; + BorderHeight = 50; + OverlayMode = true; + BorderLineThickness = 0; } - public override void CreateBorderView(View rootView) + public override bool CreateTopBorderView(View topView) { - this.rootView = rootView; - rootView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f); - rootView.CornerRadiusPolicy = VisualTransformPolicyType.Relative; + if (topView == null) + { + return false; + } + title = new TextLabel() + { + Text = "CustomBorder", + Position = new Position(20, 0), + }; + topView.Add(title); + return true; + } - borderView = new View() - { - Layout = new LinearLayout() - { - LinearAlignment = LinearLayout.Alignment.End, - LinearOrientation = LinearLayout.Orientation.Horizontal, - }, - WidthSpecification = LayoutParamPolicies.MatchParent, - HeightSpecification = LayoutParamPolicies.MatchParent, - }; - title = new TextLabel() - { - Text = "CustomBorder", - Size = new Size(300, 50), - Position = new Position(60, 0), - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, - }; - - var minimalizeIcon = new Button() - { - Text = "m", - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, - Size = new Size(50, 50), - }; - - var maximalizeIcon = new Button() - { - Text = "M", - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, - Size = new Size(50, 50), - }; - - var closeIcon = new Button() - { - Text = "C", - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, - Size = new Size(50, 50), - }; + public override bool CreateBottomBorderView(View bottomView) + { + if (bottomView == null) + { + return false; + } + bottomView.Layout = new RelativeLayout(); + minimalizeIcon = new ImageView() + { + ResourceUrl = MinimalizeIcon, + }; - var leftPadding = new View() - { - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, - Size = new Size(50, 50), - }; + maximalizeIcon = new ImageView() + { + ResourceUrl = MaximalizeIcon, + }; - var rightPadding = new View() - { - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, - Size = new Size(50, 50), - }; - - rootView.Add(leftPadding); - rootView.Add(title); - borderView.Add(minimalizeIcon); - borderView.Add(maximalizeIcon); - borderView.Add(closeIcon); - borderView.Add(rightPadding); - rootView.Add(borderView); - - minimalizeIcon.TouchEvent += OnMinimizeIconTouched; - maximalizeIcon.TouchEvent += OnMaximizeIconTouched; - closeIcon.TouchEvent += OnCloseIconTouched; - leftPadding.TouchEvent += OnLeftCornerIconTouched; - rightPadding.TouchEvent += OnRightCornerIconTouched; + closeIcon = new ImageView() + { + ResourceUrl = CloseIcon, + }; + + leftCornerIcon = new ImageView() + { + ResourceUrl = LeftCornerIcon, + }; + + rightCornerIcon = new ImageView() + { + ResourceUrl = RightCornerIcon, + }; + + RelativeLayout.SetRightTarget(minimalizeIcon, maximalizeIcon); + RelativeLayout.SetRightRelativeOffset(minimalizeIcon, 0.0f); + RelativeLayout.SetHorizontalAlignment(minimalizeIcon, RelativeLayout.Alignment.End); + RelativeLayout.SetRightTarget(maximalizeIcon, closeIcon); + RelativeLayout.SetRightRelativeOffset(maximalizeIcon, 0.0f); + RelativeLayout.SetHorizontalAlignment(maximalizeIcon, RelativeLayout.Alignment.End); + RelativeLayout.SetRightTarget(closeIcon, rightCornerIcon); + RelativeLayout.SetRightRelativeOffset(closeIcon, 0.0f); + RelativeLayout.SetHorizontalAlignment(closeIcon, RelativeLayout.Alignment.End); + RelativeLayout.SetRightRelativeOffset(rightCornerIcon, 1.0f); + RelativeLayout.SetHorizontalAlignment(rightCornerIcon, RelativeLayout.Alignment.End); + bottomView.Add(leftCornerIcon); + bottomView.Add(minimalizeIcon); + bottomView.Add(maximalizeIcon); + bottomView.Add(closeIcon); + bottomView.Add(rightCornerIcon); + + + minimalizeIcon.TouchEvent += OnMinimizeIconTouched; + maximalizeIcon.TouchEvent += OnMaximizeIconTouched; + closeIcon.TouchEvent += OnCloseIconTouched; + leftCornerIcon.TouchEvent += OnLeftBottomCornerIconTouched; + rightCornerIcon.TouchEvent += OnRightBottomCornerIconTouched; + return true; + } + + public override void CreateBorderView(View borderView) + { + this.borderView = borderView; + borderView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f); + borderView.CornerRadiusPolicy = VisualTransformPolicyType.Relative; + borderView.BackgroundColor = new Color(1, 1, 1, 0.3f); } - public override void OnCreated(View rootView) + public override void OnCreated(View borderView) { - base.OnCreated(rootView); + base.OnCreated(borderView); } - public override bool OnCloseIconTouched(object sender, View.TouchEventArgs e) + public override bool OnCloseIconTouched(object sender, View.TouchEventArgs e) { base.OnCloseIconTouched(sender, e); return true; } - public override bool OnMinimizeIconTouched(object sender, View.TouchEventArgs e) + public override bool OnMinimizeIconTouched(object sender, View.TouchEventArgs e) { - base.OnMinimizeIconTouched(sender, e); + if (e.Touch.GetState(0) == PointStateType.Up) + { + if (BorderWindow.IsMaximized() == true) + { + BorderWindow.Maximize(false); + } + preWinPositonSize = BorderWindow.WindowPositionSize; + BorderWindow.WindowPositionSize = new Rectangle(preWinPositonSize.X, preWinPositonSize.Y, 500, 0); + } return true; } + public override void OnRequestResize() + { + if (borderView != null) + { + borderView.BackgroundColor = new Color(0, 1, 0, 0.3f); // 보더의 배경을 변경할 수 있습니다. + } + } + public override void OnResized(int width, int height) { - if (rootView != null) + if (borderView != null) { if (this.width > width && hide == false) { @@ -145,7 +175,30 @@ namespace Tizen.NUI.Samples title.Show(); hide = false; } + borderView.BackgroundColor = new Color(1, 1, 1, 0.3f); // 리사이즈가 끝나면 보더의 색깔은 원래대로 돌려놓습니다. base.OnResized(width, height); + UpdateIcons(); + } + } + + private void UpdateIcons() + { + if (BorderWindow != null && borderView != null) + { + if (BorderWindow.IsMaximized() == true) + { + if (maximalizeIcon != null) + { + maximalizeIcon.ResourceUrl = RestoreIcon; + } + } + else + { + if (maximalizeIcon != null) + { + maximalizeIcon.ResourceUrl = MaximalizeIcon; + } + } } } @@ -194,8 +247,6 @@ namespace Tizen.NUI.Samples IBorderInterface customBorder = new CustomBorder(); subWindowTwo = new Window("subwin1", customBorder, new Rectangle(60, 20, 800, 800), false); - subWindowTwo.BackgroundColor = Color.Red; - var root = new View(){ Layout = new LinearLayout() { @@ -203,7 +254,7 @@ namespace Tizen.NUI.Samples }, WidthResizePolicy = ResizePolicyType.FillToParent, HeightResizePolicy = ResizePolicyType.FillToParent, - BackgroundColor = Color.Yellow, + BackgroundColor = Color.Brown, }; var image = new ImageView() @@ -227,6 +278,7 @@ namespace Tizen.NUI.Samples void Initialize() { win = NUIApplication.GetDefaultWindow(); + var root = new ImageView() { WidthResizePolicy = ResizePolicyType.FillToParent, @@ -238,23 +290,56 @@ namespace Tizen.NUI.Samples LinearOrientation = LinearLayout.Orientation.Horizontal, CellPadding = new Size(10, 10), } - - }; win.Add(root); - var imageViewA = new ImageView() + + var appFunctionList = new View() { PositionUsesPivotPoint = true, PivotPoint = PivotPoint.BottomLeft, ParentOrigin = ParentOrigin.BottomLeft, + BackgroundColor = new Color(0, 1, 1, 0.5f), + Size = new Size(500, 200), + CornerRadius = 0.3f, + CornerRadiusPolicy = VisualTransformPolicyType.Relative, + Layout = new LinearLayout() + { + LinearAlignment = LinearLayout.Alignment.CenterHorizontal, + LinearOrientation = LinearLayout.Orientation.Horizontal, + CellPadding = new Size(10, 10), + Padding = new Extents(10, 10, 10 , 10), + } + }; + root.Add(appFunctionList); + + var defaultBorder = new View() + { + Size = new Size(150, 180), + Layout = new LinearLayout() + { + LinearAlignment = LinearLayout.Alignment.Center, + LinearOrientation = LinearLayout.Orientation.Vertical, + } + }; + + var imageViewA = new ImageView() + { Size = new Size(150, 150), ResourceUrl = imagePath + "gallery-large-9.jpg", CornerRadius = 0.3f, CornerRadiusPolicy = VisualTransformPolicyType.Relative, }; - root.Add(imageViewA); - imageViewA.TouchEvent += (s, e) => + + var textViewA = new TextLabel() + { + Text = "Default", + }; + + defaultBorder.Add(imageViewA); + defaultBorder.Add(textViewA); + appFunctionList.Add(defaultBorder); + defaultBorder.TouchEvent += (s, e) => { if (e.Touch.GetState(0) == PointStateType.Up) { @@ -263,18 +348,32 @@ namespace Tizen.NUI.Samples return true; }; + var customBorder = new View() + { + Size = new Size(150, 180), + Layout = new LinearLayout() + { + LinearAlignment = LinearLayout.Alignment.Center, + LinearOrientation = LinearLayout.Orientation.Vertical, + } + }; + var imageViewB = new ImageView() { - PositionUsesPivotPoint = true, - PivotPoint = PivotPoint.BottomLeft, - ParentOrigin = ParentOrigin.BottomLeft, Size = new Size(150, 150), ResourceUrl = imagePath + "gallery-large-5.jpg", CornerRadius = 0.3f, CornerRadiusPolicy = VisualTransformPolicyType.Relative, }; - root.Add(imageViewB); - imageViewB.TouchEvent += (s, e) => + var textViewB = new TextLabel() + { + Text = "Custom", + }; + + customBorder.Add(imageViewB); + customBorder.Add(textViewB); + appFunctionList.Add(customBorder); + customBorder.TouchEvent += (s, e) => { if (e.Touch.GetState(0) == PointStateType.Up) { diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/close.png b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/close.png new file mode 100644 index 0000000000000000000000000000000000000000..c49e4801e26ec86939f0c9e15df4e6364af7b77c GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC&H|6fVg?3oVGw3ym^DWND9BhG z1NoyM{&zO?V|D%r$IbVS3j3^P6Z8auqd7g$ zh($u-r5HgUcVV#7QvZ--y(#E}=_vWa9%gpIMJArj?L@N5ZQ+~P#9*#7h4@4r$rZkd zO?*enl#yc(Y!tbX&X0R6!g}#SlzJ4^&zK0i@uX$exr!$->E|K>(_5J7^w81PdrO!< zu*Z;?2&>x4rGa?t;#{lME5#JZ_z)QhXX8#SUM;4`7)e{`<|0hNNT<`Bv*J=v;Y7A literal 0 HcmV?d00001 diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/maximalize.png b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/maximalize.png new file mode 100644 index 0000000000000000000000000000000000000000..c5cbbaf0009a8fcbd914fb673c04c9cb79f60c32 GIT binary patch literal 211 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC&H|6fVg?3oVGw3ym^DWND9BhG z%&TLZ!Z<$^ISw#V$al20N!*ns$EbtG-FS7xy%;<=weer1#>K<$slFVdQ&MBb@0P^D|WdHyG literal 0 HcmV?d00001 diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/rightCorner.png b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/rightCorner.png new file mode 100644 index 0000000000000000000000000000000000000000..68d837f44bf20b6bc52aba7ab9f502794bc3de3d GIT binary patch literal 434 zcmV;j0ZsmiP)3}IgUPpjZ(Xg! z=WKH6GgUjn{2{6IxmerOZ<#j$>Zs|nO*Txj#5IL)OQiXBhKi+qcl)+aP2(o;Zr<5- ztgpzs(kY;(nInMxEi(@DW+BV}r`I;CGk@qT*wbpvquEZoi`%=flYxES-<2$Y?O(r{ z&FJq6rkP7~(lR3Q%=_-)