Source code for stytra.gui.protocol_control
from PyQt5.QtCore import pyqtSignal, QSize
from PyQt5.QtWidgets import QProgressBar, QToolBar
from stytra.stimulation import ProtocolRunner
import datetime
from lightparam.gui import ParameterGui
from math import floor, ceil
from stytra.gui.buttons import IconButton, ToggleIconButton
[docs]class ProtocolControlToolbar(QToolBar):
"""GUI for controlling a ProtocolRunner.
This class implements the toolbar for controlling the protocol:
- toggle button for starting/stopping the Protocol;
- progress bar to display progression of the Protocol.
- a button and window for controlling Protocol parameters;
Parameters
----------
protocol_runner: :class:`ProtocolRunner <stytra.stimulation.ProtocolRunner>` object
ProtocolRunner that is controlled by the GUI.
Signals:
"""
sig_start_protocol = pyqtSignal()
""" Emitted via the toggle button click, meant to
start the protocol."""
sig_stop_protocol = pyqtSignal()
""" Emitted via the toggle button click, meant to
abort the protocol."""
def __init__(self, protocol_runner: ProtocolRunner, main_window=None):
""" """
super().__init__("Protocol running")
self.setIconSize(QSize(32, 32))
self.main_window = main_window
self.protocol_runner = protocol_runner
self.update_duration_each = 120
self._update_duration_i = 0
self.toggleStatus = ToggleIconButton(
icon_off="play", icon_on="stop", action_on="play", on=False
)
self.toggleStatus.clicked.connect(self.toggle_protocol_running)
self.addWidget(self.toggleStatus)
# Progress bar for monitoring the protocol:
self.progress_bar = QProgressBar()
self.addSeparator()
self.addWidget(self.progress_bar)
# Window with the protocol parameters:
self.act_edit = IconButton(
action_name="Edit protocol parameters", icon_name="edit_protocol"
)
self.act_edit.clicked.connect(self.show_stim_params_gui)
self.addWidget(self.act_edit)
# Connect events and signals from the ProtocolRunner to update the GUI:
self.update_progress()
self.protocol_runner.sig_timestep.connect(self.update_progress)
self.protocol_runner.sig_protocol_finished.connect(self.toggle_icon)
self.protocol_runner.sig_protocol_updated.connect(self.update_progress)
self.protocol_runner.sig_protocol_interrupted.connect(self.toggle_icon)
[docs] def show_stim_params_gui(self):
"""Create and show window to update protocol parameters.
"""
self.prot_param_win = ParameterGui(self.protocol_runner.protocol)
self.prot_param_win.show()
[docs] def toggle_protocol_running(self):
"""Emit the start and stop signals. These can be used in the Experiment
class or directly connected with the respective ProtocolRunner
start() and stop() methods.
Parameters
----------
Returns
-------
"""
# Start/stop the protocol:
if not self.protocol_runner.running:
self.progress_bar.setValue(0)
self.sig_start_protocol.emit()
else:
self.sig_stop_protocol.emit()
[docs] def toggle_icon(self):
self.toggleStatus.flip_icon(self.protocol_runner.running)
self.update_progress()
[docs] def update_progress(self):
""" Update progress bar
"""
# if self._update_duration_i == 0:
# pass
# self.protocol_runner.duration = self.protocol_runner.get_duration()
self._update_duration_i = (
self._update_duration_i + 1
) % self.update_duration_each
self.progress_bar.setMaximum(int(self.protocol_runner.duration))
self.progress_bar.setValue(int(self.protocol_runner.t))
rem = ceil(self.protocol_runner.duration - self.protocol_runner.t)
rem_min = int(floor(rem / 60))
time_info = "{}/{}s ({}:{} remaining)".format(
int(self.protocol_runner.t),
int(self.protocol_runner.duration),
rem_min,
int(rem - rem_min * 60),
)
# If experiment started, add expected end time:
if self.protocol_runner.running:
exp_end_time = self.protocol_runner.experiment.t0 + datetime.timedelta(
seconds=self.protocol_runner.duration
)
time_info += " - Ending at {}:{}:{}".format(
exp_end_time.hour, exp_end_time.minute, exp_end_time.second
)
self.progress_bar.setFormat(time_info)