From e69ea7d525d0cef9a85f09fe34d2682aa2f84563 Mon Sep 17 00:00:00 2001 From: weisj Date: Sat, 28 Mar 2020 23:57:24 +0100 Subject: [PATCH] Added option to center tabs in JTabbedPane. --- .../darklaf/ui/tabbedpane/DarkHandler.java | 3 + .../ui/tabbedpane/DarkTabbedPaneLayout.java | 18 ++++ .../DarkTabbedPaneScrollLayout.java | 27 +++++ .../ui/tabbedpane/DarkTabbedPaneUI.java | 6 ++ .../ui/tabbedpane/TabbedPaneLayout.java | 5 +- .../ui/tabbedpane/TabbedPaneScrollLayout.java | 101 +----------------- 6 files changed, 59 insertions(+), 101 deletions(-) diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkHandler.java b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkHandler.java index 4cab2577..f34a8545 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkHandler.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkHandler.java @@ -154,6 +154,9 @@ public class DarkHandler extends TabbedPaneHandler { ui.westComp = null; } ui.tabPane.doLayout(); + } else if (DarkTabbedPaneUI.KEY_CENTER_TABS.endsWith(key)) { + ui.tabPane.doLayout(); + ui.tabPane.repaint(); } } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneLayout.java b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneLayout.java index 4fd6fbd7..fd4afd6c 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneLayout.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneLayout.java @@ -35,6 +35,24 @@ public class DarkTabbedPaneLayout extends TabbedPaneLayout { this.ui = ui; } + + @Override + protected void centerTabs(final int tabPlacement, final int tabCount, final int returnAt) { + if (ui.runCount == 1 && Boolean.TRUE.equals(ui.tabPane.getClientProperty(DarkTabbedPaneUI.KEY_CENTER_TABS))) { + if (ui.isHorizontalTabPlacement()) { + int shift = (returnAt - (ui.rects[tabCount - 1].x + ui.rects[tabCount - 1].width)) / 2; + for (int i = 0; i < tabCount; i++) { + ui.rects[i].x += shift; + } + } else { + int shift = (returnAt - (ui.rects[tabCount - 1].y + ui.rects[tabCount - 1].height)) / 2; + for (int i = 0; i < tabCount; i++) { + ui.rects[i].y += shift; + } + } + } + } + /* * Non scroll-layout */ diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneScrollLayout.java b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneScrollLayout.java index b18cb0d9..86eaff92 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneScrollLayout.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneScrollLayout.java @@ -325,6 +325,12 @@ public class DarkTabbedPaneScrollLayout extends TabbedPaneScrollLayout { shiftBoundsToVisibleX(selectedBounds, leftMargin, returnAt, tabCount); } restoreHiddenTabsX(leftMargin, returnAt, tabCount); + + if (ui.minVisible == 0 && ui.maxVisible == tabCount - 1 + && Boolean.TRUE.equals(ui.tabPane.getClientProperty(DarkTabbedPaneUI.KEY_CENTER_TABS))) { + adjustForCenterX(leftMargin, returnAt, tabCount); + } + if (tabsButton.isVisible() && ui.tabPane.getSelectedIndex() < ui.maxVisible) { //Shift again. Hiding the the tab button might reveal the last tab. //Only do this if the last visible tab is not currently selected. @@ -339,6 +345,7 @@ public class DarkTabbedPaneScrollLayout extends TabbedPaneScrollLayout { adjustForDropX(leftMargin, returnAt, tabCount); layoutMoreTabsButton(tabCount); + commitShiftX(ui.currentShiftXTmp, tabCount); ui.currentShiftX = ui.currentShiftXTmp; @@ -371,6 +378,12 @@ public class DarkTabbedPaneScrollLayout extends TabbedPaneScrollLayout { shiftBoundsToVisibleY(selectedBounds, topMargin, returnAt, tabCount); } restoreHiddenTabsY(topMargin, returnAt, tabCount); + + if (ui.minVisible == 0 && ui.maxVisible == tabCount - 1 + && Boolean.TRUE.equals(ui.tabPane.getClientProperty(DarkTabbedPaneUI.KEY_CENTER_TABS))) { + adjustForCenterY(topMargin, returnAt, tabCount); + } + if (tabsButton.isVisible() && ui.tabPane.getSelectedIndex() < ui.maxVisible) { shiftTabsY(0, topMargin, bottomMargin, tabCount, false); if (ui.minVisible > 0 || ui.maxVisible < tabCount - 1) { @@ -390,6 +403,20 @@ public class DarkTabbedPaneScrollLayout extends TabbedPaneScrollLayout { ui.tabScroller.tabPanel.setPreferredSize(tabBounds.getSize()); } + @Override + protected void centerTabs(final int tabPlacement, final int tabCount, final int returnAt) { + // Do nothing. + } + + protected void adjustForCenterX(final int leftMargin, final int returnAt, final int tabCount) { + int shift = (returnAt - (ui.rects[tabCount - 1].x + ui.rects[tabCount - 1].width)) / 2; + shiftTabsX(shift, 0, returnAt, tabCount - 1, true); + } + + protected void adjustForCenterY(final int topMargin, final int returnAt, final int tabCount) { + int shift = (returnAt - (ui.rects[tabCount - 1].y + ui.rects[tabCount - 1].height)) / 2; + shiftTabsY(shift, 0, returnAt, tabCount - 1, true); + } @Override protected int preferredTabAreaWidth(final int tabPlacement, final int height) { diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneUI.java index 6d7ec667..4953572a 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneUI.java @@ -46,6 +46,12 @@ import java.util.function.Consumer; public class DarkTabbedPaneUI extends DarkTabbedPaneUIBridge { protected static final String KEY_PREFIX = "JTabbedPane."; + /* + * Centering tabs only applies if in + * - WRAP_TAB_LAYOUT there is only one tab run. + * - SCROLL_TAB_LAYOUT the viewport doesn't need to be scrolled. + */ + public static final String KEY_CENTER_TABS = KEY_PREFIX + "centerTabs"; public static final String KEY_DND = KEY_PREFIX + "dndEnabled"; public static final String KEY_NORTH_COMP = KEY_PREFIX + "northComponent"; public static final String KEY_WEST_COMP = KEY_PREFIX + "westComponent"; diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneLayout.java b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneLayout.java index 8091ec91..c697974d 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneLayout.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneLayout.java @@ -30,7 +30,7 @@ import java.awt.*; * This class should be treated as a "protected" inner class. Instantiate it only within subclasses of * BasicTabbedPaneUI. */ -public class TabbedPaneLayout implements LayoutManager { +public abstract class TabbedPaneLayout implements LayoutManager { protected final DarkTabbedPaneUIBridge ui; @@ -395,6 +395,7 @@ public class TabbedPaneLayout implements LayoutManager { } } + centerTabs(tabPlacement, tabCount, returnAt); // Pad the selected tab so that it appears raised in front padSelectedTab(tabPlacement, selectedIndex); @@ -409,6 +410,8 @@ public class TabbedPaneLayout implements LayoutManager { } } + protected abstract void centerTabs(final int tabPlacement, final int tabCount, int returnAt); + /** * Normalizes the tab runs. * diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneScrollLayout.java b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneScrollLayout.java index 09b78b6b..769dd938 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneScrollLayout.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneScrollLayout.java @@ -23,9 +23,6 @@ */ package com.github.weisj.darklaf.ui.tabbedpane; -import javax.swing.*; -import java.awt.*; - abstract class TabbedPaneScrollLayout extends TabbedPaneLayout { @@ -33,103 +30,7 @@ abstract class TabbedPaneScrollLayout extends TabbedPaneLayout { super(ui); } - protected void calculateTabRects(final int tabPlacement, final int tabCount) { - FontMetrics metrics = ui.getFontMetrics(); - Dimension size = ui.tabPane.getSize(); - Insets insets = ui.tabPane.getInsets(); - Insets tabAreaInsets = ui.getTabAreaInsets(tabPlacement); - int fontHeight = metrics.getHeight(); - int selectedIndex = ui.tabPane.getSelectedIndex(); - int i; - boolean verticalTabRuns = (tabPlacement == SwingConstants.LEFT || tabPlacement == SwingConstants.RIGHT); - boolean leftToRight = ui.tabPane.getComponentOrientation().isLeftToRight(); - int x = tabAreaInsets.left; - int y = tabAreaInsets.top; - int totalWidth = 0; - int totalHeight = 0; - - // - // Calculate bounds within which a tab run must fit - // - switch (tabPlacement) { - case SwingConstants.LEFT: - case SwingConstants.RIGHT: - ui.maxTabWidth = ui.calculateMaxTabWidth(tabPlacement); - break; - case SwingConstants.BOTTOM: - case SwingConstants.TOP: - default: - ui.maxTabHeight = ui.calculateMaxTabHeight(tabPlacement); - } - - ui.runCount = 0; - ui.selectedRun = -1; - - if (tabCount == 0) { - return; - } - - ui.selectedRun = 0; - ui.runCount = 1; - - // Run through tabs and lay them out in a single run - Rectangle rect; - for (i = 0; i < tabCount; i++) { - rect = ui.rects[i]; - - if (!verticalTabRuns) { - // Tabs on TOP or BOTTOM.... - if (i > 0) { - rect.x = ui.rects[i - 1].x + ui.rects[i - 1].width; - } else { - ui.tabRuns[0] = 0; - ui.maxTabWidth = 0; - totalHeight += ui.maxTabHeight; - rect.x = x; - } - rect.width = ui.calculateTabWidth(tabPlacement, i, metrics); - totalWidth = rect.x + rect.width; - ui.maxTabWidth = Math.max(ui.maxTabWidth, rect.width); - - rect.y = y; - rect.height = ui.maxTabHeight/* - 2*/; - - } else { - // Tabs on LEFT or RIGHT... - if (i > 0) { - rect.y = ui.rects[i - 1].y + ui.rects[i - 1].height; - } else { - ui.tabRuns[0] = 0; - ui.maxTabHeight = 0; - totalWidth = ui.maxTabWidth; - rect.y = y; - } - rect.height = ui.calculateTabHeight(tabPlacement, i, fontHeight); - totalHeight = rect.y + rect.height; - ui.maxTabHeight = Math.max(ui.maxTabHeight, rect.height); - - rect.x = x; - rect.width = ui.maxTabWidth/* - 2*/; - - } - } - - if (ui.tabsOverlapBorder) { - // Pad the selected tab so that it appears raised in front - padSelectedTab(tabPlacement, selectedIndex); - } - - // if right to left and tab placement on the top or - // the bottom, flip x positions and adjust by widths - if (!leftToRight && !verticalTabRuns) { - int rightMargin = size.width - - (insets.right + tabAreaInsets.right); - for (i = 0; i < tabCount; i++) { - ui.rects[i].x = rightMargin - ui.rects[i].x - ui.rects[i].width; - } - } - ui.tabScroller.tabPanel.setPreferredSize(new Dimension(totalWidth, totalHeight)); - } + protected abstract void calculateTabRects(final int tabPlacement, final int tabCount); protected int preferredTabAreaWidth(final int tabPlacement, final int height) { return ui.calculateMaxTabWidth(tabPlacement);