You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2026/04/19 10:44:44 UTC

(groovy) branch master updated: GROOVY-11932: Allow theme switching light/dark/system in groovyConsole (minor color tweaks)

This is an automated email from the ASF dual-hosted git repository.

paulk-asert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 2f78e78e19 GROOVY-11932: Allow theme switching light/dark/system in groovyConsole (minor color tweaks)
2f78e78e19 is described below

commit 2f78e78e196da58183846695c6ef05a984faca3a
Author: Paul King <pa...@asert.com.au>
AuthorDate: Sun Apr 19 20:44:35 2026 +1000

    GROOVY-11932: Allow theme switching light/dark/system in groovyConsole (minor color tweaks)
---
 .../groovy/groovy/console/ui/ConsoleActions.groovy | 14 ++--
 .../groovy/groovy/console/ui/ConsoleView.groovy    | 12 ++--
 .../src/main/groovy/groovy/console/ui/Icons.groovy | 75 +++++++++++++---------
 .../groovy/console/ui/view/BasicToolBar.groovy     |  8 +--
 4 files changed, 60 insertions(+), 49 deletions(-)

diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleActions.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleActions.groovy
index cc642a83bb..1466b8fe88 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleActions.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleActions.groovy
@@ -139,7 +139,7 @@ cutAction = action(
         closure: controller.&cut,
         mnemonic: 'T',
         accelerator: shortcut('X'),
-        smallIcon: Icons.menu('content_cut'),
+        smallIcon: Icons.menuSubtleBlue('content_cut'),
         shortDescription: 'Cut'
 )
 
@@ -148,7 +148,7 @@ copyAction = action(
         closure: controller.&copy,
         mnemonic: 'C',
         accelerator: shortcut('C'),
-        smallIcon: Icons.menu('content_copy'),
+        smallIcon: Icons.menuSubtleBlue('content_copy'),
         shortDescription: 'Copy'
 )
 
@@ -157,7 +157,7 @@ pasteAction = action(
         closure: controller.&paste,
         mnemonic: 'P',
         accelerator: shortcut('V'),
-        smallIcon: Icons.menu('content_paste'),
+        smallIcon: Icons.menuSubtleBlue('content_paste'),
         shortDescription: 'Paste'
 )
 
@@ -165,7 +165,7 @@ selectAllAction = action(
         name: 'Select All',
         closure: controller.&selectAll,
         mnemonic: 'A',
-        smallIcon: Icons.menu('select_all'),
+        smallIcon: Icons.menuSubtleBlue('select_all'),
         accelerator: shortcut('A')
 )
 
@@ -213,7 +213,7 @@ runJavaAction = action(
         closure: controller.&runJava,
         mnemonic: 'J',
         accelerator: shortcut('alt R'),
-        smallIcon: Icons.menu('coffee'),
+        smallIcon: Icons.menuJavaBlue('coffee'),
         shortDescription: 'Execute Java Code'
 )
 
@@ -265,7 +265,7 @@ listClasspath = action(
 clearClassloader = action(
         name: 'Clear Script Context',
         closure: controller.&clearContext,
-        smallIcon: Icons.menu('bolt'),
+        smallIcon: Icons.menuAmber('bolt'),
         mnemonic: 'C',
 )
 
@@ -413,7 +413,7 @@ smartHighlighterAction = action(
 aboutAction = action(
         name: 'About',
         closure: controller.&showAbout,
-        smallIcon: Icons.menu('info'),
+        smallIcon: Icons.menuBlue('info'),
         mnemonic: 'A'
 )
 
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleView.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleView.groovy
index cc71c74149..4119fb1c45 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleView.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleView.groovy
@@ -76,10 +76,10 @@ container(consoleFrame) {
 // — override each action's smallIcon (which is OS-themed for the screen
 // menu bar) with an app-themed instance here.
 inputEditor.textEditor.componentPopupMenu = popupMenu {
-    menuItem(cutAction,          icon: Icons.load('content_cut'))
-    menuItem(copyAction,         icon: Icons.load('content_copy'))
-    menuItem(pasteAction,        icon: Icons.load('content_paste'))
-    menuItem(selectAllAction,    icon: Icons.load('select_all'))
+    menuItem(cutAction,          icon: Icons.subtleBlue('content_cut'))
+    menuItem(copyAction,         icon: Icons.subtleBlue('content_copy'))
+    menuItem(pasteAction,        icon: Icons.subtleBlue('content_paste'))
+    menuItem(selectAllAction,    icon: Icons.subtleBlue('select_all'))
     separator()
     menuItem(undoAction,         icon: Icons.load('undo'))
     menuItem(redoAction,         icon: Icons.load('redo'))
@@ -89,8 +89,8 @@ inputEditor.textEditor.componentPopupMenu = popupMenu {
 }
 
 outputArea.componentPopupMenu = popupMenu {
-    menuItem(copyAction,         icon: Icons.load('content_copy'))
-    menuItem(selectAllAction,    icon: Icons.load('select_all'))
+    menuItem(copyAction,         icon: Icons.subtleBlue('content_copy'))
+    menuItem(selectAllAction,    icon: Icons.subtleBlue('select_all'))
     menuItem(clearOutputAction,  icon: Icons.load('delete_sweep'))
 }
 
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/Icons.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/Icons.groovy
index 8c9529f10b..2e7c2240bd 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/Icons.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/Icons.groovy
@@ -61,13 +61,14 @@ class Icons {
         menuIcon(name, { Color c -> UIManager.getColor('Label.foreground') ?: c })
     }
 
-    static DynamicSVGIcon green(String name) {
-        menuIcon(name, greenMapper({ ThemeManager.isDark() }))
-    }
-
-    static DynamicSVGIcon red(String name) {
-        menuIcon(name, redMapper({ ThemeManager.isDark() }))
-    }
+    static DynamicSVGIcon green(String name)  { menuIcon(name, greenMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon red(String name)    { menuIcon(name, redMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon blue(String name)   { menuIcon(name, blueMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon amber(String name)  { menuIcon(name, amberMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon violet(String name) { menuIcon(name, violetMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon teal(String name)   { menuIcon(name, tealMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon javaBlue(String name) { menuIcon(name, javaBlueMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon subtleBlue(String name) { menuIcon(name, subtleBlueMapper({ ThemeManager.isDark() })) }
 
     // ---- main menu-bar icons (tint follows the menu-bar background, which is OS-drawn on macOS) ----
 
@@ -75,13 +76,14 @@ class Icons {
         menuIcon(name, { Color c -> ThemeManager.menuIconForeground ?: c })
     }
 
-    static DynamicSVGIcon menuGreen(String name) {
-        menuIcon(name, greenMapper({ ThemeManager.isMenuDark() }))
-    }
-
-    static DynamicSVGIcon menuRed(String name) {
-        menuIcon(name, redMapper({ ThemeManager.isMenuDark() }))
-    }
+    static DynamicSVGIcon menuGreen(String name)  { menuIcon(name, greenMapper({ ThemeManager.isMenuDark() })) }
+    static DynamicSVGIcon menuRed(String name)    { menuIcon(name, redMapper({ ThemeManager.isMenuDark() })) }
+    static DynamicSVGIcon menuBlue(String name)   { menuIcon(name, blueMapper({ ThemeManager.isMenuDark() })) }
+    static DynamicSVGIcon menuAmber(String name)  { menuIcon(name, amberMapper({ ThemeManager.isMenuDark() })) }
+    static DynamicSVGIcon menuViolet(String name) { menuIcon(name, violetMapper({ ThemeManager.isMenuDark() })) }
+    static DynamicSVGIcon menuTeal(String name)   { menuIcon(name, tealMapper({ ThemeManager.isMenuDark() })) }
+    static DynamicSVGIcon menuJavaBlue(String name) { menuIcon(name, javaBlueMapper({ ThemeManager.isMenuDark() })) }
+    static DynamicSVGIcon menuSubtleBlue(String name) { menuIcon(name, subtleBlueMapper({ ThemeManager.isMenuDark() })) }
 
     // ---- toolbar / resizable ----
 
@@ -89,24 +91,33 @@ class Icons {
         toolbarIcon(name, { Color c -> UIManager.getColor('Label.foreground') ?: c })
     }
 
-    static DynamicSVGIcon toolbarGreen(String name) {
-        toolbarIcon(name, greenMapper({ ThemeManager.isDark() }))
-    }
-
-    static DynamicSVGIcon toolbarRed(String name) {
-        toolbarIcon(name, redMapper({ ThemeManager.isDark() }))
-    }
-
-    private static Closure<Color> greenMapper(Closure<Boolean> darkCheck) {
-        Color light = new Color(0x2E7D32)
-        Color dark = new Color(0x81C784)
-        return { Color c -> darkCheck() ? dark : light }
-    }
-
-    private static Closure<Color> redMapper(Closure<Boolean> darkCheck) {
-        Color light = new Color(0xC62828)
-        Color dark = new Color(0xEF5350)
-        return { Color c -> darkCheck() ? dark : light }
+    static DynamicSVGIcon toolbarGreen(String name)  { toolbarIcon(name, greenMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon toolbarRed(String name)    { toolbarIcon(name, redMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon toolbarBlue(String name)   { toolbarIcon(name, blueMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon toolbarAmber(String name)  { toolbarIcon(name, amberMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon toolbarViolet(String name) { toolbarIcon(name, violetMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon toolbarTeal(String name)   { toolbarIcon(name, tealMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon toolbarJavaBlue(String name) { toolbarIcon(name, javaBlueMapper({ ThemeManager.isDark() })) }
+    static DynamicSVGIcon toolbarSubtleBlue(String name) { toolbarIcon(name, subtleBlueMapper({ ThemeManager.isDark() })) }
+
+    // Material "700" for light theme / "400" for dark — muted enough not to
+    // shout next to grayscale neighbours, lifted in value for dark readability
+    private static Closure<Color> greenMapper (Closure<Boolean> darkCheck) { hueMapper(darkCheck, 0x2E7D32, 0x81C784) }
+    private static Closure<Color> redMapper   (Closure<Boolean> darkCheck) { hueMapper(darkCheck, 0xC62828, 0xEF5350) }
+    private static Closure<Color> blueMapper  (Closure<Boolean> darkCheck) { hueMapper(darkCheck, 0x1565C0, 0x64B5F6) }
+    private static Closure<Color> amberMapper (Closure<Boolean> darkCheck) { hueMapper(darkCheck, 0xEF6C00, 0xFFB74D) }
+    private static Closure<Color> violetMapper(Closure<Boolean> darkCheck) { hueMapper(darkCheck, 0x7E57C2, 0xB39DDB) }
+    private static Closure<Color> tealMapper  (Closure<Boolean> darkCheck) { hueMapper(darkCheck, 0x00838F, 0x4DD0E1) }
+    // Official Java brand blue (#007396) for light; a lifted variant for dark
+    private static Closure<Color> javaBlueMapper(Closure<Boolean> darkCheck) { hueMapper(darkCheck, 0x007396, 0x4DB6E3) }
+    // Blue-leaning slate — reads as "almost the text colour" but with enough
+    // blue to group related but unremarkable actions (cut/copy/paste).
+    private static Closure<Color> subtleBlueMapper(Closure<Boolean> darkCheck) { hueMapper(darkCheck, 0x4A6A8A, 0xA0B5CC) }
+
+    private static Closure<Color> hueMapper(Closure<Boolean> darkCheck, int light, int dark) {
+        Color lightColor = new Color(light)
+        Color darkColor = new Color(dark)
+        return { Color c -> darkCheck() ? darkColor : lightColor }
     }
 
     private static DynamicSVGIcon menuIcon(String name, Closure<Color> mapper) {
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/view/BasicToolBar.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/view/BasicToolBar.groovy
index 98db7ec925..07cd511532 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/view/BasicToolBar.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/view/BasicToolBar.groovy
@@ -34,9 +34,9 @@ toolbar = toolBar(rollover: true, visible: controller.showToolbar, constraints:
     button(undoAction,         text: null, icon: Icons.toolbar('undo'))
     button(redoAction,         text: null, icon: Icons.toolbar('redo'))
     separator(orientation: SwingConstants.VERTICAL)
-    button(cutAction,          text: null, icon: Icons.toolbar('content_cut'))
-    button(copyAction,         text: null, icon: Icons.toolbar('content_copy'))
-    button(pasteAction,        text: null, icon: Icons.toolbar('content_paste'))
+    button(cutAction,          text: null, icon: Icons.toolbarSubtleBlue('content_cut'))
+    button(copyAction,         text: null, icon: Icons.toolbarSubtleBlue('content_copy'))
+    button(pasteAction,        text: null, icon: Icons.toolbarSubtleBlue('content_paste'))
     separator(orientation: SwingConstants.VERTICAL)
     button(findAction,         text: null, icon: Icons.toolbar('search'))
     button(replaceAction,      text: null, icon: Icons.toolbar('find_replace'))
@@ -52,5 +52,5 @@ toolbar = toolBar(rollover: true, visible: controller.showToolbar, constraints:
     button(smallerFontAction,  text: null, icon: Icons.toolbar('text_decrease'))
     button(largerFontAction,   text: null, icon: Icons.toolbar('text_increase'))
     separator(orientation: SwingConstants.VERTICAL)
-    button(cycleThemeAction,   text: null, icon: Icons.toolbar('refresh'))
+    button(cycleThemeAction,   text: null, icon: Icons.toolbarViolet('refresh'))
 }