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
Expand Up @@ -53,6 +53,7 @@ private Color GetButtonBackColor(PushButtonState state)
{
Color backColor;

// Set the initial back color.
if (Control.BackColor != Forms.Control.DefaultBackColor)
{
backColor = Control.BackColor;
Expand All @@ -67,6 +68,21 @@ private Color GetButtonBackColor(PushButtonState state)
backColor = ButtonDarkModeRenderer.GetBackgroundColor(state, Control.IsDefault);
}

// Override the back color for FlatStyle buttons if specific colors are set.
if (Control.FlatStyle == FlatStyle.Flat)
{
if (state == PushButtonState.Pressed && !Control.FlatAppearance.MouseDownBackColor.IsEmpty)
{
backColor = Control.FlatAppearance.MouseDownBackColor;
}
else if (state == PushButtonState.Hot
&& !Control.FlatAppearance.MouseOverBackColor.IsEmpty
&& !IsHighContrastHighlighted())
{
backColor = Control.FlatAppearance.MouseOverBackColor;
}
}

return backColor;
}

Expand All @@ -86,6 +102,8 @@ internal override void PaintUp(PaintEventArgs e, CheckState state)
g,
Control.ClientRectangle,
Control.FlatStyle,
Control.FlatAppearance.BorderSize,
Control.FlatAppearance.BorderColor,
pushButtonState,
Control.IsDefault,
Control.Focused,
Expand Down Expand Up @@ -124,6 +142,8 @@ internal override void PaintDown(PaintEventArgs e, CheckState state)
g,
Control.ClientRectangle,
Control.FlatStyle,
Control.FlatAppearance.BorderSize,
Control.FlatAppearance.BorderColor,
PushButtonState.Pressed,
Control.IsDefault,
Control.Focused,
Expand Down Expand Up @@ -162,6 +182,8 @@ internal override void PaintOver(PaintEventArgs e, CheckState state)
g,
Control.ClientRectangle,
Control.FlatStyle,
Control.FlatAppearance.BorderSize,
Control.FlatAppearance.BorderColor,
PushButtonState.Hot,
Control.IsDefault,
Control.Focused,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public void RenderButton(
Graphics graphics,
Rectangle bounds,
FlatStyle flatStyle,
int borderSize,
Color borderColor,
PushButtonState state,
bool isDefault,
bool focused,
Expand Down Expand Up @@ -61,11 +63,16 @@ public void RenderButton(
height: bounds.Height - padding.Vertical);

// Draw button background and get content bounds
Rectangle contentBounds = DrawButtonBackground(graphics, paddedBounds, state, isDefault, backColor);
Rectangle contentBounds =
DrawButtonBackground(graphics, paddedBounds, state, isDefault, backColor, borderSize, borderColor);

// Paint image and field using the provided delegates
// Paint image using the provided delegates
paintImage(contentBounds);

// Draw button border
DrawButtonBorder(graphics, bounds, borderSize, borderColor, state, isDefault);

// Paint field using the provided delegates
paintField();

if (focused && showFocusCues)
Expand All @@ -76,7 +83,13 @@ public void RenderButton(
}
}

public abstract Rectangle DrawButtonBackground(Graphics graphics, Rectangle bounds, PushButtonState state, bool isDefault, Color backColor);
public virtual void DrawButtonBorder(Graphics graphics, Rectangle bounds, int borderSize,
Color borderColor, PushButtonState state, bool isDefault)
{
}

public abstract Rectangle DrawButtonBackground(Graphics graphics, Rectangle bounds,
PushButtonState state, bool isDefault, Color backColor, int borderSize, Color borderColor);

public abstract void DrawFocusIndicator(Graphics graphics, Rectangle contentBounds, bool isDefault);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ namespace System.Windows.Forms;
internal sealed class FlatButtonDarkModeRenderer : ButtonDarkModeRendererBase
{
private const int FocusIndicatorInflate = -3;
private const int CornerRadius = 6;
private static readonly Size s_corner = new(CornerRadius, CornerRadius);

private protected override Padding PaddingCore { get; } = new(0);

public override Rectangle DrawButtonBackground(
Graphics graphics, Rectangle bounds, PushButtonState state, bool isDefault, Color backColor)
Graphics graphics, Rectangle bounds, PushButtonState state, bool isDefault,
Color backColor, int borderSize, Color borderColor)
{
// fill background
using var back = backColor.GetCachedSolidBrushScope();
graphics.FillRectangle(back, bounds);
Rectangle rectangle = bounds;
// Shrink the drawing area to avoid overlapping the border, consistent with DrawButtonBorder's inset logic
rectangle.Inflate(-borderSize - 1, -borderSize - 1);

// draw border identical to Win32
DrawButtonBorder(graphics, bounds, state, isDefault);
graphics.FillRectangle(back, rectangle);

// return inner content area (border + 1 px system padding)
return Rectangle.Inflate(bounds, -3, -3);
Expand Down Expand Up @@ -77,33 +77,29 @@ public override Color GetBackgroundColor(PushButtonState state, bool isDefault)
_ => DefaultColors.StandardBackColor
};

private static void DrawButtonBorder(Graphics g, Rectangle bounds, PushButtonState state, bool isDefault)
public override void DrawButtonBorder(Graphics g, Rectangle bounds, int borderSize, Color borderColor, PushButtonState state, bool isDefault)
{
g.SmoothingMode = SmoothingMode.AntiAlias;

// Win32 draws its stroke fully *inside* the control → inset by 1 px
Rectangle outer = Rectangle.Inflate(bounds, -1, -1);

DrawSingleBorder(g, outer, GetBorderColor(state));
DrawSingleBorder(g, outer, borderSize, borderColor, GetBorderColor(state));

// Default button gets a second 1‑px border one pixel further inside
if (isDefault)
{
Rectangle inner = Rectangle.Inflate(outer, -1, -1);
DrawSingleBorder(g, inner, DefaultColors.AcceptFocusIndicatorBackColor);
DrawSingleBorder(g, inner, borderSize, borderColor, DefaultColors.AcceptFocusIndicatorBackColor);
}
}

private static void DrawSingleBorder(Graphics g, Rectangle rect, Color color)
private static void DrawSingleBorder(Graphics g, Rectangle rect, int borderSize, Color borderColor, Color color)
{
g.SmoothingMode = SmoothingMode.AntiAlias;

using var path = new GraphicsPath();
path.AddRoundedRectangle(rect, s_corner);

// a 1‑px stroke, aligned *inside*, is exactly what Win32 draws
using var pen = new Pen(color) { Alignment = PenAlignment.Inset };
g.DrawPath(pen, path);
using var pen = new Pen(!borderColor.IsEmpty ? borderColor : color, borderSize) { Alignment = PenAlignment.Inset };
g.DrawRectangle(pen, rect);
}

private static Color GetBorderColor(PushButtonState state) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ static void DrawButtonBorder(Graphics graphics, GraphicsPath path, Color borderC
/// <param name="graphics">The graphics context to draw on.</param>
/// <param name="bounds">The bounds of the button.</param>
/// <param name="flatStyle">The flat style of the button.</param>
/// <param name="borderSize">Size of the button border</param>
/// <param name="borderColor">Color of the button border</param>
/// <param name="state">The visual state of the button (normal, hot, pressed, disabled, default).</param>
/// <param name="isDefault">True if the button is the default button; otherwise, false.</param>
/// <param name="focused">True if the button is focused; otherwise, false.</param>
Expand All @@ -43,6 +45,8 @@ void RenderButton(
Graphics graphics,
Rectangle bounds,
FlatStyle flatStyle,
int borderSize,
Color borderColor,
PushButtonState state,
bool isDefault,
bool focused,
Expand All @@ -59,8 +63,17 @@ void RenderButton(
/// <param name="bounds">Bounds of the button</param>
/// <param name="state">State of the button (normal, hot, pressed, disabled)</param>
/// <param name="isDefault">True if button is the default button</param>
/// <param name="borderSize">Size of the button border</param>
/// <param name="borderColor">Color of the button border</param>
/// <returns>The content bounds (area inside the button for text/image)</returns>
Rectangle DrawButtonBackground(Graphics graphics, Rectangle bounds, PushButtonState state, bool isDefault, Color backColor);
Rectangle DrawButtonBackground(
Graphics graphics,
Rectangle bounds,
PushButtonState state,
bool isDefault,
Color backColor,
int borderSize,
Color borderColor);

/// <summary>
/// Draws focus indicator appropriate for this style.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ internal class PopupButtonDarkModeRenderer : ButtonDarkModeRendererBase
/// <summary>
/// Draws button background with popup styling, including subtle 3D effect.
/// </summary>
public override Rectangle DrawButtonBackground(Graphics graphics, Rectangle bounds, PushButtonState state, bool isDefault, Color backColor)
public override Rectangle DrawButtonBackground(Graphics graphics, Rectangle bounds, PushButtonState state,
bool isDefault, Color backColor, int borderSize, Color borderColor)
{
// Use padding from ButtonDarkModeRenderer
Padding padding = PaddingCore;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ internal class SystemButtonDarkModeRenderer : ButtonDarkModeRendererBase
/// <summary>
/// Draws button background with system styling (larger rounded corners).
/// </summary>
public override Rectangle DrawButtonBackground(Graphics graphics, Rectangle bounds, PushButtonState state, bool isDefault, Color backColor)
public override Rectangle DrawButtonBackground(Graphics graphics, Rectangle bounds, PushButtonState state,
bool isDefault, Color backColor, int borderSize, Color borderColor)
{
// Shrink for DarkBorderGap and FocusBorderThickness
Rectangle fillBounds = Rectangle.Inflate(bounds, -SystemStylePadding, -SystemStylePadding);
Expand Down