From c16c3759cfed50f5f16a125f0bf83704aa9d1cfa Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Fri, 13 Nov 2020 17:34:46 +0100 Subject: [PATCH 1/8] TabbedPane: - support forward/backward scroll buttons on both sides of the tab area (new default) - optionally: not applicable scroll buttons are hidden (new default) - changed configuration - removed TabbedPane.hiddenTabsNavigation - added TabbedPane.tabsPopupPolicy, TabbedPane.scrollButtonsPolicy and TabbedPane.scrollButtonsPlacement - made scroll arrows larger (issue #40; replaces PR #195) --- .../formdev/flatlaf/FlatClientProperties.java | 79 +++++- .../formdev/flatlaf/ui/FlatTabbedPaneUI.java | 244 +++++++++++++----- .../com/formdev/flatlaf/FlatLaf.properties | 7 + .../flatlaf/testing/FlatContainerTest.java | 238 ++++++++++------- .../flatlaf/testing/FlatContainerTest.jfd | 229 +++++++++------- 5 files changed, 537 insertions(+), 260 deletions(-) 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 b29b573f..fe649536 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -366,28 +366,85 @@ public interface FlatClientProperties String TABBED_PANE_TAB_CLOSE_CALLBACK = "JTabbedPane.tabCloseCallback"; /** - * Specifies how to navigate to hidden tabs. + * Specifies the display policy for the "more tabs" button, + * which shows a popup menu with the (partly) hidden tabs. *

* Component {@link javax.swing.JTabbedPane}
* Value type {@link java.lang.String}
- * Allowed Values {@link #TABBED_PANE_HIDDEN_TABS_NAVIGATION_MORE_TABS_BUTTON} - * or {@link #TABBED_PANE_HIDDEN_TABS_NAVIGATION_ARROW_BUTTONS} + * Allowed Values + * {@link #TABBED_PANE_POLICY_NEVER} or + * {@link #TABBED_PANE_POLICY_AS_NEEDED} */ - String TABBED_PANE_HIDDEN_TABS_NAVIGATION = "JTabbedPane.hiddenTabsNavigation"; + String TABBED_PANE_TABS_POPUP_POLICY = "JTabbedPane.tabsPopupPolicy"; /** - * Use "more tabs" button for navigation to hidden tabs. - * - * @see #TABBED_PANE_HIDDEN_TABS_NAVIGATION + * Specifies the display policy for the forward/backward scroll arrow buttons. + *

+ * Component {@link javax.swing.JTabbedPane}
+ * Value type {@link java.lang.String}
+ * Allowed Values + * {@link #TABBED_PANE_POLICY_NEVER}, + * {@link #TABBED_PANE_POLICY_AS_NEEDED} or + * {@link #TABBED_PANE_POLICY_AS_NEEDED_SINGLE} */ - String TABBED_PANE_HIDDEN_TABS_NAVIGATION_MORE_TABS_BUTTON = "moreTabsButton"; + String TABBED_PANE_SCROLL_BUTTONS_POLICY = "JTabbedPane.scrollButtondPolicy"; /** - * Use forward/backward buttons for navigation to hidden tabs. + * Display never. * - * @see #TABBED_PANE_HIDDEN_TABS_NAVIGATION + * @see #TABBED_PANE_TABS_POPUP_POLICY + * @see #TABBED_PANE_SCROLL_BUTTONS_POLICY */ - String TABBED_PANE_HIDDEN_TABS_NAVIGATION_ARROW_BUTTONS = "arrowButtons"; + String TABBED_PANE_POLICY_NEVER = "never"; + + /** + * Display only when needed. + *

+ * If used for {@link #TABBED_PANE_SCROLL_BUTTONS_POLICY}, both scroll arrow buttons + * are either shown or hidden. Buttons are disabled if scrolling in that + * direction is not applicable. + * + * @see #TABBED_PANE_TABS_POPUP_POLICY + * @see #TABBED_PANE_SCROLL_BUTTONS_POLICY + */ + String TABBED_PANE_POLICY_AS_NEEDED = "asNeeded"; + + /** + * Display single button only when needed. + *

+ * If scroll button placement is trailing, then this option is ignored + * and both buttons are shown or hidden as needed. + * + * @see #TABBED_PANE_SCROLL_BUTTONS_POLICY + */ + String TABBED_PANE_POLICY_AS_NEEDED_SINGLE = "asNeededSingle"; + + /** + * Specifies the placement of the forward/backward scroll arrow buttons. + *

+ * Component {@link javax.swing.JTabbedPane}
+ * Value type {@link java.lang.String}
+ * Allowed Values + * {@link #TABBED_PANE_PLACEMENT_BOTH} or + * {@link #TABBED_PANE_PLACEMENT_TRAILING} + */ + String TABBED_PANE_SCROLL_BUTTONS_PLACEMENT = "JTabbedPane.scrollButtonsPlacement"; + + /** + * The forward/backward scroll arrow buttons are placed on both sides of the tab area. + * The backward scroll button at the left/top side. + * The forward scroll button at the right/bottom side. + * + * @see #TABBED_PANE_SCROLL_BUTTONS_PLACEMENT + */ + String TABBED_PANE_PLACEMENT_BOTH = "both"; + + /** + * The forward/backward scroll arrow buttons are placed on the trailing side of the tab area. + * + * @see #TABBED_PANE_SCROLL_BUTTONS_PLACEMENT + */ + String TABBED_PANE_PLACEMENT_TRAILING = "trailing"; /** * Specifies the alignment of the tab area. 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 ed301e1b..27f6546d 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 @@ -130,7 +130,11 @@ import com.formdev.flatlaf.util.UIScale; * @uiDefault TabbedPane.showTabSeparators boolean * @uiDefault TabbedPane.tabSeparatorsFullHeight boolean * @uiDefault TabbedPane.hasFullBorder boolean - * @uiDefault TabbedPane.hiddenTabsNavigation String moreTabsButton (default) or arrowButtons + * + * @uiDefault TabbedPane.tabsPopupPolicy String never or asNeeded (default) + * @uiDefault TabbedPane.scrollButtonsPolicy String never, asNeeded or asNeededSingle (default) + * @uiDefault TabbedPane.scrollButtonsPlacement String both (default) or trailing + * * @uiDefault TabbedPane.tabAreaAlignment String leading (default), center, trailing or fill * @uiDefault TabbedPane.tabAlignment String leading, center (default) or trailing * @uiDefault TabbedPane.tabWidthMode String preferred (default), equal or compact @@ -150,9 +154,14 @@ import com.formdev.flatlaf.util.UIScale; public class FlatTabbedPaneUI extends BasicTabbedPaneUI { - // hidden tabs navigation types - protected static final int MORE_TABS_BUTTON = 0; - protected static final int ARROW_BUTTONS = 1; + // tabs popup policy / scroll arrows policy + protected static final int NEVER = 0; +// protected static final int ALWAYS = 1; + protected static final int AS_NEEDED = 2; + protected static final int AS_NEEDED_SINGLE = 3; + + // scroll arrows placement + protected static final int BOTH = 100; // tab area alignment protected static final int FILL = 100; @@ -186,10 +195,13 @@ public class FlatTabbedPaneUI protected boolean hasFullBorder; protected boolean tabsOpaque = true; - private String hiddenTabsNavigationStr; - protected int tabAreaAlignment; - protected int tabAlignment; - private String tabWidthModeStr; + private int tabsPopupPolicy; + private int scrollButtonsPolicy; + private int scrollButtonsPlacement; + + private int tabAreaAlignment; + private int tabAlignment; + private int tabWidthMode; protected Icon closeIcon; protected String arrowType; @@ -273,10 +285,14 @@ public class FlatTabbedPaneUI tabSeparatorsFullHeight = UIManager.getBoolean( "TabbedPane.tabSeparatorsFullHeight" ); hasFullBorder = UIManager.getBoolean( "TabbedPane.hasFullBorder" ); tabsOpaque = UIManager.getBoolean( "TabbedPane.tabsOpaque" ); - hiddenTabsNavigationStr = UIManager.getString( "TabbedPane.hiddenTabsNavigation" ); + + tabsPopupPolicy = parseTabsPopupPolicy( UIManager.getString( "TabbedPane.tabsPopupPolicy" ) ); + scrollButtonsPolicy = parseScrollButtonsPolicy( UIManager.getString( "TabbedPane.scrollButtonsPolicy" ) ); + scrollButtonsPlacement = parseScrollButtonsPlacement( UIManager.getString( "TabbedPane.scrollButtonsPlacement" ) ); + tabAreaAlignment = parseAlignment( UIManager.getString( "TabbedPane.tabAreaAlignment" ), LEADING ); tabAlignment = parseAlignment( UIManager.getString( "TabbedPane.tabAlignment" ), CENTER ); - tabWidthModeStr = UIManager.getString( "TabbedPane.tabWidthMode" ); + tabWidthMode = parseTabWidthMode( UIManager.getString( "TabbedPane.tabWidthMode" ) ); closeIcon = UIManager.getIcon( "TabbedPane.closeIcon" ); buttonInsets = UIManager.getInsets( "TabbedPane.buttonInsets" ); @@ -1197,11 +1213,28 @@ public class FlatTabbedPaneUI return UIManager.getBoolean( "ScrollPane.smoothScrolling" ); } - protected int getHiddenTabsNavigation() { - String str = (String) tabPane.getClientProperty( TABBED_PANE_HIDDEN_TABS_NAVIGATION ); - if( str == null ) - str = hiddenTabsNavigationStr; - return parseHiddenTabsNavigation( str ); + protected int getTabsPopupPolicy() { + Object value = tabPane.getClientProperty( TABBED_PANE_TABS_POPUP_POLICY ); + + return (value instanceof String) + ? parseTabsPopupPolicy( (String) value ) + : tabsPopupPolicy; + } + + protected int getScrollButtonsPolicy() { + Object value = tabPane.getClientProperty( TABBED_PANE_SCROLL_BUTTONS_POLICY ); + + return (value instanceof String) + ? parseScrollButtonsPolicy( (String) value ) + : scrollButtonsPolicy; + } + + protected int getScrollButtonsPlacement() { + Object value = tabPane.getClientProperty( TABBED_PANE_SCROLL_BUTTONS_PLACEMENT ); + + return (value instanceof String) + ? parseScrollButtonsPlacement( (String) value ) + : scrollButtonsPlacement; } protected int getTabAreaAlignment() { @@ -1225,20 +1258,44 @@ public class FlatTabbedPaneUI } protected int getTabWidthMode() { - String str = (String) tabPane.getClientProperty( TABBED_PANE_TAB_WIDTH_MODE ); - if( str == null ) - str = tabWidthModeStr; - return parseTabWidthMode( str ); + Object value = tabPane.getClientProperty( TABBED_PANE_TAB_WIDTH_MODE ); + + return (value instanceof String) + ? parseTabWidthMode( (String) value ) + : tabWidthMode; } - protected static int parseHiddenTabsNavigation( String str ) { + protected static int parseTabsPopupPolicy( String str ) { if( str == null ) - return MORE_TABS_BUTTON; + return AS_NEEDED; switch( str ) { default: - case TABBED_PANE_HIDDEN_TABS_NAVIGATION_MORE_TABS_BUTTON: return MORE_TABS_BUTTON; - case TABBED_PANE_HIDDEN_TABS_NAVIGATION_ARROW_BUTTONS: return ARROW_BUTTONS; + case TABBED_PANE_POLICY_AS_NEEDED: return AS_NEEDED; + case TABBED_PANE_POLICY_NEVER: return NEVER; + } + } + + protected static int parseScrollButtonsPolicy( String str ) { + if( str == null ) + return AS_NEEDED_SINGLE; + + switch( str ) { + default: + case TABBED_PANE_POLICY_AS_NEEDED_SINGLE: return AS_NEEDED_SINGLE; + case TABBED_PANE_POLICY_AS_NEEDED: return AS_NEEDED; + case TABBED_PANE_POLICY_NEVER: return NEVER; + } + } + + protected static int parseScrollButtonsPlacement( String str ) { + if( str == null ) + return BOTH; + + switch( str ) { + default: + case TABBED_PANE_PLACEMENT_BOTH: return BOTH; + case TABBED_PANE_PLACEMENT_TRAILING: return TRAILING; } } @@ -1419,6 +1476,7 @@ public class FlatTabbedPaneUI super( direction, arrowType, FlatTabbedPaneUI.this.foreground, FlatTabbedPaneUI.this.disabledForeground, null, buttonHoverBackground, null, buttonPressedBackground ); + setArrowWidth( 10 ); } @Override @@ -2127,7 +2185,11 @@ public class FlatTabbedPaneUI case TABBED_PANE_TAB_HEIGHT: case TABBED_PANE_TAB_INSETS: case TABBED_PANE_TAB_AREA_INSETS: - case TABBED_PANE_HIDDEN_TABS_NAVIGATION: + + case TABBED_PANE_TABS_POPUP_POLICY: + case TABBED_PANE_SCROLL_BUTTONS_POLICY: + case TABBED_PANE_SCROLL_BUTTONS_PLACEMENT: + case TABBED_PANE_TAB_AREA_ALIGNMENT: case TABBED_PANE_TAB_ALIGNMENT: case TABBED_PANE_TAB_WIDTH_MODE: @@ -2488,14 +2550,23 @@ public class FlatTabbedPaneUI delegate.layoutContainer( parent ); } ); - boolean useMoreButton = (getHiddenTabsNavigation() == MORE_TABS_BUTTON); + int tabsPopupPolicy = getTabsPopupPolicy(); + int scrollButtonsPolicy = getScrollButtonsPolicy(); + int scrollButtonsPlacement = getScrollButtonsPlacement(); + + boolean useMoreTabsButton = (tabsPopupPolicy == AS_NEEDED); + boolean useScrollButtons = (scrollButtonsPolicy == AS_NEEDED || scrollButtonsPolicy == AS_NEEDED_SINGLE); + boolean hideDisabledScrollButtons = (scrollButtonsPolicy == AS_NEEDED_SINGLE && scrollButtonsPlacement == BOTH); + boolean trailingScrollButtons = (scrollButtonsPlacement == TRAILING); // for right-to-left always use "more tabs" button for horizontal scrolling // because methods scrollForward() and scrollBackward() in class // BasicTabbedPaneUI.ScrollableTabSupport do not work for right-to-left boolean leftToRight = isLeftToRight(); - if( !leftToRight && !useMoreButton && isHorizontalTabPlacement() ) - useMoreButton = true; + if( !leftToRight && !useMoreTabsButton && isHorizontalTabPlacement() ) { + useMoreTabsButton = true; + useScrollButtons = false; + } // find backward/forward scroll buttons JButton backwardButton = null; @@ -2510,7 +2581,7 @@ public class FlatTabbedPaneUI } } - if( !useMoreButton && (backwardButton == null || forwardButton == null) ) + if( !useMoreTabsButton && (backwardButton == null || forwardButton == null) ) return; // should never occur Rectangle bounds = tabPane.getBounds(); @@ -2518,10 +2589,9 @@ public class FlatTabbedPaneUI int tabPlacement = tabPane.getTabPlacement(); int tabAreaAlignment = getTabAreaAlignment(); Insets tabAreaInsets = getRealTabAreaInsets( tabPlacement ); - Dimension moreButtonSize = useMoreButton ? moreTabsButton.getPreferredSize() : null; - Dimension backwardButtonSize = useMoreButton ? null : backwardButton.getPreferredSize(); - Dimension forwardButtonSize = useMoreButton ? null : forwardButton.getPreferredSize(); - boolean buttonsVisible = false; + boolean moreTabsButtonVisible = false; + boolean backwardButtonVisible = false; + boolean forwardButtonVisible = false; // TabbedPaneScrollLayout adds tabAreaInsets to tab coordinates, // but we use it to position the viewport @@ -2603,22 +2673,49 @@ public class FlatTabbedPaneUI int twi = tw - leftWidth - rightWidth - tabAreaInsets.left - tabAreaInsets.right; // layout viewport and buttons - int viewportWidth = twi; - if( viewportWidth < totalTabWidth ) { - // need buttons - buttonsVisible = true; - int buttonsWidth = useMoreButton ? moreButtonSize.width : (backwardButtonSize.width + forwardButtonSize.width); - viewportWidth = Math.max( viewportWidth - buttonsWidth, 0 ); + int x = txi; + int w = twi; - if( useMoreButton ) - moreTabsButton.setBounds( leftToRight ? (txi + twi - buttonsWidth) : txi, ty, moreButtonSize.width, th ); - else { - backwardButton.setBounds( leftToRight ? (txi + twi - buttonsWidth) : txi, ty, backwardButtonSize.width, th ); - forwardButton.setBounds( leftToRight ? (txi + twi - forwardButtonSize.width) : (txi + backwardButtonSize.width), ty, forwardButtonSize.width, th ); + if( w < totalTabWidth ) { + // available width is too small for all tabs --> need buttons + + // layout more button on trailing side + if( useMoreTabsButton ) { + int buttonWidth = moreTabsButton.getPreferredSize().width; + moreTabsButton.setBounds( leftToRight ? (x + w - buttonWidth) : x, ty, buttonWidth, th ); + x += leftToRight ? 0 : buttonWidth; + w -= buttonWidth; + moreTabsButtonVisible = true; } - tabViewport.setBounds( leftToRight ? txi : (txi + buttonsWidth), ty, viewportWidth, th ); - } else - tabViewport.setBounds( txi, ty, viewportWidth, th ); + if( useScrollButtons ) { + // layout forward button on trailing side + if( !hideDisabledScrollButtons || forwardButton.isEnabled() ) { + int buttonWidth = forwardButton.getPreferredSize().width; + forwardButton.setBounds( leftToRight ? (x + w - buttonWidth) : x, ty, buttonWidth, th ); + x += leftToRight ? 0 : buttonWidth; + w -= buttonWidth; + forwardButtonVisible = true; + } + + // layout backward button + if( !hideDisabledScrollButtons || backwardButton.isEnabled() ) { + int buttonWidth = backwardButton.getPreferredSize().width; + if( trailingScrollButtons ) { + // on trailing side + backwardButton.setBounds( leftToRight ? (x + w - buttonWidth) : x, ty, buttonWidth, th ); + x += leftToRight ? 0 : buttonWidth; + } else { + // on leading side + backwardButton.setBounds( leftToRight ? x : (x + w - buttonWidth), ty, buttonWidth, th ); + x += leftToRight ? buttonWidth : 0; + } + w -= buttonWidth; + backwardButtonVisible = true; + } + } + } + + tabViewport.setBounds( x, ty, w, th ); if( !leftToRight ) { // layout viewport so that we can get correct view width below @@ -2686,29 +2783,54 @@ public class FlatTabbedPaneUI int thi = th - topHeight - bottomHeight - tabAreaInsets.top - tabAreaInsets.bottom; // layout viewport and buttons - int viewportHeight = thi; - if( viewportHeight < totalTabHeight ) { - // need buttons - buttonsVisible = true; - int buttonsHeight = useMoreButton ? moreButtonSize.height : (backwardButtonSize.height + forwardButtonSize.height); - viewportHeight = Math.max( viewportHeight - buttonsHeight, 0 ); + int y = tyi; + int h = thi; - if( useMoreButton ) - moreTabsButton.setBounds( tx, tyi + thi - buttonsHeight, tw, moreButtonSize.height ); - else { - backwardButton.setBounds( tx, tyi + thi - buttonsHeight, tw, backwardButtonSize.height ); - forwardButton.setBounds( tx, tyi + thi - forwardButtonSize.height, tw, forwardButtonSize.height ); + if( h < totalTabHeight ) { + // available height is too small for all tabs --> need buttons + + // layout more button on bottom side + if( useMoreTabsButton ) { + int buttonHeight = moreTabsButton.getPreferredSize().height; + moreTabsButton.setBounds( tx, y + h - buttonHeight, tw, buttonHeight ); + h -= buttonHeight; + moreTabsButtonVisible = true; + } + if( useScrollButtons ) { + // layout forward button on bottom side + if( !hideDisabledScrollButtons || forwardButton.isEnabled() ) { + int buttonHeight = forwardButton.getPreferredSize().height; + forwardButton.setBounds( tx, y + h - buttonHeight, tw, buttonHeight ); + h -= buttonHeight; + forwardButtonVisible = true; + } + + // layout backward button + if( !hideDisabledScrollButtons || backwardButton.isEnabled() ) { + int buttonHeight = backwardButton.getPreferredSize().height; + if( trailingScrollButtons ) { + // on bottom side + backwardButton.setBounds( tx, y + h - buttonHeight, tw, buttonHeight ); + } else { + // on top side + backwardButton.setBounds( tx, y, tw, buttonHeight ); + y += buttonHeight; + } + h -= buttonHeight; + backwardButtonVisible = true; + } } } - tabViewport.setBounds( tx, tyi, tw, viewportHeight ); + + tabViewport.setBounds( tx, y, tw, h ); } } // show/hide viewport and buttons tabViewport.setVisible( rects.length > 0 ); - moreTabsButton.setVisible( useMoreButton && buttonsVisible ); - backwardButton.setVisible( !useMoreButton && buttonsVisible ); - forwardButton.setVisible( !useMoreButton && buttonsVisible ); + moreTabsButton.setVisible( moreTabsButtonVisible ); + backwardButton.setVisible( backwardButtonVisible ); + forwardButton.setVisible( forwardButtonVisible ); } } } diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties index 22b086a8..42786726 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -573,6 +573,13 @@ TabbedPane.arrowType=chevron TabbedPane.buttonInsets=2,1,2,1 TabbedPane.buttonArc=$Button.arc +# allowed values: never or asNeeded +TabbedPane.tabsPopupPolicy=asNeeded +# allowed values: never, asNeeded or asNeededSingle +TabbedPane.scrollButtonsPolicy=asNeededSingle +# allowed values: both or trailing +TabbedPane.scrollButtonsPlacement=both + TabbedPane.closeIcon=com.formdev.flatlaf.icons.FlatTabbedPaneCloseIcon TabbedPane.closeSize=16,16 TabbedPane.closeArc=4 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 dd98255c..d950fedf 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 @@ -137,7 +137,6 @@ public class FlatContainerTest tabbedPane.addTab( "Tab " + index, createTab( "tab content " + index ) ); break; } - } private JComponent createTab( String text ) { @@ -262,11 +261,25 @@ public class FlatContainerTest tabbedPane4.setTabPlacement( (tabPlacement >= 0) ? tabPlacement : SwingConstants.RIGHT ); } - private void hiddenTabsNavigationChanged() { - String value = (String) hiddenTabsNavigationField.getSelectedItem(); + private void tabsPopupPolicyChanged() { + String value = (String) tabsPopupPolicyField.getSelectedItem(); if( "default".equals( value ) ) value = null; - putTabbedPanesClientProperty( TABBED_PANE_HIDDEN_TABS_NAVIGATION, value ); + putTabbedPanesClientProperty( TABBED_PANE_TABS_POPUP_POLICY, value ); + } + + private void scrollButtonsPolicyChanged() { + String value = (String) scrollButtonsPolicyField.getSelectedItem(); + if( "default".equals( value ) ) + value = null; + putTabbedPanesClientProperty( TABBED_PANE_SCROLL_BUTTONS_POLICY, value ); + } + + private void scrollButtonsPlacementChanged() { + String value = (String) scrollButtonsPlacementField.getSelectedItem(); + if( "default".equals( value ) ) + value = null; + putTabbedPanesClientProperty( TABBED_PANE_SCROLL_BUTTONS_PLACEMENT, value ); } private void tabAreaAlignmentChanged() { @@ -417,33 +430,37 @@ public class FlatContainerTest customTabsCheckBox = new JCheckBox(); htmlTabsCheckBox = new JCheckBox(); multiLineTabsCheckBox = new JCheckBox(); - JLabel hiddenTabsNavigationLabel = new JLabel(); - hiddenTabsNavigationField = new JComboBox<>(); + JLabel tabsPopupPolicyLabel = new JLabel(); + tabsPopupPolicyField = new JComboBox<>(); tabBackForegroundCheckBox = new JCheckBox(); - JLabel tabPlacementLabel = new JLabel(); - tabPlacementField = new JComboBox<>(); + JLabel scrollButtonsPolicyLabel = new JLabel(); + scrollButtonsPolicyField = new JComboBox<>(); tabIconsCheckBox = new JCheckBox(); tabIconSizeSpinner = new JSpinner(); iconPlacementField = new JComboBox<>(); + JLabel scrollButtonsPlacementLabel = new JLabel(); + scrollButtonsPlacementField = new JComboBox<>(); + tabsClosableCheckBox = new JCheckBox(); + JLabel tabPlacementLabel = new JLabel(); + tabPlacementField = new JComboBox<>(); + secondTabClosableCheckBox = new TriStateCheckBox(); JLabel tabAreaAlignmentLabel = new JLabel(); tabAreaAlignmentField = new JComboBox<>(); tabAlignmentField = new JComboBox<>(); JLabel tabWidthModeLabel = new JLabel(); tabWidthModeField = new JComboBox<>(); - tabsClosableCheckBox = new JCheckBox(); + leadingComponentCheckBox = new JCheckBox(); customBorderCheckBox = new JCheckBox(); tabAreaInsetsCheckBox = new JCheckBox(); - secondTabClosableCheckBox = new TriStateCheckBox(); + trailingComponentCheckBox = new JCheckBox(); hasFullBorderCheckBox = new JCheckBox(); smallerTabHeightCheckBox = new JCheckBox(); - leadingComponentCheckBox = new JCheckBox(); + minimumTabWidthCheckBox = new JCheckBox(); hideContentSeparatorCheckBox = new JCheckBox(); smallerInsetsCheckBox = new JCheckBox(); - trailingComponentCheckBox = new JCheckBox(); + maximumTabWidthCheckBox = new JCheckBox(); showTabSeparatorsCheckBox = new JCheckBox(); secondTabWiderCheckBox = new JCheckBox(); - minimumTabWidthCheckBox = new JCheckBox(); - maximumTabWidthCheckBox = new JCheckBox(); CellConstraints cc = new CellConstraints(); //======== this ======== @@ -556,7 +573,7 @@ public class FlatContainerTest "[center]" + "[]" + "[]" + - "[]para" + + "[]" + "[]" + "[]para" + "[]" + @@ -594,38 +611,37 @@ public class FlatContainerTest multiLineTabsCheckBox.addActionListener(e -> htmlTabsChanged()); tabbedPaneControlPanel.add(multiLineTabsCheckBox, "cell 2 0"); - //---- hiddenTabsNavigationLabel ---- - hiddenTabsNavigationLabel.setText("Hidden tabs navigation:"); - tabbedPaneControlPanel.add(hiddenTabsNavigationLabel, "cell 0 1"); + //---- tabsPopupPolicyLabel ---- + tabsPopupPolicyLabel.setText("Tabs popup policy:"); + tabbedPaneControlPanel.add(tabsPopupPolicyLabel, "cell 0 1"); - //---- hiddenTabsNavigationField ---- - hiddenTabsNavigationField.setModel(new DefaultComboBoxModel<>(new String[] { + //---- tabsPopupPolicyField ---- + tabsPopupPolicyField.setModel(new DefaultComboBoxModel<>(new String[] { "default", - "moreTabsButton", - "arrowButtons" + "asNeeded", + "never" })); - hiddenTabsNavigationField.addActionListener(e -> hiddenTabsNavigationChanged()); - tabbedPaneControlPanel.add(hiddenTabsNavigationField, "cell 1 1"); + tabsPopupPolicyField.addActionListener(e -> tabsPopupPolicyChanged()); + tabbedPaneControlPanel.add(tabsPopupPolicyField, "cell 1 1"); //---- tabBackForegroundCheckBox ---- tabBackForegroundCheckBox.setText("Tab back/foreground"); tabBackForegroundCheckBox.addActionListener(e -> tabBackForegroundChanged()); tabbedPaneControlPanel.add(tabBackForegroundCheckBox, "cell 2 1"); - //---- tabPlacementLabel ---- - tabPlacementLabel.setText("Tab placement:"); - tabbedPaneControlPanel.add(tabPlacementLabel, "cell 0 2"); + //---- scrollButtonsPolicyLabel ---- + scrollButtonsPolicyLabel.setText("Scroll buttons policy:"); + tabbedPaneControlPanel.add(scrollButtonsPolicyLabel, "cell 0 2"); - //---- tabPlacementField ---- - tabPlacementField.setModel(new DefaultComboBoxModel<>(new String[] { + //---- scrollButtonsPolicyField ---- + scrollButtonsPolicyField.setModel(new DefaultComboBoxModel<>(new String[] { "default", - "top", - "bottom", - "left", - "right" + "asNeededSingle", + "asNeeded", + "never" })); - tabPlacementField.addActionListener(e -> tabPlacementChanged()); - tabbedPaneControlPanel.add(tabPlacementField, "cell 1 2"); + scrollButtonsPolicyField.addActionListener(e -> scrollButtonsPolicyChanged()); + tabbedPaneControlPanel.add(scrollButtonsPolicyField, "cell 1 2"); //---- tabIconsCheckBox ---- tabIconsCheckBox.setText("Tab icons"); @@ -648,9 +664,47 @@ public class FlatContainerTest iconPlacementField.addActionListener(e -> iconPlacementChanged()); tabbedPaneControlPanel.add(iconPlacementField, "cell 2 2"); + //---- scrollButtonsPlacementLabel ---- + scrollButtonsPlacementLabel.setText("Scroll buttons placement:"); + tabbedPaneControlPanel.add(scrollButtonsPlacementLabel, "cell 0 3"); + + //---- scrollButtonsPlacementField ---- + scrollButtonsPlacementField.setModel(new DefaultComboBoxModel<>(new String[] { + "default", + "both", + "trailing" + })); + scrollButtonsPlacementField.addActionListener(e -> scrollButtonsPlacementChanged()); + tabbedPaneControlPanel.add(scrollButtonsPlacementField, "cell 1 3"); + + //---- tabsClosableCheckBox ---- + tabsClosableCheckBox.setText("Tabs closable"); + tabsClosableCheckBox.addActionListener(e -> tabsClosableChanged()); + tabbedPaneControlPanel.add(tabsClosableCheckBox, "cell 2 3"); + + //---- tabPlacementLabel ---- + tabPlacementLabel.setText("Tab placement:"); + tabbedPaneControlPanel.add(tabPlacementLabel, "cell 0 4"); + + //---- tabPlacementField ---- + tabPlacementField.setModel(new DefaultComboBoxModel<>(new String[] { + "default", + "top", + "bottom", + "left", + "right" + })); + tabPlacementField.addActionListener(e -> tabPlacementChanged()); + tabbedPaneControlPanel.add(tabPlacementField, "cell 1 4"); + + //---- secondTabClosableCheckBox ---- + secondTabClosableCheckBox.setText("Second Tab closable"); + secondTabClosableCheckBox.addActionListener(e -> secondTabClosableChanged()); + tabbedPaneControlPanel.add(secondTabClosableCheckBox, "cell 2 4"); + //---- tabAreaAlignmentLabel ---- tabAreaAlignmentLabel.setText("Tab area/title alignment:"); - tabbedPaneControlPanel.add(tabAreaAlignmentLabel, "cell 0 3"); + tabbedPaneControlPanel.add(tabAreaAlignmentLabel, "cell 0 5"); //---- tabAreaAlignmentField ---- tabAreaAlignmentField.setModel(new DefaultComboBoxModel<>(new String[] { @@ -661,7 +715,7 @@ public class FlatContainerTest "fill" })); tabAreaAlignmentField.addActionListener(e -> tabAreaAlignmentChanged()); - tabbedPaneControlPanel.add(tabAreaAlignmentField, "cell 1 3"); + tabbedPaneControlPanel.add(tabAreaAlignmentField, "cell 1 5"); //---- tabAlignmentField ---- tabAlignmentField.setModel(new DefaultComboBoxModel<>(new String[] { @@ -671,11 +725,11 @@ public class FlatContainerTest "center" })); tabAlignmentField.addActionListener(e -> tabAlignmentChanged()); - tabbedPaneControlPanel.add(tabAlignmentField, "cell 1 3"); + tabbedPaneControlPanel.add(tabAlignmentField, "cell 1 5"); //---- tabWidthModeLabel ---- tabWidthModeLabel.setText("Tab width mode:"); - tabbedPaneControlPanel.add(tabWidthModeLabel, "cell 2 3"); + tabbedPaneControlPanel.add(tabWidthModeLabel, "cell 2 5"); //---- tabWidthModeField ---- tabWidthModeField.setModel(new DefaultComboBoxModel<>(new String[] { @@ -685,77 +739,67 @@ public class FlatContainerTest "compact" })); tabWidthModeField.addActionListener(e -> tabWidthModeChanged()); - tabbedPaneControlPanel.add(tabWidthModeField, "cell 2 3"); - - //---- tabsClosableCheckBox ---- - tabsClosableCheckBox.setText("Tabs closable"); - tabsClosableCheckBox.addActionListener(e -> tabsClosableChanged()); - tabbedPaneControlPanel.add(tabsClosableCheckBox, "cell 0 4"); - - //---- customBorderCheckBox ---- - customBorderCheckBox.setText("Custom border"); - customBorderCheckBox.addActionListener(e -> customBorderChanged()); - tabbedPaneControlPanel.add(customBorderCheckBox, "cell 1 4"); - - //---- tabAreaInsetsCheckBox ---- - tabAreaInsetsCheckBox.setText("Tab area insets (5,5,10,10)"); - tabAreaInsetsCheckBox.addActionListener(e -> tabAreaInsetsChanged()); - tabbedPaneControlPanel.add(tabAreaInsetsCheckBox, "cell 2 4"); - - //---- secondTabClosableCheckBox ---- - secondTabClosableCheckBox.setText("Second Tab closable"); - secondTabClosableCheckBox.addActionListener(e -> secondTabClosableChanged()); - tabbedPaneControlPanel.add(secondTabClosableCheckBox, "cell 0 5"); - - //---- hasFullBorderCheckBox ---- - hasFullBorderCheckBox.setText("Show content border"); - hasFullBorderCheckBox.addActionListener(e -> hasFullBorderChanged()); - tabbedPaneControlPanel.add(hasFullBorderCheckBox, "cell 1 5,alignx left,growx 0"); - - //---- smallerTabHeightCheckBox ---- - smallerTabHeightCheckBox.setText("Smaller tab height (26)"); - smallerTabHeightCheckBox.addActionListener(e -> smallerTabHeightChanged()); - tabbedPaneControlPanel.add(smallerTabHeightCheckBox, "cell 2 5"); + tabbedPaneControlPanel.add(tabWidthModeField, "cell 2 5"); //---- leadingComponentCheckBox ---- leadingComponentCheckBox.setText("Leading component"); leadingComponentCheckBox.addActionListener(e -> leadingComponentChanged()); tabbedPaneControlPanel.add(leadingComponentCheckBox, "cell 0 6"); - //---- hideContentSeparatorCheckBox ---- - hideContentSeparatorCheckBox.setText("Hide content separator"); - hideContentSeparatorCheckBox.addActionListener(e -> hideContentSeparatorChanged()); - tabbedPaneControlPanel.add(hideContentSeparatorCheckBox, "cell 1 6"); + //---- customBorderCheckBox ---- + customBorderCheckBox.setText("Custom border"); + customBorderCheckBox.addActionListener(e -> customBorderChanged()); + tabbedPaneControlPanel.add(customBorderCheckBox, "cell 1 6"); - //---- smallerInsetsCheckBox ---- - smallerInsetsCheckBox.setText("Smaller tab insets (2,2,2,2)"); - smallerInsetsCheckBox.addActionListener(e -> smallerInsetsChanged()); - tabbedPaneControlPanel.add(smallerInsetsCheckBox, "cell 2 6"); + //---- tabAreaInsetsCheckBox ---- + tabAreaInsetsCheckBox.setText("Tab area insets (5,5,10,10)"); + tabAreaInsetsCheckBox.addActionListener(e -> tabAreaInsetsChanged()); + tabbedPaneControlPanel.add(tabAreaInsetsCheckBox, "cell 2 6"); //---- trailingComponentCheckBox ---- trailingComponentCheckBox.setText("Trailing component"); trailingComponentCheckBox.addActionListener(e -> trailingComponentChanged()); tabbedPaneControlPanel.add(trailingComponentCheckBox, "cell 0 7"); - //---- showTabSeparatorsCheckBox ---- - showTabSeparatorsCheckBox.setText("Show tab separators"); - showTabSeparatorsCheckBox.addActionListener(e -> showTabSeparatorsChanged()); - tabbedPaneControlPanel.add(showTabSeparatorsCheckBox, "cell 1 7"); + //---- hasFullBorderCheckBox ---- + hasFullBorderCheckBox.setText("Show content border"); + hasFullBorderCheckBox.addActionListener(e -> hasFullBorderChanged()); + tabbedPaneControlPanel.add(hasFullBorderCheckBox, "cell 1 7,alignx left,growx 0"); - //---- secondTabWiderCheckBox ---- - secondTabWiderCheckBox.setText("Second Tab insets wider (4,20,4,20)"); - secondTabWiderCheckBox.addActionListener(e -> secondTabWiderChanged()); - tabbedPaneControlPanel.add(secondTabWiderCheckBox, "cell 2 7"); + //---- smallerTabHeightCheckBox ---- + smallerTabHeightCheckBox.setText("Smaller tab height (26)"); + smallerTabHeightCheckBox.addActionListener(e -> smallerTabHeightChanged()); + tabbedPaneControlPanel.add(smallerTabHeightCheckBox, "cell 2 7"); //---- minimumTabWidthCheckBox ---- minimumTabWidthCheckBox.setText("Minimum tab width (100)"); minimumTabWidthCheckBox.addActionListener(e -> minimumTabWidthChanged()); - tabbedPaneControlPanel.add(minimumTabWidthCheckBox, "cell 2 8"); + tabbedPaneControlPanel.add(minimumTabWidthCheckBox, "cell 0 8"); + + //---- hideContentSeparatorCheckBox ---- + hideContentSeparatorCheckBox.setText("Hide content separator"); + hideContentSeparatorCheckBox.addActionListener(e -> hideContentSeparatorChanged()); + tabbedPaneControlPanel.add(hideContentSeparatorCheckBox, "cell 1 8"); + + //---- smallerInsetsCheckBox ---- + smallerInsetsCheckBox.setText("Smaller tab insets (2,2,2,2)"); + smallerInsetsCheckBox.addActionListener(e -> smallerInsetsChanged()); + tabbedPaneControlPanel.add(smallerInsetsCheckBox, "cell 2 8"); //---- maximumTabWidthCheckBox ---- maximumTabWidthCheckBox.setText("Maximum tab width (60)"); maximumTabWidthCheckBox.addActionListener(e -> maximumTabWidthChanged()); - tabbedPaneControlPanel.add(maximumTabWidthCheckBox, "cell 2 9"); + tabbedPaneControlPanel.add(maximumTabWidthCheckBox, "cell 0 9"); + + //---- showTabSeparatorsCheckBox ---- + showTabSeparatorsCheckBox.setText("Show tab separators"); + showTabSeparatorsCheckBox.addActionListener(e -> showTabSeparatorsChanged()); + tabbedPaneControlPanel.add(showTabSeparatorsCheckBox, "cell 1 9"); + + //---- secondTabWiderCheckBox ---- + secondTabWiderCheckBox.setText("Second Tab insets wider (4,20,4,20)"); + secondTabWiderCheckBox.addActionListener(e -> secondTabWiderChanged()); + tabbedPaneControlPanel.add(secondTabWiderCheckBox, "cell 2 9"); } panel9.add(tabbedPaneControlPanel, cc.xywh(1, 11, 3, 1)); } @@ -775,29 +819,31 @@ public class FlatContainerTest private JCheckBox customTabsCheckBox; private JCheckBox htmlTabsCheckBox; private JCheckBox multiLineTabsCheckBox; - private JComboBox hiddenTabsNavigationField; + private JComboBox tabsPopupPolicyField; private JCheckBox tabBackForegroundCheckBox; - private JComboBox tabPlacementField; + private JComboBox scrollButtonsPolicyField; private JCheckBox tabIconsCheckBox; private JSpinner tabIconSizeSpinner; private JComboBox iconPlacementField; + private JComboBox scrollButtonsPlacementField; + private JCheckBox tabsClosableCheckBox; + private JComboBox tabPlacementField; + private TriStateCheckBox secondTabClosableCheckBox; private JComboBox tabAreaAlignmentField; private JComboBox tabAlignmentField; private JComboBox tabWidthModeField; - private JCheckBox tabsClosableCheckBox; + private JCheckBox leadingComponentCheckBox; private JCheckBox customBorderCheckBox; private JCheckBox tabAreaInsetsCheckBox; - private TriStateCheckBox secondTabClosableCheckBox; + private JCheckBox trailingComponentCheckBox; private JCheckBox hasFullBorderCheckBox; private JCheckBox smallerTabHeightCheckBox; - private JCheckBox leadingComponentCheckBox; + private JCheckBox minimumTabWidthCheckBox; private JCheckBox hideContentSeparatorCheckBox; private JCheckBox smallerInsetsCheckBox; - private JCheckBox trailingComponentCheckBox; + private JCheckBox maximumTabWidthCheckBox; private JCheckBox showTabSeparatorsCheckBox; private JCheckBox secondTabWiderCheckBox; - private JCheckBox minimumTabWidthCheckBox; - private JCheckBox maximumTabWidthCheckBox; // 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 2c8acf3c..47954bc0 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[][]para[][]" + "$rowConstraints": "[center][][][][][]para[][]para[][]" } ) { name: "tabbedPaneControlPanel" "opaque": false @@ -197,24 +197,24 @@ new FormModel { "value": "cell 2 0" } ) add( new FormComponent( "javax.swing.JLabel" ) { - name: "hiddenTabsNavigationLabel" - "text": "Hidden tabs navigation:" + name: "tabsPopupPolicyLabel" + "text": "Tabs popup policy:" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 1" } ) add( new FormComponent( "javax.swing.JComboBox" ) { - name: "hiddenTabsNavigationField" + name: "tabsPopupPolicyField" "model": new javax.swing.DefaultComboBoxModel { selectedItem: "default" addElement( "default" ) - addElement( "moreTabsButton" ) - addElement( "arrowButtons" ) + addElement( "asNeeded" ) + addElement( "never" ) } auxiliary() { "JavaCodeGenerator.variableLocal": false "JavaCodeGenerator.typeParameters": "String" } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "hiddenTabsNavigationChanged", false ) ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabsPopupPolicyChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 1" } ) @@ -229,26 +229,25 @@ new FormModel { "value": "cell 2 1" } ) add( new FormComponent( "javax.swing.JLabel" ) { - name: "tabPlacementLabel" - "text": "Tab placement:" + name: "scrollButtonsPolicyLabel" + "text": "Scroll buttons policy:" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 2" } ) add( new FormComponent( "javax.swing.JComboBox" ) { - name: "tabPlacementField" + name: "scrollButtonsPolicyField" "model": new javax.swing.DefaultComboBoxModel { selectedItem: "default" addElement( "default" ) - addElement( "top" ) - addElement( "bottom" ) - addElement( "left" ) - addElement( "right" ) + addElement( "asNeededSingle" ) + addElement( "asNeeded" ) + addElement( "never" ) } auxiliary() { "JavaCodeGenerator.variableLocal": false "JavaCodeGenerator.typeParameters": "String" } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabPlacementChanged", false ) ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "scrollButtonsPolicyChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 2" } ) @@ -298,11 +297,77 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 2 2" } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "scrollButtonsPlacementLabel" + "text": "Scroll buttons placement:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 3" + } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "scrollButtonsPlacementField" + "model": new javax.swing.DefaultComboBoxModel { + selectedItem: "default" + addElement( "default" ) + addElement( "both" ) + addElement( "trailing" ) + } + auxiliary() { + "JavaCodeGenerator.variableLocal": false + "JavaCodeGenerator.typeParameters": "String" + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "scrollButtonsPlacementChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 3" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "tabsClosableCheckBox" + "text": "Tabs closable" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabsClosableChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 3" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "tabPlacementLabel" + "text": "Tab placement:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 4" + } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "tabPlacementField" + "model": new javax.swing.DefaultComboBoxModel { + selectedItem: "default" + addElement( "default" ) + addElement( "top" ) + addElement( "bottom" ) + addElement( "left" ) + addElement( "right" ) + } + auxiliary() { + "JavaCodeGenerator.variableLocal": false + "JavaCodeGenerator.typeParameters": "String" + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabPlacementChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 4" + } ) + add( new FormComponent( "com.formdev.flatlaf.extras.TriStateCheckBox" ) { + name: "secondTabClosableCheckBox" + "text": "Second Tab closable" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "secondTabClosableChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 4" + } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "tabAreaAlignmentLabel" "text": "Tab area/title alignment:" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 3" + "value": "cell 0 5" } ) add( new FormComponent( "javax.swing.JComboBox" ) { name: "tabAreaAlignmentField" @@ -320,7 +385,7 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabAreaAlignmentChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 3" + "value": "cell 1 5" } ) add( new FormComponent( "javax.swing.JComboBox" ) { name: "tabAlignmentField" @@ -337,13 +402,13 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabAlignmentChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 3" + "value": "cell 1 5" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "tabWidthModeLabel" "text": "Tab width mode:" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 2 3" + "value": "cell 2 5" } ) add( new FormComponent( "javax.swing.JComboBox" ) { name: "tabWidthModeField" @@ -359,66 +424,6 @@ new FormModel { "JavaCodeGenerator.typeParameters": "String" } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabWidthModeChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 2 3" - } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "tabsClosableCheckBox" - "text": "Tabs closable" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabsClosableChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 4" - } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "customBorderCheckBox" - "text": "Custom border" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "customBorderChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 4" - } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "tabAreaInsetsCheckBox" - "text": "Tab area insets (5,5,10,10)" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabAreaInsetsChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 2 4" - } ) - add( new FormComponent( "com.formdev.flatlaf.extras.TriStateCheckBox" ) { - name: "secondTabClosableCheckBox" - "text": "Second Tab closable" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "secondTabClosableChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 5" - } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "hasFullBorderCheckBox" - "text": "Show content border" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "hasFullBorderChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 5,alignx left,growx 0" - } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "smallerTabHeightCheckBox" - "text": "Smaller tab height (26)" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "smallerTabHeightChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 2 5" } ) @@ -433,22 +438,22 @@ new FormModel { "value": "cell 0 6" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "hideContentSeparatorCheckBox" - "text": "Hide content separator" + name: "customBorderCheckBox" + "text": "Custom border" auxiliary() { "JavaCodeGenerator.variableLocal": false } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "hideContentSeparatorChanged", false ) ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "customBorderChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 6" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "smallerInsetsCheckBox" - "text": "Smaller tab insets (2,2,2,2)" + name: "tabAreaInsetsCheckBox" + "text": "Tab area insets (5,5,10,10)" auxiliary() { "JavaCodeGenerator.variableLocal": false } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "smallerInsetsChanged", false ) ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabAreaInsetsChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 2 6" } ) @@ -463,22 +468,22 @@ new FormModel { "value": "cell 0 7" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "showTabSeparatorsCheckBox" - "text": "Show tab separators" + name: "hasFullBorderCheckBox" + "text": "Show content border" auxiliary() { "JavaCodeGenerator.variableLocal": false } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showTabSeparatorsChanged", false ) ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "hasFullBorderChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 7" + "value": "cell 1 7,alignx left,growx 0" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "secondTabWiderCheckBox" - "text": "Second Tab insets wider (4,20,4,20)" + name: "smallerTabHeightCheckBox" + "text": "Smaller tab height (26)" auxiliary() { "JavaCodeGenerator.variableLocal": false } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "secondTabWiderChanged", false ) ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "smallerTabHeightChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 2 7" } ) @@ -489,6 +494,26 @@ new FormModel { "JavaCodeGenerator.variableLocal": false } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "minimumTabWidthChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 8" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "hideContentSeparatorCheckBox" + "text": "Hide content separator" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "hideContentSeparatorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 8" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "smallerInsetsCheckBox" + "text": "Smaller tab insets (2,2,2,2)" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "smallerInsetsChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 2 8" } ) @@ -499,6 +524,26 @@ new FormModel { "JavaCodeGenerator.variableLocal": false } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "maximumTabWidthChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 9" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "showTabSeparatorsCheckBox" + "text": "Show tab separators" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showTabSeparatorsChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 9" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "secondTabWiderCheckBox" + "text": "Second Tab insets wider (4,20,4,20)" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "secondTabWiderChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 2 9" } ) From 9aea006f503d7a12b83c7b92998f60fc8480d5b7 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Fri, 13 Nov 2020 18:20:00 +0100 Subject: [PATCH 2/8] TabbedPane: fixed typo in previous commit --- .../src/main/java/com/formdev/flatlaf/FlatClientProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fe649536..3e3e87ec 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -387,7 +387,7 @@ public interface FlatClientProperties * {@link #TABBED_PANE_POLICY_AS_NEEDED} or * {@link #TABBED_PANE_POLICY_AS_NEEDED_SINGLE} */ - String TABBED_PANE_SCROLL_BUTTONS_POLICY = "JTabbedPane.scrollButtondPolicy"; + String TABBED_PANE_SCROLL_BUTTONS_POLICY = "JTabbedPane.scrollButtonsPolicy"; /** * Display never. From 9e0c62092ef168a1c1a66eff8851468ec4bacf3c Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Fri, 13 Nov 2020 22:23:28 +0100 Subject: [PATCH 3/8] TabbedPane: updated UI defaults dumps for previous checkins --- flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt | 3 +++ flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt | 3 +++ flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt | 3 +++ .../com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt | 3 +++ 4 files changed, 12 insertions(+) diff --git a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt index 6d1280b7..d1e539e2 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt @@ -942,6 +942,8 @@ TabbedPane.highlight #242424 javax.swing.plaf.ColorUIResource [UI] TabbedPane.hoverColor #303234 com.formdev.flatlaf.util.DerivedColor [UI] darken(5%) TabbedPane.labelShift 1 TabbedPane.light #313131 javax.swing.plaf.ColorUIResource [UI] +TabbedPane.scrollButtonsPlacement both +TabbedPane.scrollButtonsPolicy asNeededSingle TabbedPane.selectedLabelShift -1 TabbedPane.selectedTabPadInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI] TabbedPane.selectionFollowsFocus true @@ -958,6 +960,7 @@ TabbedPane.tabSeparatorsFullHeight false TabbedPane.tabWidthMode preferred TabbedPane.tabsOpaque true TabbedPane.tabsOverlapBorder false +TabbedPane.tabsPopupPolicy asNeeded TabbedPane.textIconGap 4 TabbedPane.underlineColor #4a88c7 javax.swing.plaf.ColorUIResource [UI] TabbedPaneUI com.formdev.flatlaf.ui.FlatTabbedPaneUI diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt index de1f6fa0..6da5e87e 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt @@ -947,6 +947,8 @@ TabbedPane.highlight #ffffff javax.swing.plaf.ColorUIResource [UI] TabbedPane.hoverColor #e0e0e0 com.formdev.flatlaf.util.DerivedColor [UI] darken(7% autoInverse) TabbedPane.labelShift 1 TabbedPane.light #e3e3e3 javax.swing.plaf.ColorUIResource [UI] +TabbedPane.scrollButtonsPlacement both +TabbedPane.scrollButtonsPolicy asNeededSingle TabbedPane.selectedLabelShift -1 TabbedPane.selectedTabPadInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI] TabbedPane.selectionFollowsFocus true @@ -963,6 +965,7 @@ TabbedPane.tabSeparatorsFullHeight false TabbedPane.tabWidthMode preferred TabbedPane.tabsOpaque true TabbedPane.tabsOverlapBorder false +TabbedPane.tabsPopupPolicy asNeeded TabbedPane.textIconGap 4 TabbedPane.underlineColor #4083c9 javax.swing.plaf.ColorUIResource [UI] TabbedPaneUI com.formdev.flatlaf.ui.FlatTabbedPaneUI diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt index 53e50cd2..b05ebcdb 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt @@ -935,6 +935,8 @@ TabbedPane.highlight #ffffff javax.swing.plaf.ColorUIResource [UI] TabbedPane.hoverColor #eeeeee javax.swing.plaf.ColorUIResource [UI] TabbedPane.labelShift 1 TabbedPane.light #e3e3e3 javax.swing.plaf.ColorUIResource [UI] +TabbedPane.scrollButtonsPlacement both +TabbedPane.scrollButtonsPolicy asNeededSingle TabbedPane.selectedBackground #00ff00 javax.swing.plaf.ColorUIResource [UI] TabbedPane.selectedForeground #0000ff javax.swing.plaf.ColorUIResource [UI] TabbedPane.selectedLabelShift -1 @@ -954,6 +956,7 @@ TabbedPane.tabSeparatorsFullHeight false TabbedPane.tabWidthMode preferred TabbedPane.tabsOpaque true TabbedPane.tabsOverlapBorder false +TabbedPane.tabsPopupPolicy asNeeded TabbedPane.textIconGap 4 TabbedPane.underlineColor #ffff00 javax.swing.plaf.ColorUIResource [UI] TabbedPaneUI com.formdev.flatlaf.ui.FlatTabbedPaneUI 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 05b692ab..7df9a413 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 @@ -672,6 +672,8 @@ TabbedPane.highlight TabbedPane.hoverColor TabbedPane.labelShift TabbedPane.light +TabbedPane.scrollButtonsPlacement +TabbedPane.scrollButtonsPolicy TabbedPane.selectedLabelShift TabbedPane.selectedTabPadInsets TabbedPane.selectionFollowsFocus @@ -688,6 +690,7 @@ TabbedPane.tabSeparatorsFullHeight TabbedPane.tabWidthMode TabbedPane.tabsOpaque TabbedPane.tabsOverlapBorder +TabbedPane.tabsPopupPolicy TabbedPane.textIconGap TabbedPane.underlineColor TabbedPaneUI From c98ec041d4aac48430b4ac06b9a1b7a1a61881f5 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Fri, 13 Nov 2020 22:26:14 +0100 Subject: [PATCH 4/8] Demo: "Tabs" tab: added "Scroll buttons policy", "Scroll buttons placement" and "Tabs popup policy" configuration for PR #211 --- .../com/formdev/flatlaf/demo/TabsPanel.java | 171 +++++++++++++++++- .../com/formdev/flatlaf/demo/TabsPanel.jfd | 125 ++++++++++++- 2 files changed, 285 insertions(+), 11 deletions(-) diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/TabsPanel.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/TabsPanel.java index 128b1ebb..ae59d89b 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/TabsPanel.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/TabsPanel.java @@ -280,6 +280,25 @@ class TabsPanel tabbedPane.addTab( "C", null ); } + private void tabsPopupPolicyChanged() { + String tabsPopupPolicy = popupNeverButton.isSelected() ? TABBED_PANE_POLICY_NEVER : null; + putTabbedPanesClientProperty( TABBED_PANE_TABS_POPUP_POLICY, tabsPopupPolicy ); + } + + private void scrollButtonsPolicyChanged() { + String scrollButtonsPolicy = scrollAsNeededButton.isSelected() + ? TABBED_PANE_POLICY_AS_NEEDED + : (scrollNeverButton.isSelected() + ? TABBED_PANE_POLICY_NEVER + : null); + putTabbedPanesClientProperty( TABBED_PANE_SCROLL_BUTTONS_POLICY, scrollButtonsPolicy ); + } + + private void scrollButtonsPlacementChanged() { + String scrollButtonsPlacement = scrollTrailingButton.isSelected() ? TABBED_PANE_PLACEMENT_TRAILING : null; + putTabbedPanesClientProperty( TABBED_PANE_SCROLL_BUTTONS_PLACEMENT, scrollButtonsPlacement ); + } + private void showTabSeparatorsChanged() { Boolean showTabSeparators = showTabSeparatorsCheckBox.isSelected() ? true : null; putTabbedPanesClientProperty( TABBED_PANE_SHOW_TAB_SEPARATORS, showTabSeparators ); @@ -362,7 +381,21 @@ class TabsPanel tabAlignVerticalTabbedPane = new JTabbedPane(); tabAlignCenterTabbedPane = new JTabbedPane(); tabAlignTrailingTabbedPane = new JTabbedPane(); + separator2 = new JSeparator(); JPanel panel4 = new JPanel(); + scrollButtonsPolicyLabel = new JLabel(); + scrollButtonsPolicyToolBar = new JToolBar(); + scrollAsNeededSingleButton = new JToggleButton(); + scrollAsNeededButton = new JToggleButton(); + scrollNeverButton = new JToggleButton(); + scrollButtonsPlacementLabel = new JLabel(); + scrollButtonsPlacementToolBar = new JToolBar(); + scrollBothButton = new JToggleButton(); + scrollTrailingButton = new JToggleButton(); + tabsPopupPolicyLabel = new JLabel(); + tabsPopupPolicyToolBar = new JToolBar(); + popupAsNeededButton = new JToggleButton(); + popupNeverButton = new JToggleButton(); showTabSeparatorsCheckBox = new JCheckBox(); //======== this ======== @@ -374,7 +407,8 @@ class TabsPanel "[fill]para" + "[fill]", // rows - "[grow,fill]" + + "[grow,fill]para" + + "[]" + "[]")); //======== panel1 ======== @@ -822,23 +856,122 @@ class TabsPanel } add(panel3, "cell 2 0"); + //---- separator2 ---- + separator2.setName("separator2"); + add(separator2, "cell 0 1 3 1"); + //======== panel4 ======== { panel4.setName("panel4"); panel4.setLayout(new MigLayout( "insets 0,hidemode 3", // columns - "[]", + "[]" + + "[fill]para" + + "[fill]" + + "[fill]para", // rows + "[]" + "[center]")); + //---- scrollButtonsPolicyLabel ---- + scrollButtonsPolicyLabel.setText("Scroll buttons policy:"); + scrollButtonsPolicyLabel.setName("scrollButtonsPolicyLabel"); + panel4.add(scrollButtonsPolicyLabel, "cell 0 0"); + + //======== scrollButtonsPolicyToolBar ======== + { + scrollButtonsPolicyToolBar.setFloatable(false); + scrollButtonsPolicyToolBar.setBorder(BorderFactory.createEmptyBorder()); + scrollButtonsPolicyToolBar.setName("scrollButtonsPolicyToolBar"); + + //---- scrollAsNeededSingleButton ---- + scrollAsNeededSingleButton.setText("asNeededSingle"); + scrollAsNeededSingleButton.setFont(scrollAsNeededSingleButton.getFont().deriveFont(scrollAsNeededSingleButton.getFont().getSize() - 2f)); + scrollAsNeededSingleButton.setSelected(true); + scrollAsNeededSingleButton.setName("scrollAsNeededSingleButton"); + scrollAsNeededSingleButton.addActionListener(e -> scrollButtonsPolicyChanged()); + scrollButtonsPolicyToolBar.add(scrollAsNeededSingleButton); + + //---- scrollAsNeededButton ---- + scrollAsNeededButton.setText("asNeeded"); + scrollAsNeededButton.setFont(scrollAsNeededButton.getFont().deriveFont(scrollAsNeededButton.getFont().getSize() - 2f)); + scrollAsNeededButton.setName("scrollAsNeededButton"); + scrollAsNeededButton.addActionListener(e -> scrollButtonsPolicyChanged()); + scrollButtonsPolicyToolBar.add(scrollAsNeededButton); + + //---- scrollNeverButton ---- + scrollNeverButton.setText("never"); + scrollNeverButton.setFont(scrollNeverButton.getFont().deriveFont(scrollNeverButton.getFont().getSize() - 2f)); + scrollNeverButton.setName("scrollNeverButton"); + scrollNeverButton.addActionListener(e -> scrollButtonsPolicyChanged()); + scrollButtonsPolicyToolBar.add(scrollNeverButton); + } + panel4.add(scrollButtonsPolicyToolBar, "cell 1 0"); + + //---- scrollButtonsPlacementLabel ---- + scrollButtonsPlacementLabel.setText("Scroll buttons placement:"); + scrollButtonsPlacementLabel.setName("scrollButtonsPlacementLabel"); + panel4.add(scrollButtonsPlacementLabel, "cell 2 0"); + + //======== scrollButtonsPlacementToolBar ======== + { + scrollButtonsPlacementToolBar.setFloatable(false); + scrollButtonsPlacementToolBar.setBorder(BorderFactory.createEmptyBorder()); + scrollButtonsPlacementToolBar.setName("scrollButtonsPlacementToolBar"); + + //---- scrollBothButton ---- + scrollBothButton.setText("both"); + scrollBothButton.setFont(scrollBothButton.getFont().deriveFont(scrollBothButton.getFont().getSize() - 2f)); + scrollBothButton.setSelected(true); + scrollBothButton.setName("scrollBothButton"); + scrollBothButton.addActionListener(e -> scrollButtonsPlacementChanged()); + scrollButtonsPlacementToolBar.add(scrollBothButton); + + //---- scrollTrailingButton ---- + scrollTrailingButton.setText("trailing"); + scrollTrailingButton.setFont(scrollTrailingButton.getFont().deriveFont(scrollTrailingButton.getFont().getSize() - 2f)); + scrollTrailingButton.setName("scrollTrailingButton"); + scrollTrailingButton.addActionListener(e -> scrollButtonsPlacementChanged()); + scrollButtonsPlacementToolBar.add(scrollTrailingButton); + } + panel4.add(scrollButtonsPlacementToolBar, "cell 3 0"); + + //---- tabsPopupPolicyLabel ---- + tabsPopupPolicyLabel.setText("Tabs popup policy:"); + tabsPopupPolicyLabel.setName("tabsPopupPolicyLabel"); + panel4.add(tabsPopupPolicyLabel, "cell 0 1"); + + //======== tabsPopupPolicyToolBar ======== + { + tabsPopupPolicyToolBar.setFloatable(false); + tabsPopupPolicyToolBar.setBorder(BorderFactory.createEmptyBorder()); + tabsPopupPolicyToolBar.setName("tabsPopupPolicyToolBar"); + + //---- popupAsNeededButton ---- + popupAsNeededButton.setText("asNeeded"); + popupAsNeededButton.setFont(popupAsNeededButton.getFont().deriveFont(popupAsNeededButton.getFont().getSize() - 2f)); + popupAsNeededButton.setSelected(true); + popupAsNeededButton.setName("popupAsNeededButton"); + popupAsNeededButton.addActionListener(e -> tabsPopupPolicyChanged()); + tabsPopupPolicyToolBar.add(popupAsNeededButton); + + //---- popupNeverButton ---- + popupNeverButton.setText("never"); + popupNeverButton.setFont(popupNeverButton.getFont().deriveFont(popupNeverButton.getFont().getSize() - 2f)); + popupNeverButton.setName("popupNeverButton"); + popupNeverButton.addActionListener(e -> tabsPopupPolicyChanged()); + tabsPopupPolicyToolBar.add(popupNeverButton); + } + panel4.add(tabsPopupPolicyToolBar, "cell 1 1"); + //---- showTabSeparatorsCheckBox ---- showTabSeparatorsCheckBox.setText("Show tab separators"); showTabSeparatorsCheckBox.setName("showTabSeparatorsCheckBox"); showTabSeparatorsCheckBox.addActionListener(e -> showTabSeparatorsChanged()); - panel4.add(showTabSeparatorsCheckBox, "cell 0 0"); + panel4.add(showTabSeparatorsCheckBox, "cell 2 1 2 1"); } - add(panel4, "cell 0 1 3 1"); + add(panel4, "cell 0 2 3 1"); //---- tabPlacementButtonGroup ---- ButtonGroup tabPlacementButtonGroup = new ButtonGroup(); @@ -857,6 +990,22 @@ class TabsPanel closableTabsButtonGroup.add(squareCloseButton); closableTabsButtonGroup.add(circleCloseButton); closableTabsButtonGroup.add(redCrossCloseButton); + + //---- scrollButtonsPolicyButtonGroup ---- + ButtonGroup scrollButtonsPolicyButtonGroup = new ButtonGroup(); + scrollButtonsPolicyButtonGroup.add(scrollAsNeededSingleButton); + scrollButtonsPolicyButtonGroup.add(scrollAsNeededButton); + scrollButtonsPolicyButtonGroup.add(scrollNeverButton); + + //---- scrollButtonsPlacementButtonGroup ---- + ButtonGroup scrollButtonsPlacementButtonGroup = new ButtonGroup(); + scrollButtonsPlacementButtonGroup.add(scrollBothButton); + scrollButtonsPlacementButtonGroup.add(scrollTrailingButton); + + //---- tabsPopupPolicyButtonGroup ---- + ButtonGroup tabsPopupPolicyButtonGroup = new ButtonGroup(); + tabsPopupPolicyButtonGroup.add(popupAsNeededButton); + tabsPopupPolicyButtonGroup.add(popupNeverButton); // JFormDesigner - End of component initialization //GEN-END:initComponents } @@ -903,6 +1052,20 @@ class TabsPanel private JTabbedPane tabAlignVerticalTabbedPane; private JTabbedPane tabAlignCenterTabbedPane; private JTabbedPane tabAlignTrailingTabbedPane; + private JSeparator separator2; + private JLabel scrollButtonsPolicyLabel; + private JToolBar scrollButtonsPolicyToolBar; + private JToggleButton scrollAsNeededSingleButton; + private JToggleButton scrollAsNeededButton; + private JToggleButton scrollNeverButton; + private JLabel scrollButtonsPlacementLabel; + private JToolBar scrollButtonsPlacementToolBar; + private JToggleButton scrollBothButton; + private JToggleButton scrollTrailingButton; + private JLabel tabsPopupPolicyLabel; + private JToolBar tabsPopupPolicyToolBar; + private JToggleButton popupAsNeededButton; + private JToggleButton popupNeverButton; private JCheckBox showTabSeparatorsCheckBox; // JFormDesigner - End of variables declaration //GEN-END:variables } diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/TabsPanel.jfd b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/TabsPanel.jfd index e14e73ef..3f634b86 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/TabsPanel.jfd +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/TabsPanel.jfd @@ -7,7 +7,7 @@ new FormModel { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "insets dialog,hidemode 3" "$columnConstraints": "[grow,fill]para[fill]para[fill]" - "$rowConstraints": "[grow,fill][]" + "$rowConstraints": "[grow,fill]para[][]" } ) { name: "this" add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { @@ -98,7 +98,7 @@ new FormModel { add( new FormContainer( "javax.swing.JToolBar", new FormLayoutManager( class javax.swing.JToolBar ) ) { name: "tabLayoutToolBar" "floatable": false - "border": new javax.swing.border.EmptyBorder( 0, 0, 0, 0 ) + "border": &EmptyBorder0 new javax.swing.border.EmptyBorder( 0, 0, 0, 0 ) add( new FormComponent( "javax.swing.JToggleButton" ) { name: "scrollTabLayoutButton" "text": "scroll" @@ -450,15 +450,111 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 2 0" } ) + add( new FormComponent( "javax.swing.JSeparator" ) { + name: "separator2" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1 3 1" + } ) add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "insets 0,hidemode 3" - "$columnConstraints": "[]" - "$rowConstraints": "[center]" + "$columnConstraints": "[][fill]para[fill][fill]para" + "$rowConstraints": "[][center]" } ) { name: "panel4" auxiliary() { "JavaCodeGenerator.variableLocal": true } + add( new FormComponent( "javax.swing.JLabel" ) { + name: "scrollButtonsPolicyLabel" + "text": "Scroll buttons policy:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormContainer( "javax.swing.JToolBar", new FormLayoutManager( class javax.swing.JToolBar ) ) { + name: "scrollButtonsPolicyToolBar" + "floatable": false + "border": #EmptyBorder0 + add( new FormComponent( "javax.swing.JToggleButton" ) { + name: "scrollAsNeededSingleButton" + "text": "asNeededSingle" + "font": #SwingDerivedFont2 + "selected": true + "$buttonGroup": new FormReference( "scrollButtonsPolicyButtonGroup" ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "scrollButtonsPolicyChanged", false ) ) + } ) + add( new FormComponent( "javax.swing.JToggleButton" ) { + name: "scrollAsNeededButton" + "text": "asNeeded" + "font": #SwingDerivedFont2 + "$buttonGroup": new FormReference( "scrollButtonsPolicyButtonGroup" ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "scrollButtonsPolicyChanged", false ) ) + } ) + add( new FormComponent( "javax.swing.JToggleButton" ) { + name: "scrollNeverButton" + "text": "never" + "font": #SwingDerivedFont2 + "$buttonGroup": new FormReference( "scrollButtonsPolicyButtonGroup" ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "scrollButtonsPolicyChanged", false ) ) + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 0" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "scrollButtonsPlacementLabel" + "text": "Scroll buttons placement:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 0" + } ) + add( new FormContainer( "javax.swing.JToolBar", new FormLayoutManager( class javax.swing.JToolBar ) ) { + name: "scrollButtonsPlacementToolBar" + "floatable": false + "border": #EmptyBorder0 + add( new FormComponent( "javax.swing.JToggleButton" ) { + name: "scrollBothButton" + "text": "both" + "font": #SwingDerivedFont2 + "selected": true + "$buttonGroup": new FormReference( "scrollButtonsPlacementButtonGroup" ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "scrollButtonsPlacementChanged", false ) ) + } ) + add( new FormComponent( "javax.swing.JToggleButton" ) { + name: "scrollTrailingButton" + "text": "trailing" + "font": #SwingDerivedFont2 + "$buttonGroup": new FormReference( "scrollButtonsPlacementButtonGroup" ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "scrollButtonsPlacementChanged", false ) ) + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 3 0" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "tabsPopupPolicyLabel" + "text": "Tabs popup policy:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + add( new FormContainer( "javax.swing.JToolBar", new FormLayoutManager( class javax.swing.JToolBar ) ) { + name: "tabsPopupPolicyToolBar" + "floatable": false + "border": #EmptyBorder0 + add( new FormComponent( "javax.swing.JToggleButton" ) { + name: "popupAsNeededButton" + "text": "asNeeded" + "font": #SwingDerivedFont2 + "selected": true + "$buttonGroup": new FormReference( "tabsPopupPolicyButtonGroup" ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabsPopupPolicyChanged", false ) ) + } ) + add( new FormComponent( "javax.swing.JToggleButton" ) { + name: "popupNeverButton" + "text": "never" + "font": #SwingDerivedFont2 + "$buttonGroup": new FormReference( "tabsPopupPolicyButtonGroup" ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabsPopupPolicyChanged", false ) ) + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 1" + } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "showTabSeparatorsCheckBox" "text": "Show tab separators" @@ -467,14 +563,14 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showTabSeparatorsChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 0" + "value": "cell 2 1 2 1" } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 1 3 1" + "value": "cell 0 2 3 1" } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) - "size": new java.awt.Dimension( 1075, 860 ) + "size": new java.awt.Dimension( 1075, 895 ) } ) add( new FormNonVisual( "javax.swing.ButtonGroup" ) { name: "tabPlacementButtonGroup" @@ -491,5 +587,20 @@ new FormModel { }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 5, 1020 ) } ) + add( new FormNonVisual( "javax.swing.ButtonGroup" ) { + name: "tabsPopupPolicyButtonGroup" + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 200, 915 ) + } ) + add( new FormNonVisual( "javax.swing.ButtonGroup" ) { + name: "scrollButtonsPolicyButtonGroup" + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 200, 965 ) + } ) + add( new FormNonVisual( "javax.swing.ButtonGroup" ) { + name: "scrollButtonsPlacementButtonGroup" + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 200, 1020 ) + } ) } } From afccdc47493f2f80e6ebb57b76ac46a2453ded99 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Fri, 13 Nov 2020 23:25:19 +0100 Subject: [PATCH 5/8] Demo: "Tabs" tab: improved demo of leading and trailing tab area components by using toolbars --- .../com/formdev/flatlaf/demo/TabsPanel.java | 28 ++++++++++--------- .../flatlaf/demo/icons/buildLoadChanges.svg | 3 ++ .../com/formdev/flatlaf/demo/icons/commit.svg | 3 ++ .../com/formdev/flatlaf/demo/icons/diff.svg | 6 ++++ .../formdev/flatlaf/demo/icons/listFiles.svg | 7 +++++ .../formdev/flatlaf/demo/icons/project.svg | 6 ++++ 6 files changed, 40 insertions(+), 13 deletions(-) create mode 100644 flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/buildLoadChanges.svg create mode 100644 flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/commit.svg create mode 100644 flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/diff.svg create mode 100644 flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/listFiles.svg create mode 100644 flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/project.svg diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/TabsPanel.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/TabsPanel.java index ae59d89b..1540a5d6 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/TabsPanel.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/TabsPanel.java @@ -162,26 +162,28 @@ class TabsPanel } private void initCustomComponentsTabs( JTabbedPane tabbedPane ) { - addDefaultTabsNoContent( tabbedPane, 3 ); + addDefaultTabsNoContent( tabbedPane, 2 ); customComponentsChanged(); } private void customComponentsChanged() { - JComponent leading = null; - JComponent trailing = null; + JToolBar leading = null; + JToolBar trailing = null; if( leadingComponentButton.isSelected() ) { - leading = new JLabel( "Leading" ); - leading.setOpaque( true ); - leading.setBackground( new Color( UIManager.getColor( "Objects.Green" ).getRGB() ) ); - leading.setForeground( Color.black ); - leading.setBorder( new EmptyBorder( 4, 4, 4, 4 ) ); + leading = new JToolBar(); + leading.setFloatable( false ); + leading.setBorder( null ); + leading.add( new JButton( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/project.svg" ) ) ); } if( trailingComponentButton.isSelected() ) { - trailing = new JLabel( "Trailing" ); - trailing.setOpaque( true ); - trailing.setBackground( new Color( UIManager.getColor( "Objects.Purple" ).getRGB() ) ); - trailing.setForeground( Color.black ); - trailing.setBorder( new EmptyBorder( 4, 4, 4, 4 ) ); + trailing = new JToolBar(); + trailing.setFloatable( false ); + trailing.setBorder( null ); + trailing.add( new JButton( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/buildLoadChanges.svg" ) ) ); + trailing.add( Box.createHorizontalGlue() ); + trailing.add( new JButton( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/commit.svg" ) ) ); + trailing.add( new JButton( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/diff.svg" ) ) ); + trailing.add( new JButton( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/listFiles.svg" ) ) ); } customComponentsTabbedPane.putClientProperty( TABBED_PANE_LEADING_COMPONENT, leading ); customComponentsTabbedPane.putClientProperty( TABBED_PANE_TRAILING_COMPONENT, trailing ); diff --git a/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/buildLoadChanges.svg b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/buildLoadChanges.svg new file mode 100644 index 00000000..02f46df0 --- /dev/null +++ b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/buildLoadChanges.svg @@ -0,0 +1,3 @@ + + + diff --git a/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/commit.svg b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/commit.svg new file mode 100644 index 00000000..a3bc7b6d --- /dev/null +++ b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/commit.svg @@ -0,0 +1,3 @@ + + + diff --git a/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/diff.svg b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/diff.svg new file mode 100644 index 00000000..56821e70 --- /dev/null +++ b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/diff.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/listFiles.svg b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/listFiles.svg new file mode 100644 index 00000000..24227136 --- /dev/null +++ b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/listFiles.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/project.svg b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/project.svg new file mode 100644 index 00000000..42dda739 --- /dev/null +++ b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/project.svg @@ -0,0 +1,6 @@ + + + + + + From 7dbc6ff8a3893ce384b70b1ab500718929aa70f6 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sat, 14 Nov 2020 00:24:38 +0100 Subject: [PATCH 6/8] TabbedPane: fixes - avoid that tab area "jump" to the right/top when backward button becomes hidden - scroll arrow buttons were not always hidden in right-to-left horizontal layout --- .../formdev/flatlaf/ui/FlatTabbedPaneUI.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) 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 27f6546d..b52534ef 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 @@ -2563,7 +2563,7 @@ public class FlatTabbedPaneUI // because methods scrollForward() and scrollBackward() in class // BasicTabbedPaneUI.ScrollableTabSupport do not work for right-to-left boolean leftToRight = isLeftToRight(); - if( !leftToRight && !useMoreTabsButton && isHorizontalTabPlacement() ) { + if( !leftToRight && isHorizontalTabPlacement() ) { useMoreTabsButton = true; useScrollButtons = false; } @@ -2581,7 +2581,7 @@ public class FlatTabbedPaneUI } } - if( !useMoreTabsButton && (backwardButton == null || forwardButton == null) ) + if( backwardButton == null || forwardButton == null ) return; // should never occur Rectangle bounds = tabPane.getBounds(); @@ -2610,6 +2610,13 @@ public class FlatTabbedPaneUI // layout tab area if( tabPlacement == TOP || tabPlacement == BOTTOM ) { + // avoid that tab area "jump" to the right when backward button becomes hidden + if( useScrollButtons && hideDisabledScrollButtons ) { + Point viewPosition = tabViewport.getViewPosition(); + if( viewPosition.x <= backwardButton.getPreferredSize().width ) + tabViewport.setViewPosition( new Point( 0, viewPosition.y ) ); + } + // tab area height (maxTabHeight is zero if tab count is zero) int tabAreaHeight = (maxTabHeight > 0) ? maxTabHeight @@ -2726,6 +2733,13 @@ public class FlatTabbedPaneUI } } } else { // LEFT and RIGHT tab placement + // avoid that tab area "jump" to the top when backward button becomes hidden + if( useScrollButtons && hideDisabledScrollButtons ) { + Point viewPosition = tabViewport.getViewPosition(); + if( viewPosition.y <= backwardButton.getPreferredSize().height ) + tabViewport.setViewPosition( new Point( viewPosition.x, 0 ) ); + } + // tab area width (maxTabWidth is zero if tab count is zero) int tabAreaWidth = (maxTabWidth > 0) ? maxTabWidth From 634f7b5ba3840d31ffd2636195f9e5720ad731e0 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sat, 14 Nov 2020 00:48:37 +0100 Subject: [PATCH 7/8] CHANGELOG.md: added/updated latest TabbedPane changes --- CHANGELOG.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c870765f..c3f31cf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,16 +5,17 @@ FlatLaf Change Log #### New features and improvements -- TabbedPane: Replaced forward/backward scrolling arrow buttons with "Show - Hidden Tabs" button. If pressed, it shows a popup menu that contains (partly) - hidden tabs and selecting one activates that tab. If you prefer - forward/backward buttons, use `UIManager.put( - "TabbedPane.hiddenTabsNavigation", "arrowButtons" )`. (PR #190; issue #40) -- TabbedPane: Support scrolling tabs with mouse wheel (if `tabLayoutPolicy` is - `SCROLL_TAB_LAYOUT`). (PR #187; issue #40) -- TabbedPane: Repeat scrolling as long as arrow buttons are pressed. (PR #187; - issue #40) -- TabbedPane: Support adding custom components to left and right sides of tabs +- TabbedPane: In scroll tab layout, added "Show Hidden Tabs" button to trailing + side of tab area. If pressed, it shows a popup menu that contains (partly) + hidden tabs and selecting one activates that tab. (PR #190; issue #40) +- TabbedPane: Support forward/backward scroll arrow buttons on both sides of tab + area. Backward button on left side, forward button on right side. Not + applicable scroll buttons are hidden. (PR #211; issue #40) +- TabbedPane: Support scrolling tabs with mouse wheel in scroll tab layout. (PR + #187; issue #40) +- TabbedPane: Repeat scrolling as long as scroll arrow buttons are pressed. (PR + #187; issue #40) +- TabbedPane: Support adding custom components to left and right sides of tab area. (set client property `JTabbedPane.leadingComponent` or `JTabbedPane.trailingComponent` to a `java.awt.Component`) (PR #192; issue #40) From f9e34cbab71374f4669814f7de016a9d2eeca469 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sat, 14 Nov 2020 18:44:48 +0100 Subject: [PATCH 8/8] TabbedPane: support specifying default tab layout policy for all tabbed panes via UI value TabbedPane.tabLayoutPolicy --- CHANGELOG.md | 6 +++++- .../com/formdev/flatlaf/ui/FlatTabbedPaneUI.java | 15 ++++++++++++++- .../com/formdev/flatlaf/FlatLaf.properties | 2 ++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3f31cf0..e3c445fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,11 @@ FlatLaf Change Log - TabbedPane: Support forward/backward scroll arrow buttons on both sides of tab area. Backward button on left side, forward button on right side. Not applicable scroll buttons are hidden. (PR #211; issue #40) -- TabbedPane: Support scrolling tabs with mouse wheel in scroll tab layout. (PR +- TabbedPane: Support specifying default tab layout policy for all tabbed panes + in the application via UI value `TabbedPane.tabLayoutPolicy`. E.g. invoke + `UIManager.put( "TabbedPane.tabLayoutPolicy", "scroll" );` to use scroll + layout. +- TabbedPane: Support tab scrolling with mouse wheel (in scroll tab layout). (PR #187; issue #40) - TabbedPane: Repeat scrolling as long as scroll arrow buttons are pressed. (PR #187; issue #40) 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 b52534ef..013f397d 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 @@ -131,8 +131,9 @@ import com.formdev.flatlaf.util.UIScale; * @uiDefault TabbedPane.tabSeparatorsFullHeight boolean * @uiDefault TabbedPane.hasFullBorder boolean * + * @uiDefault TabbedPane.tabLayoutPolicy String wrap (default) or scroll * @uiDefault TabbedPane.tabsPopupPolicy String never or asNeeded (default) - * @uiDefault TabbedPane.scrollButtonsPolicy String never, asNeeded or asNeededSingle (default) + * @uiDefault TabbedPane.scrollButtonsPolicy String never, asNeeded or asNeededSingle (default) * @uiDefault TabbedPane.scrollButtonsPlacement String both (default) or trailing * * @uiDefault TabbedPane.tabAreaAlignment String leading (default), center, trailing or fill @@ -231,6 +232,18 @@ public class FlatTabbedPaneUI @Override public void installUI( JComponent c ) { + // initialize tab layout policy (if specified) + String tabLayoutPolicyStr = UIManager.getString( "TabbedPane.tabLayoutPolicy" ); + if( tabLayoutPolicyStr != null ) { + int tabLayoutPolicy; + switch( tabLayoutPolicyStr ) { + default: + case "wrap": tabLayoutPolicy = JTabbedPane.WRAP_TAB_LAYOUT; break; + case "scroll": tabLayoutPolicy = JTabbedPane.SCROLL_TAB_LAYOUT; break; + } + ((JTabbedPane)c).setTabLayoutPolicy( tabLayoutPolicy ); + } + // initialize this defaults here because they are used in constructor // of FlatTabAreaButton, which is invoked before installDefaults() arrowType = UIManager.getString( "TabbedPane.arrowType" ); diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties index 42786726..0b94527b 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -573,6 +573,8 @@ TabbedPane.arrowType=chevron TabbedPane.buttonInsets=2,1,2,1 TabbedPane.buttonArc=$Button.arc +# allowed values: wrap or scroll +#TabbedPane.tabLayoutPolicy=scroll # allowed values: never or asNeeded TabbedPane.tabsPopupPolicy=asNeeded # allowed values: never, asNeeded or asNeededSingle