Skip to content

Commit b093e1d

Browse files
committed
Improve MeasureU and fix UX inconsistencies
1 parent db2545d commit b093e1d

6 files changed

Lines changed: 398 additions & 114 deletions

File tree

‎src/main/java/sc/fiji/snt/BookmarkManager.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ public void mousePressed(final MouseEvent me) {
380380
if (sntui != null) {
381381
SNTUI.InternalUtils.addHoldToToggleKeyListener(table, sntui.plugin);
382382
}
383+
GuiUtils.JTables.installAlternatingRows(table);
383384
return table;
384385
}
385386

‎src/main/java/sc/fiji/snt/PathManagerUI.java‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6593,16 +6593,18 @@ private void showColorCustomizationDialog() {
65936593
final JPanel panel = new JPanel(new GridBagLayout());
65946594
panel.setBackground(ProofReadingTagsToolBar.this.getBackground());
65956595
final GridBagConstraints c = GuiUtils.defaultGbc();
6596-
// Align the component to the left edge of its cell
6597-
c.anchor = GridBagConstraints.WEST;
6598-
// Prevent the component from stretching horizontally
6599-
c.fill = GridBagConstraints.NONE;
6596+
c.anchor = GridBagConstraints.CENTER;
6597+
// Stretch every button to the width of the widest one in the column
6598+
c.fill = GridBagConstraints.HORIZONTAL;
66006599
// Create color selection components for each tag
66016600
c.insets = new Insets(0, 0, 5, 0);
66026601
final Map<String, ColorChooserButton> colorButtons = new HashMap<>();
66036602
tagsMap.forEach( (tagName, color) -> {
66046603
final ColorChooserButton colorButton = new ColorChooserButton(color, capitalized(tagName)
66056604
, 1f, ColorChooserButton.RIGHT);
6605+
// Pin the icon+label to the left edge so swatches stay aligned in a
6606+
// column once the buttons are stretched to a common width
6607+
colorButton.setHorizontalAlignment(SwingConstants.LEFT);
66066608
GuiUtils.Buttons.makeRoundRect(colorButton);
66076609
panel.add(colorButton, c);
66086610
colorButtons.put(tagName, colorButton);
@@ -6611,6 +6613,7 @@ private void showColorCustomizationDialog() {
66116613
// Add reset button
66126614
c.insets.top += 10;
66136615
final JButton resetButton = new JButton("Reset to Defaults", IconFactory.buttonIcon(IconFactory.GLYPH.UNDO, .9f));
6616+
resetButton.setHorizontalAlignment(SwingConstants.LEFT);
66146617
GuiUtils.Buttons.makeBorderless(resetButton);
66156618
resetButton.addActionListener(e -> {
66166619
tagsMap.keySet().forEach( tagName -> saveTagColor(tagName, null));

‎src/main/java/sc/fiji/snt/SeedManager.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,8 @@ protected void paintComponent(final Graphics g) {
409409
pushTableSelectionToOverlay();
410410
});
411411

412+
GuiUtils.JTables.installAlternatingRows(seedTable);
413+
412414
// Double-click a row -> navigate the canvas to that seed (mirrors the
413415
// Bookmark Manager pattern). Editing is available via the toolbar
414416
// button and right-click menu; all cells are read-only, so there's

‎src/main/java/sc/fiji/snt/gui/GuiUtils.java‎

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1948,21 +1948,22 @@ public static JDialog showAboutDialog() {
19481948
// All info rows below are borderless JButtons (not JLabels styled to look
19491949
// clickable) so they share the same margin/insets and stay left-aligned
19501950
final String details = getImageJVersion() + " · Java " + System.getProperty("java.version");
1951-
final JButton ijDetails = infoButton(details, IconFactory.menuIcon('\ue4e5', true, IconFactory.secondaryColor()));
1951+
final Icon refIcon = IconFactory.buttonIcon('\ue4e5', true, IconFactory.secondaryColor());
1952+
final JButton ijDetails = infoButton(details, refIcon, refIcon);
19521953
ijDetails.setToolTipText("Click to display detailed system information");
19531954
side.add(ijDetails, gbc);
19541955
gbc.gridy++;
19551956

19561957
final int threads = SNTPrefs.getThreads();
19571958
final int cores = Runtime.getRuntime().availableProcessors();
1958-
final JButton coresDetails = infoButton(threads + "/" + cores + " cores", GLYPH.MICROCHIP);
1959+
final JButton coresDetails = infoButton(threads + "/" + cores + " cores", GLYPH.MICROCHIP, refIcon);
19591960
coresDetails.setToolTipText("Threads used by SNT / cores available to the JVM.\nClick to change");
19601961
coresDetails.addActionListener(e -> SNTUtils.getContext().getService(CommandService.class).run(PrefsCmd.class, true));
19611962
side.add(coresDetails, gbc);
19621963
gbc.gridy++;
19631964

19641965
final SNTUtils.HeapInfo heapInfo = SNTUtils.getHeapInfo();
1965-
final JButton heapDetails = infoButton(heapInfo.usedMB() + "/" + heapInfo.maxMB() + " MB memory", GLYPH.GAUGE);
1966+
final JButton heapDetails = infoButton(heapInfo.usedMB() + "/" + heapInfo.maxMB() + " MB memory", GLYPH.GAUGE, refIcon);
19661967
heapDetails.setToolTipText("Used/max heap memory.\nClick to open ImageJ's memory monitor");
19671968
heapDetails.addActionListener(e -> {
19681969
try {
@@ -1973,7 +1974,7 @@ public static JDialog showAboutDialog() {
19731974
side.add(heapDetails, gbc);
19741975
gbc.gridy++;
19751976

1976-
final JButton cacheDetails = infoButton("Cache: calculating...", GLYPH.DATABASE);
1977+
final JButton cacheDetails = infoButton("Cache: calculating...", GLYPH.DATABASE, refIcon);
19771978
cacheDetails.setToolTipText("Click to open\n" + SNTUtils.getCacheDir().getAbsolutePath());
19781979
cacheDetails.addActionListener(e -> {
19791980
try {
@@ -1985,7 +1986,7 @@ public static JDialog showAboutDialog() {
19851986
side.add(cacheDetails, gbc);
19861987
gbc.gridy++;
19871988

1988-
final JButton gpuDetails = infoButton("Max OpenGL: querying...", GLYPH.CUBE);
1989+
final JButton gpuDetails = infoButton("Max OpenGL: querying...", GLYPH.CUBE, refIcon);
19891990
gpuDetails.setEnabled(false); // enabled once GLUtils.getInfo() resolves, below
19901991
side.add(gpuDetails, gbc);
19911992
gbc.gridy++;
@@ -2070,23 +2071,23 @@ private static void reportTempMsgOnButtonLabel(final AbstractButton button, fina
20702071
}
20712072

20722073
/** Borderless, zero-margin, left-aligned icon+text button used for the About dialog's info rows */
2073-
private static JButton infoButton(final String text, final Icon icon) {
2074-
final JButton button = new JButton(text, icon);
2074+
private static JButton infoButton(final String text, final Icon icon, final Icon refIcon) {
2075+
final JButton button = new JButton(text, IconFactory.fixedWidthIcon(icon, refIcon));
20752076
button.setForeground(IconFactory.secondaryColor());
20762077
Buttons.makeBorderless(button);
20772078
button.setHorizontalAlignment(SwingConstants.LEFT);
20782079
button.setMargin(new Insets(0, 0, 0, 0));
20792080
return button;
20802081
}
20812082

2082-
private static JButton infoButton(final String text, final GLYPH glyph) {
2083-
return infoButton(text, IconFactory.menuIcon(glyph, IconFactory.secondaryColor()));
2083+
private static JButton infoButton(final String text, final GLYPH glyph, final Icon refIcon) {
2084+
return infoButton(text, IconFactory.buttonIcon(glyph, IconFactory.secondaryColor(), 1f), refIcon);
20842085
}
20852086

20862087
/** Borderless icon+text button that opens {@code url} when clicked */
20872088
private static JButton urlButton(final String label, final String url, final GLYPH glyph) {
20882089
final Color c = SNTColor.average(List.of(IconFactory.defaultColor(), IconFactory.selectedColor()));
2089-
final JButton button = new JButton(label, IconFactory.menuIcon(glyph, c));
2090+
final JButton button = new JButton(label, IconFactory.buttonIcon(glyph, c, 1f));
20902091
button.setForeground(c);
20912092
Buttons.makeBorderless(button);
20922093
button.addActionListener(e -> openURL(url));
@@ -4218,6 +4219,38 @@ public Component getTableCellRendererComponent(final JTable t, final Object valu
42184219
}
42194220
}
42204221

4222+
/**
4223+
* Applies a subtle alternating-row background tint to a table (zebra striping), without requiring a custom
4224+
* {@code JTable} subclass. Wraps the default renderer registered for each of the table's column classes so
4225+
* that unselected rows alternate between the table's own background and a slight tint towards its foreground
4226+
* color.
4227+
* <p>
4228+
* Only affects columns that rely on the class-based default renderer (the normal case). A column with a renderer
4229+
* assigned directly via {@link javax.swing.table.TableColumn#setCellRenderer(javax.swing.table.TableCellRenderer)}
4230+
* bypasses the class-based lookup and is left untouched by this method.
4231+
*
4232+
* @param table the table to stripe
4233+
*/
4234+
public static void installAlternatingRows(final JTable table) {
4235+
final double tintWeight = 0.06; // small values (0.05-0.08) work best
4236+
final Set<Class<?>> columnClasses = new LinkedHashSet<>();
4237+
for (int i = 0; i < table.getColumnCount(); i++) {
4238+
columnClasses.add(table.getColumnClass(i));
4239+
}
4240+
for (final Class<?> columnClass : columnClasses) {
4241+
final javax.swing.table.TableCellRenderer original = table.getDefaultRenderer(columnClass);
4242+
if (original == null) continue;
4243+
table.setDefaultRenderer(columnClass, (tbl, value, isSelected, hasFocus, row, column) -> {
4244+
final Component c = original.getTableCellRendererComponent(tbl, value, isSelected, hasFocus, row, column);
4245+
if (!isSelected) {
4246+
c.setBackground((row % 2 == 0) ? tbl.getBackground()
4247+
: SNTColor.mix(tbl.getBackground(), tbl.getForeground(), tintWeight));
4248+
}
4249+
return c;
4250+
});
4251+
}
4252+
}
4253+
42214254
/**
42224255
* Auto-sizes the preferred width of the given column to fit its content,
42234256
* with padding.
@@ -4533,7 +4566,7 @@ protected void paintComponent(final Graphics g) {
45334566
*
45344567
* @param table the table to scroll (must be inside a {@link JScrollPane})
45354568
*/
4536-
private static void scrollToBottom(final JTable table) {
4569+
public static void scrollToBottom(final JTable table) {
45374570
SwingUtilities.invokeLater(() -> {
45384571
table.revalidate();
45394572
SwingUtilities.invokeLater(() -> {

‎src/main/java/sc/fiji/snt/gui/IconFactory.java‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,11 @@ public static Icon menuIcon(final char symbol, final boolean solid, final Color
299299
}
300300

301301
public static Icon listIcon(final JList<?> list, final GLYPH entry) {
302-
return new FADerivedIcon(entry.id, list.getFont().getSize() * 0.9f, list.getForeground(), entry.solid);
302+
return listIcon(list, entry, list.getForeground());
303+
}
304+
305+
public static Icon listIcon(final JList<?> list, final GLYPH entry, final Color color) {
306+
return new FADerivedIcon(entry.id, list.getFont().getSize() * 0.9f, color, entry.solid);
303307
}
304308

305309
public static void assignTabIcon(final JTabbedPane tabbedPane, final int tabIndex, final GLYPH entry) {
@@ -503,7 +507,16 @@ public static Icon accentIcon(final Color color, final boolean squarify) {
503507
* @return the centered fixed-width icon
504508
*/
505509
public static Icon fixedWidthIcon(final Icon icon, final Icon refIcon) {
506-
final int refWidth = refIcon.getIconWidth();
510+
return IconFactory.fixedWidthIcon(icon, refIcon.getIconWidth());
511+
}
512+
513+
/**
514+
* Wraps an icon in a fixed-width icon, centering it within a common reference.
515+
* @param icon the icon to be matched to reference
516+
* @param refWidth the target width
517+
* @return the centered fixed-width icon
518+
*/
519+
public static Icon fixedWidthIcon(final Icon icon, final int refWidth) {
507520
final int width = Math.max(icon.getIconWidth(), refWidth);
508521
return new Icon() {
509522
@Override

0 commit comments

Comments
 (0)