From c2e46ea1d5a5777a64d616d5dc8c67a7f682c4c5 Mon Sep 17 00:00:00 2001 From: Radek Davidek Date: Thu, 5 Feb 2026 16:55:11 +0100 Subject: [PATCH] panel splitter --- .../cz/kamma/kfmanager/config/AppConfig.java | 9 + .../cz/kamma/kfmanager/ui/MainWindow.java | 187 +++++++++++++++++- 2 files changed, 192 insertions(+), 4 deletions(-) diff --git a/src/main/java/cz/kamma/kfmanager/config/AppConfig.java b/src/main/java/cz/kamma/kfmanager/config/AppConfig.java index e9dd31f..768c84f 100644 --- a/src/main/java/cz/kamma/kfmanager/config/AppConfig.java +++ b/src/main/java/cz/kamma/kfmanager/config/AppConfig.java @@ -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)); + } } diff --git a/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java b/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java index 2cf131a..e30968b 100644 --- a/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java +++ b/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java @@ -26,6 +26,8 @@ public class MainWindow extends JFrame { private FilePanel leftPanel; private FilePanel rightPanel; private FilePanel activePanel; + private JSplitPane mainPanel; + private JLabel dividerStatusLabel; private JPanel buttonPanel; private JToolBar toolBar; private JComboBox commandLine; @@ -104,8 +106,9 @@ public class MainWindow extends JFrame { // Toolbar createToolBar(); - // Panel containing the two file panels - JPanel mainPanel = new JPanel(new GridLayout(1, 2, 5, 0)); + // Panel containing the two file panels with resizable divider + mainPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); + mainPanel.setContinuousLayout(true); // Left panel - load path and ViewMode from configuration String leftPath = config.getLeftPanelPath(); @@ -151,8 +154,50 @@ public class MainWindow extends JFrame { // Default value FULL is already set } - mainPanel.add(leftPanel); - mainPanel.add(rightPanel); + mainPanel.setLeftComponent(leftPanel); + 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); @@ -382,6 +427,17 @@ public class MainWindow extends JFrame { 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 java.util.List history = config.getCommandLineHistory(); for (int i = 0; i < history.size(); i++) { @@ -2851,6 +2907,129 @@ public class MainWindow extends JFrame { 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 */