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`
This commit is contained in:
Karl Tauber
2023-01-31 13:58:42 +01:00
parent 1435469ee5
commit 29b801e13d
8 changed files with 76 additions and 22 deletions

View File

@@ -11,6 +11,11 @@ FlatLaf Change Log
- Updated **JetBrains Mono** to - Updated **JetBrains Mono** to
[v2.304](https://github.com/JetBrains/JetBrainsMono/releases/tag/v2.304). [v2.304](https://github.com/JetBrains/JetBrainsMono/releases/tag/v2.304).
- Theme Editor: Support macOS light and dark themes. - 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 - TableHeader: Support column hover and pressed background and foreground
colors. (issue #636) colors. (issue #636)

View File

@@ -128,12 +128,14 @@ import com.formdev.flatlaf.util.UIScale;
* *
* @uiDefault TabbedPane.disabledForeground Color * @uiDefault TabbedPane.disabledForeground Color
* @uiDefault TabbedPane.selectedBackground Color optional * @uiDefault TabbedPane.selectedBackground Color optional
* @uiDefault TabbedPane.selectedForeground Color * @uiDefault TabbedPane.selectedForeground Color optional
* @uiDefault TabbedPane.underlineColor Color * @uiDefault TabbedPane.underlineColor Color
* @uiDefault TabbedPane.inactiveUnderlineColor Color * @uiDefault TabbedPane.inactiveUnderlineColor Color
* @uiDefault TabbedPane.disabledUnderlineColor Color * @uiDefault TabbedPane.disabledUnderlineColor Color
* @uiDefault TabbedPane.hoverColor Color * @uiDefault TabbedPane.hoverColor Color optional
* @uiDefault TabbedPane.focusColor Color * @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.tabSeparatorColor Color optional; defaults to TabbedPane.contentAreaColor
* @uiDefault TabbedPane.contentAreaColor Color * @uiDefault TabbedPane.contentAreaColor Color
* @uiDefault TabbedPane.minimumTabWidth int optional * @uiDefault TabbedPane.minimumTabWidth int optional
@@ -205,7 +207,9 @@ public class FlatTabbedPaneUI
/** @since 2.2 */ @Styleable protected Color inactiveUnderlineColor; /** @since 2.2 */ @Styleable protected Color inactiveUnderlineColor;
@Styleable protected Color disabledUnderlineColor; @Styleable protected Color disabledUnderlineColor;
@Styleable protected Color hoverColor; @Styleable protected Color hoverColor;
/** @since 3.1 */ @Styleable protected Color hoverForeground;
@Styleable protected Color focusColor; @Styleable protected Color focusColor;
/** @since 3.1 */ @Styleable protected Color focusForeground;
@Styleable protected Color tabSeparatorColor; @Styleable protected Color tabSeparatorColor;
@Styleable protected Color contentAreaColor; @Styleable protected Color contentAreaColor;
@@ -328,7 +332,9 @@ public class FlatTabbedPaneUI
inactiveUnderlineColor = FlatUIUtils.getUIColor( "TabbedPane.inactiveUnderlineColor", underlineColor ); inactiveUnderlineColor = FlatUIUtils.getUIColor( "TabbedPane.inactiveUnderlineColor", underlineColor );
disabledUnderlineColor = UIManager.getColor( "TabbedPane.disabledUnderlineColor" ); disabledUnderlineColor = UIManager.getColor( "TabbedPane.disabledUnderlineColor" );
hoverColor = UIManager.getColor( "TabbedPane.hoverColor" ); hoverColor = UIManager.getColor( "TabbedPane.hoverColor" );
hoverForeground = UIManager.getColor( "TabbedPane.hoverForeground" );
focusColor = UIManager.getColor( "TabbedPane.focusColor" ); focusColor = UIManager.getColor( "TabbedPane.focusColor" );
focusForeground = UIManager.getColor( "TabbedPane.focusForeground" );
tabSeparatorColor = UIManager.getColor( "TabbedPane.tabSeparatorColor" ); tabSeparatorColor = UIManager.getColor( "TabbedPane.tabSeparatorColor" );
contentAreaColor = UIManager.getColor( "TabbedPane.contentAreaColor" ); contentAreaColor = UIManager.getColor( "TabbedPane.contentAreaColor" );
@@ -397,7 +403,9 @@ public class FlatTabbedPaneUI
inactiveUnderlineColor = null; inactiveUnderlineColor = null;
disabledUnderlineColor = null; disabledUnderlineColor = null;
hoverColor = null; hoverColor = null;
hoverForeground = null;
focusColor = null; focusColor = null;
focusForeground = null;
tabSeparatorColor = null; tabSeparatorColor = null;
contentAreaColor = null; contentAreaColor = null;
closeIcon = null; closeIcon = null;
@@ -1141,22 +1149,37 @@ public class FlatTabbedPaneUI
} }
// plain text // 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; int mnemIndex = FlatLaf.isShowMnemonics() ? tabPane.getDisplayedMnemonicIndexAt( tabIndex ) : -1;
g.setColor( getTabForeground( tabPlacement, tabIndex, isSelected ) );
g.setColor( color );
FlatUIUtils.drawStringUnderlineCharAt( tabPane, g, title, mnemIndex, FlatUIUtils.drawStringUnderlineCharAt( tabPane, g, title, mnemIndex,
textRect.x, textRect.y + metrics.getAscent() ); 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 @Override
protected void paintTabBackground( Graphics g, int tabPlacement, int tabIndex, protected void paintTabBackground( Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected ) int x, int y, int w, int h, boolean isSelected )
@@ -1169,14 +1192,27 @@ public class FlatTabbedPaneUI
/** @since 2 */ /** @since 2 */
protected Color getTabBackground( int tabPlacement, int tabIndex, boolean isSelected ) { protected Color getTabBackground( int tabPlacement, int tabIndex, boolean isSelected ) {
boolean enabled = tabPane.isEnabled(); Color background = tabPane.getBackgroundAt( tabIndex );
return enabled && tabPane.isEnabledAt( tabIndex ) && getRolloverTab() == tabIndex
? hoverColor // tabbed pane or tab is disabled
: (enabled && isSelected && FlatUIUtils.isPermanentFocusOwner( tabPane ) if( !tabPane.isEnabled() || !tabPane.isEnabledAt( tabIndex ) )
? focusColor return background;
: (selectedBackground != null && enabled && isSelected
? selectedBackground // hover
: tabPane.getBackgroundAt( tabIndex ))); 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 @Override
@@ -1431,7 +1467,8 @@ public class FlatTabbedPaneUI
path.append( gap, false ); path.append( gap, false );
// fill gap in case that the tab is colored (e.g. focused or hover) // 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 ); ((Graphics2D)g).fill( gap );
} }
} }

View File

@@ -721,7 +721,9 @@ public class TestFlatStyleableInfo
"inactiveUnderlineColor", Color.class, "inactiveUnderlineColor", Color.class,
"disabledUnderlineColor", Color.class, "disabledUnderlineColor", Color.class,
"hoverColor", Color.class, "hoverColor", Color.class,
"hoverForeground", Color.class,
"focusColor", Color.class, "focusColor", Color.class,
"focusForeground", Color.class,
"tabSeparatorColor", Color.class, "tabSeparatorColor", Color.class,
"contentAreaColor", Color.class, "contentAreaColor", Color.class,

View File

@@ -727,7 +727,9 @@ public class TestFlatStyleableValue
testColor( c, ui, "inactiveUnderlineColor", 0x123456 ); testColor( c, ui, "inactiveUnderlineColor", 0x123456 );
testColor( c, ui, "disabledUnderlineColor", 0x123456 ); testColor( c, ui, "disabledUnderlineColor", 0x123456 );
testColor( c, ui, "hoverColor", 0x123456 ); testColor( c, ui, "hoverColor", 0x123456 );
testColor( c, ui, "hoverForeground", 0x123456 );
testColor( c, ui, "focusColor", 0x123456 ); testColor( c, ui, "focusColor", 0x123456 );
testColor( c, ui, "focusForeground", 0x123456 );
testColor( c, ui, "tabSeparatorColor", 0x123456 ); testColor( c, ui, "tabSeparatorColor", 0x123456 );
testColor( c, ui, "contentAreaColor", 0x123456 ); testColor( c, ui, "contentAreaColor", 0x123456 );

View File

@@ -906,7 +906,9 @@ public class TestFlatStyling
ui.applyStyle( "inactiveUnderlineColor: #fff" ); ui.applyStyle( "inactiveUnderlineColor: #fff" );
ui.applyStyle( "disabledUnderlineColor: #fff" ); ui.applyStyle( "disabledUnderlineColor: #fff" );
ui.applyStyle( "hoverColor: #fff" ); ui.applyStyle( "hoverColor: #fff" );
ui.applyStyle( "hoverForeground: #fff" );
ui.applyStyle( "focusColor: #fff" ); ui.applyStyle( "focusColor: #fff" );
ui.applyStyle( "focusForeground: #fff" );
ui.applyStyle( "tabSeparatorColor: #fff" ); ui.applyStyle( "tabSeparatorColor: #fff" );
ui.applyStyle( "contentAreaColor: #fff" ); ui.applyStyle( "contentAreaColor: #fff" );

View File

@@ -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.disabledUnderlineColor #7a7a7a HSL 0 0 48 javax.swing.plaf.ColorUIResource [UI]
TabbedPane.focus #ff0000 HSL 0 100 50 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.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.font [active] $defaultFont [UI]
TabbedPane.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI] TabbedPane.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
TabbedPane.hasFullBorder false TabbedPane.hasFullBorder false
TabbedPane.hiddenTabsNavigation moreTabsButton TabbedPane.hiddenTabsNavigation moreTabsButton
TabbedPane.highlight #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI] 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.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.inactiveUnderlineColor #ff00ff HSL 300 100 50 javax.swing.plaf.ColorUIResource [UI]
TabbedPane.labelShift 1 TabbedPane.labelShift 1
TabbedPane.light #e3e3e3 HSL 0 0 89 javax.swing.plaf.ColorUIResource [UI] TabbedPane.light #e3e3e3 HSL 0 0 89 javax.swing.plaf.ColorUIResource [UI]

View File

@@ -377,7 +377,9 @@ TabbedPane.underlineColor = #ff0
TabbedPane.inactiveUnderlineColor = #f0f TabbedPane.inactiveUnderlineColor = #f0f
TabbedPane.disabledUnderlineColor = #7a7a7a TabbedPane.disabledUnderlineColor = #7a7a7a
TabbedPane.hoverColor = #eee TabbedPane.hoverColor = #eee
TabbedPane.hoverForeground = #0ff
TabbedPane.focusColor = #ddd TabbedPane.focusColor = #ddd
TabbedPane.focusForeground = #ff0
TabbedPane.tabSeparatorColor = #00f TabbedPane.tabSeparatorColor = #00f
TabbedPane.contentAreaColor = #f00 TabbedPane.contentAreaColor = #f00

View File

@@ -848,6 +848,7 @@ TabbedPane.disabledForeground
TabbedPane.disabledUnderlineColor TabbedPane.disabledUnderlineColor
TabbedPane.focus TabbedPane.focus
TabbedPane.focusColor TabbedPane.focusColor
TabbedPane.focusForeground
TabbedPane.focusInputMap TabbedPane.focusInputMap
TabbedPane.font TabbedPane.font
TabbedPane.foreground TabbedPane.foreground
@@ -855,6 +856,7 @@ TabbedPane.hasFullBorder
TabbedPane.hiddenTabsNavigation TabbedPane.hiddenTabsNavigation
TabbedPane.highlight TabbedPane.highlight
TabbedPane.hoverColor TabbedPane.hoverColor
TabbedPane.hoverForeground
TabbedPane.inactiveUnderlineColor TabbedPane.inactiveUnderlineColor
TabbedPane.labelShift TabbedPane.labelShift
TabbedPane.light TabbedPane.light