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/src/Ursa/Controls/Dialog/DialogControlBase.cs b/src/Ursa/Controls/Dialog/DialogControlBase.cs
index abfdd70..a579f14 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; }
@@ -29,17 +31,17 @@ public abstract class DialogControlBase: OverlayFeedbackElement
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 +56,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