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

View File

@@ -204,4 +204,50 @@ public abstract class DialogControlBase : OverlayFeedbackElement
} }
#endregion #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); 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)); RaiseEvent(new ResultEventArgs(ClosedEvent, result));
} }
} }
protected internal override void AnchorAndUpdatePositionInfo()
{
// throw new NotImplementedException();
}
} }

View File

@@ -91,7 +91,7 @@ public partial class OverlayDialogHost
{ {
if (e.Source is DialogControlBase item) if (e.Source is DialogControlBase item)
{ {
AnchorAndUpdatePositionInfo(item); item.AnchorAndUpdatePositionInfo();
} }
} }
@@ -230,48 +230,7 @@ public partial class OverlayDialogHost
double top = GetTopPosition(control); double top = GetTopPosition(control);
SetLeft(control, left); SetLeft(control, left);
SetTop(control, top); SetTop(control, top);
AnchorAndUpdatePositionInfo(control); control.AnchorAndUpdatePositionInfo();
}
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);
} }
private double GetLeftPosition(DialogControlBase control) private double GetLeftPosition(DialogControlBase control)

View File

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