Refactor and enhance overlay feedback handling

- Promote `_containerPanel` to a protected property for better accessibility
- Extract `CoerceDelta` method to centralize constraint logic
- Implement `AnchorAndUpdatePositionInfo` across dialog controls for consistent positioning behavior
- Adjust margin binding for `DialogResizer` to include parent border margin
- Simplify pointer movement calculations and conditional checks
This commit is contained in:
rabbitism
2024-09-18 02:08:58 +08:00
parent dcba26e8af
commit 5799646488
6 changed files with 95 additions and 81 deletions

View File

@@ -55,7 +55,7 @@
</Grid>
</Border>
</Border>
<u:DialogResizer IsVisible="{TemplateBinding CanResize}" />
<u:DialogResizer IsVisible="{TemplateBinding CanResize}" Margin="{Binding #PART_Border.Margin}" />
</Panel>
</ControlTemplate>
</Setter>
@@ -242,7 +242,7 @@
</Grid>
</Border>
</Border>
<u:DialogResizer IsVisible="{TemplateBinding CanResize}"/>
<u:DialogResizer IsVisible="{TemplateBinding CanResize}" Margin="{Binding #PART_Border.Margin}"/>
</Panel>
</ControlTemplate>
</Setter>

View File

@@ -204,4 +204,50 @@ public abstract class DialogControlBase : OverlayFeedbackElement
}
#endregion
protected internal override void AnchorAndUpdatePositionInfo()
{
if (ContainerPanel is null) return;
ActualHorizontalAnchor = HorizontalPosition.Center;
ActualVerticalAnchor = VerticalPosition.Center;
double left = Canvas.GetLeft(this);
double top = Canvas.GetTop(this);
double right = ContainerPanel.Bounds.Width - left - Bounds.Width;
double bottom = ContainerPanel.Bounds.Height - top - Bounds.Height;
if (ContainerPanel is OverlayDialogHost h)
{
var snapThickness = h.SnapThickness;
if(top < snapThickness.Top)
{
Canvas.SetTop(this, 0);
ActualVerticalAnchor = VerticalPosition.Top;
VerticalOffsetRatio = 0;
}
if(bottom < snapThickness.Bottom)
{
Canvas.SetTop(this, ContainerPanel.Bounds.Height - Bounds.Height);
ActualVerticalAnchor = VerticalPosition.Bottom;
VerticalOffsetRatio = 1;
}
if(left < snapThickness.Left)
{
Canvas.SetLeft(this, 0);
ActualHorizontalAnchor = HorizontalPosition.Left;
HorizontalOffsetRatio = 0;
}
if(right < snapThickness.Right)
{
Canvas.SetLeft(this, ContainerPanel.Bounds.Width - this.Bounds.Width);
ActualHorizontalAnchor = HorizontalPosition.Right;
HorizontalOffsetRatio = 1;
}
}
left = Canvas.GetLeft(this);
top = Canvas.GetTop(this);
right = ContainerPanel.Bounds.Width - left - Bounds.Width;
bottom = ContainerPanel.Bounds.Height - top - Bounds.Height;
HorizontalOffsetRatio = (left + right) == 0 ? 0 : left / (left + right);
VerticalOffsetRatio = (top + bottom) == 0 ? 0 : top / (top + bottom);
}
}

View File

@@ -25,4 +25,9 @@ public class CustomDrawerControl: DrawerControlBase
OnElementClosing(this, null);
}
}
protected internal override void AnchorAndUpdatePositionInfo()
{
// throw new NotImplementedException();
}
}

View File

@@ -135,4 +135,9 @@ public class DefaultDrawerControl : DrawerControlBase
RaiseEvent(new ResultEventArgs(ClosedEvent, result));
}
}
protected internal override void AnchorAndUpdatePositionInfo()
{
// throw new NotImplementedException();
}
}

View File

@@ -28,8 +28,8 @@ public partial class OverlayDialogHost
}
var width = newSize.Width - control.Bounds.Width;
var height = newSize.Height - control.Bounds.Height;
var newLeft = width * control.HorizontalOffsetRatio??0;
var newTop = height * control.VerticalOffsetRatio??0;
var newLeft = width * control.HorizontalOffsetRatio ?? 0;
var newTop = height * control.VerticalOffsetRatio ?? 0;
if(control.ActualHorizontalAnchor == HorizontalPosition.Left)
{
newLeft = 0;
@@ -91,7 +91,7 @@ public partial class OverlayDialogHost
{
if (e.Source is DialogControlBase item)
{
AnchorAndUpdatePositionInfo(item);
item.AnchorAndUpdatePositionInfo();
}
}
@@ -230,48 +230,7 @@ public partial class OverlayDialogHost
double top = GetTopPosition(control);
SetLeft(control, left);
SetTop(control, top);
AnchorAndUpdatePositionInfo(control);
}
private void AnchorAndUpdatePositionInfo(DialogControlBase control)
{
control.ActualHorizontalAnchor = HorizontalPosition.Center;
control.ActualVerticalAnchor = VerticalPosition.Center;
double left = GetLeft(control);
double top = GetTop(control);
double right = Bounds.Width - left - control.Bounds.Width;
double bottom = Bounds.Height - top - control.Bounds.Height;
if(top < SnapThickness.Top)
{
SetTop(control, 0);
control.ActualVerticalAnchor = VerticalPosition.Top;
control.VerticalOffsetRatio = 0;
}
if(bottom < SnapThickness.Bottom)
{
SetTop(control, Bounds.Height - control.Bounds.Height);
control.ActualVerticalAnchor = VerticalPosition.Bottom;
control.VerticalOffsetRatio = 1;
}
if(left < SnapThickness.Left)
{
SetLeft(control, 0);
control.ActualHorizontalAnchor = HorizontalPosition.Left;
control.HorizontalOffsetRatio = 0;
}
if(right < SnapThickness.Right)
{
SetLeft(control, Bounds.Width - control.Bounds.Width);
control.ActualHorizontalAnchor = HorizontalPosition.Right;
control.HorizontalOffsetRatio = 1;
}
left = GetLeft(control);
top = GetTop(control);
right = Bounds.Width - left - control.Bounds.Width;
bottom = Bounds.Height - top - control.Bounds.Height;
control.HorizontalOffsetRatio = (left + right) == 0 ? 0 : left / (left + right);
control.VerticalOffsetRatio = (top + bottom) == 0 ? 0 : top / (top + bottom);
control.AnchorAndUpdatePositionInfo();
}
private double GetLeftPosition(DialogControlBase control)

View File

@@ -22,7 +22,7 @@ public abstract class OverlayFeedbackElement : ContentControl
private bool _resizeDragging;
private bool _moveDragging;
private Panel? _containerPanel;
protected Panel? ContainerPanel;
private Rect _resizeDragStartBounds;
private Point _resizeDragStartPoint;
@@ -110,7 +110,7 @@ public abstract class OverlayFeedbackElement : ContentControl
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
_containerPanel = this.FindAncestorOfType<Panel>();
ContainerPanel = this.FindAncestorOfType<Panel>();
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
@@ -130,73 +130,72 @@ public abstract class OverlayFeedbackElement : ContentControl
base.OnPointerMoved(e);
if (!_resizeDragging || _windowEdge is null) return;
var point = e.GetPosition(this);
var diff = point - _resizeDragStartPoint;
Vector diff = point - _resizeDragStartPoint;
var left = Canvas.GetLeft(this);
var top = Canvas.GetTop(this);
var width = _windowEdge is WindowEdge.West or WindowEdge.NorthWest or WindowEdge.SouthWest
? Bounds.Width : _resizeDragStartBounds.Width;
var height = _windowEdge is WindowEdge.North or WindowEdge.NorthEast or WindowEdge.NorthWest
? Bounds.Height : _resizeDragStartBounds.Height;
var newBounds = CalculateNewBounds(left, top, width, height, diff, _containerPanel?.Bounds, _windowEdge.Value);
var newBounds = CalculateNewBounds(left, top, width, height, diff, ContainerPanel?.Bounds, _windowEdge.Value);
Canvas.SetLeft(this, newBounds.Left);
Canvas.SetTop(this, newBounds.Top);
SetCurrentValue(WidthProperty, newBounds.Width);
SetCurrentValue(HeightProperty, newBounds.Height);
}
private Rect CalculateNewBounds(double left, double top, double width, double height, Point diff, Rect? containerBounds,
private Rect CalculateNewBounds(double left, double top, double width, double height, Vector diff, Rect? containerBounds,
WindowEdge windowEdge)
{
if (containerBounds is not null)
{
var minX = windowEdge is WindowEdge.West or WindowEdge.NorthWest or WindowEdge.SouthWest
? -left
: double.NegativeInfinity;
var minY = windowEdge is WindowEdge.North or WindowEdge.NorthEast or WindowEdge.NorthWest
? -top
: double.NegativeInfinity;
var maxX = containerBounds.Value.Width - left - MinWidth;
var maxY = containerBounds.Value.Height - top - MinHeight;
diff = new Point(MathHelpers.SafeClamp(diff.X, minX, maxX), MathHelpers.SafeClamp(diff.Y, minY, maxY));
}
diff = CoerceDelta(left, top, width, height, diff, containerBounds, windowEdge);
switch (windowEdge)
{
case WindowEdge.North:
top += diff.Y;
height -= diff.Y;
top = Math.Max(0, top);
top += diff.Y; height -= diff.Y;
break;
case WindowEdge.NorthEast:
top += diff.Y;
width += diff.X;
height -= diff.Y;
top += diff.Y; width += diff.X; height -= diff.Y;
break;
case WindowEdge.East:
width += diff.X;
break;
case WindowEdge.SouthEast:
width += diff.X;
height += diff.Y;
width += diff.X; height += diff.Y;
break;
case WindowEdge.South:
height += diff.Y;
break;
case WindowEdge.SouthWest:
left += diff.X;
width -= diff.X;
height += diff.Y;
left += diff.X; width -= diff.X; height += diff.Y;
break;
case WindowEdge.West:
left += diff.X;
width -= diff.X;
left += diff.X; width -= diff.X;
break;
case WindowEdge.NorthWest:
left += diff.X;
top += diff.Y;
width -= diff.X;
height -= diff.Y;
top += diff.Y; width -= diff.X; height -= diff.Y;
break;
}
return new Rect(left, top, width, height);
}
private Vector CoerceDelta(double left, double top, double width, double height, Vector diff, Rect? containerBounds,
WindowEdge windowEdge)
{
if (containerBounds is null) return diff;
var minX = windowEdge is WindowEdge.West or WindowEdge.NorthWest or WindowEdge.SouthWest
? -left
: -width;
var minY = windowEdge is WindowEdge.North or WindowEdge.NorthEast or WindowEdge.NorthWest
? -top
: -height;
var maxX = windowEdge is WindowEdge.West or WindowEdge.NorthWest or WindowEdge.SouthWest
? width-MinWidth
: containerBounds.Value.Width - left - width;
var maxY = windowEdge is WindowEdge.North or WindowEdge.NorthEast or WindowEdge.NorthWest
? height-MinWidth
: containerBounds.Value.Height - top - height;
return new Vector(MathHelpers.SafeClamp(diff.X, minX, maxX), MathHelpers.SafeClamp(diff.Y, minY, maxY));
}
protected internal abstract void AnchorAndUpdatePositionInfo();
}