From fc057d6ba372a822527a9d3e9dd030b269d45e3c Mon Sep 17 00:00:00 2001 From: Jean-Yves Tinevez Date: Sat, 9 Sep 2023 12:49:09 +0200 Subject: [PATCH 01/12] A specific KeymapManager for LabKit. - Defines a scope and key config context for LabKit. - Load keymaps from a user config dir specific to LabKit. - Collect command descriptions specific to LabKit. --- .../fiji/labkit/ui/LabKitKeymapManager.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/main/java/sc/fiji/labkit/ui/LabKitKeymapManager.java diff --git a/src/main/java/sc/fiji/labkit/ui/LabKitKeymapManager.java b/src/main/java/sc/fiji/labkit/ui/LabKitKeymapManager.java new file mode 100644 index 00000000..ecdd6c58 --- /dev/null +++ b/src/main/java/sc/fiji/labkit/ui/LabKitKeymapManager.java @@ -0,0 +1,41 @@ +package sc.fiji.labkit.ui; + +import org.scijava.Context; +import org.scijava.plugin.PluginService; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider.Scope; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionsBuilder; + +import bdv.ui.keymap.KeymapManager; + +public class LabKitKeymapManager extends KeymapManager +{ + + private static final String LABKIT_KEYMAP_DIR = System.getProperty( "user.home" ) + "/.labkit/keymaps"; + + /** The key-config scope for LabKit actions. */ + public static final Scope LABKIT_SCOPE = new Scope( "sc.fiji.labkit" ); + + /** The key-config context for LabKit actions. */ + public static final String LABKIT_CONTEXT = "labkit"; + + public LabKitKeymapManager() + { + super( LABKIT_KEYMAP_DIR ); + } + + /** + * Discover all {@code CommandDescriptionProvider}s with the LabKit scope. + */ + @Override + public synchronized void discoverCommandDescriptions() + { + final CommandDescriptionsBuilder builder = new CommandDescriptionsBuilder(); + try (final Context context = new Context( PluginService.class )) + { + context.inject( builder ); + builder.discoverProviders( LABKIT_SCOPE ); + context.dispose(); + setCommandDescriptions( builder.build() ); + } + } +} From efdf5b2a50df2a9fc172d7e474cca1032084fcb1 Mon Sep 17 00:00:00 2001 From: Jean-Yves Tinevez Date: Sat, 9 Sep 2023 12:51:09 +0200 Subject: [PATCH 02/12] An action that shows a preferences dialog for LabKit. Containing only a page to set the keymap. Also added to the Help menu using the original menu system of LabKit. --- .../actions/ShowPreferencesDialogAction.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/main/java/sc/fiji/labkit/ui/actions/ShowPreferencesDialogAction.java diff --git a/src/main/java/sc/fiji/labkit/ui/actions/ShowPreferencesDialogAction.java b/src/main/java/sc/fiji/labkit/ui/actions/ShowPreferencesDialogAction.java new file mode 100644 index 00000000..2add867b --- /dev/null +++ b/src/main/java/sc/fiji/labkit/ui/actions/ShowPreferencesDialogAction.java @@ -0,0 +1,91 @@ +/*- + * #%L + * The Labkit image segmentation tool for Fiji. + * %% + * Copyright (C) 2017 - 2023 Matthias Arzt + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package sc.fiji.labkit.ui.actions; + +import java.awt.Frame; + +import org.scijava.plugin.Plugin; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; +import org.scijava.ui.behaviour.io.gui.CommandDescriptions; +import org.scijava.ui.behaviour.util.Actions; + +import bdv.tools.PreferencesDialog; +import bdv.tools.ToggleDialogAction; +import bdv.ui.keymap.Keymap; +import bdv.ui.keymap.KeymapManager; +import bdv.ui.keymap.KeymapSettingsPage; +import sc.fiji.labkit.ui.Extensible; +import sc.fiji.labkit.ui.LabKitKeymapManager; +import sc.fiji.labkit.ui.MenuBar; + +public class ShowPreferencesDialogAction +{ + + public static final String ACTION_NAME = "show preferences dialog"; + + public static final String[] ACTION_DEFAULT_KEYS = new String[] { "control P" }; + + public static final String ACTION_DESCRIPTION = "Shows the preferences dialog."; + + public ShowPreferencesDialogAction( + final Extensible extensible, + final Actions actions, + final KeymapManager keymapManager, + final Frame owner ) + { + final Keymap keymap = keymapManager.getForwardSelectedKeymap(); + final PreferencesDialog preferencesDialog = new PreferencesDialog( owner, keymap, new String[] { LabKitKeymapManager.LABKIT_CONTEXT } ); + preferencesDialog.addPage( new KeymapSettingsPage( "Keymap", keymapManager, keymapManager.getCommandDescriptions() ) ); + final ToggleDialogAction action = new ToggleDialogAction( ACTION_NAME, preferencesDialog ); + actions.namedAction( action, ACTION_DEFAULT_KEYS ); + + extensible.addMenuItem( MenuBar.HELP_MENU, + "Preferences", + 99, + ignore -> action.actionPerformed( null ), + null, null ); + } + + @Plugin( type = CommandDescriptionProvider.class ) + public static class Descriptions extends CommandDescriptionProvider + { + public Descriptions() + { + super( LabKitKeymapManager.LABKIT_SCOPE, LabKitKeymapManager.LABKIT_CONTEXT ); + } + + @Override + public void getCommandDescriptions( final CommandDescriptions descriptions ) + { + descriptions.add( ACTION_NAME, ACTION_DEFAULT_KEYS, ACTION_DESCRIPTION ); + descriptions.add( "close dialog window", new String[] { "control W" }, "Closes the preferences dialog." ); + } + } +} From 0e85fd5a508d2152e5f6e9f648d898e84bf4915c Mon Sep 17 00:00:00 2001 From: Jean-Yves Tinevez Date: Sat, 9 Sep 2023 12:51:21 +0200 Subject: [PATCH 03/12] A dummy example action. --- .../fiji/labkit/ui/actions/ExampleAction.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/main/java/sc/fiji/labkit/ui/actions/ExampleAction.java diff --git a/src/main/java/sc/fiji/labkit/ui/actions/ExampleAction.java b/src/main/java/sc/fiji/labkit/ui/actions/ExampleAction.java new file mode 100644 index 00000000..d2f72b84 --- /dev/null +++ b/src/main/java/sc/fiji/labkit/ui/actions/ExampleAction.java @@ -0,0 +1,50 @@ +package sc.fiji.labkit.ui.actions; + +import java.awt.event.ActionEvent; + +import org.scijava.plugin.Plugin; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; +import org.scijava.ui.behaviour.io.gui.CommandDescriptions; +import org.scijava.ui.behaviour.util.AbstractNamedAction; +import org.scijava.ui.behaviour.util.Actions; + +import sc.fiji.labkit.ui.LabKitKeymapManager; + +public class ExampleAction extends AbstractNamedAction +{ + + private static final long serialVersionUID = 1L; + + public static final String ACTION_NAME = "example action"; + + public static final String[] ACTION_DEFAULT_KEYS = new String[] { "A" }; + + public static final String ACTION_DESCRIPTION = "Print a useless message."; + + public ExampleAction( final Actions actions ) + { + super( ACTION_NAME ); + actions.namedAction( this, ACTION_DEFAULT_KEYS ); + } + + @Override + public void actionPerformed( final ActionEvent e ) + { + System.out.println( "TROLOLO" ); // DEBUG + } + + @Plugin( type = CommandDescriptionProvider.class ) + public static class Descriptions extends CommandDescriptionProvider + { + public Descriptions() + { + super( LabKitKeymapManager.LABKIT_SCOPE, LabKitKeymapManager.LABKIT_CONTEXT ); + } + + @Override + public void getCommandDescriptions( final CommandDescriptions descriptions ) + { + descriptions.add( ACTION_NAME, ACTION_DEFAULT_KEYS, ACTION_DESCRIPTION ); + } + } +} From f8f3a47dc0452536c7d23db8c60cafeb996b97aa Mon Sep 17 00:00:00 2001 From: Jean-Yves Tinevez Date: Sat, 9 Sep 2023 12:56:41 +0200 Subject: [PATCH 04/12] Use the LabKit keymap manager in main LabKit window. This is just a toy example: It *adds* an Actions object, set to the LabKit context, to the existing shortcuts. The actions added to the Actions are linked to the keymap manager, and the keybindings can be edited in the preferences dialog. The keys that the user edits in the preferences dialog are saved to the labkit config dir ( home / .labkit / keymaps ). Right now there are just 3 actions: - show the preferences dialog - close it - the dummy example action that prints a useless message. --- .../fiji/labkit/ui/SegmentationComponent.java | 63 ++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java b/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java index ec633edd..41ab36bb 100644 --- a/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java +++ b/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java @@ -6,13 +6,13 @@ * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -29,7 +29,37 @@ package sc.fiji.labkit.ui; -import sc.fiji.labkit.ui.actions.*; +import java.awt.BorderLayout; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import javax.swing.SwingUtilities; + +import org.scijava.ui.behaviour.util.Actions; +import org.scijava.ui.behaviour.util.InputActionBindings; + +import bdv.ui.keymap.Keymap; +import bdv.ui.keymap.Keymap.UpdateListener; +import bdv.ui.keymap.KeymapManager; +import net.miginfocom.swing.MigLayout; +import sc.fiji.labkit.ui.actions.AddLabelingIoAction; +import sc.fiji.labkit.ui.actions.BatchSegmentAction; +import sc.fiji.labkit.ui.actions.BitmapImportExportAction; +import sc.fiji.labkit.ui.actions.ClassifierIoAction; +import sc.fiji.labkit.ui.actions.ClassifierSettingsAction; +import sc.fiji.labkit.ui.actions.ExampleAction; +import sc.fiji.labkit.ui.actions.LabelEditAction; +import sc.fiji.labkit.ui.actions.LabelingIoAction; +import sc.fiji.labkit.ui.actions.ResetViewAction; +import sc.fiji.labkit.ui.actions.SegmentationAsLabelAction; +import sc.fiji.labkit.ui.actions.SegmentationExportAction; +import sc.fiji.labkit.ui.actions.ShowHelpAction; +import sc.fiji.labkit.ui.actions.ShowPreferencesDialogAction; import sc.fiji.labkit.ui.menu.MenuKey; import sc.fiji.labkit.ui.models.ColoredLabelsModel; import sc.fiji.labkit.ui.models.Holder; @@ -42,10 +72,6 @@ import sc.fiji.labkit.ui.plugin.MeasureConnectedComponents; import sc.fiji.labkit.ui.segmentation.PredictionLayer; import sc.fiji.labkit.ui.segmentation.TrainClassifier; -import net.miginfocom.swing.MigLayout; - -import javax.swing.*; -import java.awt.*; /** * {@link SegmentationComponent} is the central Labkit UI component. Provides UI @@ -67,9 +93,19 @@ public class SegmentationComponent extends JPanel implements AutoCloseable { private final SegmentationModel segmentationModel; + private final KeymapManager keymapManager; + + private final Actions actions; + + private final InputActionBindings keybindings; + + private final JFrame dialogBoxOwner; + + public SegmentationComponent(JFrame dialogBoxOwner, SegmentationModel segmentationModel, boolean unmodifiableLabels) { + this.dialogBoxOwner = dialogBoxOwner; this.extensible = new DefaultExtensible(segmentationModel.context(), dialogBoxOwner); this.unmodifiableLabels = unmodifiableLabels; @@ -77,6 +113,17 @@ public SegmentationComponent(JFrame dialogBoxOwner, ImageLabelingModel imageLabelingModel = segmentationModel.imageLabelingModel(); labelingComponent = new BasicLabelingComponent(dialogBoxOwner, imageLabelingModel); labelingComponent.addBdvLayer(PredictionLayer.createPredictionLayer(segmentationModel)); + + keybindings = new InputActionBindings(); + SwingUtilities.replaceUIActionMap( this, keybindings.getConcatenatedActionMap() ); + SwingUtilities.replaceUIInputMap( this, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keybindings.getConcatenatedInputMap() ); + keymapManager = new LabKitKeymapManager(); + final Keymap keymap = keymapManager.getForwardSelectedKeymap(); + actions = new Actions( keymap.getConfig(), new String[] { LabKitKeymapManager.LABKIT_CONTEXT } ); + actions.install( keybindings, "labkit" ); + final UpdateListener updateListener = () -> actions.updateKeyConfig( keymap.getConfig() ); + keymap.updateListeners().add( updateListener ); + initActions(); setLayout(new BorderLayout()); add(initGui()); @@ -101,6 +148,8 @@ private void initActions() { labelingModel)); MeasureConnectedComponents.addAction(extensible, labelingModel); new ShowHelpAction(extensible); + new ShowPreferencesDialogAction( extensible, actions, keymapManager, dialogBoxOwner ); + new ExampleAction( actions ); labelingComponent.addShortcuts(extensible.getShortCuts()); } From f5e0b82e2af262ad69a4ebde9a7e5f286c6450aa Mon Sep 17 00:00:00 2001 From: Jean-Yves Tinevez Date: Sat, 9 Sep 2023 18:31:02 +0200 Subject: [PATCH 05/12] Add the BDV context to the keymap manager. --- src/main/java/sc/fiji/labkit/ui/LabKitKeymapManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/sc/fiji/labkit/ui/LabKitKeymapManager.java b/src/main/java/sc/fiji/labkit/ui/LabKitKeymapManager.java index ecdd6c58..0a4bbb59 100644 --- a/src/main/java/sc/fiji/labkit/ui/LabKitKeymapManager.java +++ b/src/main/java/sc/fiji/labkit/ui/LabKitKeymapManager.java @@ -5,6 +5,7 @@ import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider.Scope; import org.scijava.ui.behaviour.io.gui.CommandDescriptionsBuilder; +import bdv.KeyConfigScopes; import bdv.ui.keymap.KeymapManager; public class LabKitKeymapManager extends KeymapManager @@ -33,7 +34,7 @@ public synchronized void discoverCommandDescriptions() try (final Context context = new Context( PluginService.class )) { context.inject( builder ); - builder.discoverProviders( LABKIT_SCOPE ); + builder.discoverProviders(LABKIT_SCOPE, KeyConfigScopes.BIGDATAVIEWER); context.dispose(); setCommandDescriptions( builder.build() ); } From 721f87d6de9c475c709072dfb02a1589cf27ab27 Mon Sep 17 00:00:00 2001 From: Jean-Yves Tinevez Date: Sat, 9 Sep 2023 18:39:37 +0200 Subject: [PATCH 06/12] Make the key bindings of the BSV navigation editable. --- .../labkit/ui/BasicLabelingComponent.java | 64 +++++++++++++++++-- .../fiji/labkit/ui/SegmentationComponent.java | 7 +- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/main/java/sc/fiji/labkit/ui/BasicLabelingComponent.java b/src/main/java/sc/fiji/labkit/ui/BasicLabelingComponent.java index 09cf2481..323a4c95 100644 --- a/src/main/java/sc/fiji/labkit/ui/BasicLabelingComponent.java +++ b/src/main/java/sc/fiji/labkit/ui/BasicLabelingComponent.java @@ -29,26 +29,43 @@ package sc.fiji.labkit.ui; +import java.awt.Adjustable; +import java.awt.BorderLayout; +import java.util.Collection; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSlider; + +import org.scijava.ui.behaviour.util.AbstractNamedAction; +import org.scijava.ui.behaviour.util.Actions; +import org.scijava.ui.behaviour.util.Behaviours; +import org.scijava.ui.behaviour.util.InputActionBindings; +import org.scijava.ui.behaviour.util.TriggerBehaviourBindings; + +import bdv.ui.keymap.Keymap; +import bdv.ui.keymap.KeymapManager; import bdv.ui.splitpanel.SplitPanel; import bdv.util.BdvHandle; import bdv.util.BdvHandlePanel; import bdv.util.BdvOptions; import bdv.util.BdvStackSource; import bdv.viewer.DisplayMode; +import bdv.viewer.NavigationActions; +import bdv.viewer.ViewerPanel; +import net.miginfocom.swing.MigLayout; import sc.fiji.labkit.ui.bdv.BdvAutoContrast; import sc.fiji.labkit.ui.bdv.BdvLayer; import sc.fiji.labkit.ui.bdv.BdvLayerLink; -import sc.fiji.labkit.ui.brush.*; +import sc.fiji.labkit.ui.brush.ChangeLabel; +import sc.fiji.labkit.ui.brush.FloodFillController; +import sc.fiji.labkit.ui.brush.LabelBrushController; +import sc.fiji.labkit.ui.brush.PlanarModeController; +import sc.fiji.labkit.ui.brush.SelectLabelController; import sc.fiji.labkit.ui.labeling.LabelsLayer; import sc.fiji.labkit.ui.models.Holder; import sc.fiji.labkit.ui.models.ImageLabelingModel; import sc.fiji.labkit.ui.panel.LabelToolsPanel; -import net.miginfocom.swing.MigLayout; -import org.scijava.ui.behaviour.util.AbstractNamedAction; - -import javax.swing.*; -import java.awt.*; -import java.util.Collection; /** * A swing UI component that shows a Big Data Viewer panel and a tool bar for @@ -68,11 +85,19 @@ public class BasicLabelingComponent extends JPanel implements AutoCloseable { private JSlider zSlider; + private KeymapManager keymapManager; + public BasicLabelingComponent(final JFrame dialogBoxOwner, final ImageLabelingModel model) { + this(dialogBoxOwner, model, null); + } + + public BasicLabelingComponent(final JFrame dialogBoxOwner, final ImageLabelingModel model, + KeymapManager keymapManager) { this.model = model; this.dialogBoxOwner = dialogBoxOwner; + this.keymapManager = keymapManager; initBdv(model.spatialDimensions().numDimensions() < 3); actionsAndBehaviours = new ActionsAndBehaviours(bdvHandle); @@ -85,8 +110,33 @@ public BasicLabelingComponent(final JFrame dialogBoxOwner, private void initBdv(boolean is2D) { final BdvOptions options = BdvOptions.options(); if (is2D) options.is2D(); + if (keymapManager != null) options.keymapManager(keymapManager); + bdvHandle = new BdvHandlePanel(dialogBoxOwner, options); bdvHandle.getViewerPanel().setDisplayMode(DisplayMode.FUSED); + + if (keymapManager != null) { + ViewerPanel viewer = bdvHandle.getViewerPanel(); + + InputActionBindings keybindings = bdvHandle.getKeybindings(); + TriggerBehaviourBindings triggerbindings = bdvHandle.getTriggerbindings(); + + Keymap keymap = keymapManager.getForwardSelectedKeymap(); + + final Actions actions = new Actions(keymap.getConfig(), "bdv"); + actions.install(keybindings, "view"); + + Behaviours behaviours = new Behaviours(keymap.getConfig(), "bdv"); + behaviours.install(triggerbindings, "view"); + + viewer.getTransformEventHandler().install(behaviours); + NavigationActions.install(actions, viewer, is2D); + + keymap.updateListeners().add(() -> { + actions.updateKeyConfig(keymap.getConfig()); + behaviours.updateKeyConfig(keymap.getConfig()); + }); + } } private void initPanel() { diff --git a/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java b/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java index 41ab36bb..ea87ad0a 100644 --- a/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java +++ b/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java @@ -110,9 +110,6 @@ public SegmentationComponent(JFrame dialogBoxOwner, dialogBoxOwner); this.unmodifiableLabels = unmodifiableLabels; this.segmentationModel = segmentationModel; - ImageLabelingModel imageLabelingModel = segmentationModel.imageLabelingModel(); - labelingComponent = new BasicLabelingComponent(dialogBoxOwner, imageLabelingModel); - labelingComponent.addBdvLayer(PredictionLayer.createPredictionLayer(segmentationModel)); keybindings = new InputActionBindings(); SwingUtilities.replaceUIActionMap( this, keybindings.getConcatenatedActionMap() ); @@ -124,6 +121,10 @@ public SegmentationComponent(JFrame dialogBoxOwner, final UpdateListener updateListener = () -> actions.updateKeyConfig( keymap.getConfig() ); keymap.updateListeners().add( updateListener ); + ImageLabelingModel imageLabelingModel = segmentationModel.imageLabelingModel(); + labelingComponent = new BasicLabelingComponent(dialogBoxOwner, imageLabelingModel, keymapManager); + labelingComponent.addBdvLayer(PredictionLayer.createPredictionLayer(segmentationModel)); + initActions(); setLayout(new BorderLayout()); add(initGui()); From 961200f74f1ec1be362585dcb38502123737c367 Mon Sep 17 00:00:00 2001 From: Jean-Yves Tinevez Date: Sun, 10 Sep 2023 14:45:45 +0200 Subject: [PATCH 07/12] Use static methods to install actions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "à la mastodon." --- .../fiji/labkit/ui/SegmentationComponent.java | 4 +-- .../fiji/labkit/ui/actions/ExampleAction.java | 33 +++++++++---------- .../actions/ShowPreferencesDialogAction.java | 18 ++++------ 3 files changed, 24 insertions(+), 31 deletions(-) diff --git a/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java b/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java index ea87ad0a..8c2f792b 100644 --- a/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java +++ b/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java @@ -149,8 +149,8 @@ private void initActions() { labelingModel)); MeasureConnectedComponents.addAction(extensible, labelingModel); new ShowHelpAction(extensible); - new ShowPreferencesDialogAction( extensible, actions, keymapManager, dialogBoxOwner ); - new ExampleAction( actions ); + ShowPreferencesDialogAction.install(actions, extensible, keymapManager, dialogBoxOwner); + ExampleAction.install(actions); labelingComponent.addShortcuts(extensible.getShortCuts()); } diff --git a/src/main/java/sc/fiji/labkit/ui/actions/ExampleAction.java b/src/main/java/sc/fiji/labkit/ui/actions/ExampleAction.java index d2f72b84..314537ed 100644 --- a/src/main/java/sc/fiji/labkit/ui/actions/ExampleAction.java +++ b/src/main/java/sc/fiji/labkit/ui/actions/ExampleAction.java @@ -10,8 +10,7 @@ import sc.fiji.labkit.ui.LabKitKeymapManager; -public class ExampleAction extends AbstractNamedAction -{ +public class ExampleAction extends AbstractNamedAction { private static final long serialVersionUID = 1L; @@ -21,30 +20,28 @@ public class ExampleAction extends AbstractNamedAction public static final String ACTION_DESCRIPTION = "Print a useless message."; - public ExampleAction( final Actions actions ) - { - super( ACTION_NAME ); - actions.namedAction( this, ACTION_DEFAULT_KEYS ); + public static void install(Actions actions) { + actions.namedAction(new ExampleAction(), ACTION_DEFAULT_KEYS); + } + + public ExampleAction() { + super(ACTION_NAME); } @Override - public void actionPerformed( final ActionEvent e ) - { - System.out.println( "TROLOLO" ); // DEBUG + public void actionPerformed(final ActionEvent e) { + System.out.println("TROLOLO"); // DEBUG } - @Plugin( type = CommandDescriptionProvider.class ) - public static class Descriptions extends CommandDescriptionProvider - { - public Descriptions() - { - super( LabKitKeymapManager.LABKIT_SCOPE, LabKitKeymapManager.LABKIT_CONTEXT ); + @Plugin(type = CommandDescriptionProvider.class) + public static class Descriptions extends CommandDescriptionProvider { + public Descriptions() { + super(LabKitKeymapManager.LABKIT_SCOPE, LabKitKeymapManager.LABKIT_CONTEXT); } @Override - public void getCommandDescriptions( final CommandDescriptions descriptions ) - { - descriptions.add( ACTION_NAME, ACTION_DEFAULT_KEYS, ACTION_DESCRIPTION ); + public void getCommandDescriptions(final CommandDescriptions descriptions) { + descriptions.add(ACTION_NAME, ACTION_DEFAULT_KEYS, ACTION_DESCRIPTION); } } } diff --git a/src/main/java/sc/fiji/labkit/ui/actions/ShowPreferencesDialogAction.java b/src/main/java/sc/fiji/labkit/ui/actions/ShowPreferencesDialogAction.java index 2add867b..43516b15 100644 --- a/src/main/java/sc/fiji/labkit/ui/actions/ShowPreferencesDialogAction.java +++ b/src/main/java/sc/fiji/labkit/ui/actions/ShowPreferencesDialogAction.java @@ -54,18 +54,14 @@ public class ShowPreferencesDialogAction public static final String ACTION_DESCRIPTION = "Shows the preferences dialog."; - public ShowPreferencesDialogAction( - final Extensible extensible, - final Actions actions, - final KeymapManager keymapManager, - final Frame owner ) - { + public static void install(Actions actions, Extensible extensible, KeymapManager keymapManager, Frame owner) { final Keymap keymap = keymapManager.getForwardSelectedKeymap(); - final PreferencesDialog preferencesDialog = new PreferencesDialog( owner, keymap, new String[] { LabKitKeymapManager.LABKIT_CONTEXT } ); - preferencesDialog.addPage( new KeymapSettingsPage( "Keymap", keymapManager, keymapManager.getCommandDescriptions() ) ); - final ToggleDialogAction action = new ToggleDialogAction( ACTION_NAME, preferencesDialog ); - actions.namedAction( action, ACTION_DEFAULT_KEYS ); - + final PreferencesDialog preferencesDialog = new PreferencesDialog(owner, keymap, + new String[] { LabKitKeymapManager.LABKIT_CONTEXT }); + preferencesDialog + .addPage(new KeymapSettingsPage("Keymap", keymapManager, keymapManager.getCommandDescriptions())); + final ToggleDialogAction action = new ToggleDialogAction(ACTION_NAME, preferencesDialog); + actions.namedAction(action, ACTION_DEFAULT_KEYS); extensible.addMenuItem( MenuBar.HELP_MENU, "Preferences", 99, From 118a6c7f8fc4ac96a6c04cbb51f9742a430e5a04 Mon Sep 17 00:00:00 2001 From: Jean-Yves Tinevez Date: Sun, 10 Sep 2023 15:17:51 +0200 Subject: [PATCH 08/12] Configurable shortcuts for auto-contrast and label edits. --- .../fiji/labkit/ui/SegmentationComponent.java | 22 +++++- .../labkit/ui/actions/LabelEditAction.java | 72 ++++++++++++++++++- 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java b/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java index 8c2f792b..1709a66e 100644 --- a/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java +++ b/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java @@ -40,6 +40,9 @@ import javax.swing.JSplitPane; import javax.swing.SwingUtilities; +import org.scijava.plugin.Plugin; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; +import org.scijava.ui.behaviour.io.gui.CommandDescriptions; import org.scijava.ui.behaviour.util.Actions; import org.scijava.ui.behaviour.util.InputActionBindings; @@ -145,12 +148,13 @@ private void initActions() { new BatchSegmentAction(extensible, selectedSegmenter); new SegmentationAsLabelAction(extensible, segmentationModel); new BitmapImportExportAction(extensible, labelingModel); - new LabelEditAction(extensible, unmodifiableLabels, new ColoredLabelsModel( + new LabelEditAction(actions, extensible, unmodifiableLabels, new ColoredLabelsModel( labelingModel)); MeasureConnectedComponents.addAction(extensible, labelingModel); new ShowHelpAction(extensible); ShowPreferencesDialogAction.install(actions, extensible, keymapManager, dialogBoxOwner); ExampleAction.install(actions); + actions.runnableAction(() -> labelingComponent.autoContrast(), AUTO_CONTRAST_ACTION, AUTO_CONTRAST_KEYS); labelingComponent.addShortcuts(extensible.getShortCuts()); } @@ -202,4 +206,20 @@ public JMenuBar getMenuBar() { public void autoContrast() { labelingComponent.autoContrast(); } + + private static final String AUTO_CONTRAST_ACTION = "auto contrast"; + private static final String[] AUTO_CONTRAST_KEYS = new String[] { "not mapped" }; + private static final String AUTO_CONTRAST_DESCRIPTION = "Perform auto-contrast on the current image."; + + @Plugin(type = CommandDescriptionProvider.class) + public static class Descriptions extends CommandDescriptionProvider { + public Descriptions() { + super(LabKitKeymapManager.LABKIT_SCOPE, LabKitKeymapManager.LABKIT_CONTEXT); + } + + @Override + public void getCommandDescriptions(final CommandDescriptions descriptions) { + descriptions.add(AUTO_CONTRAST_ACTION, AUTO_CONTRAST_KEYS, AUTO_CONTRAST_DESCRIPTION); + } + } } diff --git a/src/main/java/sc/fiji/labkit/ui/actions/LabelEditAction.java b/src/main/java/sc/fiji/labkit/ui/actions/LabelEditAction.java index 27e3d73f..f5c2b125 100644 --- a/src/main/java/sc/fiji/labkit/ui/actions/LabelEditAction.java +++ b/src/main/java/sc/fiji/labkit/ui/actions/LabelEditAction.java @@ -29,23 +29,34 @@ package sc.fiji.labkit.ui.actions; +import javax.swing.JOptionPane; + +import org.scijava.plugin.Plugin; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; +import org.scijava.ui.behaviour.io.gui.CommandDescriptions; +import org.scijava.ui.behaviour.util.Actions; + import sc.fiji.labkit.ui.Extensible; +import sc.fiji.labkit.ui.LabKitKeymapManager; import sc.fiji.labkit.ui.labeling.Label; import sc.fiji.labkit.ui.models.ColoredLabelsModel; -import javax.swing.*; - /** * Implements menu items for renaming and removing individual labels. Also * allows to change the order of the labels. */ public class LabelEditAction { + private final Extensible extensible; private final ColoredLabelsModel model; - public LabelEditAction(Extensible extensible, boolean fixedLabels, + public LabelEditAction(Extensible extensible, boolean fixedLabels, ColoredLabelsModel model) { + this(null, extensible, fixedLabels, model); + } + + public LabelEditAction(Actions actions, Extensible extensible, boolean fixedLabels, ColoredLabelsModel model) { this.extensible = extensible; @@ -60,6 +71,23 @@ public LabelEditAction(Extensible extensible, boolean fixedLabels, null, null); if (!fixedLabels) extensible.addMenuItem(Label.LABEL_MENU, "Remove", 201, model::removeLabel, null, null); + + // Actions. + if (actions != null) { + if (!fixedLabels) { + actions.runnableAction(() -> renameLabel(model.selected().get()), RENAME_LABEL_ACTION, + RENAME_LABEL_KEYS); + actions.runnableAction(() -> model.moveLabel(model.selected().get(), -1), MOVE_LABEL_UP_ACTION, + MOVE_LABEL_UP_KEYS); + actions.runnableAction(() -> model.moveLabel(model.selected().get(), 1), MOVE_LABEL_DOWN_ACTION, + MOVE_LABEL_DOWN_KEYS); + actions.runnableAction(() -> model.removeLabel(model.selected().get()), REMOVE_LABEL_ACTION, + REMOVE_LABEL_KEYS); + } + actions.runnableAction(() -> model.clearLabel(model.selected().get()), CLEAR_LABEL_ACTION, + CLEAR_LABEL_KEYS); + } + } private void renameLabel(Label label) { @@ -69,4 +97,42 @@ private void renameLabel(Label label) { if (newName == null) return; model.renameLabel(label, newName); } + + @Plugin(type = CommandDescriptionProvider.class) + public static class Descriptions extends CommandDescriptionProvider { + + public Descriptions() { + super(LabKitKeymapManager.LABKIT_SCOPE, LabKitKeymapManager.LABKIT_CONTEXT); + } + + @Override + public void getCommandDescriptions(final CommandDescriptions descriptions) { + descriptions.add(RENAME_LABEL_ACTION, RENAME_LABEL_KEYS, RENAME_LABEL_DESCRIPTION); + descriptions.add(MOVE_LABEL_UP_ACTION, MOVE_LABEL_UP_KEYS, MOVE_LABEL_UP_DESCRIPTION); + descriptions.add(MOVE_LABEL_DOWN_ACTION, MOVE_LABEL_DOWN_KEYS, MOVE_LABEL_DOWN_DESCRIPTION); + descriptions.add(REMOVE_LABEL_ACTION, REMOVE_LABEL_KEYS, REMOVE_LABEL_DESCRIPTION); + descriptions.add(CLEAR_LABEL_ACTION, CLEAR_LABEL_KEYS, CLEAR_LABEL_DESCRIPTION); + } + } + + private static final String RENAME_LABEL_ACTION = "rename current label"; + private static final String MOVE_LABEL_UP_ACTION = "move selected label up"; + private static final String MOVE_LABEL_DOWN_ACTION = "move selected label down"; + private static final String REMOVE_LABEL_ACTION = "remove selected label"; + private static final String CLEAR_LABEL_ACTION = "clear selected label"; + + private static final String[] RENAME_LABEL_KEYS = new String[] { "not mapped" }; + private static final String[] MOVE_LABEL_UP_KEYS = new String[] { "not mapped" }; + private static final String[] MOVE_LABEL_DOWN_KEYS = new String[] { "not mapped" }; + private static final String[] REMOVE_LABEL_KEYS = new String[] { "not mapped" }; + private static final String[] CLEAR_LABEL_KEYS = new String[] { "not mapped" }; + + private static final String RENAME_LABEL_DESCRIPTION = "Rename the label currently selected."; + private static final String MOVE_LABEL_UP_DESCRIPTION = "Move the label currently selected up in the list."; + private static final String MOVE_LABEL_DOWN_DESCRIPTION = "Move the label currently selected down in the list."; + private static final String REMOVE_LABEL_DESCRIPTION = "Remove the label currently selected."; + private static final String CLEAR_LABEL_DESCRIPTION = "Clear the annotations for the label currently selected."; + + + } From f7d181feb8e63d0fcaaf09c1438ba62fb43646b8 Mon Sep 17 00:00:00 2001 From: Jean-Yves Tinevez Date: Sun, 10 Sep 2023 15:32:33 +0200 Subject: [PATCH 09/12] Configurable shortcut for the reset view action. --- .../fiji/labkit/ui/SegmentationComponent.java | 2 +- .../labkit/ui/actions/ResetViewAction.java | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java b/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java index 1709a66e..b797825a 100644 --- a/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java +++ b/src/main/java/sc/fiji/labkit/ui/SegmentationComponent.java @@ -144,7 +144,7 @@ private void initActions() { new LabelingIoAction(extensible, labelingModel); new AddLabelingIoAction(extensible, labelingModel.labeling()); new SegmentationExportAction(extensible, labelingModel); - new ResetViewAction(extensible, labelingModel); + new ResetViewAction(actions, extensible, labelingModel); new BatchSegmentAction(extensible, selectedSegmenter); new SegmentationAsLabelAction(extensible, segmentationModel); new BitmapImportExportAction(extensible, labelingModel); diff --git a/src/main/java/sc/fiji/labkit/ui/actions/ResetViewAction.java b/src/main/java/sc/fiji/labkit/ui/actions/ResetViewAction.java index d71b2871..4f6d0b18 100644 --- a/src/main/java/sc/fiji/labkit/ui/actions/ResetViewAction.java +++ b/src/main/java/sc/fiji/labkit/ui/actions/ResetViewAction.java @@ -29,7 +29,13 @@ package sc.fiji.labkit.ui.actions; +import org.scijava.plugin.Plugin; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; +import org.scijava.ui.behaviour.io.gui.CommandDescriptions; +import org.scijava.ui.behaviour.util.Actions; + import sc.fiji.labkit.ui.Extensible; +import sc.fiji.labkit.ui.LabKitKeymapManager; import sc.fiji.labkit.ui.MenuBar; import sc.fiji.labkit.ui.models.ImageLabelingModel; import sc.fiji.labkit.ui.models.TransformationModel; @@ -41,7 +47,12 @@ */ public class ResetViewAction { + public ResetViewAction(Extensible extensible, ImageLabelingModel model) { + this(null, extensible, model); + } + + public ResetViewAction(Actions actions, Extensible extensible, ImageLabelingModel model) { Runnable action = () -> { TransformationModel transformationModel = model.transformationModel(); transformationModel.transformToShowInterval(model.labeling().get() @@ -49,5 +60,25 @@ public ResetViewAction(Extensible extensible, ImageLabelingModel model) { }; extensible.addMenuItem(MenuBar.VIEW_MENU, "Reset View", 100, ignore -> action.run(), null, ""); + + if (actions != null) { + actions.runnableAction(() -> action.run(), RESET_VIEW_ACTION, RESET_VIEW_KEYS); + } + } + + private static final String RESET_VIEW_ACTION = "reset view"; + private static final String[] RESET_VIEW_KEYS = new String[] { "not mapped" }; + private static final String RESET_VIEW_DESCRIPTION = "Reset the current image position, zoom and rotation."; + + @Plugin(type = CommandDescriptionProvider.class) + public static class Descriptions extends CommandDescriptionProvider { + public Descriptions() { + super(LabKitKeymapManager.LABKIT_SCOPE, LabKitKeymapManager.LABKIT_CONTEXT); + } + + @Override + public void getCommandDescriptions(final CommandDescriptions descriptions) { + descriptions.add(RESET_VIEW_ACTION, RESET_VIEW_KEYS, RESET_VIEW_DESCRIPTION); + } } } From 3a511e9329ee04383457a3395ed21d4ca5dacaa1 Mon Sep 17 00:00:00 2001 From: Jean-Yves Tinevez Date: Sun, 10 Sep 2023 16:23:07 +0200 Subject: [PATCH 10/12] Configurable shortcut for the planar mode toggle. To change as little code as possible we simply make an action that toggles the planar mode button. Then we register an item listener to this button, so that it is notified when it is toggled programmatically. Also, the BasicLabelingComponent has now a 2nd set of actions and behaviours, if it is provided with a KeymapManager, distinct from the ones for the BDV. --- .../labkit/ui/BasicLabelingComponent.java | 23 ++++++- .../fiji/labkit/ui/panel/LabelToolsPanel.java | 67 +++++++++++++++++-- 2 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/main/java/sc/fiji/labkit/ui/BasicLabelingComponent.java b/src/main/java/sc/fiji/labkit/ui/BasicLabelingComponent.java index 323a4c95..9fc2254c 100644 --- a/src/main/java/sc/fiji/labkit/ui/BasicLabelingComponent.java +++ b/src/main/java/sc/fiji/labkit/ui/BasicLabelingComponent.java @@ -165,6 +165,7 @@ public Holder> addBdvLayer(BdvLayer layer) { } private JPanel initToolsPanel() { + final PlanarModeController planarModeController = new PlanarModeController( bdvHandle, model, zSlider); final LabelBrushController brushController = new LabelBrushController( @@ -173,9 +174,29 @@ private JPanel initToolsPanel() { bdvHandle, model, actionsAndBehaviours); final SelectLabelController selectLabelController = new SelectLabelController(bdvHandle, model, actionsAndBehaviours); - final JPanel toolsPanel = new LabelToolsPanel(brushController, + final LabelToolsPanel toolsPanel = new LabelToolsPanel(brushController, floodFillController, selectLabelController, planarModeController); actionsAndBehaviours.addAction(new ChangeLabel(model)); + + if (keymapManager != null) { + InputActionBindings keybindings = bdvHandle.getKeybindings(); + TriggerBehaviourBindings triggerbindings = bdvHandle.getTriggerbindings(); + + Keymap keymap = keymapManager.getForwardSelectedKeymap(); + + final Actions actions = new Actions(keymap.getConfig(), "labkit"); + actions.install(keybindings, "annotating"); + + Behaviours behaviours = new Behaviours(keymap.getConfig(), "labkit"); + behaviours.install(triggerbindings, "annotating"); + + keymap.updateListeners().add(() -> { + actions.updateKeyConfig(keymap.getConfig()); + behaviours.updateKeyConfig(keymap.getConfig()); + }); + + toolsPanel.install(actions); + } return toolsPanel; } diff --git a/src/main/java/sc/fiji/labkit/ui/panel/LabelToolsPanel.java b/src/main/java/sc/fiji/labkit/ui/panel/LabelToolsPanel.java index 33d1634d..3f3aef2e 100644 --- a/src/main/java/sc/fiji/labkit/ui/panel/LabelToolsPanel.java +++ b/src/main/java/sc/fiji/labkit/ui/panel/LabelToolsPanel.java @@ -29,17 +29,35 @@ package sc.fiji.labkit.ui.panel; +import java.awt.Color; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ItemEvent; + +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.ImageIcon; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.JToggleButton; +import javax.swing.KeyStroke; + +import org.scijava.plugin.Plugin; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; +import org.scijava.ui.behaviour.io.gui.CommandDescriptions; +import org.scijava.ui.behaviour.util.AbstractNamedAction; +import org.scijava.ui.behaviour.util.Actions; import org.scijava.ui.behaviour.util.RunnableAction; + +import net.miginfocom.swing.MigLayout; +import sc.fiji.labkit.ui.LabKitKeymapManager; import sc.fiji.labkit.ui.brush.FloodFillController; import sc.fiji.labkit.ui.brush.LabelBrushController; import sc.fiji.labkit.ui.brush.PlanarModeController; import sc.fiji.labkit.ui.brush.SelectLabelController; -import net.miginfocom.swing.MigLayout; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; /** * Panel with the tool buttons for brush, flood fill, etc... Activates and @@ -80,6 +98,10 @@ public class LabelToolsPanel extends JPanel { "- Hold down the Shift key and Left Click on the image
" + " to select the label under the cursor."; + private static final String TOGGLE_PLANAR_MODE_ACTION = "toggle planar mode"; + private static final String[] TOGGLE_PLANAR_MODE_KEYS = new String[] { "not mapped" }; + private static final String TOGGLE_PLANAR_MODE_DESCRIPTION = "Toggle between slice-by-slice editing and 3d editing."; + private final FloodFillController floodFillController; private final LabelBrushController brushController; private final SelectLabelController selectLabelController; @@ -89,6 +111,7 @@ public class LabelToolsPanel extends JPanel { private final ButtonGroup group = new ButtonGroup(); private Mode mode = ignore -> {}; + private AbstractNamedAction togglePlanarModeAction; public LabelToolsPanel(LabelBrushController brushController, FloodFillController floodFillController, SelectLabelController selectLabelController, @@ -150,13 +173,14 @@ private JPanel initOptionPanel() { private JToggleButton initPlanarModeButton() { JToggleButton button = new JToggleButton(); + this.togglePlanarModeAction = createTogglePlanarModeAction(button); ImageIcon rotateIcon = getIcon("/images/rotate.png"); ImageIcon planarIcon = getIcon("/images/planes.png"); button.setIcon(rotateIcon); button.setFocusable(false); String ENABLE_TEXT = "Click to: Enable slice by slice editing of 3d images."; String DISABLE_TEXT = "Click to: Disable slice by slice editing and freely rotate 3d images."; - button.addActionListener(ignore -> { + button.addItemListener(ignore -> { boolean selected = button.isSelected(); button.setIcon(selected ? planarIcon : rotateIcon); button.setToolTipText(selected ? DISABLE_TEXT : ENABLE_TEXT); @@ -168,6 +192,18 @@ private JToggleButton initPlanarModeButton() { return button; } + private AbstractNamedAction createTogglePlanarModeAction(JToggleButton button) { + return new AbstractNamedAction(TOGGLE_PLANAR_MODE_ACTION) { + + private static final long serialVersionUID = 1L; + + @Override + public void actionPerformed(ActionEvent e) { + button.setSelected(!button.isSelected()); + } + }; + } + private JToggleButton addActionButton(String toolTipText, Mode mode, boolean visibility, String iconPath, String activationKey, String key) { @@ -251,4 +287,21 @@ private interface Mode { void setActive(boolean active); } + + public void install(Actions actions) { + actions.namedAction(togglePlanarModeAction, TOGGLE_PLANAR_MODE_KEYS); + } + + @Plugin(type = CommandDescriptionProvider.class) + public static class Descriptions extends CommandDescriptionProvider { + public Descriptions() { + super(LabKitKeymapManager.LABKIT_SCOPE, LabKitKeymapManager.LABKIT_CONTEXT); + } + + @Override + public void getCommandDescriptions(final CommandDescriptions descriptions) { + descriptions.add(TOGGLE_PLANAR_MODE_ACTION, TOGGLE_PLANAR_MODE_KEYS, TOGGLE_PLANAR_MODE_DESCRIPTION); + } + } + } From 9c9be1e1772332fea12bcba642e97cccb61e5522 Mon Sep 17 00:00:00 2001 From: Jean-Yves Tinevez Date: Sun, 10 Sep 2023 18:25:35 +0200 Subject: [PATCH 11/12] Configuragble shortcuts for the editing mode in the tools panel. Again, we simply use named actions that perform 'doClick' on the existing toggle buttons. --- .../fiji/labkit/ui/panel/LabelToolsPanel.java | 79 +++++++++++++++++-- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/src/main/java/sc/fiji/labkit/ui/panel/LabelToolsPanel.java b/src/main/java/sc/fiji/labkit/ui/panel/LabelToolsPanel.java index 3f3aef2e..2ba086f7 100644 --- a/src/main/java/sc/fiji/labkit/ui/panel/LabelToolsPanel.java +++ b/src/main/java/sc/fiji/labkit/ui/panel/LabelToolsPanel.java @@ -34,6 +34,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; +import javax.swing.AbstractButton; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; @@ -99,8 +100,28 @@ public class LabelToolsPanel extends JPanel { " to select the label under the cursor."; private static final String TOGGLE_PLANAR_MODE_ACTION = "toggle planar mode"; + private static final String TOGGLE_MOVE_MODE_ACTION = "move mode"; + private static final String TOGGLE_DRAW_MODE_ACTION = "draw mode"; + private static final String TOGGLE_FLOOD_FILL_MODE_ACTION = "flood fill mode"; + private static final String TOGGLE_ERASE_MODE_ACTION = "erase mode"; + private static final String TOGGLE_FLOOD_ERASE_MODE_ACTION = "remove connected component mode"; + private static final String TOGGLE_SELECT_LABEL_MODE_ACTION = "select label mode"; + private static final String[] TOGGLE_PLANAR_MODE_KEYS = new String[] { "not mapped" }; + private static final String[] TOGGLE_MOVE_MODE_KEYS = new String[] { "ctrl G" }; + private static final String[] TOGGLE_DRAW_MODE_KEYS = new String[] { "ctrl D" }; + private static final String[] TOGGLE_FLOOD_FILL_MODE_KEYS = new String[] { "ctrl F" }; + private static final String[] TOGGLE_ERASE_MODE_KEYS = new String[] { "ctrl E" }; + private static final String[] TOGGLE_FLOOD_ERASE_MODE_KEYS = new String[] { "ctrl R" }; + private static final String[] TOGGLE_SELECT_LABEL_MODE_KEYS = new String[] { "not mapped" }; + private static final String TOGGLE_PLANAR_MODE_DESCRIPTION = "Toggle between slice-by-slice editing and 3d editing."; + private static final String TOGGLE_MOVE_MODE_DESCRIPTION = "Activate the move mode. Clicking and dragging will move the view."; + private static final String TOGGLE_DRAW_MODE_DESCRIPTION = "Activate the draw mode. Clicking and dragging will draw the currently selected label on the annotation layer."; + private static final String TOGGLE_FLOOD_FILL_MODE_DESCRIPTION = "Activate the flood-fill mode. Clicking inside a connected component or in a closed region in the background will repaint it with the currently selected label."; + private static final String TOGGLE_ERASE_MODE_DESCRIPTION = "Activate the eraser mode. Clicking and dragging will erase any label under the mouse."; + private static final String TOGGLE_FLOOD_ERASE_MODE_DESCRIPTION = "Activate the remove-connected-component mode. Clicking inside a connected component will erase its label."; + private static final String TOGGLE_SELECT_LABEL_MODE_DESCRIPTION = "Activate the select-label mode. Clicking on a pixel will select the label it has, if any."; private final FloodFillController floodFillController; private final LabelBrushController brushController; @@ -112,6 +133,12 @@ public class LabelToolsPanel extends JPanel { private Mode mode = ignore -> {}; private AbstractNamedAction togglePlanarModeAction; + private DoClickButtonAction toggleMoveMode; + private DoClickButtonAction toggleDrawMode; + private DoClickButtonAction toggleFloodFillMode; + private DoClickButtonAction toggleEraseMode; + private DoClickButtonAction toggleFloodEraseMode; + private DoClickButtonAction toggleSelectLabelMode; public LabelToolsPanel(LabelBrushController brushController, FloodFillController floodFillController, SelectLabelController selectLabelController, @@ -143,22 +170,29 @@ private void setVisibility(boolean brushVisible) { private void initActionButtons() { JToggleButton moveBtn = addActionButton(MOVE_TOOL_TIP, ignore -> {}, false, "/images/move.png", "MOVE_TOOL", "ctrl G"); - addActionButton(DRAW_TOOL_TIP, + JToggleButton drawBtn = addActionButton(DRAW_TOOL_TIP, brushController::setBrushActive, true, "/images/draw.png", "DRAW_TOOL", "ctrl D"); - addActionButton(FLOOD_FILL_TOOL_TIP, + JToggleButton floodFillBtn = addActionButton(FLOOD_FILL_TOOL_TIP, floodFillController::setFloodFillActive, false, "/images/fill.png", "FILL_TOOL", "ctrl F"); - addActionButton(ERASE_TOOL_TIP, + JToggleButton eraseBtn = addActionButton(ERASE_TOOL_TIP, brushController::setEraserActive, true, "/images/erase.png", "ERASE_TOOL", "ctrl E"); - addActionButton(FLOOD_ERASE_TOOL_TIP, + JToggleButton floodEraseBtn = addActionButton(FLOOD_ERASE_TOOL_TIP, floodFillController::setRemoveBlobActive, false, "/images/flooderase.png", "FLOOD_ERASE_TOOL", "ctrl R"); - addActionButton(SELECT_LABEL_TOOL_TIP, + JToggleButton selectLabelBtn = addActionButton(SELECT_LABEL_TOOL_TIP, selectLabelController::setActive, false, "/images/pipette.png"); moveBtn.doClick(); + + this.toggleMoveMode = new DoClickButtonAction(moveBtn, TOGGLE_MOVE_MODE_ACTION); + this.toggleDrawMode = new DoClickButtonAction(drawBtn, TOGGLE_DRAW_MODE_ACTION); + this.toggleFloodFillMode = new DoClickButtonAction(floodFillBtn, TOGGLE_FLOOD_FILL_MODE_ACTION); + this.toggleEraseMode = new DoClickButtonAction(eraseBtn, TOGGLE_ERASE_MODE_ACTION); + this.toggleFloodEraseMode = new DoClickButtonAction(floodEraseBtn, TOGGLE_FLOOD_ERASE_MODE_ACTION); + this.toggleSelectLabelMode = new DoClickButtonAction(selectLabelBtn, TOGGLE_SELECT_LABEL_MODE_ACTION); } private JPanel initOptionPanel() { @@ -290,6 +324,31 @@ private interface Mode { public void install(Actions actions) { actions.namedAction(togglePlanarModeAction, TOGGLE_PLANAR_MODE_KEYS); + actions.namedAction(toggleMoveMode, TOGGLE_MOVE_MODE_KEYS); + actions.namedAction(toggleDrawMode, TOGGLE_DRAW_MODE_KEYS); + actions.namedAction(toggleEraseMode, TOGGLE_ERASE_MODE_KEYS); + actions.namedAction(toggleFloodFillMode, TOGGLE_FLOOD_FILL_MODE_KEYS); + actions.namedAction(toggleFloodEraseMode, TOGGLE_FLOOD_ERASE_MODE_KEYS); + actions.namedAction(toggleSelectLabelMode, TOGGLE_SELECT_LABEL_MODE_KEYS); + } + + /** + * Named action that simply clicks on a specified button. + */ + private final static class DoClickButtonAction extends AbstractNamedAction { + + private static final long serialVersionUID = 1L; + private AbstractButton button; + + public DoClickButtonAction(AbstractButton button, String name) { + super(name); + this.button = button; + } + + @Override + public void actionPerformed(ActionEvent e) { + button.doClick(); + } } @Plugin(type = CommandDescriptionProvider.class) @@ -301,7 +360,15 @@ public Descriptions() { @Override public void getCommandDescriptions(final CommandDescriptions descriptions) { descriptions.add(TOGGLE_PLANAR_MODE_ACTION, TOGGLE_PLANAR_MODE_KEYS, TOGGLE_PLANAR_MODE_DESCRIPTION); + descriptions.add(TOGGLE_MOVE_MODE_ACTION, TOGGLE_MOVE_MODE_KEYS, TOGGLE_MOVE_MODE_DESCRIPTION); + descriptions.add(TOGGLE_DRAW_MODE_ACTION, TOGGLE_DRAW_MODE_KEYS, TOGGLE_DRAW_MODE_DESCRIPTION); + descriptions.add(TOGGLE_ERASE_MODE_ACTION, TOGGLE_ERASE_MODE_KEYS, TOGGLE_ERASE_MODE_DESCRIPTION); + descriptions.add(TOGGLE_FLOOD_FILL_MODE_ACTION, TOGGLE_FLOOD_FILL_MODE_KEYS, + TOGGLE_FLOOD_FILL_MODE_DESCRIPTION); + descriptions.add(TOGGLE_FLOOD_ERASE_MODE_ACTION, TOGGLE_FLOOD_ERASE_MODE_KEYS, + TOGGLE_FLOOD_ERASE_MODE_DESCRIPTION); + descriptions.add(TOGGLE_SELECT_LABEL_MODE_ACTION, TOGGLE_SELECT_LABEL_MODE_KEYS, + TOGGLE_SELECT_LABEL_MODE_DESCRIPTION); } } - } From e5c98fcad50fc29284c700b757415a2f5790f64c Mon Sep 17 00:00:00 2001 From: Jean-Yves Tinevez Date: Sun, 10 Sep 2023 18:25:58 +0200 Subject: [PATCH 12/12] Configurable shortcut for the next label action. --- .../labkit/ui/BasicLabelingComponent.java | 4 +- .../sc/fiji/labkit/ui/brush/ChangeLabel.java | 40 ++++++++++++++++--- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/main/java/sc/fiji/labkit/ui/BasicLabelingComponent.java b/src/main/java/sc/fiji/labkit/ui/BasicLabelingComponent.java index 9fc2254c..078d51dc 100644 --- a/src/main/java/sc/fiji/labkit/ui/BasicLabelingComponent.java +++ b/src/main/java/sc/fiji/labkit/ui/BasicLabelingComponent.java @@ -176,7 +176,8 @@ private JPanel initToolsPanel() { new SelectLabelController(bdvHandle, model, actionsAndBehaviours); final LabelToolsPanel toolsPanel = new LabelToolsPanel(brushController, floodFillController, selectLabelController, planarModeController); - actionsAndBehaviours.addAction(new ChangeLabel(model)); + ChangeLabel changeLabel = new ChangeLabel(model); + actionsAndBehaviours.addAction(changeLabel); if (keymapManager != null) { InputActionBindings keybindings = bdvHandle.getKeybindings(); @@ -196,6 +197,7 @@ private JPanel initToolsPanel() { }); toolsPanel.install(actions); + changeLabel.install(actions); } return toolsPanel; } diff --git a/src/main/java/sc/fiji/labkit/ui/brush/ChangeLabel.java b/src/main/java/sc/fiji/labkit/ui/brush/ChangeLabel.java index 94706f3f..b69ea4ab 100644 --- a/src/main/java/sc/fiji/labkit/ui/brush/ChangeLabel.java +++ b/src/main/java/sc/fiji/labkit/ui/brush/ChangeLabel.java @@ -29,23 +29,35 @@ package sc.fiji.labkit.ui.brush; -import sc.fiji.labkit.ui.labeling.Label; -import sc.fiji.labkit.ui.models.LabelingModel; -import org.scijava.ui.behaviour.util.AbstractNamedAction; - -import javax.swing.*; import java.awt.event.ActionEvent; import java.util.List; +import javax.swing.AbstractAction; +import javax.swing.KeyStroke; + +import org.scijava.plugin.Plugin; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; +import org.scijava.ui.behaviour.io.gui.CommandDescriptions; +import org.scijava.ui.behaviour.util.AbstractNamedAction; +import org.scijava.ui.behaviour.util.Actions; + +import sc.fiji.labkit.ui.LabKitKeymapManager; +import sc.fiji.labkit.ui.labeling.Label; +import sc.fiji.labkit.ui.models.LabelingModel; + /** * {@link AbstractAction} that goes to the next label when "N" is pressed. */ public class ChangeLabel extends AbstractNamedAction { + private static final String CHANGE_LABEL_ACTION = "next Label"; + private static final String[] CHANGE_LABEL_KEYS = new String[] { "N" }; + private static final String CHANGE_LABEL_DESCRIPTION = "Select the next label in the list."; + private final LabelingModel model; public ChangeLabel(LabelingModel model) { - super("Next Label"); + super(CHANGE_LABEL_ACTION); this.model = model; super.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("N")); } @@ -63,4 +75,20 @@ private Label next(List