[NUI] Implements a BorderWindow
authorjoogab.yun <joogab.yun@samsung.com>
Mon, 11 Apr 2022 02:08:24 +0000 (11:08 +0900)
committerJaehyun Cho <jaehyun0cho@gmail.com>
Wed, 20 Apr 2022 08:38:08 +0000 (17:38 +0900)
1. Requirements :
 Like the desktop environment,
 - It should be possible to resize and move by adding a border area to the window.
 - By adding buttons to the border area, each button should have a minimize, maximize, and close function.
 - Border UI should be customizable.

2. interface IBorderInterface
 - User can configure border UI by inheriting IBorderInterface.

3. class DefautBorder is the default border UI.
 - User can also override the function by inheriting this DefaultBorder.

4. Sample
 - DefautBorder
```c#
  // If null is set for the second argument when creating a window, it is configured as DefaultBorder UI.
  subWindow = new Window("subwin", null, new Rectangle(20, 20, 800, 800), false);
```

 - CustomBorder
```c#
  class CustomBorder : DefaultBorder
  {
    public override voide CreateBorderView(View rootView)
    {
      // create custom border UI
      var custom = new View();
      rootView.Add(custom);
    }
  }

  void init()
  {
    CustomBorder border = new CustomBorder();
    var subWindow =  new Window("subwin", border, new Rectangle(60, 20, 800, 800), false);
  }
```

20 files changed:
src/Tizen.NUI/res/close.png [new file with mode: 0644]
src/Tizen.NUI/res/dark_close.png [new file with mode: 0644]
src/Tizen.NUI/res/dark_leftCorner.png [new file with mode: 0644]
src/Tizen.NUI/res/dark_maximalize.png [new file with mode: 0644]
src/Tizen.NUI/res/dark_minimalize.png [new file with mode: 0644]
src/Tizen.NUI/res/dark_rightCorner.png [new file with mode: 0644]
src/Tizen.NUI/res/dark_smallwindow.png [new file with mode: 0644]
src/Tizen.NUI/res/leftCorner.png [new file with mode: 0644]
src/Tizen.NUI/res/maximalize.png [new file with mode: 0644]
src/Tizen.NUI/res/minimalize.png [new file with mode: 0644]
src/Tizen.NUI/res/rightCorner.png [new file with mode: 0644]
src/Tizen.NUI/res/smallwindow.png [new file with mode: 0644]
src/Tizen.NUI/src/public/Application/NUIApplication.cs
src/Tizen.NUI/src/public/Common/Layer.cs
src/Tizen.NUI/src/public/Window/BorderWindow.cs [new file with mode: 0755]
src/Tizen.NUI/src/public/Window/DefaultBorder.cs [new file with mode: 0755]
src/Tizen.NUI/src/public/Window/IBorderInterface.cs [new file with mode: 0755]
src/Tizen.NUI/src/public/Window/Window.cs
src/Tizen.NUI/src/public/Window/WindowEvent.cs
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/BorderWindowTest.cs [new file with mode: 0755]

diff --git a/src/Tizen.NUI/res/close.png b/src/Tizen.NUI/res/close.png
new file mode 100644 (file)
index 0000000..c49e480
Binary files /dev/null and b/src/Tizen.NUI/res/close.png differ
diff --git a/src/Tizen.NUI/res/dark_close.png b/src/Tizen.NUI/res/dark_close.png
new file mode 100644 (file)
index 0000000..3868233
Binary files /dev/null and b/src/Tizen.NUI/res/dark_close.png differ
diff --git a/src/Tizen.NUI/res/dark_leftCorner.png b/src/Tizen.NUI/res/dark_leftCorner.png
new file mode 100644 (file)
index 0000000..283f0de
Binary files /dev/null and b/src/Tizen.NUI/res/dark_leftCorner.png differ
diff --git a/src/Tizen.NUI/res/dark_maximalize.png b/src/Tizen.NUI/res/dark_maximalize.png
new file mode 100644 (file)
index 0000000..f4e330e
Binary files /dev/null and b/src/Tizen.NUI/res/dark_maximalize.png differ
diff --git a/src/Tizen.NUI/res/dark_minimalize.png b/src/Tizen.NUI/res/dark_minimalize.png
new file mode 100644 (file)
index 0000000..9ad1355
Binary files /dev/null and b/src/Tizen.NUI/res/dark_minimalize.png differ
diff --git a/src/Tizen.NUI/res/dark_rightCorner.png b/src/Tizen.NUI/res/dark_rightCorner.png
new file mode 100644 (file)
index 0000000..a39807f
Binary files /dev/null and b/src/Tizen.NUI/res/dark_rightCorner.png differ
diff --git a/src/Tizen.NUI/res/dark_smallwindow.png b/src/Tizen.NUI/res/dark_smallwindow.png
new file mode 100644 (file)
index 0000000..0ac0bb8
Binary files /dev/null and b/src/Tizen.NUI/res/dark_smallwindow.png differ
diff --git a/src/Tizen.NUI/res/leftCorner.png b/src/Tizen.NUI/res/leftCorner.png
new file mode 100644 (file)
index 0000000..6f82440
Binary files /dev/null and b/src/Tizen.NUI/res/leftCorner.png differ
diff --git a/src/Tizen.NUI/res/maximalize.png b/src/Tizen.NUI/res/maximalize.png
new file mode 100644 (file)
index 0000000..c5cbbaf
Binary files /dev/null and b/src/Tizen.NUI/res/maximalize.png differ
diff --git a/src/Tizen.NUI/res/minimalize.png b/src/Tizen.NUI/res/minimalize.png
new file mode 100644 (file)
index 0000000..6b116b2
Binary files /dev/null and b/src/Tizen.NUI/res/minimalize.png differ
diff --git a/src/Tizen.NUI/res/rightCorner.png b/src/Tizen.NUI/res/rightCorner.png
new file mode 100644 (file)
index 0000000..68d837f
Binary files /dev/null and b/src/Tizen.NUI/res/rightCorner.png differ
diff --git a/src/Tizen.NUI/res/smallwindow.png b/src/Tizen.NUI/res/smallwindow.png
new file mode 100644 (file)
index 0000000..8f4263b
Binary files /dev/null and b/src/Tizen.NUI/res/smallwindow.png differ
index 06c80ab..33c7898 100755 (executable)
@@ -40,6 +40,12 @@ namespace Tizen.NUI
         private static string currentLoadedXaml = null;
 
         /// <summary>
+        /// The border window
+        /// </summary>
+        private bool borderEnabled = false;
+        private IBorderInterface borderInterface = null;
+
+        /// <summary>
         /// Xaml loaded delegate.
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
@@ -178,6 +184,22 @@ namespace Tizen.NUI
         }
 
         /// <summary>
+        /// The constructor with a stylesheet, window mode, size, position, theme option and boderInterface
+        /// It is the only way to create an IME window.
+        /// </summary>
+        /// <param name="styleSheet">The styleSheet URL.</param>
+        /// <param name="windowMode">The windowMode.</param>
+        /// <param name="windowSize">The window size.</param>
+        /// <param name="windowPosition">The window position.</param>
+        /// <param name="borderInterface"><see cref="Tizen.NUI.IBorderInterface"/>If borderInterface is null, defaultBorder is enabled.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public NUIApplication(string styleSheet, Size2D windowSize, Position2D windowPosition, IBorderInterface borderInterface, WindowMode windowMode = WindowMode.Opaque) : base(new NUICoreBackend(styleSheet, windowMode, windowSize, windowPosition))
+        {
+            borderEnabled = true;
+            this.borderInterface = borderInterface;
+        }
+
+        /// <summary>
         /// Occurs whenever the application is resumed.
         /// </summary>
         /// <since_tizen> 4 </since_tizen>
@@ -454,6 +476,10 @@ namespace Tizen.NUI
         /// <since_tizen> 3 </since_tizen>
         protected virtual void OnPreCreate()
         {
+            if (borderEnabled)
+            {
+                GetDefaultWindow().EnableBorder(borderInterface);
+            }
         }
 
         /// <summary>
index a78c3cd..fa78077 100755 (executable)
@@ -466,8 +466,9 @@ namespace Tizen.NUI
             if (parentChildren != null)
             {
                 int currentIdx = parentChildren.IndexOf(this);
+                int idx = window.IsBorderEnabled ? 1 : 0;
 
-                if (currentIdx > 0 && currentIdx < parentChildren.Count)
+                if (currentIdx > idx && currentIdx < parentChildren.Count)
                 {
                     var low = parentChildren[currentIdx - 1];
                     LowerBelow(low);
@@ -507,6 +508,14 @@ namespace Tizen.NUI
                 parentChildren.Insert(0, this);
 
                 Interop.Layer.LowerToBottom(SwigCPtr);
+
+                if (window.IsBorderEnabled)
+                {
+                    Layer bottomLayer = window.GetBorderWindowBottomLayer();
+                    parentChildren.Remove(bottomLayer);
+                    parentChildren.Insert(0, bottomLayer);
+                    Interop.Layer.LowerToBottom(Layer.getCPtr(bottomLayer));
+                }
                 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
             }
         }
@@ -752,13 +761,19 @@ namespace Tizen.NUI
 
                 if (value < 0) throw new global::System.ArgumentOutOfRangeException(nameof(LayoutCount), "LayoutCount(" + LayoutCount + ") should not be less than zero");
 
-                int diff = value - layoutCount;
-                layoutCount = value;
-
                 if (window != null)
                 {
-                    window.LayoutController.LayoutCount += diff;
+                    if (value == 0)
+                    {
+                        window.LayoutController.LayoutCount = 0;
+                    }
+                    else
+                    {
+                        int diff = value - layoutCount;
+                        window.LayoutController.LayoutCount += diff;
+                    }
                 }
+                layoutCount = value;
             }
         }
 
diff --git a/src/Tizen.NUI/src/public/Window/BorderWindow.cs b/src/Tizen.NUI/src/public/Window/BorderWindow.cs
new file mode 100755 (executable)
index 0000000..31ee3ee
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * Copyright(c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Threading;
+using Tizen.NUI.BaseComponents;
+
+namespace Tizen.NUI
+{
+    public partial class Window
+    {
+        #region Constant Fields
+        #endregion //Constant Fields
+
+        #region Fields
+        private IBorderInterface borderInterface = null;
+        private Layer borderWindowRootLayer = null;
+        private Layer borderWindowBottomLayer = null;
+        private bool isBorderWindow = false;
+        private bool isInterceptTouch = false;
+
+        private Timer overlayTimer;
+
+        // for border area
+        private View rootView = null;
+        #endregion //Fields
+
+        #region Constructors
+        #endregion //Constructors
+
+        #region Distructors
+        #endregion //Distructors
+
+        #region Delegates
+        #endregion //Delegates
+
+        #region Events
+        #endregion //Events
+
+        #region Enums
+        /// <summary>
+        /// This is an enum for the resize direction or move value when the border area is touched.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public enum BorderDirection
+        {
+            None        = ResizeDirection.None,
+            TopLeft     = ResizeDirection.TopLeft,
+            Top         = ResizeDirection.Top,
+            TopRight    = ResizeDirection.TopRight,
+            Left        = ResizeDirection.Left,
+            Right       = ResizeDirection.Right,
+            BottomLeft  = ResizeDirection.BottomLeft,
+            Bottom      = ResizeDirection.Bottom,
+            BottomRight = ResizeDirection.BottomRight,
+            Move,
+        }
+        #endregion //Enums
+
+        #region Interfaces
+        #endregion //Interfaces
+
+        #region Properties
+        /// <summary>
+        /// Whether the border is enabled.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool IsBorderEnabled => isBorderWindow;
+        #endregion //Properties
+
+        #region Indexers
+        #endregion //Indexers
+
+        #region Methods
+        /// <summary>
+        /// Enable the border window with IBorderInterface.
+        /// This adds a border area to the Window.
+        /// The border's UI is configured using IBorderInterface.
+        /// Users can reisze and move by touching the border area.
+        /// </summary>
+        /// <param name="borderInterface">The IBorderInterface.</param>
+        /// <returns>Whether the border window is enabled</returns>
+        internal bool EnableBorder(IBorderInterface borderInterface = null)
+        {
+            if (isBorderWindow == true)
+            {
+                Tizen.Log.Error("NUI", $"Already EnableBorderWindow\n");
+                return false;
+            }
+
+            if (borderInterface == null)
+            {
+                borderInterface = new DefaultBorder();
+            }
+            this.borderInterface = borderInterface;
+
+            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.GetBorderLineThickness() * 2, (int)(borderInterface.GetBorderHeight() + borderInterface.GetBorderLineThickness()));
+
+            if (CreateBorder() == false)
+            {
+                WindowSize -= new Size2D((int)borderInterface.GetBorderLineThickness() * 2, (int)(borderInterface.GetBorderHeight() + borderInterface.GetBorderLineThickness()));
+                Resized -= OnBorderWindowResized;
+                isBorderWindow = false;
+                this.borderInterface = null;
+                return false;
+            }
+
+
+            SetTransparency(true);
+            BackgroundColor = Color.Transparent;
+            borderInterface.SetWindow(this);
+
+            EnableFloatingMode(true);
+
+            borderInterface.OnCreated(rootView);
+
+            return true;
+        }
+
+        /// Create the border UI.
+        private bool CreateBorder()
+        {
+            rootView = new View()
+            {
+                WidthResizePolicy = ResizePolicyType.FillToParent,
+                HeightResizePolicy = ResizePolicyType.FillToParent,
+                BackgroundColor = Color.Transparent,
+            };
+
+            // Gets the Border's UI.
+            borderInterface.CreateBorderView(rootView);
+            if (rootView == null)
+            {
+                return false;
+            }
+            else
+            {
+                if (borderInterface.IsOverlayMode() == true)
+                {
+                    rootView.InterceptTouchEvent += OverlayInterceptTouch;
+                }
+                // Add a view to the border layer.
+                GetBorderWindowBottomLayer().Add(rootView);
+
+                return true;
+            }
+        }
+
+        /// <summary>
+        /// Calculates which direction to resize or to move.
+        /// </summary>
+        /// <param name="xPosition">The X position.</param>
+        /// <param name="yPosition">The Y position.</param>
+        /// <returns>The BorderDirection</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public BorderDirection GetDirection(float xPosition, float yPosition)
+        {
+            BorderDirection direction = BorderDirection.None;
+
+            // check bottom left corner
+            if (xPosition < borderInterface.GetTouchThickness() && yPosition > WindowSize.Height + borderInterface.GetBorderHeight() - borderInterface.GetTouchThickness())
+            {
+                direction = BorderDirection.BottomLeft;
+            }
+            // check bottom right corner
+            else if (xPosition > WindowSize.Width + borderInterface.GetBorderLineThickness()*2 - borderInterface.GetTouchThickness() && yPosition > WindowSize.Height + borderInterface.GetBorderHeight() - borderInterface.GetTouchThickness())
+            {
+                direction = BorderDirection.BottomRight;
+            }
+            // check top left corner
+            else if (xPosition < borderInterface.GetTouchThickness() && yPosition <  borderInterface.GetTouchThickness())
+            {
+                direction = BorderDirection.TopLeft;
+            }
+            // check top right corner
+            else if (xPosition > WindowSize.Width + borderInterface.GetBorderLineThickness()*2 - borderInterface.GetTouchThickness() && yPosition < borderInterface.GetTouchThickness())
+            {
+                direction = BorderDirection.TopRight;
+            }
+            // check left side
+            else if (xPosition < borderInterface.GetTouchThickness())
+            {
+                direction = BorderDirection.Left;
+            }
+            // check right side
+            else if (xPosition > WindowSize.Width + borderInterface.GetBorderLineThickness()*2 - borderInterface.GetTouchThickness())
+            {
+                direction = BorderDirection.Right;
+            }
+            // check bottom side
+            else if (yPosition > WindowSize.Height + borderInterface.GetBorderHeight() + borderInterface.GetBorderLineThickness() - borderInterface.GetTouchThickness())
+            {
+                direction = BorderDirection.Bottom;
+            }
+            // check top side
+            else if (yPosition < borderInterface.GetTouchThickness())
+            {
+                direction = BorderDirection.Top;
+            }
+            // check move
+            else if (yPosition > WindowSize.Height)
+            {
+                direction = BorderDirection.Move;
+            }
+
+            return direction;
+        }
+
+
+        private bool OverlayInterceptTouch(object sender, View.TouchEventArgs e)
+        {
+            if (isInterceptTouch == true && overlayTimer != null)
+            {
+                overlayTimer.Start();
+            }
+            return false;
+        }
+
+        private bool OnTick(object o, Timer.TickEventArgs e)
+        {
+            GetBorderWindowBottomLayer().LowerToBottom();
+            if (rootView != null)
+            {
+                rootView.Hide();
+            }
+            isInterceptTouch = false;
+
+            overlayTimer.Stop();
+            overlayTimer.Dispose();
+            overlayTimer = null;
+            return false;
+        }
+
+        // Intercept touch on window.
+        private bool OnWinInterceptTouch(object sender, Window.TouchEventArgs e)
+        {
+            if (e.Touch.GetState(0) == PointStateType.Up)
+            {
+                if (isInterceptTouch == false && overlayTimer == null)
+                {
+                    overlayTimer = new Timer(3000);
+                    overlayTimer.Tick += OnTick;
+                    overlayTimer.Start();
+                    GetBorderWindowBottomLayer().RaiseToTop();
+                    if (rootView != null)
+                    {
+                        rootView.Show();
+                    }
+                    isInterceptTouch = true;
+                }
+            }
+            return false;
+        }
+
+        private void OverlayMode(bool enable)
+        {
+            if (borderInterface.IsOverlayMode() == true)
+            {
+                if (enable == true)
+                {
+                    InterceptTouchEvent += OnWinInterceptTouch;
+                    if (rootView != null)
+                    {
+                        rootView.Hide();
+                    }
+                }
+                else
+                {
+                    if (overlayTimer != null)
+                    {
+                        overlayTimer.Stop();
+                        overlayTimer.Dispose();
+                        overlayTimer = null;
+                    }
+                    isInterceptTouch = false;
+                    InterceptTouchEvent -= OnWinInterceptTouch;
+                    GetBorderWindowBottomLayer().LowerToBottom();
+                    if (rootView != null)
+                    {
+                        rootView.Show();
+                    }
+                }
+            }
+        }
+
+
+        // Called when the window size has changed.
+        private void OnBorderWindowResized(object sender, Window.ResizedEventArgs e)
+        {
+            Tizen.Log.Info("NUI", $"OnBorderWindowResized {e.WindowSize.Width},{e.WindowSize.Height}\n");
+            int resizeWidth = e.WindowSize.Width;
+            int resizeHeight = e.WindowSize.Height;
+            if (borderInterface.GetMinSize() != null)
+            {
+                resizeWidth = borderInterface.GetMinSize().Width > resizeWidth ? (int)borderInterface.GetMinSize().Width : resizeWidth;
+                resizeHeight = borderInterface.GetMinSize().Height > resizeHeight ? (int)borderInterface.GetMinSize().Height : resizeHeight;
+            }
+
+            if (borderInterface.GetMaxSize() != null)
+            {
+                resizeWidth = borderInterface.GetMaxSize().Width < resizeWidth ? (int)borderInterface.GetMaxSize().Width : resizeWidth;
+                resizeHeight = borderInterface.GetMaxSize().Height < resizeHeight ? (int)borderInterface.GetMaxSize().Height : resizeHeight;
+            }
+
+            if (resizeWidth != e.WindowSize.Width || resizeHeight != e.WindowSize.Height)
+            {
+                WindowSize = new Size2D(resizeWidth, resizeHeight);
+            }
+
+            if (borderInterface.IsOverlayMode() == true && IsMaximized() == true)
+            {
+                Interop.ActorInternal.SetSize(GetBorderWindowRootLayer().SwigCPtr, resizeWidth, resizeHeight);
+                Interop.ActorInternal.SetSize(GetBorderWindowBottomLayer().SwigCPtr, resizeWidth, resizeHeight);
+                OverlayMode(true);
+            }
+            else
+            {
+                Interop.ActorInternal.SetSize(GetBorderWindowRootLayer().SwigCPtr, resizeWidth, resizeHeight);
+                Interop.ActorInternal.SetSize(GetBorderWindowBottomLayer().SwigCPtr, resizeWidth + borderInterface.GetBorderLineThickness() * 2, resizeHeight+borderInterface.GetBorderHeight() + borderInterface.GetBorderLineThickness());
+                OverlayMode(false);
+            }
+
+            borderInterface.OnResized(resizeWidth, resizeHeight);
+
+            if (NDalicPINVOKE.SWIGPendingException.Pending) { throw NDalicPINVOKE.SWIGPendingException.Retrieve(); }
+        }
+
+        internal Layer GetBorderWindowBottomLayer()
+        {
+            if (borderWindowBottomLayer == null)
+            {
+                borderWindowBottomLayer = new Layer();
+                borderWindowBottomLayer.Name = "BorderWindowBottomLayer";
+                Interop.ActorInternal.SetParentOrigin(borderWindowBottomLayer.SwigCPtr, Tizen.NUI.ParentOrigin.TopCenter.SwigCPtr);
+                Interop.Actor.SetAnchorPoint(borderWindowBottomLayer.SwigCPtr, Tizen.NUI.PivotPoint.TopCenter.SwigCPtr);
+                Interop.Actor.Add(rootLayer.SwigCPtr, borderWindowBottomLayer.SwigCPtr);
+                Interop.ActorInternal.SetSize(borderWindowBottomLayer.SwigCPtr, WindowSize.Width+borderInterface.GetBorderLineThickness()*2, WindowSize.Height+borderInterface.GetBorderLineThickness());
+                borderWindowBottomLayer.SetWindow(this);
+                borderWindowBottomLayer.LowerToBottom();
+
+                if (NDalicPINVOKE.SWIGPendingException.Pending) { throw NDalicPINVOKE.SWIGPendingException.Retrieve(); }
+            }
+            return borderWindowBottomLayer;
+        }
+
+        internal Layer GetBorderWindowRootLayer()
+        {
+            if (borderWindowRootLayer == null)
+            {
+                borderWindowRootLayer = new Layer();
+                borderWindowRootLayer.Name = "RootLayer";
+                Interop.ActorInternal.SetParentOrigin(borderWindowRootLayer.SwigCPtr, Tizen.NUI.ParentOrigin.TopCenter.SwigCPtr);
+                Interop.Actor.SetAnchorPoint(borderWindowRootLayer.SwigCPtr, Tizen.NUI.PivotPoint.TopCenter.SwigCPtr);
+                Interop.Actor.Add(rootLayer.SwigCPtr, borderWindowRootLayer.SwigCPtr);
+                Interop.ActorInternal.SetSize(borderWindowRootLayer.SwigCPtr, WindowSize.Width, WindowSize.Height-borderInterface.GetBorderHeight()-borderInterface.GetBorderLineThickness());
+                Interop.ActorInternal.SetPosition(borderWindowRootLayer.SwigCPtr, 0, borderInterface.GetBorderLineThickness());
+                Tizen.NUI.Object.SetProperty(borderWindowRootLayer.SwigCPtr, Tizen.NUI.BaseComponents.View.Property.ClippingMode, new Tizen.NUI.PropertyValue((int)Tizen.NUI.ClippingModeType.ClipToBoundingBox));
+
+                if (NDalicPINVOKE.SWIGPendingException.Pending) { throw NDalicPINVOKE.SWIGPendingException.Retrieve(); }
+            }
+
+            return borderWindowRootLayer;
+        }
+
+        internal void DisposeBorder()
+        {
+            Resized -= OnBorderWindowResized;
+            if (borderInterface.IsOverlayMode() == true && rootView != null)
+            {
+                rootView.InterceptTouchEvent -= OverlayInterceptTouch;
+            }
+            borderInterface.Dispose();
+            GetBorderWindowBottomLayer().Dispose();
+        }
+
+        private void convertBorderWindowSizeToRealWindowSize(Uint16Pair size)
+        {
+            if (isBorderWindow == true)
+            {
+                var height = (ushort)(size.GetHeight() + borderInterface.GetBorderHeight()+borderInterface.GetBorderLineThickness());
+                var width = (ushort)(size.GetWidth() + borderInterface.GetBorderLineThickness()*2);
+                size.SetHeight(height);
+                size.SetWidth(width);
+            }
+        }
+
+        private void convertRealWindowSizeToBorderWindowSize(Uint16Pair size)
+        {
+            if (isBorderWindow == true && !(borderInterface.IsOverlayMode() == true && IsMaximized() == true))
+            {
+                var height = (ushort)(size.GetHeight() - borderInterface.GetBorderHeight()-borderInterface.GetBorderLineThickness());
+                var width = (ushort)(size.GetWidth() - borderInterface.GetBorderLineThickness()*2);
+                size.SetHeight(height);
+                size.SetWidth(width);
+            }
+        }
+        #endregion //Methods
+
+        #region Structs
+        #endregion //Structs
+
+        #region Classes
+        #endregion //Classes
+    }
+
+
+
+}
diff --git a/src/Tizen.NUI/src/public/Window/DefaultBorder.cs b/src/Tizen.NUI/src/public/Window/DefaultBorder.cs
new file mode 100755 (executable)
index 0000000..92022a6
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+ * Copyright(c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.ComponentModel;
+using Tizen.NUI.BaseComponents;
+
+namespace Tizen.NUI
+{
+    /// <summary>
+    /// This class creates a border UI.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class DefaultBorder : IBorderInterface
+    {
+        #region Constant Fields
+        private static readonly string ResourcePath = FrameworkInformation.ResourcePath;
+        private static readonly string MinimalizeIcon = ResourcePath + "minimalize.png";
+        private static readonly string MaximalizeIcon = ResourcePath + "maximalize.png";
+        private static readonly string PreviousIcon = ResourcePath + "smallwindow.png";
+        private static readonly string CloseIcon = ResourcePath + "close.png";
+        private static readonly string LeftCornerIcon = ResourcePath + "leftCorner.png";
+        private static readonly string RightCornerIcon = ResourcePath + "rightCorner.png";
+
+        private static readonly string DarkMinimalizeIcon = ResourcePath + "dark_minimalize.png";
+        private static readonly string DarkMaximalizeIcon = ResourcePath + "dark_maximalize.png";
+        private static readonly string DarkPreviousIcon = ResourcePath + "dark_smallwindow.png";
+        private static readonly string DarkCloseIcon = ResourcePath + "dark_close.png";
+        private static readonly string DarkLeftCornerIcon = ResourcePath + "dark_leftCorner.png";
+        private static readonly string DarkRightCornerIcon = ResourcePath + "dark_rightCorner.png";
+
+
+        private static readonly uint DefaultHeight = 50;
+        private static readonly uint DefaultLineThickness = 5;
+        private static readonly uint DefaultTouchThickness = 20;
+        private static readonly Color DefaultBackgroundColor = new Color(1, 1, 1, 0.3f);
+        private static readonly Color DefaultClickedBackgroundColor = new Color(1, 1, 1, 0.4f);
+        private static readonly Size2D DefaultMinSize = new Size2D(500, 0);
+        #endregion //Constant Fields
+
+
+        #region Fields
+        private Color backgroundColor;
+        private View rootView;
+        private Window window = null;
+
+        private ImageView minimalizeIcon;
+        private ImageView maximalizeIcon;
+        private ImageView closeIcon;
+        private ImageView leftCornerIcon;
+        private ImageView rightCornerIcon;
+
+        private Window.BorderDirection direction = Window.BorderDirection.None;
+        private float preScale = 0;
+
+        private View windowView = null;
+        private bool isWinGestures = false;
+        private Timer timer;
+
+        private CurrentGesture currentGesture = CurrentGesture.None;
+        #endregion //Fields
+
+        #region Events
+        private PanGestureDetector borderPanGestureDetector;
+        private PinchGestureDetector borderPinchGestureDetector;
+        private PanGestureDetector winPanGestureDetector;
+        private TapGestureDetector winTapGestureDetector;
+        #endregion //Events
+
+        #region Enums
+        private enum CurrentGesture
+        {
+          None = 0,
+          TapGesture = 1,
+          PanGesture = 2,
+          PinchGesture = 3,
+        }
+        #endregion //Enums
+
+        #region Methods
+
+        /// <summary>
+        /// Sets the window which the border is enabled.
+        /// </summary>
+        /// <param name="window">The window in which the border is enabled.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual void SetWindow(Window window)
+        {
+          this.window = window;
+        }
+
+        /// <summary>
+        /// Returns the window which borders is enabled.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual Window GetWindow()
+        {
+            return window;
+        }
+
+        /// <summary>
+        /// Create border UI. Users can override this method to draw border UI.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual void CreateBorderView(View rootView)
+        {
+            this.rootView = rootView;
+            rootView.BackgroundColor = DefaultBackgroundColor;
+            rootView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f);
+            rootView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
+
+            View borderView = new View()
+            {
+                Layout = new LinearLayout()
+                {
+                    LinearAlignment = LinearLayout.Alignment.End,
+                    LinearOrientation = LinearLayout.Orientation.Horizontal,
+                },
+                WidthSpecification = LayoutParamPolicies.MatchParent,
+                HeightSpecification = LayoutParamPolicies.MatchParent,
+            };
+
+            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);
+
+            minimalizeIcon.TouchEvent += OnMinimizeIconTouched;
+            maximalizeIcon.TouchEvent += OnMaximizeIconTouched;
+            closeIcon.TouchEvent += OnCloseIconTouched;
+            leftCornerIcon.TouchEvent += OnLeftCornerIconTouched;
+            rightCornerIcon.TouchEvent += OnRightCornerIconTouched;
+        }
+
+        /// Determines the behavior of pinch gesture.
+        private void OnPinchGestureDetected(object source, PinchGestureDetector.DetectedEventArgs e)
+        {
+            if (e.PinchGesture.State == Gesture.StateType.Started)
+            {
+                preScale = e.PinchGesture.Scale;
+            }
+            else if (e.PinchGesture.State == Gesture.StateType.Finished || e.PinchGesture.State == Gesture.StateType.Cancelled)
+            {
+                if (preScale > e.PinchGesture.Scale)
+                {
+                    if (window.IsMaximized())
+                    {
+                        window.Maximize(false);
+                    }
+                    else
+                    {
+                        window.Minimize(true);
+                    }
+                }
+                else
+                {
+                    window.Maximize(true);
+                }
+            }
+        }
+
+        /// Determines the behavior of borders.
+        private void OnPanGestureDetected(object source, PanGestureDetector.DetectedEventArgs e)
+        {
+            PanGesture panGesture = e.PanGesture;
+
+            if (panGesture.State == Gesture.StateType.Started)
+            {
+                direction = window.GetDirection(panGesture.Position.X, panGesture.Position.Y);
+                if (direction == Window.BorderDirection.Move)
+                {
+                    if (window.IsMaximized() == true)
+                    {
+                        window.Maximize(false);
+                    }
+                    else
+                    {
+                        window.RequestMoveToServer();
+                    }
+                }
+                else if (direction != Window.BorderDirection.None)
+                {
+                    window.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)
+                {
+                    window.WindowSize += new Size2D((int)panGesture.ScreenDisplacement.X, (int)panGesture.ScreenDisplacement.Y);
+                }
+                else if (direction == Window.BorderDirection.Left || direction == Window.BorderDirection.Right)
+                {
+                    window.WindowSize += new Size2D((int)panGesture.ScreenDisplacement.X, 0);
+                }
+                else if (direction == Window.BorderDirection.Bottom || direction == Window.BorderDirection.Top)
+                {
+                    window.WindowSize += new Size2D(0, (int)panGesture.ScreenDisplacement.Y);
+                }
+                else if (direction == Window.BorderDirection.Move)
+                {
+                    window.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;
+                ClearWindowGesture();
+            }
+        }
+
+
+        /// <summary>
+        /// This is an event callback when the left corner icon is touched.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual bool OnLeftCornerIconTouched(object sender, View.TouchEventArgs e)
+        {
+            if (e.Touch.GetState(0) == PointStateType.Down)
+            {
+              ClearWindowGesture();
+              if(window.IsMinimized() == true)
+              {
+                window.RequestResizeToServer(Window.ResizeDirection.TopLeft);
+              }
+              else
+              {
+                window.RequestResizeToServer(Window.ResizeDirection.BottomLeft);
+              }
+            }
+            return true;
+        }
+
+        /// <summary>
+        ///This is an event callback when the right corner icon is touched.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual bool OnRightCornerIconTouched(object sender, View.TouchEventArgs e)
+        {
+            if (e.Touch.GetState(0) == PointStateType.Down)
+            {
+              ClearWindowGesture();
+              if(window.IsMinimized() == true)
+              {
+                window.RequestResizeToServer(Window.ResizeDirection.TopRight);
+              }
+              else
+              {
+                window.RequestResizeToServer(Window.ResizeDirection.BottomRight);
+              }
+            }
+            return true;
+        }
+
+
+        /// <summary>
+        /// This is an event callback when the minimize button is touched.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual bool OnMinimizeIconTouched(object sender, View.TouchEventArgs e)
+        {
+            if (e.Touch.GetState(0) == PointStateType.Up)
+            {
+                ClearWindowGesture();
+                window.Minimize(true);
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// This is an event callback when the maximum button is touched.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual bool OnMaximizeIconTouched(object sender, View.TouchEventArgs e)
+        {
+            if (e.Touch.GetState(0) == PointStateType.Up)
+            {
+                ClearWindowGesture();
+                if (window.IsMaximized())
+                {
+                  window.Maximize(false);
+                }
+                else
+                {
+                  window.Maximize(true);
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// This is an event callback when the close button is touched.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual bool OnCloseIconTouched(object sender, View.TouchEventArgs e)
+        {
+            if (e.Touch.GetState(0) == PointStateType.Up)
+            {
+                window.Destroy();
+                window = null;
+            }
+            return true;
+        }
+
+
+        private void UpdateIcons()
+        {
+            if (window != null && rootView != null)
+            {
+                if (window.IsMaximized() == true)
+                {
+                    if (maximalizeIcon != null)
+                    {
+                        maximalizeIcon.ResourceUrl = DarkPreviousIcon;
+                    }
+                    if (minimalizeIcon != null)
+                    {
+                        minimalizeIcon.ResourceUrl = DarkMinimalizeIcon;
+                    }
+                    if (closeIcon != null)
+                    {
+                        closeIcon.ResourceUrl = DarkCloseIcon;
+                    }
+                    if (leftCornerIcon != null)
+                    {
+                        leftCornerIcon.ResourceUrl = DarkLeftCornerIcon;
+                    }
+                    if (rightCornerIcon != null)
+                    {
+                        rightCornerIcon.ResourceUrl = DarkRightCornerIcon;
+                    }
+                    rootView.CornerRadius = new Vector4(0, 0, 0, 0);
+                    rootView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
+                    window.SetTransparency(false);
+                }
+                else
+                {
+                    if (maximalizeIcon != null)
+                    {
+                        maximalizeIcon.ResourceUrl = MaximalizeIcon;
+                    }
+                    if (minimalizeIcon != null)
+                    {
+                        minimalizeIcon.ResourceUrl = MinimalizeIcon;
+                    }
+                    if (closeIcon != null)
+                    {
+                        closeIcon.ResourceUrl = CloseIcon;
+                    }
+                    if (leftCornerIcon != null)
+                    {
+                        leftCornerIcon.ResourceUrl = LeftCornerIcon;
+                    }
+                    if (rightCornerIcon != null)
+                    {
+                        rightCornerIcon.ResourceUrl = RightCornerIcon;
+                    }
+                    rootView.CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f);
+                    rootView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
+                    window.SetTransparency(true);
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Called after the border UI is created.
+        /// </summary>
+        /// <param name="rootView">The root view on which the border.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual void OnCreated(View rootView)
+        {
+            // Register to resize and move through pan gestures.
+            borderPanGestureDetector = new PanGestureDetector();
+            borderPanGestureDetector.Attach(rootView);
+            borderPanGestureDetector.Detected += OnPanGestureDetected;
+
+            // Register touch event for effect when border is touched.
+            rootView.LeaveRequired = true;
+            rootView.TouchEvent += (s, e) =>
+            {
+                if (e.Touch.GetState(0) == PointStateType.Started)
+                {
+                    backgroundColor = new Color(rootView.BackgroundColor);
+                    rootView.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;
+                }
+                return true;
+            };
+
+            borderPinchGestureDetector = new PinchGestureDetector();
+            borderPinchGestureDetector.Attach(rootView);
+            borderPinchGestureDetector.Detected += OnPinchGestureDetected;
+
+            AddInterceptGesture();
+        }
+
+
+        // Register an intercept touch event on the window.
+        private void AddInterceptGesture()
+        {
+            isWinGestures = false;
+            window.InterceptTouchEvent += OnWinInterceptedTouch;
+        }
+
+        // Intercept touch on window.
+        private bool OnWinInterceptedTouch(object sender, Window.TouchEventArgs e)
+        {
+            if (e.Touch.GetState(0) == PointStateType.Stationary && e.Touch.GetPointCount() == 2)
+            {
+                if (isWinGestures == false && timer == null)
+                {
+                    timer = new Timer(300);
+                    timer.Tick += OnTick;
+                    timer.Start();
+                }
+            }
+            else
+            {
+                currentGesture = CurrentGesture.None;
+                if (timer != null)
+                {
+                    timer.Stop();
+                    timer.Dispose();
+                }
+            }
+            return false;
+        }
+
+        // If two finger long press is done, create a windowView.
+        // then, Register a gesture on the windowView to do a resize or move.
+        private bool OnTick(object o, Timer.TickEventArgs e)
+        {
+            windowView = new View()
+            {
+                WidthResizePolicy = ResizePolicyType.FillToParent,
+                HeightResizePolicy = ResizePolicyType.FillToParent,
+                BackgroundColor = new Vector4(1, 1, 1, 0.5f),
+            };
+            windowView.TouchEvent += (s, e) =>
+            {
+                return true;
+            };
+            window.Add(windowView);
+
+            winTapGestureDetector = new TapGestureDetector();
+            winTapGestureDetector.Attach(windowView);
+            winTapGestureDetector.SetMaximumTapsRequired(3);
+            winTapGestureDetector.Detected += OnWinTapGestureDetected;
+
+            winPanGestureDetector = new PanGestureDetector();
+            winPanGestureDetector.Attach(windowView);
+            winPanGestureDetector.Detected += OnWinPanGestureDetected;
+
+            window.InterceptTouchEvent -= OnWinInterceptedTouch;
+            isWinGestures = true;
+            return false;
+        }
+
+        // Behavior when the window is tapped.
+        private void OnWinTapGestureDetected(object source, TapGestureDetector.DetectedEventArgs e)
+        {
+          if (currentGesture <= CurrentGesture.TapGesture)
+          {
+              currentGesture = CurrentGesture.TapGesture;
+              if (e.TapGesture.NumberOfTaps == 2)
+              {
+                  if (window.IsMaximized() == false)
+                  {
+                    window.Maximize(true);
+                  }
+                  else
+                  {
+                    window.Maximize(false);
+                  }
+              }
+              else
+              {
+                  ClearWindowGesture();
+              }
+          }
+        }
+
+        // Window moves through pan gestures.
+        private void OnWinPanGestureDetected(object source, PanGestureDetector.DetectedEventArgs e)
+        {
+            if (currentGesture <= CurrentGesture.PanGesture /*&& panGesture.NumberOfTouches == 1*/)
+            {
+                PanGesture panGesture = e.PanGesture;
+
+                if (panGesture.State == Gesture.StateType.Started)
+                {
+                    currentGesture = CurrentGesture.PanGesture;
+                    if (window.IsMaximized() == true)
+                    {
+                        window.Maximize(false);
+                    }
+                    else
+                    {
+                        window.RequestMoveToServer();
+                    }
+                }
+                else if (panGesture.State == Gesture.StateType.Finished || panGesture.State == Gesture.StateType.Cancelled)
+                {
+                    currentGesture = CurrentGesture.None;
+                    ClearWindowGesture();
+                }
+            }
+        }
+
+        private void ClearWindowGesture()
+        {
+            if (isWinGestures)
+            {
+                winPanGestureDetector.Dispose();
+                winTapGestureDetector.Dispose();
+
+                isWinGestures = false;
+                window.Remove(windowView);
+                window.InterceptTouchEvent += OnWinInterceptedTouch;
+            }
+        }
+
+        /// <summary>
+        /// Called when the window is resized.
+        /// </summary>
+        /// <param name="width">The width of the resized window</param>
+        /// <param name="height">The height of the resized window</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual void OnResized(int width, int height)
+        {
+            UpdateIcons();
+        }
+
+        /// <summary>
+        /// Returns the thickness of the border.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual uint GetBorderLineThickness()
+        {
+            return DefaultLineThickness;
+        }
+
+        /// <summary>
+        /// Returns the thickness of the border's touch area.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual uint GetTouchThickness()
+        {
+            return DefaultTouchThickness;
+        }
+
+        /// <summary>
+        /// Returns the height of the border.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual uint GetBorderHeight()
+        {
+            return DefaultHeight;
+        }
+
+        /// <summary>
+        /// Returns the minimum size by which the window will small.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual Size2D GetMinSize()
+        {
+            return DefaultMinSize;
+        }
+
+        /// <summary>
+        /// Returns the maximum size by which the window will big.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual Size2D GetMaxSize()
+        {
+            return null;
+        }
+
+        /// <summary>
+        /// Returns whether overlay mode is present.
+        /// If overlay mode is true, the border area is hidden when the window is maximized.
+        /// And if you touched at screen, the border area is shown on the screen.
+        /// Default value is false;
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual bool IsOverlayMode()
+        {
+            return false;
+        }
+
+        /// <summary>
+        /// Dispose
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual void Dispose()
+        {
+            ClearWindowGesture();
+            window.InterceptTouchEvent -= OnWinInterceptedTouch;
+            borderPanGestureDetector.Dispose();
+            borderPinchGestureDetector.Dispose();
+            if (windowView != null)
+            {
+                windowView.Dispose();
+            }
+            if (rootView != null)
+            {
+                rootView.Dispose();
+            }
+        }
+        #endregion //Methods
+
+    }
+}
diff --git a/src/Tizen.NUI/src/public/Window/IBorderInterface.cs b/src/Tizen.NUI/src/public/Window/IBorderInterface.cs
new file mode 100755 (executable)
index 0000000..e3d6848
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright(c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.ComponentModel;
+using Tizen.NUI.BaseComponents;
+
+namespace Tizen.NUI
+{
+    /// <summary>
+    /// This is the interface used to draw the border UI.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public interface IBorderInterface
+    {
+        /// <summary>
+        /// Create border UI. User can override this method to draw border UI.
+        /// </summary>
+        /// <param name="rootView">The root view on which the border.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void CreateBorderView(View rootView);
+
+
+        /// <summary>
+        /// Called after the border UI is created.
+        /// </summary>
+        /// <param name="rootView">The root view on which the border.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void OnCreated(View rootView);
+
+        /// <summary>
+        /// Called when the window is resized.
+        /// </summary>
+        /// <param name="width">The width of the resized window</param>
+        /// <param name="height">The height of the resized window</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void OnResized(int width, int height);
+
+        /// <summary>
+        /// Returns the thickness of the border.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public uint GetBorderLineThickness();
+
+        /// <summary>
+        /// Returns the thickness of the border's touch area.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public uint GetTouchThickness();
+
+        /// <summary>
+        /// Returns the height of the border.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public uint GetBorderHeight();
+
+        /// <summary>
+        /// Returns the minimum size by which the window will small.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Size2D GetMinSize();
+
+        /// <summary>
+        /// Returns the maximum size by which the window will big.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Size2D GetMaxSize();
+
+        /// <summary>
+        /// Sets The window to which the border is added.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void SetWindow(Window window);
+
+        /// <summary>
+        /// Returns the window with borders added.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Window GetWindow();
+
+        /// <summary>
+        /// Returns whether overlay mode is present.
+        /// If overlay mode is true, the border area is hidden when the window is maximized.
+        /// And if you touched at screen, the border area is shown on the screen.
+        /// Default value is false;
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool IsOverlayMode();
+
+        /// <summary>
+        /// Dispose
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Dispose();
+    }
+}
index fcfd78e..3436578 100644 (file)
@@ -36,6 +36,7 @@ namespace Tizen.NUI
     {
         private HandleRef stageCPtr;
         private Layer rootLayer;
+        private Layer borderLayer;
         private string windowTitle;
         private List<Layer> childLayers = new List<Layer>();
         private LayoutController localController;
@@ -126,6 +127,30 @@ namespace Tizen.NUI
         }
 
         /// <summary>
+        /// Creates a new Window with a specific name.<br />
+        /// This creates an extra window in addition to the default main window<br />
+        /// </summary>
+        /// <param name="name">The name for extra window. </param>
+        /// <param name="borderInterface"><see cref="Tizen.NUI.IBorderInterface"/>If borderInterface is null, defaultBorder is enabled.</param>
+        /// <param name="windowPosition">The position and size of the Window.</param>
+        /// <param name="isTranslucent">Whether Window is translucent.</param>
+        /// <returns>A new Window.</returns>
+        /// <feature> http://tizen.org/feature/opengles.surfaceless_context </feature>
+        /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Window(string name, IBorderInterface borderInterface, Rectangle windowPosition = null, bool isTranslucent = false) : this(Interop.Window.New(Rectangle.getCPtr(windowPosition), name, isTranslucent), true)
+        {
+            if (IsSupportedMultiWindow() == false)
+            {
+                NUILog.Error("This device does not support surfaceless_context. So Window cannot be created. ");
+            }
+            this.windowTitle = name;
+            this.EnableBorder(borderInterface);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+
+        /// <summary>
         /// Enumeration for orientation of the window is the way in which a rectangular page is oriented for normal viewing.
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
@@ -318,6 +343,11 @@ namespace Tizen.NUI
         public enum ResizeDirection
         {
             /// <summary>
+            /// None type.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            None = 0,
+            /// <summary>
             /// Start resizing window to the top-left edge.
             /// </summary>
             [EditorBrowsable(EditorBrowsableState.Never)]
@@ -1345,8 +1375,17 @@ namespace Tizen.NUI
             {
                 throw new ArgumentNullException(nameof(layer));
             }
-            Interop.Window.Add(SwigCPtr, Layer.getCPtr(layer));
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+
+            if (isBorderWindow)
+            {
+                Interop.Actor.Add(GetBorderWindowRootLayer().SwigCPtr, layer.SwigCPtr);
+                if (NDalicPINVOKE.SWIGPendingException.Pending) { throw NDalicPINVOKE.SWIGPendingException.Retrieve(); }
+            }
+            else
+            {
+                Interop.Window.Add(SwigCPtr, Layer.getCPtr(layer));
+                if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            }
 
             LayersChildren?.Add(layer);
             layer.SetWindow(this);
@@ -1368,6 +1407,9 @@ namespace Tizen.NUI
         internal Vector2 GetSize()
         {
             var val = new Uint16Pair(Interop.Window.GetSize(SwigCPtr), true);
+
+            convertRealWindowSizeToBorderWindowSize(val);
+
             Vector2 ret = new Vector2(val.GetWidth(), val.GetHeight());
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
             val.Dispose();
@@ -1398,16 +1440,29 @@ namespace Tizen.NUI
 
         internal Layer GetRootLayer()
         {
-            // Window.IsInstalled() is actually true only when called from event thread and
-            // Core has been initialized, not when Stage is ready.
-            if (rootLayer == null && Window.IsInstalled())
+            if (isBorderWindow)
             {
-                rootLayer = new Layer(Interop.Window.GetRootLayer(SwigCPtr), true);
-                if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-                LayersChildren?.Add(rootLayer);
-                rootLayer.SetWindow(this);
+                if(borderLayer == null)
+                {
+                    borderLayer = GetBorderWindowRootLayer();
+                    LayersChildren?.Add(borderLayer);
+                    borderLayer.SetWindow(this);
+                }
+                return borderLayer;
+            }
+            else
+            {
+                // Window.IsInstalled() is actually true only when called from event thread and
+                // Core has been initialized, not when Stage is ready.
+                if (rootLayer == null && Window.IsInstalled())
+                {
+                    rootLayer = new Layer(Interop.Window.GetRootLayer(SwigCPtr), true);
+                    if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+                    LayersChildren?.Add(rootLayer);
+                    rootLayer.SetWindow(this);
+                }
+                return rootLayer;
             }
-            return rootLayer;
         }
 
         internal void SetBackgroundColor(Vector4 color)
@@ -1458,6 +1513,9 @@ namespace Tizen.NUI
                 throw new ArgumentNullException(nameof(size));
             }
             var val = new Uint16Pair((uint)size.Width, (uint)size.Height);
+
+            convertBorderWindowSizeToRealWindowSize(val);
+
             Interop.Window.SetSize(SwigCPtr, Uint16Pair.getCPtr(val));
             val.Dispose();
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
@@ -1467,6 +1525,9 @@ namespace Tizen.NUI
         internal Size2D GetWindowSize()
         {
             var val = new Uint16Pair(Interop.Window.GetSize(SwigCPtr), true);
+
+            convertRealWindowSizeToBorderWindowSize(val);
+
             Size2D ret = new Size2D(val.GetWidth(), val.GetHeight());
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
             val.Dispose();
@@ -1497,6 +1558,17 @@ namespace Tizen.NUI
 
         internal void SetPositionSize(Rectangle positionSize)
         {
+            if (positionSize == null)
+            {
+                throw new ArgumentNullException(nameof(positionSize));
+            }
+            var val = new Uint16Pair((uint)positionSize.Width, (uint)positionSize.Height);
+
+            convertBorderWindowSizeToRealWindowSize(val);
+
+            positionSize.Width = val.GetX();
+            positionSize.Height = val.GetY();
+
             Interop.Window.SetPositionSize(SwigCPtr, Rectangle.getCPtr(positionSize));
 
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
@@ -1666,6 +1738,11 @@ namespace Tizen.NUI
                 //Release your own managed resources here.
                 //You should release all of your own disposable objects here.
 
+                if (IsBorderEnabled)
+                {
+                    DisposeBorder();
+                }
+
                 if (rootLayer != null)
                 {
                     rootLayer.Dispose();
index 36318d7..d2219b9 100755 (executable)
@@ -32,6 +32,7 @@ namespace Tizen.NUI
     {
         private WindowFocusChangedEventCallbackType windowFocusChangedEventCallback;
         private RootLayerTouchDataCallbackType rootLayerTouchDataCallback;
+        private RootLayerTouchDataCallbackType rootLayerInterceptTouchDataCallback;
         private WheelEventCallbackType wheelEventCallback;
         private EventCallbackDelegateType1 stageKeyCallbackDelegate;
         private EventCallbackDelegateType0 stageEventProcessingFinishedEventCallbackDelegate;
@@ -60,6 +61,8 @@ namespace Tizen.NUI
         private VoidSignal contextLostSignal;
         private VoidSignal contextRegainedSignal;
         private AuxiliaryMessageEventCallbackType auxiliaryMessageEventCallback;
+        private TouchDataSignal interceptTouchDataSignal;
+        private TouchSignal interceptTouchSignal;
 
         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
         private delegate void WindowFocusChangedEventCallbackType(IntPtr window, bool focusGained);
@@ -145,6 +148,40 @@ namespace Tizen.NUI
         }
 
         /// <summary>
+        /// An event for the touched signal which can be used to subscribe or unsubscribe the event handler provided by the user.<br />
+        /// The touched signal is emitted when the touch input is received.<br />
+        /// This can receive touch events before child. <br />
+        /// If it returns false, the child can receive the touch event. If it returns true, the touch event is intercepted. So child cannot receive touch event.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public event ReturnTypeEventHandler<object, TouchEventArgs, bool> InterceptTouchEvent
+        {
+            add
+            {
+                if (rootLayerInterceptTouchDataEventHandler == null)
+                {
+                    rootLayerInterceptTouchDataCallback = OnWindowInterceptTouch;
+                    interceptTouchDataSignal = this.InterceptTouchDataSignal();
+                    interceptTouchDataSignal?.Connect(rootLayerInterceptTouchDataCallback);
+                }
+                rootLayerInterceptTouchDataEventHandler += value;
+            }
+            remove
+            {
+                rootLayerInterceptTouchDataEventHandler -= value;
+                interceptTouchSignal = TouchSignal();
+                if (rootLayerInterceptTouchDataEventHandler == null && interceptTouchSignal?.Empty() == false && rootLayerInterceptTouchDataCallback != null)
+                {
+                    interceptTouchDataSignal?.Disconnect(rootLayerInterceptTouchDataCallback);
+                    if (interceptTouchDataSignal?.Empty() == true)
+                    {
+                        rootLayerInterceptTouchDataCallback = null;
+                    }
+                }
+            }
+        }
+
+        /// <summary>
         /// Emits the event when the wheel event is received.
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
@@ -360,6 +397,7 @@ namespace Tizen.NUI
         public event EventHandler ViewAdded;
         private event EventHandler<FocusChangedEventArgs> windowFocusChangedEventHandler;
         private event EventHandler<TouchEventArgs> rootLayerTouchDataEventHandler;
+        private ReturnTypeEventHandler<object, TouchEventArgs, bool> rootLayerInterceptTouchDataEventHandler;
         private event EventHandler<WheelEventArgs> stageWheelHandler;
         private event EventHandler<KeyEventArgs> stageKeyHandler;
         private event EventHandler stageEventProcessingFinishedEventHandler;
@@ -518,6 +556,15 @@ namespace Tizen.NUI
             return ret;
         }
 
+        internal TouchDataSignal InterceptTouchDataSignal()
+        {
+            TouchDataSignal ret = new TouchDataSignal(Interop.ActorSignal.ActorInterceptTouchSignal(Layer.getCPtr(GetRootLayer())), false);
+            if (NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
+
         internal VoidSignal ContextLostSignal()
         {
             VoidSignal ret = new VoidSignal(Interop.StageSignal.ContextLostSignal(stageCPtr), false);
@@ -571,6 +618,12 @@ namespace Tizen.NUI
                 rootLayerTouchDataCallback = null;
             }
 
+            if (rootLayerInterceptTouchDataCallback != null)
+            {
+                interceptTouchDataSignal?.Disconnect(rootLayerInterceptTouchDataCallback);
+                rootLayerInterceptTouchDataCallback = null;
+            }
+
             if (wheelEventCallback != null)
             {
                 wheelSignal?.Disconnect(wheelEventCallback);
@@ -716,6 +769,24 @@ namespace Tizen.NUI
             return false;
         }
 
+        private bool OnWindowInterceptTouch(IntPtr view, IntPtr touchData)
+        {
+            if (touchData == global::System.IntPtr.Zero)
+            {
+                NUILog.Error("touchData should not be null!");
+                return true;
+            }
+
+            bool consumed = false;
+            if (rootLayerInterceptTouchDataEventHandler != null)
+            {
+                TouchEventArgs e = new TouchEventArgs();
+                e.Touch = Tizen.NUI.Touch.GetTouchFromPtr(touchData);
+                consumed = rootLayerInterceptTouchDataEventHandler(this, e);
+            }
+            return consumed;
+        }
+
         private bool OnStageWheel(IntPtr rootLayer, IntPtr wheelEvent)
         {
             if (wheelEvent == global::System.IntPtr.Zero)
diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/BorderWindowTest.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/BorderWindowTest.cs
new file mode 100755 (executable)
index 0000000..0265132
--- /dev/null
@@ -0,0 +1,354 @@
+
+using System;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Components;
+using System.Collections.Generic;
+
+
+namespace Tizen.NUI.Samples
+{
+  public class BorderWindowTest : IExample
+  {
+    private Window win;
+    private Window subWindowOne = null;
+    private Window subWindowTwo = null;
+    private static readonly string imagePath = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "/images/Dali/CubeTransitionEffect/";
+
+
+    class CustomBorder : DefaultBorder
+    {
+      private int width = 500;
+      private bool hide = false;
+      private View rootView;
+      private View borderView;
+      private TextLabel title;
+
+      public CustomBorder() : base()
+      {
+      }
+
+
+      public override void CreateBorderView(View rootView)
+      {
+          this.rootView = rootView;
+          // rootView.BackgroundColor = new Color(1, 1, 1, 0.3f);
+          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,
+          };
+          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),
+          };
+
+
+          var leftPadding = new View()
+          {
+              PositionUsesPivotPoint = true,
+              PivotPoint = PivotPoint.BottomLeft,
+              ParentOrigin = ParentOrigin.BottomLeft,
+              Size = new Size(50, 50),
+          };
+
+          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;
+      }
+
+      public override void OnCreated(View rootView)
+      {
+        base.OnCreated(rootView);
+      }
+
+      public override bool  OnCloseIconTouched(object sender, View.TouchEventArgs e)
+      {
+        base.OnCloseIconTouched(sender, e);
+        return true;
+      }
+
+      public override bool  OnMinimizeIconTouched(object sender, View.TouchEventArgs e)
+      {
+        base.OnMinimizeIconTouched(sender, e);
+        return true;
+      }
+
+      public override void OnResized(int width, int height)
+      {
+        if (rootView != null)
+        {
+          if (this.width > width && hide == false)
+          {
+            title.Hide();
+            hide = true;
+          }
+          else if (this.width < width && hide == true)
+          {
+            title.Show();
+            hide = false;
+          }
+          base.OnResized(width, height);
+        }
+      }
+
+      public override uint GetBorderLineThickness()
+      {
+        return base.GetBorderLineThickness();
+      }
+
+      public override uint GetTouchThickness()
+      {
+        return base.GetTouchThickness();
+      }
+
+      public override uint GetBorderHeight()
+      {
+        return base.GetBorderHeight();
+      }
+
+      public override Size2D GetMinSize()
+      {
+        return base.GetMinSize();
+      }
+
+      public override Size2D GetMaxSize()
+      {
+        return base.GetMaxSize();
+      }
+
+      public override void SetWindow(Window window)
+      {
+        base.SetWindow(window);
+      }
+
+      public override Window GetWindow()
+      {
+        return base.GetWindow();
+      }
+
+      public override void Dispose()
+      {
+        base.Dispose();
+      }
+
+      public override bool IsOverlayMode()
+      {
+        return true;
+      }
+
+
+    }
+
+    void CreateSubWindowOne()
+    {
+      if (subWindowOne == null)
+      {
+        subWindowOne = new Window("subwin1", null, new Rectangle(20, 20, 800, 800), false);
+
+        var root = new ImageView()
+        {
+          WidthResizePolicy = ResizePolicyType.FillToParent,
+          HeightResizePolicy = ResizePolicyType.FillToParent,
+          ResourceUrl = imagePath + "gallery-large-9.jpg",
+          CornerRadius = new Vector4(0.03f, 0.03f, 0.03f, 0.03f),
+          CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+        };
+        subWindowOne.Add(root);
+
+        TextLabel text = new TextLabel("Hello Tizen NUI World");
+        text.HorizontalAlignment = HorizontalAlignment.Center;
+        text.VerticalAlignment = VerticalAlignment.Center;
+        text.TextColor = Color.CornflowerBlue;
+        text.HeightResizePolicy = ResizePolicyType.FillToParent;
+        text.WidthResizePolicy = ResizePolicyType.FillToParent;
+        root.Add(text);
+
+        Animation animation = new Animation(2000);
+        animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(180.0f)), PositionAxis.X), 0, 500);
+        animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(0.0f)), PositionAxis.X), 500, 1000);
+        animation.Looping = true;
+        animation.Play();
+      }
+      else
+      {
+        subWindowOne.Minimize(false);
+      }
+    }
+
+    void CreateSubWindowTwo()
+    {
+      if (subWindowTwo == null)
+      {
+        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()
+          {
+              LinearAlignment = LinearLayout.Alignment.CenterHorizontal,
+          },
+          WidthResizePolicy = ResizePolicyType.FillToParent,
+          HeightResizePolicy = ResizePolicyType.FillToParent,
+          BackgroundColor = Color.Yellow,
+        };
+
+        var image = new ImageView()
+        {
+          Size = new Size(300, 300),
+          ResourceUrl = imagePath + "gallery-large-5.jpg",
+          CornerRadius = new Vector4(0.03f, 0.03f, 0, 0),
+          CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+        };
+        root.Add(image);
+        subWindowTwo.Add(root);
+      }
+      else
+      {
+        subWindowTwo.Minimize(false);
+      }
+    }
+
+
+
+    void Initialize()
+    {
+        win = NUIApplication.GetDefaultWindow();
+
+             List<Window.WindowOrientation> list = new List<Window.WindowOrientation>();
+        list.Add(Window.WindowOrientation.Landscape);
+        list.Add(Window.WindowOrientation.LandscapeInverse);
+        list.Add(Window.WindowOrientation.NoOrientationPreference);
+        list.Add(Window.WindowOrientation.Portrait);
+        list.Add(Window.WindowOrientation.PortraitInverse);
+        win.SetAvailableOrientations(list);
+
+        var root = new ImageView()
+        {
+          WidthResizePolicy = ResizePolicyType.FillToParent,
+          HeightResizePolicy = ResizePolicyType.FillToParent,
+          ResourceUrl = imagePath + "gallery-large-14.jpg",
+          Layout = new LinearLayout()
+          {
+              LinearAlignment = LinearLayout.Alignment.CenterHorizontal,
+              LinearOrientation = LinearLayout.Orientation.Horizontal,
+              CellPadding = new Size(10, 10),
+          }
+
+
+        };
+        win.Add(root);
+
+        var imageViewA = new ImageView()
+        {
+          PositionUsesPivotPoint = true,
+          PivotPoint = PivotPoint.BottomLeft,
+          ParentOrigin = ParentOrigin.BottomLeft,
+          Size = new Size(150, 150),
+          ResourceUrl = imagePath + "gallery-large-9.jpg",
+          CornerRadius = 0.3f,
+          CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+        };
+        root.Add(imageViewA);
+        imageViewA.TouchEvent += (s, e) =>
+        {
+          if (e.Touch.GetState(0) == PointStateType.Up)
+          {
+            CreateSubWindowOne();
+          }
+          return true;
+        };
+
+        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) =>
+        {
+          if (e.Touch.GetState(0) == PointStateType.Up)
+          {
+            CreateSubWindowTwo();
+          }
+          return true;
+        };
+    }
+
+    public void Activate()
+    {
+      Initialize();
+    }
+
+    public void Deactivate()
+    {
+    }
+
+
+  }
+}