TableHeader: support column hover and pressed background and foreground colors (issue #636)

This commit is contained in:
Karl Tauber
2023-01-30 14:21:44 +01:00
parent 4a0bd2c09f
commit 1435469ee5
17 changed files with 148 additions and 14 deletions

View File

@@ -11,6 +11,8 @@ 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.
- TableHeader: Support column hover and pressed background and foreground
colors. (issue #636)
#### Fixed bugs #### Fixed bugs

View File

@@ -59,6 +59,10 @@ import com.formdev.flatlaf.util.UIScale;
* *
* <!-- FlatTableHeaderUI --> * <!-- FlatTableHeaderUI -->
* *
* @uiDefault TableHeader.hoverBackground Color optional
* @uiDefault TableHeader.hoverForeground Color optional
* @uiDefault TableHeader.pressedBackground Color optional
* @uiDefault TableHeader.pressedForeground Color optional
* @uiDefault TableHeader.bottomSeparatorColor Color * @uiDefault TableHeader.bottomSeparatorColor Color
* @uiDefault TableHeader.height int * @uiDefault TableHeader.height int
* @uiDefault TableHeader.sortIconPosition String right (default), left, top or bottom * @uiDefault TableHeader.sortIconPosition String right (default), left, top or bottom
@@ -81,6 +85,10 @@ public class FlatTableHeaderUI
extends BasicTableHeaderUI extends BasicTableHeaderUI
implements StyleableUI implements StyleableUI
{ {
/** @since 3.1 */ @Styleable protected Color hoverBackground;
/** @since 3.1 */ @Styleable protected Color hoverForeground;
/** @since 3.1 */ @Styleable protected Color pressedBackground;
/** @since 3.1 */ @Styleable protected Color pressedForeground;
@Styleable protected Color bottomSeparatorColor; @Styleable protected Color bottomSeparatorColor;
@Styleable protected int height; @Styleable protected int height;
@Styleable(type=String.class) protected int sortIconPosition; @Styleable(type=String.class) protected int sortIconPosition;
@@ -113,6 +121,10 @@ public class FlatTableHeaderUI
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
hoverBackground = UIManager.getColor( "TableHeader.hoverBackground" );
hoverForeground = UIManager.getColor( "TableHeader.hoverForeground" );
pressedBackground = UIManager.getColor( "TableHeader.pressedBackground" );
pressedForeground = UIManager.getColor( "TableHeader.pressedForeground" );
bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" ); bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
height = UIManager.getInt( "TableHeader.height" ); height = UIManager.getInt( "TableHeader.height" );
sortIconPosition = parseSortIconPosition( UIManager.getString( "TableHeader.sortIconPosition" ) ); sortIconPosition = parseSortIconPosition( UIManager.getString( "TableHeader.sortIconPosition" ) );
@@ -122,6 +134,10 @@ public class FlatTableHeaderUI
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
hoverBackground = null;
hoverForeground = null;
pressedBackground = null;
pressedForeground = null;
bottomSeparatorColor = null; bottomSeparatorColor = null;
oldStyleValues = null; oldStyleValues = null;
@@ -211,6 +227,12 @@ public class FlatTableHeaderUI
return super.getRolloverColumn(); return super.getRolloverColumn();
} }
@Override
protected void rolloverColumnUpdated( int oldColumn, int newColumn ) {
header.repaint( header.getHeaderRect( oldColumn ) );
header.repaint( header.getHeaderRect( newColumn ) );
}
@Override @Override
public void paint( Graphics g, JComponent c ) { public void paint( Graphics g, JComponent c ) {
fixDraggedAndResizingColumns( header ); fixDraggedAndResizingColumns( header );
@@ -243,21 +265,16 @@ public class FlatTableHeaderUI
} }
} }
// temporary use own default renderer if necessary // temporary use own default renderer
FlatTableCellHeaderRenderer sortIconRenderer = null; FlatTableCellHeaderRenderer tempRenderer = new FlatTableCellHeaderRenderer( header.getDefaultRenderer() );
if( sortIconPosition != SwingConstants.RIGHT ) { header.setDefaultRenderer( tempRenderer );
sortIconRenderer = new FlatTableCellHeaderRenderer( header.getDefaultRenderer() );
header.setDefaultRenderer( sortIconRenderer );
}
// paint header // paint header
super.paint( g, c ); super.paint( g, c );
// restore default renderer // restore default renderer
if( sortIconRenderer != null ) { tempRenderer.reset();
sortIconRenderer.reset(); header.setDefaultRenderer( tempRenderer.delegate );
header.setDefaultRenderer( sortIconRenderer.delegate );
}
} }
private boolean isSystemDefaultRenderer( Object headerRenderer ) { private boolean isSystemDefaultRenderer( Object headerRenderer ) {
@@ -318,8 +335,8 @@ public class FlatTableHeaderUI
//---- class FlatTableCellHeaderRenderer ---------------------------------- //---- class FlatTableCellHeaderRenderer ----------------------------------
/** /**
* A delegating header renderer that is only used to paint sort arrows at * A delegating header renderer that is only used to paint hover and pressed
* top, bottom or left position. * background/foreground and to paint sort arrows at top, bottom or left position.
*/ */
private class FlatTableCellHeaderRenderer private class FlatTableCellHeaderRenderer
implements TableCellRenderer, Border, UIResource implements TableCellRenderer, Border, UIResource
@@ -327,6 +344,9 @@ public class FlatTableHeaderUI
private final TableCellRenderer delegate; private final TableCellRenderer delegate;
private JLabel l; private JLabel l;
private Color oldBackground;
private Color oldForeground;
private Boolean oldOpaque;
private int oldHorizontalTextPosition = -1; private int oldHorizontalTextPosition = -1;
private Border origBorder; private Border origBorder;
private Icon sortIcon; private Icon sortIcon;
@@ -345,11 +365,38 @@ public class FlatTableHeaderUI
l = (JLabel) c; l = (JLabel) c;
// hover and pressed background/foreground
TableColumn draggedColumn = header.getDraggedColumn();
Color background = null;
Color foreground = null;
if( draggedColumn != null && header.getTable().convertColumnIndexToView( draggedColumn.getModelIndex() ) == column ) {
background = pressedBackground;
foreground = pressedForeground;
} else if( getRolloverColumn() == column ) {
background = hoverBackground;
foreground = hoverForeground;
}
if( background != null ) {
if( oldBackground == null )
oldBackground = l.getBackground();
if( oldOpaque == null )
oldOpaque = l.isOpaque();
l.setBackground( FlatUIUtils.deriveColor( background, header.getBackground() ) );
l.setOpaque( true );
}
if( foreground != null ) {
if( oldForeground == null )
oldForeground = l.getForeground();
l.setForeground( FlatUIUtils.deriveColor( foreground, header.getForeground() ) );
}
// sort icon
if( sortIconPosition == SwingConstants.LEFT ) { if( sortIconPosition == SwingConstants.LEFT ) {
// left
if( oldHorizontalTextPosition < 0 ) if( oldHorizontalTextPosition < 0 )
oldHorizontalTextPosition = l.getHorizontalTextPosition(); oldHorizontalTextPosition = l.getHorizontalTextPosition();
l.setHorizontalTextPosition( SwingConstants.RIGHT ); l.setHorizontalTextPosition( SwingConstants.RIGHT );
} else { } else if( sortIconPosition == SwingConstants.TOP || sortIconPosition == SwingConstants.BOTTOM ) {
// top or bottom // top or bottom
sortIcon = l.getIcon(); sortIcon = l.getIcon();
origBorder = l.getBorder(); origBorder = l.getBorder();
@@ -361,7 +408,16 @@ public class FlatTableHeaderUI
} }
void reset() { void reset() {
if( l != null && sortIconPosition == SwingConstants.LEFT && oldHorizontalTextPosition >= 0 ) if( l == null )
return;
if( oldBackground != null )
l.setBackground( oldBackground );
if( oldForeground != null )
l.setForeground( oldForeground );
if( oldOpaque != null )
l.setOpaque( oldOpaque );
if( oldHorizontalTextPosition >= 0 )
l.setHorizontalTextPosition( oldHorizontalTextPosition ); l.setHorizontalTextPosition( oldHorizontalTextPosition );
} }

View File

@@ -331,6 +331,8 @@ Table.gridColor = lighten($Table.background,8%)
#---- TableHeader ---- #---- TableHeader ----
TableHeader.hoverBackground = lighten($TableHeader.background,5%,derived)
TableHeader.pressedBackground = lighten($TableHeader.background,10%,derived)
TableHeader.separatorColor = lighten($TableHeader.background,10%) TableHeader.separatorColor = lighten($TableHeader.background,10%)
TableHeader.bottomSeparatorColor = $TableHeader.separatorColor TableHeader.bottomSeparatorColor = $TableHeader.separatorColor

View File

@@ -338,6 +338,8 @@ Table.gridColor = darken($Table.background,8%)
#---- TableHeader ---- #---- TableHeader ----
TableHeader.hoverBackground = darken($TableHeader.background,5%,derived)
TableHeader.pressedBackground = darken($TableHeader.background,10%,derived)
TableHeader.separatorColor = darken($TableHeader.background,10%) TableHeader.separatorColor = darken($TableHeader.background,10%)
TableHeader.bottomSeparatorColor = $TableHeader.separatorColor TableHeader.bottomSeparatorColor = $TableHeader.separatorColor

View File

@@ -804,6 +804,10 @@ public class TestFlatStyleableInfo
FlatTableHeaderUI ui = (FlatTableHeaderUI) c.getUI(); FlatTableHeaderUI ui = (FlatTableHeaderUI) c.getUI();
Map<String, Class<?>> expected = expectedMap( Map<String, Class<?>> expected = expectedMap(
"hoverBackground", Color.class,
"hoverForeground", Color.class,
"pressedBackground", Color.class,
"pressedForeground", Color.class,
"bottomSeparatorColor", Color.class, "bottomSeparatorColor", Color.class,
"height", int.class, "height", int.class,
"sortIconPosition", String.class, "sortIconPosition", String.class,

View File

@@ -802,6 +802,10 @@ public class TestFlatStyleableValue
JTableHeader c = new JTableHeader(); JTableHeader c = new JTableHeader();
FlatTableHeaderUI ui = (FlatTableHeaderUI) c.getUI(); FlatTableHeaderUI ui = (FlatTableHeaderUI) c.getUI();
testColor( c, ui, "hoverBackground", 0x123456 );
testColor( c, ui, "hoverForeground", 0x123456 );
testColor( c, ui, "pressedBackground", 0x123456 );
testColor( c, ui, "pressedForeground", 0x123456 );
testColor( c, ui, "bottomSeparatorColor", 0x123456 ); testColor( c, ui, "bottomSeparatorColor", 0x123456 );
testInteger( c, ui, "height", 123 ); testInteger( c, ui, "height", 123 );
testString( c, ui, "sortIconPosition", "top" ); testString( c, ui, "sortIconPosition", "top" );

View File

@@ -999,6 +999,10 @@ public class TestFlatStyling
JTableHeader c = new JTableHeader(); JTableHeader c = new JTableHeader();
FlatTableHeaderUI ui = (FlatTableHeaderUI) c.getUI(); FlatTableHeaderUI ui = (FlatTableHeaderUI) c.getUI();
ui.applyStyle( "hoverBackground: #fff" );
ui.applyStyle( "hoverForeground: #fff" );
ui.applyStyle( "pressedBackground: #fff" );
ui.applyStyle( "pressedForeground: #fff" );
ui.applyStyle( "bottomSeparatorColor: #fff" ); ui.applyStyle( "bottomSeparatorColor: #fff" );
ui.applyStyle( "height: 20" ); ui.applyStyle( "height: 20" );
ui.applyStyle( "sortIconPosition: top" ); ui.applyStyle( "sortIconPosition: top" );

View File

@@ -197,6 +197,14 @@ TabbedPane.buttonHoverBackground = TabbedPane.background
TabbedPane.buttonPressedBackground = TabbedPane.background TabbedPane.buttonPressedBackground = TabbedPane.background
#---- TableHeader ----
TableHeader.hoverBackground = TableHeader.background
TableHeader.hoverForeground = TableHeader.foreground
TableHeader.pressedBackground = TableHeader.background
TableHeader.pressedForeground = TableHeader.foreground
#---- TitlePane ---- #---- TitlePane ----
TitlePane.buttonHoverBackground = TitlePane.background TitlePane.buttonHoverBackground = TitlePane.background

View File

@@ -1131,6 +1131,8 @@ TableHeader.focusCellBackground #46494b HSL 204 3 28 javax.swing.plaf.Col
TableHeader.font [active] $defaultFont [UI] TableHeader.font [active] $defaultFont [UI]
TableHeader.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI] TableHeader.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
TableHeader.height 25 TableHeader.height 25
TableHeader.hoverBackground #525658 HSL 200 4 33 com.formdev.flatlaf.util.DerivedColor [UI] lighten(5% autoInverse)
TableHeader.pressedBackground #5f6365 HSL 200 3 38 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10% autoInverse)
TableHeader.separatorColor #5f6365 HSL 200 3 38 javax.swing.plaf.ColorUIResource [UI] TableHeader.separatorColor #5f6365 HSL 200 3 38 javax.swing.plaf.ColorUIResource [UI]
TableHeader.showTrailingVerticalLine false TableHeader.showTrailingVerticalLine false
TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI

View File

@@ -1136,6 +1136,8 @@ TableHeader.focusCellBackground #ffffff HSL 0 0 100 javax.swing.plaf.Col
TableHeader.font [active] $defaultFont [UI] TableHeader.font [active] $defaultFont [UI]
TableHeader.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI] TableHeader.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
TableHeader.height 25 TableHeader.height 25
TableHeader.hoverBackground #f2f2f2 HSL 0 0 95 com.formdev.flatlaf.util.DerivedColor [UI] darken(5% autoInverse)
TableHeader.pressedBackground #e6e6e6 HSL 0 0 90 com.formdev.flatlaf.util.DerivedColor [UI] darken(10% autoInverse)
TableHeader.separatorColor #e6e6e6 HSL 0 0 90 javax.swing.plaf.ColorUIResource [UI] TableHeader.separatorColor #e6e6e6 HSL 0 0 90 javax.swing.plaf.ColorUIResource [UI]
TableHeader.showTrailingVerticalLine false TableHeader.showTrailingVerticalLine false
TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI

View File

@@ -1141,6 +1141,8 @@ TableHeader.focusCellBackground #282828 HSL 0 0 16 javax.swing.plaf.Col
TableHeader.font [active] $defaultFont [UI] TableHeader.font [active] $defaultFont [UI]
TableHeader.foreground #dddddd HSL 0 0 87 javax.swing.plaf.ColorUIResource [UI] TableHeader.foreground #dddddd HSL 0 0 87 javax.swing.plaf.ColorUIResource [UI]
TableHeader.height 25 TableHeader.height 25
TableHeader.hoverBackground #353535 HSL 0 0 21 com.formdev.flatlaf.util.DerivedColor [UI] lighten(5% autoInverse)
TableHeader.pressedBackground #424242 HSL 0 0 26 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10% autoInverse)
TableHeader.separatorColor #424242 HSL 0 0 26 javax.swing.plaf.ColorUIResource [UI] TableHeader.separatorColor #424242 HSL 0 0 26 javax.swing.plaf.ColorUIResource [UI]
TableHeader.showTrailingVerticalLine false TableHeader.showTrailingVerticalLine false
TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI

View File

@@ -1145,6 +1145,8 @@ TableHeader.focusCellBackground #ffffff HSL 0 0 100 javax.swing.plaf.Col
TableHeader.font [active] $defaultFont [UI] TableHeader.font [active] $defaultFont [UI]
TableHeader.foreground #262626 HSL 0 0 15 javax.swing.plaf.ColorUIResource [UI] TableHeader.foreground #262626 HSL 0 0 15 javax.swing.plaf.ColorUIResource [UI]
TableHeader.height 25 TableHeader.height 25
TableHeader.hoverBackground #f2f2f2 HSL 0 0 95 com.formdev.flatlaf.util.DerivedColor [UI] darken(5% autoInverse)
TableHeader.pressedBackground #e6e6e6 HSL 0 0 90 com.formdev.flatlaf.util.DerivedColor [UI] darken(10% autoInverse)
TableHeader.separatorColor #e6e6e6 HSL 0 0 90 javax.swing.plaf.ColorUIResource [UI] TableHeader.separatorColor #e6e6e6 HSL 0 0 90 javax.swing.plaf.ColorUIResource [UI]
TableHeader.showTrailingVerticalLine false TableHeader.showTrailingVerticalLine false
TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI

View File

@@ -1165,6 +1165,10 @@ TableHeader.focusCellBackground #4444ff HSL 240 100 63 javax.swing.plaf.Col
TableHeader.font [active] $defaultFont [UI] TableHeader.font [active] $defaultFont [UI]
TableHeader.foreground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI] TableHeader.foreground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
TableHeader.height 25 TableHeader.height 25
TableHeader.hoverBackground #1111ff HSL 240 100 53 com.formdev.flatlaf.util.DerivedColor [UI] darken(10% autoInverse)
TableHeader.hoverForeground #e6e6e6 HSL 0 0 90 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10% autoInverse)
TableHeader.pressedBackground #0000dd HSL 240 100 43 com.formdev.flatlaf.util.DerivedColor [UI] darken(20% autoInverse)
TableHeader.pressedForeground #cccccc HSL 0 0 80 com.formdev.flatlaf.util.DerivedColor [UI] lighten(20% autoInverse)
TableHeader.separatorColor #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI] TableHeader.separatorColor #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI]
TableHeader.showTrailingVerticalLine false TableHeader.showTrailingVerticalLine false
TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI

View File

@@ -647,6 +647,10 @@ public class FlatTestFrame
Component view = ((JScrollPane)c).getViewport().getView(); Component view = ((JScrollPane)c).getViewport().getView();
if( view != null ) if( view != null )
action.accept( view, "view" ); action.accept( view, "view" );
JViewport columnHeader = ((JScrollPane)c).getColumnHeader();
if( columnHeader != null )
action.accept( columnHeader.getView(), "columnHeader" );
} else if( c instanceof JTabbedPane ) { } else if( c instanceof JTabbedPane ) {
JTabbedPane tabPane = (JTabbedPane)c; JTabbedPane tabPane = (JTabbedPane)c;
int tabCount = tabPane.getTabCount(); int tabCount = tabPane.getTabCount();

View File

@@ -409,6 +409,10 @@ Table.gridColor = #0ff
TableHeader.background = #44f TableHeader.background = #44f
TableHeader.foreground = #fff TableHeader.foreground = #fff
TableHeader.hoverBackground = darken($TableHeader.background,10%,derived)
TableHeader.hoverForeground = lighten($TableHeader.foreground,10%,derived)
TableHeader.pressedBackground = darken($TableHeader.background,20%,derived)
TableHeader.pressedForeground = lighten($TableHeader.foreground,20%,derived)
TableHeader.separatorColor = #0f0 TableHeader.separatorColor = #0f0
TableHeader.bottomSeparatorColor = #0f0 TableHeader.bottomSeparatorColor = #0f0

View File

@@ -26,6 +26,8 @@ import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import javax.swing.*; import javax.swing.*;
import javax.swing.table.DefaultTableModel; import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableRowSorter; import javax.swing.table.TableRowSorter;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultTreeModel;
@@ -1051,6 +1053,11 @@ class FlatThemePreviewAll
{ {
Function<Object, Object> uiDefaultsGetter; Function<Object, Object> uiDefaultsGetter;
@Override
protected JTableHeader createDefaultTableHeader() {
return new PreviewTableHeader( columnModel );
}
@Override @Override
public void paint( Graphics g ) { public void paint( Graphics g ) {
if( !Beans.isDesignTime() ) { if( !Beans.isDesignTime() ) {
@@ -1061,5 +1068,26 @@ class FlatThemePreviewAll
} else } else
super.paint( g ); super.paint( g );
} }
//---- class PreviewTableHeader ----
private class PreviewTableHeader
extends JTableHeader
{
PreviewTableHeader( TableColumnModel columnModel ) {
super( columnModel );
}
@Override
public void paint( Graphics g ) {
if( !Beans.isDesignTime() ) {
// needed for DefaultTableCellHeaderRenderer
FlatLaf.runWithUIDefaultsGetter( uiDefaultsGetter, () -> {
super.paint( g );
} );
} else
super.paint( g );
}
}
} }
} }

View File

@@ -926,6 +926,10 @@ TableHeader.focusCellBackground
TableHeader.font TableHeader.font
TableHeader.foreground TableHeader.foreground
TableHeader.height TableHeader.height
TableHeader.hoverBackground
TableHeader.hoverForeground
TableHeader.pressedBackground
TableHeader.pressedForeground
TableHeader.separatorColor TableHeader.separatorColor
TableHeader.showTrailingVerticalLine TableHeader.showTrailingVerticalLine
TableHeaderUI TableHeaderUI