mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-29 15:19:12 +08:00
Reconstruct Demension and add four arithmetic operations
This commit is contained in:
+175
-12
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user