mirror of
https://github.com/FroggMaster/CreamInstaller.git
synced 2026-06-12 11:01:23 -07:00
Migrate Legacy Theme Code into Theme Manager / Shitty Fix for Selection in Dark Mode / Shitty Comments
- Moved as much of the legacy theme code as I could find into ThemeManager - Some shitty comments added VIA AI (probably better than I'd write anyways) - Some adjustments to how the highlight is being rendered, for some fucking reason the system highlight refuses to match on the left/right (probably some dumb shit I'm doing.) > This version makes things clearer/easier to read in dark mode.
This commit is contained in:
@@ -21,6 +21,11 @@ internal sealed class CustomTreeView : TreeView
|
||||
private readonly Dictionary<TreeNode, Rectangle> selectionBounds = [];
|
||||
private SolidBrush backBrush;
|
||||
private Color lastBackColor; // Tracks the last background color
|
||||
|
||||
// Selection background brush (used instead of SystemBrushes.Highlight to support dark mode)
|
||||
private SolidBrush selectionBrush;
|
||||
private Color lastSelectionBackColor;
|
||||
|
||||
private ToolStripDropDown comboBoxDropDown;
|
||||
private Font comboBoxFont;
|
||||
private Form form;
|
||||
@@ -46,6 +51,8 @@ internal sealed class CustomTreeView : TreeView
|
||||
{
|
||||
backBrush?.Dispose();
|
||||
backBrush = null;
|
||||
selectionBrush?.Dispose();
|
||||
selectionBrush = null;
|
||||
comboBoxFont?.Dispose();
|
||||
comboBoxFont = null;
|
||||
comboBoxDropDown?.Dispose();
|
||||
@@ -60,6 +67,10 @@ internal sealed class CustomTreeView : TreeView
|
||||
backBrush?.Dispose();
|
||||
backBrush = null;
|
||||
lastBackColor = Color.Empty;
|
||||
|
||||
selectionBrush?.Dispose();
|
||||
selectionBrush = null;
|
||||
lastSelectionBackColor = Color.Empty;
|
||||
}
|
||||
|
||||
private void DrawTreeNode(object sender, DrawTreeNodeEventArgs e)
|
||||
@@ -71,17 +82,29 @@ internal sealed class CustomTreeView : TreeView
|
||||
|
||||
bool highlighted = (e.State & TreeNodeStates.Selected) == TreeNodeStates.Selected && Focused;
|
||||
Graphics graphics = e.Graphics;
|
||||
|
||||
// Recreate brush if background color changed
|
||||
|
||||
// Recreate back brush if background color changed
|
||||
if (backBrush == null || lastBackColor != BackColor)
|
||||
{
|
||||
backBrush?.Dispose();
|
||||
backBrush = new(BackColor);
|
||||
lastBackColor = BackColor;
|
||||
}
|
||||
|
||||
|
||||
// If highlighted, prepare a selection brush that respects the theme
|
||||
if (highlighted)
|
||||
{
|
||||
Color selColor = ThemeManager.CustomTreeViewSelectionBackColor;
|
||||
if (selectionBrush == null || lastSelectionBackColor != selColor)
|
||||
{
|
||||
selectionBrush?.Dispose();
|
||||
selectionBrush = new(selColor);
|
||||
lastSelectionBackColor = selColor;
|
||||
}
|
||||
}
|
||||
|
||||
Font font = node.NodeFont ?? Font;
|
||||
Brush brush = highlighted ? SystemBrushes.Highlight : backBrush;
|
||||
Brush brush = highlighted ? (Brush)selectionBrush : backBrush;
|
||||
Rectangle bounds = node.Bounds;
|
||||
Rectangle selectionBounds = bounds;
|
||||
|
||||
@@ -166,8 +189,8 @@ internal sealed class CustomTreeView : TreeView
|
||||
checkBoxBounds = new(checkBoxBounds.Location, checkBoxBounds.Size + bounds.Size with { Height = 0 });
|
||||
graphics.FillRectangle(backBrush, bounds);
|
||||
point = new(bounds.Location.X - 1 + left, bounds.Location.Y + 1);
|
||||
TextRenderer.DrawText(graphics, text, font, point,
|
||||
Enabled ? ThemeManager.CustomTreeViewProxyColor : ThemeManager.CustomTreeViewDisabledProxyColor,
|
||||
TextRenderer.DrawText(graphics, text, font, point,
|
||||
Enabled ? ThemeManager.CustomTreeViewProxyColor : ThemeManager.CustomTreeViewDisabledProxyColor,
|
||||
TextFormatFlags.Default);
|
||||
|
||||
this.checkBoxBounds[selection] = RectangleToClient(checkBoxBounds);
|
||||
@@ -189,16 +212,9 @@ internal sealed class CustomTreeView : TreeView
|
||||
selectionBounds = new(selectionBounds.Location,
|
||||
selectionBounds.Size + bounds.Size with { Height = 0 });
|
||||
Rectangle comboBoxBounds = bounds;
|
||||
|
||||
// Draw custom themed combobox
|
||||
using (SolidBrush comboBrush = new(comboBackColor))
|
||||
using (Pen borderPen = new(comboBorderColor))
|
||||
{
|
||||
graphics.FillRectangle(comboBrush, bounds);
|
||||
graphics.DrawRectangle(borderPen, bounds);
|
||||
point = new(bounds.Location.X + 3, bounds.Location.Y + bounds.Height / 2 - size.Height / 2);
|
||||
TextRenderer.DrawText(graphics, text, comboBoxFont, point, comboTextColor, TextFormatFlags.Default);
|
||||
}
|
||||
|
||||
// Themed combobox background + text (centralized in ThemeManager)
|
||||
ThemeManager.DrawCustomComboBox(graphics, bounds, comboBoxFont, text);
|
||||
|
||||
size = new(14, 0);
|
||||
left = -1;
|
||||
@@ -207,28 +223,9 @@ internal sealed class CustomTreeView : TreeView
|
||||
selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
|
||||
comboBoxBounds = new(comboBoxBounds.Location,
|
||||
comboBoxBounds.Size + new Size(bounds.Size.Width + left, 0));
|
||||
|
||||
// Draw custom themed dropdown button
|
||||
using (SolidBrush comboBrush = new(comboBackColor))
|
||||
using (Pen borderPen = new(comboBorderColor))
|
||||
{
|
||||
graphics.FillRectangle(comboBrush, bounds);
|
||||
graphics.DrawRectangle(borderPen, bounds);
|
||||
|
||||
// Draw arrow
|
||||
int arrowSize = 3;
|
||||
Point arrowTop = new(bounds.X + bounds.Width / 2, bounds.Y + bounds.Height / 2 - 1);
|
||||
Point[] arrowPoints = new[]
|
||||
{
|
||||
arrowTop,
|
||||
new Point(arrowTop.X - arrowSize, arrowTop.Y - arrowSize),
|
||||
new Point(arrowTop.X + arrowSize, arrowTop.Y - arrowSize)
|
||||
};
|
||||
using (SolidBrush arrowBrush = new(comboTextColor))
|
||||
{
|
||||
graphics.FillPolygon(arrowBrush, arrowPoints);
|
||||
}
|
||||
}
|
||||
|
||||
// Themed combobox dropdown button (centralized in ThemeManager)
|
||||
ThemeManager.DrawCustomComboBoxButton(graphics, bounds);
|
||||
|
||||
this.comboBoxBounds[selection] = RectangleToClient(comboBoxBounds);
|
||||
}
|
||||
@@ -270,7 +267,7 @@ internal sealed class CustomTreeView : TreeView
|
||||
comboBoxDropDown ??= new();
|
||||
comboBoxDropDown.ShowItemToolTips = false;
|
||||
comboBoxDropDown.Items.Clear();
|
||||
|
||||
|
||||
foreach (string proxy in proxies)
|
||||
{
|
||||
bool canUse = true;
|
||||
|
||||
@@ -7,7 +7,13 @@ namespace CreamInstaller.Utility;
|
||||
|
||||
internal static class ThemeManager
|
||||
{
|
||||
// VS-like dark colors
|
||||
// -----------------------------------------------------------------
|
||||
// Color definitions (do not change values)
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// ----------------------------
|
||||
// Dark mode colors
|
||||
// ----------------------------
|
||||
private static readonly Color DarkBack = ColorTranslator.FromHtml("#1E1E1E");
|
||||
private static readonly Color DarkBackAlt = ColorTranslator.FromHtml("#252525");
|
||||
private static readonly Color DarkBorder = ColorTranslator.FromHtml("#3F3F46");
|
||||
@@ -15,171 +21,249 @@ internal static class ThemeManager
|
||||
private static readonly Color DarkForeDim = ColorTranslator.FromHtml("#9CA3AF");
|
||||
private static readonly Color Accent = ColorTranslator.FromHtml("#0E639C");
|
||||
private static readonly Color DarkLink = ColorTranslator.FromHtml("#64B5F6");
|
||||
|
||||
// CustomTreeView dark-mode specific colors
|
||||
private static readonly Color DarkPlatform = ColorTranslator.FromHtml("#FFFF99");
|
||||
private static readonly Color DarkId = ColorTranslator.FromHtml("#99FFFF");
|
||||
private static readonly Color DarkProxy = ColorTranslator.FromHtml("#99FF99");
|
||||
private static readonly Color DarkSelectionBack = ColorTranslator.FromHtml("#2A2D2E");
|
||||
private static readonly Color DarkComboBack = DarkBackAlt; // #252525
|
||||
private static readonly Color DarkComboBorder = DarkBorder; // #3F3F46
|
||||
private static readonly Color DarkComboText = DarkFore; // #D4D4D4
|
||||
|
||||
// ----------------------------
|
||||
// Light mode colors (system defaults)
|
||||
// ----------------------------
|
||||
private static readonly Color LightBack = SystemColors.Control;
|
||||
private static readonly Color LightBackAlt = SystemColors.ControlLightLight;
|
||||
private static readonly Color LightFore = SystemColors.ControlText;
|
||||
private static readonly Color LightBorder = SystemColors.ControlDark;
|
||||
|
||||
internal static Color CustomTreeViewPlatformColor => Program.DarkModeEnabled
|
||||
? ColorTranslator.FromHtml("#FFFF99") // Light yellow for dark mode
|
||||
: ColorTranslator.FromHtml("#696900"); // Dark yellow for light mode
|
||||
// CustomTreeView light-mode specific colors
|
||||
private static readonly Color LightPlatform = ColorTranslator.FromHtml("#696900");
|
||||
private static readonly Color LightId = ColorTranslator.FromHtml("#006969");
|
||||
private static readonly Color LightProxy = ColorTranslator.FromHtml("#006900");
|
||||
private static readonly Color LightSelectionBack = SystemColors.Highlight;
|
||||
private static readonly Color LightComboBack = SystemColors.Control;
|
||||
private static readonly Color LightComboBorder = SystemColors.ControlDark;
|
||||
private static readonly Color LightComboText = SystemColors.ControlText;
|
||||
|
||||
internal static Color CustomTreeViewIdColor => Program.DarkModeEnabled
|
||||
? ColorTranslator.FromHtml("#99FFFF") // Light cyan for dark mode
|
||||
: ColorTranslator.FromHtml("#006969"); // Dark cyan for light mode
|
||||
// -----------------------------------------------------------------
|
||||
// Theme-aware properties used by other components (CustomTreeView etc.)
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
internal static Color CustomTreeViewProxyColor => Program.DarkModeEnabled
|
||||
? ColorTranslator.FromHtml("#99FF99") // Light green for dark mode
|
||||
: ColorTranslator.FromHtml("#006900"); // Dark green for light mode
|
||||
internal static bool IsDark => Program.DarkModeEnabled;
|
||||
|
||||
internal static Color CustomTreeViewHighlightPlatformColor => ColorTranslator.FromHtml("#FFFF99"); // C1
|
||||
internal static Color CustomTreeViewPlatformColor => IsDark ? DarkPlatform : LightPlatform;
|
||||
|
||||
internal static Color CustomTreeViewIdColor => IsDark ? DarkId : LightId;
|
||||
|
||||
internal static Color CustomTreeViewProxyColor => IsDark ? DarkProxy : LightProxy;
|
||||
|
||||
internal static Color CustomTreeViewHighlightPlatformColor => DarkPlatform; // C1 (uses same color for highlight)
|
||||
internal static Color CustomTreeViewDisabledPlatformColor => ColorTranslator.FromHtml("#AAAA69"); // C3
|
||||
internal static Color CustomTreeViewHighlightIdColor => ColorTranslator.FromHtml("#99FFFF"); // C4
|
||||
internal static Color CustomTreeViewHighlightIdColor => DarkId; // C4
|
||||
internal static Color CustomTreeViewDisabledIdColor => ColorTranslator.FromHtml("#69AAAA"); // C6
|
||||
internal static Color CustomTreeViewDisabledProxyColor => ColorTranslator.FromHtml("#69AA69"); // C8
|
||||
|
||||
internal static Color CustomTreeViewComboBackColor => Program.DarkModeEnabled
|
||||
? DarkBackAlt // #252525
|
||||
: SystemColors.Control;
|
||||
// Background color used when a tree node is selected.
|
||||
// Keeps light-mode behavior using the system highlight, but supplies a custom dark color for dark mode
|
||||
internal static Color CustomTreeViewSelectionBackColor => IsDark ? DarkSelectionBack : LightSelectionBack;
|
||||
|
||||
internal static Color CustomTreeViewComboBorderColor => Program.DarkModeEnabled
|
||||
? DarkBorder // #3F3F46
|
||||
: SystemColors.ControlDark;
|
||||
internal static Color CustomTreeViewComboBackColor => IsDark ? DarkComboBack : LightComboBack;
|
||||
|
||||
internal static Color CustomTreeViewComboTextColor => Program.DarkModeEnabled
|
||||
? DarkFore // #D4D4D4
|
||||
: SystemColors.ControlText;
|
||||
internal static Color CustomTreeViewComboBorderColor => IsDark ? DarkComboBorder : LightComboBorder;
|
||||
|
||||
internal static Color CustomTreeViewComboTextColor => IsDark ? DarkComboText : LightComboText;
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Public / Internal API
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Toggle dark mode and re-apply theming to all open forms.
|
||||
/// </summary>
|
||||
internal static void ToggleDarkMode(Form anyForm)
|
||||
{
|
||||
Program.DarkModeEnabled = !Program.DarkModeEnabled;
|
||||
ApplyToAllOpenForms();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply current theme to a single form and its child controls.
|
||||
/// </summary>
|
||||
internal static void Apply(Form form)
|
||||
{
|
||||
if (form is null) return;
|
||||
if (!Program.DarkModeEnabled)
|
||||
if (!IsDark)
|
||||
{
|
||||
Reset(form);
|
||||
return;
|
||||
}
|
||||
|
||||
form.SuspendLayout();
|
||||
form.BackColor = DarkBack;
|
||||
form.ForeColor = DarkFore;
|
||||
ApplyTitleBar(form);
|
||||
|
||||
foreach (Control c in form.Controls)
|
||||
ApplyControlTheme(c, true);
|
||||
|
||||
form.ResumeLayout(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply the theme to all currently open forms.
|
||||
/// </summary>
|
||||
internal static void ApplyToAllOpenForms()
|
||||
{
|
||||
foreach (Form openForm in Application.OpenForms.Cast<Form>())
|
||||
Apply(openForm);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Control theming helpers
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Apply theming to a control tree. Entry point which recurses children
|
||||
/// then applies either the dark or light styling logic.
|
||||
/// </summary>
|
||||
private static void ApplyControlTheme(Control control, bool dark)
|
||||
{
|
||||
if (control is null) return;
|
||||
|
||||
// Recurse first so parent layering still works correctly
|
||||
foreach (Control child in control.Controls)
|
||||
ApplyControlTheme(child, dark);
|
||||
|
||||
if (dark)
|
||||
{
|
||||
switch (control)
|
||||
{
|
||||
case GroupBox gb:
|
||||
gb.ForeColor = DarkFore;
|
||||
gb.BackColor = DarkBackAlt;
|
||||
break;
|
||||
case Button b:
|
||||
b.FlatStyle = FlatStyle.Flat;
|
||||
b.FlatAppearance.BorderColor = DarkBorder;
|
||||
b.BackColor = DarkBackAlt;
|
||||
b.ForeColor = DarkFore;
|
||||
break;
|
||||
case CheckBox cb:
|
||||
cb.BackColor = DarkBack;
|
||||
cb.ForeColor = DarkFore;
|
||||
break;
|
||||
case LinkLabel ll:
|
||||
ll.BackColor = DarkBack;
|
||||
ll.ForeColor = DarkFore;
|
||||
ll.LinkColor = DarkLink;
|
||||
ll.ActiveLinkColor = Color.White;
|
||||
ll.VisitedLinkColor = DarkLink;
|
||||
break;
|
||||
case Label lbl:
|
||||
lbl.BackColor = DarkBack;
|
||||
lbl.ForeColor = DarkFore;
|
||||
break;
|
||||
case ProgressBar pb:
|
||||
pb.ForeColor = Accent;
|
||||
pb.BackColor = DarkBackAlt;
|
||||
break;
|
||||
case TreeView tv:
|
||||
tv.BackColor = DarkBackAlt;
|
||||
tv.ForeColor = DarkFore;
|
||||
tv.LineColor = DarkBorder;
|
||||
tv.Invalidate(); // Forces a redraw
|
||||
break;
|
||||
case RichTextBox rtb:
|
||||
rtb.BackColor = DarkBackAlt;
|
||||
rtb.ForeColor = DarkFore;
|
||||
break;
|
||||
case TableLayoutPanel tlp:
|
||||
tlp.BackColor = DarkBack;
|
||||
break;
|
||||
case FlowLayoutPanel flp:
|
||||
flp.BackColor = DarkBack;
|
||||
break;
|
||||
}
|
||||
TryApplyScrollbarTheme(control, true);
|
||||
}
|
||||
ApplyDarkControl(control);
|
||||
else
|
||||
ApplyLightControl(control);
|
||||
|
||||
// Try to apply themed scrollbars where applicable
|
||||
TryApplyScrollbarTheme(control, dark);
|
||||
}
|
||||
|
||||
// Separated dark/light cases to make the intent clearer and reduce duplication
|
||||
private static void ApplyDarkControl(Control control)
|
||||
{
|
||||
switch (control)
|
||||
{
|
||||
switch (control)
|
||||
{
|
||||
case GroupBox gb:
|
||||
gb.BackColor = LightBack;
|
||||
gb.ForeColor = LightFore;
|
||||
break;
|
||||
case Button b:
|
||||
b.FlatStyle = FlatStyle.Standard;
|
||||
b.BackColor = LightBack;
|
||||
b.ForeColor = LightFore;
|
||||
break;
|
||||
case CheckBox cb:
|
||||
cb.BackColor = LightBack;
|
||||
cb.ForeColor = LightFore;
|
||||
break;
|
||||
case LinkLabel ll:
|
||||
ll.BackColor = LightBack;
|
||||
ll.ForeColor = LightFore;
|
||||
ll.LinkColor = SystemColors.HotTrack;
|
||||
ll.ActiveLinkColor = SystemColors.Highlight;
|
||||
ll.VisitedLinkColor = SystemColors.HotTrack;
|
||||
break;
|
||||
case Label lbl:
|
||||
lbl.BackColor = LightBack;
|
||||
lbl.ForeColor = LightFore;
|
||||
break;
|
||||
case ProgressBar pb:
|
||||
pb.BackColor = LightBack;
|
||||
pb.ForeColor = LightFore;
|
||||
break;
|
||||
case TreeView tv:
|
||||
tv.BackColor = LightBack;
|
||||
tv.ForeColor = LightFore;
|
||||
tv.LineColor = LightBorder;
|
||||
tv.Invalidate(); // Forces a redraw
|
||||
break;
|
||||
case RichTextBox rtb:
|
||||
rtb.BackColor = LightBack;
|
||||
rtb.ForeColor = LightFore;
|
||||
break;
|
||||
case TableLayoutPanel tlp:
|
||||
tlp.BackColor = LightBack;
|
||||
break;
|
||||
case FlowLayoutPanel flp:
|
||||
flp.BackColor = LightBack;
|
||||
break;
|
||||
}
|
||||
TryApplyScrollbarTheme(control, false);
|
||||
// Group box background/foreground
|
||||
case GroupBox gb:
|
||||
gb.ForeColor = DarkFore;
|
||||
gb.BackColor = DarkBackAlt;
|
||||
break;
|
||||
|
||||
// Buttons: flat appearance, border and foreground
|
||||
case Button b:
|
||||
b.FlatStyle = FlatStyle.Flat;
|
||||
b.FlatAppearance.BorderColor = DarkBorder;
|
||||
b.BackColor = DarkBackAlt;
|
||||
b.ForeColor = DarkFore;
|
||||
break;
|
||||
|
||||
// Checkboxes: match form background and foreground
|
||||
case CheckBox cb:
|
||||
cb.BackColor = DarkBack;
|
||||
cb.ForeColor = DarkFore;
|
||||
break;
|
||||
|
||||
// LinkLabel: color and active/visited styling
|
||||
case LinkLabel ll:
|
||||
ll.BackColor = DarkBack;
|
||||
ll.ForeColor = DarkFore;
|
||||
ll.LinkColor = DarkLink;
|
||||
ll.ActiveLinkColor = Color.White;
|
||||
ll.VisitedLinkColor = DarkLink;
|
||||
break;
|
||||
|
||||
// Labels: dark background, light foreground
|
||||
case Label lbl:
|
||||
lbl.BackColor = DarkBack;
|
||||
lbl.ForeColor = DarkFore;
|
||||
break;
|
||||
|
||||
// ProgressBar uses accent color for foreground
|
||||
case ProgressBar pb:
|
||||
pb.ForeColor = Accent;
|
||||
pb.BackColor = DarkBackAlt;
|
||||
break;
|
||||
|
||||
// TreeView: darker alternate background, light text, darker lines
|
||||
case TreeView tv:
|
||||
tv.BackColor = DarkBackAlt;
|
||||
tv.ForeColor = DarkFore;
|
||||
tv.LineColor = DarkBorder;
|
||||
tv.Invalidate(); // Forces a redraw
|
||||
break;
|
||||
|
||||
// RichTextBox follows alternate dark background
|
||||
case RichTextBox rtb:
|
||||
rtb.BackColor = DarkBackAlt;
|
||||
rtb.ForeColor = DarkFore;
|
||||
break;
|
||||
|
||||
// Layout panels set a consistent background
|
||||
case TableLayoutPanel tlp:
|
||||
tlp.BackColor = DarkBack;
|
||||
break;
|
||||
case FlowLayoutPanel flp:
|
||||
flp.BackColor = DarkBack;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyLightControl(Control control)
|
||||
{
|
||||
switch (control)
|
||||
{
|
||||
case GroupBox gb:
|
||||
gb.BackColor = LightBack;
|
||||
gb.ForeColor = LightFore;
|
||||
break;
|
||||
case Button b:
|
||||
b.FlatStyle = FlatStyle.Standard;
|
||||
b.BackColor = LightBack;
|
||||
b.ForeColor = LightFore;
|
||||
break;
|
||||
case CheckBox cb:
|
||||
cb.BackColor = LightBack;
|
||||
cb.ForeColor = LightFore;
|
||||
break;
|
||||
case LinkLabel ll:
|
||||
ll.BackColor = LightBack;
|
||||
ll.ForeColor = LightFore;
|
||||
ll.LinkColor = SystemColors.HotTrack;
|
||||
ll.ActiveLinkColor = SystemColors.Highlight;
|
||||
ll.VisitedLinkColor = SystemColors.HotTrack;
|
||||
break;
|
||||
case Label lbl:
|
||||
lbl.BackColor = LightBack;
|
||||
lbl.ForeColor = LightFore;
|
||||
break;
|
||||
case ProgressBar pb:
|
||||
pb.BackColor = LightBack;
|
||||
pb.ForeColor = LightFore;
|
||||
break;
|
||||
case TreeView tv:
|
||||
tv.BackColor = LightBack;
|
||||
tv.ForeColor = LightFore;
|
||||
tv.LineColor = LightBorder;
|
||||
tv.Invalidate(); // Forces a redraw
|
||||
break;
|
||||
case RichTextBox rtb:
|
||||
rtb.BackColor = LightBack;
|
||||
rtb.ForeColor = LightFore;
|
||||
break;
|
||||
case TableLayoutPanel tlp:
|
||||
tlp.BackColor = LightBack;
|
||||
break;
|
||||
case FlowLayoutPanel flp:
|
||||
flp.BackColor = LightBack;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,17 +278,15 @@ internal static class ThemeManager
|
||||
form.ResumeLayout(true);
|
||||
}
|
||||
|
||||
internal static void ApplyToAllOpenForms()
|
||||
{
|
||||
foreach (Form openForm in Application.OpenForms.Cast<Form>())
|
||||
Apply(openForm);
|
||||
}
|
||||
// -----------------------------------------------------------------
|
||||
// Titlebar / platform-specific helpers
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
private static void ApplyTitleBar(Form form)
|
||||
{
|
||||
try
|
||||
{
|
||||
int useDark = Program.DarkModeEnabled ? 1 : 0;
|
||||
int useDark = IsDark ? 1 : 0;
|
||||
NativeMethods.EnableDarkTitleBar(form.Handle, useDark);
|
||||
}
|
||||
catch { }
|
||||
@@ -220,12 +302,18 @@ internal static class ThemeManager
|
||||
catch { }
|
||||
}
|
||||
|
||||
// Right Click context menu styling
|
||||
// -----------------------------------------------------------------
|
||||
// Context menu / ToolStrip theming
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Apply theme to a context menu (ContextMenuStrip).
|
||||
/// </summary>
|
||||
internal static void ApplyContextMenu(ContextMenuStrip contextMenu)
|
||||
{
|
||||
if (contextMenu is null) return;
|
||||
|
||||
bool dark = Program.DarkModeEnabled;
|
||||
bool dark = IsDark;
|
||||
|
||||
contextMenu.BackColor = dark ? DarkBackAlt : SystemColors.Menu;
|
||||
contextMenu.ForeColor = dark ? DarkFore : SystemColors.MenuText;
|
||||
@@ -251,7 +339,7 @@ internal static class ThemeManager
|
||||
{
|
||||
if (dropDown is null) return;
|
||||
|
||||
bool dark = Program.DarkModeEnabled;
|
||||
bool dark = IsDark;
|
||||
|
||||
dropDown.BackColor = dark ? DarkBackAlt : SystemColors.Menu;
|
||||
dropDown.ForeColor = dark ? DarkFore : SystemColors.MenuText;
|
||||
@@ -269,10 +357,14 @@ internal static class ThemeManager
|
||||
item.ForeColor = dark ? DarkFore : SystemColors.MenuText;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Themed renderers for menus
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
private class DarkContextMenuRenderer : ToolStripProfessionalRenderer
|
||||
{
|
||||
public DarkContextMenuRenderer() : base(new DarkMenuColorTable()) { }
|
||||
|
||||
|
||||
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
|
||||
{
|
||||
if (e.Item.Selected)
|
||||
@@ -284,7 +376,7 @@ internal static class ThemeManager
|
||||
private class DarkDropDownRenderer : ToolStripProfessionalRenderer
|
||||
{
|
||||
public DarkDropDownRenderer() : base(new DarkMenuColorTable()) { }
|
||||
|
||||
|
||||
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
|
||||
{
|
||||
// Force text color to stay light even when selected
|
||||
@@ -309,6 +401,53 @@ internal static class ThemeManager
|
||||
public override Color SeparatorDark => ColorTranslator.FromHtml("#3F3F46");
|
||||
public override Color SeparatorLight => ColorTranslator.FromHtml("#3F3F46");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Theming helpers for CustomTreeView
|
||||
// All rendering logic for the CustomTreeView's proxy combo box and dropdown
|
||||
// button is centralized here so theming resides in ThemeManager.
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Draws the themed combobox area (background, border and text) used in CustomTreeView.
|
||||
/// This centralizes colors and rendering for light/dark modes.
|
||||
/// </summary>
|
||||
internal static void DrawCustomComboBox(Graphics graphics, Rectangle rect, Font font, string text)
|
||||
{
|
||||
if (graphics is null) return;
|
||||
using SolidBrush comboBrush = new(CustomTreeViewComboBackColor);
|
||||
using Pen borderPen = new(CustomTreeViewComboBorderColor);
|
||||
graphics.FillRectangle(comboBrush, rect);
|
||||
graphics.DrawRectangle(borderPen, rect);
|
||||
// Draw text inside the combobox
|
||||
Size textSize = TextRenderer.MeasureText(graphics, text, font);
|
||||
Point textPoint = new(rect.Left +3, rect.Top + rect.Height /2 - textSize.Height /2);
|
||||
TextRenderer.DrawText(graphics, text, font, textPoint, CustomTreeViewComboTextColor, TextFormatFlags.Default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the themed dropdown button (right-side arrow) used in CustomTreeView comboboxes.
|
||||
/// </summary>
|
||||
internal static void DrawCustomComboBoxButton(Graphics graphics, Rectangle rect)
|
||||
{
|
||||
if (graphics is null) return;
|
||||
using SolidBrush comboBrush = new(CustomTreeViewComboBackColor);
|
||||
using Pen borderPen = new(CustomTreeViewComboBorderColor);
|
||||
graphics.FillRectangle(comboBrush, rect);
|
||||
graphics.DrawRectangle(borderPen, rect);
|
||||
|
||||
// Draw the arrow glyph centered in the rect
|
||||
int arrowSize =3;
|
||||
Point arrowTop = new(rect.X + rect.Width /2, rect.Y + rect.Height /2 -1);
|
||||
Point[] arrowPoints = new[]
|
||||
{
|
||||
arrowTop,
|
||||
new Point(arrowTop.X - arrowSize, arrowTop.Y - arrowSize),
|
||||
new Point(arrowTop.X + arrowSize, arrowTop.Y - arrowSize)
|
||||
};
|
||||
using SolidBrush arrowBrush = new(CustomTreeViewComboTextColor);
|
||||
graphics.FillPolygon(arrowBrush, arrowPoints);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class NativeMethods
|
||||
@@ -322,4 +461,4 @@ internal static class NativeMethods
|
||||
{
|
||||
_ = DwmSetWindowAttribute(handle, DWMWA_USE_IMMERSIVE_DARK_MODE, ref useDark, sizeof(int));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user