Pārlūkot izejas kodu

Merge pull request #1495 from Sorien/master

Fix Window Size Constraints
Steven Kirk 7 gadi atpakaļ
vecāks
revīzija
d79b74055a

+ 5 - 1
src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs

@@ -36,7 +36,11 @@ namespace Avalonia.Android.Platform.SkiaPlatform
             _clientSize = value;
             UpdateParams();
         }
-        
+
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+        }
+
         public IScreenImpl Screen { get; }
 
         public Point Position

+ 8 - 2
src/Avalonia.Controls/Platform/IWindowBaseImpl.cs

@@ -55,7 +55,7 @@ namespace Avalonia.Platform
         /// Gets the platform window handle.
         /// </summary>
         IPlatformHandle Handle { get; }
-        
+       
         /// <summary>
         /// Gets the maximum size of a window on the system.
         /// </summary>
@@ -65,7 +65,13 @@ namespace Avalonia.Platform
         /// Sets the client size of the toplevel.
         /// </summary>
         void Resize(Size clientSize);
-        
+
+        /// <summary>
+        /// Minimum width of the window.
+        /// </summary>
+        /// 
+        void SetMinMaxSize(Size minSize, Size maxSize);
+
         /// <summary>
         /// Gets platform specific display information
         /// </summary>

+ 5 - 0
src/Avalonia.Controls/WindowBase.cs

@@ -47,6 +47,11 @@ namespace Avalonia.Controls
         {
             IsVisibleProperty.OverrideDefaultValue<WindowBase>(false);
             IsVisibleProperty.Changed.AddClassHandler<WindowBase>(x => x.IsVisibleChanged);
+
+            MinWidthProperty.Changed.AddClassHandler<WindowBase>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size((double)e.NewValue, w.MinHeight), new Size(w.MaxWidth, w.MaxHeight)));
+            MinHeightProperty.Changed.AddClassHandler<WindowBase>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight)));
+            MaxWidthProperty.Changed.AddClassHandler<WindowBase>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size((double)e.NewValue, w.MaxHeight)));
+            MaxHeightProperty.Changed.AddClassHandler<WindowBase>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size(w.MaxWidth, (double)e.NewValue)));
         }
 
         public WindowBase(IWindowBaseImpl impl) : this(impl, AvaloniaLocator.Current)

+ 4 - 0
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@@ -67,6 +67,10 @@ namespace Avalonia.DesignerSupport.Remote
             RenderIfNeeded();
         }
 
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+        }
+
         public IScreenImpl Screen { get; } = new ScreenStub();
 
         public void Activate()

+ 4 - 0
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@@ -78,6 +78,10 @@ namespace Avalonia.DesignerSupport.Remote
 
         public IScreenImpl Screen { get; } = new ScreenStub();
 
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+        }
+
         public void SetTitle(string title)
         {
         }

+ 15 - 13
src/Gtk/Avalonia.Gtk3/Interop/Native.cs

@@ -265,7 +265,7 @@ namespace Avalonia.Gtk3.Interop
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
             public delegate void gtk_window_close(GtkWindow window);
 
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
+            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
             public delegate void gtk_window_set_geometry_hints(GtkWindow window, IntPtr geometry_widget, ref GdkGeometry geometry, GdkWindowHints geom_mask);
 
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
@@ -424,6 +424,7 @@ namespace Avalonia.Gtk3.Interop
         public static D.gdk_window_set_override_redirect GdkWindowSetOverrideRedirect;
         public static D.gtk_widget_set_size_request GtkWindowSetSizeRequest;
         public static D.gtk_window_set_default_size GtkWindowSetDefaultSize;
+        public static D.gtk_window_set_geometry_hints GtkWindowSetGeometryHints;
         public static D.gtk_window_get_position GtkWindowGetPosition;
         public static D.gtk_window_move GtkWindowMove;
         public static D.gtk_file_chooser_dialog_new GtkFileChooserDialogNew;
@@ -505,6 +506,7 @@ namespace Avalonia.Gtk3.Interop
         public static D.cairo_set_font_size CairoSetFontSize;
         public static D.cairo_move_to CairoMoveTo;
         public static D.cairo_destroy CairoDestroy;
+
         public const int G_TYPE_OBJECT = 80;
     }
 
@@ -742,19 +744,19 @@ namespace Avalonia.Gtk3.Interop
     }
 
     [StructLayout(LayoutKind.Sequential)]
-    struct GdkGeometry
+    public struct GdkGeometry
     {
-        gint min_width;
-        gint min_height;
-        gint max_width;
-        gint max_height;
-        gint base_width;
-        gint base_height;
-        gint width_inc;
-        gint height_inc;
-        gdouble min_aspect;
-        gdouble max_aspect;
-        gint win_gravity;
+        public gint min_width;
+        public gint min_height;
+        public gint max_width;
+        public gint max_height;
+        public gint base_width;
+        public gint base_height;
+        public gint width_inc;
+        public gint height_inc;
+        public gdouble min_aspect;
+        public gdouble max_aspect;
+        public gint win_gravity;
     }
 
     enum GdkWindowHints

+ 15 - 0
src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs

@@ -341,6 +341,20 @@ namespace Avalonia.Gtk3
             }
         }
 
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+            if (GtkWidget.IsClosed)
+                return;
+
+            GdkGeometry geometry = new GdkGeometry();
+            geometry.min_width = minSize.Width > 0 ? (int)minSize.Width : -1;
+            geometry.min_height = minSize.Height > 0 ? (int)minSize.Height : -1;
+            geometry.max_width = !Double.IsInfinity(maxSize.Width) && maxSize.Width > 0 ? (int)maxSize.Width : 999999;
+            geometry.max_height = !Double.IsInfinity(maxSize.Height) && maxSize.Height > 0 ? (int)maxSize.Height : 999999;
+
+            Native.GtkWindowSetGeometryHints(GtkWidget, IntPtr.Zero, ref geometry, GdkWindowHints.GDK_HINT_MIN_SIZE | GdkWindowHints.GDK_HINT_MAX_SIZE);
+        } 
+
         public IMouseDevice MouseDevice => Gtk3Platform.Mouse;
 
         public double Scaling => LastKnownScaleFactor = (int) (Native.GtkWidgetGetScaleFactor?.Invoke(GtkWidget) ?? 1);
@@ -431,6 +445,7 @@ namespace Avalonia.Gtk3
         {
             if (GtkWidget.IsClosed)
                 return;
+         
             Native.GtkWindowResize(GtkWidget, (int)value.Width, (int)value.Height);
             if (OverrideRedirect)
             {

+ 4 - 0
src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs

@@ -161,6 +161,10 @@ namespace Avalonia.MonoMac
             Position = pos;
         }
 
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+        }
+
         public IScreenImpl Screen
         {
             get;

+ 10 - 0
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@@ -626,6 +626,16 @@ namespace Avalonia.Win32.Interop
             public uint[] cols;
         }
 
+        [StructLayout(LayoutKind.Sequential)]
+        public struct MINMAXINFO
+        {
+            public POINT ptReserved;
+            public POINT ptMaxSize;
+            public POINT ptMaxPosition;
+            public POINT ptMinTrackSize;
+            public POINT ptMaxTrackSize;
+        }
+
         public const int SizeOf_BITMAPINFOHEADER = 40;
 
         [DllImport("user32.dll")]

+ 29 - 1
src/Windows/Avalonia.Win32/WindowImpl.cs

@@ -36,6 +36,9 @@ namespace Avalonia.Win32
         private WindowState _showWindowState;
         private FramebufferManager _framebuffer;
         private OleDropTarget _dropTarget;
+        private Size _minSize;
+        private Size _maxSize;
+
 #if USE_MANAGED_DRAG
         private readonly ManagedWindowResizeDragHelper _managedDrag;
 #endif
@@ -103,6 +106,12 @@ namespace Avalonia.Win32
             }
         }
 
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+            _minSize = minSize;
+            _maxSize = maxSize;
+        }
+
         public IScreenImpl Screen
         {
             get;
@@ -618,7 +627,26 @@ namespace Avalonia.Win32
                 case UnmanagedMethods.WindowsMessage.WM_MOVE:
                     PositionChanged?.Invoke(new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)));
                     return IntPtr.Zero;
-                    
+
+                case UnmanagedMethods.WindowsMessage.WM_GETMINMAXINFO:
+
+                    MINMAXINFO mmi = Marshal.PtrToStructure<UnmanagedMethods.MINMAXINFO>(lParam);
+
+                    if  (_minSize.Width > 0)
+                        mmi.ptMinTrackSize.X = (int)((_minSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right);
+
+                    if (_minSize.Height > 0)
+                        mmi.ptMinTrackSize.Y = (int)((_minSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom);
+
+                    if (!Double.IsInfinity(_maxSize.Width) && _maxSize.Width > 0)
+                        mmi.ptMaxTrackSize.X = (int)((_maxSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right);
+
+                    if (!Double.IsInfinity(_maxSize.Height) && _maxSize.Height > 0)
+                        mmi.ptMaxTrackSize.Y = (int)((_maxSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom);
+
+                    Marshal.StructureToPtr(mmi, lParam, true);
+                    return IntPtr.Zero;
+
                 case UnmanagedMethods.WindowsMessage.WM_DISPLAYCHANGE:
                     (Screen as ScreenImpl)?.InvalidateScreensCache();
                     return IntPtr.Zero;

+ 4 - 0
src/iOS/Avalonia.iOS/EmbeddableImpl.cs

@@ -14,6 +14,10 @@ namespace Avalonia.iOS
             
         }
 
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+        }
+
         public IDisposable ShowDialog()
         {
             return Disposable.Empty;