Browse Source

[MONOMAC] Implemented maximize/unmaximize for borderless windows

Nikita Tsukanov 8 years ago
parent
commit
c954a86607

+ 6 - 0
samples/ControlCatalog/ControlCatalog.csproj

@@ -32,6 +32,9 @@
     <EmbeddedResource Include="MainView.xaml">
       <SubType>Designer</SubType>
     </EmbeddedResource>
+    <EmbeddedResource Include="DecoratedWindow.xaml">
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
     <EmbeddedResource Include="Pages\DialogsPage.xaml">
       <SubType>Designer</SubType>
     </EmbeddedResource>
@@ -86,6 +89,9 @@
     <Compile Include="MainView.xaml.cs">
       <DependentUpon>MainView.xaml</DependentUpon>
     </Compile>
+    <Compile Include="DecoratedWindow.xaml.cs">
+      <DependentUpon>DecoratedWindow.xaml</DependentUpon>
+    </Compile>
     <Compile Include="MainWindow.xaml.cs">
       <DependentUpon>MainWindow.xaml</DependentUpon>
     </Compile>

+ 33 - 0
samples/ControlCatalog/DecoratedWindow.xaml

@@ -0,0 +1,33 @@
+<Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300"
+        Title="Avalonia Control Gallery"
+        Icon="resm:ControlCatalog.Assets.test_icon.ico?assembly=ControlCatalog"
+        xmlns:local="clr-namespace:ControlCatalog;assembly=ControlCatalog" HasSystemDecorations="False">
+    <Grid RowDefinitions="5,*,5" ColumnDefinitions="5,*,5">
+        <DockPanel  Grid.Column="1"  Grid.Row="1" >
+            <Grid Name="TitleBar" Background="LightBlue" DockPanel.Dock="Top" ColumnDefinitions="Auto,*,Auto">
+                <TextBlock VerticalAlignment="Center" Margin="5,0,0,0">Title</TextBlock>
+                <StackPanel Grid.Column="2" Orientation="Horizontal">
+                    <StackPanel.Styles>
+                        <Style Selector="Button">
+                            <Setter Property="Margin" Value="2"/>
+                        </Style>
+                    </StackPanel.Styles>
+                    <Button Name="MinimizeButton">_</Button>
+                    <Button Name="MaximizeButton">[ ]</Button>
+                    <Button Name="CloseButton">X</Button>
+                </StackPanel>
+            </Grid>
+            <Border Background="White" Margin="5">
+                <TextBlock>Hello world!</TextBlock>
+            </Border>
+        </DockPanel>
+        <Border Name="TopLeft" Background="Red"/>
+        <Border Name="TopRight" Background="Red" Grid.Column="2" />
+        <Border Name="BottomLeft" Background="Red" Grid.Row="2" />
+        <Border Name="BottomRight" Background="Red"  Grid.Row="2" Grid.Column="2"/>
+        <Border Name="Top" Background="Blue" Grid.Column="1" />
+        <Border Name="Right" Background="Blue" Grid.Row="1"  Grid.Column="2" />
+        <Border Name="Bottom" Background="Blue" Grid.Row="2" Grid.Column="1"  />
+        <Border Name="Left" Background="Blue"  Grid.Row="1" />
+    </Grid>
+</Window>

+ 53 - 0
samples/ControlCatalog/DecoratedWindow.xaml.cs

@@ -0,0 +1,53 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using System;
+using Avalonia.Input;
+
+namespace ControlCatalog
+{
+    public class DecoratedWindow : Window
+    {
+        public DecoratedWindow()
+        {
+            this.InitializeComponent();
+            this.AttachDevTools();
+        }
+
+        void SetupSide(string name, StandardCursorType cursor, WindowEdge edge)
+        {
+            var ctl = this.FindControl<Control>(name);
+            ctl.Cursor = new Cursor(cursor);
+            ctl.PointerPressed += delegate
+            {
+                PlatformImpl.BeginResizeDrag(edge);
+            };
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+            this.FindControl<Control>("TitleBar").PointerPressed += delegate
+            {
+                PlatformImpl.BeginMoveDrag();
+            };
+            SetupSide("Left", StandardCursorType.LeftSide, WindowEdge.West);
+            SetupSide("Right", StandardCursorType.RightSide, WindowEdge.East);
+            SetupSide("Top", StandardCursorType.TopSide, WindowEdge.South);
+            SetupSide("Bottom", StandardCursorType.BottomSize, WindowEdge.North);
+            SetupSide("TopLeft", StandardCursorType.TopLeftCorner, WindowEdge.NorthWest);
+            SetupSide("TopRight", StandardCursorType.TopRightCorner, WindowEdge.NorthEast);
+            SetupSide("BottomLeft", StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest);
+            SetupSide("BottomRight", StandardCursorType.BottomRightCorner, WindowEdge.SouthEast);
+            this.FindControl<Button>("MinimizeButton").Click += delegate { this.WindowState = WindowState.Minimized; };
+            this.FindControl<Button>("MaximizeButton").Click += delegate
+            {
+                WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
+            };
+            this.FindControl<Button>("CloseButton").Click += delegate
+            {
+                Close();
+            };
+        }
+    }
+}

+ 1 - 1
samples/ControlCatalog/MainView.xaml.cs

@@ -15,7 +15,7 @@ namespace ControlCatalog
             if (AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().IsDesktop)
                 ((IList) this.FindControl<TabControl>("Sidebar").Items).Add(new TabItem()
                 {
-                    Header = "System dialogs",
+                    Header = "Dialogs",
                     Content = new DialogsPage()
                 });
         }

+ 1 - 0
samples/ControlCatalog/Pages/DialogsPage.xaml

@@ -7,5 +7,6 @@
           <CheckBox Name="IsModal" IsChecked="True"/>
           <TextBlock>Modal to window</TextBlock>
       </StackPanel>
+      <Button Name="DecoratedWindow">Decorated window</Button>
   </StackPanel>
 </UserControl>

+ 4 - 0
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@@ -30,6 +30,10 @@ namespace ControlCatalog.Pages
                     Title = "Select folder"
                 }.ShowAsync(GetWindow());
             };
+            this.FindControl<Button>("DecoratedWindow").Click += delegate
+            {
+                new DecoratedWindow().Show();
+            };
         }
 
         Window GetWindow() => this.FindControl<CheckBox>("IsModal").IsChecked ? (Window)this.VisualRoot : null;

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

@@ -2,6 +2,7 @@
 using Avalonia.Controls;
 using Avalonia.Platform;
 using MonoMac.AppKit;
+using MonoMac.CoreGraphics;
 using MonoMac.ObjCRuntime;
 
 namespace Avalonia.MonoMac
@@ -42,6 +43,12 @@ namespace Avalonia.MonoMac
                 _impl.Deactivated?.Invoke();
                 base.ResignKeyWindow();
             }
+
+            private bool _canBecomeKeyAndMain;
+            public override bool CanBecomeKeyWindow => _canBecomeKeyAndMain;
+            public override bool CanBecomeMainWindow => _canBecomeKeyAndMain;
+
+            public void SetCanBecomeKeyAndMain() => _canBecomeKeyAndMain = true;
         }
 
         protected virtual NSWindowDelegate CreateWindowDelegate() => new WindowBaseDelegate(this);
@@ -49,6 +56,7 @@ namespace Avalonia.MonoMac
         public class WindowBaseDelegate : NSWindowDelegate
         {
             readonly WindowBaseImpl _impl;
+            private CGRect? _lastUnmaximizedFrame;
 
             public WindowBaseDelegate(WindowBaseImpl impl)
             {
@@ -66,6 +74,18 @@ namespace Avalonia.MonoMac
                 _impl.Window = null;
                 _impl.Dispose();
             }
+
+            public override CGRect WillUseStandardFrame(NSWindow window, CGRect newFrame)
+            {
+                if (_impl is WindowImpl w && w.UndecoratedIsMaximized && w.UndecoratedLastUnmaximizedFrame.HasValue)
+                    return w.UndecoratedLastUnmaximizedFrame.Value;
+                return window.Screen.VisibleFrame;
+            }
+
+            public override bool ShouldZoom(NSWindow window, CGRect newFrame)
+            {
+                return true;
+            }
         }
 
 

+ 28 - 8
src/OSX/Avalonia.MonoMac/WindowImpl.cs

@@ -2,16 +2,19 @@
 using Avalonia.Controls;
 using Avalonia.Platform;
 using MonoMac.AppKit;
+using MonoMac.CoreGraphics;
 
 namespace Avalonia.MonoMac
 {
     class WindowImpl : WindowBaseImpl, IWindowImpl
     {
-        bool _decorated = true;
+        public bool IsDecorated = true;
+        public CGRect? UndecoratedLastUnmaximizedFrame;
 
         public WindowImpl()
         {
             UpdateStyle();
+            Window.SetCanBecomeKeyAndMain();
         }
 
         public WindowState WindowState
@@ -20,8 +23,9 @@ namespace Avalonia.MonoMac
             {
                 if (Window.IsMiniaturized)
                     return WindowState.Minimized;
+                if (IsZoomed)
+                    return WindowState.Maximized;
                 return WindowState.Normal;
-
             }
             set
             {
@@ -29,8 +33,8 @@ namespace Avalonia.MonoMac
                 {
                     if (Window.IsMiniaturized)
                         Window.Deminiaturize(Window);
-                    if (!Window.IsZoomed)
-                        Window.PerformZoom(Window);
+                    if (!IsZoomed)
+                        DoZoom();
                 }
                 else if (value.HasFlag(WindowState.Minimized))
                     Window.Miniaturize(Window);
@@ -38,12 +42,28 @@ namespace Avalonia.MonoMac
                 {
                     if (Window.IsMiniaturized)
                         Window.Deminiaturize(Window);
-                    if (Window.IsZoomed)
-                        Window.IsZoomed = false;
+                    if (IsZoomed)
+                        DoZoom();
                 }
             }
         }
 
+        bool IsZoomed => IsDecorated ? Window.IsZoomed : UndecoratedIsMaximized;
+
+        public bool UndecoratedIsMaximized => Window.Frame == Window.Screen.VisibleFrame;
+
+        void DoZoom()
+        {
+            if (IsDecorated)
+                Window.PerformZoom(Window);
+            else
+            {
+                if (!UndecoratedIsMaximized)
+                    UndecoratedLastUnmaximizedFrame = Window.Frame;
+                Window.Zoom(Window);
+            }
+        }
+
         public void SetIcon(IWindowIconImpl icon)
         {
             //No-OP, see http://stackoverflow.com/a/7038671/2231814
@@ -56,7 +76,7 @@ namespace Avalonia.MonoMac
 
         protected override NSWindowStyle GetStyle()
         {
-            if (_decorated)
+            if (IsDecorated)
                 return NSWindowStyle.Closable | NSWindowStyle.Resizable | NSWindowStyle.Miniaturizable |
                        NSWindowStyle.Titled;
             return NSWindowStyle.Borderless;
@@ -64,7 +84,7 @@ namespace Avalonia.MonoMac
 
         public void SetSystemDecorations(bool enabled)
         {
-            _decorated = true;
+            IsDecorated = enabled;
             UpdateStyle();
         }