Files
OAC-Swing/src/main/java/org/openautonomousconnection/oacswing/component/OACTabbedPane.java

191 lines
6.2 KiB
Java

/* Author: Maple
* Feb. 2 2026
* */
package org.openautonomousconnection.oacswing.component;
import lombok.NonNull;
import org.openautonomousconnection.oacswing.component.design.DesignManager;
import javax.swing.*;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
import java.awt.*;
public class OACTabbedPane extends JTabbedPane implements OACComponent {
private boolean selectionSyncInstalled;
public OACTabbedPane() {
super();
}
public OACTabbedPane(int tabPlacement) {
super(tabPlacement);
}
public OACTabbedPane(int tabPlacement, int tabLayoutPolicy) {
super(tabPlacement, tabLayoutPolicy);
}
@Override
public void init() {
applyDesignColors();
}
@Override
public void updateUI() {
super.updateUI();
applyDesignColors();
}
private void applyDesignColors() {
Color bg = DesignManager.resolveBackground(OACTabbedPane.class, getBackground());
Color fg = DesignManager.resolveForeground(OACTabbedPane.class, getForeground());
Color selectedBg = DesignManager.resolveHovered(OACButton.class, bg.darker());
Color selectedFg = fg;
Color border = DesignManager.resolveBorderColor(bg.darker());
setOpaque(true);
setBackground(bg);
setForeground(fg);
setUI(new DesignTabbedPaneUI(bg, selectedBg, border));
applyTabItemColors(bg, fg, selectedBg, selectedFg);
installSelectionSyncIfNeeded();
}
private void applyTabItemColors(Color bg, Color fg, Color selectedBg, Color selectedFg) {
int selectedIndex = getSelectedIndex();
for (int i = 0; i < getTabCount(); i++) {
boolean selected = i == selectedIndex;
setBackgroundAt(i, selected ? selectedBg : bg);
setForegroundAt(i, selected ? selectedFg : fg);
}
repaint();
}
private void installSelectionSyncIfNeeded() {
if (selectionSyncInstalled) {
return;
}
addChangeListener(e -> {
Color bg = DesignManager.resolveBackground(OACTabbedPane.class, getBackground());
Color fg = DesignManager.resolveForeground(OACTabbedPane.class, getForeground());
Color selectedBg = DesignManager.resolveHovered(OACButton.class, bg.darker());
applyTabItemColors(bg, fg, selectedBg, fg);
});
selectionSyncInstalled = true;
}
private static final class DesignTabbedPaneUI extends BasicTabbedPaneUI {
private final Color background;
private final Color selectedBackground;
private final Color borderColor;
private DesignTabbedPaneUI(Color background, Color selectedBackground, Color borderColor) {
this.background = background;
this.selectedBackground = selectedBackground;
this.borderColor = borderColor;
}
@Override
protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected) {
g.setColor(isSelected ? selectedBackground : background);
g.fillRect(x, y, w, h);
}
@Override
protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected) {
g.setColor(borderColor);
g.drawRect(x, y, w, h);
}
@Override
protected void paintFocusIndicator(Graphics g, int tabPlacement, Rectangle[] rects,
int tabIndex, Rectangle iconRect, Rectangle textRect, boolean isSelected) {
// no-op to avoid bright LAF focus ring
}
@Override
protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) {
int width = tabPane.getWidth();
int height = tabPane.getHeight();
Insets insets = tabPane.getInsets();
int x = insets.left;
int y = insets.top;
int w = width - insets.right - insets.left;
int h = height - insets.top - insets.bottom;
switch (tabPlacement) {
case LEFT -> {
x += calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
w -= (x - insets.left);
}
case RIGHT -> w -= calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
case BOTTOM -> h -= calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
default -> {
y += calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
h -= (y - insets.top);
}
}
g.setColor(background);
g.fillRect(x, y, w, h);
g.setColor(borderColor);
g.drawRect(x, y, Math.max(0, w - 1), Math.max(0, h - 1));
}
}
@Override
public void addTab(String title, Component component) {
this.initOther(component);
super.addTab(title, component);
applyDesignColors();
}
@Override
public void addTab(String title, Icon icon, Component component) {
this.initOther(component);
super.addTab(title, icon, component);
applyDesignColors();
}
@Override
public void addTab(String title, Icon icon, Component component, String tip) {
this.initOther(component);
super.addTab(title, icon, component, tip);
applyDesignColors();
}
@Override
public Component add(Component comp) {
this.initOther(comp);
return super.add(comp);
}
@Override
public Component add(Component comp, int index) {
this.initOther(comp);
return super.add(comp, index);
}
@Override
public void add(@NonNull Component comp, Object constraints) {
this.initOther(comp);
super.add(comp, constraints);
}
@Override
public Component add(String name, Component comp) {
this.initOther(comp);
return super.add(name, comp);
}
@Override
public void add(Component comp, Object constraints, int index) {
this.initOther(comp);
super.add(comp, constraints, index);
}
}