Skip to content

Commit aa2be98

Browse files
committed
Bugfix: default colors not being set in Stream mode.
While at it Improve UX of default colors widget
1 parent f32dbbc commit aa2be98

4 files changed

Lines changed: 129 additions & 38 deletions

File tree

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

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5186,26 +5186,30 @@ protected void updateImageContent(final int resamplingFactor) {
51865186
}).start();
51875187
}
51885188

5189-
protected void setSelectedColor(final Color newColor) {
5190-
SNTPrefs.setSelectedPathColor(newColor);
5189+
/**
5190+
* Sets default path colors.
5191+
*
5192+
* @param newSelectedColor new default color for selected paths
5193+
* @param newDeselectedColor new default color for deselected paths
5194+
*/
5195+
protected void setSelectedAndDeselectedColors(final Color newSelectedColor, final Color newDeselectedColor) {
5196+
SNTPrefs.setSelectedPathColor(newSelectedColor);
5197+
SNTPrefs.setDeselectedPathColor(newDeselectedColor);
51915198
selectedColor3f = Utils.toColor3f(SNTPrefs.selectedPathColor());
5192-
if (getUI() != null && getUI().bvvSNT != null) {
5193-
getUI().bvvSNT.getRenderingOptions().selectedColor = SNTPrefs.selectedPathColor();
5194-
}
5195-
updateTracingViewers(true);
5196-
}
5197-
5198-
protected void setDeselectedColor(final Color newColor) {
5199-
SNTPrefs.setDeselectedPathColor(newColor);
52005199
deselectedColor3f = Utils.toColor3f(SNTPrefs.deselectedPathColor());
52015200
if (getUI() != null && getUI().recViewer != null) {
52025201
getUI().recViewer.setDefaultColor(new ColorRGB(SNTPrefs.deselectedPathColor().getRed(),
52035202
SNTPrefs.deselectedPathColor().getGreen(), SNTPrefs.deselectedPathColor().getBlue()));
52045203
if (pathAndFillManager.size() > 0) getUI().recViewer.syncPathManagerList();
52055204
}
52065205
if (getUI() != null && getUI().bvvSNT != null) {
5206+
getUI().bvvSNT.getRenderingOptions().selectedColor = SNTPrefs.selectedPathColor();
52075207
getUI().bvvSNT.getRenderingOptions().fallbackColor = SNTPrefs.deselectedPathColor();
52085208
}
5209+
if (getUI() != null && getUI().bdvSNT != null) {
5210+
getUI().bdvSNT.getRenderingOptions().selectedColor = SNTPrefs.selectedPathColor();
5211+
getUI().bdvSNT.getRenderingOptions().fallbackColor = SNTPrefs.deselectedPathColor();
5212+
}
52095213
updateTracingViewers(true);
52105214
}
52115215

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,16 @@ public class SNTPrefs { // TODO: Adopt PrefService
5656
public static final Color DEFAULT_DESELECTED_COLOR = Color.MAGENTA;
5757
protected static final Color3f DEFAULT_SELECTED_COLOR3F = Utils.toColor3f(Color.GREEN);
5858
protected static final Color3f DEFAULT_DESELECTED_COLOR3F = Utils.toColor3f(Color.MAGENTA);
59+
// Okabe-Ito yellow/sky-blue: safe alternative to the green/magenta defaults above for red-green color vision
60+
// deficiencies. These are high-luminance, so they should stay legible against the dark background of fluorescent
61+
// images
62+
public static final Color COLORBLIND_SAFE_SELECTED_COLOR = new Color(240, 228, 66);
63+
public static final Color COLORBLIND_SAFE_DESELECTED_COLOR = new Color(86, 180, 233);
64+
/** Default state of the "Enforce default colors over Path Manager tags" option */
65+
public static final boolean DEFAULT_ENFORCE_DEFAULT_PATH_COLORS = false;
5966
private static Color selectedColor = DEFAULT_SELECTED_COLOR;
6067
private static Color deselectedColor = DEFAULT_DESELECTED_COLOR;
61-
private boolean displayCustomPathColors = true;
68+
private boolean displayCustomPathColors = !DEFAULT_ENFORCE_DEFAULT_PATH_COLORS;
6269

6370
/* Tracing */
6471
private boolean requireShiftToFork;

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

Lines changed: 106 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.scijava.command.CommandModule;
4242
import org.scijava.command.CommandService;
4343
import org.scijava.util.Types;
44+
import sc.fiji.snt.analysis.ColorMapper;
4445
import sc.fiji.snt.analysis.SNTTable;
4546
import sc.fiji.snt.analysis.TreeStatistics;
4647
import sc.fiji.snt.analysis.curation.PlausibilityCheck;
@@ -1869,7 +1870,7 @@ private JPanel sourcePanel(final ImagePlus imp) {
18691870
});
18701871

18711872
final JCheckBox autoCTcheckbox = new JCheckBox("Auto-load channel/frame when starting new paths", plugin.autoCT);
1872-
commandFinder.register(autoCTcheckbox, "Toggle Auto-load CT Position of New Paths",
1873+
registerInCommandFinder(autoCTcheckbox, "Toggle Auto-load CT Position of New Paths",
18731874
"Main Tab", "Data Source");
18741875
GuiUtils.addTooltip(autoCTcheckbox, "Automatically loads the active channel and frame of the starting " +
18751876
"node of newly created paths.<br>" +
@@ -2624,7 +2625,7 @@ private JPanel miscPanel() {
26242625
prefsButton.addActionListener(e -> (new CmdRunner(PrefsCmd.class)).execute());
26252626
gdb.fill = GridBagConstraints.NONE;
26262627
miscPanel.add(prefsButton, gdb);
2627-
commandFinder.register(prefsButton, "Options tab");
2628+
registerInCommandFinder(prefsButton, "Options tab");
26282629
return miscPanel;
26292630
}
26302631

@@ -3340,16 +3341,16 @@ private JPanel secondaryDataPanel() {
33403341
final JMenuItem mi1 = new JMenuItem("Secondary Layer Creation Wizard...",
33413342
IconFactory.menuIcon(IconFactory.GLYPH.WIZARD));
33423343
ScriptRecorder.setRecordingCall(mi1, "snt.getUI().runSecondaryLayerWizard()");
3343-
commandFinder.register(mi1, "Main tab", "Interactive tracing (II Layer)");
3344+
registerInCommandFinder(mi1, "Main tab", "Interactive tracing (II Layer)");
33443345
mi1.setToolTipText("Create a secondary layer using built-in image processing routines");
33453346
mi1.addActionListener(e -> runSecondaryLayerWizard(true));
33463347
final JMenuItem mi2 = GuiUtils.MenuItems.fromOpenImage();
33473348
mi2.addActionListener(e -> loadSecondaryImage(true));
33483349
mi2.setEnabled(!plugin.isStreamMode());
3349-
commandFinder.register(mi2, "Main tab", "Interactive tracing (II Layer)");
3350+
registerInCommandFinder(mi2, "Main tab", "Interactive tracing (II Layer)");
33503351
final JMenuItem mi3 = GuiUtils.MenuItems.fromFileImage();
33513352
mi3.addActionListener(e -> loadSecondaryImage(false));
3352-
commandFinder.register(mi3, "Main tab", "Interactive tracing (II Layer)");
3353+
registerInCommandFinder(mi3, "Main tab", "Interactive tracing (II Layer)");
33533354
final JMenuItem mi4 = new JMenuItem("Flush Current Layer...", IconFactory.menuIcon(IconFactory.GLYPH.TOILET));
33543355
registerInCommandFinder(mi4, "Flush Secondary Layer", "Main tab", "Interactive tracing");
33553356
mi4.addActionListener(e -> {
@@ -3371,7 +3372,7 @@ private JPanel secondaryDataPanel() {
33713372
(new DynamicCmdRunner(WekaModelLoader.class, null)).run();
33723373
});
33733374
ScriptRecorder.setRecordingCall(mi5, "snt.getUI().runCommand(\"From Labkit/TWS Model...\")");
3374-
commandFinder.register(mi5, "Main tab", "Interactive tracing (II Layer)");
3375+
registerInCommandFinder(mi5, "Main tab", "Interactive tracing (II Layer)");
33753376
GuiUtils.addSeparator(secLayerMenu, "Create:");
33763377
secLayerMenu.add(mi1);
33773378
GuiUtils.addSeparator(secLayerMenu, "Load Precomputed:");
@@ -3384,7 +3385,7 @@ private JPanel secondaryDataPanel() {
33843385
secLayerMenu.addSeparator();
33853386
final JMenuItem mi6 = GuiUtils.MenuItems.openHelpURL("Help on Secondary Layers",
33863387
"https://imagej.net/plugins/snt/manual#tracing-on-secondary-image");
3387-
commandFinder.register(mi6, "Main tab", "Interactive tracing (II Layer)");
3388+
registerInCommandFinder(mi6, "Main tab", "Interactive tracing (II Layer)");
33883389
secLayerMenu.add(mi6);
33893390

33903391
// Assemble panel
@@ -4467,14 +4468,14 @@ private JPanel renderingPanel() {
44674468
}
44684469

44694470
private JPanel colorOptionsPanel() {
4470-
final ColorChooserButton colorChooser1 = new ColorChooserButton(SNTPrefs.selectedPathColor(), " Selected: ");
4471+
final ColorChooserButton colorChooser1 = new ColorChooserButton(SNTPrefs.selectedPathColor(), "Selected: ");
44714472
colorChooser1.setName("Color for Selected Paths");
44724473
colorChooser1.addColorChangedListener(newColor -> {
44734474
if (SNTPrefs.deselectedPathColor().equals(newColor)) {
44744475
guiError("Selected and deselected colors cannot be the same.");
4475-
colorChooser1.setSelectedColor(SNTPrefs.selectedPathColor(), true);
4476+
colorChooser1.setSelectedColor(SNTPrefs.selectedPathColor(), false); // revert only, no need to re-notify
44764477
} else {
4477-
plugin.setSelectedColor(newColor);
4478+
plugin.setSelectedAndDeselectedColors(newColor, SNTPrefs.deselectedPathColor());
44784479
}
44794480
});
44804481
registerInCommandFinder(colorChooser1, "Default color for selected paths", "Main Tab");
@@ -4483,13 +4484,13 @@ private JPanel colorOptionsPanel() {
44834484
colorChooser2.addColorChangedListener(newColor -> {
44844485
if (SNTPrefs.selectedPathColor().equals(newColor)) {
44854486
guiError("Selected and deselected colors cannot be the same.");
4486-
colorChooser2.setSelectedColor(SNTPrefs.deselectedPathColor(), true);
4487+
colorChooser2.setSelectedColor(SNTPrefs.deselectedPathColor(), false); // revert only, no need to re-notify
44874488
} else {
4488-
plugin.setDeselectedColor(newColor);
4489+
plugin.setSelectedAndDeselectedColors(SNTPrefs.selectedPathColor(), newColor);
44894490
}
44904491
});
44914492
registerInCommandFinder(colorChooser2, "Default color for deselected paths", "Main Tab");
4492-
final JCheckBox jcheckbox = new JCheckBox("Override color tags with default colors", !plugin.getPrefs().getDisplayCustomPathColors());
4493+
final JCheckBox jcheckbox = new JCheckBox("Enforce default colors over Path Manager tags", !plugin.getPrefs().getDisplayCustomPathColors());
44934494
//jcheckbox.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
44944495
GuiUtils.addTooltip(jcheckbox,
44954496
"Whether default colors above should be used even when color tags have been applied in the Path Manager.<br><br>" +
@@ -4499,35 +4500,113 @@ private JPanel colorOptionsPanel() {
44994500
plugin.getPrefs().setDisplayCustomPathColors(!jcheckbox.isSelected());
45004501
plugin.updateTracingViewers(true);
45014502
});
4502-
final JButton resetButton1 = resetButton("default path colors");
4503+
final JButton resetButton1 = resetButton("default selected color");
45034504
resetButton1.addActionListener( e-> {
45044505
colorChooser1.setSelectedColor(SNTPrefs.DEFAULT_SELECTED_COLOR, true);
4505-
showStatus("Default path colors reset", true);
4506+
showStatus("Selected color reset", true);
45064507
});
4507-
final JButton resetButton2 = resetButton("default path colors");
4508+
final JButton resetButton2 = resetButton("default deselected color");
45084509
resetButton2.addActionListener( e-> {
45094510
colorChooser2.setSelectedColor(SNTPrefs.DEFAULT_DESELECTED_COLOR, true);
4510-
showStatus("Default path colors reset", true);
4511+
showStatus("Deselected color reset", true);
45114512
});
4513+
4514+
4515+
// Assemble elements
45124516
final JToolBar toolbar = new JToolBar();
4517+
toolbar.setFloatable(false);
45134518
toolbar.setBackground(null);
4514-
toolbar.add(Box.createHorizontalGlue());
4519+
toolbar.setBorder(null); // don't let the toolbar add its own inset
4520+
toolbar.setMargin(null);
4521+
final int gap = jcheckbox.getIconTextGap();
4522+
for (final ColorChooserButton cb : new ColorChooserButton[]{colorChooser1, colorChooser2}) {
4523+
final Insets m = cb.getMargin();
4524+
cb.setMargin(new Insets(m.top, gap, m.bottom, m.right));
4525+
}
4526+
GuiUtils.Buttons.addToGroup(List.of(colorChooser1, resetButton1));
45154527
toolbar.add(colorChooser1);
45164528
toolbar.add(resetButton1);
4517-
GuiUtils.Buttons.addToGroup(List.of(colorChooser1, resetButton1));
4518-
toolbar.add(Box.createHorizontalStrut(InternalUtils.MARGIN * 2));
4529+
toolbar.add(Box.createHorizontalStrut(InternalUtils.MARGIN));
45194530
toolbar.addSeparator();
4520-
toolbar.add(Box.createHorizontalStrut(InternalUtils.MARGIN * 2));
4531+
toolbar.add(Box.createHorizontalStrut(InternalUtils.MARGIN));
45214532
toolbar.add(colorChooser2);
45224533
toolbar.add(resetButton2);
45234534
GuiUtils.Buttons.addToGroup(List.of(colorChooser2, resetButton2));
4524-
toolbar.add(Box.createHorizontalGlue());
4525-
final JPanel panel = new JPanel(new BorderLayout());
4526-
panel.add(toolbar, BorderLayout.CENTER);
4527-
panel.add(jcheckbox, BorderLayout.SOUTH);
4535+
4536+
final JPanel topPanel = new JPanel(new BorderLayout());
4537+
topPanel.setBorder(null);
4538+
topPanel.add(toolbar, BorderLayout.WEST);
4539+
topPanel.add(resetPathColorsOptionsButton(colorChooser1, colorChooser2, jcheckbox), BorderLayout.EAST);
4540+
4541+
final JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
4542+
bottomPanel.setBorder(null);
4543+
bottomPanel.add(jcheckbox);
4544+
4545+
final JPanel panel = new JPanel();
4546+
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
4547+
panel.setBorder(null); // don't let the panel add its own inset
4548+
panel.add(topPanel);
4549+
panel.add(bottomPanel);
45284550
return panel;
45294551
}
45304552

4553+
private JButton resetPathColorsOptionsButton(final ColorChooserButton selected, final ColorChooserButton deselected,
4554+
final JCheckBox enforceDefaultColorsCheckbox) {
4555+
final JPopupMenu optionsMenu = new JPopupMenu();
4556+
final JButton optionsButton = GuiUtils.Buttons.OptionsButton(GLYPH.DROPLET, 1f, optionsMenu);
4557+
GuiUtils.addTooltip(optionsButton, "More options for default path colors");
4558+
JMenuItem jmi = new JMenuItem("Swap Selected/Deselected Colors", IconFactory.menuIcon(GLYPH.ARROWS_LR));
4559+
jmi.addActionListener(e -> {
4560+
final Color currentSelected = selected.getSelectedColor();
4561+
final Color currentDeselected = deselected.getSelectedColor();
4562+
// Bypass the ColorChooserButtons' own "colors cannot match" guard. Set both
4563+
// colors in one call so only one BVV/BDV resync/repaint happens, not two racing
4564+
// ones (see SNT#setSelectedAndDeselectedColors)
4565+
selected.setSelectedColor(currentDeselected, false);
4566+
deselected.setSelectedColor(currentSelected, false);
4567+
plugin.setSelectedAndDeselectedColors(currentDeselected, currentSelected);
4568+
showStatus("Selected/Deselected colors swapped", true);
4569+
});
4570+
registerInCommandFinder(jmi, null, "Main tab", "Default Path Colors");
4571+
optionsMenu.add(jmi);
4572+
jmi = new JMenuItem("Use Colorblind-Safe Colors", IconFactory.menuIcon(GLYPH.EYE_LOW_VISION));
4573+
jmi.setToolTipText("Applies an Okabe-Ito colorblind-safe yellow/sky-blue pair");
4574+
jmi.addActionListener(e -> {
4575+
selected.setSelectedColor(SNTPrefs.COLORBLIND_SAFE_SELECTED_COLOR, false);
4576+
deselected.setSelectedColor(SNTPrefs.COLORBLIND_SAFE_DESELECTED_COLOR, false);
4577+
plugin.setSelectedAndDeselectedColors(SNTPrefs.COLORBLIND_SAFE_SELECTED_COLOR,
4578+
SNTPrefs.COLORBLIND_SAFE_DESELECTED_COLOR);
4579+
showStatus("Colorblind-safe path colors applied", true);
4580+
});
4581+
registerInCommandFinder(jmi, null, "Main tab", "Default Path Colors");
4582+
optionsMenu.add(jmi);
4583+
optionsMenu.addSeparator();
4584+
jmi = new JMenuItem("Discard All Path Manager Color Tags/Mappings...", IconFactory.menuIcon(GLYPH.BROOM));
4585+
jmi.addActionListener(e -> {
4586+
if (!noPathsError() && guiUtils.getConfirmation(
4587+
"Remove color mappings/tags from all paths?", "Reset Path Colors?")) {
4588+
ColorMapper.unMap(pathAndFillManager.getPaths());
4589+
plugin.updateAllViewers();
4590+
}
4591+
});
4592+
registerInCommandFinder(jmi, null, "Main tab", "Default Path Colors");
4593+
optionsMenu.add(jmi);
4594+
optionsMenu.addSeparator();
4595+
jmi = new JMenuItem("Reset Defaults", IconFactory.menuIcon(GLYPH.UNDO));
4596+
jmi.addActionListener(e -> {
4597+
// Bypass the guard/listener on all three settings and drive plugin/prefs directly
4598+
selected.setSelectedColor(SNTPrefs.DEFAULT_SELECTED_COLOR, false);
4599+
deselected.setSelectedColor(SNTPrefs.DEFAULT_DESELECTED_COLOR, false);
4600+
plugin.setSelectedAndDeselectedColors(SNTPrefs.DEFAULT_SELECTED_COLOR, SNTPrefs.DEFAULT_DESELECTED_COLOR);
4601+
enforceDefaultColorsCheckbox.setSelected(SNTPrefs.DEFAULT_ENFORCE_DEFAULT_PATH_COLORS);
4602+
plugin.getPrefs().setDisplayCustomPathColors(!SNTPrefs.DEFAULT_ENFORCE_DEFAULT_PATH_COLORS);
4603+
showStatus("Color settings reset", true);
4604+
});
4605+
registerInCommandFinder(jmi, null, "Main tab", "Default Path Colors");
4606+
optionsMenu.add(jmi);
4607+
return optionsButton;
4608+
}
4609+
45314610
private JPanel snappingPanel() {
45324611

45334612
tracingOptionsPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
@@ -4672,7 +4751,7 @@ public void itemStateChanged(final ItemEvent e) {
46724751
// the best one visually (SigmaPalette-style)
46734752
final JMenuItem tuneCost = new JMenuItem("Cost Function Selection Wizard...", IconFactory.menuIcon(GLYPH.WIZARD));
46744753
tuneCost.setToolTipText("Compare cost-function variants on a probe segment to pick the most suitable one");
4675-
commandFinder.register(tuneCost, "Main tab", "Interactive Tracing", "Algorithm Settings");
4754+
registerInCommandFinder(tuneCost, null, "Main tab", "Interactive Tracing", "Algorithm Settings");
46764755
tuneCost.addActionListener(e -> {
46774756
final CommandService cs = plugin.getContext().getService(CommandService.class);
46784757
if (cs != null) cs.run(CostFunctionSelectionCmd.class, true);
@@ -4760,7 +4839,7 @@ protected void done() {
47604839
final JRadioButtonMenuItem rubberBandTracingRbmi = new JRadioButtonMenuItem("Live Preview", plugin.rubberBandTracing);
47614840
GuiUtils.addTooltip(rubberBandTracingRbmi, "<html>Continuously previews the path to the cursor position as you move the mouse."
47624841
+ "(ala NeuronJ).<br>Click to confirm each segment. <b>Only recommended for 2D images.");
4763-
commandFinder.register(rubberBandTracingRbmi, "Main tab", "Interactive Tracing", "Algorithm Settings");
4842+
registerInCommandFinder(rubberBandTracingRbmi, "Main tab", "Interactive Tracing", "Algorithm Settings");
47644843
tracingModeButtonGroup.add(standardTracingRbmi);
47654844
tracingModeButtonGroup.add(rubberBandTracingRbmi);
47664845
optionsMenu.add(standardTracingRbmi);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ public enum GLYPH {
115115
DOWNLOAD('\uf019', true), //
116116
DOTCIRCLE('\uf192', true), //
117117
DRAFT('\uf568', true), //
118+
DROPLET('\uf043', true ), //
118119
ELLIPSIS('\uf141', true), //
119120
EQUALS('\uf52c', true), //
120121
EXPAND('\uf065', true), //

0 commit comments

Comments
 (0)