Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
// Note: Each text string must be unique to support reliable lookup in fromString().

/**
* Acquisition modes for all microscope geometry types.
* Acquisition modes for all microscope geometries.
* <p>
* Use the {@code modesByType} method to get valid modes based on {@link GeometryType}.
*/
public enum AcquisitionMode {
NO_SCAN("No scan (fixed sheet)"),
Expand Down Expand Up @@ -71,7 +73,7 @@ public String toString() {
}

/**
* Returns {@code true} if the {@link AcquisitionMode} is a stage scan mode.
* Returns {@code true} if the {@code AcquisitionMode} is a stage scan mode.
*
* @return {@code true} if the mode is stage scan mode
*/
Expand All @@ -85,13 +87,13 @@ public boolean isStageScanMode() {
* This list is filtered based on hardware capabilities: if {@code hasStageScanning}
* is {@code false}, all stage-scan related modes are excluded.
*
* @param geometry the {@link GeometryType} to query; if {@code null}, an empty list is returned
* @param geometryType the {@link GeometryType} to query; if {@code null}, an empty list is returned
* @param hasStageScanning {@code true} if stage scan hardware is available
* @return a {@code List} of {@link AcquisitionMode} constants
* @return an array of {@code AcquisitionMode} constants
*/
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
public static AcquisitionMode[] modesByType(final GeometryType geometryType, final boolean hasStageScanning) {
return Optional.ofNullable(geometryType)
.map(MODES_BY_GEOMETRY::get) // returns null if geometryType is not in map
.orElse(Collections.emptyList())
.stream()
.filter(mode -> hasStageScanning || !mode.isStageScanMode())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,10 @@ public static boolean isCameraActive(final CameraData[] cameras, final String ca
}
return false;
}

@Override
public String toString() {
return String.format("%s[name=%s]", getClass().getSimpleName(), name_);
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.micromanager.lightsheetmanager.api.data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -10,8 +9,6 @@

/**
* Camera trigger modes.
*
* <p>All modes should use hardware triggering.
*/
public enum CameraMode {
INTERNAL("Internal"),
Expand All @@ -23,15 +20,15 @@ public enum CameraMode {

private final String text_;

private static final Map<String, CameraMode> stringToEnum =
private static final Map<String, CameraMode> STRING_TO_ENUM =
Stream.of(values()).collect(Collectors.toUnmodifiableMap(Object::toString, e -> e));

CameraMode(final String text) {
text_ = text;
}

public static CameraMode fromString(final String symbol) {
return stringToEnum.getOrDefault(symbol, CameraMode.EDGE);
return STRING_TO_ENUM.getOrDefault(symbol, CameraMode.EDGE);
}

/**
Expand All @@ -53,11 +50,11 @@ public static boolean hasOverlapTrigger(final CameraLibrary camLib) {
* @param camLib the camera device adapter
* @return {@code true} if the camera supports the mode
*/
private static boolean hasPseudoOverlapTrigger(CameraLibrary camLib) {
private static boolean hasPseudoOverlapTrigger(final CameraLibrary camLib) {
return camLib == CameraLibrary.PCOCAMERA || camLib == CameraLibrary.PVCAM;
}

private static boolean hasLevelTrigger(CameraLibrary camLib) {
private static boolean hasLevelTrigger(final CameraLibrary camLib) {
return camLib == CameraLibrary.HAMAMATSU ||
camLib == CameraLibrary.ANDORSDK3 ||
camLib == CameraLibrary.PCOCAMERA;
Expand All @@ -69,37 +66,35 @@ private static boolean hasLevelTrigger(CameraLibrary camLib) {
* @param camLib the camera device adapter
* @return {@code true} if the camera supports the mode
*/
private static boolean hasLightSheetTrigger(CameraLibrary camLib) {
private static boolean hasLightSheetTrigger(final CameraLibrary camLib) {
return camLib == CameraLibrary.HAMAMATSU ||
camLib == CameraLibrary.ANDORSDK3 ||
camLib == CameraLibrary.PVCAM || // not sure about this
camLib == CameraLibrary.DEMOCAMERA; // for testing only
}

public static boolean isCameraValid(CameraLibrary camLib) {
public static boolean isCameraValid(final CameraLibrary camLib) {
return camLib != CameraLibrary.UNKNOWN;
}

public static CameraMode[] getAvailableModes(CameraLibrary camLib) {
public static CameraMode[] modesByDeviceLibrary(final CameraLibrary cameraLibrary) {
ArrayList<CameraMode> modes = new ArrayList<>();
if (isCameraValid(camLib)) {
if (isCameraValid(cameraLibrary)) {
modes.add(CameraMode.EDGE);
if (hasLevelTrigger(camLib)) {
if (hasLevelTrigger(cameraLibrary)) {
modes.add(CameraMode.LEVEL);
}
if (hasOverlapTrigger(camLib)) {
if (hasOverlapTrigger(cameraLibrary)) {
modes.add(CameraMode.OVERLAP);
}
if (hasPseudoOverlapTrigger(camLib)) {
if (hasPseudoOverlapTrigger(cameraLibrary)) {
modes.add(CameraMode.PSEUDO_OVERLAP);
}
if (hasLightSheetTrigger(camLib)) {
if (hasLightSheetTrigger(cameraLibrary)) {
modes.add(CameraMode.VIRTUAL_SLIT);
}
}
return modes.stream()
.map(CameraMode::toString)
.toArray(CameraMode[]::new);
return modes.toArray(CameraMode[]::new);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@
import org.micromanager.lightsheetmanager.api.AcquisitionSettings;
import org.micromanager.lightsheetmanager.model.DataStorage;

// TODO: make public instead of abstract? use this in demo mode?

/**
* Base acquisition settings for all microscopes.
*/
public abstract class DefaultAcquisitionSettings implements AcquisitionSettings {

public abstract static class Builder<T extends Builder<T>> implements AcquisitionSettings.Builder<T> {

private String saveDirectory_ = "";
private String saveNamePrefix_ = "";
private String saveDirectory_ = System.getProperty("user.home");
private String saveNamePrefix_ = "Experiment";
private boolean saveDuringAcq_ = false;
private boolean demoMode_ = false;
private DataStorage.SaveMode saveMode_ = DataStorage.SaveMode.ND_TIFF;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public class CheckBox extends JCheckBox {
public static final int LEFT = SwingConstants.LEFT;
public static final int RIGHT = SwingConstants.RIGHT;

private boolean isLocked_ = false;

public CheckBox(final String text, final boolean defaultState) {
super(text, defaultState);
setHorizontalTextPosition(RIGHT);
Expand All @@ -28,8 +30,59 @@ public CheckBox(final String text, final int fontSize, final boolean defaultStat
setFocusPainted(false);
}

/**
* Set the locked state, in the locked state the {@code CheckBox}
* will not respond to button presses or mouse clicks.
*
* @param locked the locked state
*/
public void setLocked(final boolean locked) {
isLocked_ = locked;
if (locked) {
setFont(getFont().deriveFont(java.awt.Font.BOLD));
} else {
setFont(getFont().deriveFont(java.awt.Font.PLAIN));
}
}

/**
* Sets the selected state of the {@code CheckBox}.
*
* @param state the new selection state
* @param shouldFire {@code true} fires events, {@code false} updates silently
*/
public void setSelected(boolean state, boolean shouldFire) {
if (shouldFire) {
// Standard behavior: updates state and triggers events
super.setSelected(state);
} else {
// "Silent" behavior: updates state via model without firing ActionEvents
getModel().setSelected(state);
}
}

public void registerListener(final Method method) {
addItemListener(method::run);
addActionListener(method::run);
}

@Override
public void setSelected(boolean state) {
// default to true, always fires events
setSelected(state, true);
}

@Override
protected void processMouseEvent(java.awt.event.MouseEvent e) {
if (!isLocked_) {
super.processMouseEvent(e);
}
}

@Override
protected void processKeyEvent(java.awt.event.KeyEvent e) {
if (!isLocked_) {
super.processKeyEvent(e);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ public void setSelected(final String text, final boolean state) {
}
}

public String getSelectedButtonText() {
// Returns the text of the selected button.
public String getSelectedText() {
for (final JRadioButton button : buttons) {
if (button.isSelected()) {
return button.getText();
Expand All @@ -88,6 +89,16 @@ public String getSelectedButtonText() {
return "";
}

// Returns the selected index or -1 if nothing is selected.
public int getSelectedIndex() {
for (int i = 0; i < buttons.size(); i++) {
if (buttons.get(i).isSelected()) {
return i;
}
}
return -1;
}

public void registerListener(final Method method) {
for (final JRadioButton button : buttons) {
button.addActionListener(method::run);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +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.getValidModes(geometryType, isUsingScanSettings),
cmbAcquisitionModes_ = new ComboBox<>(
AcquisitionMode.modesByType(geometryType, isUsingScanSettings),
acqSettings.acquisitionMode(),
180, 24);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class CameraTab extends Panel implements ListeningPanel {
private RadioButton radPrimaryCamera_;
private CheckBox cbxUseSimultaneousCameras_;
private List<CheckBox> cbxCameras_;
private int selectedIndex_;

private final TabPanel tabPanel_;
private final LightSheetManager model_;
Expand Down Expand Up @@ -71,7 +72,7 @@ private void createUserInterface() {
final CameraBase camera = model_.devices().firstImagingCamera();
if (camera != null) {
final CameraLibrary camLib = CameraLibrary.fromString(camera.getDeviceLibrary());
modes = CameraMode.getAvailableModes(camLib);
modes = CameraMode.modesByDeviceLibrary(camLib);
}

cmbCameraTriggerMode_ = new ComboBox<>(modes,
Expand Down Expand Up @@ -112,6 +113,11 @@ private void createUserInterface() {
cbxCameras_.add(checkBox);
}

// we can only set this after we load the settings
selectedIndex_ = radPrimaryCamera_.getSelectedIndex();
// must not disable the primary camera
cbxCameras_.get(selectedIndex_).setLocked(true);

final Panel pnlCameraSelectionRow = new Panel();
pnlCameraSelectionRow.add(new JLabel("Select Primary Camera"), "wrap");
pnlCameraSelectionRow.add(radPrimaryCamera_, "");
Expand Down Expand Up @@ -177,31 +183,37 @@ private boolean[] activeCameras() {
return active;
}

// Change the order of the imaging camera array based on user input.
private void computeCameraOrder() {
// change the order of the imaging camera array
final String selected = radPrimaryCamera_.getSelectedButtonText();
final String[] cameraNames = model_.devices().imagingCameraNames();
final ArrayList<CameraData> cameraData = new ArrayList<>(cameraNames.length);
// cache the previous index
final int lastSelectedIndex = selectedIndex_;

// check if the selected primary camera is active before changing the array order
boolean isSelectedActive = true;
final boolean[] active = activeCameras();
for (int i = 0; i < cameraNames.length; i++) {
if (cameraNames[i].equals(selected)) {
isSelectedActive = active[i];
break;
}
}
// unlock the checkbox for the old primary camera
cbxCameras_.get(lastSelectedIndex).setLocked(false);

// lock the checkbox for the new primary camera
final String selected = radPrimaryCamera_.getSelectedText();
selectedIndex_ = radPrimaryCamera_.getSelectedIndex();
cbxCameras_.get(selectedIndex_).setSelected(true, false);
cbxCameras_.get(selectedIndex_).setLocked(true);

// the first array index is the primary camera
cameraData.add(new CameraData(selected, isSelectedActive));
final String[] cameraNames = model_.devices().imagingCameraNames();
final ArrayList<CameraData> cameraData = new ArrayList<>(cameraNames.length);
cameraData.add(new CameraData(selected, true));

// TODO(Brandon): uses simple ordering that works for 2 cameras,
// but needs additional work to support 4. Use a reorderable JTable?
// but needs additional work to support 4.

// add cameras in a linear order for now
final boolean[] active = activeCameras();
for (int i = 0; i < cameraNames.length; i++) {
if (!selected.equals(cameraNames[i])) {
cameraData.add(new CameraData(cameraNames[i], active[i]));
}
}

// update camera order
model_.acquisitions().settingsBuilder()
.imagingCameraOrder(cameraData.toArray(CameraData[]::new));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@
* A utility class for making dialog boxes.
*
*/
public class DialogUtils {
public final class DialogUtils {

/** This class should not be instantiated. */
private DialogUtils() {
throw new AssertionError("Utility class; do not instantiate.");
}

/**Standard error reporting or delegate to JTextArea component. */
public static boolean SEND_ERROR_TO_COMPONENT = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@

public final class WindowUtils {

/** This class should not be instantiated. */
private WindowUtils() {
throw new AssertionError("Utility class; do not instantiate.");
}

/**
* Returns true if the window is displayable and not null.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,6 @@ boolean setup() {
// return false;
// }

// we must have an active camera if we are using simultaneous cameras
if (model_.acquisitions().settings().isUsingSimultaneousCameras()) {
final CameraData[] cameras = model_.acquisitions().settings().imagingCameraOrder();
if (cameras.length > 0 && !cameras[0].isActive()) {
studio_.logs().showError("The primary camera MUST be active in simultaneous cameras mode!");
return false;
}
}

// set the "Core-Camera" property to the first logical camera device
final String cameraName = model_.devices().firstImagingCamera().getDeviceName();
try {
Expand Down
Loading
Loading