Reconstruct Demension and add four arithmetic operations

This commit is contained in:
chinboy
2025-09-09 10:39:33 +08:00
parent 73f8c4bda9
commit 81918b1cd8
9 changed files with 214 additions and 151 deletions
+175 -12
View File
@@ -12,6 +12,14 @@ public enum DimensionUnitType
public struct Dimension: IEquatable<Dimension>
{
public DimensionUnitType UnitType => _type;
public bool IsPercentage => _type == DimensionUnitType.Percentage;
public bool IsAbsolute => _type == DimensionUnitType.Pixel;
public double Value => _value;
private readonly DimensionUnitType _type;
private readonly double _value;
@@ -35,17 +43,131 @@ public struct Dimension: IEquatable<Dimension>
_type = type;
_value = value;
}
public DimensionUnitType UnitType => _type;
public bool IsAbsolute => _type == DimensionUnitType.Pixel;
public bool IsPercentage => _type == DimensionUnitType.Percentage;
public bool IsPixel => _type == DimensionUnitType.Pixel;
public double Value => _value;
public double Resolve(double referenceSize)
{
return _type switch
{
DimensionUnitType.Percentage => _value * referenceSize / 100.0,
DimensionUnitType.Pixel => _value,
_ => _value
};
}
private static void ValidateSameUnit(Dimension a, Dimension b)
{
if (a._type != b._type)
{
throw new InvalidOperationException("Cannot perform operation on dimensions with different units");
}
}
#region 自定义四则运算符
public static Dimension operator +(Dimension a, Dimension b)
{
ValidateSameUnit(a, b);
return new Dimension(a._value + b._value, a._type);
}
public static Dimension operator +(Dimension a, double b)
{
return new Dimension(a._value + b, a._type);
}
public static Dimension operator +(double a, Dimension b)
{
return new Dimension(a + b._value, b._type);
}
public static Dimension operator -(Dimension a, Dimension b)
{
ValidateSameUnit(a, b);
return new Dimension(a._value - b._value, a._type);
}
public static Dimension operator -(Dimension a, double b)
{
return new Dimension(a._value - b, a._type);
}
public static Dimension operator -(double a, Dimension b)
{
return new Dimension(a - b._value, b._type);
}
public static Dimension operator *(Dimension a, Dimension b)
{
ValidateSameUnit(a, b);
return new Dimension(a._value * b._value, a._type);
}
public static Dimension operator *(Dimension a, double b)
{
return new Dimension(a._value * b, a._type);
}
public static Dimension operator *(double a, Dimension b)
{
return new Dimension(a * b._value, b._type);
}
public static Dimension operator /(Dimension a, Dimension b)
{
ValidateSameUnit(a, b);
if (Math.Abs(b._value) < double.Epsilon)
{
throw new DivideByZeroException("Division by zero");
}
return new Dimension(a._value / b._value, a._type);
}
public static Dimension operator /(Dimension a, double b)
{
if (Math.Abs(b) < double.Epsilon)
{
throw new DivideByZeroException("Division by zero");
}
return new Dimension(a._value / b, a._type);
}
public static Dimension operator /(double a, Dimension b)
{
if (Math.Abs(b._value) < double.Epsilon)
{
throw new DivideByZeroException("Division by zero");
}
return new Dimension(a / b._value, b._type);
}
public static Dimension operator %(Dimension a, Dimension b)
{
ValidateSameUnit(a, b);
if (Math.Abs(b._value) < double.Epsilon)
{
throw new DivideByZeroException("Modulo by zero");
}
return new Dimension(a._value % b._value, a._type);
}
public static Dimension operator %(Dimension a, double b)
{
if (Math.Abs(b) < double.Epsilon)
{
throw new DivideByZeroException("Modulo by zero");
}
return new Dimension(a._value % b, a._type);
}
public static Dimension operator +(Dimension a) => a;
public static Dimension operator -(Dimension a)
{
return new Dimension(-a._value, a._type);
}
#endregion
public static bool operator ==(Dimension a, Dimension b)
{
return (MathUtils.AreClose(a._value, b._value) && a._type == b._type);
@@ -56,6 +178,30 @@ public struct Dimension: IEquatable<Dimension>
return !(gl1 == gl2);
}
public static bool operator <(Dimension a, Dimension b)
{
ValidateSameUnit(a, b);
return a._value < b._value;
}
public static bool operator >(Dimension a, Dimension b)
{
ValidateSameUnit(a, b);
return a._value > b._value;
}
public static bool operator <=(Dimension a, Dimension b)
{
ValidateSameUnit(a, b);
return a._value <= b._value;
}
public static bool operator >=(Dimension a, Dimension b)
{
ValidateSameUnit(a, b);
return a._value >= b._value;
}
public override bool Equals(object? o)
{
if (o == null)
@@ -78,7 +224,7 @@ public struct Dimension: IEquatable<Dimension>
public override int GetHashCode()
{
return _value.GetHashCode() ^ _type.GetHashCode();
return HashCode.Combine(_value, _type);
}
public override string ToString()
@@ -123,4 +269,21 @@ public struct Dimension: IEquatable<Dimension>
return result;
}
public static Dimension Min(Dimension a, Dimension b)
{
ValidateSameUnit(a, b);
return new Dimension(Math.Min(a._value, b._value), a._type);
}
public static Dimension Max(Dimension a, Dimension b)
{
ValidateSameUnit(a, b);
return new Dimension(Math.Max(a._value, b._value), a._type);
}
public static Dimension Clamp(Dimension value, Dimension min, Dimension max)
{
ValidateSameUnit(value, min);
ValidateSameUnit(value, max);
return new Dimension(Math.Clamp(value._value, min._value, max._value), value._type);
}
}
+8 -27
View File
@@ -58,12 +58,6 @@ public class Dialog : Control,
public static readonly StyledProperty<bool> IsDragMovableProperty =
AvaloniaProperty.Register<Dialog, bool>(nameof (IsDragMovable), false);
public static readonly StyledProperty<DialogHorizontalPlacement> HorizontalPlacementProperty =
AvaloniaProperty.Register<Dialog, DialogHorizontalPlacement>(nameof(HorizontalPlacement));
public static readonly StyledProperty<DialogVerticalPlacement> VerticalPlacementProperty =
AvaloniaProperty.Register<Dialog, DialogVerticalPlacement>(nameof(VerticalPlacement));
public static readonly StyledProperty<Rect?> PlacementRectProperty =
AvaloniaProperty.Register<Dialog, Rect?>(nameof(PlacementRect));
@@ -82,11 +76,11 @@ public class Dialog : Control,
public static readonly StyledProperty<bool> IsLightDismissEnabledProperty =
AvaloniaProperty.Register<Dialog, bool>(nameof(IsLightDismissEnabled), false);
public static readonly StyledProperty<double> HorizontalOffsetProperty =
AvaloniaProperty.Register<Dialog, double>(nameof(HorizontalOffset));
public static readonly StyledProperty<Dimension> HorizontalOffsetProperty =
AvaloniaProperty.Register<Dialog, Dimension>(nameof(HorizontalOffset));
public static readonly StyledProperty<double> VerticalOffsetProperty =
AvaloniaProperty.Register<Dialog, double>(nameof(VerticalOffset));
public static readonly StyledProperty<Dimension> VerticalOffsetProperty =
AvaloniaProperty.Register<Dialog, Dimension>(nameof(VerticalOffset));
public static readonly StyledProperty<bool> TopmostProperty =
AvaloniaProperty.Register<Dialog, bool>(nameof(Topmost));
@@ -163,18 +157,6 @@ public class Dialog : Control,
set => SetValue(IsDragMovableProperty, value);
}
public DialogHorizontalPlacement HorizontalPlacement
{
get => GetValue(HorizontalPlacementProperty);
set => SetValue(HorizontalPlacementProperty, value);
}
public DialogVerticalPlacement VerticalPlacement
{
get => GetValue(VerticalPlacementProperty);
set => SetValue(VerticalPlacementProperty, value);
}
public Rect? PlacementRect
{
get => GetValue(PlacementRectProperty);
@@ -206,13 +188,13 @@ public class Dialog : Control,
set => SetValue(OverlayInputPassThroughElementProperty, value);
}
public double HorizontalOffset
public Dimension HorizontalOffset
{
get => GetValue(HorizontalOffsetProperty);
set => SetValue(HorizontalOffsetProperty, value);
}
public double VerticalOffset
public Dimension VerticalOffset
{
get => GetValue(VerticalOffsetProperty);
set => SetValue(VerticalOffsetProperty, value);
@@ -749,9 +731,8 @@ public class Dialog : Control,
{
dialogHost.ConfigurePosition(new DialogPositionRequest(
placementTarget,
HorizontalPlacement,
VerticalPlacement,
new Point(HorizontalOffset, VerticalOffset),
HorizontalOffset,
VerticalOffset,
PlacementRect ?? new Rect(default, placementTarget.Bounds.Size),
CustomDialogPlacementCallback));
}
@@ -1,19 +0,0 @@
namespace AtomUI.Controls;
[Flags]
public enum DialogHorizontalPlacement
{
Left,
Center,
Right,
Custom
}
[Flags]
public enum DialogVerticalPlacement
{
Top,
Center,
Bottom,
Custom
}
@@ -6,22 +6,21 @@ namespace AtomUI.Controls;
public class DialogPositionRequest
{
internal DialogPositionRequest(Visual target,
DialogHorizontalPlacement horizontalPlacement,
DialogVerticalPlacement verticalPlacement,
Point offset,
Dimension horizontalOffset,
Dimension verticalOffset,
Rect? anchorRect = null,
CustomDialogPlacementCallback? placementCallback = null)
{
Target = target;
HorizontalPlacement = horizontalPlacement;
VerticalPlacement = verticalPlacement;
Offset = offset;
Target = target;
HorizontalOffset = horizontalOffset;
VerticalOffset = verticalOffset;
AnchorRect = anchorRect;
PlacementCallback = placementCallback;
}
public Visual Target { get; }
public DialogHorizontalPlacement HorizontalPlacement { get; set; }
public DialogVerticalPlacement VerticalPlacement { get; set; }
public Point Offset { get; }
public Dimension HorizontalOffset { get; set; }
public Dimension VerticalOffset { get; set; }
public Rect? AnchorRect { get; }
public DialogPositionerConstraintAdjustment ConstraintAdjustment {get;}
public CustomDialogPlacementCallback? PlacementCallback { get; }
@@ -4,12 +4,11 @@ namespace AtomUI.Controls.DialogPositioning;
public record CustomDialogPlacement
{
public DialogHorizontalPlacement HorizontalPlacement { get; set; } = DialogHorizontalPlacement.Center;
public DialogVerticalPlacement VerticalPlacement { get; set; } = DialogVerticalPlacement.Center;
public Dimension HorizontalOffset { get; set; }
public Dimension VerticalOffset { get; set; }
public Size DialogSize { get; }
public Visual Target { get; }
public Point Offset { get; set; }
public DialogPositionerConstraintAdjustment ConstraintAdjustment { get; set; }
public Rect AnchorRectangle { get; set; }
@@ -5,11 +5,10 @@ namespace AtomUI.Controls.DialogPositioning;
public record struct DialogPositionerParameters
{
public Rect AnchorRectangle { get; set; }
public DialogHorizontalPlacement HorizontalPlacement { get; set; }
public DialogVerticalPlacement VerticalPlacement { get; set; }
public Dimension HorizontalOffset { get; set; }
public Dimension VerticalOffset { get; set; }
public Size Size { get; set; }
public DialogPositionerConstraintAdjustment ConstraintAdjustment { get; set; }
public Point Offset { get; set; }
}
public interface IDialogPositioner
@@ -94,32 +93,27 @@ internal static class DialogPositionerExtensions
Size dialogSize)
{
DialogPositionerParameters positionerParameters = default;
positionerParameters.Offset = positionRequest.Offset;
positionerParameters.HorizontalOffset = positionRequest.HorizontalOffset;
positionerParameters.VerticalOffset = positionRequest.VerticalOffset;
positionerParameters.Size = dialogSize;
positionerParameters.ConstraintAdjustment = positionRequest.ConstraintAdjustment;
if (positionRequest.HorizontalPlacement == DialogHorizontalPlacement.Custom ||
positionRequest.VerticalPlacement == DialogVerticalPlacement.Custom)
if (positionRequest.PlacementCallback != null)
{
if (positionRequest.PlacementCallback is null)
throw new InvalidOperationException(
"CustomDialogPlacementCallback property must be set, when Placement=PlacementMode.Custom");
var customPlacementParameters = new CustomDialogPlacement(
dialogSize,
positionRequest.Target)
{
HorizontalPlacement = positionerParameters.HorizontalPlacement,
VerticalPlacement = positionerParameters.VerticalPlacement,
HorizontalOffset = positionerParameters.HorizontalOffset,
VerticalOffset = positionerParameters.VerticalOffset,
ConstraintAdjustment = positionerParameters.ConstraintAdjustment,
Offset = positionerParameters.Offset
};
positionRequest.PlacementCallback.Invoke(customPlacementParameters);
positionerParameters.HorizontalPlacement = customPlacementParameters.HorizontalPlacement;
positionerParameters.VerticalPlacement = customPlacementParameters.VerticalPlacement;
positionerParameters.HorizontalOffset = customPlacementParameters.HorizontalOffset;
positionerParameters.VerticalOffset = customPlacementParameters.VerticalOffset;
positionerParameters.ConstraintAdjustment = customPlacementParameters.ConstraintAdjustment;
positionerParameters.Offset = customPlacementParameters.Offset;
}
return positionerParameters;
}
@@ -39,10 +39,9 @@ public class ManagedDialogPositioner : IDialogPositioner
new Rect(
parameters.AnchorRectangle.TopLeft * _dialog.Scaling,
parameters.AnchorRectangle.Size * _dialog.Scaling),
parameters.HorizontalPlacement,
parameters.VerticalPlacement,
parameters.ConstraintAdjustment,
parameters.Offset * _dialog.Scaling);
parameters.HorizontalOffset,
parameters.VerticalOffset,
parameters.ConstraintAdjustment);
_dialog.MoveAndResize(
rect.Position,
@@ -51,10 +50,9 @@ public class ManagedDialogPositioner : IDialogPositioner
private Rect Calculate(Size translatedSize,
Rect anchorRect,
DialogHorizontalPlacement horizontalPlacement,
DialogVerticalPlacement verticalPlacement,
DialogPositionerConstraintAdjustment constraintAdjustment,
Point offset)
Dimension horizontalOffset,
Dimension verticalOffset,
DialogPositionerConstraintAdjustment constraintAdjustment)
{
var parentGeometry = _dialog.ParentClientAreaScreenGeometry;
anchorRect = anchorRect.Translate(parentGeometry.TopLeft);
@@ -96,42 +94,8 @@ public class ManagedDialogPositioner : IDialogPositioner
static bool IsValid(in Rect rc) => rc.Width > 0 && rc.Height > 0;
var offsetX = 0.0d;
var offsetY = 0.0d;
if (horizontalPlacement == DialogHorizontalPlacement.Left)
{
offsetX = 0;
}
else if (horizontalPlacement == DialogHorizontalPlacement.Right)
{
offsetX = bounds.Right - translatedSize.Width;
}
else if (horizontalPlacement == DialogHorizontalPlacement.Center)
{
offsetX = (bounds.Width - translatedSize.Width) / 2;
}
else
{
offsetX = offset.X;
}
if (verticalPlacement == DialogVerticalPlacement.Top)
{
offsetY = 0;
}
else if (verticalPlacement == DialogVerticalPlacement.Bottom)
{
offsetY = bounds.Bottom - translatedSize.Height;
}
else if (verticalPlacement == DialogVerticalPlacement.Center)
{
offsetY = (bounds.Height - translatedSize.Height) / 2;
}
else
{
offsetY = offset.Y;
}
var offsetX = horizontalOffset.Resolve(bounds.Width);
var offsetY = verticalOffset.Resolve(bounds.Height);
Rect geo = new Rect(new Point(offsetX, offsetY), translatedSize);
@@ -34,12 +34,6 @@ public sealed class OverlayDialogHost : ContentControl,
public static readonly StyledProperty<bool> IsModalProperty =
Dialog.IsModalProperty.AddOwner<OverlayDialogHost>();
public static readonly StyledProperty<DialogHorizontalPlacement> HorizontalPlacementProperty =
Dialog.HorizontalPlacementProperty.AddOwner<OverlayDialogHost>();
public static readonly StyledProperty<DialogVerticalPlacement> VerticalPlacementProperty =
Dialog.VerticalPlacementProperty.AddOwner<OverlayDialogHost>();
public static readonly StyledProperty<Transform?> TransformProperty =
AvaloniaProperty.Register<OverlayDialogHost, Transform?>(nameof (Transform));
@@ -76,18 +70,6 @@ public sealed class OverlayDialogHost : ContentControl,
set => SetValue(IsModalProperty, value);
}
public DialogHorizontalPlacement HorizontalPlacement
{
get => GetValue(HorizontalPlacementProperty);
set => SetValue(HorizontalPlacementProperty, value);
}
public DialogVerticalPlacement VerticalPlacement
{
get => GetValue(VerticalPlacementProperty);
set => SetValue(VerticalPlacementProperty, value);
}
public Transform? Transform
{
get => GetValue(TransformProperty);
+2 -2
View File
@@ -36,7 +36,7 @@ public class SkeletonLine : AbstractSkeleton
protected override Size MeasureOverride(Size availableSize)
{
var actualWidth = availableSize.Width;
if (LineWidth.IsPixel)
if (LineWidth.IsAbsolute)
{
actualWidth = LineWidth.Value;
}
@@ -48,7 +48,7 @@ public class SkeletonLine : AbstractSkeleton
{
var size = base.ArrangeOverride(finalSize);
var actualWidth = finalSize.Width;
if (!LineWidth.IsPixel)
if (!LineWidth.IsAbsolute)
{
if (!double.IsInfinity(actualWidth))
{