From 29b801e13d302569f147e98eb774044223be5878 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Tue, 31 Jan 2023 13:58:42 +0100 Subject: [PATCH] TabbedPane: support hover and focused tab foreground colors (issue #627) changed background behavior: `tabbedPane.getBackgroundAt(tabIndex)` now has higher priority than `TabbedPane.focusColor` and `TabbedPane.selectedBackground` --- CHANGELOG.md | 5 ++ .../formdev/flatlaf/ui/FlatTabbedPaneUI.java | 81 ++++++++++++++----- .../flatlaf/ui/TestFlatStyleableInfo.java | 2 + .../flatlaf/ui/TestFlatStyleableValue.java | 2 + .../formdev/flatlaf/ui/TestFlatStyling.java | 2 + .../dumps/uidefaults/FlatTestLaf_1.8.0.txt | 2 + .../flatlaf/testing/FlatTestLaf.properties | 2 + .../flatlaf/themeeditor/FlatLafUIKeys.txt | 2 + 8 files changed, 76 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a010b010..74653744 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ FlatLaf Change Log - Updated **JetBrains Mono** to [v2.304](https://github.com/JetBrains/JetBrainsMono/releases/tag/v2.304). - Theme Editor: Support macOS light and dark themes. +- TabbedPane: Support hover and focused tab foreground colors. (issue #627) +- TabbedPane: `tabbedPane.getBackgroundAt(tabIndex)` now has higher priority + than `TabbedPane.focusColor` and `TabbedPane.selectedBackground`. If + `tabbedPane.setBackgroundAt(tabIndex)` is used to set a color for a single + tab, then this color is now used even if the tab is focused or selected. - TableHeader: Support column hover and pressed background and foreground colors. (issue #636) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java index 1ecc0dd9..f2ff61be 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java @@ -128,12 +128,14 @@ import com.formdev.flatlaf.util.UIScale; * * @uiDefault TabbedPane.disabledForeground Color * @uiDefault TabbedPane.selectedBackground Color optional - * @uiDefault TabbedPane.selectedForeground Color + * @uiDefault TabbedPane.selectedForeground Color optional * @uiDefault TabbedPane.underlineColor Color * @uiDefault TabbedPane.inactiveUnderlineColor Color * @uiDefault TabbedPane.disabledUnderlineColor Color - * @uiDefault TabbedPane.hoverColor Color - * @uiDefault TabbedPane.focusColor Color + * @uiDefault TabbedPane.hoverColor Color optional + * @uiDefault TabbedPane.hoverForeground Color optional + * @uiDefault TabbedPane.focusColor Color optional + * @uiDefault TabbedPane.focusForeground Color optional * @uiDefault TabbedPane.tabSeparatorColor Color optional; defaults to TabbedPane.contentAreaColor * @uiDefault TabbedPane.contentAreaColor Color * @uiDefault TabbedPane.minimumTabWidth int optional @@ -205,7 +207,9 @@ public class FlatTabbedPaneUI /** @since 2.2 */ @Styleable protected Color inactiveUnderlineColor; @Styleable protected Color disabledUnderlineColor; @Styleable protected Color hoverColor; + /** @since 3.1 */ @Styleable protected Color hoverForeground; @Styleable protected Color focusColor; + /** @since 3.1 */ @Styleable protected Color focusForeground; @Styleable protected Color tabSeparatorColor; @Styleable protected Color contentAreaColor; @@ -328,7 +332,9 @@ public class FlatTabbedPaneUI inactiveUnderlineColor = FlatUIUtils.getUIColor( "TabbedPane.inactiveUnderlineColor", underlineColor ); disabledUnderlineColor = UIManager.getColor( "TabbedPane.disabledUnderlineColor" ); hoverColor = UIManager.getColor( "TabbedPane.hoverColor" ); + hoverForeground = UIManager.getColor( "TabbedPane.hoverForeground" ); focusColor = UIManager.getColor( "TabbedPane.focusColor" ); + focusForeground = UIManager.getColor( "TabbedPane.focusForeground" ); tabSeparatorColor = UIManager.getColor( "TabbedPane.tabSeparatorColor" ); contentAreaColor = UIManager.getColor( "TabbedPane.contentAreaColor" ); @@ -397,7 +403,9 @@ public class FlatTabbedPaneUI inactiveUnderlineColor = null; disabledUnderlineColor = null; hoverColor = null; + hoverForeground = null; focusColor = null; + focusForeground = null; tabSeparatorColor = null; contentAreaColor = null; closeIcon = null; @@ -1141,22 +1149,37 @@ public class FlatTabbedPaneUI } // plain text - Color color; - if( tabPane.isEnabled() && tabPane.isEnabledAt( tabIndex ) ) { - color = tabPane.getForegroundAt( tabIndex ); - if( isSelected && selectedForeground != null && color == tabPane.getForeground() ) - color = selectedForeground; - } else - color = disabledForeground; - int mnemIndex = FlatLaf.isShowMnemonics() ? tabPane.getDisplayedMnemonicIndexAt( tabIndex ) : -1; - - g.setColor( color ); + g.setColor( getTabForeground( tabPlacement, tabIndex, isSelected ) ); FlatUIUtils.drawStringUnderlineCharAt( tabPane, g, title, mnemIndex, textRect.x, textRect.y + metrics.getAscent() ); } ); } + /** @since 3.1 */ + protected Color getTabForeground( int tabPlacement, int tabIndex, boolean isSelected ) { + // tabbed pane or tab is disabled + if( !tabPane.isEnabled() || !tabPane.isEnabledAt( tabIndex ) ) + return disabledForeground; + + // hover + if( hoverForeground != null && getRolloverTab() == tabIndex ) + return hoverForeground; + + // tab foreground (if set) + Color foreground = tabPane.getForegroundAt( tabIndex ); + if( foreground != tabPane.getForeground() ) + return foreground; + + // focused and selected + if( focusForeground != null && isSelected && FlatUIUtils.isPermanentFocusOwner( tabPane ) ) + return focusForeground; + if( selectedForeground != null && isSelected ) + return selectedForeground; + + return foreground; + } + @Override protected void paintTabBackground( Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected ) @@ -1169,14 +1192,27 @@ public class FlatTabbedPaneUI /** @since 2 */ protected Color getTabBackground( int tabPlacement, int tabIndex, boolean isSelected ) { - boolean enabled = tabPane.isEnabled(); - return enabled && tabPane.isEnabledAt( tabIndex ) && getRolloverTab() == tabIndex - ? hoverColor - : (enabled && isSelected && FlatUIUtils.isPermanentFocusOwner( tabPane ) - ? focusColor - : (selectedBackground != null && enabled && isSelected - ? selectedBackground - : tabPane.getBackgroundAt( tabIndex ))); + Color background = tabPane.getBackgroundAt( tabIndex ); + + // tabbed pane or tab is disabled + if( !tabPane.isEnabled() || !tabPane.isEnabledAt( tabIndex ) ) + return background; + + // hover + if( hoverColor != null && getRolloverTab() == tabIndex ) + return hoverColor; + + // tab background (if set) + if( background != tabPane.getBackground() ) + return background; + + // focused and selected + if( focusColor != null && isSelected && FlatUIUtils.isPermanentFocusOwner( tabPane ) ) + return focusColor; + if( selectedBackground != null && isSelected ) + return selectedBackground; + + return background; } @Override @@ -1431,7 +1467,8 @@ public class FlatTabbedPaneUI path.append( gap, false ); // fill gap in case that the tab is colored (e.g. focused or hover) - g.setColor( getTabBackground( tabPlacement, selectedIndex, true ) ); + Color background = getTabBackground( tabPlacement, selectedIndex, true ); + g.setColor( FlatUIUtils.deriveColor( background, tabPane.getBackground() ) ); ((Graphics2D)g).fill( gap ); } } diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java index 50029c61..16a8e8f0 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java @@ -721,7 +721,9 @@ public class TestFlatStyleableInfo "inactiveUnderlineColor", Color.class, "disabledUnderlineColor", Color.class, "hoverColor", Color.class, + "hoverForeground", Color.class, "focusColor", Color.class, + "focusForeground", Color.class, "tabSeparatorColor", Color.class, "contentAreaColor", Color.class, diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableValue.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableValue.java index 0405c694..eac5d453 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableValue.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableValue.java @@ -727,7 +727,9 @@ public class TestFlatStyleableValue testColor( c, ui, "inactiveUnderlineColor", 0x123456 ); testColor( c, ui, "disabledUnderlineColor", 0x123456 ); testColor( c, ui, "hoverColor", 0x123456 ); + testColor( c, ui, "hoverForeground", 0x123456 ); testColor( c, ui, "focusColor", 0x123456 ); + testColor( c, ui, "focusForeground", 0x123456 ); testColor( c, ui, "tabSeparatorColor", 0x123456 ); testColor( c, ui, "contentAreaColor", 0x123456 ); diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java index bc819350..29c7a5b1 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java @@ -906,7 +906,9 @@ public class TestFlatStyling ui.applyStyle( "inactiveUnderlineColor: #fff" ); ui.applyStyle( "disabledUnderlineColor: #fff" ); ui.applyStyle( "hoverColor: #fff" ); + ui.applyStyle( "hoverForeground: #fff" ); ui.applyStyle( "focusColor: #fff" ); + ui.applyStyle( "focusForeground: #fff" ); ui.applyStyle( "tabSeparatorColor: #fff" ); ui.applyStyle( "contentAreaColor: #fff" ); diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt index 40e3d9a8..e3e853db 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt @@ -1085,12 +1085,14 @@ TabbedPane.disabledForeground #777777 HSL 0 0 47 javax.swing.plaf.Colo TabbedPane.disabledUnderlineColor #7a7a7a HSL 0 0 48 javax.swing.plaf.ColorUIResource [UI] TabbedPane.focus #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI] TabbedPane.focusColor #dddddd HSL 0 0 87 javax.swing.plaf.ColorUIResource [UI] +TabbedPane.focusForeground #ffff00 HSL 60 100 50 javax.swing.plaf.ColorUIResource [UI] TabbedPane.font [active] $defaultFont [UI] TabbedPane.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI] TabbedPane.hasFullBorder false TabbedPane.hiddenTabsNavigation moreTabsButton TabbedPane.highlight #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI] TabbedPane.hoverColor #eeeeee HSL 0 0 93 javax.swing.plaf.ColorUIResource [UI] +TabbedPane.hoverForeground #00ffff HSL 180 100 50 javax.swing.plaf.ColorUIResource [UI] TabbedPane.inactiveUnderlineColor #ff00ff HSL 300 100 50 javax.swing.plaf.ColorUIResource [UI] TabbedPane.labelShift 1 TabbedPane.light #e3e3e3 HSL 0 0 89 javax.swing.plaf.ColorUIResource [UI] diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties index c97ae553..d8c6d942 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties @@ -377,7 +377,9 @@ TabbedPane.underlineColor = #ff0 TabbedPane.inactiveUnderlineColor = #f0f TabbedPane.disabledUnderlineColor = #7a7a7a TabbedPane.hoverColor = #eee +TabbedPane.hoverForeground = #0ff TabbedPane.focusColor = #ddd +TabbedPane.focusForeground = #ff0 TabbedPane.tabSeparatorColor = #00f TabbedPane.contentAreaColor = #f00 diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt index 3b7167f8..c42da0c1 100644 --- a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt @@ -848,6 +848,7 @@ TabbedPane.disabledForeground TabbedPane.disabledUnderlineColor TabbedPane.focus TabbedPane.focusColor +TabbedPane.focusForeground TabbedPane.focusInputMap TabbedPane.font TabbedPane.foreground @@ -855,6 +856,7 @@ TabbedPane.hasFullBorder TabbedPane.hiddenTabsNavigation TabbedPane.highlight TabbedPane.hoverColor +TabbedPane.hoverForeground TabbedPane.inactiveUnderlineColor TabbedPane.labelShift TabbedPane.light