psychopy 2025.2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- psychopy/CHANGELOG.txt +3981 -0
- psychopy/GIT_SHA +1 -0
- psychopy/LICENSE.txt +11 -0
- psychopy/LICENSES.txt +55 -0
- psychopy/VERSION +1 -0
- psychopy/__init__.py +148 -0
- psychopy/alerts/__init__.py +65 -0
- psychopy/alerts/_alerts.py +224 -0
- psychopy/alerts/_errorHandler.py +50 -0
- psychopy/alerts/alertsCatalogue/1000.yaml +0 -0
- psychopy/alerts/alertsCatalogue/1100.yaml +0 -0
- psychopy/alerts/alertsCatalogue/1500.yaml +0 -0
- psychopy/alerts/alertsCatalogue/2000.yaml +0 -0
- psychopy/alerts/alertsCatalogue/2100.yaml +0 -0
- psychopy/alerts/alertsCatalogue/2110.yaml +0 -0
- psychopy/alerts/alertsCatalogue/2115.yaml +21 -0
- psychopy/alerts/alertsCatalogue/2120.yaml +22 -0
- psychopy/alerts/alertsCatalogue/2150.yaml +0 -0
- psychopy/alerts/alertsCatalogue/2155.yaml +21 -0
- psychopy/alerts/alertsCatalogue/2300.yaml +0 -0
- psychopy/alerts/alertsCatalogue/2500.yaml +0 -0
- psychopy/alerts/alertsCatalogue/3000.yaml +0 -0
- psychopy/alerts/alertsCatalogue/3100.yaml +0 -0
- psychopy/alerts/alertsCatalogue/3110.yaml +25 -0
- psychopy/alerts/alertsCatalogue/3115.yaml +24 -0
- psychopy/alerts/alertsCatalogue/3200.yaml +0 -0
- psychopy/alerts/alertsCatalogue/3210.yaml +27 -0
- psychopy/alerts/alertsCatalogue/3400.yaml +0 -0
- psychopy/alerts/alertsCatalogue/3600.yaml +0 -0
- psychopy/alerts/alertsCatalogue/3610.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4000.yaml +0 -0
- psychopy/alerts/alertsCatalogue/4051.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4052.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4100.yaml +0 -0
- psychopy/alerts/alertsCatalogue/4105.yaml +18 -0
- psychopy/alerts/alertsCatalogue/4115.yaml +21 -0
- psychopy/alerts/alertsCatalogue/4120.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4125.yaml +23 -0
- psychopy/alerts/alertsCatalogue/4130.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4160.yaml +25 -0
- psychopy/alerts/alertsCatalogue/4200.yaml +0 -0
- psychopy/alerts/alertsCatalogue/4205.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4210.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4305.yaml +21 -0
- psychopy/alerts/alertsCatalogue/4310.yaml +21 -0
- psychopy/alerts/alertsCatalogue/4315.yaml +21 -0
- psychopy/alerts/alertsCatalogue/4320.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4325.yaml +23 -0
- psychopy/alerts/alertsCatalogue/4330.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4335.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4340.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4405.yaml +24 -0
- psychopy/alerts/alertsCatalogue/4505.yaml +22 -0
- psychopy/alerts/alertsCatalogue/4510.yaml +25 -0
- psychopy/alerts/alertsCatalogue/4520.yaml +26 -0
- psychopy/alerts/alertsCatalogue/4530.yaml +23 -0
- psychopy/alerts/alertsCatalogue/4540.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4545.yaml +22 -0
- psychopy/alerts/alertsCatalogue/4550.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4605.yaml +22 -0
- psychopy/alerts/alertsCatalogue/4610.yaml +22 -0
- psychopy/alerts/alertsCatalogue/4615.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4705.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4710.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4810.yaml +19 -0
- psychopy/alerts/alertsCatalogue/5000.yaml +0 -0
- psychopy/alerts/alertsCatalogue/5055.yaml +25 -0
- psychopy/alerts/alertsCatalogue/6000.yaml +0 -0
- psychopy/alerts/alertsCatalogue/6105.yaml +18 -0
- psychopy/alerts/alertsCatalogue/7105.yaml +19 -0
- psychopy/alerts/alertsCatalogue/8105.yaml +21 -0
- psychopy/alerts/alertsCatalogue/8110.yaml +21 -0
- psychopy/alerts/alertsCatalogue/9998.yaml +19 -0
- psychopy/alerts/alertsCatalogue/9999.yaml +19 -0
- psychopy/alerts/alertsCatalogue/alertCategories.yaml +123 -0
- psychopy/alerts/alertsCatalogue/alertTemplate.yaml +19 -0
- psychopy/alerts/alertsCatalogue/alertmsg.py +173 -0
- psychopy/alerts/alertsCatalogue/generateAlertmsg.py +34 -0
- psychopy/alerts/alerttools.py +322 -0
- psychopy/app/Resources/README.md +12 -0
- psychopy/app/Resources/__init__.py +0 -0
- psychopy/app/Resources/betasplash.png +0 -0
- psychopy/app/Resources/betasplash@2x.png +0 -0
- psychopy/app/Resources/builder.ico +0 -0
- psychopy/app/Resources/classic/FlowBottom_CompLeft.png +0 -0
- psychopy/app/Resources/classic/FlowBottom_CompRight.png +0 -0
- psychopy/app/Resources/classic/FlowTop_CompLeft.png +0 -0
- psychopy/app/Resources/classic/FlowTop_CompRight.png +0 -0
- psychopy/app/Resources/classic/README.txt +9 -0
- psychopy/app/Resources/classic/__init__.py +0 -0
- psychopy/app/Resources/classic/_layouts.ai +1138 -1
- psychopy/app/Resources/classic/add.png +0 -0
- psychopy/app/Resources/classic/add@2x.png +0 -0
- psychopy/app/Resources/classic/addExp32.png +0 -0
- psychopy/app/Resources/classic/add_many.png +0 -0
- psychopy/app/Resources/classic/add_many@2x.png +0 -0
- psychopy/app/Resources/classic/alerts.png +0 -0
- psychopy/app/Resources/classic/beta.png +0 -0
- psychopy/app/Resources/classic/browser.png +0 -0
- psychopy/app/Resources/classic/browser@2x.png +0 -0
- psychopy/app/Resources/classic/bug16.png +0 -0
- psychopy/app/Resources/classic/case.png +0 -0
- psychopy/app/Resources/classic/case@2x.png +0 -0
- psychopy/app/Resources/classic/circle_mask.png +0 -0
- psychopy/app/Resources/classic/circle_mask@2x.png +0 -0
- psychopy/app/Resources/classic/clear.png +0 -0
- psychopy/app/Resources/classic/clear@2x.png +0 -0
- psychopy/app/Resources/classic/coderclass16.png +0 -0
- psychopy/app/Resources/classic/coderfunc16.png +0 -0
- psychopy/app/Resources/classic/coderimport16.png +0 -0
- psychopy/app/Resources/classic/coderjs16.png +0 -0
- psychopy/app/Resources/classic/coderpython16.png +0 -0
- psychopy/app/Resources/classic/codervar16.png +0 -0
- psychopy/app/Resources/classic/cogwindow32.png +0 -0
- psychopy/app/Resources/classic/color32.png +0 -0
- psychopy/app/Resources/classic/compile32.png +0 -0
- psychopy/app/Resources/classic/compile_js.png +0 -0
- psychopy/app/Resources/classic/compile_js@2x.png +0 -0
- psychopy/app/Resources/classic/compile_py.png +0 -0
- psychopy/app/Resources/classic/compile_py@2x.png +0 -0
- psychopy/app/Resources/classic/copy16.png +0 -0
- psychopy/app/Resources/classic/currentFile.png +0 -0
- psychopy/app/Resources/classic/currentFile@2x.png +0 -0
- psychopy/app/Resources/classic/delete16.png +0 -0
- psychopy/app/Resources/classic/desktop.png +0 -0
- psychopy/app/Resources/classic/desktop@2x.png +0 -0
- psychopy/app/Resources/classic/devices.png +0 -0
- psychopy/app/Resources/classic/devices@2x.png +0 -0
- psychopy/app/Resources/classic/dirup16.png +0 -0
- psychopy/app/Resources/classic/docclose16.png +0 -0
- psychopy/app/Resources/classic/download.png +0 -0
- psychopy/app/Resources/classic/edit.png +0 -0
- psychopy/app/Resources/classic/edit@2x.png +0 -0
- psychopy/app/Resources/classic/editbtn.png +0 -0
- psychopy/app/Resources/classic/editbtn16.png +0 -0
- psychopy/app/Resources/classic/editbtn16@2x.png +0 -0
- psychopy/app/Resources/classic/editbtn@2x.png +0 -0
- psychopy/app/Resources/classic/email.png +0 -0
- psychopy/app/Resources/classic/email@2x.png +0 -0
- psychopy/app/Resources/classic/experiment.png +0 -0
- psychopy/app/Resources/classic/experiment@2x.png +0 -0
- psychopy/app/Resources/classic/expsettings.png +0 -0
- psychopy/app/Resources/classic/expsettings@2x.png +0 -0
- psychopy/app/Resources/classic/file.png +0 -0
- psychopy/app/Resources/classic/file@2x.png +0 -0
- psychopy/app/Resources/classic/fileaudio.png +0 -0
- psychopy/app/Resources/classic/fileaudio@2x.png +0 -0
- psychopy/app/Resources/classic/filecss.png +0 -0
- psychopy/app/Resources/classic/filecss@2x.png +0 -0
- psychopy/app/Resources/classic/filecsv.png +0 -0
- psychopy/app/Resources/classic/filecsv@2x.png +0 -0
- psychopy/app/Resources/classic/filedesign.png +0 -0
- psychopy/app/Resources/classic/filedesign@2x.png +0 -0
- psychopy/app/Resources/classic/filefont.png +0 -0
- psychopy/app/Resources/classic/filefont@2x.png +0 -0
- psychopy/app/Resources/classic/filegit.png +0 -0
- psychopy/app/Resources/classic/filegit@2x.png +0 -0
- psychopy/app/Resources/classic/filehtml.png +0 -0
- psychopy/app/Resources/classic/filehtml@2x.png +0 -0
- psychopy/app/Resources/classic/fileimage.png +0 -0
- psychopy/app/Resources/classic/fileimage@2x.png +0 -0
- psychopy/app/Resources/classic/fileinfo.png +0 -0
- psychopy/app/Resources/classic/fileinfo@2x.png +0 -0
- psychopy/app/Resources/classic/filejs.png +0 -0
- psychopy/app/Resources/classic/filejs@2x.png +0 -0
- psychopy/app/Resources/classic/filejson.png +0 -0
- psychopy/app/Resources/classic/filejson@2x.png +0 -0
- psychopy/app/Resources/classic/filenew.png +0 -0
- psychopy/app/Resources/classic/filenew32.png +0 -0
- psychopy/app/Resources/classic/filenew@2x.png +0 -0
- psychopy/app/Resources/classic/fileopen.png +0 -0
- psychopy/app/Resources/classic/fileopen32.png +0 -0
- psychopy/app/Resources/classic/fileopen@2x.png +0 -0
- psychopy/app/Resources/classic/filepkg.png +0 -0
- psychopy/app/Resources/classic/filepkg@2x.png +0 -0
- psychopy/app/Resources/classic/filepsyexp.png +0 -0
- psychopy/app/Resources/classic/filepsyexp@2x.png +0 -0
- psychopy/app/Resources/classic/filepy.png +0 -0
- psychopy/app/Resources/classic/filepy@2x.png +0 -0
- psychopy/app/Resources/classic/filesave.png +0 -0
- psychopy/app/Resources/classic/filesave32.png +0 -0
- psychopy/app/Resources/classic/filesave@2x.png +0 -0
- psychopy/app/Resources/classic/filesaveas.png +0 -0
- psychopy/app/Resources/classic/filesaveas32.png +0 -0
- psychopy/app/Resources/classic/filesaveas@2x.png +0 -0
- psychopy/app/Resources/classic/filetxt.png +0 -0
- psychopy/app/Resources/classic/filetxt@2x.png +0 -0
- psychopy/app/Resources/classic/fileunknown.png +0 -0
- psychopy/app/Resources/classic/fileunknown@2x.png +0 -0
- psychopy/app/Resources/classic/filevideo.png +0 -0
- psychopy/app/Resources/classic/filevideo@2x.png +0 -0
- psychopy/app/Resources/classic/filter.png +0 -0
- psychopy/app/Resources/classic/filter@2x.png +0 -0
- psychopy/app/Resources/classic/find.png +0 -0
- psychopy/app/Resources/classic/find@2x.png +0 -0
- psychopy/app/Resources/classic/folder-open16.png +0 -0
- psychopy/app/Resources/classic/folder16.png +0 -0
- psychopy/app/Resources/classic/foldernew16.png +0 -0
- psychopy/app/Resources/classic/fork.png +0 -0
- psychopy/app/Resources/classic/fork@2x.png +0 -0
- psychopy/app/Resources/classic/github.png +0 -0
- psychopy/app/Resources/classic/github@2x.png +0 -0
- psychopy/app/Resources/classic/globe.png +0 -0
- psychopy/app/Resources/classic/globe@2x.png +0 -0
- psychopy/app/Resources/classic/globe_bug.png +0 -0
- psychopy/app/Resources/classic/globe_bug@2x.png +0 -0
- psychopy/app/Resources/classic/globe_greensync.png +0 -0
- psychopy/app/Resources/classic/globe_greensync@2x.png +0 -0
- psychopy/app/Resources/classic/globe_info.png +0 -0
- psychopy/app/Resources/classic/globe_info@2x.png +0 -0
- psychopy/app/Resources/classic/globe_magnifier.png +0 -0
- psychopy/app/Resources/classic/globe_magnifier@2x.png +0 -0
- psychopy/app/Resources/classic/globe_run.png +0 -0
- psychopy/app/Resources/classic/globe_run@2x.png +0 -0
- psychopy/app/Resources/classic/globe_user.png +0 -0
- psychopy/app/Resources/classic/globe_user@2x.png +0 -0
- psychopy/app/Resources/classic/goto16.png +0 -0
- psychopy/app/Resources/classic/greendot.png +0 -0
- psychopy/app/Resources/classic/greendot@2x.png +0 -0
- psychopy/app/Resources/classic/greenglobe.png +0 -0
- psychopy/app/Resources/classic/greenglobe@2x.png +0 -0
- psychopy/app/Resources/classic/greenglobe_bug.png +0 -0
- psychopy/app/Resources/classic/greenglobe_bug@2x.png +0 -0
- psychopy/app/Resources/classic/greenglobe_greensync.png +0 -0
- psychopy/app/Resources/classic/greenglobe_greensync@2x.png +0 -0
- psychopy/app/Resources/classic/greenglobe_info.png +0 -0
- psychopy/app/Resources/classic/greenglobe_info@2x.png +0 -0
- psychopy/app/Resources/classic/greenglobe_magnifier.png +0 -0
- psychopy/app/Resources/classic/greenglobe_magnifier@2x.png +0 -0
- psychopy/app/Resources/classic/greenglobe_run.png +0 -0
- psychopy/app/Resources/classic/greenglobe_run@2x.png +0 -0
- psychopy/app/Resources/classic/greenglobe_user.png +0 -0
- psychopy/app/Resources/classic/greenglobe_user@2x.png +0 -0
- psychopy/app/Resources/classic/greydot.png +0 -0
- psychopy/app/Resources/classic/greydot@2x.png +0 -0
- psychopy/app/Resources/classic/greytick.png +0 -0
- psychopy/app/Resources/classic/greytick@2x.png +0 -0
- psychopy/app/Resources/classic/invalid_img.png +0 -0
- psychopy/app/Resources/classic/jsPilot.png +0 -0
- psychopy/app/Resources/classic/jsPilot@2x.png +0 -0
- psychopy/app/Resources/classic/jsRun.png +0 -0
- psychopy/app/Resources/classic/jsRun@2x.png +0 -0
- psychopy/app/Resources/classic/libroot.png +0 -0
- psychopy/app/Resources/classic/libroot@2x.png +0 -0
- psychopy/app/Resources/classic/loop.png +0 -0
- psychopy/app/Resources/classic/loop@2x.png +0 -0
- psychopy/app/Resources/classic/monitor16.png +0 -0
- psychopy/app/Resources/classic/monitors.png +0 -0
- psychopy/app/Resources/classic/monitors16.png +0 -0
- psychopy/app/Resources/classic/monitors32.png +0 -0
- psychopy/app/Resources/classic/monitors@2x.png +0 -0
- psychopy/app/Resources/classic/orangedot.png +0 -0
- psychopy/app/Resources/classic/orangedot@2x.png +0 -0
- psychopy/app/Resources/classic/pavlovia.png +0 -0
- psychopy/app/Resources/classic/pavlovia16.png +0 -0
- psychopy/app/Resources/classic/pavlovia16@2x.png +0 -0
- psychopy/app/Resources/classic/pavlovia@2x.png +0 -0
- psychopy/app/Resources/classic/pavsync.png +0 -0
- psychopy/app/Resources/classic/pavsync@2x.png +0 -0
- psychopy/app/Resources/classic/person_off.png +0 -0
- psychopy/app/Resources/classic/person_off@2x.png +0 -0
- psychopy/app/Resources/classic/person_on.png +0 -0
- psychopy/app/Resources/classic/person_on@2x.png +0 -0
- psychopy/app/Resources/classic/photometer.png +0 -0
- psychopy/app/Resources/classic/photometer@2x.png +0 -0
- psychopy/app/Resources/classic/plugin16.png +0 -0
- psychopy/app/Resources/classic/plugin16@2x.png +0 -0
- psychopy/app/Resources/classic/plugins32.png +0 -0
- psychopy/app/Resources/classic/plus.png +0 -0
- psychopy/app/Resources/classic/plus@2x.png +0 -0
- psychopy/app/Resources/classic/preferences-app.png +0 -0
- psychopy/app/Resources/classic/preferences-app48.png +0 -0
- psychopy/app/Resources/classic/preferences-app@2x.png +0 -0
- psychopy/app/Resources/classic/preferences-conn.png +0 -0
- psychopy/app/Resources/classic/preferences-conn48.png +0 -0
- psychopy/app/Resources/classic/preferences-conn@2x.png +0 -0
- psychopy/app/Resources/classic/preferences-debug.png +0 -0
- psychopy/app/Resources/classic/preferences-debug@2x.png +0 -0
- psychopy/app/Resources/classic/preferences-general.png +0 -0
- psychopy/app/Resources/classic/preferences-general48.png +0 -0
- psychopy/app/Resources/classic/preferences-general@2x.png +0 -0
- psychopy/app/Resources/classic/preferences-hardware.png +0 -0
- psychopy/app/Resources/classic/preferences-hardware48.png +0 -0
- psychopy/app/Resources/classic/preferences-hardware@2x.png +0 -0
- psychopy/app/Resources/classic/preferences-keyboard.png +0 -0
- psychopy/app/Resources/classic/preferences-keyboard48.png +0 -0
- psychopy/app/Resources/classic/preferences-keyboard@2x.png +0 -0
- psychopy/app/Resources/classic/preferences-pilot.png +0 -0
- psychopy/app/Resources/classic/preferences-pilot@2x.png +0 -0
- psychopy/app/Resources/classic/preferences32.png +0 -0
- psychopy/app/Resources/classic/pyPilot.png +0 -0
- psychopy/app/Resources/classic/pyPilot@2x.png +0 -0
- psychopy/app/Resources/classic/pyRun.png +0 -0
- psychopy/app/Resources/classic/pyRun@2x.png +0 -0
- psychopy/app/Resources/classic/reddot.png +0 -0
- psychopy/app/Resources/classic/reddot@2x.png +0 -0
- psychopy/app/Resources/classic/redglobe.png +0 -0
- psychopy/app/Resources/classic/redglobe@2x.png +0 -0
- psychopy/app/Resources/classic/redglobe_bug.png +0 -0
- psychopy/app/Resources/classic/redglobe_bug@2x.png +0 -0
- psychopy/app/Resources/classic/redglobe_greensync.png +0 -0
- psychopy/app/Resources/classic/redglobe_greensync@2x.png +0 -0
- psychopy/app/Resources/classic/redglobe_info.png +0 -0
- psychopy/app/Resources/classic/redglobe_info@2x.png +0 -0
- psychopy/app/Resources/classic/redglobe_magnifier.png +0 -0
- psychopy/app/Resources/classic/redglobe_magnifier@2x.png +0 -0
- psychopy/app/Resources/classic/redglobe_run.png +0 -0
- psychopy/app/Resources/classic/redglobe_run@2x.png +0 -0
- psychopy/app/Resources/classic/redglobe_user.png +0 -0
- psychopy/app/Resources/classic/redglobe_user@2x.png +0 -0
- psychopy/app/Resources/classic/redo.png +0 -0
- psychopy/app/Resources/classic/redo32.png +0 -0
- psychopy/app/Resources/classic/redo@2x.png +0 -0
- psychopy/app/Resources/classic/regex.png +0 -0
- psychopy/app/Resources/classic/regex@2x.png +0 -0
- psychopy/app/Resources/classic/removeExp32.png +0 -0
- psychopy/app/Resources/classic/rename16.png +0 -0
- psychopy/app/Resources/classic/restart.png +0 -0
- psychopy/app/Resources/classic/restart@2x.png +0 -0
- psychopy/app/Resources/classic/run.png +0 -0
- psychopy/app/Resources/classic/run@2x.png +0 -0
- psychopy/app/Resources/classic/runner.png +0 -0
- psychopy/app/Resources/classic/runner@2x.png +0 -0
- psychopy/app/Resources/classic/runnerPilot.png +0 -0
- psychopy/app/Resources/classic/runnerPilot@2x.png +0 -0
- psychopy/app/Resources/classic/savebtn.png +0 -0
- psychopy/app/Resources/classic/savebtn16.png +0 -0
- psychopy/app/Resources/classic/savebtn16@2x.png +0 -0
- psychopy/app/Resources/classic/savebtn@2x.png +0 -0
- psychopy/app/Resources/classic/search.png +0 -0
- psychopy/app/Resources/classic/search@2x.png +0 -0
- psychopy/app/Resources/classic/showBuilder.png +0 -0
- psychopy/app/Resources/classic/showBuilder@2x.png +0 -0
- psychopy/app/Resources/classic/showCoder.png +0 -0
- psychopy/app/Resources/classic/showCoder@2x.png +0 -0
- psychopy/app/Resources/classic/showRunner.png +0 -0
- psychopy/app/Resources/classic/showRunner@2x.png +0 -0
- psychopy/app/Resources/classic/starred.png +0 -0
- psychopy/app/Resources/classic/starred@2x.png +0 -0
- psychopy/app/Resources/classic/start.png +0 -0
- psychopy/app/Resources/classic/start@2x.png +0 -0
- psychopy/app/Resources/classic/stdout.png +0 -0
- psychopy/app/Resources/classic/stop.png +0 -0
- psychopy/app/Resources/classic/stop32.png +0 -0
- psychopy/app/Resources/classic/stop@2x.png +0 -0
- psychopy/app/Resources/classic/switchCtrlBot.png +0 -0
- psychopy/app/Resources/classic/switchCtrlBot@2x.png +0 -0
- psychopy/app/Resources/classic/switchCtrlLeft.png +0 -0
- psychopy/app/Resources/classic/switchCtrlLeft@2x.png +0 -0
- psychopy/app/Resources/classic/switchCtrlRight.png +0 -0
- psychopy/app/Resources/classic/switchCtrlRight@2x.png +0 -0
- psychopy/app/Resources/classic/switchCtrlTop.png +0 -0
- psychopy/app/Resources/classic/switchCtrlTop@2x.png +0 -0
- psychopy/app/Resources/classic/tick.png +0 -0
- psychopy/app/Resources/classic/tick@2x.png +0 -0
- psychopy/app/Resources/classic/undo.png +0 -0
- psychopy/app/Resources/classic/undo32.png +0 -0
- psychopy/app/Resources/classic/undo@2x.png +0 -0
- psychopy/app/Resources/classic/unstarred.png +0 -0
- psychopy/app/Resources/classic/unstarred@2x.png +0 -0
- psychopy/app/Resources/classic/user_none.png +0 -0
- psychopy/app/Resources/classic/view-refresh16.png +0 -0
- psychopy/app/Resources/classic/viewbtn.png +0 -0
- psychopy/app/Resources/classic/viewbtn16.png +0 -0
- psychopy/app/Resources/classic/viewbtn16@2x.png +0 -0
- psychopy/app/Resources/classic/viewbtn@2x.png +0 -0
- psychopy/app/Resources/classic/windows16.png +0 -0
- psychopy/app/Resources/classic/windows16@2x.png +0 -0
- psychopy/app/Resources/coder.ico +0 -0
- psychopy/app/Resources/dark/FlowBottom_CompLeft.png +0 -0
- psychopy/app/Resources/dark/FlowBottom_CompRight.png +0 -0
- psychopy/app/Resources/dark/FlowTop_CompLeft.png +0 -0
- psychopy/app/Resources/dark/FlowTop_CompRight.png +0 -0
- psychopy/app/Resources/dark/README.txt +3 -0
- psychopy/app/Resources/dark/__init__.py +0 -0
- psychopy/app/Resources/dark/add.png +0 -0
- psychopy/app/Resources/dark/add@2x.png +0 -0
- psychopy/app/Resources/dark/addExp32.png +0 -0
- psychopy/app/Resources/dark/addExp32@2x.png +0 -0
- psychopy/app/Resources/dark/add_many.png +0 -0
- psychopy/app/Resources/dark/add_many@2x.png +0 -0
- psychopy/app/Resources/dark/alerts.png +0 -0
- psychopy/app/Resources/dark/alerts@2x.png +0 -0
- psychopy/app/Resources/dark/beta.png +0 -0
- psychopy/app/Resources/dark/beta@2x.png +0 -0
- psychopy/app/Resources/dark/browser.png +0 -0
- psychopy/app/Resources/dark/browser@2x.png +0 -0
- psychopy/app/Resources/dark/bug16.png +0 -0
- psychopy/app/Resources/dark/bug16@2x.png +0 -0
- psychopy/app/Resources/dark/case.png +0 -0
- psychopy/app/Resources/dark/case@2x.png +0 -0
- psychopy/app/Resources/dark/circle_mask.png +0 -0
- psychopy/app/Resources/dark/circle_mask@2x.png +0 -0
- psychopy/app/Resources/dark/clear.png +0 -0
- psychopy/app/Resources/dark/clear@2x.png +0 -0
- psychopy/app/Resources/dark/coderclass16.png +0 -0
- psychopy/app/Resources/dark/coderclass16@2x.png +0 -0
- psychopy/app/Resources/dark/coderfunc16.png +0 -0
- psychopy/app/Resources/dark/coderfunc16@2x.png +0 -0
- psychopy/app/Resources/dark/coderimport16.png +0 -0
- psychopy/app/Resources/dark/coderimport16@2x.png +0 -0
- psychopy/app/Resources/dark/coderjs.png +0 -0
- psychopy/app/Resources/dark/coderjs@2x.png +0 -0
- psychopy/app/Resources/dark/coderpython.png +0 -0
- psychopy/app/Resources/dark/coderpython@2x.png +0 -0
- psychopy/app/Resources/dark/codervar16.png +0 -0
- psychopy/app/Resources/dark/codervar16@2x.png +0 -0
- psychopy/app/Resources/dark/cogwindow32.png +0 -0
- psychopy/app/Resources/dark/cogwindow32@2x.png +0 -0
- psychopy/app/Resources/dark/color32.png +0 -0
- psychopy/app/Resources/dark/color32@2x.png +0 -0
- psychopy/app/Resources/dark/compile_js.png +0 -0
- psychopy/app/Resources/dark/compile_js@2x.png +0 -0
- psychopy/app/Resources/dark/compile_py.png +0 -0
- psychopy/app/Resources/dark/compile_py@2x.png +0 -0
- psychopy/app/Resources/dark/copy16.png +0 -0
- psychopy/app/Resources/dark/copy16@2x.png +0 -0
- psychopy/app/Resources/dark/currentFile16.png +0 -0
- psychopy/app/Resources/dark/currentFile16@2x.png +0 -0
- psychopy/app/Resources/dark/delete16.png +0 -0
- psychopy/app/Resources/dark/delete16@2x.png +0 -0
- psychopy/app/Resources/dark/desktop.png +0 -0
- psychopy/app/Resources/dark/desktop@2x.png +0 -0
- psychopy/app/Resources/dark/devices.png +0 -0
- psychopy/app/Resources/dark/devices@2x.png +0 -0
- psychopy/app/Resources/dark/dirup16.png +0 -0
- psychopy/app/Resources/dark/dirup16@2x.png +0 -0
- psychopy/app/Resources/dark/docclose16.png +0 -0
- psychopy/app/Resources/dark/docclose16@2x.png +0 -0
- psychopy/app/Resources/dark/download.png +0 -0
- psychopy/app/Resources/dark/download@2x.png +0 -0
- psychopy/app/Resources/dark/edit.png +0 -0
- psychopy/app/Resources/dark/edit@2x.png +0 -0
- psychopy/app/Resources/dark/editbtn16.png +0 -0
- psychopy/app/Resources/dark/editbtn16@2x.png +0 -0
- psychopy/app/Resources/dark/email.png +0 -0
- psychopy/app/Resources/dark/email@2x.png +0 -0
- psychopy/app/Resources/dark/experiment.png +0 -0
- psychopy/app/Resources/dark/experiment@2x.png +0 -0
- psychopy/app/Resources/dark/expsettings.png +0 -0
- psychopy/app/Resources/dark/expsettings@2x.png +0 -0
- psychopy/app/Resources/dark/file.png +0 -0
- psychopy/app/Resources/dark/file@16w.png +0 -0
- psychopy/app/Resources/dark/file@16w@2x.png +0 -0
- psychopy/app/Resources/dark/file@2x.png +0 -0
- psychopy/app/Resources/dark/fileaudio.png +0 -0
- psychopy/app/Resources/dark/fileaudio@2x.png +0 -0
- psychopy/app/Resources/dark/filecss.png +0 -0
- psychopy/app/Resources/dark/filecss@2x.png +0 -0
- psychopy/app/Resources/dark/filecsv.png +0 -0
- psychopy/app/Resources/dark/filecsv@2x.png +0 -0
- psychopy/app/Resources/dark/filedesign.png +0 -0
- psychopy/app/Resources/dark/filedesign@2x.png +0 -0
- psychopy/app/Resources/dark/filefont.png +0 -0
- psychopy/app/Resources/dark/filefont@2x.png +0 -0
- psychopy/app/Resources/dark/filegit.png +0 -0
- psychopy/app/Resources/dark/filegit@2x.png +0 -0
- psychopy/app/Resources/dark/filehtml.png +0 -0
- psychopy/app/Resources/dark/filehtml@2x.png +0 -0
- psychopy/app/Resources/dark/fileimage.png +0 -0
- psychopy/app/Resources/dark/fileimage@2x.png +0 -0
- psychopy/app/Resources/dark/fileinfo.png +0 -0
- psychopy/app/Resources/dark/fileinfo@2x.png +0 -0
- psychopy/app/Resources/dark/filejs.png +0 -0
- psychopy/app/Resources/dark/filejs@2x.png +0 -0
- psychopy/app/Resources/dark/filejson.png +0 -0
- psychopy/app/Resources/dark/filejson@2x.png +0 -0
- psychopy/app/Resources/dark/filenew.png +0 -0
- psychopy/app/Resources/dark/filenew32.png +0 -0
- psychopy/app/Resources/dark/filenew32@2x.png +0 -0
- psychopy/app/Resources/dark/filenew@2x.png +0 -0
- psychopy/app/Resources/dark/fileopen.png +0 -0
- psychopy/app/Resources/dark/fileopen32.png +0 -0
- psychopy/app/Resources/dark/fileopen32@2x.png +0 -0
- psychopy/app/Resources/dark/fileopen@2x.png +0 -0
- psychopy/app/Resources/dark/filepkg.png +0 -0
- psychopy/app/Resources/dark/filepkg@2x.png +0 -0
- psychopy/app/Resources/dark/filepsyexp.png +0 -0
- psychopy/app/Resources/dark/filepsyexp@2x.png +0 -0
- psychopy/app/Resources/dark/filepy.png +0 -0
- psychopy/app/Resources/dark/filepy@2x.png +0 -0
- psychopy/app/Resources/dark/filesave.png +0 -0
- psychopy/app/Resources/dark/filesave32.png +0 -0
- psychopy/app/Resources/dark/filesave32@2x.png +0 -0
- psychopy/app/Resources/dark/filesave@2x.png +0 -0
- psychopy/app/Resources/dark/filesaveas.png +0 -0
- psychopy/app/Resources/dark/filesaveas32.png +0 -0
- psychopy/app/Resources/dark/filesaveas32@2x.png +0 -0
- psychopy/app/Resources/dark/filesaveas@2x.png +0 -0
- psychopy/app/Resources/dark/filetxt.png +0 -0
- psychopy/app/Resources/dark/filetxt@2x.png +0 -0
- psychopy/app/Resources/dark/fileunknown.png +0 -0
- psychopy/app/Resources/dark/fileunknown@2x.png +0 -0
- psychopy/app/Resources/dark/filevideo.png +0 -0
- psychopy/app/Resources/dark/filevideo@2x.png +0 -0
- psychopy/app/Resources/dark/filter.png +0 -0
- psychopy/app/Resources/dark/filter@2x.png +0 -0
- psychopy/app/Resources/dark/find.png +0 -0
- psychopy/app/Resources/dark/find@2x.png +0 -0
- psychopy/app/Resources/dark/folder-open16.png +0 -0
- psychopy/app/Resources/dark/folder-open16@2x.png +0 -0
- psychopy/app/Resources/dark/folder16.png +0 -0
- psychopy/app/Resources/dark/folder16@2x.png +0 -0
- psychopy/app/Resources/dark/foldernew16.png +0 -0
- psychopy/app/Resources/dark/foldernew16@2x.png +0 -0
- psychopy/app/Resources/dark/fork.png +0 -0
- psychopy/app/Resources/dark/fork@2x.png +0 -0
- psychopy/app/Resources/dark/github.png +0 -0
- psychopy/app/Resources/dark/github@2x.png +0 -0
- psychopy/app/Resources/dark/globe.png +0 -0
- psychopy/app/Resources/dark/globe@2x.png +0 -0
- psychopy/app/Resources/dark/globe_bug.png +0 -0
- psychopy/app/Resources/dark/globe_bug@2x.png +0 -0
- psychopy/app/Resources/dark/globe_greensync.png +0 -0
- psychopy/app/Resources/dark/globe_greensync@2x.png +0 -0
- psychopy/app/Resources/dark/globe_info.png +0 -0
- psychopy/app/Resources/dark/globe_info@2x.png +0 -0
- psychopy/app/Resources/dark/globe_magnifier.png +0 -0
- psychopy/app/Resources/dark/globe_magnifier@2x.png +0 -0
- psychopy/app/Resources/dark/globe_run.png +0 -0
- psychopy/app/Resources/dark/globe_run@2x.png +0 -0
- psychopy/app/Resources/dark/globe_user.png +0 -0
- psychopy/app/Resources/dark/globe_user@2x.png +0 -0
- psychopy/app/Resources/dark/goto.png +0 -0
- psychopy/app/Resources/dark/goto@2x.png +0 -0
- psychopy/app/Resources/dark/greendot.png +0 -0
- psychopy/app/Resources/dark/greendot@2x.png +0 -0
- psychopy/app/Resources/dark/greenglobe.png +0 -0
- psychopy/app/Resources/dark/greenglobe@2x.png +0 -0
- psychopy/app/Resources/dark/greenglobe_bug.png +0 -0
- psychopy/app/Resources/dark/greenglobe_bug@2x.png +0 -0
- psychopy/app/Resources/dark/greenglobe_greensync.png +0 -0
- psychopy/app/Resources/dark/greenglobe_greensync@2x.png +0 -0
- psychopy/app/Resources/dark/greenglobe_info.png +0 -0
- psychopy/app/Resources/dark/greenglobe_info@2x.png +0 -0
- psychopy/app/Resources/dark/greenglobe_magnifier.png +0 -0
- psychopy/app/Resources/dark/greenglobe_magnifier@2x.png +0 -0
- psychopy/app/Resources/dark/greenglobe_run.png +0 -0
- psychopy/app/Resources/dark/greenglobe_run@2x.png +0 -0
- psychopy/app/Resources/dark/greenglobe_user.png +0 -0
- psychopy/app/Resources/dark/greenglobe_user@2x.png +0 -0
- psychopy/app/Resources/dark/greydot.png +0 -0
- psychopy/app/Resources/dark/greydot@2x.png +0 -0
- psychopy/app/Resources/dark/greytick.png +0 -0
- psychopy/app/Resources/dark/greytick@2x.png +0 -0
- psychopy/app/Resources/dark/invalid_img.png +0 -0
- psychopy/app/Resources/dark/jsPilot.png +0 -0
- psychopy/app/Resources/dark/jsPilot@2x.png +0 -0
- psychopy/app/Resources/dark/jsRun.png +0 -0
- psychopy/app/Resources/dark/jsRun@2x.png +0 -0
- psychopy/app/Resources/dark/libroot16.png +0 -0
- psychopy/app/Resources/dark/libroot16@2x.png +0 -0
- psychopy/app/Resources/dark/loop.png +0 -0
- psychopy/app/Resources/dark/loop@2x.png +0 -0
- psychopy/app/Resources/dark/monitor16.png +0 -0
- psychopy/app/Resources/dark/monitor16@2x.png +0 -0
- psychopy/app/Resources/dark/monitors.png +0 -0
- psychopy/app/Resources/dark/monitors32.png +0 -0
- psychopy/app/Resources/dark/monitors32@2x.png +0 -0
- psychopy/app/Resources/dark/monitors@2x.png +0 -0
- psychopy/app/Resources/dark/orangedot.png +0 -0
- psychopy/app/Resources/dark/orangedot@2x.png +0 -0
- psychopy/app/Resources/dark/pavlovia.png +0 -0
- psychopy/app/Resources/dark/pavlovia16.png +0 -0
- psychopy/app/Resources/dark/pavlovia16@2x.png +0 -0
- psychopy/app/Resources/dark/pavlovia@2x.png +0 -0
- psychopy/app/Resources/dark/pavsync.png +0 -0
- psychopy/app/Resources/dark/pavsync@2x.png +0 -0
- psychopy/app/Resources/dark/person_off.png +0 -0
- psychopy/app/Resources/dark/person_off@2x.png +0 -0
- psychopy/app/Resources/dark/person_on.png +0 -0
- psychopy/app/Resources/dark/person_on@2x.png +0 -0
- psychopy/app/Resources/dark/photometer.png +0 -0
- psychopy/app/Resources/dark/photometer@2x.png +0 -0
- psychopy/app/Resources/dark/plugin16.png +0 -0
- psychopy/app/Resources/dark/plugin16@2x.png +0 -0
- psychopy/app/Resources/dark/plugins32.png +0 -0
- psychopy/app/Resources/dark/plugins32@2x.png +0 -0
- psychopy/app/Resources/dark/plus.png +0 -0
- psychopy/app/Resources/dark/plus@2x.png +0 -0
- psychopy/app/Resources/dark/preferences-app.png +0 -0
- psychopy/app/Resources/dark/preferences-app48.png +0 -0
- psychopy/app/Resources/dark/preferences-app48@2x.png +0 -0
- psychopy/app/Resources/dark/preferences-app@2x.png +0 -0
- psychopy/app/Resources/dark/preferences-conn.png +0 -0
- psychopy/app/Resources/dark/preferences-conn48.png +0 -0
- psychopy/app/Resources/dark/preferences-conn48@2x.png +0 -0
- psychopy/app/Resources/dark/preferences-conn@2x.png +0 -0
- psychopy/app/Resources/dark/preferences-debug.png +0 -0
- psychopy/app/Resources/dark/preferences-debug@2x.png +0 -0
- psychopy/app/Resources/dark/preferences-general.png +0 -0
- psychopy/app/Resources/dark/preferences-general48.png +0 -0
- psychopy/app/Resources/dark/preferences-general48@2x.png +0 -0
- psychopy/app/Resources/dark/preferences-general@2x.png +0 -0
- psychopy/app/Resources/dark/preferences-hardware.png +0 -0
- psychopy/app/Resources/dark/preferences-hardware48.png +0 -0
- psychopy/app/Resources/dark/preferences-hardware48@2x.png +0 -0
- psychopy/app/Resources/dark/preferences-hardware@2x.png +0 -0
- psychopy/app/Resources/dark/preferences-keyboard.png +0 -0
- psychopy/app/Resources/dark/preferences-keyboard48.png +0 -0
- psychopy/app/Resources/dark/preferences-keyboard48@2x.png +0 -0
- psychopy/app/Resources/dark/preferences-keyboard@2x.png +0 -0
- psychopy/app/Resources/dark/preferences-pilot.png +0 -0
- psychopy/app/Resources/dark/preferences-pilot@2x.png +0 -0
- psychopy/app/Resources/dark/preferences32.png +0 -0
- psychopy/app/Resources/dark/preferences32@2x.png +0 -0
- psychopy/app/Resources/dark/pyPilot.png +0 -0
- psychopy/app/Resources/dark/pyPilot@2x.png +0 -0
- psychopy/app/Resources/dark/pyRun.png +0 -0
- psychopy/app/Resources/dark/pyRun@2x.png +0 -0
- psychopy/app/Resources/dark/reddot.png +0 -0
- psychopy/app/Resources/dark/reddot@2x.png +0 -0
- psychopy/app/Resources/dark/redglobe.png +0 -0
- psychopy/app/Resources/dark/redglobe@2x.png +0 -0
- psychopy/app/Resources/dark/redglobe_bug.png +0 -0
- psychopy/app/Resources/dark/redglobe_bug@2x.png +0 -0
- psychopy/app/Resources/dark/redglobe_greensync.png +0 -0
- psychopy/app/Resources/dark/redglobe_greensync@2x.png +0 -0
- psychopy/app/Resources/dark/redglobe_info.png +0 -0
- psychopy/app/Resources/dark/redglobe_info@2x.png +0 -0
- psychopy/app/Resources/dark/redglobe_magnifier.png +0 -0
- psychopy/app/Resources/dark/redglobe_magnifier@2x.png +0 -0
- psychopy/app/Resources/dark/redglobe_run.png +0 -0
- psychopy/app/Resources/dark/redglobe_run@2x.png +0 -0
- psychopy/app/Resources/dark/redglobe_user.png +0 -0
- psychopy/app/Resources/dark/redglobe_user@2x.png +0 -0
- psychopy/app/Resources/dark/redo.png +0 -0
- psychopy/app/Resources/dark/redo32.png +0 -0
- psychopy/app/Resources/dark/redo32@2x.png +0 -0
- psychopy/app/Resources/dark/redo@2x.png +0 -0
- psychopy/app/Resources/dark/regex.png +0 -0
- psychopy/app/Resources/dark/regex@2x.png +0 -0
- psychopy/app/Resources/dark/removeExp32.png +0 -0
- psychopy/app/Resources/dark/removeExp32@2x.png +0 -0
- psychopy/app/Resources/dark/rename16.png +0 -0
- psychopy/app/Resources/dark/rename16@2x.png +0 -0
- psychopy/app/Resources/dark/restart.png +0 -0
- psychopy/app/Resources/dark/restart@2x.png +0 -0
- psychopy/app/Resources/dark/runner.png +0 -0
- psychopy/app/Resources/dark/runner@2x.png +0 -0
- psychopy/app/Resources/dark/runnerPilot.png +0 -0
- psychopy/app/Resources/dark/runnerPilot@2x.png +0 -0
- psychopy/app/Resources/dark/savebtn16.png +0 -0
- psychopy/app/Resources/dark/savebtn16@2x.png +0 -0
- psychopy/app/Resources/dark/search.png +0 -0
- psychopy/app/Resources/dark/search@2x.png +0 -0
- psychopy/app/Resources/dark/showBuilder.png +0 -0
- psychopy/app/Resources/dark/showBuilder@2x.png +0 -0
- psychopy/app/Resources/dark/showCoder.png +0 -0
- psychopy/app/Resources/dark/showCoder@2x.png +0 -0
- psychopy/app/Resources/dark/showRunner.png +0 -0
- psychopy/app/Resources/dark/showRunner@2x.png +0 -0
- psychopy/app/Resources/dark/starred.png +0 -0
- psychopy/app/Resources/dark/starred@2x.png +0 -0
- psychopy/app/Resources/dark/start.png +0 -0
- psychopy/app/Resources/dark/start@2x.png +0 -0
- psychopy/app/Resources/dark/stdout.png +0 -0
- psychopy/app/Resources/dark/stdout@2x.png +0 -0
- psychopy/app/Resources/dark/stop.png +0 -0
- psychopy/app/Resources/dark/stop32.png +0 -0
- psychopy/app/Resources/dark/stop32@2x.png +0 -0
- psychopy/app/Resources/dark/stop@2x.png +0 -0
- psychopy/app/Resources/dark/switchCtrlBot.png +0 -0
- psychopy/app/Resources/dark/switchCtrlBot@2x.png +0 -0
- psychopy/app/Resources/dark/switchCtrlLeft.png +0 -0
- psychopy/app/Resources/dark/switchCtrlLeft@2x.png +0 -0
- psychopy/app/Resources/dark/switchCtrlRight.png +0 -0
- psychopy/app/Resources/dark/switchCtrlRight@2x.png +0 -0
- psychopy/app/Resources/dark/switchCtrlTop.png +0 -0
- psychopy/app/Resources/dark/switchCtrlTop@2x.png +0 -0
- psychopy/app/Resources/dark/tick.png +0 -0
- psychopy/app/Resources/dark/tick@2x.png +0 -0
- psychopy/app/Resources/dark/undo.png +0 -0
- psychopy/app/Resources/dark/undo32.png +0 -0
- psychopy/app/Resources/dark/undo32@2x.png +0 -0
- psychopy/app/Resources/dark/undo@2x.png +0 -0
- psychopy/app/Resources/dark/unstarred.png +0 -0
- psychopy/app/Resources/dark/unstarred@2x.png +0 -0
- psychopy/app/Resources/dark/user_none.png +0 -0
- psychopy/app/Resources/dark/view-refresh16.png +0 -0
- psychopy/app/Resources/dark/view-refresh16@2x.png +0 -0
- psychopy/app/Resources/dark/viewbtn16.png +0 -0
- psychopy/app/Resources/dark/viewbtn16@2x.png +0 -0
- psychopy/app/Resources/dark/windows16.png +0 -0
- psychopy/app/Resources/dark/windows16@2x.png +0 -0
- psychopy/app/Resources/light/FlowBottom_CompLeft.png +0 -0
- psychopy/app/Resources/light/FlowBottom_CompRight.png +0 -0
- psychopy/app/Resources/light/FlowTop_CompLeft.png +0 -0
- psychopy/app/Resources/light/FlowTop_CompRight.png +0 -0
- psychopy/app/Resources/light/README.txt +3 -0
- psychopy/app/Resources/light/__init__.py +0 -0
- psychopy/app/Resources/light/add.png +0 -0
- psychopy/app/Resources/light/add@2x.png +0 -0
- psychopy/app/Resources/light/addExp32.png +0 -0
- psychopy/app/Resources/light/addExp32@2x.png +0 -0
- psychopy/app/Resources/light/add_many.png +0 -0
- psychopy/app/Resources/light/add_many@2x.png +0 -0
- psychopy/app/Resources/light/alerts.png +0 -0
- psychopy/app/Resources/light/alerts@2x.png +0 -0
- psychopy/app/Resources/light/beta.png +0 -0
- psychopy/app/Resources/light/beta@2x.png +0 -0
- psychopy/app/Resources/light/browser.png +0 -0
- psychopy/app/Resources/light/browser@2x.png +0 -0
- psychopy/app/Resources/light/bug16.png +0 -0
- psychopy/app/Resources/light/bug16@2x.png +0 -0
- psychopy/app/Resources/light/case.png +0 -0
- psychopy/app/Resources/light/case@2x.png +0 -0
- psychopy/app/Resources/light/circle_mask.png +0 -0
- psychopy/app/Resources/light/circle_mask@2x.png +0 -0
- psychopy/app/Resources/light/clear.png +0 -0
- psychopy/app/Resources/light/clear@2x.png +0 -0
- psychopy/app/Resources/light/coderclass16.png +0 -0
- psychopy/app/Resources/light/coderclass16@2x.png +0 -0
- psychopy/app/Resources/light/coderfunc16.png +0 -0
- psychopy/app/Resources/light/coderfunc16@2x.png +0 -0
- psychopy/app/Resources/light/coderimport16.png +0 -0
- psychopy/app/Resources/light/coderimport16@2x.png +0 -0
- psychopy/app/Resources/light/coderjs.png +0 -0
- psychopy/app/Resources/light/coderjs@2x.png +0 -0
- psychopy/app/Resources/light/coderpython.png +0 -0
- psychopy/app/Resources/light/coderpython@2x.png +0 -0
- psychopy/app/Resources/light/codervar16.png +0 -0
- psychopy/app/Resources/light/codervar16@2x.png +0 -0
- psychopy/app/Resources/light/cogwindow32.png +0 -0
- psychopy/app/Resources/light/cogwindow32@2x.png +0 -0
- psychopy/app/Resources/light/color16.png +0 -0
- psychopy/app/Resources/light/color16@2x.png +0 -0
- psychopy/app/Resources/light/color32.png +0 -0
- psychopy/app/Resources/light/color32@2x.png +0 -0
- psychopy/app/Resources/light/compile_js.png +0 -0
- psychopy/app/Resources/light/compile_js@2x.png +0 -0
- psychopy/app/Resources/light/compile_py.png +0 -0
- psychopy/app/Resources/light/compile_py@2x.png +0 -0
- psychopy/app/Resources/light/copy16.png +0 -0
- psychopy/app/Resources/light/copy16@2x.png +0 -0
- psychopy/app/Resources/light/currentFile16.png +0 -0
- psychopy/app/Resources/light/currentFile16@2x.png +0 -0
- psychopy/app/Resources/light/delete16.png +0 -0
- psychopy/app/Resources/light/delete16@2x.png +0 -0
- psychopy/app/Resources/light/delete8.png +0 -0
- psychopy/app/Resources/light/desktop.png +0 -0
- psychopy/app/Resources/light/desktop@2x.png +0 -0
- psychopy/app/Resources/light/devices.png +0 -0
- psychopy/app/Resources/light/devices@2x.png +0 -0
- psychopy/app/Resources/light/dirup16.png +0 -0
- psychopy/app/Resources/light/dirup16@2x.png +0 -0
- psychopy/app/Resources/light/docclose16.png +0 -0
- psychopy/app/Resources/light/docclose16@2x.png +0 -0
- psychopy/app/Resources/light/download.png +0 -0
- psychopy/app/Resources/light/download@2x.png +0 -0
- psychopy/app/Resources/light/edit.png +0 -0
- psychopy/app/Resources/light/edit@2x.png +0 -0
- psychopy/app/Resources/light/editbtn16.png +0 -0
- psychopy/app/Resources/light/editbtn16@2x.png +0 -0
- psychopy/app/Resources/light/email.png +0 -0
- psychopy/app/Resources/light/email@2x.png +0 -0
- psychopy/app/Resources/light/experiment.png +0 -0
- psychopy/app/Resources/light/experiment@2x.png +0 -0
- psychopy/app/Resources/light/expsettings.png +0 -0
- psychopy/app/Resources/light/expsettings@2x.png +0 -0
- psychopy/app/Resources/light/file.png +0 -0
- psychopy/app/Resources/light/file@2x.png +0 -0
- psychopy/app/Resources/light/fileaudio.png +0 -0
- psychopy/app/Resources/light/fileaudio@2x.png +0 -0
- psychopy/app/Resources/light/filecss.png +0 -0
- psychopy/app/Resources/light/filecss@2x.png +0 -0
- psychopy/app/Resources/light/filecsv.png +0 -0
- psychopy/app/Resources/light/filecsv@2x.png +0 -0
- psychopy/app/Resources/light/filedesign.png +0 -0
- psychopy/app/Resources/light/filedesign@2x.png +0 -0
- psychopy/app/Resources/light/filefont.png +0 -0
- psychopy/app/Resources/light/filefont@2x.png +0 -0
- psychopy/app/Resources/light/filegit.png +0 -0
- psychopy/app/Resources/light/filegit@2x.png +0 -0
- psychopy/app/Resources/light/filehtml.png +0 -0
- psychopy/app/Resources/light/filehtml@2x.png +0 -0
- psychopy/app/Resources/light/fileimage.png +0 -0
- psychopy/app/Resources/light/fileimage@2x.png +0 -0
- psychopy/app/Resources/light/fileinfo.png +0 -0
- psychopy/app/Resources/light/fileinfo@2x.png +0 -0
- psychopy/app/Resources/light/filejs.png +0 -0
- psychopy/app/Resources/light/filejs@2x.png +0 -0
- psychopy/app/Resources/light/filejson.png +0 -0
- psychopy/app/Resources/light/filejson@2x.png +0 -0
- psychopy/app/Resources/light/filenew.png +0 -0
- psychopy/app/Resources/light/filenew32.png +0 -0
- psychopy/app/Resources/light/filenew32@2x.png +0 -0
- psychopy/app/Resources/light/filenew@2x.png +0 -0
- psychopy/app/Resources/light/fileopen.png +0 -0
- psychopy/app/Resources/light/fileopen32.png +0 -0
- psychopy/app/Resources/light/fileopen32@2x.png +0 -0
- psychopy/app/Resources/light/fileopen@2x.png +0 -0
- psychopy/app/Resources/light/filepkg.png +0 -0
- psychopy/app/Resources/light/filepkg@2x.png +0 -0
- psychopy/app/Resources/light/filepsyexp.png +0 -0
- psychopy/app/Resources/light/filepsyexp@2x.png +0 -0
- psychopy/app/Resources/light/filepy.png +0 -0
- psychopy/app/Resources/light/filepy@2x.png +0 -0
- psychopy/app/Resources/light/filesave.png +0 -0
- psychopy/app/Resources/light/filesave32.png +0 -0
- psychopy/app/Resources/light/filesave32@2x.png +0 -0
- psychopy/app/Resources/light/filesave@2x.png +0 -0
- psychopy/app/Resources/light/filesaveas.png +0 -0
- psychopy/app/Resources/light/filesaveas32.png +0 -0
- psychopy/app/Resources/light/filesaveas32@2x.png +0 -0
- psychopy/app/Resources/light/filesaveas@2x.png +0 -0
- psychopy/app/Resources/light/filetxt.png +0 -0
- psychopy/app/Resources/light/filetxt@2x.png +0 -0
- psychopy/app/Resources/light/fileunknown.png +0 -0
- psychopy/app/Resources/light/fileunknown@2x.png +0 -0
- psychopy/app/Resources/light/filevideo.png +0 -0
- psychopy/app/Resources/light/filevideo@2x.png +0 -0
- psychopy/app/Resources/light/filter.png +0 -0
- psychopy/app/Resources/light/filter@2x.png +0 -0
- psychopy/app/Resources/light/find.png +0 -0
- psychopy/app/Resources/light/find@2x.png +0 -0
- psychopy/app/Resources/light/folder-open16.png +0 -0
- psychopy/app/Resources/light/folder-open16@2x.png +0 -0
- psychopy/app/Resources/light/folder16.png +0 -0
- psychopy/app/Resources/light/folder16@2x.png +0 -0
- psychopy/app/Resources/light/foldernew16.png +0 -0
- psychopy/app/Resources/light/foldernew16@2x.png +0 -0
- psychopy/app/Resources/light/fork.png +0 -0
- psychopy/app/Resources/light/fork@2x.png +0 -0
- psychopy/app/Resources/light/github.png +0 -0
- psychopy/app/Resources/light/github@2x.png +0 -0
- psychopy/app/Resources/light/globe.png +0 -0
- psychopy/app/Resources/light/globe@2x.png +0 -0
- psychopy/app/Resources/light/globe_bug.png +0 -0
- psychopy/app/Resources/light/globe_bug@2x.png +0 -0
- psychopy/app/Resources/light/globe_greensync.png +0 -0
- psychopy/app/Resources/light/globe_greensync@2x.png +0 -0
- psychopy/app/Resources/light/globe_info.png +0 -0
- psychopy/app/Resources/light/globe_info@2x.png +0 -0
- psychopy/app/Resources/light/globe_magnifier.png +0 -0
- psychopy/app/Resources/light/globe_magnifier@2x.png +0 -0
- psychopy/app/Resources/light/globe_run.png +0 -0
- psychopy/app/Resources/light/globe_run@2x.png +0 -0
- psychopy/app/Resources/light/globe_user.png +0 -0
- psychopy/app/Resources/light/globe_user@2x.png +0 -0
- psychopy/app/Resources/light/goto16.png +0 -0
- psychopy/app/Resources/light/goto16@2x.png +0 -0
- psychopy/app/Resources/light/greendot.png +0 -0
- psychopy/app/Resources/light/greendot@2x.png +0 -0
- psychopy/app/Resources/light/greenglobe.png +0 -0
- psychopy/app/Resources/light/greenglobe@2x.png +0 -0
- psychopy/app/Resources/light/greenglobe_bug.png +0 -0
- psychopy/app/Resources/light/greenglobe_bug@2x.png +0 -0
- psychopy/app/Resources/light/greenglobe_greensync.png +0 -0
- psychopy/app/Resources/light/greenglobe_greensync@2x.png +0 -0
- psychopy/app/Resources/light/greenglobe_info.png +0 -0
- psychopy/app/Resources/light/greenglobe_info@2x.png +0 -0
- psychopy/app/Resources/light/greenglobe_magnifier.png +0 -0
- psychopy/app/Resources/light/greenglobe_magnifier@2x.png +0 -0
- psychopy/app/Resources/light/greenglobe_run.png +0 -0
- psychopy/app/Resources/light/greenglobe_run@2x.png +0 -0
- psychopy/app/Resources/light/greenglobe_user.png +0 -0
- psychopy/app/Resources/light/greenglobe_user@2x.png +0 -0
- psychopy/app/Resources/light/greydot.png +0 -0
- psychopy/app/Resources/light/greydot@2x.png +0 -0
- psychopy/app/Resources/light/greytick.png +0 -0
- psychopy/app/Resources/light/greytick@2x.png +0 -0
- psychopy/app/Resources/light/invalid_img.png +0 -0
- psychopy/app/Resources/light/jsPilot.png +0 -0
- psychopy/app/Resources/light/jsPilot@2x.png +0 -0
- psychopy/app/Resources/light/jsRun.png +0 -0
- psychopy/app/Resources/light/jsRun@2x.png +0 -0
- psychopy/app/Resources/light/libroot16.png +0 -0
- psychopy/app/Resources/light/libroot16@2x.png +0 -0
- psychopy/app/Resources/light/loop.png +0 -0
- psychopy/app/Resources/light/loop@2x.png +0 -0
- psychopy/app/Resources/light/monitor16.png +0 -0
- psychopy/app/Resources/light/monitor16@2x.png +0 -0
- psychopy/app/Resources/light/monitors.png +0 -0
- psychopy/app/Resources/light/monitors32.png +0 -0
- psychopy/app/Resources/light/monitors32@2x.png +0 -0
- psychopy/app/Resources/light/monitors@2x.png +0 -0
- psychopy/app/Resources/light/orangedot.png +0 -0
- psychopy/app/Resources/light/orangedot@2x.png +0 -0
- psychopy/app/Resources/light/pavlovia.png +0 -0
- psychopy/app/Resources/light/pavlovia16.png +0 -0
- psychopy/app/Resources/light/pavlovia16@2x.png +0 -0
- psychopy/app/Resources/light/pavlovia@2x.png +0 -0
- psychopy/app/Resources/light/pavsync.png +0 -0
- psychopy/app/Resources/light/pavsync@2x.png +0 -0
- psychopy/app/Resources/light/person_off.png +0 -0
- psychopy/app/Resources/light/person_off@2x.png +0 -0
- psychopy/app/Resources/light/person_on.png +0 -0
- psychopy/app/Resources/light/person_on@2x.png +0 -0
- psychopy/app/Resources/light/photometer.png +0 -0
- psychopy/app/Resources/light/photometer@2x.png +0 -0
- psychopy/app/Resources/light/plugin16.png +0 -0
- psychopy/app/Resources/light/plugin16@2x.png +0 -0
- psychopy/app/Resources/light/plugins32.png +0 -0
- psychopy/app/Resources/light/plugins32@2x.png +0 -0
- psychopy/app/Resources/light/plus.png +0 -0
- psychopy/app/Resources/light/plus@2x.png +0 -0
- psychopy/app/Resources/light/preferences-app.png +0 -0
- psychopy/app/Resources/light/preferences-app48.png +0 -0
- psychopy/app/Resources/light/preferences-app48@2x.png +0 -0
- psychopy/app/Resources/light/preferences-app@2x.png +0 -0
- psychopy/app/Resources/light/preferences-conn.png +0 -0
- psychopy/app/Resources/light/preferences-conn48.png +0 -0
- psychopy/app/Resources/light/preferences-conn48@2x.png +0 -0
- psychopy/app/Resources/light/preferences-conn@2x.png +0 -0
- psychopy/app/Resources/light/preferences-general.png +0 -0
- psychopy/app/Resources/light/preferences-general48.png +0 -0
- psychopy/app/Resources/light/preferences-general48@2x.png +0 -0
- psychopy/app/Resources/light/preferences-general@2x.png +0 -0
- psychopy/app/Resources/light/preferences-hardware.png +0 -0
- psychopy/app/Resources/light/preferences-hardware48.png +0 -0
- psychopy/app/Resources/light/preferences-hardware48@2x.png +0 -0
- psychopy/app/Resources/light/preferences-hardware@2x.png +0 -0
- psychopy/app/Resources/light/preferences-keyboard.png +0 -0
- psychopy/app/Resources/light/preferences-keyboard48.png +0 -0
- psychopy/app/Resources/light/preferences-keyboard48@2x.png +0 -0
- psychopy/app/Resources/light/preferences-keyboard@2x.png +0 -0
- psychopy/app/Resources/light/preferences-pilot.png +0 -0
- psychopy/app/Resources/light/preferences-pilot@2x.png +0 -0
- psychopy/app/Resources/light/preferences32.png +0 -0
- psychopy/app/Resources/light/preferences32@2x.png +0 -0
- psychopy/app/Resources/light/pyPilot.png +0 -0
- psychopy/app/Resources/light/pyPilot@2x.png +0 -0
- psychopy/app/Resources/light/pyRun.png +0 -0
- psychopy/app/Resources/light/pyRun@2x.png +0 -0
- psychopy/app/Resources/light/reddot.png +0 -0
- psychopy/app/Resources/light/reddot@2x.png +0 -0
- psychopy/app/Resources/light/redglobe.png +0 -0
- psychopy/app/Resources/light/redglobe@2x.png +0 -0
- psychopy/app/Resources/light/redglobe_bug.png +0 -0
- psychopy/app/Resources/light/redglobe_bug@2x.png +0 -0
- psychopy/app/Resources/light/redglobe_greensync.png +0 -0
- psychopy/app/Resources/light/redglobe_greensync@2x.png +0 -0
- psychopy/app/Resources/light/redglobe_info.png +0 -0
- psychopy/app/Resources/light/redglobe_info@2x.png +0 -0
- psychopy/app/Resources/light/redglobe_magnifier.png +0 -0
- psychopy/app/Resources/light/redglobe_magnifier@2x.png +0 -0
- psychopy/app/Resources/light/redglobe_run.png +0 -0
- psychopy/app/Resources/light/redglobe_run@2x.png +0 -0
- psychopy/app/Resources/light/redglobe_user.png +0 -0
- psychopy/app/Resources/light/redglobe_user@2x.png +0 -0
- psychopy/app/Resources/light/redo.png +0 -0
- psychopy/app/Resources/light/redo32.png +0 -0
- psychopy/app/Resources/light/redo32@2x.png +0 -0
- psychopy/app/Resources/light/redo@2x.png +0 -0
- psychopy/app/Resources/light/regex.png +0 -0
- psychopy/app/Resources/light/regex@2x.png +0 -0
- psychopy/app/Resources/light/removeExp32.png +0 -0
- psychopy/app/Resources/light/removeExp32@2x.png +0 -0
- psychopy/app/Resources/light/rename16.png +0 -0
- psychopy/app/Resources/light/rename16@2x.png +0 -0
- psychopy/app/Resources/light/restart.png +0 -0
- psychopy/app/Resources/light/restart@2x.png +0 -0
- psychopy/app/Resources/light/runner.png +0 -0
- psychopy/app/Resources/light/runner@2x.png +0 -0
- psychopy/app/Resources/light/runnerPilot.png +0 -0
- psychopy/app/Resources/light/runnerPilot@2x.png +0 -0
- psychopy/app/Resources/light/savebtn16.png +0 -0
- psychopy/app/Resources/light/savebtn16@2x.png +0 -0
- psychopy/app/Resources/light/search.png +0 -0
- psychopy/app/Resources/light/search@2x.png +0 -0
- psychopy/app/Resources/light/showBuilder.png +0 -0
- psychopy/app/Resources/light/showBuilder@2x.png +0 -0
- psychopy/app/Resources/light/showCoder.png +0 -0
- psychopy/app/Resources/light/showCoder@2x.png +0 -0
- psychopy/app/Resources/light/showRunner.png +0 -0
- psychopy/app/Resources/light/showRunner@2x.png +0 -0
- psychopy/app/Resources/light/starred.png +0 -0
- psychopy/app/Resources/light/starred@2x.png +0 -0
- psychopy/app/Resources/light/start.png +0 -0
- psychopy/app/Resources/light/start@2x.png +0 -0
- psychopy/app/Resources/light/stdout.png +0 -0
- psychopy/app/Resources/light/stdout@2x.png +0 -0
- psychopy/app/Resources/light/stop.png +0 -0
- psychopy/app/Resources/light/stop32.png +0 -0
- psychopy/app/Resources/light/stop32@2x.png +0 -0
- psychopy/app/Resources/light/stop@2x.png +0 -0
- psychopy/app/Resources/light/switchCtrlBot.png +0 -0
- psychopy/app/Resources/light/switchCtrlBot@2x.png +0 -0
- psychopy/app/Resources/light/switchCtrlLeft.png +0 -0
- psychopy/app/Resources/light/switchCtrlLeft@2x.png +0 -0
- psychopy/app/Resources/light/switchCtrlRight.png +0 -0
- psychopy/app/Resources/light/switchCtrlRight@2x.png +0 -0
- psychopy/app/Resources/light/switchCtrlTop.png +0 -0
- psychopy/app/Resources/light/switchCtrlTop@2x.png +0 -0
- psychopy/app/Resources/light/tick.png +0 -0
- psychopy/app/Resources/light/tick@2x.png +0 -0
- psychopy/app/Resources/light/undo.png +0 -0
- psychopy/app/Resources/light/undo32.png +0 -0
- psychopy/app/Resources/light/undo32@2x.png +0 -0
- psychopy/app/Resources/light/undo@2x.png +0 -0
- psychopy/app/Resources/light/unstarred.png +0 -0
- psychopy/app/Resources/light/unstarred@2x.png +0 -0
- psychopy/app/Resources/light/user_none.png +0 -0
- psychopy/app/Resources/light/view-refresh16.png +0 -0
- psychopy/app/Resources/light/view-refresh16@2x.png +0 -0
- psychopy/app/Resources/light/viewbtn16.png +0 -0
- psychopy/app/Resources/light/viewbtn16@2x.png +0 -0
- psychopy/app/Resources/light/windows16.png +0 -0
- psychopy/app/Resources/light/windows16@2x.png +0 -0
- psychopy/app/Resources/moveComponentIcons.py +50 -0
- psychopy/app/Resources/psychopy.desktop +13 -0
- psychopy/app/Resources/psychopy.icns +0 -0
- psychopy/app/Resources/psychopy.ico +0 -0
- psychopy/app/Resources/psychopy.png +0 -0
- psychopy/app/Resources/psychopy.xml +9 -0
- psychopy/app/Resources/psychopy@2x.png +0 -0
- psychopy/app/Resources/routine_templates/Basic.psyexp +344 -0
- psychopy/app/Resources/routine_templates/Misc.psyexp +228 -0
- psychopy/app/Resources/routine_templates/Online.psyexp +200 -0
- psychopy/app/Resources/routine_templates/Trials.psyexp +735 -0
- psychopy/app/Resources/routine_templates/readme.md +14 -0
- psychopy/app/Resources/runner.ico +0 -0
- psychopy/app/Resources/splash.png +0 -0
- psychopy/app/Resources/splash@2x.png +0 -0
- psychopy/app/Resources/tips.txt +45 -0
- psychopy/app/Resources/tips_ar_001.txt +45 -0
- psychopy/app/Resources/tips_fr_FR.txt +45 -0
- psychopy/app/Resources/tips_ja_JP.txt +42 -0
- psychopy/app/Resources/tips_zh_CN.txt +45 -0
- psychopy/app/Resources/window.ico +0 -0
- psychopy/app/__init__.py +339 -0
- psychopy/app/__main__.py +3 -0
- psychopy/app/_psychopyApp.py +1298 -0
- psychopy/app/appData.spec +58 -0
- psychopy/app/builder/__init__.py +5 -0
- psychopy/app/builder/builder.py +4738 -0
- psychopy/app/builder/dialogs/__init__.py +1910 -0
- psychopy/app/builder/dialogs/dlgsCode.py +631 -0
- psychopy/app/builder/dialogs/dlgsConditions.py +669 -0
- psychopy/app/builder/dialogs/findDlg.py +275 -0
- psychopy/app/builder/dialogs/paramCtrls.py +1802 -0
- psychopy/app/builder/validators.py +589 -0
- psychopy/app/coder/__init__.py +8 -0
- psychopy/app/coder/codeEditorBase.py +460 -0
- psychopy/app/coder/coder.py +3100 -0
- psychopy/app/coder/fileBrowser.py +714 -0
- psychopy/app/coder/folding.py +128 -0
- psychopy/app/coder/psychoParser.py +139 -0
- psychopy/app/coder/repl.py +496 -0
- psychopy/app/coder/sourceTree.py +302 -0
- psychopy/app/colorpicker/__init__.py +594 -0
- psychopy/app/colorpicker/ui.py +336 -0
- psychopy/app/connections/__init__.py +10 -0
- psychopy/app/connections/news.py +104 -0
- psychopy/app/connections/sendusage.py +61 -0
- psychopy/app/connections/updates.py +642 -0
- psychopy/app/console.py +164 -0
- psychopy/app/deviceManager/__init__.py +1 -0
- psychopy/app/deviceManager/addDialog.py +218 -0
- psychopy/app/deviceManager/dialog.py +185 -0
- psychopy/app/deviceManager/panel.py +191 -0
- psychopy/app/deviceManager/utils.py +60 -0
- psychopy/app/dialogs.py +664 -0
- psychopy/app/errorDlg.py +238 -0
- psychopy/app/frametracker.py +8 -0
- psychopy/app/idle.py +181 -0
- psychopy/app/jobs.py +676 -0
- psychopy/app/linuxconfig/__init__.py +153 -0
- psychopy/app/linuxconfig/ui.py +88 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +12695 -0
- psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.po +10199 -0
- psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/da_DK/LC_MESSAGE/messages.po +10199 -0
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.po +11221 -0
- psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/el_GR/LC_MESSAGE/messages.po +10200 -0
- psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_NZ/LC_MESSAGE/messages.po +10200 -0
- psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_US/LC_MESSAGE/messages.po +10195 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +11917 -0
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +11924 -0
- psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_US/LC_MESSAGE/messages.po +11917 -0
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.po +11084 -0
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.po +11590 -0
- psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fi_FI/LC_MESSAGE/messages.po +10199 -0
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.po +11091 -0
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.po +11072 -0
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.po +11071 -0
- psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hu_HU/LC_MESSAGE/messages.po +10200 -0
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.po +11072 -0
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +11268 -0
- psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ko_KR/LC_MESSAGE/messages.po +10199 -0
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.po +11463 -0
- psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nl_NL/LC_MESSAGE/messages.po +10200 -0
- psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nn_NO/LC_MESSAGE/messages.po +10200 -0
- psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pl_PL/LC_MESSAGE/messages.po +10200 -0
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +11288 -0
- psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ro_RO/LC_MESSAGE/messages.po +10200 -0
- psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ru_RU/LC_MESSAGE/messages.po +10199 -0
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.po +11441 -0
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.po +11069 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.po +12085 -0
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.po +11929 -0
- psychopy/app/localizedStrings.py +386 -0
- psychopy/app/pavlovia_ui/__init__.py +22 -0
- psychopy/app/pavlovia_ui/_base.py +268 -0
- psychopy/app/pavlovia_ui/functions.py +176 -0
- psychopy/app/pavlovia_ui/menu.py +140 -0
- psychopy/app/pavlovia_ui/project.py +943 -0
- psychopy/app/pavlovia_ui/search.py +444 -0
- psychopy/app/pavlovia_ui/sync.py +137 -0
- psychopy/app/pavlovia_ui/user.py +264 -0
- psychopy/app/plugin_manager/__init__.py +5 -0
- psychopy/app/plugin_manager/dialog.py +402 -0
- psychopy/app/plugin_manager/output.py +132 -0
- psychopy/app/plugin_manager/packageIndex.py +303 -0
- psychopy/app/plugin_manager/packages.py +643 -0
- psychopy/app/plugin_manager/plugins.py +1363 -0
- psychopy/app/plugin_manager/utils.py +115 -0
- psychopy/app/preferencesDlg.py +771 -0
- psychopy/app/psychopyApp.py +207 -0
- psychopy/app/ribbon.py +1019 -0
- psychopy/app/runner/__init__.py +1 -0
- psychopy/app/runner/runner.py +1299 -0
- psychopy/app/runner/scriptProcess.py +363 -0
- psychopy/app/stdout/__init__.py +1 -0
- psychopy/app/stdout/stdOutRich.py +410 -0
- psychopy/app/sysInfoDlg.py +242 -0
- psychopy/app/themes/__init__.py +78 -0
- psychopy/app/themes/colors.py +201 -0
- psychopy/app/themes/css/contrast_black.css +112 -0
- psychopy/app/themes/css/contrast_white.css +115 -0
- psychopy/app/themes/css/dark.css +112 -0
- psychopy/app/themes/css/light.css +115 -0
- psychopy/app/themes/fonts.py +629 -0
- psychopy/app/themes/handlers.py +321 -0
- psychopy/app/themes/icons.py +267 -0
- psychopy/app/themes/spec/Classic.json +154 -0
- psychopy/app/themes/spec/ClassicDark.json +154 -0
- psychopy/app/themes/spec/GitHub.json +154 -0
- psychopy/app/themes/spec/HiVisDark.json +153 -0
- psychopy/app/themes/spec/HiVisLight.json +154 -0
- psychopy/app/themes/spec/MinimalDark.json +154 -0
- psychopy/app/themes/spec/MinimalLight.json +153 -0
- psychopy/app/themes/spec/PsychopyDark.json +231 -0
- psychopy/app/themes/spec/PsychopyLight.json +236 -0
- psychopy/app/themes/ui.py +74 -0
- psychopy/app/ui/__init__.py +184 -0
- psychopy/app/urls.py +31 -0
- psychopy/app/utils.py +1741 -0
- psychopy/app/viewer/__init__.py +0 -0
- psychopy/assets/Psychopy Window Favicon@16w.png +0 -0
- psychopy/assets/Psychopy Window Favicon@32w.png +0 -0
- psychopy/assets/USB-C.png +0 -0
- psychopy/assets/USB.png +0 -0
- psychopy/assets/__init__.py +0 -0
- psychopy/assets/click.png +0 -0
- psychopy/assets/clicknext.png +0 -0
- psychopy/assets/creditCard.png +0 -0
- psychopy/assets/default.mp3 +0 -0
- psychopy/assets/default.mp4 +0 -0
- psychopy/assets/default.png +0 -0
- psychopy/assets/fonts/Arvo-Bold.ttf +0 -0
- psychopy/assets/fonts/Arvo-BoldItalic.ttf +0 -0
- psychopy/assets/fonts/Arvo-Italic.ttf +0 -0
- psychopy/assets/fonts/Arvo-Regular.ttf +0 -0
- psychopy/assets/fonts/DejaVuSerif.ttf +0 -0
- psychopy/assets/fonts/IndieFlower-Regular.ttf +0 -0
- psychopy/assets/fonts/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
- psychopy/assets/fonts/JetBrainsMono-VariableFont_wght.ttf +0 -0
- psychopy/assets/fonts/NotoSans-Bold.ttf +0 -0
- psychopy/assets/fonts/NotoSans-BoldItalic.ttf +0 -0
- psychopy/assets/fonts/NotoSans-Italic.ttf +0 -0
- psychopy/assets/fonts/NotoSans-Regular.ttf +0 -0
- psychopy/assets/next.png +0 -0
- psychopy/assets/psychopy.ico +0 -0
- psychopy/assets/psychopy.png +0 -0
- psychopy/assets/templates/__init__.py +0 -0
- psychopy/assets/templates/instruct1.png +0 -0
- psychopy/assets/templates/instruct2.png +0 -0
- psychopy/assets/touch.png +0 -0
- psychopy/assets/touchnext.png +0 -0
- psychopy/assets/voicekeyThresholdStim.wav +0 -0
- psychopy/assets/window.ico +0 -0
- psychopy/changes/2023.1.0.md +9 -0
- psychopy/changes/2024.1.0.md +16 -0
- psychopy/changes/__init__.py +0 -0
- psychopy/clock.py +619 -0
- psychopy/colors.py +1058 -0
- psychopy/compatibility.py +147 -0
- psychopy/constants.py +87 -0
- psychopy/contrib/__init__.py +0 -0
- psychopy/contrib/configobj/LICENSE +39 -0
- psychopy/contrib/configobj/__init__.py +2455 -0
- psychopy/contrib/configobj/_version.py +2 -0
- psychopy/contrib/configobj/validate.py +1458 -0
- psychopy/contrib/lazy_import.py +402 -0
- psychopy/contrib/mseq.py +273 -0
- psychopy/contrib/mseqSearch.py +183 -0
- psychopy/contrib/psi.py +100 -0
- psychopy/contrib/quest.py +484 -0
- psychopy/contrib/tesselate.py +188 -0
- psychopy/core.py +167 -0
- psychopy/data/__init__.py +45 -0
- psychopy/data/base.py +566 -0
- psychopy/data/counterbalance.py +210 -0
- psychopy/data/experiment.py +1049 -0
- psychopy/data/fit.py +248 -0
- psychopy/data/routine.py +94 -0
- psychopy/data/shelf.py +237 -0
- psychopy/data/staircase.py +2270 -0
- psychopy/data/trial.py +2505 -0
- psychopy/data/utils.py +858 -0
- psychopy/demos/__init__.py +0 -0
- psychopy/demos/builder/Design Templates/branchedExperiment/README.md +5 -0
- psychopy/demos/builder/Design Templates/branchedExperiment/branchedExperiment.psyexp +354 -0
- psychopy/demos/builder/Design Templates/branchedExperiment/trialTypes.xlsx +0 -0
- psychopy/demos/builder/Design Templates/psychophysicsStaircase/README.md +20 -0
- psychopy/demos/builder/Design Templates/psychophysicsStaircase/psychophysicsStaircase.psyexp +286 -0
- psychopy/demos/builder/Design Templates/psychophysicsStairsInterleaved/README.md +14 -0
- psychopy/demos/builder/Design Templates/psychophysicsStairsInterleaved/psychophysicsStaircaseInterleaved.psyexp +340 -0
- psychopy/demos/builder/Design Templates/psychophysicsStairsInterleaved/stairDefinitions.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/README.md +18 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/chooseBlock.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/facesBlock.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/housesBlock.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks.psyexp +219 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/stims/face01.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/stims/face02.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/stims/face03.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/stims/house01.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/stims/house02.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/stims/house03.jpg +0 -0
- psychopy/demos/builder/Experiments/BART/README.md +30 -0
- psychopy/demos/builder/Experiments/BART/assets/background.jpg +0 -0
- psychopy/demos/builder/Experiments/BART/assets/background.png +0 -0
- psychopy/demos/builder/Experiments/BART/assets/bang.mp3 +0 -0
- psychopy/demos/builder/Experiments/BART/assets/bang.wav +0 -0
- psychopy/demos/builder/Experiments/BART/assets/blueBalloon.png +0 -0
- psychopy/demos/builder/Experiments/BART/assets/greenBalloon.png +0 -0
- psychopy/demos/builder/Experiments/BART/assets/redBalloon.png +0 -0
- psychopy/demos/builder/Experiments/BART/bart.psyexp +844 -0
- psychopy/demos/builder/Experiments/BART/spreadsheets/conditions.xlsx +0 -0
- psychopy/demos/builder/Experiments/BigFiveInventory/BFI.psyexp +255 -0
- psychopy/demos/builder/Experiments/BigFiveInventory/README.md +23 -0
- psychopy/demos/builder/Experiments/BigFiveInventory/TIPI.xlsx +0 -0
- psychopy/demos/builder/Experiments/BigFiveInventory/bigFiveItems.xlsx +0 -0
- psychopy/demos/builder/Experiments/BigFiveInventory/demographics.xlsx +0 -0
- psychopy/demos/builder/Experiments/BigFiveInventory/mini_IPIP.xlsx +0 -0
- psychopy/demos/builder/Experiments/GoNoGo/conditions.xlsx +0 -0
- psychopy/demos/builder/Experiments/GoNoGo/gng.psyexp +462 -0
- psychopy/demos/builder/Experiments/GoNoGo/go.png +0 -0
- psychopy/demos/builder/Experiments/GoNoGo/nogo.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/README.md +5 -0
- psychopy/demos/builder/Experiments/dragAndDrop/drag_and_drop.psyexp +494 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/blank_grid.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/make_shapes.psyexp +221 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/readme.md +4 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_1.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_10.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_2.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_3.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_4.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_5.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_6.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_7.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_8.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_9.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solutions.xlsx +0 -0
- psychopy/demos/builder/Experiments/goNoGo/readme.md +14 -0
- psychopy/demos/builder/Experiments/mentalRotation/F.png +0 -0
- psychopy/demos/builder/Experiments/mentalRotation/FR.png +0 -0
- psychopy/demos/builder/Experiments/mentalRotation/MentalRot.csv +33 -0
- psychopy/demos/builder/Experiments/mentalRotation/MentalRotation.psyexp +646 -0
- psychopy/demos/builder/Experiments/mentalRotation/README.md +23 -0
- psychopy/demos/builder/Experiments/navon/NavonTask.psyexp +509 -0
- psychopy/demos/builder/Experiments/navon/README.md +26 -0
- psychopy/demos/builder/Experiments/navon/bigHsmallH.png +0 -0
- psychopy/demos/builder/Experiments/navon/bigHsmallS.png +0 -0
- psychopy/demos/builder/Experiments/navon/bigSsmallH.png +0 -0
- psychopy/demos/builder/Experiments/navon/bigSsmallS.png +0 -0
- psychopy/demos/builder/Experiments/navon/mask.png +0 -0
- psychopy/demos/builder/Experiments/navon/stimuli.pptx +0 -0
- psychopy/demos/builder/Experiments/navon/trialTypes.xlsx +0 -0
- psychopy/demos/builder/Experiments/sternberg/README.md +14 -0
- psychopy/demos/builder/Experiments/sternberg/mainTrials.xlsx +0 -0
- psychopy/demos/builder/Experiments/sternberg/pracTrials.xlsx +0 -0
- psychopy/demos/builder/Experiments/sternberg/sternberg.psyexp +649 -0
- psychopy/demos/builder/Experiments/stroop/README.md +15 -0
- psychopy/demos/builder/Experiments/stroop/stroop.psyexp +321 -0
- psychopy/demos/builder/Experiments/stroop/trialTypes.csv +7 -0
- psychopy/demos/builder/Experiments/stroopExtended/README.md +14 -0
- psychopy/demos/builder/Experiments/stroopExtended/stroop.psyexp +418 -0
- psychopy/demos/builder/Experiments/stroopExtended/stroopReverse.psyexp +418 -0
- psychopy/demos/builder/Experiments/stroopExtended/trialTypes.xlsx +0 -0
- psychopy/demos/builder/Experiments/stroopExtended/trialTypesReverse.xlsx +0 -0
- psychopy/demos/builder/Experiments/stroopVoice/README.md +27 -0
- psychopy/demos/builder/Experiments/stroopVoice/conditions.xlsx +0 -0
- psychopy/demos/builder/Experiments/stroopVoice/stroopVoice.psyexp +382 -0
- psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +371 -0
- psychopy/demos/builder/Feature Demos/buttonBox/readme.md +5 -0
- psychopy/demos/builder/Feature Demos/counterbalance/counterbalance.psyexp +308 -0
- psychopy/demos/builder/Feature Demos/gratings/gratings.psyexp +391 -0
- psychopy/demos/builder/Feature Demos/gratings/readme.md +8 -0
- psychopy/demos/builder/Feature Demos/movies/movie.psyexp +220 -0
- psychopy/demos/builder/Feature Demos/movies/readme.md +3 -0
- psychopy/demos/builder/Feature Demos/noise/face.jpg +0 -0
- psychopy/demos/builder/Feature Demos/noise/noise.psyexp +477 -0
- psychopy/demos/builder/Feature Demos/noise/readme.md +3 -0
- psychopy/demos/builder/Feature Demos/panorama/panImg.jpg +0 -0
- psychopy/demos/builder/Feature Demos/panorama/panorama.psyexp +177 -0
- psychopy/demos/builder/Feature Demos/pilotMode/pilotMode.psyexp +434 -0
- psychopy/demos/builder/Feature Demos/pilotMode/readme.md +7 -0
- psychopy/demos/builder/Feature Demos/progress/progressBar.psyexp +451 -0
- psychopy/demos/builder/Feature Demos/progress/readme.md +1 -0
- psychopy/demos/builder/Feature Demos/sliders/README.md +8 -0
- psychopy/demos/builder/Feature Demos/sliders/fruitConditions.xlsx +0 -0
- psychopy/demos/builder/Feature Demos/sliders/sliders.psyexp +984 -0
- psychopy/demos/builder/Feature Demos/visualValidator/readme.md +7 -0
- psychopy/demos/builder/Feature Demos/visualValidator/visualValidator.psyexp +199 -0
- psychopy/demos/builder/Hardware/EEG_parallel_component/EEG_triggers_parallel_comp.psyexp +639 -0
- psychopy/demos/builder/Hardware/EEG_serial_code/EEG_triggers_serial_code.psyexp +415 -0
- psychopy/demos/builder/Hardware/EEG_serial_component/EEG_triggers_serial_comp.psyexp +659 -0
- psychopy/demos/builder/Hardware/EGI_netstation/README.md +17 -0
- psychopy/demos/builder/Hardware/EGI_netstation/stroop.psyexp +339 -0
- psychopy/demos/builder/Hardware/EGI_netstation/trialTypesEEG.csv +7 -0
- psychopy/demos/builder/Hardware/Eyetracking_visual_search/readme.md +19 -0
- psychopy/demos/builder/Hardware/Eyetracking_visual_search/trials_params.xlsx +0 -0
- psychopy/demos/builder/Hardware/Eyetracking_visual_search/visualSearch.psyexp +830 -0
- psychopy/demos/builder/Hardware/camera/camera.psyexp +330 -0
- psychopy/demos/builder/Hardware/camera/readme.md +6 -0
- psychopy/demos/builder/Hardware/eyetracking/eyetracking.psyexp +459 -0
- psychopy/demos/builder/Hardware/eyetracking/readme.md +7 -0
- psychopy/demos/builder/Hardware/eyetracking_custom_cal/Bullseye_grey.mov +0 -0
- psychopy/demos/builder/Hardware/eyetracking_custom_cal/eyetracking_custom_cal.psyexp +468 -0
- psychopy/demos/builder/Hardware/eyetracking_custom_cal/readme.md +7 -0
- psychopy/demos/builder/Hardware/fMRI/fMRI_demo.psyexp +211 -0
- psychopy/demos/builder/Hardware/fMRI/readme.md +7 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer/lsl_triggers_demo.psyexp +360 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer/lsl_triggers_demo_legacy.psyexp +360 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer/lsl_triggers_demo_legacy_legacy.psyexp +312 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy.psyexp +360 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy_legacy.psyexp +360 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy_legacy_legacy.psyexp +312 -0
- psychopy/demos/builder/Hardware/microphone/microphone.psyexp +484 -0
- psychopy/demos/builder/Hardware/microphone/phrases.xlsx +0 -0
- psychopy/demos/builder/Hardware/microphone/readme.md +9 -0
- psychopy/demos/builder/Hardware/pump/README.md +19 -0
- psychopy/demos/builder/Hardware/pump/pump.psyexp +646 -0
- psychopy/demos/builder/Helper Tools/achorVSalignment/FlowCircular-Regular.ttf +0 -0
- psychopy/demos/builder/Helper Tools/achorVSalignment/anchorAlignment.psyexp +350 -0
- psychopy/demos/builder/Helper Tools/achorVSalignment/readme.md +5 -0
- psychopy/demos/builder/Helper Tools/clockFace/README.md +3 -0
- psychopy/demos/builder/Helper Tools/clockFace/clockFace.psyexp +211 -0
- psychopy/demos/builder/Helper Tools/colors/README.md +5 -0
- psychopy/demos/builder/Helper Tools/colors/colors.psyexp +321 -0
- psychopy/demos/builder/Helper Tools/drawPolygon/README.md +5 -0
- psychopy/demos/builder/Helper Tools/drawPolygon/drawPolygon.psyexp +704 -0
- psychopy/demos/builder/Helper Tools/keyNameFinder/README.md +14 -0
- psychopy/demos/builder/Helper Tools/keyNameFinder/keyNameFinder.psyexp +225 -0
- psychopy/demos/builder/Helper Tools/spatialUnits/README.md +6 -0
- psychopy/demos/builder/Helper Tools/spatialUnits/unitDemo.psyexp +206 -0
- psychopy/demos/builder/README.txt +43 -0
- psychopy/demos/builder/__init__.py +0 -0
- psychopy/demos/coder/__init__.py +0 -0
- psychopy/demos/coder/basic/hello_world.py +37 -0
- psychopy/demos/coder/csvFromPsydat.py +29 -0
- psychopy/demos/coder/experiment control/JND_staircase_analysis.py +85 -0
- psychopy/demos/coder/experiment control/JND_staircase_exp.py +110 -0
- psychopy/demos/coder/experiment control/TrialHandler.py +64 -0
- psychopy/demos/coder/experiment control/TrialHandler2.py +42 -0
- psychopy/demos/coder/experiment control/__init__.py +0 -0
- psychopy/demos/coder/experiment control/autoDraw_autoLog.py +50 -0
- psychopy/demos/coder/experiment control/experimentHandler.py +57 -0
- psychopy/demos/coder/experiment control/fMRI_launchScan.py +74 -0
- psychopy/demos/coder/experiment control/gammaMotionAnalysis.py +68 -0
- psychopy/demos/coder/experiment control/gammaMotionNull.py +169 -0
- psychopy/demos/coder/experiment control/logFiles.py +55 -0
- psychopy/demos/coder/experiment control/piloting.py +65 -0
- psychopy/demos/coder/experiment control/runtimeInfo.py +79 -0
- psychopy/demos/coder/hardware/CRS_BitsBox.py +75 -0
- psychopy/demos/coder/hardware/CRS_BitsPlusPlus.py +73 -0
- psychopy/demos/coder/hardware/RiftHeadTrackingExample.py +95 -0
- psychopy/demos/coder/hardware/RiftMinimal.py +44 -0
- psychopy/demos/coder/hardware/VSHD_Distortion.py +49 -0
- psychopy/demos/coder/hardware/__init__.py +0 -0
- psychopy/demos/coder/hardware/camera.py +90 -0
- psychopy/demos/coder/hardware/cedrusRB730.py +38 -0
- psychopy/demos/coder/hardware/crsBitsAdvancedDemo.py +780 -0
- psychopy/demos/coder/hardware/egi_netstation.py +45 -0
- psychopy/demos/coder/hardware/hdf5_extract.py +133 -0
- psychopy/demos/coder/hardware/ioLab_bbox.py +62 -0
- psychopy/demos/coder/hardware/labjack_u3.py +61 -0
- psychopy/demos/coder/hardware/monitorDemo.py +28 -0
- psychopy/demos/coder/hardware/parallelPortOutput.py +49 -0
- psychopy/demos/coder/hardware/qmixPump.py +79 -0
- psychopy/demos/coder/hardware/testSoundLatency.py +127 -0
- psychopy/demos/coder/input/GUI.py +52 -0
- psychopy/demos/coder/input/__init__.py +0 -0
- psychopy/demos/coder/input/customMouse.py +51 -0
- psychopy/demos/coder/input/joystick_universal.py +84 -0
- psychopy/demos/coder/input/keyNameFinder.py +39 -0
- psychopy/demos/coder/input/mic.png +0 -0
- psychopy/demos/coder/input/mouse.py +66 -0
- psychopy/demos/coder/iohub/delaytest.py +231 -0
- psychopy/demos/coder/iohub/eyetracking/gcCursor/images/canal.jpg +0 -0
- psychopy/demos/coder/iohub/eyetracking/gcCursor/images/fall.jpg +0 -0
- psychopy/demos/coder/iohub/eyetracking/gcCursor/images/lake.jpg +0 -0
- psychopy/demos/coder/iohub/eyetracking/gcCursor/images/party.jpg +0 -0
- psychopy/demos/coder/iohub/eyetracking/gcCursor/images/swimming.jpg +0 -0
- psychopy/demos/coder/iohub/eyetracking/gcCursor/readTrialEventsByConditionVariables.py +67 -0
- psychopy/demos/coder/iohub/eyetracking/gcCursor/readTrialEventsByMessages.py +34 -0
- psychopy/demos/coder/iohub/eyetracking/gcCursor/run.py +323 -0
- psychopy/demos/coder/iohub/eyetracking/gcCursor/trial_conditions.xlsx +0 -0
- psychopy/demos/coder/iohub/eyetracking/simple.py +147 -0
- psychopy/demos/coder/iohub/eyetracking/validation.py +251 -0
- psychopy/demos/coder/iohub/iodatastore/saveEventReport.py +56 -0
- psychopy/demos/coder/iohub/keyboard.py +189 -0
- psychopy/demos/coder/iohub/keyboardreactiontime.py +88 -0
- psychopy/demos/coder/iohub/launchHub.py +160 -0
- psychopy/demos/coder/iohub/mouse.py +112 -0
- psychopy/demos/coder/iohub/mouse_multi_window.py +124 -0
- psychopy/demos/coder/iohub/serial/_parseserial.py +53 -0
- psychopy/demos/coder/iohub/serial/customparser.py +84 -0
- psychopy/demos/coder/iohub/serial/pstbox.py +166 -0
- psychopy/demos/coder/iohub/wintab/_wintabgraphics.py +281 -0
- psychopy/demos/coder/iohub/wintab/pen_demo.py +260 -0
- psychopy/demos/coder/misc/encrypt_data.py +48 -0
- psychopy/demos/coder/misc/hdf5_2_csv +33 -0
- psychopy/demos/coder/misc/makeMovie.py +28 -0
- psychopy/demos/coder/misc/rigidBodyTransform.py +76 -0
- psychopy/demos/coder/stimuli/Campaign.ttf +0 -0
- psychopy/demos/coder/stimuli/MovieStim.py +65 -0
- psychopy/demos/coder/stimuli/__init__.py +0 -0
- psychopy/demos/coder/stimuli/aperture.py +37 -0
- psychopy/demos/coder/stimuli/beach.jpg +0 -0
- psychopy/demos/coder/stimuli/bufferImageStim.py +78 -0
- psychopy/demos/coder/stimuli/clockface.py +43 -0
- psychopy/demos/coder/stimuli/colorPalette.py +134 -0
- psychopy/demos/coder/stimuli/compare_text_timing.py +193 -0
- psychopy/demos/coder/stimuli/counterphase.py +43 -0
- psychopy/demos/coder/stimuli/customTextures.py +57 -0
- psychopy/demos/coder/stimuli/dot_gabors.py +35 -0
- psychopy/demos/coder/stimuli/dots.py +35 -0
- psychopy/demos/coder/stimuli/elementArrays.py +92 -0
- psychopy/demos/coder/stimuli/embeddedOpenGL.py +35 -0
- psychopy/demos/coder/stimuli/face.jpg +0 -0
- psychopy/demos/coder/stimuli/face_jpg.py +48 -0
- psychopy/demos/coder/stimuli/gabor.py +30 -0
- psychopy/demos/coder/stimuli/imagesAndPatches.py +51 -0
- psychopy/demos/coder/stimuli/jwpIntro.mp4 +0 -0
- psychopy/demos/coder/stimuli/kanizsa.py +41 -0
- psychopy/demos/coder/stimuli/maskReveal.py +63 -0
- psychopy/demos/coder/stimuli/plaid.py +43 -0
- psychopy/demos/coder/stimuli/ratingScale.py +183 -0
- psychopy/demos/coder/stimuli/rotatingFlashingWedge.py +37 -0
- psychopy/demos/coder/stimuli/screensAndWindows.py +58 -0
- psychopy/demos/coder/stimuli/secondOrderGratings.py +66 -0
- psychopy/demos/coder/stimuli/shapeContains.py +50 -0
- psychopy/demos/coder/stimuli/shapes.py +63 -0
- psychopy/demos/coder/stimuli/soundStimuli.py +49 -0
- psychopy/demos/coder/stimuli/starField.py +48 -0
- psychopy/demos/coder/stimuli/stim3d.py +107 -0
- psychopy/demos/coder/stimuli/textBoxStim/textbox_glyph_placement.py +93 -0
- psychopy/demos/coder/stimuli/textBoxStim/textbox_simple.py +71 -0
- psychopy/demos/coder/stimuli/textStimuli.py +106 -0
- psychopy/demos/coder/stimuli/textbox_editable.py +64 -0
- psychopy/demos/coder/stimuli/variousVisualStims.py +47 -0
- psychopy/demos/coder/stimuli/visual_noise.py +31 -0
- psychopy/demos/coder/sysInfo.py +56 -0
- psychopy/demos/coder/timing/__init__.py +0 -0
- psychopy/demos/coder/timing/callOnFlip.py +39 -0
- psychopy/demos/coder/timing/clocksAndTimers.py +46 -0
- psychopy/demos/coder/timing/millikeyKeyboardTimingTest.py +323 -0
- psychopy/demos/coder/timing/timeByFrames.py +80 -0
- psychopy/demos/coder/timing/timeByFramesEx.py +107 -0
- psychopy/demos/coder/understanding psychopy/colors.py +70 -0
- psychopy/demos/coder/understanding psychopy/fontLayout.py +69 -0
- psychopy/demos/demo_migration.py +214 -0
- psychopy/demos/modernizeDemos.py +16 -0
- psychopy/demos/test_demo_migration.py +155 -0
- psychopy/devices/__init__.py +8 -0
- psychopy/event.py +1339 -0
- psychopy/exceptions.py +59 -0
- psychopy/experiment/__init__.py +51 -0
- psychopy/experiment/_experiment.py +1514 -0
- psychopy/experiment/blankTemplate.xltx +0 -0
- psychopy/experiment/components/__init__.py +402 -0
- psychopy/experiment/components/_base.py +1689 -0
- psychopy/experiment/components/aperture/__init__.py +153 -0
- psychopy/experiment/components/aperture/classic/aperture.png +0 -0
- psychopy/experiment/components/aperture/classic/aperture@2x.png +0 -0
- psychopy/experiment/components/aperture/dark/aperture.png +0 -0
- psychopy/experiment/components/aperture/dark/aperture@2x.png +0 -0
- psychopy/experiment/components/aperture/light/aperture.png +0 -0
- psychopy/experiment/components/aperture/light/aperture@2x.png +0 -0
- psychopy/experiment/components/brush/__init__.py +165 -0
- psychopy/experiment/components/brush/classic/brush.png +0 -0
- psychopy/experiment/components/brush/classic/brush@2x.png +0 -0
- psychopy/experiment/components/brush/dark/brush.png +0 -0
- psychopy/experiment/components/brush/dark/brush@2x.png +0 -0
- psychopy/experiment/components/brush/light/brush.png +0 -0
- psychopy/experiment/components/brush/light/brush@2x.png +0 -0
- psychopy/experiment/components/button/__init__.py +493 -0
- psychopy/experiment/components/button/classic/button.png +0 -0
- psychopy/experiment/components/button/classic/button@2x.png +0 -0
- psychopy/experiment/components/button/dark/button.png +0 -0
- psychopy/experiment/components/button/dark/button@2x.png +0 -0
- psychopy/experiment/components/button/light/button.png +0 -0
- psychopy/experiment/components/button/light/button@2x.png +0 -0
- psychopy/experiment/components/buttonBox/__init__.py +322 -0
- psychopy/experiment/components/buttonBox/classic/buttonBox.png +0 -0
- psychopy/experiment/components/buttonBox/classic/buttonBox@2x.png +0 -0
- psychopy/experiment/components/buttonBox/dark/buttonBox.png +0 -0
- psychopy/experiment/components/buttonBox/dark/buttonBox@2x.png +0 -0
- psychopy/experiment/components/buttonBox/light/buttonBox.png +0 -0
- psychopy/experiment/components/buttonBox/light/buttonBox@2x.png +0 -0
- psychopy/experiment/components/camera/__init__.py +381 -0
- psychopy/experiment/components/camera/classic/webcam.png +0 -0
- psychopy/experiment/components/camera/classic/webcam@2x.png +0 -0
- psychopy/experiment/components/camera/dark/webcam.png +0 -0
- psychopy/experiment/components/camera/dark/webcam@2x.png +0 -0
- psychopy/experiment/components/camera/light/webcam.png +0 -0
- psychopy/experiment/components/camera/light/webcam@2x.png +0 -0
- psychopy/experiment/components/code/__init__.py +299 -0
- psychopy/experiment/components/code/classic/code.png +0 -0
- psychopy/experiment/components/code/classic/code@2x.png +0 -0
- psychopy/experiment/components/code/dark/code.png +0 -0
- psychopy/experiment/components/code/dark/code@2x.png +0 -0
- psychopy/experiment/components/code/light/code.png +0 -0
- psychopy/experiment/components/code/light/code@2x.png +0 -0
- psychopy/experiment/components/dots/__init__.py +199 -0
- psychopy/experiment/components/dots/classic/dots.png +0 -0
- psychopy/experiment/components/dots/classic/dots@2x.png +0 -0
- psychopy/experiment/components/dots/dark/dots.png +0 -0
- psychopy/experiment/components/dots/dark/dots@2x.png +0 -0
- psychopy/experiment/components/dots/dots.xcf +0 -0
- psychopy/experiment/components/dots/light/dots.png +0 -0
- psychopy/experiment/components/dots/light/dots@2x.png +0 -0
- psychopy/experiment/components/eyetracker_record/__init__.py +194 -0
- psychopy/experiment/components/eyetracker_record/classic/eyetracker_record.png +0 -0
- psychopy/experiment/components/eyetracker_record/classic/eyetracker_record@2x.png +0 -0
- psychopy/experiment/components/eyetracker_record/dark/eyetracker_record.png +0 -0
- psychopy/experiment/components/eyetracker_record/dark/eyetracker_record@2x.png +0 -0
- psychopy/experiment/components/eyetracker_record/light/eyetracker_record.png +0 -0
- psychopy/experiment/components/eyetracker_record/light/eyetracker_record@2x.png +0 -0
- psychopy/experiment/components/form/__init__.py +227 -0
- psychopy/experiment/components/form/classic/form.png +0 -0
- psychopy/experiment/components/form/classic/form@2x.png +0 -0
- psychopy/experiment/components/form/dark/form.png +0 -0
- psychopy/experiment/components/form/dark/form@2x.png +0 -0
- psychopy/experiment/components/form/formItems.xltx +0 -0
- psychopy/experiment/components/form/light/form.png +0 -0
- psychopy/experiment/components/form/light/form@2x.png +0 -0
- psychopy/experiment/components/grating/__init__.py +203 -0
- psychopy/experiment/components/grating/classic/grating.png +0 -0
- psychopy/experiment/components/grating/classic/grating@2x.png +0 -0
- psychopy/experiment/components/grating/dark/grating.png +0 -0
- psychopy/experiment/components/grating/dark/grating@2x.png +0 -0
- psychopy/experiment/components/grating/light/grating.png +0 -0
- psychopy/experiment/components/grating/light/grating@2x.png +0 -0
- psychopy/experiment/components/image/__init__.py +195 -0
- psychopy/experiment/components/image/classic/image.png +0 -0
- psychopy/experiment/components/image/classic/image@2x.png +0 -0
- psychopy/experiment/components/image/dark/image.png +0 -0
- psychopy/experiment/components/image/dark/image@2x.png +0 -0
- psychopy/experiment/components/image/light/image.png +0 -0
- psychopy/experiment/components/image/light/image@2x.png +0 -0
- psychopy/experiment/components/joyButtons/__init__.py +453 -0
- psychopy/experiment/components/joyButtons/classic/joyButtons.png +0 -0
- psychopy/experiment/components/joyButtons/classic/joybuttons@2x.png +0 -0
- psychopy/experiment/components/joyButtons/dark/joyButtons.png +0 -0
- psychopy/experiment/components/joyButtons/dark/joyButtons@2x.png +0 -0
- psychopy/experiment/components/joyButtons/light/joyButtons.png +0 -0
- psychopy/experiment/components/joyButtons/light/joyButtons@2x.png +0 -0
- psychopy/experiment/components/joyButtons/virtualJoyButtons.py +34 -0
- psychopy/experiment/components/joystick/__init__.py +572 -0
- psychopy/experiment/components/joystick/classic/joystick.png +0 -0
- psychopy/experiment/components/joystick/classic/joystick@2x.png +0 -0
- psychopy/experiment/components/joystick/dark/joystick.png +0 -0
- psychopy/experiment/components/joystick/dark/joystick@2x.png +0 -0
- psychopy/experiment/components/joystick/light/joystick.png +0 -0
- psychopy/experiment/components/joystick/light/joystick@2x.png +0 -0
- psychopy/experiment/components/joystick/virtualJoystick.py +40 -0
- psychopy/experiment/components/keyboard/__init__.py +568 -0
- psychopy/experiment/components/keyboard/classic/keyboard.png +0 -0
- psychopy/experiment/components/keyboard/classic/keyboard@2x.png +0 -0
- psychopy/experiment/components/keyboard/dark/keyboard.png +0 -0
- psychopy/experiment/components/keyboard/dark/keyboard@2x.png +0 -0
- psychopy/experiment/components/keyboard/light/keyboard.png +0 -0
- psychopy/experiment/components/keyboard/light/keyboard@2x.png +0 -0
- psychopy/experiment/components/keyboard.xcf +0 -0
- psychopy/experiment/components/microphone/__init__.py +600 -0
- psychopy/experiment/components/microphone/classic/microphone.png +0 -0
- psychopy/experiment/components/microphone/classic/microphone@2x.png +0 -0
- psychopy/experiment/components/microphone/dark/microphone.png +0 -0
- psychopy/experiment/components/microphone/dark/microphone@2x.png +0 -0
- psychopy/experiment/components/microphone/light/microphone.png +0 -0
- psychopy/experiment/components/microphone/light/microphone@2x.png +0 -0
- psychopy/experiment/components/mouse/__init__.py +773 -0
- psychopy/experiment/components/mouse/classic/mouse.png +0 -0
- psychopy/experiment/components/mouse/classic/mouse@2x.png +0 -0
- psychopy/experiment/components/mouse/dark/mouse.png +0 -0
- psychopy/experiment/components/mouse/dark/mouse@2x.png +0 -0
- psychopy/experiment/components/mouse/light/mouse.png +0 -0
- psychopy/experiment/components/mouse/light/mouse@2x.png +0 -0
- psychopy/experiment/components/movie/__init__.py +348 -0
- psychopy/experiment/components/movie/classic/movie.png +0 -0
- psychopy/experiment/components/movie/classic/movie@2x.png +0 -0
- psychopy/experiment/components/movie/dark/movie.png +0 -0
- psychopy/experiment/components/movie/dark/movie@2x.png +0 -0
- psychopy/experiment/components/movie/light/movie.png +0 -0
- psychopy/experiment/components/movie/light/movie@2x.png +0 -0
- psychopy/experiment/components/panorama/__init__.py +456 -0
- psychopy/experiment/components/panorama/classic/panorama.png +0 -0
- psychopy/experiment/components/panorama/classic/panorama@2x.png +0 -0
- psychopy/experiment/components/panorama/dark/panorama.png +0 -0
- psychopy/experiment/components/panorama/dark/panorama@2x.png +0 -0
- psychopy/experiment/components/panorama/light/panorama.png +0 -0
- psychopy/experiment/components/panorama/light/panorama@2x.png +0 -0
- psychopy/experiment/components/parallelOut/__init__.py +178 -0
- psychopy/experiment/components/parallelOut/classic/parallel.png +0 -0
- psychopy/experiment/components/parallelOut/classic/parallel@2x.png +0 -0
- psychopy/experiment/components/parallelOut/dark/parallel.png +0 -0
- psychopy/experiment/components/parallelOut/dark/parallel@2x.png +0 -0
- psychopy/experiment/components/parallelOut/light/parallel.png +0 -0
- psychopy/experiment/components/parallelOut/light/parallel@2x.png +0 -0
- psychopy/experiment/components/polygon/__init__.py +332 -0
- psychopy/experiment/components/polygon/classic/polygon.png +0 -0
- psychopy/experiment/components/polygon/classic/polygon@2x.png +0 -0
- psychopy/experiment/components/polygon/dark/polygon.png +0 -0
- psychopy/experiment/components/polygon/dark/polygon@2x.png +0 -0
- psychopy/experiment/components/polygon/light/polygon.png +0 -0
- psychopy/experiment/components/polygon/light/polygon@2x.png +0 -0
- psychopy/experiment/components/progress/__init__.py +130 -0
- psychopy/experiment/components/progress/classic/progress.png +0 -0
- psychopy/experiment/components/progress/classic/progress@2x.png +0 -0
- psychopy/experiment/components/progress/dark/progress.png +0 -0
- psychopy/experiment/components/progress/dark/progress@2x.png +0 -0
- psychopy/experiment/components/progress/light/progress.png +0 -0
- psychopy/experiment/components/progress/light/progress@2x.png +0 -0
- psychopy/experiment/components/resourceManager/__init__.py +176 -0
- psychopy/experiment/components/resourceManager/classic/resource_manager.png +0 -0
- psychopy/experiment/components/resourceManager/classic/resource_manager@2x.png +0 -0
- psychopy/experiment/components/resourceManager/dark/resource_manager.png +0 -0
- psychopy/experiment/components/resourceManager/dark/resource_manager@2x.png +0 -0
- psychopy/experiment/components/resourceManager/light/resource_manager.png +0 -0
- psychopy/experiment/components/resourceManager/light/resource_manager@2x.png +0 -0
- psychopy/experiment/components/roi/__init__.py +316 -0
- psychopy/experiment/components/roi/classic/eyetracker_roi.png +0 -0
- psychopy/experiment/components/roi/classic/eyetracker_roi@2x.png +0 -0
- psychopy/experiment/components/roi/dark/eyetracker_roi.png +0 -0
- psychopy/experiment/components/roi/dark/eyetracker_roi@2X.png +0 -0
- psychopy/experiment/components/roi/light/eyetracker_roi.png +0 -0
- psychopy/experiment/components/roi/light/eyetracker_roi@2X.png +0 -0
- psychopy/experiment/components/routineSettings/__init__.py +387 -0
- psychopy/experiment/components/routineSettings/classic/routineSettings.png +0 -0
- psychopy/experiment/components/routineSettings/classic/routineSettings@2x.png +0 -0
- psychopy/experiment/components/routineSettings/dark/routineSettings.png +0 -0
- psychopy/experiment/components/routineSettings/dark/routineSettings@2x.png +0 -0
- psychopy/experiment/components/routineSettings/light/routineSettings.png +0 -0
- psychopy/experiment/components/routineSettings/light/routineSettings@2x.png +0 -0
- psychopy/experiment/components/serialOut/__init__.py +304 -0
- psychopy/experiment/components/serialOut/classic/serial.png +0 -0
- psychopy/experiment/components/serialOut/classic/serial@2x.png +0 -0
- psychopy/experiment/components/serialOut/dark/serial.png +0 -0
- psychopy/experiment/components/serialOut/dark/serial@2x.png +0 -0
- psychopy/experiment/components/serialOut/light/serial.png +0 -0
- psychopy/experiment/components/serialOut/light/serial@2x.png +0 -0
- psychopy/experiment/components/settings/JS_htmlHeader.tmpl +23 -0
- psychopy/experiment/components/settings/JS_setupExp.tmpl +28 -0
- psychopy/experiment/components/settings/__init__.py +2254 -0
- psychopy/experiment/components/settings/classic/settings.png +0 -0
- psychopy/experiment/components/settings/classic/settings@2x.png +0 -0
- psychopy/experiment/components/settings/dark/settings.png +0 -0
- psychopy/experiment/components/settings/dark/settings@2x.png +0 -0
- psychopy/experiment/components/settings/eyetracking.py +108 -0
- psychopy/experiment/components/settings/light/settings.png +0 -0
- psychopy/experiment/components/settings/light/settings@2x.png +0 -0
- psychopy/experiment/components/slider/__init__.py +410 -0
- psychopy/experiment/components/slider/classic/slider.png +0 -0
- psychopy/experiment/components/slider/classic/slider@2x.png +0 -0
- psychopy/experiment/components/slider/dark/slider.png +0 -0
- psychopy/experiment/components/slider/dark/slider@2x.png +0 -0
- psychopy/experiment/components/slider/light/slider.png +0 -0
- psychopy/experiment/components/slider/light/slider@2x.png +0 -0
- psychopy/experiment/components/sound/__init__.py +441 -0
- psychopy/experiment/components/sound/classic/sound.png +0 -0
- psychopy/experiment/components/sound/classic/sound@2x.png +0 -0
- psychopy/experiment/components/sound/dark/sound.png +0 -0
- psychopy/experiment/components/sound/dark/sound@2x.png +0 -0
- psychopy/experiment/components/sound/light/sound.png +0 -0
- psychopy/experiment/components/sound/light/sound@2x.png +0 -0
- psychopy/experiment/components/soundsensor/__init__.py +324 -0
- psychopy/experiment/components/soundsensor/classic/soundsensor.png +0 -0
- psychopy/experiment/components/soundsensor/classic/soundsensor@2x.png +0 -0
- psychopy/experiment/components/soundsensor/dark/soundsensor.png +0 -0
- psychopy/experiment/components/soundsensor/dark/soundsensor@2x.png +0 -0
- psychopy/experiment/components/soundsensor/light/soundsensor.png +0 -0
- psychopy/experiment/components/soundsensor/light/soundsensor@2x.png +0 -0
- psychopy/experiment/components/static/__init__.py +293 -0
- psychopy/experiment/components/static/classic/static.png +0 -0
- psychopy/experiment/components/static/classic/static@2x.png +0 -0
- psychopy/experiment/components/static/dark/static.png +0 -0
- psychopy/experiment/components/static/dark/static@2x.png +0 -0
- psychopy/experiment/components/static/light/static.png +0 -0
- psychopy/experiment/components/static/light/static@2x.png +0 -0
- psychopy/experiment/components/text/__init__.py +190 -0
- psychopy/experiment/components/text/classic/text.png +0 -0
- psychopy/experiment/components/text/classic/text@2x.png +0 -0
- psychopy/experiment/components/text/dark/text.png +0 -0
- psychopy/experiment/components/text/dark/text@2x.png +0 -0
- psychopy/experiment/components/text/light/text.png +0 -0
- psychopy/experiment/components/text/light/text@2x.png +0 -0
- psychopy/experiment/components/textbox/__init__.py +336 -0
- psychopy/experiment/components/textbox/classic/textbox.png +0 -0
- psychopy/experiment/components/textbox/classic/textbox@2x.png +0 -0
- psychopy/experiment/components/textbox/dark/textbox.png +0 -0
- psychopy/experiment/components/textbox/dark/textbox@2x.png +0 -0
- psychopy/experiment/components/textbox/light/textbox.png +0 -0
- psychopy/experiment/components/textbox/light/textbox@2x.png +0 -0
- psychopy/experiment/components/unknown/__init__.py +87 -0
- psychopy/experiment/components/unknown/classic/unknown.png +0 -0
- psychopy/experiment/components/unknown/classic/unknown@2x.png +0 -0
- psychopy/experiment/components/unknown/dark/unknown.png +0 -0
- psychopy/experiment/components/unknown/dark/unknown@2x.png +0 -0
- psychopy/experiment/components/unknown/light/unknown.png +0 -0
- psychopy/experiment/components/unknown/light/unknown@2x.png +0 -0
- psychopy/experiment/components/unknownPlugin/__init__.py +86 -0
- psychopy/experiment/components/unknownPlugin/classic/unknownPlugin.png +0 -0
- psychopy/experiment/components/unknownPlugin/classic/unknownPlugin@2x.png +0 -0
- psychopy/experiment/components/unknownPlugin/dark/unknownPlugin.png +0 -0
- psychopy/experiment/components/unknownPlugin/dark/unknownPlugin@2x.png +0 -0
- psychopy/experiment/components/unknownPlugin/light/unknownPlugin.png +0 -0
- psychopy/experiment/components/unknownPlugin/light/unknownPlugin@2x.png +0 -0
- psychopy/experiment/components/utils.py +0 -0
- psychopy/experiment/components/variable/__init__.py +184 -0
- psychopy/experiment/components/variable/classic/variable.png +0 -0
- psychopy/experiment/components/variable/classic/variable@2x.png +0 -0
- psychopy/experiment/components/variable/dark/variable.png +0 -0
- psychopy/experiment/components/variable/dark/variable@2x.png +0 -0
- psychopy/experiment/components/variable/light/variable.png +0 -0
- psychopy/experiment/components/variable/light/variable@2x.png +0 -0
- psychopy/experiment/devices.py +303 -0
- psychopy/experiment/experiment.xsd +223 -0
- psychopy/experiment/exports.py +390 -0
- psychopy/experiment/flow.py +547 -0
- psychopy/experiment/localization.py +11 -0
- psychopy/experiment/loopTemplate.xltx +0 -0
- psychopy/experiment/loops.py +1051 -0
- psychopy/experiment/monitor.py +74 -0
- psychopy/experiment/params.py +541 -0
- psychopy/experiment/plugins.py +42 -0
- psychopy/experiment/py2js.py +183 -0
- psychopy/experiment/py2js_transpiler.py +613 -0
- psychopy/experiment/questPlusTemplate.xltx +0 -0
- psychopy/experiment/questTemplate.xltx +0 -0
- psychopy/experiment/routines/__init__.py +108 -0
- psychopy/experiment/routines/_base.py +1172 -0
- psychopy/experiment/routines/audioValidator/__init__.py +229 -0
- psychopy/experiment/routines/audioValidator/classic/audio_validator.png +0 -0
- psychopy/experiment/routines/audioValidator/classic/audio_validator@2x.png +0 -0
- psychopy/experiment/routines/audioValidator/dark/audio_validator.png +0 -0
- psychopy/experiment/routines/audioValidator/dark/audio_validator@2x.png +0 -0
- psychopy/experiment/routines/audioValidator/light/audio_validator.png +0 -0
- psychopy/experiment/routines/audioValidator/light/audio_validator@2x.png +0 -0
- psychopy/experiment/routines/counterbalance/__init__.py +320 -0
- psychopy/experiment/routines/counterbalance/classic/counterbalance.png +0 -0
- psychopy/experiment/routines/counterbalance/classic/counterbalance@2x.png +0 -0
- psychopy/experiment/routines/counterbalance/counterbalanceItems.xltx +0 -0
- psychopy/experiment/routines/counterbalance/dark/counterbalance.png +0 -0
- psychopy/experiment/routines/counterbalance/dark/counterbalance@2x.png +0 -0
- psychopy/experiment/routines/counterbalance/light/counterbalance.png +0 -0
- psychopy/experiment/routines/counterbalance/light/counterbalance@2x.png +0 -0
- psychopy/experiment/routines/eyetracker_calibrate/__init__.py +334 -0
- psychopy/experiment/routines/eyetracker_calibrate/classic/eyetracker_calib.png +0 -0
- psychopy/experiment/routines/eyetracker_calibrate/dark/eyetracker_calib.png +0 -0
- psychopy/experiment/routines/eyetracker_calibrate/dark/eyetracker_calib@2x.png +0 -0
- psychopy/experiment/routines/eyetracker_calibrate/light/eyetracker_calib.png +0 -0
- psychopy/experiment/routines/eyetracker_calibrate/light/eyetracker_calib@2x.png +0 -0
- psychopy/experiment/routines/eyetracker_validate/__init__.py +354 -0
- psychopy/experiment/routines/eyetracker_validate/classic/eyetracker_valid.png +0 -0
- psychopy/experiment/routines/eyetracker_validate/dark/eyetracker_valid.png +0 -0
- psychopy/experiment/routines/eyetracker_validate/dark/eyetracker_valid@2x.png +0 -0
- psychopy/experiment/routines/eyetracker_validate/light/eyetracker_valid.png +0 -0
- psychopy/experiment/routines/eyetracker_validate/light/eyetracker_valid@2x.png +0 -0
- psychopy/experiment/routines/pavlovia_survey/__init__.py +236 -0
- psychopy/experiment/routines/pavlovia_survey/classic/survey.png +0 -0
- psychopy/experiment/routines/pavlovia_survey/classic/survey@2x.png +0 -0
- psychopy/experiment/routines/pavlovia_survey/dark/survey.png +0 -0
- psychopy/experiment/routines/pavlovia_survey/dark/survey@2x.png +0 -0
- psychopy/experiment/routines/pavlovia_survey/light/survey.png +0 -0
- psychopy/experiment/routines/pavlovia_survey/light/survey@2x.png +0 -0
- psychopy/experiment/routines/unknown/__init__.py +30 -0
- psychopy/experiment/routines/unknown/classic/eyetracker_record.png +0 -0
- psychopy/experiment/routines/unknown/classic/unknown.png +0 -0
- psychopy/experiment/routines/unknown/dark/eyetracker_record.png +0 -0
- psychopy/experiment/routines/unknown/dark/eyetracker_record@2x.png +0 -0
- psychopy/experiment/routines/unknown/dark/unknown.png +0 -0
- psychopy/experiment/routines/unknown/dark/unknown@2x.png +0 -0
- psychopy/experiment/routines/unknown/light/eyetracker_record.png +0 -0
- psychopy/experiment/routines/unknown/light/eyetracker_record@2x.png +0 -0
- psychopy/experiment/routines/unknown/light/unknown.png +0 -0
- psychopy/experiment/routines/unknown/light/unknown@2x.png +0 -0
- psychopy/experiment/routines/utils.py +0 -0
- psychopy/experiment/routines/visualValidator/__init__.py +395 -0
- psychopy/experiment/routines/visualValidator/classic/visual_validator.png +0 -0
- psychopy/experiment/routines/visualValidator/classic/visual_validator@2x.png +0 -0
- psychopy/experiment/routines/visualValidator/dark/visual_validator.png +0 -0
- psychopy/experiment/routines/visualValidator/dark/visual_validator@2x.png +0 -0
- psychopy/experiment/routines/visualValidator/light/visual_validator.png +0 -0
- psychopy/experiment/routines/visualValidator/light/visual_validator@2x.png +0 -0
- psychopy/experiment/staircaseTemplate.xltx +0 -0
- psychopy/experiment/utils.py +44 -0
- psychopy/filters.py +11 -0
- psychopy/gamma.py +9 -0
- psychopy/gui/__init__.py +47 -0
- psychopy/gui/qtgui.py +882 -0
- psychopy/gui/util.py +74 -0
- psychopy/gui/wxgui.py +420 -0
- psychopy/hardware/__init__.py +178 -0
- psychopy/hardware/base.py +466 -0
- psychopy/hardware/bbtk/__init__.py +24 -0
- psychopy/hardware/brainproducts.py +25 -0
- psychopy/hardware/button.py +238 -0
- psychopy/hardware/buttonbox/__init__.py +122 -0
- psychopy/hardware/camera/__init__.py +3657 -0
- psychopy/hardware/cedrus.py +24 -0
- psychopy/hardware/crs/__init__.py +46 -0
- psychopy/hardware/crs/bits.py +37 -0
- psychopy/hardware/crs/colorcal.py +18 -0
- psychopy/hardware/crs/optical.py +33 -0
- psychopy/hardware/crs/shaders.py +34 -0
- psychopy/hardware/emotiv.py +33 -0
- psychopy/hardware/emulator.py +46 -0
- psychopy/hardware/exceptions.py +86 -0
- psychopy/hardware/eyetracker.py +132 -0
- psychopy/hardware/forp.py +37 -0
- psychopy/hardware/gammasci.py +26 -0
- psychopy/hardware/iolab.py +24 -0
- psychopy/hardware/joystick/__init__.py +1196 -0
- psychopy/hardware/joystick/_base.py +251 -0
- psychopy/hardware/joystick/backend_glfw.py +306 -0
- psychopy/hardware/joystick/backend_pyglet.py +309 -0
- psychopy/hardware/joystick/mappings.py +287 -0
- psychopy/hardware/keyboard.py +975 -0
- psychopy/hardware/knownDevices.json +52 -0
- psychopy/hardware/labhackers.py +27 -0
- psychopy/hardware/labjacks.py +26 -0
- psychopy/hardware/lightsensor.py +789 -0
- psychopy/hardware/listener.py +330 -0
- psychopy/hardware/manager.py +992 -0
- psychopy/hardware/microphone.py +1630 -0
- psychopy/hardware/minolta.py +33 -0
- psychopy/hardware/monitor.py +144 -0
- psychopy/hardware/mouse/__init__.py +885 -0
- psychopy/hardware/photometer/__init__.py +207 -0
- psychopy/hardware/pr.py +33 -0
- psychopy/hardware/qmix.py +32 -0
- psychopy/hardware/serialdevice.py +387 -0
- psychopy/hardware/soundsensor.py +476 -0
- psychopy/hardware/spatial/__init__.py +231 -0
- psychopy/hardware/speaker.py +351 -0
- psychopy/hardware/triggerbox/__init__.py +56 -0
- psychopy/hardware/triggerbox/base.py +170 -0
- psychopy/hardware/triggerbox/parallel.py +362 -0
- psychopy/info.py +719 -0
- psychopy/iohub/__init__.py +50 -0
- psychopy/iohub/client/__init__.py +1481 -0
- psychopy/iohub/client/connect.py +260 -0
- psychopy/iohub/client/eyetracker/__init__.py +4 -0
- psychopy/iohub/client/eyetracker/validation/__init__.py +8 -0
- psychopy/iohub/client/eyetracker/validation/posgrid.py +274 -0
- psychopy/iohub/client/eyetracker/validation/procedure.py +1292 -0
- psychopy/iohub/client/eyetracker/validation/trigger.py +240 -0
- psychopy/iohub/client/keyboard.py +513 -0
- psychopy/iohub/client/wintab.py +378 -0
- psychopy/iohub/constants.py +1176 -0
- psychopy/iohub/datastore/__init__.py +439 -0
- psychopy/iohub/datastore/default_datastore.yaml +8 -0
- psychopy/iohub/datastore/util.py +868 -0
- psychopy/iohub/default_config.yaml +17 -0
- psychopy/iohub/devices/__init__.py +1047 -0
- psychopy/iohub/devices/computer.py +607 -0
- psychopy/iohub/devices/default_device.yaml +15 -0
- psychopy/iohub/devices/deviceConfigValidation.py +519 -0
- psychopy/iohub/devices/display/__init__.py +755 -0
- psychopy/iohub/devices/display/default_display.yaml +118 -0
- psychopy/iohub/devices/display/supported_config_settings.yaml +69 -0
- psychopy/iohub/devices/eventfilters.py +3572 -0
- psychopy/iohub/devices/experiment/__init__.py +316 -0
- psychopy/iohub/devices/experiment/default_experiment.yaml +74 -0
- psychopy/iohub/devices/experiment/supported_config_settings.yaml +26 -0
- psychopy/iohub/devices/eyetracker/__init__.py +474 -0
- psychopy/iohub/devices/eyetracker/calibration/__init__.py +1 -0
- psychopy/iohub/devices/eyetracker/calibration/procedure.py +391 -0
- psychopy/iohub/devices/eyetracker/default_eyetracker.yaml +18 -0
- psychopy/iohub/devices/eyetracker/eye_events.py +1751 -0
- psychopy/iohub/devices/eyetracker/filters/__init__.py +4 -0
- psychopy/iohub/devices/eyetracker/filters/parser.py +913 -0
- psychopy/iohub/devices/eyetracker/hw/__init__.py +4 -0
- psychopy/iohub/devices/eyetracker/hw/gazepoint/__init__.py +29 -0
- psychopy/iohub/devices/eyetracker/hw/gazepoint/gp3/__init__.py +29 -0
- psychopy/iohub/devices/eyetracker/hw/gazepoint/gp3/calibration.py +18 -0
- psychopy/iohub/devices/eyetracker/hw/gazepoint/gp3/eyetracker.py +31 -0
- psychopy/iohub/devices/eyetracker/hw/mouse/__init__.py +8 -0
- psychopy/iohub/devices/eyetracker/hw/mouse/calibration.py +10 -0
- psychopy/iohub/devices/eyetracker/hw/mouse/default_eyetracker.yaml +102 -0
- psychopy/iohub/devices/eyetracker/hw/mouse/eyetracker.py +443 -0
- psychopy/iohub/devices/eyetracker/hw/mouse/supported_config_settings.yaml +110 -0
- psychopy/iohub/devices/eyetracker/hw/pupil_labs/__init__.py +4 -0
- psychopy/iohub/devices/eyetracker/hw/pupil_labs/neon/__init__.py +27 -0
- psychopy/iohub/devices/eyetracker/hw/pupil_labs/neon/eyetracker.py +18 -0
- psychopy/iohub/devices/eyetracker/hw/pupil_labs/pupil_core/__init__.py +29 -0
- psychopy/iohub/devices/eyetracker/hw/pupil_labs/pupil_core/bisector.py +20 -0
- psychopy/iohub/devices/eyetracker/hw/pupil_labs/pupil_core/constants.py +19 -0
- psychopy/iohub/devices/eyetracker/hw/pupil_labs/pupil_core/data_parse.py +22 -0
- psychopy/iohub/devices/eyetracker/hw/pupil_labs/pupil_core/eyetracker.py +18 -0
- psychopy/iohub/devices/eyetracker/hw/pupil_labs/pupil_core/pupil_remote.py +18 -0
- psychopy/iohub/devices/eyetracker/hw/sr_research/__init__.py +4 -0
- psychopy/iohub/devices/eyetracker/hw/sr_research/eyelink/__init__.py +28 -0
- psychopy/iohub/devices/eyetracker/hw/sr_research/eyelink/calibration.py +22 -0
- psychopy/iohub/devices/eyetracker/hw/sr_research/eyelink/eyetracker.py +38 -0
- psychopy/iohub/devices/eyetracker/hw/tobii/__init__.py +29 -0
- psychopy/iohub/devices/eyetracker/hw/tobii/calibration.py +19 -0
- psychopy/iohub/devices/eyetracker/hw/tobii/eyetracker.py +17 -0
- psychopy/iohub/devices/eyetracker/hw/tobii/tobiiwrapper.py +19 -0
- psychopy/iohub/devices/eyetracker/supported_config_settings.yaml +44 -0
- psychopy/iohub/devices/keyboard/__init__.py +309 -0
- psychopy/iohub/devices/keyboard/darwin.py +431 -0
- psychopy/iohub/devices/keyboard/darwinkey.py +94 -0
- psychopy/iohub/devices/keyboard/default_keyboard.yaml +94 -0
- psychopy/iohub/devices/keyboard/linux2.py +102 -0
- psychopy/iohub/devices/keyboard/supported_config_settings.yaml +39 -0
- psychopy/iohub/devices/keyboard/win32.py +356 -0
- psychopy/iohub/devices/mouse/__init__.py +709 -0
- psychopy/iohub/devices/mouse/darwin.py +414 -0
- psychopy/iohub/devices/mouse/default_mouse.yaml +92 -0
- psychopy/iohub/devices/mouse/linux2.py +172 -0
- psychopy/iohub/devices/mouse/supported_config_settings.yaml +39 -0
- psychopy/iohub/devices/mouse/win32.py +284 -0
- psychopy/iohub/devices/pyXHook.py +619 -0
- psychopy/iohub/devices/serial/__init__.py +779 -0
- psychopy/iohub/devices/serial/default_pstbox.yaml +108 -0
- psychopy/iohub/devices/serial/default_serial.yaml +108 -0
- psychopy/iohub/devices/serial/supported_config_settings.yaml +85 -0
- psychopy/iohub/devices/serial/supported_config_settings_pstbox.yaml +85 -0
- psychopy/iohub/devices/supported_config_settings.yaml +36 -0
- psychopy/iohub/devices/wintab/__init__.py +580 -0
- psychopy/iohub/devices/wintab/default_wintab.yaml +89 -0
- psychopy/iohub/devices/wintab/supported_config_settings.yaml +42 -0
- psychopy/iohub/devices/wintab/win32.py +722 -0
- psychopy/iohub/devices/xlib.py +6795 -0
- psychopy/iohub/errors.py +61 -0
- psychopy/iohub/lazy_import.py +582 -0
- psychopy/iohub/net.py +349 -0
- psychopy/iohub/server.py +1075 -0
- psychopy/iohub/start_iohub_process.py +121 -0
- psychopy/iohub/util/__init__.py +832 -0
- psychopy/iohub/util/visualangle.py +126 -0
- psychopy/layout.py +916 -0
- psychopy/liaison.py +471 -0
- psychopy/locale_setup.py +41 -0
- psychopy/localization/__init__.py +22 -0
- psychopy/localization/_localization.py +155 -0
- psychopy/localization/generateTranslationTemplate.py +257 -0
- psychopy/localization/mappings.txt +170 -0
- psychopy/localization/messages.pot +9950 -0
- psychopy/localization/readme.txt +68 -0
- psychopy/logging.py +415 -0
- psychopy/microphone.py +28 -0
- psychopy/misc.py +40 -0
- psychopy/monitors/MonitorCenter.py +1354 -0
- psychopy/monitors/__init__.py +30 -0
- psychopy/monitors/calibData.py +78 -0
- psychopy/monitors/calibTools.py +1301 -0
- psychopy/monitors/getLumSeries.py +50 -0
- psychopy/monitors/psychopy-icon.svg +395 -0
- psychopy/monitors/psychopy.ico +0 -0
- psychopy/parallel/__init__.py +206 -0
- psychopy/parallel/_dlportio.py +150 -0
- psychopy/parallel/_inpout.py +120 -0
- psychopy/parallel/_linux.py +105 -0
- psychopy/piloting.py +61 -0
- psychopy/platform_specific/__init__.py +46 -0
- psychopy/platform_specific/darwin.py +326 -0
- psychopy/platform_specific/linux.py +77 -0
- psychopy/platform_specific/win32.py +124 -0
- psychopy/plugins/__init__.py +1397 -0
- psychopy/plugins/util.py +104 -0
- psychopy/preferences/Darwin.spec +294 -0
- psychopy/preferences/FreeBSD.spec +294 -0
- psychopy/preferences/Linux.spec +294 -0
- psychopy/preferences/Windows.spec +294 -0
- psychopy/preferences/__init__.py +20 -0
- psychopy/preferences/baseNoArch.spec +290 -0
- psychopy/preferences/devices.py +80 -0
- psychopy/preferences/generateHints.py +93 -0
- psychopy/preferences/generateSpec.py +80 -0
- psychopy/preferences/hints.py +367 -0
- psychopy/preferences/preferences.py +448 -0
- psychopy/projects/__init__.py +11 -0
- psychopy/projects/gitignore.py +45 -0
- psychopy/projects/pavlovia.py +1674 -0
- psychopy/projects/sshkeys.py +107 -0
- psychopy/psychojs.zip +0 -0
- psychopy/pylintrc +69 -0
- psychopy/scripts/__init__.py +0 -0
- psychopy/scripts/psychopy-pkgutil.py +969 -0
- psychopy/scripts/psyexpCompile.py +229 -0
- psychopy/session.py +1651 -0
- psychopy/sound/__init__.py +50 -0
- psychopy/sound/_base.py +399 -0
- psychopy/sound/audioclip.py +1325 -0
- psychopy/sound/audiodevice.py +857 -0
- psychopy/sound/backend_ptb.py +406 -0
- psychopy/sound/backend_pygame.py +323 -0
- psychopy/sound/backend_pyo.py +64 -0
- psychopy/sound/backend_pysound.py +324 -0
- psychopy/sound/backend_sounddevice.py +44 -0
- psychopy/sound/backends/__init__.py +0 -0
- psychopy/sound/exceptions.py +115 -0
- psychopy/sound/microphone.py +357 -0
- psychopy/sound/sound.py +58 -0
- psychopy/sound/transcribe.py +1321 -0
- psychopy/tests/README.md +344 -0
- psychopy/tests/__init__.py +47 -0
- psychopy/tests/data/Electronic_Chime-KevanGC-495939803.wav +0 -0
- psychopy/tests/data/TestCircle_w128h128_bottom_left.png +0 -0
- psychopy/tests/data/TestCircle_w128h128_bottom_right.png +0 -0
- psychopy/tests/data/TestCircle_w128h128_center_center.png +0 -0
- psychopy/tests/data/TestCircle_w128h128_top_left.png +0 -0
- psychopy/tests/data/TestCircle_w128h128_top_right.png +0 -0
- psychopy/tests/data/TestCircle_w128h64_bottom_left.png +0 -0
- psychopy/tests/data/TestCircle_w128h64_bottom_right.png +0 -0
- psychopy/tests/data/TestCircle_w128h64_center_center.png +0 -0
- psychopy/tests/data/TestCircle_w128h64_top_left.png +0 -0
- psychopy/tests/data/TestCircle_w128h64_top_right.png +0 -0
- psychopy/tests/data/TestCircle_w64h128_bottom_left.png +0 -0
- psychopy/tests/data/TestCircle_w64h128_bottom_right.png +0 -0
- psychopy/tests/data/TestCircle_w64h128_center_center.png +0 -0
- psychopy/tests/data/TestCircle_w64h128_top_left.png +0 -0
- psychopy/tests/data/TestCircle_w64h128_top_right.png +0 -0
- psychopy/tests/data/TestCircle_w64h64_bottom_left.png +0 -0
- psychopy/tests/data/TestCircle_w64h64_bottom_right.png +0 -0
- psychopy/tests/data/TestCircle_w64h64_center_center.png +0 -0
- psychopy/tests/data/TestCircle_w64h64_top_left.png +0 -0
- psychopy/tests/data/TestCircle_w64h64_top_right.png +0 -0
- psychopy/tests/data/TestForm_scrolling_nq10_s0.5.png +0 -0
- psychopy/tests/data/TestForm_scrolling_nq10_s0.png +0 -0
- psychopy/tests/data/TestForm_scrolling_nq10_s1.png +0 -0
- psychopy/tests/data/TestForm_scrolling_nq1_s0.5.png +0 -0
- psychopy/tests/data/TestForm_scrolling_nq1_s0.png +0 -0
- psychopy/tests/data/TestForm_scrolling_nq1_s1.png +0 -0
- psychopy/tests/data/TestForm_scrolling_nq3_s0.5.png +0 -0
- psychopy/tests/data/TestForm_scrolling_nq3_s0.png +0 -0
- psychopy/tests/data/TestForm_scrolling_nq3_s1.png +0 -0
- psychopy/tests/data/TestImage_w128h128_bottom_left.png +0 -0
- psychopy/tests/data/TestImage_w128h128_bottom_right.png +0 -0
- psychopy/tests/data/TestImage_w128h128_center_center.png +0 -0
- psychopy/tests/data/TestImage_w128h128_top_left.png +0 -0
- psychopy/tests/data/TestImage_w128h128_top_right.png +0 -0
- psychopy/tests/data/TestImage_w128h64_bottom_left.png +0 -0
- psychopy/tests/data/TestImage_w128h64_bottom_right.png +0 -0
- psychopy/tests/data/TestImage_w128h64_center_center.png +0 -0
- psychopy/tests/data/TestImage_w128h64_top_left.png +0 -0
- psychopy/tests/data/TestImage_w128h64_top_right.png +0 -0
- psychopy/tests/data/TestImage_w64h128_bottom_left.png +0 -0
- psychopy/tests/data/TestImage_w64h128_bottom_right.png +0 -0
- psychopy/tests/data/TestImage_w64h128_center_center.png +0 -0
- psychopy/tests/data/TestImage_w64h128_top_left.png +0 -0
- psychopy/tests/data/TestImage_w64h128_top_right.png +0 -0
- psychopy/tests/data/TestImage_w64h64_bottom_left.png +0 -0
- psychopy/tests/data/TestImage_w64h64_bottom_right.png +0 -0
- psychopy/tests/data/TestImage_w64h64_center_center.png +0 -0
- psychopy/tests/data/TestImage_w64h64_top_left.png +0 -0
- psychopy/tests/data/TestImage_w64h64_top_right.png +0 -0
- psychopy/tests/data/TestProgress_testValue_horizontal_center center_0.3.png +0 -0
- psychopy/tests/data/TestProgress_testValue_horizontal_center center_0.6.png +0 -0
- psychopy/tests/data/TestProgress_testValue_horizontal_left center_0.3.png +0 -0
- psychopy/tests/data/TestProgress_testValue_horizontal_left center_0.6.png +0 -0
- psychopy/tests/data/TestProgress_testValue_horizontal_right center_0.3.png +0 -0
- psychopy/tests/data/TestProgress_testValue_horizontal_right center_0.6.png +0 -0
- psychopy/tests/data/TestProgress_testValue_minmax_0.png +0 -0
- psychopy/tests/data/TestProgress_testValue_minmax_1.png +0 -0
- psychopy/tests/data/TestProgress_testValue_vertical_bottom center_0.3.png +0 -0
- psychopy/tests/data/TestProgress_testValue_vertical_bottom center_0.6.png +0 -0
- psychopy/tests/data/TestProgress_testValue_vertical_center center_0.3.png +0 -0
- psychopy/tests/data/TestProgress_testValue_vertical_center center_0.6.png +0 -0
- psychopy/tests/data/TestProgress_testValue_vertical_top center_0.3.png +0 -0
- psychopy/tests/data/TestProgress_testValue_vertical_top center_0.6.png +0 -0
- psychopy/tests/data/TestProgress_w128h128_bottom_left.png +0 -0
- psychopy/tests/data/TestProgress_w128h128_bottom_right.png +0 -0
- psychopy/tests/data/TestProgress_w128h128_center_center.png +0 -0
- psychopy/tests/data/TestProgress_w128h128_top_left.png +0 -0
- psychopy/tests/data/TestProgress_w128h128_top_right.png +0 -0
- psychopy/tests/data/TestProgress_w128h64_bottom_left.png +0 -0
- psychopy/tests/data/TestProgress_w128h64_bottom_right.png +0 -0
- psychopy/tests/data/TestProgress_w128h64_center_center.png +0 -0
- psychopy/tests/data/TestProgress_w128h64_top_left.png +0 -0
- psychopy/tests/data/TestProgress_w128h64_top_right.png +0 -0
- psychopy/tests/data/TestProgress_w64h128_bottom_left.png +0 -0
- psychopy/tests/data/TestProgress_w64h128_bottom_right.png +0 -0
- psychopy/tests/data/TestProgress_w64h128_center_center.png +0 -0
- psychopy/tests/data/TestProgress_w64h128_top_left.png +0 -0
- psychopy/tests/data/TestProgress_w64h128_top_right.png +0 -0
- psychopy/tests/data/TestProgress_w64h64_bottom_left.png +0 -0
- psychopy/tests/data/TestProgress_w64h64_bottom_right.png +0 -0
- psychopy/tests/data/TestProgress_w64h64_center_center.png +0 -0
- psychopy/tests/data/TestProgress_w64h64_top_left.png +0 -0
- psychopy/tests/data/TestProgress_w64h64_top_right.png +0 -0
- psychopy/tests/data/TestROI_w128h128_bottom_left.png +0 -0
- psychopy/tests/data/TestROI_w128h128_bottom_right.png +0 -0
- psychopy/tests/data/TestROI_w128h128_center_center.png +0 -0
- psychopy/tests/data/TestROI_w128h128_top_left.png +0 -0
- psychopy/tests/data/TestROI_w128h128_top_right.png +0 -0
- psychopy/tests/data/TestROI_w128h64_bottom_left.png +0 -0
- psychopy/tests/data/TestROI_w128h64_bottom_right.png +0 -0
- psychopy/tests/data/TestROI_w128h64_center_center.png +0 -0
- psychopy/tests/data/TestROI_w128h64_top_left.png +0 -0
- psychopy/tests/data/TestROI_w128h64_top_right.png +0 -0
- psychopy/tests/data/TestROI_w64h128_bottom_left.png +0 -0
- psychopy/tests/data/TestROI_w64h128_bottom_right.png +0 -0
- psychopy/tests/data/TestROI_w64h128_center_center.png +0 -0
- psychopy/tests/data/TestROI_w64h128_top_left.png +0 -0
- psychopy/tests/data/TestROI_w64h128_top_right.png +0 -0
- psychopy/tests/data/TestROI_w64h64_bottom_left.png +0 -0
- psychopy/tests/data/TestROI_w64h64_bottom_right.png +0 -0
- psychopy/tests/data/TestROI_w64h64_center_center.png +0 -0
- psychopy/tests/data/TestROI_w64h64_top_left.png +0 -0
- psychopy/tests/data/TestROI_w64h64_top_right.png +0 -0
- psychopy/tests/data/TestSession_exp1.png +0 -0
- psychopy/tests/data/TestSession_exp2.png +0 -0
- psychopy/tests/data/TestShape_w128h128_bottom_left.png +0 -0
- psychopy/tests/data/TestShape_w128h128_bottom_right.png +0 -0
- psychopy/tests/data/TestShape_w128h128_center_center.png +0 -0
- psychopy/tests/data/TestShape_w128h128_top_left.png +0 -0
- psychopy/tests/data/TestShape_w128h128_top_right.png +0 -0
- psychopy/tests/data/TestShape_w128h64_bottom_left.png +0 -0
- psychopy/tests/data/TestShape_w128h64_bottom_right.png +0 -0
- psychopy/tests/data/TestShape_w128h64_center_center.png +0 -0
- psychopy/tests/data/TestShape_w128h64_top_left.png +0 -0
- psychopy/tests/data/TestShape_w128h64_top_right.png +0 -0
- psychopy/tests/data/TestShape_w64h128_bottom_left.png +0 -0
- psychopy/tests/data/TestShape_w64h128_bottom_right.png +0 -0
- psychopy/tests/data/TestShape_w64h128_center_center.png +0 -0
- psychopy/tests/data/TestShape_w64h128_top_left.png +0 -0
- psychopy/tests/data/TestShape_w64h128_top_right.png +0 -0
- psychopy/tests/data/TestShape_w64h64_bottom_left.png +0 -0
- psychopy/tests/data/TestShape_w64h64_bottom_right.png +0 -0
- psychopy/tests/data/TestShape_w64h64_center_center.png +0 -0
- psychopy/tests/data/TestShape_w64h64_top_left.png +0 -0
- psychopy/tests/data/TestShape_w64h64_top_right.png +0 -0
- psychopy/tests/data/TestTarget_w128h128_bottom_left.png +0 -0
- psychopy/tests/data/TestTarget_w128h128_bottom_right.png +0 -0
- psychopy/tests/data/TestTarget_w128h128_center_center.png +0 -0
- psychopy/tests/data/TestTarget_w128h128_top_left.png +0 -0
- psychopy/tests/data/TestTarget_w128h128_top_right.png +0 -0
- psychopy/tests/data/TestTarget_w128h64_bottom_left.png +0 -0
- psychopy/tests/data/TestTarget_w128h64_bottom_right.png +0 -0
- psychopy/tests/data/TestTarget_w128h64_center_center.png +0 -0
- psychopy/tests/data/TestTarget_w128h64_top_left.png +0 -0
- psychopy/tests/data/TestTarget_w128h64_top_right.png +0 -0
- psychopy/tests/data/TestTarget_w64h128_bottom_left.png +0 -0
- psychopy/tests/data/TestTarget_w64h128_bottom_right.png +0 -0
- psychopy/tests/data/TestTarget_w64h128_center_center.png +0 -0
- psychopy/tests/data/TestTarget_w64h128_top_left.png +0 -0
- psychopy/tests/data/TestTarget_w64h128_top_right.png +0 -0
- psychopy/tests/data/TestTarget_w64h64_bottom_left.png +0 -0
- psychopy/tests/data/TestTarget_w64h64_bottom_right.png +0 -0
- psychopy/tests/data/TestTarget_w64h64_center_center.png +0 -0
- psychopy/tests/data/TestTarget_w64h64_top_left.png +0 -0
- psychopy/tests/data/TestTarget_w64h64_top_right.png +0 -0
- psychopy/tests/data/TestTextbox_testLetterSpacing_0p6.png +0 -0
- psychopy/tests/data/TestTextbox_testLetterSpacing_0p8.png +0 -0
- psychopy/tests/data/TestTextbox_testLetterSpacing_1.png +0 -0
- psychopy/tests/data/TestTextbox_testLetterSpacing_1p2.png +0 -0
- psychopy/tests/data/TestTextbox_testLetterSpacing_1p4.png +0 -0
- psychopy/tests/data/TestTextbox_testLetterSpacing_1p6.png +0 -0
- psychopy/tests/data/TestTextbox_testLetterSpacing_1p8.png +0 -0
- psychopy/tests/data/TestTextbox_testLetterSpacing_2p0.png +0 -0
- psychopy/tests/data/TestTextbox_testLetterSpacing_None.png +0 -0
- psychopy/tests/data/TestUnknownPluginComponent_load_resave.psyexp +135 -0
- psychopy/tests/data/Test_textbox/test_ori_0_bottom right.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_0_center.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_0_top left.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_120_bottom right.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_120_center.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_120_top left.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_180_bottom right.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_180_center.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_180_top left.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_240_bottom right.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_240_center.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_240_top left.png +0 -0
- psychopy/tests/data/Test_textbox_testSpeechpoint_-3ovr8_0ovr8.png +0 -0
- psychopy/tests/data/Test_textbox_testSpeechpoint_0ovr8_-3ovr8.png +0 -0
- psychopy/tests/data/Test_textbox_testSpeechpoint_0ovr8_3ovr8.png +0 -0
- psychopy/tests/data/Test_textbox_testSpeechpoint_3ovr8_0ovr8.png +0 -0
- psychopy/tests/data/Test_textbox_w128h128_bottom_left.png +0 -0
- psychopy/tests/data/Test_textbox_w128h128_bottom_right.png +0 -0
- psychopy/tests/data/Test_textbox_w128h128_center_center.png +0 -0
- psychopy/tests/data/Test_textbox_w128h128_top_left.png +0 -0
- psychopy/tests/data/Test_textbox_w128h128_top_right.png +0 -0
- psychopy/tests/data/Test_textbox_w128h64_bottom_left.png +0 -0
- psychopy/tests/data/Test_textbox_w128h64_bottom_right.png +0 -0
- psychopy/tests/data/Test_textbox_w128h64_center_center.png +0 -0
- psychopy/tests/data/Test_textbox_w128h64_top_left.png +0 -0
- psychopy/tests/data/Test_textbox_w128h64_top_right.png +0 -0
- psychopy/tests/data/Test_textbox_w64h128_bottom_left.png +0 -0
- psychopy/tests/data/Test_textbox_w64h128_bottom_right.png +0 -0
- psychopy/tests/data/Test_textbox_w64h128_center_center.png +0 -0
- psychopy/tests/data/Test_textbox_w64h128_top_left.png +0 -0
- psychopy/tests/data/Test_textbox_w64h128_top_right.png +0 -0
- psychopy/tests/data/Test_textbox_w64h64_bottom_left.png +0 -0
- psychopy/tests/data/Test_textbox_w64h64_bottom_right.png +0 -0
- psychopy/tests/data/Test_textbox_w64h64_center_center.png +0 -0
- psychopy/tests/data/Test_textbox_w64h64_top_left.png +0 -0
- psychopy/tests/data/Test_textbox_w64h64_top_right.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w128h128_bottom_left.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w128h128_bottom_right.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w128h128_center_center.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w128h128_top_left.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w128h128_top_right.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w128h64_bottom_left.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w128h64_bottom_right.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w128h64_center_center.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w128h64_top_left.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w128h64_top_right.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w64h128_bottom_left.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w64h128_bottom_right.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w64h128_center_center.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w64h128_top_left.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w64h128_top_right.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w64h64_bottom_left.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w64h64_bottom_right.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w64h64_center_center.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w64h64_top_left.png +0 -0
- psychopy/tests/data/Test_uax14_textbox_w64h64_top_right.png +0 -0
- psychopy/tests/data/TextComponent_disabled.psyexp +63 -0
- psychopy/tests/data/TextComponent_not_disabled.psyexp +63 -0
- psychopy/tests/data/aperture1_deg.png +0 -0
- psychopy/tests/data/aperture1_degFlat.png +0 -0
- psychopy/tests/data/aperture1_degFlatPos.png +0 -0
- psychopy/tests/data/aperture1_norm.png +0 -0
- psychopy/tests/data/aperture1_normHexbackground.png +0 -0
- psychopy/tests/data/aperture1_normNoShade.png +0 -0
- psychopy/tests/data/aperture1_pix.png +0 -0
- psychopy/tests/data/aperture1_stencil.png +0 -0
- psychopy/tests/data/aperture2_deg.png +0 -0
- psychopy/tests/data/aperture2_degFlat.png +0 -0
- psychopy/tests/data/aperture2_degFlatPos.png +0 -0
- psychopy/tests/data/aperture2_norm.png +0 -0
- psychopy/tests/data/aperture2_normHexbackground.png +0 -0
- psychopy/tests/data/aperture2_normNoShade.png +0 -0
- psychopy/tests/data/aperture2_pix.png +0 -0
- psychopy/tests/data/aperture2_stencil.png +0 -0
- psychopy/tests/data/beatandrcos_cm.png +0 -0
- psychopy/tests/data/beatandrcos_deg.png +0 -0
- psychopy/tests/data/beatandrcos_degFlat.png +0 -0
- psychopy/tests/data/beatandrcos_degFlatPos.png +0 -0
- psychopy/tests/data/beatandrcos_height.png +0 -0
- psychopy/tests/data/beatandrcos_norm.png +0 -0
- psychopy/tests/data/beatandrcos_normAddBlend.png +0 -0
- psychopy/tests/data/beatandrcos_normHexbackground.png +0 -0
- psychopy/tests/data/beatandrcos_pix.png +0 -0
- psychopy/tests/data/beatandrcos_stencil.png +0 -0
- psychopy/tests/data/blend_add_cm.png +0 -0
- psychopy/tests/data/blend_add_deg.png +0 -0
- psychopy/tests/data/blend_add_degFlat.png +0 -0
- psychopy/tests/data/blend_add_degFlatPos.png +0 -0
- psychopy/tests/data/blend_add_height.png +0 -0
- psychopy/tests/data/blend_add_norm.png +0 -0
- psychopy/tests/data/blend_add_normAddBlend.png +0 -0
- psychopy/tests/data/blend_add_normHexbackground.png +0 -0
- psychopy/tests/data/blend_add_normNoShade.png +0 -0
- psychopy/tests/data/blend_add_pix.png +0 -0
- psychopy/tests/data/blend_add_stencil.png +0 -0
- psychopy/tests/data/broken2020_2_5_resources/broken_resources.psyexp +84 -0
- psychopy/tests/data/broken2020_2_5_resources/psychopy72.png +0 -0
- psychopy/tests/data/bufferimg_gabor_cm.png +0 -0
- psychopy/tests/data/bufferimg_gabor_deg.png +0 -0
- psychopy/tests/data/bufferimg_gabor_degFlat.png +0 -0
- psychopy/tests/data/bufferimg_gabor_degFlatPos.png +0 -0
- psychopy/tests/data/bufferimg_gabor_height.png +0 -0
- psychopy/tests/data/bufferimg_gabor_norm.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normAddBlend.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normHexbackground.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normNoShade.png +0 -0
- psychopy/tests/data/bufferimg_gabor_pix.png +0 -0
- psychopy/tests/data/bufferimg_gabor_stencil.png +0 -0
- psychopy/tests/data/circleHex_cm.png +0 -0
- psychopy/tests/data/circleHex_deg.png +0 -0
- psychopy/tests/data/circleHex_degFlat.png +0 -0
- psychopy/tests/data/circleHex_degFlatPos.png +0 -0
- psychopy/tests/data/circleHex_height.png +0 -0
- psychopy/tests/data/circleHex_norm.png +0 -0
- psychopy/tests/data/circleHex_normAddBlend.png +0 -0
- psychopy/tests/data/circleHex_normHexbackground.png +0 -0
- psychopy/tests/data/circleHex_normNoShade.png +0 -0
- psychopy/tests/data/circleHex_pix.png +0 -0
- psychopy/tests/data/circleHex_stencil.png +0 -0
- psychopy/tests/data/corrFullRandom.csv +16 -0
- psychopy/tests/data/corrFullRandom.tsv +6 -0
- psychopy/tests/data/corrFullRandomTH2.csv +16 -0
- psychopy/tests/data/corrMultiKeyExpWide.csv +3 -0
- psychopy/tests/data/corrMultiKeyTrials.csv +8 -0
- psychopy/tests/data/corrMultiKeyTrials.xlsx +0 -0
- psychopy/tests/data/corrRandom.csv +16 -0
- psychopy/tests/data/corrRandom.tsv +6 -0
- psychopy/tests/data/corrRandomTH2.csv +16 -0
- psychopy/tests/data/corrXlsx.xlsx +0 -0
- psychopy/tests/data/correctScript/js/correctCodeComponent.js +181 -0
- psychopy/tests/data/correctScript/js/correctImageComponent.js +204 -0
- psychopy/tests/data/correctScript/js/correctKeyboardComponent.js +225 -0
- psychopy/tests/data/correctScript/js/correctMouseComponent.js +221 -0
- psychopy/tests/data/correctScript/js/correctMovieComponent.js +210 -0
- psychopy/tests/data/correctScript/js/correctPolygonComponent.js +205 -0
- psychopy/tests/data/correctScript/js/correctSliderComponent.js +209 -0
- psychopy/tests/data/correctScript/js/correctSoundComponent.js +205 -0
- psychopy/tests/data/correctScript/js/correctTextComponent.js +207 -0
- psychopy/tests/data/correctScript/python/correctApertureComponent.py +157 -0
- psychopy/tests/data/correctScript/python/correctCodeComponent.py +135 -0
- psychopy/tests/data/correctScript/python/correctDotsComponent.py +161 -0
- psychopy/tests/data/correctScript/python/correctEnvGratingComponent.py +167 -0
- psychopy/tests/data/correctScript/python/correctFormComponent.py +150 -0
- psychopy/tests/data/correctScript/python/correctGratingComponent.py +158 -0
- psychopy/tests/data/correctScript/python/correctImageComponent.py +160 -0
- psychopy/tests/data/correctScript/python/correctJoyButtonsComponent.py +204 -0
- psychopy/tests/data/correctScript/python/correctJoystickComponent.py +214 -0
- psychopy/tests/data/correctScript/python/correctKeyboardComponent.py +169 -0
- psychopy/tests/data/correctScript/python/correctMicrophoneComponent.py +163 -0
- psychopy/tests/data/correctScript/python/correctMouseComponent.py +174 -0
- psychopy/tests/data/correctScript/python/correctMovieComponent.py +160 -0
- psychopy/tests/data/correctScript/python/correctNoiseStimComponent.py +169 -0
- psychopy/tests/data/correctScript/python/correctParallelOutComponent.py +156 -0
- psychopy/tests/data/correctScript/python/correctPatchComponent.py +159 -0
- psychopy/tests/data/correctScript/python/correctPolygonComponent.py +159 -0
- psychopy/tests/data/correctScript/python/correctQmixPumpComponent.py +174 -0
- psychopy/tests/data/correctScript/python/correctRatingScaleComponent.py +152 -0
- psychopy/tests/data/correctScript/python/correctSliderComponent.py +159 -0
- psychopy/tests/data/correctScript/python/correctSoundComponent.py +157 -0
- psychopy/tests/data/correctScript/python/correctStaticComponent.py +176 -0
- psychopy/tests/data/correctScript/python/correctTextComponent.py +159 -0
- psychopy/tests/data/correctScript/python/correctVariableComponent.py +139 -0
- psychopy/tests/data/correctScript/python/correctcedrusButtonBoxComponent.py +199 -0
- psychopy/tests/data/correctScript/python/correctioLabsButtonBoxComponent.py +187 -0
- psychopy/tests/data/dataTest.xlsx +0 -0
- psychopy/tests/data/dots_cm.png +0 -0
- psychopy/tests/data/dots_deg.png +0 -0
- psychopy/tests/data/dots_degFlat.png +0 -0
- psychopy/tests/data/dots_degFlatPos.png +0 -0
- psychopy/tests/data/dots_height.png +0 -0
- psychopy/tests/data/dots_norm.png +0 -0
- psychopy/tests/data/dots_normAddBlend.png +0 -0
- psychopy/tests/data/dots_normHexbackground.png +0 -0
- psychopy/tests/data/dots_normNoShade.png +0 -0
- psychopy/tests/data/dots_pix.png +0 -0
- psychopy/tests/data/dots_stencil.png +0 -0
- psychopy/tests/data/duplicateHeaders.csv +2 -0
- psychopy/tests/data/elarray1_cm.png +0 -0
- psychopy/tests/data/elarray1_deg.png +0 -0
- psychopy/tests/data/elarray1_degFlat.png +0 -0
- psychopy/tests/data/elarray1_degFlatPos.png +0 -0
- psychopy/tests/data/elarray1_height.png +0 -0
- psychopy/tests/data/elarray1_norm.png +0 -0
- psychopy/tests/data/elarray1_normAddBlend.png +0 -0
- psychopy/tests/data/elarray1_normHexbackground.png +0 -0
- psychopy/tests/data/elarray1_pix.png +0 -0
- psychopy/tests/data/elarray1_stencil.png +0 -0
- psychopy/tests/data/envelopeandrcos_cm.png +0 -0
- psychopy/tests/data/envelopeandrcos_deg.png +0 -0
- psychopy/tests/data/envelopeandrcos_degFlat.png +0 -0
- psychopy/tests/data/envelopeandrcos_degFlatPos.png +0 -0
- psychopy/tests/data/envelopeandrcos_height.png +0 -0
- psychopy/tests/data/envelopeandrcos_norm.png +0 -0
- psychopy/tests/data/envelopeandrcos_normAddBlend.png +0 -0
- psychopy/tests/data/envelopeandrcos_normHexbackground.png +0 -0
- psychopy/tests/data/envelopeandrcos_pix.png +0 -0
- psychopy/tests/data/envelopeandrcos_stencil.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_cm.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_deg.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_degFlat.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_degFlatPos.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_height.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_norm.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_normAddBlend.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_normHexbackground.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_pix.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_stencil.png +0 -0
- psychopy/tests/data/filltext.png +0 -0
- psychopy/tests/data/form_font_demographics.png +0 -0
- psychopy/tests/data/form_font_demographics.xlsx +0 -0
- psychopy/tests/data/form_font_languages.png +0 -0
- psychopy/tests/data/form_font_languages.xlsx +0 -0
- psychopy/tests/data/form_font_nonstandard.png +0 -0
- psychopy/tests/data/futureParams.psyexp +150 -0
- psychopy/tests/data/gabor1_cm.png +0 -0
- psychopy/tests/data/gabor1_deg.png +0 -0
- psychopy/tests/data/gabor1_degFlat.png +0 -0
- psychopy/tests/data/gabor1_degFlatPos.png +0 -0
- psychopy/tests/data/gabor1_height.png +0 -0
- psychopy/tests/data/gabor1_norm.png +0 -0
- psychopy/tests/data/gabor1_normAddBlend.png +0 -0
- psychopy/tests/data/gabor1_normHexbackground.png +0 -0
- psychopy/tests/data/gabor1_normNoShade.png +0 -0
- psychopy/tests/data/gabor1_pix.png +0 -0
- psychopy/tests/data/gabor1_stencil.png +0 -0
- psychopy/tests/data/gabor2_cm.png +0 -0
- psychopy/tests/data/gabor2_deg.png +0 -0
- psychopy/tests/data/gabor2_degFlat.png +0 -0
- psychopy/tests/data/gabor2_degFlatPos.png +0 -0
- psychopy/tests/data/gabor2_height.png +0 -0
- psychopy/tests/data/gabor2_norm.png +0 -0
- psychopy/tests/data/gabor2_normAddBlend.png +0 -0
- psychopy/tests/data/gabor2_normHexbackground.png +0 -0
- psychopy/tests/data/gabor2_normNoShade.png +0 -0
- psychopy/tests/data/gabor2_pix.png +0 -0
- psychopy/tests/data/gabor2_stencil.png +0 -0
- psychopy/tests/data/ghost_stroop.psyexp +131 -0
- psychopy/tests/data/ghost_trialTypes.xlsx +0 -0
- psychopy/tests/data/green_48000.flac.dist +0 -0
- psychopy/tests/data/greyscale.jpg +0 -0
- psychopy/tests/data/greyscale2.png +0 -0
- psychopy/tests/data/greyscale2_cm.png +0 -0
- psychopy/tests/data/greyscale2_deg.png +0 -0
- psychopy/tests/data/greyscale2_degFlat.png +0 -0
- psychopy/tests/data/greyscale2_degFlatPos.png +0 -0
- psychopy/tests/data/greyscale2_height.png +0 -0
- psychopy/tests/data/greyscale2_norm.png +0 -0
- psychopy/tests/data/greyscale2_normAddBlend.png +0 -0
- psychopy/tests/data/greyscale2_normHexbackground.png +0 -0
- psychopy/tests/data/greyscale2_normNoShade.png +0 -0
- psychopy/tests/data/greyscale2_pix.png +0 -0
- psychopy/tests/data/greyscale2_stencil.png +0 -0
- psychopy/tests/data/greyscaleLowContr_cm.png +0 -0
- psychopy/tests/data/greyscaleLowContr_deg.png +0 -0
- psychopy/tests/data/greyscaleLowContr_degFlat.png +0 -0
- psychopy/tests/data/greyscaleLowContr_degFlatPos.png +0 -0
- psychopy/tests/data/greyscaleLowContr_height.png +0 -0
- psychopy/tests/data/greyscaleLowContr_norm.png +0 -0
- psychopy/tests/data/greyscaleLowContr_normAddBlend.png +0 -0
- psychopy/tests/data/greyscaleLowContr_normHexbackground.png +0 -0
- psychopy/tests/data/greyscaleLowContr_normNoShade.png +0 -0
- psychopy/tests/data/greyscaleLowContr_pix.png +0 -0
- psychopy/tests/data/greyscaleLowContr_stencil.png +0 -0
- psychopy/tests/data/greyscale_cm.png +0 -0
- psychopy/tests/data/greyscale_deg.png +0 -0
- psychopy/tests/data/greyscale_degFlat.png +0 -0
- psychopy/tests/data/greyscale_degFlatPos.png +0 -0
- psychopy/tests/data/greyscale_height.png +0 -0
- psychopy/tests/data/greyscale_norm.png +0 -0
- psychopy/tests/data/greyscale_normAddBlend.png +0 -0
- psychopy/tests/data/greyscale_normHexbackground.png +0 -0
- psychopy/tests/data/greyscale_normNoShade.png +0 -0
- psychopy/tests/data/greyscale_pix.png +0 -0
- psychopy/tests/data/greyscale_stencil.png +0 -0
- psychopy/tests/data/imageAndGauss_cm.png +0 -0
- psychopy/tests/data/imageAndGauss_deg.png +0 -0
- psychopy/tests/data/imageAndGauss_degFlat.png +0 -0
- psychopy/tests/data/imageAndGauss_degFlatPos.png +0 -0
- psychopy/tests/data/imageAndGauss_height.png +0 -0
- psychopy/tests/data/imageAndGauss_norm.png +0 -0
- psychopy/tests/data/imageAndGauss_normAddBlend.png +0 -0
- psychopy/tests/data/imageAndGauss_normHexbackground.png +0 -0
- psychopy/tests/data/imageAndGauss_normNoShade.png +0 -0
- psychopy/tests/data/imageAndGauss_pix.png +0 -0
- psychopy/tests/data/imageAndGauss_stencil.png +0 -0
- psychopy/tests/data/movFrame1_cm.png +0 -0
- psychopy/tests/data/movFrame1_deg.png +0 -0
- psychopy/tests/data/movFrame1_degFlat.png +0 -0
- psychopy/tests/data/movFrame1_degFlatPos.png +0 -0
- psychopy/tests/data/movFrame1_height.png +0 -0
- psychopy/tests/data/movFrame1_norm.png +0 -0
- psychopy/tests/data/movFrame1_normAddBlend.png +0 -0
- psychopy/tests/data/movFrame1_normHexbackground.png +0 -0
- psychopy/tests/data/movFrame1_normNoShade.png +0 -0
- psychopy/tests/data/movFrame1_pix.png +0 -0
- psychopy/tests/data/movFrame1_stencil.png +0 -0
- psychopy/tests/data/multiKeypressExperiment.psydat +357 -0
- psychopy/tests/data/multiKeypressTrialhandler.psydat +252 -0
- psychopy/tests/data/multiStairConds.xlsx +0 -0
- psychopy/tests/data/multiStairQuestPlus.xlsx +0 -0
- psychopy/tests/data/newstyle.psydat +6155 -0
- psychopy/tests/data/noiseAndRcos_cm.png +0 -0
- psychopy/tests/data/noiseAndRcos_deg.png +0 -0
- psychopy/tests/data/noiseAndRcos_degFlat.png +0 -0
- psychopy/tests/data/noiseAndRcos_degFlatPos.png +0 -0
- psychopy/tests/data/noiseAndRcos_height.png +0 -0
- psychopy/tests/data/noiseAndRcos_norm.png +0 -0
- psychopy/tests/data/noiseAndRcos_normAddBlend.png +0 -0
- psychopy/tests/data/noiseAndRcos_normHexbackground.png +0 -0
- psychopy/tests/data/noiseAndRcos_normNoShade.png +0 -0
- psychopy/tests/data/noiseAndRcos_pix.png +0 -0
- psychopy/tests/data/noiseAndRcos_stencil.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_cm.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_deg.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_degFlat.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_degFlatPos.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_height.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_norm.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normAddBlend.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normHexbackground.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normNoShade.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_pix.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_stencil.png +0 -0
- psychopy/tests/data/numpyImage_cm.png +0 -0
- psychopy/tests/data/numpyImage_deg.png +0 -0
- psychopy/tests/data/numpyImage_degFlat.png +0 -0
- psychopy/tests/data/numpyImage_degFlatPos.png +0 -0
- psychopy/tests/data/numpyImage_height.png +0 -0
- psychopy/tests/data/numpyImage_norm.png +0 -0
- psychopy/tests/data/numpyImage_normAddBlend.png +0 -0
- psychopy/tests/data/numpyImage_normHexbackground.png +0 -0
- psychopy/tests/data/numpyImage_normNoShade.png +0 -0
- psychopy/tests/data/numpyImage_pix.png +0 -0
- psychopy/tests/data/numpyImage_stencil.png +0 -0
- psychopy/tests/data/numpyLowContr_cm.png +0 -0
- psychopy/tests/data/numpyLowContr_deg.png +0 -0
- psychopy/tests/data/numpyLowContr_degFlat.png +0 -0
- psychopy/tests/data/numpyLowContr_degFlatPos.png +0 -0
- psychopy/tests/data/numpyLowContr_height.png +0 -0
- psychopy/tests/data/numpyLowContr_norm.png +0 -0
- psychopy/tests/data/numpyLowContr_normAddBlend.png +0 -0
- psychopy/tests/data/numpyLowContr_normHexbackground.png +0 -0
- psychopy/tests/data/numpyLowContr_normNoShade.png +0 -0
- psychopy/tests/data/numpyLowContr_pix.png +0 -0
- psychopy/tests/data/numpyLowContr_stencil.png +0 -0
- psychopy/tests/data/oldstyle.psydat +1534 -0
- psychopy/tests/data/oldstyle_stair.psydat +263 -0
- psychopy/tests/data/ratingscale1_cm.png +0 -0
- psychopy/tests/data/ratingscale1_deg.png +0 -0
- psychopy/tests/data/ratingscale1_degFlat.png +0 -0
- psychopy/tests/data/ratingscale1_degFlatPos.png +0 -0
- psychopy/tests/data/ratingscale1_height.png +0 -0
- psychopy/tests/data/ratingscale1_norm.png +0 -0
- psychopy/tests/data/ratingscale1_normAddBlend.png +0 -0
- psychopy/tests/data/ratingscale1_normHexbackground.png +0 -0
- psychopy/tests/data/ratingscale1_normNoShade.png +0 -0
- psychopy/tests/data/ratingscale1_pix.png +0 -0
- psychopy/tests/data/ratingscale1_stencil.png +0 -0
- psychopy/tests/data/red_16000.flac.dist +0 -0
- psychopy/tests/data/retroListParam.psyexp +82 -0
- psychopy/tests/data/right_to_left_unidcode.xlsx +0 -0
- psychopy/tests/data/sample.meshwarp.data +11522 -0
- psychopy/tests/data/shape2_1_cm.png +0 -0
- psychopy/tests/data/shape2_1_deg.png +0 -0
- psychopy/tests/data/shape2_1_degFlat.png +0 -0
- psychopy/tests/data/shape2_1_degFlatPos.png +0 -0
- psychopy/tests/data/shape2_1_height.png +0 -0
- psychopy/tests/data/shape2_1_norm.png +0 -0
- psychopy/tests/data/shape2_1_normAddBlend.png +0 -0
- psychopy/tests/data/shape2_1_normHexbackground.png +0 -0
- psychopy/tests/data/shape2_1_normNoShade.png +0 -0
- psychopy/tests/data/shape2_1_pix.png +0 -0
- psychopy/tests/data/shape2_1_stencil.png +0 -0
- psychopy/tests/data/shape2_2_cm.png +0 -0
- psychopy/tests/data/shape2_2_deg.png +0 -0
- psychopy/tests/data/shape2_2_degFlat.png +0 -0
- psychopy/tests/data/shape2_2_degFlatPos.png +0 -0
- psychopy/tests/data/shape2_2_height.png +0 -0
- psychopy/tests/data/shape2_2_norm.png +0 -0
- psychopy/tests/data/shape2_2_normAddBlend.png +0 -0
- psychopy/tests/data/shape2_2_normHexbackground.png +0 -0
- psychopy/tests/data/shape2_2_normNoShade.png +0 -0
- psychopy/tests/data/shape2_2_pix.png +0 -0
- psychopy/tests/data/shape2_2_stencil.png +0 -0
- psychopy/tests/data/simpleimage1_cm.png +0 -0
- psychopy/tests/data/simpleimage1_deg.png +0 -0
- psychopy/tests/data/simpleimage1_degFlat.png +0 -0
- psychopy/tests/data/simpleimage1_degFlatPos.png +0 -0
- psychopy/tests/data/simpleimage1_height.png +0 -0
- psychopy/tests/data/simpleimage1_norm.png +0 -0
- psychopy/tests/data/simpleimage1_normAddBlend.png +0 -0
- psychopy/tests/data/simpleimage1_normHexbackground.png +0 -0
- psychopy/tests/data/simpleimage1_normNoShade.png +0 -0
- psychopy/tests/data/simpleimage1_pix.png +0 -0
- psychopy/tests/data/simpleimage1_stencil.png +0 -0
- psychopy/tests/data/test001EntryImporting.psyexp +66 -0
- psychopy/tests/data/testMovie.mp4 +0 -0
- psychopy/tests/data/test_basic_run.py +1 -0
- psychopy/tests/data/test_circle_radius_.1height.png +0 -0
- psychopy/tests/data/test_circle_radius_.2height.png +0 -0
- psychopy/tests/data/test_circle_radius_10pix.png +0 -0
- psychopy/tests/data/test_circle_radius_20pix.png +0 -0
- psychopy/tests/data/test_components/testClearKeyboard/testClearKeyboard.psyexp +200 -0
- psychopy/tests/data/test_form_combinations_choice_bigItem.png +0 -0
- psychopy/tests/data/test_form_combinations_choice_bigItemOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_choice_bigResp.png +0 -0
- psychopy/tests/data/test_form_combinations_choice_bigRespOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_description_bigItem.png +0 -0
- psychopy/tests/data/test_form_combinations_description_bigItemOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_description_bigResp.png +0 -0
- psychopy/tests/data/test_form_combinations_description_bigRespOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_free text_bigItem.png +0 -0
- psychopy/tests/data/test_form_combinations_free text_bigItemOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_free text_bigResp.png +0 -0
- psychopy/tests/data/test_form_combinations_free text_bigRespOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_heading_bigItem.png +0 -0
- psychopy/tests/data/test_form_combinations_heading_bigItemOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_heading_bigResp.png +0 -0
- psychopy/tests/data/test_form_combinations_heading_bigRespOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_radio_bigItem.png +0 -0
- psychopy/tests/data/test_form_combinations_radio_bigItemOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_radio_bigResp.png +0 -0
- psychopy/tests/data/test_form_combinations_radio_bigRespOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_rating_bigItem.png +0 -0
- psychopy/tests/data/test_form_combinations_rating_bigItemOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_rating_bigResp.png +0 -0
- psychopy/tests/data/test_form_combinations_rating_bigRespOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_slider_bigItem.png +0 -0
- psychopy/tests/data/test_form_combinations_slider_bigItemOverflow.png +0 -0
- psychopy/tests/data/test_form_combinations_slider_bigResp.png +0 -0
- psychopy/tests/data/test_form_combinations_slider_bigRespOverflow.png +0 -0
- psychopy/tests/data/test_get_resources/blue.png +0 -0
- psychopy/tests/data/test_get_resources/groupA.csv +3 -0
- psychopy/tests/data/test_get_resources/groupB.csv +3 -0
- psychopy/tests/data/test_get_resources/groups.csv +3 -0
- psychopy/tests/data/test_get_resources/handledbyrm_constrloop.psyexp +143 -0
- psychopy/tests/data/test_get_resources/handledbyrm_noloop.psyexp +114 -0
- psychopy/tests/data/test_get_resources/handledbyrm_recurloop.psyexp +138 -0
- psychopy/tests/data/test_get_resources/handledbyrm_strloop.psyexp +126 -0
- psychopy/tests/data/test_get_resources/handledbystatic_constrloop.psyexp +141 -0
- psychopy/tests/data/test_get_resources/handledbystatic_noloop.psyexp +112 -0
- psychopy/tests/data/test_get_resources/handledbystatic_recurloop.psyexp +136 -0
- psychopy/tests/data/test_get_resources/handledbystatic_strloop.psyexp +124 -0
- psychopy/tests/data/test_get_resources/unhandled_constrloop.psyexp +128 -0
- psychopy/tests/data/test_get_resources/unhandled_noloop.psyexp +99 -0
- psychopy/tests/data/test_get_resources/unhandled_recurloop.psyexp +123 -0
- psychopy/tests/data/test_get_resources/unhandled_strloop.psyexp +111 -0
- psychopy/tests/data/test_get_resources/white.png +0 -0
- psychopy/tests/data/test_get_resources/yellow.png +0 -0
- psychopy/tests/data/test_image_aspect_default_None.png +0 -0
- psychopy/tests/data/test_image_aspect_default_xFull_yNone.png +0 -0
- psychopy/tests/data/test_image_aspect_default_xNone_yFull.png +0 -0
- psychopy/tests/data/test_image_aspect_default_xNone_yNone.png +0 -0
- psychopy/tests/data/test_image_flip_anchor_horiz.png +0 -0
- psychopy/tests/data/test_image_flip_anchor_vert.png +0 -0
- psychopy/tests/data/test_loaded_namespace/test_counterbalance.psyexp +142 -0
- psychopy/tests/data/test_loaded_namespace/test_custom_missing.psyexp +129 -0
- psychopy/tests/data/test_loaded_namespace/test_missing_counterbalance.psyexp +116 -0
- psychopy/tests/data/test_loaded_namespace/test_mix_exp.psyexp +181 -0
- psychopy/tests/data/test_loaded_namespace/test_mix_missing.psyexp +140 -0
- psychopy/tests/data/test_loaded_namespace/test_mix_name_calibration.psyexp +164 -0
- psychopy/tests/data/test_loops/testLoopsBlocks.psyexp +161 -0
- psychopy/tests/data/test_loops/testStaircase.psyexp +105 -0
- psychopy/tests/data/test_loops/test_current_loop_attr.psyexp +185 -0
- psychopy/tests/data/test_panorama/panoramaTestImage.png +0 -0
- psychopy/tests/data/test_panorama/panoramaTestImage.svg +1 -0
- psychopy/tests/data/test_panorama/testPanorama_mvmt_-0.3_-0.3.png +0 -0
- psychopy/tests/data/test_panorama/testPanorama_mvmt_-0.3_0.3.png +0 -0
- psychopy/tests/data/test_panorama/testPanorama_mvmt_-1.0_-0.3.png +0 -0
- psychopy/tests/data/test_panorama/testPanorama_mvmt_-1.0_0.3.png +0 -0
- psychopy/tests/data/test_panorama/testPanorama_mvmt_0.0_-1.0.png +0 -0
- psychopy/tests/data/test_panorama/testPanorama_mvmt_0.0_1.0.png +0 -0
- psychopy/tests/data/test_panorama/testPanorama_mvmt_0.3_-0.3.png +0 -0
- psychopy/tests/data/test_panorama/testPanorama_mvmt_0.3_0.3.png +0 -0
- psychopy/tests/data/test_resources.psyexp +491 -0
- psychopy/tests/data/test_session/outside_root/externalExp.psyexp +116 -0
- psychopy/tests/data/test_session/root/annotation/annotation.psyexp +161 -0
- psychopy/tests/data/test_session/root/error/error.psyexp +93 -0
- psychopy/tests/data/test_session/root/exp1/exp1.psyexp +133 -0
- psychopy/tests/data/test_session/root/exp2/exp2.psyexp +133 -0
- psychopy/tests/data/test_session/root/frameRate/frameRate.psyexp +114 -0
- psychopy/tests/data/test_session/root/invUseVersion/invUseVersion.psyexp +133 -0
- psychopy/tests/data/test_session/root/testClockFormat/testClockFormat.psyexp +122 -0
- psychopy/tests/data/test_session/root/testCtrls/testCtrls.psyexp +115 -0
- psychopy/tests/data/test_session/root/testEditExpInfo/testEditExpInfo.psyexp +135 -0
- psychopy/tests/data/test_session/root/testFutureTrials/testFutureTrials.psyexp +155 -0
- psychopy/tests/data/test_session/root/testNamedButtonBox/testNamedButtonBox.psyexp +145 -0
- psychopy/tests/data/test_session/root/testTrialNav/trialNav.psyexp +158 -0
- psychopy/tests/data/test_slider_horiz_accute_horiz.png +0 -0
- psychopy/tests/data/test_slider_horiz_accute_vert.png +0 -0
- psychopy/tests/data/test_slider_horiz_horiz.png +0 -0
- psychopy/tests/data/test_slider_horiz_obtuse_horiz.png +0 -0
- psychopy/tests/data/test_slider_horiz_obtuse_vert.png +0 -0
- psychopy/tests/data/test_slider_horiz_vert.png +0 -0
- psychopy/tests/data/test_slider_ticklabelloc_blanks.png +0 -0
- psychopy/tests/data/test_slider_ticklabelloc_clustered.png +0 -0
- psychopy/tests/data/test_slider_ticklabelloc_morelabels.png +0 -0
- psychopy/tests/data/test_slider_ticklabelloc_morelabelsclustered.png +0 -0
- psychopy/tests/data/test_slider_ticklabelloc_moreticks.png +0 -0
- psychopy/tests/data/test_slider_ticklabelloc_moreticksclustered.png +0 -0
- psychopy/tests/data/test_slider_ticklabelloc_nolabels.png +0 -0
- psychopy/tests/data/test_slider_ticklabelloc_noticks.png +0 -0
- psychopy/tests/data/test_slider_ticklabelloc_simple.png +0 -0
- psychopy/tests/data/test_slider_triangle_horiz_False_flip_False.png +0 -0
- psychopy/tests/data/test_slider_triangle_horiz_False_flip_True.png +0 -0
- psychopy/tests/data/test_slider_triangle_horiz_True_flip_False.png +0 -0
- psychopy/tests/data/test_slider_triangle_horiz_True_flip_True.png +0 -0
- psychopy/tests/data/test_sounds/default_16000.wav +0 -0
- psychopy/tests/data/test_sounds/default_192000.wav +0 -0
- psychopy/tests/data/test_sounds/default_22050.wav +0 -0
- psychopy/tests/data/test_sounds/default_32000.wav +0 -0
- psychopy/tests/data/test_sounds/default_44100.wav +0 -0
- psychopy/tests/data/test_sounds/default_48000.wav +0 -0
- psychopy/tests/data/test_sounds/default_8000.wav +0 -0
- psychopy/tests/data/test_sounds/default_96000.wav +0 -0
- psychopy/tests/data/test_static_component_script.psyexp +76 -0
- psychopy/tests/data/test_win_bg_large_256_default.png +0 -0
- psychopy/tests/data/test_win_bg_large_500_default.png +0 -0
- psychopy/tests/data/test_win_bg_small_200_default.png +0 -0
- psychopy/tests/data/test_win_bg_small_256_default.png +0 -0
- psychopy/tests/data/test_win_bg_tall_200_default.png +0 -0
- psychopy/tests/data/test_win_bg_tall_256_default.png +0 -0
- psychopy/tests/data/test_win_bg_tall_500_default.png +0 -0
- psychopy/tests/data/test_win_bg_tall_fill_default.png +0 -0
- psychopy/tests/data/test_win_bg_wide_200_default.png +0 -0
- psychopy/tests/data/test_win_bg_wide_256_default.png +0 -0
- psychopy/tests/data/test_win_bg_wide_500_default.png +0 -0
- psychopy/tests/data/test_win_bg_wide_fill_default.png +0 -0
- psychopy/tests/data/test_win_bgcolor_blue.png +0 -0
- psychopy/tests/data/test_win_bgcolor_green.png +0 -0
- psychopy/tests/data/test_win_bgcolor_red.png +0 -0
- psychopy/tests/data/testimage.jpg +0 -0
- psychopy/tests/data/testimagegray.jpg +0 -0
- psychopy/tests/data/testpixels.png +0 -0
- psychopy/tests/data/testwedges.png +0 -0
- psychopy/tests/data/text1_cm.png +0 -0
- psychopy/tests/data/text1_deg.png +0 -0
- psychopy/tests/data/text1_degFlat.png +0 -0
- psychopy/tests/data/text1_degFlatPos.png +0 -0
- psychopy/tests/data/text1_height.png +0 -0
- psychopy/tests/data/text1_norm.png +0 -0
- psychopy/tests/data/text1_normAddBlend.png +0 -0
- psychopy/tests/data/text1_normHexbackground.png +0 -0
- psychopy/tests/data/text1_normNoShade.png +0 -0
- psychopy/tests/data/text1_pix.png +0 -0
- psychopy/tests/data/text1_stencil.png +0 -0
- psychopy/tests/data/text2_cm.png +0 -0
- psychopy/tests/data/text2_deg.png +0 -0
- psychopy/tests/data/text2_degFlat.png +0 -0
- psychopy/tests/data/text2_degFlatPos.png +0 -0
- psychopy/tests/data/text2_norm.png +0 -0
- psychopy/tests/data/text2_normNoShade.png +0 -0
- psychopy/tests/data/text2_pix.png +0 -0
- psychopy/tests/data/textbox_charcolors_default_roygbiv.png +0 -0
- psychopy/tests/data/textbox_charcolors_default_white_hello_black_there.png +0 -0
- psychopy/tests/data/textbox_default_align_bottom_center.png +0 -0
- psychopy/tests/data/textbox_default_align_bottom_left.png +0 -0
- psychopy/tests/data/textbox_default_align_bottom_right.png +0 -0
- psychopy/tests/data/textbox_default_align_center.png +0 -0
- psychopy/tests/data/textbox_default_align_center_center.png +0 -0
- psychopy/tests/data/textbox_default_align_center_left.png +0 -0
- psychopy/tests/data/textbox_default_align_center_right.png +0 -0
- psychopy/tests/data/textbox_default_align_centre.png +0 -0
- psychopy/tests/data/textbox_default_align_centre_centre.png +0 -0
- psychopy/tests/data/textbox_default_align_more_than_two_words.png +0 -0
- psychopy/tests/data/textbox_default_align_someword.png +0 -0
- psychopy/tests/data/textbox_default_align_top_center.png +0 -0
- psychopy/tests/data/textbox_default_align_top_left.png +0 -0
- psychopy/tests/data/textbox_default_align_top_right.png +0 -0
- psychopy/tests/data/textbox_default_colors_WOB.png +0 -0
- psychopy/tests/data/textbox_default_colors_exemplar1.png +0 -0
- psychopy/tests/data/textbox_default_colors_exemplar2.png +0 -0
- psychopy/tests/data/textbox_default_colors_exemplar3.png +0 -0
- psychopy/tests/data/textbox_default_colors_tyke1.png +0 -0
- psychopy/tests/data/textbox_default_colors_tyke2.png +0 -0
- psychopy/tests/data/textbox_default_colors_tyke3.png +0 -0
- psychopy/tests/data/textbox_default_cutoff_top.png +0 -0
- psychopy/tests/data/textbox_default_exemplar_1.png +0 -0
- psychopy/tests/data/textbox_default_exemplar_2.png +0 -0
- psychopy/tests/data/textbox_default_exemplar_3.png +0 -0
- psychopy/tests/data/textbox_default_exemplar_4.png +0 -0
- psychopy/tests/data/textbox_default_tyke_1.png +0 -0
- psychopy/tests/data/textbox_default_tyke_2.png +0 -0
- psychopy/tests/data/textbox_typing_blank.png +0 -0
- psychopy/tests/data/textbox_typing_longKoeran.png +0 -0
- psychopy/tests/data/textbox_typing_longWord.png +0 -0
- psychopy/tests/data/textbox_typing_navDel.png +0 -0
- psychopy/tests/data/textbox_typing_navLR.png +0 -0
- psychopy/tests/data/textbox_typing_newline.png +0 -0
- psychopy/tests/data/textbox_typing_pangram.png +0 -0
- psychopy/tests/data/textbox_uax14_align_bottom_center.png +0 -0
- psychopy/tests/data/textbox_uax14_align_bottom_left.png +0 -0
- psychopy/tests/data/textbox_uax14_align_bottom_right.png +0 -0
- psychopy/tests/data/textbox_uax14_align_center.png +0 -0
- psychopy/tests/data/textbox_uax14_align_center_center.png +0 -0
- psychopy/tests/data/textbox_uax14_align_center_left.png +0 -0
- psychopy/tests/data/textbox_uax14_align_center_right.png +0 -0
- psychopy/tests/data/textbox_uax14_align_centre.png +0 -0
- psychopy/tests/data/textbox_uax14_align_centre_centre.png +0 -0
- psychopy/tests/data/textbox_uax14_align_more_than_two_words.png +0 -0
- psychopy/tests/data/textbox_uax14_align_someword.png +0 -0
- psychopy/tests/data/textbox_uax14_align_top_center.png +0 -0
- psychopy/tests/data/textbox_uax14_align_top_left.png +0 -0
- psychopy/tests/data/textbox_uax14_align_top_right.png +0 -0
- psychopy/tests/data/textbox_uax14_colors_WOB.png +0 -0
- psychopy/tests/data/textbox_uax14_colors_exemplar1.png +0 -0
- psychopy/tests/data/textbox_uax14_colors_exemplar2.png +0 -0
- psychopy/tests/data/textbox_uax14_colors_exemplar3.png +0 -0
- psychopy/tests/data/textbox_uax14_colors_tyke1.png +0 -0
- psychopy/tests/data/textbox_uax14_colors_tyke2.png +0 -0
- psychopy/tests/data/textbox_uax14_colors_tyke3.png +0 -0
- psychopy/tests/data/textbox_uax14_cutoff_top.png +0 -0
- psychopy/tests/data/textbox_uax14_exemplar_1.png +0 -0
- psychopy/tests/data/textbox_uax14_exemplar_2.png +0 -0
- psychopy/tests/data/textbox_uax14_exemplar_3.png +0 -0
- psychopy/tests/data/textbox_uax14_exemplar_4.png +0 -0
- psychopy/tests/data/textbox_uax14_tyke_1.png +0 -0
- psychopy/tests/data/textbox_uax14_tyke_2.png +0 -0
- psychopy/tests/data/trialTypes.csv +1 -0
- psychopy/tests/data/trialTypes.docx +0 -0
- psychopy/tests/data/trialTypes.pkl +0 -0
- psychopy/tests/data/trialTypes.tsv +7 -0
- psychopy/tests/data/trialTypes.xls +0 -0
- psychopy/tests/data/trialTypes.xlsx +0 -0
- psychopy/tests/data/trialTypes_eu.csv +7 -0
- psychopy/tests/data/trialsBlankCols.xlsx +0 -0
- psychopy/tests/data/wedge1_cm.png +0 -0
- psychopy/tests/data/wedge1_deg.png +0 -0
- psychopy/tests/data/wedge1_degFlat.png +0 -0
- psychopy/tests/data/wedge1_degFlatPos.png +0 -0
- psychopy/tests/data/wedge1_height.png +0 -0
- psychopy/tests/data/wedge1_norm.png +0 -0
- psychopy/tests/data/wedge1_normAddBlend.png +0 -0
- psychopy/tests/data/wedge1_normHexbackground.png +0 -0
- psychopy/tests/data/wedge1_normNoShade.png +0 -0
- psychopy/tests/data/wedge1_pix.png +0 -0
- psychopy/tests/data/wedge1_stencil.png +0 -0
- psychopy/tests/data/wedge2_cm.png +0 -0
- psychopy/tests/data/wedge2_deg.png +0 -0
- psychopy/tests/data/wedge2_degFlat.png +0 -0
- psychopy/tests/data/wedge2_degFlatPos.png +0 -0
- psychopy/tests/data/wedge2_height.png +0 -0
- psychopy/tests/data/wedge2_norm.png +0 -0
- psychopy/tests/data/wedge2_normAddBlend.png +0 -0
- psychopy/tests/data/wedge2_normHexbackground.png +0 -0
- psychopy/tests/data/wedge2_normNoShade.png +0 -0
- psychopy/tests/data/wedge2_pix.png +0 -0
- psychopy/tests/data/wedge2_stencil.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale-1_-1_pos-0.4_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale-1_-1_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale-1_1_pos-0.4_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale-1_1_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale-2_-2_pos-0.4_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale-2_-2_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale-2_2_pos-0.4_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale-2_2_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale1_-1_pos-0.4_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale1_-1_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale1_1_pos-0.4_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale1_1_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale2_-2_pos-0.4_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale2_-2_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale2_2_pos-0.4_0.png +0 -0
- psychopy/tests/data/winScalePos_ori0_scale2_2_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori45_scale-1_-1_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori45_scale-1_1_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori45_scale-2_-2_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori45_scale-2_2_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori45_scale1_-1_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori45_scale1_1_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori45_scale2_-2_pos0_0.png +0 -0
- psychopy/tests/data/winScalePos_ori45_scale2_2_pos0_0.png +0 -0
- psychopy/tests/doc/run_btn.png +0 -0
- psychopy/tests/doc/test-suite-bugs.jpg +0 -0
- psychopy/tests/doc/user-bugs.jpg +0 -0
- psychopy/tests/dummy_xorg.conf +21 -0
- psychopy/tests/run.py +50 -0
- psychopy/tests/test_Installation.py +38 -0
- psychopy/tests/test_alerts/test_alerts.py +37 -0
- psychopy/tests/test_alerts/test_alerttools.py +132 -0
- psychopy/tests/test_app/__init__.py +0 -0
- psychopy/tests/test_app/conftest.py +40 -0
- psychopy/tests/test_app/test_builder/__init__.py +0 -0
- psychopy/tests/test_app/test_builder/test_BuilderFrame.py +166 -0
- psychopy/tests/test_app/test_builder/test_CompileFromBuilder.py +133 -0
- psychopy/tests/test_app/test_builder/test_ComponentDialogs.py +98 -0
- psychopy/tests/test_app/test_command_line.py +65 -0
- psychopy/tests/test_app/test_runner/__init__.py +0 -0
- psychopy/tests/test_app/test_runner/test_RunnerFrame.py +166 -0
- psychopy/tests/test_app/test_speed.py +147 -0
- psychopy/tests/test_app/test_themes/test_icons.py +79 -0
- psychopy/tests/test_codecov.py +29 -0
- psychopy/tests/test_colors/test_Color.py +41 -0
- psychopy/tests/test_data/dataPrev.xlsx +0 -0
- psychopy/tests/test_data/test_ExperimentHandler.py +171 -0
- psychopy/tests/test_data/test_MultiStairHandler.py +174 -0
- psychopy/tests/test_data/test_StairHandlers.py +1241 -0
- psychopy/tests/test_data/test_TrialHandler.py +335 -0
- psychopy/tests/test_data/test_TrialHandler2.py +584 -0
- psychopy/tests/test_data/test_TrialHandlerExt.py +359 -0
- psychopy/tests/test_data/test_fitFunctions.py +101 -0
- psychopy/tests/test_data/test_utils.py +173 -0
- psychopy/tests/test_data/test_xlsx.py +92 -0
- psychopy/tests/test_demos/test_builder_demos.py +52 -0
- psychopy/tests/test_experiment/__init__.py +0 -0
- psychopy/tests/test_experiment/known_py_diffs.txt +47 -0
- psychopy/tests/test_experiment/needs_wx/__init__.py +0 -0
- psychopy/tests/test_experiment/needs_wx/componsTemplate.txt +14780 -0
- psychopy/tests/test_experiment/needs_wx/genComponsTemplate.py +130 -0
- psychopy/tests/test_experiment/needs_wx/test_Experiment.py +406 -0
- psychopy/tests/test_experiment/needs_wx/test_components.py +170 -0
- psychopy/tests/test_experiment/test_component_compile_js.py +59 -0
- psychopy/tests/test_experiment/test_component_compile_python.py +165 -0
- psychopy/tests/test_experiment/test_components/__init__.py +1 -0
- psychopy/tests/test_experiment/test_components/test_ButtonBoxComponent.py +218 -0
- psychopy/tests/test_experiment/test_components/test_CodeComponent.py +70 -0
- psychopy/tests/test_experiment/test_components/test_GratingComponent.py +7 -0
- psychopy/tests/test_experiment/test_components/test_ImageComponent.py +8 -0
- psychopy/tests/test_experiment/test_components/test_KeyboardComponent.py +28 -0
- psychopy/tests/test_experiment/test_components/test_MouseComponent.py +136 -0
- psychopy/tests/test_experiment/test_components/test_PolygonComponent.py +65 -0
- psychopy/tests/test_experiment/test_components/test_ResourceManagerComponent.py +50 -0
- psychopy/tests/test_experiment/test_components/test_RoutineSettingsComponent.py +16 -0
- psychopy/tests/test_experiment/test_components/test_SettingsComponent.py +80 -0
- psychopy/tests/test_experiment/test_components/test_StaticComponent.py +51 -0
- psychopy/tests/test_experiment/test_components/test_UnknownPluginComponent.py +27 -0
- psychopy/tests/test_experiment/test_components/test_all_components.py +104 -0
- psychopy/tests/test_experiment/test_components/test_base_components.py +477 -0
- psychopy/tests/test_experiment/test_experiment.py +199 -0
- psychopy/tests/test_experiment/test_loops.py +103 -0
- psychopy/tests/test_experiment/test_params.py +363 -0
- psychopy/tests/test_experiment/test_py2js.py +230 -0
- psychopy/tests/test_experiment/test_routines/__init__.py +1 -0
- psychopy/tests/test_experiment/test_routines/test_EyetrackerCalibrationRoutine.py +9 -0
- psychopy/tests/test_experiment/test_routines/test_PhotodiodeValidationRoutine.py +9 -0
- psychopy/tests/test_experiment/test_routines/test_all_routines.py +23 -0
- psychopy/tests/test_experiment/test_routines/test_base_routine.py +154 -0
- psychopy/tests/test_experiment/test_routines/test_standalone_routines.py +36 -0
- psychopy/tests/test_gui/test_DlgFromDictQt.py +82 -0
- psychopy/tests/test_gui/test_DlgFromDictWx.py +82 -0
- psychopy/tests/test_hardware/__init__.py +0 -0
- psychopy/tests/test_hardware/test_device_manager.py +36 -0
- psychopy/tests/test_hardware/test_emulator.py +106 -0
- psychopy/tests/test_hardware/test_gammasci.py +35 -0
- psychopy/tests/test_hardware/test_keyboard.py +241 -0
- psychopy/tests/test_hardware/test_keyboard_events.py +362 -0
- psychopy/tests/test_hardware/test_photodiode.py +66 -0
- psychopy/tests/test_hardware/test_ports.py +129 -0
- psychopy/tests/test_iohub/__init__.py +1 -0
- psychopy/tests/test_iohub/test_computer.py +124 -0
- psychopy/tests/test_iohub/test_event_get_and_clear.py +94 -0
- psychopy/tests/test_iohub/test_keyboard.py +91 -0
- psychopy/tests/test_iohub/test_launch.py +19 -0
- psychopy/tests/test_iohub/testutil.py +54 -0
- psychopy/tests/test_liaison/test_Liaison.py +275 -0
- psychopy/tests/test_misc/__init__.py +0 -0
- psychopy/tests/test_misc/memory_usage.py +164 -0
- psychopy/tests/test_misc/test_GammaFun.py +15 -0
- psychopy/tests/test_misc/test_clock.py +63 -0
- psychopy/tests/test_misc/test_color.py +205 -0
- psychopy/tests/test_misc/test_core.py +451 -0
- psychopy/tests/test_misc/test_event.py +308 -0
- psychopy/tests/test_misc/test_info.py +18 -0
- psychopy/tests/test_misc/test_layout.py +49 -0
- psychopy/tests/test_misc/test_locale.py +38 -0
- psychopy/tests/test_misc/test_web.py +22 -0
- psychopy/tests/test_monitors/test_monitors.py +91 -0
- psychopy/tests/test_plugins/__init__.py +0 -0
- psychopy/tests/test_plugins/test_plugin_stubs.py +125 -0
- psychopy/tests/test_preferences/__init__.py +0 -0
- psychopy/tests/test_preferences/test_prefs.py +28 -0
- psychopy/tests/test_session/test_Session.py +257 -0
- psychopy/tests/test_sound/__init__.py +0 -0
- psychopy/tests/test_sound/test_audioclip.py +331 -0
- psychopy/tests/test_sound/test_hamming.py +45 -0
- psychopy/tests/test_sound/test_sound.py +138 -0
- psychopy/tests/test_sound/test_sound_pygame.py +67 -0
- psychopy/tests/test_tools/test_animationtools.py +51 -0
- psychopy/tests/test_tools/test_arraytools.py +242 -0
- psychopy/tests/test_tools/test_attributetools.py +257 -0
- psychopy/tests/test_tools/test_colorspacetools.py +150 -0
- psychopy/tests/test_tools/test_environmenttools.py +52 -0
- psychopy/tests/test_tools/test_fileerrortools.py +97 -0
- psychopy/tests/test_tools/test_filetools.py +104 -0
- psychopy/tests/test_tools/test_imagetools.py +57 -0
- psychopy/tests/test_tools/test_mathtools.py +688 -0
- psychopy/tests/test_tools/test_stringtools.py +143 -0
- psychopy/tests/test_tools/test_versionchooser.py +209 -0
- psychopy/tests/test_tools/test_viewtools.py +168 -0
- psychopy/tests/test_validators/__init__.py +0 -0
- psychopy/tests/test_validators/test_voicekeyValidator.py +95 -0
- psychopy/tests/test_visual/__init__.py +0 -0
- psychopy/tests/test_visual/measure_parity.py +243 -0
- psychopy/tests/test_visual/test_all_stimuli.py +655 -0
- psychopy/tests/test_visual/test_basevisual.py +564 -0
- psychopy/tests/test_visual/test_brush.py +68 -0
- psychopy/tests/test_visual/test_button.py +15 -0
- psychopy/tests/test_visual/test_circle.py +74 -0
- psychopy/tests/test_visual/test_contains_overlaps.py +242 -0
- psychopy/tests/test_visual/test_custommouse.py +47 -0
- psychopy/tests/test_visual/test_dots.py +155 -0
- psychopy/tests/test_visual/test_form.py +414 -0
- psychopy/tests/test_visual/test_framepacking.py +41 -0
- psychopy/tests/test_visual/test_gamma.py +152 -0
- psychopy/tests/test_visual/test_glfw_backend.py +14 -0
- psychopy/tests/test_visual/test_image.py +219 -0
- psychopy/tests/test_visual/test_panorama.py +41 -0
- psychopy/tests/test_visual/test_progress.py +96 -0
- psychopy/tests/test_visual/test_projections.py +215 -0
- psychopy/tests/test_visual/test_projections_interactive.py +163 -0
- psychopy/tests/test_visual/test_roi.py +105 -0
- psychopy/tests/test_visual/test_shape.py +23 -0
- psychopy/tests/test_visual/test_slider.py +328 -0
- psychopy/tests/test_visual/test_target.py +35 -0
- psychopy/tests/test_visual/test_textbox.py +508 -0
- psychopy/tests/test_visual/test_winFlipTiming.py +95 -0
- psychopy/tests/test_visual/test_winScalePos.py +78 -0
- psychopy/tests/test_visual/test_window.py +124 -0
- psychopy/tests/utils.py +372 -0
- psychopy/tools/LineBreak.txt +3597 -0
- psychopy/tools/__init__.py +9 -0
- psychopy/tools/animationtools.py +49 -0
- psychopy/tools/apptools.py +32 -0
- psychopy/tools/arraytools.py +561 -0
- psychopy/tools/attributetools.py +263 -0
- psychopy/tools/audiotools.py +361 -0
- psychopy/tools/colorspacetools.py +717 -0
- psychopy/tools/coordinatetools.py +104 -0
- psychopy/tools/environmenttools.py +62 -0
- psychopy/tools/fileerrortools.py +66 -0
- psychopy/tools/filetools.py +406 -0
- psychopy/tools/fontmanager.py +1065 -0
- psychopy/tools/gltools.py +7367 -0
- psychopy/tools/imagetools.py +65 -0
- psychopy/tools/linebreak.py +322 -0
- psychopy/tools/mathtools.py +4910 -0
- psychopy/tools/monitorunittools.py +276 -0
- psychopy/tools/movietools.py +1111 -0
- psychopy/tools/pkgtools.py +654 -0
- psychopy/tools/plottools.py +25 -0
- psychopy/tools/rifttools.py +76 -0
- psychopy/tools/stereotools.py +9 -0
- psychopy/tools/stimulustools.py +198 -0
- psychopy/tools/stringtools.py +466 -0
- psychopy/tools/systemtools.py +1331 -0
- psychopy/tools/typetools.py +52 -0
- psychopy/tools/unittools.py +16 -0
- psychopy/tools/versionchooser.py +604 -0
- psychopy/tools/viewtools.py +1068 -0
- psychopy/tools/wizard.py +804 -0
- psychopy/validation/__init__.py +6 -0
- psychopy/validation/audio.py +78 -0
- psychopy/validation/visual.py +119 -0
- psychopy/visual/__init__.py +121 -0
- psychopy/visual/aperture.py +333 -0
- psychopy/visual/backends/__init__.py +77 -0
- psychopy/visual/backends/_base.py +481 -0
- psychopy/visual/backends/gamma.py +349 -0
- psychopy/visual/backends/glfwbackend.py +24 -0
- psychopy/visual/backends/pygamebackend.py +343 -0
- psychopy/visual/backends/pygletbackend.py +970 -0
- psychopy/visual/basevisual.py +2027 -0
- psychopy/visual/brush.py +204 -0
- psychopy/visual/bufferimage.py +311 -0
- psychopy/visual/button.py +194 -0
- psychopy/visual/circle.py +165 -0
- psychopy/visual/custommouse.py +263 -0
- psychopy/visual/dot.py +734 -0
- psychopy/visual/dropdown.py +165 -0
- psychopy/visual/elementarray.py +802 -0
- psychopy/visual/filters.py +419 -0
- psychopy/visual/form.py +1195 -0
- psychopy/visual/globalVars.py +24 -0
- psychopy/visual/grating.py +581 -0
- psychopy/visual/helpers.py +336 -0
- psychopy/visual/image.py +438 -0
- psychopy/visual/line.py +227 -0
- psychopy/visual/movie.py +12 -0
- psychopy/visual/movie2.py +21 -0
- psychopy/visual/movie3.py +18 -0
- psychopy/visual/movies/__init__.py +2334 -0
- psychopy/visual/movies/frame.py +258 -0
- psychopy/visual/movies/metadata.py +242 -0
- psychopy/visual/movies/players/_base.py +364 -0
- psychopy/visual/nnlvs.py +830 -0
- psychopy/visual/noise.py +32 -0
- psychopy/visual/panorama.py +313 -0
- psychopy/visual/patch.py +21 -0
- psychopy/visual/pie.py +237 -0
- psychopy/visual/polygon.py +226 -0
- psychopy/visual/progress.py +313 -0
- psychopy/visual/radial.py +29 -0
- psychopy/visual/ratingscale.py +18 -0
- psychopy/visual/rect.py +195 -0
- psychopy/visual/rift.py +2660 -0
- psychopy/visual/roi.py +141 -0
- psychopy/visual/secondorder.py +27 -0
- psychopy/visual/shaders.py +787 -0
- psychopy/visual/shape.py +897 -0
- psychopy/visual/simpleimage.py +303 -0
- psychopy/visual/slider.py +1222 -0
- psychopy/visual/stim3d.py +2109 -0
- psychopy/visual/target.py +278 -0
- psychopy/visual/text.py +769 -0
- psychopy/visual/textbox/__init__.py +1280 -0
- psychopy/visual/textbox/fontmanager.py +574 -0
- psychopy/visual/textbox/parsedtext.py +317 -0
- psychopy/visual/textbox/textgrid.py +278 -0
- psychopy/visual/textbox/textureatlas.py +248 -0
- psychopy/visual/textbox2/__init__.py +4 -0
- psychopy/visual/textbox2/textbox2.py +1970 -0
- psychopy/visual/vlcmoviestim.py +1294 -0
- psychopy/visual/window.py +3910 -0
- psychopy/visual/windowframepack.py +86 -0
- psychopy/visual/windowwarp.py +457 -0
- psychopy/voicekey/__init__.py +56 -0
- psychopy/voicekey/labjack_vks.py +9 -0
- psychopy/voicekey/parallel_vks.py +9 -0
- psychopy/voicekey/vk_tools.py +131 -0
- psychopy/web.py +289 -0
- psychopy-2025.2.4.dist-info/METADATA +160 -0
- psychopy-2025.2.4.dist-info/RECORD +3127 -0
- psychopy-2025.2.4.dist-info/WHEEL +4 -0
- psychopy-2025.2.4.dist-info/entry_points.txt +5 -0
- psychopy-2025.2.4.dist-info/licenses/LICENSE +674 -0
|
@@ -0,0 +1,3910 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""A class representing a window for displaying one or more stimuli"""
|
|
5
|
+
|
|
6
|
+
# Part of the PsychoPy library
|
|
7
|
+
# Copyright (C) 2002-2018 Jonathan Peirce (C) 2019-2025 Open Science Tools Ltd.
|
|
8
|
+
# Distributed under the terms of the GNU General Public License (GPL).
|
|
9
|
+
|
|
10
|
+
import ctypes
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
import weakref
|
|
14
|
+
import atexit
|
|
15
|
+
from itertools import product
|
|
16
|
+
from collections import deque
|
|
17
|
+
|
|
18
|
+
from psychopy.contrib.lazy_import import lazy_import
|
|
19
|
+
from psychopy import colors, event
|
|
20
|
+
from psychopy.localization import _translate
|
|
21
|
+
from psychopy.tools.systemtools import getCurrentPID, registerPID
|
|
22
|
+
import math
|
|
23
|
+
# from psychopy.clock import monotonicClock
|
|
24
|
+
|
|
25
|
+
# try to find avbin (we'll overload pyglet's load_library tool and then
|
|
26
|
+
# add some paths
|
|
27
|
+
from ..colors import Color, colorSpaces
|
|
28
|
+
from .textbox2 import TextBox2
|
|
29
|
+
|
|
30
|
+
import pyglet
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
haveAvbin = False
|
|
34
|
+
|
|
35
|
+
# on windows try to load avbin now (other libs can interfere)
|
|
36
|
+
if sys.platform == 'win32':
|
|
37
|
+
# make sure we also check in SysWOW64 if on 64-bit windows
|
|
38
|
+
if 'C:\\Windows\\SysWOW64' not in os.environ['PATH']:
|
|
39
|
+
os.environ['PATH'] += ';C:\\Windows\\SysWOW64'
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
from pyglet.media import avbin
|
|
43
|
+
haveAvbin = True
|
|
44
|
+
except ImportError:
|
|
45
|
+
haveAvbin = False
|
|
46
|
+
# either avbin isn't installed or scipy.stats has been imported
|
|
47
|
+
# (prevents avbin loading)
|
|
48
|
+
except AttributeError:
|
|
49
|
+
# avbin is not found, causing exception in pyglet 1.2??
|
|
50
|
+
# (running psychopy 1.81 standalone on windows 7):
|
|
51
|
+
#
|
|
52
|
+
# File "C:\Program Files (x86)\PsychoPy2\lib\site-packages\
|
|
53
|
+
# pyglet\media\avbin.py", line 158, in <module>
|
|
54
|
+
# av.avbin_get_version.restype = ctypes.c_int
|
|
55
|
+
# AttributeError: 'NoneType' object has no attribute
|
|
56
|
+
# 'avbin_get_version'
|
|
57
|
+
haveAvbin = False
|
|
58
|
+
except Exception:
|
|
59
|
+
# WindowsError on some systems
|
|
60
|
+
# AttributeError if using avbin5 from pyglet 1.2?
|
|
61
|
+
haveAvbin = False
|
|
62
|
+
|
|
63
|
+
# for pyglet 1.3
|
|
64
|
+
if not haveAvbin:
|
|
65
|
+
try:
|
|
66
|
+
from pyglet.media.sources import avbin
|
|
67
|
+
haveAvbin = True
|
|
68
|
+
except ImportError:
|
|
69
|
+
haveAvbin = False
|
|
70
|
+
except AttributeError:
|
|
71
|
+
haveAvbin = False
|
|
72
|
+
except Exception:
|
|
73
|
+
haveAvbin = False
|
|
74
|
+
|
|
75
|
+
import psychopy # so we can get the __path__
|
|
76
|
+
from psychopy import core, platform_specific, logging, prefs, monitors
|
|
77
|
+
import psychopy.event
|
|
78
|
+
from . import backends, image
|
|
79
|
+
|
|
80
|
+
# tools must only be imported *after* event or MovieStim breaks on win32
|
|
81
|
+
# (JWP has no idea why!)
|
|
82
|
+
from psychopy.tools.attributetools import attributeSetter, setAttribute
|
|
83
|
+
from psychopy.tools.arraytools import val2array
|
|
84
|
+
from psychopy.tools.monitorunittools import convertToPix
|
|
85
|
+
import psychopy.tools.viewtools as viewtools
|
|
86
|
+
import psychopy.tools.gltools as gltools
|
|
87
|
+
import psychopy.tools.mathtools as mathtools
|
|
88
|
+
from .text import TextStim
|
|
89
|
+
from .grating import GratingStim
|
|
90
|
+
from .helpers import setColor
|
|
91
|
+
from . import globalVars
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
from PIL import Image
|
|
95
|
+
except ImportError:
|
|
96
|
+
import Image
|
|
97
|
+
|
|
98
|
+
import numpy
|
|
99
|
+
|
|
100
|
+
from psychopy.core import rush
|
|
101
|
+
|
|
102
|
+
reportNDroppedFrames = 5 # stop raising warning after this
|
|
103
|
+
|
|
104
|
+
# import pyglet.gl, pyglet.window, pyglet.image, pyglet.font, pyglet.event
|
|
105
|
+
from . import shaders as _shaders
|
|
106
|
+
try:
|
|
107
|
+
from pyglet import media
|
|
108
|
+
havePygletMedia = True
|
|
109
|
+
except Exception:
|
|
110
|
+
havePygletMedia = False
|
|
111
|
+
|
|
112
|
+
# lazy_import puts pygame into the namespace but delays import until needed
|
|
113
|
+
lazy_import(globals(), "import pygame")
|
|
114
|
+
|
|
115
|
+
DEBUG = False
|
|
116
|
+
IOHUB_ACTIVE = False
|
|
117
|
+
retinaContext = None # only needed for retina-ready displays
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class OpenWinList(list):
|
|
121
|
+
"""Class to keep keep track of windows that have been opened.
|
|
122
|
+
|
|
123
|
+
Uses a list of weak references so that we don't stop the window
|
|
124
|
+
being deleted.
|
|
125
|
+
|
|
126
|
+
"""
|
|
127
|
+
def append(self, item):
|
|
128
|
+
list.append(self, weakref.ref(item))
|
|
129
|
+
|
|
130
|
+
def remove(self, item):
|
|
131
|
+
for ref in self:
|
|
132
|
+
obj = ref()
|
|
133
|
+
if obj is None or item == obj:
|
|
134
|
+
list.remove(self, ref)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
openWindows = core.openWindows = OpenWinList() # core needs this for wait()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class Window():
|
|
141
|
+
"""Used to set up a context in which to draw objects,
|
|
142
|
+
using either `pyglet <http://www.pyglet.org>`_,
|
|
143
|
+
`pygame <http://www.pygame.org>`_, or `glfw <https://www.glfw.org>`_.
|
|
144
|
+
|
|
145
|
+
The pyglet backend allows multiple windows to be created, allows the user
|
|
146
|
+
to specify which screen to use (if more than one is available, duh!) and
|
|
147
|
+
allows movies to be rendered.
|
|
148
|
+
|
|
149
|
+
The GLFW backend is a new addition which provides most of the same features
|
|
150
|
+
as pyglet, but provides greater flexibility for complex display
|
|
151
|
+
configurations.
|
|
152
|
+
|
|
153
|
+
Pygame may still work for you but it's officially deprecated in this
|
|
154
|
+
project (we won't be fixing pygame-specific bugs).
|
|
155
|
+
|
|
156
|
+
"""
|
|
157
|
+
USE_LEGACY_GL = pyglet.version < '2.0'
|
|
158
|
+
def __init__(self,
|
|
159
|
+
size=(800, 600),
|
|
160
|
+
pos=None,
|
|
161
|
+
color=(0, 0, 0),
|
|
162
|
+
colorSpace='rgb',
|
|
163
|
+
backgroundImage=None,
|
|
164
|
+
backgroundFit="cover",
|
|
165
|
+
rgb=None,
|
|
166
|
+
dkl=None,
|
|
167
|
+
lms=None,
|
|
168
|
+
fullscr=None,
|
|
169
|
+
allowGUI=None,
|
|
170
|
+
monitor=None,
|
|
171
|
+
bitsMode=None,
|
|
172
|
+
winType=None,
|
|
173
|
+
units=None,
|
|
174
|
+
gamma=None,
|
|
175
|
+
blendMode='avg',
|
|
176
|
+
screen=0,
|
|
177
|
+
viewScale=None,
|
|
178
|
+
viewPos=None,
|
|
179
|
+
viewOri=0.0,
|
|
180
|
+
waitBlanking=True,
|
|
181
|
+
allowStencil=False,
|
|
182
|
+
multiSample=False,
|
|
183
|
+
numSamples=2,
|
|
184
|
+
stereo=False,
|
|
185
|
+
name='window1',
|
|
186
|
+
title="PsychoPy",
|
|
187
|
+
checkTiming=True,
|
|
188
|
+
useFBO=False,
|
|
189
|
+
useRetina=True,
|
|
190
|
+
autoLog=True,
|
|
191
|
+
gammaErrorPolicy='raise',
|
|
192
|
+
bpc=(8, 8, 8),
|
|
193
|
+
depthBits=8,
|
|
194
|
+
stencilBits=8,
|
|
195
|
+
backendConf=None,
|
|
196
|
+
infoMsg=None):
|
|
197
|
+
"""
|
|
198
|
+
These attributes can only be set at initialization. See further down
|
|
199
|
+
for a list of attributes which can be changed after initialization
|
|
200
|
+
of the Window, e.g. color, colorSpace, gamma etc.
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
size : array-like of int
|
|
205
|
+
Size of the window in pixels [x, y].
|
|
206
|
+
pos : array-like of int
|
|
207
|
+
Location of the top-left corner of the window on the screen [x, y].
|
|
208
|
+
color : array-like of float
|
|
209
|
+
Color of background as [r, g, b] list or single value. Each gun can
|
|
210
|
+
take values between -1.0 and 1.0.
|
|
211
|
+
fullscr : bool or None
|
|
212
|
+
Create a window in 'full-screen' mode. Better timing can be achieved
|
|
213
|
+
in full-screen mode.
|
|
214
|
+
allowGUI : bool or None
|
|
215
|
+
If set to False, window will be drawn with no frame and no buttons
|
|
216
|
+
to close etc., use `None` for value from preferences.
|
|
217
|
+
winType : str or None
|
|
218
|
+
Set the window type or back-end to use. If `None` then PsychoPy will
|
|
219
|
+
revert to user/site preferences.
|
|
220
|
+
monitor : :class:`~psychopy.monitors.Monitor` or None
|
|
221
|
+
The monitor to be used during the experiment. If `None` a default
|
|
222
|
+
monitor profile will be used.
|
|
223
|
+
units : str or None
|
|
224
|
+
Defines the default units of stimuli drawn in the window (can be
|
|
225
|
+
overridden by each stimulus). Values can be *None*, 'height' (of the
|
|
226
|
+
window), 'norm' (normalised), 'deg', 'cm', 'pix'. See :ref:`units`
|
|
227
|
+
for explanation of options.
|
|
228
|
+
screen : int
|
|
229
|
+
Specifies the physical screen that stimuli will appear on ('pyglet'
|
|
230
|
+
and 'glfw' `winType` only). Values can be >0 if more than one screen
|
|
231
|
+
is present.
|
|
232
|
+
viewScale : array-like of float or None
|
|
233
|
+
Scaling factors [x, y] to apply custom scaling to the current units
|
|
234
|
+
of the :class:`~psychopy.visual.Window` instance.
|
|
235
|
+
viewPos : array-like of float or None
|
|
236
|
+
If not `None`, redefines the origin within the window, in the units
|
|
237
|
+
of the window. Values outside the borders will be clamped to lie on
|
|
238
|
+
the border.
|
|
239
|
+
viewOri : float
|
|
240
|
+
A single value determining the orientation of the view in degrees.
|
|
241
|
+
waitBlanking : bool or None
|
|
242
|
+
After a call to :py:attr:`~Window.flip()` should we wait for the
|
|
243
|
+
blank before the script continues.
|
|
244
|
+
bitsMode : bool
|
|
245
|
+
DEPRECATED in 1.80.02. Use BitsSharp class from pycrsltd
|
|
246
|
+
instead.
|
|
247
|
+
checkTiming : bool
|
|
248
|
+
Whether to calculate frame duration on initialization. Estimated
|
|
249
|
+
duration is saved in :py:attr:`~Window.monitorFramePeriod`. The
|
|
250
|
+
message displayed on the screen can be set with the `infoMsg`
|
|
251
|
+
argument.
|
|
252
|
+
allowStencil : bool
|
|
253
|
+
When set to `True`, this allows operations that use the OpenGL
|
|
254
|
+
stencil buffer (notably, allowing the
|
|
255
|
+
:class:`~psychopy.visual.Aperture` to be used).
|
|
256
|
+
multiSample : bool
|
|
257
|
+
If `True` and your graphics driver supports multisample buffers,
|
|
258
|
+
multiple color samples will be taken per-pixel, providing an
|
|
259
|
+
anti-aliased image through spatial filtering. This setting cannot
|
|
260
|
+
be changed after opening a window. Only works with 'pyglet' and
|
|
261
|
+
'glfw' `winTypes`, and `useFBO` is `False`.
|
|
262
|
+
numSamples : int
|
|
263
|
+
A single value specifying the number of samples per pixel if
|
|
264
|
+
multisample is enabled. The higher the number, the better the
|
|
265
|
+
image quality, but can delay frame flipping. The largest number of
|
|
266
|
+
samples is determined by ``GL_MAX_SAMPLES``, usually 16 or 32 on
|
|
267
|
+
newer hardware, will crash if number is invalid.
|
|
268
|
+
stereo : bool
|
|
269
|
+
If `True` and your graphics card supports quad buffers then
|
|
270
|
+
this will be enabled. You can switch between left and right-eye
|
|
271
|
+
scenes for drawing operations using
|
|
272
|
+
:py:attr:`~psychopy.visual.Window.setBuffer()`.
|
|
273
|
+
title : str
|
|
274
|
+
Name of the Window according to your Operating System. This is
|
|
275
|
+
the text which appears on the title sash.
|
|
276
|
+
useRetina : bool
|
|
277
|
+
In PsychoPy >1.85.3 this should always be `True` as pyglet
|
|
278
|
+
(or Apple) no longer allows us to create a non-retina display.
|
|
279
|
+
NB when you use Retina display the initial win size
|
|
280
|
+
request will be in the larger pixels but subsequent use of
|
|
281
|
+
``units='pix'`` should refer to the tiny Retina pixels. Window.size
|
|
282
|
+
will give the actual size of the screen in Retina pixels.
|
|
283
|
+
gammaErrorPolicy: str
|
|
284
|
+
If `raise`, an error is raised if the gamma table is unable to be
|
|
285
|
+
retrieved or set. If `warn`, a warning is raised instead. If
|
|
286
|
+
`ignore`, neither an error nor a warning are raised.
|
|
287
|
+
bpc : array_like or int
|
|
288
|
+
Bits per color (BPC) for the back buffer as a tuple to specify
|
|
289
|
+
bit depths for each color channel separately (red, green, blue), or
|
|
290
|
+
a single value to set all of them to the same value. Valid values
|
|
291
|
+
depend on the output color depth of the display (screen) the window
|
|
292
|
+
is set to use and the system graphics configuration. By default, it
|
|
293
|
+
is assumed the display has 8-bits per color (8, 8, 8). Behaviour may
|
|
294
|
+
be undefined for non-fullscreen windows, or if multiple screens are
|
|
295
|
+
attached with varying color output depths.
|
|
296
|
+
depthBits : int
|
|
297
|
+
Back buffer depth bits. Default is 8, but can be set higher (eg. 24)
|
|
298
|
+
if drawing 3D stimuli to minimize artifacts such a 'Z-fighting'.
|
|
299
|
+
stencilBits : int
|
|
300
|
+
Back buffer stencil bits. Default is 8.
|
|
301
|
+
backendConf : dict or None
|
|
302
|
+
Additional options to pass to the backend specified by `winType`.
|
|
303
|
+
Each backend may provide unique functionality which may not be
|
|
304
|
+
available across all of them. This allows you to pass special
|
|
305
|
+
configuration options to a specific backend to configure the
|
|
306
|
+
feature.
|
|
307
|
+
infoMsg : str or None
|
|
308
|
+
Message to display during frame rate measurement (i.e., when
|
|
309
|
+
``checkTiming=True``). Default is None, which means that a default
|
|
310
|
+
message is displayed. If you want to hide the message, pass an
|
|
311
|
+
empty string.
|
|
312
|
+
|
|
313
|
+
Notes
|
|
314
|
+
-----
|
|
315
|
+
* Some parameters (e.g. units) can now be given default values in the
|
|
316
|
+
user/site preferences and these will be used if `None` is given here.
|
|
317
|
+
If you do specify a value here it will take precedence over
|
|
318
|
+
preferences.
|
|
319
|
+
|
|
320
|
+
Attributes
|
|
321
|
+
----------
|
|
322
|
+
size : array-like (float)
|
|
323
|
+
Dimensions of the window's drawing area/buffer in pixels [w, h].
|
|
324
|
+
monitorFramePeriod : float
|
|
325
|
+
Refresh rate of the display if ``checkTiming=True`` on window
|
|
326
|
+
instantiation.
|
|
327
|
+
|
|
328
|
+
"""
|
|
329
|
+
# what local vars are defined (these are the init params) for use by
|
|
330
|
+
# __repr__
|
|
331
|
+
self._initParams = dir()
|
|
332
|
+
self._closed = False
|
|
333
|
+
self.backend = None # this will be set later
|
|
334
|
+
for unecess in ['self', 'checkTiming', 'rgb', 'dkl', ]:
|
|
335
|
+
self._initParams.remove(unecess)
|
|
336
|
+
|
|
337
|
+
# Check autoLog value
|
|
338
|
+
if autoLog not in (True, False):
|
|
339
|
+
raise ValueError(
|
|
340
|
+
'autoLog must be either True or False for visual.Window')
|
|
341
|
+
|
|
342
|
+
self.autoLog = False # to suppress log msg during init
|
|
343
|
+
self.name = name
|
|
344
|
+
self.clientSize = numpy.array(size, int) # size of window, not buffer
|
|
345
|
+
# size of the window when restored (not fullscreen)
|
|
346
|
+
self._windowedSize = self.clientSize.copy()
|
|
347
|
+
|
|
348
|
+
self.pos = pos
|
|
349
|
+
# this will get overridden once the window is created
|
|
350
|
+
self.winHandle = None
|
|
351
|
+
self.useFBO = useFBO
|
|
352
|
+
self.useRetina = useRetina and sys.platform == 'darwin'
|
|
353
|
+
|
|
354
|
+
if gammaErrorPolicy not in ['raise', 'warn', 'ignore']:
|
|
355
|
+
raise ValueError('Unexpected `gammaErrorPolicy`')
|
|
356
|
+
self.gammaErrorPolicy = gammaErrorPolicy
|
|
357
|
+
|
|
358
|
+
self._toLog = []
|
|
359
|
+
self._toCall = []
|
|
360
|
+
# settings for the monitor: local settings (if available) override
|
|
361
|
+
# monitor
|
|
362
|
+
# if we have a monitors.Monitor object (psychopy 0.54 onwards)
|
|
363
|
+
# convert to a Monitor object
|
|
364
|
+
if not monitor:
|
|
365
|
+
self.monitor = monitors.Monitor('__blank__', autoLog=autoLog)
|
|
366
|
+
elif isinstance(monitor, str):
|
|
367
|
+
self.monitor = monitors.Monitor(monitor, autoLog=autoLog)
|
|
368
|
+
elif hasattr(monitor, 'keys'):
|
|
369
|
+
# convert into a monitor object
|
|
370
|
+
self.monitor = monitors.Monitor('temp', currentCalib=monitor,
|
|
371
|
+
verbose=False, autoLog=autoLog)
|
|
372
|
+
else:
|
|
373
|
+
self.monitor = monitor
|
|
374
|
+
|
|
375
|
+
# otherwise monitor will just be a dict
|
|
376
|
+
self.scrWidthCM = self.monitor.getWidth()
|
|
377
|
+
self.scrDistCM = self.monitor.getDistance()
|
|
378
|
+
|
|
379
|
+
scrSize = self.monitor.getSizePix()
|
|
380
|
+
if scrSize is None:
|
|
381
|
+
self.scrWidthPIX = None
|
|
382
|
+
else:
|
|
383
|
+
self.scrWidthPIX = scrSize[0]
|
|
384
|
+
|
|
385
|
+
# if fullscreen not specified, get from prefs
|
|
386
|
+
if fullscr is None:
|
|
387
|
+
fullscr = prefs.general['fullscr']
|
|
388
|
+
self._isFullScr = fullscr
|
|
389
|
+
|
|
390
|
+
self.units = units
|
|
391
|
+
|
|
392
|
+
if allowGUI is None:
|
|
393
|
+
allowGUI = prefs.general['allowGUI']
|
|
394
|
+
self.allowGUI = allowGUI
|
|
395
|
+
|
|
396
|
+
self.screen = screen
|
|
397
|
+
self.stereo = stereo # use quad buffer if requested (and if possible)
|
|
398
|
+
|
|
399
|
+
# enable multisampling
|
|
400
|
+
self.multiSample = multiSample
|
|
401
|
+
self.numSamples = numSamples
|
|
402
|
+
|
|
403
|
+
# load color conversion matrices
|
|
404
|
+
self.dkl_rgb = self.monitor.getDKL_RGB()
|
|
405
|
+
self.lms_rgb = self.monitor.getLMS_RGB()
|
|
406
|
+
|
|
407
|
+
# set screen color
|
|
408
|
+
self.__dict__['colorSpace'] = colorSpace
|
|
409
|
+
if rgb is not None:
|
|
410
|
+
logging.warning("Use of rgb arguments to stimuli are deprecated. "
|
|
411
|
+
"Please use color and colorSpace args instead")
|
|
412
|
+
color = rgb
|
|
413
|
+
colorSpace = 'rgb'
|
|
414
|
+
elif dkl is not None:
|
|
415
|
+
logging.warning("Use of dkl arguments to stimuli are deprecated. "
|
|
416
|
+
"Please use color and colorSpace args instead")
|
|
417
|
+
color = dkl
|
|
418
|
+
colorSpace = 'dkl'
|
|
419
|
+
elif lms is not None:
|
|
420
|
+
logging.warning("Use of lms arguments to stimuli are deprecated. "
|
|
421
|
+
"Please use color and colorSpace args instead")
|
|
422
|
+
color = lms
|
|
423
|
+
colorSpace = 'lms'
|
|
424
|
+
self.setColor(color, colorSpace=colorSpace, log=False)
|
|
425
|
+
|
|
426
|
+
self.allowStencil = allowStencil
|
|
427
|
+
# check whether FBOs are supported
|
|
428
|
+
if blendMode == 'add' and not self.useFBO:
|
|
429
|
+
logging.warning('User requested a blendmode of "add" but '
|
|
430
|
+
'window requires useFBO=True')
|
|
431
|
+
# resort to the simpler blending without float rendering
|
|
432
|
+
self.__dict__['blendMode'] = 'avg'
|
|
433
|
+
else:
|
|
434
|
+
self.__dict__['blendMode'] = blendMode
|
|
435
|
+
# then set up gl context and then call self.setBlendMode
|
|
436
|
+
|
|
437
|
+
# setup context and openGL()
|
|
438
|
+
if winType is None: # choose the default windowing
|
|
439
|
+
winType = "pyglet"
|
|
440
|
+
self.winType = winType
|
|
441
|
+
|
|
442
|
+
# setup the context
|
|
443
|
+
|
|
444
|
+
# backend specific options are passed as a dictionary
|
|
445
|
+
backendConf = backendConf if backendConf is not None else {}
|
|
446
|
+
|
|
447
|
+
# Here we make sure all the open windows use the same `winType` and have
|
|
448
|
+
# context sharing enabled. The context to share is passed as an option
|
|
449
|
+
# to `backendConf`.
|
|
450
|
+
if openWindows:
|
|
451
|
+
primaryWindow = openWindows[0]() # resolve ref
|
|
452
|
+
if primaryWindow.winType != self.winType:
|
|
453
|
+
raise ValueError(
|
|
454
|
+
"Only one kind of `winType` can be used per session.")
|
|
455
|
+
|
|
456
|
+
# Allow for context sharing, only used by the GLFW backend, Pyglet
|
|
457
|
+
# uses `shadow_window` by default here so we don't need to worry
|
|
458
|
+
# about it.
|
|
459
|
+
backendConf['share'] = self
|
|
460
|
+
|
|
461
|
+
if not isinstance(backendConf, dict): # type check on options
|
|
462
|
+
raise TypeError(
|
|
463
|
+
'Object passed to `backendConf` must be type `dict`.')
|
|
464
|
+
|
|
465
|
+
# augment settings with dedicated attributes
|
|
466
|
+
backendConf['bpc'] = bpc
|
|
467
|
+
backendConf['depthBits'] = depthBits
|
|
468
|
+
backendConf['stencilBits'] = stencilBits
|
|
469
|
+
|
|
470
|
+
# get the backend, pass the options to it
|
|
471
|
+
self.backend = backends.getBackend(win=self, backendConf=backendConf)
|
|
472
|
+
|
|
473
|
+
self.winHandle = self.backend.winHandle
|
|
474
|
+
global GL
|
|
475
|
+
GL = self.backend.GL
|
|
476
|
+
|
|
477
|
+
# check whether shaders are supported
|
|
478
|
+
# also will need to check for ARB_float extension,
|
|
479
|
+
# but that should be done after context is created
|
|
480
|
+
self._haveShaders = self.backend.shadersSupported
|
|
481
|
+
|
|
482
|
+
self._setupGL()
|
|
483
|
+
|
|
484
|
+
self.blendMode = self.blendMode
|
|
485
|
+
|
|
486
|
+
# now that we have a window handle, set title
|
|
487
|
+
self.title = title
|
|
488
|
+
|
|
489
|
+
# parameters for transforming the overall view
|
|
490
|
+
self.viewScale = val2array(viewScale)
|
|
491
|
+
if viewPos is not None and self.units is None:
|
|
492
|
+
raise ValueError('You must define the window units to use viewPos')
|
|
493
|
+
self.viewPos = val2array(viewPos, withScalar=False)
|
|
494
|
+
self.viewOri = float(viewOri)
|
|
495
|
+
if self.viewOri != 0. and self.viewPos is not None:
|
|
496
|
+
msg = "Window: viewPos & viewOri are currently incompatible"
|
|
497
|
+
raise NotImplementedError(msg)
|
|
498
|
+
|
|
499
|
+
# scaling factor for HiDPI displays, `None` until initialized
|
|
500
|
+
self._contentScaleFactor = None
|
|
501
|
+
|
|
502
|
+
# Code to allow iohub to know id of any psychopy windows created
|
|
503
|
+
# so kb and mouse event filtering by window id can be supported.
|
|
504
|
+
#
|
|
505
|
+
# If an iohubConnection is active, give this window os handle to
|
|
506
|
+
# to the ioHub server. If windows were already created before the
|
|
507
|
+
# iohub was active, also send them to iohub.
|
|
508
|
+
#
|
|
509
|
+
if IOHUB_ACTIVE:
|
|
510
|
+
from psychopy.iohub.client import ioHubConnection as ioconn
|
|
511
|
+
if ioconn.ACTIVE_CONNECTION:
|
|
512
|
+
from psychopy.iohub.client import windowInfoDict
|
|
513
|
+
win_infos = []
|
|
514
|
+
win_handles = []
|
|
515
|
+
for w in openWindows:
|
|
516
|
+
winfo = windowInfoDict(w())
|
|
517
|
+
win_infos.append(winfo)
|
|
518
|
+
win_handles.append(w()._hw_handle)
|
|
519
|
+
|
|
520
|
+
if self._hw_handle not in win_handles:
|
|
521
|
+
winfo = windowInfoDict(self)
|
|
522
|
+
win_infos.append(winfo)
|
|
523
|
+
win_handles.append(self._hw_handle)
|
|
524
|
+
ioconn.ACTIVE_CONNECTION.registerWindowHandles(*win_infos)
|
|
525
|
+
self.backend.onMoveCallback = ioconn.ACTIVE_CONNECTION.updateWindowPos
|
|
526
|
+
|
|
527
|
+
# near and far clipping planes
|
|
528
|
+
self._nearClip = 0.1
|
|
529
|
+
self._farClip = 100.0
|
|
530
|
+
|
|
531
|
+
# 3D rendering related attributes
|
|
532
|
+
self.frontFace = 'ccw'
|
|
533
|
+
self.depthFunc = 'less'
|
|
534
|
+
self.depthMask = False
|
|
535
|
+
self.cullFace = False
|
|
536
|
+
self.cullFaceMode = 'back'
|
|
537
|
+
self.draw3d = False
|
|
538
|
+
|
|
539
|
+
# gl viewport and scissor
|
|
540
|
+
self._viewport = self._scissor = None # set later
|
|
541
|
+
|
|
542
|
+
self._fboVerts = numpy.ascontiguousarray(
|
|
543
|
+
[[-1, -1], [-1, 1], [1, 1], [1, -1]], dtype=numpy.float32)
|
|
544
|
+
self._fboTexCoords = numpy.ascontiguousarray(
|
|
545
|
+
[[0, 0], [0, 1], [1, 1], [1, 0]], dtype=numpy.float32)
|
|
546
|
+
|
|
547
|
+
# scene light sources
|
|
548
|
+
self._lights = []
|
|
549
|
+
self._useLights = False
|
|
550
|
+
self._nLights = 0
|
|
551
|
+
self._ambientLight = numpy.array([0.0, 0.0, 0.0, 1.0],
|
|
552
|
+
dtype=numpy.float32)
|
|
553
|
+
|
|
554
|
+
# stereo rendering settings, set later by the user
|
|
555
|
+
self._eyeOffset = 0.0
|
|
556
|
+
self._convergeOffset = 0.0
|
|
557
|
+
|
|
558
|
+
# gamma
|
|
559
|
+
self.bits = None # this may change in a few lines time!
|
|
560
|
+
self.__dict__['gamma'] = gamma
|
|
561
|
+
self._setupGamma(gamma)
|
|
562
|
+
|
|
563
|
+
# setup bits++ if needed. NB The new preferred method is for this
|
|
564
|
+
# to be handled by the bits class instead. (we pass the Window to
|
|
565
|
+
# bits not passing bits to the window)
|
|
566
|
+
if bitsMode is not None:
|
|
567
|
+
logging.warn("Use of Window(bitsMode=******) is deprecated. See "
|
|
568
|
+
"the Coder>Demos>Hardware demo for new methods")
|
|
569
|
+
self.bitsMode = bitsMode # could be [None, 'fast', 'slow']
|
|
570
|
+
logging.warn("calling Window(...,bitsMode='fast') is deprecated."
|
|
571
|
+
" XXX provide further info")
|
|
572
|
+
from psychopy.hardware.crs.bits import BitsPlusPlus
|
|
573
|
+
self.bits = self.interface = BitsPlusPlus(self)
|
|
574
|
+
self.haveBits = True
|
|
575
|
+
if (hasattr(self.monitor, 'linearizeLums') or
|
|
576
|
+
hasattr(self.monitor, 'lineariseLums')):
|
|
577
|
+
# rather than a gamma value we could use bits++ and provide a
|
|
578
|
+
# complete linearised lookup table using
|
|
579
|
+
# monitor.linearizeLums(lumLevels)
|
|
580
|
+
self.__dict__['gamma'] = None
|
|
581
|
+
|
|
582
|
+
self.frameClock = core.Clock() # from psycho/core
|
|
583
|
+
self.frames = 0 # frames since last fps calc
|
|
584
|
+
self.movieFrames = [] # list of captured frames (Image objects)
|
|
585
|
+
|
|
586
|
+
self.recordFrameIntervals = False
|
|
587
|
+
# Be able to omit the long timegap that follows each time turn it off
|
|
588
|
+
self.recordFrameIntervalsJustTurnedOn = False
|
|
589
|
+
self.nDroppedFrames = 0
|
|
590
|
+
self.frameIntervals = []
|
|
591
|
+
self._frameTimes = deque(maxlen=1000) # 1000 keeps overhead low
|
|
592
|
+
|
|
593
|
+
self._toDraw = []
|
|
594
|
+
self._heldDraw = []
|
|
595
|
+
self._toDrawDepths = []
|
|
596
|
+
self._eventDispatchers = []
|
|
597
|
+
|
|
598
|
+
# dict of stimulus:validator pairs
|
|
599
|
+
self.validators = {}
|
|
600
|
+
|
|
601
|
+
self.lastFrameT = core.getTime()
|
|
602
|
+
self.waitBlanking = waitBlanking
|
|
603
|
+
|
|
604
|
+
# set the swap interval if using GLFW
|
|
605
|
+
if self.winType == 'glfw':
|
|
606
|
+
self.backend.setSwapInterval(int(waitBlanking))
|
|
607
|
+
|
|
608
|
+
self.refreshThreshold = 1.0 # initial val needed by flip()
|
|
609
|
+
|
|
610
|
+
# store editable stimuli
|
|
611
|
+
self._editableChildren = []
|
|
612
|
+
self._currentEditableRef = None
|
|
613
|
+
# store draggable stimuli
|
|
614
|
+
self.currentDraggable = None
|
|
615
|
+
|
|
616
|
+
# splash screen
|
|
617
|
+
self._splashTextbox = None # created on first use
|
|
618
|
+
self._showSplash = False
|
|
619
|
+
self.resetViewport() # set viewport to full window size
|
|
620
|
+
|
|
621
|
+
# transformation
|
|
622
|
+
self._projectionMatrix = numpy.identity(4, dtype=numpy.float32)
|
|
623
|
+
self._viewMatrix = numpy.identity(4, dtype=numpy.float32)
|
|
624
|
+
|
|
625
|
+
self._projectionMatrixNeedsUpdate = True
|
|
626
|
+
self._viewMatrixNeedsUpdate = True
|
|
627
|
+
|
|
628
|
+
self.setDefaultView() # initialize view/proj matrix
|
|
629
|
+
|
|
630
|
+
# piloting indicator
|
|
631
|
+
self._pilotingIndicator = None
|
|
632
|
+
self._showPilotingIndicator = False
|
|
633
|
+
|
|
634
|
+
# over several frames with no drawing
|
|
635
|
+
self._monitorFrameRate = None
|
|
636
|
+
# for testing when to stop drawing a stim:
|
|
637
|
+
self.monitorFramePeriod = 0.0
|
|
638
|
+
if checkTiming:
|
|
639
|
+
self._monitorFrameRate = self.getActualFrameRate(infoMsg=infoMsg)
|
|
640
|
+
|
|
641
|
+
if self._monitorFrameRate is not None:
|
|
642
|
+
self.monitorFramePeriod = 1.0 / self._monitorFrameRate
|
|
643
|
+
else:
|
|
644
|
+
self.monitorFramePeriod = 1.0 / 60 # assume a flat panel?
|
|
645
|
+
self.refreshThreshold = self.monitorFramePeriod * 1.2
|
|
646
|
+
openWindows.append(self)
|
|
647
|
+
|
|
648
|
+
self.autoLog = autoLog
|
|
649
|
+
if self.autoLog:
|
|
650
|
+
logging.exp("Created %s = %s" % (self.name, str(self)))
|
|
651
|
+
|
|
652
|
+
# Make sure this window's close method is called when exiting, even in
|
|
653
|
+
# the event of an error we should be able to restore the original gamma
|
|
654
|
+
# table. Note that a reference to this window object will live in this
|
|
655
|
+
# function, preventing it from being garbage collected.
|
|
656
|
+
def close_on_exit():
|
|
657
|
+
if self._closed is False:
|
|
658
|
+
self.close()
|
|
659
|
+
|
|
660
|
+
atexit.register(close_on_exit)
|
|
661
|
+
|
|
662
|
+
self._mouse = event.Mouse(win=self)
|
|
663
|
+
self.backgroundImage = backgroundImage
|
|
664
|
+
self.backgroundFit = backgroundFit
|
|
665
|
+
if hasattr(self.backgroundImage, "draw"):
|
|
666
|
+
self.backgroundImage.draw()
|
|
667
|
+
|
|
668
|
+
def __del__(self):
|
|
669
|
+
if self._closed is False:
|
|
670
|
+
self.close()
|
|
671
|
+
|
|
672
|
+
def __enter__(self):
|
|
673
|
+
return self
|
|
674
|
+
|
|
675
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
676
|
+
if not self._closed:
|
|
677
|
+
self.close()
|
|
678
|
+
|
|
679
|
+
def __str__(self):
|
|
680
|
+
className = 'Window'
|
|
681
|
+
paramStrings = []
|
|
682
|
+
for param in self._initParams:
|
|
683
|
+
if hasattr(self, param):
|
|
684
|
+
paramStrings.append("%s=%s" %
|
|
685
|
+
(param, repr(getattr(self, param))))
|
|
686
|
+
else:
|
|
687
|
+
paramStrings.append("%s=UNKNOWN" % (param))
|
|
688
|
+
# paramStrings = ["%s=%s" %(param, getattr(self, param))
|
|
689
|
+
# for param in self._initParams]
|
|
690
|
+
params = ", ".join(paramStrings)
|
|
691
|
+
s = "%s(%s)" % (className, params)
|
|
692
|
+
return s
|
|
693
|
+
|
|
694
|
+
@attributeSetter
|
|
695
|
+
def title(self, value):
|
|
696
|
+
self.__dict__['title'] = value
|
|
697
|
+
if hasattr(self.winHandle, "set_caption"):
|
|
698
|
+
# Pyglet backend
|
|
699
|
+
self.winHandle.set_caption(value)
|
|
700
|
+
elif hasattr(self.winHandle, "SetWindowTitle"):
|
|
701
|
+
# GLFW backend
|
|
702
|
+
self.winHandle.SetWindowTitle(value)
|
|
703
|
+
else:
|
|
704
|
+
# Unknown backend
|
|
705
|
+
logging.warning(f"Cannot set Window title in backend {self.winType}")
|
|
706
|
+
|
|
707
|
+
@attributeSetter
|
|
708
|
+
def units(self, value):
|
|
709
|
+
"""*None*, 'height' (of the window), 'norm', 'deg', 'cm', 'pix'
|
|
710
|
+
Defines the default units of stimuli initialized in the window.
|
|
711
|
+
I.e. if you change units, already initialized stimuli won't change
|
|
712
|
+
their units.
|
|
713
|
+
|
|
714
|
+
Can be overridden by each stimulus, if units is specified on
|
|
715
|
+
initialization.
|
|
716
|
+
|
|
717
|
+
See :ref:`units` for explanation of options.
|
|
718
|
+
|
|
719
|
+
"""
|
|
720
|
+
if value is None:
|
|
721
|
+
value = prefs.general['units']
|
|
722
|
+
self.__dict__['units'] = value
|
|
723
|
+
|
|
724
|
+
def setUnits(self, value, log=True):
|
|
725
|
+
setAttribute(self, 'units', value, log=log)
|
|
726
|
+
|
|
727
|
+
@attributeSetter
|
|
728
|
+
def viewPos(self, value):
|
|
729
|
+
"""The origin of the window onto which stimulus-objects are drawn.
|
|
730
|
+
|
|
731
|
+
The value should be given in the units defined for the window. NB:
|
|
732
|
+
Never change a single component (x or y) of the origin, instead replace
|
|
733
|
+
the viewPos-attribute in one shot, e.g.::
|
|
734
|
+
|
|
735
|
+
win.viewPos = [new_xval, new_yval] # This is the way to do it
|
|
736
|
+
win.viewPos[0] = new_xval # DO NOT DO THIS! Errors will result.
|
|
737
|
+
|
|
738
|
+
"""
|
|
739
|
+
self.__dict__['viewPos'] = value
|
|
740
|
+
if value is not None:
|
|
741
|
+
# let setter take care of normalisation
|
|
742
|
+
setattr(self, '_viewPosNorm', value)
|
|
743
|
+
|
|
744
|
+
@attributeSetter
|
|
745
|
+
def _viewPosNorm(self, value):
|
|
746
|
+
"""Normalised value of viewPos, hidden from user view."""
|
|
747
|
+
# first convert to pixels, then normalise to window units
|
|
748
|
+
viewPos_pix = convertToPix([0, 0], list(value),
|
|
749
|
+
units=self.units, win=self)[:2]
|
|
750
|
+
viewPos_norm = viewPos_pix / (self.size / 2.0)
|
|
751
|
+
# Clip to +/- 1; should going out-of-window raise an exception?
|
|
752
|
+
viewPos_norm = numpy.clip(viewPos_norm, a_min=-1., a_max=1.)
|
|
753
|
+
self._viewMatrixNeedsUpdate = True
|
|
754
|
+
self.__dict__['_viewPosNorm'] = viewPos_norm
|
|
755
|
+
|
|
756
|
+
def setViewPos(self, value, log=True):
|
|
757
|
+
setAttribute(self, 'viewPos', value, log=log)
|
|
758
|
+
|
|
759
|
+
@attributeSetter
|
|
760
|
+
def viewOri(self, value):
|
|
761
|
+
"""Set the rotation of the view in degrees.
|
|
762
|
+
|
|
763
|
+
The rotation is applied around the origin of the window, which is
|
|
764
|
+
defined by the viewPos attribute. The rotation is applied after scaling
|
|
765
|
+
but before translation.
|
|
766
|
+
|
|
767
|
+
"""
|
|
768
|
+
self.__dict__['viewOri'] = value
|
|
769
|
+
self._viewMatrixNeedsUpdate = True
|
|
770
|
+
|
|
771
|
+
def setViewOri(self, value, log=True):
|
|
772
|
+
setAttribute(self, 'viewOri', value, log=log)
|
|
773
|
+
|
|
774
|
+
@attributeSetter
|
|
775
|
+
def viewScale(self, value):
|
|
776
|
+
"""Set the scale factors for the view.
|
|
777
|
+
|
|
778
|
+
The scaling is applied around the origin of the window, which is defined
|
|
779
|
+
by the viewPos attribute. The scaling is applied before translation and
|
|
780
|
+
rotation.
|
|
781
|
+
|
|
782
|
+
"""
|
|
783
|
+
self.__dict__['viewScale'] = value
|
|
784
|
+
self._viewMatrixNeedsUpdate = True
|
|
785
|
+
|
|
786
|
+
def setViewScale(self, value, log=True):
|
|
787
|
+
setAttribute(self, 'viewScale', value, log=log)
|
|
788
|
+
|
|
789
|
+
def _updateViewMatrix(self):
|
|
790
|
+
"""Update the default orthographic view matrix based on the current
|
|
791
|
+
window settings.
|
|
792
|
+
"""
|
|
793
|
+
if self._viewMatrixNeedsUpdate:
|
|
794
|
+
if self.viewScale is None:
|
|
795
|
+
sx, sy = [1.0, 1.0]
|
|
796
|
+
else:
|
|
797
|
+
sx, sy = self.viewScale
|
|
798
|
+
|
|
799
|
+
if self.viewOri is None:
|
|
800
|
+
viewOri = 0.0
|
|
801
|
+
else:
|
|
802
|
+
viewOri = self.viewOri
|
|
803
|
+
|
|
804
|
+
if self.viewPos is None:
|
|
805
|
+
tx, ty = [0.0, 0.0]
|
|
806
|
+
else:
|
|
807
|
+
tx, ty = self.viewPos
|
|
808
|
+
|
|
809
|
+
scaleMatrix = mathtools.scaleMatrix([sx, sy, 1.0])
|
|
810
|
+
rotateMatrix = mathtools.rotationMatrix(viewOri, axis='-z')
|
|
811
|
+
translateMatrix = mathtools.translationMatrix([tx, ty, 0.0])
|
|
812
|
+
|
|
813
|
+
# compute SRT matrix
|
|
814
|
+
self._viewMatrix[:, :] = mathtools.multMatrix([
|
|
815
|
+
translateMatrix,
|
|
816
|
+
rotateMatrix,
|
|
817
|
+
scaleMatrix])
|
|
818
|
+
self._viewMatrixNeedsUpdate = False
|
|
819
|
+
|
|
820
|
+
def _updateProjectionMatrix(self):
|
|
821
|
+
"""Update the default projection matrix based on the current window
|
|
822
|
+
settings.
|
|
823
|
+
"""
|
|
824
|
+
if self._projectionMatrixNeedsUpdate:
|
|
825
|
+
# widthOver2 = self.size[0] / 2.0
|
|
826
|
+
# heightOver2 = self.size[1] / 2.0
|
|
827
|
+
# self._projectionMatrix[:, :] = viewtools.orthoProjectionMatrix(
|
|
828
|
+
# -widthOver2, widthOver2, # -X, +X
|
|
829
|
+
# -heightOver2, heightOver2, # -Y, +Y
|
|
830
|
+
# -1.0, 1.0, # -Z, +Z
|
|
831
|
+
# dtype=numpy.float32)
|
|
832
|
+
self._projectionMatrix[:, :] = numpy.identity(4, dtype=numpy.float32)
|
|
833
|
+
self._projectionMatrixNeedsUpdate = False
|
|
834
|
+
|
|
835
|
+
@property
|
|
836
|
+
def fullscr(self):
|
|
837
|
+
"""Return whether the window is in fullscreen mode."""
|
|
838
|
+
return self._isFullScr
|
|
839
|
+
|
|
840
|
+
@fullscr.setter
|
|
841
|
+
def fullscr(self, value):
|
|
842
|
+
"""Set whether fullscreen mode is `True` or `False` (not all backends
|
|
843
|
+
can toggle an open window).
|
|
844
|
+
"""
|
|
845
|
+
self.backend.setFullScr(value)
|
|
846
|
+
self._isFullScr = value
|
|
847
|
+
|
|
848
|
+
@attributeSetter
|
|
849
|
+
def waitBlanking(self, value):
|
|
850
|
+
"""After a call to :py:attr:`~Window.flip()` should we wait for the
|
|
851
|
+
blank before the script continues.
|
|
852
|
+
|
|
853
|
+
"""
|
|
854
|
+
self.__dict__['waitBlanking'] = value
|
|
855
|
+
|
|
856
|
+
@attributeSetter
|
|
857
|
+
def recordFrameIntervals(self, value):
|
|
858
|
+
"""Record time elapsed per frame.
|
|
859
|
+
|
|
860
|
+
Provides accurate measures of frame intervals to determine
|
|
861
|
+
whether frames are being dropped. The intervals are the times between
|
|
862
|
+
calls to :py:attr:`~Window.flip()`. Set to `True` only during the
|
|
863
|
+
time-critical parts of the script. Set this to `False` while the screen
|
|
864
|
+
is not being updated, i.e., during any slow, non-frame-time-critical
|
|
865
|
+
sections of your code, including inter-trial-intervals,
|
|
866
|
+
``event.waitkeys()``, ``core.wait()``, or ``image.setImage()``.
|
|
867
|
+
|
|
868
|
+
Examples
|
|
869
|
+
--------
|
|
870
|
+
Enable frame interval recording, successive frame intervals will be
|
|
871
|
+
stored::
|
|
872
|
+
|
|
873
|
+
win.recordFrameIntervals = True
|
|
874
|
+
|
|
875
|
+
Frame intervals can be saved by calling the
|
|
876
|
+
:py:attr:`~Window.saveFrameIntervals` method::
|
|
877
|
+
|
|
878
|
+
win.saveFrameIntervals()
|
|
879
|
+
|
|
880
|
+
"""
|
|
881
|
+
# was off, and now turning it on
|
|
882
|
+
self.recordFrameIntervalsJustTurnedOn = bool(
|
|
883
|
+
not self.recordFrameIntervals and value)
|
|
884
|
+
self.__dict__['recordFrameIntervals'] = value
|
|
885
|
+
self.frameClock.reset()
|
|
886
|
+
|
|
887
|
+
def setRecordFrameIntervals(self, value=True, log=None):
|
|
888
|
+
"""Usually you can use 'stim.attribute = value' syntax instead,
|
|
889
|
+
but use this method if you need to suppress the log message.
|
|
890
|
+
"""
|
|
891
|
+
setAttribute(self, 'recordFrameIntervals', value, log)
|
|
892
|
+
|
|
893
|
+
def saveFrameIntervals(self, fileName=None, clear=True):
|
|
894
|
+
"""Save recorded screen frame intervals to disk, as comma-separated
|
|
895
|
+
values.
|
|
896
|
+
|
|
897
|
+
Parameters
|
|
898
|
+
----------
|
|
899
|
+
fileName : *None* or str
|
|
900
|
+
*None* or the filename (including path if necessary) in which to
|
|
901
|
+
store the data. If None then 'lastFrameIntervals.log' will be used.
|
|
902
|
+
clear : bool
|
|
903
|
+
Clear buffer frames intervals were stored after saving. Default is
|
|
904
|
+
`True`.
|
|
905
|
+
|
|
906
|
+
"""
|
|
907
|
+
if not fileName:
|
|
908
|
+
fileName = 'lastFrameIntervals.log'
|
|
909
|
+
if len(self.frameIntervals):
|
|
910
|
+
intervalStr = str(self.frameIntervals)[1:-1]
|
|
911
|
+
f = open(fileName, 'w')
|
|
912
|
+
f.write(intervalStr)
|
|
913
|
+
f.close()
|
|
914
|
+
if clear:
|
|
915
|
+
self.frameIntervals = []
|
|
916
|
+
self.frameClock.reset()
|
|
917
|
+
|
|
918
|
+
def _setCurrent(self):
|
|
919
|
+
"""Make this window's OpenGL context current.
|
|
920
|
+
|
|
921
|
+
If called on a window whose context is current, the function will return
|
|
922
|
+
immediately. This reduces the number of redundant calls if no context
|
|
923
|
+
switch is required. If ``useFBO=True``, the framebuffer is bound after
|
|
924
|
+
the context switch.
|
|
925
|
+
|
|
926
|
+
"""
|
|
927
|
+
# don't configure if we haven't changed context
|
|
928
|
+
if not self.backend.setCurrent():
|
|
929
|
+
return
|
|
930
|
+
|
|
931
|
+
# if we are using an FBO, bind it
|
|
932
|
+
if hasattr(self, 'frameBuffer'):
|
|
933
|
+
GL.glBindFramebufferEXT(GL.GL_FRAMEBUFFER,
|
|
934
|
+
self.frameBuffer)
|
|
935
|
+
GL.glReadBuffer(GL.GL_COLOR_ATTACHMENT0)
|
|
936
|
+
GL.glDrawBuffer(GL.GL_COLOR_ATTACHMENT0)
|
|
937
|
+
|
|
938
|
+
# NB - check if we need these
|
|
939
|
+
GL.glActiveTexture(GL.GL_TEXTURE0)
|
|
940
|
+
GL.glBindTexture(GL.GL_TEXTURE_2D, 0)
|
|
941
|
+
|
|
942
|
+
# set these to match the current window or buffer's settings
|
|
943
|
+
fbw, fbh = self.frameBufferSize
|
|
944
|
+
self.viewport = self.scissor = [0, 0, fbw, fbh]
|
|
945
|
+
self.scissorTest = True
|
|
946
|
+
|
|
947
|
+
# apply the view transforms for this window
|
|
948
|
+
#self.applyEyeTransform()
|
|
949
|
+
|
|
950
|
+
def onResize(self, width, height):
|
|
951
|
+
"""A default resize event handler.
|
|
952
|
+
|
|
953
|
+
This default handler updates the GL viewport to cover the entire
|
|
954
|
+
window and sets the ``GL_PROJECTION`` matrix to be orthogonal in
|
|
955
|
+
window space. The bottom-left corner is (0, 0) and the top-right
|
|
956
|
+
corner is the width and height of the :class:`~psychopy.visual.Window`
|
|
957
|
+
in pixels.
|
|
958
|
+
|
|
959
|
+
Override this event handler with your own to create another
|
|
960
|
+
projection, for example in perspective.
|
|
961
|
+
"""
|
|
962
|
+
# this has to be external so that pyglet can use it too without
|
|
963
|
+
# circular referencing
|
|
964
|
+
self.backend.onResize(width, height)
|
|
965
|
+
|
|
966
|
+
def logOnFlip(self, msg, level, obj=None):
|
|
967
|
+
"""Send a log message that should be time-stamped at the next
|
|
968
|
+
:py:attr:`~Window.flip()` command.
|
|
969
|
+
|
|
970
|
+
Parameters
|
|
971
|
+
----------
|
|
972
|
+
msg : str
|
|
973
|
+
The message to be logged.
|
|
974
|
+
level : int
|
|
975
|
+
The level of importance for the message.
|
|
976
|
+
obj : object, optional
|
|
977
|
+
The python object that might be associated with this message if
|
|
978
|
+
desired.
|
|
979
|
+
|
|
980
|
+
"""
|
|
981
|
+
self._toLog.append({'msg': msg, 'level': level, 'obj': repr(obj)})
|
|
982
|
+
|
|
983
|
+
def callOnFlip(self, function, *args, **kwargs):
|
|
984
|
+
"""Call a function immediately after the next :py:attr:`~Window.flip()`
|
|
985
|
+
command.
|
|
986
|
+
|
|
987
|
+
The first argument should be the function to call, the following args
|
|
988
|
+
should be used exactly as you would for your normal call to the
|
|
989
|
+
function (can use ordered arguments or keyword arguments as normal).
|
|
990
|
+
|
|
991
|
+
e.g. If you have a function that you would normally call like this::
|
|
992
|
+
|
|
993
|
+
pingMyDevice(portToPing, channel=2, level=0)
|
|
994
|
+
|
|
995
|
+
then you could call :py:attr:`~Window.callOnFlip()` to have the function
|
|
996
|
+
call synchronized with the frame flip like this::
|
|
997
|
+
|
|
998
|
+
win.callOnFlip(pingMyDevice, portToPing, channel=2, level=0)
|
|
999
|
+
|
|
1000
|
+
"""
|
|
1001
|
+
self._toCall.append({'function': function,
|
|
1002
|
+
'args': args,
|
|
1003
|
+
'kwargs': kwargs})
|
|
1004
|
+
|
|
1005
|
+
def timeOnFlip(self, obj, attrib, format=float):
|
|
1006
|
+
"""Retrieves the time on the next flip and assigns it to the `attrib`
|
|
1007
|
+
for this `obj`.
|
|
1008
|
+
|
|
1009
|
+
Parameters
|
|
1010
|
+
----------
|
|
1011
|
+
obj : dict or object
|
|
1012
|
+
A mutable object (usually a dict of class instance).
|
|
1013
|
+
attrib : str
|
|
1014
|
+
Key or attribute of `obj` to assign the flip time to.
|
|
1015
|
+
format : str, class or None
|
|
1016
|
+
Format in which to return time, see clock.Timestamp.resolve() for more info. Defaults to `float`.
|
|
1017
|
+
|
|
1018
|
+
Examples
|
|
1019
|
+
--------
|
|
1020
|
+
Assign time on flip to the ``tStartRefresh`` key of ``myTimingDict``::
|
|
1021
|
+
|
|
1022
|
+
win.getTimeOnFlip(myTimingDict, 'tStartRefresh')
|
|
1023
|
+
|
|
1024
|
+
"""
|
|
1025
|
+
self.callOnFlip(self._assignFlipTime, obj, attrib, format)
|
|
1026
|
+
|
|
1027
|
+
def getFutureFlipTime(self, targetTime=0, clock=None):
|
|
1028
|
+
"""The expected time of the next screen refresh. This is currently
|
|
1029
|
+
calculated as win._lastFrameTime + refreshInterval
|
|
1030
|
+
|
|
1031
|
+
Parameters
|
|
1032
|
+
-----------
|
|
1033
|
+
targetTime: float
|
|
1034
|
+
The delay *from now* for which you want the flip time. 0 will give the
|
|
1035
|
+
because that the earliest we can achieve. 0.15 will give the schedule
|
|
1036
|
+
flip time that gets as close to 150 ms as possible
|
|
1037
|
+
clock : None, 'ptb', 'now' or any Clock object
|
|
1038
|
+
If True then the time returned is compatible with ptb.GetSecs()
|
|
1039
|
+
verbose: bool
|
|
1040
|
+
Set to True to view the calculations along the way
|
|
1041
|
+
"""
|
|
1042
|
+
baseClock = logging.defaultClock
|
|
1043
|
+
if not self.monitorFramePeriod:
|
|
1044
|
+
raise AttributeError("Cannot calculate nextFlipTime due to unknown "
|
|
1045
|
+
"monitorFramePeriod")
|
|
1046
|
+
lastFlip = self._frameTimes[-1] # unlike win.lastFrameTime this is always on
|
|
1047
|
+
timeNext = lastFlip + self.monitorFramePeriod
|
|
1048
|
+
now = baseClock.getTime()
|
|
1049
|
+
if (now + targetTime) > timeNext: # target is more than 1 frame in future
|
|
1050
|
+
extraFrames = math.ceil((now + targetTime - timeNext)/self.monitorFramePeriod)
|
|
1051
|
+
thisT = timeNext + extraFrames*self.monitorFramePeriod
|
|
1052
|
+
else:
|
|
1053
|
+
thisT = timeNext
|
|
1054
|
+
# convert back to target clock timebase
|
|
1055
|
+
if clock=='ptb': # add back the lastResetTime (that's the clock difference)
|
|
1056
|
+
output = thisT + baseClock.getLastResetTime()
|
|
1057
|
+
elif clock=='now': # time from now is easy!
|
|
1058
|
+
output = thisT - now
|
|
1059
|
+
elif clock:
|
|
1060
|
+
output = thisT + baseClock.getLastResetTime() - clock.getLastResetTime()
|
|
1061
|
+
else:
|
|
1062
|
+
output = thisT
|
|
1063
|
+
|
|
1064
|
+
return output
|
|
1065
|
+
|
|
1066
|
+
def _assignFlipTime(self, obj, attrib, format=float):
|
|
1067
|
+
"""Helper function to assign the time of last flip to the obj.attrib
|
|
1068
|
+
|
|
1069
|
+
Parameters
|
|
1070
|
+
----------
|
|
1071
|
+
obj : dict or object
|
|
1072
|
+
A mutable object (usually a dict of class instance).
|
|
1073
|
+
attrib : str
|
|
1074
|
+
Key or attribute of ``obj`` to assign the flip time to.
|
|
1075
|
+
format : str, class or None
|
|
1076
|
+
Format in which to return time, see clock.Timestamp.resolve() for more info. Defaults to `float`.
|
|
1077
|
+
|
|
1078
|
+
"""
|
|
1079
|
+
frameTime = self._frameTime.resolve(format=format)
|
|
1080
|
+
if hasattr(obj, attrib):
|
|
1081
|
+
setattr(obj, attrib, frameTime)
|
|
1082
|
+
elif isinstance(obj, dict):
|
|
1083
|
+
obj[attrib] = frameTime
|
|
1084
|
+
else:
|
|
1085
|
+
raise TypeError("Window.getTimeOnFlip() should be called with an "
|
|
1086
|
+
"object and its attribute or a dict and its key. "
|
|
1087
|
+
"In this case it was called with obj={}"
|
|
1088
|
+
.format(repr(obj)))
|
|
1089
|
+
|
|
1090
|
+
def _cleanEditables(self):
|
|
1091
|
+
"""
|
|
1092
|
+
Make sure there are no dead refs in the editables list
|
|
1093
|
+
"""
|
|
1094
|
+
for ref in self._editableChildren:
|
|
1095
|
+
obj = ref()
|
|
1096
|
+
if obj is None:
|
|
1097
|
+
self._editableChildren.remove(ref)
|
|
1098
|
+
|
|
1099
|
+
@property
|
|
1100
|
+
def currentEditable(self):
|
|
1101
|
+
"""The editable (Text?) object that currently has key focus"""
|
|
1102
|
+
if self._currentEditableRef:
|
|
1103
|
+
return self._currentEditableRef()
|
|
1104
|
+
|
|
1105
|
+
@currentEditable.setter
|
|
1106
|
+
def currentEditable(self, editable):
|
|
1107
|
+
"""Keeps the current editable stored as a weak ref"""
|
|
1108
|
+
# Ensure that item is added to editables list
|
|
1109
|
+
self.addEditable(editable)
|
|
1110
|
+
|
|
1111
|
+
# Set the editable as the current editable stim in the window
|
|
1112
|
+
eRef = None
|
|
1113
|
+
for ref in weakref.getweakrefs(editable):
|
|
1114
|
+
if ref in self._editableChildren:
|
|
1115
|
+
eRef = ref
|
|
1116
|
+
break
|
|
1117
|
+
if eRef:
|
|
1118
|
+
self._currentEditableRef = eRef
|
|
1119
|
+
|
|
1120
|
+
def addEditable(self, editable):
|
|
1121
|
+
"""Adds an editable element to the screen (something to which
|
|
1122
|
+
characters can be sent with meaning from the keyboard).
|
|
1123
|
+
|
|
1124
|
+
The current editable object receiving chars is Window.currentEditable
|
|
1125
|
+
|
|
1126
|
+
:param editable:
|
|
1127
|
+
:return:
|
|
1128
|
+
"""
|
|
1129
|
+
# Ignore if object is not editable
|
|
1130
|
+
if not hasattr(editable, "editable"):
|
|
1131
|
+
return
|
|
1132
|
+
if not editable.editable:
|
|
1133
|
+
return
|
|
1134
|
+
# If editable is already present do nothing
|
|
1135
|
+
eRef = False
|
|
1136
|
+
for ref in weakref.getweakrefs(editable):
|
|
1137
|
+
if ref in self._editableChildren:
|
|
1138
|
+
eRef = ref
|
|
1139
|
+
break
|
|
1140
|
+
|
|
1141
|
+
if eRef is False:
|
|
1142
|
+
eRef = weakref.ref(editable)
|
|
1143
|
+
# If editable is not already present, add it to the editables list
|
|
1144
|
+
self._editableChildren.append(eRef)
|
|
1145
|
+
|
|
1146
|
+
# If this is the first editable obj then make it the current
|
|
1147
|
+
if len(self._editableChildren) == 1:
|
|
1148
|
+
self._currentEditableRef = eRef
|
|
1149
|
+
# Clean editables list
|
|
1150
|
+
self._cleanEditables()
|
|
1151
|
+
|
|
1152
|
+
def removeEditable(self, editable):
|
|
1153
|
+
# If editable is present, remove it from editables list
|
|
1154
|
+
for ref in weakref.getweakrefs(editable):
|
|
1155
|
+
if ref in self._editableChildren:
|
|
1156
|
+
# If editable was current, move on to next current
|
|
1157
|
+
if self.currentEditable == editable:
|
|
1158
|
+
self.nextEditable()
|
|
1159
|
+
self._editableChildren.remove(ref)
|
|
1160
|
+
return True
|
|
1161
|
+
else:
|
|
1162
|
+
logging.warning(f"Request to remove editable object {editable} could not be completed as weakref "
|
|
1163
|
+
f"to this object could not be found in window.")
|
|
1164
|
+
# Clean editables list
|
|
1165
|
+
self._cleanEditables()
|
|
1166
|
+
|
|
1167
|
+
return False
|
|
1168
|
+
|
|
1169
|
+
def nextEditable(self):
|
|
1170
|
+
"""Moves focus of the cursor to the next editable window"""
|
|
1171
|
+
# Clean editables list
|
|
1172
|
+
self._cleanEditables()
|
|
1173
|
+
# Progress
|
|
1174
|
+
if self.currentEditable is None:
|
|
1175
|
+
if len(self._editableChildren):
|
|
1176
|
+
self._currentEditableRef = self._editableChildren[0]
|
|
1177
|
+
else:
|
|
1178
|
+
for ref in weakref.getweakrefs(self.currentEditable):
|
|
1179
|
+
if ref in self._editableChildren:
|
|
1180
|
+
cei = self._editableChildren.index(ref)
|
|
1181
|
+
nei = cei+1
|
|
1182
|
+
if nei >= len(self._editableChildren):
|
|
1183
|
+
nei=0
|
|
1184
|
+
self._currentEditableRef = self._editableChildren[nei]
|
|
1185
|
+
return self.currentEditable
|
|
1186
|
+
|
|
1187
|
+
@classmethod
|
|
1188
|
+
def dispatchAllWindowEvents(cls):
|
|
1189
|
+
"""
|
|
1190
|
+
Dispatches events for all pyglet windows. Used by iohub 2.0
|
|
1191
|
+
psychopy kb event integration.
|
|
1192
|
+
"""
|
|
1193
|
+
Window.backend.dispatchEvents()
|
|
1194
|
+
|
|
1195
|
+
def clearAutoDraw(self):
|
|
1196
|
+
"""
|
|
1197
|
+
Remove all autoDraw components, meaning they get autoDraw set to False and are not
|
|
1198
|
+
added to any list (as in .stashAutoDraw)
|
|
1199
|
+
"""
|
|
1200
|
+
for thisStim in self._toDraw.copy():
|
|
1201
|
+
# set autoDraw to False
|
|
1202
|
+
thisStim.autoDraw = False
|
|
1203
|
+
|
|
1204
|
+
def stashAutoDraw(self):
|
|
1205
|
+
"""
|
|
1206
|
+
Put autoDraw components on 'hold', meaning they get autoDraw set to False but
|
|
1207
|
+
are added to an internal list to be 'released' when .releaseAutoDraw is called.
|
|
1208
|
+
"""
|
|
1209
|
+
for thisStim in self._toDraw.copy():
|
|
1210
|
+
# set autoDraw to False
|
|
1211
|
+
thisStim.autoDraw = False
|
|
1212
|
+
# add stim to held list
|
|
1213
|
+
self._heldDraw.append(thisStim)
|
|
1214
|
+
|
|
1215
|
+
def retrieveAutoDraw(self):
|
|
1216
|
+
"""
|
|
1217
|
+
Add all stimuli which are on 'hold' back into the autoDraw list, and clear the
|
|
1218
|
+
hold list.
|
|
1219
|
+
"""
|
|
1220
|
+
for thisStim in self._heldDraw:
|
|
1221
|
+
# set autoDraw to True
|
|
1222
|
+
thisStim.autoDraw = True
|
|
1223
|
+
# clear list
|
|
1224
|
+
self._heldDraw = []
|
|
1225
|
+
|
|
1226
|
+
def flip(self, clearBuffer=True):
|
|
1227
|
+
"""Flip the front and back buffers after drawing everything for your
|
|
1228
|
+
frame. (This replaces the :py:attr:`~Window.update()` method, better
|
|
1229
|
+
reflecting what is happening underneath).
|
|
1230
|
+
|
|
1231
|
+
Parameters
|
|
1232
|
+
----------
|
|
1233
|
+
clearBuffer : bool, optional
|
|
1234
|
+
Clear the draw buffer after flipping. Default is `True`.
|
|
1235
|
+
|
|
1236
|
+
Returns
|
|
1237
|
+
-------
|
|
1238
|
+
float or None
|
|
1239
|
+
Wall-clock time in seconds the flip completed. Returns `None` if
|
|
1240
|
+
:py:attr:`~Window.waitBlanking` is `False`.
|
|
1241
|
+
|
|
1242
|
+
Notes
|
|
1243
|
+
-----
|
|
1244
|
+
* The time returned when :py:attr:`~Window.waitBlanking` is `True`
|
|
1245
|
+
corresponds to when the graphics driver releases the draw buffer to
|
|
1246
|
+
accept draw commands again. This time is usually close to the vertical
|
|
1247
|
+
sync signal of the display.
|
|
1248
|
+
|
|
1249
|
+
Examples
|
|
1250
|
+
--------
|
|
1251
|
+
|
|
1252
|
+
Results in a clear screen after flipping::
|
|
1253
|
+
|
|
1254
|
+
win.flip(clearBuffer=True)
|
|
1255
|
+
|
|
1256
|
+
The screen is not cleared (so represent the previous screen)::
|
|
1257
|
+
|
|
1258
|
+
win.flip(clearBuffer=False)
|
|
1259
|
+
|
|
1260
|
+
"""
|
|
1261
|
+
# draw message/splash if needed
|
|
1262
|
+
if self._showSplash:
|
|
1263
|
+
self._splashTextbox.draw()
|
|
1264
|
+
|
|
1265
|
+
if self._toDraw:
|
|
1266
|
+
for thisStim in self._toDraw:
|
|
1267
|
+
# draw
|
|
1268
|
+
thisStim.draw()
|
|
1269
|
+
# draw validation rect if needed
|
|
1270
|
+
if thisStim in self.validators:
|
|
1271
|
+
self.validators[thisStim].draw()
|
|
1272
|
+
# handle dragging
|
|
1273
|
+
if getattr(thisStim, "draggable", False):
|
|
1274
|
+
thisStim.doDragging()
|
|
1275
|
+
|
|
1276
|
+
if getattr(thisStim, "clickable", False):
|
|
1277
|
+
thisStim.doPointerActions()
|
|
1278
|
+
|
|
1279
|
+
else:
|
|
1280
|
+
self.backend.setCurrent()
|
|
1281
|
+
|
|
1282
|
+
# set these to match the current window or buffer's settings
|
|
1283
|
+
self.viewport = self.scissor = \
|
|
1284
|
+
(0, 0, self.frameBufferSize[0], self.frameBufferSize[1])
|
|
1285
|
+
if not self.scissorTest:
|
|
1286
|
+
self.scissorTest = True
|
|
1287
|
+
|
|
1288
|
+
# clear the projection and modelview matrix for FBO blit
|
|
1289
|
+
# DEPRECATED: these are all removed from OpenGL 3.1
|
|
1290
|
+
if self.USE_LEGACY_GL:
|
|
1291
|
+
GL.glMatrixMode(GL.GL_PROJECTION)
|
|
1292
|
+
GL.glLoadIdentity()
|
|
1293
|
+
GL.glOrtho(-1, 1, -1, 1, -1, 1)
|
|
1294
|
+
GL.glMatrixMode(GL.GL_MODELVIEW)
|
|
1295
|
+
GL.glLoadIdentity()
|
|
1296
|
+
|
|
1297
|
+
# disable lighting
|
|
1298
|
+
self.useLights = False
|
|
1299
|
+
|
|
1300
|
+
# Check for mouse clicks on editables
|
|
1301
|
+
if hasattr(self, '_editableChildren'):
|
|
1302
|
+
# Make sure _editableChildren has actually been created
|
|
1303
|
+
editablesOnScreen = []
|
|
1304
|
+
for thisObj in self._editableChildren:
|
|
1305
|
+
# Iterate through editables and decide which one should have focus
|
|
1306
|
+
if isinstance(thisObj, weakref.ref):
|
|
1307
|
+
# Solidify weakref if necessary
|
|
1308
|
+
thisObj = thisObj()
|
|
1309
|
+
if thisObj is None:
|
|
1310
|
+
continue
|
|
1311
|
+
if isinstance(thisObj.autoDraw, (bool, int, float)):
|
|
1312
|
+
# Store whether this editable is on screen
|
|
1313
|
+
editablesOnScreen.append(thisObj.autoDraw)
|
|
1314
|
+
else:
|
|
1315
|
+
editablesOnScreen.append(False)
|
|
1316
|
+
if self._mouse.isPressedIn(thisObj):
|
|
1317
|
+
# If editable was clicked on, give it focus
|
|
1318
|
+
self.currentEditable = thisObj
|
|
1319
|
+
# If there is only one editable on screen, make sure it starts off with focus
|
|
1320
|
+
if sum(editablesOnScreen) == 1:
|
|
1321
|
+
self.currentEditable = self._editableChildren[editablesOnScreen.index(True)]()
|
|
1322
|
+
|
|
1323
|
+
flipThisFrame = self._startOfFlip()
|
|
1324
|
+
if self.useFBO and flipThisFrame:
|
|
1325
|
+
self.draw3d = False # disable 3d drawing
|
|
1326
|
+
self._prepareFBOrender()
|
|
1327
|
+
# need blit the framebuffer object to the actual back buffer
|
|
1328
|
+
|
|
1329
|
+
# unbind the framebuffer as the render target
|
|
1330
|
+
GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0)
|
|
1331
|
+
GL.glDisable(GL.GL_BLEND)
|
|
1332
|
+
stencilOn = self.stencilTest
|
|
1333
|
+
self.stencilTest = False
|
|
1334
|
+
|
|
1335
|
+
if self.bits is not None:
|
|
1336
|
+
self.bits._prepareFBOrender()
|
|
1337
|
+
|
|
1338
|
+
# before flipping need to copy the renderBuffer to the
|
|
1339
|
+
# frameBuffer
|
|
1340
|
+
GL.glActiveTexture(GL.GL_TEXTURE0)
|
|
1341
|
+
GL.glEnable(GL.GL_TEXTURE_2D)
|
|
1342
|
+
GL.glBindTexture(GL.GL_TEXTURE_2D, self.frameTexture)
|
|
1343
|
+
if self.USE_LEGACY_GL:
|
|
1344
|
+
GL.glColor3f(1.0, 1.0, 1.0) # glColor multiplies with texture
|
|
1345
|
+
|
|
1346
|
+
GL.glColorMask(True, True, True, True)
|
|
1347
|
+
|
|
1348
|
+
self._renderFBO()
|
|
1349
|
+
|
|
1350
|
+
GL.glEnable(GL.GL_BLEND)
|
|
1351
|
+
self._finishFBOrender()
|
|
1352
|
+
|
|
1353
|
+
# call this before flip() whether FBO was used or not
|
|
1354
|
+
self._afterFBOrender()
|
|
1355
|
+
|
|
1356
|
+
self.backend.swapBuffers(flipThisFrame)
|
|
1357
|
+
|
|
1358
|
+
if self.useFBO and flipThisFrame:
|
|
1359
|
+
# set rendering back to the framebuffer object
|
|
1360
|
+
GL.glBindFramebuffer(
|
|
1361
|
+
GL.GL_FRAMEBUFFER, self.frameBuffer)
|
|
1362
|
+
GL.glReadBuffer(GL.GL_COLOR_ATTACHMENT0)
|
|
1363
|
+
GL.glDrawBuffer(GL.GL_COLOR_ATTACHMENT0)
|
|
1364
|
+
# set to no active rendering texture
|
|
1365
|
+
GL.glActiveTexture(GL.GL_TEXTURE0)
|
|
1366
|
+
GL.glBindTexture(GL.GL_TEXTURE_2D, 0)
|
|
1367
|
+
if stencilOn:
|
|
1368
|
+
self.stencilTest = True
|
|
1369
|
+
|
|
1370
|
+
# rescale, reposition, & rotate
|
|
1371
|
+
# DEPRECATED: these are all removed from OpenGL 3.1
|
|
1372
|
+
if self.USE_LEGACY_GL:
|
|
1373
|
+
GL.glMatrixMode(GL.GL_MODELVIEW)
|
|
1374
|
+
GL.glLoadIdentity()
|
|
1375
|
+
if self.viewScale is not None:
|
|
1376
|
+
# DEPRECATED: these are all removed from OpenGL 3.1
|
|
1377
|
+
GL.glScalef(self.viewScale[0], self.viewScale[1], 1)
|
|
1378
|
+
|
|
1379
|
+
absScaleX = abs(self.viewScale[0])
|
|
1380
|
+
absScaleY = abs(self.viewScale[1])
|
|
1381
|
+
else:
|
|
1382
|
+
absScaleX, absScaleY = 1, 1
|
|
1383
|
+
|
|
1384
|
+
if self.viewPos is not None:
|
|
1385
|
+
# here we must use normalised units in _viewPosNorm,
|
|
1386
|
+
# see the corresponding attributeSetter above
|
|
1387
|
+
normRfPosX = self._viewPosNorm[0] / absScaleX
|
|
1388
|
+
normRfPosY = self._viewPosNorm[1] / absScaleY
|
|
1389
|
+
|
|
1390
|
+
# DEPRECATED: these are all removed from OpenGL 3.1
|
|
1391
|
+
GL.glTranslatef(normRfPosX, normRfPosY, 0.0)
|
|
1392
|
+
|
|
1393
|
+
if self.viewOri: # float
|
|
1394
|
+
# the logic below for flip is partially correct, but does not
|
|
1395
|
+
# handle a nonzero viewPos
|
|
1396
|
+
flip = 1
|
|
1397
|
+
if self.viewScale is not None:
|
|
1398
|
+
_f = self.viewScale[0] * self.viewScale[1]
|
|
1399
|
+
if _f < 0:
|
|
1400
|
+
flip = -1
|
|
1401
|
+
# DEPERECATED: these are all removed from OpenGL 3.1
|
|
1402
|
+
GL.glRotatef(flip * self.viewOri, 0.0, 0.0, -1.0)
|
|
1403
|
+
|
|
1404
|
+
# reset returned buffer for next frame
|
|
1405
|
+
self._endOfFlip(clearBuffer)
|
|
1406
|
+
|
|
1407
|
+
# waitBlanking
|
|
1408
|
+
if self.waitBlanking and flipThisFrame:
|
|
1409
|
+
# DEPRECATED: these are all removed from OpenGL 3.1
|
|
1410
|
+
if self.USE_LEGACY_GL:
|
|
1411
|
+
GL.glBegin(GL.GL_POINTS)
|
|
1412
|
+
GL.glColor4f(0, 0, 0, 0)
|
|
1413
|
+
if sys.platform == 'win32' and self.glVendor.startswith('ati'):
|
|
1414
|
+
pass
|
|
1415
|
+
else:
|
|
1416
|
+
# this corrupts text rendering on win with some ATI cards :-(
|
|
1417
|
+
GL.glVertex2i(10, 10)
|
|
1418
|
+
pass
|
|
1419
|
+
GL.glEnd()
|
|
1420
|
+
GL.glFinish()
|
|
1421
|
+
|
|
1422
|
+
# get timestamp
|
|
1423
|
+
self._frameTime = now = logging.defaultClock.getTime()
|
|
1424
|
+
self._frameTimes.append(self._frameTime)
|
|
1425
|
+
|
|
1426
|
+
# run scheduled functions immediately after flip completes
|
|
1427
|
+
n_items = len(self._toCall)
|
|
1428
|
+
for i in range(n_items):
|
|
1429
|
+
self._toCall[i]['function'](*self._toCall[i]['args'], **self._toCall[i]['kwargs'])
|
|
1430
|
+
# leave newly scheduled functions for next flip
|
|
1431
|
+
del self._toCall[:n_items]
|
|
1432
|
+
|
|
1433
|
+
# do bookkeeping
|
|
1434
|
+
if self.recordFrameIntervals:
|
|
1435
|
+
self.frames += 1
|
|
1436
|
+
deltaT = now - self.lastFrameT
|
|
1437
|
+
self.lastFrameT = now
|
|
1438
|
+
|
|
1439
|
+
if self.recordFrameIntervalsJustTurnedOn: # don't do anything
|
|
1440
|
+
self.recordFrameIntervalsJustTurnedOn = False
|
|
1441
|
+
else: # past the first frame since turned on
|
|
1442
|
+
self.frameIntervals.append(deltaT)
|
|
1443
|
+
if deltaT > self.refreshThreshold:
|
|
1444
|
+
self.nDroppedFrames += 1
|
|
1445
|
+
if self.nDroppedFrames < reportNDroppedFrames:
|
|
1446
|
+
txt = 't of last frame was %.2fms (=1/%i)'
|
|
1447
|
+
msg = txt % (deltaT * 1000, 1 / deltaT)
|
|
1448
|
+
logging.warning(msg, t=now)
|
|
1449
|
+
elif self.nDroppedFrames == reportNDroppedFrames:
|
|
1450
|
+
logging.warning("Multiple dropped frames have "
|
|
1451
|
+
"occurred - I'll stop bothering you "
|
|
1452
|
+
"about them!")
|
|
1453
|
+
|
|
1454
|
+
# log events
|
|
1455
|
+
for logEntry in self._toLog:
|
|
1456
|
+
# {'msg':msg, 'level':level, 'obj':copy.copy(obj)}
|
|
1457
|
+
logging.log(msg=logEntry['msg'],
|
|
1458
|
+
level=logEntry['level'],
|
|
1459
|
+
t=now,
|
|
1460
|
+
obj=logEntry['obj'])
|
|
1461
|
+
del self._toLog[:]
|
|
1462
|
+
|
|
1463
|
+
# keep the system awake (prevent screen-saver or sleep)
|
|
1464
|
+
platform_specific.sendStayAwake()
|
|
1465
|
+
|
|
1466
|
+
# draw background (if present) for next frame
|
|
1467
|
+
if hasattr(self.backgroundImage, "draw"):
|
|
1468
|
+
self.backgroundImage.draw()
|
|
1469
|
+
|
|
1470
|
+
# draw piloting indicator (if piloting) for next frame
|
|
1471
|
+
if self._showPilotingIndicator:
|
|
1472
|
+
self._pilotingIndicator.draw()
|
|
1473
|
+
|
|
1474
|
+
# If self.waitBlanking is True, then return the time that
|
|
1475
|
+
# GL.glFinish() returned, set as the 'now' variable. Otherwise
|
|
1476
|
+
# return None as before
|
|
1477
|
+
#
|
|
1478
|
+
if self.waitBlanking is True:
|
|
1479
|
+
return now
|
|
1480
|
+
|
|
1481
|
+
def update(self):
|
|
1482
|
+
"""Deprecated: use Window.flip() instead
|
|
1483
|
+
"""
|
|
1484
|
+
# clearBuffer was the original behaviour for win.update()
|
|
1485
|
+
self.flip(clearBuffer=True)
|
|
1486
|
+
|
|
1487
|
+
def multiFlip(self, flips=1, clearBuffer=True):
|
|
1488
|
+
"""Flip multiple times while maintaining the display constant.
|
|
1489
|
+
Use this method for precise timing.
|
|
1490
|
+
|
|
1491
|
+
**WARNING:** This function should not be used. See the `Notes` section
|
|
1492
|
+
for details.
|
|
1493
|
+
|
|
1494
|
+
Parameters
|
|
1495
|
+
----------
|
|
1496
|
+
flips : int, optional
|
|
1497
|
+
The number of monitor frames to flip. Floats will be
|
|
1498
|
+
rounded to integers, and a warning will be emitted.
|
|
1499
|
+
``Window.multiFlip(flips=1)`` is equivalent to ``Window.flip()``.
|
|
1500
|
+
Defaults to `1`.
|
|
1501
|
+
clearBuffer : bool, optional
|
|
1502
|
+
Whether to clear the screen after the last flip.
|
|
1503
|
+
Defaults to `True`.
|
|
1504
|
+
|
|
1505
|
+
Notes
|
|
1506
|
+
-----
|
|
1507
|
+
- This function can behave unpredictably, and the PsychoPy authors
|
|
1508
|
+
recommend against using it. See
|
|
1509
|
+
https://github.com/psychopy/psychopy/issues/867 for more information.
|
|
1510
|
+
|
|
1511
|
+
Examples
|
|
1512
|
+
--------
|
|
1513
|
+
Example of using ``multiFlip``::
|
|
1514
|
+
|
|
1515
|
+
# Draws myStim1 to buffer
|
|
1516
|
+
myStim1.draw()
|
|
1517
|
+
# Show stimulus for 4 frames (90 ms at 60Hz)
|
|
1518
|
+
myWin.multiFlip(clearBuffer=False, flips=6)
|
|
1519
|
+
# Draw myStim2 "on top of" myStim1
|
|
1520
|
+
# (because buffer was not cleared above)
|
|
1521
|
+
myStim2.draw()
|
|
1522
|
+
# Show this for 2 frames (30 ms at 60Hz)
|
|
1523
|
+
myWin.multiFlip(flips=2)
|
|
1524
|
+
# Show blank screen for 3 frames (buffer was cleared above)
|
|
1525
|
+
myWin.multiFlip(flips=3)
|
|
1526
|
+
|
|
1527
|
+
"""
|
|
1528
|
+
if flips < 1:
|
|
1529
|
+
logging.error("flips argument for multiFlip should be "
|
|
1530
|
+
"a positive integer")
|
|
1531
|
+
|
|
1532
|
+
if flips != int(flips):
|
|
1533
|
+
flips = int(round(flips))
|
|
1534
|
+
logging.warning("Number of flips was not an integer; "
|
|
1535
|
+
"rounding to the next integer. Will flip "
|
|
1536
|
+
"%i times." % flips)
|
|
1537
|
+
|
|
1538
|
+
if flips > 1 and not self.waitBlanking:
|
|
1539
|
+
logging.warning("Call to Window.multiFlip() with flips > 1 is "
|
|
1540
|
+
"unnecessary because Window.waitBlanking=False")
|
|
1541
|
+
|
|
1542
|
+
# Do the flipping with last flip as special case
|
|
1543
|
+
for _ in range(flips - 1):
|
|
1544
|
+
self.flip(clearBuffer=False)
|
|
1545
|
+
self.flip(clearBuffer=clearBuffer)
|
|
1546
|
+
|
|
1547
|
+
|
|
1548
|
+
|
|
1549
|
+
def setBuffer(self, buffer, clear=True):
|
|
1550
|
+
"""Choose which buffer to draw to ('left' or 'right').
|
|
1551
|
+
|
|
1552
|
+
Requires the Window to be initialised with stereo=True and requires a
|
|
1553
|
+
graphics card that supports quad buffering (e,g nVidia Quadro series)
|
|
1554
|
+
|
|
1555
|
+
PsychoPy always draws to the back buffers, so 'left' will use
|
|
1556
|
+
``GL_BACK_LEFT`` This then needs to be flipped once both eye's buffers
|
|
1557
|
+
have been rendered.
|
|
1558
|
+
|
|
1559
|
+
Parameters
|
|
1560
|
+
----------
|
|
1561
|
+
buffer : str
|
|
1562
|
+
Buffer to draw to. Can either be 'left' or 'right'.
|
|
1563
|
+
clear : bool, optional
|
|
1564
|
+
Clear the buffer before drawing. Default is ``True``.
|
|
1565
|
+
|
|
1566
|
+
Examples
|
|
1567
|
+
--------
|
|
1568
|
+
Stereoscopic rendering example using quad-buffers::
|
|
1569
|
+
|
|
1570
|
+
win = visual.Window(...., stereo=True)
|
|
1571
|
+
while True:
|
|
1572
|
+
# clear may not actually be needed
|
|
1573
|
+
win.setBuffer('left', clear=True)
|
|
1574
|
+
# do drawing for left eye
|
|
1575
|
+
win.setBuffer('right', clear=True)
|
|
1576
|
+
# do drawing for right eye
|
|
1577
|
+
win.flip()
|
|
1578
|
+
|
|
1579
|
+
"""
|
|
1580
|
+
if buffer == 'left':
|
|
1581
|
+
GL.glDrawBuffer(GL.GL_BACK_LEFT)
|
|
1582
|
+
elif buffer == 'right':
|
|
1583
|
+
GL.glDrawBuffer(GL.GL_BACK_RIGHT)
|
|
1584
|
+
else:
|
|
1585
|
+
raise "Unknown buffer '%s' requested in Window.setBuffer" % buffer
|
|
1586
|
+
if clear:
|
|
1587
|
+
self.clearBuffer()
|
|
1588
|
+
|
|
1589
|
+
def clearBuffer(self, color=True, depth=False, stencil=False):
|
|
1590
|
+
"""Clear the present buffer (to which you are currently drawing) without
|
|
1591
|
+
flipping the window.
|
|
1592
|
+
|
|
1593
|
+
Useful if you want to generate movie sequences from the back buffer
|
|
1594
|
+
without actually taking the time to flip the window.
|
|
1595
|
+
|
|
1596
|
+
Set `color` prior to clearing to set the color to clear the color buffer
|
|
1597
|
+
to. By default, the depth buffer is cleared to a value of 1.0.
|
|
1598
|
+
|
|
1599
|
+
Parameters
|
|
1600
|
+
----------
|
|
1601
|
+
color, depth, stencil : bool
|
|
1602
|
+
Buffers to clear.
|
|
1603
|
+
|
|
1604
|
+
Examples
|
|
1605
|
+
--------
|
|
1606
|
+
Clear the color buffer to a specified color::
|
|
1607
|
+
|
|
1608
|
+
win.color = (1, 0, 0)
|
|
1609
|
+
win.clearBuffer(color=True)
|
|
1610
|
+
|
|
1611
|
+
Clear only the depth buffer, `depthMask` must be `True` or else this
|
|
1612
|
+
will have no effect. Depth mask is usually `True` by default, but
|
|
1613
|
+
may change::
|
|
1614
|
+
|
|
1615
|
+
win.depthMask = True
|
|
1616
|
+
win.clearBuffer(color=False, depth=True, stencil=False)
|
|
1617
|
+
|
|
1618
|
+
"""
|
|
1619
|
+
clearBufferBits = GL.GL_NONE
|
|
1620
|
+
|
|
1621
|
+
if color:
|
|
1622
|
+
clearBufferBits |= GL.GL_COLOR_BUFFER_BIT
|
|
1623
|
+
|
|
1624
|
+
if depth:
|
|
1625
|
+
clearBufferBits |= GL.GL_DEPTH_BUFFER_BIT
|
|
1626
|
+
|
|
1627
|
+
if stencil:
|
|
1628
|
+
clearBufferBits |= GL.GL_STENCIL_BUFFER_BIT
|
|
1629
|
+
|
|
1630
|
+
# reset returned buffer for next frame
|
|
1631
|
+
GL.glClear(clearBufferBits)
|
|
1632
|
+
|
|
1633
|
+
@property
|
|
1634
|
+
def size(self):
|
|
1635
|
+
"""Size of the drawable area in pixels (w, h)."""
|
|
1636
|
+
# report clientSize until we get framebuffer size from
|
|
1637
|
+
# the backend, needs to be done properly in the future
|
|
1638
|
+
if self.backend is not None:
|
|
1639
|
+
return self.viewport[2:]
|
|
1640
|
+
else:
|
|
1641
|
+
return self.clientSize
|
|
1642
|
+
|
|
1643
|
+
@property
|
|
1644
|
+
def frameBufferSize(self):
|
|
1645
|
+
"""Size of the framebuffer in pixels (w, h)."""
|
|
1646
|
+
# Dimensions should match window size unless using a retina display
|
|
1647
|
+
return self.backend.frameBufferSize
|
|
1648
|
+
|
|
1649
|
+
@property
|
|
1650
|
+
def windowedSize(self):
|
|
1651
|
+
"""Size of the window to use when not fullscreen (w, h)."""
|
|
1652
|
+
return self._windowedSize
|
|
1653
|
+
|
|
1654
|
+
@windowedSize.setter
|
|
1655
|
+
def windowedSize(self, value):
|
|
1656
|
+
"""Size of the window to use when not fullscreen (w, h)."""
|
|
1657
|
+
self._windowedSize[:] = value
|
|
1658
|
+
|
|
1659
|
+
def getContentScaleFactor(self):
|
|
1660
|
+
"""Get the scaling factor required for scaling correctly on high-DPI
|
|
1661
|
+
displays.
|
|
1662
|
+
|
|
1663
|
+
If the returned value is 1.0, no scaling needs to be applied to objects
|
|
1664
|
+
drawn on the backbuffer. A value >1.0 indicates that the backbuffer is
|
|
1665
|
+
larger than the reported client area, requiring points to be scaled to
|
|
1666
|
+
maintain constant size across similarly sized displays. In other words,
|
|
1667
|
+
the scaling required to convert framebuffer to client coordinates.
|
|
1668
|
+
|
|
1669
|
+
Returns
|
|
1670
|
+
-------
|
|
1671
|
+
float
|
|
1672
|
+
Scaling factor to be applied along both horizontal and vertical
|
|
1673
|
+
dimensions.
|
|
1674
|
+
|
|
1675
|
+
Examples
|
|
1676
|
+
--------
|
|
1677
|
+
Get the size of the client area::
|
|
1678
|
+
|
|
1679
|
+
clientSize = win.frameBufferSize / win.getContentScaleFactor()
|
|
1680
|
+
|
|
1681
|
+
Get the framebuffer size from the client size::
|
|
1682
|
+
|
|
1683
|
+
frameBufferSize = win.clientSize * win.getContentScaleFactor()
|
|
1684
|
+
|
|
1685
|
+
Convert client (window) to framebuffer pixel coordinates (eg., a mouse
|
|
1686
|
+
coordinate, vertices, etc.)::
|
|
1687
|
+
|
|
1688
|
+
# `mousePosXY` is an array ...
|
|
1689
|
+
frameBufferXY = mousePosXY * win.getContentScaleFactor()
|
|
1690
|
+
# you can also use the attribute ...
|
|
1691
|
+
frameBufferXY = mousePosXY * win.contentScaleFactor
|
|
1692
|
+
|
|
1693
|
+
Notes
|
|
1694
|
+
-----
|
|
1695
|
+
* This value is only valid after the window has been fully realized.
|
|
1696
|
+
|
|
1697
|
+
"""
|
|
1698
|
+
# this might be accessed at lots of points, probably shouldn't compute
|
|
1699
|
+
# this all the time
|
|
1700
|
+
if self._contentScaleFactor is not None:
|
|
1701
|
+
return self._contentScaleFactor
|
|
1702
|
+
|
|
1703
|
+
sx = self.frameBufferSize[0] / float(self.clientSize[0])
|
|
1704
|
+
sy = self.frameBufferSize[1] / float(self.clientSize[1])
|
|
1705
|
+
|
|
1706
|
+
if sx != sy: # messed up DPI settings return 1.0 and show warning
|
|
1707
|
+
self._contentScaleFactor = 1.0
|
|
1708
|
+
else:
|
|
1709
|
+
self._contentScaleFactor = sx
|
|
1710
|
+
|
|
1711
|
+
return self._contentScaleFactor
|
|
1712
|
+
|
|
1713
|
+
@property
|
|
1714
|
+
def contentScaleFactor(self):
|
|
1715
|
+
"""Scaling factor (`float`) to use when drawing to the backbuffer to
|
|
1716
|
+
convert framebuffer to client coordinates.
|
|
1717
|
+
|
|
1718
|
+
See Also
|
|
1719
|
+
--------
|
|
1720
|
+
getContentScaleFactor
|
|
1721
|
+
|
|
1722
|
+
"""
|
|
1723
|
+
return self.getContentScaleFactor()
|
|
1724
|
+
|
|
1725
|
+
@property
|
|
1726
|
+
def aspect(self):
|
|
1727
|
+
"""Aspect ratio of the current viewport (width / height)."""
|
|
1728
|
+
return self._viewport[2] / float(self._viewport[3])
|
|
1729
|
+
|
|
1730
|
+
@property
|
|
1731
|
+
def ambientLight(self):
|
|
1732
|
+
"""Ambient light color for the scene [r, g, b, a]. Values range from 0.0
|
|
1733
|
+
to 1.0. Only applicable if `useLights` is `True`.
|
|
1734
|
+
|
|
1735
|
+
Examples
|
|
1736
|
+
--------
|
|
1737
|
+
Setting the ambient light color::
|
|
1738
|
+
|
|
1739
|
+
win.ambientLight = [0.5, 0.5, 0.5]
|
|
1740
|
+
|
|
1741
|
+
# don't do this!!!
|
|
1742
|
+
win.ambientLight[0] = 0.5
|
|
1743
|
+
win.ambientLight[1] = 0.5
|
|
1744
|
+
win.ambientLight[2] = 0.5
|
|
1745
|
+
|
|
1746
|
+
"""
|
|
1747
|
+
# TODO - use signed color and colorspace instead
|
|
1748
|
+
return self._ambientLight[:3]
|
|
1749
|
+
|
|
1750
|
+
@ambientLight.setter
|
|
1751
|
+
def ambientLight(self, value):
|
|
1752
|
+
self._ambientLight[:3] = value
|
|
1753
|
+
GL.glLightModelfv(GL.GL_LIGHT_MODEL_AMBIENT,
|
|
1754
|
+
numpy.ctypeslib.as_ctypes(self._ambientLight))
|
|
1755
|
+
|
|
1756
|
+
@property
|
|
1757
|
+
def lights(self):
|
|
1758
|
+
"""Scene lights.
|
|
1759
|
+
|
|
1760
|
+
This is specified as an array of `~psychopy.visual.LightSource`
|
|
1761
|
+
objects. If a single value is given, it will be converted to a `list`
|
|
1762
|
+
before setting. Set `useLights` to `True` before rendering to enable
|
|
1763
|
+
lighting/shading on subsequent objects. If `lights` is `None` or an
|
|
1764
|
+
empty `list`, no lights will be enabled if `useLights=True`, however,
|
|
1765
|
+
the scene ambient light set with `ambientLight` will be still be used.
|
|
1766
|
+
|
|
1767
|
+
Examples
|
|
1768
|
+
--------
|
|
1769
|
+
Create a directional light source and add it to scene lights::
|
|
1770
|
+
|
|
1771
|
+
dirLight = gltools.LightSource((0., 1., 0.), lightType='directional')
|
|
1772
|
+
win.lights = dirLight # `win.lights` will be a list when accessed!
|
|
1773
|
+
|
|
1774
|
+
Multiple lights can be specified by passing values as a list::
|
|
1775
|
+
|
|
1776
|
+
myLights = [gltools.LightSource((0., 5., 0.)),
|
|
1777
|
+
gltools.LightSource((-2., -2., 0.))
|
|
1778
|
+
win.lights = myLights
|
|
1779
|
+
|
|
1780
|
+
"""
|
|
1781
|
+
return self._lights
|
|
1782
|
+
|
|
1783
|
+
@lights.setter
|
|
1784
|
+
def lights(self, value):
|
|
1785
|
+
# if None or empty list, disable all lights
|
|
1786
|
+
if value is None or not value:
|
|
1787
|
+
for index in range(self._nLights):
|
|
1788
|
+
GL.glDisable(GL.GL_LIGHT0 + index)
|
|
1789
|
+
|
|
1790
|
+
self._nLights = 0 # set number of lights to zero
|
|
1791
|
+
self._lights = value
|
|
1792
|
+
|
|
1793
|
+
return
|
|
1794
|
+
|
|
1795
|
+
# set the lights and make sure it's a list if a single value was passed
|
|
1796
|
+
self._lights = value if isinstance(value, (list, tuple,)) else [value]
|
|
1797
|
+
|
|
1798
|
+
# disable excess lights if less lights were specified this time
|
|
1799
|
+
oldNumLights = self._nLights
|
|
1800
|
+
self._nLights = len(self._lights) # number of lights enabled
|
|
1801
|
+
if oldNumLights > self._nLights:
|
|
1802
|
+
for index in range(self._nLights, oldNumLights):
|
|
1803
|
+
GL.glDisable(GL.GL_LIGHT0 + index)
|
|
1804
|
+
|
|
1805
|
+
# Setup legacy lights, new spec shader programs should access the
|
|
1806
|
+
# `lights` attribute directly to setup lighting uniforms.
|
|
1807
|
+
# The index of the lights is defined by the order it appears in
|
|
1808
|
+
# `self._lights`.
|
|
1809
|
+
for index, light in enumerate(self._lights):
|
|
1810
|
+
enumLight = GL.GL_LIGHT0 + index
|
|
1811
|
+
|
|
1812
|
+
# convert data in light class to ctypes
|
|
1813
|
+
#pos = numpy.ctypeslib.as_ctypes(light.pos)
|
|
1814
|
+
diffuse = numpy.ctypeslib.as_ctypes(light._diffuseRGB)
|
|
1815
|
+
specular = numpy.ctypeslib.as_ctypes(light._specularRGB)
|
|
1816
|
+
ambient = numpy.ctypeslib.as_ctypes(light._ambientRGB)
|
|
1817
|
+
|
|
1818
|
+
# pass values to OpenGL
|
|
1819
|
+
#GL.glLightfv(enumLight, GL.GL_POSITION, pos)
|
|
1820
|
+
GL.glLightfv(enumLight, GL.GL_DIFFUSE, diffuse)
|
|
1821
|
+
GL.glLightfv(enumLight, GL.GL_SPECULAR, specular)
|
|
1822
|
+
GL.glLightfv(enumLight, GL.GL_AMBIENT, ambient)
|
|
1823
|
+
|
|
1824
|
+
constant, linear, quadratic = light._kAttenuation
|
|
1825
|
+
GL.glLightf(enumLight, GL.GL_CONSTANT_ATTENUATION, constant)
|
|
1826
|
+
GL.glLightf(enumLight, GL.GL_LINEAR_ATTENUATION, linear)
|
|
1827
|
+
GL.glLightf(enumLight, GL.GL_QUADRATIC_ATTENUATION, quadratic)
|
|
1828
|
+
|
|
1829
|
+
# enable the light
|
|
1830
|
+
GL.glEnable(enumLight)
|
|
1831
|
+
|
|
1832
|
+
@property
|
|
1833
|
+
def useLights(self):
|
|
1834
|
+
"""Enable scene lighting.
|
|
1835
|
+
|
|
1836
|
+
Lights will be enabled if using legacy OpenGL lighting. Stimuli using
|
|
1837
|
+
shaders for lighting should check if `useLights` is `True` since this
|
|
1838
|
+
will have no effect on them, and disable or use a no lighting shader
|
|
1839
|
+
instead. Lights will be transformed to the current view matrix upon
|
|
1840
|
+
setting to `True`.
|
|
1841
|
+
|
|
1842
|
+
Lights are transformed by the present `GL_MODELVIEW` matrix. Setting
|
|
1843
|
+
`useLights` will result in their positions being transformed by it.
|
|
1844
|
+
If you want lights to appear at the specified positions in world space,
|
|
1845
|
+
make sure the current matrix defines the view/eye transformation when
|
|
1846
|
+
setting `useLights=True`.
|
|
1847
|
+
|
|
1848
|
+
This flag is reset to `False` at the beginning of each frame. Should be
|
|
1849
|
+
`False` if rendering 2D stimuli or else the colors will be incorrect.
|
|
1850
|
+
"""
|
|
1851
|
+
return self._useLights
|
|
1852
|
+
|
|
1853
|
+
@useLights.setter
|
|
1854
|
+
def useLights(self, value):
|
|
1855
|
+
self._useLights = value
|
|
1856
|
+
|
|
1857
|
+
# DEPRECATED: this is not needed in modern OpenGL
|
|
1858
|
+
|
|
1859
|
+
# # Setup legacy lights, new spec shader programs should access the
|
|
1860
|
+
# # `lights` attribute directly to setup lighting uniforms.
|
|
1861
|
+
# if self._useLights and self._lights:
|
|
1862
|
+
# GL.glEnable(GL.GL_LIGHTING)
|
|
1863
|
+
# # make sure specular lights are computed relative to eye position,
|
|
1864
|
+
# # this is more realistic than the default. Does not affect shaders.
|
|
1865
|
+
# GL.glLightModeli(GL.GL_LIGHT_MODEL_LOCAL_VIEWER, GL.GL_TRUE)
|
|
1866
|
+
|
|
1867
|
+
# # update light positions for current model matrix
|
|
1868
|
+
# for index, light in enumerate(self._lights):
|
|
1869
|
+
# enumLight = GL.GL_LIGHT0 + index
|
|
1870
|
+
# pos = numpy.ctypeslib.as_ctypes(light.pos)
|
|
1871
|
+
# GL.glLightfv(enumLight, GL.GL_POSITION, pos)
|
|
1872
|
+
# else:
|
|
1873
|
+
# # disable lights
|
|
1874
|
+
# GL.glDisable(GL.GL_LIGHTING)
|
|
1875
|
+
|
|
1876
|
+
def updateLights(self, index=None):
|
|
1877
|
+
"""Explicitly update scene lights if they were modified.
|
|
1878
|
+
|
|
1879
|
+
This is required if modifications to objects referenced in `lights` have
|
|
1880
|
+
been changed since assignment. If you removed or added items of `lights`
|
|
1881
|
+
you must refresh all of them.
|
|
1882
|
+
|
|
1883
|
+
Parameters
|
|
1884
|
+
----------
|
|
1885
|
+
index : int, optional
|
|
1886
|
+
Index of light source in `lights` to update. If `None`, all lights
|
|
1887
|
+
will be refreshed.
|
|
1888
|
+
|
|
1889
|
+
Examples
|
|
1890
|
+
--------
|
|
1891
|
+
Call `updateLights` if you modified lights directly like this::
|
|
1892
|
+
|
|
1893
|
+
win.lights[1].diffuseColor = [1., 0., 0.]
|
|
1894
|
+
win.updateLights(1)
|
|
1895
|
+
|
|
1896
|
+
"""
|
|
1897
|
+
if self._lights is None:
|
|
1898
|
+
return # nop if there are no lights
|
|
1899
|
+
|
|
1900
|
+
if index is None:
|
|
1901
|
+
self.lights = self._lights
|
|
1902
|
+
else:
|
|
1903
|
+
if index > len(self._lights) - 1:
|
|
1904
|
+
raise IndexError('Invalid index for `lights`.')
|
|
1905
|
+
|
|
1906
|
+
enumLight = GL.GL_LIGHT0 + index
|
|
1907
|
+
|
|
1908
|
+
# light object to modify
|
|
1909
|
+
light = self._lights[index]
|
|
1910
|
+
|
|
1911
|
+
# convert data in light class to ctypes
|
|
1912
|
+
# pos = numpy.ctypeslib.as_ctypes(light.pos)
|
|
1913
|
+
diffuse = numpy.ctypeslib.as_ctypes(light.diffuse)
|
|
1914
|
+
specular = numpy.ctypeslib.as_ctypes(light.specular)
|
|
1915
|
+
ambient = numpy.ctypeslib.as_ctypes(light.ambient)
|
|
1916
|
+
|
|
1917
|
+
# pass values to OpenGL
|
|
1918
|
+
# GL.glLightfv(enumLight, GL.GL_POSITION, pos)
|
|
1919
|
+
GL.glLightfv(enumLight, GL.GL_DIFFUSE, diffuse)
|
|
1920
|
+
GL.glLightfv(enumLight, GL.GL_SPECULAR, specular)
|
|
1921
|
+
GL.glLightfv(enumLight, GL.GL_AMBIENT, ambient)
|
|
1922
|
+
|
|
1923
|
+
def resetViewport(self):
|
|
1924
|
+
"""Reset the viewport to cover the whole framebuffer.
|
|
1925
|
+
|
|
1926
|
+
Set the viewport to match the dimensions of the back buffer or
|
|
1927
|
+
framebuffer (if `useFBO=True`). The scissor rectangle is also set to
|
|
1928
|
+
match the dimensions of the viewport.
|
|
1929
|
+
|
|
1930
|
+
"""
|
|
1931
|
+
# use the framebuffer size here, not the window size (hi-dpi compat)
|
|
1932
|
+
bufferWidth, bufferHeight = self.frameBufferSize
|
|
1933
|
+
self.scissor = self.viewport = [0, 0, bufferWidth, bufferHeight]
|
|
1934
|
+
|
|
1935
|
+
@property
|
|
1936
|
+
def viewport(self):
|
|
1937
|
+
"""Viewport rectangle (x, y, w, h) for the current draw buffer.
|
|
1938
|
+
|
|
1939
|
+
Values `x` and `y` define the origin, and `w` and `h` the size of the
|
|
1940
|
+
rectangle in pixels.
|
|
1941
|
+
|
|
1942
|
+
This is typically set to cover the whole buffer, however it can be
|
|
1943
|
+
changed for applications like multi-view rendering. Stimuli will draw
|
|
1944
|
+
according to the new shape of the viewport, for instance and stimulus
|
|
1945
|
+
with position (0, 0) will be drawn at the center of the viewport, not
|
|
1946
|
+
the window.
|
|
1947
|
+
|
|
1948
|
+
Examples
|
|
1949
|
+
--------
|
|
1950
|
+
Constrain drawing to the left and right halves of the screen, where
|
|
1951
|
+
stimuli will be drawn centered on the new rectangle. Note that you need
|
|
1952
|
+
to set both the `viewport` and the `scissor` rectangle::
|
|
1953
|
+
|
|
1954
|
+
x, y, w, h = win.frameBufferSize # size of the framebuffer
|
|
1955
|
+
win.viewport = win.scissor = [x, y, w / 2.0, h]
|
|
1956
|
+
# draw left stimuli ...
|
|
1957
|
+
|
|
1958
|
+
win.viewport = win.scissor = [x + (w / 2.0), y, w / 2.0, h]
|
|
1959
|
+
# draw right stimuli ...
|
|
1960
|
+
|
|
1961
|
+
# restore drawing to the whole screen
|
|
1962
|
+
win.viewport = win.scissor = [x, y, w, h]
|
|
1963
|
+
|
|
1964
|
+
"""
|
|
1965
|
+
return self._viewport
|
|
1966
|
+
|
|
1967
|
+
@viewport.setter
|
|
1968
|
+
def viewport(self, value):
|
|
1969
|
+
self._viewport = numpy.array(value, int)
|
|
1970
|
+
GL.glViewport(*self._viewport)
|
|
1971
|
+
|
|
1972
|
+
@property
|
|
1973
|
+
def scissor(self):
|
|
1974
|
+
"""Scissor rectangle (x, y, w, h) for the current draw buffer.
|
|
1975
|
+
|
|
1976
|
+
Values `x` and `y` define the origin, and `w` and `h` the size
|
|
1977
|
+
of the rectangle in pixels. The scissor operation is only active
|
|
1978
|
+
if `scissorTest=True`.
|
|
1979
|
+
|
|
1980
|
+
Usually, the scissor and viewport are set to the same rectangle
|
|
1981
|
+
to prevent drawing operations from `spilling` into other regions
|
|
1982
|
+
of the screen. For instance, calling `clearBuffer` will only
|
|
1983
|
+
clear within the scissor rectangle.
|
|
1984
|
+
|
|
1985
|
+
Setting the scissor rectangle but not the viewport will restrict
|
|
1986
|
+
drawing within the defined region (like a rectangular aperture),
|
|
1987
|
+
not changing the positions of stimuli.
|
|
1988
|
+
|
|
1989
|
+
"""
|
|
1990
|
+
return self._scissor
|
|
1991
|
+
|
|
1992
|
+
@scissor.setter
|
|
1993
|
+
def scissor(self, value):
|
|
1994
|
+
self._scissor = numpy.array(value, int)
|
|
1995
|
+
GL.glScissor(*self._scissor)
|
|
1996
|
+
|
|
1997
|
+
@property
|
|
1998
|
+
def scissorTest(self):
|
|
1999
|
+
"""`True` if scissor testing is enabled."""
|
|
2000
|
+
return self._scissorTest
|
|
2001
|
+
|
|
2002
|
+
@scissorTest.setter
|
|
2003
|
+
def scissorTest(self, value):
|
|
2004
|
+
if value is True:
|
|
2005
|
+
GL.glEnable(GL.GL_SCISSOR_TEST)
|
|
2006
|
+
elif value is False:
|
|
2007
|
+
GL.glDisable(GL.GL_SCISSOR_TEST)
|
|
2008
|
+
else:
|
|
2009
|
+
raise TypeError("Value must be boolean.")
|
|
2010
|
+
|
|
2011
|
+
self._scissorTest = value
|
|
2012
|
+
|
|
2013
|
+
@property
|
|
2014
|
+
def stencilTest(self):
|
|
2015
|
+
"""`True` if stencil testing is enabled."""
|
|
2016
|
+
return self._stencilTest
|
|
2017
|
+
|
|
2018
|
+
@stencilTest.setter
|
|
2019
|
+
def stencilTest(self, value):
|
|
2020
|
+
if value is True:
|
|
2021
|
+
GL.glEnable(GL.GL_STENCIL_TEST)
|
|
2022
|
+
elif value is False:
|
|
2023
|
+
GL.glDisable(GL.GL_STENCIL_TEST)
|
|
2024
|
+
else:
|
|
2025
|
+
raise TypeError("Value must be boolean.")
|
|
2026
|
+
|
|
2027
|
+
self._stencilTest = value
|
|
2028
|
+
|
|
2029
|
+
@property
|
|
2030
|
+
def nearClip(self):
|
|
2031
|
+
"""Distance to the near clipping plane in meters."""
|
|
2032
|
+
return self._nearClip
|
|
2033
|
+
|
|
2034
|
+
@nearClip.setter
|
|
2035
|
+
def nearClip(self, value):
|
|
2036
|
+
self._nearClip = value
|
|
2037
|
+
|
|
2038
|
+
@property
|
|
2039
|
+
def farClip(self):
|
|
2040
|
+
"""Distance to the far clipping plane in meters."""
|
|
2041
|
+
return self._farClip
|
|
2042
|
+
|
|
2043
|
+
@farClip.setter
|
|
2044
|
+
def farClip(self, value):
|
|
2045
|
+
self._farClip = value
|
|
2046
|
+
|
|
2047
|
+
@property
|
|
2048
|
+
def projectionMatrix(self):
|
|
2049
|
+
"""Projection matrix defined as a 4x4 numpy array."""
|
|
2050
|
+
return self._projectionMatrix
|
|
2051
|
+
|
|
2052
|
+
@projectionMatrix.setter
|
|
2053
|
+
def projectionMatrix(self, value):
|
|
2054
|
+
self._projectionMatrix = numpy.asarray(value, numpy.float32)
|
|
2055
|
+
assert self._projectionMatrix.shape == (4, 4)
|
|
2056
|
+
|
|
2057
|
+
@property
|
|
2058
|
+
def viewMatrix(self):
|
|
2059
|
+
"""View matrix defined as a 4x4 numpy array."""
|
|
2060
|
+
return self._viewMatrix
|
|
2061
|
+
|
|
2062
|
+
@viewMatrix.setter
|
|
2063
|
+
def viewMatrix(self, value):
|
|
2064
|
+
self._viewMatrix = numpy.asarray(value, numpy.float32)
|
|
2065
|
+
assert self._viewMatrix.shape == (4, 4)
|
|
2066
|
+
|
|
2067
|
+
@property
|
|
2068
|
+
def eyeOffset(self):
|
|
2069
|
+
"""Eye offset in centimeters.
|
|
2070
|
+
|
|
2071
|
+
This value is used by `setPerspectiveView` to apply a lateral
|
|
2072
|
+
offset to the view, therefore it must be set prior to calling it. Use a
|
|
2073
|
+
positive offset for the right eye, and a negative one for the left.
|
|
2074
|
+
Offsets should be the distance to from the middle of the face to the
|
|
2075
|
+
center of the eye, or half the inter-ocular distance.
|
|
2076
|
+
|
|
2077
|
+
"""
|
|
2078
|
+
return self._eyeOffset * 100.0
|
|
2079
|
+
|
|
2080
|
+
@eyeOffset.setter
|
|
2081
|
+
def eyeOffset(self, value):
|
|
2082
|
+
self._eyeOffset = value / 100.0
|
|
2083
|
+
|
|
2084
|
+
@property
|
|
2085
|
+
def convergeOffset(self):
|
|
2086
|
+
"""Convergence offset from monitor in centimeters.
|
|
2087
|
+
|
|
2088
|
+
This is value corresponds to the offset from screen plane to set the
|
|
2089
|
+
convergence plane (or point for `toe-in` projections). Positive offsets
|
|
2090
|
+
move the plane farther away from the viewer, while negative offsets
|
|
2091
|
+
nearer. This value is used by `setPerspectiveView` and should be set
|
|
2092
|
+
before calling it to take effect.
|
|
2093
|
+
|
|
2094
|
+
Notes
|
|
2095
|
+
-----
|
|
2096
|
+
* This value is only applicable for `setToeIn` and `setOffAxisView`.
|
|
2097
|
+
|
|
2098
|
+
"""
|
|
2099
|
+
return self._convergeOffset * 100.0
|
|
2100
|
+
|
|
2101
|
+
@convergeOffset.setter
|
|
2102
|
+
def convergeOffset(self, value):
|
|
2103
|
+
self._convergeOffset = value / 100.0
|
|
2104
|
+
|
|
2105
|
+
def _clearDepthBuffer(self):
|
|
2106
|
+
"""Clear the depth buffer.
|
|
2107
|
+
"""
|
|
2108
|
+
oldDepthMask = self.depthMask
|
|
2109
|
+
GL.glDepthMask(GL.GL_TRUE)
|
|
2110
|
+
GL.glClear(GL.GL_DEPTH_BUFFER_BIT)
|
|
2111
|
+
|
|
2112
|
+
if oldDepthMask is False: # return to old state if needed
|
|
2113
|
+
GL.glDepthMask(GL.GL_FALSE)
|
|
2114
|
+
|
|
2115
|
+
def setOffAxisView(self, applyTransform=True, clearDepth=True):
|
|
2116
|
+
"""Set an off-axis projection.
|
|
2117
|
+
|
|
2118
|
+
Create an off-axis projection for subsequent rendering calls. Sets the
|
|
2119
|
+
`viewMatrix` and `projectionMatrix` accordingly so the scene origin is
|
|
2120
|
+
on the screen plane. If `eyeOffset` is correct and the view distance and
|
|
2121
|
+
screen size is defined in the monitor configuration, the resulting view
|
|
2122
|
+
will approximate `ortho-stereo` viewing.
|
|
2123
|
+
|
|
2124
|
+
The convergence plane can be adjusted by setting `convergeOffset`. By
|
|
2125
|
+
default, the convergence plane is set to the screen plane. Any points
|
|
2126
|
+
on the screen plane will have zero disparity.
|
|
2127
|
+
|
|
2128
|
+
Parameters
|
|
2129
|
+
----------
|
|
2130
|
+
applyTransform : bool
|
|
2131
|
+
Apply transformations after computing them in immediate mode. Same
|
|
2132
|
+
as calling :py:attr:`~Window.applyEyeTransform()` afterwards.
|
|
2133
|
+
clearDepth : bool, optional
|
|
2134
|
+
Clear the depth buffer.
|
|
2135
|
+
|
|
2136
|
+
"""
|
|
2137
|
+
scrDistM = 0.5 if self.scrDistCM is None else self.scrDistCM / 100.0
|
|
2138
|
+
scrWidthM = 0.5 if self.scrWidthCM is None else self.scrWidthCM / 100.0
|
|
2139
|
+
|
|
2140
|
+
# Not in full screen mode? Need to compute the dimensions of the display
|
|
2141
|
+
# area to ensure disparities are correct even when in windowed-mode.
|
|
2142
|
+
aspect = self.size[0] / self.size[1]
|
|
2143
|
+
if not self._isFullScr:
|
|
2144
|
+
scrWidthM = (self.size[0] / self.scrWidthPIX) * scrWidthM
|
|
2145
|
+
|
|
2146
|
+
frustum = viewtools.computeFrustum(
|
|
2147
|
+
scrWidthM, # width of screen
|
|
2148
|
+
aspect, # aspect ratio
|
|
2149
|
+
scrDistM, # distance to screen
|
|
2150
|
+
eyeOffset=self._eyeOffset,
|
|
2151
|
+
convergeOffset=self._convergeOffset,
|
|
2152
|
+
nearClip=self._nearClip,
|
|
2153
|
+
farClip=self._farClip)
|
|
2154
|
+
|
|
2155
|
+
self._projectionMatrix = viewtools.perspectiveProjectionMatrix(*frustum)
|
|
2156
|
+
|
|
2157
|
+
# translate away from screen
|
|
2158
|
+
self._viewMatrix = numpy.identity(4, dtype=numpy.float32)
|
|
2159
|
+
self._viewMatrix[0, 3] = -self._eyeOffset # apply eye offset
|
|
2160
|
+
self._viewMatrix[2, 3] = -scrDistM # displace scene away from viewer
|
|
2161
|
+
|
|
2162
|
+
if applyTransform:
|
|
2163
|
+
self.applyEyeTransform(clearDepth=clearDepth)
|
|
2164
|
+
|
|
2165
|
+
def setToeInView(self, applyTransform=True, clearDepth=True):
|
|
2166
|
+
"""Set toe-in projection.
|
|
2167
|
+
|
|
2168
|
+
Create a toe-in projection for subsequent rendering calls. Sets the
|
|
2169
|
+
`viewMatrix` and `projectionMatrix` accordingly so the scene origin is
|
|
2170
|
+
on the screen plane. The value of `convergeOffset` will define the
|
|
2171
|
+
convergence point of the view, which is offset perpendicular to the
|
|
2172
|
+
center of the screen plane. Points falling on a vertical line at the
|
|
2173
|
+
convergence point will have zero disparity.
|
|
2174
|
+
|
|
2175
|
+
Parameters
|
|
2176
|
+
----------
|
|
2177
|
+
applyTransform : bool
|
|
2178
|
+
Apply transformations after computing them in immediate mode. Same
|
|
2179
|
+
as calling :py:attr:`~Window.applyEyeTransform()` afterwards.
|
|
2180
|
+
clearDepth : bool, optional
|
|
2181
|
+
Clear the depth buffer.
|
|
2182
|
+
|
|
2183
|
+
Notes
|
|
2184
|
+
-----
|
|
2185
|
+
* This projection mode is only 'correct' if the viewer's eyes are
|
|
2186
|
+
converged at the convergence point. Due to perspective, this
|
|
2187
|
+
projection introduces vertical disparities which increase in magnitude
|
|
2188
|
+
with eccentricity. Use `setOffAxisView` if you want to display
|
|
2189
|
+
something the viewer can look around the screen comfortably.
|
|
2190
|
+
|
|
2191
|
+
"""
|
|
2192
|
+
scrDistM = 0.5 if self.scrDistCM is None else self.scrDistCM / 100.0
|
|
2193
|
+
scrWidthM = 0.5 if self.scrWidthCM is None else self.scrWidthCM / 100.0
|
|
2194
|
+
|
|
2195
|
+
# Not in full screen mode? Need to compute the dimensions of the display
|
|
2196
|
+
# area to ensure disparities are correct even when in windowed-mode.
|
|
2197
|
+
aspect = self.size[0] / self.size[1]
|
|
2198
|
+
if not self._isFullScr:
|
|
2199
|
+
scrWidthM = (self.size[0] / self.scrWidthPIX) * scrWidthM
|
|
2200
|
+
|
|
2201
|
+
frustum = viewtools.computeFrustum(
|
|
2202
|
+
scrWidthM, # width of screen
|
|
2203
|
+
aspect, # aspect ratio
|
|
2204
|
+
scrDistM, # distance to screen
|
|
2205
|
+
nearClip=self._nearClip,
|
|
2206
|
+
farClip=self._farClip)
|
|
2207
|
+
|
|
2208
|
+
self._projectionMatrix = viewtools.perspectiveProjectionMatrix(*frustum)
|
|
2209
|
+
|
|
2210
|
+
# translate away from screen
|
|
2211
|
+
eyePos = (self._eyeOffset, 0.0, scrDistM)
|
|
2212
|
+
convergePoint = (0.0, 0.0, self.convergeOffset)
|
|
2213
|
+
self._viewMatrix = viewtools.lookAt(eyePos, convergePoint)
|
|
2214
|
+
|
|
2215
|
+
if applyTransform:
|
|
2216
|
+
self.applyEyeTransform(clearDepth=clearDepth)
|
|
2217
|
+
|
|
2218
|
+
def setPerspectiveView(self, applyTransform=True, clearDepth=True):
|
|
2219
|
+
"""Set the projection and view matrix to render with perspective.
|
|
2220
|
+
|
|
2221
|
+
Matrices are computed using values specified in the monitor
|
|
2222
|
+
configuration with the scene origin on the screen plane. Calculations
|
|
2223
|
+
assume units are in meters. If `eyeOffset != 0`, the view will be
|
|
2224
|
+
transformed laterally, however the frustum shape will remain the
|
|
2225
|
+
same.
|
|
2226
|
+
|
|
2227
|
+
Note that the values of :py:attr:`~Window.projectionMatrix` and
|
|
2228
|
+
:py:attr:`~Window.viewMatrix` will be replaced when calling this
|
|
2229
|
+
function.
|
|
2230
|
+
|
|
2231
|
+
Parameters
|
|
2232
|
+
----------
|
|
2233
|
+
applyTransform : bool
|
|
2234
|
+
Apply transformations after computing them in immediate mode. Same
|
|
2235
|
+
as calling :py:attr:`~Window.applyEyeTransform()` afterwards if
|
|
2236
|
+
`False`.
|
|
2237
|
+
clearDepth : bool, optional
|
|
2238
|
+
Clear the depth buffer.
|
|
2239
|
+
|
|
2240
|
+
"""
|
|
2241
|
+
# NB - we should eventually compute these matrices lazily since they may
|
|
2242
|
+
# not change over the course of an experiment under most circumstances.
|
|
2243
|
+
#
|
|
2244
|
+
scrDistM = 0.5 if self.scrDistCM is None else self.scrDistCM / 100.0
|
|
2245
|
+
scrWidthM = 0.5 if self.scrWidthCM is None else self.scrWidthCM / 100.0
|
|
2246
|
+
|
|
2247
|
+
# Not in full screen mode? Need to compute the dimensions of the display
|
|
2248
|
+
# area to ensure disparities are correct even when in windowed-mode.
|
|
2249
|
+
aspect = self.size[0] / self.size[1]
|
|
2250
|
+
if not self._isFullScr:
|
|
2251
|
+
scrWidthM = (self.size[0] / self.scrWidthPIX) * scrWidthM
|
|
2252
|
+
|
|
2253
|
+
frustum = viewtools.computeFrustum(
|
|
2254
|
+
scrWidthM, # width of screen
|
|
2255
|
+
aspect, # aspect ratio
|
|
2256
|
+
scrDistM, # distance to screen
|
|
2257
|
+
nearClip=self._nearClip,
|
|
2258
|
+
farClip=self._farClip)
|
|
2259
|
+
|
|
2260
|
+
self._projectionMatrix = \
|
|
2261
|
+
viewtools.perspectiveProjectionMatrix(*frustum, dtype=numpy.float32)
|
|
2262
|
+
|
|
2263
|
+
# translate away from screen
|
|
2264
|
+
self._viewMatrix = numpy.identity(4, dtype=numpy.float32)
|
|
2265
|
+
self._viewMatrix[0, 3] = -self._eyeOffset # apply eye offset
|
|
2266
|
+
self._viewMatrix[2, 3] = -scrDistM # displace scene away from viewer
|
|
2267
|
+
|
|
2268
|
+
if applyTransform:
|
|
2269
|
+
self.applyEyeTransform(clearDepth=clearDepth)
|
|
2270
|
+
|
|
2271
|
+
def setDefaultView(self, applyTransform=True, clearDepth=True):
|
|
2272
|
+
"""Set the projection and view matrix to PsychoPy's default.
|
|
2273
|
+
|
|
2274
|
+
This is the mode which is typically used for rendering 2D stimuli. It should
|
|
2275
|
+
be called prior to rendering any 2D stimuli if the projection has been
|
|
2276
|
+
changed.
|
|
2277
|
+
|
|
2278
|
+
"""
|
|
2279
|
+
self._updateViewMatrix()
|
|
2280
|
+
self._updateProjectionMatrix()
|
|
2281
|
+
|
|
2282
|
+
if applyTransform:
|
|
2283
|
+
self.applyEyeTransform(clearDepth=clearDepth)
|
|
2284
|
+
|
|
2285
|
+
def setOrthographicView(self, applyTransform=True, clearDepth=True):
|
|
2286
|
+
"""Set the projection and view matrix to render with orthographic view.
|
|
2287
|
+
|
|
2288
|
+
Orthographic projection is used to render 3D objects without perspective
|
|
2289
|
+
distortion. The scene origin is centered on the screen plane. The
|
|
2290
|
+
frustum is defined by the size of the window in pixels, with the origin
|
|
2291
|
+
at the center of the window. 2D stimuli are typically drawn using this
|
|
2292
|
+
projection.
|
|
2293
|
+
|
|
2294
|
+
Note that the values of :py:attr:`~Window.projectionMatrix` and
|
|
2295
|
+
:py:attr:`~Window.viewMatrix` will be replaced when calling this
|
|
2296
|
+
function.
|
|
2297
|
+
|
|
2298
|
+
Parameters
|
|
2299
|
+
----------
|
|
2300
|
+
applyTransform : bool
|
|
2301
|
+
Apply transformations after computing them in immediate mode. Same
|
|
2302
|
+
as calling :py:attr:`~Window.applyEyeTransform()` afterwards if
|
|
2303
|
+
`False`.
|
|
2304
|
+
clearDepth : bool, optional
|
|
2305
|
+
Clear the depth buffer.
|
|
2306
|
+
|
|
2307
|
+
"""
|
|
2308
|
+
self._updateViewMatrix()
|
|
2309
|
+
|
|
2310
|
+
widthOver2 = self.size[0] / 2.0
|
|
2311
|
+
heightOver2 = self.size[1] / 2.0
|
|
2312
|
+
self._projectionMatrix[:, :] = viewtools.orthoProjectionMatrix(
|
|
2313
|
+
-widthOver2, widthOver2, # -X, +X
|
|
2314
|
+
-heightOver2, heightOver2, # -Y, +Y
|
|
2315
|
+
-1.0, 1.0, # -Z, +Z
|
|
2316
|
+
dtype=numpy.float32)
|
|
2317
|
+
self._projectionMatrix[:, :] = numpy.identity(4, dtype=numpy.float32)
|
|
2318
|
+
|
|
2319
|
+
if applyTransform:
|
|
2320
|
+
self.applyEyeTransform(clearDepth=clearDepth)
|
|
2321
|
+
|
|
2322
|
+
def applyEyeTransform(self, clearDepth=True):
|
|
2323
|
+
"""Apply the current view and projection matrices.
|
|
2324
|
+
|
|
2325
|
+
Matrices specified by attributes :py:attr:`~Window.viewMatrix` and
|
|
2326
|
+
:py:attr:`~Window.projectionMatrix` are applied using 'immediate mode'
|
|
2327
|
+
OpenGL functions. Subsequent drawing operations will be affected until
|
|
2328
|
+
:py:attr:`~Window.flip()` is called.
|
|
2329
|
+
|
|
2330
|
+
All transformations in ``GL_PROJECTION`` and ``GL_MODELVIEW`` matrix
|
|
2331
|
+
stacks will be cleared (set to identity) prior to applying. After this
|
|
2332
|
+
is called, the current matrix mode will be set to ``GL_MODELVIEW``.
|
|
2333
|
+
|
|
2334
|
+
Parameters
|
|
2335
|
+
----------
|
|
2336
|
+
clearDepth : bool
|
|
2337
|
+
Clear the depth buffer. This may be required prior to rendering 3D
|
|
2338
|
+
objects.
|
|
2339
|
+
|
|
2340
|
+
Examples
|
|
2341
|
+
--------
|
|
2342
|
+
Using a custom view and projection matrix::
|
|
2343
|
+
|
|
2344
|
+
# Must be called every frame since these values are reset after
|
|
2345
|
+
# `flip()` is called!
|
|
2346
|
+
win.viewMatrix = viewtools.lookAt( ... )
|
|
2347
|
+
win.projectionMatrix = viewtools.perspectiveProjectionMatrix( ... )
|
|
2348
|
+
win.applyEyeTransform()
|
|
2349
|
+
# draw 3D objects here ...
|
|
2350
|
+
|
|
2351
|
+
"""
|
|
2352
|
+
if self.USE_LEGACY_GL:
|
|
2353
|
+
# apply the projection and view transformations
|
|
2354
|
+
GL.glMatrixMode(GL.GL_PROJECTION)
|
|
2355
|
+
GL.glLoadIdentity()
|
|
2356
|
+
projMat = self._projectionMatrix.ctypes.data_as(
|
|
2357
|
+
ctypes.POINTER(ctypes.c_float))
|
|
2358
|
+
GL.glMultTransposeMatrixf(projMat)
|
|
2359
|
+
|
|
2360
|
+
GL.glMatrixMode(GL.GL_MODELVIEW)
|
|
2361
|
+
GL.glLoadIdentity()
|
|
2362
|
+
viewMat = self._viewMatrix.ctypes.data_as(
|
|
2363
|
+
ctypes.POINTER(ctypes.c_float))
|
|
2364
|
+
GL.glMultTransposeMatrixf(viewMat)
|
|
2365
|
+
|
|
2366
|
+
oldDepthMask = self.depthMask
|
|
2367
|
+
if clearDepth:
|
|
2368
|
+
GL.glDepthMask(GL.GL_TRUE)
|
|
2369
|
+
GL.glClear(GL.GL_DEPTH_BUFFER_BIT)
|
|
2370
|
+
|
|
2371
|
+
if oldDepthMask is False: # return to old state if needed
|
|
2372
|
+
GL.glDepthMask(GL.GL_FALSE)
|
|
2373
|
+
|
|
2374
|
+
def resetEyeTransform(self, clearDepth=True):
|
|
2375
|
+
"""Restore the default projection and view settings to PsychoPy
|
|
2376
|
+
defaults. Call this prior to drawing 2D stimuli objects (i.e.
|
|
2377
|
+
GratingStim, ImageStim, Rect, etc.) if any eye transformations were
|
|
2378
|
+
applied for the stimuli to be drawn correctly.
|
|
2379
|
+
|
|
2380
|
+
Parameters
|
|
2381
|
+
----------
|
|
2382
|
+
clearDepth : bool
|
|
2383
|
+
Clear the depth buffer upon reset. This ensures successive draw
|
|
2384
|
+
commands are not affected by previous data written to the depth
|
|
2385
|
+
buffer. Default is `True`.
|
|
2386
|
+
|
|
2387
|
+
Notes
|
|
2388
|
+
-----
|
|
2389
|
+
* Calling :py:attr:`~Window.flip()` automatically resets the view and
|
|
2390
|
+
projection to defaults. So you don't need to call this unless you are
|
|
2391
|
+
mixing 3D and 2D stimuli.
|
|
2392
|
+
|
|
2393
|
+
Examples
|
|
2394
|
+
--------
|
|
2395
|
+
Going between 3D and 2D stimuli::
|
|
2396
|
+
|
|
2397
|
+
# 2D stimuli can be drawn before setting a perspective projection
|
|
2398
|
+
win.setPerspectiveView()
|
|
2399
|
+
# draw 3D stimuli here ...
|
|
2400
|
+
win.resetEyeTransform()
|
|
2401
|
+
# 2D stimuli can be drawn here again ...
|
|
2402
|
+
win.flip()
|
|
2403
|
+
|
|
2404
|
+
"""
|
|
2405
|
+
self.setOrthographicView(clearDepth)
|
|
2406
|
+
|
|
2407
|
+
if self.USE_LEGACY_GL:
|
|
2408
|
+
self.applyEyeTransform(clearDepth)
|
|
2409
|
+
|
|
2410
|
+
def coordToRay(self, screenXY):
|
|
2411
|
+
"""Convert a screen coordinate to a direction vector.
|
|
2412
|
+
|
|
2413
|
+
Takes a screen/window coordinate and computes a vector which projects
|
|
2414
|
+
a ray from the viewpoint through it (line-of-sight). Any 3D point
|
|
2415
|
+
touching the ray will appear at the screen coordinate.
|
|
2416
|
+
|
|
2417
|
+
Uses the current `viewport` and `projectionMatrix` to calculate the
|
|
2418
|
+
vector. The vector is in eye-space, where the origin of the scene is
|
|
2419
|
+
centered at the viewpoint and the forward direction aligned with the -Z
|
|
2420
|
+
axis. A ray of (0, 0, -1) results from a point at the very center of the
|
|
2421
|
+
screen assuming symmetric frustums.
|
|
2422
|
+
|
|
2423
|
+
Note that if you are using a flipped/mirrored view, you must invert your
|
|
2424
|
+
supplied screen coordinates (`screenXY`) prior to passing them to this
|
|
2425
|
+
function.
|
|
2426
|
+
|
|
2427
|
+
Parameters
|
|
2428
|
+
----------
|
|
2429
|
+
screenXY : array_like
|
|
2430
|
+
X, Y screen coordinate. Must be in units of the window.
|
|
2431
|
+
|
|
2432
|
+
Returns
|
|
2433
|
+
-------
|
|
2434
|
+
ndarray
|
|
2435
|
+
Normalized direction vector [x, y, z].
|
|
2436
|
+
|
|
2437
|
+
Examples
|
|
2438
|
+
--------
|
|
2439
|
+
Getting the direction vector between the mouse cursor and the eye::
|
|
2440
|
+
|
|
2441
|
+
mx, my = mouse.getPos()
|
|
2442
|
+
dir = win.coordToRay((mx, my))
|
|
2443
|
+
|
|
2444
|
+
Set the position of a 3D stimulus object using the mouse, constrained to
|
|
2445
|
+
a plane. The object origin will always be at the screen coordinate of
|
|
2446
|
+
the mouse cursor::
|
|
2447
|
+
|
|
2448
|
+
# the eye position in the scene is defined by a rigid body pose
|
|
2449
|
+
win.viewMatrix = camera.getViewMatrix()
|
|
2450
|
+
win.applyEyeTransform()
|
|
2451
|
+
|
|
2452
|
+
# get the mouse location and calculate the intercept
|
|
2453
|
+
mx, my = mouse.getPos()
|
|
2454
|
+
ray = win.coordToRay([mx, my])
|
|
2455
|
+
result = intersectRayPlane( # from mathtools
|
|
2456
|
+
orig=camera.pos,
|
|
2457
|
+
dir=camera.transformNormal(ray),
|
|
2458
|
+
planeOrig=(0, 0, -10),
|
|
2459
|
+
planeNormal=(0, 1, 0))
|
|
2460
|
+
|
|
2461
|
+
# if result is `None`, there is no intercept
|
|
2462
|
+
if result is not None:
|
|
2463
|
+
pos, dist = result
|
|
2464
|
+
objModel.thePose.pos = pos
|
|
2465
|
+
else:
|
|
2466
|
+
objModel.thePose.pos = (0, 0, -10) # plane origin
|
|
2467
|
+
|
|
2468
|
+
If you don't define the position of the viewer with a `RigidBodyPose`,
|
|
2469
|
+
you can obtain the appropriate eye position and rotate the ray by doing
|
|
2470
|
+
the following::
|
|
2471
|
+
|
|
2472
|
+
pos = numpy.linalg.inv(win.viewMatrix)[:3, 3]
|
|
2473
|
+
ray = win.coordToRay([mx, my]).dot(win.viewMatrix[:3, :3])
|
|
2474
|
+
# then ...
|
|
2475
|
+
result = intersectRayPlane(
|
|
2476
|
+
orig=pos,
|
|
2477
|
+
dir=ray,
|
|
2478
|
+
planeOrig=(0, 0, -10),
|
|
2479
|
+
planeNormal=(0, 1, 0))
|
|
2480
|
+
|
|
2481
|
+
"""
|
|
2482
|
+
# put in units of pixels
|
|
2483
|
+
if self.units == 'pix':
|
|
2484
|
+
scrX, scrY = numpy.asarray(screenXY, numpy.float32)
|
|
2485
|
+
else:
|
|
2486
|
+
scrX, scrY = convertToPix(numpy.asarray([0, 0]),
|
|
2487
|
+
numpy.asarray(screenXY),
|
|
2488
|
+
units=self.units,
|
|
2489
|
+
win=self)[:2]
|
|
2490
|
+
|
|
2491
|
+
# transform psychopy mouse coordinates to viewport coordinates
|
|
2492
|
+
scrX += (self.size[0] / 2.)
|
|
2493
|
+
scrY += (self.size[1] / 2.)
|
|
2494
|
+
|
|
2495
|
+
# get the NDC coordinates of the
|
|
2496
|
+
projX = 2. * (scrX - self.viewport[0]) / self.viewport[2] - 1.
|
|
2497
|
+
projY = 2. * (scrY - self.viewport[1]) / self.viewport[3] - 1.
|
|
2498
|
+
|
|
2499
|
+
vecNear = numpy.array((projX, projY, 0., 1.), dtype=numpy.float32)
|
|
2500
|
+
vecFar = numpy.array((projX, projY, 1., 1.), dtype=numpy.float32)
|
|
2501
|
+
|
|
2502
|
+
# compute the inverse projection matrix
|
|
2503
|
+
invPM = numpy.linalg.inv(self.projectionMatrix)
|
|
2504
|
+
|
|
2505
|
+
vecNear[:] = vecNear.dot(invPM.T)
|
|
2506
|
+
vecFar[:] = vecFar.dot(invPM.T)
|
|
2507
|
+
|
|
2508
|
+
vecNear /= vecNear[3]
|
|
2509
|
+
vecFar /= vecFar[3]
|
|
2510
|
+
|
|
2511
|
+
# direction vector, get rid of `w`
|
|
2512
|
+
dirVec = vecFar[:3] - vecNear[:3]
|
|
2513
|
+
|
|
2514
|
+
return dirVec / numpy.linalg.norm(dirVec)
|
|
2515
|
+
|
|
2516
|
+
def getMovieFrame(self, buffer='front'):
|
|
2517
|
+
"""Capture the current Window as an image.
|
|
2518
|
+
|
|
2519
|
+
Saves to stack for :py:attr:`~Window.saveMovieFrames()`. As of v1.81.00
|
|
2520
|
+
this also returns the frame as a PIL image
|
|
2521
|
+
|
|
2522
|
+
This can be done at any time (usually after a :py:attr:`~Window.flip()`
|
|
2523
|
+
command).
|
|
2524
|
+
|
|
2525
|
+
Frames are stored in memory until a :py:attr:`~Window.saveMovieFrames()`
|
|
2526
|
+
command is issued. You can issue :py:attr:`~Window.getMovieFrame()` as
|
|
2527
|
+
often as you like and then save them all in one go when finished.
|
|
2528
|
+
|
|
2529
|
+
The back buffer will return the frame that hasn't yet been 'flipped'
|
|
2530
|
+
to be visible on screen but has the advantage that the mouse and any
|
|
2531
|
+
other overlapping windows won't get in the way.
|
|
2532
|
+
|
|
2533
|
+
The default front buffer is to be called immediately after a
|
|
2534
|
+
:py:attr:`~Window.flip()` and gives a complete copy of the screen at the
|
|
2535
|
+
window's coordinates.
|
|
2536
|
+
|
|
2537
|
+
Parameters
|
|
2538
|
+
----------
|
|
2539
|
+
buffer : str, optional
|
|
2540
|
+
Buffer to capture.
|
|
2541
|
+
|
|
2542
|
+
Returns
|
|
2543
|
+
-------
|
|
2544
|
+
Image
|
|
2545
|
+
Buffer pixel contents as a PIL/Pillow image object.
|
|
2546
|
+
|
|
2547
|
+
"""
|
|
2548
|
+
im = self._getFrame(buffer=buffer)
|
|
2549
|
+
self.movieFrames.append(im)
|
|
2550
|
+
return im
|
|
2551
|
+
|
|
2552
|
+
def _getPixels(self, rect=None, buffer='front', includeAlpha=True,
|
|
2553
|
+
makeLum=False):
|
|
2554
|
+
"""Return an array of pixel values from the current window buffer or
|
|
2555
|
+
sub-region.
|
|
2556
|
+
|
|
2557
|
+
Parameters
|
|
2558
|
+
----------
|
|
2559
|
+
rect : tuple[int], optional
|
|
2560
|
+
The region of the window to capture in pixel coordinates (left,
|
|
2561
|
+
bottom, width, height). If `None`, the whole window is captured.
|
|
2562
|
+
buffer : str, optional
|
|
2563
|
+
Buffer to capture.
|
|
2564
|
+
includeAlpha : bool, optional
|
|
2565
|
+
Include the alpha channel in the returned array. Default is `True`.
|
|
2566
|
+
makeLum : bool, optional
|
|
2567
|
+
Convert the RGB values to luminance values. Values are rounded to
|
|
2568
|
+
the nearest integer. Default is `False`.
|
|
2569
|
+
|
|
2570
|
+
Returns
|
|
2571
|
+
-------
|
|
2572
|
+
ndarray
|
|
2573
|
+
Pixel values as a 3D array of shape (height, width, channels). If
|
|
2574
|
+
`includeAlpha` is `False`, the array will have shape (height, width,
|
|
2575
|
+
3). If `makeLum` is `True`, the array will have shape (height,
|
|
2576
|
+
width).
|
|
2577
|
+
|
|
2578
|
+
Examples
|
|
2579
|
+
--------
|
|
2580
|
+
Get the pixel values of the whole window::
|
|
2581
|
+
|
|
2582
|
+
pix = win._getPixels()
|
|
2583
|
+
|
|
2584
|
+
Get pixel values and convert to luminance and get average::
|
|
2585
|
+
|
|
2586
|
+
pix = win._getPixels(makeLum=True)
|
|
2587
|
+
average = pix.mean()
|
|
2588
|
+
|
|
2589
|
+
"""
|
|
2590
|
+
# do the reading of the pixels
|
|
2591
|
+
if buffer == 'back' and self.useFBO:
|
|
2592
|
+
GL.glReadBuffer(GL.GL_COLOR_ATTACHMENT0)
|
|
2593
|
+
elif buffer == 'back':
|
|
2594
|
+
GL.glReadBuffer(GL.GL_BACK)
|
|
2595
|
+
elif buffer == 'front':
|
|
2596
|
+
if self.useFBO:
|
|
2597
|
+
GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0)
|
|
2598
|
+
GL.glReadBuffer(GL.GL_FRONT)
|
|
2599
|
+
else:
|
|
2600
|
+
raise ValueError("Requested read from buffer '{}' but should be "
|
|
2601
|
+
"'front' or 'back'".format(buffer))
|
|
2602
|
+
|
|
2603
|
+
if rect:
|
|
2604
|
+
# box corners in pix
|
|
2605
|
+
left, bottom, w, h = rect
|
|
2606
|
+
else:
|
|
2607
|
+
left = bottom = 0
|
|
2608
|
+
w, h = self.size
|
|
2609
|
+
|
|
2610
|
+
# get pixel data
|
|
2611
|
+
bufferDat = (GL.GLubyte * (4 * w * h))()
|
|
2612
|
+
GL.glReadPixels(
|
|
2613
|
+
left, bottom, w, h,
|
|
2614
|
+
GL.GL_RGBA,
|
|
2615
|
+
GL.GL_UNSIGNED_BYTE,
|
|
2616
|
+
bufferDat)
|
|
2617
|
+
|
|
2618
|
+
# convert to array
|
|
2619
|
+
toReturn = numpy.frombuffer(bufferDat, dtype=numpy.uint8)
|
|
2620
|
+
toReturn = toReturn.reshape((h, w, 4))
|
|
2621
|
+
|
|
2622
|
+
# rebind front buffer if needed
|
|
2623
|
+
if buffer == 'front' and self.useFBO:
|
|
2624
|
+
GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, self.frameBuffer)
|
|
2625
|
+
|
|
2626
|
+
# if we want the color data without an alpha channel, we need to
|
|
2627
|
+
# convert the data to a numpy array and remove the alpha channel
|
|
2628
|
+
if not includeAlpha:
|
|
2629
|
+
toReturn = toReturn[:, :, :3] # remove alpha channel
|
|
2630
|
+
|
|
2631
|
+
# convert to luminance if requested
|
|
2632
|
+
if makeLum:
|
|
2633
|
+
coeffs = [0.2989, 0.5870, 0.1140]
|
|
2634
|
+
toReturn = numpy.rint(numpy.dot(toReturn[:, :, :3], coeffs)).astype(
|
|
2635
|
+
numpy.uint8)
|
|
2636
|
+
|
|
2637
|
+
return toReturn
|
|
2638
|
+
|
|
2639
|
+
def _getFrame(self, rect=None, buffer='front'):
|
|
2640
|
+
"""Return the current Window as an image.
|
|
2641
|
+
"""
|
|
2642
|
+
# GL.glLoadIdentity()
|
|
2643
|
+
# do the reading of the pixels
|
|
2644
|
+
if buffer == 'back' and self.useFBO:
|
|
2645
|
+
GL.glReadBuffer(GL.GL_COLOR_ATTACHMENT0)
|
|
2646
|
+
elif buffer == 'back':
|
|
2647
|
+
GL.glReadBuffer(GL.GL_BACK)
|
|
2648
|
+
elif buffer == 'front':
|
|
2649
|
+
if self.useFBO:
|
|
2650
|
+
GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0)
|
|
2651
|
+
GL.glReadBuffer(GL.GL_FRONT)
|
|
2652
|
+
else:
|
|
2653
|
+
raise ValueError("Requested read from buffer '{}' but should be "
|
|
2654
|
+
"'front' or 'back'".format(buffer))
|
|
2655
|
+
|
|
2656
|
+
if rect:
|
|
2657
|
+
x, y = self.size # of window, not image
|
|
2658
|
+
imType = 'RGBA' # not tested with anything else
|
|
2659
|
+
|
|
2660
|
+
# box corners in pix
|
|
2661
|
+
left = int((rect[0] / 2. + 0.5) * x)
|
|
2662
|
+
bottom = int((rect[3] / 2. + 0.5) * y)
|
|
2663
|
+
w = int((rect[2] / 2. + 0.5) * x) - left
|
|
2664
|
+
h = int((rect[1] / 2. + 0.5) * y) - bottom
|
|
2665
|
+
else:
|
|
2666
|
+
left = bottom = 0
|
|
2667
|
+
w, h = self.size
|
|
2668
|
+
|
|
2669
|
+
# http://www.opengl.org/sdk/docs/man/xhtml/glGetTexImage.xml
|
|
2670
|
+
bufferDat = (GL.GLubyte * (4 * w * h))()
|
|
2671
|
+
GL.glReadPixels(left, bottom, w, h,
|
|
2672
|
+
GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, bufferDat)
|
|
2673
|
+
try:
|
|
2674
|
+
im = Image.fromstring(mode='RGBA', size=(w, h),
|
|
2675
|
+
data=bufferDat)
|
|
2676
|
+
except Exception:
|
|
2677
|
+
im = Image.frombytes(mode='RGBA', size=(w, h),
|
|
2678
|
+
data=bufferDat)
|
|
2679
|
+
|
|
2680
|
+
im = im.transpose(Image.FLIP_TOP_BOTTOM)
|
|
2681
|
+
im = im.convert('RGB')
|
|
2682
|
+
|
|
2683
|
+
if self.useFBO and buffer == 'front':
|
|
2684
|
+
GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, self.frameBuffer)
|
|
2685
|
+
return im
|
|
2686
|
+
|
|
2687
|
+
@property
|
|
2688
|
+
def screenshot(self):
|
|
2689
|
+
return self._getFrame()
|
|
2690
|
+
|
|
2691
|
+
def saveMovieFrames(self, fileName, codec='libx264',
|
|
2692
|
+
fps=30, clearFrames=True):
|
|
2693
|
+
"""Writes any captured frames to disk.
|
|
2694
|
+
|
|
2695
|
+
Will write any format that is understood by PIL (tif, jpg, png, ...)
|
|
2696
|
+
|
|
2697
|
+
Parameters
|
|
2698
|
+
----------
|
|
2699
|
+
filename : str
|
|
2700
|
+
Name of file, including path. The extension at the end of the file
|
|
2701
|
+
determines the type of file(s) created. If an image type (e.g. .png)
|
|
2702
|
+
is given, then multiple static frames are created. If it is .gif
|
|
2703
|
+
then an animated GIF image is created (although you will get higher
|
|
2704
|
+
quality GIF by saving PNG files and then combining them in dedicated
|
|
2705
|
+
image manipulation software, such as GIMP). On Windows and Linux
|
|
2706
|
+
`.mpeg` files can be created if `pymedia` is installed. On macOS
|
|
2707
|
+
`.mov` files can be created if the pyobjc-frameworks-QTKit is
|
|
2708
|
+
installed. Unfortunately the libs used for movie generation can be
|
|
2709
|
+
flaky and poor quality. As for animated GIFs, better results can be
|
|
2710
|
+
achieved by saving as individual .png frames and then combining them
|
|
2711
|
+
into a movie using software like ffmpeg.
|
|
2712
|
+
codec : str, optional
|
|
2713
|
+
The codec to be used **by moviepy** for mp4/mpg/mov files. If
|
|
2714
|
+
`None` then the default will depend on file extension. Can be
|
|
2715
|
+
one of ``libx264``, ``mpeg4`` for mp4/mov files. Can be
|
|
2716
|
+
``rawvideo``, ``png`` for avi files (not recommended). Can be
|
|
2717
|
+
``libvorbis`` for ogv files. Default is ``libx264``.
|
|
2718
|
+
fps : int, optional
|
|
2719
|
+
The frame rate to be used throughout the movie. **Only for
|
|
2720
|
+
quicktime (.mov) movies.**. Default is `30`.
|
|
2721
|
+
clearFrames : bool, optional
|
|
2722
|
+
Set this to `False` if you want the frames to be kept for
|
|
2723
|
+
additional calls to ``saveMovieFrames``. Default is `True`.
|
|
2724
|
+
|
|
2725
|
+
Examples
|
|
2726
|
+
--------
|
|
2727
|
+
Writes a series of static frames as frame001.tif, frame002.tif etc.::
|
|
2728
|
+
|
|
2729
|
+
myWin.saveMovieFrames('frame.tif')
|
|
2730
|
+
|
|
2731
|
+
As of PsychoPy 1.84.1 the following are written with moviepy::
|
|
2732
|
+
|
|
2733
|
+
myWin.saveMovieFrames('stimuli.mp4') # codec = 'libx264' or 'mpeg4'
|
|
2734
|
+
myWin.saveMovieFrames('stimuli.mov')
|
|
2735
|
+
myWin.saveMovieFrames('stimuli.gif')
|
|
2736
|
+
|
|
2737
|
+
"""
|
|
2738
|
+
fileRoot, fileExt = os.path.splitext(fileName)
|
|
2739
|
+
fileExt = fileExt.lower() # easier than testing both later
|
|
2740
|
+
if len(self.movieFrames) == 0:
|
|
2741
|
+
logging.error('no frames to write - did you forget to update '
|
|
2742
|
+
'your window or call win.getMovieFrame()?')
|
|
2743
|
+
return
|
|
2744
|
+
else:
|
|
2745
|
+
logging.info('Writing %i frames to %s' % (len(self.movieFrames),
|
|
2746
|
+
fileName))
|
|
2747
|
+
|
|
2748
|
+
if fileExt in ['.gif', '.mpg', '.mpeg', '.mp4', '.mov']:
|
|
2749
|
+
# lazy loading of moviepy.editor (rarely needed)
|
|
2750
|
+
from moviepy import ImageSequenceClip
|
|
2751
|
+
# save variety of movies with moviepy
|
|
2752
|
+
numpyFrames = []
|
|
2753
|
+
for frame in self.movieFrames:
|
|
2754
|
+
numpyFrames.append(numpy.array(frame))
|
|
2755
|
+
clip = ImageSequenceClip(numpyFrames, fps=fps)
|
|
2756
|
+
if fileExt == '.gif':
|
|
2757
|
+
clip.write_gif(fileName, fps=fps, fuzz=0, opt='nq')
|
|
2758
|
+
else:
|
|
2759
|
+
clip.write_videofile(fileName, codec=codec)
|
|
2760
|
+
elif len(self.movieFrames) == 1:
|
|
2761
|
+
# save an image using pillow
|
|
2762
|
+
self.movieFrames[0].save(fileName)
|
|
2763
|
+
else:
|
|
2764
|
+
frmc = numpy.ceil(numpy.log10(len(self.movieFrames) + 1))
|
|
2765
|
+
frame_name_format = "%s%%0%dd%s" % (fileRoot, frmc, fileExt)
|
|
2766
|
+
for frameN, thisFrame in enumerate(self.movieFrames):
|
|
2767
|
+
thisFileName = frame_name_format % (frameN + 1,)
|
|
2768
|
+
thisFrame.save(thisFileName)
|
|
2769
|
+
if clearFrames:
|
|
2770
|
+
self.movieFrames = []
|
|
2771
|
+
|
|
2772
|
+
def _getRegionOfFrame(self, rect=(-1, 1, 1, -1), buffer='front',
|
|
2773
|
+
power2=False, squarePower2=False):
|
|
2774
|
+
"""Deprecated function, here for historical reasons. You may now use
|
|
2775
|
+
`:py:attr:`~Window._getFrame()` and specify a rect to get a sub-region,
|
|
2776
|
+
just as used here.
|
|
2777
|
+
|
|
2778
|
+
power2 can be useful with older OpenGL versions to avoid interpolation
|
|
2779
|
+
in :py:attr:`PatchStim`. If power2 or squarePower2, it will expand rect
|
|
2780
|
+
dimensions up to next power of two. squarePower2 uses the max
|
|
2781
|
+
dimensions. You need to check what your hardware & OpenGL supports,
|
|
2782
|
+
and call :py:attr:`~Window._getRegionOfFrame()` as appropriate.
|
|
2783
|
+
"""
|
|
2784
|
+
# Ideally: rewrite using GL frame buffer object; glReadPixels == slow
|
|
2785
|
+
region = self._getFrame(rect=rect, buffer=buffer)
|
|
2786
|
+
if power2 or squarePower2: # use to avoid interpolation in PatchStim
|
|
2787
|
+
if squarePower2:
|
|
2788
|
+
maxsize = max(region.size)
|
|
2789
|
+
xPowerOf2 = int(2**numpy.ceil(numpy.log2(maxsize)))
|
|
2790
|
+
yPowerOf2 = xPowerOf2
|
|
2791
|
+
else:
|
|
2792
|
+
xPowerOf2 = int(2**numpy.ceil(numpy.log2(region.size[0])))
|
|
2793
|
+
yPowerOf2 = int(2**numpy.ceil(numpy.log2(region.size[1])))
|
|
2794
|
+
imP2 = Image.new('RGBA', (xPowerOf2, yPowerOf2))
|
|
2795
|
+
# paste centered
|
|
2796
|
+
imP2.paste(region, (int(xPowerOf2 / 2. - region.size[0] / 2.),
|
|
2797
|
+
int(yPowerOf2 / 2.) - region.size[1] / 2))
|
|
2798
|
+
region = imP2
|
|
2799
|
+
return region
|
|
2800
|
+
|
|
2801
|
+
def close(self):
|
|
2802
|
+
"""Close the window (and reset the Bits++ if necess).
|
|
2803
|
+
"""
|
|
2804
|
+
self._closed = True
|
|
2805
|
+
|
|
2806
|
+
# If iohub is running, inform it to stop using this win id
|
|
2807
|
+
# for mouse events
|
|
2808
|
+
try:
|
|
2809
|
+
if IOHUB_ACTIVE:
|
|
2810
|
+
from psychopy.iohub.client import ioHubConnection
|
|
2811
|
+
ioHubConnection.ACTIVE_CONNECTION.unregisterWindowHandles(self._hw_handle)
|
|
2812
|
+
except Exception:
|
|
2813
|
+
pass
|
|
2814
|
+
|
|
2815
|
+
self.backend.close() # moved here, dereferencing the window prevents
|
|
2816
|
+
# backend specific actions to take place
|
|
2817
|
+
|
|
2818
|
+
try:
|
|
2819
|
+
openWindows.remove(self)
|
|
2820
|
+
except Exception:
|
|
2821
|
+
pass
|
|
2822
|
+
|
|
2823
|
+
try:
|
|
2824
|
+
self.mouseVisible = True
|
|
2825
|
+
except Exception:
|
|
2826
|
+
# can cause unimportant "'NoneType' object is not callable"
|
|
2827
|
+
pass
|
|
2828
|
+
|
|
2829
|
+
try:
|
|
2830
|
+
if self.bits is not None:
|
|
2831
|
+
self.bits.reset()
|
|
2832
|
+
except Exception:
|
|
2833
|
+
pass
|
|
2834
|
+
try:
|
|
2835
|
+
logging.flush()
|
|
2836
|
+
except Exception:
|
|
2837
|
+
pass
|
|
2838
|
+
|
|
2839
|
+
def fps(self):
|
|
2840
|
+
"""Report the frames per second since the last call to this function
|
|
2841
|
+
(or since the window was created if this is first call)"""
|
|
2842
|
+
fps = self.frames / self.frameClock.getTime()
|
|
2843
|
+
self.frameClock.reset()
|
|
2844
|
+
self.frames = 0
|
|
2845
|
+
return fps
|
|
2846
|
+
|
|
2847
|
+
@property
|
|
2848
|
+
def depthTest(self):
|
|
2849
|
+
"""`True` if depth testing is enabled."""
|
|
2850
|
+
return self._depthTest
|
|
2851
|
+
|
|
2852
|
+
@depthTest.setter
|
|
2853
|
+
def depthTest(self, value):
|
|
2854
|
+
if value is True:
|
|
2855
|
+
GL.glEnable(GL.GL_DEPTH_TEST)
|
|
2856
|
+
elif value is False:
|
|
2857
|
+
GL.glDisable(GL.GL_DEPTH_TEST)
|
|
2858
|
+
else:
|
|
2859
|
+
raise TypeError("Value must be boolean.")
|
|
2860
|
+
|
|
2861
|
+
self._depthTest = value
|
|
2862
|
+
|
|
2863
|
+
@property
|
|
2864
|
+
def depthFunc(self):
|
|
2865
|
+
"""Depth test comparison function for rendering."""
|
|
2866
|
+
return self._depthFunc
|
|
2867
|
+
|
|
2868
|
+
@depthFunc.setter
|
|
2869
|
+
def depthFunc(self, value):
|
|
2870
|
+
depthFuncs = {'never': GL.GL_NEVER, 'less': GL.GL_LESS,
|
|
2871
|
+
'equal': GL.GL_EQUAL, 'lequal': GL.GL_LEQUAL,
|
|
2872
|
+
'greater': GL.GL_GREATER, 'notequal': GL.GL_NOTEQUAL,
|
|
2873
|
+
'gequal': GL.GL_GEQUAL, 'always': GL.GL_ALWAYS}
|
|
2874
|
+
|
|
2875
|
+
GL.glDepthFunc(depthFuncs[value])
|
|
2876
|
+
|
|
2877
|
+
self._depthFunc = value
|
|
2878
|
+
|
|
2879
|
+
@property
|
|
2880
|
+
def depthMask(self):
|
|
2881
|
+
"""`True` if depth masking is enabled. Writing to the depth buffer will
|
|
2882
|
+
be disabled.
|
|
2883
|
+
"""
|
|
2884
|
+
return self._depthMask
|
|
2885
|
+
|
|
2886
|
+
@depthMask.setter
|
|
2887
|
+
def depthMask(self, value):
|
|
2888
|
+
if value is True:
|
|
2889
|
+
GL.glDepthMask(GL.GL_TRUE)
|
|
2890
|
+
elif value is False:
|
|
2891
|
+
GL.glDepthMask(GL.GL_FALSE)
|
|
2892
|
+
else:
|
|
2893
|
+
raise TypeError("Value must be boolean.")
|
|
2894
|
+
|
|
2895
|
+
self._depthMask = value
|
|
2896
|
+
|
|
2897
|
+
@property
|
|
2898
|
+
def cullFaceMode(self):
|
|
2899
|
+
"""Face culling mode, either `back`, `front` or `both`."""
|
|
2900
|
+
return self._cullFaceMode
|
|
2901
|
+
|
|
2902
|
+
@cullFaceMode.setter
|
|
2903
|
+
def cullFaceMode(self, value):
|
|
2904
|
+
if value == 'back':
|
|
2905
|
+
GL.glCullFace(GL.GL_BACK)
|
|
2906
|
+
elif value == 'front':
|
|
2907
|
+
GL.glCullFace(GL.GL_FRONT)
|
|
2908
|
+
elif value == 'both':
|
|
2909
|
+
GL.glCullFace(GL.GL_FRONT_AND_BACK)
|
|
2910
|
+
else:
|
|
2911
|
+
raise ValueError('Invalid face cull mode.')
|
|
2912
|
+
|
|
2913
|
+
self._cullFaceMode = value
|
|
2914
|
+
|
|
2915
|
+
@property
|
|
2916
|
+
def cullFace(self):
|
|
2917
|
+
"""`True` if face culling is enabled.`"""
|
|
2918
|
+
return self._cullFace
|
|
2919
|
+
|
|
2920
|
+
@cullFace.setter
|
|
2921
|
+
def cullFace(self, value):
|
|
2922
|
+
if value is True:
|
|
2923
|
+
GL.glEnable(GL.GL_CULL_FACE)
|
|
2924
|
+
elif value is False:
|
|
2925
|
+
GL.glDisable(GL.GL_CULL_FACE)
|
|
2926
|
+
else:
|
|
2927
|
+
raise TypeError('Value must be type `bool`.')
|
|
2928
|
+
|
|
2929
|
+
self._cullFace = value
|
|
2930
|
+
|
|
2931
|
+
@property
|
|
2932
|
+
def frontFace(self):
|
|
2933
|
+
"""Face winding order to define front, either `ccw` or `cw`."""
|
|
2934
|
+
return self._frontFace
|
|
2935
|
+
|
|
2936
|
+
@frontFace.setter
|
|
2937
|
+
def frontFace(self, value):
|
|
2938
|
+
if value == 'ccw':
|
|
2939
|
+
GL.glFrontFace(GL.GL_CCW)
|
|
2940
|
+
elif value == 'cw':
|
|
2941
|
+
GL.glFrontFace(GL.GL_CW)
|
|
2942
|
+
else:
|
|
2943
|
+
raise ValueError('Invalid value, must be `ccw` or `cw`.')
|
|
2944
|
+
|
|
2945
|
+
self._frontFace = value
|
|
2946
|
+
|
|
2947
|
+
@property
|
|
2948
|
+
def draw3d(self):
|
|
2949
|
+
"""`True` if 3D drawing is enabled on this window."""
|
|
2950
|
+
return self._draw3d
|
|
2951
|
+
|
|
2952
|
+
@draw3d.setter
|
|
2953
|
+
def draw3d(self, value):
|
|
2954
|
+
if value is True:
|
|
2955
|
+
if self.depthMask is False:
|
|
2956
|
+
self.depthMask = True
|
|
2957
|
+
if self.depthTest is False:
|
|
2958
|
+
self.depthTest = True
|
|
2959
|
+
if self.cullFace is False:
|
|
2960
|
+
self.cullFace = True
|
|
2961
|
+
elif value is False:
|
|
2962
|
+
if self.depthMask is True:
|
|
2963
|
+
self.depthMask = False
|
|
2964
|
+
if self.depthTest is True:
|
|
2965
|
+
self.depthTest = False
|
|
2966
|
+
if self.cullFace is True:
|
|
2967
|
+
self.cullFace = False
|
|
2968
|
+
else:
|
|
2969
|
+
raise TypeError('Value must be type `bool`.')
|
|
2970
|
+
|
|
2971
|
+
self._draw3d = value
|
|
2972
|
+
|
|
2973
|
+
@attributeSetter
|
|
2974
|
+
def blendMode(self, blendMode):
|
|
2975
|
+
"""Blend mode to use."""
|
|
2976
|
+
self.__dict__['blendMode'] = blendMode
|
|
2977
|
+
if blendMode == 'avg':
|
|
2978
|
+
GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA)
|
|
2979
|
+
if hasattr(self, '_shaders'):
|
|
2980
|
+
self._progSignedFrag = self._shaders['signedColor']
|
|
2981
|
+
self._progSignedTex = self._shaders['signedTex']
|
|
2982
|
+
self._progSignedTexMask = self._shaders['signedTexMask']
|
|
2983
|
+
self._progSignedTexMask1D = self._shaders['signedTexMask1D']
|
|
2984
|
+
self._progImageStim = self._shaders['imageStim']
|
|
2985
|
+
elif blendMode == 'add':
|
|
2986
|
+
GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE)
|
|
2987
|
+
if hasattr(self, '_shaders'):
|
|
2988
|
+
self._progSignedFrag = self._shaders['signedColor_adding']
|
|
2989
|
+
self._progSignedTex = self._shaders['signedTex_adding']
|
|
2990
|
+
self._progSignedTexMask = self._shaders['signedTexMask_adding']
|
|
2991
|
+
tmp = self._shaders['signedTexMask1D_adding']
|
|
2992
|
+
self._progSignedTexMask1D = tmp
|
|
2993
|
+
self._progImageStim = self._shaders['imageStim_adding']
|
|
2994
|
+
else:
|
|
2995
|
+
raise ValueError("Window blendMode should be set to 'avg' or 'add'"
|
|
2996
|
+
" but we received the value {}"
|
|
2997
|
+
.format(repr(blendMode)))
|
|
2998
|
+
|
|
2999
|
+
def setBlendMode(self, blendMode, log=None):
|
|
3000
|
+
"""Usually you can use 'stim.attribute = value' syntax instead,
|
|
3001
|
+
but use this method if you need to suppress the log message.
|
|
3002
|
+
"""
|
|
3003
|
+
setAttribute(self, 'blendMode', blendMode, log)
|
|
3004
|
+
|
|
3005
|
+
@property
|
|
3006
|
+
def colorSpace(self):
|
|
3007
|
+
"""The name of the color space currently being used
|
|
3008
|
+
|
|
3009
|
+
Value should be: a string or None
|
|
3010
|
+
|
|
3011
|
+
For strings and hex values this is not needed.
|
|
3012
|
+
If None the default colorSpace for the stimulus is
|
|
3013
|
+
used (defined during initialisation).
|
|
3014
|
+
|
|
3015
|
+
Please note that changing colorSpace does not change stimulus
|
|
3016
|
+
parameters. Thus you usually want to specify colorSpace before
|
|
3017
|
+
setting the color. Example::
|
|
3018
|
+
|
|
3019
|
+
# A light green text
|
|
3020
|
+
stim = visual.TextStim(win, 'Color me!',
|
|
3021
|
+
color=(0, 1, 0), colorSpace='rgb')
|
|
3022
|
+
|
|
3023
|
+
# An almost-black text
|
|
3024
|
+
stim.colorSpace = 'rgb255'
|
|
3025
|
+
|
|
3026
|
+
# Make it light green again
|
|
3027
|
+
stim.color = (128, 255, 128)
|
|
3028
|
+
"""
|
|
3029
|
+
if hasattr(self, '_colorSpace'):
|
|
3030
|
+
return self._colorSpace
|
|
3031
|
+
else:
|
|
3032
|
+
return 'rgb'
|
|
3033
|
+
@colorSpace.setter
|
|
3034
|
+
def colorSpace(self, value):
|
|
3035
|
+
if value in colorSpaces:
|
|
3036
|
+
self._colorSpace = value
|
|
3037
|
+
else:
|
|
3038
|
+
logging.error(f"'{value}' is not a valid color space")
|
|
3039
|
+
|
|
3040
|
+
@property
|
|
3041
|
+
def color(self):
|
|
3042
|
+
"""Set the color of the window.
|
|
3043
|
+
|
|
3044
|
+
This command sets the color that the blank screen will have on the
|
|
3045
|
+
next clear operation. As a result it effectively takes TWO
|
|
3046
|
+
:py:attr:`~Window.flip()` operations to become visible (the first uses
|
|
3047
|
+
the color to create the new screen, the second presents that screen to
|
|
3048
|
+
the viewer). For this reason, if you want to changed background color of
|
|
3049
|
+
the window "on the fly", it might be a better idea to draw a
|
|
3050
|
+
:py:attr:`Rect` that fills the whole window with the desired
|
|
3051
|
+
:py:attr:`Rect.fillColor` attribute. That'll show up on first flip.
|
|
3052
|
+
|
|
3053
|
+
See other stimuli (e.g. :py:attr:`GratingStim.color`)
|
|
3054
|
+
for more info on the color attribute which essentially works the same on
|
|
3055
|
+
all PsychoPy stimuli.
|
|
3056
|
+
|
|
3057
|
+
See :ref:`colorspaces` for further information about the ways to
|
|
3058
|
+
specify colors and their various implications.
|
|
3059
|
+
"""
|
|
3060
|
+
if hasattr(self, '_color'):
|
|
3061
|
+
return getattr(self._color, self.colorSpace)
|
|
3062
|
+
@color.setter
|
|
3063
|
+
def color(self, value):
|
|
3064
|
+
if isinstance(value, Color):
|
|
3065
|
+
# If supplied with a color object, set as that
|
|
3066
|
+
self._color = value
|
|
3067
|
+
else:
|
|
3068
|
+
# Otherwise, use it to make a color object
|
|
3069
|
+
self._color = Color(value, self.colorSpace)
|
|
3070
|
+
if not self._color:
|
|
3071
|
+
self._color = Color()
|
|
3072
|
+
logging.error(f"'{value}' is not a valid {self.colorSpace} color")
|
|
3073
|
+
|
|
3074
|
+
# if it is None then this will be done during window setup
|
|
3075
|
+
if self.backend is not None:
|
|
3076
|
+
self.backend.setCurrent() # make sure this window is active
|
|
3077
|
+
GL.glClearColor(*self._color.render('rgba1'))
|
|
3078
|
+
|
|
3079
|
+
def setColor(self, color, colorSpace=None, operation='', log=None):
|
|
3080
|
+
"""Usually you can use ``stim.attribute = value`` syntax instead,
|
|
3081
|
+
but use this method if you want to set color and colorSpace
|
|
3082
|
+
simultaneously.
|
|
3083
|
+
|
|
3084
|
+
See :py:attr:`~Window.color` for documentation on colors.
|
|
3085
|
+
"""
|
|
3086
|
+
self.colorSpace = colorSpace
|
|
3087
|
+
self.color = color
|
|
3088
|
+
|
|
3089
|
+
def setRGB(self, newRGB):
|
|
3090
|
+
"""Deprecated: As of v1.61.00 please use `setColor()` instead
|
|
3091
|
+
"""
|
|
3092
|
+
self.setColor(newRGB, colorSpace="rgb")
|
|
3093
|
+
|
|
3094
|
+
@property
|
|
3095
|
+
def rgb(self):
|
|
3096
|
+
if hasattr(self, "_color"):
|
|
3097
|
+
return self._color.render("rgb")
|
|
3098
|
+
@rgb.setter
|
|
3099
|
+
def rgb(self, value):
|
|
3100
|
+
self.color = Color(value, 'rgb')
|
|
3101
|
+
|
|
3102
|
+
@attributeSetter
|
|
3103
|
+
def backgroundImage(self, value):
|
|
3104
|
+
"""
|
|
3105
|
+
Background image for the window, can be either a visual.ImageStim object or anything which could be passed to
|
|
3106
|
+
visual.ImageStim.image to create one. Will be drawn each time `win.flip()` is called, meaning it is always
|
|
3107
|
+
below all other contents of the window.
|
|
3108
|
+
"""
|
|
3109
|
+
if value in (None, "None", "none", ""):
|
|
3110
|
+
# If given None, store so we know not to use a background image
|
|
3111
|
+
self._backgroundImage = None
|
|
3112
|
+
self.__dict__['backgroundImage'] = self._backgroundImage
|
|
3113
|
+
return
|
|
3114
|
+
elif hasattr(value, "draw") and hasattr(value, "win"):
|
|
3115
|
+
# If given a visual object, set its parent window to self and use it
|
|
3116
|
+
value.win = self
|
|
3117
|
+
self._backgroundImage = value
|
|
3118
|
+
else:
|
|
3119
|
+
# Otherwise, try to make an image from value (start off as if backgroundFit was None)
|
|
3120
|
+
self._backgroundImage = image.ImageStim(self, image=value, size=None, pos=(0, 0))
|
|
3121
|
+
|
|
3122
|
+
# Set background fit again now that we have an image
|
|
3123
|
+
if hasattr(self, "_backgroundFit"):
|
|
3124
|
+
self.backgroundFit = self._backgroundFit
|
|
3125
|
+
|
|
3126
|
+
self.__dict__['backgroundImage'] = self._backgroundImage
|
|
3127
|
+
|
|
3128
|
+
@attributeSetter
|
|
3129
|
+
def backgroundFit(self, value):
|
|
3130
|
+
"""
|
|
3131
|
+
How should the background image of this window fit? Options are:
|
|
3132
|
+
|
|
3133
|
+
None, "None", "none"
|
|
3134
|
+
No scaling is applied, image is present at its pixel size unaltered.
|
|
3135
|
+
"cover"
|
|
3136
|
+
Image is scaled such that it covers the whole screen without changing its aspect ratio. In other words,
|
|
3137
|
+
both dimensions are evenly scaled such that its SHORTEST dimension matches the window's LONGEST dimension.
|
|
3138
|
+
"contain"
|
|
3139
|
+
Image is scaled such that it is contained within the screen without changing its aspect ratio. In other
|
|
3140
|
+
words, both dimensions are evenly scaled such that its LONGEST dimension matches the window's SHORTEST
|
|
3141
|
+
dimension.
|
|
3142
|
+
"scaleDown", "scale-down", "scaledown"
|
|
3143
|
+
If image is bigger than the window along any dimension, it will behave as if backgroundFit were "contain".
|
|
3144
|
+
Otherwise, it will behave as if backgroundFit were None.
|
|
3145
|
+
"""
|
|
3146
|
+
self._backgroundFit = value
|
|
3147
|
+
|
|
3148
|
+
# Skip if no background image
|
|
3149
|
+
if (not hasattr(self, "_backgroundImage")) or (self._backgroundImage is None):
|
|
3150
|
+
self.__dict__['backgroundFit'] = self._backgroundFit
|
|
3151
|
+
return
|
|
3152
|
+
|
|
3153
|
+
# If value is scaleDown or alias, set to None or "contain" based on relative size
|
|
3154
|
+
if value in ("scaleDown", "scale-down", "scaledown"):
|
|
3155
|
+
overflow = numpy.asarray(self._backgroundImage._origSize) > numpy.asarray(self.size)
|
|
3156
|
+
if overflow.any():
|
|
3157
|
+
value = "contain"
|
|
3158
|
+
else:
|
|
3159
|
+
value = None
|
|
3160
|
+
|
|
3161
|
+
if value in (None, "None", "none"):
|
|
3162
|
+
# If value is None, don't change the backgroundImage at all
|
|
3163
|
+
pass
|
|
3164
|
+
elif value == "fill":
|
|
3165
|
+
# If value is fill, make backgroundImage fill screen
|
|
3166
|
+
self._backgroundImage.units = "norm"
|
|
3167
|
+
self._backgroundImage.size = (2, 2)
|
|
3168
|
+
self._backgroundImage.pos = (0, 0)
|
|
3169
|
+
if value in ("contain", "cover"):
|
|
3170
|
+
# If value is contain or cover, set one dimension to fill screen and the other to maintain ratio
|
|
3171
|
+
ratios = numpy.asarray(self._backgroundImage._origSize) / numpy.asarray(self.size)
|
|
3172
|
+
if value == "cover":
|
|
3173
|
+
i = ratios.argmin()
|
|
3174
|
+
else:
|
|
3175
|
+
i = ratios.argmax()
|
|
3176
|
+
size = [None, None]
|
|
3177
|
+
size[i] = 2
|
|
3178
|
+
self._backgroundImage.units = "norm"
|
|
3179
|
+
self._backgroundImage.size = size
|
|
3180
|
+
self._backgroundImage.pos = (0, 0)
|
|
3181
|
+
|
|
3182
|
+
self.__dict__['backgroundFit'] = self._backgroundFit
|
|
3183
|
+
|
|
3184
|
+
def _setupGamma(self, gammaVal):
|
|
3185
|
+
"""A private method to work out how to handle gamma for this Window
|
|
3186
|
+
given that the user might have specified an explicit value, or maybe
|
|
3187
|
+
gave a Monitor.
|
|
3188
|
+
"""
|
|
3189
|
+
# determine which gamma value to use (or native ramp)
|
|
3190
|
+
if gammaVal is not None:
|
|
3191
|
+
self._checkGamma()
|
|
3192
|
+
self.useNativeGamma = False
|
|
3193
|
+
elif not self.monitor.gammaIsDefault():
|
|
3194
|
+
if self.monitor.getGamma() is not None:
|
|
3195
|
+
self.__dict__['gamma'] = self.monitor.getGamma()
|
|
3196
|
+
self.useNativeGamma = False
|
|
3197
|
+
else:
|
|
3198
|
+
self.__dict__['gamma'] = None # gamma wasn't set anywhere
|
|
3199
|
+
self.useNativeGamma = True
|
|
3200
|
+
|
|
3201
|
+
# then try setting it
|
|
3202
|
+
if self.useNativeGamma:
|
|
3203
|
+
if self.autoLog:
|
|
3204
|
+
logging.info('Using gamma table of operating system')
|
|
3205
|
+
else:
|
|
3206
|
+
if self.autoLog:
|
|
3207
|
+
logging.info('Using gamma: self.gamma' + str(self.gamma))
|
|
3208
|
+
self.gamma = gammaVal # using either pygame or bits++
|
|
3209
|
+
|
|
3210
|
+
|
|
3211
|
+
@attributeSetter
|
|
3212
|
+
def gamma(self, gamma):
|
|
3213
|
+
"""Set the monitor gamma for linearization.
|
|
3214
|
+
|
|
3215
|
+
Warnings
|
|
3216
|
+
--------
|
|
3217
|
+
Don't use this if using a Bits++ or Bits#, as it overrides monitor
|
|
3218
|
+
settings.
|
|
3219
|
+
|
|
3220
|
+
"""
|
|
3221
|
+
self._checkGamma(gamma)
|
|
3222
|
+
|
|
3223
|
+
if self.bits is not None:
|
|
3224
|
+
msg = ("Do not use try to set the gamma of a window with "
|
|
3225
|
+
"Bits++/Bits# enabled. It was ambiguous what should "
|
|
3226
|
+
"happen. Use the setGamma() function of the bits box "
|
|
3227
|
+
"instead")
|
|
3228
|
+
raise DeprecationWarning(msg)
|
|
3229
|
+
|
|
3230
|
+
self.backend.gamma = self.__dict__['gamma']
|
|
3231
|
+
|
|
3232
|
+
def setGamma(self, gamma, log=None):
|
|
3233
|
+
"""Usually you can use 'stim.attribute = value' syntax instead,
|
|
3234
|
+
but use this method if you need to suppress the log message.
|
|
3235
|
+
|
|
3236
|
+
"""
|
|
3237
|
+
setAttribute(self, 'gamma', gamma, log)
|
|
3238
|
+
|
|
3239
|
+
@attributeSetter
|
|
3240
|
+
def gammaRamp(self, newRamp):
|
|
3241
|
+
"""Sets the hardware CLUT using a specified 3xN array of floats ranging
|
|
3242
|
+
between 0.0 and 1.0.
|
|
3243
|
+
|
|
3244
|
+
Array must have a number of rows equal to 2 ^ max(bpc).
|
|
3245
|
+
|
|
3246
|
+
"""
|
|
3247
|
+
self.backend.gammaRamp = newRamp
|
|
3248
|
+
|
|
3249
|
+
def _checkGamma(self, gamma=None):
|
|
3250
|
+
if gamma is None:
|
|
3251
|
+
gamma = self.gamma
|
|
3252
|
+
if isinstance(gamma, (float, int)):
|
|
3253
|
+
self.__dict__['gamma'] = [gamma] * 3
|
|
3254
|
+
elif hasattr(gamma, '__iter__'):
|
|
3255
|
+
self.__dict__['gamma'] = gamma
|
|
3256
|
+
else:
|
|
3257
|
+
raise ValueError('gamma must be a numeric scalar or iterable')
|
|
3258
|
+
|
|
3259
|
+
def setScale(self, units, font='dummyFont', prevScale=(1.0, 1.0)):
|
|
3260
|
+
"""DEPRECATED: this method used to be used to switch between units for
|
|
3261
|
+
stimulus drawing but this is now handled by the stimuli themselves and
|
|
3262
|
+
the window should always be left in units of 'pix'
|
|
3263
|
+
"""
|
|
3264
|
+
if self.useRetina:
|
|
3265
|
+
retinaScale = 2.0
|
|
3266
|
+
else:
|
|
3267
|
+
retinaScale = 1.0
|
|
3268
|
+
# then unit-specific changes
|
|
3269
|
+
if units == "norm":
|
|
3270
|
+
thisScale = numpy.array([1.0, 1.0])
|
|
3271
|
+
elif units == "height":
|
|
3272
|
+
thisScale = numpy.array([2.0 * self.size[1] / self.size[0], 2.0])
|
|
3273
|
+
elif units in ["pix", "pixels"]:
|
|
3274
|
+
thisScale = 2.0 / numpy.array(self.size) * retinaScale
|
|
3275
|
+
elif units == "cm":
|
|
3276
|
+
# windowPerCM = windowPerPIX / CMperPIX
|
|
3277
|
+
# = (window/winPIX) / (scrCm/scrPIX)
|
|
3278
|
+
if self.scrWidthCM in [0, None] or self.scrWidthPIX in [0, None]:
|
|
3279
|
+
logging.error('you did not give the width of the screen (pixels'
|
|
3280
|
+
' and cm). Check settings in MonitorCentre.')
|
|
3281
|
+
core.wait(1.0)
|
|
3282
|
+
core.quit()
|
|
3283
|
+
thisScale = ((numpy.array([2.0, 2.0]) / self.size * retinaScale)
|
|
3284
|
+
/ (self.scrWidthCM / self.scrWidthPIX))
|
|
3285
|
+
elif units in ["deg", "degs"]:
|
|
3286
|
+
# windowPerDeg = winPerCM * CMperDEG
|
|
3287
|
+
# = winPerCM * tan(pi/180) * distance
|
|
3288
|
+
if ((self.scrWidthCM in [0, None]) or
|
|
3289
|
+
(self.scrWidthPIX in [0, None])):
|
|
3290
|
+
logging.error('you did not give the width of the screen (pixels'
|
|
3291
|
+
' and cm). Check settings in MonitorCentre.')
|
|
3292
|
+
core.wait(1.0)
|
|
3293
|
+
core.quit()
|
|
3294
|
+
cmScale = ((numpy.array([2.0, 2.0]) / self.size) * retinaScale /
|
|
3295
|
+
(self.scrWidthCM / self.scrWidthPIX))
|
|
3296
|
+
thisScale = cmScale * 0.017455 * self.scrDistCM
|
|
3297
|
+
elif units == "stroke_font":
|
|
3298
|
+
lw = 2 * font.letterWidth
|
|
3299
|
+
thisScale = numpy.array([lw, lw] / self.size * retinaScale / 38.0)
|
|
3300
|
+
# actually set the scale as appropriate
|
|
3301
|
+
# allows undoing of a previous scaling procedure
|
|
3302
|
+
if self.USE_LEGACY_GL:
|
|
3303
|
+
thisScale = thisScale / numpy.asarray(prevScale)
|
|
3304
|
+
GL.glScalef(thisScale[0], thisScale[1], 1.0)
|
|
3305
|
+
|
|
3306
|
+
return thisScale
|
|
3307
|
+
|
|
3308
|
+
def _checkMatchingSizes(self, requested, actual):
|
|
3309
|
+
"""Checks whether the requested and actual screen sizes differ.
|
|
3310
|
+
If not then a warning is output and the window size is set to actual
|
|
3311
|
+
"""
|
|
3312
|
+
if list(requested) != list(actual):
|
|
3313
|
+
logging.warning("User requested fullscreen with size %s, "
|
|
3314
|
+
"but screen is actually %s. Using actual size" %
|
|
3315
|
+
(requested, actual))
|
|
3316
|
+
self.clientSize = numpy.array(actual)
|
|
3317
|
+
|
|
3318
|
+
def _setupGL(self):
|
|
3319
|
+
"""Setup OpenGL state for this window.
|
|
3320
|
+
"""
|
|
3321
|
+
# setup screen color
|
|
3322
|
+
self.color = self.color # call attributeSetter
|
|
3323
|
+
GL.glClearDepth(1.0)
|
|
3324
|
+
|
|
3325
|
+
# viewport or drawable area of the framebuffer
|
|
3326
|
+
self.viewport = self.scissor = \
|
|
3327
|
+
(0, 0, self.frameBufferSize[0], self.frameBufferSize[1])
|
|
3328
|
+
self.scissorTest = True
|
|
3329
|
+
self.stencilTest = False
|
|
3330
|
+
self.depthTest = False
|
|
3331
|
+
|
|
3332
|
+
if self.USE_LEGACY_GL:
|
|
3333
|
+
GL.glMatrixMode(GL.GL_PROJECTION) # Reset the projection matrix
|
|
3334
|
+
GL.glLoadIdentity()
|
|
3335
|
+
GL.gluOrtho2D(-1, 1, -1, 1)
|
|
3336
|
+
|
|
3337
|
+
GL.glMatrixMode(GL.GL_MODELVIEW) # Reset the modelview matrix
|
|
3338
|
+
GL.glLoadIdentity()
|
|
3339
|
+
|
|
3340
|
+
GL.glEnable(GL.GL_DEPTH_TEST) # Enables Depth Testing
|
|
3341
|
+
GL.glDepthFunc(GL.GL_LESS) # The Type Of Depth Test To Do
|
|
3342
|
+
|
|
3343
|
+
GL.glShadeModel(GL.GL_SMOOTH) # Color Shading (FLAT or SMOOTH)
|
|
3344
|
+
GL.glEnable(GL.GL_POINT_SMOOTH) # Enable Point Smoothing
|
|
3345
|
+
|
|
3346
|
+
GL.glEnable(GL.GL_BLEND)
|
|
3347
|
+
|
|
3348
|
+
# check for GL_ARB_texture_float
|
|
3349
|
+
# (which is needed for shaders to be useful)
|
|
3350
|
+
# this needs to be done AFTER the context has been created
|
|
3351
|
+
if not GL.gl_info.have_extension('GL_ARB_texture_float'):
|
|
3352
|
+
self._haveShaders = False
|
|
3353
|
+
|
|
3354
|
+
GL.glClear(GL.GL_COLOR_BUFFER_BIT)
|
|
3355
|
+
|
|
3356
|
+
# identify gfx card vendor
|
|
3357
|
+
self.glVendor = GL.gl_info.get_vendor().lower()
|
|
3358
|
+
|
|
3359
|
+
requestedFBO = self.useFBO
|
|
3360
|
+
if self._haveShaders: # do this after setting up FrameBufferObject
|
|
3361
|
+
self._setupShaders()
|
|
3362
|
+
else:
|
|
3363
|
+
self.useFBO = False
|
|
3364
|
+
if self.useFBO:
|
|
3365
|
+
success = self._setupFrameBuffer()
|
|
3366
|
+
if not success:
|
|
3367
|
+
self.useFBO = False
|
|
3368
|
+
if requestedFBO and not self.useFBO:
|
|
3369
|
+
logging.warning("Framebuffer object (FBO) not supported on "
|
|
3370
|
+
"this graphics card")
|
|
3371
|
+
if self.blendMode == 'add' and not self.useFBO:
|
|
3372
|
+
logging.warning("Framebuffer object (FBO) is required for "
|
|
3373
|
+
"blendMode='add'. Reverting to blendMode='avg'")
|
|
3374
|
+
self.blendMode = 'avg'
|
|
3375
|
+
|
|
3376
|
+
def _setupShaders(self):
|
|
3377
|
+
if self.USE_LEGACY_GL:
|
|
3378
|
+
self._progSignedTexFont = _shaders.compileProgram(
|
|
3379
|
+
_shaders.vertSimple, _shaders.fragSignedColorTexFont)
|
|
3380
|
+
else:
|
|
3381
|
+
self._progSignedTexFont = _shaders.compileProgram(
|
|
3382
|
+
_shaders.vertSimpleText, _shaders.fragSignedColorTexFont)
|
|
3383
|
+
|
|
3384
|
+
self._progFBOtoFrame = _shaders.compileProgram(
|
|
3385
|
+
_shaders.vertSimple, _shaders.fragFBOtoFrame)
|
|
3386
|
+
self._shaders = {}
|
|
3387
|
+
self._shaders['signedColor'] = _shaders.compileProgram(
|
|
3388
|
+
_shaders.vertSimple, _shaders.fragSignedColor)
|
|
3389
|
+
self._shaders['signedColor_adding'] = _shaders.compileProgram(
|
|
3390
|
+
_shaders.vertSimple, _shaders.fragSignedColor_adding)
|
|
3391
|
+
self._shaders['signedTex'] = _shaders.compileProgram(
|
|
3392
|
+
_shaders.vertSimple, _shaders.fragSignedColorTex)
|
|
3393
|
+
self._shaders['signedTexMask'] = _shaders.compileProgram(
|
|
3394
|
+
_shaders.vertSimple, _shaders.fragSignedColorTexMask)
|
|
3395
|
+
self._shaders['signedTexMask1D'] = _shaders.compileProgram(
|
|
3396
|
+
_shaders.vertSimple, _shaders.fragSignedColorTexMask1D)
|
|
3397
|
+
self._shaders['signedTex_adding'] = _shaders.compileProgram(
|
|
3398
|
+
_shaders.vertSimple, _shaders.fragSignedColorTex_adding)
|
|
3399
|
+
self._shaders['signedTexMask_adding'] = _shaders.compileProgram(
|
|
3400
|
+
_shaders.vertSimple, _shaders.fragSignedColorTexMask_adding)
|
|
3401
|
+
self._shaders['signedTexMask1D_adding'] = _shaders.compileProgram(
|
|
3402
|
+
_shaders.vertSimple, _shaders.fragSignedColorTexMask1D_adding)
|
|
3403
|
+
self._shaders['imageStim'] = _shaders.compileProgram(
|
|
3404
|
+
_shaders.vertSimple, _shaders.fragImageStim)
|
|
3405
|
+
self._shaders['imageStim_adding'] = _shaders.compileProgram(
|
|
3406
|
+
_shaders.vertSimple, _shaders.fragImageStim_adding)
|
|
3407
|
+
# self._shaders['stim3d_phong'] = {}
|
|
3408
|
+
|
|
3409
|
+
# # Create shader flags, these are used as keys to pick the appropriate
|
|
3410
|
+
# # shader for the given material and lighting configuration.
|
|
3411
|
+
# shaderFlags = []
|
|
3412
|
+
# for i in range(0, 8 + 1):
|
|
3413
|
+
# for j in product((True, False), repeat=1):
|
|
3414
|
+
# shaderFlags.append((i, j[0]))
|
|
3415
|
+
|
|
3416
|
+
# # Compile shaders based on generated flags.
|
|
3417
|
+
# for flag in shaderFlags:
|
|
3418
|
+
# # Define GLSL preprocessor values to enable code paths for specific
|
|
3419
|
+
# # material properties.
|
|
3420
|
+
# srcDefs = {'MAX_LIGHTS': flag[0]}
|
|
3421
|
+
|
|
3422
|
+
# if flag[1]: # has diffuse texture map
|
|
3423
|
+
# srcDefs['DIFFUSE_TEXTURE'] = 1
|
|
3424
|
+
|
|
3425
|
+
# # embed #DEFINE statements in GLSL source code
|
|
3426
|
+
# vertSrc = gltools.embedShaderSourceDefs(
|
|
3427
|
+
# _shaders.vertPhongLighting, srcDefs)
|
|
3428
|
+
# fragSrc = gltools.embedShaderSourceDefs(
|
|
3429
|
+
# _shaders.fragPhongLighting, srcDefs)
|
|
3430
|
+
|
|
3431
|
+
# # build a shader program
|
|
3432
|
+
# prog = gltools.createProgram()
|
|
3433
|
+
# vertexShader = gltools.compileShader(
|
|
3434
|
+
# vertSrc, GL.GL_VERTEX_SHADER)
|
|
3435
|
+
# fragmentShader = gltools.compileShader(
|
|
3436
|
+
# fragSrc, GL.GL_FRAGMENT_SHADER)
|
|
3437
|
+
|
|
3438
|
+
# gltools.attachShader(prog, vertexShader)
|
|
3439
|
+
# gltools.attachShader(prog, fragmentShader)
|
|
3440
|
+
# gltools.linkProgram(prog)
|
|
3441
|
+
# gltools.detachShader(prog, vertexShader)
|
|
3442
|
+
# gltools.detachShader(prog, fragmentShader)
|
|
3443
|
+
# gltools.deleteShader(vertexShader)
|
|
3444
|
+
# gltools.deleteShader(fragmentShader)
|
|
3445
|
+
|
|
3446
|
+
# # set the flag
|
|
3447
|
+
# self._shaders['stim3d_phong'][flag] = prog
|
|
3448
|
+
|
|
3449
|
+
def _setupFrameBuffer(self):
|
|
3450
|
+
"""Setup the framebuffer object for this window.
|
|
3451
|
+
|
|
3452
|
+
Returns
|
|
3453
|
+
-------
|
|
3454
|
+
bool
|
|
3455
|
+
`True` if the framebuffer was successfully setup, `False` otherwise.
|
|
3456
|
+
If `False`, the framebuffer was not complete. Make sure that your
|
|
3457
|
+
driver supports the necessary formats.
|
|
3458
|
+
|
|
3459
|
+
"""
|
|
3460
|
+
# Setup framebuffer
|
|
3461
|
+
self.frameBuffer = GL.GLuint()
|
|
3462
|
+
GL.glGenFramebuffers(1, ctypes.byref(self.frameBuffer))
|
|
3463
|
+
GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, self.frameBuffer)
|
|
3464
|
+
|
|
3465
|
+
# Create texture to render to
|
|
3466
|
+
self.frameTexture = GL.GLuint()
|
|
3467
|
+
GL.glGenTextures(1, ctypes.byref(self.frameTexture))
|
|
3468
|
+
GL.glBindTexture(GL.GL_TEXTURE_2D, self.frameTexture)
|
|
3469
|
+
GL.glTexParameteri(
|
|
3470
|
+
GL.GL_TEXTURE_2D,
|
|
3471
|
+
GL.GL_TEXTURE_MAG_FILTER,
|
|
3472
|
+
GL.GL_LINEAR)
|
|
3473
|
+
GL.glTexParameteri(
|
|
3474
|
+
GL.GL_TEXTURE_2D,
|
|
3475
|
+
GL.GL_TEXTURE_MIN_FILTER,
|
|
3476
|
+
GL.GL_LINEAR)
|
|
3477
|
+
GL.glTexImage2D(
|
|
3478
|
+
GL.GL_TEXTURE_2D, 0, GL.GL_RGBA32F,
|
|
3479
|
+
int(self.size[0]), int(self.size[1]), 0,
|
|
3480
|
+
GL.GL_RGBA, GL.GL_FLOAT, None)
|
|
3481
|
+
# attach texture to the frame buffer
|
|
3482
|
+
GL.glFramebufferTexture2D(
|
|
3483
|
+
GL.GL_FRAMEBUFFER,
|
|
3484
|
+
GL.GL_COLOR_ATTACHMENT0,
|
|
3485
|
+
GL.GL_TEXTURE_2D,
|
|
3486
|
+
self.frameTexture, 0)
|
|
3487
|
+
|
|
3488
|
+
# add a stencil buffer
|
|
3489
|
+
self._stencilTexture = GL.GLuint()
|
|
3490
|
+
GL.glGenRenderbuffers(1, ctypes.byref(
|
|
3491
|
+
self._stencilTexture)) # like glGenTextures
|
|
3492
|
+
GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, self._stencilTexture)
|
|
3493
|
+
GL.glRenderbufferStorage(
|
|
3494
|
+
GL.GL_RENDERBUFFER,
|
|
3495
|
+
GL.GL_DEPTH24_STENCIL8,
|
|
3496
|
+
int(self.size[0]), int(self.size[1]))
|
|
3497
|
+
GL.glFramebufferRenderbuffer(
|
|
3498
|
+
GL.GL_FRAMEBUFFER,
|
|
3499
|
+
GL.GL_DEPTH_ATTACHMENT,
|
|
3500
|
+
GL.GL_RENDERBUFFER,
|
|
3501
|
+
self._stencilTexture)
|
|
3502
|
+
GL.glFramebufferRenderbuffer(
|
|
3503
|
+
GL.GL_FRAMEBUFFER,
|
|
3504
|
+
GL.GL_STENCIL_ATTACHMENT,
|
|
3505
|
+
GL.GL_RENDERBUFFER,
|
|
3506
|
+
self._stencilTexture)
|
|
3507
|
+
|
|
3508
|
+
# check the framebuffer status
|
|
3509
|
+
status = GL.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER)
|
|
3510
|
+
if status != GL.GL_FRAMEBUFFER_COMPLETE:
|
|
3511
|
+
logging.error("Error in framebuffer activation")
|
|
3512
|
+
# UNBIND THE FRAME BUFFER OBJECT THAT WE HAD CREATED
|
|
3513
|
+
GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0)
|
|
3514
|
+
|
|
3515
|
+
return False
|
|
3516
|
+
|
|
3517
|
+
GL.glDisable(GL.GL_TEXTURE_2D)
|
|
3518
|
+
|
|
3519
|
+
# clear the buffers (otherwise the texture memory can contain
|
|
3520
|
+
# junk from other app)
|
|
3521
|
+
GL.glClear(GL.GL_COLOR_BUFFER_BIT)
|
|
3522
|
+
GL.glClear(GL.GL_STENCIL_BUFFER_BIT)
|
|
3523
|
+
GL.glClear(GL.GL_DEPTH_BUFFER_BIT)
|
|
3524
|
+
|
|
3525
|
+
return True
|
|
3526
|
+
|
|
3527
|
+
@property
|
|
3528
|
+
def mouseVisible(self):
|
|
3529
|
+
"""Returns the visibility of the mouse cursor."""
|
|
3530
|
+
return self.backend.mouseVisible
|
|
3531
|
+
|
|
3532
|
+
@mouseVisible.setter
|
|
3533
|
+
def mouseVisible(self, visibility):
|
|
3534
|
+
"""Sets the visibility of the mouse cursor.
|
|
3535
|
+
|
|
3536
|
+
If Window was initialized with ``allowGUI=False`` then the mouse is
|
|
3537
|
+
initially set to invisible, otherwise it will initially be visible.
|
|
3538
|
+
|
|
3539
|
+
Usage::
|
|
3540
|
+
|
|
3541
|
+
win.mouseVisible = False
|
|
3542
|
+
win.mouseVisible = True
|
|
3543
|
+
|
|
3544
|
+
"""
|
|
3545
|
+
self.backend.setMouseVisibility(visibility)
|
|
3546
|
+
|
|
3547
|
+
def setMouseVisible(self, visibility, log=None):
|
|
3548
|
+
"""Usually you can use 'stim.attribute = value' syntax instead,
|
|
3549
|
+
but use this method if you need to suppress the log message."""
|
|
3550
|
+
setAttribute(self, 'mouseVisible', visibility, log)
|
|
3551
|
+
|
|
3552
|
+
def setMouseType(self, name='arrow'):
|
|
3553
|
+
"""Change the appearance of the cursor for this window. Cursor types
|
|
3554
|
+
provide contextual hints about how to interact with on-screen objects.
|
|
3555
|
+
|
|
3556
|
+
The graphics used 'standard cursors' provided by the operating system.
|
|
3557
|
+
They may vary in appearance and hot spot location across platforms. The
|
|
3558
|
+
following names are valid on most platforms:
|
|
3559
|
+
|
|
3560
|
+
* ``arrow`` : Default pointer.
|
|
3561
|
+
* ``ibeam`` : Indicates text can be edited.
|
|
3562
|
+
* ``crosshair`` : Crosshair with hot-spot at center.
|
|
3563
|
+
* ``hand`` : A pointing hand.
|
|
3564
|
+
* ``hresize`` : Double arrows pointing horizontally.
|
|
3565
|
+
* ``vresize`` : Double arrows pointing vertically.
|
|
3566
|
+
|
|
3567
|
+
Parameters
|
|
3568
|
+
----------
|
|
3569
|
+
name : str
|
|
3570
|
+
Type of standard cursor to use (see above). Default is ``arrow``.
|
|
3571
|
+
|
|
3572
|
+
Notes
|
|
3573
|
+
-----
|
|
3574
|
+
* On Windows the ``crosshair`` option is negated with the background
|
|
3575
|
+
color. It will not be visible when placed over 50% grey fields.
|
|
3576
|
+
|
|
3577
|
+
"""
|
|
3578
|
+
if hasattr(self.backend, "setMouseType"):
|
|
3579
|
+
self.backend.setMouseType(name)
|
|
3580
|
+
|
|
3581
|
+
def showPilotingIndicator(self):
|
|
3582
|
+
"""
|
|
3583
|
+
Show the visual indicator which shows we are in piloting mode.
|
|
3584
|
+
"""
|
|
3585
|
+
# if we haven't made the indicator yet, do that now
|
|
3586
|
+
if self._pilotingIndicator is None:
|
|
3587
|
+
self._pilotingIndicator = TextBox2(
|
|
3588
|
+
self, text=_translate("PILOTING: Switch to run mode before testing."),
|
|
3589
|
+
letterHeight=0.1, alignment="bottom left",
|
|
3590
|
+
units="norm", size=(2, 2),
|
|
3591
|
+
borderColor="#EC9703", color="#EC9703", fillColor="transparent",
|
|
3592
|
+
borderWidth=20,
|
|
3593
|
+
autoDraw=False
|
|
3594
|
+
)
|
|
3595
|
+
# mark it as to be shown
|
|
3596
|
+
self._showPilotingIndicator = True
|
|
3597
|
+
|
|
3598
|
+
def hidePilotingIndicator(self):
|
|
3599
|
+
"""
|
|
3600
|
+
Hide the visual indicator which shows we are in piloting mode.
|
|
3601
|
+
"""
|
|
3602
|
+
# mark indicator as to be hidden
|
|
3603
|
+
self._showPilotingIndicator = False
|
|
3604
|
+
|
|
3605
|
+
def showMessage(self, msg):
|
|
3606
|
+
"""Show a message in the window. This can be used to show information
|
|
3607
|
+
to the participant.
|
|
3608
|
+
|
|
3609
|
+
This creates a TextBox2 object that is displayed in the window. The
|
|
3610
|
+
text can be updated by calling this method again with a new message.
|
|
3611
|
+
The updated text will appear the next time `draw()` is called.
|
|
3612
|
+
|
|
3613
|
+
Parameters
|
|
3614
|
+
----------
|
|
3615
|
+
msg : str or None
|
|
3616
|
+
Message text to display. If None, then any existing message is
|
|
3617
|
+
removed.
|
|
3618
|
+
|
|
3619
|
+
"""
|
|
3620
|
+
if msg is None:
|
|
3621
|
+
self.hideMessage()
|
|
3622
|
+
else:
|
|
3623
|
+
self._showSplash = True
|
|
3624
|
+
|
|
3625
|
+
if self._splashTextbox is None: # create the textbox
|
|
3626
|
+
self._splashTextbox = TextBox2(
|
|
3627
|
+
self, text=msg,
|
|
3628
|
+
units="norm", size=(2, 2), alignment="center", # full screen and centred
|
|
3629
|
+
letterHeight=0.1, # font size relative to window
|
|
3630
|
+
autoDraw=False
|
|
3631
|
+
)
|
|
3632
|
+
else:
|
|
3633
|
+
self._splashTextbox.text = str(msg) # update the text
|
|
3634
|
+
# set text color to contrast with background
|
|
3635
|
+
self._splashTextbox.color = self._color.getReadable(contrast=1)
|
|
3636
|
+
|
|
3637
|
+
def hideMessage(self):
|
|
3638
|
+
"""Remove any message that is currently being displayed."""
|
|
3639
|
+
self._showSplash = False
|
|
3640
|
+
|
|
3641
|
+
def getActualFrameRate(self, nIdentical=10, nMaxFrames=100,
|
|
3642
|
+
nWarmUpFrames=10, threshold=1, infoMsg=None):
|
|
3643
|
+
"""Measures the actual frames-per-second (FPS) for the screen.
|
|
3644
|
+
|
|
3645
|
+
This is done by waiting (for a max of `nMaxFrames`) until
|
|
3646
|
+
`nIdentical` frames in a row have identical frame times (std dev below
|
|
3647
|
+
`threshold` ms).
|
|
3648
|
+
|
|
3649
|
+
Parameters
|
|
3650
|
+
----------
|
|
3651
|
+
nIdentical : int, optional
|
|
3652
|
+
The number of consecutive frames that will be evaluated.
|
|
3653
|
+
Higher --> greater precision. Lower --> faster.
|
|
3654
|
+
nMaxFrames : int, optional
|
|
3655
|
+
The maximum number of frames to wait for a matching set of
|
|
3656
|
+
nIdentical.
|
|
3657
|
+
nWarmUpFrames : int, optional
|
|
3658
|
+
The number of frames to display before starting the test
|
|
3659
|
+
(this is in place to allow the system to settle after opening
|
|
3660
|
+
the `Window` for the first time.
|
|
3661
|
+
threshold : int or float, optional
|
|
3662
|
+
The threshold for the std deviation (in ms) before the set
|
|
3663
|
+
are considered a match.
|
|
3664
|
+
|
|
3665
|
+
Returns
|
|
3666
|
+
-------
|
|
3667
|
+
float or None
|
|
3668
|
+
Frame rate (FPS) in seconds. If there is no such sequence of
|
|
3669
|
+
identical frames a warning is logged and `None` will be returned.
|
|
3670
|
+
|
|
3671
|
+
"""
|
|
3672
|
+
if nIdentical > nMaxFrames:
|
|
3673
|
+
raise ValueError(
|
|
3674
|
+
'Parameter `nIdentical` must be equal to or less than '
|
|
3675
|
+
'`nMaxFrames`')
|
|
3676
|
+
|
|
3677
|
+
screen = self.screen
|
|
3678
|
+
name = self.name
|
|
3679
|
+
|
|
3680
|
+
if infoMsg is None:
|
|
3681
|
+
infoMsg = "Attempting to measure frame rate of screen, please wait ..."
|
|
3682
|
+
|
|
3683
|
+
self.showMessage(infoMsg)
|
|
3684
|
+
|
|
3685
|
+
# log that we're measuring the frame rate now
|
|
3686
|
+
if self.autoLog:
|
|
3687
|
+
msg = "{}: Attempting to measure frame rate of screen ({:d}) ..."
|
|
3688
|
+
logging.exp(msg.format(name, screen))
|
|
3689
|
+
|
|
3690
|
+
# Disable `recordFrameIntervals` prior to the warmup as we expect to see
|
|
3691
|
+
# some instability here.
|
|
3692
|
+
recordFrmIntsOrig = self.recordFrameIntervals
|
|
3693
|
+
self.recordFrameIntervals = False
|
|
3694
|
+
|
|
3695
|
+
# warm-up, allow the system to settle a bit before measuring frames
|
|
3696
|
+
for frameN in range(nWarmUpFrames):
|
|
3697
|
+
self.flip()
|
|
3698
|
+
|
|
3699
|
+
# run test frames
|
|
3700
|
+
self.recordFrameIntervals = True # record intervals for actual test
|
|
3701
|
+
threshSecs = threshold / 1000.0 # must be in seconds
|
|
3702
|
+
for frameN in range(nMaxFrames):
|
|
3703
|
+
self.flip()
|
|
3704
|
+
recentFrames = self.frameIntervals[-nIdentical:]
|
|
3705
|
+
nIntervals = len(self.frameIntervals)
|
|
3706
|
+
if len(recentFrames) < 3:
|
|
3707
|
+
continue # no need to check variance yet
|
|
3708
|
+
recentFramesStd = numpy.std(recentFrames) # compute variability
|
|
3709
|
+
if nIntervals >= nIdentical and recentFramesStd < threshSecs:
|
|
3710
|
+
# average duration of recent frames
|
|
3711
|
+
period = numpy.mean(recentFrames) # log this too?
|
|
3712
|
+
rate = 1.0 / period # compute frame rate in Hz
|
|
3713
|
+
if self.autoLog:
|
|
3714
|
+
scrStr = "" if screen is None else " (%i)" % screen
|
|
3715
|
+
msg = "Screen{} actual frame rate measured at {:.2f}Hz"
|
|
3716
|
+
logging.exp(msg.format(scrStr, rate))
|
|
3717
|
+
|
|
3718
|
+
self.recordFrameIntervals = recordFrmIntsOrig
|
|
3719
|
+
self.frameIntervals = []
|
|
3720
|
+
self.hideMessage() # remove the message
|
|
3721
|
+
return rate
|
|
3722
|
+
|
|
3723
|
+
self.hideMessage() # remove the message
|
|
3724
|
+
|
|
3725
|
+
# if we get here we reached end of `maxFrames` with no consistent value
|
|
3726
|
+
msg = ("Couldn't measure a consistent frame rate!\n"
|
|
3727
|
+
" - Is your graphics card set to sync to vertical blank?\n"
|
|
3728
|
+
" - Are you running other processes on your computer?\n")
|
|
3729
|
+
logging.warning(msg)
|
|
3730
|
+
|
|
3731
|
+
return None
|
|
3732
|
+
|
|
3733
|
+
def getMsPerFrame(self, nFrames=60, showVisual=False, msg='', msDelay=0.):
|
|
3734
|
+
"""Assesses the monitor refresh rate (average, median, SD) under
|
|
3735
|
+
current conditions, over at least 60 frames.
|
|
3736
|
+
|
|
3737
|
+
Records time for each refresh (frame) for n frames (at least 60),
|
|
3738
|
+
while displaying an optional visual. The visual is just eye-candy to
|
|
3739
|
+
show that something is happening when assessing many frames. You can
|
|
3740
|
+
also give it text to display instead of a visual,
|
|
3741
|
+
e.g., ``msg='(testing refresh rate...)'``; setting msg implies
|
|
3742
|
+
``showVisual == False``.
|
|
3743
|
+
|
|
3744
|
+
To simulate refresh rate under cpu load, you can specify a time to
|
|
3745
|
+
wait within the loop prior to doing the :py:attr:`~Window.flip()`.
|
|
3746
|
+
If 0 < msDelay < 100, wait for that long in ms.
|
|
3747
|
+
|
|
3748
|
+
Returns timing stats (in ms) of:
|
|
3749
|
+
|
|
3750
|
+
- average time per frame, for all frames
|
|
3751
|
+
- standard deviation of all frames
|
|
3752
|
+
- median, as the average of 12 frame times around the median
|
|
3753
|
+
(~monitor refresh rate)
|
|
3754
|
+
|
|
3755
|
+
:Author:
|
|
3756
|
+
- 2010 written by Jeremy Gray
|
|
3757
|
+
|
|
3758
|
+
"""
|
|
3759
|
+
|
|
3760
|
+
# lower bound of 60 samples--need enough to estimate the SD
|
|
3761
|
+
nFrames = max(60, nFrames)
|
|
3762
|
+
num2avg = 12 # how many to average from around the median
|
|
3763
|
+
if len(msg):
|
|
3764
|
+
showVisual = False
|
|
3765
|
+
showText = True
|
|
3766
|
+
myMsg = TextStim(self, text=msg, italic=True,
|
|
3767
|
+
color=(.7, .6, .5), colorSpace='rgb',
|
|
3768
|
+
height=0.1, autoLog=False)
|
|
3769
|
+
else:
|
|
3770
|
+
showText = False
|
|
3771
|
+
if showVisual:
|
|
3772
|
+
x, y = self.size
|
|
3773
|
+
myStim = GratingStim(self, tex='sin', mask='gauss',
|
|
3774
|
+
size=[.6 * y / float(x), .6], sf=3.0,
|
|
3775
|
+
opacity=.2,
|
|
3776
|
+
autoLog=False)
|
|
3777
|
+
clockt = [] # clock times
|
|
3778
|
+
# end of drawing time, in clock time units,
|
|
3779
|
+
# for testing how long myStim.draw() takes
|
|
3780
|
+
drawt = []
|
|
3781
|
+
|
|
3782
|
+
if msDelay > 0 and msDelay < 100:
|
|
3783
|
+
doWait = True
|
|
3784
|
+
delayTime = msDelay / 1000. # sec
|
|
3785
|
+
else:
|
|
3786
|
+
doWait = False
|
|
3787
|
+
|
|
3788
|
+
winUnitsSaved = self.units
|
|
3789
|
+
# norm is required for the visual (or text) display, as coded below
|
|
3790
|
+
self.units = 'norm'
|
|
3791
|
+
|
|
3792
|
+
# accumulate secs per frame (and time-to-draw) for a bunch of frames:
|
|
3793
|
+
rush(True)
|
|
3794
|
+
for i in range(5): # wake everybody up
|
|
3795
|
+
self.flip()
|
|
3796
|
+
for i in range(nFrames): # ... and go for real this time
|
|
3797
|
+
clockt.append(core.getTime())
|
|
3798
|
+
if showVisual:
|
|
3799
|
+
myStim.setPhase(1.0 / nFrames, '+', log=False)
|
|
3800
|
+
myStim.setSF(3. / nFrames, '+', log=False)
|
|
3801
|
+
myStim.setOri(12. / nFrames, '+', log=False)
|
|
3802
|
+
myStim.setOpacity(.9 / nFrames, '+', log=False)
|
|
3803
|
+
myStim.draw()
|
|
3804
|
+
elif showText:
|
|
3805
|
+
myMsg.draw()
|
|
3806
|
+
if doWait:
|
|
3807
|
+
core.wait(delayTime)
|
|
3808
|
+
drawt.append(core.getTime())
|
|
3809
|
+
self.flip()
|
|
3810
|
+
rush(False)
|
|
3811
|
+
|
|
3812
|
+
self.units = winUnitsSaved # restore
|
|
3813
|
+
|
|
3814
|
+
frameTimes = [(clockt[i] - clockt[i - 1])
|
|
3815
|
+
for i in range(1, len(clockt))]
|
|
3816
|
+
drawTimes = [(drawt[i] - clockt[i]) for
|
|
3817
|
+
i in range(len(clockt))] # == drawing only
|
|
3818
|
+
freeTimes = [frameTimes[i] - drawTimes[i] for
|
|
3819
|
+
i in range(len(frameTimes))] # == unused time
|
|
3820
|
+
|
|
3821
|
+
# cast to float so that the resulting type == type(0.123)
|
|
3822
|
+
# for median
|
|
3823
|
+
frameTimes.sort()
|
|
3824
|
+
# median-most slice
|
|
3825
|
+
msPFmed = 1000. * float(numpy.average(
|
|
3826
|
+
frameTimes[((nFrames - num2avg) // 2):((nFrames + num2avg) // 2)]))
|
|
3827
|
+
msPFavg = 1000. * float(numpy.average(frameTimes))
|
|
3828
|
+
msPFstd = 1000. * float(numpy.std(frameTimes))
|
|
3829
|
+
msdrawAvg = 1000. * float(numpy.average(drawTimes))
|
|
3830
|
+
msdrawSD = 1000. * float(numpy.std(drawTimes))
|
|
3831
|
+
msfree = 1000. * float(numpy.average(freeTimes))
|
|
3832
|
+
|
|
3833
|
+
return msPFavg, msPFstd, msPFmed # msdrawAvg, msdrawSD, msfree
|
|
3834
|
+
|
|
3835
|
+
def _startOfFlip(self):
|
|
3836
|
+
"""Custom hardware classes may want to prevent flipping from
|
|
3837
|
+
occurring and can override this method as needed.
|
|
3838
|
+
|
|
3839
|
+
Return `True` to indicate hardware flip.
|
|
3840
|
+
"""
|
|
3841
|
+
return True
|
|
3842
|
+
|
|
3843
|
+
def _renderFBO(self):
|
|
3844
|
+
"""Perform a warp operation.
|
|
3845
|
+
|
|
3846
|
+
(in this case a copy operation without any warping)
|
|
3847
|
+
"""
|
|
3848
|
+
if self.USE_LEGACY_GL:
|
|
3849
|
+
GL.glBegin(GL.GL_QUADS)
|
|
3850
|
+
GL.glTexCoord2f(0.0, 0.0)
|
|
3851
|
+
GL.glVertex2f(-1.0, -1.0)
|
|
3852
|
+
GL.glTexCoord2f(0.0, 1.0)
|
|
3853
|
+
GL.glVertex2f(-1.0, 1.0)
|
|
3854
|
+
GL.glTexCoord2f(1.0, 1.0)
|
|
3855
|
+
GL.glVertex2f(1.0, 1.0)
|
|
3856
|
+
GL.glTexCoord2f(1.0, 0.0)
|
|
3857
|
+
GL.glVertex2f(1.0, -1.0)
|
|
3858
|
+
GL.glEnd()
|
|
3859
|
+
else:
|
|
3860
|
+
gltools.setUniformSampler2D(self._progFBOtoFrame, b'texture', 0)
|
|
3861
|
+
gltools.drawClientArrays({
|
|
3862
|
+
'gl_Vertex': self._fboVerts,
|
|
3863
|
+
'gl_MultiTexCoord0': self._fboTexCoords},
|
|
3864
|
+
'GL_QUADS')
|
|
3865
|
+
|
|
3866
|
+
def _prepareFBOrender(self):
|
|
3867
|
+
gltools.useProgram(self._progFBOtoFrame)
|
|
3868
|
+
|
|
3869
|
+
def _finishFBOrender(self):
|
|
3870
|
+
gltools.useProgram(None)
|
|
3871
|
+
|
|
3872
|
+
def _afterFBOrender(self):
|
|
3873
|
+
pass
|
|
3874
|
+
|
|
3875
|
+
def _endOfFlip(self, clearBuffer):
|
|
3876
|
+
"""Override end of flip with custom color channel masking if required.
|
|
3877
|
+
"""
|
|
3878
|
+
if clearBuffer:
|
|
3879
|
+
GL.glClear(GL.GL_COLOR_BUFFER_BIT)
|
|
3880
|
+
|
|
3881
|
+
|
|
3882
|
+
def getMsPerFrame(myWin, nFrames=60, showVisual=False, msg='', msDelay=0.):
|
|
3883
|
+
"""
|
|
3884
|
+
Deprecated: please use the getMsPerFrame method in the
|
|
3885
|
+
`psychopy.visual.Window` class.
|
|
3886
|
+
|
|
3887
|
+
Assesses the monitor refresh rate (average, median, SD) under current
|
|
3888
|
+
conditions, over at least 60 frames.
|
|
3889
|
+
|
|
3890
|
+
Records time for each refresh (frame) for n frames (at least 60), while
|
|
3891
|
+
displaying an optional visual. The visual is just eye-candy to show that
|
|
3892
|
+
something is happening when assessing many frames. You can also give it
|
|
3893
|
+
text to display instead of a visual, e.g.,
|
|
3894
|
+
msg='(testing refresh rate...)'; setting msg implies showVisual == False.
|
|
3895
|
+
To simulate refresh rate under
|
|
3896
|
+
cpu load, you can specify a time to wait within the loop prior to
|
|
3897
|
+
doing the win.flip(). If 0 < msDelay < 100, wait for that long in ms.
|
|
3898
|
+
|
|
3899
|
+
Returns timing stats (in ms) of:
|
|
3900
|
+
|
|
3901
|
+
- average time per frame, for all frames
|
|
3902
|
+
- standard deviation of all frames
|
|
3903
|
+
- median, as the average of 12 frame times around the median
|
|
3904
|
+
(~monitor refresh rate)
|
|
3905
|
+
|
|
3906
|
+
:Author:
|
|
3907
|
+
- 2010 written by Jeremy Gray
|
|
3908
|
+
"""
|
|
3909
|
+
return myWin.getMsPerFrame(nFrames=60, showVisual=showVisual, msg=msg,
|
|
3910
|
+
msDelay=0.)
|