using System.Windows.Input; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Input; namespace ClaudeDo.Ui.Views.Controls; /// Reusable modal chrome: titlebar (drag + close) wrapping a body and optional footer. public class ModalShell : ContentControl { public static readonly StyledProperty TitleProperty = AvaloniaProperty.Register(nameof(Title)); public static readonly StyledProperty FooterProperty = AvaloniaProperty.Register(nameof(Footer)); public static readonly StyledProperty CloseCommandProperty = AvaloniaProperty.Register(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("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); } }