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
- 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
tabs in all "Arc" themes, in "Hiberbee Dark" and in all "Material UI Lite"
themes.

View File

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

View File

@@ -59,6 +59,7 @@ import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.IntConsumer;
import java.util.function.Predicate;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.swing.Action;
@@ -82,10 +83,12 @@ import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.TabbedPaneUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
import javax.swing.text.JTextComponent;
import javax.swing.text.View;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.icons.FlatTabbedPaneCloseIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
@@ -127,6 +130,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TabbedPane.selectedBackground Color optional
* @uiDefault TabbedPane.selectedForeground Color
* @uiDefault TabbedPane.underlineColor Color
* @uiDefault TabbedPane.inactiveUnderlineColor Color
* @uiDefault TabbedPane.disabledUnderlineColor Color
* @uiDefault TabbedPane.hoverColor Color
* @uiDefault TabbedPane.focusColor Color
@@ -198,6 +202,7 @@ public class FlatTabbedPaneUI
@Styleable protected Color selectedBackground;
@Styleable protected Color selectedForeground;
@Styleable protected Color underlineColor;
/** @since 2.2 */ @Styleable protected Color inactiveUnderlineColor;
@Styleable protected Color disabledUnderlineColor;
@Styleable protected Color hoverColor;
@Styleable protected Color focusColor;
@@ -288,6 +293,7 @@ public class FlatTabbedPaneUI
super.installUI( c );
FlatSelectedTabRepainter.install();
installStyle();
}
@@ -318,6 +324,7 @@ public class FlatTabbedPaneUI
selectedBackground = UIManager.getColor( "TabbedPane.selectedBackground" );
selectedForeground = UIManager.getColor( "TabbedPane.selectedForeground" );
underlineColor = UIManager.getColor( "TabbedPane.underlineColor" );
inactiveUnderlineColor = FlatUIUtils.getUIColor( "TabbedPane.inactiveUnderlineColor", underlineColor );
disabledUnderlineColor = UIManager.getColor( "TabbedPane.disabledUnderlineColor" );
hoverColor = UIManager.getColor( "TabbedPane.hoverColor" );
focusColor = UIManager.getColor( "TabbedPane.focusColor" );
@@ -385,6 +392,7 @@ public class FlatTabbedPaneUI
selectedBackground = null;
selectedForeground = null;
underlineColor = null;
inactiveUnderlineColor = null;
disabledUnderlineColor = null;
hoverColor = null;
focusColor = null;
@@ -733,7 +741,6 @@ public class FlatTabbedPaneUI
// increase size of repaint region to include part of content border
if( contentSeparatorHeight > 0 &&
getTabType() == TAB_TYPE_CARD &&
clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, true ) )
{
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 ) {
g.setColor( tabPane.isEnabled() ? underlineColor : disabledUnderlineColor );
g.setColor( tabPane.isEnabled()
? (isTabbedPaneOrChildFocused() ? underlineColor : inactiveUnderlineColor)
: disabledUnderlineColor );
// paint underline selection
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
* - not using UIManager.getColor("TabbedPane.contentAreaColor") to be GUI builder friendly
@@ -3341,4 +3367,77 @@ public class FlatTabbedPaneUI
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() );
}
private static boolean isInActiveWindow( Component c, Window activeWindow ) {
static boolean isInActiveWindow( Component c, Window activeWindow ) {
Window window = SwingUtilities.windowForComponent( c );
return window == activeWindow ||
(window != null && window.getType() == Window.Type.POPUP && window.getOwner() == activeWindow);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1045,6 +1045,7 @@ TabbedPane.hasFullBorder false
TabbedPane.hiddenTabsNavigation moreTabsButton
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.inactiveUnderlineColor #466a92 HSL 212 35 42 javax.swing.plaf.ColorUIResource [UI]
TabbedPane.labelShift 1
TabbedPane.light #2f3031 HSL 210 2 19 javax.swing.plaf.ColorUIResource [UI]
TabbedPane.scrollButtonsPlacement both

View File

@@ -1050,6 +1050,7 @@ TabbedPane.hasFullBorder false
TabbedPane.hiddenTabsNavigation moreTabsButton
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.inactiveUnderlineColor #97bbdc HSL 209 50 73 javax.swing.plaf.ColorUIResource [UI]
TabbedPane.labelShift 1
TabbedPane.light #e1e1e1 HSL 0 0 88 javax.swing.plaf.ColorUIResource [UI]
TabbedPane.scrollButtonsPlacement both

View File

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

View File

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

View File

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