From ca2110800ca82fb864827d087075ada461ebcf3f Mon Sep 17 00:00:00 2001 From: Reasel Date: Wed, 24 Jun 2026 09:58:17 -0700 Subject: [PATCH] Pin buttons/stats, scroll only session history Disable PluginPanel outer scroll wrap so Start/Stop and live stats stay fixed. Move history list into a CENTER scroll pane that tracks viewport width, eliminating horizontal scroll and keeping the buttons reachable when history grows long. --- README.md | 2 +- panel-preview.png | Bin 7662 -> 7526 bytes .../afkstatstracker/AfkStatsTrackerPanel.java | 96 ++++++++++++------ 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 03951c6..f556d10 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Tracked Stats: Purpose: To track afk metrics to compare between activies and methods. Similar to tracking DPS and Kills/hr. -Session history shows your most recent sessions first. Click a session name to rename it. Sessions can be copied to clipboard or deleted (with confirmation). +Session history shows your most recent sessions first. Click a session name to rename it. Sessions can be copied to clipboard or deleted (with confirmation). The Start/Stop buttons and live stats stay pinned in place; only the history list scrolls when it grows long. ## Wiki Guide diff --git a/panel-preview.png b/panel-preview.png index 04b6505c79168687bfead03537afe24193317cbf..8b267c5fd4fd8d1ccda82d1bf6cd2ad1febfe1cc 100644 GIT binary patch literal 7526 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 updateStats()); timer.setRepeats(true); - // Main content panel - JPanel contentPanel = new JPanel(); - contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS)); + // Pinned top panel (buttons + stats + history header) — never scrolls + JPanel topPanel = new JPanel(); + topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.Y_AXIS)); // Button panel JPanel buttonPanel = new JPanel(new GridLayout(1, 2, 5, 0)); @@ -128,14 +134,22 @@ public AfkStatsTrackerPanel(AfkStatsTrackerPlugin plugin, SessionHistoryManager statsPanel.add(distanceIndicator); statsPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, statsPanel.getPreferredSize().height)); - // History section - JPanel historySection = createHistorySection(); + // History header (pinned) + scrollable data area + JPanel historyHeader = createHistoryHeader(); + + historyContainer = new ScrollablePanel(); - contentPanel.add(buttonPanel); - contentPanel.add(statsPanel); - contentPanel.add(historySection); + historyScrollPane = new JScrollPane(historyContainer); + historyScrollPane.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); + historyScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + refreshHistoryPanel(); - add(contentPanel, BorderLayout.NORTH); + topPanel.add(buttonPanel); + topPanel.add(statsPanel); + topPanel.add(historyHeader); + + add(topPanel, BorderLayout.NORTH); + add(historyScrollPane, BorderLayout.CENTER); } private JPanel createStatCard(String title, String tooltip) @@ -192,13 +206,11 @@ private JPanel createSessionCard() return card; } - private JPanel createHistorySection() + private JPanel createHistoryHeader() { - JPanel section = new JPanel(new BorderLayout()); - section.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); - - // Header with toggle JPanel header = new JPanel(new BorderLayout()); + header.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); + JLabel headerLabel = new JLabel("▼ Session History"); headerLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); headerLabel.addMouseListener(new MouseAdapter() @@ -208,25 +220,12 @@ public void mouseClicked(MouseEvent e) { historyExpanded = !historyExpanded; headerLabel.setText((historyExpanded ? "▼" : "▶") + " Session History"); - historyContainer.setVisible(historyExpanded); + historyScrollPane.setVisible(historyExpanded); revalidate(); } }); header.add(headerLabel, BorderLayout.WEST); - - // History container - historyContainer = new JPanel(); - historyContainer.setLayout(new BoxLayout(historyContainer, BoxLayout.Y_AXIS)); - - JScrollPane scrollPane = new JScrollPane(historyContainer); - scrollPane.setPreferredSize(new Dimension(0, 300)); - scrollPane.setBorder(null); - - section.add(header, BorderLayout.NORTH); - section.add(scrollPane, BorderLayout.CENTER); - - refreshHistoryPanel(); - return section; + return header; } public void refreshHistoryPanel() @@ -464,6 +463,45 @@ public void stopTimer() } } + // Vertical list whose width follows the viewport, so rows shrink/truncate instead of forcing a horizontal scrollbar + private static class ScrollablePanel extends JPanel implements Scrollable + { + ScrollablePanel() + { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + } + + @Override + public Dimension getPreferredScrollableViewportSize() + { + return getPreferredSize(); + } + + @Override + public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) + { + return 16; + } + + @Override + public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) + { + return visibleRect.height; + } + + @Override + public boolean getScrollableTracksViewportWidth() + { + return true; + } + + @Override + public boolean getScrollableTracksViewportHeight() + { + return false; + } + } + private static class ConsistencyIndicator extends JPanel { private static final int MARKER_SIZE = 8;