TabbedPane: selected tab underline color now changes depending on whether the focus is within the tab content (issue #398)

This commit is contained in:
Karl Tauber
2022-04-19 22:19:47 +02:00
parent aca9931560
commit b57e4c0565
14 changed files with 121 additions and 3 deletions

View File

@@ -5,6 +5,8 @@ FlatLaf Change Log
#### New features and improvements #### New features and improvements
- TabbedPane: Selected tab underline color now changes depending on whether the
focus is within the tab content. (issue #398)
- IntelliJ Themes: TabbedPane now use different background color for selected - IntelliJ Themes: TabbedPane now use different background color for selected
tabs in all "Arc" themes, in "Hiberbee Dark" and in all "Material UI Lite" tabs in all "Arc" themes, in "Hiberbee Dark" and in all "Material UI Lite"
themes. themes.

View File

@@ -618,6 +618,7 @@ public class IntelliJTheme
// TabbedPane // TabbedPane
uiKeyCopying.put( "TabbedPane.selectedBackground", "DefaultTabs.underlinedTabBackground" ); uiKeyCopying.put( "TabbedPane.selectedBackground", "DefaultTabs.underlinedTabBackground" );
uiKeyCopying.put( "TabbedPane.selectedForeground", "DefaultTabs.underlinedTabForeground" ); uiKeyCopying.put( "TabbedPane.selectedForeground", "DefaultTabs.underlinedTabForeground" );
uiKeyCopying.put( "TabbedPane.inactiveUnderlineColor", "DefaultTabs.inactiveUnderlineColor" );
// TitlePane // TitlePane
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" ); uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );

View File

@@ -59,6 +59,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.IntConsumer; import java.util.function.IntConsumer;
import java.util.function.Predicate;
import javax.accessibility.Accessible; import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleContext;
import javax.swing.Action; import javax.swing.Action;
@@ -82,10 +83,12 @@ import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener; import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.TabbedPaneUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTabbedPaneUI; import javax.swing.plaf.basic.BasicTabbedPaneUI;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import javax.swing.text.View; import javax.swing.text.View;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.icons.FlatTabbedPaneCloseIcon; import com.formdev.flatlaf.icons.FlatTabbedPaneCloseIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
@@ -127,6 +130,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TabbedPane.selectedBackground Color optional * @uiDefault TabbedPane.selectedBackground Color optional
* @uiDefault TabbedPane.selectedForeground Color * @uiDefault TabbedPane.selectedForeground Color
* @uiDefault TabbedPane.underlineColor Color * @uiDefault TabbedPane.underlineColor Color
* @uiDefault TabbedPane.inactiveUnderlineColor Color
* @uiDefault TabbedPane.disabledUnderlineColor Color * @uiDefault TabbedPane.disabledUnderlineColor Color
* @uiDefault TabbedPane.hoverColor Color * @uiDefault TabbedPane.hoverColor Color
* @uiDefault TabbedPane.focusColor Color * @uiDefault TabbedPane.focusColor Color
@@ -198,6 +202,7 @@ public class FlatTabbedPaneUI
@Styleable protected Color selectedBackground; @Styleable protected Color selectedBackground;
@Styleable protected Color selectedForeground; @Styleable protected Color selectedForeground;
@Styleable protected Color underlineColor; @Styleable protected Color underlineColor;
/** @since 2.2 */ @Styleable protected Color inactiveUnderlineColor;
@Styleable protected Color disabledUnderlineColor; @Styleable protected Color disabledUnderlineColor;
@Styleable protected Color hoverColor; @Styleable protected Color hoverColor;
@Styleable protected Color focusColor; @Styleable protected Color focusColor;
@@ -288,6 +293,7 @@ public class FlatTabbedPaneUI
super.installUI( c ); super.installUI( c );
FlatSelectedTabRepainter.install();
installStyle(); installStyle();
} }
@@ -318,6 +324,7 @@ public class FlatTabbedPaneUI
selectedBackground = UIManager.getColor( "TabbedPane.selectedBackground" ); selectedBackground = UIManager.getColor( "TabbedPane.selectedBackground" );
selectedForeground = UIManager.getColor( "TabbedPane.selectedForeground" ); selectedForeground = UIManager.getColor( "TabbedPane.selectedForeground" );
underlineColor = UIManager.getColor( "TabbedPane.underlineColor" ); underlineColor = UIManager.getColor( "TabbedPane.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" );
focusColor = UIManager.getColor( "TabbedPane.focusColor" ); focusColor = UIManager.getColor( "TabbedPane.focusColor" );
@@ -385,6 +392,7 @@ public class FlatTabbedPaneUI
selectedBackground = null; selectedBackground = null;
selectedForeground = null; selectedForeground = null;
underlineColor = null; underlineColor = null;
inactiveUnderlineColor = null;
disabledUnderlineColor = null; disabledUnderlineColor = null;
hoverColor = null; hoverColor = null;
focusColor = null; focusColor = null;
@@ -733,7 +741,6 @@ public class FlatTabbedPaneUI
// increase size of repaint region to include part of content border // increase size of repaint region to include part of content border
if( contentSeparatorHeight > 0 && if( contentSeparatorHeight > 0 &&
getTabType() == TAB_TYPE_CARD &&
clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, true ) ) clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, true ) )
{ {
int sh = scale( contentSeparatorHeight ); int sh = scale( contentSeparatorHeight );
@@ -1205,7 +1212,9 @@ public class FlatTabbedPaneUI
} }
protected void paintTabSelection( Graphics g, int tabPlacement, int x, int y, int w, int h ) { protected void paintTabSelection( Graphics g, int tabPlacement, int x, int y, int w, int h ) {
g.setColor( tabPane.isEnabled() ? underlineColor : disabledUnderlineColor ); g.setColor( tabPane.isEnabled()
? (isTabbedPaneOrChildFocused() ? underlineColor : inactiveUnderlineColor)
: disabledUnderlineColor );
// paint underline selection // paint underline selection
boolean atBottom = (getTabType() != TAB_TYPE_CARD); boolean atBottom = (getTabType() != TAB_TYPE_CARD);
@@ -1236,6 +1245,23 @@ public class FlatTabbedPaneUI
} }
} }
/** @since 2.2 */
@SuppressWarnings( "unchecked" )
protected boolean isTabbedPaneOrChildFocused() {
KeyboardFocusManager keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
Object value = tabPane.getClientProperty( FlatClientProperties.COMPONENT_FOCUS_OWNER );
if( value instanceof Predicate ) {
return ((Predicate<JComponent>)value).test( tabPane ) &&
FlatUIUtils.isInActiveWindow( tabPane, keyboardFocusManager.getActiveWindow() );
}
Component focusOwner = keyboardFocusManager.getPermanentFocusOwner();
return focusOwner != null &&
SwingUtilities.isDescendingFrom( focusOwner, tabPane ) &&
FlatUIUtils.isInActiveWindow( focusOwner, keyboardFocusManager.getActiveWindow() );
}
/** /**
* Actually does nearly the same as super.paintContentBorder() but * Actually does nearly the same as super.paintContentBorder() but
* - not using UIManager.getColor("TabbedPane.contentAreaColor") to be GUI builder friendly * - not using UIManager.getColor("TabbedPane.contentAreaColor") to be GUI builder friendly
@@ -3341,4 +3367,77 @@ public class FlatTabbedPaneUI
delegate.actionPerformed( e ); delegate.actionPerformed( e );
} }
} }
//---- class FlatSelectedTabRepainter -------------------------------------
private static class FlatSelectedTabRepainter
implements PropertyChangeListener//, Runnable
{
private static FlatSelectedTabRepainter instance;
private KeyboardFocusManager keyboardFocusManager;
static void install() {
synchronized( FlatSelectedTabRepainter.class ) {
if( instance != null )
return;
instance = new FlatSelectedTabRepainter();
}
}
FlatSelectedTabRepainter() {
keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
keyboardFocusManager.addPropertyChangeListener( this );
}
private void uninstall() {
synchronized( FlatSelectedTabRepainter.class ) {
if( instance == null )
return;
keyboardFocusManager.removePropertyChangeListener( this );
keyboardFocusManager = null;
instance = null;
}
}
@Override
public void propertyChange( PropertyChangeEvent e ) {
// uninstall if no longer using FlatLaf
if( !(UIManager.getLookAndFeel() instanceof FlatLaf) ) {
uninstall();
return;
}
switch( e.getPropertyName() ) {
case "permanentFocusOwner":
Object oldValue = e.getOldValue();
Object newValue = e.getNewValue();
if( oldValue instanceof Component )
repaintSelectedTabs( (Component) oldValue );
if( newValue instanceof Component )
repaintSelectedTabs( (Component) newValue );
break;
case "activeWindow":
repaintSelectedTabs( keyboardFocusManager.getPermanentFocusOwner() );
break;
}
}
private void repaintSelectedTabs( Component c ) {
if( c instanceof JTabbedPane )
repaintSelectedTab( (JTabbedPane) c );
while( (c = SwingUtilities.getAncestorOfClass( JTabbedPane.class, c )) != null )
repaintSelectedTab( (JTabbedPane) c );
}
private void repaintSelectedTab( JTabbedPane tabbedPane ) {
TabbedPaneUI ui = tabbedPane.getUI();
if( ui instanceof FlatTabbedPaneUI )
((FlatTabbedPaneUI) ui).repaintTab( tabbedPane.getSelectedIndex() );
}
}
} }

View File

@@ -245,7 +245,7 @@ public class FlatUIUtils
isInActiveWindow( c, keyboardFocusManager.getActiveWindow() ); isInActiveWindow( c, keyboardFocusManager.getActiveWindow() );
} }
private static boolean isInActiveWindow( Component c, Window activeWindow ) { static boolean isInActiveWindow( Component c, Window activeWindow ) {
Window window = SwingUtilities.windowForComponent( c ); Window window = SwingUtilities.windowForComponent( c );
return window == activeWindow || return window == activeWindow ||
(window != null && window.getType() == Window.Type.POPUP && window.getOwner() == activeWindow); (window != null && window.getType() == Window.Type.POPUP && window.getOwner() == activeWindow);

View File

@@ -306,6 +306,7 @@ SplitPaneDivider.draggingColor = $Component.borderColor
#---- TabbedPane ---- #---- TabbedPane ----
TabbedPane.underlineColor = @accentUnderlineColor TabbedPane.underlineColor = @accentUnderlineColor
TabbedPane.inactiveUnderlineColor = mix(@accentUnderlineColor,$TabbedPane.background,60%)
TabbedPane.disabledUnderlineColor = lighten(@background,23%) TabbedPane.disabledUnderlineColor = lighten(@background,23%)
TabbedPane.hoverColor = darken($TabbedPane.background,5%,derived noAutoInverse) TabbedPane.hoverColor = darken($TabbedPane.background,5%,derived noAutoInverse)
TabbedPane.focusColor = mix(@selectionBackground,$TabbedPane.background,25%) TabbedPane.focusColor = mix(@selectionBackground,$TabbedPane.background,25%)

View File

@@ -313,6 +313,7 @@ SplitPaneDivider.draggingColor = $Component.borderColor
#---- TabbedPane ---- #---- TabbedPane ----
TabbedPane.underlineColor = @accentUnderlineColor TabbedPane.underlineColor = @accentUnderlineColor
TabbedPane.inactiveUnderlineColor = mix(@accentUnderlineColor,$TabbedPane.background,50%)
TabbedPane.disabledUnderlineColor = darken(@background,28%) TabbedPane.disabledUnderlineColor = darken(@background,28%)
TabbedPane.hoverColor = darken($TabbedPane.background,7%,derived) TabbedPane.hoverColor = darken($TabbedPane.background,7%,derived)
TabbedPane.focusColor = mix(@selectionBackground,$TabbedPane.background,10%) TabbedPane.focusColor = mix(@selectionBackground,$TabbedPane.background,10%)

View File

@@ -82,6 +82,13 @@ HelpButton.hoverBorderColor = null
Slider.focusedColor = fade($Component.focusColor,40%,derived) Slider.focusedColor = fade($Component.focusColor,40%,derived)
#---- TabbedPane ----
# colors from JBUI.CurrentTheme.DefaultTabs.inactiveUnderlineColor()
[light]TabbedPane.inactiveUnderlineColor = #9ca7b8
[dark]TabbedPane.inactiveUnderlineColor = #747a80
#---- ToggleButton ---- #---- ToggleButton ----
ToggleButton.startBackground = $ToggleButton.background ToggleButton.startBackground = $ToggleButton.background

View File

@@ -693,6 +693,7 @@ public class TestFlatStyleableInfo
"selectedBackground", Color.class, "selectedBackground", Color.class,
"selectedForeground", Color.class, "selectedForeground", Color.class,
"underlineColor", Color.class, "underlineColor", Color.class,
"inactiveUnderlineColor", Color.class,
"disabledUnderlineColor", Color.class, "disabledUnderlineColor", Color.class,
"hoverColor", Color.class, "hoverColor", Color.class,
"focusColor", Color.class, "focusColor", Color.class,

View File

@@ -862,6 +862,7 @@ public class TestFlatStyling
ui.applyStyle( "selectedBackground: #fff" ); ui.applyStyle( "selectedBackground: #fff" );
ui.applyStyle( "selectedForeground: #fff" ); ui.applyStyle( "selectedForeground: #fff" );
ui.applyStyle( "underlineColor: #fff" ); ui.applyStyle( "underlineColor: #fff" );
ui.applyStyle( "inactiveUnderlineColor: #fff" );
ui.applyStyle( "disabledUnderlineColor: #fff" ); ui.applyStyle( "disabledUnderlineColor: #fff" );
ui.applyStyle( "hoverColor: #fff" ); ui.applyStyle( "hoverColor: #fff" );
ui.applyStyle( "focusColor: #fff" ); ui.applyStyle( "focusColor: #fff" );

View File

@@ -1045,6 +1045,7 @@ TabbedPane.hasFullBorder false
TabbedPane.hiddenTabsNavigation moreTabsButton TabbedPane.hiddenTabsNavigation moreTabsButton
TabbedPane.highlight #232324 HSL 240 1 14 javax.swing.plaf.ColorUIResource [UI] TabbedPane.highlight #232324 HSL 240 1 14 javax.swing.plaf.ColorUIResource [UI]
TabbedPane.hoverColor #303234 HSL 210 4 20 com.formdev.flatlaf.util.DerivedColor [UI] darken(5%) TabbedPane.hoverColor #303234 HSL 210 4 20 com.formdev.flatlaf.util.DerivedColor [UI] darken(5%)
TabbedPane.inactiveUnderlineColor #466a92 HSL 212 35 42 javax.swing.plaf.ColorUIResource [UI]
TabbedPane.labelShift 1 TabbedPane.labelShift 1
TabbedPane.light #2f3031 HSL 210 2 19 javax.swing.plaf.ColorUIResource [UI] TabbedPane.light #2f3031 HSL 210 2 19 javax.swing.plaf.ColorUIResource [UI]
TabbedPane.scrollButtonsPlacement both TabbedPane.scrollButtonsPlacement both

View File

@@ -1050,6 +1050,7 @@ 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 #e0e0e0 HSL 0 0 88 com.formdev.flatlaf.util.DerivedColor [UI] darken(7% autoInverse) TabbedPane.hoverColor #e0e0e0 HSL 0 0 88 com.formdev.flatlaf.util.DerivedColor [UI] darken(7% autoInverse)
TabbedPane.inactiveUnderlineColor #97bbdc HSL 209 50 73 javax.swing.plaf.ColorUIResource [UI]
TabbedPane.labelShift 1 TabbedPane.labelShift 1
TabbedPane.light #e1e1e1 HSL 0 0 88 javax.swing.plaf.ColorUIResource [UI] TabbedPane.light #e1e1e1 HSL 0 0 88 javax.swing.plaf.ColorUIResource [UI]
TabbedPane.scrollButtonsPlacement both TabbedPane.scrollButtonsPlacement both

View File

@@ -1060,6 +1060,7 @@ 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.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]
TabbedPane.scrollButtonsPlacement both TabbedPane.scrollButtonsPlacement both

View File

@@ -347,6 +347,7 @@ TabbedPane.disabledForeground = #777
TabbedPane.selectedBackground = #0f0 TabbedPane.selectedBackground = #0f0
TabbedPane.selectedForeground = #00f TabbedPane.selectedForeground = #00f
TabbedPane.underlineColor = #ff0 TabbedPane.underlineColor = #ff0
TabbedPane.inactiveUnderlineColor = #f0f
TabbedPane.disabledUnderlineColor = #7a7a7a TabbedPane.disabledUnderlineColor = #7a7a7a
TabbedPane.hoverColor = #eee TabbedPane.hoverColor = #eee
TabbedPane.focusColor = #ddd TabbedPane.focusColor = #ddd

View File

@@ -821,6 +821,7 @@ TabbedPane.hasFullBorder
TabbedPane.hiddenTabsNavigation TabbedPane.hiddenTabsNavigation
TabbedPane.highlight TabbedPane.highlight
TabbedPane.hoverColor TabbedPane.hoverColor
TabbedPane.inactiveUnderlineColor
TabbedPane.labelShift TabbedPane.labelShift
TabbedPane.light TabbedPane.light
TabbedPane.scrollButtonsPlacement TabbedPane.scrollButtonsPlacement