Merge pull request #4 from nqrduck/category-settings

Category settings
This commit is contained in:
Julia P 2024-03-02 21:01:12 +01:00 committed by GitHub
commit cb5df0a9af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 174 additions and 50 deletions

View file

@ -2,6 +2,7 @@ import logging
from collections import OrderedDict
from PyQt6.QtCore import pyqtSlot, pyqtSignal, QObject
from nqrduck.module.module_model import ModuleModel
from.settings import Setting
logger = logging.getLogger(__name__)
@ -18,35 +19,7 @@ class BaseSpectrometerModel(ModuleModel):
"""
settings : OrderedDict
pulse_parameter_options : OrderedDict
class Setting(QObject):
"""A setting for the spectrometer is a value that is the same for all events in a pulse sequence.
E.g. the number of averages or the number of points in a spectrum.
"""
settings_changed = pyqtSignal()
def __init__(self, name : str, default : str, description : str) -> None:
"""Initializes the setting.
Arguments:
name (str) -- The name of the setting
default (str) -- The default value of the setting
description (str) -- The description of the setting
"""
super().__init__()
self.name = name
self.value = default
self.description = description
@pyqtSlot(str)
def on_value_changed(self, value):
logger.debug("Setting %s changed to %s", self.name, value)
self.value = value
self.settings_changed.emit()
def get_setting(self):
return float(self.value)
class PulseParameter:
"""A pulse parameter is a value that can be different for each event in a pulse sequence.
E.g. the transmit pulse power or the phase of the transmit pulse.
@ -115,18 +88,11 @@ class BaseSpectrometerModel(ModuleModel):
self.settings = OrderedDict()
self.pulse_parameter_options = OrderedDict()
def add_setting(self, name : str, value: str, description : str, category : str) -> None:
"""Adds a setting to the spectrometer.
Arguments:
name (str) -- The name of the setting
value (str) -- The default value of the setting
description (str) -- The description of the setting
category (str) -- The category of the setting
"""
def add_setting(self, setting : Setting, category : str) -> None:
if category not in self.settings.keys():
self.settings[category] = []
self.settings[category].append(self.Setting(name, value, description))
self.settings[category].append(setting)
def get_setting_by_name(self, name : str) -> Setting:
"""Gets a setting by its name.

View file

@ -1,10 +1,11 @@
import logging
from pathlib import Path
from PyQt6.QtWidgets import QWidget, QLabel, QLineEdit, QHBoxLayout, QSizePolicy, QSpacerItem, QVBoxLayout
from PyQt6.QtWidgets import QWidget, QLabel, QLineEdit, QHBoxLayout, QSizePolicy, QSpacerItem, QVBoxLayout, QCheckBox, QComboBox
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import Qt, pyqtSlot
from nqrduck.module.module_view import ModuleView
from nqrduck.assets.icons import Logos
from .settings import FloatSetting, IntSetting, BooleanSetting, SelectionSetting, StringSetting
logger = logging.getLogger(__name__)
@ -46,18 +47,31 @@ class BaseSpectrometerView(ModuleView):
category_layout.addWidget(category_label)
for setting in self.module.model.settings[category]:
logger.debug("Adding setting to settings view: %s", setting.name)
spacer = QSpacerItem(20, 20)
# Create a label for the setting
setting_label = QLabel(setting.name)
setting_label.setMinimumWidth(200)
# Add an QLineEdit for the setting
line_edit = QLineEdit(str(setting.value))
line_edit.setMinimumWidth(100)
# Add a horizontal layout for the setting
layout = QHBoxLayout()
# Connect the editingFinished signal to the on_value_changed slot of the setting
line_edit.editingFinished.connect(lambda x=line_edit, s=setting: s.on_value_changed(x.text()))
# Depending on the setting type we add different widgets to the view
if isinstance(setting, FloatSetting) or isinstance(setting, IntSetting) or isinstance(setting, StringSetting):
edit_widget = QLineEdit(str(setting.value))
edit_widget.setMinimumWidth(100)
# Connect the editingFinished signal to the on_value_changed slot of the setting
edit_widget.editingFinished.connect(lambda x=edit_widget, s=setting: s.on_value_changed(x.text()))
elif isinstance(setting, BooleanSetting):
edit_widget = QCheckBox()
edit_widget.setChecked(setting.value)
edit_widget.stateChanged.connect(lambda x=edit_widget, s=setting: s.on_value_changed(x))
elif isinstance(setting, SelectionSetting):
edit_widget = QComboBox()
edit_widget.addItems(setting.options)
edit_widget.setCurrentText(setting.value)
edit_widget.currentTextChanged.connect(lambda x=edit_widget, s=setting: s.on_value_changed(x))
# Add a icon that can be used as a tooltip
if setting.description is not None:
logger.debug("Adding tooltip to setting: %s", setting.name)
@ -68,11 +82,13 @@ class BaseSpectrometerView(ModuleView):
icon_label.setFixedSize(icon.availableSizes()[0])
icon_label.setToolTip(setting.description)
# Add a horizontal layout for the setting
layout = QHBoxLayout()
# Add the label and the line edit to the layout
layout.addItem(spacer)
layout.addWidget(setting_label)
layout.addWidget(line_edit)
layout.addWidget(edit_widget)
layout.addWidget(icon_label)
layout.addStretch(1)
# Add the layout to the vertical layout of the widget
@ -84,4 +100,5 @@ class BaseSpectrometerView(ModuleView):
# Push all the settings to the top of the widget
self._ui_form.verticalLayout.addStretch(1)

View file

@ -0,0 +1,141 @@
import logging
import ipaddress
from PyQt6.QtCore import QObject, pyqtSignal, pyqtSlot
logger = logging.getLogger(__name__)
class Setting(QObject):
"""A setting for the spectrometer is a value that is the same for all events in a pulse sequence.
E.g. the number of averages or the number of points in a spectrum."""
settings_changed = pyqtSignal()
def __init__(self, name, description) -> None:
super().__init__()
self.name = name
self.description = description
@pyqtSlot(str)
def on_value_changed(self, value):
logger.debug("Setting %s changed to %s", self.name, value)
self.value = value
self.settings_changed.emit()
def get_setting(self):
return float(self.value)
class FloatSetting(Setting):
""" A setting that is a Float. """
def __init__(self, name : str, default : float, description : str) -> None:
super().__init__(name, description)
self.value = default
@property
def value(self):
return self._value
@value.setter
def value(self, value):
try:
self._value = float(value)
except ValueError:
raise ValueError("Value must be a float")
self.settings_changed.emit()
class IntSetting(Setting):
""" A setting that is an Integer."""
def __init__(self, name : str, default : int, description : str) -> None:
super().__init__(name, description)
self.value = default
@property
def value(self):
return self._value
@value.setter
def value(self, value):
try:
self._value = int(value)
except ValueError:
raise ValueError("Value must be an int")
self.settings_changed.emit()
class BooleanSetting(Setting):
""" A setting that is a Boolean."""
def __init__(self, name : str, default : bool, description : str) -> None:
super().__init__(name, description)
self.value = default
@property
def value(self):
return self._value
@value.setter
def value(self, value):
try:
self._value = bool(value)
except ValueError:
raise ValueError("Value must be a bool")
self.settings_changed.emit()
class SelectionSetting(Setting):
""" A setting that is a selection from a list of options."""
def __init__(self, name : str, options : list, default : str, description : str) -> None:
super().__init__(name, description)
# Check if default is in options
if default not in options:
raise ValueError("Default value must be one of the options")
self.options = options
self.value = default
@property
def value(self):
return self._value
@value.setter
def value(self, value):
if value in self.options:
self._value = value
else:
raise ValueError("Value must be one of the options")
self.settings_changed.emit()
class IPSetting(Setting):
""" A setting that is an IP address."""
def __init__(self, name : str, default : str, description : str) -> None:
super().__init__(name, description)
self.value = default
@property
def value(self):
return self._value
@value.setter
def value(self, value):
try:
ipaddress.ip_address(value)
self._value = value
except ValueError:
raise ValueError("Value must be a valid IP address")
self.settings_changed.emit()
class StringSetting(Setting):
""" A setting that is a string."""
def __init__(self, name : str, default : str, description : str) -> None:
super().__init__(name, description)
self.value = default
@property
def value(self):
return self._value
@value.setter
def value(self, value):
try:
self._value = str(value)
except ValueError:
raise ValueError("Value must be a string")
self.settings_changed.emit()