
com.github.weisj.darklaf.ui.tabbedpane.DarkTabbedPaneScrollLayout Maven / Gradle / Ivy
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.weisj.darklaf.ui.tabbedpane;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.util.function.Function;
public class DarkTabbedPaneScrollLayout extends TabbedPaneScrollLayout {
private DarkTabbedPaneUI ui;
public DarkTabbedPaneScrollLayout(final DarkTabbedPaneUI ui) {
super(ui);
this.ui = ui;
}
public void layoutContainer(final Container parent) {
int tabPlacement = ui.tabPane.getTabPlacement();
Insets insets = ui.tabPane.getInsets();
Insets tabAreaInsets = ui.getTabAreaInsets(tabPlacement);
int selectedIndex = ui.tabPane.getSelectedIndex();
Component visibleComponent = ui.getVisibleComponent();
calculateLayoutInfo();
Component selectedComponent = null;
if (selectedIndex < 0) {
if (visibleComponent != null) {
// The last tab was removed, so remove the component
ui.setVisibleComponent(null);
}
} else {
selectedComponent = ui.tabPane.getComponentAt(selectedIndex);
}
if (ui.tabPane.getTabCount() == 0) {
ui.scrollableTabSupport.hideMoreTabsButton();
return;
}
boolean shouldChangeFocus = false;
// In order to allow programs to use a single component
// as the display for multiple tabs, we will not change
// the visible component if the currently selected tab
// has a null component. This is a bit dicey, as we don't
// explicitly state we support this in the spec, but since
// programs are now depending on this, we're making it work.
//
if (selectedComponent != null) {
if (selectedComponent != visibleComponent &&
visibleComponent != null) {
Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
if (owner != null && SwingUtilities.isDescendingFrom(owner, visibleComponent)) {
shouldChangeFocus = true;
}
}
ui.setVisibleComponent(selectedComponent);
}
int tx, ty, tw, th; // tab area bounds
int cx, cy, cw, ch; // content area bounds
Insets contentInsets = ui.getContentBorderInsets(tabPlacement);
Rectangle bounds = ui.tabPane.getBounds();
int numChildren = ui.tabPane.getComponentCount();
if (numChildren > 0) {
switch (tabPlacement) {
case SwingConstants.LEFT:
tw = ui.calculateTabAreaWidth(tabPlacement, ui.runCount, ui.maxTabWidth);
th = bounds.height - insets.top - insets.bottom - tabAreaInsets.top - tabAreaInsets.bottom;
tx = insets.left + tabAreaInsets.left;
ty = insets.top + tabAreaInsets.top;
cx = insets.left + tw + contentInsets.left + tabAreaInsets.left + tabAreaInsets.right;
cy = insets.top + contentInsets.top;
cw = bounds.width - insets.left - insets.right - tw - contentInsets.left - contentInsets.right
- tabAreaInsets.left - tabAreaInsets.right;
ch = bounds.height - insets.top - insets.bottom - contentInsets.top - contentInsets.bottom;
tw -= tabAreaInsets.left + tabAreaInsets.right;
break;
case SwingConstants.RIGHT:
tw = ui.calculateTabAreaWidth(tabPlacement, ui.runCount, ui.maxTabWidth);
th = bounds.height - insets.top - insets.bottom - tabAreaInsets.top - tabAreaInsets.bottom;
tx = bounds.width - insets.right - tw + tabAreaInsets.left;
ty = insets.top + tabAreaInsets.top;
cx = insets.left + contentInsets.left;
cy = insets.top + contentInsets.top;
cw = bounds.width - insets.left - insets.right - tw - contentInsets.left - contentInsets.right;
ch = bounds.height - insets.top - insets.bottom - contentInsets.top - contentInsets.bottom;
tw -= tabAreaInsets.left + tabAreaInsets.right;
break;
case SwingConstants.BOTTOM:
tw = bounds.width - insets.left - insets.right - tabAreaInsets.left - tabAreaInsets.right;
th = ui.calculateTabAreaHeight(tabPlacement, ui.runCount, ui.maxTabHeight);
tx = insets.left + tabAreaInsets.left;
ty = bounds.height - insets.bottom - th + tabAreaInsets.top;
cx = insets.left + contentInsets.left;
cy = insets.top + contentInsets.top;
cw = bounds.width - insets.left - insets.right - contentInsets.left - contentInsets.right;
ch = bounds.height - insets.top - insets.bottom - th - contentInsets.top - contentInsets.bottom;
th -= tabAreaInsets.top + tabAreaInsets.bottom;
break;
default:
tw = bounds.width - insets.left - insets.right - tabAreaInsets.left - tabAreaInsets.right;
th = ui.calculateTabAreaHeight(tabPlacement, ui.runCount, ui.maxTabHeight);
tx = insets.left + tabAreaInsets.left;
ty = insets.top + tabAreaInsets.top;
cx = insets.left + contentInsets.left;
cy = insets.top + th + contentInsets.top;
cw = bounds.width - insets.left - insets.right - contentInsets.left - contentInsets.right;
ch = bounds.height - insets.top - insets.bottom - th - contentInsets.top - contentInsets.bottom;
th -= tabAreaInsets.top + tabAreaInsets.bottom;
break;
}
JButton moreTabs = ui.scrollableTabSupport.moreTabsButton;
JComponent newTab = ui.scrollableTabSupport.newTabButton;
for (int i = 0; i < numChildren; i++) {
Component child = ui.tabPane.getComponent(i);
if (ui.tabScroller != null && child == ui.tabScroller.viewport) {
int vw = tw;
int vh = th;
Dimension butSize = moreTabs.isVisible()
? moreTabs.getPreferredSize()
: new Dimension(0, 0);
boolean showNewTabButton = newTab.isVisible() && newTab.getParent() == ui.tabPane;
Dimension butSize2 = showNewTabButton
? newTab.getPreferredSize()
: new Dimension(0, 0);
boolean leftToRight = ui.tabPane.getComponentOrientation().isLeftToRight();
if (tabPlacement == SwingConstants.LEFT || tabPlacement == SwingConstants.RIGHT) {
vh = th - butSize.height - butSize2.height;
moreTabs.setBounds(tx, ty + vh + butSize2.height, ui.maxTabWidth, butSize.height);
if (showNewTabButton) {
newTab.setBounds(tx, ty + vh, ui.maxTabWidth, butSize2.height);
}
} else {
if (leftToRight) {
vw = tw - butSize.width - butSize2.width;
moreTabs.setBounds(tx + vw + butSize2.width, ty, butSize.width, ui.maxTabHeight);
if (showNewTabButton) {
newTab.setBounds(tx + vw, ty, butSize2.width, ui.maxTabHeight);
}
} else {
vw = tw - butSize.width - butSize2.width;
moreTabs.setBounds(tx, ty, butSize.width, ui.maxTabHeight);
if (showNewTabButton) {
newTab.setBounds(tx + butSize.width, ty, butSize2.width, ui.maxTabHeight);
}
tx += butSize.width + butSize2.width;
}
}
child.setBounds(tx, ty, vw, vh);
} else {
int tabHeight = ui.maxTabHeight + tabAreaInsets.top + tabAreaInsets.bottom;
int tabWidth = ui.maxTabWidth + tabAreaInsets.left + tabAreaInsets.right;
int compHeight = ch;
int compY = cy;
if (ui.northComp != null) {
int nh = ui.northComp.getPreferredSize().height;
compY -= nh;
compHeight += nh;
}
if (ui.southComp != null) {
compHeight += ui.southComp.getPreferredSize().height;
}
if (child == ui.leadingComp && ui.leadingComp != null) {
ui.layoutLeadingComponent(child, tabWidth, tabHeight, insets, tx, ty, tabPlacement);
} else if (child == ui.trailingComp && ui.trailingComp != null) {
ui.layoutTrailingComponent(child, tabWidth, tabHeight, insets, tx, ty, tw, th, tabPlacement);
} else if (child == ui.northComp && ui.northComp != null) {
ui.northComp.setBounds(cx, cy - ui.northComp.getPreferredSize().height,
cw, ui.northComp.getPreferredSize().height);
} else if (child == ui.southComp && ui.southComp != null) {
ui.southComp.setBounds(cx, cy + ch, cw, ui.southComp.getPreferredSize().height);
} else if (child == ui.eastComp && ui.eastComp != null) {
ui.eastComp.setBounds(cx + cw, compY, ui.eastComp.getPreferredSize().width, compHeight);
} else if (child == ui.westComp && ui.westComp != null) {
ui.westComp.setBounds(cx - ui.westComp.getPreferredSize().width, compY,
ui.westComp.getPreferredSize().width, compHeight);
} else if (child != moreTabs && child != newTab) {
child.setBounds(cx, cy, cw, ch);
}
}
}
layoutTabComponents();
if (shouldChangeFocus) {
if (!ui.requestFocusForVisibleComponent()) {
ui.tabPane.requestFocus();
}
}
}
}
@Override
protected void layoutTabComponents() {
ui.layoutTabComponents();
}
@Override
protected Dimension calculateSize(final boolean minimum) {
int tabPlacement = ui.tabPane.getTabPlacement();
Insets insets = ui.tabPane.getInsets();
Insets contentInsets = ui.getContentBorderInsets(tabPlacement);
Insets tabAreaInsets = ui.getTabAreaInsets(tabPlacement);
int height = 0;
int width = 0;
int cWidth = 0;
int cHeight = 0;
// Determine minimum size required to display largest
// child in each dimension
//
for (int i = 0; i < ui.tabPane.getTabCount(); i++) {
Component component = ui.tabPane.getComponentAt(i);
if (component != null) {
Dimension size = minimum ? component.getMinimumSize() : component.getPreferredSize();
if (size != null) {
cHeight = Math.max(size.height, cHeight);
cWidth = Math.max(size.width, cWidth);
}
}
}
// Add content border insets to minimum size
width += cWidth;
height += cHeight;
int tabExtent;
// Calculate how much space the tabs will need, based on the
// minimum size required to display largest child + content border
//
if (ui.tabPane.getTabCount() > 0) {
if (!ui.isHorizontalTabPlacement()) {
int tabHeight = ui.calculateTabHeight(tabPlacement, ui.tabPane.getSelectedIndex(),
ui.getFontMetrics().getHeight());
if (ui.scrollableTabSupport.moreTabsButton.isVisible()) {
tabHeight += ui.scrollableTabSupport.moreTabsButton.getPreferredSize().height;
}
height = Math.max(height, tabHeight);
tabExtent = preferredTabAreaWidth(tabPlacement, height - tabAreaInsets.top - tabAreaInsets.bottom);
width += tabExtent;
} else {
int tabWidth = ui.calculateTabWidth(tabPlacement, ui.tabPane.getSelectedIndex(), ui.getFontMetrics());
if (ui.scrollableTabSupport.moreTabsButton.isVisible()) {
tabWidth += ui.scrollableTabSupport.moreTabsButton.getPreferredSize().width;
}
width = Math.max(width, tabWidth);
tabExtent = preferredTabAreaHeight(tabPlacement, width - tabAreaInsets.left - tabAreaInsets.right);
height += tabExtent;
}
}
return new Dimension(width + insets.left + insets.right + contentInsets.left + contentInsets.right,
height + insets.bottom + insets.top + contentInsets.top + contentInsets.bottom);
}
@SuppressWarnings("SuspiciousNameCombination")
@Override
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);
boolean verticalTabRuns = !ui.isHorizontalTabPlacement();
boolean leftToRight = ui.tabPane.getComponentOrientation().isLeftToRight();
if (!ui.isHorizontalTabPlacement()) {
ui.maxTabWidth = ui.calculateMaxTabWidth(tabPlacement);
} else {
ui.maxTabHeight = ui.calculateMaxTabHeight(tabPlacement);
}
ui.runCount = 0;
ui.selectedRun = -1;
if (tabCount == 0) return;
ui.selectedRun = 0;
ui.runCount = 1;
Rectangle tabBounds = new Rectangle(0, 0, 0, 0);
for (int i = 0; i < tabCount; i++) {
calculateRect(i, tabBounds, metrics, verticalTabRuns, tabPlacement);
}
JButton tabsButton = ui.scrollableTabSupport.moreTabsButton;
Rectangle selectedBounds = ui.tabPane.getSelectedIndex() > 0
? new Rectangle(ui.rects[ui.tabPane.getSelectedIndex()])
: new Rectangle(0, 0, 0, 0);
if (!verticalTabRuns) {
int rightMargin = size.width - (insets.right + tabAreaInsets.right
+ insets.left + tabAreaInsets.left);
Point p = getMargins(tabPlacement);
int leftMargin = p.x;
int returnAt = p.y;
ui.currentShiftXTmp = ui.currentShiftX;
shiftTabsX(0, leftMargin, returnAt, tabCount, false);
if (!(ui.minVisible == ui.maxVisible && ui.minVisible == ui.tabPane.getSelectedIndex())) {
selectedBounds.x += ui.currentShiftXTmp;
shiftBoundsToVisibleX(selectedBounds, leftMargin, returnAt, tabCount);
}
restoreHiddenTabsX(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.
//Otherwise the selected tab forces the whole tab area the jump by the width of the tab button.
int margin = returnAt + tabsButton.getPreferredSize().width;
shiftTabsX(0, leftMargin, margin, tabCount, false);
if (ui.minVisible > 0 || ui.maxVisible < tabCount - 1) {
//Tab button is still visible but may hide a further tab. restore visible bounds.
shiftTabsX(0, leftMargin, returnAt, tabCount, false);
}
}
adjustForDropX(leftMargin, returnAt, tabCount);
layoutMoreTabsButton(tabCount);
commitShiftX(ui.currentShiftXTmp, tabCount);
ui.currentShiftX = ui.currentShiftXTmp;
if (!leftToRight) {
if (tabsButton.isVisible()) {
rightMargin -= tabsButton.getWidth();
}
JComponent newTabButton = ui.scrollableTabSupport.newTabButton;
if (newTabButton.isVisible() && newTabButton.getParent() == ui.tabPane) {
rightMargin -= newTabButton.getWidth();
}
for (int i = 0; i < tabCount; i++) {
ui.rects[i].x = rightMargin - ui.rects[i].x - ui.rects[i].width;
}
}
if (ui.scrollableTabSupport.newTabButton.isVisible()) {
layoutNewTabButton(true, leftToRight, leftMargin, returnAt, tabCount);
}
} else {
int bottomMargin = size.height - (insets.bottom + tabAreaInsets.bottom
+ insets.top + tabAreaInsets.top);
Point p = getMargins(tabPlacement);
int topMargin = p.x;
int returnAt = p.y;
ui.currentShiftYTmp = ui.currentShiftY;
shiftTabsY(0, topMargin, returnAt, tabCount, false);
if (!(ui.minVisible == ui.maxVisible && ui.minVisible == ui.tabPane.getSelectedIndex())) {
selectedBounds.y += ui.currentShiftYTmp;
shiftBoundsToVisibleY(selectedBounds, topMargin, returnAt, tabCount);
}
restoreHiddenTabsY(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) {
shiftTabsY(0, topMargin, returnAt, tabCount, false);
}
}
adjustForDropY(topMargin, returnAt, tabCount);
layoutMoreTabsButton(tabCount);
commitShiftY(ui.currentShiftYTmp, tabCount);
ui.currentShiftY = ui.currentShiftYTmp;
if (ui.scrollableTabSupport.newTabButton.isVisible()) {
layoutNewTabButton(false, leftToRight, topMargin, returnAt, tabCount);
}
}
ui.tabScroller.tabPanel.setPreferredSize(tabBounds.getSize());
ui.tabScroller.tabPanel.invalidate();
}
@Override
protected int preferredTabAreaWidth(final int tabPlacement, final int height) {
return ui.calculateMaxTabWidth(tabPlacement);
}
@Override
protected int preferredTabAreaHeight(final int tabPlacement, final int width) {
return ui.calculateMaxTabHeight(tabPlacement);
}
@SuppressWarnings("SuspiciousNameCombination")
@NotNull
@Contract("_ -> new")
protected Point getMargins(final int tabPlacement) {
Dimension size = ui.tabPane.getSize();
Insets insets = ui.tabPane.getInsets();
Insets tabAreaInsets = ui.getTabAreaInsets(tabPlacement);
JButton tabsButton = ui.scrollableTabSupport.moreTabsButton;
JComponent newTabsButton = ui.scrollableTabSupport.newTabButton;
if (ui.isHorizontalTabPlacement()) {
int leftMargin = 0;
int returnAt = size.width - (insets.right + tabAreaInsets.right
+ insets.left + tabAreaInsets.left);
if (tabsButton.isVisible()) {
returnAt -= tabsButton.getPreferredSize().width;
}
if (newTabsButton.isVisible() && newTabsButton.getParent() == ui.tabPane) {
returnAt -= newTabsButton.getPreferredSize().width;
}
return new Point(leftMargin, returnAt);
} else {
int topMargin = 0;
int returnAt = size.height - (insets.bottom + tabAreaInsets.bottom
+ insets.top + tabAreaInsets.top);
if (tabsButton.isVisible()) {
returnAt -= tabsButton.getPreferredSize().height;
}
if (newTabsButton.isVisible() && newTabsButton.getParent() == ui.tabPane) {
returnAt -= newTabsButton.getPreferredSize().height;
}
return new Point(topMargin, returnAt);
}
}
protected void adjustForDropX(final int minX, final int maxX, final int tabCount) {
if (ui.dropSourceIndex >= 0 && ui.dropSourceIndex < ui.tabPane.getTabCount()) {
//Hide the source tab.
int shift = ui.rects[ui.dropSourceIndex].width;
ui.rects[ui.dropSourceIndex].setSize(0, 0);
commitShiftX(ui.dropSourceIndex + 1, tabCount - 1, -1 * shift, tabCount);
}
if (ui.sourceEqualsTarget && ui.dropTargetIndex >= 0 && ui.dropTargetIndex < ui.tabPane.getTabCount()) {
commitShiftX(ui.dropTargetIndex, tabCount - 1, ui.dropRect.width, tabCount);
}
shiftTabsX(0, minX, maxX, tabCount, false);
}
protected void layoutNewTabButton(final boolean horizontal, final boolean leftToRight,
final int minVal, final int maxVal, final int tabCount) {
JComponent button = ui.scrollableTabSupport.newTabButton;
Dimension buttonBounds = button.getPreferredSize();
if (horizontal) {
if (leftToRight) {
if (ui.rects[tabCount - 1].x + ui.rects[tabCount - 1].width + buttonBounds.width > maxVal) {
ui.tabPane.add(button);
} else {
ui.scrollableTabSupport.tabPanel.add(button);
}
} else {
int x = ui.rects[tabCount - 1].x;
if (x - buttonBounds.width < minVal) {
ui.tabPane.add(button);
} else {
ui.scrollableTabSupport.tabPanel.add(button);
}
}
} else {
if (ui.rects[tabCount - 1].y + ui.rects[tabCount - 1].height + buttonBounds.height > maxVal) {
ui.tabPane.add(button);
} else {
ui.scrollableTabSupport.tabPanel.add(button);
}
}
}
protected void commitShiftX(final int shift, final int tabCount) {
commitShiftX(0, tabCount - 1, shift, tabCount);
}
protected void commitShiftX(final int low, final int high, final int shift, final int tabCount) {
for (int i = Math.max(low, 0); i <= Math.min(high, tabCount - 1); i++) {
ui.rects[i].x += shift;
}
}
protected void commitShiftY(final int shift, final int tabCount) {
commitShiftY(0, tabCount - 1, shift, tabCount);
}
protected void commitShiftY(final int low, final int high, final int shift, final int tabCount) {
for (int i = Math.max(low, 0); i <= Math.min(high, tabCount - 1); i++) {
ui.rects[i].y += shift;
}
}
protected void shiftBoundsToVisibleX(@NotNull final Rectangle selectedBounds, final int leftMargin,
final int rightMargin, final int tabCount) {
if (selectedBounds.x + selectedBounds.width > rightMargin) {
//SelectedTab is not fully visible. Covered on right side.
shiftTabsX(rightMargin - selectedBounds.x - selectedBounds.width,
leftMargin, rightMargin, tabCount, true);
} else if (selectedBounds.x < leftMargin) {
//SelectedTab is not fully visible. Covered on left side.
shiftTabsX(-selectedBounds.x + leftMargin, leftMargin, rightMargin, tabCount, true);
}
}
protected void shiftBoundsToVisibleY(@NotNull final Rectangle selectedBounds, final int topMargin,
final int bottomMargin, final int tabCount) {
if (selectedBounds.y + selectedBounds.height > bottomMargin) {
//SelectedTab is not fully visible. Covered on right side.
shiftTabsY(bottomMargin - selectedBounds.y - selectedBounds.height,
topMargin, bottomMargin, tabCount, true);
} else if (selectedBounds.y < topMargin) {
//SelectedTab is not fully visible. Covered on left side.
shiftTabsY(-selectedBounds.y + topMargin,
topMargin, bottomMargin, tabCount, true);
}
}
protected void calculateRect(final int i, final Rectangle tabBounds, final FontMetrics metrics,
final boolean verticalTabRuns, final int tabPlacement) {
Rectangle rect = ui.rects[i];
if (!verticalTabRuns) {
if (i > 0) {
rect.x = ui.rects[i - 1].x + ui.rects[i - 1].width;
} else {
ui.tabRuns[0] = 0;
ui.maxTabWidth = 0;
tabBounds.height = ui.maxTabHeight;
rect.x = tabBounds.x;
}
rect.width = ui.calculateTabWidth(tabPlacement, i, metrics);
tabBounds.width = rect.x + rect.width;
ui.maxTabWidth = Math.max(ui.maxTabWidth, rect.width);
rect.y = tabBounds.y;
rect.height = ui.maxTabHeight;
} else {
if (i > 0) {
rect.y = ui.rects[i - 1].y + ui.rects[i - 1].height;
} else {
ui.tabRuns[0] = 0;
ui.maxTabHeight = 0;
tabBounds.width = ui.maxTabWidth;
rect.y = tabBounds.y;
}
rect.height = ui.calculateTabHeight(tabPlacement, i, metrics.getHeight());
tabBounds.height = rect.y + rect.height;
ui.maxTabHeight = Math.max(ui.maxTabHeight, rect.height);
rect.x = tabBounds.x;
rect.width = ui.maxTabWidth;
}
}
protected void restoreHiddenTabsX(final int minX, final int maxX, final int tabCount) {
if (ui.maxVisible < 0 || ui.maxVisible >= tabCount) return;
int space = Math.max(maxX - ui.rects[ui.maxVisible].x - ui.rects[ui.maxVisible].width - ui.currentShiftXTmp, 0);
int shift = Math.min(minX - ui.rects[0].x - ui.currentShiftXTmp, space);
shiftTabsX(shift, minX, maxX, tabCount, true);
}
protected void restoreHiddenTabsY(final int minY, final int maxY, final int tabCount) {
if (ui.maxVisible < 0 || ui.maxVisible >= tabCount) return;
int space = Math.max(maxY - ui.rects[ui.maxVisible].y - ui.rects[ui.maxVisible].height - ui.currentShiftYTmp, 0);
int shift = Math.min(minY - ui.rects[0].y - ui.currentShiftYTmp, space);
shiftTabsY(shift, minY, maxY, tabCount, true);
}
protected void adjustForDropY(final int minY, final int maxY, final int tabCount) {
if (ui.dropSourceIndex >= 0 && ui.dropSourceIndex < ui.tabPane.getTabCount()) {
//Hide the source tab.
int shift = ui.rects[ui.dropSourceIndex].height;
ui.rects[ui.dropSourceIndex].setSize(0, 0);
commitShiftY(ui.dropSourceIndex + 1, tabCount - 1, -1 * shift, tabCount);
}
if (ui.sourceEqualsTarget && ui.dropTargetIndex >= 0 && ui.dropTargetIndex < ui.tabPane.getTabCount()) {
commitShiftY(ui.dropTargetIndex, tabCount - 1, ui.dropRect.height, tabCount);
}
shiftTabsY(0, minY, maxY, tabCount, false);
}
@SuppressWarnings("SuspiciousNameCombination")
public void updateVisibleRange(final int tapPlacement) {
Point p = getMargins(tapPlacement);
if (ui.isHorizontalTabPlacement()) {
shiftTabsX(0, p.x, p.y, ui.tabPane.getTabCount(), false);
} else {
shiftTabsY(0, p.x, p.y, ui.tabPane.getTabCount(), false);
}
}
protected void layoutMoreTabsButton(final int tabCount) {
final JButton button = ui.scrollableTabSupport.moreTabsButton;
if (ui.minVisible > 0 || ui.maxVisible < tabCount - 1) {
if (ui.scrollableTabSupport.moreTabsButton.isVisible()) {
if (ui.minVisible != ui.minVisibleOld || ui.maxVisible != ui.maxVisibleOld) {
ui.scrollableTabSupport.showMoreTabsButton();
}
} else {
ui.scrollableTabSupport.showMoreTabsButton();
}
// Update old values.
ui.minVisibleOld = ui.minVisible;
ui.maxVisibleOld = ui.maxVisible;
} else if (button.isVisible()) {
ui.scrollableTabSupport.hideMoreTabsButton();
}
}
protected void shiftTabsX(final int shift, final int minX, final int returnAt,
final int tabCount, final boolean updateShift) {
shiftTabs(shift, minX, returnAt, tabCount, updateShift, true);
}
protected void shiftTabsY(final int shift, final int minY, final int returnAt,
final int tabCount, final boolean updateShift) {
shiftTabs(shift, minY, returnAt, tabCount, updateShift, false);
}
protected void shiftTabs(final int shift, final int minVal, final int returnAt,
final int tabCount, final boolean updateShift, final boolean isX) {
int min = -1;
int max = -1;
int minStart = ui.minVisible < 0 || ui.minVisible >= tabCount ? 0 : ui.minVisible;
int maxStart = ui.maxVisible < 0 || ui.maxVisible >= tabCount ? tabCount - 1 : ui.maxVisible;
int currShift = isX ? ui.currentShiftXTmp + shift : ui.currentShiftYTmp + shift;
Function isVisible = isX ? (i -> isVisibleX(i, currShift, minVal, returnAt))
: (i -> isVisibleY(i, currShift, minVal, returnAt));
if (isVisible.apply(minStart)) {
//Descent to find minimum.
min = minStart;
for (int i = minStart - 1; i >= 0; i--) {
if (isVisible.apply(i)) {
min = i;
} else {
break;
}
}
} else {
//Ascent to find minimum.
for (int i = minStart + 1; i < tabCount; i++) {
if (isVisible.apply(i)) {
min = i;
break;
}
}
}
if (min == -1) {
min = tabCount;
}
if (isVisible.apply(maxStart)) {
//Ascent to find maximum.
max = maxStart;
for (int i = maxStart + 1; i < tabCount; i++) {
if (isVisible.apply(i)) {
max = i;
} else {
break;
}
}
} else {
//Descent to find maximum.
for (int i = maxStart - 1; i >= 0; i--) {
if (isVisible.apply(i)) {
max = i;
break;
}
}
}
ui.minVisible = min;
ui.maxVisible = max;
if (updateShift) {
if (isX) {
ui.currentShiftXTmp += shift;
} else {
ui.currentShiftYTmp += shift;
}
}
}
@Contract(pure = true)
protected boolean isVisibleX(final int i, final int shift, final int minX, final int maxX) {
int begin = ui.rects[i].x + shift;
int end = begin + ui.rects[i].width;
return !(begin >= maxX || end < minX);
}
@Contract(pure = true)
protected boolean isVisibleY(final int i, final int shift, final int minX, final int maxX) {
int begin = ui.rects[i].y + shift;
int end = begin + ui.rects[i].height;
return !(begin >= maxX || end < minX);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy