diff --git a/src/Ursa.Themes.Semi/Controls/Dialog.axaml b/src/Ursa.Themes.Semi/Controls/Dialog.axaml index b894472..2b113fb 100644 --- a/src/Ursa.Themes.Semi/Controls/Dialog.axaml +++ b/src/Ursa.Themes.Semi/Controls/Dialog.axaml @@ -26,11 +26,6 @@ Grid.Column="0" Grid.ColumnSpan="2" Background="Transparent" > - - - - - + diff --git a/src/Ursa/Controls/Dialog/DialogBox.cs b/src/Ursa/Controls/Dialog/DialogBox.cs index 36e5e2b..fe27fa7 100644 --- a/src/Ursa/Controls/Dialog/DialogBox.cs +++ b/src/Ursa/Controls/Dialog/DialogBox.cs @@ -97,6 +97,8 @@ public static class DialogBox { Content = new TView() { DataContext = vm }, DataContext = vm, + ExtendToClientArea = options.ExtendToClientArea, + Title = options.Title, }; var host = OverlayDialogManager.GetOverlayDialogHost(hostId); host?.AddModalDialog(t); diff --git a/src/Ursa/Controls/Dialog/DialogControl.cs b/src/Ursa/Controls/Dialog/DialogControl.cs index 945f81a..737d4d6 100644 --- a/src/Ursa/Controls/Dialog/DialogControl.cs +++ b/src/Ursa/Controls/Dialog/DialogControl.cs @@ -15,10 +15,12 @@ public class DialogControl: ContentControl public const string PART_CloseButton = "PART_CloseButton"; public const string PART_TitleArea = "PART_TitleArea"; public const string PC_ExtendClientArea = ":extend"; + public const string PC_Modal = ":modal"; private Button? _closeButton; private Panel? _titleArea; public event EventHandler? OnClose; + public event EventHandler? OnLayerChange; public static readonly StyledProperty TitleProperty = AvaloniaProperty.Register( nameof(Title)); @@ -93,7 +95,7 @@ public class DialogControl: ContentControl public Task ShowAsync() { var tcs = new TaskCompletionSource(); - + PseudoClasses.Set(PC_Modal, true); void OnCloseHandler(object sender, object? args) { if (args is T result) @@ -124,4 +126,24 @@ public class DialogControl: ContentControl OnClose?.Invoke(this, null); } } + + public void BringForward() + { + OnLayerChange?.Invoke(this, new DialogLayerChangeEventArgs(DialogLayerChangeType.BringForward)); + } + + public void SendBackward() + { + OnLayerChange?.Invoke(this, new DialogLayerChangeEventArgs(DialogLayerChangeType.SendBackward)); + } + + public void BringToFront() + { + OnLayerChange?.Invoke(this, new DialogLayerChangeEventArgs(DialogLayerChangeType.BringToFront)); + } + + public void SendToBack() + { + OnLayerChange?.Invoke(this, new DialogLayerChangeEventArgs(DialogLayerChangeType.SendToBack)); + } } \ No newline at end of file diff --git a/src/Ursa/Controls/Dialog/DialogLayerChangeEventArgs.cs b/src/Ursa/Controls/Dialog/DialogLayerChangeEventArgs.cs new file mode 100644 index 0000000..12ec4ee --- /dev/null +++ b/src/Ursa/Controls/Dialog/DialogLayerChangeEventArgs.cs @@ -0,0 +1,18 @@ +namespace Ursa.Controls; + +public class DialogLayerChangeEventArgs +{ + public DialogLayerChangeType ChangeType { get; } + public DialogLayerChangeEventArgs(DialogLayerChangeType type) + { + ChangeType = type; + } +} + +public enum DialogLayerChangeType +{ + BringForward, + SendBackward, + BringToFront, + SendToBack +} \ No newline at end of file diff --git a/src/Ursa/Controls/Dialog/OverlayDialogHost.cs b/src/Ursa/Controls/Dialog/OverlayDialogHost.cs index 8a39e71..5887964 100644 --- a/src/Ursa/Controls/Dialog/OverlayDialogHost.cs +++ b/src/Ursa/Controls/Dialog/OverlayDialogHost.cs @@ -9,37 +9,38 @@ using Avalonia.Media; using Avalonia.Utilities; using Avalonia.VisualTree; -namespace Ursa.Controls; +namespace Ursa.Controls; -public class OverlayDialogHost: Canvas +public class OverlayDialogHost : Canvas { private readonly List _dialogs = new(); private readonly List _modalDialogs = new(); private readonly List _masks = new(); - + public string? HostId { get; set; } - + private Point _lastPoint; - public static readonly StyledProperty OverlayMaskBrushProperty = AvaloniaProperty.Register( - nameof(OverlayMaskBrush)); + public static readonly StyledProperty OverlayMaskBrushProperty = + AvaloniaProperty.Register( + nameof(OverlayMaskBrush)); public IBrush? OverlayMaskBrush { get => GetValue(OverlayMaskBrushProperty); set => SetValue(OverlayMaskBrushProperty, value); } - + private Border CreateOverlayMask() => new() { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, Width = this.Bounds.Width, - Height = this.Bounds.Height, + Height = this.Bounds.Height, [!BackgroundProperty] = this[!OverlayMaskBrushProperty], IsVisible = true, }; - + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); @@ -70,7 +71,7 @@ public class OverlayDialogHost: Canvas if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) { var p = e.GetPosition(this); - var left= p.X - _lastPoint.X; + var left = p.X - _lastPoint.X; var top = p.Y - _lastPoint.Y; left = MathUtilities.Clamp(left, 0, Bounds.Width - item.Bounds.Width); top = MathUtilities.Clamp(top, 0, Bounds.Height - item.Bounds.Height); @@ -93,7 +94,9 @@ public class OverlayDialogHost: Canvas { this.Children.Add(control); _dialogs.Add(control); + control.ZIndex = Children.Last().ZIndex + 1; control.OnClose += OnDialogClose; + control.OnLayerChange += OnDialogLayerChange; } private void OnDialogClose(object sender, object? e) @@ -102,11 +105,12 @@ public class OverlayDialogHost: Canvas { this.Children.Remove(control); control.OnClose -= OnDialogClose; + control.OnLayerChange -= OnDialogLayerChange; if (_dialogs.Contains(control)) { _dialogs.Remove(control); } - else if(_modalDialogs.Contains(control)) + else if (_modalDialogs.Contains(control)) { _modalDialogs.Remove(control); if (_masks.Count > 0) @@ -116,7 +120,7 @@ public class OverlayDialogHost: Canvas _masks.Remove(last); if (_masks.Count > 0) { - _masks.Last().IsVisible= true; + _masks.Last().IsVisible = true; } } } @@ -133,7 +137,41 @@ public class OverlayDialogHost: Canvas { _masks[i].IsVisible = false; } + _masks.Add(mask); control.OnClose += OnDialogClose; + control.OnLayerChange += OnDialogLayerChange; + } + + private void OnDialogLayerChange(object sender, DialogLayerChangeEventArgs e) + { + if (sender is not DialogControl control) + return; + if (!_dialogs.Contains(control)) + return; + int index = _dialogs.IndexOf(control); + _dialogs.Remove(control); + int newIndex = index; + switch (e.ChangeType) + { + case DialogLayerChangeType.BringForward: + newIndex = MathUtilities.Clamp(index + 1, 0, _dialogs.Count); + break; + case DialogLayerChangeType.SendBackward: + newIndex = MathUtilities.Clamp(index - 1, 0, _dialogs.Count); + break; + case DialogLayerChangeType.BringToFront: + newIndex = _dialogs.Count; + break; + case DialogLayerChangeType.SendToBack: + newIndex = 0; + break; + } + + _dialogs.Insert(newIndex, control); + for (int i = 0; i < _dialogs.Count; i++) + { + _dialogs[i].ZIndex = i; + } } } \ No newline at end of file