Skip to content

Commit e8c02bf

Browse files
committed
Code cleanup: Consolidate BigViewer code
1 parent 6c8ed96 commit e8c02bf

3 files changed

Lines changed: 115 additions & 155 deletions

File tree

‎src/main/java/sc/fiji/snt/viewer/AbstractBigViewer.java‎

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,45 @@ void resizeCardPanelsAsNeeded(final JComponent refPanel) {
355355
* @param step current step (0-based; ignored in indeterminate mode)
356356
* @param nSteps total steps (0 = hide, negative = indeterminate)
357357
*/
358-
public abstract void updateStatus(String message, int step, int nSteps);
358+
public void updateStatus(final String message, final int step, final int nSteps) {
359+
SwingUtilities.invokeLater(() -> {
360+
if (progressBar == null) return;
361+
if (nSteps == 0) {
362+
progressBar.setIndeterminate(false);
363+
progressBar.setVisible(false);
364+
progressBar.setValue(0);
365+
progressBar.setString("");
366+
} else if (nSteps < 0) {
367+
progressBar.setIndeterminate(true);
368+
progressBar.setString(message == null ? "" : message);
369+
progressBar.setVisible(true);
370+
} else {
371+
progressBar.setIndeterminate(false);
372+
progressBar.setMaximum(nSteps);
373+
progressBar.setValue(step);
374+
progressBar.setString(message == null ? "" : message);
375+
progressBar.setVisible(true);
376+
}
377+
});
378+
}
379+
380+
/** Progress bar docked at the bottom of the card panel: see {@link #initProgressBar} */
381+
private JProgressBar progressBar;
382+
383+
/**
384+
* Creates the progress bar driven by {@link #updateStatus(String, int, int)} and docks it at the
385+
* bottom of the card panel, below all cards and without a card header. This avoids the viewport
386+
* flicker caused by adding the bar to the frame's BorderLayout.SOUTH.
387+
*
388+
* @param cardPanel the viewer's card panel
389+
*/
390+
protected void initProgressBar(final bdv.ui.CardPanel cardPanel) {
391+
progressBar = new JProgressBar(0, 100);
392+
progressBar.setStringPainted(true);
393+
progressBar.setString("");
394+
progressBar.setVisible(false);
395+
addToCardPanelBottom(cardPanel, progressBar);
396+
}
359397

360398
/**
361399
* Forces {@code snt}'s image metadata (dimensions, calibration, pixel data, channel/frame) to be
@@ -839,6 +877,61 @@ protected static void registerCommandFinderAccelerator(final InputMap sntIMap, f
839877
private static final java.util.concurrent.atomic.AtomicInteger keyframeCounter =
840878
new java.util.concurrent.atomic.AtomicInteger(1);
841879

880+
/**
881+
* Registers SNT's viewer keybindings shared by Bvv and Bdv: {@code M} (marker), {@code H}
882+
* (hold to hide annotations), {@code L} (secondary layer), {@code P} (pick sigma point) and,
883+
* if a tracer is available, the tracing shortcuts (G, Shift+G, Enter, Esc, Z, Space). They must
884+
* go through BDV/BVV's keybindings system, since its input trigger layer shadows ordinary Swing
885+
* InputMaps. Same {@code sntIMap}/{@code sntAMap} constraints as
886+
* {@link #registerCommandFinderAccelerator}.
887+
*
888+
* @param sntIMap the viewer's own SNT-overlay {@link InputMap}, not yet installed
889+
* @param sntAMap the matching {@link ActionMap}, not yet installed
890+
* @param actions the viewer's {@link Actions}
891+
* @param addMarker the action bound to {@code M}
892+
* @param tracer the viewer's tracer, or {@code null} if tracing is unavailable
893+
*/
894+
protected void registerSntKeybindings(final InputMap sntIMap, final ActionMap sntAMap,
895+
final Actions actions, final Action addMarker, final AbstractTracer tracer) {
896+
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_M, 0), "snt-add-marker");
897+
sntAMap.put("snt-add-marker", addMarker);
898+
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_H, 0, false), "snt-hide-annotations-press");
899+
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_H, 0, true), "snt-hide-annotations-release");
900+
sntAMap.put("snt-hide-annotations-press", actions.hideAnnotationsPressAction());
901+
sntAMap.put("snt-hide-annotations-release", actions.hideAnnotationsReleaseAction());
902+
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_L, 0), "snt-toggle-secondary-layer");
903+
sntAMap.put("snt-toggle-secondary-layer", actions.toggleSecondaryLayerTracingAction());
904+
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0), "snt-pick-sigma-point");
905+
sntAMap.put("snt-pick-sigma-point", actions.pickSigmaPointAction());
906+
if (tracer == null) return;
907+
// Grab Nearest Path/Add Nearest Path to Selection: mirrors InteractiveTracerCanvas's
908+
// G/Shift+G shortcuts on the classic canvas (see AbstractTracer#getSelectNearestPathAction).
909+
// NB: this intentionally shadows BDV/BVV's own native "toggle grouping" (plain G)
910+
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_G, 0), "snt-select-nearest-path");
911+
sntAMap.put("snt-select-nearest-path", tracer.getSelectNearestPathAction(false));
912+
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.SHIFT_DOWN_MASK), "snt-append-nearest-path");
913+
sntAMap.put("snt-append-nearest-path", tracer.getSelectNearestPathAction(true));
914+
// Finish/discard the in-progress tracing path without a canvas click: a double click to finish is
915+
// itself a click, and its first (clickCount==1) event is indistinguishable from an ordinary
916+
// "extend path" click, so it lands a spurious node right next to the previous. Enter/Esc avoids
917+
// this since neither is a MouseEvent
918+
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "snt-finish-path");
919+
sntAMap.put("snt-finish-path", tracer.getFinishPathAction());
920+
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "snt-discard-path");
921+
sntAMap.put("snt-discard-path", tracer.getDiscardPathAction());
922+
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0), "snt-undo-segment"); // see Tracer#undoLastSegment
923+
sntAMap.put("snt-undo-segment", tracer.getUndoSegmentAction());
924+
// Space: a quick tap flips tracing on/off permanently (like clicking No tracing/Manual/Interactive);
925+
// holding it past a threshold instead changes to "No tracing" for as long as it's held and snaps
926+
// back on release (mirrors InteractiveTracerCanvas#mousePressed hold-Space-to-pan convention). See
927+
// AbstractTracer#getToggleTracingHoldPressAction/ReleaseAction for the tap/hold logic (shadows BDV's own native
928+
// Space binding)
929+
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), "snt-toggle-tracing-hold-press");
930+
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true), "snt-toggle-tracing-hold-release");
931+
sntAMap.put("snt-toggle-tracing-hold-press", tracer.getToggleTracingHoldPressAction());
932+
sntAMap.put("snt-toggle-tracing-hold-release", tracer.getToggleTracingHoldReleaseAction());
933+
}
934+
842935
/**
843936
* Registers the {@code K} hotkey that captures a {@link Keyframe}: the script-ready line is
844937
* printed to the console and copied to the clipboard. Same {@code sntIMap}/{@code sntAMap}

‎src/main/java/sc/fiji/snt/viewer/Bdv.java‎

Lines changed: 19 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ public static Bdv getInstance() {
123123
// Grace period added on top of an animated setViewerTransform()'s own duration before a trace click
124124
// is accepted again; mirrors Bvv's own RECENTER_SETTLE_BUFFER_MS constant/rationale.
125125
private static final long TRANSFORM_SETTLE_BUFFER_MS = 150;
126-
private JProgressBar progressBar; // Docked at CardPanel bottom; see updateStatus()
127126

128127

129128

@@ -640,32 +639,6 @@ public void repaint() {
640639
if (viewerPanel != null) viewerPanel.requestRepaint();
641640
}
642641

643-
/**
644-
* @see AbstractBigViewer#updateStatus(String, int, int)
645-
*/
646-
@Override
647-
public void updateStatus(final String message, final int step, final int nSteps) {
648-
SwingUtilities.invokeLater(() -> {
649-
if (progressBar == null) return;
650-
if (nSteps == 0) {
651-
progressBar.setIndeterminate(false);
652-
progressBar.setVisible(false);
653-
progressBar.setValue(0);
654-
progressBar.setString("");
655-
} else if (nSteps < 0) {
656-
progressBar.setIndeterminate(true);
657-
progressBar.setString(message == null ? "" : message);
658-
progressBar.setVisible(true);
659-
} else {
660-
progressBar.setIndeterminate(false);
661-
progressBar.setMaximum(nSteps);
662-
progressBar.setValue(step);
663-
progressBar.setString(message == null ? "" : message);
664-
progressBar.setVisible(true);
665-
}
666-
});
667-
}
668-
669642
/**
670643
* @see AbstractBigViewer#resyncCalibrationFromActiveSource()
671644
*/
@@ -917,6 +890,23 @@ private void updateSliceClip(final AffineTransform3D transform) {
917890
annotationOverlay.setCamParams(Double.MAX_VALUE, slabZ, slabZ);
918891
}
919892

893+
/** Places a marker at the current mouse position (M key) */
894+
private Action addMarkerAction() {
895+
return new AbstractAction("Add Marker") {
896+
@Override
897+
public void actionPerformed(final java.awt.event.ActionEvent e) {
898+
if (blockMarkerPlacement()) return;
899+
final RealPoint pos = new RealPoint(3);
900+
getGlobalMouseCoordinates(pos);
901+
final double x = pos.getDoublePosition(0);
902+
final double y = pos.getDoublePosition(1);
903+
final double z = pos.getDoublePosition(2);
904+
getMarkerManager().add(x, y, z);
905+
showViewerMessage(String.format("Marker placed at (%.1f, %.1f, %.1f)", x, y, z));
906+
}
907+
};
908+
}
909+
920910
private void initializeCardPanel() {
921911
// addCard() below builds JComponents (Card/HeaderPanel) directly, which is
922912
// unsafe if this runs off-EDT (e.g. from a SciJava command thread): it can
@@ -944,68 +934,14 @@ private void initializeCardPanel() {
944934
cp.setCardExpanded("SNT Controls", true);
945935
});
946936
resizeCardPanelsAsNeeded(cp.getComponent());
947-
// Progress bar: docked at the bottom of the card panel, below all cards, without a card
948-
// header - see Bvv's identical placement for why (avoids viewport flicker vs. BorderLayout.SOUTH)
949-
progressBar = new JProgressBar(0, 100);
950-
progressBar.setStringPainted(true);
951-
progressBar.setString("");
952-
progressBar.setVisible(false);
953-
addToCardPanelBottom(cp, progressBar);
937+
initProgressBar(cp);
954938
}
955939

956940
// M and H keys via BDV's keybindings system so the trigger layer sees them
957941
if (bdvHandle.getSplitPanel().getTopLevelAncestor() instanceof bdv.viewer.ViewerFrame vf) {
958942
final javax.swing.InputMap sntIMap = new javax.swing.InputMap();
959943
final javax.swing.ActionMap sntAMap = new javax.swing.ActionMap();
960-
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_M, 0), "snt-add-marker");
961-
sntAMap.put("snt-add-marker", new AbstractAction() {
962-
@Override
963-
public void actionPerformed(final java.awt.event.ActionEvent e) {
964-
if (blockMarkerPlacement()) return;
965-
final RealPoint pos = new RealPoint(3);
966-
getGlobalMouseCoordinates(pos);
967-
final double x = pos.getDoublePosition(0);
968-
final double y = pos.getDoublePosition(1);
969-
final double z = pos.getDoublePosition(2);
970-
getMarkerManager().add(x, y, z);
971-
showViewerMessage(String.format("Marker placed at (%.1f, %.1f, %.1f)", x, y, z));
972-
}
973-
});
974-
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_H, 0, false), "snt-hide-annotations-press");
975-
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_H, 0, true), "snt-hide-annotations-release");
976-
sntAMap.put("snt-hide-annotations-press", actions.hideAnnotationsPressAction());
977-
sntAMap.put("snt-hide-annotations-release", actions.hideAnnotationsReleaseAction());
978-
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_L, 0), "snt-toggle-secondary-layer");
979-
sntAMap.put("snt-toggle-secondary-layer", actions.toggleSecondaryLayerTracingAction());
980-
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0), "snt-pick-sigma-point");
981-
sntAMap.put("snt-pick-sigma-point", actions.pickSigmaPointAction());
982-
if (tracer != null) {
983-
// Grab Nearest Path/Add Nearest Path to Selection: mirrors InteractiveTracerCanvas's
984-
// G/Shift+G shortcuts on the classic canvas (see AbstractTracer#getSelectNearestPathAction).
985-
// NB: this intentionally shadows BDV/BVV's own native "toggle grouping" (plain G)
986-
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_G, 0), "snt-select-nearest-path");
987-
sntAMap.put("snt-select-nearest-path", tracer.getSelectNearestPathAction(false));
988-
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_G, java.awt.event.InputEvent.SHIFT_DOWN_MASK), "snt-append-nearest-path");
989-
sntAMap.put("snt-append-nearest-path", tracer.getSelectNearestPathAction(true));
990-
// Finish/discard the in-progress tracing path without a canvas click (see Bvv's identical
991-
// wiring for why Enter/Esc are used instead of a double click to finish)
992-
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "snt-finish-path");
993-
sntAMap.put("snt-finish-path", tracer.getFinishPathAction());
994-
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "snt-discard-path");
995-
sntAMap.put("snt-discard-path", tracer.getDiscardPathAction());
996-
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0), "snt-undo-segment"); // see Tracer#undoLastSegment
997-
sntAMap.put("snt-undo-segment", tracer.getUndoSegmentAction());
998-
// Space: a quick tap flips tracing on/off permanently (like clicking No tracing/ Manual/Interactive);
999-
// holding it past a threshold instead changes to "No tracing" for as long as it's held and snaps back
1000-
// on release (mirrors InteractiveTracerCanvas#mousePressed hold-Space-to-pan convention). See
1001-
// AbstractTracer#getToggleTracingHoldPressAction/ReleaseAction for the tap/hold logic. Like G above,
1002-
// this intentionally shadows BDV's own native Space binding, if any, since both maps share this same
1003-
// "snt" input map
1004-
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), "snt-toggle-tracing-hold-press");
1005-
sntIMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true), "snt-toggle-tracing-hold-release");
1006-
sntAMap.put("snt-toggle-tracing-hold-press", tracer.getToggleTracingHoldPressAction());
1007-
sntAMap.put("snt-toggle-tracing-hold-release", tracer.getToggleTracingHoldReleaseAction());
1008-
}
944+
registerSntKeybindings(sntIMap, sntAMap, actions, addMarkerAction(), tracer);
1009945
registerKeyframeCapture(sntIMap, sntAMap);
1010946
// Command palette shortcut: wired unconditionally (not just in Stream mode), since the BDV
1011947
// window can be opened in classic mode too, and its own keybindings layer needs this regardless

0 commit comments

Comments
 (0)