diff --git a/CHANGELOG.md b/CHANGELOG.md index 43462b45..a010b010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ 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. +- TableHeader: Support column hover and pressed background and foreground + colors. (issue #636) #### Fixed bugs diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderUI.java index d749f698..5093529b 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderUI.java @@ -59,6 +59,10 @@ import com.formdev.flatlaf.util.UIScale; * * * + * @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.height int * @uiDefault TableHeader.sortIconPosition String right (default), left, top or bottom @@ -81,6 +85,10 @@ public class FlatTableHeaderUI extends BasicTableHeaderUI 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 int height; @Styleable(type=String.class) protected int sortIconPosition; @@ -113,6 +121,10 @@ public class FlatTableHeaderUI protected void 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" ); height = UIManager.getInt( "TableHeader.height" ); sortIconPosition = parseSortIconPosition( UIManager.getString( "TableHeader.sortIconPosition" ) ); @@ -122,6 +134,10 @@ public class FlatTableHeaderUI protected void uninstallDefaults() { super.uninstallDefaults(); + hoverBackground = null; + hoverForeground = null; + pressedBackground = null; + pressedForeground = null; bottomSeparatorColor = null; oldStyleValues = null; @@ -211,6 +227,12 @@ public class FlatTableHeaderUI return super.getRolloverColumn(); } + @Override + protected void rolloverColumnUpdated( int oldColumn, int newColumn ) { + header.repaint( header.getHeaderRect( oldColumn ) ); + header.repaint( header.getHeaderRect( newColumn ) ); + } + @Override public void paint( Graphics g, JComponent c ) { fixDraggedAndResizingColumns( header ); @@ -243,21 +265,16 @@ public class FlatTableHeaderUI } } - // temporary use own default renderer if necessary - FlatTableCellHeaderRenderer sortIconRenderer = null; - if( sortIconPosition != SwingConstants.RIGHT ) { - sortIconRenderer = new FlatTableCellHeaderRenderer( header.getDefaultRenderer() ); - header.setDefaultRenderer( sortIconRenderer ); - } + // temporary use own default renderer + FlatTableCellHeaderRenderer tempRenderer = new FlatTableCellHeaderRenderer( header.getDefaultRenderer() ); + header.setDefaultRenderer( tempRenderer ); // paint header super.paint( g, c ); // restore default renderer - if( sortIconRenderer != null ) { - sortIconRenderer.reset(); - header.setDefaultRenderer( sortIconRenderer.delegate ); - } + tempRenderer.reset(); + header.setDefaultRenderer( tempRenderer.delegate ); } private boolean isSystemDefaultRenderer( Object headerRenderer ) { @@ -318,8 +335,8 @@ public class FlatTableHeaderUI //---- class FlatTableCellHeaderRenderer ---------------------------------- /** - * A delegating header renderer that is only used to paint sort arrows at - * top, bottom or left position. + * A delegating header renderer that is only used to paint hover and pressed + * background/foreground and to paint sort arrows at top, bottom or left position. */ private class FlatTableCellHeaderRenderer implements TableCellRenderer, Border, UIResource @@ -327,6 +344,9 @@ public class FlatTableHeaderUI private final TableCellRenderer delegate; private JLabel l; + private Color oldBackground; + private Color oldForeground; + private Boolean oldOpaque; private int oldHorizontalTextPosition = -1; private Border origBorder; private Icon sortIcon; @@ -345,11 +365,38 @@ public class FlatTableHeaderUI 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 ) { + // left if( oldHorizontalTextPosition < 0 ) oldHorizontalTextPosition = l.getHorizontalTextPosition(); l.setHorizontalTextPosition( SwingConstants.RIGHT ); - } else { + } else if( sortIconPosition == SwingConstants.TOP || sortIconPosition == SwingConstants.BOTTOM ) { // top or bottom sortIcon = l.getIcon(); origBorder = l.getBorder(); @@ -361,7 +408,16 @@ public class FlatTableHeaderUI } 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 ); } diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties index 4fe07ee4..e475c807 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties @@ -331,6 +331,8 @@ Table.gridColor = lighten($Table.background,8%) #---- TableHeader ---- +TableHeader.hoverBackground = lighten($TableHeader.background,5%,derived) +TableHeader.pressedBackground = lighten($TableHeader.background,10%,derived) TableHeader.separatorColor = lighten($TableHeader.background,10%) TableHeader.bottomSeparatorColor = $TableHeader.separatorColor diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties index 98b064e4..5b15b284 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties @@ -338,6 +338,8 @@ Table.gridColor = darken($Table.background,8%) #---- TableHeader ---- +TableHeader.hoverBackground = darken($TableHeader.background,5%,derived) +TableHeader.pressedBackground = darken($TableHeader.background,10%,derived) TableHeader.separatorColor = darken($TableHeader.background,10%) TableHeader.bottomSeparatorColor = $TableHeader.separatorColor 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 79bbf2c3..50029c61 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 @@ -804,6 +804,10 @@ public class TestFlatStyleableInfo FlatTableHeaderUI ui = (FlatTableHeaderUI) c.getUI(); Map> expected = expectedMap( + "hoverBackground", Color.class, + "hoverForeground", Color.class, + "pressedBackground", Color.class, + "pressedForeground", Color.class, "bottomSeparatorColor", Color.class, "height", int.class, "sortIconPosition", String.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 d96db0fa..0405c694 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 @@ -802,6 +802,10 @@ public class TestFlatStyleableValue JTableHeader c = new JTableHeader(); 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 ); testInteger( c, ui, "height", 123 ); testString( c, ui, "sortIconPosition", "top" ); 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 f3c023f2..bc819350 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 @@ -999,6 +999,10 @@ public class TestFlatStyling JTableHeader c = new JTableHeader(); 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( "height: 20" ); ui.applyStyle( "sortIconPosition: top" ); diff --git a/flatlaf-extras/src/main/resources/com/formdev/flatlaf/extras/resources/DerivedColorKeys.properties b/flatlaf-extras/src/main/resources/com/formdev/flatlaf/extras/resources/DerivedColorKeys.properties index 7a29655d..8f47973e 100644 --- a/flatlaf-extras/src/main/resources/com/formdev/flatlaf/extras/resources/DerivedColorKeys.properties +++ b/flatlaf-extras/src/main/resources/com/formdev/flatlaf/extras/resources/DerivedColorKeys.properties @@ -197,6 +197,14 @@ TabbedPane.buttonHoverBackground = 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.buttonHoverBackground = TitlePane.background diff --git a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt index 46220326..59a64eaa 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt @@ -1131,6 +1131,8 @@ TableHeader.focusCellBackground #46494b HSL 204 3 28 javax.swing.plaf.Col TableHeader.font [active] $defaultFont [UI] TableHeader.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI] 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.showTrailingVerticalLine false TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt index 1b845b2b..c4afe118 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt @@ -1136,6 +1136,8 @@ TableHeader.focusCellBackground #ffffff HSL 0 0 100 javax.swing.plaf.Col TableHeader.font [active] $defaultFont [UI] TableHeader.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI] 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.showTrailingVerticalLine false TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI diff --git a/flatlaf-testing/dumps/uidefaults/FlatMacDarkLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatMacDarkLaf_1.8.0.txt index 12d45358..8b51c3a4 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatMacDarkLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatMacDarkLaf_1.8.0.txt @@ -1141,6 +1141,8 @@ TableHeader.focusCellBackground #282828 HSL 0 0 16 javax.swing.plaf.Col TableHeader.font [active] $defaultFont [UI] TableHeader.foreground #dddddd HSL 0 0 87 javax.swing.plaf.ColorUIResource [UI] 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.showTrailingVerticalLine false TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI diff --git a/flatlaf-testing/dumps/uidefaults/FlatMacLightLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatMacLightLaf_1.8.0.txt index 1bd44db4..4892650f 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatMacLightLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatMacLightLaf_1.8.0.txt @@ -1145,6 +1145,8 @@ TableHeader.focusCellBackground #ffffff HSL 0 0 100 javax.swing.plaf.Col TableHeader.font [active] $defaultFont [UI] TableHeader.foreground #262626 HSL 0 0 15 javax.swing.plaf.ColorUIResource [UI] 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.showTrailingVerticalLine false TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt index 86fe7e20..40e3d9a8 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt @@ -1165,6 +1165,10 @@ TableHeader.focusCellBackground #4444ff HSL 240 100 63 javax.swing.plaf.Col TableHeader.font [active] $defaultFont [UI] TableHeader.foreground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI] 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.showTrailingVerticalLine false TableHeaderUI com.formdev.flatlaf.ui.FlatTableHeaderUI diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java index 41c28b0d..84e79473 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java @@ -647,6 +647,10 @@ public class FlatTestFrame Component view = ((JScrollPane)c).getViewport().getView(); if( view != null ) action.accept( view, "view" ); + + JViewport columnHeader = ((JScrollPane)c).getColumnHeader(); + if( columnHeader != null ) + action.accept( columnHeader.getView(), "columnHeader" ); } else if( c instanceof JTabbedPane ) { JTabbedPane tabPane = (JTabbedPane)c; int tabCount = tabPane.getTabCount(); 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 d5bbb704..c97ae553 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 @@ -409,6 +409,10 @@ Table.gridColor = #0ff TableHeader.background = #44f 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.bottomSeparatorColor = #0f0 diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePreviewAll.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePreviewAll.java index 24451123..d77a4c2c 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePreviewAll.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePreviewAll.java @@ -26,6 +26,8 @@ import java.util.function.Function; import java.util.function.Predicate; import javax.swing.*; import javax.swing.table.DefaultTableModel; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableColumnModel; import javax.swing.table.TableRowSorter; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; @@ -1051,6 +1053,11 @@ class FlatThemePreviewAll { Function uiDefaultsGetter; + @Override + protected JTableHeader createDefaultTableHeader() { + return new PreviewTableHeader( columnModel ); + } + @Override public void paint( Graphics g ) { if( !Beans.isDesignTime() ) { @@ -1061,5 +1068,26 @@ class FlatThemePreviewAll } else 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 ); + } + } } } 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 ea7b437b..3b7167f8 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 @@ -926,6 +926,10 @@ TableHeader.focusCellBackground TableHeader.font TableHeader.foreground TableHeader.height +TableHeader.hoverBackground +TableHeader.hoverForeground +TableHeader.pressedBackground +TableHeader.pressedForeground TableHeader.separatorColor TableHeader.showTrailingVerticalLine TableHeaderUI