Skip to content

Commit 60f13ca

Browse files
fdrgsptlambert03pre-commit-ci[bot]
authored
fix: use widget from pymmcore-widgets main branch (#269)
* fix: use ChannelGroupWidget * feat: update MultiDWidget * test: update * change import * style: [pre-commit.ci] auto fixes [...] * fix: pins --------- Co-authored-by: Talley Lambert <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent c2e4560 commit 60f13ca

File tree

5 files changed

+67
-41
lines changed

5 files changed

+67
-41
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ dynamic = ["version"]
3636
dependencies = [
3737
"fonticon-materialdesignicons6",
3838
"napari >=0.4.13",
39-
"pymmcore-plus >=0.6.3",
40-
"pymmcore-widgets >=0.3.0",
39+
"pymmcore-plus >=0.7.1",
40+
"pymmcore-widgets >=0.4.0",
4141
"superqt >=0.3.1",
4242
"tifffile",
4343
"useq-schema >=0.1.0",

src/napari_micromanager/_gui_objects/_mda_widget.py

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
from __future__ import annotations
22

3+
import warnings
4+
from pathlib import Path
35
from typing import TYPE_CHECKING, cast
46

57
from pymmcore_widgets import MDAWidget
68
from qtpy.QtCore import Qt
7-
from qtpy.QtWidgets import QCheckBox, QGridLayout, QSizePolicy, QVBoxLayout, QWidget
9+
from qtpy.QtWidgets import (
10+
QCheckBox,
11+
QGridLayout,
12+
QMessageBox,
13+
QSizePolicy,
14+
QVBoxLayout,
15+
QWidget,
16+
)
817
from useq import MDASequence
918

1019
from napari_micromanager._mda_meta import SEQUENCE_META_KEY, SequenceMeta
1120

1221
from ._save_widget import SaveWidget
1322

1423
if TYPE_CHECKING:
15-
from pathlib import Path
16-
1724
from pymmcore_plus import CMMCorePlus
1825

1926

@@ -25,36 +32,35 @@ def __init__(
2532
) -> None:
2633
super().__init__(include_run_button=True, parent=parent, mmcore=mmcore)
2734

35+
# add save widget
36+
v_layout = cast(QVBoxLayout, self._central_widget.layout())
2837
self._save_groupbox = SaveWidget()
2938
self._save_groupbox.setSizePolicy(
3039
QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed
3140
)
3241
self._save_groupbox.setChecked(False)
33-
34-
v_layout = cast(QVBoxLayout, self.layout())
42+
self._save_groupbox.toggled.connect(self._on_save_toggled)
43+
self._save_groupbox._directory.textChanged.connect(self._on_save_toggled)
44+
self._save_groupbox._fname.textChanged.connect(self._on_save_toggled)
3545
v_layout.insertWidget(0, self._save_groupbox)
3646

37-
self.channel_groupbox.setMinimumHeight(230)
47+
# add split channel checkbox
48+
self.channel_widget.setMinimumHeight(230)
3849
self.checkBox_split_channels = QCheckBox(text="Split Channels")
3950
self.checkBox_split_channels.toggled.connect(self._toggle_split_channel)
40-
g_layout = cast(QGridLayout, self.channel_groupbox.layout())
51+
g_layout = cast(QGridLayout, self.channel_widget.layout())
4152
g_layout.addWidget(self.checkBox_split_channels, 1, 0)
42-
43-
# TODO: stage_pos_groupbox should have a valueChanged signal
44-
# and that should be connected to _toggle_checkbox_save_pos
45-
self._save_groupbox.toggled.connect(self._toggle_checkbox_save_pos)
46-
self.position_groupbox.valueChanged.connect(self._toggle_checkbox_save_pos)
47-
self.channel_groupbox.valueChanged.connect(self._toggle_split_channel)
53+
self.channel_widget.valueChanged.connect(self._toggle_split_channel)
4854

4955
def _toggle_split_channel(self) -> None:
50-
if not self.channel_groupbox.value():
51-
self.checkBox_split_channels.setChecked(False)
52-
53-
def _toggle_checkbox_save_pos(self) -> None:
5456
if (
55-
self.position_groupbox.isChecked()
56-
and len(self.position_groupbox.value()) > 0
57+
not self.channel_widget.value()
58+
or self.channel_widget._table.rowCount() == 1
5759
):
60+
self.checkBox_split_channels.setChecked(False)
61+
62+
def _on_save_toggled(self) -> None:
63+
if self.position_widget.value():
5864
self._save_groupbox._split_pos_checkbox.setEnabled(True)
5965

6066
else:
@@ -89,3 +95,33 @@ def set_state(self, state: dict | MDASequence | str | Path) -> None:
8995

9096
self.checkBox_split_channels.setChecked(meta.split_channels)
9197
self._save_groupbox.set_state(meta)
98+
99+
def _on_run_clicked(self) -> None:
100+
if (
101+
self._save_groupbox.isChecked()
102+
and not self._save_groupbox._directory.text()
103+
):
104+
warnings.warn("Select a directory to save the data.", stacklevel=2)
105+
return
106+
107+
if not Path(self._save_groupbox._directory.text()).exists():
108+
if self._create_new_folder():
109+
Path(self._save_groupbox._directory.text()).mkdir(parents=True)
110+
else:
111+
return
112+
113+
super()._on_run_clicked()
114+
115+
def _create_new_folder(self) -> bool:
116+
"""Create a QMessageBox to ask to create directory if it doesn't exist."""
117+
msgBox = QMessageBox()
118+
msgBox.setWindowTitle("Create Directory")
119+
msgBox.setIcon(QMessageBox.Icon.Question)
120+
msgBox.setText(
121+
f"Directory {self._save_groupbox._directory.text()} "
122+
"does not exist. Create it?"
123+
)
124+
msgBox.setStandardButtons(
125+
QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel
126+
)
127+
return bool(msgBox.exec() == QMessageBox.StandardButton.Ok)

src/napari_micromanager/_gui_objects/_toolbar.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from pymmcore_plus import CMMCorePlus
88
from pymmcore_widgets import (
99
CameraRoiWidget,
10+
ChannelGroupWidget,
1011
ChannelWidget,
1112
ConfigurationWidget,
1213
DefaultCameraExposureWidget,
@@ -212,10 +213,12 @@ def _add_channels(self) -> QToolBar:
212213
ch_toolbar.setMinimumHeight(TOOLBAR_SIZE)
213214

214215
wdg = self._create_groupbox()
216+
wdg.layout().setSpacing(5)
215217
wdg.setStyleSheet(GROUPBOX_STYLE)
216218

217219
ch_lbl = QLabel(text="Channel:")
218220
wdg.layout().addWidget(ch_lbl)
221+
wdg.layout().addWidget(ChannelGroupWidget())
219222
wdg.layout().addWidget(ChannelWidget())
220223

221224
ch_toolbar.addWidget(wdg)
@@ -301,7 +304,7 @@ def _make_tool_button(self, tooltip: str, btn_icon: str) -> QPushButton:
301304
def _add_plugins_toolbar(self) -> QToolBar:
302305
"""Add a QToolBar containing plugins QPushButtons.
303306
304-
e.g. MDA, Explore, ...
307+
e.g. MDA, ...
305308
306309
QPushButtons are connected to the `_show_dock_widget` method.
307310
@@ -318,11 +321,7 @@ def _add_plugins_toolbar(self) -> QToolBar:
318321
wdg.setStyleSheet("border: 0px;")
319322

320323
mda = self._make_plugin_button("MDA", "MultiDimensional Acquisition")
321-
explorer = self._make_plugin_button(
322-
"Explorer", "MultiDimensional Grid Acquisition"
323-
)
324324
wdg.layout().addWidget(mda)
325-
wdg.layout().addWidget(explorer)
326325

327326
plgs_toolbar.addWidget(wdg)
328327

tests/conftest.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
import useq
66
from napari_micromanager._mda_meta import SEQUENCE_META_KEY, SequenceMeta
77
from napari_micromanager.main_window import MainWindow
8-
from pymmcore_plus import CMMCorePlus, _logger
8+
from pymmcore_plus import CMMCorePlus, configure_logging
99

10-
_logger.set_log_level("CRITICAL")
10+
configure_logging(strerr_level="CRITICAL")
1111

1212

1313
# to create a new CMMCorePlus() for every test
@@ -45,13 +45,9 @@ def main_window(core: CMMCorePlus, make_napari_viewer):
4545

4646

4747
@pytest.fixture(params=MDAS, ids=MDA_IDS)
48-
def mda_sequence(request) -> useq.MDASequence:
49-
meta = {
50-
SEQUENCE_META_KEY: SequenceMeta(
51-
mode="mda", file_name="test_mda", should_save=True
52-
)
53-
}
54-
return useq.MDASequence(**request.param, metadata=meta)
48+
def mda_sequence(request: pytest.FixtureRequest) -> useq.MDASequence:
49+
seq_meta = SequenceMeta(mode="mda", file_name="test_mda", should_save=True)
50+
return useq.MDASequence(**request.param, metadata={SEQUENCE_META_KEY: seq_meta})
5551

5652

5753
@pytest.fixture(params=[True, False], ids=["splitC", "no_splitC"])

tests/test_multid_widget.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,7 @@ def test_saving_mda(
7575
expected_shape.pop(mda.used_axes.find("c"))
7676
nfiles = len(list((tmp_path / f"{meta.file_name}_000").iterdir()))
7777
assert nfiles == 2 if multiC else 1
78-
elif splitC:
79-
# FIXME: from tlambert03: just doing this to make the test pass
80-
# but this should be tested more thoroughly
81-
assert [x.name for x in tmp_path.rglob("*.tif")] == [
82-
f"{meta.file_name}_000_DAPI_000.tif"
83-
]
78+
# splitC with one channel is the same as not split
8479
else:
8580
assert [p.name for p in tmp_path.iterdir()] == [f"{meta.file_name}_000.tif"]
8681
assert data_shape == expected_shape

0 commit comments

Comments
 (0)