mirror of
https://github.com/nqrduck/nqrduck-pulseprogrammer.git
synced 2024-11-09 11:20:01 +00:00
Merge branch 'formbuilder-and-function-optimization'
This commit is contained in:
commit
668681cdf3
5 changed files with 104 additions and 35 deletions
|
@ -0,0 +1 @@
|
||||||
|
"""Empty file to make this directory a package."""
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""Controller of the pulse programmer module."""
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
import decimal
|
import decimal
|
||||||
|
@ -8,8 +9,12 @@ from nqrduck_spectrometer.pulsesequence import PulseSequence
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class PulseProgrammerController(ModuleController):
|
|
||||||
|
|
||||||
|
class PulseProgrammerController(ModuleController):
|
||||||
|
"""Controller of the pulse programmer module.
|
||||||
|
|
||||||
|
This class is responsible for handling the logic of the pulse programmer module.
|
||||||
|
"""
|
||||||
def on_loading(self, pulse_parameter_options: dict) -> None:
|
def on_loading(self, pulse_parameter_options: dict) -> None:
|
||||||
"""This method is called when the module is loaded. It sets the pulse parameter options in the model.
|
"""This method is called when the module is loaded. It sets the pulse parameter options in the model.
|
||||||
|
|
||||||
|
@ -65,7 +70,9 @@ class PulseProgrammerController(ModuleController):
|
||||||
except decimal.InvalidOperation:
|
except decimal.InvalidOperation:
|
||||||
logger.error("Duration must be a positive number")
|
logger.error("Duration must be a positive number")
|
||||||
# Emit signal to the nqrduck core to show an error message
|
# Emit signal to the nqrduck core to show an error message
|
||||||
self.module.nqrduck_signal.emit("notification", ["Error", "Duration must be a positive number"])
|
self.module.nqrduck_signal.emit(
|
||||||
|
"notification", ["Error", "Duration must be a positive number"]
|
||||||
|
)
|
||||||
break
|
break
|
||||||
self.module.model.events_changed.emit()
|
self.module.model.events_changed.emit()
|
||||||
|
|
||||||
|
@ -80,11 +87,16 @@ class PulseProgrammerController(ModuleController):
|
||||||
for i, event in enumerate(self.module.model.pulse_sequence.events):
|
for i, event in enumerate(self.module.model.pulse_sequence.events):
|
||||||
if event.name == event_name:
|
if event.name == event_name:
|
||||||
if i > 0:
|
if i > 0:
|
||||||
self.module.model.pulse_sequence.events[i], self.module.model.pulse_sequence.events[i-1] = self.module.model.pulse_sequence.events[i-1], self.module.model.pulse_sequence.events[i]
|
(
|
||||||
|
self.module.model.pulse_sequence.events[i],
|
||||||
|
self.module.model.pulse_sequence.events[i - 1],
|
||||||
|
) = (
|
||||||
|
self.module.model.pulse_sequence.events[i - 1],
|
||||||
|
self.module.model.pulse_sequence.events[i],
|
||||||
|
)
|
||||||
break
|
break
|
||||||
self.module.model.events_changed.emit()
|
self.module.model.events_changed.emit()
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def on_move_event_right(self, event_name: str) -> None:
|
def on_move_event_right(self, event_name: str) -> None:
|
||||||
"""This method moves the event one position to the right if possible.
|
"""This method moves the event one position to the right if possible.
|
||||||
|
@ -96,7 +108,13 @@ class PulseProgrammerController(ModuleController):
|
||||||
for i, event in enumerate(self.module.model.pulse_sequence.events):
|
for i, event in enumerate(self.module.model.pulse_sequence.events):
|
||||||
if event.name == event_name:
|
if event.name == event_name:
|
||||||
if i < len(self.module.model.pulse_sequence.events) - 1:
|
if i < len(self.module.model.pulse_sequence.events) - 1:
|
||||||
self.module.model.pulse_sequence.events[i], self.module.model.pulse_sequence.events[i+1] = self.module.model.pulse_sequence.events[i+1], self.module.model.pulse_sequence.events[i]
|
(
|
||||||
|
self.module.model.pulse_sequence.events[i],
|
||||||
|
self.module.model.pulse_sequence.events[i + 1],
|
||||||
|
) = (
|
||||||
|
self.module.model.pulse_sequence.events[i + 1],
|
||||||
|
self.module.model.pulse_sequence.events[i],
|
||||||
|
)
|
||||||
break
|
break
|
||||||
self.module.model.events_changed.emit()
|
self.module.model.events_changed.emit()
|
||||||
|
|
||||||
|
@ -117,7 +135,6 @@ class PulseProgrammerController(ModuleController):
|
||||||
with open(path, "w") as file:
|
with open(path, "w") as file:
|
||||||
file.write(json.dumps(sequence, cls=DecimalEncoder))
|
file.write(json.dumps(sequence, cls=DecimalEncoder))
|
||||||
|
|
||||||
|
|
||||||
def load_pulse_sequence(self, path: str) -> None:
|
def load_pulse_sequence(self, path: str) -> None:
|
||||||
"""This method loads a pulse sequence from a file.
|
"""This method loads a pulse sequence from a file.
|
||||||
|
|
||||||
|
@ -131,7 +148,9 @@ class PulseProgrammerController(ModuleController):
|
||||||
|
|
||||||
sequence = json.loads(sequence)
|
sequence = json.loads(sequence)
|
||||||
|
|
||||||
loaded_sequence = PulseSequence.load_sequence(sequence, self.module.model.pulse_parameter_options)
|
loaded_sequence = PulseSequence.load_sequence(
|
||||||
|
sequence, self.module.model.pulse_parameter_options
|
||||||
|
)
|
||||||
|
|
||||||
self.module.model.pulse_sequence = loaded_sequence
|
self.module.model.pulse_sequence = loaded_sequence
|
||||||
self.module.model.events_changed.emit()
|
self.module.model.events_changed.emit()
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""Model for the pulse programmer module."""
|
||||||
import logging
|
import logging
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from PyQt6.QtCore import pyqtSignal
|
from PyQt6.QtCore import pyqtSignal
|
||||||
|
@ -8,11 +9,25 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class PulseProgrammerModel(ModuleModel):
|
class PulseProgrammerModel(ModuleModel):
|
||||||
|
"""Model for the pulse programmer module.
|
||||||
|
|
||||||
|
This class is responsible for storing the data of the pulse programmer module.
|
||||||
|
|
||||||
|
Signals:
|
||||||
|
pulse_parameter_options_changed: Emitted when the pulse parameter options change.
|
||||||
|
events_changed: Emitted when the events in the pulse sequence change.
|
||||||
|
pulse_sequence_changed: Emitted when the pulse sequence changes.
|
||||||
|
"""
|
||||||
pulse_parameter_options_changed = pyqtSignal()
|
pulse_parameter_options_changed = pyqtSignal()
|
||||||
events_changed = pyqtSignal()
|
events_changed = pyqtSignal()
|
||||||
pulse_sequence_changed = pyqtSignal()
|
pulse_sequence_changed = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, module):
|
def __init__(self, module):
|
||||||
|
"""Initializes the pulse programmer model.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
module (Module): The module to which this model belongs.
|
||||||
|
"""
|
||||||
super().__init__(module)
|
super().__init__(module)
|
||||||
self.pulse_parameter_options = OrderedDict()
|
self.pulse_parameter_options = OrderedDict()
|
||||||
self.pulse_sequence = PulseSequence("Untitled pulse sequence")
|
self.pulse_sequence = PulseSequence("Untitled pulse sequence")
|
||||||
|
@ -25,7 +40,7 @@ class PulseProgrammerModel(ModuleModel):
|
||||||
duration (float): The duration of the event in µs. Defaults to 20.
|
duration (float): The duration of the event in µs. Defaults to 20.
|
||||||
"""
|
"""
|
||||||
self.pulse_sequence.events.append(
|
self.pulse_sequence.events.append(
|
||||||
PulseSequence.Event(event_name, "%.16gu" % float(duration))
|
PulseSequence.Event(event_name, f"{float(duration):.16g}u")
|
||||||
)
|
)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Creating event %s with object id %s",
|
"Creating event %s with object id %s",
|
||||||
|
@ -50,6 +65,7 @@ class PulseProgrammerModel(ModuleModel):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pulse_parameter_options(self):
|
def pulse_parameter_options(self):
|
||||||
|
"""dict: The pulse parameter options."""
|
||||||
return self._pulse_parameter_options
|
return self._pulse_parameter_options
|
||||||
|
|
||||||
@pulse_parameter_options.setter
|
@pulse_parameter_options.setter
|
||||||
|
@ -60,6 +76,7 @@ class PulseProgrammerModel(ModuleModel):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pulse_sequence(self):
|
def pulse_sequence(self):
|
||||||
|
"""PulseSequence: The pulse sequence."""
|
||||||
return self._pulse_sequence
|
return self._pulse_sequence
|
||||||
|
|
||||||
@pulse_sequence.setter
|
@pulse_sequence.setter
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
|
"""Initialize the PulseProgrammer module."""
|
||||||
from nqrduck.module.module import Module
|
from nqrduck.module.module import Module
|
||||||
from .model import PulseProgrammerModel
|
from .model import PulseProgrammerModel
|
||||||
from .controller import PulseProgrammerController
|
from .controller import PulseProgrammerController
|
||||||
from .view import PulseProgrammerView
|
from .view import PulseProgrammerView
|
||||||
|
|
||||||
class PulseProgrammer(Module):
|
class PulseProgrammer(Module):
|
||||||
|
"""The pulse programmer module."""
|
||||||
def __init__(self, model, view, controller):
|
def __init__(self, model, view, controller):
|
||||||
|
"""Initializes the pulse programmer module.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
model (PulseProgrammerModel): The model of the pulse programmer module.
|
||||||
|
view (PulseProgrammerView): The view of the pulse programmer module.
|
||||||
|
controller (PulseProgrammerController): The controller of the pulse programmer module.
|
||||||
|
"""
|
||||||
super().__init__(model, None, controller)
|
super().__init__(model, None, controller)
|
||||||
self.view = None
|
self.view = None
|
||||||
self.pulse_programmer_view = view(self)
|
self.pulse_programmer_view = view(self)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""This module contains the view for the pulse programmer module. It is responsible for displaying the pulse sequence and the pulse parameter options."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import functools
|
import functools
|
||||||
from PyQt6.QtGui import QValidator
|
from PyQt6.QtGui import QValidator
|
||||||
|
@ -29,17 +31,21 @@ from nqrduck.helpers.formbuilder import (
|
||||||
DuckFormBuilder,
|
DuckFormBuilder,
|
||||||
DuckFormFunctionSelectionField,
|
DuckFormFunctionSelectionField,
|
||||||
DuckFormCheckboxField,
|
DuckFormCheckboxField,
|
||||||
DuckFormDropdownField,
|
|
||||||
DuckFormFloatField,
|
DuckFormFloatField,
|
||||||
DuckFormIntField,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class PulseProgrammerView(ModuleView):
|
class PulseProgrammerView(ModuleView):
|
||||||
|
"""View for the pulse programmer module."""
|
||||||
|
|
||||||
def __init__(self, module):
|
def __init__(self, module):
|
||||||
|
"""Initializes the pulse programmer view.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
module (Module): The module to which this view belongs.
|
||||||
|
"""
|
||||||
super().__init__(module)
|
super().__init__(module)
|
||||||
|
|
||||||
self.setup_pulsetable()
|
self.setup_pulsetable()
|
||||||
|
@ -58,11 +64,9 @@ class PulseProgrammerView(ModuleView):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def setup_pulsetable(self) -> None:
|
def setup_pulsetable(self) -> None:
|
||||||
"""Setup the table for the pulse sequence. Also add buttons for saving and loading pulse sequences and editing and creation of events"""
|
"""Setup the table for the pulse sequence. Also add buttons for saving and loading pulse sequences and editing and creation of events."""
|
||||||
# Create pulse table
|
# Create pulse table
|
||||||
self.title = QLabel(
|
self.title = QLabel(f"Pulse Sequence: {self.module.model.pulse_sequence.name}")
|
||||||
"Pulse Sequence: %s" % self.module.model.pulse_sequence.name
|
|
||||||
)
|
|
||||||
# Make title bold
|
# Make title bold
|
||||||
font = self.title.font()
|
font = self.title.font()
|
||||||
font.setBold(True)
|
font.setBold(True)
|
||||||
|
@ -133,7 +137,7 @@ class PulseProgrammerView(ModuleView):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Updating pulse sequence to %s", self.module.model.pulse_sequence.name
|
"Updating pulse sequence to %s", self.module.model.pulse_sequence.name
|
||||||
)
|
)
|
||||||
self.title.setText("Pulse Sequence: %s" % self.module.model.pulse_sequence.name)
|
self.title.setText(f"Pulse Sequence: {self.module.model.pulse_sequence.name}")
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def on_pulse_parameter_options_changed(self) -> None:
|
def on_pulse_parameter_options_changed(self) -> None:
|
||||||
|
@ -177,9 +181,7 @@ class PulseProgrammerView(ModuleView):
|
||||||
for event in self.module.model.pulse_sequence.events:
|
for event in self.module.model.pulse_sequence.events:
|
||||||
logger.debug("Adding event to pulseprogrammer view: %s", event.name)
|
logger.debug("Adding event to pulseprogrammer view: %s", event.name)
|
||||||
# Create a label for the event
|
# Create a label for the event
|
||||||
event_label = QLabel(
|
event_label = QLabel(f"{event.name} : {event.duration * 1e6:.16g} µs")
|
||||||
"%s : %.16g µs" % (event.name, (event.duration * 1e6))
|
|
||||||
)
|
|
||||||
event_layout.addWidget(event_label)
|
event_layout.addWidget(event_label)
|
||||||
|
|
||||||
# Delete the old widget and create a new one
|
# Delete the old widget and create a new one
|
||||||
|
@ -260,7 +262,14 @@ class PulseProgrammerView(ModuleView):
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def on_table_button_clicked(self, event, parameter) -> None:
|
def on_table_button_clicked(self, event, parameter) -> None:
|
||||||
"""This method is called whenever a button in the pulse table is clicked. It opens a dialog to set the options for the parameter."""
|
"""This method is called whenever a button in the pulse table is clicked.
|
||||||
|
|
||||||
|
It opens a dialog to set the options for the parameter.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
event (PulseSequence.Event): The event for which the parameter options should be set.
|
||||||
|
parameter (str): The name of the parameter for which the options should be set.
|
||||||
|
"""
|
||||||
logger.debug("Button for event %s and parameter %s clicked", event, parameter)
|
logger.debug("Button for event %s and parameter %s clicked", event, parameter)
|
||||||
# Create a QDialog to set the options for the parameter.
|
# Create a QDialog to set the options for the parameter.
|
||||||
description = f"Set options for {parameter}"
|
description = f"Set options for {parameter}"
|
||||||
|
@ -346,9 +355,17 @@ class PulseProgrammerView(ModuleView):
|
||||||
|
|
||||||
class EventOptionsWidget(QWidget):
|
class EventOptionsWidget(QWidget):
|
||||||
"""This class is a widget that can be used to set the options for a pulse parameter.
|
"""This class is a widget that can be used to set the options for a pulse parameter.
|
||||||
|
|
||||||
This widget is then added to the the first row of the according event column in the pulse table.
|
This widget is then added to the the first row of the according event column in the pulse table.
|
||||||
It has a edit button that opens a dialog that allows the user to change the options for the event (name and duration).
|
It has a edit button that opens a dialog that allows the user to change the options for the event (name and duration).
|
||||||
Furthermore it has a delete button that deletes the event from the pulse sequence.
|
Furthermore it has a delete button that deletes the event from the pulse sequence.
|
||||||
|
|
||||||
|
Signals:
|
||||||
|
delete_event: Emitted when the delete button is clicked.
|
||||||
|
change_event_duration: Emitted when the duration of the event is changed.
|
||||||
|
change_event_name: Emitted when the name of the event is changed.
|
||||||
|
move_event_left: Emitted when the move left button is clicked.
|
||||||
|
move_event_right: Emitted when the move right button is clicked.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
delete_event = pyqtSignal(str)
|
delete_event = pyqtSignal(str)
|
||||||
|
@ -358,6 +375,7 @@ class EventOptionsWidget(QWidget):
|
||||||
move_event_right = pyqtSignal(str)
|
move_event_right = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, event):
|
def __init__(self, event):
|
||||||
|
"""Initializes the EventOptionsWidget."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.event = event
|
self.event = event
|
||||||
|
|
||||||
|
@ -411,6 +429,7 @@ class EventOptionsWidget(QWidget):
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def edit_event(self) -> None:
|
def edit_event(self) -> None:
|
||||||
"""This method is called when the edit button is clicked. It opens a dialog that allows the user to change the event name and duration.
|
"""This method is called when the edit button is clicked. It opens a dialog that allows the user to change the event name and duration.
|
||||||
|
|
||||||
If the user clicks ok, the change_event_name and change_event_duration signals are emitted.
|
If the user clicks ok, the change_event_name and change_event_duration signals are emitted.
|
||||||
"""
|
"""
|
||||||
logger.debug("Edit button clicked for event %s", self.event.name)
|
logger.debug("Edit button clicked for event %s", self.event.name)
|
||||||
|
@ -419,7 +438,7 @@ class EventOptionsWidget(QWidget):
|
||||||
dialog = QDialog(self)
|
dialog = QDialog(self)
|
||||||
dialog.setWindowTitle("Edit event")
|
dialog.setWindowTitle("Edit event")
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
label = QLabel("Edit event %s" % self.event.name)
|
label = QLabel(f"Edit event {self.event.name}")
|
||||||
layout.addWidget(label)
|
layout.addWidget(label)
|
||||||
|
|
||||||
# Create the inputs for event name, duration
|
# Create the inputs for event name, duration
|
||||||
|
@ -457,7 +476,9 @@ class EventOptionsWidget(QWidget):
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def create_delete_event_dialog(self) -> None:
|
def create_delete_event_dialog(self) -> None:
|
||||||
"""This method is called when the delete button is clicked. It creates a dialog that asks the user if he is sure he wants to delete the event.
|
"""This method is called when the delete button is clicked.
|
||||||
|
|
||||||
|
It creates a dialog that asks the user if he is sure he wants to delete the event.
|
||||||
If the user clicks yes, the delete_event signal is emitted.
|
If the user clicks yes, the delete_event signal is emitted.
|
||||||
"""
|
"""
|
||||||
# Create an 'are you sure' dialog
|
# Create an 'are you sure' dialog
|
||||||
|
@ -465,7 +486,7 @@ class EventOptionsWidget(QWidget):
|
||||||
dialog = QDialog(self)
|
dialog = QDialog(self)
|
||||||
dialog.setWindowTitle("Delete event")
|
dialog.setWindowTitle("Delete event")
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
label = QLabel("Are you sure you want to delete event %s?" % self.event.name)
|
label = QLabel(f"Are you sure you want to delete event {self.event.name}?")
|
||||||
layout.addWidget(label)
|
layout.addWidget(label)
|
||||||
buttons = QDialogButtonBox(
|
buttons = QDialogButtonBox(
|
||||||
QDialogButtonBox.StandardButton.Yes | QDialogButtonBox.StandardButton.No
|
QDialogButtonBox.StandardButton.Yes | QDialogButtonBox.StandardButton.No
|
||||||
|
@ -494,6 +515,7 @@ class AddEventDialog(QDialog):
|
||||||
"""This dialog is created whenever a new event is added to the pulse sequence. It allows the user to enter a name for the event."""
|
"""This dialog is created whenever a new event is added to the pulse sequence. It allows the user to enter a name for the event."""
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
|
"""Initializes the AddEventDialog."""
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
self.setWindowTitle("Add Event")
|
self.setWindowTitle("Add Event")
|
||||||
|
@ -544,7 +566,7 @@ class AddEventDialog(QDialog):
|
||||||
return self.name_input.text()
|
return self.name_input.text()
|
||||||
|
|
||||||
def get_duration(self) -> float:
|
def get_duration(self) -> float:
|
||||||
"""Returns the duration entered by the user, or a fallback value."
|
"""Returns the duration entered by the user, or a fallback value.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
float: The duration value provided by the user, or 20
|
float: The duration value provided by the user, or 20
|
||||||
|
@ -600,6 +622,7 @@ class QFileManager:
|
||||||
"""This class provides methods for opening and saving files."""
|
"""This class provides methods for opening and saving files."""
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
|
"""Initializes the QFileManager."""
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
def loadFileDialog(self) -> str:
|
def loadFileDialog(self) -> str:
|
||||||
|
|
Loading…
Reference in a new issue