diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d2a186e..5830963a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ FlatLaf Change Log - Added "Gradianto Nature Green" theme. - Updated "Arc Dark", "Cyan", "Dark purple", "Gradianto", "Gray", "Gruvbox" and "One Dark" themes. - +- TabbedPane: Support hiding tab area if it contains only one tab. (set client + property `JTabbedPane.hideTabAreaWithOneTab` to `true`) #### Fixed bugs 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 7011e39c..4cbdb775 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -219,7 +219,7 @@ public interface FlatClientProperties */ String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded"; - //---- JScrollBar --------------------------------------------------------- + //---- JScrollBar / JScrollPane ------------------------------------------- /** * Specifies whether the decrease/increase arrow buttons of a scrollbar are shown. @@ -263,6 +263,14 @@ public interface FlatClientProperties */ String TABBED_PANE_HAS_FULL_BORDER = "JTabbedPane.hasFullBorder"; + /** + * Specifies whether the tab area should be hidded if it contains only one tab. + *
+ * Component {@link javax.swing.JTabbedPane}
+ * Value type {@link java.lang.Boolean}
+ */
+ String TABBED_PANE_HIDE_TAB_AREA_WITH_ONE_TAB = "JTabbedPane.hideTabAreaWithOneTab";
+
/**
* Specifies the minimum width of a tab.
*
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 013f397d..7438dbf7 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 @@ -693,6 +693,26 @@ public class FlatTabbedPaneUI return Math.max( tabHeight, scale( clientPropertyInt( tabPane, TABBED_PANE_TAB_HEIGHT, this.tabHeight ) ) ); } + @Override + protected int calculateMaxTabWidth( int tabPlacement ) { + return hideTabArea() ? 0 : super.calculateMaxTabWidth( tabPlacement ); + } + + @Override + protected int calculateMaxTabHeight( int tabPlacement ) { + return hideTabArea() ? 0 : super.calculateMaxTabHeight( tabPlacement ); + } + + @Override + protected int calculateTabAreaWidth( int tabPlacement, int vertRunCount, int maxTabWidth ) { + return hideTabArea() ? 0 : super.calculateTabAreaWidth( tabPlacement, vertRunCount, maxTabWidth ); + } + + @Override + protected int calculateTabAreaHeight( int tabPlacement, int horizRunCount, int maxTabHeight ) { + return hideTabArea() ? 0 : super.calculateTabAreaHeight( tabPlacement, horizRunCount, maxTabHeight ); + } + @Override protected Insets getTabInsets( int tabPlacement, int tabIndex ) { Object value = getTabClientProperty( tabIndex, TABBED_PANE_TAB_INSETS ); @@ -752,7 +772,7 @@ public class FlatTabbedPaneUI */ @Override protected Insets getContentBorderInsets( int tabPlacement ) { - if( contentSeparatorHeight == 0 || !clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, true ) ) + if( hideTabArea() || contentSeparatorHeight == 0 || !clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, true ) ) return new Insets( 0, 0, 0, 0 ); boolean hasFullBorder = clientPropertyBoolean( tabPane, TABBED_PANE_HAS_FULL_BORDER, this.hasFullBorder ); @@ -787,6 +807,9 @@ public class FlatTabbedPaneUI @Override public void paint( Graphics g, JComponent c ) { + if( hideTabArea() ) + return; + ensureCurrentLayout(); int tabPlacement = tabPane.getTabPlacement(); @@ -1226,6 +1249,13 @@ public class FlatTabbedPaneUI return UIManager.getBoolean( "ScrollPane.smoothScrolling" ); } + protected boolean hideTabArea() { + return tabPane.getTabCount() == 1 && + leadingComponent == null && + trailingComponent == null && + clientPropertyBoolean( tabPane, TABBED_PANE_HIDE_TAB_AREA_WITH_ONE_TAB, false ); + } + protected int getTabsPopupPolicy() { Object value = tabPane.getClientProperty( TABBED_PANE_TABS_POPUP_POLICY ); @@ -2193,6 +2223,7 @@ public class FlatTabbedPaneUI case TABBED_PANE_SHOW_TAB_SEPARATORS: case TABBED_PANE_SHOW_CONTENT_SEPARATOR: case TABBED_PANE_HAS_FULL_BORDER: + case TABBED_PANE_HIDE_TAB_AREA_WITH_ONE_TAB: case TABBED_PANE_MINIMUM_TAB_WIDTH: case TABBED_PANE_MAXIMUM_TAB_WIDTH: case TABBED_PANE_TAB_HEIGHT: 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 d950fedf..4fdc86af 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 @@ -78,6 +78,11 @@ public class FlatContainerTest putTabbedPanesClientProperty( TABBED_PANE_SHOW_CONTENT_SEPARATOR, showContentSeparator ); } + private void hideTabAreaWithOneTabChanged() { + boolean hideTabAreaWithOneTab = hideTabAreaWithOneTabCheckBox.isSelected(); + putTabbedPanesClientProperty( TABBED_PANE_HIDE_TAB_AREA_WITH_ONE_TAB, hideTabAreaWithOneTab ); + } + private void hasFullBorderChanged() { Boolean hasFullBorder = hasFullBorderCheckBox.isSelected() ? true : null; putTabbedPanesClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder ); @@ -461,6 +466,7 @@ public class FlatContainerTest maximumTabWidthCheckBox = new JCheckBox(); showTabSeparatorsCheckBox = new JCheckBox(); secondTabWiderCheckBox = new JCheckBox(); + hideTabAreaWithOneTabCheckBox = new JCheckBox(); CellConstraints cc = new CellConstraints(); //======== this ======== @@ -579,6 +585,7 @@ public class FlatContainerTest "[]" + "[]para" + "[]" + + "[]" + "[]")); //---- tabScrollCheckBox ---- @@ -800,6 +807,11 @@ public class FlatContainerTest secondTabWiderCheckBox.setText("Second Tab insets wider (4,20,4,20)"); secondTabWiderCheckBox.addActionListener(e -> secondTabWiderChanged()); tabbedPaneControlPanel.add(secondTabWiderCheckBox, "cell 2 9"); + + //---- hideTabAreaWithOneTabCheckBox ---- + hideTabAreaWithOneTabCheckBox.setText("Hide tab area with one tab"); + hideTabAreaWithOneTabCheckBox.addActionListener(e -> hideTabAreaWithOneTabChanged()); + tabbedPaneControlPanel.add(hideTabAreaWithOneTabCheckBox, "cell 1 10"); } panel9.add(tabbedPaneControlPanel, cc.xywh(1, 11, 3, 1)); } @@ -844,6 +856,7 @@ public class FlatContainerTest private JCheckBox maximumTabWidthCheckBox; private JCheckBox showTabSeparatorsCheckBox; private JCheckBox secondTabWiderCheckBox; + private JCheckBox hideTabAreaWithOneTabCheckBox; // JFormDesigner - End of variables declaration //GEN-END:variables private JTabbedPane[] allTabbedPanes; 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 47954bc0..205708ed 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( "com.formdev.flatlaf.testing.FlatTestFrame$NoRightToLeftPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "insets 0,hidemode 3" "$columnConstraints": "[][fill][]" - "$rowConstraints": "[center][][][][][]para[][]para[][]" + "$rowConstraints": "[center][][][][][]para[][]para[][][]" } ) { name: "tabbedPaneControlPanel" "opaque": false @@ -547,6 +547,16 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 2 9" } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "hideTabAreaWithOneTabCheckBox" + "text": "Hide tab area with one tab" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "hideTabAreaWithOneTabChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 10" + } ) }, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) { "gridY": 11 "gridWidth": 3