diff --git a/CreamInstaller/Components/CustomTreeView.cs b/CreamInstaller/Components/CustomTreeView.cs
index 6e07ee4..2ec2971 100644
--- a/CreamInstaller/Components/CustomTreeView.cs
+++ b/CreamInstaller/Components/CustomTreeView.cs
@@ -75,11 +75,14 @@ internal sealed class CustomTreeView : TreeView
private void DrawTreeNode(object sender, DrawTreeNodeEventArgs e)
{
- e.DrawDefault = true;
TreeNode node = e.Node;
if (node is not { IsVisible: true })
+ {
+ e.DrawDefault = true;
return;
+ }
+ bool dark = Program.DarkModeEnabled;
bool highlighted = (e.State & TreeNodeStates.Selected) == TreeNodeStates.Selected && Focused;
Graphics graphics = e.Graphics;
@@ -103,12 +106,43 @@ internal sealed class CustomTreeView : TreeView
}
}
+ Form form = FindForm();
+
+ if (dark && CheckBoxes)
+ {
+ // In dark mode we take full ownership of the row so the system never
+ // gets a chance to paint a light-background checkbox.
+ e.DrawDefault = false;
+
+ // Row background
+ Rectangle rowRect = new(0, node.Bounds.Top, ClientSize.Width, node.Bounds.Height);
+ graphics.FillRectangle(highlighted ? selectionBrush : backBrush, rowRect);
+
+ // Node text
+ Font nodeFont = node.NodeFont ?? Font;
+ Color textColor = Enabled ? ForeColor : SystemColors.GrayText;
+ TextRenderer.DrawText(graphics, node.Text, nodeFont,
+ new Point(node.Bounds.Left, node.Bounds.Top + 1), textColor, TextFormatFlags.Default);
+
+ // Checkbox glyph – pure GDI so it matches the dark-themed CheckBox controls
+ CheckBoxState cbState = node.Checked
+ ? (Enabled ? CheckBoxState.CheckedNormal : CheckBoxState.CheckedDisabled)
+ : (Enabled ? CheckBoxState.UncheckedNormal : CheckBoxState.UncheckedDisabled);
+ Size cbSize = CheckBoxRenderer.GetGlyphSize(graphics, cbState);
+ int cbX = node.Bounds.Left - cbSize.Width - 2;
+ int cbY = node.Bounds.Top + node.Bounds.Height / 2 - cbSize.Height / 2;
+ ThemeManager.DrawDarkCheckBox(graphics, new Point(cbX, cbY), cbSize, node.Checked, Enabled);
+ }
+ else
+ {
+ e.DrawDefault = true;
+ }
+
Font font = node.NodeFont ?? Font;
Brush brush = highlighted ? (Brush)selectionBrush : backBrush;
Rectangle bounds = node.Bounds;
Rectangle selectionBounds = bounds;
- Form form = FindForm();
if (form is not SelectForm and not SelectDialogForm)
return;
@@ -168,18 +202,19 @@ internal sealed class CustomTreeView : TreeView
graphics.FillRectangle(brush, bounds);
}
- CheckBoxState checkBoxState = selection.UseProxy
- ? Enabled ? CheckBoxState.CheckedPressed : CheckBoxState.CheckedDisabled
- : Enabled
- ? CheckBoxState.UncheckedPressed
- : CheckBoxState.UncheckedDisabled;
- size = CheckBoxRenderer.GetGlyphSize(graphics, checkBoxState);
+ CheckBoxState proxyState = selection.UseProxy
+ ? (Enabled ? CheckBoxState.CheckedNormal : CheckBoxState.CheckedDisabled)
+ : (Enabled ? CheckBoxState.UncheckedNormal : CheckBoxState.UncheckedDisabled);
+ size = CheckBoxRenderer.GetGlyphSize(graphics, proxyState);
bounds = bounds with { X = bounds.X + bounds.Width, Width = size.Width };
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + bounds.Size with { Height = 0 });
Rectangle checkBoxBounds = bounds;
graphics.FillRectangle(backBrush, bounds);
point = new(bounds.Left, bounds.Top + bounds.Height / 2 - size.Height / 2 - 1);
- CheckBoxRenderer.DrawCheckBox(graphics, point, checkBoxState);
+ if (dark)
+ ThemeManager.DrawDarkCheckBox(graphics, point, size, selection.UseProxy, Enabled);
+ else
+ CheckBoxRenderer.DrawCheckBox(graphics, point, proxyState);
text = ProxyToggleString;
size = TextRenderer.MeasureText(graphics, text, font);
diff --git a/CreamInstaller/Utility/ThemeManager.cs b/CreamInstaller/Utility/ThemeManager.cs
index eef74be..60f3809 100644
--- a/CreamInstaller/Utility/ThemeManager.cs
+++ b/CreamInstaller/Utility/ThemeManager.cs
@@ -422,6 +422,70 @@ internal static class ThemeManager
// button is centralized here so theming resides in ThemeManager.
// -----------------------------------------------------------------
+ // Dark checkbox colors – matched to how the system renders the "All" CheckBox control
+ // in dark mode: dark fill, mid-gray border, light foreground tick.
+ private static readonly Color DarkCbBorder = ColorTranslator.FromHtml("#6B6B6B");
+ private static readonly Color DarkCbDisabledBorder = ColorTranslator.FromHtml("#454545");
+
+ ///
+ /// Draws a checkbox glyph in pure GDI that matches the appearance of a dark-themed
+ /// WinForms CheckBox control (same background, border, tick colors, and rounded corners).
+ /// Use this in owner-draw contexts where CheckBoxRenderer always paints a white background.
+ ///
+ internal static void DrawDarkCheckBox(Graphics g, Point point, Size glyphSize, bool isChecked, bool enabled = true)
+ {
+ if (g is null) return;
+ int w = glyphSize.Width;
+ int h = glyphSize.Height;
+ Rectangle box = new(point.X, point.Y, w - 1, h - 1);
+ int radius = Math.Max(2, w / 5); // rounded corner radius proportional to glyph size
+
+ // Build rounded rectangle path
+ using System.Drawing.Drawing2D.GraphicsPath path = RoundedRect(box, radius);
+
+ // Fill
+ using SolidBrush fillBrush = new(DarkBackAlt);
+ g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
+ g.FillPath(fillBrush, path);
+
+ // Border
+ using Pen borderPen = new(enabled ? DarkCbBorder : DarkCbDisabledBorder);
+ g.DrawPath(borderPen, path);
+
+ if (isChecked)
+ {
+ Color tickColor = enabled ? DarkFore : DarkForeDim;
+ using Pen tickPen = new(tickColor, 1.7f)
+ {
+ StartCap = System.Drawing.Drawing2D.LineCap.Round,
+ EndCap = System.Drawing.Drawing2D.LineCap.Round,
+ LineJoin = System.Drawing.Drawing2D.LineJoin.Round,
+ };
+ // Scale tick proportionally to the glyph size
+ float scaleX = w / 13f;
+ float scaleY = h / 13f;
+ g.DrawLines(tickPen, new PointF[]
+ {
+ new(point.X + 2 * scaleX, point.Y + 6 * scaleY),
+ new(point.X + 5 * scaleX, point.Y + 9 * scaleY),
+ new(point.X + 10 * scaleX, point.Y + 3 * scaleY),
+ });
+ }
+ g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.Default;
+ }
+
+ private static System.Drawing.Drawing2D.GraphicsPath RoundedRect(Rectangle r, int radius)
+ {
+ int d = radius * 2;
+ System.Drawing.Drawing2D.GraphicsPath path = new();
+ path.AddArc(r.Left, r.Top, d, d, 180, 90);
+ path.AddArc(r.Right - d, r.Top, d, d, 270, 90);
+ path.AddArc(r.Right - d, r.Bottom - d, d, d, 0, 90);
+ path.AddArc(r.Left, r.Bottom - d, d, d, 90, 90);
+ path.CloseFigure();
+ return path;
+ }
+
///
/// Draws the themed combobox area (background, border and text) used in CustomTreeView.
/// This centralizes colors and rendering for light/dark modes.