feat: refactor layer storage and index reset rule.
This commit is contained in:
@@ -4,11 +4,12 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800"
|
||||
xmlns:vm="clr-namespace:Ursa.Demo.ViewModels;assembly=Ursa.Demo"
|
||||
xmlns:u="https://irihi.tech/ursa"
|
||||
x:DataType="vm:DrawerDemoViewModel"
|
||||
x:CompileBindings="True"
|
||||
d:DesignHeight="450"
|
||||
x:Class="Ursa.Demo.Pages.DrawerDemo">
|
||||
<StackPanel HorizontalAlignment="Left">
|
||||
<Button Content="Call Drawer" Command="{Binding OpenDrawerCommand}"></Button>
|
||||
</StackPanel>
|
||||
<Canvas HorizontalAlignment="Left" Width="500">
|
||||
<Button Content="Call Drawer" HorizontalAlignment="Stretch" Command="{Binding OpenDrawerCommand}"></Button>
|
||||
</Canvas>
|
||||
</UserControl>
|
||||
|
||||
@@ -59,8 +59,7 @@
|
||||
<Setter Property="ContextFlyout">
|
||||
<MenuFlyout>
|
||||
<MenuItem
|
||||
Command="{Binding $parent[u:CustomDialogControl].CloseDialog}"
|
||||
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
|
||||
Command="{Binding $parent[u:DialogControlBase].Close}"
|
||||
Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
|
||||
<MenuItem.Icon>
|
||||
<PathIcon
|
||||
@@ -76,7 +75,7 @@
|
||||
<Setter Property="ContextFlyout">
|
||||
<MenuFlyout>
|
||||
<MenuItem
|
||||
Command="{Binding $parent[u:CustomDialogControl].UpdateLayer}"
|
||||
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
|
||||
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
|
||||
Header="{DynamicResource STRING_MENU_BRING_FORWARD}">
|
||||
<MenuItem.Icon>
|
||||
@@ -87,7 +86,7 @@
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Command="{Binding $parent[u:CustomDialogControl].UpdateLayer}"
|
||||
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
|
||||
CommandParameter="{x:Static u:DialogLayerChangeType.BringToFront}"
|
||||
Header="{DynamicResource STRING_MENU_BRING_TO_FRONT}">
|
||||
<MenuItem.Icon>
|
||||
@@ -98,7 +97,7 @@
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Command="{Binding $parent[u:CustomDialogControl].UpdateLayer}"
|
||||
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
|
||||
CommandParameter="{x:Static u:DialogLayerChangeType.SendBackward}"
|
||||
Header="{DynamicResource STRING_MENU_SEND_BACKWARD}">
|
||||
<MenuItem.Icon>
|
||||
@@ -109,7 +108,7 @@
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Command="{Binding $parent[u:CustomDialogControl].UpdateLayer}"
|
||||
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
|
||||
CommandParameter="{x:Static u:DialogLayerChangeType.SendToBack}"
|
||||
Header="{DynamicResource STRING_MENU_SEND_TO_BACK}">
|
||||
<MenuItem.Icon>
|
||||
@@ -120,8 +119,7 @@
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Command="{Binding $parent[u:CustomDialogControl].CloseDialog}"
|
||||
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
|
||||
Command="{Binding $parent[u:DialogControlBase].Close}"
|
||||
Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
|
||||
<MenuItem.Icon>
|
||||
<PathIcon
|
||||
@@ -347,8 +345,7 @@
|
||||
<Setter Property="ContextFlyout">
|
||||
<MenuFlyout>
|
||||
<MenuItem
|
||||
Command="{Binding $parent[u:CustomDialogControl].CloseDialog}"
|
||||
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
|
||||
Command="{Binding $parent[u:DialogControlBase].Close}"
|
||||
Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
|
||||
<MenuItem.Icon>
|
||||
<PathIcon
|
||||
@@ -364,7 +361,7 @@
|
||||
<Setter Property="ContextFlyout">
|
||||
<MenuFlyout>
|
||||
<MenuItem
|
||||
Command="{Binding $parent[u:CustomDialogControl].UpdateLayer}"
|
||||
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
|
||||
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
|
||||
Header="{DynamicResource STRING_MENU_BRING_FORWARD}">
|
||||
<MenuItem.Icon>
|
||||
@@ -375,7 +372,7 @@
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Command="{Binding $parent[u:CustomDialogControl].UpdateLayer}"
|
||||
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
|
||||
CommandParameter="{x:Static u:DialogLayerChangeType.BringToFront}"
|
||||
Header="{DynamicResource STRING_MENU_BRING_TO_FRONT}">
|
||||
<MenuItem.Icon>
|
||||
@@ -386,7 +383,7 @@
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Command="{Binding $parent[u:CustomDialogControl].UpdateLayer}"
|
||||
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
|
||||
CommandParameter="{x:Static u:DialogLayerChangeType.SendBackward}"
|
||||
Header="{DynamicResource STRING_MENU_SEND_BACKWARD}">
|
||||
<MenuItem.Icon>
|
||||
@@ -397,7 +394,7 @@
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Command="{Binding $parent[u:CustomDialogControl].UpdateLayer}"
|
||||
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
|
||||
CommandParameter="{x:Static u:DialogLayerChangeType.SendToBack}"
|
||||
Header="{DynamicResource STRING_MENU_SEND_TO_BACK}">
|
||||
<MenuItem.Icon>
|
||||
@@ -408,7 +405,7 @@
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Command="{Binding $parent[u:CustomDialogControl].CloseDialog}"
|
||||
Command="{Binding $parent[u:DialogControlBase].Close}"
|
||||
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
|
||||
Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
|
||||
<MenuItem.Icon>
|
||||
|
||||
@@ -27,6 +27,7 @@ public abstract class DialogControlBase: OverlayFeedbackElement
|
||||
internal double? HorizontalOffsetRatio { get; set; }
|
||||
internal double? VerticalOffsetRatio { get; set; }
|
||||
internal bool CanClickOnMaskToClose { get; set; }
|
||||
internal bool CanLightDismiss { get; set; }
|
||||
|
||||
protected internal Button? _closeButton;
|
||||
private Panel? _titleArea;
|
||||
|
||||
@@ -26,4 +26,6 @@ public class OverlayDialogOptions
|
||||
public DialogButton Buttons { get; set; } = DialogButton.OKCancel;
|
||||
public string? Title { get; set; } = null;
|
||||
public bool IsCloseButtonVisible { get; set; } = true;
|
||||
|
||||
public bool CanLightDismiss { get; set; }
|
||||
}
|
||||
@@ -191,6 +191,7 @@ public static class OverlayDialog
|
||||
options.VerticalAnchor == VerticalPosition.Center ? null : options.VerticalOffset;
|
||||
control.CanClickOnMaskToClose = options.CanClickOnMaskToClose;
|
||||
control.IsCloseButtonVisible = options.IsCloseButtonVisible;
|
||||
control.CanLightDismiss = options.CanLightDismiss;
|
||||
}
|
||||
|
||||
private static void ConfigureDefaultDialogControl(DefaultDialogControl control, OverlayDialogOptions? options)
|
||||
@@ -208,6 +209,7 @@ public static class OverlayDialog
|
||||
control.Mode = options.Mode;
|
||||
control.Buttons = options.Buttons;
|
||||
control.Title = options.Title;
|
||||
control.CanLightDismiss = options.CanLightDismiss;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
using Avalonia.Utilities;
|
||||
using Ursa.Controls.OverlayShared;
|
||||
using Ursa.Controls.Shapes;
|
||||
using Ursa.EventArgs;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
@@ -21,7 +22,7 @@ public partial class OverlayDialogHost
|
||||
public Thickness SnapThickness { get; set; } = new Thickness(0);
|
||||
|
||||
|
||||
private void ResetDialogPosition(DialogControlBase control, Size oldSize, Size newSize)
|
||||
private void ResetDialogPosition(DialogControlBase control, Size newSize)
|
||||
{
|
||||
var width = newSize.Width - control.Bounds.Width;
|
||||
var height = newSize.Height - control.Bounds.Height;
|
||||
@@ -82,8 +83,17 @@ public partial class OverlayDialogHost
|
||||
|
||||
internal void AddDialog(DialogControlBase control)
|
||||
{
|
||||
PureRectangle? mask = null;
|
||||
if (control.CanLightDismiss)
|
||||
{
|
||||
CreateOverlayMask(false, control.CanLightDismiss);
|
||||
}
|
||||
if (mask is not null)
|
||||
{
|
||||
Children.Add(mask);
|
||||
}
|
||||
this.Children.Add(control);
|
||||
_dialogs.Add(control);
|
||||
_layers.Add(new DialogPair(mask, control));
|
||||
control.Measure(this.Bounds.Size);
|
||||
control.Arrange(new Rect(control.DesiredSize));
|
||||
SetToPosition(control);
|
||||
@@ -96,27 +106,19 @@ public partial class OverlayDialogHost
|
||||
{
|
||||
if (sender is DialogControlBase control)
|
||||
{
|
||||
Children.Remove(control);
|
||||
var layer = _layers.FirstOrDefault(a => a.Element == control);
|
||||
if (layer is null) return;
|
||||
_layers.Remove(layer);
|
||||
|
||||
control.RemoveHandler(OverlayFeedbackElement.ClosedEvent, OnDialogControlClosing);
|
||||
control.RemoveHandler(DialogControlBase.LayerChangedEvent, OnDialogLayerChanged);
|
||||
if (_dialogs.Contains(control))
|
||||
|
||||
Children.Remove(control);
|
||||
|
||||
if (layer.Mask is not null)
|
||||
{
|
||||
_dialogs.Remove(control);
|
||||
}
|
||||
else if (_modalDialogs.Contains(control))
|
||||
{
|
||||
if (_masks.Count > 0)
|
||||
{
|
||||
var last = _masks.Last();
|
||||
await _maskDisappearAnimation.RunAsync(last);
|
||||
this.Children.Remove(last);
|
||||
_masks.Remove(last);
|
||||
if (_masks.Count > 0)
|
||||
{
|
||||
_masks.Last().IsVisible = true;
|
||||
}
|
||||
}
|
||||
_modalDialogs.Remove(control);
|
||||
await _maskDisappearAnimation.RunAsync(layer.Mask);
|
||||
Children.Remove(layer.Mask);
|
||||
}
|
||||
|
||||
ResetZIndices();
|
||||
@@ -129,9 +131,8 @@ public partial class OverlayDialogHost
|
||||
/// <param name="control"></param>
|
||||
internal void AddModalDialog(DialogControlBase control)
|
||||
{
|
||||
var mask = CreateOverlayMask(control.CanClickOnMaskToClose);
|
||||
_masks.Add(mask);
|
||||
_modalDialogs.Add(control);
|
||||
var mask = CreateOverlayMask(true, control.CanClickOnMaskToClose);
|
||||
_layers.Add(new DialogPair(mask, control));
|
||||
control.SetAsModal(true);
|
||||
ResetZIndices();
|
||||
this.Children.Add(mask);
|
||||
@@ -148,41 +149,31 @@ public partial class OverlayDialogHost
|
||||
// Handle dialog layer change event
|
||||
private void OnDialogLayerChanged(object sender, DialogLayerChangeEventArgs e)
|
||||
{
|
||||
if (sender is not CustomDialogControl control)
|
||||
if (sender is not DialogControlBase control)
|
||||
return;
|
||||
if (!_dialogs.Contains(control))
|
||||
return;
|
||||
int index = _dialogs.IndexOf(control);
|
||||
_dialogs.Remove(control);
|
||||
var layer = _layers.FirstOrDefault(a => a.Element == control);
|
||||
if (layer is null) return;
|
||||
int index = _layers.IndexOf(layer);
|
||||
_layers.Remove(layer);
|
||||
int newIndex = index;
|
||||
switch (e.ChangeType)
|
||||
{
|
||||
case DialogLayerChangeType.BringForward:
|
||||
newIndex = MathUtilities.Clamp(index + 1, 0, _dialogs.Count);
|
||||
newIndex = MathUtilities.Clamp(index + 1, 0, _layers.Count);
|
||||
break;
|
||||
case DialogLayerChangeType.SendBackward:
|
||||
newIndex = MathUtilities.Clamp(index - 1, 0, _dialogs.Count);
|
||||
newIndex = MathUtilities.Clamp(index - 1, 0, _layers.Count);
|
||||
break;
|
||||
case DialogLayerChangeType.BringToFront:
|
||||
newIndex = _dialogs.Count;
|
||||
newIndex = _layers.Count;
|
||||
break;
|
||||
case DialogLayerChangeType.SendToBack:
|
||||
newIndex = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
_dialogs.Insert(newIndex, control);
|
||||
for (int i = 0; i < _dialogs.Count; i++)
|
||||
{
|
||||
_dialogs[i].ZIndex = i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _masks.Count * 2; i += 2)
|
||||
{
|
||||
_masks[i].ZIndex = _dialogs.Count + i;
|
||||
(_modalDialogs[i] as Control)!.ZIndex = _dialogs.Count + i + 1;
|
||||
}
|
||||
|
||||
_layers.Insert(newIndex, layer);
|
||||
ResetZIndices();
|
||||
}
|
||||
|
||||
private void SetToPosition(DialogControlBase? control)
|
||||
|
||||
@@ -12,15 +12,9 @@ public partial class OverlayDialogHost
|
||||
{
|
||||
internal async void AddDrawer(DrawerControlBase control)
|
||||
{
|
||||
var mask = CreateOverlayMask(false);
|
||||
var mask = CreateOverlayMask(true, false);
|
||||
mask.Opacity = 0;
|
||||
_masks.Add(mask);
|
||||
_modalDialogs.Add(control);
|
||||
// control.SetAsModal(true);
|
||||
for (int i = 0; i < _masks.Count-1; i++)
|
||||
{
|
||||
_masks[i].Opacity = 0.5;
|
||||
}
|
||||
_layers.Add(new DialogPair(mask, control));
|
||||
ResetZIndices();
|
||||
this.Children.Add(mask);
|
||||
this.Children.Add(control);
|
||||
@@ -66,23 +60,16 @@ public partial class OverlayDialogHost
|
||||
{
|
||||
if (sender is DrawerControlBase control)
|
||||
{
|
||||
var layer = _layers.FirstOrDefault(a => a.Element == control);
|
||||
if(layer is null) return;
|
||||
_layers.Remove(layer);
|
||||
if (layer.Mask is not null)
|
||||
{
|
||||
layer.Mask.RemoveHandler(PointerPressedEvent, ClickMaskToCloseDialog);
|
||||
}
|
||||
Children.Remove(control);
|
||||
control.RemoveHandler(OverlayFeedbackElement.ClosedEvent, OnDialogControlClosing);
|
||||
control.RemoveHandler(DialogControlBase.LayerChangedEvent, OnDialogLayerChanged);
|
||||
if (_modalDialogs.Contains(control))
|
||||
{
|
||||
_modalDialogs.Remove(control);
|
||||
if (_masks.Count > 0)
|
||||
{
|
||||
var last = _masks.Last();
|
||||
this.Children.Remove(last);
|
||||
_masks.Remove(last);
|
||||
if (_masks.Count > 0)
|
||||
{
|
||||
_masks.Last().IsVisible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ResetZIndices();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using Avalonia.Input;
|
||||
using Avalonia.Media;
|
||||
using Ursa.Controls.OverlayShared;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media.Immutable;
|
||||
using Avalonia.Styling;
|
||||
using Ursa.Controls.Shapes;
|
||||
|
||||
@@ -14,18 +15,21 @@ namespace Ursa.Controls;
|
||||
|
||||
public partial class OverlayDialogHost: Canvas
|
||||
{
|
||||
private readonly List<OverlayFeedbackElement> _dialogs = new();
|
||||
private readonly List<OverlayFeedbackElement> _modalDialogs = new();
|
||||
private readonly List<PureRectangle> _masks = new();
|
||||
private static readonly Animation _maskAppearAnimation;
|
||||
private static readonly Animation _maskDisappearAnimation;
|
||||
|
||||
private readonly List<DialogPair> _layers = new List<DialogPair>();
|
||||
|
||||
private struct DialogPair
|
||||
private class DialogPair
|
||||
{
|
||||
internal PureRectangle Mask;
|
||||
internal OverlayFeedbackElement Dialog;
|
||||
internal PureRectangle? Mask;
|
||||
internal OverlayFeedbackElement Element;
|
||||
|
||||
public DialogPair(PureRectangle? mask, OverlayFeedbackElement element)
|
||||
{
|
||||
Mask = mask;
|
||||
Element = element;
|
||||
}
|
||||
}
|
||||
|
||||
static OverlayDialogHost()
|
||||
@@ -63,33 +67,38 @@ public partial class OverlayDialogHost: Canvas
|
||||
set => SetValue(OverlayMaskBrushProperty, value);
|
||||
}
|
||||
|
||||
private PureRectangle CreateOverlayMask(bool canCloseOnClick)
|
||||
private PureRectangle CreateOverlayMask(bool modal, bool canCloseOnClick)
|
||||
{
|
||||
PureRectangle rec = new()
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch,
|
||||
Width = this.Bounds.Width,
|
||||
Height = this.Bounds.Height,
|
||||
[!Shape.FillProperty] = this[!OverlayMaskBrushProperty],
|
||||
IsVisible = true,
|
||||
};
|
||||
if (modal)
|
||||
{
|
||||
rec[!Shape.FillProperty] = this[!OverlayMaskBrushProperty];
|
||||
}
|
||||
else if(canCloseOnClick)
|
||||
{
|
||||
rec.SetCurrentValue(Shape.FillProperty, Brushes.Transparent);
|
||||
}
|
||||
if (canCloseOnClick)
|
||||
{
|
||||
rec.AddHandler(PointerReleasedEvent, ClickBorderToCloseDialog);
|
||||
rec.AddHandler(PointerReleasedEvent, ClickMaskToCloseDialog);
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
||||
private void ClickBorderToCloseDialog(object sender, PointerReleasedEventArgs e)
|
||||
private void ClickMaskToCloseDialog(object sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
if (sender is PureRectangle border)
|
||||
{
|
||||
int i = _masks.IndexOf(border);
|
||||
if (_modalDialogs[i] is { } element)
|
||||
var layer = _layers.FirstOrDefault(a => a.Mask == border);
|
||||
if (layer is not null)
|
||||
{
|
||||
element.Close();
|
||||
border.RemoveHandler(PointerReleasedEvent, ClickBorderToCloseDialog);
|
||||
layer.Element.Close();
|
||||
border.RemoveHandler(PointerReleasedEvent, ClickMaskToCloseDialog);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,26 +119,16 @@ public partial class OverlayDialogHost: Canvas
|
||||
protected sealed override void OnSizeChanged(SizeChangedEventArgs e)
|
||||
{
|
||||
base.OnSizeChanged(e);
|
||||
for (int i = 0; i < _masks.Count; i++)
|
||||
for (int i = 0; i < _layers.Count; i++)
|
||||
{
|
||||
_masks[i].Width = this.Bounds.Width;
|
||||
_masks[i].Height = this.Bounds.Height;
|
||||
}
|
||||
|
||||
var oldSize = e.PreviousSize;
|
||||
var newSize = e.NewSize;
|
||||
foreach (var dialog in _dialogs)
|
||||
{
|
||||
if (dialog is DialogControlBase c)
|
||||
if (_layers[i].Mask is { } rect)
|
||||
{
|
||||
ResetDialogPosition(c, oldSize, newSize);
|
||||
rect.Width = this.Bounds.Width;
|
||||
rect.Height = this.Bounds.Height;
|
||||
}
|
||||
}
|
||||
foreach (var modalDialog in _modalDialogs)
|
||||
{
|
||||
if (modalDialog is DialogControlBase c)
|
||||
if (_layers[i].Element is DialogControlBase d)
|
||||
{
|
||||
ResetDialogPosition(c, oldSize, newSize);
|
||||
ResetDialogPosition(d, e.NewSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,31 +136,17 @@ public partial class OverlayDialogHost: Canvas
|
||||
private void ResetZIndices()
|
||||
{
|
||||
int index = 0;
|
||||
for ( int i = 0; i< _dialogs.Count; i++)
|
||||
{
|
||||
_dialogs[i].ZIndex = index;
|
||||
index++;
|
||||
}
|
||||
for(int i = 0; i< _masks.Count; i++)
|
||||
{
|
||||
_masks[i].ZIndex = index;
|
||||
index++;
|
||||
(_modalDialogs[i] as Control)!.ZIndex = index;
|
||||
index++;
|
||||
}
|
||||
|
||||
int index2 = 0;
|
||||
for (int i = 0; i < _layers.Count; i++)
|
||||
{
|
||||
if(_layers[i].Mask is { } mask)
|
||||
{
|
||||
mask.ZIndex = index2;
|
||||
index2++;
|
||||
mask.ZIndex = index;
|
||||
index++;
|
||||
}
|
||||
if(_layers[i].Dialog is { } dialog)
|
||||
if(_layers[i].Element is { } dialog)
|
||||
{
|
||||
dialog.ZIndex = index2;
|
||||
index2++;
|
||||
dialog.ZIndex = index;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user