- Drive modal title-bar dragging manually via pointer capture + Window.Position; Avalonia 12's BeginMoveDrag and VisualRoot-as-Window cast no longer work (VisualRoot is a TopLevelHost). Applies to ModalShell and WorktreeModalView. - Toggle the MainWindow maximize button between maximize/restore glyphs on WindowState changes (adds Icon.WinRestore geometry). - Add the ToggleButton.day-toggle style used by the Prime weekday picker row. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
71 lines
2.8 KiB
C#
71 lines
2.8 KiB
C#
using System.Windows.Input;
|
|
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Controls.Primitives;
|
|
using Avalonia.Input;
|
|
|
|
namespace ClaudeDo.Ui.Views.Controls;
|
|
|
|
/// <summary>Reusable modal chrome: titlebar (drag + close) wrapping a body and optional footer.</summary>
|
|
public class ModalShell : ContentControl
|
|
{
|
|
public static readonly StyledProperty<string?> TitleProperty =
|
|
AvaloniaProperty.Register<ModalShell, string?>(nameof(Title));
|
|
|
|
public static readonly StyledProperty<object?> FooterProperty =
|
|
AvaloniaProperty.Register<ModalShell, object?>(nameof(Footer));
|
|
|
|
public static readonly StyledProperty<ICommand?> CloseCommandProperty =
|
|
AvaloniaProperty.Register<ModalShell, ICommand?>(nameof(CloseCommand));
|
|
|
|
public string? Title { get => GetValue(TitleProperty); set => SetValue(TitleProperty, value); }
|
|
public object? Footer { get => GetValue(FooterProperty); set => SetValue(FooterProperty, value); }
|
|
public ICommand? CloseCommand { get => GetValue(CloseCommandProperty); set => SetValue(CloseCommandProperty, value); }
|
|
|
|
private Window? _window;
|
|
private PixelPoint _dragStartScreen;
|
|
private PixelPoint _dragStartPos;
|
|
private bool _dragging;
|
|
|
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
|
{
|
|
base.OnApplyTemplate(e);
|
|
if (e.NameScope.Find<Border>("PART_TitleBar") is { } bar)
|
|
{
|
|
bar.PointerPressed += OnTitleBarPressed;
|
|
bar.PointerMoved += OnTitleBarMoved;
|
|
bar.PointerReleased += OnTitleBarReleased;
|
|
}
|
|
}
|
|
|
|
// VisualRoot is a TopLevelHost (not the Window) in Avalonia 12, so resolve the
|
|
// owning Window via TopLevel.GetTopLevel and drive the move manually — BeginMoveDrag
|
|
// and a VisualRoot-as-Window cast both fail here.
|
|
private void OnTitleBarPressed(object? sender, PointerPressedEventArgs e)
|
|
{
|
|
if (!e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) return;
|
|
_window = TopLevel.GetTopLevel(this) as Window;
|
|
if (_window is null) return;
|
|
_dragStartScreen = _window.PointToScreen(e.GetPosition(_window));
|
|
_dragStartPos = _window.Position;
|
|
_dragging = true;
|
|
e.Pointer.Capture(sender as IInputElement);
|
|
}
|
|
|
|
private void OnTitleBarMoved(object? sender, PointerEventArgs e)
|
|
{
|
|
if (!_dragging || _window is null
|
|
|| !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) return;
|
|
var cur = _window.PointToScreen(e.GetPosition(_window));
|
|
_window.Position = new PixelPoint(
|
|
_dragStartPos.X + (cur.X - _dragStartScreen.X),
|
|
_dragStartPos.Y + (cur.Y - _dragStartScreen.Y));
|
|
}
|
|
|
|
private void OnTitleBarReleased(object? sender, PointerReleasedEventArgs e)
|
|
{
|
|
_dragging = false;
|
|
e.Pointer.Capture(null);
|
|
}
|
|
}
|