diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java index 0c7c31a2..1ce48b33 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -254,6 +254,15 @@ public interface FlatClientProperties */ String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight"; + /** + * Specifies the insets of a tab. + *

+ * Component {@link javax.swing.JTabbedPane} + * or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})
+ * Value type {@link java.awt.Insets} + */ + String TABBED_PANE_TAB_INSETS = "JTabbedPane.tabInsets"; + /** * Specifies whether tabs are closable. * If set to {@code true} on a tabbed pane component, all tabs in that tabbed pane are closable. diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java index 7536883c..ec86fcd7 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java @@ -529,6 +529,14 @@ public class FlatTabbedPaneUI return Math.max( tabHeight, super.calculateTabHeight( tabPlacement, tabIndex, fontHeight ) - 2 /* was added by superclass */ ); } + @Override + protected Insets getTabInsets( int tabPlacement, int tabIndex ) { + Object value = getTabClientProperty( tabIndex, TABBED_PANE_TAB_INSETS ); + return (value instanceof Insets) + ? scale( (Insets) value ) + : super.getTabInsets( tabPlacement, tabIndex ); + } + @Override protected Insets getTabAreaInsets( int tabPlacement ) { Insets currentTabAreaInsets = super.getTabAreaInsets( tabPlacement ); @@ -1503,6 +1511,8 @@ public class FlatTabbedPaneUI PropertyChangeListener propertyChangeDelegate; ChangeListener changeDelegate; + private final PropertyChangeListener contentListener = this::contentPropertyChange; + private int pressedTabIndex = -1; void installListeners() { @@ -1512,7 +1522,7 @@ public class FlatTabbedPaneUI for( Component c : tabPane.getComponents() ) { if( !(c instanceof UIResource) ) - c.addPropertyChangeListener( TABBED_PANE_TAB_CLOSABLE, this ); + c.addPropertyChangeListener( contentListener ); } } @@ -1523,7 +1533,7 @@ public class FlatTabbedPaneUI for( Component c : tabPane.getComponents() ) { if( !(c instanceof UIResource) ) - c.removePropertyChangeListener( TABBED_PANE_TAB_CLOSABLE, this ); + c.removePropertyChangeListener( contentListener ); } } @@ -1604,21 +1614,19 @@ public class FlatTabbedPaneUI @Override public void propertyChange( PropertyChangeEvent e ) { // invoke delegate listener - if( e.getSource() instanceof JTabbedPane ) { - switch( e.getPropertyName() ) { - case "tabPlacement": - case "opaque": - case "background": - case "indexForTabComponent": - runWithOriginalLayoutManager( () -> { - propertyChangeDelegate.propertyChange( e ); - } ); - break; - - default: + switch( e.getPropertyName() ) { + case "tabPlacement": + case "opaque": + case "background": + case "indexForTabComponent": + runWithOriginalLayoutManager( () -> { propertyChangeDelegate.propertyChange( e ); - break; - } + } ); + break; + + default: + propertyChangeDelegate.propertyChange( e ); + break; } // handle event @@ -1636,6 +1644,7 @@ public class FlatTabbedPaneUI case TABBED_PANE_SHOW_CONTENT_SEPARATOR: case TABBED_PANE_HAS_FULL_BORDER: case TABBED_PANE_TAB_HEIGHT: + case TABBED_PANE_TAB_INSETS: case TABBED_PANE_HIDDEN_TABS_NAVIGATION: case TABBED_PANE_TAB_CLOSABLE: tabPane.revalidate(); @@ -1671,6 +1680,16 @@ public class FlatTabbedPaneUI ensureSelectedTabIsVisible(); } + protected void contentPropertyChange( PropertyChangeEvent e ) { + switch( e.getPropertyName() ) { + case TABBED_PANE_TAB_INSETS: + case TABBED_PANE_TAB_CLOSABLE: + tabPane.revalidate(); + tabPane.repaint(); + break; + } + } + //---- interface ComponentListener ---- @Override @@ -1689,14 +1708,14 @@ public class FlatTabbedPaneUI public void componentAdded( ContainerEvent e ) { Component c = e.getChild(); if( !(c instanceof UIResource) ) - c.addPropertyChangeListener( TABBED_PANE_TAB_CLOSABLE, this ); + c.addPropertyChangeListener( contentListener ); } @Override public void componentRemoved( ContainerEvent e ) { Component c = e.getChild(); if( !(c instanceof UIResource) ) - c.removePropertyChangeListener( TABBED_PANE_TAB_CLOSABLE, this ); + c.removePropertyChangeListener( contentListener ); } } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java index b6da5b97..6326e004 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java @@ -299,6 +299,26 @@ public class FlatContainerTest } } + private void smallerTabHeightChanged() { + Integer tabHeight = smallerTabHeightCheckBox.isSelected() ? 20 : null; + putTabbedPanesClientProperty( TABBED_PANE_TAB_HEIGHT, tabHeight ); + } + + private void smallerInsetsChanged() { + Insets insets = smallerInsetsCheckBox.isSelected() ? new Insets( 2, 2, 2, 2 ) : null; + putTabbedPanesClientProperty( TABBED_PANE_TAB_INSETS, insets ); + } + + private void secondTabWiderChanged() { + Insets insets = secondTabWiderCheckBox.isSelected() ? new Insets( 4, 20, 4, 20 ) : null; + + JTabbedPane[] tabbedPanes = new JTabbedPane[] { tabbedPane1, tabbedPane2, tabbedPane3, tabbedPane4 }; + for( JTabbedPane tabbedPane : tabbedPanes ) { + Component c = tabbedPane.getComponentAt( 1 ); + ((JComponent)c).putClientProperty( TABBED_PANE_TAB_INSETS, insets ); + } + } + private void initComponents() { // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents JPanel panel9 = new JPanel(); @@ -337,6 +357,9 @@ public class FlatContainerTest trailingComponentCheckBox = new JCheckBox(); tabsClosableCheckBox = new JCheckBox(); secondTabClosableCheckBox = new TriStateCheckBox(); + smallerTabHeightCheckBox = new JCheckBox(); + smallerInsetsCheckBox = new JCheckBox(); + secondTabWiderCheckBox = new JCheckBox(); CellConstraints cc = new CellConstraints(); //======== this ======== @@ -451,6 +474,7 @@ public class FlatContainerTest "[center]" + "[]" + "[]" + + "[]" + "[]")); //---- moreTabsCheckBox ---- @@ -559,6 +583,21 @@ public class FlatContainerTest secondTabClosableCheckBox.setText("Second Tab closable"); secondTabClosableCheckBox.addActionListener(e -> secondTabClosableChanged()); panel14.add(secondTabClosableCheckBox, "cell 3 3"); + + //---- smallerTabHeightCheckBox ---- + smallerTabHeightCheckBox.setText("Smaller tab height"); + smallerTabHeightCheckBox.addActionListener(e -> smallerTabHeightChanged()); + panel14.add(smallerTabHeightCheckBox, "cell 0 4 2 1"); + + //---- smallerInsetsCheckBox ---- + smallerInsetsCheckBox.setText("Smaller insets"); + smallerInsetsCheckBox.addActionListener(e -> smallerInsetsChanged()); + panel14.add(smallerInsetsCheckBox, "cell 2 4"); + + //---- secondTabWiderCheckBox ---- + secondTabWiderCheckBox.setText("Second Tab wider"); + secondTabWiderCheckBox.addActionListener(e -> secondTabWiderChanged()); + panel14.add(secondTabWiderCheckBox, "cell 3 4"); } panel9.add(panel14, cc.xywh(1, 11, 3, 1)); } @@ -588,6 +627,9 @@ public class FlatContainerTest private JCheckBox trailingComponentCheckBox; private JCheckBox tabsClosableCheckBox; private TriStateCheckBox secondTabClosableCheckBox; + private JCheckBox smallerTabHeightCheckBox; + private JCheckBox smallerInsetsCheckBox; + private JCheckBox secondTabWiderCheckBox; // JFormDesigner - End of variables declaration //GEN-END:variables //---- class Tab1Panel ---------------------------------------------------- diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.jfd index 9e64f1f6..e6c45887 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.jfd @@ -132,7 +132,7 @@ new FormModel { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "insets 0,hidemode 3" "$columnConstraints": "[][fill][][][fill]" - "$rowConstraints": "[center][][][]" + "$rowConstraints": "[center][][][][]" } ) { name: "panel14" "opaque": false @@ -347,6 +347,36 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 3 3" } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "smallerTabHeightCheckBox" + "text": "Smaller tab height" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "smallerTabHeightChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 4 2 1" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "smallerInsetsCheckBox" + "text": "Smaller insets" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "smallerInsetsChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 4" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "secondTabWiderCheckBox" + "text": "Second Tab wider" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "secondTabWiderChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 3 4" + } ) }, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) { "gridY": 11 "gridWidth": 3