Browse Source

Merge 78bcdaa4b8 into 658afb8717

pull/20945/merge
Nathan Nguyen 16 hours ago
committed by GitHub
parent
commit
cd60d73064
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      src/Avalonia.Controls.ColorPicker/Avalonia.Controls.ColorPicker.csproj
  2. 2
      src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPicker.xaml
  3. 2
      src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml
  4. 2
      src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorPicker.xaml
  5. 2
      src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorView.xaml
  6. 1
      tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj
  7. 110
      tests/Avalonia.Controls.UnitTests/ColorPickerTests/ColorPickerHelpersTests.cs

1
src/Avalonia.Controls.ColorPicker/Avalonia.Controls.ColorPicker.csproj

@ -23,6 +23,7 @@
<ItemGroup Label="InternalsVisibleTo">
<InternalsVisibleTo Include="Avalonia.DesignerSupport, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Controls.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
</ItemGroup>
</Project>

2
src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPicker.xaml

@ -122,7 +122,7 @@
AutomationProperties.Name="Third Component"
Grid.Column="0"
IsAlphaVisible="False"
IsPerceptive="True"
IsPerceptive="False"
Orientation="Vertical"
ColorModel="Hsva"
ColorComponent="{Binding ThirdComponent, ElementName=ColorSpectrum}"

2
src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml

@ -366,7 +366,7 @@
AutomationProperties.Name="Third Component"
Grid.Column="0"
IsAlphaVisible="False"
IsPerceptive="True"
IsPerceptive="False"
Orientation="Vertical"
ColorModel="Hsva"
ColorComponent="{Binding ThirdComponent, ElementName=ColorSpectrum}"

2
src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorPicker.xaml

@ -123,7 +123,7 @@
AutomationProperties.Name="Third Component"
Grid.Column="0"
IsAlphaVisible="False"
IsPerceptive="True"
IsPerceptive="False"
Orientation="Vertical"
ColorModel="Hsva"
ColorComponent="{Binding ThirdComponent, ElementName=ColorSpectrum}"

2
src/Avalonia.Controls.ColorPicker/Themes/Simple/ColorView.xaml

@ -329,7 +329,7 @@
AutomationProperties.Name="Third Component"
Grid.Column="0"
IsAlphaVisible="False"
IsPerceptive="True"
IsPerceptive="False"
Orientation="Vertical"
ColorModel="Hsva"
ColorComponent="{Binding ThirdComponent, ElementName=ColorSpectrum}"

1
tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj

@ -23,6 +23,7 @@
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.ColorPicker\Avalonia.Controls.ColorPicker.csproj" />
<ProjectReference Include="..\Avalonia.UnitTests\Avalonia.UnitTests.csproj" />
<Compile Include="../Shared/ScopedSanityCheck.cs"/>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />

110
tests/Avalonia.Controls.UnitTests/ColorPickerTests/ColorPickerHelpersTests.cs

@ -0,0 +1,110 @@
using System;
using System.Threading.Tasks;
using Avalonia.Collections.Pooled;
using Avalonia.Controls.Primitives;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Controls.UnitTests.ColorPickerTests;
/// <summary>
/// Tests that <see cref="ColorPickerHelpers.CreateComponentBitmapAsync"/> produces
/// accurate pixel output when <c>isPerceptive=false</c> — the mode the ColorSpectrum's
/// third-component slider should use.
///
/// Regression tests for https://github.com/AvaloniaUI/Avalonia/issues/20925
/// </summary>
public class ColorPickerHelpersTests : ScopedTestBase
{
/// <summary>
/// When sweeping Hue at a fixed desaturated selection (S=0.2, V=0.5),
/// every pixel's brightest channel should be bounded by V — not boosted to 255.
/// </summary>
[Fact]
public async Task Hue_Slider_Bitmap_Reflects_Actual_Saturation_And_Value()
{
var selection = new HsvColor(alpha: 1.0, hue: 180, saturation: 0.2, value: 0.5);
using var pixels = await GenerateSliderBitmap(ColorComponent.Component1, selection, height: 360);
// Sample mid-strip. In HSV, max RGB channel = V for any hue.
var (r, g, b) = ReadPixel(pixels, row: 180);
var maxChannel = Math.Max(r, Math.Max(g, b));
double expectedMax = selection.V * 255;
Assert.InRange(maxChannel, expectedMax - 10, expectedMax + 10);
}
/// <summary>
/// When sweeping Saturation, the brightest channel at full saturation is bounded
/// by the current Value — not forced to 255 by perceptive V=1.0 override.
/// </summary>
[Theory]
[InlineData(0.1)]
[InlineData(0.5)]
[InlineData(0.9)]
public async Task Saturation_Slider_Bitmap_Respects_Current_Value(double currentValue)
{
var selection = new HsvColor(alpha: 1.0, hue: 200, saturation: 0.8, value: currentValue);
using var pixels = await GenerateSliderBitmap(ColorComponent.Component2, selection);
// Row 0 = highest saturation (bitmap sweeps high→low top-to-bottom).
var (r, g, b) = ReadPixel(pixels, row: 0);
var maxChannel = Math.Max(r, Math.Max(g, b));
double expectedMax = currentValue * 255;
Assert.InRange(maxChannel, expectedMax - 20, expectedMax + 20);
}
/// <summary>
/// When sweeping Value at low Saturation (S=0.1), the top pixel should be
/// near-grey (low chroma) — not vivid from a perceptive S=1.0 override.
/// </summary>
[Fact]
public async Task Value_Slider_Bitmap_Respects_Current_Saturation()
{
var selection = new HsvColor(alpha: 1.0, hue: 30, saturation: 0.1, value: 0.8);
using var pixels = await GenerateSliderBitmap(ColorComponent.Component3, selection);
// Row 0 = highest Value. In HSV, chroma = V * S * 255 ≤ S * 255.
var (r, g, b) = ReadPixel(pixels, row: 0);
int chroma = Math.Max(r, Math.Max(g, b)) - Math.Min(r, Math.Min(g, b));
// At S=0.1 the max possible chroma is 25.5 — near-grey for any V.
// With perceptive S=1.0 override, chroma would be ~252.
Assert.InRange(chroma, 0, selection.S * 255 + 10);
}
private static async Task<PooledList<byte>> GenerateSliderBitmap(
ColorComponent component,
HsvColor baseColor,
int height = 100)
{
const int width = 1;
var buffer = new PooledList<byte>(width * height * 4, ClearMode.Never, sizeToCapacity: true);
await ColorPickerHelpers.CreateComponentBitmapAsync(
buffer, width, height,
Orientation.Vertical,
ColorModel.Hsva,
component,
baseColor,
isAlphaVisible: false,
isPerceptive: false);
return buffer;
}
/// <summary>
/// Reads a pixel from a 1-pixel-wide vertical BGRA bitmap at the given row.
/// </summary>
private static (byte R, byte G, byte B) ReadPixel(PooledList<byte> bgraData, int row)
{
int offset = row * 4;
return (R: bgraData[offset + 2], G: bgraData[offset + 1], B: bgraData[offset]);
}
}
Loading…
Cancel
Save