Skip to content

Commit a256f09

Browse files
committed
always show checked rows
1 parent 20464c9 commit a256f09

File tree

3 files changed

+27
-25
lines changed

3 files changed

+27
-25
lines changed

src/pymmcore_widgets/config_presets/_config_groups_editor.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
QLabel,
1515
QSpacerItem,
1616
QSplitter,
17+
QTableWidgetItem,
1718
QVBoxLayout,
1819
QWidget,
1920
)
@@ -239,11 +240,11 @@ def _update_model_from_gui(self) -> None:
239240
preset.settings = list(self.currentSettings())
240241

241242

242-
def _is_not_objective(prop: DeviceProperty) -> bool:
243+
def _is_not_objective(item: QTableWidgetItem, prop: DeviceProperty) -> bool:
243244
return not any(x in prop.device for x in prop.core.guessObjectiveDevices())
244245

245246

246-
def _light_path_predicate(prop: DeviceProperty) -> bool | None:
247+
def _light_path_predicate(item: QTableWidgetItem, prop: DeviceProperty) -> bool | None:
247248
devtype = prop.deviceType()
248249
if devtype in (
249250
DeviceType.Camera,
@@ -258,7 +259,7 @@ def _light_path_predicate(prop: DeviceProperty) -> bool | None:
258259
return False
259260
if devtype == DeviceType.Shutter and prop.name == Keyword.State.value:
260261
return False
261-
if not _is_not_objective(prop):
262+
if not _is_not_objective(item, prop):
262263
return False
263264
return None
264265

@@ -299,12 +300,25 @@ def __init__(self, parent: QWidget | None = None) -> None:
299300
layout.addLayout(shutter_layout)
300301
layout.addWidget(self.props)
301302

302-
def _show_all_toggled(self, checked: bool) -> None:
303+
def _show_all_toggled(self, show_all: bool) -> None:
304+
def predicate_with_checked_override(
305+
item: QTableWidgetItem, prop: DeviceProperty
306+
) -> bool | None:
307+
"""Predicate that shows checked properties regardless of heuristic."""
308+
# Always show checked rows
309+
if item.checkState() == Qt.CheckState.Checked:
310+
return True
311+
# For unchecked properties, apply the original heuristic
312+
if not show_all:
313+
return _light_path_predicate(item, prop)
314+
else:
315+
return _is_not_objective(item, prop)
316+
303317
self.props.filterDevices(
304318
exclude_devices=(DeviceType.Camera, DeviceType.Core),
305319
include_read_only=False,
306320
include_pre_init=False,
307-
predicate=_light_path_predicate if not checked else _is_not_objective,
321+
predicate=predicate_with_checked_override,
308322
)
309323

310324
def settings(self) -> Iterable[tuple[str, str, str]]:

src/pymmcore_widgets/device_properties/_device_property_table.py

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -206,28 +206,21 @@ def filterDevices(
206206
include_read_only: bool = True,
207207
include_pre_init: bool = True,
208208
init_props_only: bool = False,
209-
predicate: Callable[[DeviceProperty], bool | None] | None = None,
209+
predicate: (
210+
Callable[[QTableWidgetItem, DeviceProperty], bool | None] | None
211+
) = None,
210212
) -> None:
211213
"""Update the table to only show devices that match the given query/filter."""
212214
exclude_devices = set(exclude_devices)
213215
include_devices = set(include_devices)
214216
for row in range(self.rowCount()):
215-
item = self.item(row, 0)
216-
prop = cast("DeviceProperty", item.data(self.PROP_ROLE))
217-
if include_devices and prop.deviceType() not in include_devices:
218-
self.hideRow(row)
217+
if (item := self.item(row, 0)) is None:
219218
continue
220-
if predicate:
221-
result = predicate(prop)
222-
if result is False:
223-
self.hideRow(row)
224-
continue
225-
# if result is True:
226-
# self.showRow(row)
227-
# continue
228-
# for None: fall through to other filters
219+
prop = cast("DeviceProperty", item.data(self.PROP_ROLE))
229220
if (
230-
(prop.isReadOnly() and not include_read_only)
221+
(include_devices and prop.deviceType() not in include_devices)
222+
or (predicate and predicate(item, prop) is False)
223+
or (prop.isReadOnly() and not include_read_only)
231224
or (prop.isPreInit() and not include_pre_init)
232225
or (init_props_only and not prop.isPreInit())
233226
or (prop.deviceType() in exclude_devices)

tests/test_config_groups_editor.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ def test_checked_properties_remain_visible(
3939

4040
# First, enable "show all properties" to see all available properties
4141
show_all_checkbox.setChecked(True)
42-
qtbot.wait(10) # Allow UI to update
4342

4443
# Find a property that would normally be hidden by the heuristic
4544
# Look for properties visible now but hidden when show_all is False
@@ -52,15 +51,13 @@ def test_checked_properties_remain_visible(
5251

5352
# Temporarily disable show_all to see which rows get hidden
5453
show_all_checkbox.setChecked(False)
55-
qtbot.wait(10)
5654

5755
for row in visible_rows_all:
5856
if props_table.isRowHidden(row):
5957
hidden_by_heuristic_rows.append(row)
6058

6159
# Re-enable show_all
6260
show_all_checkbox.setChecked(True)
63-
qtbot.wait(10)
6461

6562
# Skip test if no properties are hidden by heuristic
6663
if not hidden_by_heuristic_rows:
@@ -74,14 +71,12 @@ def test_checked_properties_remain_visible(
7471
assert item is not None, f"No item found at row {test_row}"
7572

7673
item.setCheckState(Qt.CheckState.Checked)
77-
qtbot.wait(10)
7874

7975
# Verify the property is checked
8076
assert item.checkState() == Qt.CheckState.Checked
8177

8278
# Now disable "show all properties" - this should trigger the filtering
8379
show_all_checkbox.setChecked(False)
84-
qtbot.wait(10)
8580

8681
# The checked property should still be visible despite the heuristic
8782
assert not props_table.isRowHidden(test_row), (

0 commit comments

Comments
 (0)