diff --git a/src/main/java/sc/fiji/snt/PathManagerUI.java b/src/main/java/sc/fiji/snt/PathManagerUI.java index 28f99064..a8f153d3 100644 --- a/src/main/java/sc/fiji/snt/PathManagerUI.java +++ b/src/main/java/sc/fiji/snt/PathManagerUI.java @@ -2258,10 +2258,17 @@ protected void saveTable() { protected void measureCells() { final Collection trees = getMultipleTrees(); if (trees == null) return; - if (!MeasureUI.instances.isEmpty()) { - guiUtils.error("A Measurements prompt seems to be already open."); - MeasureUI.instances.get(MeasureUI.instances.size()-1).toFront(); - } else { + boolean newInstance = true; + if (MeasureUI.instances != null && !MeasureUI.instances.isEmpty()) { + if (guiUtils.getConfirmation("A Measurements prompt seems to be already open. Close it?", + "Measurements Prompt Already Open")) { + MeasureUI.instances.get(MeasureUI.instances.size() - 1).dispose(); + } else { + newInstance = false; + MeasureUI.instances.get(MeasureUI.instances.size()-1).toFront(); + } + } + if (newInstance) { new MeasureUI(plugin, trees).setVisible(true); } } diff --git a/src/main/java/sc/fiji/snt/SNTUI.java b/src/main/java/sc/fiji/snt/SNTUI.java index 9c2e3e8b..299ec77f 100644 --- a/src/main/java/sc/fiji/snt/SNTUI.java +++ b/src/main/java/sc/fiji/snt/SNTUI.java @@ -351,9 +351,8 @@ public void windowClosing(final WindowEvent e) { InternalUtils.addSeparatorWithURL(tab3, "Legacy 3D Viewer:", true, c3); ++c3.gridy; final String msg2 = - "The Legacy 3D Viewer is a functional tracing canvas " + - "but it depends on outdated services that are now deprecated. " + - "It may not function reliably on recent operating systems."; + "The Legacy 3D Viewer is a functional tracing canvas but it depends on " + + "stalled services that may not function reliably during complex tasks."; tab3.add(largeMsg(msg2), c3); c3.gridy++; try { diff --git a/src/main/java/sc/fiji/snt/gui/MeasureUI.java b/src/main/java/sc/fiji/snt/gui/MeasureUI.java index 3523d9b1..176a6aab 100644 --- a/src/main/java/sc/fiji/snt/gui/MeasureUI.java +++ b/src/main/java/sc/fiji/snt/gui/MeasureUI.java @@ -70,6 +70,7 @@ public class MeasureUI extends JFrame { private static final Class[] columnClasses = new Class[] { String.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class }; public static final List instances = new ArrayList<>(); + private final MeasurePanel panel; @Parameter private PrefService prefService; @@ -100,7 +101,7 @@ private MeasureUI(final Context context, final Collection trees) { super("SNT Measurements"); context.inject(this); guiUtils = new GuiUtils(this); - final MeasurePanel panel = new MeasurePanel(trees); + panel = new MeasurePanel(trees); add(panel); pack(); instances.add(this); @@ -110,19 +111,22 @@ private MeasureUI(final Context context, final Collection trees) { public void windowClosing(final WindowEvent e) { final boolean exit = backgroundTask == null || backgroundTask.isDone() || guiUtils.getConfirmation( "Measurements are still being retrieved. Interrupt nevertheless?", "Interrupt?"); - if (exit) { - panel.savePreferences(); - instances.remove(MeasureUI.this); - if (backgroundTask != null && !backgroundTask.isDone()) { - backgroundTask.cancel(true); - backgroundTask.done(); - } - dispose(); - } + if (exit) dispose(); } }); } + @Override + public void dispose() { + panel.savePreferences(); + instances.remove(MeasureUI.this); + if (backgroundTask != null && !backgroundTask.isDone()) { + backgroundTask.cancel(true); + backgroundTask.done(); + } + super.dispose(); + } + @Override public void setVisible(final boolean b) { // Script friendly version @@ -173,6 +177,7 @@ class MeasurePanel extends JPanel { private static final long serialVersionUID = 1L; private final CheckBoxList metricList; private final DefaultTableModel statsTableModel; + private final JButton runButton; @SuppressWarnings("unchecked") MeasurePanel(final Collection trees) { @@ -285,7 +290,8 @@ public void componentResized(final ComponentEvent e) { TablePopupMenu.install(statsTable, statsTableScrollPane); add(statsTableScrollPane, c); - final JButton runButton = new JButton("Measure " + trees.size() + " Reconstruction(s)"); + runButton = new JButton("Measure 100 Comp. Reconstruction(s)"); + updateRunButtonLabel(trees.size()); runButton.addActionListener(new GenerateTableAction(trees, statsTableModel)); final JButton optionsButton = optionsButton(trees); GuiUtils.equalizeHeight(runButton, optionsButton); @@ -304,6 +310,16 @@ public void componentResized(final ComponentEvent e) { add(buttonPanel, c); } + private void updateRunButtonLabel(final int nTrees) { + SwingUtilities.invokeLater(() -> { + runButton.setText( + String.format("Measure %d %s Reconstruction(s)", nTrees, (distinguishCompartments) ? "Comp. " : "")); + runButton.setToolTipText((distinguishCompartments) + ? "Measurements will be split into known compartments\n(axon, dendrites, etc.)" + : "Measurements will be retrieved for the whole cell\nwithout compartment (axon, dendrites, etc.) distinction"); + }); + } + private JButton optionsButton(final Collection trees) { final JButton optionsButton = new JButton(IconFactory.getButtonIcon(IconFactory.GLYPH.OPTIONS, 1.3f)); optionsButton.setToolTipText("Options & Utilities"); @@ -311,8 +327,11 @@ private JButton optionsButton(final Collection trees) { GuiUtils.addSeparator(optionsMenu, "Options:"); final JCheckBoxMenuItem jcmi1 = new JCheckBoxMenuItem("Distinguish Compartments", distinguishCompartments); - jcmi1.addActionListener(e -> distinguishCompartments = jcmi1.isSelected()); - jcmi1.setToolTipText("Whether measurements should be grouped by cellular\n" + jcmi1.addActionListener(e -> { + distinguishCompartments = jcmi1.isSelected(); + updateRunButtonLabel(trees.size()); + }); + jcmi1.setToolTipText("Whether measurements should be slip into cellular\n" + "compartment (e.g., \"axon\", \"dendrites\", etc.)"); optionsMenu.add(jcmi1); final JCheckBoxMenuItem jcmi4 = new JCheckBoxMenuItem("Debug mode", SNTUtils.isDebugMode()); diff --git a/src/main/java/sc/fiji/snt/gui/SNTCommandFinder.java b/src/main/java/sc/fiji/snt/gui/SNTCommandFinder.java index 84fd53af..22451f71 100644 --- a/src/main/java/sc/fiji/snt/gui/SNTCommandFinder.java +++ b/src/main/java/sc/fiji/snt/gui/SNTCommandFinder.java @@ -22,14 +22,7 @@ package sc.fiji.snt.gui; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.Insets; -import java.awt.Rectangle; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; @@ -49,35 +42,13 @@ import java.util.Map; import java.util.TreeMap; -import javax.swing.AbstractAction; -import javax.swing.AbstractButton; -import javax.swing.Action; -import javax.swing.ActionMap; -import javax.swing.InputMap; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JRootPane; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.JTextField; -import javax.swing.JToggleButton; -import javax.swing.KeyStroke; -import javax.swing.ListSelectionModel; -import javax.swing.MenuElement; -import javax.swing.SwingUtilities; -import javax.swing.UIManager; +import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; +import org.scijava.ui.awt.AWTWindows; import org.scijava.util.PlatformUtils; import com.formdev.flatlaf.FlatClientProperties; @@ -136,21 +107,6 @@ public SNTCommandFinder(final Viewer3D viewer3D) { guiUtils = new GuiUtils(viewer3D.getFrame()); } - void install(final JMenu toolsMenu) { - final Action action = new AbstractAction(NAME) { - - private static final long serialVersionUID = -7030359886427866104L; - - @Override - public void actionPerformed(final ActionEvent e) { - toggleVisibility(); - } - - }; - action.putValue(Action.ACCELERATOR_KEY, ACCELERATOR); - toolsMenu.add(new JMenuItem(action)); - } - Map getShortcuts() { if (!cmdScrapper.scrapeSuccessful()) cmdScrapper.scrape(); @@ -530,12 +486,6 @@ JToggleButton recordButton( ) { }); return recButton; } - - @Override - Font getPlaceholderFont() { - return getFont().deriveFont(Font.ITALIC); - } - } private class PromptDocumentListener implements DocumentListener { @@ -658,17 +608,11 @@ void center() { } void center(final Container component) { - if (component == null) - return; - final Rectangle bounds = component.getBounds(); - final Dimension w = getSize(); - int x = bounds.x + (bounds.width - w.width) / 2; - int y = bounds.y + (bounds.height - w.height) / 2; - if (x < 0) - x = 0; //component.getX(); - if (y < 0) - y = 0;// component.getY(); - setLocation(x, y); + if (component == null) { + AWTWindows.centerWindow(this); + } else { + AWTWindows.centerWindow(component.getBounds(), this); + } } } diff --git a/src/main/java/sc/fiji/snt/gui/cmds/FigCreatorCmd.java b/src/main/java/sc/fiji/snt/gui/cmds/FigCreatorCmd.java index f5420436..371aa0f3 100644 --- a/src/main/java/sc/fiji/snt/gui/cmds/FigCreatorCmd.java +++ b/src/main/java/sc/fiji/snt/gui/cmds/FigCreatorCmd.java @@ -109,12 +109,16 @@ private void init() { final ArrayList choices = new ArrayList<>(mi.getChoices()); choices.remove(0); mi.setChoices(choices); + } else { + resolveInput("noRasterOutput"); } if (noGeodesicTransformation) { final MutableModuleItem mi = (MutableModuleItem) getInfo().getInput("uprightRotation", String.class); final ArrayList choices = new ArrayList<>(mi.getChoices()); choices.remove(1); mi.setChoices(choices); + } else { + resolveInput("noGeodesicTransformation"); } } diff --git a/src/main/java/sc/fiji/snt/plugin/TreeMapperCmd.java b/src/main/java/sc/fiji/snt/plugin/TreeMapperCmd.java index 52d68124..d7db4e2f 100644 --- a/src/main/java/sc/fiji/snt/plugin/TreeMapperCmd.java +++ b/src/main/java/sc/fiji/snt/plugin/TreeMapperCmd.java @@ -41,6 +41,7 @@ import org.scijava.plugin.Plugin; import org.scijava.prefs.PrefService; import org.scijava.util.ColorRGB; +import org.scijava.util.Colors; import org.scijava.widget.Button; import sc.fiji.snt.analysis.*; @@ -102,6 +103,10 @@ public class TreeMapperCmd extends CommonDynamicCmd { @Override public void run() { + if (nanColor == null) { + error("Color for \"undefined values\" has not been specified. Please define it and re-run."); + return; + } statusService.showStatus("Applying Color Code..."); SNTUtils.log("Color Coding Tree (" + measurementChoice + ") using " + lutChoice); @@ -120,15 +125,15 @@ public void run() { try { if (trees.size() == 1) { mapper = new TreeColorMapper(context()); - mapper.setMinMax(Double.NaN, Double.NaN); - if (nanColor != null) - mapper.setNaNColor(new Color(nanColor.getRed(), nanColor.getGreen(), nanColor.getBlue())); - mapper.map(trees.iterator().next(), measurementChoice, colorTable); } else { mapper = new MultiTreeColorMapper(trees); - mapper.setMinMax(Double.NaN, Double.NaN); - if (nanColor != null) - mapper.setNaNColor(new Color(nanColor.getRed(), nanColor.getGreen(), nanColor.getBlue())); + } + mapper.setMinMax(Double.NaN, Double.NaN); + if (nanColor != null) + mapper.setNaNColor(new Color(nanColor.getRed(), nanColor.getGreen(), nanColor.getBlue())); + if (trees.size() == 1) { + mapper.map(trees.iterator().next(), measurementChoice, colorTable); + } else { mapper.map(measurementChoice, colorTable); } } catch (final IllegalArgumentException exc) { @@ -157,6 +162,8 @@ private void init() { resolveInput("onlyConnectivitySafeMetrics"); if (lutChoice == null) lutChoice = prefService.get(getClass(), "lutChoice", "mpl-viridis.lut"); + if (nanColor == null) + nanColor = Colors.GRAY; setChoices(); setLUTs(); } diff --git a/src/main/java/sc/fiji/snt/viewer/Viewer3D.java b/src/main/java/sc/fiji/snt/viewer/Viewer3D.java index ae819528..4a415fde 100644 --- a/src/main/java/sc/fiji/snt/viewer/Viewer3D.java +++ b/src/main/java/sc/fiji/snt/viewer/Viewer3D.java @@ -4560,13 +4560,20 @@ private JPopupMenu measureMenu() { mi.addActionListener(e -> { List trees = getSelectedTrees(); if (trees == null || trees.isEmpty()) return; - initTable(); + boolean newInstance = true; if (MeasureUI.instances != null && !MeasureUI.instances.isEmpty()) { - guiUtils.error("A Measurements prompt seems to be already open."); - MeasureUI.instances.get(MeasureUI.instances.size()-1).toFront(); - trees = null; - } else { + if (guiUtils.getConfirmation("A Measurements prompt seems to be already open. Close it?", + "Measurements Prompt Already Open")) { + MeasureUI.instances.get(MeasureUI.instances.size() - 1).dispose(); + } else { + newInstance = false; + MeasureUI.instances.get(MeasureUI.instances.size()-1).toFront(); + trees = null; + } + } + if (newInstance) { final MeasureUI measureUI = new MeasureUI(trees); + initTable(); measureUI.setTable(table); measureUI.setVisible(true); }