diff --git a/COPYING.txt b/COPYING
similarity index 100%
rename from COPYING.txt
rename to COPYING
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 54cbe98..0000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,5 +0,0 @@
-recursive-include opensesame_plugins *
-graft pygaze/_eyetracker/alea
-global-exclude *.pyc
-global-exclude *.pyo
-
diff --git a/opensesame_plugins/artwork/icons.svg b/artwork/icons.svg
similarity index 100%
rename from opensesame_plugins/artwork/icons.svg
rename to artwork/icons.svg
diff --git a/opensesame_plugins/pygaze/__init__.py b/opensesame_plugins/pygaze/__init__.py
new file mode 100644
index 0000000..65ed55f
--- /dev/null
+++ b/opensesame_plugins/pygaze/__init__.py
@@ -0,0 +1,2 @@
+# The name of the packages to check for updates on conda and pip
+packages = ['pygaze']
diff --git a/opensesame_plugins/pygaze/pygaze_drift_correct/__init__.py b/opensesame_plugins/pygaze/pygaze_drift_correct/__init__.py
new file mode 100644
index 0000000..fd0bdea
--- /dev/null
+++ b/opensesame_plugins/pygaze/pygaze_drift_correct/__init__.py
@@ -0,0 +1,40 @@
+"""Performs eye-tracker drift correction"""
+
+category = 'PyGaze'
+priority = 10
+help = 'manual/eyetracking/pygaze'
+icon = 'os-pygaze_drift_correct'
+controls = [
+ {'type': 'line_edit',
+ 'var': 'xpos',
+ 'label': 'X position',
+ 'tooltip': 'X coordinate for drift correction'},
+ {'type': 'line_edit',
+ 'var': 'ypos',
+ 'label': 'Y position',
+ 'tooltip': 'Y position for drift correction'},
+ {'type': 'line_edit',
+ 'var': 'target_color',
+ 'label': 'Target color',
+ 'tooltip': 'Color for the drift-correction target',
+ 'name': 'line_edit_target_color'},
+ {'type': 'combobox',
+ 'var': 'target_style',
+ 'label': 'Target style (OpenSesame >= 2.8.0)',
+ 'options': ['default',
+ 'large-filled',
+ 'small-filled',
+ 'large-open',
+ 'small-open',
+ 'large-cross',
+ 'small-cross'],
+ 'tooltip': 'Style for the drift-correction target',
+ 'name': 'combobox_target_style'},
+ {'type': 'checkbox',
+ 'var': 'draw_target',
+ 'label': 'Show display with drift-correction target',
+ 'tooltip': 'Indicates whether a drift-correction display should be shown'},
+ {'type': 'checkbox',
+ 'var': 'fixation_triggered',
+ 'label': 'Fixation triggered (no spacebar press required)',
+ 'tooltip': 'Indicates whether drift correction should be performed as soon as a stable fixation is detected'}]
diff --git a/opensesame_plugins/pygaze/pygaze_drift_correct/pygaze_drift_correct.py b/opensesame_plugins/pygaze/pygaze_drift_correct/pygaze_drift_correct.py
new file mode 100644
index 0000000..cac0580
--- /dev/null
+++ b/opensesame_plugins/pygaze/pygaze_drift_correct/pygaze_drift_correct.py
@@ -0,0 +1,89 @@
+"""This file is part of PyGaze.
+
+PyGaze is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+PyGaze is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with PyGaze. If not, see .
+"""
+
+import inspect
+from openexp.canvas import Canvas
+from libopensesame.item import Item
+from libqtopensesame.items.qtautoplugin import QtAutoPlugin
+from pygaze.display import Display
+
+
+class PygazeDriftCorrect(Item):
+
+ def reset(self):
+ self.var.xpos = 0
+ self.var.ypos = 0
+ self.var.fixation_triggered = u'no'
+ self.var.target_color = u'[foreground]'
+ self.var.target_style = u'default'
+ self.var.draw_target = u'yes'
+
+ def prepare_drift_correction_canvas(self):
+ """A hook to prepare the canvas with the drift-correction target."""
+ if self.var.draw_target == u'yes':
+ self.dc_canvas = Canvas(self.experiment)
+ self.dc_canvas.fixdot(
+ self.var.xpos, self.var.ypos, color=self.var.target_color,
+ style=self.var.target_style)
+ else:
+ self.dc_canvas = None
+
+ def draw_drift_correction_canvas(self, x, y):
+ """A hook to show the canvas with the drift-correction target."""
+ if self.dc_canvas is not None:
+ self.dc_canvas.show()
+
+ def prepare(self):
+ super().prepare()
+ self.prepare_drift_correction_canvas()
+ self.experiment.pygaze_eyetracker. \
+ set_draw_drift_correction_target_func(
+ self.draw_drift_correction_canvas)
+
+ def run(self):
+ self.set_item_onset()
+ xpos = self.var.width / 2 + self.var.xpos
+ ypos = self.var.height / 2 + self.var.ypos
+ while True:
+ success = self.experiment.pygaze_eyetracker.drift_correction(
+ pos=(xpos, ypos),
+ fix_triggered=self.var.fixation_triggered == 'yes')
+ if success:
+ break
+
+
+class QtPygazeDriftCorrect(PygazeDriftCorrect, QtAutoPlugin):
+
+ def __init__(self, name, experiment, script=None):
+ PygazeDriftCorrect.__init__(self, name, experiment, script)
+ QtAutoPlugin.__init__(self, __file__)
+
+ def init_edit_widget(self):
+ super().init_edit_widget()
+ self.custom_interactions()
+
+ def apply_edit_changes(self):
+ if not super().apply_edit_changes() or self.lock:
+ return False
+ self.custom_interactions()
+
+ def custom_interactions(self):
+ """Disables the target-style combobox if no target display should be
+ drawn
+ """
+ draw_target = self.var.draw_target == u'yes'
+ self.combobox_target_style.setEnabled(draw_target)
+ self.line_edit_target_color.setEnabled(draw_target)
diff --git a/opensesame_plugins/pygaze/pygaze_init/__init__.py b/opensesame_plugins/pygaze/pygaze_init/__init__.py
new file mode 100644
index 0000000..dfe7d7e
--- /dev/null
+++ b/opensesame_plugins/pygaze/pygaze_init/__init__.py
@@ -0,0 +1,107 @@
+"""Initializes and calibrates the eye tracker"""
+
+category = 'PyGaze'
+priority = 10
+help = 'manual/eyetracking/pygaze'
+icon = 'os-pygaze_init'
+controls = [
+ {'type': 'combobox',
+ 'var': 'tracker_type',
+ 'label': 'Select tracker type',
+ 'options': ['Simple dummy',
+ 'Advanced dummy (mouse simulation)',
+ 'EyeLink',
+ 'EyeLogic',
+ 'SMI',
+ 'EyeTribe',
+ 'OpenGaze',
+ 'Alea',
+ 'Tobii',
+ 'Tobii-legacy',
+ 'Tobii Pro Glasses 2'],
+ 'tooltip': 'A list of supported eye trackers'},
+ {'type': 'checkbox',
+ 'var': 'calibrate',
+ 'label': 'Calibrate tracker',
+ 'tooltip': 'Indicates whether calibration should be started'},
+ {'type': 'checkbox',
+ 'var': 'calbeep',
+ 'label': 'Calibration beep',
+ 'tooltip': 'Play a beep when the calibration target jumps',
+ 'name': 'checkbox_calbeep'},
+ {'type': 'line_edit',
+ 'label': 'Log file',
+ 'var': '_logfile',
+ 'tooltip': 'The name for the log file'},
+ {'type': 'spinbox',
+ 'var': 'sacc_vel_thr',
+ 'label': 'Saccade velocity threshold',
+ 'min_val': 0,
+ 'max_val': 100000,
+ 'suffix': ' °/s',
+ 'tooltip': 'Velocity threshold for saccade detection algorithm',
+ 'name': 'spinbox_sacc_vel_thr'},
+ {'type': 'spinbox',
+ 'var': 'sacc_acc_thr',
+ 'label': 'Saccade acceleration threshold',
+ 'min_val': 0,
+ 'max_val': 100000,
+ 'suffix': ' °/s/s',
+ 'tooltip': 'Acceleration threshold for saccade detection algorithm',
+ 'name': 'spinbox_sacc_acc_thr'},
+ {'type': 'text',
+ 'label': 'Warning: PyLink is required for EyeLink functionality and is not installed. Visit http://osdoc.cogsci.nl/manual/eyetracking/eyelink/ for more information.',
+ 'name': 'text_eyelink_pylink_check'},
+ {'type': 'text', 'label': 'DUMMY', 'name': 'text_pygaze_version'},
+ {'type': 'line_edit',
+ 'label': 'Alea API key',
+ 'var': 'alea_api_key',
+ 'name': 'line_edit_alea_api_key',
+ 'tooltip': 'The API key provided to you by Alea'},
+ {'type': 'checkbox',
+ 'var': 'alea_animated_calibration',
+ 'label': 'Animated calibration target',
+ 'tooltip': 'Turn on child-friendly animated calibration targets',
+ 'name': 'checkbox_alea_animated_calibration'},
+ {'type': 'checkbox',
+ 'var': 'eyelink_force_drift_correct',
+ 'label': 'Force drift correction (for EyeLink 1000)',
+ 'tooltip': 'Turn on active drift correction',
+ 'name': 'checkbox_eyelink_force_drift_correct'},
+ {'type': 'combobox',
+ 'var': 'eyelink_pupil_size_mode',
+ 'label': 'Pupil-size mode',
+ 'tooltip': 'Determines whether pupil size is recorded as area or diameter',
+ 'name': 'combobox_eyelink_pupil_size_mode',
+ 'options': ['area', 'diameter']},
+ {'type': 'line_edit',
+ 'label': 'SMI IP address',
+ 'var': 'smi_ip',
+ 'name': 'line_edit_smi_ip',
+ 'tooltip': "The tracker's IP address"},
+ {'type': 'spinbox',
+ 'var': 'smi_send_port',
+ 'label': 'SMI send-port number',
+ 'min_val': 0,
+ 'max_val': 100000,
+ 'name': 'spinbox_smi_send_port',
+ 'tooltip': 'Port number for sending messages to the SMI tracker'},
+ {'type': 'spinbox',
+ 'var': 'smi_recv_port',
+ 'label': 'SMI receive-port number',
+ 'min_val': 0,
+ 'max_val': 100000,
+ 'name': 'spinbox_smi_recv_port',
+ 'tooltip': 'Port number for receiving messages from the SMI tracker'},
+ {'type': 'line_edit',
+ 'label': 'Tobii Glasses IPV4/IPv6 address',
+ 'var': 'tobiiglasses_address',
+ 'name': 'line_edit_tobiiglasses_address',
+ 'tooltip': 'The Tobii Pro Glasses IPv4/IPv6 address'},
+ {'type': 'spinbox',
+ 'label': 'Tobii Glasses UDP port number',
+ 'var': 'tobiiglasses_udpport',
+ 'min_val': 0,
+ 'max_val': 100000,
+ 'name': 'spinbox_tobiiglasses_udpport',
+ 'tooltip': 'Port number for the Tobii Pro Glasses 2 eye-tracker'}]
diff --git a/opensesame_plugins/pygaze/pygaze_init/pygaze_init.py b/opensesame_plugins/pygaze/pygaze_init/pygaze_init.py
new file mode 100644
index 0000000..eb3892f
--- /dev/null
+++ b/opensesame_plugins/pygaze/pygaze_init/pygaze_init.py
@@ -0,0 +1,253 @@
+#-*- coding:utf-8 -*-
+
+"""
+This file is part of PyGaze.
+
+PyGaze is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+PyGaze is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with PyGaze. If not, see .
+"""
+
+import os
+import inspect
+from openexp.canvas import Canvas
+from libopensesame.exceptions import OSException, InvalidValue
+from libopensesame.item import Item
+from libopensesame.oslogging import oslogger
+from libqtopensesame.items.qtautoplugin import QtAutoPlugin
+from pygaze.eyetracker import EyeTracker
+from pygaze.display import Display
+import pygaze
+
+
+class PygazeInit(Item):
+
+ def __init__(self, name, experiment, string=None):
+ super().__init__(name, experiment, string)
+ self.reload_pygaze()
+
+ def reset(self):
+ # Generic settings
+ self.var.tracker_type = u'Simple dummy'
+ self.var.calibrate = u'yes'
+ self.var.calbeep = u'yes'
+ self.var.sacc_vel_thr = 35
+ self.var.sacc_acc_thr = 9500
+ self.var._logfile = u'automatic'
+ # Alea-specific settings
+ self.var.alea_api_key = u'Contact Alea for an API key'
+ self.var.alea_animated_calibration = u'no'
+ # EyeLink-specific settings
+ self.var.eyelink_force_drift_correct = u'yes'
+ self.var.eyelink_pupil_size_mode = u'area'
+ # SMI-specific settings
+ self.var.smi_ip = u'127.0.0.1'
+ self.var.smi_send_port = 4444
+ self.var.smi_recv_port = 5555
+ # Tobii Pro Glasses 2 settings
+ self.var.tobiiglasses_address = u'192.168.71.50'
+ self.var.tobiiglasses_udpport = 49152
+
+ def close(self):
+ """Closes the connection with the eye tracker when the experiment is
+ finished.
+ """
+ oslogger.debug('Starting PyGaze deinitialisation')
+ self.clock.sleep(1000)
+ self.experiment.pygaze_eyetracker.close()
+ self.experiment.pygaze_eyetracker = None
+ oslogger.debug('Finished PyGaze deinitialisation')
+ self.clock.sleep(1000)
+
+ def draw_calibration_canvas(self, x, y):
+ """A hook to prepare the canvas with the clibration target."""
+ dc_canvas = Canvas(self.experiment)
+ x -= dc_canvas._xcenter
+ y -= dc_canvas._ycenter
+ dc_canvas.fixdot(x, y, style='large-open')
+ if self.var.calbeep == 'yes':
+ self.beep.play()
+ dc_canvas.show()
+
+ def reload_pygaze(self):
+ """Reloads pygaze modules to get a clean start. This is necessary,
+ because otherwise PyGaze will try to use the old experiment instance
+ when the experiment is executed twice. Explicitly reloading all
+ OpenSesame-related modules will fix this.
+ """
+ from pygaze import settings
+ settings.osexperiment = self.experiment
+ settings.DISPTYPE = u'opensesame'
+ settings.DISPSIZE = self.resolution()
+ settings.BGC = self.var.background
+ settings.FGC = self.var.foreground
+ settings.ALEAKEY = self.var.alea_api_key
+ if self.var.calbeep == u'yes':
+ settings.EYELINKCALBEEP = True
+ else:
+ settings.EYELINKCALBEEP = False
+ if self.var.alea_animated_calibration == u'yes':
+ settings.ALEAANIMATEDCALIBRATION = True
+ else:
+ settings.ALEAANIMATEDCALIBRATION = False
+
+ def run(self):
+ if hasattr(self.experiment, u'pygaze_eyetracker'):
+ raise OSException(
+ 'You should have only one instance of `pygaze_init` in your experiment')
+ self.set_item_onset()
+ # Determine the tracker type and perform certain tracker-specific
+ # operations.
+ kwdict = {}
+ if self.var.tracker_type == u'Simple dummy':
+ tracker_type = u'dumbdummy'
+ elif self.var.tracker_type == u'Advanced dummy (mouse simulation)':
+ tracker_type = u'dummy'
+ elif self.var.tracker_type == u'EyeLink':
+ tracker_type = u'eyelink'
+ kwdict[u'eyelink_force_drift_correct'] = \
+ self.var.eyelink_force_drift_correct == u'yes'
+ kwdict[u'pupil_size_mode'] = self.var.eyelink_pupil_size_mode
+ elif self.var.tracker_type == u'EyeLogic':
+ tracker_type = u'eyelogic'
+ elif self.var.tracker_type == u'SMI':
+ tracker_type = u'smi'
+ kwdict[u'ip'] = self.var.smi_ip
+ kwdict[u'sendport'] = self.var.smi_send_port
+ kwdict[u'receiveport'] = self.var.smi_recv_port
+ elif self.var.tracker_type == u'EyeTribe':
+ tracker_type = u'eyetribe'
+ elif self.var.tracker_type == u'OpenGaze':
+ tracker_type = u'opengaze'
+ elif self.var.tracker_type == u'Alea':
+ tracker_type = u'alea'
+ kwdict[u'alea_key'] = self.var.alea_api_key
+ kwdict[u'animated_calibration'] = \
+ self.var.alea_animated_calibration == u'yes'
+ elif self.var.tracker_type == u'Tobii':
+ tracker_type = u'tobii'
+ elif self.var.tracker_type == u'Tobii-legacy':
+ tracker_type = u'tobii-legacy'
+ elif self.var.tracker_type == u'Tobii Pro Glasses 2':
+ tracker_type = u'tobiiglasses'
+ kwdict[u'address'] = self.var.tobiiglasses_address
+ kwdict[u'udpport'] = self.var.tobiiglasses_udpport
+ else:
+ raise InvalidValue(
+ f'Unknown tracker type: {self.var.tracker_type}')
+ # Determine logfile
+ if self.var._logfile == u'automatic':
+ logfile = os.path.splitext(self.var.logfile)[0]
+ if tracker_type == u'eyelink':
+ # Automatically shorten filenames like 'subject-0', because
+ # these are too long. This avoids having to rename logfiles
+ # all the time.
+ basename = os.path.basename(logfile)
+ dirname = os.path.dirname(logfile)
+ if len(basename) > 8 and basename.startswith(u'subject-'):
+ basename = u'sub_' + basename[8:]
+ logfile = os.path.join(dirname, basename)
+ print(u'Attention: EyeLink logfile renamed to %s.edf' \
+ % logfile)
+ elif basename == u'defaultlog':
+ logfile = u'default'
+ print(u'Attention: EyeLink logfile renamed to %s.edf' \
+ % logfile)
+ logfile = logfile + u'.edf'
+ kwdict[u'data_file'] = logfile
+ else:
+ logfile = self.var._logfile
+ # Register the logfile with OpenSesame
+ self.experiment.data_files.append(logfile)
+ # Determine event detection. Currently, only the EyeLink has native
+ # event detection.
+ if tracker_type == u'eyelink':
+ event_detection = u'native'
+ else:
+ event_detection = u'pygaze'
+ # Initialize pygaze and the eye-tracker object
+ self.experiment.pygaze_display = Display(u'opensesame')
+ self.experiment.pygaze_eyetracker = EyeTracker(
+ self.experiment.pygaze_display,
+ trackertype=tracker_type,
+ eventdetection=event_detection,
+ saccade_velocity_threshold=self.var.sacc_vel_thr,
+ saccade_acceleration_threshold=self.var.sacc_acc_thr,
+ logfile=logfile,
+ **kwdict)
+ if self.var.calbeep == u'yes':
+ from openexp.synth import synth
+ self.beep = synth(self.experiment)
+ self.experiment.pygaze_eyetracker.set_draw_calibration_target_func(
+ self.draw_calibration_canvas)
+ self.experiment.pygaze_eyetracker.set_draw_drift_correction_target_func(
+ self.draw_calibration_canvas)
+ self.experiment.cleanup_functions.append(self.close)
+ if self.var.calibrate == u'yes':
+ self.experiment.pygaze_eyetracker.calibrate()
+ self.python_workspace[u'eyetracker'] = self.experiment.pygaze_eyetracker
+
+
+class QtPygazeInit(PygazeInit, QtAutoPlugin):
+
+ def __init__(self, name, experiment, script=None):
+ PygazeInit.__init__(self, name, experiment, script)
+ QtAutoPlugin.__init__(self, __file__)
+
+ def init_edit_widget(self):
+ super().init_edit_widget()
+ self.custom_interactions()
+ self.text_pygaze_version.setText(
+ f'PyGaze version {pygaze.version}')
+
+ def apply_edit_changes(self):
+ if not super().apply_edit_changes() or self.lock:
+ return False
+ self.custom_interactions()
+
+ def edit_widget(self):
+ if self.lock:
+ return
+ self.lock = True
+ w = super().edit_widget()
+ self.custom_interactions()
+ self.lock = False
+ return w
+
+ def custom_interactions(self):
+ """Activates the relevant controls for each tracker."""
+ alea = self.var.tracker_type == u'Alea'
+ self.line_edit_alea_api_key.setEnabled(alea)
+ self.checkbox_alea_animated_calibration.setEnabled(alea)
+ smi = self.var.tracker_type == u'SMI'
+ self.line_edit_smi_ip.setEnabled(smi)
+ self.spinbox_smi_send_port.setEnabled(smi)
+ self.spinbox_smi_recv_port.setEnabled(smi)
+ eyelink = self.var.tracker_type == u'EyeLink'
+ self.checkbox_eyelink_force_drift_correct.setEnabled(eyelink)
+ self.combobox_eyelink_pupil_size_mode.setEnabled(eyelink)
+ self.spinbox_sacc_acc_thr.setDisabled(eyelink)
+ self.spinbox_sacc_vel_thr.setDisabled(eyelink)
+ tobiiglasses = self.var.tracker_type == u'Tobii Pro Glasses 2'
+ self.line_edit_tobiiglasses_address.setEnabled(tobiiglasses)
+ self.spinbox_tobiiglasses_udpport.setEnabled(tobiiglasses)
+ if eyelink:
+ try:
+ import pylink
+ except Exception as e:
+ pylink = None
+ if pylink is None:
+ self.text_eyelink_pylink_check.show()
+ else:
+ self.text_eyelink_pylink_check.hide()
+ else:
+ self.text_eyelink_pylink_check.hide()
diff --git a/opensesame_plugins/pygaze/pygaze_log/__init__.py b/opensesame_plugins/pygaze/pygaze_log/__init__.py
new file mode 100644
index 0000000..83be897
--- /dev/null
+++ b/opensesame_plugins/pygaze/pygaze_log/__init__.py
@@ -0,0 +1,23 @@
+"""Writes information to the eye-tracker logfile"""
+
+category = 'PyGaze'
+priority = 10
+icon = 'os-pygaze_log'
+help = 'manual/eyetracking/pygaze'
+controls = [
+ {'type': 'spinbox',
+ 'var': 'throttle',
+ 'label': 'Pause between messages',
+ 'min_val': 0,
+ 'max_val': 1000,
+ 'suffix': ' ms',
+ 'tooltip': 'A pause between messages to avoid overloading the eye tracker'},
+ {'type': 'checkbox',
+ 'var': 'auto_log',
+ 'label': 'Automatically log all variables',
+ 'tooltip': 'Automatically send all experimental variables to the eye tracker'},
+ {'type': 'editor',
+ 'var': 'msg',
+ 'label': 'Log message',
+ 'syntax': False,
+ 'tooltip': 'The message to write to the eye tracker'}]
diff --git a/opensesame_plugins/pygaze/pygaze_log/pygaze_log.py b/opensesame_plugins/pygaze/pygaze_log/pygaze_log.py
new file mode 100644
index 0000000..4257c3f
--- /dev/null
+++ b/opensesame_plugins/pygaze/pygaze_log/pygaze_log.py
@@ -0,0 +1,40 @@
+#-*- coding:utf-8 -*-
+
+"""
+This file is part of PyGaze.
+
+PyGaze is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+PyGaze is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with PyGaze. If not, see .
+"""
+
+from libopensesame.item import Item
+from pygaze.display import Display
+
+
+class PygazeLog(Item):
+
+ def reset(self):
+ self.var.msg = ''
+ self.var.auto_log = 'no'
+ self.var.throttle = 2
+
+ def run(self):
+ self.set_item_onset()
+ for msg in self.var.msg.split(u'\n'):
+ self.experiment.pygaze_eyetracker.log(self.syntax.eval_text(msg))
+ self.clock.sleep(self.var.throttle)
+ if self.var.auto_log == u'yes':
+ for logvar, info in self.experiment.var.inspect().items():
+ self.experiment.pygaze_eyetracker.log_var(
+ logvar, info[u'value'])
+ self.clock.sleep(self.var.throttle)
diff --git a/opensesame_plugins/pygaze/pygaze_start_recording/__init__.py b/opensesame_plugins/pygaze/pygaze_start_recording/__init__.py
new file mode 100644
index 0000000..1805ad0
--- /dev/null
+++ b/opensesame_plugins/pygaze/pygaze_start_recording/__init__.py
@@ -0,0 +1,12 @@
+"""Puts the eye tracker out of recording mode"""
+
+category = 'PyGaze'
+priority = 10
+help = 'manual/eyetracking/pygaze'
+icon = 'os-pygaze_start_recording'
+controls = [
+ {'type': 'line_edit',
+ 'var': 'status_msg',
+ 'label': 'Status message',
+ 'tooltip': 'A text to use as status message'
+ }]
diff --git a/opensesame_plugins/pygaze/pygaze_start_recording/pygaze_start_recording.py b/opensesame_plugins/pygaze/pygaze_start_recording/pygaze_start_recording.py
new file mode 100644
index 0000000..f454664
--- /dev/null
+++ b/opensesame_plugins/pygaze/pygaze_start_recording/pygaze_start_recording.py
@@ -0,0 +1,33 @@
+#-*- coding:utf-8 -*-
+
+"""
+This file is part of PyGaze.
+
+PyGaze is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+PyGaze is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with PyGaze. If not, see .
+"""
+
+from libopensesame.item import Item
+from pygaze.display import Display
+
+
+class PygazeStartRecording(Item):
+
+ def reset(self):
+ self.var.status_msg = 'start_trial'
+
+ def run(self):
+ self.set_item_onset()
+ self.experiment.pygaze_eyetracker.start_recording()
+ self.experiment.pygaze_eyetracker.status_msg(self.var.status_msg)
+ self.experiment.pygaze_eyetracker.log(self.var.status_msg)
diff --git a/opensesame_plugins/pygaze/pygaze_stop_recording/__init__.py b/opensesame_plugins/pygaze/pygaze_stop_recording/__init__.py
new file mode 100644
index 0000000..a1a0183
--- /dev/null
+++ b/opensesame_plugins/pygaze/pygaze_stop_recording/__init__.py
@@ -0,0 +1,10 @@
+category = 'PyGaze'
+priority = 10
+help = 'manual/eyetracking/pygaze'
+icon = 'os-pygaze_stop_recording'
+controls = [
+ {'type': 'line_edit',
+ 'var': 'status_msg',
+ 'label': 'Status message',
+ 'tooltip': 'A text to use as status message'
+ }]
diff --git a/opensesame_plugins/pygaze/pygaze_stop_recording/pygaze_stop_recording.py b/opensesame_plugins/pygaze/pygaze_stop_recording/pygaze_stop_recording.py
new file mode 100644
index 0000000..c41dac4
--- /dev/null
+++ b/opensesame_plugins/pygaze/pygaze_stop_recording/pygaze_stop_recording.py
@@ -0,0 +1,33 @@
+#-*- coding:utf-8 -*-
+
+"""
+This file is part of PyGaze.
+
+PyGaze is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+PyGaze is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with PyGaze. If not, see .
+"""
+
+from libopensesame.item import Item
+from pygaze.display import Display
+
+
+class PygazeStopRecording(Item):
+
+ def reset(self):
+ self.var.status_msg = 'stop_trial'
+
+ def run(self):
+ self.set_item_onset()
+ self.experiment.pygaze_eyetracker.status_msg(self.var.status_msg)
+ self.experiment.pygaze_eyetracker.log(self.var.status_msg)
+ self.experiment.pygaze_eyetracker.stop_recording()
diff --git a/opensesame_plugins/pygaze/pygaze_wait/__init__.py b/opensesame_plugins/pygaze/pygaze_wait/__init__.py
new file mode 100644
index 0000000..baca00b
--- /dev/null
+++ b/opensesame_plugins/pygaze/pygaze_wait/__init__.py
@@ -0,0 +1,20 @@
+category = 'PyGaze'
+priority = 10
+help = 'manual/eyetracking/pygaze'
+icon = 'os-pygaze_wait'
+controls = [
+ {
+ 'type': 'combobox',
+ 'var': 'event',
+ 'label': 'Event',
+ 'options': [
+ 'Saccade start',
+ 'Saccade end',
+ 'Fixation start',
+ 'Fixation end',
+ 'Blink start',
+ 'Blink end'
+ ],
+ 'tooltip': 'An eye-tracker event to wait for'
+ }
+]
diff --git a/opensesame_plugins/pygaze/pygaze_wait/pygaze_wait.py b/opensesame_plugins/pygaze/pygaze_wait/pygaze_wait.py
new file mode 100644
index 0000000..adf27cd
--- /dev/null
+++ b/opensesame_plugins/pygaze/pygaze_wait/pygaze_wait.py
@@ -0,0 +1,55 @@
+#-*- coding:utf-8 -*-
+
+"""
+This file is part of PyGaze.
+
+PyGaze is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+PyGaze is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with PyGaze. If not, see .
+"""
+
+from libopensesame.item import Item
+from libopensesame.exceptions import InvalidValue
+from pygaze.display import Display
+
+
+class PygazeWait(Item):
+
+ def reset(self):
+ self.var.event = 'Saccade start'
+
+ def prepare(self):
+ super().prepare()
+ if self.var.event == u'Saccade start':
+ self.wait_func = self.experiment.pygaze_eyetracker. \
+ wait_for_saccade_start
+ elif self.var.event == u'Saccade end':
+ self.wait_func = self.experiment.pygaze_eyetracker. \
+ wait_for_saccade_end
+ elif self.var.event == u'Fixation start':
+ self.wait_func = self.experiment.pygaze_eyetracker. \
+ wait_for_fixation_start
+ elif self.var.event == u'Fixation end':
+ self.wait_func = self.experiment.pygaze_eyetracker. \
+ wait_for_fixation_end
+ elif self.var.event == u'Blink start':
+ self.wait_func = self.experiment.pygaze_eyetracker. \
+ wait_for_blink_start
+ elif self.var.event == u'Blink end':
+ self.wait_func = self.experiment.pygaze_eyetracker. \
+ wait_for_blink_start
+ else:
+ raise InvalidValue(f'Unknown event: {self.var.event}')
+
+ def run(self):
+ self.wait_func()
+ self.set_item_onset()
diff --git a/opensesame_plugins/pygaze_drift_correct/info.yaml b/opensesame_plugins/pygaze_drift_correct/info.yaml
deleted file mode 100644
index 237eb7d..0000000
--- a/opensesame_plugins/pygaze_drift_correct/info.yaml
+++ /dev/null
@@ -1,39 +0,0 @@
-category: PyGaze
-priority: 10
-help: manual/eyetracking/pygaze
-icon: os-pygaze_drift_correct
-controls:
- - type: line_edit
- var: xpos
- label: X position
- tooltip: X coordinate for drift correction
- - type: line_edit
- var: ypos
- label: Y position
- tooltip: Y position for drift correction
- - type: line_edit
- var: target_color
- label: Target color
- tooltip: Color for the drift-correction target
- name: line_edit_target_color
- - type: combobox
- var: target_style
- label: 'Target style (OpenSesame >= 2.8.0)'
- options:
- - default
- - large-filled
- - small-filled
- - large-open
- - small-open
- - large-cross
- - small-cross
- tooltip: Style for the drift-correction target
- name: combobox_target_style
- - type: checkbox
- var: draw_target
- label: Show display with drift-correction target
- tooltip: Indicates whether a drift-correction display should be shown
- - type: checkbox
- var: fixation_triggered
- label: Fixation triggered (no spacebar press required)
- tooltip: Indicates whether drift correction should be performed as soon as a stable fixation is detected
diff --git a/opensesame_plugins/pygaze_drift_correct/pygaze_drift_correct.py b/opensesame_plugins/pygaze_drift_correct/pygaze_drift_correct.py
deleted file mode 100644
index e14e039..0000000
--- a/opensesame_plugins/pygaze_drift_correct/pygaze_drift_correct.py
+++ /dev/null
@@ -1,138 +0,0 @@
-#-*- coding:utf-8 -*-
-
-"""
-This file is part of PyGaze.
-
-PyGaze is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-PyGaze is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with PyGaze. If not, see .
-"""
-
-import inspect
-from openexp.canvas import canvas
-from libopensesame.item import item
-from libqtopensesame.items.qtautoplugin import qtautoplugin
-from pygaze.display import Display
-
-class pygaze_drift_correct(item):
-
- """Plug-in runtime definition."""
-
- description = u'Perform eye-tracker drift correction'
-
- def reset(self):
-
- """
- desc:
- Resets plug-in settings.
- """
-
- self.var.xpos = 0
- self.var.ypos = 0
- self.var.fixation_triggered = u'no'
- self.var.target_color = u'[foreground]'
- self.var.target_style = u'default'
- self.var.draw_target = u'yes'
-
- def prepare_drift_correction_canvas(self):
-
- """A hook to prepare the canvas with the drift-correction target."""
-
- if self.var.draw_target == u'yes':
- self.dc_canvas = canvas(self.experiment)
- self.dc_canvas.fixdot(self.var.xpos, self.var.ypos,
- color=self.var.target_color, style=self.var.target_style)
- else:
- self.dc_canvas = None
-
- def draw_drift_correction_canvas(self, x, y):
-
- """
- A hook to show the canvas with the drift-correction target.
-
- Arguments:
- x -- The X coordinate (unused).
- y -- The Y coordinate (unused).
- """
-
- if self.dc_canvas is not None:
- self.dc_canvas.show()
-
- def prepare(self):
-
- """The preparation phase of the plug-in goes here."""
-
- item.prepare(self)
- self.prepare_drift_correction_canvas()
- self.experiment.pygaze_eyetracker.set_draw_drift_correction_target_func(
- self.draw_drift_correction_canvas)
-
- def run(self):
-
- """The run phase of the plug-in goes here."""
-
- self.set_item_onset()
- if self.var.uniform_coordinates == u'yes':
- xpos = self.var.width / 2 + self.var.xpos
- ypos = self.var.height / 2 + self.var.ypos
- else:
- xpos = self.var.xpos
- ypos = self.var.ypos
- while True:
- success = self.experiment.pygaze_eyetracker.drift_correction(
- pos=(xpos, ypos),
- fix_triggered=self.var.fixation_triggered==u'yes')
- if success:
- break
-
-class qtpygaze_drift_correct(pygaze_drift_correct, qtautoplugin):
-
- """Plug-in GUI definition."""
-
- def __init__(self, name, experiment, script=None):
-
- """
- Constructor.
-
- Arguments:
- name -- The name of the plug-in.
- experiment -- The experiment object.
-
- Keyword arguments:
- script -- A definition script. (default=None)
- """
-
- pygaze_drift_correct.__init__(self, name, experiment, script)
- qtautoplugin.__init__(self, __file__)
-
- def init_edit_widget(self):
-
- qtautoplugin.init_edit_widget(self)
- self.custom_interactions()
-
- def apply_edit_changes(self):
-
- """Apply the controls"""
-
- if not qtautoplugin.apply_edit_changes(self) or self.lock:
- return False
- self.custom_interactions()
-
- def custom_interactions(self):
-
- """
- Disables the target-style combobox if no target display should be drawn.
- """
-
- draw_target = self.var.draw_target == u'yes'
- self.combobox_target_style.setEnabled(draw_target)
- self.line_edit_target_color.setEnabled(draw_target)
diff --git a/opensesame_plugins/pygaze_init/info.yaml b/opensesame_plugins/pygaze_init/info.yaml
deleted file mode 100644
index e16f963..0000000
--- a/opensesame_plugins/pygaze_init/info.yaml
+++ /dev/null
@@ -1,111 +0,0 @@
-category: PyGaze
-priority: 10
-help: manual/eyetracking/pygaze
-icon: os-pygaze_init
-controls:
- - type: combobox
- var: tracker_type
- label: Select tracker type
- options:
- - Simple dummy
- - Advanced dummy (mouse simulation)
- - EyeLink
- - EyeLogic
- - SMI
- - EyeTribe
- - OpenGaze
- - Alea
- - Tobii
- - Tobii-legacy
- - Tobii Pro Glasses 2
- tooltip: A list of supported eye trackers
- - type: checkbox
- var: calibrate
- label: Calibrate tracker
- tooltip: Indicates whether calibration should be started
- - type: checkbox
- var: calbeep
- label: Calibration beep
- tooltip: Play a beep when the calibration target jumps
- name: checkbox_calbeep
- - type: line_edit
- label: Log file
- var: _logfile
- tooltip: The name for the log file
- - type: spinbox
- var: sacc_vel_thr
- label: Saccade velocity threshold
- min_val: 0
- max_val: 100000
- suffix: ' °/s'
- tooltip: Velocity threshold for saccade detection algorithm
- name: spinbox_sacc_vel_thr
- - type: spinbox
- var: sacc_acc_thr
- label: Saccade acceleration threshold
- min_val: 0
- max_val: 100000
- suffix: ' °/s/s'
- tooltip: Acceleration threshold for saccade detection algorithm
- name: spinbox_sacc_acc_thr
- - type: text
- label: 'Warning: PyLink is required for EyeLink functionality and is not installed. Visit http://osdoc.cogsci.nl/manual/eyetracking/eyelink/ for more information.'
- name: text_eyelink_pylink_check
- - type: text
- label: DUMMY
- name: text_pygaze_version
- - type: line_edit
- label: Alea API key
- var: alea_api_key
- name: line_edit_alea_api_key
- tooltip: "The API key provided to you by Alea"
- - type: checkbox
- var: alea_animated_calibration
- label: Animated calibration target
- tooltip: Turn on child-friendly animated calibration targets
- name: checkbox_alea_animated_calibration
- - type: checkbox
- var: eyelink_force_drift_correct
- label: Force drift correction (for EyeLink 1000)
- tooltip: Turn on active drift correction
- name: checkbox_eyelink_force_drift_correct
- - type: combobox
- var: eyelink_pupil_size_mode
- label: Pupil-size mode
- tooltip: Determines whether pupil size is recorded as area or diameter
- name: combobox_eyelink_pupil_size_mode
- options:
- - area
- - diameter
- - type: line_edit
- label: SMI IP address
- var: smi_ip
- name: line_edit_smi_ip
- tooltip: "The tracker's IP address"
- - type: spinbox
- var: smi_send_port
- label: SMI send-port number
- min_val: 0
- max_val: 100000
- name: spinbox_smi_send_port
- tooltip: Port number for sending messages to the SMI tracker
- - type: spinbox
- var: smi_recv_port
- label: SMI receive-port number
- min_val: 0
- max_val: 100000
- name: spinbox_smi_recv_port
- tooltip: Port number for receiving messages from the SMI tracker
- - type: line_edit
- label: Tobii Glasses IPV4/IPv6 address
- var: tobiiglasses_address
- name: line_edit_tobiiglasses_address
- tooltip: "The Tobii Pro Glasses IPv4/IPv6 address"
- - type: spinbox
- label: Tobii Glasses UDP port number
- var: tobiiglasses_udpport
- min_val: 0
- max_val: 100000
- name: spinbox_tobiiglasses_udpport
- tooltip: "Port number for the Tobii Pro Glasses 2 eye-tracker"
-
diff --git a/opensesame_plugins/pygaze_init/pygaze_init.py b/opensesame_plugins/pygaze_init/pygaze_init.py
deleted file mode 100644
index a5620c8..0000000
--- a/opensesame_plugins/pygaze_init/pygaze_init.py
+++ /dev/null
@@ -1,334 +0,0 @@
-#-*- coding:utf-8 -*-
-
-"""
-This file is part of PyGaze.
-
-PyGaze is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-PyGaze is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with PyGaze. If not, see .
-"""
-
-import os
-import inspect
-from openexp.canvas import canvas
-from libopensesame import debug
-from libopensesame.exceptions import osexception
-from libopensesame.item import item
-from libqtopensesame.items.qtautoplugin import qtautoplugin
-from pygaze.eyetracker import EyeTracker
-from pygaze.display import Display
-import pygaze
-
-class pygaze_init(item):
-
- """
- desc:
- Plug-in runtime definition.
- """
-
- description = u'Initialize and calibrate eye tracker'
-
- def __init__(self, name, experiment, string=None):
-
- item.__init__(self, name, experiment, string)
- self.reload_pygaze()
-
- def reset(self):
-
- """
- desc:
- Resets plug-in settings.
- """
-
- # Generic settings
- self.var.tracker_type = u'Simple dummy'
- self.var.calibrate = u'yes'
- self.var.calbeep = u'yes'
- self.var.sacc_vel_thr = 35
- self.var.sacc_acc_thr = 9500
- self.var._logfile = u'automatic'
- # Alea-specific settings
- self.var.alea_api_key = u'Contact Alea for an API key'
- self.var.alea_animated_calibration = u'no'
- # EyeLink-specific settings
- self.var.eyelink_force_drift_correct = u'yes'
- self.var.eyelink_pupil_size_mode = u'area'
- # SMI-specific settings
- self.var.smi_ip = u'127.0.0.1'
- self.var.smi_send_port = 4444
- self.var.smi_recv_port = 5555
- # Tobii Pro Glasses 2 settings
- self.var.tobiiglasses_address = u'192.168.71.50'
- self.var.tobiiglasses_udpport = 49152
-
- def close(self):
-
- """
- desc:
- Closes the connection with the eye tracker when the experiment is
- finished.
- """
-
- debug.msg(u'Starting PyGaze deinitialisation')
- self.clock.sleep(1000)
- self.experiment.pygaze_eyetracker.close()
- self.experiment.pygaze_eyetracker = None
- debug.msg(u'Finished PyGaze deinitialisation')
- self.clock.sleep(1000)
-
- def draw_calibration_canvas(self, x, y):
-
- """
- desc:
- A hook to prepare the canvas with the clibration target.
-
- arguments:
- x:
- desc: The X coordinate.
- type: int
- y:
- desc: The Y coordinate.
- type: int
- """
-
- dc_canvas = canvas(self.experiment)
- # Coordinates are always sent in 0,0=top-left mode, so we need to
- # correct for this if we're using uniform coordinates.
- if self.var.uniform_coordinates == u'yes':
- x -= dc_canvas._xcenter
- y -= dc_canvas._ycenter
- dc_canvas.fixdot(x, y, style=u'large-open')
- if self.var.calbeep == 'yes':
- self.beep.play()
- dc_canvas.show()
-
- def reload_pygaze(self):
-
- """
- desc:
- Reloads pygaze modules to get a clean start. This is necessary,
- because otherwise PyGaze will try to use the old experiment instance
- when the experiment is executed twice. Explicitly reloading all
- OpenSesame-related modules will fix this.
- """
-
- from pygaze import settings
- settings.osexperiment = self.experiment
- settings.DISPTYPE = u'opensesame'
- settings.DISPSIZE = self.resolution()
- settings.BGC = self.var.background
- settings.FGC = self.var.foreground
- settings.ALEAKEY = self.var.alea_api_key
-
- if self.var.calbeep == u'yes':
- settings.EYELINKCALBEEP = True
- else:
- settings.EYELINKCALBEEP = False
-
- if self.var.alea_animated_calibration == u'yes':
- settings.ALEAANIMATEDCALIBRATION = True
- else:
- settings.ALEAANIMATEDCALIBRATION = False
-
- def run(self):
-
- """
- desc:
- The run phase of the plug-in goes here.
- """
-
- if hasattr(self.experiment, u'pygaze_eyetracker'):
- raise osexception(
- u'You should have only one instance of `pygaze_init` in your experiment')
- self.set_item_onset()
- # Determine the tracker type and perform certain tracker-specific
- # operations.
- kwdict = {}
- if self.var.tracker_type == u'Simple dummy':
- tracker_type = u'dumbdummy'
- elif self.var.tracker_type == u'Advanced dummy (mouse simulation)':
- tracker_type = u'dummy'
- elif self.var.tracker_type == u'EyeLink':
- tracker_type = u'eyelink'
- kwdict[u'eyelink_force_drift_correct'] = \
- self.var.eyelink_force_drift_correct == u'yes'
- kwdict[u'pupil_size_mode'] = self.var.eyelink_pupil_size_mode
- elif self.var.tracker_type == u'EyeLogic':
- tracker_type = u'eyelogic'
- elif self.var.tracker_type == u'SMI':
- tracker_type = u'smi'
- kwdict[u'ip'] = self.var.smi_ip
- kwdict[u'sendport'] = self.var.smi_send_port
- kwdict[u'receiveport'] = self.var.smi_recv_port
- elif self.var.tracker_type == u'EyeTribe':
- tracker_type = u'eyetribe'
- elif self.var.tracker_type == u'OpenGaze':
- tracker_type = u'opengaze'
- elif self.var.tracker_type == u'Alea':
- tracker_type = u'alea'
- kwdict[u'alea_key'] = self.var.alea_api_key
- kwdict[u'animated_calibration'] = \
- self.var.alea_animated_calibration == u'yes'
- elif self.var.tracker_type == u'Tobii':
- tracker_type = u'tobii'
- elif self.var.tracker_type == u'Tobii-legacy':
- tracker_type = u'tobii-legacy'
- elif self.var.tracker_type == u'Tobii Pro Glasses 2':
- tracker_type = u'tobiiglasses'
- kwdict[u'address'] = self.var.tobiiglasses_address
- kwdict[u'udpport'] = self.var.tobiiglasses_udpport
- else:
- raise osexception(
- u'Unknown tracker type: %s' % self.var.tracker_type)
- # Determine logfile
- if self.var._logfile == u'automatic':
- logfile = os.path.splitext(self.var.logfile)[0]
- if tracker_type == u'eyelink':
- # Automatically shorten filenames like 'subject-0', because
- # these are too long. This avoids having to rename logfiles
- # all the time.
- basename = os.path.basename(logfile)
- dirname = os.path.dirname(logfile)
- if len(basename) > 8 and basename.startswith(u'subject-'):
- basename = u'sub_' + basename[8:]
- logfile = os.path.join(dirname, basename)
- print(u'Attention: EyeLink logfile renamed to %s.edf' \
- % logfile)
- elif basename == u'defaultlog':
- logfile = u'default'
- print(u'Attention: EyeLink logfile renamed to %s.edf' \
- % logfile)
- logfile = logfile + u'.edf'
- kwdict[u'data_file'] = logfile
- else:
- logfile = self.var._logfile
- # Register the logfile with OpenSesame
- self.experiment.data_files.append(logfile)
- # Determine event detection. Currently, only the EyeLink has native
- # event detection.
- if tracker_type == u'eyelink':
- event_detection = u'native'
- else:
- event_detection = u'pygaze'
- # Initialize pygaze and the eye-tracker object
- self.experiment.pygaze_display = Display(u'opensesame')
- self.experiment.pygaze_eyetracker = EyeTracker(
- self.experiment.pygaze_display,
- trackertype=tracker_type,
- eventdetection=event_detection,
- saccade_velocity_threshold=self.var.sacc_vel_thr,
- saccade_acceleration_threshold=self.var.sacc_acc_thr,
- logfile=logfile,
- **kwdict)
- if self.var.calbeep == u'yes':
- from openexp.synth import synth
- self.beep = synth(self.experiment)
- self.experiment.pygaze_eyetracker.set_draw_calibration_target_func(
- self.draw_calibration_canvas)
- self.experiment.pygaze_eyetracker.set_draw_drift_correction_target_func(
- self.draw_calibration_canvas)
- self.experiment.cleanup_functions.append(self.close)
- if self.var.calibrate == u'yes':
- self.experiment.pygaze_eyetracker.calibrate()
- self.python_workspace[u'eyetracker'] = self.experiment.pygaze_eyetracker
-
-class qtpygaze_init(pygaze_init, qtautoplugin):
-
- """
- desc:
- Plug-in GUI definition.
- """
-
- def __init__(self, name, experiment, script=None):
-
- """
- Constructor.
-
- Arguments:
- name -- The name of the plug-in.
- experiment -- The experiment object.
-
- Keyword arguments:
- script -- A definition script. (default=None)
- """
-
- pygaze_init.__init__(self, name, experiment, script)
- qtautoplugin.__init__(self, __file__)
-
- def init_edit_widget(self):
-
- qtautoplugin.init_edit_widget(self)
- self.custom_interactions()
- self.text_pygaze_version.setText(
- u'PyGaze version %s' % pygaze.version)
-
- def apply_edit_changes(self):
-
- """
- desc:
- Applies the controls.
- """
-
- if not qtautoplugin.apply_edit_changes(self) or self.lock:
- return False
- self.custom_interactions()
-
- def edit_widget(self):
-
- """
- Refreshes the controls.
-
- Returns:
- The QWidget containing the controls
- """
-
- if self.lock:
- return
- self.lock = True
- w = qtautoplugin.edit_widget(self)
- self.custom_interactions()
- self.lock = False
- return w
-
- def custom_interactions(self):
-
- """
- desc:
- Activates the relevant controls for each tracker.
- """
-
- alea = self.var.tracker_type == u'Alea'
- self.line_edit_alea_api_key.setEnabled(alea)
- self.checkbox_alea_animated_calibration.setEnabled(alea)
- smi = self.var.tracker_type == u'SMI'
- self.line_edit_smi_ip.setEnabled(smi)
- self.spinbox_smi_send_port.setEnabled(smi)
- self.spinbox_smi_recv_port.setEnabled(smi)
- eyelink = self.var.tracker_type == u'EyeLink'
- self.checkbox_eyelink_force_drift_correct.setEnabled(eyelink)
- self.combobox_eyelink_pupil_size_mode.setEnabled(eyelink)
- self.spinbox_sacc_acc_thr.setDisabled(eyelink)
- self.spinbox_sacc_vel_thr.setDisabled(eyelink)
- tobiiglasses = self.var.tracker_type == u'Tobii Pro Glasses 2'
- self.line_edit_tobiiglasses_address.setEnabled(tobiiglasses)
- self.spinbox_tobiiglasses_udpport.setEnabled(tobiiglasses)
- if eyelink:
- try:
- import pylink
- except:
- pylink = None
- if pylink == None:
- self.text_eyelink_pylink_check.show()
- else:
- self.text_eyelink_pylink_check.hide()
- else:
- self.text_eyelink_pylink_check.hide()
diff --git a/opensesame_plugins/pygaze_log/info.yaml b/opensesame_plugins/pygaze_log/info.yaml
deleted file mode 100644
index a1ae487..0000000
--- a/opensesame_plugins/pygaze_log/info.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-category: PyGaze
-priority: 10
-icon: os-pygaze_log
-help: manual/eyetracking/pygaze
-controls:
- - type: spinbox
- var: throttle
- label: Pause between messages
- min_val: 0
- max_val: 1000
- suffix: ' ms'
- tooltip: A pause between messages to avoid overloading the eye tracker
- - type: checkbox
- var: auto_log
- label: Automatically log all variables
- tooltip: Automatically send all experimental variables to the eye tracker
- - type: editor
- var: msg
- label: Log message
- syntax: false
- tooltip: The message to write to the eye tracker
diff --git a/opensesame_plugins/pygaze_log/pygaze_log.py b/opensesame_plugins/pygaze_log/pygaze_log.py
deleted file mode 100644
index ee02c6f..0000000
--- a/opensesame_plugins/pygaze_log/pygaze_log.py
+++ /dev/null
@@ -1,60 +0,0 @@
-#-*- coding:utf-8 -*-
-
-"""
-This file is part of PyGaze.
-
-PyGaze is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-PyGaze is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with PyGaze. If not, see .
-"""
-
-from libopensesame.item import item
-from libqtopensesame.items.qtautoplugin import qtautoplugin
-from pygaze.display import Display
-
-class pygaze_log(item):
-
- """Plug-in runtime definition."""
-
- description = u'Writes information to the eye-tracker logfile'
-
- def reset(self):
-
- """
- desc:
- Resets plug-in settings.
- """
-
- self.var.msg = u''
- self.var.auto_log = u'no'
- self.var.throttle = 2
-
- def run(self):
-
- """The run phase of the plug-in goes here."""
-
- self.set_item_onset()
- for msg in self.var.msg.split(u'\n'):
- self.experiment.pygaze_eyetracker.log(self.syntax.eval_text(msg))
- self.clock.sleep(self.var.throttle)
- if self.var.auto_log == u'yes':
- for logvar, info in self.experiment.var.inspect().items():
- self.experiment.pygaze_eyetracker.log_var(logvar,
- info[u'value'])
- self.clock.sleep(self.var.throttle)
-
-class qtpygaze_log(pygaze_log, qtautoplugin):
-
- def __init__(self, name, experiment, script=None):
-
- pygaze_log.__init__(self, name, experiment, script)
- qtautoplugin.__init__(self, __file__)
diff --git a/opensesame_plugins/pygaze_start_recording/info.yaml b/opensesame_plugins/pygaze_start_recording/info.yaml
deleted file mode 100644
index 92073b3..0000000
--- a/opensesame_plugins/pygaze_start_recording/info.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-category: PyGaze
-priority: 10
-help: manual/eyetracking/pygaze
-icon: os-pygaze_start_recording
-controls:
- - type: line_edit
- var: status_msg
- label: Status message
- tooltip: A text to use as status message
diff --git a/opensesame_plugins/pygaze_start_recording/pygaze_start_recording.py b/opensesame_plugins/pygaze_start_recording/pygaze_start_recording.py
deleted file mode 100644
index 5b23992..0000000
--- a/opensesame_plugins/pygaze_start_recording/pygaze_start_recording.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#-*- coding:utf-8 -*-
-
-"""
-This file is part of PyGaze.
-
-PyGaze is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-PyGaze is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with PyGaze. If not, see .
-"""
-
-from libopensesame.item import item
-from libqtopensesame.items.qtautoplugin import qtautoplugin
-from pygaze.display import Display
-
-class pygaze_start_recording(item):
-
- """Plug-in runtime definition."""
-
- description = u'Puts the eye tracker into recording mode'
-
- def reset(self):
-
- """
- desc:
- Resets plug-in settings.
- """
-
- self.var.status_msg = u'start_trial'
-
- def run(self):
-
- """The run phase of the plug-in goes here."""
-
- self.set_item_onset()
- self.experiment.pygaze_eyetracker.start_recording()
- self.experiment.pygaze_eyetracker.status_msg(self.var.status_msg)
- self.experiment.pygaze_eyetracker.log(self.var.status_msg)
-
-class qtpygaze_start_recording(pygaze_start_recording, qtautoplugin):
-
- def __init__(self, name, experiment, script=None):
-
- pygaze_start_recording.__init__(self, name, experiment, script)
- qtautoplugin.__init__(self, __file__)
diff --git a/opensesame_plugins/pygaze_stop_recording/info.yaml b/opensesame_plugins/pygaze_stop_recording/info.yaml
deleted file mode 100644
index f19eb27..0000000
--- a/opensesame_plugins/pygaze_stop_recording/info.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-category: PyGaze
-priority: 10
-help: manual/eyetracking/pygaze
-icon: os-pygaze_stop_recording
-controls:
- - type: line_edit
- var: status_msg
- label: Status message
- tooltip: A text to use as status message
diff --git a/opensesame_plugins/pygaze_stop_recording/pygaze_stop_recording.py b/opensesame_plugins/pygaze_stop_recording/pygaze_stop_recording.py
deleted file mode 100644
index 32d2ec7..0000000
--- a/opensesame_plugins/pygaze_stop_recording/pygaze_stop_recording.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#-*- coding:utf-8 -*-
-
-"""
-This file is part of PyGaze.
-
-PyGaze is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-PyGaze is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with PyGaze. If not, see .
-"""
-
-from libopensesame.item import item
-from libqtopensesame.items.qtautoplugin import qtautoplugin
-from pygaze.display import Display
-
-class pygaze_stop_recording(item):
-
- """Plug-in runtime definition."""
-
- description = u'Stops recording of eye tracking data'
-
- def reset(self):
-
- """
- desc:
- Resets plug-in settings.
- """
-
- self.var.status_msg = u'stop_trial'
-
- def prepare(self):
-
- """The preparation phase of the plug-in goes here."""
-
- item.prepare(self)
-
- def run(self):
-
- """The run phase of the plug-in goes here."""
-
- self.set_item_onset()
- self.experiment.pygaze_eyetracker.status_msg(self.var.status_msg)
- self.experiment.pygaze_eyetracker.log(self.var.status_msg)
- self.experiment.pygaze_eyetracker.stop_recording()
-
-class qtpygaze_stop_recording(pygaze_stop_recording, qtautoplugin):
-
- def __init__(self, name, experiment, script=None):
-
- pygaze_stop_recording.__init__(self, name, experiment, script)
- qtautoplugin.__init__(self, __file__)
diff --git a/opensesame_plugins/pygaze_wait/info.yaml b/opensesame_plugins/pygaze_wait/info.yaml
deleted file mode 100644
index bc8db80..0000000
--- a/opensesame_plugins/pygaze_wait/info.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-category: PyGaze
-priority: 10
-help: manual/eyetracking/pygaze
-icon: os-pygaze_wait
-controls:
- - type: combobox
- var: event
- label: Event
- options:
- - Saccade start
- - Saccade end
- - Fixation start
- - Fixation end
- - Blink start
- - Blink end
- tooltip: An eye-tracker event to wait for
diff --git a/opensesame_plugins/pygaze_wait/pygaze_wait.py b/opensesame_plugins/pygaze_wait/pygaze_wait.py
deleted file mode 100644
index b31602d..0000000
--- a/opensesame_plugins/pygaze_wait/pygaze_wait.py
+++ /dev/null
@@ -1,78 +0,0 @@
-#-*- coding:utf-8 -*-
-
-"""
-This file is part of PyGaze.
-
-PyGaze is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-PyGaze is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with PyGaze. If not, see .
-"""
-
-from libopensesame.item import item
-from libopensesame.exceptions import osexception
-from libqtopensesame.items.qtautoplugin import qtautoplugin
-from pygaze.display import Display
-
-class pygaze_wait(item):
-
- """Plug-in runtime definition."""
-
- description = u'Waits for an eye-tracker event'
-
- def reset(self):
-
- """
- desc:
- Resets plug-in settings.
- """
-
- self.var.event = u'Saccade start'
-
- def prepare(self):
-
- """The preparation phase of the plug-in goes here."""
-
- item.prepare(self)
- if self.var.event == u'Saccade start':
- self.wait_func = self.experiment.pygaze_eyetracker. \
- wait_for_saccade_start
- elif self.var.event == u'Saccade end':
- self.wait_func = self.experiment.pygaze_eyetracker. \
- wait_for_saccade_end
- elif self.var.event == u'Fixation start':
- self.wait_func = self.experiment.pygaze_eyetracker. \
- wait_for_fixation_start
- elif self.var.event == u'Fixation end':
- self.wait_func = self.experiment.pygaze_eyetracker. \
- wait_for_fixation_end
- elif self.var.event == u'Blink start':
- self.wait_func = self.experiment.pygaze_eyetracker. \
- wait_for_blink_start
- elif self.var.event == u'Blink end':
- self.wait_func = self.experiment.pygaze_eyetracker. \
- wait_for_blink_start
- else:
- raise osexception(u'Unknown event: %s' % self.var.event)
-
- def run(self):
-
- """The run phase of the plug-in goes here."""
-
- self.wait_func()
- self.set_item_onset()
-
-class qtpygaze_wait(pygaze_wait, qtautoplugin):
-
- def __init__(self, name, experiment, script=None):
-
- pygaze_wait.__init__(self, name, experiment, script)
- qtautoplugin.__init__(self, __file__)
diff --git a/pygaze/__init__.py b/pygaze/__init__.py
index 6691408..84f5ff1 100644
--- a/pygaze/__init__.py
+++ b/pygaze/__init__.py
@@ -25,7 +25,7 @@
import sys
import os
-__version__ = version = "0.7.6"
+__version__ = version = "0.8.7"
strict_version = StrictVersion(__version__)
# The version without the prerelease (if any): e.g. 3.0.0
main_version = ".".join([str(i) for i in strict_version.version])
diff --git a/pygaze/_mouse/osmouse.py b/pygaze/_mouse/osmouse.py
index 182d7dc..71457c7 100644
--- a/pygaze/_mouse/osmouse.py
+++ b/pygaze/_mouse/osmouse.py
@@ -53,8 +53,6 @@ def __init__(self, mousebuttonlist=settings.MOUSEBUTTONLIST,
pass
self.experiment = settings.osexperiment
- self.uniform_coordinates = \
- self.experiment.var.uniform_coordinates == "yes"
self.mouse = mouse(self.experiment, buttonlist=mousebuttonlist,
timeout=timeout)
@@ -62,7 +60,7 @@ def _from_pos(self, pos):
"""Convert OpenSesame coordinates to PyGaze coordinates."""
- if pos is None or not self.uniform_coordinates:
+ if pos is None:
return pos
return pos[0]+self.mouse._xcenter, pos[1]+self.mouse._ycenter
@@ -70,7 +68,7 @@ def _to_pos(self, pos):
"""Convert PyGaze coordinates to OpenSesame coordinates."""
- if pos is None or not self.uniform_coordinates:
+ if pos is None:
return pos
return pos[0]-self.mouse._xcenter, pos[1]-self.mouse._ycenter
diff --git a/pygaze/_screen/osscreen.py b/pygaze/_screen/osscreen.py
index d71269b..fa6a247 100644
--- a/pygaze/_screen/osscreen.py
+++ b/pygaze/_screen/osscreen.py
@@ -52,8 +52,6 @@ def __init__(self, screen=None, **args):
pass
self.experiment = settings.osexperiment
- self.uniform_coordinates = \
- self.experiment.var.uniform_coordinates == "yes"
self.create(screen=screen)
def _pos(self, pos):
@@ -63,9 +61,8 @@ def _pos(self, pos):
if pos in (None, (None, None)):
return None, None
x, y = pos
- if self.uniform_coordinates:
- x -= self.canvas._xcenter
- y -= self.canvas._ycenter
+ x -= self.canvas._xcenter
+ y -= self.canvas._ycenter
return x, y
def create(self, screen=None):
diff --git a/pygaze/_time/ostime.py b/pygaze/_time/ostime.py
index 76945f4..b19acbd 100644
--- a/pygaze/_time/ostime.py
+++ b/pygaze/_time/ostime.py
@@ -63,18 +63,18 @@ def get_time(self):
# see pygaze._time.basetime.BaseTime
- return settings.osexperiment.time()
+ return settings.osexperiment.clock.time()
def pause(self, pausetime):
# see pygaze._time.basetime.BaseTime
- return settings.osexperiment.sleep(pausetime)
+ return settings.osexperiment.clock.sleep(pausetime)
def expend(self):
# see pygaze._time.basetime.BaseTime
- return settings.osexperiment.time()
+ return settings.osexperiment.clock.time()
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..2c8e56f
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,23 @@
+[tool.poetry]
+name = "pygaze"
+version = "0.8.7"
+description = "A Python library for eye tracking"
+authors = [
+ "Edwin Dalmaijer ",
+ "Sebastiaan Mathôt "
+]
+readme = "readme.md"
+license = "COPYING"
+packages = [
+ {include = "pygaze"},
+ {include = "opensesame_plugins"}
+]
+homepage = "https://pygaze.org"
+repository = "https://github.com/esdalmaijer/PyGaze/"
+
+[tool.poetry.dependencies]
+python = ">= 3.7"
+
+[build-system]
+requires = ["poetry-core"]
+build-backend = "poetry.core.masonry.api"
diff --git a/README.md b/readme.md
similarity index 94%
rename from README.md
rename to readme.md
index 26b46cd..6c65e07 100644
--- a/README.md
+++ b/readme.md
@@ -1,6 +1,6 @@
# PyGaze - the open-source toolbox for eye tracking
-*Copyright 2013 - 2022, Edwin Dalmaijer, Sebastiaan Mathôt, and contributors*
+*Copyright 2013 - 2023, Edwin Dalmaijer, Sebastiaan Mathôt, and contributors*
For more information, see:
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 3c6e79c..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-[bdist_wheel]
-universal=1
diff --git a/setup.py b/setup.py
deleted file mode 100755
index ea7848a..0000000
--- a/setup.py
+++ /dev/null
@@ -1,120 +0,0 @@
-#!/usr/bin/env python
-
-"""
-This file is part of PyGaze.
-
-PyGaze is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-PyGaze is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with qnotero. If not, see .
-"""
-
-import os
-import sys
-import glob
-import pygaze
-from setuptools import setup
-
-print("Running setup for PyGaze version {}".format(pygaze.__version__))
-
-
-def files(path):
-
- return [
- fname
- for fname in glob.glob(path) if os.path.isfile(fname)
- and not fname.endswith('.pyc')
- ]
-
-
-def data_files():
-
- """
- desc:
- The OpenSesame plug-ins are installed as additional data. Under Windows,
- there is no special folder to put these plug-ins in, so we skip this
- step.
-
- returns:
- desc: A list of data files to include.
- type: list
- """
-
- return [
- ("share/opensesame_plugins/pygaze_init/resources/locale",
- files("opensesame_plugins/pygaze_init/resources/locale/*")),
- ("share/opensesame_plugins/pygaze_init",
- files("opensesame_plugins/pygaze_init/*")),
- ("share/opensesame_plugins/pygaze_drift_correct",
- files("opensesame_plugins/pygaze_drift_correct/*")),
- ("share/opensesame_plugins/pygaze_log",
- files("opensesame_plugins/pygaze_log/*")),
- ("share/opensesame_plugins/pygaze_start_recording",
- files("opensesame_plugins/pygaze_start_recording/*")),
- ("share/opensesame_plugins/pygaze_stop_recording",
- files("opensesame_plugins/pygaze_stop_recording/*")),
- ("share/opensesame_plugins/pygaze_wait",
- files("opensesame_plugins/pygaze_wait/*"))
- ]
-
-
-def get_readme():
-
- if os.path.exists('README.md'):
- with open('README.md') as fd:
- return fd.read()
- return 'No readme information'
-
-
-setup(
- name='pygaze' if 'bdist_deb' in sys.argv else u'python-pygaze',
- python_requires=">=3",
- version=pygaze.__version__,
- description="A Python library for eye tracking",
- long_description=get_readme(),
- long_description_content_type='text/markdown',
- author="Edwin Dalmaijer",
- author_email="edwin.dalmaijer@gmail.com",
- url="http://www.pygaze.org/",
- classifiers=[
- 'Development Status :: 4 - Beta',
- 'Intended Audience :: Science/Research',
- 'Topic :: Scientific/Engineering',
- 'Environment :: MacOS X',
- 'Environment :: Win32 (MS Windows)',
- 'Environment :: X11 Applications',
- 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
- 'Programming Language :: Python :: 3',
- ],
- include_package_data=True,
- package_data={
- "pygaze._eyetracker.alea": ["*.dll"],
- "pygaze._eyetracker.eyelogic": ["*.dll"]
- },
- packages=[
- "pygaze",
- "pygaze._display",
- "pygaze._eyetracker",
- "pygaze._eyetracker.alea",
- "pygaze._eyetracker.eyelogic",
- "pygaze._eyetracker.tobiiglasses",
- "pygaze._joystick",
- "pygaze._keyboard",
- "pygaze._logfile",
- "pygaze._misc",
- "pygaze._mouse",
- "pygaze._screen",
- "pygaze._sound",
- "pygaze._time",
- "pygaze.plugins",
- ],
- data_files=data_files()
-)
diff --git a/stdeb.cfg b/stdeb.cfg
deleted file mode 100644
index 6ca90a8..0000000
--- a/stdeb.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-[DEFAULT]
-Source=pygaze
-Package=pygaze
-Debian-version=1
-Suite=focal
-Copyright-File=COPYING.txt