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 @@ -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.7";
public static final String version = "0.5.8";

private Studio studio_;
private LightSheetManager model_;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.micromanager.lightsheetmanager.api;

import org.micromanager.lightsheetmanager.api.data.AcquisitionMode;
import org.micromanager.lightsheetmanager.api.data.CameraData;
import org.micromanager.lightsheetmanager.api.data.CameraMode;
import org.micromanager.lightsheetmanager.api.internal.DefaultChannelSettings;
import org.micromanager.lightsheetmanager.api.internal.DefaultScanSettings;
Expand Down Expand Up @@ -37,14 +38,7 @@ interface Builder<T extends AcquisitionSettings.Builder<T>> extends AcquisitionS
*
* @param cameraOrder the imaging camera order
*/
T imagingCameraOrder(final String[] cameraOrder);

/**
* Sets the active imaging cameras.
*
* @param camerasActive the active imaging cameras
*/
T imagingCamerasActive(final boolean[] camerasActive);
T imagingCameraOrder(final CameraData[] cameraOrder);

/**
* Sets the acquisition to acquire from multiple simultaneous cameras.
Expand Down Expand Up @@ -213,14 +207,7 @@ interface Builder<T extends AcquisitionSettings.Builder<T>> extends AcquisitionS
*
* @return the imaging camera order
*/
String[] imagingCameraOrder();

/**
* Returns an array of active imaging cameras.
*
* @return an array of active imaging cameras
*/
boolean[] imagingCamerasActive();
CameraData[] imagingCameraOrder();

/**
* Returns true if acquiring from both imaging cameras.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.micromanager.lightsheetmanager.api.data;

// Used to track imaging camera order for simultaneous imaging cameras.
public class CameraData {

private String name_;
private boolean isActive_;

public CameraData(final String name, final boolean isActive) {
name_ = name;
isActive_ = isActive;
}

public String name() {
return name_;
}

public void name(final String name) {
name_ = name;
}

public boolean isActive() {
return isActive_;
}

public void isActive(final boolean isActive) {
isActive_ = isActive;
}

public static boolean isCameraActive(final CameraData[] cameras, final String cameraName) {
for (CameraData camera : cameras) {
if (camera.name().equals(cameraName)) {
return camera.isActive();
}
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.micromanager.lightsheetmanager.api.AcquisitionSettingsSCAPE;
import org.micromanager.lightsheetmanager.api.data.AcquisitionMode;
import org.micromanager.lightsheetmanager.api.data.CameraData;
import org.micromanager.lightsheetmanager.api.data.CameraMode;

public class DefaultAcquisitionSettingsSCAPE extends DefaultAcquisitionSettings implements AcquisitionSettingsSCAPE {
Expand All @@ -19,8 +20,7 @@ public static class Builder extends DefaultAcquisitionSettings.Builder<Builder>
private AcquisitionMode acquisitionMode_ = AcquisitionMode.NO_SCAN;

private CameraMode cameraMode_ = CameraMode.EDGE;
private String[] imagingCameraOrder_ = {};
private boolean[] imagingCamerasActive_ = {};
private CameraData[] imagingCameraOrder_ = {};
private boolean useSimultaneousCameras_ = true;

private boolean useChannels_ = false;
Expand Down Expand Up @@ -58,7 +58,6 @@ public Builder(final DefaultAcquisitionSettingsSCAPE acqSettings) {
acquisitionMode_ = acqSettings.acquisitionMode_;
cameraMode_ = acqSettings.cameraMode_;
imagingCameraOrder_ = acqSettings.imagingCameraOrder_;
imagingCamerasActive_ = acqSettings.imagingCamerasActive_;
useSimultaneousCameras_ = acqSettings.useSimultaneousCameras_;
useChannels_ = acqSettings.useChannels_;
useTimePoints_ = acqSettings.useTimePoints_;
Expand Down Expand Up @@ -107,22 +106,11 @@ public Builder cameraMode(final CameraMode cameraMode) {
* @param cameraOrder the imaging camera order
*/
@Override
public Builder imagingCameraOrder(final String[] cameraOrder) {
public Builder imagingCameraOrder(final CameraData[] cameraOrder) {
imagingCameraOrder_ = cameraOrder;
return this;
}

/**
* Sets the active imaging cameras.
*
* @param camerasActive the active imaging cameras
*/
@Override
public Builder imagingCamerasActive(final boolean[] camerasActive) {
imagingCamerasActive_ = camerasActive;
return this;
}

/**
* Sets the acquisition to acquire from multiple simultaneous cameras.
*
Expand Down Expand Up @@ -322,8 +310,7 @@ public String toString() {
private final AcquisitionMode acquisitionMode_;

private final CameraMode cameraMode_;
private final String[] imagingCameraOrder_;
private final boolean[] imagingCamerasActive_;
private final CameraData[] imagingCameraOrder_;
private final boolean useSimultaneousCameras_;

private final boolean useChannels_;
Expand Down Expand Up @@ -356,7 +343,6 @@ private DefaultAcquisitionSettingsSCAPE(Builder builder) {
acquisitionMode_ = builder.acquisitionMode_;
cameraMode_ = builder.cameraMode_;
imagingCameraOrder_ = builder.imagingCameraOrder_;
imagingCamerasActive_ = builder.imagingCamerasActive_;
useSimultaneousCameras_ = builder.useSimultaneousCameras_;
useChannels_ = builder.useChannels_;
useTimePoints_ = builder.useTimePoints_;
Expand Down Expand Up @@ -506,20 +492,10 @@ public CameraMode cameraMode() {
* @return the imaging camera order
*/
@Override
public String[] imagingCameraOrder() {
public CameraData[] imagingCameraOrder() {
return imagingCameraOrder_;
}

/**
* Returns an array of active imaging cameras.
*
* @return an array of active imaging cameras
*/
@Override
public boolean[] imagingCamerasActive() {
return imagingCamerasActive_;
}

/**
* Returns true if acquiring from all active imaging cameras on a single view.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.micromanager.lightsheetmanager.gui.tabs;

import org.micromanager.lightsheetmanager.api.data.CameraData;
import org.micromanager.lightsheetmanager.api.data.CameraLibrary;
import org.micromanager.lightsheetmanager.api.data.CameraMode;
import org.micromanager.lightsheetmanager.gui.components.Button;
Expand Down Expand Up @@ -31,7 +32,7 @@ public class CameraTab extends Panel implements ListeningPanel {
private ComboBox cmbCameraTriggerMode_;
private RadioButton radPrimaryCamera_;
private CheckBox cbxUseSimultaneousCameras_;
private List<CheckBox> cbxActiveCameras_;
private List<CheckBox> cbxCameras_;

private final TabPanel tabPanel_;
private final LightSheetManager model_;
Expand Down Expand Up @@ -63,22 +64,30 @@ private void createUserInterface() {
btnCustomROI_ = new Button("Custom", 140, 30);
btnGetCurrentROI_ = new Button("Get Current ROI", 140, 30);

// TODO: use optional here for camera?

// get the imaging camera library
String[] modes = {""};
final CameraBase camera = model_.devices().firstImagingCamera();
final CameraLibrary camLib = CameraLibrary.fromString(camera.getDeviceLibrary());
if (camera != null) {
final CameraLibrary camLib = CameraLibrary.fromString(camera.getDeviceLibrary());
modes = CameraMode.getAvailableModes(camLib);
}

cmbCameraTriggerMode_ = new ComboBox(CameraMode.getAvailableModes(camLib),
cmbCameraTriggerMode_ = new ComboBox(modes,
model_.acquisitions().settings().cameraMode().toString());

// validate that the logical device name exists
final String[] cameraNames = model_.devices().imagingCameraNames();
cbxActiveCameras_ = new ArrayList<>(cameraNames.length);
cbxCameras_ = new ArrayList<>(cameraNames.length);

// the first element of the list is the primary camera
String primaryCamera = "";
final String[] cameraOrder = model_.acquisitions().settings().imagingCameraOrder();
final CameraData[] cameraOrder = model_.acquisitions().settings().imagingCameraOrder();
if (cameraOrder.length > 0) {
primaryCamera = cameraOrder[0];
primaryCamera = cameraOrder[0].name();
} else {
primaryCamera = cameraNames[0]; // default to first camera name
}

// simultaneous camera settings
Expand All @@ -94,11 +103,12 @@ private void createUserInterface() {
"[]6[]"
);

final boolean[] activeCameras = model_.acquisitions().settings().imagingCamerasActive();
for (int i = 0; i < cameraNames.length; i++) {
final CheckBox checkBox = new CheckBox("Active", activeCameras[i]);
// we already have the camera order array
for (String cameraName : cameraNames) {
final boolean isActive = CameraData.isCameraActive(cameraOrder, cameraName);
final CheckBox checkBox = new CheckBox("Active", isActive);
pnlCheckboxes.add(checkBox, "wrap");
cbxActiveCameras_.add(checkBox);
cbxCameras_.add(checkBox);
}

final Panel pnlCameraSelectionRow = new Panel();
Expand Down Expand Up @@ -142,30 +152,12 @@ private void createEventHandlers() {
tabPanel_.swapSetupPathPanels(cameraMode);
});

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

// select primary camera
radPrimaryCamera_.registerListener(e -> {
final String selected = radPrimaryCamera_.getSelectedButtonText();
final String[] cameraNames = model_.devices().imagingCameraNames();
final List<String> cameraOrder = new ArrayList<>();
// the first array index is the primary camera
cameraOrder.add(selected);
for (String cameraName : cameraNames) {
if (!selected.equals(cameraName)) {
cameraOrder.add(cameraName);
}
}
model_.acquisitions().settingsBuilder()
.imagingCameraOrder(cameraOrder.toArray(String[]::new));
});
radPrimaryCamera_.registerListener(e -> computeCameraOrder());

// active camera check boxes
for (CheckBox cbx : cbxActiveCameras_) {
cbx.registerListener(e ->
model_.acquisitions().settingsBuilder()
.imagingCamerasActive(activeCameras()));
for (CheckBox cbx : cbxCameras_) {
cbx.registerListener(e -> computeCameraOrder());
}

// use all active cameras
Expand All @@ -177,13 +169,43 @@ private void createEventHandlers() {
}

private boolean[] activeCameras() {
boolean[] active = new boolean[cbxActiveCameras_.size()];
for (int i = 0; i < cbxActiveCameras_.size(); i++) {
active[i] = cbxActiveCameras_.get(i).isSelected();
boolean[] active = new boolean[cbxCameras_.size()];
for (int i = 0; i < cbxCameras_.size(); i++) {
active[i] = cbxCameras_.get(i).isSelected();
}
return active;
}

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);

// 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;
}
}

// the first array index is the primary camera
cameraData.add(new CameraData(selected, isSelectedActive));
// TODO(Brandon): uses simple ordering that works for 2 cameras,
// but needs additional work to support 4. Use a reorderable JTable?
for (int i = 0; i < cameraNames.length; i++) {
if (!selected.equals(cameraNames[i])) {
System.out.println("cameraNames[i] " + cameraNames[i] + "active[i] " + active[i]);
cameraData.add(new CameraData(cameraNames[i], active[i]));
}
}
model_.acquisitions().settingsBuilder()
.imagingCameraOrder(cameraData.toArray(CameraData[]::new));
}

@Override
public void selected() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import mmcorej.Configuration;
import mmcorej.StrVector;
import org.micromanager.lightsheetmanager.LightSheetManager;
import org.micromanager.lightsheetmanager.api.data.CameraData;
import org.micromanager.lightsheetmanager.api.data.CameraLibrary;
import mmcorej.CMMCore;
import mmcorej.DeviceType;
Expand Down Expand Up @@ -297,14 +298,12 @@ public CameraBase firstImagingCamera() {
return (CameraBase) deviceMap_.get(deviceKey);
}

// TODO: active needs to be synchronized with the order, since order changes but active does not
// For simultaneous cameras
public String firstActiveCameraName() {
final String[] cameras = model_.acquisitions().settings().imagingCameraOrder();
final boolean[] active = model_.acquisitions().settings().imagingCamerasActive();
for (int i = 0; i < cameras.length; i++) {
if (active[i]) {
return cameras[i];
final CameraData[] cameras = model_.acquisitions().settings().imagingCameraOrder();
for (CameraData camera : cameras) {
if (camera.isActive()) {
return camera.name();
}
}
return "";
Expand Down Expand Up @@ -348,11 +347,10 @@ public CameraBase[] imagingCameras() {
String[] cameraNames;
if (model_.acquisitions().settings().isUsingSimultaneousCameras()) {
ArrayList<String> names = new ArrayList<>();
final String[] cameras = model_.acquisitions().settings().imagingCameraOrder();
final boolean[] active = model_.acquisitions().settings().imagingCamerasActive();
for (int i = 0; i < cameras.length; i++) {
if (active[i]) {
names.add(cameras[i]);
final CameraData[] cameras = model_.acquisitions().settings().imagingCameraOrder();
for (CameraData camera : cameras) {
if (camera.isActive()) {
names.add(camera.name());
}
}
cameraNames = names.toArray(String[]::new);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ boolean setup() {
// }

// we must have an active camera if we are using simultaneous cameras
if (model_.acquisitions().settings().isUsingSimultaneousCameras()) {
final boolean[] active = model_.acquisitions().settings().imagingCamerasActive();
if (IntStream.range(0, active.length).noneMatch(i -> active[i])) {
studio_.logs().showError("Using simultaneous cameras and no cameras are active!");
return false;
}
// TODO: primary camera must be active
}
// if (model_.acquisitions().settings().isUsingSimultaneousCameras()) {
// final boolean[] active = model_.acquisitions().settings().imagingCamerasActive();
// if (IntStream.range(0, active.length).noneMatch(i -> active[i])) {
// studio_.logs().showError("Using simultaneous cameras and no cameras are active!");
// return false;
// }
// // TODO: primary camera must be active
// }

// this is needed for LSMAcquisitionEvents to work with multiple positions
if (core_.getFocusDevice().isEmpty()
Expand Down
Loading