From 188694a28715c715be5cc9fd13581be0eb03f679 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 17 Feb 2026 17:07:37 -0800 Subject: [PATCH 1/4] remove computeActualVolumeDuration, only need computeVolumeDuration --- .../gui/tabs/AcquisitionTab.java | 4 +- .../acquisitions/AcquisitionEngineSCAPE.java | 48 +++---------------- 2 files changed, 9 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/AcquisitionTab.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/AcquisitionTab.java index 1d76886..801a793 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/AcquisitionTab.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/AcquisitionTab.java @@ -326,9 +326,9 @@ private void acqFinishedCallback() { btnSpeedTest_.setEnabled(true); }); } catch (InterruptedException e) { - e.printStackTrace(); + model_.studio().logs().logError("Acquisition was interrupted!"); } catch (InvocationTargetException e) { - e.printStackTrace(); + model_.studio().logs().logError("Could not update UI components."); } } 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 90bc513..002ce5c 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineSCAPE.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineSCAPE.java @@ -902,14 +902,14 @@ private boolean doHardwareCalculations(PLogicSCAPE plc) { // test acq was here - double volumeDuration = computeActualVolumeDuration(acqSettings_); - double timepointDuration = computeTimePointDuration(); - long timepointIntervalMs = Math.round(acqSettings_.timePointInterval() * 1000.0); + final double volumeDuration = computeVolumeDuration(acqSettings_); + final double timepointDuration = computeTimePointDuration(); + final long timepointIntervalMs = Math.round(acqSettings_.timePointInterval() * 1000.0); // use hardware timing if < 1 second between time points // experimentally need ~0.5 sec to set up acquisition, this gives a bit of cushion // cannot do this in getCurrentAcquisitionSettings because of mutually recursive - // call with computeActualVolumeDuration() + // call with computeVolumeDuration() boolean isUsingHardwareTimePoints = false; // TODO: asb_ not built yet if (acqSettings_.isUsingTimePoints() && acqSettings_.numTimePoints() > 1 @@ -1355,7 +1355,7 @@ private double getSliceDuration(DefaultTimingSettings.Builder tsb) { } private double computeTimePointDuration() { - final double volumeDuration = computeActualVolumeDuration(acqSettings_); + final double volumeDuration = computeVolumeDuration(acqSettings_); if (acqSettings_.isUsingMultiplePositions()) { // use 1.5 seconds motor move between positions // (could be wildly off but was estimated using actual system @@ -1369,38 +1369,6 @@ private double computeTimePointDuration() { return volumeDuration; } - private double computeActualVolumeDuration(final DefaultAcquisitionSettingsSCAPE acqSettings) { - final MultiChannelMode channelMode = acqSettings.channelSettings().channelMode(); - final int numChannels = acqSettings.channelSettings().numChannels(); - final int numViews = acqSettings.volumeSettings().numViews(); - final double delayBeforeSide = acqSettings.volumeSettings().delayBeforeView(); - int numCameraTriggers = acqSettings.volumeSettings().slicesPerView(); - if (acqSettings.cameraMode() == CameraMode.OVERLAP) { - numCameraTriggers += 1; - } - // stackDuration is per-side, per-channel, per-position - - final double stackDuration = numCameraTriggers * acqSettings.timingSettings().sliceDuration(); - if (acqSettings.isUsingStageScanning()) { // || acqSettings.isStageStepping) { - // TODO: stage scanning code - return 0; - } else { - // piezo scan - double channelSwitchDelay = 0; - if (channelMode == MultiChannelMode.VOLUME) { - channelSwitchDelay = 500; // estimate channel switching overhead time as 0.5s - // actual value will be hardware-dependent - } - if (channelMode == MultiChannelMode.SLICE_HW) { - return numViews * (delayBeforeSide + stackDuration * numChannels); // channelSwitchDelay = 0 - } else { - return numViews * numChannels - * (delayBeforeSide + stackDuration) - + (numChannels - 1) * channelSwitchDelay; - } - } - } - @Override public void updateDurationLabels() { updateSlicePeriodLabel(pnlVolumeDurations_.getSliceDurationLabel()); @@ -1413,7 +1381,7 @@ private void updateSlicePeriodLabel(final JLabel label) { model_.acquisitions().recalculateSliceTiming(); model_.acquisitions().settingsBuilder().build(); label.setText(String.format("%.3f ms", acqSettings.timingSettings().sliceDuration())); - System.out.println("updating slice label to: " + acqSettings.timingSettings().sliceDuration()); + //System.out.println("updating slice label to: " + acqSettings.timingSettings().sliceDuration()); } private void updateVolumeDurationLabel(final JLabel label) { @@ -1445,10 +1413,8 @@ private void updateTotalTimeDurationLabel(final JLabel label) { private double computeTotalTimeDuration() { final DefaultAcquisitionSettingsSCAPE acqSettings = model_.acquisitions().settingsBuilder().build(); - final double duration = acqSettings.numTimePoints() * acqSettings.timePointInterval() + return acqSettings.numTimePoints() * acqSettings.timePointInterval() + computeTimePointDuration()/1000; - System.out.println("duratioN: " + duration); - return duration; } /** From 65479cb1ecf9951e261a8268e53f7ce24940d860 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 17 Feb 2026 17:41:05 -0800 Subject: [PATCH 2/4] only need one version of computeTimePointDuration --- .../model/acquisitions/AcquisitionEngine.java | 12 +------ .../acquisitions/AcquisitionEngineSCAPE.java | 33 +++++-------------- 2 files changed, 10 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngine.java b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngine.java index 8e1c0e8..17bf0f5 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngine.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngine.java @@ -247,23 +247,13 @@ protected DefaultSummaryMetadata addMMSummaryMetadata(JSONObject summaryMetadata } } - // TODO: keep long method name versions or just use aliases? - public DefaultAcquisitionSettingsSCAPE settings() { return acqSettings_; } -// -// public DefaultAcquisitionSettingsDISPIM getAcquisitionSettings() { -// return acqSettings_; -// } -// + public DefaultAcquisitionSettingsSCAPE.Builder settingsBuilder() { return asb_; } -// -// public DefaultAcquisitionSettingsDISPIM.Builder getAcquisitionSettingsBuilder() { -// return asb_; -// } public AutofocusMM autofocus() { return autofocus_; 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 002ce5c..1691088 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineSCAPE.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineSCAPE.java @@ -1354,21 +1354,6 @@ private double getSliceDuration(DefaultTimingSettings.Builder tsb) { ); } - private double computeTimePointDuration() { - final double volumeDuration = computeVolumeDuration(acqSettings_); - if (acqSettings_.isUsingMultiplePositions()) { - // use 1.5 seconds motor move between positions - // (could be wildly off but was estimated using actual system - // and then slightly padded to be conservative to avoid errors - // where positions aren't completed in time for next position) - // could estimate the actual time by analyzing the position's relative locations - // and using the motor speed and acceleration time - return studio_.positions().getPositionList().getNumberOfPositions() * - (volumeDuration + 1500 + acqSettings_.postMoveDelay()); - } - return volumeDuration; - } - @Override public void updateDurationLabels() { updateSlicePeriodLabel(pnlVolumeDurations_.getSliceDurationLabel()); @@ -1380,12 +1365,12 @@ private void updateSlicePeriodLabel(final JLabel label) { final DefaultAcquisitionSettingsSCAPE acqSettings = model_.acquisitions().settings(); model_.acquisitions().recalculateSliceTiming(); model_.acquisitions().settingsBuilder().build(); - label.setText(String.format("%.3f ms", acqSettings.timingSettings().sliceDuration())); + label.setText(String.format("%.3f ms", acqSettings_.timingSettings().sliceDuration())); //System.out.println("updating slice label to: " + acqSettings.timingSettings().sliceDuration()); } private void updateVolumeDurationLabel(final JLabel label) { - double duration = computeVolumeDuration(model_.acquisitions().settingsBuilder().build()); + final double duration = computeVolumeDuration(model_.acquisitions().settingsBuilder().build()); if (duration > 1000) { label.setText(String.format("%.3f s", duration / 1000)); // round to ms } else { @@ -1398,7 +1383,7 @@ private void updateVolumeDurationLabel(final JLabel label) { */ private void updateTotalTimeDurationLabel(final JLabel label) { String s = ""; - double duration = computeTotalTimeDuration(); + final double duration = computeTotalTimeDuration(); if (duration < 60) { // less than 1 min s += String.format("%.3f s", duration); } else if (duration < 60*60) { // between 1 min and 1 hour @@ -1422,10 +1407,9 @@ private double computeTotalTimeDuration() { * is that it also takes into account the multiple positions, if any. * @return duration in ms */ - private double computeTimePointDuration2() { - final DefaultAcquisitionSettingsSCAPE acqSettings = model_.acquisitions().settings(); - final double volumeDuration = computeVolumeDuration(acqSettings); - if (acqSettings.isUsingMultiplePositions()) { + private double computeTimePointDuration() { + final double volumeDuration = computeVolumeDuration(acqSettings_); + if (acqSettings_.isUsingMultiplePositions()) { try { // use 1.5 seconds motor move between positions // (could be wildly off but was estimated using actual system @@ -1434,9 +1418,10 @@ private double computeTimePointDuration2() { // could estimate the actual time by analyzing the position's relative locations // and using the motor speed and acceleration time return studio_.positions().getPositionList().getNumberOfPositions() * - (volumeDuration + 1500 + model_.acquisitions().settings().postMoveDelay()); + (volumeDuration + 1500 + acqSettings_.postMoveDelay()); } catch (Exception e) { - studio_.logs().showError("Error getting position list for multiple XY positions"); + studio_.logs().logError("Error getting position list for multiple XY positions"); + return volumeDuration; } } return volumeDuration; From 3cefe3a6d5679d5fc7195780446e65f05ff76d52 Mon Sep 17 00:00:00 2001 From: Brandon Date: Wed, 18 Feb 2026 08:43:20 -0800 Subject: [PATCH 3/4] make ComboBox generic to improve enum serialization --- .../LightSheetManagerPlugin.java | 2 +- .../api/data/AcquisitionMode.java | 43 +++-------------- .../api/data/AutofocusMode.java | 18 ------- .../api/data/AutofocusType.java | 18 ------- .../api/data/CameraLibrary.java | 6 +-- .../api/data/CameraMode.java | 15 ++---- .../api/data/GeometryType.java | 19 ++++---- .../api/data/LightSheetType.java | 19 ++++---- .../api/data/MultiChannelMode.java | 23 --------- .../gui/components/ComboBox.java | 48 ++++--------------- .../gui/tabs/AcquisitionTab.java | 14 ++---- .../gui/tabs/AutofocusTab.java | 24 +++++----- .../lightsheetmanager/gui/tabs/CameraTab.java | 13 ++--- .../gui/tabs/acquisition/SaveDataPanel.java | 11 ++--- .../tabs/acquisition/VolumeSettingsPanel.java | 21 ++++---- .../gui/tabs/channels/ChannelTablePanel.java | 12 ++--- .../gui/tabs/setup/JoystickPanel.java | 13 +++-- .../gui/tabs/setup/SingleAxisPanel.java | 15 +++--- .../model/devices/DeviceBase.java | 22 +++++++++ .../devices/LightSheetDeviceManager.java | 42 ++++++++++++---- 20 files changed, 153 insertions(+), 245 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/LightSheetManagerPlugin.java b/src/main/java/org/micromanager/lightsheetmanager/LightSheetManagerPlugin.java index 75163f8..0b6c692 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/LightSheetManagerPlugin.java +++ b/src/main/java/org/micromanager/lightsheetmanager/LightSheetManagerPlugin.java @@ -12,7 +12,7 @@ public class LightSheetManagerPlugin implements MenuPlugin, SciJavaPlugin { public static final String copyright = "Applied Scientific Instrumentation (ASI), 2022-2026"; public static final String description = "A plugin to control various types of light sheet microscopes."; public static final String menuName = "Light Sheet Manager"; - public static final String version = "0.5.8"; + public static final String version = "0.5.9"; private Studio studio_; private LightSheetManager model_; diff --git a/src/main/java/org/micromanager/lightsheetmanager/api/data/AcquisitionMode.java b/src/main/java/org/micromanager/lightsheetmanager/api/data/AcquisitionMode.java index 4368aa5..aa579f4 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/api/data/AcquisitionMode.java +++ b/src/main/java/org/micromanager/lightsheetmanager/api/data/AcquisitionMode.java @@ -6,8 +6,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; // To add a new AcquisitionMode: // 1) Add a new constant to the enum. @@ -63,9 +61,6 @@ public enum AcquisitionMode { // Display text used in the UI private final String text_; - private static final Map STRING_TO_ENUM = - Stream.of(values()).collect(Collectors.toMap(Object::toString, e -> e)); - AcquisitionMode(final String text) { text_ = text; } @@ -94,39 +89,13 @@ public boolean isStageScanMode() { * @param hasStageScanning {@code true} if stage scan hardware is available * @return a {@code List} of {@link AcquisitionMode} constants */ - public static List getValidModes(final GeometryType geometry, final boolean hasStageScanning) { + public static AcquisitionMode[] getValidModes(final GeometryType geometry, final boolean hasStageScanning) { return Optional.ofNullable(geometry) - .map(MODES_BY_GEOMETRY::get) // returns null if geometry is not in map - .orElse(Collections.emptyList()) - .stream() - .filter(mode -> hasStageScanning || !mode.isStageScanMode()) - .collect(Collectors.toList()); - } - - /** - * Return an array of {@code String} labels for a dropdown menu. - * - * @param geometry the microscope {@link GeometryType} - * @param hasStageScanning {@code true} if stage scan hardware is available - * @return an array of strings - */ - public static String[] getLabels(final GeometryType geometry, final boolean hasStageScanning) { - return getValidModes(geometry, hasStageScanning).stream() - .map(AcquisitionMode::toString) - .toArray(String[]::new); + .map(MODES_BY_GEOMETRY::get) // returns null if geometry is not in map + .orElse(Collections.emptyList()) + .stream() + .filter(mode -> hasStageScanning || !mode.isStageScanMode()) + .toArray(AcquisitionMode[]::new); } - /** - * Returns the {@link AcquisitionMode} associated with the string label. - *

- * If the provided string is {@code null} or does not match any known - * acquisition mode, an empty {@link Optional} is returned. - * - * @param str the string label to convert (Example: "Stage scan") - * @return an {@link Optional} containing the matching {@link AcquisitionMode}, - * or an empty {@code Optional} if no match is found. - */ - public static Optional fromString(final String str) { - return Optional.ofNullable(str).map(STRING_TO_ENUM::get); - } } diff --git a/src/main/java/org/micromanager/lightsheetmanager/api/data/AutofocusMode.java b/src/main/java/org/micromanager/lightsheetmanager/api/data/AutofocusMode.java index 40be707..884ac52 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/api/data/AutofocusMode.java +++ b/src/main/java/org/micromanager/lightsheetmanager/api/data/AutofocusMode.java @@ -1,10 +1,5 @@ package org.micromanager.lightsheetmanager.api.data; -import java.util.Arrays; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; - /** * The autofocus mode for the general autofocus settings. */ @@ -14,23 +9,10 @@ public enum AutofocusMode { private final String name_; - private static final Map stringToEnum = - Stream.of(values()).collect(Collectors.toMap(Object::toString, e -> e)); - AutofocusMode(final String name) { name_ = name; } - public static String[] toArray() { - return Arrays.stream(values()) - .map(AutofocusMode::toString) - .toArray(String[]::new); - } - - public static AutofocusMode fromString(final String symbol) { - return stringToEnum.getOrDefault(symbol, AutofocusMode.FIXED_PIEZO_SWEEP_SLICE); - } - @Override public String toString() { return name_; diff --git a/src/main/java/org/micromanager/lightsheetmanager/api/data/AutofocusType.java b/src/main/java/org/micromanager/lightsheetmanager/api/data/AutofocusType.java index 5495d72..0912fe0 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/api/data/AutofocusType.java +++ b/src/main/java/org/micromanager/lightsheetmanager/api/data/AutofocusType.java @@ -1,10 +1,5 @@ package org.micromanager.lightsheetmanager.api.data; -import java.util.Arrays; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; - /** * The type of scoring algorithm for the general autofocus settings. */ @@ -23,23 +18,10 @@ public enum AutofocusType { private final String name_; - private static final Map stringToEnum = - Stream.of(values()).collect(Collectors.toMap(Object::toString, e -> e)); - AutofocusType(final String name) { name_ = name; } - public static String[] toArray() { - return Arrays.stream(values()) - .map(AutofocusType::toString) - .toArray(String[]::new); - } - - public static AutofocusType fromString(final String symbol) { - return stringToEnum.getOrDefault(symbol, AutofocusType.EDGES); - } - @Override public String toString() { return name_; diff --git a/src/main/java/org/micromanager/lightsheetmanager/api/data/CameraLibrary.java b/src/main/java/org/micromanager/lightsheetmanager/api/data/CameraLibrary.java index 3c6f74d..cfc25fc 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/api/data/CameraLibrary.java +++ b/src/main/java/org/micromanager/lightsheetmanager/api/data/CameraLibrary.java @@ -17,8 +17,8 @@ public enum CameraLibrary { private final String text_; - private static final Map stringToEnum = - Stream.of(values()).collect(Collectors.toMap(Object::toString, e -> e)); + private static final Map STRING_TO_ENUM = + Stream.of(values()).collect(Collectors.toUnmodifiableMap(Object::toString, e -> e)); CameraLibrary(final String text) { text_ = text; @@ -30,6 +30,6 @@ public String toString() { } public static CameraLibrary fromString(final String symbol) { - return stringToEnum.getOrDefault(symbol, CameraLibrary.UNKNOWN); + return STRING_TO_ENUM.getOrDefault(symbol, CameraLibrary.UNKNOWN); } } \ No newline at end of file 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 bba7d5d..6b968b3 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/api/data/CameraMode.java +++ b/src/main/java/org/micromanager/lightsheetmanager/api/data/CameraMode.java @@ -24,7 +24,7 @@ public enum CameraMode { private final String text_; private static final Map stringToEnum = - Stream.of(values()).collect(Collectors.toMap(Object::toString, e -> e)); + Stream.of(values()).collect(Collectors.toUnmodifiableMap(Object::toString, e -> e)); CameraMode(final String text) { text_ = text; @@ -34,15 +34,6 @@ public static CameraMode fromString(final String symbol) { return stringToEnum.getOrDefault(symbol, CameraMode.EDGE); } - /** - * @return an array of Strings containing all possible camera trigger modes. - */ - public static String[] toArray() { - return Arrays.stream(values()) - .map(CameraMode::toString) - .toArray(String[]::new); - } - /** * Does camera support overlap/synchronous mode? * @@ -89,7 +80,7 @@ public static boolean isCameraValid(CameraLibrary camLib) { return camLib != CameraLibrary.UNKNOWN; } - public static String[] getAvailableModes(CameraLibrary camLib) { + public static CameraMode[] getAvailableModes(CameraLibrary camLib) { ArrayList modes = new ArrayList<>(); if (isCameraValid(camLib)) { modes.add(CameraMode.EDGE); @@ -108,7 +99,7 @@ public static String[] getAvailableModes(CameraLibrary camLib) { } return modes.stream() .map(CameraMode::toString) - .toArray(String[]::new); + .toArray(CameraMode[]::new); } @Override diff --git a/src/main/java/org/micromanager/lightsheetmanager/api/data/GeometryType.java b/src/main/java/org/micromanager/lightsheetmanager/api/data/GeometryType.java index c58cf84..93e422e 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/api/data/GeometryType.java +++ b/src/main/java/org/micromanager/lightsheetmanager/api/data/GeometryType.java @@ -1,8 +1,6 @@ package org.micromanager.lightsheetmanager.api.data; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.util.Arrays; public enum GeometryType { UNKNOWN("Unknown"), @@ -10,12 +8,8 @@ public enum GeometryType { ISPIM("iSPIM"), OSPIM("oSPIM"), MESOSPIM("mesoSPIM"), - OPENSPIML("OpenSPIM-L"), SCAPE("SCAPE"); - private static final Map stringToEnum = - Stream.of(values()).collect(Collectors.toMap(Object::toString, e -> e)); - private final String label_; GeometryType(final String label) { @@ -27,7 +21,14 @@ public String toString() { return label_; } - public static GeometryType fromString(final String symbol) { - return stringToEnum.getOrDefault(symbol, GeometryType.UNKNOWN); + public static GeometryType fromString(final String propertyValue) { + if (propertyValue == null || propertyValue.isEmpty()) { + return UNKNOWN; + } + return Arrays.stream(values()) + .filter(g -> g.label_.equalsIgnoreCase(propertyValue)) + .findFirst() + .orElse(UNKNOWN); } + } diff --git a/src/main/java/org/micromanager/lightsheetmanager/api/data/LightSheetType.java b/src/main/java/org/micromanager/lightsheetmanager/api/data/LightSheetType.java index baa49ec..c4a2995 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/api/data/LightSheetType.java +++ b/src/main/java/org/micromanager/lightsheetmanager/api/data/LightSheetType.java @@ -1,17 +1,11 @@ package org.micromanager.lightsheetmanager.api.data; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.util.Arrays; public enum LightSheetType { - UNKNOWN("Unknown"), STATIC("Static"), SCANNED("Scanned"); - private static final Map stringToEnum = - Stream.of(values()).collect(Collectors.toMap(Object::toString, e -> e)); - private final String label_; LightSheetType(final String label) { @@ -23,7 +17,14 @@ public String toString() { return label_; } - public static LightSheetType fromString(final String symbol) { - return stringToEnum.getOrDefault(symbol, LightSheetType.UNKNOWN); + public static LightSheetType fromString(final String propertyValue) { + if (propertyValue == null || propertyValue.isEmpty()) { + return STATIC; + } + return Arrays.stream(values()) + .filter(g -> g.label_.equalsIgnoreCase(propertyValue)) + .findFirst() + .orElse(STATIC); } + } diff --git a/src/main/java/org/micromanager/lightsheetmanager/api/data/MultiChannelMode.java b/src/main/java/org/micromanager/lightsheetmanager/api/data/MultiChannelMode.java index c522e48..6dc9e32 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/api/data/MultiChannelMode.java +++ b/src/main/java/org/micromanager/lightsheetmanager/api/data/MultiChannelMode.java @@ -1,11 +1,5 @@ package org.micromanager.lightsheetmanager.api.data; -import java.util.Arrays; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; - public enum MultiChannelMode { VOLUME("Every Volume"), VOLUME_HW("Every Volume (PLogic)"), @@ -13,9 +7,6 @@ public enum MultiChannelMode { private final String text_; - private static final Map STRING_TO_ENUM = - Stream.of(values()).collect(Collectors.toMap(Object::toString, e -> e)); - MultiChannelMode(final String text) { text_ = text; } @@ -25,18 +16,4 @@ public String toString() { return text_; } - public static MultiChannelMode getByIndex(final int index) { - return values()[index]; - } - - public static String[] toArray() { - return Arrays.stream(values()) - .map(MultiChannelMode::toString) - .toArray(String[]::new); - } - - public static Optional fromString(final String str) { - return Optional.ofNullable(str).map(STRING_TO_ENUM::get); - } - } diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/components/ComboBox.java b/src/main/java/org/micromanager/lightsheetmanager/gui/components/ComboBox.java index 5a5a5d8..8883cf0 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/components/ComboBox.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/components/ComboBox.java @@ -5,49 +5,22 @@ import java.awt.Dimension; import java.util.Arrays; -public class ComboBox extends JComboBox { +public class ComboBox extends JComboBox { - private static int defaultWidth = 100; - private static int defaultHeight = 20; - - private String selected; - private final String[] labels; - - public ComboBox(final String[] labels, final String selected) { - super(labels); - this.labels = labels; - this.selected = selected; - init(defaultWidth, defaultHeight); - } - - public ComboBox(final String[] labels, final String selected, final int width, final int height) { + public ComboBox(final T[] labels, final T selected, final int width, final int height) { super(labels); - this.labels = labels; - this.selected = selected; - init(width, height); - } - - private void init(final int width, final int height) { setAbsoluteSize(width, height); - setSelectedIndex(getIndex(selected)); + setSelectedItem(selected); setFocusable(false); // removes the focus highlight } - public static void setDefaultSize(final int width, final int height) { - defaultWidth = width; - defaultHeight = height; - } - - private int getIndex(final String label) { - return Arrays.asList(labels).indexOf(label); - } - - public String getSelected() { - return selected; + @SuppressWarnings("unchecked") + public T getSelected() { + return (T) getSelectedItem(); } - public void setSelected(final String label) { - setSelectedIndex(getIndex(label)); + public void setSelected(final T item) { + setSelectedItem(item); } public void setAbsoluteSize(final int width, final int height) { @@ -58,10 +31,7 @@ public void setAbsoluteSize(final int width, final int height) { } public void registerListener(final Method method) { - addActionListener(event -> { - selected = (String)getSelectedItem(); - method.run(event); - }); + addActionListener(method::run); } } \ No newline at end of file diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/AcquisitionTab.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/AcquisitionTab.java index 801a793..8f2d2c2 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/AcquisitionTab.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/AcquisitionTab.java @@ -4,7 +4,6 @@ import java.lang.reflect.InvocationTargetException; import java.util.concurrent.Future; import javax.swing.SwingUtilities; -import org.micromanager.Studio; import org.micromanager.lightsheetmanager.LightSheetManagerFrame; import org.micromanager.lightsheetmanager.api.data.GeometryType; import org.micromanager.lightsheetmanager.api.internal.DefaultAcquisitionSettingsSCAPE; @@ -36,7 +35,7 @@ public class AcquisitionTab extends Panel implements ListeningPanel { private Panel pnlRight_; private Panel pnlButtons_; - private ComboBox cmbAcquisitionModes_; + private ComboBox cmbAcquisitionModes_; // acquisition buttons private ToggleButton btnRunAcquisition_; @@ -167,8 +166,8 @@ private void createUserInterface() { // acquisition mode combo box final boolean isUsingScanSettings = model_.devices().isUsingStageScanning(); final GeometryType geometryType = model_.devices().adapter().geometry(); - cmbAcquisitionModes_ = new ComboBox(AcquisitionMode.getLabels(geometryType, isUsingScanSettings), - acqSettings.acquisitionMode().toString(), + cmbAcquisitionModes_ = new ComboBox<>(AcquisitionMode.getValidModes(geometryType, isUsingScanSettings), + acqSettings.acquisitionMode(), 180, 24); cbxUseAdvancedTiming_ = new CheckBox("Use advanced timing settings", @@ -269,11 +268,8 @@ private void createEventHandlers() { }); // select the acquisition mode - cmbAcquisitionModes_.registerListener(e -> { - final String selected = cmbAcquisitionModes_.getSelected(); - AcquisitionMode.fromString(selected).ifPresent(mode -> - model_.acquisitions().settingsBuilder().acquisitionMode(mode)); - }); + cmbAcquisitionModes_.registerListener(e -> + model_.acquisitions().settingsBuilder().acquisitionMode(cmbAcquisitionModes_.getSelected())); // TODO: should timing recalc be part of setting use advanced timing value in model? // switches timing panels based on check box diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/AutofocusTab.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/AutofocusTab.java index 6d36b79..63711d7 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/AutofocusTab.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/AutofocusTab.java @@ -26,14 +26,14 @@ public class AutofocusTab extends Panel implements ListeningPanel { private Spinner spnNumImages_; private Spinner spnStepSize_; //private Spinner spnToleranceUm_; - private ComboBox cmbAutofocusMode_; - private ComboBox cmbScoringMethod_; + private ComboBox cmbAutofocusMode_; + private ComboBox cmbScoringMethod_; private Button btnRunAutofocus_; // autofocus options during setup private CheckBox cbxAutofocusEveryPass_; private CheckBox cbxAutofocusBeforeAcq_; - private ComboBox cmbAutofocusChannel_; + private ComboBox cmbAutofocusChannel_; // TODO: impl private Spinner spnAutofocusEveryX_; private Spinner spnMaxOffset_; @@ -89,12 +89,10 @@ public void createUserInterface() { // spnToleranceUm_ = Spinner.createDoubleSpinner( // acqSettings.autofocusSettings().toleranceUm(), 0.0, 1.0, 0.01); - ComboBox.setDefaultSize(120, 20); - cmbScoringMethod_ = new ComboBox(AutofocusType.toArray(), - acqSettings.autofocusSettings().scoringMethod().toString()); - ComboBox.setDefaultSize(140, 20); - cmbAutofocusMode_ = new ComboBox(AutofocusMode.toArray(), - acqSettings.autofocusSettings().mode().toString()); + cmbScoringMethod_ = new ComboBox<>(AutofocusType.values(), + acqSettings.autofocusSettings().scoringMethod(), 120, 20); + cmbAutofocusMode_ = new ComboBox<>(AutofocusMode.values(), + acqSettings.autofocusSettings().mode(), 140, 20); btnRunAutofocus_ = new Button("Run Autofocus", 120, 30); btnRunAutofocus_.setEnabled(false); // FIXME: impl autofocus @@ -108,7 +106,7 @@ public void createUserInterface() { cbxAutofocusEveryPass_ = new CheckBox("Autofocus every stage pass", 12, false, CheckBox.RIGHT); cbxAutofocusBeforeAcq_ = new CheckBox("Autofocus before starting acquisition", 12, false, CheckBox.RIGHT); - cmbAutofocusChannel_ = new ComboBox(labels, "None", 60, 20); + cmbAutofocusChannel_ = new ComboBox<>(labels, "None", 60, 20); spnAutofocusEveryX_ = Spinner.createIntegerSpinner(10, 0, 1000, 1); spnMaxOffset_ = Spinner.createIntegerSpinner(3, 0, 10, 1); @@ -128,7 +126,7 @@ public void createUserInterface() { final Spinner spnCorrectEveryX = Spinner.createIntegerSpinner(100, 0, 1000, 1); final Spinner spnMaxDistance = Spinner.createIntegerSpinner(96, 0, 100, 1); final Spinner spnMinMovement = Spinner.createDoubleSpinner(1.0, 0.0, 10.0, 0.5); - final ComboBox cmbChannel = new ComboBox(labels, "None", 60, 20); + final ComboBox cmbChannel = new ComboBox<>(labels, "None", 60, 20); // add ui elements to the panel add(lblTitle, "span 2, wrap"); @@ -211,10 +209,10 @@ private void createEventHandlers() { // .autofocusSettingsBuilder().toleranceUm(spnToleranceUm_.getDouble())); cmbAutofocusMode_.registerListener(e -> model_.acquisitions().settingsBuilder() - .autofocusSettingsBuilder().mode(AutofocusMode.fromString(cmbAutofocusMode_.getSelected()))); + .autofocusSettingsBuilder().mode(cmbAutofocusMode_.getSelected())); cmbScoringMethod_.registerListener(e -> model_.acquisitions().settingsBuilder() - .autofocusSettingsBuilder().scoringMethod(AutofocusType.fromString(cmbScoringMethod_.getSelected()))); + .autofocusSettingsBuilder().scoringMethod(cmbScoringMethod_.getSelected())); btnRunAutofocus_.registerListener(e -> model_.acquisitions().autofocus().run()); diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/CameraTab.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/CameraTab.java index e6c0141..cf19cf5 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/CameraTab.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/CameraTab.java @@ -29,7 +29,7 @@ public class CameraTab extends Panel implements ListeningPanel { private Button btnCustomROI_; private Button btnGetCurrentROI_; - private ComboBox cmbCameraTriggerMode_; + private ComboBox cmbCameraTriggerMode_; private RadioButton radPrimaryCamera_; private CheckBox cbxUseSimultaneousCameras_; private List cbxCameras_; @@ -67,15 +67,15 @@ private void createUserInterface() { // TODO: use optional here for camera? // get the imaging camera library - String[] modes = {""}; + CameraMode[] modes = {}; final CameraBase camera = model_.devices().firstImagingCamera(); if (camera != null) { final CameraLibrary camLib = CameraLibrary.fromString(camera.getDeviceLibrary()); modes = CameraMode.getAvailableModes(camLib); } - cmbCameraTriggerMode_ = new ComboBox(modes, - model_.acquisitions().settings().cameraMode().toString()); + cmbCameraTriggerMode_ = new ComboBox<>(modes, + model_.acquisitions().settings().cameraMode(), 140, 20); // validate that the logical device name exists final String[] cameraNames = model_.devices().imagingCameraNames(); @@ -87,7 +87,8 @@ private void createUserInterface() { if (cameraOrder.length > 0) { primaryCamera = cameraOrder[0].name(); } else { - primaryCamera = cameraNames[0]; // default to first camera name + // TODO: what is a sensible default here? make sure cameraNames is always populated? + // primaryCamera = cameraNames[0]; // default to first camera name } // simultaneous camera settings @@ -146,7 +147,7 @@ private void createEventHandlers() { // camera trigger mode cmbCameraTriggerMode_.registerListener(e -> { - final CameraMode cameraMode = CameraMode.fromString(cmbCameraTriggerMode_.getSelected()); + final CameraMode cameraMode = cmbCameraTriggerMode_.getSelected(); model_.acquisitions().settingsBuilder().cameraMode(cameraMode); tabPanel_.getAcquisitionTab().getSliceSettingsPanel().switchUI(cameraMode); tabPanel_.swapSetupPathPanels(cameraMode); diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/acquisition/SaveDataPanel.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/acquisition/SaveDataPanel.java index e986ab9..fb59d07 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/acquisition/SaveDataPanel.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/acquisition/SaveDataPanel.java @@ -28,7 +28,7 @@ public class SaveDataPanel extends Panel { private Button btnBrowse_; private Button btnOpen_; - private ComboBox cbxSaveMode_; + private ComboBox cbxSaveMode_; private CheckBox cbxSaveWhileAcquiring_; private final FileDialogs.FileType directorySelect_; @@ -76,8 +76,8 @@ public void createUserInterface() { btnBrowse_ = new Button("...", 26, 20); btnOpen_ = new Button(Icons.FOLDER, 26, 20); - cbxSaveMode_ = new ComboBox(DataStorage.SaveMode.toArray(), - acqSettings.saveMode().toString(), 110, 20); + cbxSaveMode_ = new ComboBox<>(DataStorage.SaveMode.values(), + acqSettings.saveMode(), 110, 20); cbxSaveWhileAcquiring_ = new CheckBox("Save images during acquisition", acqSettings.isSavingImagesDuringAcquisition()); @@ -107,7 +107,7 @@ public void createEventHandlers() { // use the text field so we don't need to update settings btnOpen_.registerListener(e -> - openDirectory(txtSaveDirectory_.getText().trim())); + openDirectory(txtSaveDirectory_.getText())); cbxSaveWhileAcquiring_.registerListener(e -> model_.acquisitions().settingsBuilder().saveImagesDuringAcquisition( @@ -117,8 +117,7 @@ public void createEventHandlers() { model_.acquisitions().settingsBuilder().saveNamePrefix(txtSaveFileName_.getText())); cbxSaveMode_.registerListener(e -> - model_.acquisitions().settingsBuilder().saveMode( - DataStorage.SaveMode.fromString(cbxSaveMode_.getSelected()))); + model_.acquisitions().settingsBuilder().saveMode(cbxSaveMode_.getSelected())); } diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/acquisition/VolumeSettingsPanel.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/acquisition/VolumeSettingsPanel.java index 4824db5..380cfdd 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/acquisition/VolumeSettingsPanel.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/acquisition/VolumeSettingsPanel.java @@ -13,8 +13,8 @@ public class VolumeSettingsPanel extends Panel { - private ComboBox cmbNumViews_; - private ComboBox cmbFirstView_; + private ComboBox cmbNumViews_; + private ComboBox cmbFirstView_; private Spinner spnViewDelay_; private Spinner spnSliceStepSize_; @@ -38,11 +38,10 @@ private void createUserInterface() { .settings().volumeSettings(); // create labels for combo boxes - ArrayList labels = new ArrayList<>(numImagingPaths); + Integer[] viewOptions = new Integer[numImagingPaths]; for (int i = 0; i < numImagingPaths; i++) { - labels.add(String.valueOf(i+1)); + viewOptions[i] = i + 1; } - final String[] lbls = labels.toArray(new String[0]); final Label lblNumViews = new Label("Number of views:"); final Label lblFirstView = new Label("First view:"); @@ -54,15 +53,15 @@ private void createUserInterface() { // than the number of sides, default to 1. int numViews = volumeSettings.numViews(); int firstView = volumeSettings.firstView(); - if (numViews > labels.size()) { + if (numViews > viewOptions.length) { numViews = 1; } - if (firstView > labels.size()) { + if (firstView > viewOptions.length) { firstView = 1; } - cmbNumViews_ = new ComboBox(lbls, String.valueOf(numViews), 60, 20); - cmbFirstView_ = new ComboBox(lbls, String.valueOf(firstView), 60, 20); + cmbNumViews_ = new ComboBox<>(viewOptions, numViews, 60, 20); + cmbFirstView_ = new ComboBox<>(viewOptions, firstView, 60, 20); spnViewDelay_ = Spinner.createDoubleSpinner( volumeSettings.delayBeforeView(), 0.0, Double.MAX_VALUE, 0.25); @@ -101,12 +100,12 @@ private void createEventHandlers() { cmbNumViews_.registerListener(e -> { model_.acquisitions().settingsBuilder().volumeSettingsBuilder() - .numViews(Integer.parseInt(cmbNumViews_.getSelected())); + .numViews(cmbNumViews_.getSelected()); }); cmbFirstView_.registerListener(e -> { model_.acquisitions().settingsBuilder().volumeSettingsBuilder() - .firstView(Integer.parseInt(cmbFirstView_.getSelected())); + .firstView(cmbFirstView_.getSelected()); }); spnViewDelay_.registerListener(e -> { 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 9c2610f..a6a2860 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 @@ -23,8 +23,8 @@ public class ChannelTablePanel extends Panel { private Button btnRemoveChannel_; private Button btnRefresh_; - private ComboBox cmbChannelGroup_; - private ComboBox cmbChannelMode_; + private ComboBox cmbChannelGroup_; + private ComboBox cmbChannelMode_; private final ChannelTable table_; private final LightSheetManager model_; @@ -50,12 +50,12 @@ private void createUserInterface() { btnRefresh_.setToolTipText("Refresh the channel panel with the latest configuration groups settings."); final String[] groupLabels = table_.getChannelGroups(); - cmbChannelGroup_ = new ComboBox(groupLabels, + cmbChannelGroup_ = new ComboBox<>(groupLabels, model_.acquisitions().settings().channelSettings().channelGroup(), 120, 22); - cmbChannelMode_ = new ComboBox(MultiChannelMode.toArray(), - model_.acquisitions().settings().channelSettings().channelMode().toString(), + cmbChannelMode_ = new ComboBox<>(MultiChannelMode.values(), + model_.acquisitions().settings().channelSettings().channelMode(), 120, 22); add(lblChannelGroup_, "split 2"); @@ -122,7 +122,7 @@ private void createEventHandlers() { // select channel mode cmbChannelMode_.registerListener(e -> { model_.acquisitions().settingsBuilder().channelSettingsBuilder() - .channelMode(MultiChannelMode.getByIndex(cmbChannelMode_.getSelectedIndex())); + .channelMode(cmbChannelMode_.getSelected()); }); } 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 0995bef..e045326 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 @@ -10,9 +10,9 @@ // TODO: find a better way to organize vendor specific panels/ui elements public class JoystickPanel extends Panel { - private ComboBox cmbJoystick_; - private ComboBox cmbLeftWheel_; - private ComboBox cmbRightWheel_; + private ComboBox cmbJoystick_; + private ComboBox cmbLeftWheel_; + private ComboBox cmbRightWheel_; private LightSheetManager model_; @@ -37,10 +37,9 @@ private void createUserInterface() { // TODO: enum for combo values String[] labels = {"Imaging Piezo", "XYStage", "Imaging Slice"}; - ComboBox.setDefaultSize(100, 20); - cmbJoystick_ = new ComboBox(labels, "XYStage"); - cmbLeftWheel_ = new ComboBox(labels, "Imaging Piezo"); - cmbRightWheel_ = new ComboBox(labels, "Imaging Slice"); + cmbJoystick_ = new ComboBox<>(labels, "XYStage", 100, 20); + cmbLeftWheel_ = new ComboBox<>(labels, "Imaging Piezo", 100, 20); + cmbRightWheel_ = new ComboBox<>(labels, "Imaging Slice", 100, 20); add(lblJoystick, ""); add(cmbJoystick_, "wrap"); diff --git a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/SingleAxisPanel.java b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/SingleAxisPanel.java index 4a2dbca..03b82f9 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/SingleAxisPanel.java +++ b/src/main/java/org/micromanager/lightsheetmanager/gui/tabs/setup/SingleAxisPanel.java @@ -18,7 +18,7 @@ public class SingleAxisPanel extends Panel { - private ComboBox cbxPattern_; + private ComboBox cbxPattern_; private Spinner spnAmplitude_; private Spinner spnPeriod_; @@ -42,20 +42,19 @@ private void createUserInterface() { final JLabel lblPeriod = new JLabel("Period [ms]:"); - final String[] patterns = SingleAxis.Pattern.toArray(); + final SingleAxis.Pattern[] patterns = SingleAxis.Pattern.values(); - String pattern = patterns[0]; + SingleAxis.Pattern pattern = patterns[0]; double amplitudeY = 0; int periodY = 0; if (isUsingPLogic_) { - final ASIScanner scanner = model_.devices() - .device("IllumSlice"); - pattern = scanner.sa().getPatternY().toString(); + final ASIScanner scanner = model_.devices().device("IllumSlice"); + pattern = scanner.sa().getPatternY(); amplitudeY = scanner.sa().getAmplitudeY(); periodY = scanner.sa().getPeriodY(); } - cbxPattern_ = new ComboBox(patterns, pattern, 100, 24); + cbxPattern_ = new ComboBox<>(patterns, pattern, 100, 24); spnAmplitude_ = Spinner.createDoubleSpinner(amplitudeY, 0.0, 100.0, 1.0); spnPeriod_ = Spinner.createIntegerSpinner(periodY, 0, 100, 1); @@ -74,7 +73,7 @@ private void createEventHandlers() { .device("IllumSlice"); cbxPattern_.registerListener(e -> { - galvo.sa().setPatternY(SingleAxis.Pattern.fromString(cbxPattern_.getSelected())); + galvo.sa().setPatternY(cbxPattern_.getSelected()); }); spnAmplitude_.registerListener(e -> { diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/devices/DeviceBase.java b/src/main/java/org/micromanager/lightsheetmanager/model/devices/DeviceBase.java index 03fd8f4..cf01c3c 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/devices/DeviceBase.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/devices/DeviceBase.java @@ -101,6 +101,28 @@ public void setPropertyFloat(final String propertyName, final double propertyVal } } + public double getPropertyUpperLimit(final String propertyName) { + try { + if (core_.hasPropertyLimits(deviceName_, propertyName)) { + return core_.getPropertyUpperLimit(deviceName_, propertyName); + } + } catch (Exception e) { + studio_.logs().logDebugMessage("Property " + propertyName + " has no upper limit or is non-numeric."); + } + return Double.MAX_VALUE; + } + + public double getPropertyLowerLimit(final String propertyName) { + try { + if (core_.hasPropertyLimits(deviceName_, propertyName)) { + return core_.getPropertyLowerLimit(deviceName_, propertyName); + } + } catch (Exception e) { + studio_.logs().logDebugMessage("Property " + propertyName + " has no lower limit or is non-numeric."); + } + return -Double.MAX_VALUE; // Double.MIN_VALUE is a value close to 0 so use -Double.MAX_VALUE + } + public boolean isPropertyPreInit(final String propertyName) { boolean result = false; try { diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/devices/LightSheetDeviceManager.java b/src/main/java/org/micromanager/lightsheetmanager/model/devices/LightSheetDeviceManager.java index 344d554..952baa9 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/devices/LightSheetDeviceManager.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/devices/LightSheetDeviceManager.java @@ -4,6 +4,7 @@ import org.micromanager.Studio; import org.micromanager.lightsheetmanager.api.data.GeometryType; import org.micromanager.lightsheetmanager.api.data.LightSheetType; +import org.micromanager.lightsheetmanager.model.utils.MathUtils; import java.util.Arrays; import java.util.Map; @@ -11,9 +12,9 @@ /** - * The device adapter "LightSheetDeviceManager". - * - *

Contained in the DeviceManager object as "LightSheetDeviceManager". + * The device adapter "LightSheetManager". + *

+ * Contained in the DeviceManager object as "LightSheetDeviceManager". */ public class LightSheetDeviceManager extends DeviceBase { @@ -21,7 +22,6 @@ public class LightSheetDeviceManager extends DeviceBase { public static final String UNDEFINED = "Undefined"; // TODO: use this for validation - // TODO: parse this to a more useful object for version comparisons? private String version_; // pre-init properties @@ -41,8 +41,17 @@ public LightSheetDeviceManager(final Studio studio, final String deviceName) { */ private void loadPreInitProperties() { version_ = getProperty("Version"); + + // if GeometryType.UNKNOWN then we open the plugin error screen geometryType_ = GeometryType.fromString(getProperty("MicroscopeGeometry")); + if (geometryType_ == GeometryType.UNKNOWN) { + studio_.logs().logError("LightSheetDeviceManager: Failed to identify microscope geometry! " + + "Device adapter returned: " + getProperty("MicroscopeGeometry")); + } + + // default to LightSheetType.STATIC on parsing error lightSheetType_ = LightSheetType.fromString(getProperty("LightSheetType")); + // change defaults based on microscope geometry int defaultImaging = 1; int defaultIllumination = 1; @@ -50,9 +59,22 @@ private void loadPreInitProperties() { defaultImaging = 2; defaultIllumination = 2; } - numImagingPaths_ = parsePropertyInt("ImagingPaths", defaultImaging); - numIlluminationPaths_ = parsePropertyInt("IlluminationPaths", defaultIllumination); - numSimultaneousCameras_ = parsePropertyInt("SimultaneousCameras", 1); + + // use the defaults if there is a parsing error + final int numImaging = parsePropertyInt("ImagingPaths", defaultImaging); + final int numIllum = parsePropertyInt("IlluminationPaths", defaultIllumination); + final int numCameras = parsePropertyInt("SimultaneousCameras", 1); + + // constrain the values to the range of the property limits + numImagingPaths_ = MathUtils.clamp(numImaging, + (int) getPropertyLowerLimit("ImagingPaths"), + (int) getPropertyUpperLimit("ImagingPaths")); + numIlluminationPaths_ = MathUtils.clamp(numIllum, + (int) getPropertyLowerLimit("IlluminationPaths"), + (int) getPropertyUpperLimit("IlluminationPaths")); + numSimultaneousCameras_ = MathUtils.clamp(numCameras, + (int) getPropertyLowerLimit("SimultaneousCameras"), + (int) getPropertyUpperLimit("SimultaneousCameras")); } /** @@ -69,13 +91,13 @@ private int parsePropertyInt(final String propertyName, final int defaultValue) } private boolean isPositionDevice(final String deviceName) { - final DeviceType deviceType = getDeviceType(deviceName); + final DeviceType deviceType = deviceType(deviceName); return deviceType == DeviceType.StageDevice || deviceType == DeviceType.XYStageDevice || deviceType == DeviceType.GalvoDevice; } - private DeviceType getDeviceType(final String deviceName) { + private DeviceType deviceType(final String deviceName) { try { return core_.getDeviceType(deviceName); } catch (Exception e) { @@ -128,7 +150,7 @@ public Map deviceMap() { */ public Map deviceTypeMap() { return deviceMap().entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> getDeviceType(e.getValue()))); + .collect(Collectors.toMap(Map.Entry::getKey, e -> deviceType(e.getValue()))); } /** From 146aa24da94064ea44d0ed48da80234837713cd7 Mon Sep 17 00:00:00 2001 From: bls337 Date: Wed, 18 Feb 2026 08:46:22 -0800 Subject: [PATCH 4/4] Add files via upload --- .../model/utils/MathUtils.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/main/java/org/micromanager/lightsheetmanager/model/utils/MathUtils.java diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/utils/MathUtils.java b/src/main/java/org/micromanager/lightsheetmanager/model/utils/MathUtils.java new file mode 100644 index 0000000..867f5f5 --- /dev/null +++ b/src/main/java/org/micromanager/lightsheetmanager/model/utils/MathUtils.java @@ -0,0 +1,36 @@ +package org.micromanager.lightsheetmanager.model.utils; + +/** + * Math utilities. + */ +public class MathUtils { + + private MathUtils() { + // prevent instantiation + } + + /** + * Returns the value constrained to the range min to max. + * + * @param value the value to clamp + * @param min the minimum value + * @param max the maximum value + * @return the clamped value + */ + public static int clamp(final int value, final int min, final int max) { + return Math.max(min, Math.min(value, max)); + } + + /** + * Returns the value constrained to the range min to max. + * + * @param value the value to clamp + * @param min the minimum value + * @param max the maximum value + * @return the clamped value + */ + public static double clamp(final double value, final double min, final double max) { + return Math.max(min, Math.min(value, max)); + } + +}