Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Drawing;
Expand Down Expand Up @@ -91,8 +91,9 @@ private void PaintCore(PaintEventArgs e)
PaintBackgroundImage(e);

Color? customOnColor = Control.ShouldSerializeBackColor()
? Control.BackColor
: null;
&& Control.BackColor.A == byte.MaxValue
? Control.BackColor
: null;

Color? customBorderColor = Control.FlatAppearance.BorderColor.IsEmpty
? null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Drawing;
Expand Down Expand Up @@ -90,8 +90,9 @@ private void PaintCore(PaintEventArgs e)
PaintBackgroundImage(e);

Color? customOnColor = Control.ShouldSerializeBackColor()
? Control.BackColor
: null;
&& Control.BackColor.A == byte.MaxValue
? Control.BackColor
: null;

Color? customBorderColor = Control.FlatAppearance.BorderColor.IsEmpty
? null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Drawing;
Expand Down Expand Up @@ -88,7 +88,7 @@ public override void RenderControl(Graphics graphics)
metrics,
textSize);

graphics.Clear(Control.BackColor);
PaintControlBackground(graphics);

if (contentBounds.Width <= 0 || contentBounds.Height <= 0)
{
Expand Down Expand Up @@ -218,7 +218,7 @@ private void RenderSwitch(Graphics graphics, Rectangle rect, ToggleSwitchMetrics
Color circleColor = Control.Enabled
? highContrast
? highContrastForeground
: PopupButtonColorMath.GetReadableForeColor(offColor, onColor)
: PopupButtonColorMath.GetReadableForeColor(backgroundColor)
: SystemColors.GrayText;
circleColor = ApplyInteractionShade(circleColor, focus);
borderColor = ApplyInteractionShade(borderColor, focus);
Expand Down Expand Up @@ -329,6 +329,25 @@ private void EnsurePositionInitialized()
_positionInitialized = true;
}

private void PaintControlBackground(Graphics graphics)
{
if (Control.BackgroundImage is null && !Control.BackColor.HasTransparency())
{
graphics.Clear(Control.BackColor);
return;
}

Rectangle clipRectangle = Rectangle.Ceiling(graphics.ClipBounds);
clipRectangle.Intersect(Control.ClientRectangle);
if (clipRectangle.Width <= 0 || clipRectangle.Height <= 0)
{
return;
}

using PaintEventArgs paintEventArgs = new(graphics, clipRectangle);
Control.PaintBackground(paintEventArgs, clipRectangle);
}

private static float EaseOut(float value)
=> 1 - ((1 - value) * (1 - value));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Drawing;
Expand Down Expand Up @@ -123,6 +123,15 @@ internal void DrawGlyph(
borderColor = ApplyInteractionShade(borderColor, focus);
backColor = ApplyInteractionShade(backColor, focus);

// Blend the outer circle toward the accent based on animated checked progress
// (_dotScaleCurrent), so check and uncheck transitions stay smooth and symmetric.
float checkedProgress = Math.Clamp(
_dotScaleCurrent,
0f,
1f);
Color activeBackColor = LerpColor(backColor, onColor, checkedProgress);
Color activeBorderColor = LerpColor(borderColor, onColor, checkedProgress);

float normalOuterScale = 1f / HoverGrowth;
float outerScale = Lerp(normalOuterScale, 1f, enabled ? _hoverCurrent : 0f);
RectangleF outerBounds = ScaleFromCenter(bounds, outerScale);
Expand All @@ -133,7 +142,7 @@ internal void DrawGlyph(
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;

using (var brush = backColor.GetCachedSolidBrushScope())
using (var brush = activeBackColor.GetCachedSolidBrushScope())
{
graphics.FillEllipse(brush, outerBounds);
}
Expand All @@ -142,7 +151,7 @@ internal void DrawGlyph(
1,
Control.LogicalToDeviceUnits(flatStyle == FlatStyle.Popup ? 2 : 1));

using (var pen = new Pen(borderColor, borderThickness))
using (var pen = new Pen(activeBorderColor, borderThickness))
{
graphics.DrawEllipse(pen, outerBounds);
}
Expand All @@ -156,22 +165,11 @@ internal void DrawGlyph(
dotDiameter,
dotDiameter);

Color dotOutlineColor = highContrast
Color dotColor = highContrast
? SystemColors.HighlightText
: PopupButtonColorMath.GetReadableForeColor(onColor, backColor);
int outlineThickness = Math.Max(1, Control.LogicalToDeviceUnits(1));
using var outlineBrush = dotOutlineColor.GetCachedSolidBrushScope();
graphics.FillEllipse(outlineBrush, dotRectangle);

RectangleF accentRectangle = RectangleF.Inflate(
dotRectangle,
-outlineThickness,
-outlineThickness);
if (accentRectangle.Width > 0 && accentRectangle.Height > 0)
{
using var dotBrush = onColor.GetCachedSolidBrushScope();
graphics.FillEllipse(dotBrush, accentRectangle);
}
: PopupButtonColorMath.GetReadableForeColor(onColor);
using var dotBrush = dotColor.GetCachedSolidBrushScope();
graphics.FillEllipse(dotBrush, dotRectangle);
}
}
finally
Expand Down Expand Up @@ -226,6 +224,20 @@ private static float EaseOut(float progress)
private static float Lerp(float from, float to, float progress)
=> from + ((to - from) * Math.Clamp(progress, 0f, 1f));

private static Color LerpColor(Color from, Color to, float progress)
{
progress = Math.Clamp(progress, 0f, 1f);

return Color.FromArgb(
LerpChannel(from.A, to.A, progress),
LerpChannel(from.R, to.R, progress),
LerpChannel(from.G, to.G, progress),
LerpChannel(from.B, to.B, progress));

static int LerpChannel(int from, int to, float progress)
=> from + (int)((to - from) * progress);
}

private static RectangleF ScaleFromCenter(Rectangle bounds, float scale)
{
float width = bounds.Width * scale;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,43 @@ public void CheckBox_ModernGlyph_DefaultCheckedColorUsesWindowsAccent()
}

[WinFormsFact]
public void CheckBox_ModernGlyph_BrightAccentUsesReadableCheckmark()
public void CheckBox_ModernGlyph_TransparentBackColor_CheckedUsesWindowsAccent()
{
if (SystemInformation.HighContrast)
{
return;
}

using Panel parent = new() { BackColor = Color.White };
using CheckBox box = new()
{
BackColor = Color.Transparent,
CheckState = CheckState.Checked,
Size = new Size(40, 24),
VisualStylesMode = VisualStylesMode.Net11
};
parent.Controls.Add(box);

using Bitmap bitmap = new(box.Width, box.Height);
using Graphics graphics = Graphics.FromImage(bitmap);
PaintEventArgs e = new(graphics, box.ClientRectangle);

box.CreateStandardAdapter().PaintUp(e, box.CheckState);

Assert.True(CountPixels(bitmap, Application.SystemVisualSettings.AccentColor) > 0);
}

[WinFormsTheory]
[InlineData(0xFF, 0xB9, 0x00, 0, 0, 0)]
[InlineData(0x00, 0x66, 0xCC, 255, 255, 255)]
[InlineData(0x4D, 0x4D, 0x4D, 255, 255, 255)]
public void CheckBox_ModernGlyph_AccentUsesReadableCheckmark(
int accentR,
int accentG,
int accentB,
int expectedR,
int expectedG,
int expectedB)
{
if (SystemInformation.HighContrast)
{
Expand All @@ -637,7 +673,7 @@ public void CheckBox_ModernGlyph_BrightAccentUsesReadableCheckmark()
renderer.NotifyCheckStateChanged(CheckState.Checked);
using Bitmap bitmap = new(24, 24);
using Graphics graphics = Graphics.FromImage(bitmap);
Color brightAccent = Color.FromArgb(0xFF, 0xB9, 0x00);
Color accent = Color.FromArgb(accentR, accentG, accentB);

renderer.DrawGlyph(
graphics,
Expand All @@ -646,10 +682,10 @@ public void CheckBox_ModernGlyph_BrightAccentUsesReadableCheckmark()
enabled: true,
hovered: false,
focused: false,
customOnColor: brightAccent,
customOnColor: accent,
customBorderColor: null);

Assert.True(CountPixels(bitmap, Color.Black) > 0);
Assert.True(CountPixels(bitmap, Color.FromArgb(expectedR, expectedG, expectedB)) > 0);
}

[WinFormsFact]
Expand Down Expand Up @@ -831,6 +867,35 @@ public void CheckBox_ToggleSwitch_DefaultOnColorUsesWindowsAccent()
Assert.True(CountPixels(bitmap, Application.SystemVisualSettings.AccentColor) > 0);
}

[WinFormsFact]
public void CheckBox_ToggleSwitch_DarkAccentUsesReadableThumbColor()
{
if (SystemInformation.HighContrast)
{
return;
}

using SystemVisualSettingsTestScope settingsScope =
new(clientAreaAnimationEnabled: true, accentColor: Color.FromArgb(0x4D, 0x4D, 0x4D));
using CheckBox box = new()
{
Appearance = Appearance.ToggleSwitch,
BackColor = Color.Black,
Checked = true,
Size = new Size(60, 24),
VisualStylesMode = VisualStylesMode.Net11
};
Rendering.CheckBox.AnimatedToggleSwitchRenderer renderer =
box.TestAccessor.Dynamic.ToggleSwitchRenderer;
renderer.SynchronizeState();
using Bitmap bitmap = new(box.Width, box.Height);
using Graphics graphics = Graphics.FromImage(bitmap);

renderer.RenderControl(graphics);

Assert.True(CountPixels(bitmap, Color.White) > 0);
}

[WinFormsFact]
public void CheckBox_ToggleSwitch_HoverAndFocusAnimateWithoutChangingPreferredSize()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,4 +226,30 @@ public void CheckBox_VisualStylesMode_DefaultIsAmbient()

Assert.Equal(VisualStylesMode.Inherit, checkBox.VisualStylesMode);
}

[WinFormsTheory]
[InlineData(true)]
[InlineData(false)]
public void CheckBox_ToggleSwitch_TransparentBackColor_DoesNotThrow(bool useBackgroundImage)
{
using SystemVisualSettingsTestScope settingsScope = new(
clientAreaAnimationEnabled: false,
highContrastEnabled: false);
using Bitmap backgroundImage = new(10, 10);
using Panel parent = new() { BackColor = Color.LightBlue, Size = new Size(200, 100) };
using CheckBox checkBox = new()
{
Parent = parent,
Appearance = Appearance.ToggleSwitch,
VisualStylesMode = VisualStylesMode.Net11,
BackColor = Color.Transparent,
BackgroundImage = useBackgroundImage ? backgroundImage : null,
Size = new Size(140, 36),
Text = "Matrix"
};
parent.CreateControl();
using Bitmap bitmap = new(checkBox.Width, checkBox.Height);

checkBox.DrawToBitmap(bitmap, new Rectangle(Point.Empty, checkBox.Size));
}
}
Loading