panel splitter

This commit is contained in:
Radek Davidek 2026-02-05 16:55:11 +01:00
parent 72661040df
commit c2e46ea1d5
2 changed files with 192 additions and 4 deletions

View File

@ -1001,4 +1001,13 @@ public class AppConfig {
} }
} }
} }
// --- Divider position persistence (split pane) ---
public double getDividerPosition() {
return Double.parseDouble(properties.getProperty("mainPanel.dividerPosition", "0.5"));
}
public void setDividerPosition(double position) {
properties.setProperty("mainPanel.dividerPosition", String.valueOf(position));
}
} }

View File

@ -26,6 +26,8 @@ public class MainWindow extends JFrame {
private FilePanel leftPanel; private FilePanel leftPanel;
private FilePanel rightPanel; private FilePanel rightPanel;
private FilePanel activePanel; private FilePanel activePanel;
private JSplitPane mainPanel;
private JLabel dividerStatusLabel;
private JPanel buttonPanel; private JPanel buttonPanel;
private JToolBar toolBar; private JToolBar toolBar;
private JComboBox<String> commandLine; private JComboBox<String> commandLine;
@ -104,8 +106,9 @@ public class MainWindow extends JFrame {
// Toolbar // Toolbar
createToolBar(); createToolBar();
// Panel containing the two file panels // Panel containing the two file panels with resizable divider
JPanel mainPanel = new JPanel(new GridLayout(1, 2, 5, 0)); mainPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
mainPanel.setContinuousLayout(true);
// Left panel - load path and ViewMode from configuration // Left panel - load path and ViewMode from configuration
String leftPath = config.getLeftPanelPath(); String leftPath = config.getLeftPanelPath();
@ -151,8 +154,50 @@ public class MainWindow extends JFrame {
// Default value FULL is already set // Default value FULL is already set
} }
mainPanel.add(leftPanel); mainPanel.setLeftComponent(leftPanel);
mainPanel.add(rightPanel); mainPanel.setRightComponent(rightPanel);
// Restore divider position from configuration
SwingUtilities.invokeLater(() -> {
double savedPosition = config.getDividerPosition();
if (savedPosition >= 0.0 && savedPosition <= 1.0) {
mainPanel.setDividerLocation(savedPosition);
} else {
// If it was saved as absolute pixels (historically), use as int
mainPanel.setDividerLocation((int) savedPosition);
}
updateDividerTooltip(mainPanel);
});
mainPanel.setOneTouchExpandable(true);
updateDividerTooltip(mainPanel);
// Listen for divider position changes to update saved position and tooltip
mainPanel.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, e -> {
int location = mainPanel.getDividerLocation();
int width = mainPanel.getWidth();
int dividerSize = mainPanel.getDividerSize();
if (width > dividerSize) {
double proportionalPosition = (double) location / (width - dividerSize);
config.setDividerPosition(proportionalPosition);
}
updateDividerTooltip(mainPanel);
// Immediately show tooltip during drag if possible
for (Component c : mainPanel.getComponents()) {
if (c != mainPanel.getLeftComponent() && c != mainPanel.getRightComponent() && c instanceof JComponent) {
MouseEvent postEvent = new MouseEvent(c, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false);
ToolTipManager.sharedInstance().mouseMoved(postEvent);
}
}
});
mainPanel.addComponentListener(new java.awt.event.ComponentAdapter() {
@Override
public void componentResized(java.awt.event.ComponentEvent e) {
updateDividerTooltip(mainPanel);
}
});
add(mainPanel, BorderLayout.CENTER); add(mainPanel, BorderLayout.CENTER);
@ -382,6 +427,17 @@ public class MainWindow extends JFrame {
cmdPanel.add(commandLine, BorderLayout.CENTER); cmdPanel.add(commandLine, BorderLayout.CENTER);
dividerStatusLabel = new JLabel("");
dividerStatusLabel.setFont(new Font("Monospaced", Font.BOLD, 13));
dividerStatusLabel.setForeground(Color.WHITE);
dividerStatusLabel.setBackground(new Color(0, 120, 215));
dividerStatusLabel.setOpaque(true);
dividerStatusLabel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(new Color(0, 90, 160)),
BorderFactory.createEmptyBorder(2, 10, 2, 10)
));
cmdPanel.add(dividerStatusLabel, BorderLayout.EAST);
// Load history from config // Load history from config
java.util.List<String> history = config.getCommandLineHistory(); java.util.List<String> history = config.getCommandLineHistory();
for (int i = 0; i < history.size(); i++) { for (int i = 0; i < history.size(); i++) {
@ -2851,6 +2907,129 @@ public class MainWindow extends JFrame {
if (rightPanel != null) rightPanel.showDrivePopup(); if (rightPanel != null) rightPanel.showDrivePopup();
} }
/**
* Update divider tooltip with percentage sizes
*/
private void updateDividerTooltip(JSplitPane splitPane) {
if (splitPane == null) return;
// Get divider location in pixels
int location = splitPane.getDividerLocation();
int totalSize = splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT ?
splitPane.getWidth() : splitPane.getHeight();
int dividerSize = splitPane.getDividerSize();
int max = totalSize - dividerSize;
if (max > 0) {
double proportionalPosition = (double) location / max;
// Calculate percentages
int leftPercent = (int) Math.round(proportionalPosition * 100);
int rightPercent = 100 - leftPercent;
String firstLabel = splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT ? "Left" : "Top";
String secondLabel = splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT ? "Right" : "Bottom";
String tooltip = String.format("%s: %d%% | %s: %d%%", firstLabel, leftPercent, secondLabel, rightPercent);
splitPane.setToolTipText(tooltip);
if (dividerStatusLabel != null) {
dividerStatusLabel.setText(String.format("%d%% : %d%%", leftPercent, rightPercent));
dividerStatusLabel.setToolTipText(tooltip);
}
// Set tooltip also on the divider component itself
Component left = splitPane.getLeftComponent();
Component right = splitPane.getRightComponent();
for (Component c : splitPane.getComponents()) {
if (c != left && c != right) {
if (c instanceof JComponent jc) {
jc.setToolTipText(tooltip);
ToolTipManager.sharedInstance().registerComponent(jc);
}
// Add mouse listener to the divider if not already present
boolean hasListener = false;
for (MouseMotionListener ml : c.getMouseMotionListeners()) {
if (ml instanceof DividerMouseHandler) {
hasListener = true;
((DividerMouseHandler)ml).updateTooltip(tooltip);
break;
}
}
if (!hasListener) {
DividerMouseHandler handler = new DividerMouseHandler(splitPane, tooltip);
c.addMouseListener(handler);
c.addMouseMotionListener(handler);
}
}
}
}
}
private class DividerMouseHandler extends MouseAdapter {
private final JSplitPane splitPane;
private String currentTooltip;
private JWindow tooltipWindow;
private JLabel tipLabel;
public DividerMouseHandler(JSplitPane splitPane, String tooltip) {
this.splitPane = splitPane;
this.currentTooltip = tooltip;
tooltipWindow = new JWindow();
tipLabel = new JLabel();
tipLabel.setFont(new Font("SansSerif", Font.BOLD, 14));
tipLabel.setBorder(BorderFactory.createEmptyBorder(5, 12, 5, 12));
tipLabel.setBackground(new Color(40, 40, 40)); // Very dark gray
tipLabel.setForeground(Color.WHITE);
tipLabel.setOpaque(true);
tooltipWindow.add(tipLabel);
tooltipWindow.pack();
tooltipWindow.setAlwaysOnTop(true);
}
public void updateTooltip(String tooltip) {
this.currentTooltip = tooltip;
if (tipLabel != null) {
tipLabel.setText(tooltip);
tooltipWindow.pack();
}
}
@Override
public void mouseEntered(MouseEvent e) {
showWindow(e);
}
@Override
public void mouseExited(MouseEvent e) {
tooltipWindow.setVisible(false);
}
@Override
public void mouseMoved(MouseEvent e) {
updateLocation(e);
}
@Override
public void mouseDragged(MouseEvent e) {
updateLocation(e);
updateDividerTooltip(splitPane);
}
private void showWindow(MouseEvent e) {
tipLabel.setText(currentTooltip);
tooltipWindow.pack();
updateLocation(e);
tooltipWindow.setVisible(true);
}
private void updateLocation(MouseEvent e) {
Point p = e.getLocationOnScreen();
tooltipWindow.setLocation(p.x + 15, p.y + 15);
}
}
/** /**
* Save configuration and exit application * Save configuration and exit application
*/ */