From 780580220f66280acc5aee08ffc216461036c7ea Mon Sep 17 00:00:00 2001 From: Gabriel Selzer Date: Mon, 25 Aug 2025 11:34:25 -0500 Subject: [PATCH 1/2] Fix: Pass mmcore in config_group widgets --- src/pymmcore_widgets/_icons.py | 7 +++++-- .../_models/_config_group_pivot_model.py | 8 ++++++-- .../_views/_config_groups_tree.py | 8 +++++--- .../_views/_config_presets_table.py | 17 +++++++++++------ .../_views/_property_setting_delegate.py | 12 ++++++++++++ 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/pymmcore_widgets/_icons.py b/src/pymmcore_widgets/_icons.py index 49c4a62aa..06062899b 100644 --- a/src/pymmcore_widgets/_icons.py +++ b/src/pymmcore_widgets/_icons.py @@ -53,15 +53,18 @@ def __str__(self) -> str: return self.value @classmethod - def for_device_type(cls, device_type: DeviceType | str) -> StandardIcon: + def for_device_type( + cls, device_type: DeviceType | str, mmcore: CMMCorePlus | None = None + ) -> StandardIcon: """Return an icon for a specific device type. If a string is provided, it will be resolved to a DeviceType using the CMMCorePlus.instance. """ if isinstance(device_type, str): # device label + core = mmcore or CMMCorePlus.instance() try: - device_type = CMMCorePlus.instance().getDeviceType(device_type) + device_type = core.getDeviceType(device_type) except Exception: # pragma: no cover device_type = DeviceType.Unknown diff --git a/src/pymmcore_widgets/_models/_config_group_pivot_model.py b/src/pymmcore_widgets/_models/_config_group_pivot_model.py index a1277f24a..20711794b 100644 --- a/src/pymmcore_widgets/_models/_config_group_pivot_model.py +++ b/src/pymmcore_widgets/_models/_config_group_pivot_model.py @@ -10,14 +10,18 @@ from ._q_config_model import QConfigGroupsModel if TYPE_CHECKING: + from pymmcore_plus import CMMCorePlus from qtpy.QtWidgets import QWidget class ConfigGroupPivotModel(QAbstractTableModel): """Pivot a single ConfigGroup into rows=Device/Property, cols=Presets.""" - def __init__(self, parent: QWidget | None = None) -> None: + def __init__( + self, parent: QWidget | None = None, mmcore: CMMCorePlus | None = None + ) -> None: super().__init__(parent) + self._mmcore = mmcore self._src: QConfigGroupsModel | None = None self._gidx: QModelIndex | None = None self._presets: list[ConfigPreset] = [] @@ -155,7 +159,7 @@ def headerData( dev, _prop = self._rows[section] except IndexError: # pragma: no cover return None - if icon := StandardIcon.for_device_type(dev): + if icon := StandardIcon.for_device_type(dev, self._mmcore): return icon.icon().pixmap(QSize(16, 16)) return None diff --git a/src/pymmcore_widgets/config_presets/_views/_config_groups_tree.py b/src/pymmcore_widgets/config_presets/_views/_config_groups_tree.py index bf86c15d7..6388c0d9a 100644 --- a/src/pymmcore_widgets/config_presets/_views/_config_groups_tree.py +++ b/src/pymmcore_widgets/config_presets/_views/_config_groups_tree.py @@ -21,14 +21,16 @@ def create_from_core( cls, core: CMMCorePlus, parent: QWidget | None = None ) -> ConfigGroupsTree: """Create a ConfigGroupsTree from a CMMCorePlus instance.""" - obj = cls(parent) + obj = cls(parent, core) model = QConfigGroupsModel.create_from_core(core) obj.setModel(model) return obj - def __init__(self, parent: QWidget | None = None) -> None: + def __init__( + self, parent: QWidget | None = None, core: CMMCorePlus | None = None + ) -> None: super().__init__(parent) - self.setItemDelegateForColumn(2, PropertySettingDelegate(self)) + self.setItemDelegateForColumn(2, PropertySettingDelegate(self, mmcore=core)) def setModel(self, model: QAbstractItemModel | None) -> None: """Set the model for the tree view.""" diff --git a/src/pymmcore_widgets/config_presets/_views/_config_presets_table.py b/src/pymmcore_widgets/config_presets/_views/_config_presets_table.py index e77a0f806..44090ab85 100644 --- a/src/pymmcore_widgets/config_presets/_views/_config_presets_table.py +++ b/src/pymmcore_widgets/config_presets/_views/_config_presets_table.py @@ -36,16 +36,19 @@ class ConfigPresetsTableView(QTableView): `setGroup` with the name or index of the group you want to view. """ - def __init__(self, parent: QWidget | None = None) -> None: + def __init__( + self, parent: QWidget | None = None, mmcore: CMMCorePlus | None = None + ) -> None: super().__init__(parent) - self.setItemDelegate(PropertySettingDelegate(self)) + self._mmcore = mmcore + self.setItemDelegate(PropertySettingDelegate(self, mmcore=mmcore)) self._transpose_proxy: QTransposeProxyModel | None = None self._pivot_model: ConfigGroupPivotModel | None = None def setModel(self, model: QAbstractItemModel | None) -> None: """Set the model for the table view.""" if isinstance(model, QConfigGroupsModel): - matrix = ConfigGroupPivotModel() + matrix = ConfigGroupPivotModel(mmcore=self._mmcore) matrix.setSourceModel(model) elif isinstance(model, ConfigGroupPivotModel): # pragma: no cover matrix = model @@ -151,14 +154,16 @@ def create_from_core( cls, core: CMMCorePlus, parent: QWidget | None = None ) -> ConfigPresetsTable: """Create a PresetsTable from a CMMCorePlus instance.""" - obj = cls(parent) + obj = cls(parent, core) model = QConfigGroupsModel.create_from_core(core) obj.setModel(model) return obj - def __init__(self, parent: QWidget | None = None) -> None: + def __init__( + self, parent: QWidget | None = None, mmcore: CMMCorePlus | None = None + ) -> None: super().__init__(parent) - self.view = ConfigPresetsTableView(self) + self.view = ConfigPresetsTableView(self, mmcore=mmcore) self._toolbar = tb = QToolBar(self) tb.setIconSize(QSize(16, 16)) diff --git a/src/pymmcore_widgets/config_presets/_views/_property_setting_delegate.py b/src/pymmcore_widgets/config_presets/_views/_property_setting_delegate.py index 30cbe47cf..23d32a5c7 100644 --- a/src/pymmcore_widgets/config_presets/_views/_property_setting_delegate.py +++ b/src/pymmcore_widgets/config_presets/_views/_property_setting_delegate.py @@ -1,15 +1,26 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from qtpy.QtCore import QAbstractItemModel, QModelIndex, Qt from qtpy.QtWidgets import QStyledItemDelegate, QStyleOptionViewItem, QWidget from pymmcore_widgets._models import DevicePropertySetting from pymmcore_widgets.device_properties import PropertyWidget +if TYPE_CHECKING: + from pymmcore_plus import CMMCorePlus + class PropertySettingDelegate(QStyledItemDelegate): """Item delegate that uses a PropertyWidget for editing PropertySetting values.""" + def __init__( + self, parent: QWidget | None = None, mmcore: CMMCorePlus | None = None + ) -> None: + super().__init__(parent) + self._mmcore = mmcore + def createEditor( self, parent: QWidget | None, option: QStyleOptionViewItem, index: QModelIndex ) -> QWidget | None: @@ -21,6 +32,7 @@ def createEditor( setting.device_label, setting.property_name, parent=parent, + mmcore=self._mmcore, connect_core=False, ) widget.setValue(setting.value) # avoids commitData warnings From dc7720839542294a701d861e819dac469992aca3 Mon Sep 17 00:00:00 2001 From: Gabriel Selzer Date: Mon, 25 Aug 2025 11:40:04 -0500 Subject: [PATCH 2/2] Provide default value for mmcore=None --- src/pymmcore_widgets/_models/_config_group_pivot_model.py | 4 ++-- .../config_presets/_views/_config_presets_table.py | 4 ++-- .../config_presets/_views/_property_setting_delegate.py | 8 ++------ 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/pymmcore_widgets/_models/_config_group_pivot_model.py b/src/pymmcore_widgets/_models/_config_group_pivot_model.py index 20711794b..d6c5e7146 100644 --- a/src/pymmcore_widgets/_models/_config_group_pivot_model.py +++ b/src/pymmcore_widgets/_models/_config_group_pivot_model.py @@ -2,6 +2,7 @@ from typing import TYPE_CHECKING, Any +from pymmcore_plus import CMMCorePlus from qtpy.QtCore import QAbstractTableModel, QModelIndex, QSize, Qt from pymmcore_widgets._icons import StandardIcon @@ -10,7 +11,6 @@ from ._q_config_model import QConfigGroupsModel if TYPE_CHECKING: - from pymmcore_plus import CMMCorePlus from qtpy.QtWidgets import QWidget @@ -21,7 +21,7 @@ def __init__( self, parent: QWidget | None = None, mmcore: CMMCorePlus | None = None ) -> None: super().__init__(parent) - self._mmcore = mmcore + self._mmcore = mmcore or CMMCorePlus.instance() self._src: QConfigGroupsModel | None = None self._gidx: QModelIndex | None = None self._presets: list[ConfigPreset] = [] diff --git a/src/pymmcore_widgets/config_presets/_views/_config_presets_table.py b/src/pymmcore_widgets/config_presets/_views/_config_presets_table.py index 44090ab85..c54d04504 100644 --- a/src/pymmcore_widgets/config_presets/_views/_config_presets_table.py +++ b/src/pymmcore_widgets/config_presets/_views/_config_presets_table.py @@ -3,6 +3,7 @@ from contextlib import suppress from typing import TYPE_CHECKING +from pymmcore_plus import CMMCorePlus from qtpy.QtCore import ( QAbstractItemModel, QModelIndex, @@ -19,7 +20,6 @@ from ._property_setting_delegate import PropertySettingDelegate if TYPE_CHECKING: - from pymmcore_plus import CMMCorePlus from PyQt6.QtGui import QAction else: @@ -40,7 +40,7 @@ def __init__( self, parent: QWidget | None = None, mmcore: CMMCorePlus | None = None ) -> None: super().__init__(parent) - self._mmcore = mmcore + self._mmcore = mmcore or CMMCorePlus.instance() self.setItemDelegate(PropertySettingDelegate(self, mmcore=mmcore)) self._transpose_proxy: QTransposeProxyModel | None = None self._pivot_model: ConfigGroupPivotModel | None = None diff --git a/src/pymmcore_widgets/config_presets/_views/_property_setting_delegate.py b/src/pymmcore_widgets/config_presets/_views/_property_setting_delegate.py index 23d32a5c7..8c61dff5b 100644 --- a/src/pymmcore_widgets/config_presets/_views/_property_setting_delegate.py +++ b/src/pymmcore_widgets/config_presets/_views/_property_setting_delegate.py @@ -1,16 +1,12 @@ from __future__ import annotations -from typing import TYPE_CHECKING - +from pymmcore_plus import CMMCorePlus from qtpy.QtCore import QAbstractItemModel, QModelIndex, Qt from qtpy.QtWidgets import QStyledItemDelegate, QStyleOptionViewItem, QWidget from pymmcore_widgets._models import DevicePropertySetting from pymmcore_widgets.device_properties import PropertyWidget -if TYPE_CHECKING: - from pymmcore_plus import CMMCorePlus - class PropertySettingDelegate(QStyledItemDelegate): """Item delegate that uses a PropertyWidget for editing PropertySetting values.""" @@ -19,7 +15,7 @@ def __init__( self, parent: QWidget | None = None, mmcore: CMMCorePlus | None = None ) -> None: super().__init__(parent) - self._mmcore = mmcore + self._mmcore = mmcore or CMMCorePlus.instance() def createEditor( self, parent: QWidget | None, option: QStyleOptionViewItem, index: QModelIndex