Files
OAC-Swing/src/main/java/org/openautonomousconnection/oacswing/component/OACTitleBar.java
2026-02-14 16:36:02 +01:00

173 lines
4.7 KiB
Java

/* Author: UnlegitDqrk
* Feb. 2 2026
* */
package org.openautonomousconnection.oacswing.component;
import lombok.Getter;
import lombok.Setter;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
/**
* Custom title bar with tabs and window control buttons.
*/
public class OACTitleBar extends OACPanel {
@Getter
@Setter
private static int HEIGHT = 42;
private final OACFrame frame;
private final OACTabbedPane tabs;
private Point dragStartOnScreen;
private Point dragStartFrameLocation;
/**
* Creates a title bar for the given frame.
*
* @param frame owning frame
*/
public OACTitleBar(OACFrame frame) {
super(new BorderLayout());
this.frame = frame;
setPreferredSize(new Dimension(1, HEIGHT));
setBorder(new EmptyBorder(6, 10, 6, 10));
tabs = createTabs();
OACPanel left = new OACPanel(new BorderLayout());
left.setOpaque(false);
left.add(tabs, BorderLayout.CENTER);
OACPanel right = createWindowControls();
add(left, BorderLayout.CENTER);
add(right, BorderLayout.EAST);
installDragToMove();
installDoubleClickMaximize();
}
/**
* Returns the tab component.
*
* @return tabbed pane
*/
public OACTabbedPane getTabs() {
return tabs;
}
/**
* Adds a new tab.
*
* @param title tab title
* @param panel tab body
*/
public void addTab(String title, OACPanel panel) {
tabs.addTab(title, panel);
}
private OACTabbedPane createTabs() {
OACTabbedPane tp = new OACTabbedPane(OACTabbedPane.TOP, OACTabbedPane.SCROLL_TAB_LAYOUT);
tp.setOpaque(false);
tp.setFocusable(false);
return tp;
}
private OACPanel createWindowControls() {
OACPanel p = new OACPanel(new FlowLayout(FlowLayout.RIGHT, 8, 0));
p.setOpaque(false);
OACButton min = createTitleButton("");
OACButton max = createTitleButton("");
OACButton close = createTitleButton("");
min.addActionListener(e -> frame.setState(Frame.ICONIFIED));
max.addActionListener(e -> toggleMaximize());
close.addActionListener(e -> frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING)));
p.add(min);
p.add(max);
p.add(close);
return p;
}
private OACButton createTitleButton(String text) {
OACButton b = new OACButton(text);
b.setFocusable(false);
b.setBorderPainted(false);
b.setContentAreaFilled(true);
b.setOpaque(true);
b.setBorder(null);
b.setPreferredSize(new Dimension(42, 28));
return b;
}
private void installDragToMove() {
MouseAdapter drag = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
dragStartOnScreen = e.getLocationOnScreen();
dragStartFrameLocation = frame.getLocation();
}
@Override
public void mouseDragged(MouseEvent e) {
if (dragStartOnScreen == null || dragStartFrameLocation == null) {
return;
}
Point now = e.getLocationOnScreen();
int dx = now.x - dragStartOnScreen.x;
int dy = now.y - dragStartOnScreen.y;
if ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH) {
return;
}
frame.setLocation(dragStartFrameLocation.x + dx, dragStartFrameLocation.y + dy);
frame.dispatchEvent(new ComponentEvent(e.getComponent(), ComponentEvent.COMPONENT_MOVED));
}
};
addMouseListener(drag);
addMouseMotionListener(drag);
}
private void installDoubleClickMaximize() {
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) {
toggleMaximize();
}
}
});
}
private void toggleMaximize() {
int state = frame.getExtendedState();
boolean maximized = (state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH;
if (maximized) {
frame.setExtendedState(state & ~Frame.MAXIMIZED_BOTH);
} else {
frame.setExtendedState(state | Frame.MAXIMIZED_BOTH);
}
frame.dispatchEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED));
}
}