teamsiso/src/TeamsISO.App/MainWindow.xaml.cs
Zac Gaetano bab29b02ab
All checks were successful
CI / build-and-test (push) Successful in 37s
feat(ui): chromeless title bar with custom caption controls
MainWindow drops the standard Windows title bar (WindowStyle=None + WindowChrome with CaptionHeight=44, ResizeBorderThickness=6, UseAeroCaptionButtons=False) and draws its own minimize / maximize-restore / close buttons inline in the existing header strip. The custom buttons opt into shell:WindowChrome.IsHitTestVisibleInChrome=True so clicks fire on them rather than starting a window drag.

Result: the entire top of the window is now ours, matching the Microsoft Teams desktop client's flush header look. The 'TeamsISO + by Wild Dragon' branding sits at the same baseline as the engine-status pill and the caption controls, and dragging anywhere not occupied by an interactive widget moves the window.

Caption-button styles in the theme: 46x32 hover-tinted, with the close button turning the Windows 11 #C42B1C red on hover. Maximize-button glyph swaps between the single-rectangle and overlapping-rectangles variants on StateChanged.

Drive-by: ParticipantViewModel.{FramesIn,FramesOut,IncomingResolution} setters dropped from private to public so {Run Text=...} bindings (which default to TwoWay on Run) can attach without WPF throwing 'cannot work on read-only property'.
2026-05-08 00:55:57 -04:00

45 lines
1.7 KiB
C#

using System.Windows;
using System.Windows.Shapes;
using TeamsISO.App.ViewModels;
namespace TeamsISO.App;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
StateChanged += OnWindowStateChanged;
}
public MainWindow(MainViewModel viewModel) : this()
{
DataContext = viewModel;
}
/// <summary>Custom min button — chrome'd window has no system caption buttons.</summary>
private void OnMinimize(object sender, RoutedEventArgs e) =>
WindowState = WindowState.Minimized;
/// <summary>Toggles maximize/restore. Bound to the maximize button + double-click on the drag region.</summary>
private void OnMaximizeRestore(object sender, RoutedEventArgs e) =>
WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
/// <summary>Custom close button.</summary>
private void OnClose(object sender, RoutedEventArgs e) => Close();
/// <summary>
/// Swap the maximize-button glyph between the "single rectangle" (when normal) and the
/// "two-overlapping-rectangles" (when maximized) variants, matching the Windows 11
/// caption-button conventions.
/// </summary>
private void OnWindowStateChanged(object? sender, EventArgs e)
{
if (FindName("MaximizeIcon") is not Path icon) return;
icon.Data = WindowState == WindowState.Maximized
// Two-rectangle "restore" glyph
? System.Windows.Media.Geometry.Parse("M 2,0 L 10,0 L 10,8 M 0,2 L 8,2 L 8,10 L 0,10 Z")
// Single-rectangle "maximize" glyph
: System.Windows.Media.Geometry.Parse("M 0,0 L 10,0 L 10,10 L 0,10 Z");
}
}