diff --git a/blipblop/ui/audioblop.py b/blipblop/ui/audioblop.py index e584e87..47bcac9 100644 --- a/blipblop/ui/audioblop.py +++ b/blipblop/ui/audioblop.py @@ -1,105 +1,13 @@ -from PyQt5.QtWidgets import QAction, QComboBox, QFormLayout, QGridLayout, QLabel, QPushButton, QSizePolicy, QSlider, QSpinBox, QSplitter, QTextEdit, QVBoxLayout, QWidget -from PyQt5.QtCore import QPoint, QRandomGenerator, QTimer, Qt, endl, pyqtSignal +from PyQt5.QtWidgets import QAction, QGridLayout, QLabel, QPushButton, QSizePolicy, QSplitter, QVBoxLayout, QWidget +from PyQt5.QtCore import QPoint, QRandomGenerator, QTimer, Qt, pyqtSignal from PyQt5.QtGui import QColor, QFont, QIcon, QKeySequence, QPainter, QPen, QPixmap from PyQt5.QtMultimedia import QMediaPlayer -import os import blipblop.constants as cnst from blipblop.ui.countdownlabel import CountdownLabel +from blipblop.ui.settings import AuditoryTaskSettings import datetime as dt -class SettingsPanel(QWidget): - def __init__(self, parent=None): - super().__init__(parent=parent) - - self._trial_spinner = QSpinBox() - self._trial_spinner.setMinimum(5) - self._trial_spinner.setMaximum(25) - self._trial_spinner.setValue(5) - self._trial_spinner.setToolTip("Number of consecutive trials (5 - 25)") - - self._min_delay_spinner = QSpinBox() - self._min_delay_spinner.setMinimum(1) - self._min_delay_spinner.setMaximum(10) - self._min_delay_spinner.setValue(1) - self._min_delay_spinner.setToolTip("Minimum delay between start of trial and stimulus display [s]") - - self._max_delay_spinner = QSpinBox() - self._max_delay_spinner.setMinimum(1) - self._max_delay_spinner.setMaximum(10) - self._max_delay_spinner.setValue(5) - self._max_delay_spinner.setToolTip("Maximum delay between start of trial and stimulus display [s]") - - self._countdown_spinner = QSpinBox() - self._countdown_spinner.setMinimum(1) - self._countdown_spinner.setMaximum(10) - self._countdown_spinner.setValue(3) - self._countdown_spinner.setToolTip("Pause between trials [s]") - - self._saliency_slider = QSlider(Qt.Horizontal) - self._saliency_slider.setMinimum(0) - self._saliency_slider.setMaximum(100) - self._saliency_slider.setSliderPosition(100) - self._saliency_slider.setTickInterval(25) - self._saliency_slider.setTickPosition(QSlider.TicksBelow) - self._saliency_slider.setToolTip("Saliency of the stimulus, i.e. its loudness") - - self._sound_combo = QComboBox() - for k in cnst.SNDS_DICT.keys(): - self._sound_combo.addItem(k) - - self._instructions = QTextEdit() - self._instructions.setMarkdown("* fixate central cross\n * press start (enter) when ready\n * press space bar as soon as the stimulus occurs") - self._instructions.setMinimumHeight(200) - self._instructions.setReadOnly(True) - - form_layout = QFormLayout() - form_layout.addRow("Settings", None) - form_layout.addRow("number of trials", self._trial_spinner) - form_layout.addRow("minimum delay [s]", self._min_delay_spinner) - form_layout.addRow("maximum delay [s]", self._max_delay_spinner) - form_layout.addRow("pause [s]", self._countdown_spinner) - form_layout.addRow("stimulus saliency", self._saliency_slider) - form_layout.addRow("stimulus sound", self._sound_combo) - form_layout.addRow("instructions", self._instructions) - self.setLayout(form_layout) - - @property - def trials(self): - return self._trial_spinner.value() - - @property - def saliency(self): - return self._saliency_slider.sliderPosition() - - @property - def size(self): - return self._size_slider.sliderPosition() - - @property - def min_delay(self): - return self._min_delay_spinner.value() - - @property - def max_delay(self): - return self._max_delay_spinner.value() - - @property - def countdown(self): - return self._countdown_spinner.value() - - @property - def sound(self): - return self._sound_combo.currentText() - - def set_enabled(self, enabled): - self._trial_spinner.setEnabled(enabled) - self._saliency_slider.setEnabled(enabled) - self._countdown_spinner.setEnabled(enabled) - self._min_delay_spinner.setEnabled(enabled) - self._max_delay_spinner.setEnabled(enabled) - self._sound_combo.setEnabled(enabled) - class AudioBlop(QWidget): task_done = pyqtSignal() @@ -107,7 +15,7 @@ class AudioBlop(QWidget): def __init__(self, parent=None) -> None: super().__init__(parent=parent) - + widget = QWidget() grid = QGridLayout() grid.setColumnStretch(0, 1) @@ -116,37 +24,37 @@ class AudioBlop(QWidget): grid.setRowStretch(3, 1) widget.setLayout(grid) - l = QLabel("Auditory reaction test") - l.setPixmap(QPixmap(":/icons/auditory_task")) - grid.addWidget(l, 0, 0, Qt.AlignLeft) - - l2 =QLabel("Measurement of auditory reaction times\npress enter to start") + icon_label = QLabel("Auditory reaction test") + icon_label.setPixmap(QPixmap(":/icons/auditory_task")) + grid.addWidget(icon_label, 0, 0, Qt.AlignLeft) + + heading_label = QLabel("Measurement of auditory reaction times\npress enter to start") font = QFont() font.setBold(True) font.setPointSize(20) - l2.setFont(font) - l2.setStyleSheet("color: #2D4B9A") - grid.addWidget(l2, 1, 0, 1, 2, Qt.AlignLeft) - + heading_label.setFont(font) + heading_label.setStyleSheet("color: #2D4B9A") + grid.addWidget(heading_label, 1, 0, 1, 2, Qt.AlignLeft) + settings_btn = QPushButton(QIcon(":/icons/settings"), "") settings_btn.setToolTip("edit task settings") settings_btn.setShortcut(QKeySequence("alt+s")) settings_btn.clicked.connect(self.on_toggle_settings) grid.addWidget(settings_btn, 0, 3, Qt.AlignRight) - + self._status_label = QLabel("Ready to start, press enter ...") grid.addWidget(self._status_label, 4, 0, Qt.AlignLeft) self._countdown_label = CountdownLabel(text="Next trial in:") grid.addWidget(self._countdown_label, 4, 1, Qt.AlignCenter) self._countdown_label.countdown_done.connect(self.run_trial) - + self._draw_area = QLabel() self._draw_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) grid.addWidget(self._draw_area, 2, 1) - - self._settings = SettingsPanel() - + + self._settings = AuditoryTaskSettings() + self._splitter = QSplitter() self._splitter.addWidget(widget) self._splitter.addWidget(self._settings) @@ -155,7 +63,7 @@ class AudioBlop(QWidget): vbox = QVBoxLayout() vbox.addWidget(self._splitter) self.setLayout(vbox) - + self.reset_canvas() self.create_actions() @@ -168,12 +76,12 @@ class AudioBlop(QWidget): self._player = QMediaPlayer() self._random_generator = QRandomGenerator() self.setFocus() - + def create_actions(self): self._start_action = QAction("start trial") self._start_action.setShortcuts([QKeySequence("enter"), QKeySequence("return")]) self._start_action.triggered.connect(self.on_trial_start) - + self._reaction = QAction("reaction") self._reaction.setShortcut(QKeySequence("space")) self._reaction.triggered.connect(self.on_reaction) @@ -181,7 +89,7 @@ class AudioBlop(QWidget): self._abort = QAction("abort") self._abort.setShortcut(QKeySequence("escape")) self._abort.triggered.connect(self.on_abort) - + self.addAction(self._start_action) self.addAction(self._reaction) self.addAction(self._abort) @@ -189,7 +97,7 @@ class AudioBlop(QWidget): def on_reaction(self): if not self._session_running or not self._trial_running: return - + self._response_time = dt.datetime.now() if self._trial_counter < self._settings.trials: self._status_label.setText("Trial %i of %i" % (self._trial_counter, self._settings.trials)) @@ -206,14 +114,13 @@ class AudioBlop(QWidget): return self._countdown_label.start(self._settings.countdown) - def reset_canvas(self): bkg_color = QColor() bkg_color.setAlphaF(0.0) canvas = QPixmap(400, 400) self._canvas_center = QPoint(200, 200) canvas.fill(bkg_color) - self.draw_fixation(canvas) + self.draw_fixation(canvas) self._draw_area.setPixmap(canvas) self._draw_area.update() @@ -222,7 +129,7 @@ class AudioBlop(QWidget): right = QPoint(225, 200) top = QPoint(200, 175) bottom = QPoint(200, 225) - painter = QPainter(pixmap) + painter = QPainter(pixmap) painter.setPen(QPen(Qt.red, 2, Qt.SolidLine)) painter.drawLine(left, right) painter.drawLine(top, bottom) @@ -234,7 +141,7 @@ class AudioBlop(QWidget): def blip(self): self._player.play() self._start_time = dt.datetime.now() - + def on_trial_start(self): if self._trial_running: return @@ -251,9 +158,10 @@ class AudioBlop(QWidget): self._trial_counter += 1 self._status_label.setText("Trial %i of %i running" % (self._trial_counter, self._settings.trials)) content = cnst.get_sound(self._settings.sound) + self._player.setMedia(content) self._player.setVolume(self._settings.saliency) - + min_interval = int(self._settings.min_delay * 10) max_interval = int(self._settings.max_delay * 10) interval = self._random_generator.bounded(min_interval, max_interval) * 100 @@ -263,15 +171,15 @@ class AudioBlop(QWidget): self._timer.setInterval(int(interval)) self._timer.timeout.connect(self.blip) self._timer.start() - + def on_abort(self): self.reset() self.task_aborted.emit() - + @property def results(self): return self._reaction_times - + def reset(self): self._trial_counter = 0 self._session_running = 0 @@ -281,7 +189,7 @@ class AudioBlop(QWidget): self._status_label.setText("Ready to start...") self._settings.set_enabled(True) self._countdown_label.stop() - + def on_toggle_settings(self): if self._splitter.sizes()[1] > 0: self._splitter.widget(1).hide() diff --git a/blipblop/ui/settings.py b/blipblop/ui/settings.py new file mode 100644 index 0000000..65759e2 --- /dev/null +++ b/blipblop/ui/settings.py @@ -0,0 +1,132 @@ +from PyQt5.QtWidgets import QComboBox, QFormLayout, QSlider, QSpinBox, QTextEdit, QWidget +from PyQt5.QtCore import Qt +import blipblop.constants as cnst + + +class TaskSettings(QWidget): + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self._trial_spinner = QSpinBox() + self._trial_spinner.setMinimum(5) + self._trial_spinner.setMaximum(25) + self._trial_spinner.setValue(5) + self._trial_spinner.setToolTip("Number of consecutive trials (5 - 25)") + + self._min_delay_spinner = QSpinBox() + self._min_delay_spinner.setMinimum(1) + self._min_delay_spinner.setMaximum(10) + self._min_delay_spinner.setValue(1) + self._min_delay_spinner.setToolTip("Minimum delay between start of trial and stimulus display [s]") + + self._max_delay_spinner = QSpinBox() + self._max_delay_spinner.setMinimum(1) + self._max_delay_spinner.setMaximum(10) + self._max_delay_spinner.setValue(5) + self._max_delay_spinner.setToolTip("Maximum delay between start of trial and stimulus display [s]") + + self._countdown_spinner = QSpinBox() + self._countdown_spinner.setMinimum(1) + self._countdown_spinner.setMaximum(10) + self._countdown_spinner.setValue(3) + self._countdown_spinner.setToolTip("Pause between trials [s]") + + self._saliency_slider = QSlider(Qt.Horizontal) + self._saliency_slider.setMinimum(0) + self._saliency_slider.setMaximum(100) + self._saliency_slider.setSliderPosition(100) + self._saliency_slider.setTickInterval(25) + self._saliency_slider.setTickPosition(QSlider.TicksBelow) + + self._instructions = QTextEdit() + self._instructions.setMarkdown("* fixate central cross\n * press start (enter) when ready\n * press space bar as soon as the stimulus occurs") + self._instructions.setMinimumHeight(200) + self._instructions.setReadOnly(True) + + self.form_layout = QFormLayout() + self.form_layout.addRow("Settings", None) + self.form_layout.addRow("number of trials", self._trial_spinner) + self.form_layout.addRow("minimum delay [s]", self._min_delay_spinner) + self.form_layout.addRow("maximum delay [s]", self._max_delay_spinner) + self.form_layout.addRow("pause [s]", self._countdown_spinner) + self.form_layout.addRow("stimulus saliency", self._saliency_slider) + self.form_layout.addRow("instructions", self._instructions) + self.setLayout(self.form_layout) + + @property + def trials(self): + return self._trial_spinner.value() + + @property + def saliency(self): + return self._saliency_slider.sliderPosition() + + @property + def size(self): + return self._size_slider.sliderPosition() + + @property + def min_delay(self): + return self._min_delay_spinner.value() + + @property + def max_delay(self): + return self._max_delay_spinner.value() + + @property + def countdown(self): + return self._countdown_spinner.value() + + def set_enabled(self, enabled): + self._trial_spinner.setEnabled(enabled) + self._saliency_slider.setEnabled(enabled) + self._countdown_spinner.setEnabled(enabled) + self._min_delay_spinner.setEnabled(enabled) + self._max_delay_spinner.setEnabled(enabled) + + +class AuditoryTaskSettings(TaskSettings): + + def __init__(self, parent=None): + super().__init__(parent=parent) + self._saliency_slider.setToolTip("Saliency of the stimulus, i.e. its loudness") + + self._sound_combo = QComboBox() + for k in cnst.SNDS_DICT.keys(): + self._sound_combo.addItem(k) + + self.form_layout.insertRow(self.form_layout.rowCount() -1, "stimulus sound", self._sound_combo) + + def set_enabled(self, enabled): + super().set_enabled(enabled) + self._sound_combo.setEnabled(enabled) + + @property + def sound(self): + return self._sound_combo.currentText() + + +class VisualTaskSettings(TaskSettings): + + def __init__(self, parent=None): + super().__init__(parent=parent) + self._saliency_slider.setToolTip("Saliency of the stimulus, i.e. its opacity") + + self._size_slider = QSlider(Qt.Horizontal) + self._size_slider.setMinimum(0) + self._size_slider.setMaximum(200) + self._size_slider.setSliderPosition(100) + self._size_slider.setTickInterval(25) + self._size_slider.setTickPosition(QSlider.TicksBelow) + self._size_slider.setToolTip("Diameter of the stimulus in pixel") + + self.form_layout.insertRow(self.form_layout.rowCount() -1, "stimulus size", self._size_slider) + + def set_enabled(self, enabled): + super().set_enabled(enabled) + self._size_slider.setEnabled(enabled) + + @property + def size(self): + return self._size_slider.sliderPosition() diff --git a/blipblop/ui/visualblip.py b/blipblop/ui/visualblip.py index 7652e8d..e94b07d 100644 --- a/blipblop/ui/visualblip.py +++ b/blipblop/ui/visualblip.py @@ -1,104 +1,11 @@ -from PyQt5.QtWidgets import QAction, QFormLayout, QGridLayout, QLabel, QLineEdit, QPushButton, QSizePolicy, QSlider, QSpinBox, QSplitter, QTextEdit, QVBoxLayout, QWidget -from PyQt5.QtCore import QPoint, QRandomGenerator, QTimer, Qt, pyqtSignal, QSettings +from PyQt5.QtWidgets import QAction, QGridLayout, QLabel, QPushButton, QSizePolicy, QSplitter, QVBoxLayout, QWidget +from PyQt5.QtCore import QPoint, QRandomGenerator, QTimer, Qt, pyqtSignal from PyQt5.QtGui import QColor, QFont, QIcon, QKeySequence, QPainter, QBrush, QPen, QPixmap -import os -import blipblop.constants as cnst from blipblop.ui.countdownlabel import CountdownLabel +from blipblop.ui.settings import VisualTaskSettings import datetime as dt -class SettingsPanel(QWidget): - def __init__(self, parent=None): - super().__init__(parent=parent) - - self._trial_spinner = QSpinBox() - self._trial_spinner.setMinimum(5) - self._trial_spinner.setMaximum(25) - self._trial_spinner.setValue(5) - self._trial_spinner.setToolTip("Number of consecutive trials (5 - 25)") - - self._min_delay_spinner = QSpinBox() - self._min_delay_spinner.setMinimum(1) - self._min_delay_spinner.setMaximum(10) - self._min_delay_spinner.setValue(1) - self._min_delay_spinner.setToolTip("Minimum delay between start of trial and stimulus display [s]") - - self._max_delay_spinner = QSpinBox() - self._max_delay_spinner.setMinimum(1) - self._max_delay_spinner.setMaximum(10) - self._max_delay_spinner.setValue(5) - self._max_delay_spinner.setToolTip("Maximum delay between start of trial and stimulus display [s]") - - self._saliency_slider = QSlider(Qt.Horizontal) - self._saliency_slider.setMinimum(0) - self._saliency_slider.setMaximum(100) - self._saliency_slider.setSliderPosition(100) - self._saliency_slider.setTickInterval(25) - self._saliency_slider.setTickPosition(QSlider.TicksBelow) - self._saliency_slider.setToolTip("Saliency of the stimulus, i.e. its opacity") - - self._size_slider = QSlider(Qt.Horizontal) - self._size_slider.setMinimum(0) - self._size_slider.setMaximum(200) - self._size_slider.setSliderPosition(100) - self._size_slider.setTickInterval(25) - self._size_slider.setTickPosition(QSlider.TicksBelow) - self._size_slider.setToolTip("Diameter of the stimulus in pixel") - - self._countdown_spinner = QSpinBox() - self._countdown_spinner.setMinimum(2) - self._countdown_spinner.setMaximum(30) - self._countdown_spinner.setValue(5) - self._countdown_spinner.setToolTip("Pause/countdown for next trial") - - self._instructions = QTextEdit() - self._instructions.setMarkdown("* fixate central cross\n * press start (enter) when ready\n * press space bar as soon as the stimulus occurs") - self._instructions.setMinimumHeight(200) - self._instructions.setReadOnly(True) - - form_layout = QFormLayout() - form_layout.addRow("Settings", None) - form_layout.addRow("number of trials", self._trial_spinner) - form_layout.addRow("pause until next trial [s]", self._countdown_spinner) - form_layout.addRow("minimum delay [s]", self._min_delay_spinner) - form_layout.addRow("maximum delay [s]", self._max_delay_spinner) - form_layout.addRow("stimulus saliency", self._saliency_slider) - form_layout.addRow("stimulus size", self._size_slider) - form_layout.addRow("instructions", self._instructions) - self.setLayout(form_layout) - - @property - def trials(self): - return self._trial_spinner.value() - - @property - def saliency(self): - return self._saliency_slider.sliderPosition() - - @property - def size(self): - return self._size_slider.sliderPosition() - - @property - def min_delay(self): - return self._min_delay_spinner.value() - - @property - def max_delay(self): - return self._max_delay_spinner.value() - - @property - def countdown(self): - return self._countdown_spinner.value() - - def set_enabled(self, enabled): - self._trial_spinner.setEnabled(enabled) - self._saliency_slider.setEnabled(enabled) - self._size_slider.setEnabled(enabled) - self._countdown_spinner.setEnabled(enabled) - self._min_delay_spinner.setEnabled(enabled) - self._max_delay_spinner.setEnabled(enabled) - class VisualBlip(QWidget): task_done = pyqtSignal() @@ -106,7 +13,7 @@ class VisualBlip(QWidget): def __init__(self, parent=None) -> None: super().__init__(parent=parent) - + widget = QWidget() grid = QGridLayout() grid.setColumnStretch(0, 1) @@ -115,37 +22,37 @@ class VisualBlip(QWidget): grid.setRowStretch(3, 1) widget.setLayout(grid) - l = QLabel("Visual reaction test") - l.setPixmap(QPixmap(":/icons/visual_task")) - grid.addWidget(l, 0, 0, Qt.AlignLeft) + icon_label = QLabel("Visual reaction test") + icon_label.setPixmap(QPixmap(":/icons/visual_task")) + grid.addWidget(icon_label, 0, 0, Qt.AlignLeft) - l2 = QLabel("Measurement of visual reaction times\npress enter to start") + heading_label = QLabel("Measurement of visual reaction times\npress enter to start") font = QFont() font.setBold(True) font.setPointSize(20) - l2.setFont(font) - l2.setStyleSheet("color: #2D4B9A") - grid.addWidget(l2, 1, 0, 1, 2, Qt.AlignLeft) - + heading_label.setFont(font) + heading_label.setStyleSheet("color: #2D4B9A") + grid.addWidget(heading_label, 1, 0, 1, 2, Qt.AlignLeft) + settings_btn = QPushButton(QIcon(":/icons/settings"), "") settings_btn.setToolTip("edit task settings") settings_btn.setShortcut(QKeySequence("alt+s")) settings_btn.clicked.connect(self.on_toggle_settings) grid.addWidget(settings_btn, 0, 3, Qt.AlignRight) - + self._status_label = QLabel("Ready to start, press enter ...") grid.addWidget(self._status_label, 4, 0, Qt.AlignBaseline) - + self._countdown_label = CountdownLabel(text="Next trial in:") grid.addWidget(self._countdown_label, 4, 1, Qt.AlignCenter) self._countdown_label.countdown_done.connect(self.run_trial) - + self._draw_area = QLabel() self._draw_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) grid.addWidget(self._draw_area, 2, 1) - - self._settings = SettingsPanel() - + + self._settings = VisualTaskSettings() + self._splitter = QSplitter() self._splitter.addWidget(widget) self._splitter.addWidget(self._settings) @@ -154,7 +61,7 @@ class VisualBlip(QWidget): vbox = QVBoxLayout() vbox.addWidget(self._splitter) self.setLayout(vbox) - + self.reset_canvas() self.create_actions() @@ -167,12 +74,12 @@ class VisualBlip(QWidget): self._random_generator = QRandomGenerator() self.setFocus() - + def create_actions(self): self._start_action = QAction("start trial") self._start_action.setShortcuts([QKeySequence("enter"), QKeySequence("return")]) self._start_action.triggered.connect(self.on_trial_start) - + self._reaction = QAction("reaction") self._reaction.setShortcut(QKeySequence("space")) self._reaction.triggered.connect(self.on_reaction) @@ -180,7 +87,7 @@ class VisualBlip(QWidget): self._abort = QAction("abort") self._abort.setShortcut(QKeySequence("escape")) self._abort.triggered.connect(self.on_abort) - + self.addAction(self._start_action) self.addAction(self._reaction) self.addAction(self._abort) @@ -188,7 +95,7 @@ class VisualBlip(QWidget): def on_reaction(self): if not self._session_running or not self._trial_running: return - + self._response_time = dt.datetime.now() if self._trial_counter < self._settings.trials: self._status_label.setText("Trial %i of %i" % (self._trial_counter, self._settings.trials)) @@ -212,7 +119,7 @@ class VisualBlip(QWidget): canvas = QPixmap(400, 400) self._canvas_center = QPoint(200, 200) canvas.fill(bkg_color) - self.draw_fixation(canvas) + self.draw_fixation(canvas) self._draw_area.setPixmap(canvas) self._draw_area.update() @@ -221,7 +128,7 @@ class VisualBlip(QWidget): right = QPoint(225, 200) top = QPoint(200, 175) bottom = QPoint(200, 225) - painter = QPainter(pixmap) + painter = QPainter(pixmap) painter.setPen(QPen(Qt.red, 2, Qt.SolidLine)) painter.drawLine(left, right) painter.drawLine(top, bottom) @@ -232,24 +139,24 @@ class VisualBlip(QWidget): def blip(self): stim_size = self._settings.size - painter = QPainter(self._draw_area.pixmap()) + painter = QPainter(self._draw_area.pixmap()) painter.setPen(QPen(Qt.red, 1, Qt.SolidLine)) color = QColor(Qt.red) color.setAlphaF(self._settings.saliency/100) - painter.setBrush(QBrush(color, Qt.SolidPattern)) + painter.setBrush(QBrush(color, Qt.SolidPattern)) painter.drawEllipse(self._canvas_center, stim_size, stim_size) painter.end() self._start_time = dt.datetime.now() self._draw_area.update() - + def on_trial_start(self): if self._trial_running: return if not self._session_running: self._settings.set_enabled(False) - self._session_running = True + self._session_running = True self._countdown_label.start(time=self._settings.countdown) - + def run_trial(self): self._trial_running = True if self._trial_counter >= self._settings.trials: @@ -267,15 +174,15 @@ class VisualBlip(QWidget): self._timer.setInterval(int(interval)) self._timer.timeout.connect(self.blip) self._timer.start() - + def on_abort(self): self.reset() self.task_aborted.emit() - + @property def results(self): return self._reaction_times - + def reset(self): self.reset_canvas() self._trial_counter = 0 @@ -286,7 +193,7 @@ class VisualBlip(QWidget): self._status_label.setText("Ready to start...") self._countdown_label.stop() self._settings.set_enabled(True) - + def on_toggle_settings(self): if self._splitter.sizes()[1] > 0: self._splitter.widget(1).hide()