2 * Copyright(c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 extern alias TizenSystemInformation;
18 using TizenSystemInformation.Tizen.System;
21 using System.Collections.Generic;
22 using System.ComponentModel;
24 using System.Threading;
25 using Tizen.NUI.BaseComponents;
29 public partial class Window
31 #region Constant Fields
32 #endregion //Constant Fields
35 private IBorderInterface borderInterface = null;
36 private Layer borderWindowRootLayer = null;
37 private Layer borderWindowBottomLayer = null;
38 private bool isBorderWindow = false;
41 private View rootView = null;
42 private BorderView borderView = null;
43 private View topView = null;
44 private View contentsView = null;
45 private View bottomView = null;
46 private bool isTop = false;
47 private bool isBottom = false;
48 private float borderHeight = 0;
49 private int screenWidth = 0;
50 private int screenHeight = 0;
54 #endregion //Constructors
57 #endregion //Distructors
60 internal delegate void BorderCloseDelegate();
61 private BorderCloseDelegate borderCloseDelegate = null;
63 #endregion //Delegates
70 /// This is an enum for the resize direction or move value when the border area is touched.
72 [EditorBrowsable(EditorBrowsableState.Never)]
73 public enum BorderDirection
75 None = ResizeDirection.None,
76 TopLeft = ResizeDirection.TopLeft,
77 Top = ResizeDirection.Top,
78 TopRight = ResizeDirection.TopRight,
79 Left = ResizeDirection.Left,
80 Right = ResizeDirection.Right,
81 BottomLeft = ResizeDirection.BottomLeft,
82 Bottom = ResizeDirection.Bottom,
83 BottomRight = ResizeDirection.BottomRight,
88 /// This enum is the policy when resizing the border window.
90 [EditorBrowsable(EditorBrowsableState.Never)]
91 public enum BorderResizePolicyType
94 /// The window can be resized freely.
98 /// The window is resized according to the ratio.
102 /// The window is not resized and is fixed.
109 #endregion //Interfaces
113 /// Whether the border is enabled.
115 [EditorBrowsable(EditorBrowsableState.Never)]
116 public bool IsBorderEnabled => isBorderWindow;
117 #endregion //Properties
120 #endregion //Indexers
124 /// Called when the border is closed.
125 /// If the delegate is declared, the delegate is called, otherwise window is destroyed.
127 internal void BorderDestroy()
129 if (borderCloseDelegate != null)
131 borderCloseDelegate();
139 /// Enable the border window with IBorderInterface.
140 /// This adds a border area to the Window.
141 /// The border's UI is configured using IBorderInterface.
142 /// Users can reisze and move by touching the border area.
144 /// <param name="borderInterface">The IBorderInterface.</param>
145 /// <param name="borderCloseDelegate">The BorderCloseDelegate. When close, this delegate is called.</param>
146 /// <returns>Whether the border window is enabled</returns>
147 internal bool EnableBorder(IBorderInterface borderInterface, BorderCloseDelegate borderCloseDelegate = null)
149 if (isBorderWindow == true)
151 Tizen.Log.Error("NUI", $"Already EnableBorderWindow\n");
157 Information.TryGetValue<int>("http://tizen.org/feature/screen.width", out screenWidth);
158 Information.TryGetValue<int>("http://tizen.org/feature/screen.height", out screenHeight);
160 catch (DllNotFoundException e)
162 Tizen.Log.Fatal("NUI", $"{e}\n");
165 if (borderInterface == null)
167 borderInterface = new DefaultBorder();
169 this.borderInterface = borderInterface;
170 this.borderCloseDelegate = borderCloseDelegate;
172 GetDefaultLayer().Name = "OriginalRootLayer";
174 SetTransparency(true);
175 BackgroundColor = Color.Transparent;
176 borderInterface.BorderWindow = this;
178 if (CreateBorder() == true)
180 using var realWindowSize = new Size2D(WindowSize.Width, WindowSize.Height);
182 isBorderWindow = true;
184 Resized += OnBorderWindowResized;
186 borderInterface.OnCreated(borderView);
188 // Increase the window size as much as the border area.
190 if (isTop) borderHeight += topView.SizeHeight;
191 if (isBottom) borderHeight += bottomView.SizeHeight;
193 // Sets the minimum / maximum size to be resized by RequestResizeToServer.
194 if (borderInterface.MinSize != null)
196 using Size2D mimimumSize = new Size2D(borderInterface.MinSize.Width, borderInterface.MinSize.Height + (int)borderHeight);
197 SetMimimumSize(mimimumSize);
199 if (borderInterface.MaxSize != null)
201 using Size2D maximuSize = new Size2D(borderInterface.MaxSize.Width, borderInterface.MaxSize.Height + (int)borderHeight);
202 SetMaximumSize(maximuSize);
205 // When running the app for the first time, if it runs in full size, do Maximize(true).
206 if (screenWidth != 0 && screenHeight != 0 &&
207 realWindowSize.Width >= screenWidth && realWindowSize.Height >= screenHeight &&
208 IsMaximized() == false)
211 borderInterface.OnMaximize(true);
212 ResizedEventArgs e = new ResizedEventArgs();
213 e.WindowSize = WindowSize;
214 OnBorderWindowResized(this, e);
218 WindowSize += new Size2D((int)borderInterface.BorderLineThickness * 2, (int)(borderHeight + borderInterface.BorderLineThickness * 2));
221 // If it is BorderResizePolicyType.KeepRatio type, it will be resized according to the ratio.
222 if (borderInterface.ResizePolicy == BorderResizePolicyType.KeepRatio)
224 AddAuxiliaryHint("wm.policy.win.resize_aspect_ratio", "1");
227 // Add a view to the border layer.
228 GetBorderWindowBottomLayer().Add(rootView);
230 FocusChanged += OnWindowFocusChanged;
236 this.borderInterface.Dispose();
241 private void OnWindowFocusChanged(object sender, Window.FocusChangedEventArgs e)
243 if (e.FocusGained == true && IsMaximized() == false)
245 // Raises the window when the window is focused.
250 /// Create the border UI.
251 private bool CreateBorder()
253 rootView = new View()
255 WidthResizePolicy = ResizePolicyType.FillToParent,
256 HeightResizePolicy = ResizePolicyType.FillToParent,
257 BackgroundColor = Color.Transparent,
260 ushort padding = (ushort) borderInterface.BorderLineThickness;
261 borderView = new BorderView()
263 GrabTouchAfterLeave = true,
264 WidthResizePolicy = ResizePolicyType.FillToParent,
265 HeightResizePolicy = ResizePolicyType.FillToParent,
266 BackgroundColor = Color.Transparent,
267 Layout = new LinearLayout() {
268 LinearOrientation = LinearLayout.Orientation.Vertical,
269 LinearAlignment = LinearLayout.Alignment.Top
271 Padding = new Extents(padding, padding, padding, padding),
273 borderInterface.CreateBorderView(borderView);
277 WidthSpecification = LayoutParamPolicies.MatchParent,
278 SizeHeight = borderInterface.BorderHeight,
279 BackgroundColor = Color.Transparent,
282 contentsView = new View()
284 BackgroundColor = Color.Transparent,
285 WidthSpecification = LayoutParamPolicies.MatchParent,
288 bottomView = new View()
290 WidthSpecification = LayoutParamPolicies.MatchParent,
291 SizeHeight = borderInterface.BorderHeight,
292 BackgroundColor = Color.Transparent,
295 // // Gets the Border's UI.
296 if (borderInterface.CreateTopBorderView(topView) == true && topView != null)
298 borderView.Add(topView);
301 borderView.Add(contentsView);
302 if (borderInterface.CreateBottomBorderView(bottomView) == true && bottomView != null)
304 borderView.Add(bottomView);
307 rootView.Add(borderView);
309 return isTop || isBottom;
313 /// Calculates which direction to resize or to move.
315 /// <param name="xPosition">The X position.</param>
316 /// <param name="yPosition">The Y position.</param>
317 /// <returns>The BorderDirection</returns>
318 [EditorBrowsable(EditorBrowsableState.Never)]
319 public BorderDirection GetDirection(float xPosition, float yPosition)
321 BorderDirection direction = BorderDirection.None;
323 // check bottom left corner
324 if (xPosition < borderInterface.TouchThickness && yPosition > WindowSize.Height + borderHeight - borderInterface.TouchThickness)
326 direction = BorderDirection.BottomLeft;
328 // check bottom right corner
329 else if (xPosition > WindowSize.Width + (float)(borderInterface.BorderLineThickness * 2) - borderInterface.TouchThickness && yPosition > WindowSize.Height + borderHeight - borderInterface.TouchThickness)
331 direction = BorderDirection.BottomRight;
333 // check top left corner
334 else if (xPosition < borderInterface.TouchThickness && yPosition < borderInterface.TouchThickness)
336 direction = BorderDirection.TopLeft;
338 // check top right corner
339 else if (xPosition > WindowSize.Width + (float)(borderInterface.BorderLineThickness * 2) - borderInterface.TouchThickness && yPosition < borderInterface.TouchThickness)
341 direction = BorderDirection.TopRight;
344 else if (xPosition < borderInterface.TouchThickness)
346 direction = BorderDirection.Left;
349 else if (xPosition > WindowSize.Width + (float)(borderInterface.BorderLineThickness * 2) - borderInterface.TouchThickness)
351 direction = BorderDirection.Right;
354 else if (yPosition > WindowSize.Height + borderHeight + borderInterface.BorderLineThickness - borderInterface.TouchThickness)
356 direction = BorderDirection.Bottom;
359 else if (yPosition < borderInterface.TouchThickness)
361 direction = BorderDirection.Top;
364 else if ((yPosition > WindowSize.Height) || (isTop == true && yPosition < topView.SizeHeight))
366 direction = BorderDirection.Move;
372 private void DoOverlayMode(bool enable)
374 if (borderInterface.OverlayMode == true)
376 borderInterface.OnOverlayMode(enable);
377 borderView?.OverlayMode(enable);
380 GetBorderWindowBottomLayer().RaiseToTop();
384 GetBorderWindowBottomLayer().LowerToBottom();
390 // Called when the window size has changed.
391 private void OnBorderWindowResized(object sender, Window.ResizedEventArgs e)
393 Tizen.Log.Info("NUI", $"OnBorderWindowResized {e.WindowSize.Width},{e.WindowSize.Height}\n");
394 int resizeWidth = e.WindowSize.Width;
395 int resizeHeight = e.WindowSize.Height;
397 borderInterface.OnResized(resizeWidth, resizeHeight);
399 // reset borderHeight
401 if (isTop) borderHeight += topView.SizeHeight;
402 if (isBottom) borderHeight += bottomView.SizeHeight;
404 if (borderInterface.OverlayMode == true && IsMaximized() == true)
406 Interop.ActorInternal.SetSize(GetBorderWindowRootLayer().SwigCPtr, resizeWidth, resizeHeight);
407 Interop.ActorInternal.SetSize(GetBorderWindowBottomLayer().SwigCPtr, resizeWidth, resizeHeight);
408 Interop.ActorInternal.SetPosition(GetBorderWindowRootLayer().SwigCPtr, 0, 0);
409 if (contentsView != null)
411 contentsView.SizeHeight = resizeHeight - borderHeight - (float)(borderInterface.BorderLineThickness * 2);
417 float height = (isTop == true) ? topView.SizeHeight : 0;
418 Interop.ActorInternal.SetSize(GetBorderWindowRootLayer().SwigCPtr, resizeWidth, resizeHeight);
419 Interop.ActorInternal.SetSize(GetBorderWindowBottomLayer().SwigCPtr, resizeWidth + (float)(borderInterface.BorderLineThickness * 2), resizeHeight + borderHeight + (float)(borderInterface.BorderLineThickness * 2));
420 Interop.ActorInternal.SetPosition(GetBorderWindowRootLayer().SwigCPtr, 0, height + borderInterface.BorderLineThickness);
421 if (contentsView != null)
423 contentsView.SizeHeight = resizeHeight;
425 DoOverlayMode(false);
428 if (NDalicPINVOKE.SWIGPendingException.Pending) { throw NDalicPINVOKE.SWIGPendingException.Retrieve(); }
431 internal Layer GetBorderWindowBottomLayer()
433 if (borderWindowBottomLayer == null)
435 borderWindowBottomLayer = new Layer();
436 borderWindowBottomLayer.Name = "BorderWindowBottomLayer";
437 using Vector3 topCentor = new Vector3(0.5f, 0.0f, 0.5f);
438 Interop.ActorInternal.SetParentOrigin(borderWindowBottomLayer.SwigCPtr, topCentor.SwigCPtr);
439 Interop.Actor.SetAnchorPoint(borderWindowBottomLayer.SwigCPtr, topCentor.SwigCPtr);
440 Interop.Actor.Add(rootLayer.SwigCPtr, borderWindowBottomLayer.SwigCPtr);
441 Interop.ActorInternal.SetSize(borderWindowBottomLayer.SwigCPtr, WindowSize.Width + (float)(borderInterface.BorderLineThickness * 2), WindowSize.Height + (float)(borderInterface.BorderLineThickness * 2));
442 borderWindowBottomLayer.SetWindow(this);
443 borderWindowBottomLayer.LowerToBottom();
445 if (NDalicPINVOKE.SWIGPendingException.Pending) { throw NDalicPINVOKE.SWIGPendingException.Retrieve(); }
447 return borderWindowBottomLayer;
450 internal Layer GetBorderWindowRootLayer()
452 if (borderWindowRootLayer == null)
454 borderWindowRootLayer = new Layer();
455 borderWindowRootLayer.Name = "RootLayer";
456 using Vector3 topCentor = new Vector3(0.5f, 0.0f, 0.5f);
457 Interop.ActorInternal.SetParentOrigin(borderWindowRootLayer.SwigCPtr, topCentor.SwigCPtr);
458 Interop.Actor.SetAnchorPoint(borderWindowRootLayer.SwigCPtr, topCentor.SwigCPtr);
459 Interop.Actor.Add(rootLayer.SwigCPtr, borderWindowRootLayer.SwigCPtr);
460 Interop.ActorInternal.SetSize(borderWindowRootLayer.SwigCPtr, WindowSize.Width, WindowSize.Height - borderHeight - borderInterface.BorderLineThickness * 2);
461 float height = (isTop == true) ? topView.SizeHeight : 0;
462 Interop.ActorInternal.SetPosition(borderWindowRootLayer.SwigCPtr, 0, height + borderInterface.BorderLineThickness);
463 using PropertyValue propertyValue = new Tizen.NUI.PropertyValue((int)Tizen.NUI.ClippingModeType.ClipToBoundingBox);
464 Tizen.NUI.Object.SetProperty(borderWindowRootLayer.SwigCPtr, Tizen.NUI.BaseComponents.View.Property.ClippingMode, propertyValue);
466 if (NDalicPINVOKE.SWIGPendingException.Pending) { throw NDalicPINVOKE.SWIGPendingException.Retrieve(); }
469 return borderWindowRootLayer;
472 internal void DisposeBorder()
474 Resized -= OnBorderWindowResized;
475 borderInterface.Dispose();
476 GetBorderWindowBottomLayer().Dispose();
479 private void convertBorderWindowSizeToRealWindowSize(Uint16Pair size)
481 if (isBorderWindow == true)
483 var height = (ushort)(size.GetHeight() + borderHeight + borderInterface.BorderLineThickness * 2);
484 var width = (ushort)(size.GetWidth() + borderInterface.BorderLineThickness * 2);
485 size.SetHeight(height);
486 size.SetWidth(width);
490 private void convertRealWindowSizeToBorderWindowSize(Uint16Pair size)
492 if (isBorderWindow == true && !(borderInterface.OverlayMode == true && IsMaximized() == true))
494 var height = (ushort)(size.GetHeight() - borderHeight - borderInterface.BorderLineThickness * 2);
495 var width = (ushort)(size.GetWidth() - borderInterface.BorderLineThickness * 2);
496 size.SetHeight(height);
497 size.SetWidth(width);
506 // View class for border view.
507 private class BorderView : View
509 private bool overlayEnabled = false;
512 /// Set whether or not it is in overlay mode.
513 /// The borderView's OverlayMode means that it is displayed at the top of the screen.
514 /// In this case, the borderView should pass the event so that lower layers can receive the event.
516 /// <param name="enabled">The true if borderView is Overlay mode. false otherwise.</param>
517 [EditorBrowsable(EditorBrowsableState.Never)]
518 public void OverlayMode(bool enabled)
520 overlayEnabled = enabled;
523 protected override bool HitTest(Touch touch)
525 // If borderView is in overlay mode, pass the hittest.
526 if (overlayEnabled == true)