refactor(ColorPicker): replace MathUtilities.Clamp with Math.Clamp for consistency

This commit is contained in:
chinboy
2026-05-07 13:12:52 +08:00
parent f377a0b64e
commit 91ec928358
16 changed files with 62 additions and 89 deletions
+1
View File
@@ -4,6 +4,7 @@
<Project Path="src/AtomUI.Controls.Shared/AtomUI.Controls.Shared.csproj" />
<Project Path="src/AtomUI.Controls/AtomUI.Controls.csproj" />
<Project Path="src/AtomUI.Core/AtomUI.Core.csproj" />
<Project Path="src/AtomUI.Desktop.Controls.ColorPicker/AtomUI.Desktop.Controls.ColorPicker.csproj" />
<Project Path="src/AtomUI.Desktop.Controls/AtomUI.Desktop.Controls.csproj" />
<Project Path="src/AtomUI.Fonts.AlibabaSans/AtomUI.Fonts.AlibabaSans.csproj" />
<Project Path="src/AtomUI.Generator/AtomUI.Generator.csproj" />
@@ -5,14 +5,12 @@ using AtomUI.Theme;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Converters;
using Avalonia.Controls.Diagnostics;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Input.Raw;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Threading;
using Avalonia.VisualTree;
namespace AtomUI.Desktop.Controls;
@@ -294,9 +292,6 @@ public abstract class AbstractColorPicker : AvaloniaButton,
_flyoutStateHelper.FlyoutAboutToClose += HandleFlyoutAboutToClose;
_flyoutStateHelper.FlyoutOpened += HandleFlyoutOpened;
_flyoutStateHelper.FlyoutClosed += HandleFlyoutClosed;
_flyoutStateHelper.OpenFlyoutPredicate = FlyoutOpenPredicate;
_flyoutStateHelper.ClickHideFlyoutPredicate = ClickHideFlyoutPredicate;
_flyoutStateHelper[!FlyoutStateHelper.TriggerTypeProperty] = this[!TriggerTypeProperty];
_flyoutStateHelper[!FlyoutStateHelper.MouseEnterDelayProperty] = this[!MouseEnterDelayProperty];
_flyoutStateHelper[!FlyoutStateHelper.MouseLeaveDelayProperty] = this[!MouseLeaveDelayProperty];
@@ -341,7 +336,10 @@ public abstract class AbstractColorPicker : AvaloniaButton,
PickerFlyout = CreatePickerFlyout();
PickerFlyout.Opened += HandlePickerFlyoutOpened;
PickerFlyout.Closed += HandlePickerFlyoutClosed;
PickerFlyout.PresenterCreated += HandlePickerFlyoutPresenterCreated;
if (PickerFlyout is AbstractColorPickerFlyout colorPickerFlyout)
{
colorPickerFlyout.PresenterCreated += HandlePickerFlyoutPresenterCreated;
}
_flyoutStateHelper.Flyout = PickerFlyout;
}
_flyoutStateHelper.AnchorTarget = this;
@@ -392,9 +390,9 @@ public abstract class AbstractColorPicker : AvaloniaButton,
UpdatePseudoClasses();
}
private void HandlePickerFlyoutPresenterCreated(object? sender, FlyoutPresenterCreatedEventArgs args)
private void HandlePickerFlyoutPresenterCreated(object? sender, Control presenter)
{
NotifyFlyoutPresenterCreated(args.Presenter);
NotifyFlyoutPresenterCreated(presenter);
}
protected virtual void NotifyFlyoutOpened()
@@ -440,33 +438,6 @@ public abstract class AbstractColorPicker : AvaloniaButton,
return region.Contains(args.Position);
}
protected virtual bool ClickHideFlyoutPredicate(IPopupHostProvider hostProvider, RawPointerEventArgs args)
{
if (hostProvider.PopupHost != args.Root)
{
if (args.Root is PopupRoot root)
{
var parent = root.Parent;
while (parent != null)
{
if (parent == hostProvider.PopupHost)
{
return false;
}
if (parent is Control parentControl && parentControl.GetVisualRoot() == hostProvider.PopupHost)
{
return false;
}
parent = parent.Parent;
}
}
return true;
}
return false;
}
protected virtual void UpdatePseudoClasses()
{
PseudoClasses.Set(StdPseudoClass.FlyoutOpen, IsFlyoutOpen);
@@ -571,6 +542,6 @@ public abstract class AbstractColorPicker : AvaloniaButton,
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
Dispatcher.UIThread.Post(this.EnableTransitions);
Dispatcher.Post(this.EnableTransitions);
}
}
}
@@ -1,4 +1,5 @@
using Avalonia;
using Avalonia.Controls;
namespace AtomUI.Desktop.Controls;
@@ -57,5 +58,12 @@ internal abstract class AbstractColorPickerFlyout : Flyout
get => GetValue(IsPaletteGroupEnabledProperty);
set => SetValue(IsPaletteGroupEnabledProperty, value);
}
internal event EventHandler<Control>? PresenterCreated;
protected void NotifyPresenterCreated(Control presenter)
{
PresenterCreated?.Invoke(this, presenter);
}
}
}
@@ -169,7 +169,6 @@ public class ColorPicker : AbstractColorPicker
protected override Flyout CreatePickerFlyout()
{
var flyout = new ColorPickerFlyout();
flyout.IsDetectMouseClickEnabled = false;
flyout[!ColorPickerFlyout.IsMotionEnabledProperty] = this[!IsMotionEnabledProperty];
flyout[!ColorPickerFlyout.IsClearEnabledProperty] = this[!IsClearEnabledProperty];
flyout[!ColorPickerFlyout.FormatProperty] = this[!FormatProperty];
@@ -34,6 +34,7 @@ internal class ColorPickerFlyout : AbstractColorPickerFlyout
Presenter[!ColorPickerView.PaletteGroupProperty] = this[!PaletteGroupProperty];
flyoutPresenter.Content = Presenter;
NotifyPresenterCreated(flyoutPresenter);
return flyoutPresenter;
}
}
}
@@ -2,7 +2,6 @@ using Avalonia;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Utilities;
using Thumb = AtomUI.Controls.Primitives.Thumb;
namespace AtomUI.Desktop.Controls;
@@ -130,7 +129,7 @@ internal abstract class AbstractColorPickerSliderTrack : TemplatedControl
var factor = e.Vector / delta;
var oldValue = Value;
SetCurrentValue(ValueProperty, MathUtilities.Clamp(
SetCurrentValue(ValueProperty, Math.Clamp(
Value + delta,
Minimum,
Maximum));
@@ -176,4 +175,4 @@ internal abstract class AbstractColorPickerSliderTrack : TemplatedControl
ApplyThumbDrag(e);
}
}
}
}
@@ -7,7 +7,6 @@ using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Utilities;
using Avalonia.VisualTree;
using Thumb = AtomUI.Controls.Primitives.Thumb;
@@ -174,7 +173,7 @@ internal abstract class AbstractColorSlider : RangeBase
var thumbLength = ThumbSize + double.Epsilon;
var trackLength = Track.Bounds.Width - thumbLength;
var trackPos = posOnTrack.Position.X;
var logicalPos = MathUtilities.Clamp((trackPos - thumbLength * 0.5) / trackLength, 0.0d, 1.0d);
var logicalPos = Math.Clamp((trackPos - thumbLength * 0.5) / trackLength, 0.0d, 1.0d);
var calcVal = Math.Abs(-logicalPos);
var range = Maximum - Minimum;
var finalValue = calcVal * range + Minimum;
@@ -190,4 +189,4 @@ internal abstract class AbstractColorSlider : RangeBase
IsDragging = true;
}
}
}
}
@@ -10,7 +10,6 @@ using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Utilities;
using Avalonia.VisualTree;
using AvaloniaButton = Avalonia.Controls.Button;
@@ -401,7 +400,7 @@ internal class ColorSlider : AbstractColorSlider
{
var baseRgbColor = Color;
byte componentValue = Convert.ToByte(MathUtilities.Clamp(sliderPercent * 255, 0, 255));
byte componentValue = Convert.ToByte(Math.Clamp(sliderPercent * 255, 0, 255));
switch (component)
{
@@ -644,4 +643,4 @@ internal class ColorSlider : AbstractColorSlider
}
return size;
}
}
}
@@ -1,10 +1,10 @@
using System.Diagnostics;
using AtomUI.Desktop.Controls.Themes;
using AtomUI.Utils;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
using Avalonia.Utilities;
using Thumb = AtomUI.Controls.Primitives.Thumb;
namespace AtomUI.Desktop.Controls;
@@ -38,7 +38,7 @@ internal class ColorSliderThumb : Thumb
protected override void OnSizeChanged(SizeChangedEventArgs e)
{
base.OnSizeChanged(e);
Debug.Assert(MathUtilities.AreClose(e.NewSize.Width, e.NewSize.Height));
Debug.Assert(MathUtils.AreClose(e.NewSize.Width, e.NewSize.Height));
CornerRadius = new CornerRadius(e.NewSize.Width / 2);
}
@@ -60,4 +60,4 @@ internal class ColorSliderThumb : Thumb
{
InnerCornerRadius = new CornerRadius(args.NewSize.Width / 2);
}
}
}
@@ -15,7 +15,6 @@ using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Threading;
using Avalonia.Utilities;
namespace AtomUI.Desktop.Controls;
@@ -383,7 +382,7 @@ internal class ColorSpectrum : TemplatedControl
// See discussion: https://github.com/AvaloniaUI/Avalonia/discussions/9077
//
// To work-around this issue the selection ellipse is refreshed here.
Dispatcher.UIThread.Post(UpdateEllipse);
Dispatcher.Post(UpdateEllipse);
// OnAttachedToVisualTree is called after OnApplyTemplate so events cannot be connected here
}
@@ -539,7 +538,7 @@ internal class ColorSpectrum : TemplatedControl
}
/// <inheritdoc/>
protected override void OnGotFocus(GotFocusEventArgs e)
protected override void OnGotFocus(FocusChangedEventArgs e)
{
// We only want to bother with the color name tool tip if we can provide color names.
if (_selectionEllipsePanel != null &&
@@ -554,7 +553,7 @@ internal class ColorSpectrum : TemplatedControl
}
/// <inheritdoc/>
protected override void OnLostFocus(RoutedEventArgs e)
protected override void OnLostFocus(FocusChangedEventArgs e)
{
// We only want to bother with the color name tool tip if we can provide color names.
if (_selectionEllipsePanel != null &&
@@ -943,7 +942,7 @@ internal class ColorSpectrum : TemplatedControl
// The gradient image contains two dimensions of HSL information, but not the third.
// We should keep the third where it already was.
// Note: This can sometimes cause a crash -- possibly due to differences in c# rounding. Therefore, index is now clamped.
Hsv hsvAtPoint = _hsvValues[MathUtilities.Clamp((y * width + x), 0, _hsvValues.Count - 1)];
Hsv hsvAtPoint = _hsvValues[Math.Clamp((y * width + x), 0, _hsvValues.Count - 1)];
var hsvColor = HsvColor;
@@ -992,9 +991,9 @@ internal class ColorSpectrum : TemplatedControl
Hsv hsvColor = new Hsv(HsvColor);
hsvColor.H = MathUtilities.Clamp(hsvColor.H, _minHueFromLastBitmapCreation, _maxHueFromLastBitmapCreation);
hsvColor.S = MathUtilities.Clamp(hsvColor.S, _minSaturationFromLastBitmapCreation / 100.0, _maxSaturationFromLastBitmapCreation / 100.0);
hsvColor.V = MathUtilities.Clamp(hsvColor.V, _minValueFromLastBitmapCreation / 100.0, _maxValueFromLastBitmapCreation / 100.0);
hsvColor.H = Math.Clamp(hsvColor.H, _minHueFromLastBitmapCreation, _maxHueFromLastBitmapCreation);
hsvColor.S = Math.Clamp(hsvColor.S, _minSaturationFromLastBitmapCreation / 100.0, _maxSaturationFromLastBitmapCreation / 100.0);
hsvColor.V = Math.Clamp(hsvColor.V, _minValueFromLastBitmapCreation / 100.0, _maxValueFromLastBitmapCreation / 100.0);
double xPercent = 0;
double yPercent = 0;
@@ -1239,7 +1238,7 @@ internal class ColorSpectrum : TemplatedControl
}
});
await Dispatcher.UIThread.InvokeAsync(() =>
await Dispatcher.InvokeAsync(() =>
{
ColorSpectrumComponents components2 = Components;
_minBitmap = ColorPickerHelpers.CreateBitmapFromPixelData(bgraMinPixelData, pixelWidth, pixelHeight);
@@ -1607,4 +1606,4 @@ internal class ColorSpectrum : TemplatedControl
return lum <= 0.5;
}
}
}
@@ -227,7 +227,6 @@ public class GradientColorPicker : AbstractColorPicker
protected override Flyout CreatePickerFlyout()
{
var flyout = new GradientColorPickerFlyout();
flyout.IsDetectMouseClickEnabled = false;
flyout[!GradientColorPickerFlyout.IsMotionEnabledProperty] = this[!IsMotionEnabledProperty];
flyout[!GradientColorPickerFlyout.IsClearEnabledProperty] = this[!IsClearEnabledProperty];
@@ -357,4 +356,4 @@ public class GradientColorPicker : AbstractColorPicker
ClearColor();
}
#endregion
}
}
@@ -34,6 +34,7 @@ internal class GradientColorPickerFlyout : AbstractColorPickerFlyout
Presenter[!GradientColorPickerView.PaletteGroupProperty] = this[!PaletteGroupProperty];
flyoutPresenter.Content = Presenter;
NotifyPresenterCreated(flyoutPresenter);
return flyoutPresenter;
}
}
}
@@ -4,7 +4,6 @@ using Avalonia;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Threading;
namespace AtomUI.Desktop.Controls;
@@ -88,6 +87,6 @@ internal class PaletteColorItem : AvaloniaRadioButton
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
Dispatcher.UIThread.Post(this.EnableTransitions);
Dispatcher.Post(this.EnableTransitions);
}
}
}
@@ -13,7 +13,7 @@
IsGhostStyle="True"
IsMotionEnabled="{TemplateBinding IsMotionEnabled}">
<atom:ColorPickerCollapse.ItemTemplate>
<DataTemplate>
<DataTemplate x:DataType="atom:ColorPickerPalette">
<ItemsControl ItemsSource="{Binding Colors}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
@@ -41,4 +41,4 @@
Value="{atom:ColorPickerTokenResource ColorPickerPresetPanelWidth}" />
</ControlTheme>
</ResourceDictionary>
</ResourceDictionary>
@@ -9,7 +9,6 @@ using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Utilities;
namespace AtomUI.Desktop.Controls.Primitives;
@@ -223,7 +222,7 @@ internal static class ColorPickerHelpers
{
// Sweep hue
newRgbColor = HsvColor.ToRgb(
MathUtilities.Clamp(componentValue, 0.0, 360.0),
Math.Clamp(componentValue, 0.0, 360.0),
baseHsvColor.S,
baseHsvColor.V,
baseHsvColor.A);
@@ -233,7 +232,7 @@ internal static class ColorPickerHelpers
// Sweep red
newRgbColor = new Color(
baseRgbColor.A,
Convert.ToByte(MathUtilities.Clamp(componentValue, 0.0, 255.0)),
Convert.ToByte(Math.Clamp(componentValue, 0.0, 255.0)),
baseRgbColor.G,
baseRgbColor.B);
}
@@ -247,7 +246,7 @@ internal static class ColorPickerHelpers
// Sweep saturation
newRgbColor = HsvColor.ToRgb(
baseHsvColor.H,
MathUtilities.Clamp(componentValue, 0.0, 1.0),
Math.Clamp(componentValue, 0.0, 1.0),
baseHsvColor.V,
baseHsvColor.A);
}
@@ -257,7 +256,7 @@ internal static class ColorPickerHelpers
newRgbColor = new Color(
baseRgbColor.A,
baseRgbColor.R,
Convert.ToByte(MathUtilities.Clamp(componentValue, 0.0, 255.0)),
Convert.ToByte(Math.Clamp(componentValue, 0.0, 255.0)),
baseRgbColor.B);
}
@@ -271,7 +270,7 @@ internal static class ColorPickerHelpers
newRgbColor = HsvColor.ToRgb(
baseHsvColor.H,
baseHsvColor.S,
MathUtilities.Clamp(componentValue, 0.0, 1.0),
Math.Clamp(componentValue, 0.0, 1.0),
baseHsvColor.A);
}
else
@@ -281,7 +280,7 @@ internal static class ColorPickerHelpers
baseRgbColor.A,
baseRgbColor.R,
baseRgbColor.G,
Convert.ToByte(MathUtilities.Clamp(componentValue, 0.0, 255.0)));
Convert.ToByte(Math.Clamp(componentValue, 0.0, 255.0)));
}
break;
@@ -295,13 +294,13 @@ internal static class ColorPickerHelpers
baseHsvColor.H,
baseHsvColor.S,
baseHsvColor.V,
MathUtilities.Clamp(componentValue, 0.0, 1.0));
Math.Clamp(componentValue, 0.0, 1.0));
}
else
{
// Sweep alpha
newRgbColor = new Color(
Convert.ToByte(MathUtilities.Clamp(componentValue, 0.0, 255.0)),
Convert.ToByte(Math.Clamp(componentValue, 0.0, 255.0)),
baseRgbColor.R,
baseRgbColor.G,
baseRgbColor.B);
@@ -627,4 +626,4 @@ internal static class ColorPickerHelpers
new Vector(96, 96), pixelWidth * 4);
}
}
}
}
@@ -3,7 +3,6 @@
using AtomUI.Media;
using Avalonia.Media;
using Avalonia.Utilities;
namespace AtomUI.Desktop.Controls.Primitives;
@@ -68,10 +67,10 @@ internal struct Rgb
public Color ToColor(double alpha = 1.0)
{
return Color.FromArgb(
(byte)MathUtilities.Clamp(alpha * 255.0, 0x00, 0xFF),
(byte)MathUtilities.Clamp(R * 255.0, 0x00, 0xFF),
(byte)MathUtilities.Clamp(G * 255.0, 0x00, 0xFF),
(byte)MathUtilities.Clamp(B * 255.0, 0x00, 0xFF));
(byte)Math.Clamp(alpha * 255.0, 0x00, 0xFF),
(byte)Math.Clamp(R * 255.0, 0x00, 0xFF),
(byte)Math.Clamp(G * 255.0, 0x00, 0xFF),
(byte)Math.Clamp(B * 255.0, 0x00, 0xFF));
}
/// <summary>
@@ -83,10 +82,10 @@ internal struct Rgb
// Instantiating an HsvColor is unfortunately necessary to use existing conversions
// Clamping must be done here as it isn't done in the conversion method (internal-use only)
HsvColor hsvColor = ColorUtils.ToHsv(
MathUtilities.Clamp(R, 0.0, 1.0),
MathUtilities.Clamp(G, 0.0, 1.0),
MathUtilities.Clamp(B, 0.0, 1.0));
Math.Clamp(R, 0.0, 1.0),
Math.Clamp(G, 0.0, 1.0),
Math.Clamp(B, 0.0, 1.0));
return new Hsv(hsvColor);
}
}
}