Refactor and optimize overlay dialog handling and resizing logic

- Remove unused `_moveDragging` variable in `OverlayFeedbackElement.cs`
- Rename private static animations to follow PascalCase in `OverlayDialogHost.Shared.cs`
- Simplify and streamline `ClickMaskToCloseDialog`, `OnPointerMoved`, `OnPointerPressed`, and `OnPointerReleased` methods in `OverlayDialogHost.Dialog.cs`
- Remove redundant null checks and streamline method calls in various files
- Optimize `_moveDragging` logic and pointer event handling in `DialogControlBase.cs`

This commit enhances readability, maintains consistency in naming conventions, and optimizes the code for better performance and clarity.
This commit is contained in:
rabbitism
2024-09-18 02:37:17 +08:00
parent 5799646488
commit dccb3c029c
5 changed files with 102 additions and 155 deletions

View File

@@ -31,6 +31,9 @@ public abstract class DialogControlBase : OverlayFeedbackElement
private bool _isFullScreen; private bool _isFullScreen;
private Panel? _titleArea; private Panel? _titleArea;
private bool _moveDragging;
private Point _moveDragStartPoint;
static DialogControlBase() static DialogControlBase()
{ {
@@ -88,17 +91,44 @@ public abstract class DialogControlBase : OverlayFeedbackElement
private void OnTitlePointerPressed(InputElement sender, PointerPressedEventArgs e) private void OnTitlePointerPressed(InputElement sender, PointerPressedEventArgs e)
{ {
e.Source = this; //e.Source = this;
if (ContainerPanel is OverlayDialogHost h)
{
if (h.IsTopLevel && this.IsFullScreen)
{
var top = TopLevel.GetTopLevel(this);
if (top is Window w)
{
w.BeginMoveDrag(e);
return;
}
}
}
if (!e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) return;
if (IsFullScreen) return;
_moveDragging = true;
_moveDragStartPoint = e.GetPosition(this);
} }
private void OnTitlePointerMove(InputElement sender, PointerEventArgs e) private void OnTitlePointerMove(InputElement sender, PointerEventArgs e)
{ {
e.Source = this; //e.Source = this;
if (!_moveDragging) return;
if (ContainerPanel is null) return;
var p = e.GetPosition(this);
var left = Canvas.GetLeft(this) + p.X - _moveDragStartPoint.X;
var top = Canvas.GetTop(this) + p.Y - _moveDragStartPoint.Y;
left = MathHelpers.SafeClamp(left, 0, ContainerPanel.Bounds.Width - Bounds.Width);
top = MathHelpers.SafeClamp(top, 0, ContainerPanel.Bounds.Height - Bounds.Height);
Canvas.SetLeft(this, left);
Canvas.SetTop(this, top);
} }
private void OnTitlePointerRelease(InputElement sender, PointerReleasedEventArgs e) private void OnTitlePointerRelease(InputElement sender, PointerReleasedEventArgs e)
{ {
e.Source = this; // e.Source = this;
_moveDragging = false;
AnchorAndUpdatePositionInfo();
} }
private void OnCloseButtonClick(object? sender, RoutedEventArgs args) private void OnCloseButtonClick(object? sender, RoutedEventArgs args)

View File

@@ -1,5 +1,4 @@
using Avalonia; using Avalonia;
using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Irihi.Avalonia.Shared.Helpers; using Irihi.Avalonia.Shared.Helpers;
@@ -10,10 +9,8 @@ namespace Ursa.Controls;
public partial class OverlayDialogHost public partial class OverlayDialogHost
{ {
private Point _lastPoint; public Thickness SnapThickness { get; set; } = new(0);
public Thickness SnapThickness { get; set; } = new Thickness(0);
private static void ResetDialogPosition(DialogControlBase control, Size newSize) private static void ResetDialogPosition(DialogControlBase control, Size newSize)
{ {
control.MaxWidth = newSize.Width; control.MaxWidth = newSize.Width;
@@ -26,138 +23,71 @@ public partial class OverlayDialogHost
SetTop(control, 0); SetTop(control, 0);
return; return;
} }
var width = newSize.Width - control.Bounds.Width; var width = newSize.Width - control.Bounds.Width;
var height = newSize.Height - control.Bounds.Height; var height = newSize.Height - control.Bounds.Height;
var newLeft = width * control.HorizontalOffsetRatio ?? 0; var newLeft = width * control.HorizontalOffsetRatio ?? 0;
var newTop = height * control.VerticalOffsetRatio ?? 0; var newTop = height * control.VerticalOffsetRatio ?? 0;
if(control.ActualHorizontalAnchor == HorizontalPosition.Left) if (control.ActualHorizontalAnchor == HorizontalPosition.Left) newLeft = 0;
{ if (control.ActualHorizontalAnchor == HorizontalPosition.Right) newLeft = newSize.Width - control.Bounds.Width;
newLeft = 0; if (control.ActualVerticalAnchor == VerticalPosition.Top) newTop = 0;
} if (control.ActualVerticalAnchor == VerticalPosition.Bottom) newTop = newSize.Height - control.Bounds.Height;
if (control.ActualHorizontalAnchor == HorizontalPosition.Right)
{
newLeft = newSize.Width - control.Bounds.Width;
}
if (control.ActualVerticalAnchor == VerticalPosition.Top)
{
newTop = 0;
}
if (control.ActualVerticalAnchor == VerticalPosition.Bottom)
{
newTop = newSize.Height - control.Bounds.Height;
}
SetLeft(control, Math.Max(0.0, newLeft)); SetLeft(control, Math.Max(0.0, newLeft));
SetTop(control, Math.Max(0.0, newTop)); SetTop(control, Math.Max(0.0, newTop));
} }
protected override void OnPointerMoved(PointerEventArgs e)
{
if (e.Source is DialogControlBase item)
{
if (item.IsFullScreen) return;
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
var p = e.GetPosition(this);
var left = p.X - _lastPoint.X;
var top = p.Y - _lastPoint.Y;
left = MathHelpers.SafeClamp(left, 0, Bounds.Width - item.Bounds.Width);
top = MathHelpers.SafeClamp(top, 0, Bounds.Height - item.Bounds.Height);
SetLeft(item, left);
SetTop(item, top);
}
}
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
if (e.Source is DialogControlBase item)
{
if (IsTopLevel && item.IsFullScreen)
{
var top = TopLevel.GetTopLevel(item);
if (top is Window w)
{
w.BeginMoveDrag(e);
}
}
else
{
_lastPoint = e.GetPosition(item);
}
}
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
if (e.Source is DialogControlBase item)
{
item.AnchorAndUpdatePositionInfo();
}
}
internal void AddDialog(DialogControlBase control) internal void AddDialog(DialogControlBase control)
{ {
PureRectangle? mask = null; PureRectangle? mask = null;
if (control.CanLightDismiss) if (control.CanLightDismiss) mask = CreateOverlayMask(false, control.CanLightDismiss);
{ if (mask is not null) Children.Add(mask);
mask = CreateOverlayMask(false, control.CanLightDismiss); Children.Add(control);
}
if (mask is not null)
{
Children.Add(mask);
}
this.Children.Add(control);
_layers.Add(new DialogPair(mask, control, false)); _layers.Add(new DialogPair(mask, control, false));
if (control.IsFullScreen) if (control.IsFullScreen)
{ {
control.Width = Bounds.Width; control.Width = Bounds.Width;
control.Height = Bounds.Height; control.Height = Bounds.Height;
} }
control.MaxWidth = Bounds.Width; control.MaxWidth = Bounds.Width;
control.MaxHeight = Bounds.Height; control.MaxHeight = Bounds.Height;
control.Measure(this.Bounds.Size); control.Measure(Bounds.Size);
control.Arrange(new Rect(control.DesiredSize)); control.Arrange(new Rect(control.DesiredSize));
SetToPosition(control); SetToPosition(control);
control.AddHandler(OverlayFeedbackElement.ClosedEvent, OnDialogControlClosing); control.AddHandler(OverlayFeedbackElement.ClosedEvent, OnDialogControlClosing);
control.AddHandler(DialogControlBase.LayerChangedEvent, OnDialogLayerChanged); control.AddHandler(DialogControlBase.LayerChangedEvent, OnDialogLayerChanged);
ResetZIndices(); ResetZIndices();
} }
private async void OnDialogControlClosing(object? sender, object? e) private async void OnDialogControlClosing(object? sender, object? e)
{ {
if (sender is DialogControlBase control) if (sender is not DialogControlBase control) return;
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);
layer.Mask?.RemoveHandler(PointerPressedEvent, DragMaskToMoveWindow);
Children.Remove(control);
if (layer.Mask is not null)
{ {
var layer = _layers.FirstOrDefault(a => a.Element == control); Children.Remove(layer.Mask);
if (layer is null) return; if (layer.Modal)
_layers.Remove(layer);
control.RemoveHandler(OverlayFeedbackElement.ClosedEvent, OnDialogControlClosing);
control.RemoveHandler(DialogControlBase.LayerChangedEvent, OnDialogLayerChanged);
control.RemoveHandler(PointerPressedEvent, DragMaskToMoveWindow);
Children.Remove(control);
if (layer.Mask is not null)
{ {
Children.Remove(layer.Mask); _modalCount--;
IsInModalStatus = _modalCount > 0;
if (layer.Modal) if (!IsAnimationDisabled) await MaskDisappearAnimation.RunAsync(layer.Mask);
{
_modalCount--;
IsInModalStatus = _modalCount > 0;
if (!IsAnimationDisabled)
{
await _maskDisappearAnimation.RunAsync(layer.Mask);
}
}
} }
ResetZIndices();
} }
ResetZIndices();
} }
/// <summary> /// <summary>
/// Add a dialog as a modal dialog to the host /// Add a dialog as a modal dialog to the host
/// </summary> /// </summary>
/// <param name="control"></param> /// <param name="control"></param>
internal void AddModalDialog(DialogControlBase control) internal void AddModalDialog(DialogControlBase control)
@@ -166,24 +96,22 @@ public partial class OverlayDialogHost
_layers.Add(new DialogPair(mask, control)); _layers.Add(new DialogPair(mask, control));
control.SetAsModal(true); control.SetAsModal(true);
ResetZIndices(); ResetZIndices();
this.Children.Add(mask); Children.Add(mask);
this.Children.Add(control); Children.Add(control);
if (control.IsFullScreen) if (control.IsFullScreen)
{ {
control.Width = Bounds.Width; control.Width = Bounds.Width;
control.Height = Bounds.Height; control.Height = Bounds.Height;
} }
control.MaxWidth = Bounds.Width; control.MaxWidth = Bounds.Width;
control.MaxHeight = Bounds.Height; control.MaxHeight = Bounds.Height;
control.Measure(this.Bounds.Size); control.Measure(Bounds.Size);
control.Arrange(new Rect(control.DesiredSize)); control.Arrange(new Rect(control.DesiredSize));
SetToPosition(control); SetToPosition(control);
control.AddHandler(OverlayFeedbackElement.ClosedEvent, OnDialogControlClosing); control.AddHandler(OverlayFeedbackElement.ClosedEvent, OnDialogControlClosing);
control.AddHandler(DialogControlBase.LayerChangedEvent, OnDialogLayerChanged); control.AddHandler(DialogControlBase.LayerChangedEvent, OnDialogLayerChanged);
if (!IsAnimationDisabled) if (!IsAnimationDisabled) MaskAppearAnimation.RunAsync(mask);
{
_maskAppearAnimation.RunAsync(mask);
}
var element = control.GetVisualDescendants().OfType<InputElement>().FirstOrDefault(a => a.Focusable); var element = control.GetVisualDescendants().OfType<InputElement>().FirstOrDefault(a => a.Focusable);
element?.Focus(); element?.Focus();
@@ -200,9 +128,9 @@ public partial class OverlayDialogHost
return; return;
var layer = _layers.FirstOrDefault(a => a.Element == control); var layer = _layers.FirstOrDefault(a => a.Element == control);
if (layer is null) return; if (layer is null) return;
int index = _layers.IndexOf(layer); var index = _layers.IndexOf(layer);
_layers.Remove(layer); _layers.Remove(layer);
int newIndex = index; var newIndex = index;
switch (e.ChangeType) switch (e.ChangeType)
{ {
case DialogLayerChangeType.BringForward: case DialogLayerChangeType.BringForward:
@@ -222,12 +150,12 @@ public partial class OverlayDialogHost
_layers.Insert(newIndex, layer); _layers.Insert(newIndex, layer);
ResetZIndices(); ResetZIndices();
} }
private void SetToPosition(DialogControlBase? control) private void SetToPosition(DialogControlBase? control)
{ {
if (control is null) return; if (control is null) return;
double left = GetLeftPosition(control); var left = GetLeftPosition(control);
double top = GetTopPosition(control); var top = GetTopPosition(control);
SetLeft(control, left); SetLeft(control, left);
SetTop(control, top); SetTop(control, top);
control.AnchorAndUpdatePositionInfo(); control.AnchorAndUpdatePositionInfo();
@@ -235,9 +163,8 @@ public partial class OverlayDialogHost
private double GetLeftPosition(DialogControlBase control) private double GetLeftPosition(DialogControlBase control)
{ {
double left; var offset = Math.Max(0, control.HorizontalOffset ?? 0);
double offset = Math.Max(0, control.HorizontalOffset ?? 0); var left = Bounds.Width - control.Bounds.Width;
left = this.Bounds.Width - control.Bounds.Width;
if (control.HorizontalAnchor == HorizontalPosition.Center) if (control.HorizontalAnchor == HorizontalPosition.Center)
{ {
left *= 0.5; left *= 0.5;
@@ -249,20 +176,18 @@ public partial class OverlayDialogHost
} }
else if (control.HorizontalAnchor == HorizontalPosition.Right) else if (control.HorizontalAnchor == HorizontalPosition.Right)
{ {
double leftOffset = Bounds.Width - control.Bounds.Width - offset; var leftOffset = Bounds.Width - control.Bounds.Width - offset;
leftOffset = Math.Max(0, leftOffset); leftOffset = Math.Max(0, leftOffset);
if(control.HorizontalOffset.HasValue) if (control.HorizontalOffset.HasValue) left = MathHelpers.SafeClamp(left, 0, leftOffset);
{
left = MathHelpers.SafeClamp(left, 0, leftOffset);
}
} }
return left; return left;
} }
private double GetTopPosition(DialogControlBase control) private double GetTopPosition(DialogControlBase control)
{ {
double offset = Math.Max(0, control.VerticalOffset ?? 0); var offset = Math.Max(0, control.VerticalOffset ?? 0);
var top = this.Bounds.Height - control.Bounds.Height; var top = Bounds.Height - control.Bounds.Height;
if (control.VerticalAnchor == VerticalPosition.Center) if (control.VerticalAnchor == VerticalPosition.Center)
{ {
top *= 0.5; top *= 0.5;
@@ -277,8 +202,7 @@ public partial class OverlayDialogHost
var topOffset = Math.Max(0, Bounds.Height - control.Bounds.Height - offset); var topOffset = Math.Max(0, Bounds.Height - control.Bounds.Height - offset);
top = MathHelpers.SafeClamp(top, 0, topOffset); top = MathHelpers.SafeClamp(top, 0, topOffset);
} }
return top; return top;
} }
} }

View File

@@ -42,7 +42,7 @@ public partial class OverlayDialogHost
} }
else else
{ {
await Task.WhenAll(animation.RunAsync(control), _maskAppearAnimation.RunAsync(mask)); await Task.WhenAll(animation.RunAsync(control), MaskAppearAnimation.RunAsync(mask));
} }
} }
} }
@@ -67,7 +67,7 @@ public partial class OverlayDialogHost
} }
else else
{ {
await Task.WhenAll(animation.RunAsync(control), _maskAppearAnimation.RunAsync(mask)); await Task.WhenAll(animation.RunAsync(control), MaskAppearAnimation.RunAsync(mask));
} }
var element = control.GetVisualDescendants().OfType<InputElement>().FirstOrDefault(a => a.Focusable); var element = control.GetVisualDescendants().OfType<InputElement>().FirstOrDefault(a => a.Focusable);
element?.Focus(); element?.Focus();
@@ -174,7 +174,7 @@ public partial class OverlayDialogHost
if (!IsAnimationDisabled) if (!IsAnimationDisabled)
{ {
var disappearAnimation = CreateAnimation(control.Bounds.Size, control.Position, false); var disappearAnimation = CreateAnimation(control.Bounds.Size, control.Position, false);
await Task.WhenAll(disappearAnimation.RunAsync(control), _maskDisappearAnimation.RunAsync(layer.Mask)); await Task.WhenAll(disappearAnimation.RunAsync(control), MaskDisappearAnimation.RunAsync(layer.Mask));
} }
Children.Remove(layer.Mask); Children.Remove(layer.Mask);
} }

View File

@@ -14,8 +14,8 @@ namespace Ursa.Controls;
public partial class OverlayDialogHost: Canvas public partial class OverlayDialogHost: Canvas
{ {
private static readonly Animation _maskAppearAnimation; private static readonly Animation MaskAppearAnimation;
private static readonly Animation _maskDisappearAnimation; private static readonly Animation MaskDisappearAnimation;
private readonly List<DialogPair> _layers = new List<DialogPair>(10); private readonly List<DialogPair> _layers = new List<DialogPair>(10);
@@ -61,8 +61,8 @@ public partial class OverlayDialogHost: Canvas
static OverlayDialogHost() static OverlayDialogHost()
{ {
ClipToBoundsProperty.OverrideDefaultValue<OverlayDialogHost>(true); ClipToBoundsProperty.OverrideDefaultValue<OverlayDialogHost>(true);
_maskAppearAnimation = CreateOpacityAnimation(true); MaskAppearAnimation = CreateOpacityAnimation(true);
_maskDisappearAnimation = CreateOpacityAnimation(false); MaskDisappearAnimation = CreateOpacityAnimation(false);
} }
private static Animation CreateOpacityAnimation(bool appear) private static Animation CreateOpacityAnimation(bool appear)
@@ -128,28 +128,21 @@ public partial class OverlayDialogHost: Canvas
{ {
return; return;
} }
if (sender is PureRectangle mask) if (sender is not PureRectangle mask) return;
if(TopLevel.GetTopLevel(mask) is Window window)
{ {
var window = this.GetVisualAncestors().OfType<Window>().FirstOrDefault(); window.BeginMoveDrag(e);
if(window is not null)
{
window.BeginMoveDrag(e);
}
} }
} }
private void ClickMaskToCloseDialog(object? sender, PointerReleasedEventArgs e) private void ClickMaskToCloseDialog(object? sender, PointerReleasedEventArgs e)
{ {
if (sender is PureRectangle border) if (sender is not PureRectangle border) return;
{ var layer = _layers.FirstOrDefault(a => a.Mask == border);
var layer = _layers.FirstOrDefault(a => a.Mask == border); if (layer is null) return;
if (layer is not null) border.RemoveHandler(PointerReleasedEvent, ClickMaskToCloseDialog);
{ border.RemoveHandler(PointerPressedEvent, DragMaskToMoveWindow);
layer.Element.Close(); layer.Element.Close();
border.RemoveHandler(PointerReleasedEvent, ClickMaskToCloseDialog);
border.RemoveHandler(PointerPressedEvent, DragMaskToMoveWindow);
}
}
} }
private IDisposable? _modalStatusSubscription; private IDisposable? _modalStatusSubscription;
private int? _toplevelHash; private int? _toplevelHash;

View File

@@ -20,7 +20,6 @@ public abstract class OverlayFeedbackElement : ContentControl
nameof(Closed), RoutingStrategies.Bubble); nameof(Closed), RoutingStrategies.Bubble);
private bool _resizeDragging; private bool _resizeDragging;
private bool _moveDragging;
protected Panel? ContainerPanel; protected Panel? ContainerPanel;
private Rect _resizeDragStartBounds; private Rect _resizeDragStartBounds;
@@ -142,6 +141,7 @@ public abstract class OverlayFeedbackElement : ContentControl
Canvas.SetTop(this, newBounds.Top); Canvas.SetTop(this, newBounds.Top);
SetCurrentValue(WidthProperty, newBounds.Width); SetCurrentValue(WidthProperty, newBounds.Width);
SetCurrentValue(HeightProperty, newBounds.Height); SetCurrentValue(HeightProperty, newBounds.Height);
AnchorAndUpdatePositionInfo();
} }
private Rect CalculateNewBounds(double left, double top, double width, double height, Vector diff, Rect? containerBounds, private Rect CalculateNewBounds(double left, double top, double width, double height, Vector diff, Rect? containerBounds,