better scrolling
This commit is contained in:
parent
abd2ba15b8
commit
8279f1bc3d
@ -725,9 +725,23 @@ public class FilePanelTab extends JPanel {
|
|||||||
JScrollBar hBar = sp.getHorizontalScrollBar();
|
JScrollBar hBar = sp.getHorizontalScrollBar();
|
||||||
if (hBar != null && hBar.isVisible()) {
|
if (hBar != null && hBar.isVisible()) {
|
||||||
int rotation = e.getWheelRotation();
|
int rotation = e.getWheelRotation();
|
||||||
// Scroll by a larger amount for significantly faster movement
|
int colWidth = fileTable.getColumnModel().getColumn(0).getPreferredWidth();
|
||||||
int amount = rotation * hBar.getUnitIncrement() * 10;
|
if (colWidth > 0) {
|
||||||
hBar.setValue(hBar.getValue() + amount);
|
// Calculate current value and round to nearest column to ensure snapping
|
||||||
|
int currentVal = hBar.getValue();
|
||||||
|
int currentCol = (int) Math.round((double) currentVal / colWidth);
|
||||||
|
|
||||||
|
// Scroll by 2 columns per notch for speed but keep it aligned
|
||||||
|
int nextCol = currentCol + (rotation * 2);
|
||||||
|
int newVal = nextCol * colWidth;
|
||||||
|
|
||||||
|
// Bounds checking
|
||||||
|
int maxVal = hBar.getMaximum() - hBar.getVisibleAmount();
|
||||||
|
if (newVal < 0) newVal = 0;
|
||||||
|
if (newVal > maxVal) newVal = maxVal;
|
||||||
|
|
||||||
|
hBar.setValue(newVal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e.consume();
|
e.consume();
|
||||||
@ -2706,6 +2720,49 @@ public class FilePanelTab extends JPanel {
|
|||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int calculateCurrentColumnWidth() {
|
||||||
|
if (tableModel.items == null || tableModel.items.isEmpty()) return 0;
|
||||||
|
|
||||||
|
java.awt.FontMetrics fm = fileTable.getFontMetrics(fileTable.getFont());
|
||||||
|
int maxTextWidth = 0;
|
||||||
|
int maxIconWidth = 0;
|
||||||
|
|
||||||
|
for (FileItem item : tableModel.items) {
|
||||||
|
if (item == null) continue;
|
||||||
|
String name = item.getName();
|
||||||
|
// Match truncation from renderer for BRIEF mode
|
||||||
|
int maxLen = persistedConfig != null ? persistedConfig.getBriefModeMaxNameLength() : 30;
|
||||||
|
if (name.length() > maxLen) {
|
||||||
|
int startLen = persistedConfig != null ? persistedConfig.getBriefModeStartLength() : 20;
|
||||||
|
int endLen = persistedConfig != null ? persistedConfig.getBriefModeEndLength() : 10;
|
||||||
|
String sep = persistedConfig != null ? persistedConfig.getBriefModeSeparator() : "...";
|
||||||
|
if (startLen + endLen < name.length()) {
|
||||||
|
name = name.substring(0, startLen) + sep + name.substring(name.length() - endLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String display = name;
|
||||||
|
if (item.isDirectory()) {
|
||||||
|
display = "[" + display + "]";
|
||||||
|
}
|
||||||
|
int w = fm.stringWidth(display);
|
||||||
|
if (w > maxTextWidth) maxTextWidth = w;
|
||||||
|
|
||||||
|
Icon icon = getItemIcon(item);
|
||||||
|
if (icon != null) {
|
||||||
|
int iw = icon.getIconWidth();
|
||||||
|
if (iw > maxIconWidth) maxIconWidth = iw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxTextWidth == 0) {
|
||||||
|
maxTextWidth = fm.stringWidth("WWWWWWWWWW");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add icon width and padding (left/right + gap between icon and text)
|
||||||
|
int padding = 36; // reasonable extra space
|
||||||
|
return maxTextWidth + maxIconWidth + padding;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateColumnWidths() {
|
private void updateColumnWidths() {
|
||||||
if (viewMode == ViewMode.FULL) {
|
if (viewMode == ViewMode.FULL) {
|
||||||
if (fileTable.getColumnModel().getColumnCount() == 3) {
|
if (fileTable.getColumnModel().getColumnCount() == 3) {
|
||||||
@ -2730,51 +2787,32 @@ public class FilePanelTab extends JPanel {
|
|||||||
// Turn off auto-resize so preferred widths are honored and horizontal scrolling appears
|
// Turn off auto-resize so preferred widths are honored and horizontal scrolling appears
|
||||||
fileTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
fileTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
||||||
|
|
||||||
// Compute the preferred column width based on the longest displayed
|
int columnWidth = calculateCurrentColumnWidth();
|
||||||
// name in the current directory (include brackets for directories)
|
int viewportWidth = fileTable.getParent().getWidth();
|
||||||
// plus the widest icon width and some padding.
|
|
||||||
java.awt.FontMetrics fm = fileTable.getFontMetrics(fileTable.getFont());
|
|
||||||
int maxTextWidth = 0;
|
|
||||||
int maxIconWidth = 0;
|
|
||||||
|
|
||||||
for (FileItem item : tableModel.items) {
|
|
||||||
if (item == null) continue;
|
|
||||||
String name = item.getName();
|
|
||||||
// Match truncation from renderer for BRIEF mode
|
|
||||||
int maxLen = persistedConfig != null ? persistedConfig.getBriefModeMaxNameLength() : 30;
|
|
||||||
if (name.length() > maxLen) {
|
|
||||||
int startLen = persistedConfig != null ? persistedConfig.getBriefModeStartLength() : 20;
|
|
||||||
int endLen = persistedConfig != null ? persistedConfig.getBriefModeEndLength() : 10;
|
|
||||||
String sep = persistedConfig != null ? persistedConfig.getBriefModeSeparator() : "...";
|
|
||||||
if (startLen + endLen < name.length()) {
|
|
||||||
name = name.substring(0, startLen) + sep + name.substring(name.length() - endLen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String display = name;
|
|
||||||
if (item.isDirectory()) {
|
|
||||||
display = "[" + display + "]";
|
|
||||||
}
|
|
||||||
int w = fm.stringWidth(display);
|
|
||||||
if (w > maxTextWidth) maxTextWidth = w;
|
|
||||||
|
|
||||||
Icon icon = getItemIcon(item);
|
|
||||||
if (icon != null) {
|
|
||||||
int iw = icon.getIconWidth();
|
|
||||||
if (iw > maxIconWidth) maxIconWidth = iw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxTextWidth == 0) {
|
|
||||||
maxTextWidth = fm.stringWidth("WWWWWWWWWW");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add icon width and padding (left/right + gap between icon and text)
|
|
||||||
int padding = 36; // reasonable extra space
|
|
||||||
int columnWidth = maxTextWidth + maxIconWidth + padding;
|
|
||||||
|
|
||||||
for (int i = 0; i < columnCount; i++) {
|
for (int i = 0; i < columnCount; i++) {
|
||||||
fileTable.getColumnModel().getColumn(i).setPreferredWidth(columnWidth);
|
fileTable.getColumnModel().getColumn(i).setPreferredWidth(columnWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjust the very last column to make the total table width such that
|
||||||
|
// the maximum scroll position is a multiple of columnWidth.
|
||||||
|
if (tableModel.extraColumns > 0 && columnWidth > 0 && viewportWidth > 0) {
|
||||||
|
int actualDataWidth = tableModel.briefColumns * columnWidth;
|
||||||
|
int k = (int) Math.ceil((double) (actualDataWidth - viewportWidth) / columnWidth);
|
||||||
|
int targetTotalWidth = k * columnWidth + viewportWidth;
|
||||||
|
|
||||||
|
int widthOfOthers = (columnCount - 1) * columnWidth;
|
||||||
|
int lastColWidth = targetTotalWidth - widthOfOthers;
|
||||||
|
if (lastColWidth > 0) {
|
||||||
|
fileTable.getColumnModel().getColumn(columnCount - 1).setPreferredWidth(lastColWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure horizontal scrollbar snaps to column widths
|
||||||
|
JScrollPane sp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, fileTable);
|
||||||
|
if (sp != null) {
|
||||||
|
sp.getHorizontalScrollBar().setUnitIncrement(columnWidth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3191,6 +3229,7 @@ public class FilePanelTab extends JPanel {
|
|||||||
private List<FileItem> items = new ArrayList<>();
|
private List<FileItem> items = new ArrayList<>();
|
||||||
private String[] columnNames = {"Name", "Size", "Date"};
|
private String[] columnNames = {"Name", "Size", "Date"};
|
||||||
public int briefColumns = 1;
|
public int briefColumns = 1;
|
||||||
|
public int extraColumns = 0;
|
||||||
public int briefRowsPerColumn = 10;
|
public int briefRowsPerColumn = 10;
|
||||||
|
|
||||||
public void setItems(List<FileItem> items) {
|
public void setItems(List<FileItem> items) {
|
||||||
@ -3211,6 +3250,7 @@ public class FilePanelTab extends JPanel {
|
|||||||
public void calculateBriefLayout() {
|
public void calculateBriefLayout() {
|
||||||
if (items.isEmpty()) {
|
if (items.isEmpty()) {
|
||||||
briefColumns = 1;
|
briefColumns = 1;
|
||||||
|
extraColumns = 0;
|
||||||
briefRowsPerColumn = 1;
|
briefRowsPerColumn = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -3221,11 +3261,36 @@ public class FilePanelTab extends JPanel {
|
|||||||
if (availableHeight <= 0 || rowHeight <= 0) {
|
if (availableHeight <= 0 || rowHeight <= 0) {
|
||||||
briefRowsPerColumn = Math.max(1, items.size());
|
briefRowsPerColumn = Math.max(1, items.size());
|
||||||
briefColumns = 1;
|
briefColumns = 1;
|
||||||
|
extraColumns = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
briefRowsPerColumn = Math.max(1, availableHeight / rowHeight);
|
briefRowsPerColumn = Math.max(1, availableHeight / rowHeight);
|
||||||
briefColumns = (int) Math.ceil((double) items.size() / briefRowsPerColumn);
|
briefColumns = (int) Math.ceil((double) items.size() / briefRowsPerColumn);
|
||||||
|
|
||||||
|
// Calculate extra columns to allow snapping correctly at the end.
|
||||||
|
// We want the scrolling to stop precisely when the last column is fully visible
|
||||||
|
// on the right, but also ensure the left-most visible column is snapped to the left edge.
|
||||||
|
int colWidth = calculateCurrentColumnWidth();
|
||||||
|
int viewportWidth = fileTable.getParent().getWidth();
|
||||||
|
if (colWidth > 0 && viewportWidth > 0 && briefColumns > 0) {
|
||||||
|
int actualWidth = briefColumns * colWidth;
|
||||||
|
if (actualWidth > viewportWidth) {
|
||||||
|
// Smallest k such that (k * colWidth + viewportWidth) >= actualWidth
|
||||||
|
int k = (int) Math.ceil((double) (actualWidth - viewportWidth) / colWidth);
|
||||||
|
int neededWidth = k * colWidth + viewportWidth;
|
||||||
|
// How many extra columns of 'colWidth' would it take?
|
||||||
|
// We'll adjust the last one's width in updateColumnWidths
|
||||||
|
extraColumns = (int) Math.ceil((double) (neededWidth - actualWidth) / colWidth);
|
||||||
|
if (extraColumns == 0 && neededWidth > actualWidth) {
|
||||||
|
extraColumns = 1; // Need at least one to hold the fractional part
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
extraColumns = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
extraColumns = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileItem getItemFromBriefLayout(int row, int column) {
|
public FileItem getItemFromBriefLayout(int row, int column) {
|
||||||
@ -3233,6 +3298,8 @@ public class FilePanelTab extends JPanel {
|
|||||||
return getItem(row);
|
return getItem(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (column >= briefColumns) return null;
|
||||||
|
|
||||||
int index = column * briefRowsPerColumn + row;
|
int index = column * briefRowsPerColumn + row;
|
||||||
if (index >= 0 && index < items.size()) {
|
if (index >= 0 && index < items.size()) {
|
||||||
return items.get(index);
|
return items.get(index);
|
||||||
@ -3251,7 +3318,7 @@ public class FilePanelTab extends JPanel {
|
|||||||
@Override
|
@Override
|
||||||
public int getColumnCount() {
|
public int getColumnCount() {
|
||||||
if (viewMode == ViewMode.BRIEF) {
|
if (viewMode == ViewMode.BRIEF) {
|
||||||
return briefColumns;
|
return briefColumns + extraColumns;
|
||||||
}
|
}
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user