diff --git a/demo/Ursa.Demo/Dialogs/DialogWithAction.axaml b/demo/Ursa.Demo/Dialogs/DialogWithAction.axaml index 7ab2c67..4132581 100644 --- a/demo/Ursa.Demo/Dialogs/DialogWithAction.axaml +++ b/demo/Ursa.Demo/Dialogs/DialogWithAction.axaml @@ -5,6 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Ursa.Demo.Dialogs" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:u="https://irihi.tech/ursa" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" d:DesignHeight="450" @@ -30,6 +31,7 @@ HorizontalAlignment="Right" Orientation="Horizontal" Spacing="8"> + + + diff --git a/demo/Ursa.PrismDialogDemo/MainWindow.axaml.cs b/demo/Ursa.PrismDialogDemo/MainWindow.axaml.cs index ad95fd4..1b51033 100644 --- a/demo/Ursa.PrismDialogDemo/MainWindow.axaml.cs +++ b/demo/Ursa.PrismDialogDemo/MainWindow.axaml.cs @@ -7,15 +7,22 @@ namespace Ursa.PrismDialogDemo; public partial class MainWindow : Window { - private IUrsaOverlayDialogService _ursa; - public MainWindow(IUrsaOverlayDialogService ursa) + private IUrsaOverlayDialogService _dialogService; + private IUrsaDrawerService _drawerService; + public MainWindow(IUrsaOverlayDialogService dialogService, IUrsaDrawerService drawerService) { InitializeComponent(); - _ursa = ursa; + _dialogService = dialogService; + _drawerService = drawerService; } - private void Button_OnClick(object? sender, RoutedEventArgs e) + private void DialogButton_OnClick(object? sender, RoutedEventArgs e) { - _ursa.ShowModal("Default", null, null, null); + _dialogService.ShowModal("Default", null, null, null); + } + + private void DrawerButton_OnClick(object? sender, RoutedEventArgs e) + { + _drawerService.ShowModal("Default", null, null, null); } } \ No newline at end of file diff --git a/src/Ursa.PrismExtension/IUrsaDrawerService.cs b/src/Ursa.PrismExtension/IUrsaDrawerService.cs index 7d97bfc..77f7dc9 100644 --- a/src/Ursa.PrismExtension/IUrsaDrawerService.cs +++ b/src/Ursa.PrismExtension/IUrsaDrawerService.cs @@ -5,6 +5,8 @@ namespace Ursa.PrismExtension; public interface IUrsaDrawerService { - public Task ShowDrawer(string viewName, object? vm, string? hostId = null, DefaultDrawerOptions? options = null); - public Task ShowCustomDrawer(string viewName, object? vm, string? hostId = null, CustomDrawerOptions? options = null); + public void Show(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null); + public void ShowCustom(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null); + public Task ShowModal(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null); + public Task ShowCustomModal(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null); } \ No newline at end of file diff --git a/src/Ursa.PrismExtension/UrsaDrawerService.cs b/src/Ursa.PrismExtension/UrsaDrawerService.cs index 99b9a43..7cd7add 100644 --- a/src/Ursa.PrismExtension/UrsaDrawerService.cs +++ b/src/Ursa.PrismExtension/UrsaDrawerService.cs @@ -7,16 +7,27 @@ namespace Ursa.PrismExtension; public class UrsaDrawerService(IContainerExtension container): IUrsaDrawerService { - public Task ShowDrawer(string viewName, object? vm, string? hostId = null, DefaultDrawerOptions? options = null) + public void Show(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null) { var v = container.Resolve(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName); - return Drawer.Show(v, vm, hostId, options); + Drawer.Show(v, vm, hostId, options); } - - public Task ShowCustomDrawer(string viewName, object? vm, string? hostId = null, - CustomDrawerOptions? options = null) + + public void ShowCustom(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null) { var v = container.Resolve(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName); - return Drawer.ShowCustom(v, vm, hostId, options); + Drawer.ShowCustom(v, vm, hostId, options); + } + + public Task ShowModal(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null) + { + var v = container.Resolve(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName); + return Drawer.ShowModal(v, vm, hostId, options); + } + + public Task ShowCustomModal(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null) + { + var v = container.Resolve(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName); + return Drawer.ShowCustomModal(v, vm, hostId, options); } } \ No newline at end of file diff --git a/src/Ursa/Controls/Dialog/DialogControlBase.cs b/src/Ursa/Controls/Dialog/DialogControlBase.cs index abfdd70..5c45fb4 100644 --- a/src/Ursa/Controls/Dialog/DialogControlBase.cs +++ b/src/Ursa/Controls/Dialog/DialogControlBase.cs @@ -1,8 +1,10 @@ +using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.LogicalTree; using Irihi.Avalonia.Shared.Helpers; using Ursa.Common; using Ursa.Controls.OverlayShared; @@ -13,12 +15,12 @@ namespace Ursa.Controls; [TemplatePart(PART_CloseButton, typeof(Button))] [TemplatePart(PART_TitleArea, typeof(Panel))] [PseudoClasses(PC_Modal)] -public abstract class DialogControlBase: OverlayFeedbackElement +public abstract class DialogControlBase : OverlayFeedbackElement { public const string PART_CloseButton = "PART_CloseButton"; public const string PART_TitleArea = "PART_TitleArea"; public const string PC_Modal = ":modal"; - + internal HorizontalPosition HorizontalAnchor { get; set; } = HorizontalPosition.Center; internal VerticalPosition VerticalAnchor { get; set; } = VerticalPosition.Center; internal HorizontalPosition ActualHorizontalAnchor { get; set; } @@ -27,19 +29,18 @@ public abstract class DialogControlBase: OverlayFeedbackElement internal double? VerticalOffset { get; set; } internal double? HorizontalOffsetRatio { get; set; } internal double? VerticalOffsetRatio { get; set; } - internal bool CanClickOnMaskToClose { get; set; } internal bool CanLightDismiss { get; set; } - + internal bool CanDragMove { get; set; } + protected internal Button? _closeButton; private Panel? _titleArea; - - internal void SetAsModal(bool modal) - { - PseudoClasses.Set(PC_Modal, modal); - } - - public static readonly RoutedEvent LayerChangedEvent = RoutedEvent.Register( - nameof(LayerChanged), RoutingStrategies.Bubble); + + #region Layer Management + + public static readonly RoutedEvent LayerChangedEvent = + RoutedEvent.Register( + nameof(LayerChanged), RoutingStrategies.Bubble); + public event EventHandler LayerChanged { add => AddHandler(LayerChangedEvent, value); @@ -54,35 +55,133 @@ public abstract class DialogControlBase: OverlayFeedbackElement } } + #endregion + + #region DragMove AttachedPropert + + public static readonly AttachedProperty CanDragMoveProperty = + AvaloniaProperty.RegisterAttached("CanDragMove"); + + public static void SetCanDragMove(InputElement obj, bool value) => obj.SetValue(CanDragMoveProperty, value); + public static bool GetCanDragMove(InputElement obj) => obj.GetValue(CanDragMoveProperty); + + private static void OnCanDragMoveChanged(InputElement arg1, AvaloniaPropertyChangedEventArgs arg2) + { + if (arg2.NewValue.Value) + { + arg1.AddHandler(PointerPressedEvent, OnPointerPressed, RoutingStrategies.Bubble); + arg1.AddHandler(PointerMovedEvent, OnPointerMoved, RoutingStrategies.Bubble); + arg1.AddHandler(PointerReleasedEvent, OnPointerReleased, RoutingStrategies.Bubble); + } + else + { + arg1.RemoveHandler(PointerPressedEvent, OnPointerPressed); + arg1.RemoveHandler(PointerMovedEvent, OnPointerMoved); + arg1.RemoveHandler(PointerReleasedEvent, OnPointerReleased); + } + + void OnPointerPressed(InputElement sender, PointerPressedEventArgs e) + { + if (sender.FindLogicalAncestorOfType() is { } dialog) + { + e.Source = dialog; + } + } + + void OnPointerMoved(InputElement sender, PointerEventArgs e) + { + if (sender.FindLogicalAncestorOfType() is { } dialog) + { + e.Source = dialog; + } + } + + void OnPointerReleased(InputElement sender, PointerReleasedEventArgs e) + { + if (sender.FindLogicalAncestorOfType() is { } dialog) + { + e.Source = dialog; + } + } + } + + #endregion + + #region Close AttachedProperty + + public static readonly AttachedProperty CanCloseProperty = + AvaloniaProperty.RegisterAttached("CanClose"); + + public static void SetCanClose(InputElement obj, bool value) => obj.SetValue(CanCloseProperty, value); + public static bool GetCanClose(InputElement obj) => obj.GetValue(CanCloseProperty); + private static void OnCanCloseChanged(InputElement arg1, AvaloniaPropertyChangedEventArgs arg2) + { + if (arg2.NewValue.Value) + { + arg1.AddHandler(PointerPressedEvent, OnPointerPressed, RoutingStrategies.Bubble); + } + void OnPointerPressed(InputElement sender, PointerPressedEventArgs e) + { + if (sender.FindLogicalAncestorOfType() is { } dialog) + { + dialog.Close(); + } + } + } + #endregion + + static DialogControlBase() + { + CanDragMoveProperty.Changed.AddClassHandler(OnCanDragMoveChanged); + CanCloseProperty.Changed.AddClassHandler(OnCanCloseChanged); + } + + + + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); - _titleArea?.RemoveHandler(PointerMovedEvent, OnTitlePointerMove); - _titleArea?.RemoveHandler(PointerPressedEvent, OnTitlePointerPressed); - _titleArea?.RemoveHandler(PointerReleasedEvent, OnTitlePointerRelease); _titleArea = e.NameScope.Find(PART_TitleArea); - _titleArea?.AddHandler(PointerMovedEvent, OnTitlePointerMove, RoutingStrategies.Bubble); - _titleArea?.AddHandler(PointerPressedEvent, OnTitlePointerPressed, RoutingStrategies.Bubble); - _titleArea?.AddHandler(PointerReleasedEvent, OnTitlePointerRelease, RoutingStrategies.Bubble); + if (CanDragMove) + { + _titleArea?.RemoveHandler(PointerMovedEvent, OnTitlePointerMove); + _titleArea?.RemoveHandler(PointerPressedEvent, OnTitlePointerPressed); + _titleArea?.RemoveHandler(PointerReleasedEvent, OnTitlePointerRelease); + + _titleArea?.AddHandler(PointerMovedEvent, OnTitlePointerMove, RoutingStrategies.Bubble); + _titleArea?.AddHandler(PointerPressedEvent, OnTitlePointerPressed, RoutingStrategies.Bubble); + _titleArea?.AddHandler(PointerReleasedEvent, OnTitlePointerRelease, RoutingStrategies.Bubble); + } + else + { + if (_titleArea is not null) _titleArea.IsHitTestVisible = false; + } + Button.ClickEvent.RemoveHandler(OnCloseButtonClick, _closeButton); _closeButton = e.NameScope.Find