diff --git a/App/Controls/SizedFrame.cs b/App/Controls/SizedFrame.cs
new file mode 100644
index 0000000..a666c55
--- /dev/null
+++ b/App/Controls/SizedFrame.cs
@@ -0,0 +1,68 @@
+using System;
+using Windows.Foundation;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace Coder.Desktop.App.Controls;
+
+public class SizedFrameEventArgs : EventArgs
+{
+ public Size NewSize { get; init; }
+}
+
+///
+/// SizedFrame extends Frame by adding a SizeChanged event, which will be triggered when:
+/// - The contained Page's content's size changes
+/// - We switch to a different page.
+///
+/// Sadly this is necessary because Window.Content.SizeChanged doesn't trigger when the Page's content changes.
+///
+public class SizedFrame : Frame
+{
+ public delegate void SizeChangeDelegate(object sender, SizedFrameEventArgs e);
+
+ public new event SizeChangeDelegate? SizeChanged;
+
+ private Size _lastSize;
+
+ public void SetPage(Page page)
+ {
+ if (ReferenceEquals(page, Content)) return;
+
+ // Set the new event listener.
+ if (page.Content is not FrameworkElement newElement)
+ throw new Exception("Failed to get Page.Content as FrameworkElement on SizedFrame navigation");
+ newElement.SizeChanged += Content_SizeChanged;
+
+ // Unset the previous event listener.
+ if (Content is Page { Content: FrameworkElement oldElement })
+ oldElement.SizeChanged -= Content_SizeChanged;
+
+ // We don't use RootFrame.Navigate here because it doesn't let you
+ // instantiate the page yourself. We also don't need forwards/backwards
+ // capabilities.
+ Content = page;
+
+ // Fire an event.
+ Content_SizeChanged(newElement, null);
+ }
+
+ public Size GetContentSize()
+ {
+ if (Content is not Page { Content: FrameworkElement frameworkElement })
+ throw new Exception("Failed to get Content as FrameworkElement for SizedFrame");
+
+ frameworkElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
+ return new Size(frameworkElement.ActualWidth, frameworkElement.ActualHeight);
+ }
+
+ private void Content_SizeChanged(object sender, SizeChangedEventArgs? _)
+ {
+ var size = GetContentSize();
+ if (size == _lastSize) return;
+ _lastSize = size;
+
+ var args = new SizedFrameEventArgs { NewSize = size };
+ SizeChanged?.Invoke(this, args);
+ }
+}
diff --git a/App/Views/SignInWindow.xaml b/App/Views/SignInWindow.xaml
index 299c0c1..d2c1326 100644
--- a/App/Views/SignInWindow.xaml
+++ b/App/Views/SignInWindow.xaml
@@ -4,6 +4,7 @@
x:Class="Coder.Desktop.App.Views.SignInWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:controls="using:Coder.Desktop.App.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
@@ -13,5 +14,5 @@
-
+
diff --git a/App/Views/SignInWindow.xaml.cs b/App/Views/SignInWindow.xaml.cs
index 771dda0..3fe4b5c 100644
--- a/App/Views/SignInWindow.xaml.cs
+++ b/App/Views/SignInWindow.xaml.cs
@@ -1,18 +1,20 @@
+using System;
using Windows.Graphics;
+using Coder.Desktop.App.Controls;
using Coder.Desktop.App.ViewModels;
using Coder.Desktop.App.Views.Pages;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Media;
namespace Coder.Desktop.App.Views;
///
-/// The dialog window to allow the user to sign into their Coder server.
+/// The dialog window to allow the user to sign in to their Coder server.
///
public sealed partial class SignInWindow : Window
{
- private const double WIDTH = 600.0;
- private const double HEIGHT = 300.0;
+ private const double WIDTH = 500.0;
private readonly SignInUrlPage _signInUrlPage;
private readonly SignInTokenPage _signInTokenPage;
@@ -20,9 +22,18 @@ public sealed partial class SignInWindow : Window
public SignInWindow(SignInViewModel viewModel)
{
InitializeComponent();
+ SystemBackdrop = new DesktopAcrylicBackdrop();
+ RootFrame.SizeChanged += RootFrame_SizeChanged;
+
_signInUrlPage = new SignInUrlPage(this, viewModel);
_signInTokenPage = new SignInTokenPage(this, viewModel);
+ // Prevent the window from being resized.
+ if (AppWindow.Presenter is not OverlappedPresenter presenter)
+ throw new Exception("Failed to get OverlappedPresenter for window");
+ presenter.IsMaximizable = false;
+ presenter.IsResizable = false;
+
NavigateToUrlPage();
ResizeWindow();
MoveWindowToCenterOfDisplay();
@@ -30,20 +41,32 @@ public SignInWindow(SignInViewModel viewModel)
public void NavigateToTokenPage()
{
- RootFrame.Content = _signInTokenPage;
+ RootFrame.SetPage(_signInTokenPage);
}
public void NavigateToUrlPage()
{
- RootFrame.Content = _signInUrlPage;
+ RootFrame.SetPage(_signInUrlPage);
+ }
+
+ private void RootFrame_SizeChanged(object sender, SizedFrameEventArgs e)
+ {
+ ResizeWindow(e.NewSize.Height);
}
private void ResizeWindow()
{
+ ResizeWindow(RootFrame.GetContentSize().Height);
+ }
+
+ private void ResizeWindow(double height)
+ {
+ if (height <= 0) height = 100; // will be resolved next frame typically
+
var scale = DisplayScale.WindowScale(this);
- var height = (int)(HEIGHT * scale);
- var width = (int)(WIDTH * scale);
- AppWindow.Resize(new SizeInt32(width, height));
+ var newWidth = (int)(WIDTH * scale);
+ var newHeight = (int)(height * scale);
+ AppWindow.ResizeClient(new SizeInt32(newWidth, newHeight));
}
private void MoveWindowToCenterOfDisplay()
diff --git a/App/Views/TrayWindow.xaml b/App/Views/TrayWindow.xaml
index c9aa24b..0d87874 100644
--- a/App/Views/TrayWindow.xaml
+++ b/App/Views/TrayWindow.xaml
@@ -19,6 +19,6 @@
-
+
diff --git a/App/Views/TrayWindow.xaml.cs b/App/Views/TrayWindow.xaml.cs
index 7fd1482..2df9693 100644
--- a/App/Views/TrayWindow.xaml.cs
+++ b/App/Views/TrayWindow.xaml.cs
@@ -1,9 +1,9 @@
using System;
using System.Runtime.InteropServices;
-using Windows.Foundation;
using Windows.Graphics;
using Windows.System;
using Windows.UI.Core;
+using Coder.Desktop.App.Controls;
using Coder.Desktop.App.Models;
using Coder.Desktop.App.Services;
using Coder.Desktop.App.Views.Pages;
@@ -48,6 +48,7 @@ public TrayWindow(IRpcController rpcController, ICredentialManager credentialMan
AppWindow.Hide();
SystemBackdrop = new DesktopAcrylicBackdrop();
Activated += Window_Activated;
+ RootFrame.SizeChanged += RootFrame_SizeChanged;
rpcController.StateChanged += RpcController_StateChanged;
credentialManager.CredentialsChanged += CredentialManager_CredentialsChanged;
@@ -120,55 +121,31 @@ public void SetRootFrame(Page page)
return;
}
- if (ReferenceEquals(page, RootFrame.Content)) return;
-
- if (page.Content is not FrameworkElement newElement)
- throw new Exception("Failed to get Page.Content as FrameworkElement on RootFrame navigation");
- newElement.SizeChanged += Content_SizeChanged;
-
- // Unset the previous event listener.
- if (RootFrame.Content is Page { Content: FrameworkElement oldElement })
- oldElement.SizeChanged -= Content_SizeChanged;
-
- // Swap them out and reconfigure the window.
- // We don't use RootFrame.Navigate here because it doesn't let you
- // instantiate the page yourself. We also don't need forwards/backwards
- // capabilities.
- RootFrame.Content = page;
- ResizeWindow();
- MoveWindow();
+ RootFrame.SetPage(page);
}
- private void Content_SizeChanged(object sender, SizeChangedEventArgs e)
+ private void RootFrame_SizeChanged(object sender, SizedFrameEventArgs e)
{
- ResizeWindow();
+ ResizeWindow(e.NewSize.Height);
MoveWindow();
}
private void ResizeWindow()
{
- if (RootFrame.Content is not Page { Content: FrameworkElement frameworkElement })
- throw new Exception("Failed to get Content as FrameworkElement for window");
-
- // Measure the desired size of the content
- frameworkElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
-
- // Adjust the AppWindow size
- var scale = GetDisplayScale();
- var height = (int)(frameworkElement.ActualHeight * scale);
- var width = (int)(WIDTH * scale);
- AppWindow.Resize(new SizeInt32(width, height));
+ ResizeWindow(RootFrame.GetContentSize().Height);
}
- private double GetDisplayScale()
+ private void ResizeWindow(double height)
{
- var hwnd = WindowNative.GetWindowHandle(this);
- var dpi = NativeApi.GetDpiForWindow(hwnd);
- if (dpi == 0) return 1; // assume scale of 1
- return dpi / 96.0; // 96 DPI == 1
+ if (height <= 0) height = 100; // will be resolved next frame typically
+
+ var scale = DisplayScale.WindowScale(this);
+ var newWidth = (int)(WIDTH * scale);
+ var newHeight = (int)(height * scale);
+ AppWindow.Resize(new SizeInt32(newWidth, newHeight));
}
- public void MoveResizeAndActivate()
+ private void MoveResizeAndActivate()
{
SaveCursorPos();
ResizeWindow();
@@ -268,9 +245,6 @@ public static class NativeApi
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hwnd);
- [DllImport("user32.dll")]
- public static extern int GetDpiForWindow(IntPtr hwnd);
-
public struct POINT
{
public int X;