From 16393e0cd5d19878bf0fc17eaa7b5898f31bd14f Mon Sep 17 00:00:00 2001 From: Akumas_Coffin_ <68540569+AkumasCoffin@users.noreply.github.com> Date: Thu, 14 May 2026 21:52:07 +1000 Subject: [PATCH] Use ColorUIResource for theme overrides + brighten chart series colors Toggle-off problem: applyExplicitOverrides was storing plain java.awt.Color values via UIManager.put. LookAndFeel.installColorsAndFont only replaces a component's existing colour when it is null or an instance of UIResource - plain Colors are not, so once a component picked up its dark colour it kept that colour for the rest of the JVM lifetime even after toggling back to light mode. Switching every override to ColorUIResource lets subsequent updateComponentTreeUI calls replace the cached colour cleanly. Chart visibility: the JavaFX charts on the Channel tab (NoiseSquelchView) were inheriting Modena's default 8-colour series palette, which has several hues that read poorly against a dark plot background. The existing sdrtrunk_style.css also hardcodes .chart-symbol to solid black. Override .default-color0..7.chart-series-line and matching .chart-line-symbol selectors with a brighter high-contrast palette, darken the plot background to #1c1c1c for stronger contrast against the grid lines, and add explicit colours for axis tick marks, alternate row fills and legend border. --- .../dsheirer/gui/theme/ThemeManager.java | 56 ++++++++++--------- src/main/resources/sdrtrunk_dark.css | 52 ++++++++++++++++- 2 files changed, 82 insertions(+), 26 deletions(-) diff --git a/src/main/java/io/github/dsheirer/gui/theme/ThemeManager.java b/src/main/java/io/github/dsheirer/gui/theme/ThemeManager.java index c3fd7baf..bee03494 100644 --- a/src/main/java/io/github/dsheirer/gui/theme/ThemeManager.java +++ b/src/main/java/io/github/dsheirer/gui/theme/ThemeManager.java @@ -39,6 +39,7 @@ import javax.swing.LookAndFeel; import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; +import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.metal.MetalLookAndFeel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -328,37 +329,42 @@ public class ThemeManager private void applyExplicitOverrides(boolean darkMode) { - Color bgPanel; - Color bgRaised; - Color bgInput; - Color bgSelection; - Color fgPrimary; - Color fgSelection; - Color fgDisabled; - Color border; + //Colors stored under UIManager keys must be ColorUIResource (or null) for + //LookAndFeel.installColorsAndFont() to overwrite a component's existing colour + //on subsequent updateComponentTreeUI calls. Using a plain java.awt.Color pins + //the component foreground/background permanently and prevents the theme from + //ever toggling back. + ColorUIResource bgPanel; + ColorUIResource bgRaised; + ColorUIResource bgInput; + ColorUIResource bgSelection; + ColorUIResource fgPrimary; + ColorUIResource fgSelection; + ColorUIResource fgDisabled; + ColorUIResource border; if(darkMode) { - bgPanel = new Color(0x2b2b2b); - bgRaised = new Color(0x3c3f41); - bgInput = new Color(0x313335); - bgSelection = new Color(0x214283); - fgPrimary = new Color(0xe6e6e6); - fgSelection = Color.WHITE; - fgDisabled = new Color(0x6a6a6a); - border = new Color(0x4f5356); + bgPanel = new ColorUIResource(0x2b2b2b); + bgRaised = new ColorUIResource(0x3c3f41); + bgInput = new ColorUIResource(0x313335); + bgSelection = new ColorUIResource(0x214283); + fgPrimary = new ColorUIResource(0xe6e6e6); + fgSelection = new ColorUIResource(Color.WHITE); + fgDisabled = new ColorUIResource(0x6a6a6a); + border = new ColorUIResource(0x4f5356); } else { //Light mode mirrors FlatLightLaf's palette. - bgPanel = new Color(0xf2f2f2); - bgRaised = new Color(0xffffff); - bgInput = new Color(0xffffff); - bgSelection = new Color(0x2675bf); - fgPrimary = new Color(0x1e1e1e); - fgSelection = Color.WHITE; - fgDisabled = new Color(0x8c8c8c); - border = new Color(0xc4c4c4); + bgPanel = new ColorUIResource(0xf2f2f2); + bgRaised = new ColorUIResource(0xffffff); + bgInput = new ColorUIResource(0xffffff); + bgSelection = new ColorUIResource(0x2675bf); + fgPrimary = new ColorUIResource(0x1e1e1e); + fgSelection = new ColorUIResource(Color.WHITE); + fgDisabled = new ColorUIResource(0x8c8c8c); + border = new ColorUIResource(0xc4c4c4); } String[] simpleComponents = { @@ -406,7 +412,7 @@ public class ThemeManager } UIManager.put("Table.gridColor", border); - UIManager.put("Table.alternateRowColor", new Color(darkMode ? 0x353739 : 0xfafafa)); + UIManager.put("Table.alternateRowColor", new ColorUIResource(darkMode ? 0x353739 : 0xfafafa)); UIManager.put("TableHeader.background", bgRaised); UIManager.put("TableHeader.foreground", fgPrimary); UIManager.put("TableHeader.cellBorder", javax.swing.BorderFactory.createMatteBorder(0, 0, 1, 1, border)); diff --git a/src/main/resources/sdrtrunk_dark.css b/src/main/resources/sdrtrunk_dark.css index 61183a07..4c257590 100644 --- a/src/main/resources/sdrtrunk_dark.css +++ b/src/main/resources/sdrtrunk_dark.css @@ -364,18 +364,30 @@ } .chart +{ + -fx-background-color: #2b2b2b; + -fx-padding: 5px; +} + +.chart-content { -fx-background-color: #2b2b2b; } .chart-plot-background { - -fx-background-color: #313335; + -fx-background-color: #1c1c1c; } .axis { -fx-tick-label-fill: #ececec; + AXIS_COLOR: #4f5356; +} + +.axis .axis-tick-mark, .axis .axis-minor-tick-mark +{ + -fx-stroke: #6a6f73; } .axis-label @@ -388,13 +400,51 @@ -fx-stroke: #3c3f41; } +.chart-alternative-row-fill +{ + -fx-fill: transparent; + -fx-stroke: transparent; +} + +.chart-alternative-column-fill +{ + -fx-fill: transparent; + -fx-stroke: transparent; +} + .chart-legend { -fx-background-color: #313335; -fx-text-fill: #ececec; + -fx-border-color: #4f5356; + -fx-border-width: 1; +} + +.chart-legend-item +{ + -fx-text-fill: #ececec; } .chart-title { -fx-text-fill: #ececec; } + +/* Bright high-contrast palette for chart series lines and symbols on a dark plot background. */ +.default-color0.chart-series-line { -fx-stroke: #ff5555; } +.default-color1.chart-series-line { -fx-stroke: #55aaff; } +.default-color2.chart-series-line { -fx-stroke: #55ff7f; } +.default-color3.chart-series-line { -fx-stroke: #ffd34f; } +.default-color4.chart-series-line { -fx-stroke: #cf9bff; } +.default-color5.chart-series-line { -fx-stroke: #4fe6ff; } +.default-color6.chart-series-line { -fx-stroke: #ff7fbf; } +.default-color7.chart-series-line { -fx-stroke: #ffffff; } + +.default-color0.chart-line-symbol, .default-color0.chart-symbol { -fx-background-color: #ff5555, #2b2b2b; } +.default-color1.chart-line-symbol, .default-color1.chart-symbol { -fx-background-color: #55aaff, #2b2b2b; } +.default-color2.chart-line-symbol, .default-color2.chart-symbol { -fx-background-color: #55ff7f, #2b2b2b; } +.default-color3.chart-line-symbol, .default-color3.chart-symbol { -fx-background-color: #ffd34f, #2b2b2b; } +.default-color4.chart-line-symbol, .default-color4.chart-symbol { -fx-background-color: #cf9bff, #2b2b2b; } +.default-color5.chart-line-symbol, .default-color5.chart-symbol { -fx-background-color: #4fe6ff, #2b2b2b; } +.default-color6.chart-line-symbol, .default-color6.chart-symbol { -fx-background-color: #ff7fbf, #2b2b2b; } +.default-color7.chart-line-symbol, .default-color7.chart-symbol { -fx-background-color: #ffffff, #2b2b2b; }