From 796c38093a791f523123b653bb8b1513c77c8af2 Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 8 May 2026 11:36:35 -0700 Subject: [PATCH 01/10] add basic camera validation --- .../lightsheetmanager/LightSheetManager.java | 7 ++++- .../model/DeviceManager.java | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/LightSheetManager.java b/src/main/java/org/micromanager/lightsheetmanager/LightSheetManager.java index 5e53761d..925c1069 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/LightSheetManager.java +++ b/src/main/java/org/micromanager/lightsheetmanager/LightSheetManager.java @@ -81,12 +81,17 @@ public boolean setup() { final String message = "AcquisitionEngine not implemented for " + geometryType; studio_.logs().logError(message); errorText_ = message; - return false; // early exit => error + return false; // early exit => show error ui } // load settings userSettings_.load(); + // validate settings + if (!devices().validateCameras()) { + return false; // early exit => show error ui + } + // TODO: put this somewhere better, need to put this value into LightSheetEventAdapter for now LightSheetEventAdapter.isUsingMultipleCameras = deviceManager_.adapter().numSimultaneousCameras() > 1; diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/DeviceManager.java b/src/main/java/org/micromanager/lightsheetmanager/model/DeviceManager.java index 4636fca1..98977540 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/DeviceManager.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/DeviceManager.java @@ -350,6 +350,36 @@ public CameraBase[] imagingCameras() { .toArray(CameraBase[]::new); } + /** + * Returns {@code true} if all cameras in the settings are valid. + * This is used to detect changes in pre-init properties. + * + * @return {@code true} if the cameras are valid + */ + public boolean validateCameras() { + // cameras in settings + final CameraData[] cameras = model_.acquisitions().settings().imagingCameraOrder(); + if (cameras.length == 0) { + final String message = "No cameras found in the settings."; + model_.studio().logs().logError(message); + model_.setErrorText(message); + return false; + } + + // valid camera names + final List validNames = Arrays.asList(imagingCameraNames()); + + for (CameraData camera : cameras) { + if (!validNames.contains(camera.name())) { + final String message = "Camera in settings not found in hardware: " + camera.name(); + model_.studio().logs().logError(message); + model_.setErrorText(message); + return false; + } + } + return true; + } + public DeviceAdapter adapter() { return (DeviceAdapter)deviceMap_.get("LightSheetDeviceManager"); } From 7da3b4ed7abce978dc2b37baf030e77aab39ab11 Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 8 May 2026 13:00:15 -0700 Subject: [PATCH 02/10] better error handling for no cameras, add default camera order --- .../model/DeviceManager.java | 39 ++++++++++++++++--- .../lightsheetmanager/model/UserSettings.java | 2 + 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/DeviceManager.java b/src/main/java/org/micromanager/lightsheetmanager/model/DeviceManager.java index 98977540..dd953d2f 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/DeviceManager.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/DeviceManager.java @@ -335,15 +335,14 @@ public String[] imagingCameraNames() { } public CameraBase[] imagingCameras() { - String[] cameraNames; - ArrayList names = new ArrayList<>(); + final List names = new ArrayList<>(); final CameraData[] cameras = model_.acquisitions().settings().imagingCameraOrder(); for (CameraData camera : cameras) { if (camera.isActive()) { names.add(camera.name()); } } - cameraNames = names.toArray(String[]::new); + final String[] cameraNames = names.toArray(String[]::new); return Arrays.stream(cameraNames) .map(name -> (CameraBase)deviceMap_.get(name)) .filter(Objects::nonNull) @@ -359,27 +358,55 @@ public CameraBase[] imagingCameras() { public boolean validateCameras() { // cameras in settings final CameraData[] cameras = model_.acquisitions().settings().imagingCameraOrder(); + + // check for no cameras if (cameras.length == 0) { final String message = "No cameras found in the settings."; model_.studio().logs().logError(message); - model_.setErrorText(message); - return false; + if (DialogUtils.showYesNoDialog(null, "No Imaging Cameras", + message + "\nWould you like to use the default imaging camera order?")) { + useDefaultImagingCameraOrder(); + return true; + } else { + model_.setErrorText(message); + return false; + } } // valid camera names final List validNames = Arrays.asList(imagingCameraNames()); + // check for camera name mismatches for (CameraData camera : cameras) { if (!validNames.contains(camera.name())) { - final String message = "Camera in settings not found in hardware: " + camera.name(); + final String message = "Camera in settings not found in hardware: " + camera.name() + + ", consider creating a new user profile if the pre-init properties changed."; model_.studio().logs().logError(message); model_.setErrorText(message); return false; } } + return true; } + /** + * Used to create the default imaging camera order. + */ + public void useDefaultImagingCameraOrder() { + final List cameras = new ArrayList<>(); + final String[] cameraNames = imagingCameraNames(); + for (String name : cameraNames) { + // Note: there is no ui control to change the active state of the + // camera when there is only 1 camera, so make sure it's active. + cameras.add(new CameraData(name, cameraNames.length == 1)); + } + // update settings with default camera order + model_.acquisitions().settingsBuilder() + .imagingCameraOrder(cameras.toArray(new CameraData[0])); + model_.acquisitions().updateAcquisitionSettings(); + } + public DeviceAdapter adapter() { return (DeviceAdapter)deviceMap_.get("LightSheetDeviceManager"); } diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/UserSettings.java b/src/main/java/org/micromanager/lightsheetmanager/model/UserSettings.java index 8902e712..7c8060c8 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/UserSettings.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/UserSettings.java @@ -90,6 +90,8 @@ public void load() { if (json.equals(SETTINGS_NOT_FOUND)) { model_.studio().logs().logDebugMessage( "settings not found, using default settings for " + geometryType); + // add the cameras to the imaging camera order + model_.devices().useDefaultImagingCameraOrder(); } else { // validate user settings and create AcquisitionSettings object final Optional settingsJson = validateUserSettings(json); From c90041980941ffbe88c1c5f8530784dccf7890df Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 8 May 2026 13:55:48 -0700 Subject: [PATCH 03/10] do not include virual slit camera trigger mode in scape --- .../micromanager/lightsheetmanager/api/data/CameraMode.java | 5 +++-- .../lightsheetmanager/gui/tabs/acquisition/CameraPanel.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/api/data/CameraMode.java b/src/main/java/org/micromanager/lightsheetmanager/api/data/CameraMode.java index 9b86ea97..3e717e54 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/api/data/CameraMode.java +++ b/src/main/java/org/micromanager/lightsheetmanager/api/data/CameraMode.java @@ -77,7 +77,8 @@ public static boolean isCameraValid(final CameraLibrary camLib) { return camLib != CameraLibrary.UNKNOWN; } - public static CameraMode[] modesByDeviceLibrary(final CameraLibrary cameraLibrary) { + public static CameraMode[] modesByDeviceLibrary( + final CameraLibrary cameraLibrary, final GeometryType geometry) { ArrayList modes = new ArrayList<>(); if (isCameraValid(cameraLibrary)) { modes.add(CameraMode.EDGE); @@ -90,7 +91,7 @@ public static CameraMode[] modesByDeviceLibrary(final CameraLibrary cameraLibrar if (hasPseudoOverlapTrigger(cameraLibrary)) { modes.add(CameraMode.PSEUDO_OVERLAP); } - if (hasLightSheetTrigger(cameraLibrary)) { + if (geometry != GeometryType.SCAPE && hasLightSheetTrigger(cameraLibrary)) { modes.add(CameraMode.VIRTUAL_SLIT); } } diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/acquisition/CameraPanel.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/acquisition/CameraPanel.java index 541325dd..ec8d7d67 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/acquisition/CameraPanel.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/acquisition/CameraPanel.java @@ -50,7 +50,7 @@ private void createUserInterface() { final CameraBase camera = model_.devices().firstImagingCamera(); if (camera != null) { final CameraLibrary camLib = CameraLibrary.fromString(camera.getDeviceLibrary()); - modes = CameraMode.modesByDeviceLibrary(camLib); + modes = CameraMode.modesByDeviceLibrary(camLib, model_.devices().adapter().geometry()); } cmbCameraMode_ = new ComboBox<>(modes, From 9b8d1031243132a18a8e0748b03ccf9274955006 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 11 May 2026 10:27:11 -0700 Subject: [PATCH 04/10] start of saving js settings --- .../gui/tabs/setup/JoystickPanel.java | 7 +++- .../model/PluginSettings.java | 42 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/JoystickPanel.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/JoystickPanel.java index cc9a8a6e..000deb6f 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/JoystickPanel.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/JoystickPanel.java @@ -15,7 +15,7 @@ import java.util.Objects; /** - * Control an ASI joystick. + * Control an ASI joystick, left wheel, and right wheel. */ public class JoystickPanel extends Panel { @@ -26,6 +26,7 @@ public class JoystickPanel extends Panel { private String previousJoystick_; private String previousLeftWheel_; private String previousRightWheel_; + private Map methods_; private final LightSheetManager model_; @@ -113,6 +114,7 @@ private void createEventHandlers() { // select joystick input cmbJoystick_.registerListener(() -> { final String selected = cmbJoystick_.getSelected(); + model_.pluginSettings().joystickPanel().joystick(selected); methods_.get(previousJoystick_).run(); // disable the previous device switch (selected) { case "None": @@ -136,6 +138,7 @@ private void createEventHandlers() { // select left wheel input cmbLeftWheel_.registerListener(() -> { final String selected = cmbLeftWheel_.getSelected(); + model_.pluginSettings().joystickPanel().leftWheel(selected); methods_.get(previousLeftWheel_).run(); // disable the previous device switch (selected) { case "Imaging Piezo": @@ -164,6 +167,7 @@ private void createEventHandlers() { // select right wheel input cmbRightWheel_.registerListener(() -> { final String selected = cmbRightWheel_.getSelected(); + model_.pluginSettings().joystickPanel().rightWheel(selected); methods_.get(previousRightWheel_).run(); // disable the previous device switch (selected) { case "Imaging Piezo": @@ -189,4 +193,5 @@ private void createEventHandlers() { previousRightWheel_ = selected; }); } + } diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/PluginSettings.java b/src/main/java/org/micromanager/lightsheetmanager/model/PluginSettings.java index c57bcff1..e411048e 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/PluginSettings.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/PluginSettings.java @@ -10,8 +10,14 @@ public class PluginSettings { private boolean isPollingPositions_ = true; + private final JoystickData joystick_ = new JoystickData(); + private final XYZGrid xyzGrid_ = new XYZGrid(); + public JoystickData joystickPanel() { + return joystick_; + } + public XYZGrid xyzGrid() { return xyzGrid_; } @@ -37,4 +43,40 @@ public static PluginSettings fromJson(final String json) { return new Gson().fromJson(json, PluginSettings.class); } + public static class JoystickData { + + private String joystick_; + private String leftWheel_; + private String rightWheel_; + + JoystickData() { + joystick_ = "None"; + leftWheel_ = "None"; + rightWheel_ = "None"; + } + + public String joystick() { + return joystick_; + } + + public String leftWheel() { + return leftWheel_; + } + + public String rightWheel() { + return rightWheel_; + } + + public void joystick(final String joystick) { + joystick_ = joystick; + } + + public void leftWheel(final String leftWheel) { + leftWheel_ = leftWheel; + } + + public void rightWheel(final String rightWheel) { + rightWheel_ = rightWheel; + } + } } From 528729a5cd562cc46acf8de6e63e31fb75d0f202 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 11 May 2026 13:05:59 -0700 Subject: [PATCH 05/10] save js panel settings and reload on startup --- .../gui/tabs/setup/JoystickPanel.java | 134 +++++++++--------- 1 file changed, 65 insertions(+), 69 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/JoystickPanel.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/JoystickPanel.java index 000deb6f..e2ca6c83 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/JoystickPanel.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/JoystickPanel.java @@ -39,18 +39,22 @@ public JoystickPanel(final LightSheetManager model) { } createUserInterface(); createEventHandlers(); + if (model_.devices().isUsingPLogic()) { + initHardware(); + } } private void createMap() { final ASIXYStage xyStage = model_.devices().device("SampleXY"); final ASIZStage zStage = model_.devices().device("SampleZ"); + final ASIZStage stage = model_.devices().device("IllumAngle"); final ASIScanner scanner = model_.devices().device("IllumSlice"); - final ASIPiezo piezo = model_.devices().device("ImagingFocus"); + final ASIPiezo piezo = model_.devices().device("ImagingFocus"); // set to the default values - previousJoystick_ = "None"; - previousLeftWheel_ = "None"; - previousRightWheel_ = "None"; + previousJoystick_ = model_.pluginSettings().joystickPanel().joystick(); + previousLeftWheel_ = model_.pluginSettings().joystickPanel().leftWheel(); + previousRightWheel_ = model_.pluginSettings().joystickPanel().rightWheel(); methods_ = new HashMap<>(); @@ -68,10 +72,16 @@ private void createMap() { scanner.js().inputX(Joystick.Input.NONE); scanner.js().inputY(Joystick.Input.NONE); }); - methods_.put("Light Sheet Tilt", () -> {}); // TODO: impl + methods_.put("Light Sheet Tilt", () -> stage.js().input(Joystick.Input.NONE)); methods_.put("Sample Height", () -> zStage.js().input(Joystick.Input.NONE)); } + private void initHardware() { + setJoystick(cmbJoystick_.getSelected()); + setWheel(cmbLeftWheel_.getSelected(), Joystick.Input.LEFT_WHEEL); + setWheel(cmbRightWheel_.getSelected(), Joystick.Input.RIGHT_WHEEL); + } + private void createUserInterface() { final JLabel lblJoystick = new JLabel("Joystick:"); final JLabel lblLeftWheel = new JLabel("Left Wheel:"); @@ -97,9 +107,9 @@ private void createUserInterface() { "Sample Height" }; - cmbJoystick_ = new ComboBox<>(joystickLabels, "None", 100, 24); - cmbLeftWheel_ = new ComboBox<>(wheelLabels, "None", 100, 24); - cmbRightWheel_ = new ComboBox<>(wheelLabels, "None", 100, 24); + cmbJoystick_ = new ComboBox<>(joystickLabels, previousJoystick_, 100, 24); + cmbLeftWheel_ = new ComboBox<>(wheelLabels, previousLeftWheel_, 100, 24); + cmbRightWheel_ = new ComboBox<>(wheelLabels, previousRightWheel_, 100, 24); add(lblJoystick, ""); add(cmbJoystick_, "wrap"); @@ -116,23 +126,8 @@ private void createEventHandlers() { final String selected = cmbJoystick_.getSelected(); model_.pluginSettings().joystickPanel().joystick(selected); methods_.get(previousJoystick_).run(); // disable the previous device - switch (selected) { - case "None": - return; // early exit => do nothing - case "Scanner": - final ASIScanner scanner = model_.devices().device("IllumSlice"); - scanner.js().inputX(Joystick.Input.JOYSTICK_X); - scanner.js().inputY(Joystick.Input.JOYSTICK_Y); - break; - case "XYStage": - final ASIXYStage xyStage = model_.devices().device("SampleXY"); - xyStage.js().enabled(true); - break; - default: - break; - } - // track the previous device to disable later - previousJoystick_ = selected; + setJoystick(selected); + previousJoystick_ = selected; // track the previous device to disable later }); // select left wheel input @@ -140,28 +135,8 @@ private void createEventHandlers() { final String selected = cmbLeftWheel_.getSelected(); model_.pluginSettings().joystickPanel().leftWheel(selected); methods_.get(previousLeftWheel_).run(); // disable the previous device - switch (selected) { - case "Imaging Piezo": - final ASIPiezo piezo = model_.devices().device("ImagingFocus"); - piezo.js().input(Joystick.Input.LEFT_WHEEL); - break; - case "Imaging Slice": - final ASIScanner scanner = model_.devices().device("IllumSlice"); - scanner.js().inputX(Joystick.Input.LEFT_WHEEL); - break; - case "Light Sheet Tilt": - final ASIZStage stage = model_.devices().device("IllumAngle"); - stage.js().input(Joystick.Input.LEFT_WHEEL); - break; - case "Sample Height": - final ASIZStage zStage = model_.devices().device("SampleZ"); - zStage.js().input(Joystick.Input.LEFT_WHEEL); - break; - default: - break; - } - // track the previous device to disable later - previousLeftWheel_ = selected; + setWheel(selected, Joystick.Input.LEFT_WHEEL); + previousLeftWheel_ = selected; // track the previous device to disable later }); // select right wheel input @@ -169,29 +144,50 @@ private void createEventHandlers() { final String selected = cmbRightWheel_.getSelected(); model_.pluginSettings().joystickPanel().rightWheel(selected); methods_.get(previousRightWheel_).run(); // disable the previous device - switch (selected) { - case "Imaging Piezo": - final ASIPiezo piezo = model_.devices().device("ImagingFocus"); - piezo.js().input(Joystick.Input.RIGHT_WHEEL); - break; - case "Imaging Slice": - final ASIScanner scanner = model_.devices().device("IllumSlice"); - scanner.js().inputX(Joystick.Input.RIGHT_WHEEL); - break; - case "Light Sheet Tilt": - final ASIZStage stage = model_.devices().device("IllumAngle"); - stage.js().input(Joystick.Input.RIGHT_WHEEL); - break; - case "Sample Height": - final ASIZStage zStage = model_.devices().device("SampleZ"); - zStage.js().input(Joystick.Input.RIGHT_WHEEL); - break; - default: - break; - } - // track the previous device to disable later - previousRightWheel_ = selected; + setWheel(selected, Joystick.Input.RIGHT_WHEEL); + previousRightWheel_ = selected; // track the previous device to disable later }); } + private void setJoystick(final String selected) { + switch (selected) { + case "None": + return; // early exit => do nothing + case "Scanner": + final ASIScanner scanner = model_.devices().device("IllumSlice"); + scanner.js().inputX(Joystick.Input.JOYSTICK_X); + scanner.js().inputY(Joystick.Input.JOYSTICK_Y); + break; + case "XYStage": + final ASIXYStage xyStage = model_.devices().device("SampleXY"); + xyStage.js().enabled(true); + break; + default: + break; + } + } + + private void setWheel(final String selected, final Joystick.Input target) { + switch (selected) { + case "Imaging Piezo": + final ASIPiezo piezo = model_.devices().device("ImagingFocus"); + piezo.js().input(target); + break; + case "Imaging Slice": + final ASIScanner scanner = model_.devices().device("IllumSlice"); + scanner.js().inputX(target); + break; + case "Light Sheet Tilt": + final ASIZStage stage = model_.devices().device("IllumAngle"); + stage.js().input(target); + break; + case "Sample Height": + final ASIZStage zStage = model_.devices().device("SampleZ"); + zStage.js().input(target); + break; + default: + break; + } + } + } From 001c8220146844f677d71f70612c56544a3954f1 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 11 May 2026 13:08:44 -0700 Subject: [PATCH 06/10] make sure to unregister for events in acq engine --- .../model/acquisitions/AcquisitionEngineScape.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java index d01462fa..92b8ec4d 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java @@ -788,6 +788,9 @@ boolean finish() { } } + // unregister to stop ghost events + studio_.events().unregisterForEvents(this); + // start polling for navigation panel if (isPolling_) { studio_.logs().logMessage("started position polling after acquisition"); From 67a14f56087d0ab9ec41478d091f4d168da5eeac Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 11 May 2026 13:41:32 -0700 Subject: [PATCH 07/10] imaging slice actually controls the sclice now --- .../lightsheetmanager/gui/tabs/setup/JoystickPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/JoystickPanel.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/JoystickPanel.java index e2ca6c83..73353bf4 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/JoystickPanel.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/JoystickPanel.java @@ -175,7 +175,7 @@ private void setWheel(final String selected, final Joystick.Input target) { break; case "Imaging Slice": final ASIScanner scanner = model_.devices().device("IllumSlice"); - scanner.js().inputX(target); + scanner.js().inputY(target); break; case "Light Sheet Tilt": final ASIZStage stage = model_.devices().device("IllumAngle"); From 20269a15c36089058c0ea82a2e0a2a22906351e9 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 11 May 2026 15:31:39 -0700 Subject: [PATCH 08/10] restore timepoints for non hardware timepoints, dont open 2 live windows --- .../lightsheetmanager/gui/tabs/setup/CameraPanel.java | 8 ++++++++ .../model/acquisitions/AcquisitionEngineScape.java | 1 + 2 files changed, 9 insertions(+) diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/CameraPanel.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/CameraPanel.java index a87f8fa3..027cba21 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/CameraPanel.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/CameraPanel.java @@ -106,6 +106,10 @@ private void createEventHandlers() { break; case SCAPE: btnInvertedPath_.registerListener(() -> { + if (!btnInvertedPath_.isSelected()) { + model_.studio().live().setLiveModeOn(false); + return; + } closeLiveModeWindow(); final CameraBase camera = model_.devices().device("PreviewCamera"); if (camera != null) { @@ -127,6 +131,10 @@ private void createEventHandlers() { // live mode btnLiveMode_.registerListener(() -> { + if (!btnLiveMode_.isSelected()) { + model_.studio().live().setLiveModeOn(false); + return; + } closeLiveModeWindow(); final CameraBase camera = model_.devices().firstImagingCamera(); if (camera != null) { diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java index 92b8ec4d..936c1d50 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java @@ -619,6 +619,7 @@ public void close() { AcquisitionEvent baseEvent = new AcquisitionEvent(currentAcquisition_); if (acqSettings_.isUsingTimePoints()) { baseEvent.setAxisPosition(LightSheetEventAdapter.TIME_AXIS, timeIndex); + baseEvent.setMinimumStartTime((long) (timeIndex * (model_.acquisitions().settings().timePointInterval() * 1000.0))); } // Loop 2: XY positions for (int positionIndex = 0; positionIndex < numPositions; positionIndex++) { From ea3fd4428ad88c3728a15f583d64d6466bcc1972 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 11 May 2026 17:24:17 -0700 Subject: [PATCH 09/10] fix multiple channels for a single camera --- .../acquisitions/LightSheetEventAdapter.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/LightSheetEventAdapter.java b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/LightSheetEventAdapter.java index 68299acd..0f233ccf 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/LightSheetEventAdapter.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/LightSheetEventAdapter.java @@ -195,7 +195,18 @@ public AcquisitionEvent next() { cameraEvent.setAxisPosition(CAMERA_AXIS, cameraIndex_ + (currentChannelIndex_ * cameraDeviceNames_.length)); } else { - cameraEvent.setAxisPosition(CAMERA_AXIS, cameraIndex_); + Object position = event.getAxisPosition(CAMERA_AXIS); + int baseIndex = 0; + + if (position != null) { + try { + baseIndex = Integer.parseInt(position.toString()); + } catch (NumberFormatException e) { + // ignore => number already assigned + } + } + + cameraEvent.setAxisPosition(CAMERA_AXIS, baseIndex + cameraIndex_); } cameraIndex_++; return cameraEvent; @@ -218,6 +229,7 @@ public boolean hasNext() { public AcquisitionEvent next() { AcquisitionEvent sliceEvent = event.copy(); sliceEvent.setAxisPosition(AcqEngMetadata.Z_AXIS, zIndex_); + // System.out.println("Final Event Axes: " + sliceEvent.getAxesAsJSONString()); // The tiger controller handles Z axis, so no need to add the actual Z position zIndex_++; return sliceEvent; @@ -244,7 +256,6 @@ public AcquisitionEvent next() { } timePointEvent.setTimeIndex(frameIndex_); frameIndex_++; - return timePointEvent; } }; @@ -253,7 +264,7 @@ public AcquisitionEvent next() { /** * Make an iterator for events for each active channel * - * @param channelList + * @param channelList the list of channels to iterate over * @return */ public static Function> channels( @@ -299,7 +310,7 @@ public AcquisitionEvent next() { * the axes that assume the order in the list provided correspond to the * desired indices * - * @param positionList + * @param positionList the list of positions or iterate over * @return */ public static Function> positions( From 25cbac96653627bfef5b028d031e55e9177dfa72 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 11 May 2026 17:42:50 -0700 Subject: [PATCH 10/10] add error message to every volume plogic in scape --- .../gui/tabs/channels/ChannelTablePanel.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/channels/ChannelTablePanel.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/channels/ChannelTablePanel.java index a687f878..cee3bbc8 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/channels/ChannelTablePanel.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/channels/ChannelTablePanel.java @@ -9,9 +9,10 @@ import org.micromanager.lightsheetmanager.LightSheetManager; import org.micromanager.lightsheetmanager.api.data.ChannelMode; import org.micromanager.lightsheetmanager.gui.components.SettingsListener; +import org.micromanager.lightsheetmanager.gui.utils.DialogUtils; import org.micromanager.lightsheetmanager.model.channels.ChannelSpec; -import javax.swing.JLabel; +import javax.swing.*; import java.util.Objects; /** @@ -60,7 +61,7 @@ private void createUserInterface() { cmbChannelMode_ = new ComboBox<>(ChannelMode.values(), model_.acquisitions().settings().channels().mode(), - 120, 22); + 140, 22); add(lblChannelGroup_, "split 2"); add(cmbChannelGroup_, "wrap"); @@ -125,8 +126,14 @@ private void createEventHandlers() { // select channel mode cmbChannelMode_.registerListener(() -> { - model_.acquisitions().settingsBuilder().channelBuilder() - .mode(cmbChannelMode_.getSelected()); + final ChannelMode selected = cmbChannelMode_.getSelected(); + model_.acquisitions().settingsBuilder().channelBuilder().mode(selected); + if (selected == ChannelMode.VOLUME_HW) { + SwingUtilities.invokeLater(() -> { + DialogUtils.showErrorMessage(cmbChannelMode_, "Not Implemented", + "Not implemented in SCAPE, please contact ASI to request this feature."); + }); + } }); }