psychopy 2024.1.4__py3-none-any.whl → 2024.2.0__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.

Potentially problematic release.


This version of psychopy might be problematic. Click here for more details.

Files changed (325) hide show
  1. psychopy/.DS_Store +0 -0
  2. psychopy/CHANGELOG.txt +206 -0
  3. psychopy/GIT_SHA +1 -0
  4. psychopy/VERSION +1 -0
  5. psychopy/__init__.py +77 -15
  6. psychopy/app/Resources/classic/plugin16.png +0 -0
  7. psychopy/app/Resources/classic/plugin16@2x.png +0 -0
  8. psychopy/app/Resources/dark/plugin16.png +0 -0
  9. psychopy/app/Resources/dark/plugin16@2x.png +0 -0
  10. psychopy/app/Resources/light/plugin16.png +0 -0
  11. psychopy/app/Resources/light/plugin16@2x.png +0 -0
  12. psychopy/app/__init__.py +76 -2
  13. psychopy/app/_psychopyApp.py +126 -101
  14. psychopy/app/builder/builder.py +14 -10
  15. psychopy/app/builder/dialogs/__init__.py +8 -8
  16. psychopy/app/builder/dialogs/dlgsConditions.py +12 -13
  17. psychopy/app/builder/dialogs/paramCtrls.py +24 -57
  18. psychopy/app/builder/validators.py +2 -2
  19. psychopy/app/coder/codeEditorBase.py +8 -8
  20. psychopy/app/coder/coder.py +4 -4
  21. psychopy/app/connections/sendusage.py +2 -2
  22. psychopy/app/connections/updates.py +9 -9
  23. psychopy/app/dialogs.py +34 -2
  24. psychopy/app/idle.py +31 -0
  25. psychopy/app/jobs.py +21 -3
  26. psychopy/app/linuxconfig/__init__.py +9 -0
  27. psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
  28. psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +4602 -2540
  29. psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
  30. psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +56 -54
  31. psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +53 -43
  32. psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
  33. psychopy/app/locale/es_US/LC_MESSAGE/messages.po +56 -54
  34. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
  35. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +1011 -942
  36. psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +9415 -5
  37. psychopy/app/pavlovia_ui/_base.py +33 -3
  38. psychopy/app/pavlovia_ui/search.py +0 -1
  39. psychopy/app/plugin_manager/dialog.py +104 -51
  40. psychopy/app/plugin_manager/packages.py +5 -0
  41. psychopy/app/plugin_manager/plugins.py +145 -67
  42. psychopy/app/preferencesDlg.py +8 -8
  43. psychopy/app/psychopyApp.py +11 -5
  44. psychopy/app/ribbon.py +124 -14
  45. psychopy/app/runner/runner.py +6 -1
  46. psychopy/app/stdout/stdOutRich.py +27 -11
  47. psychopy/app/themes/icons.py +52 -2
  48. psychopy/assets/__init__.py +0 -0
  49. psychopy/assets/click.png +0 -0
  50. psychopy/assets/clicknext.png +0 -0
  51. psychopy/assets/next.png +0 -0
  52. psychopy/assets/psychopy.ico +0 -0
  53. psychopy/assets/psychopy.png +0 -0
  54. psychopy/assets/templates/__init__.py +0 -0
  55. psychopy/assets/touch.png +0 -0
  56. psychopy/assets/touchnext.png +0 -0
  57. psychopy/assets/window.ico +0 -0
  58. psychopy/changes/2023.1.0.md +9 -0
  59. psychopy/changes/2024.1.0.md +16 -0
  60. psychopy/changes/__init__.py +0 -0
  61. psychopy/clock.py +2 -2
  62. psychopy/colors.py +2 -1
  63. psychopy/compatibility.py +53 -1
  64. psychopy/contrib/.DS_Store +0 -0
  65. psychopy/contrib/configobj/__init__.py +10 -8
  66. psychopy/data/__init__.py +3 -2
  67. psychopy/data/base.py +5 -5
  68. psychopy/data/experiment.py +130 -4
  69. psychopy/data/routine.py +56 -0
  70. psychopy/data/staircase.py +2 -2
  71. psychopy/data/trial.py +559 -97
  72. psychopy/data/utils.py +56 -21
  73. psychopy/demos/.DS_Store +0 -0
  74. psychopy/demos/builder/.DS_Store +0 -0
  75. psychopy/demos/builder/Design Templates/.DS_Store +0 -0
  76. psychopy/demos/builder/Experiments/.DS_Store +0 -0
  77. psychopy/demos/builder/Feature Demos/.DS_Store +0 -0
  78. psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +375 -0
  79. psychopy/demos/builder/Feature Demos/buttonBox/readme.md +5 -0
  80. psychopy/demos/builder/Feature Demos/pilotMode/pilotMode.psyexp +433 -0
  81. psychopy/demos/builder/Feature Demos/pilotMode/readme.md +7 -0
  82. psychopy/demos/builder/Hardware/.DS_Store +0 -0
  83. psychopy/demos/builder/Helper Tools/.DS_Store +0 -0
  84. psychopy/demos/coder/.DS_Store +0 -0
  85. psychopy/demos/coder/hardware/testSoundLatency.py +2 -2
  86. psychopy/demos/coder/iohub/.DS_Store +0 -0
  87. psychopy/demos/coder/misc/hdf5_2_csv +33 -0
  88. psychopy/event.py +30 -29
  89. psychopy/experiment/.DS_Store +0 -0
  90. psychopy/experiment/_experiment.py +6 -6
  91. psychopy/experiment/components/.DS_Store +0 -0
  92. psychopy/experiment/components/__init__.py +6 -3
  93. psychopy/experiment/components/_base.py +286 -131
  94. psychopy/experiment/components/aperture/.DS_Store +0 -0
  95. psychopy/experiment/components/brush/.DS_Store +0 -0
  96. psychopy/experiment/components/button/.DS_Store +0 -0
  97. psychopy/experiment/components/button/__init__.py +5 -1
  98. psychopy/experiment/components/buttonBox/.DS_Store +0 -0
  99. psychopy/experiment/components/camera/.DS_Store +0 -0
  100. psychopy/experiment/components/code/.DS_Store +0 -0
  101. psychopy/experiment/components/dots/.DS_Store +0 -0
  102. psychopy/experiment/components/eyetracker_record/.DS_Store +0 -0
  103. psychopy/experiment/components/eyetracker_record/__init__.py +92 -30
  104. psychopy/experiment/components/form/.DS_Store +0 -0
  105. psychopy/experiment/components/form/__init__.py +6 -2
  106. psychopy/experiment/components/grating/.DS_Store +0 -0
  107. psychopy/experiment/components/grating/__init__.py +14 -3
  108. psychopy/experiment/components/image/.DS_Store +0 -0
  109. psychopy/experiment/components/image/__init__.py +14 -3
  110. psychopy/experiment/components/joyButtons/.DS_Store +0 -0
  111. psychopy/experiment/components/joystick/.DS_Store +0 -0
  112. psychopy/experiment/components/keyboard/.DS_Store +0 -0
  113. psychopy/experiment/components/keyboard/__init__.py +22 -10
  114. psychopy/experiment/components/microphone/.DS_Store +0 -0
  115. psychopy/experiment/components/microphone/__init__.py +59 -39
  116. psychopy/experiment/components/mouse/.DS_Store +0 -0
  117. psychopy/experiment/components/mouse/__init__.py +44 -29
  118. psychopy/experiment/components/movie/.DS_Store +0 -0
  119. psychopy/experiment/components/movie/__init__.py +1 -1
  120. psychopy/experiment/components/panorama/.DS_Store +0 -0
  121. psychopy/experiment/components/parallelOut/.DS_Store +0 -0
  122. psychopy/experiment/components/patch/.DS_Store +0 -0
  123. psychopy/experiment/components/polygon/.DS_Store +0 -0
  124. psychopy/experiment/components/polygon/__init__.py +26 -6
  125. psychopy/experiment/components/progress/.DS_Store +0 -0
  126. psychopy/experiment/components/ratingScale/.DS_Store +0 -0
  127. psychopy/experiment/components/resourceManager/.DS_Store +0 -0
  128. psychopy/experiment/components/roi/.DS_Store +0 -0
  129. psychopy/experiment/components/roi/__init__.py +5 -0
  130. psychopy/experiment/components/routineSettings/.DS_Store +0 -0
  131. psychopy/experiment/components/routineSettings/__init__.py +57 -10
  132. psychopy/experiment/components/serialOut/.DS_Store +0 -0
  133. psychopy/experiment/components/settings/.DS_Store +0 -0
  134. psychopy/experiment/components/settings/__init__.py +117 -42
  135. psychopy/experiment/components/slider/.DS_Store +0 -0
  136. psychopy/experiment/components/sound/.DS_Store +0 -0
  137. psychopy/experiment/components/sound/__init__.py +54 -19
  138. psychopy/experiment/components/static/.DS_Store +0 -0
  139. psychopy/experiment/components/static/__init__.py +1 -1
  140. psychopy/experiment/components/text/.DS_Store +0 -0
  141. psychopy/experiment/components/text/__init__.py +28 -3
  142. psychopy/experiment/components/textbox/.DS_Store +0 -0
  143. psychopy/experiment/components/textbox/__init__.py +12 -2
  144. psychopy/experiment/components/unknown/.DS_Store +0 -0
  145. psychopy/experiment/components/unknown/__init__.py +1 -2
  146. psychopy/experiment/components/unknownPlugin/.DS_Store +0 -0
  147. psychopy/experiment/components/unknownPlugin/__init__.py +2 -2
  148. psychopy/experiment/components/variable/.DS_Store +0 -0
  149. psychopy/experiment/flow.py +11 -4
  150. psychopy/experiment/loops.py +85 -37
  151. psychopy/experiment/params.py +74 -32
  152. psychopy/experiment/py2js_transpiler.py +8 -1
  153. psychopy/experiment/routines/.DS_Store +0 -0
  154. psychopy/experiment/routines/_base.py +102 -22
  155. psychopy/experiment/routines/counterbalance/.DS_Store +0 -0
  156. psychopy/experiment/routines/counterbalance/__init__.py +5 -1
  157. psychopy/experiment/routines/eyetracker_calibrate/.DS_Store +0 -0
  158. psychopy/experiment/routines/eyetracker_validate/.DS_Store +0 -0
  159. psychopy/experiment/routines/pavlovia_survey/.DS_Store +0 -0
  160. psychopy/experiment/routines/photodiodeValidator/.DS_Store +0 -0
  161. psychopy/experiment/routines/photodiodeValidator/__init__.py +6 -5
  162. psychopy/experiment/routines/unknown/.DS_Store +0 -0
  163. psychopy/gui/wxgui.py +4 -4
  164. psychopy/hardware/.DS_Store +0 -0
  165. psychopy/hardware/__init__.py +1 -1
  166. psychopy/hardware/base.py +12 -0
  167. psychopy/hardware/camera/__init__.py +1 -15
  168. psychopy/hardware/cedrus.py +10 -11
  169. psychopy/hardware/crs/colorcal.py +13 -22
  170. psychopy/hardware/crs/optical.py +10 -20
  171. psychopy/hardware/emulator.py +17 -14
  172. psychopy/hardware/eyetracker.py +42 -118
  173. psychopy/hardware/gammasci.py +4 -15
  174. psychopy/hardware/keyboard.py +102 -10
  175. psychopy/hardware/listener.py +3 -0
  176. psychopy/hardware/microphone.py +148 -18
  177. psychopy/hardware/minolta.py +8 -15
  178. psychopy/hardware/photodiode.py +191 -16
  179. psychopy/hardware/photometer/__init__.py +11 -19
  180. psychopy/hardware/pr.py +8 -15
  181. psychopy/hardware/speaker.py +39 -4
  182. psychopy/info.py +0 -71
  183. psychopy/iohub/.DS_Store +0 -0
  184. psychopy/iohub/__init__.py +1 -1
  185. psychopy/iohub/client/__init__.py +30 -20
  186. psychopy/iohub/client/keyboard.py +24 -24
  187. psychopy/iohub/datastore/__init__.py +2 -2
  188. psychopy/iohub/datastore/util.py +2 -2
  189. psychopy/iohub/default_config.yaml +1 -1
  190. psychopy/iohub/devices/.DS_Store +0 -0
  191. psychopy/iohub/devices/__init__.py +112 -25
  192. psychopy/iohub/devices/deviceConfigValidation.py +2 -1
  193. psychopy/iohub/devices/experiment/default_experiment.yaml +12 -1
  194. psychopy/iohub/devices/experiment/supported_config_settings.yaml +5 -1
  195. psychopy/iohub/devices/eyetracker/.DS_Store +0 -0
  196. psychopy/iohub/devices/eyetracker/__init__.py +46 -0
  197. psychopy/iohub/devices/eyetracker/calibration/procedure.py +2 -2
  198. psychopy/iohub/devices/eyetracker/hw/gazepoint/__init__.py +14 -2
  199. psychopy/iohub/devices/eyetracker/hw/mouse/eyetracker.py +3 -4
  200. psychopy/iohub/server.py +2 -2
  201. psychopy/iohub/start_iohub_process.py +3 -0
  202. psychopy/iohub/util/__init__.py +62 -70
  203. psychopy/layout.py +5 -5
  204. psychopy/logging.py +8 -1
  205. psychopy/microphone.py +10 -37
  206. psychopy/platform_specific/__init__.py +0 -2
  207. psychopy/platform_specific/darwin.py +1 -3
  208. psychopy/platform_specific/linux.py +31 -33
  209. psychopy/platform_specific/win32.py +38 -13
  210. psychopy/plugins/__init__.py +148 -116
  211. psychopy/plugins/util.py +39 -0
  212. psychopy/preferences/Darwin.spec +4 -2
  213. psychopy/preferences/FreeBSD.spec +4 -2
  214. psychopy/preferences/Linux.spec +4 -2
  215. psychopy/preferences/Windows.spec +4 -2
  216. psychopy/preferences/baseNoArch.spec +4 -2
  217. psychopy/preferences/preferences.py +47 -24
  218. psychopy/projects/pavlovia.py +47 -4
  219. psychopy/scripts/psyexpCompile.py +0 -4
  220. psychopy/session.py +153 -21
  221. psychopy/sound/__init__.py +31 -21
  222. psychopy/sound/_base.py +20 -3
  223. psychopy/sound/audioclip.py +320 -33
  224. psychopy/sound/backend_ptb.py +47 -58
  225. psychopy/sound/backend_pygame.py +1 -1
  226. psychopy/sound/backend_pysound.py +6 -15
  227. psychopy/sound/transcribe.py +53 -0
  228. psychopy/tests/.DS_Store +0 -0
  229. psychopy/tests/data/.DS_Store +0 -0
  230. psychopy/tests/data/TestUnknownPluginComponent_load_resave.psyexp +135 -0
  231. psychopy/tests/data/Test_textbox/test_ori_0_bottom right.png +0 -0
  232. psychopy/tests/data/Test_textbox/test_ori_0_center.png +0 -0
  233. psychopy/tests/data/Test_textbox/test_ori_0_top left.png +0 -0
  234. psychopy/tests/data/Test_textbox/test_ori_120_bottom right.png +0 -0
  235. psychopy/tests/data/Test_textbox/test_ori_120_center.png +0 -0
  236. psychopy/tests/data/Test_textbox/test_ori_120_top left.png +0 -0
  237. psychopy/tests/data/Test_textbox/test_ori_180_bottom right.png +0 -0
  238. psychopy/tests/data/Test_textbox/test_ori_180_center.png +0 -0
  239. psychopy/tests/data/Test_textbox/test_ori_180_top left.png +0 -0
  240. psychopy/tests/data/Test_textbox/test_ori_240_bottom right.png +0 -0
  241. psychopy/tests/data/Test_textbox/test_ori_240_center.png +0 -0
  242. psychopy/tests/data/Test_textbox/test_ori_240_top left.png +0 -0
  243. psychopy/tests/data/correctScript/.DS_Store +0 -0
  244. psychopy/tests/data/test_components/testClearKeyboard/testClearKeyboard.psyexp +200 -0
  245. psychopy/tests/data/test_session/.DS_Store +0 -0
  246. psychopy/tests/data/test_session/root/testFutureTrials/testFutureTrials.psyexp +155 -0
  247. psychopy/tests/data/test_session/root/testTrialNav/trialNav.psyexp +158 -0
  248. psychopy/tests/test_app/.DS_Store +0 -0
  249. psychopy/tests/test_app/conftest.py +2 -2
  250. psychopy/tests/test_app/test_speed.py +4 -1
  251. psychopy/tests/test_data/test_TrialHandler2.py +146 -1
  252. psychopy/tests/test_experiment/.DS_Store +0 -0
  253. psychopy/tests/test_experiment/needs_wx/genComponsTemplate.py +3 -3
  254. psychopy/tests/test_experiment/needs_wx/test_components.py +2 -2
  255. psychopy/tests/test_experiment/test_components/test_KeyboardComponent.py +28 -0
  256. psychopy/tests/test_experiment/test_components/test_UnknownPluginComponent.py +27 -0
  257. psychopy/tests/test_experiment/test_components/test_base_components.py +58 -0
  258. psychopy/tests/test_experiment/test_py2js.py +1 -1
  259. psychopy/tests/test_hardware/test_keyboard.py +31 -0
  260. psychopy/tests/test_hardware/test_ports.py +1 -11
  261. psychopy/tests/test_liaison/test_Liaison.py +47 -0
  262. psychopy/tests/test_misc/test_core.py +5 -0
  263. psychopy/tests/test_session/test_Session.py +5 -1
  264. psychopy/tests/test_tools/test_versionchooser.py +39 -8
  265. psychopy/tests/test_visual/test_all_stimuli.py +0 -97
  266. psychopy/tests/test_visual/test_image.py +6 -5
  267. psychopy/tests/test_visual/test_textbox.py +36 -0
  268. psychopy/tests/utils.py +4 -0
  269. psychopy/tools/filetools.py +1 -1
  270. psychopy/tools/pkgtools.py +160 -137
  271. psychopy/tools/versionchooser.py +10 -10
  272. psychopy/tools/wizard.py +3 -3
  273. psychopy/visual/.DS_Store +0 -0
  274. psychopy/visual/backends/pygletbackend.py +24 -13
  275. psychopy/visual/basevisual.py +5 -11
  276. psychopy/visual/button.py +2 -14
  277. psychopy/visual/helpers.py +5 -5
  278. psychopy/visual/line.py +1 -2
  279. psychopy/visual/movie2.py +7 -816
  280. psychopy/visual/movie3.py +7 -589
  281. psychopy/visual/movies/__init__.py +8 -11
  282. psychopy/visual/movies/frame.py +5 -2
  283. psychopy/visual/movies/players/ffpyplayer_player.py +5 -2
  284. psychopy/visual/noise.py +8 -7
  285. psychopy/visual/patch.py +7 -16
  286. psychopy/visual/radial.py +9 -7
  287. psychopy/visual/ratingscale.py +8 -1415
  288. psychopy/visual/secondorder.py +10 -9
  289. psychopy/visual/shape.py +7 -2
  290. psychopy/visual/text.py +1 -1
  291. psychopy/visual/textbox2/textbox2.py +28 -5
  292. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/METADATA +8 -13
  293. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/RECORD +307 -213
  294. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/WHEEL +1 -1
  295. psychopy/app/Resources/click.png +0 -0
  296. psychopy/app/Resources/next.png +0 -0
  297. psychopy/experiment/components/patch/__init__.py +0 -121
  298. psychopy/experiment/components/patch/classic/patch.png +0 -0
  299. psychopy/experiment/components/patch/dark/patch.png +0 -0
  300. psychopy/experiment/components/patch/dark/patch@2x.png +0 -0
  301. psychopy/experiment/components/patch/light/patch.png +0 -0
  302. psychopy/experiment/components/patch/light/patch@2x.png +0 -0
  303. psychopy/experiment/components/ratingScale/__init__.py +0 -337
  304. psychopy/experiment/components/ratingScale/classic/ratingscale.png +0 -0
  305. psychopy/experiment/components/ratingScale/classic/ratingscale@2x.png +0 -0
  306. psychopy/experiment/components/ratingScale/dark/ratingScale@2x.png +0 -0
  307. psychopy/experiment/components/ratingScale/dark/ratingscale.png +0 -0
  308. psychopy/experiment/components/ratingScale/light/ratingScale@2x.png +0 -0
  309. psychopy/experiment/components/ratingScale/light/ratingscale.png +0 -0
  310. psychopy/platform_specific/posix.py +0 -16
  311. psychopy/tests/test_sound/test_microphone.py +0 -217
  312. psychopy/tests/test_visual/test_ratingScale.py +0 -299
  313. /psychopy/{app/Resources → assets}/Psychopy Window Favicon@16w.png +0 -0
  314. /psychopy/{app/Resources → assets}/Psychopy Window Favicon@32w.png +0 -0
  315. /psychopy/{app/Resources → assets}/USB-C.png +0 -0
  316. /psychopy/{app/Resources → assets}/USB.png +0 -0
  317. /psychopy/{app/Resources → assets}/creditCard.png +0 -0
  318. /psychopy/{app/Resources → assets}/default.mp3 +0 -0
  319. /psychopy/{app/Resources → assets}/default.mp4 +0 -0
  320. /psychopy/{app/Resources → assets}/default.png +0 -0
  321. /psychopy/{app/Resources → assets/templates}/instruct1.png +0 -0
  322. /psychopy/{app/Resources → assets/templates}/instruct2.png +0 -0
  323. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/entry_points.txt +0 -0
  324. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/licenses/AUTHORS.md +0 -0
  325. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -43,7 +43,7 @@ _numpyRandomImports = ['random', 'randint', 'normal', 'shuffle', 'choice as rand
43
43
 
44
44
  # this is not a standard component - it will appear on toolbar not in
45
45
  # components panel
46
- ioDeviceMap = dict(ioUtil.getDeviceNames())
46
+ ioDeviceMap = dict(ioUtil.getDeviceNames(device_name="eyetracker.hw"))
47
47
  ioDeviceMap['None'] = ""
48
48
 
49
49
  # Keyboard backend options
@@ -85,7 +85,9 @@ class SettingsComponent:
85
85
  winSize=(1024, 768), screen=1, monitor='testMonitor', winBackend='pyglet',
86
86
  showMouse=False, saveLogFile=True, showExpInfo=True,
87
87
  expInfo="{'participant':'f\"{randint(0, 999999):06.0f}\"', 'session':'001'}",
88
- units='height', logging='warning',
88
+ units='height',
89
+ logging="info",
90
+ consoleLoggingLevel="warning",
89
91
  color='$[0,0,0]', colorSpace='rgb', enableEscape=True,
90
92
  measureFrameRate=True, frameRate="", frameRateMsg=_translate(
91
93
  "Attempting to measure frame rate of screen, please wait..."
@@ -117,8 +119,10 @@ class SettingsComponent:
117
119
  plCompanionAddress="neon.local",
118
120
  plCompanionPort=8080,
119
121
  plCompanionRecordingEnabled=True,
122
+ ecSampleRate='default',
120
123
  keyboardBackend="ioHub",
121
- filename=None, exportHTML='on Sync', endMessage=''
124
+ filename=None, exportHTML='on Sync',
125
+ endMessage=_translate("Thank you for your patience.")
122
126
  ):
123
127
  self.type = 'Settings'
124
128
  self.exp = exp # so we can access the experiment if necess
@@ -397,6 +401,7 @@ class SettingsComponent:
397
401
  "Save psydat file",
398
402
  "Save hdf5 file",
399
403
  "logging level",
404
+ "consoleLoggingLevel",
400
405
  "clockFormat",
401
406
  ]
402
407
  self.params['Data filename'] = Param(
@@ -460,11 +465,23 @@ class SettingsComponent:
460
465
  "useful for viewing and analyzing complex data in structures."),
461
466
  label=_translate("Save hdf5 file"), categ='Data')
462
467
  self.params['logging level'] = Param(
463
- logging, valType='code', inputType="choice",
468
+ logging, valType='code', inputType="choice", categ='Data',
464
469
  allowedVals=['error', 'warning', 'data', 'exp', 'info', 'debug'],
465
- hint=_translate("How much output do you want in the log files? "
466
- "('error' is fewest messages, 'debug' is most)"),
467
- label=_translate("Logging level"), categ='Data')
470
+ hint=_translate(
471
+ "How much output do you want in the log files? ('error' is fewest "
472
+ "messages, 'debug' is most)"
473
+ ),
474
+ label=_translate("File logging level")
475
+ )
476
+ self.params['consoleLoggingLevel'] = Param(
477
+ consoleLoggingLevel, valType='code', inputType="choice", categ='Data',
478
+ allowedVals=['error', 'warning', 'data', 'exp', 'info', 'debug'],
479
+ hint=_translate(
480
+ "How much output do you want displayed in the console / app? ('error' "
481
+ "is fewest messages, 'debug' is most)"
482
+ ),
483
+ label=_translate("Console / app logging level")
484
+ )
468
485
  self.params['clockFormat'] = Param(
469
486
  clockFormat, valType="str", inputType="choice", categ="Data",
470
487
  allowedVals=["iso", "float"],
@@ -526,6 +543,7 @@ class SettingsComponent:
526
543
  "plPupilRemoteAddress", "plPupilRemotePort", "plPupilRemoteTimeoutMs",
527
544
  "plPupilCaptureRecordingEnabled", "plPupilCaptureRecordingLocation"],
528
545
  "Pupil Labs (Neon)": ["plCompanionAddress", "plCompanionPort", "plCompanionRecordingEnabled"],
546
+ "EyeLogic": ["ecSampleRate"],
529
547
  }
530
548
  for tracker in trackerParams:
531
549
  for depParam in trackerParams[tracker]:
@@ -742,6 +760,13 @@ class SettingsComponent:
742
760
  label=_translate("Recording enabled"), categ="Eyetracking"
743
761
  )
744
762
 
763
+ # EyeLogic
764
+ self.params['ecSampleRate'] = Param(
765
+ ecSampleRate, valType='str', inputType="single",
766
+ hint=_translate("Eyetracker sampling rate: 'default' or <integer>[Hz]. Defaults to tracking mode '0'."),
767
+ label=_translate("Sampling rate"), categ="Eyetracking"
768
+ )
769
+
745
770
  # Input
746
771
  self.params['keyboardBackend'] = Param(
747
772
  keyboardBackend, valType='str', inputType="choice",
@@ -994,7 +1019,6 @@ class SettingsComponent:
994
1019
  "# start off with values from experiment settings\n"
995
1020
  "_fullScr = %(Full-screen window)s\n"
996
1021
  "_winSize = %(Window size (pixels))s\n"
997
- "_loggingLevel = logging.getLevel('%(logging level)s')\n"
998
1022
  "# if in pilot mode, apply overrides according to preferences\n"
999
1023
  "if PILOTING:\n"
1000
1024
  " # force windowed mode\n"
@@ -1002,10 +1026,6 @@ class SettingsComponent:
1002
1026
  " _fullScr = False\n"
1003
1027
  " # set window size\n"
1004
1028
  " _winSize = prefs.piloting['forcedWindowSize']\n"
1005
- " # override logging level\n"
1006
- " _loggingLevel = logging.getLevel(\n"
1007
- " prefs.piloting['pilotLoggingLevel']\n"
1008
- " )\n"
1009
1029
  )
1010
1030
  buff.writeIndented(code % self.params)
1011
1031
 
@@ -1311,17 +1331,30 @@ class SettingsComponent:
1311
1331
  buff.writeIndentedLines(code)
1312
1332
  buff.setIndentLevel(+1, relative=True)
1313
1333
 
1314
- # set logging level
1334
+ # set app logging level
1315
1335
  code = (
1316
- "# this outputs to the screen, not a file\n"
1317
- "logging.console.setLevel(_loggingLevel)\n"
1336
+ "# set how much information should be printed to the console / app\n"
1337
+ "if PILOTING:\n"
1338
+ " logging.console.setLevel(\n"
1339
+ " prefs.piloting['pilotConsoleLoggingLevel']\n"
1340
+ " )\n"
1341
+ "else:\n"
1342
+ " logging.console.setLevel('%(consoleLoggingLevel)s')\n"
1318
1343
  )
1319
1344
  buff.writeIndentedLines(code % self.params)
1320
-
1345
+ # create log file
1321
1346
  if self.params['Save log file'].val:
1322
1347
  code = (
1323
1348
  "# save a log file for detail verbose info\n"
1324
- "logFile = logging.LogFile(filename+'.log', level=_loggingLevel)\n"
1349
+ "logFile = logging.LogFile(filename+'.log')\n"
1350
+ "if PILOTING:\n"
1351
+ " logFile.setLevel(\n"
1352
+ " prefs.piloting['pilotLoggingLevel']\n"
1353
+ " )\n"
1354
+ "else:\n"
1355
+ " logFile.setLevel(\n"
1356
+ " logging.getLevel('%(logging level)s')\n"
1357
+ " )\n"
1325
1358
  "\n"
1326
1359
  "return logFile\n"
1327
1360
  )
@@ -1408,6 +1441,7 @@ class SettingsComponent:
1408
1441
  "ioConfig = {}\n"
1409
1442
  )
1410
1443
  buff.writeIndentedLines(code % inits)
1444
+
1411
1445
  # Add eyetracker config
1412
1446
  if self.params['eyetracker'] != "None":
1413
1447
  # Alert user if window is not fullscreen
@@ -1506,8 +1540,8 @@ class SettingsComponent:
1506
1540
  buff.writeIndentedLines(code % inits)
1507
1541
  buff.setIndentLevel(1, relative=True)
1508
1542
  code = (
1509
- "'sample_filtering': %(elDataFiltering)s,\n"
1510
- "'elLiveFiltering': %(elLiveFiltering)s,\n"
1543
+ "'FILTER_FILE': %(elDataFiltering)s,\n"
1544
+ "'FILTER_ONLINE': %(elLiveFiltering)s,\n"
1511
1545
  )
1512
1546
  buff.writeIndentedLines(code % inits)
1513
1547
  buff.setIndentLevel(-1, relative=True)
@@ -1623,6 +1657,22 @@ class SettingsComponent:
1623
1657
  )
1624
1658
  buff.writeIndentedLines(code % inits)
1625
1659
 
1660
+ elif self.params['eyetracker'] == "EyeLogic":
1661
+ code = (
1662
+ "'runtime_settings': {\n"
1663
+ )
1664
+ buff.writeIndentedLines(code % inits)
1665
+ buff.setIndentLevel(1, relative=True)
1666
+ code = (
1667
+ "'sampling_rate': %(ecSampleRate)s,\n"
1668
+ )
1669
+ buff.writeIndentedLines(code % inits)
1670
+ buff.setIndentLevel(-1, relative=True)
1671
+ code = (
1672
+ "}\n"
1673
+ )
1674
+ buff.writeIndentedLines(code % inits)
1675
+
1626
1676
  # Close ioDevice dict
1627
1677
  buff.setIndentLevel(-1, relative=True)
1628
1678
  code = (
@@ -1635,36 +1685,66 @@ class SettingsComponent:
1635
1685
  code = (
1636
1686
  "\n"
1637
1687
  "# Setup iohub keyboard\n"
1638
- "ioConfig['Keyboard'] = dict(use_keymap='psychopy')\n\n"
1688
+ "ioConfig['Keyboard'] = dict(use_keymap='psychopy')\n"
1639
1689
  )
1640
1690
  buff.writeIndentedLines(code % inits)
1641
1691
 
1642
1692
  if self.needIoHub and self.params['keyboardBackend'] == 'PsychToolbox':
1643
1693
  alert(code=4550)
1644
1694
 
1645
- # Start ioHub server
1695
+ # Add experiment handler filename to ioConfig
1646
1696
  if self.needIoHub:
1697
+ code = (
1698
+ "\n"
1699
+ "# Setup iohub experiment\n"
1700
+ "ioConfig['Experiment'] = dict(filename=thisExp.dataFileName)\n"
1701
+ )
1702
+ buff.writeIndentedLines(code % inits)
1703
+
1704
+ # Make ioDataStoreConfig dict
1705
+ if self.params['Save hdf5 file'].val:
1706
+ code = (
1707
+ "\n"
1708
+ "# --- Setup iohub hdf5 datastore ---\n"
1709
+ )
1710
+ buff.writeIndentedLines(code % inits)
1647
1711
  # Specify session
1648
1712
  code = (
1649
- "ioSession = '1'\n"
1650
- "if 'session' in expInfo:\n"
1713
+ "ioSession = str(expInfo.get('session', '1'))\n"
1714
+ )
1715
+ buff.writeIndentedLines(code % inits)
1716
+ # Create ioDataStoreConfig dict
1717
+ code = (
1718
+ "ioDataStoreConfig = {"
1651
1719
  )
1652
1720
  buff.writeIndentedLines(code % inits)
1653
1721
  buff.setIndentLevel(1, relative=True)
1654
1722
  code = (
1655
- "ioSession = str(expInfo['session'])\n"
1723
+ f"'experiment_code': %(expName)s,\n" # noqa: F541
1724
+ "'session_code': ioSession,\n"
1725
+ "'datastore_name': thisExp.dataFileName,\n"
1656
1726
  )
1657
1727
  buff.writeIndentedLines(code % inits)
1658
1728
  buff.setIndentLevel(-1, relative=True)
1659
- # Start server
1729
+ code = (
1730
+ "}\n"
1731
+ )
1732
+ buff.writeIndentedLines(code % inits)
1733
+
1734
+ # Start ioHub server
1735
+ if self.needIoHub:
1736
+ code = (
1737
+ "\n"
1738
+ "# Start ioHub server\n"
1739
+ )
1740
+ buff.writeIndentedLines(code % inits)
1660
1741
  if self.params['Save hdf5 file'].val:
1661
1742
  code = (
1662
- f"ioServer = io.launchHubServer(window=win, experiment_code=%(expName)s, session_code=ioSession, "
1663
- f"datastore_name=thisExp.dataFileName, **ioConfig)\n"
1743
+ "ioServer = io.launchHubServer(window=win, **ioDataStoreConfig, **ioConfig)\n"
1664
1744
  )
1665
1745
  else:
1666
1746
  code = (
1667
- f"ioServer = io.launchHubServer(window=win, **ioConfig)\n"
1747
+ "ioServer = io.launchHubServer(window=win, **ioConfig)\n"
1668
1748
  )
1669
1749
  buff.writeIndentedLines(code % inits)
1670
1750
  else:
@@ -1675,6 +1755,7 @@ class SettingsComponent:
1675
1755
 
1676
1756
  # store ioServer
1677
1757
  code = (
1758
+ "\n"
1678
1759
  "# store ioServer object in the device manager\n"
1679
1760
  "deviceManager.ioServer = ioServer\n"
1680
1761
  )
@@ -1822,7 +1903,7 @@ class SettingsComponent:
1822
1903
  "if expInfo is not None:\n"
1823
1904
  " # get/measure frame rate if not already in expInfo\n"
1824
1905
  " if win._monitorFrameRate is None:\n"
1825
- " win.getActualFrameRate(infoMsg=%(frameRateMsg)s)\n"
1906
+ " win._monitorFrameRate = win.getActualFrameRate(infoMsg=%(frameRateMsg)s)\n"
1826
1907
  " expInfo['frameRate'] = win._monitorFrameRate\n"
1827
1908
  )
1828
1909
  buff.writeIndentedLines(code % params)
@@ -1962,11 +2043,11 @@ class SettingsComponent:
1962
2043
  "if thisExp.status != PAUSED:\n"
1963
2044
  " return\n"
1964
2045
  "\n"
2046
+ "# start a timer to figure out how long we're paused for\n"
2047
+ "pauseTimer = core.Clock()\n"
1965
2048
  "# pause any playback components\n"
1966
2049
  "for comp in playbackComponents:\n"
1967
2050
  " comp.pause()\n"
1968
- "# prevent components from auto-drawing\n"
1969
- "win.stashAutoDraw()\n"
1970
2051
  "# make sure we have a keyboard\n"
1971
2052
  "defaultKeyboard = deviceManager.getDevice('defaultKeyboard')\n"
1972
2053
  "if defaultKeyboard is None:\n"
@@ -1985,19 +2066,17 @@ class SettingsComponent:
1985
2066
  " endExperiment(thisExp, win=win)\n"
1986
2067
  )
1987
2068
  code += (
1988
- " # flip the screen\n"
1989
- " win.flip()\n"
2069
+ " # sleep 1ms so other threads can execute\n"
2070
+ " clock.time.sleep(0.001)\n"
1990
2071
  "# if stop was requested while paused, quit\n"
1991
2072
  "if thisExp.status == FINISHED:\n"
1992
2073
  " endExperiment(thisExp, win=win)\n"
1993
2074
  "# resume any playback components\n"
1994
2075
  "for comp in playbackComponents:\n"
1995
2076
  " comp.play()\n"
1996
- "# restore auto-drawn components\n"
1997
- "win.retrieveAutoDraw()\n"
1998
2077
  "# reset any timers\n"
1999
2078
  "for timer in timers:\n"
2000
- " timer.reset()\n"
2079
+ " timer.addTime(-pauseTimer.getTime())\n"
2001
2080
  )
2002
2081
  buff.writeIndentedLines(code % self.params)
2003
2082
 
@@ -2036,11 +2115,10 @@ class SettingsComponent:
2036
2115
  " # Flip one final time so any remaining win.callOnFlip() \n"
2037
2116
  " # and win.timeOnFlip() tasks get executed\n"
2038
2117
  " win.flip()\n"
2118
+ "# return console logger level to WARNING\n"
2119
+ "logging.console.setLevel(logging.WARNING)\n"
2039
2120
  "# mark experiment handler as finished\n"
2040
2121
  "thisExp.status = FINISHED\n"
2041
- "# shut down eyetracker, if there is one\n"
2042
- "if deviceManager.getDevice('eyetracker') is not None:\n"
2043
- " deviceManager.removeDevice('eyetracker')\n"
2044
2122
  )
2045
2123
  if self.params['Save log file'].val:
2046
2124
  code += (
@@ -2077,9 +2155,6 @@ class SettingsComponent:
2077
2155
  " # and win.timeOnFlip() tasks get executed before quitting\n"
2078
2156
  " win.flip()\n"
2079
2157
  " win.close()\n"
2080
- "# shut down eyetracker, if there is one\n"
2081
- "if deviceManager.getDevice('eyetracker') is not None:\n"
2082
- " deviceManager.removeDevice('eyetracker')\n"
2083
2158
  )
2084
2159
  if self.params['Save log file'].val:
2085
2160
  code += (
@@ -52,9 +52,6 @@ class SoundComponent(BaseDeviceComponent):
52
52
  "volume", "hammingWindow", # Playback tab
53
53
  ]
54
54
  # params
55
- self.params['stopType'].allowedVals = ['duration (s)']
56
- self.params['stopType'].hint = _translate('The maximum duration of a'
57
- ' sound in seconds')
58
55
  hnt = _translate("When does the Component end? (blank to use the "
59
56
  "duration of the media)")
60
57
  self.params['stopVal'].hint = hnt
@@ -209,35 +206,33 @@ class SoundComponent(BaseDeviceComponent):
209
206
  def writeFrameCode(self, buff):
210
207
  """Write the code that will be called every frame
211
208
  """
212
- # Write start code
209
+ # Write start code to update parameters. Unlike BaseVisualComponents, which
210
+ # inserts writeActiveTestCode() after the start code, we need to insert it
211
+ # here before the start code to provide the correct parameters for calling
212
+ # the play() method.
213
+
214
+ buff.writeIndented("\n")
215
+ buff.writeIndented(f"# *{self.params['name']}* updates\n")
213
216
  self.writeParamUpdates(buff, 'set every frame')
217
+
218
+ # write code for starting
214
219
  indented = self.writeStartTestCode(buff)
215
220
  if indented:
216
221
  if self.params['syncScreenRefresh'].val:
217
- code = ("%(name)s.play(when=win) # sync with win flip\n") % self.params
222
+ code = ("%(name)s.play(when=win) # sync with win flip\n")
218
223
  else:
219
- code = "%(name)s.play() # start the sound (it finishes automatically)\n" % self.params
220
- buff.writeIndented(code)
224
+ code = "%(name)s.play() # start the sound (it finishes automatically)\n"
225
+ buff.writeIndentedLines(code % self.params)
221
226
  buff.setIndentLevel(-indented, relative=True)
222
227
 
223
- # Write stop code
224
- indented = self.writeStopTestCode(buff)
228
+ # write code for stopping
229
+ indented = self.writeStopTestCode(buff, extra=" or %(name)s.isFinished")
225
230
  if indented:
226
231
  code = ("%(name)s.stop()\n")
227
232
  buff.writeIndentedLines(code % self.params)
228
233
  # because of the 'if' statement of the time test
229
234
  buff.setIndentLevel(-indented, relative=True)
230
235
 
231
- # Update status
232
- code = (
233
- "# update %(name)s status according to whether it's playing\n"
234
- "if %(name)s.isPlaying:\n"
235
- " %(name)s.status = STARTED\n"
236
- "elif %(name)s.isFinished:\n"
237
- " %(name)s.status = FINISHED\n"
238
- )
239
- buff.writeIndentedLines(code % self.params)
240
-
241
236
  def writeFrameCodeJS(self, buff):
242
237
  """Write the code that will be called every frame
243
238
  """
@@ -305,3 +300,43 @@ class SoundComponent(BaseDeviceComponent):
305
300
  "%(name)s.stop(); // ensure sound has stopped at end of Routine\n"
306
301
  )
307
302
  buff.writeIndentedLines(code % self.params)
303
+
304
+ def writeParamUpdate(
305
+ self,
306
+ buff,
307
+ compName,
308
+ paramName,
309
+ val,
310
+ updateType,
311
+ params=None,
312
+ target="PsychoPy",
313
+ ):
314
+ """
315
+ Overload BaseComponent.writeParamUpdate to handle special case for SoundComponent
316
+ """
317
+ # when writing param updates for Sound.sound, needs to be `setValue` in JS
318
+ # (this is intended as a temporary patch - please delete when `setSound` in JS can accept
319
+ # the same range of values as in Py)
320
+ if target == 'PsychoJS' and paramName == "sound":
321
+ # get logging string
322
+ if updateType == 'set every frame' and target == 'PsychoJS':
323
+ loggingStr = ', false'
324
+ else:
325
+ loggingStr = ''
326
+ # write setValue code
327
+ code = (
328
+ f"{compName}.setValue({val}{loggingStr});\n"
329
+ )
330
+ buff.writeIndented(code)
331
+ else:
332
+ # do normal stuff for every other param
333
+ BaseDeviceComponent.writeParamUpdate(
334
+ self,
335
+ buff,
336
+ compName,
337
+ paramName,
338
+ val,
339
+ updateType,
340
+ params=params,
341
+ target=target,
342
+ )
@@ -246,7 +246,7 @@ class StaticComponent(BaseComponent):
246
246
  paramName=fieldName,
247
247
  val=prms[fieldName],
248
248
  updateType=prms[fieldName].updates,
249
- params=prms)
249
+ params=prms, target=target)
250
250
  # Comment to mark end of updates
251
251
  if target == "PsychoJS":
252
252
  code = "// Component updates done\n"
@@ -24,7 +24,8 @@ class TextComponent(BaseVisualComponent):
24
24
  text=_translate('Any text\n\nincluding line breaks'),
25
25
  font='Arial', units='from exp settings',
26
26
  color='white', colorSpace='rgb',
27
- pos=(0, 0), letterHeight=0.05, ori=0,
27
+ pos=(0, 0), letterHeight=0.05,
28
+ ori=0, draggable=False,
28
29
  startType='time (s)', startVal=0.0,
29
30
  stopType='duration (s)', stopVal=1.0,
30
31
  flip='None', startEstim='', durationEstim='', wrapWidth='',
@@ -58,6 +59,14 @@ class TextComponent(BaseVisualComponent):
58
59
  hint=_translate("The font name (e.g. Comic Sans)"),
59
60
  label=_translate("Font"))
60
61
  del self.params['size'] # because you can't specify width for text
62
+ self.params['draggable'] = Param(
63
+ draggable, valType="code", inputType="bool", categ="Layout",
64
+ updates="constant",
65
+ label=_translate("Draggable?"),
66
+ hint=_translate(
67
+ "Should this stimulus be moveble by clicking and dragging?"
68
+ )
69
+ )
61
70
  self.params['letterHeight'] = Param(
62
71
  letterHeight, valType='num', inputType="single", allowedTypes=[], categ='Formatting',
63
72
  updates='constant', allowedUpdates=_allow3[:], # copy the list
@@ -86,6 +95,22 @@ class TextComponent(BaseVisualComponent):
86
95
  del self.params['fillColor']
87
96
  del self.params['borderColor']
88
97
 
98
+ def _getParamCaps(self, paramName):
99
+ """
100
+ TEMPORARY FIX
101
+
102
+ TextStim in JS doesn't accept `letterHeight` as a param. Ideally this needs to be fixed
103
+ in JS, but in the meantime overloading this function in Python to write `setHeight`
104
+ rather than `setLetterHeight` means it stops biting users.
105
+ """
106
+ # call base function
107
+ paramName = BaseVisualComponent._getParamCaps(self, paramName)
108
+ # replace letterHeight
109
+ if paramName == "LetterHeight":
110
+ paramName = "Height"
111
+
112
+ return paramName
113
+
89
114
  def writeInitCode(self, buff):
90
115
  # do we need units code?
91
116
  if self.params['units'].val == 'from exp settings':
@@ -103,7 +128,7 @@ class TextComponent(BaseVisualComponent):
103
128
  " text=%(text)s,\n"
104
129
  " font=%(font)s,\n"
105
130
  " " + unitsStr +
106
- "pos=%(pos)s, height=%(letterHeight)s, "
131
+ "pos=%(pos)s, draggable=%(draggable)s, height=%(letterHeight)s, "
107
132
  "wrapWidth=%(wrapWidth)s, ori=%(ori)s, \n"
108
133
  " color=%(color)s, colorSpace=%(colorSpace)s, "
109
134
  "opacity=%(opacity)s, \n"
@@ -141,7 +166,7 @@ class TextComponent(BaseVisualComponent):
141
166
  " name: '%(name)s',\n"
142
167
  " text: %(text)s,\n"
143
168
  " font: %(font)s,\n" + unitsStr +
144
- " pos: %(pos)s, height: %(letterHeight)s,"
169
+ " pos: %(pos)s, draggable: %(draggable)s, height: %(letterHeight)s,"
145
170
  " wrapWidth: %(wrapWidth)s, ori: %(ori)s,\n"
146
171
  " languageStyle: %(languageStyle)s,\n"
147
172
  " color: new util.Color(%(color)s),"
@@ -28,7 +28,7 @@ class TextboxComponent(BaseVisualComponent):
28
28
  font='Arial', units='from exp settings', bold=False, italic=False,
29
29
  color='white', colorSpace='rgb', opacity="",
30
30
  pos=(0, 0), size=(0.5, 0.5), letterHeight=0.05, ori=0,
31
- speechPoint="",
31
+ speechPoint="", draggable=False,
32
32
  anchor='center', alignment='center',
33
33
  lineSpacing=1.0, padding=0, # gap between box and text
34
34
  startType='time (s)', startVal=0.0,
@@ -107,6 +107,14 @@ class TextboxComponent(BaseVisualComponent):
107
107
  hint=_translate("horiz = left-right reversed; vert = up-down"
108
108
  " reversed; $var = variable"),
109
109
  label=_translate("Flip vertical"))
110
+ self.params['draggable'] = Param(
111
+ draggable, valType="code", inputType="bool", categ="Layout",
112
+ updates="constant",
113
+ label=_translate("Draggable?"),
114
+ hint=_translate(
115
+ "Should this stimulus be moveble by clicking and dragging?"
116
+ )
117
+ )
110
118
  self.params['languageStyle'] = Param(
111
119
  languageStyle, valType='str', inputType="choice", categ='Formatting',
112
120
  allowedVals=['LTR', 'RTL', 'Arabic'],
@@ -207,7 +215,7 @@ class TextboxComponent(BaseVisualComponent):
207
215
  code = (
208
216
  "%(name)s = visual.TextBox2(\n"
209
217
  " win, text=%(text)s, placeholder=%(placeholder)s, font=%(font)s,\n"
210
- " pos=%(pos)s," + unitsStr +
218
+ " ori=%(ori)s, pos=%(pos)s, draggable=%(draggable)s, " + unitsStr +
211
219
  " letterHeight=%(letterHeight)s,\n"
212
220
  " size=%(size)s, borderWidth=%(borderWidth)s,\n"
213
221
  " color=%(color)s, colorSpace=%(colorSpace)s,\n"
@@ -249,9 +257,11 @@ class TextboxComponent(BaseVisualComponent):
249
257
  " placeholder: %(placeholder)s,\n"
250
258
  " font: %(font)s,\n"
251
259
  " pos: %(pos)s, \n"
260
+ " draggable: %(draggable)s,\n"
252
261
  " letterHeight: %(letterHeight)s,\n"
253
262
  " lineSpacing: %(lineSpacing)s,\n"
254
263
  " size: %(size)s," + unitsStr +
264
+ " ori: %(ori)s,\n"
255
265
  " color: %(color)s, colorSpace: %(colorSpace)s,\n"
256
266
  " fillColor: %(fillColor)s, borderColor: %(borderColor)s,\n"
257
267
  " languageStyle: %(languageStyle)s,\n"
@@ -22,13 +22,12 @@ class UnknownComponent(BaseComponent):
22
22
  'future)')
23
23
 
24
24
  def __init__(self, exp, parentName, name='', compType="UnknownComponent"):
25
- self.type = compType
26
25
  self.exp = exp # so we can access the experiment if necess
27
26
  self.parentName = parentName # to access the routine too if needed
28
27
  self.params = {}
29
28
  self.depends = []
30
29
  super(UnknownComponent, self).__init__(exp, parentName, name=name)
31
- self.order += []
30
+ self.type = compType
32
31
 
33
32
  @property
34
33
  def _xml(self):
@@ -20,13 +20,13 @@ class UnknownPluginComponent(BaseComponent):
20
20
  tooltip = _translate('Unknown: A component which comes from a plugin which you do not have installed & activated.')
21
21
 
22
22
  def __init__(self, exp, parentName, name='', compType="UnknownPluginComponent"):
23
- self.type = compType
24
23
  self.exp = exp # so we can access the experiment if necess
25
24
  self.parentName = parentName # to access the routine too if needed
26
25
  self.params = {}
27
26
  self.depends = []
28
27
  super(UnknownPluginComponent, self).__init__(exp, parentName, name=name)
29
- self.order += []
28
+ # replace default type with the type given
29
+ self.type = compType
30
30
 
31
31
  @property
32
32
  def _xml(self):
@@ -432,11 +432,18 @@ class Flow(list):
432
432
  loopStack.remove(thisEntry.loop)
433
433
  script.writeIndentedLines(code)
434
434
  # quit when all routines are finished
435
- script.writeIndented("flowScheduler.add(quitPsychoJS, %(End Message)s, true);\n" % self.exp.settings.params)
435
+ code = (
436
+ "flowScheduler.add(quitPsychoJS, %(End Message)s, true);\n"
437
+ )
438
+ script.writeIndentedLines(code % self.exp.settings.params)
436
439
  # handled all the flow entries
437
- code = ("\n// quit if user presses Cancel in dialog box:\n"
438
- "dialogCancelScheduler.add(quitPsychoJS, '', false);\n\n")
439
- script.writeIndentedLines(code)
440
+ code = (
441
+ "\n"
442
+ "// quit if user presses Cancel in dialog box:\n"
443
+ "dialogCancelScheduler.add(quitPsychoJS, %(End Message)s, false);\n"
444
+ "\n"
445
+ )
446
+ script.writeIndentedLines(code % self.exp.settings.params)
440
447
 
441
448
  # Write resource list
442
449
  resourceFiles = []