From c8f74781704f6baa6b442eafafefb8d4ec6f53d2 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sat, 27 Mar 2021 11:02:33 +0100 Subject: [PATCH] JIDE: JideTabbedPane: - use `FlatTabbedPaneCloseIcon` for tab close buttons - scale close buttons - fix close buttons location --- .../jideoss/ui/FlatJideTabbedPaneUI.java | 148 +++++++++++++++++- .../flatlaf/jideoss/FlatLaf.properties | 3 + .../uidefaults/FlatDarkLaf_1.8.0_202.txt | 2 + .../uidefaults/FlatLightLaf_1.8.0_202.txt | 2 + .../uidefaults/FlatTestLaf_1.8.0_202.txt | 2 + .../uidefaults/JIDE-FlatDarkLaf_1.8.0_202.txt | 2 - .../JIDE-FlatLightLaf_1.8.0_202.txt | 2 - .../flatlaf/themeeditor/FlatLafUIKeys.txt | 2 + 8 files changed, 158 insertions(+), 5 deletions(-) diff --git a/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatJideTabbedPaneUI.java b/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatJideTabbedPaneUI.java index 1e611eb3..6bd37a37 100644 --- a/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatJideTabbedPaneUI.java +++ b/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatJideTabbedPaneUI.java @@ -21,12 +21,15 @@ import static com.formdev.flatlaf.FlatClientProperties.TABBED_PANE_SHOW_TAB_SEPA import static com.formdev.flatlaf.FlatClientProperties.clientPropertyBoolean; import static com.formdev.flatlaf.util.UIScale.scale; import java.awt.Color; +import java.awt.Component; +import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; +import java.awt.LayoutManager; import java.awt.Rectangle; import java.awt.Shape; import java.awt.event.MouseListener; @@ -34,15 +37,19 @@ import java.awt.event.MouseMotionListener; import java.awt.geom.Path2D; import java.awt.geom.Rectangle2D; import java.beans.PropertyChangeListener; +import javax.swing.Icon; +import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; +import com.formdev.flatlaf.icons.FlatTabbedPaneCloseIcon; import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.util.UIScale; import com.jidesoft.plaf.LookAndFeelFactory; import com.jidesoft.plaf.UIDefaultsLookup; import com.jidesoft.plaf.basic.BasicJideTabbedPaneUI; import com.jidesoft.swing.JideTabbedPane; +import com.jidesoft.swing.JideTabbedPane.NoFocusButton; /** * Provides the Flat LaF UI delegate for {@link com.jidesoft.swing.JideTabbedPane}. @@ -68,6 +75,11 @@ public class FlatJideTabbedPaneUI protected boolean hasFullBorder; protected boolean tabsOverlapBorder; + protected Icon closeIcon; + + protected int closeButtonLeftMarginUnscaled; + protected int closeButtonRightMarginUnscaled; + private Object[] oldRenderingHints; public static ComponentUI createUI( JComponent c ) { @@ -100,6 +112,11 @@ public class FlatJideTabbedPaneUI hasFullBorder = UIManager.getBoolean( "TabbedPane.hasFullBorder" ); tabsOverlapBorder = UIManager.getBoolean( "TabbedPane.tabsOverlapBorder" ); + closeIcon = new FlatJideTabCloseIcon(); + + closeButtonLeftMarginUnscaled = _closeButtonLeftMargin; + closeButtonRightMarginUnscaled = _closeButtonRightMargin; + // scale _textIconGap = scale( _textIconGap ); tabHeight = scale( tabHeight ); @@ -117,6 +134,7 @@ public class FlatJideTabbedPaneUI focusColor = null; tabSeparatorColor = null; contentAreaColor = null; + closeIcon = null; } @Override @@ -159,14 +177,23 @@ public class FlatJideTabbedPaneUI return new RolloverMouseMotionHandler(); } + @Override + protected LayoutManager createLayoutManager() { + return (_tabPane.getTabLayoutPolicy() == JideTabbedPane.SCROLL_TAB_LAYOUT) + ? new FlatJideTabbedPaneScrollLayout() + : super.createLayoutManager(); + } + @Override protected int calculateTabHeight( int tabPlacement, int tabIndex, FontMetrics metrics ) { + updateCloseButtonMargins(); return Math.max( tabHeight, super.calculateTabHeight( tabPlacement, tabIndex, metrics ) ); } @Override protected int calculateTabWidth( int tabPlacement, int tabIndex, FontMetrics metrics ) { - return Math.max( tabHeight, super.calculateTabWidth( tabPlacement, tabIndex, metrics ) ); + updateCloseButtonMargins(); + return Math.max( tabHeight, super.calculateTabWidth( tabPlacement, tabIndex, metrics ) - 3 ); } @Override @@ -189,6 +216,26 @@ public class FlatJideTabbedPaneUI return JideTabbedPane.SHAPE_BOX; } + @Override + protected int getLeftMargin() { + return 0; + } + + @Override + protected int getTabGap() { + return 0; + } + + @Override + protected int getLayoutSize() { + return 0; + } + + @Override + protected int getTabRightPadding() { + return 0; + } + /** * The content border insets are used to create a separator between tabs and content. * If client property JTabbedPane.hasFullBorder is true, then the content border insets @@ -430,4 +477,103 @@ public class FlatJideTabbedPaneUI int run = getRunForTab( _tabPane.getTabCount(), tabIndex ); return lastTabInRun( _tabPane.getTabCount(), run ) == tabIndex; } + + @Override + public void ensureCloseButtonCreated() { + super.ensureCloseButtonCreated(); + + if( _closeButtons == null ) + return; + + // make sure that close buttons use our icon and do not fill background + for( JButton closeButton : _closeButtons ) { + if( closeButton.getIcon() != closeIcon ) + closeButton.setIcon( closeIcon ); + if( closeButton.isContentAreaFilled() ) + closeButton.setContentAreaFilled( false ); + } + } + + protected void updateCloseButtonMargins() { + // scale close button margins + _closeButtonLeftMargin = scale( closeButtonLeftMarginUnscaled ); + _closeButtonRightMargin = scale( closeButtonRightMarginUnscaled ); + + // since close button size is hardcoded to 16x16 in NoFocusButton.getPreferredSize(), + // add difference between scaled and unscaled close button size to margins + int offset = (closeIcon.getIconWidth() - 16) / 2; + _closeButtonLeftMargin += offset; + _closeButtonRightMargin += offset; + } + + //---- class FlatJideTabbedPaneScrollLayout ------------------------------- + + protected class FlatJideTabbedPaneScrollLayout + extends TabbedPaneScrollLayout + { + @Override + public void layoutContainer( Container parent ) { + updateCloseButtonMargins(); + + super.layoutContainer( parent ); + + updateCloseButtons(); + } + + private void updateCloseButtons() { + if( !scrollableTabLayoutEnabled() || !isShowCloseButton() || !isShowCloseButtonOnTab() ) + return; + + for( int i = 0; i < _closeButtons.length; i++ ) { + JButton closeButton = _closeButtons[i]; + if( closeButton.getWidth() == 0 || closeButton.getHeight() == 0 ) + continue; // not visible + + closeButton.setBounds( getTabCloseBounds( i ) ); + } + } + + private Rectangle getTabCloseBounds( int tabIndex ) { + int iconWidth = closeIcon.getIconWidth(); + int iconHeight = closeIcon.getIconHeight(); + Rectangle tabRect = _rects[tabIndex]; + Insets tabInsets = getTabInsets( _tabPane.getTabPlacement(), tabIndex ); + + // use one-third of right/left tab insets as gap between tab text and close button + if( _tabPane.getTabPlacement() == JideTabbedPane.TOP || _tabPane.getTabPlacement() == JideTabbedPane.BOTTOM ) { + return new Rectangle( + _tabPane.getComponentOrientation().isLeftToRight() + ? (tabRect.x + tabRect.width - (tabInsets.right / 3 * 2) - iconWidth) + : (tabRect.x + (tabInsets.left / 3 * 2)), + tabRect.y + (tabRect.height - iconHeight) / 2, + iconWidth, + iconHeight ); + } else { + return new Rectangle( + tabRect.x + (tabRect.width - iconWidth) / 2, + tabRect.y + tabRect.height - (tabInsets.bottom / 3 * 2) - iconHeight, + iconWidth, + iconHeight ); + } + } + } + + //---- class FlatJideTabAreaArrowIcon ------------------------------------- + + protected class FlatJideTabCloseIcon + extends FlatTabbedPaneCloseIcon + { + @Override + public void paintIcon( Component c, Graphics g, int x, int y ) { + NoFocusButton button = (NoFocusButton) c; + + if( _tabPane.isShowCloseButtonOnMouseOver() && !button.isMouseOver() ) { + Object property = _tabPane.getClientProperty( "JideTabbedPane.mouseOverTabIndex" ); + if( property instanceof Integer && button.getIndex() >= 0 && (Integer) property != button.getIndex() ) + return; + } + + super.paintIcon( c, g, x, y ); + } + } } diff --git a/flatlaf-jide-oss/src/main/resources/com/formdev/flatlaf/jideoss/FlatLaf.properties b/flatlaf-jide-oss/src/main/resources/com/formdev/flatlaf/jideoss/FlatLaf.properties index be03720a..a4c48098 100644 --- a/flatlaf-jide-oss/src/main/resources/com/formdev/flatlaf/jideoss/FlatLaf.properties +++ b/flatlaf-jide-oss/src/main/resources/com/formdev/flatlaf/jideoss/FlatLaf.properties @@ -81,3 +81,6 @@ JideTabbedPane.tabAreaInsets = $TabbedPane.tabAreaInsets JideTabbedPane.contentBorderInsets = 0,0,0,0 JideTabbedPane.tabRunOverlay = $TabbedPane.tabRunOverlay JideTabbedPane.shadow = $TabbedPane.shadow + +JideTabbedPane.closeButtonLeftMargin = 0 +JideTabbedPane.closeButtonRightMargin = 0 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 317d0fa9..a383c63e 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt @@ -489,6 +489,8 @@ JideSplitButtonUI com.formdev.flatlaf.jideoss.ui.FlatJideSplitButto #---- JideTabbedPane ---- JideTabbedPane.background #3c3f41 javax.swing.plaf.ColorUIResource [UI] +JideTabbedPane.closeButtonLeftMargin 0 +JideTabbedPane.closeButtonRightMargin 0 JideTabbedPane.contentBorderInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI] JideTabbedPane.foreground #bbbbbb javax.swing.plaf.ColorUIResource [UI] JideTabbedPane.shadow #3c3f41 javax.swing.plaf.ColorUIResource [UI] 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 899ee0ae..6f41d1e7 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt @@ -494,6 +494,8 @@ JideSplitButtonUI com.formdev.flatlaf.jideoss.ui.FlatJideSplitButto #---- JideTabbedPane ---- JideTabbedPane.background #f2f2f2 javax.swing.plaf.ColorUIResource [UI] +JideTabbedPane.closeButtonLeftMargin 0 +JideTabbedPane.closeButtonRightMargin 0 JideTabbedPane.contentBorderInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI] JideTabbedPane.foreground #000000 javax.swing.plaf.ColorUIResource [UI] JideTabbedPane.shadow #f2f2f2 javax.swing.plaf.ColorUIResource [UI] 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 7fa30e96..152930fa 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt @@ -485,6 +485,8 @@ JideSplitButtonUI com.formdev.flatlaf.jideoss.ui.FlatJideSplitButto #---- JideTabbedPane ---- JideTabbedPane.background #ccffcc javax.swing.plaf.ColorUIResource [UI] +JideTabbedPane.closeButtonLeftMargin 0 +JideTabbedPane.closeButtonRightMargin 0 JideTabbedPane.contentBorderInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI] JideTabbedPane.foreground #ff0000 javax.swing.plaf.ColorUIResource [UI] JideTabbedPane.shadow #ccffcc javax.swing.plaf.ColorUIResource [UI] diff --git a/flatlaf-testing/dumps/uidefaults/JIDE-FlatDarkLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/JIDE-FlatDarkLaf_1.8.0_202.txt index c6a60a4f..9c228198 100644 --- a/flatlaf-testing/dumps/uidefaults/JIDE-FlatDarkLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/JIDE-FlatDarkLaf_1.8.0_202.txt @@ -108,12 +108,10 @@ + JideTabbedPane.buttonMargin 5 + JideTabbedPane.buttonSize 18 + JideTabbedPane.closeButtonAlignment 11 -+ JideTabbedPane.closeButtonLeftMargin 2 + JideTabbedPane.closeButtonMargin 2 + JideTabbedPane.closeButtonMarginHorizonal 3 + JideTabbedPane.closeButtonMarginSize 6 + JideTabbedPane.closeButtonMarginVertical 3 -+ JideTabbedPane.closeButtonRightMargin 2 + JideTabbedPane.compressedStyleCloseButtonMarginHorizontal 0 + JideTabbedPane.compressedStyleCloseButtonMarginVertical 0 + JideTabbedPane.compressedStyleIconMargin 12 diff --git a/flatlaf-testing/dumps/uidefaults/JIDE-FlatLightLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/JIDE-FlatLightLaf_1.8.0_202.txt index 24f9de05..57f4bb8f 100644 --- a/flatlaf-testing/dumps/uidefaults/JIDE-FlatLightLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/JIDE-FlatLightLaf_1.8.0_202.txt @@ -108,12 +108,10 @@ + JideTabbedPane.buttonMargin 5 + JideTabbedPane.buttonSize 18 + JideTabbedPane.closeButtonAlignment 11 -+ JideTabbedPane.closeButtonLeftMargin 2 + JideTabbedPane.closeButtonMargin 2 + JideTabbedPane.closeButtonMarginHorizonal 3 + JideTabbedPane.closeButtonMarginSize 6 + JideTabbedPane.closeButtonMarginVertical 3 -+ JideTabbedPane.closeButtonRightMargin 2 + JideTabbedPane.compressedStyleCloseButtonMarginHorizontal 0 + JideTabbedPane.compressedStyleCloseButtonMarginVertical 0 + JideTabbedPane.compressedStyleIconMargin 12 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 bf51c220..4cafd761 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 @@ -343,6 +343,8 @@ JideSplitButton.selectionForeground JideSplitButton.textIconGap JideSplitButtonUI JideTabbedPane.background +JideTabbedPane.closeButtonLeftMargin +JideTabbedPane.closeButtonRightMargin JideTabbedPane.contentBorderInsets JideTabbedPane.foreground JideTabbedPane.shadow