psychopy 2024.1.3__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 (331) 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/localizedStrings.py +11 -9
  19. psychopy/app/builder/validators.py +2 -2
  20. psychopy/app/coder/codeEditorBase.py +8 -8
  21. psychopy/app/coder/coder.py +4 -4
  22. psychopy/app/connections/sendusage.py +2 -2
  23. psychopy/app/connections/updates.py +9 -9
  24. psychopy/app/dialogs.py +34 -2
  25. psychopy/app/idle.py +31 -0
  26. psychopy/app/jobs.py +21 -3
  27. psychopy/app/linuxconfig/__init__.py +9 -0
  28. psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
  29. psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +4602 -2540
  30. psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
  31. psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +56 -54
  32. psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +53 -43
  33. psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
  34. psychopy/app/locale/es_US/LC_MESSAGE/messages.po +56 -54
  35. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
  36. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +1258 -1176
  37. psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +9415 -5
  38. psychopy/app/pavlovia_ui/_base.py +33 -3
  39. psychopy/app/pavlovia_ui/search.py +0 -1
  40. psychopy/app/plugin_manager/dialog.py +104 -51
  41. psychopy/app/plugin_manager/packages.py +5 -0
  42. psychopy/app/plugin_manager/plugins.py +152 -67
  43. psychopy/app/preferencesDlg.py +8 -8
  44. psychopy/app/psychopyApp.py +11 -5
  45. psychopy/app/ribbon.py +124 -14
  46. psychopy/app/runner/runner.py +6 -1
  47. psychopy/app/stdout/stdOutRich.py +27 -11
  48. psychopy/app/themes/icons.py +52 -2
  49. psychopy/assets/__init__.py +0 -0
  50. psychopy/assets/click.png +0 -0
  51. psychopy/assets/clicknext.png +0 -0
  52. psychopy/assets/next.png +0 -0
  53. psychopy/assets/psychopy.ico +0 -0
  54. psychopy/assets/psychopy.png +0 -0
  55. psychopy/assets/templates/__init__.py +0 -0
  56. psychopy/assets/touch.png +0 -0
  57. psychopy/assets/touchnext.png +0 -0
  58. psychopy/assets/window.ico +0 -0
  59. psychopy/changes/2023.1.0.md +9 -0
  60. psychopy/changes/2024.1.0.md +16 -0
  61. psychopy/changes/__init__.py +0 -0
  62. psychopy/clock.py +2 -2
  63. psychopy/colors.py +2 -1
  64. psychopy/compatibility.py +53 -1
  65. psychopy/contrib/.DS_Store +0 -0
  66. psychopy/contrib/configobj/__init__.py +10 -8
  67. psychopy/data/__init__.py +3 -2
  68. psychopy/data/base.py +5 -5
  69. psychopy/data/experiment.py +130 -4
  70. psychopy/data/routine.py +56 -0
  71. psychopy/data/staircase.py +2 -2
  72. psychopy/data/trial.py +559 -97
  73. psychopy/data/utils.py +56 -21
  74. psychopy/demos/.DS_Store +0 -0
  75. psychopy/demos/builder/.DS_Store +0 -0
  76. psychopy/demos/builder/Design Templates/.DS_Store +0 -0
  77. psychopy/demos/builder/Experiments/.DS_Store +0 -0
  78. psychopy/demos/builder/Feature Demos/.DS_Store +0 -0
  79. psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +375 -0
  80. psychopy/demos/builder/Feature Demos/buttonBox/readme.md +5 -0
  81. psychopy/demos/builder/Feature Demos/pilotMode/pilotMode.psyexp +433 -0
  82. psychopy/demos/builder/Feature Demos/pilotMode/readme.md +7 -0
  83. psychopy/demos/builder/Feature Demos/progress/progressBar.psyexp +4 -4
  84. psychopy/demos/builder/Hardware/.DS_Store +0 -0
  85. psychopy/demos/builder/Helper Tools/.DS_Store +0 -0
  86. psychopy/demos/coder/.DS_Store +0 -0
  87. psychopy/demos/coder/hardware/testSoundLatency.py +2 -2
  88. psychopy/demos/coder/iohub/.DS_Store +0 -0
  89. psychopy/demos/coder/misc/hdf5_2_csv +33 -0
  90. psychopy/event.py +30 -29
  91. psychopy/experiment/.DS_Store +0 -0
  92. psychopy/experiment/_experiment.py +6 -6
  93. psychopy/experiment/components/.DS_Store +0 -0
  94. psychopy/experiment/components/__init__.py +6 -3
  95. psychopy/experiment/components/_base.py +286 -131
  96. psychopy/experiment/components/aperture/.DS_Store +0 -0
  97. psychopy/experiment/components/brush/.DS_Store +0 -0
  98. psychopy/experiment/components/button/.DS_Store +0 -0
  99. psychopy/experiment/components/button/__init__.py +5 -1
  100. psychopy/experiment/components/buttonBox/.DS_Store +0 -0
  101. psychopy/experiment/components/buttonBox/__init__.py +21 -12
  102. psychopy/experiment/components/camera/.DS_Store +0 -0
  103. psychopy/experiment/components/code/.DS_Store +0 -0
  104. psychopy/experiment/components/dots/.DS_Store +0 -0
  105. psychopy/experiment/components/eyetracker_record/.DS_Store +0 -0
  106. psychopy/experiment/components/eyetracker_record/__init__.py +92 -30
  107. psychopy/experiment/components/form/.DS_Store +0 -0
  108. psychopy/experiment/components/form/__init__.py +6 -2
  109. psychopy/experiment/components/grating/.DS_Store +0 -0
  110. psychopy/experiment/components/grating/__init__.py +14 -3
  111. psychopy/experiment/components/image/.DS_Store +0 -0
  112. psychopy/experiment/components/image/__init__.py +14 -3
  113. psychopy/experiment/components/joyButtons/.DS_Store +0 -0
  114. psychopy/experiment/components/joystick/.DS_Store +0 -0
  115. psychopy/experiment/components/keyboard/.DS_Store +0 -0
  116. psychopy/experiment/components/keyboard/__init__.py +22 -10
  117. psychopy/experiment/components/microphone/.DS_Store +0 -0
  118. psychopy/experiment/components/microphone/__init__.py +59 -39
  119. psychopy/experiment/components/mouse/.DS_Store +0 -0
  120. psychopy/experiment/components/mouse/__init__.py +44 -29
  121. psychopy/experiment/components/movie/.DS_Store +0 -0
  122. psychopy/experiment/components/movie/__init__.py +1 -1
  123. psychopy/experiment/components/panorama/.DS_Store +0 -0
  124. psychopy/experiment/components/parallelOut/.DS_Store +0 -0
  125. psychopy/experiment/components/patch/.DS_Store +0 -0
  126. psychopy/experiment/components/polygon/.DS_Store +0 -0
  127. psychopy/experiment/components/polygon/__init__.py +26 -6
  128. psychopy/experiment/components/progress/.DS_Store +0 -0
  129. psychopy/experiment/components/progress/__init__.py +1 -1
  130. psychopy/experiment/components/ratingScale/.DS_Store +0 -0
  131. psychopy/experiment/components/resourceManager/.DS_Store +0 -0
  132. psychopy/experiment/components/roi/.DS_Store +0 -0
  133. psychopy/experiment/components/roi/__init__.py +5 -0
  134. psychopy/experiment/components/routineSettings/.DS_Store +0 -0
  135. psychopy/experiment/components/routineSettings/__init__.py +57 -10
  136. psychopy/experiment/components/serialOut/.DS_Store +0 -0
  137. psychopy/experiment/components/settings/.DS_Store +0 -0
  138. psychopy/experiment/components/settings/__init__.py +117 -42
  139. psychopy/experiment/components/slider/.DS_Store +0 -0
  140. psychopy/experiment/components/sound/.DS_Store +0 -0
  141. psychopy/experiment/components/sound/__init__.py +54 -19
  142. psychopy/experiment/components/static/.DS_Store +0 -0
  143. psychopy/experiment/components/static/__init__.py +1 -1
  144. psychopy/experiment/components/text/.DS_Store +0 -0
  145. psychopy/experiment/components/text/__init__.py +28 -3
  146. psychopy/experiment/components/textbox/.DS_Store +0 -0
  147. psychopy/experiment/components/textbox/__init__.py +12 -2
  148. psychopy/experiment/components/unknown/.DS_Store +0 -0
  149. psychopy/experiment/components/unknown/__init__.py +1 -2
  150. psychopy/experiment/components/unknownPlugin/.DS_Store +0 -0
  151. psychopy/experiment/components/unknownPlugin/__init__.py +2 -2
  152. psychopy/experiment/components/variable/.DS_Store +0 -0
  153. psychopy/experiment/flow.py +11 -4
  154. psychopy/experiment/loops.py +85 -37
  155. psychopy/experiment/params.py +74 -32
  156. psychopy/experiment/py2js_transpiler.py +8 -1
  157. psychopy/experiment/routines/.DS_Store +0 -0
  158. psychopy/experiment/routines/_base.py +102 -22
  159. psychopy/experiment/routines/counterbalance/.DS_Store +0 -0
  160. psychopy/experiment/routines/counterbalance/__init__.py +5 -1
  161. psychopy/experiment/routines/eyetracker_calibrate/.DS_Store +0 -0
  162. psychopy/experiment/routines/eyetracker_validate/.DS_Store +0 -0
  163. psychopy/experiment/routines/pavlovia_survey/.DS_Store +0 -0
  164. psychopy/experiment/routines/photodiodeValidator/.DS_Store +0 -0
  165. psychopy/experiment/routines/photodiodeValidator/__init__.py +7 -6
  166. psychopy/experiment/routines/unknown/.DS_Store +0 -0
  167. psychopy/gui/wxgui.py +4 -4
  168. psychopy/hardware/.DS_Store +0 -0
  169. psychopy/hardware/__init__.py +1 -1
  170. psychopy/hardware/base.py +12 -0
  171. psychopy/hardware/camera/__init__.py +1 -15
  172. psychopy/hardware/cedrus.py +10 -11
  173. psychopy/hardware/crs/colorcal.py +13 -22
  174. psychopy/hardware/crs/optical.py +10 -20
  175. psychopy/hardware/emulator.py +17 -14
  176. psychopy/hardware/eyetracker.py +42 -118
  177. psychopy/hardware/gammasci.py +4 -15
  178. psychopy/hardware/keyboard.py +102 -11
  179. psychopy/hardware/listener.py +3 -0
  180. psychopy/hardware/microphone.py +148 -18
  181. psychopy/hardware/minolta.py +8 -15
  182. psychopy/hardware/photodiode.py +191 -16
  183. psychopy/hardware/photometer/__init__.py +11 -19
  184. psychopy/hardware/pr.py +8 -15
  185. psychopy/hardware/speaker.py +39 -4
  186. psychopy/info.py +0 -71
  187. psychopy/iohub/.DS_Store +0 -0
  188. psychopy/iohub/__init__.py +1 -1
  189. psychopy/iohub/client/__init__.py +30 -20
  190. psychopy/iohub/client/keyboard.py +24 -24
  191. psychopy/iohub/datastore/__init__.py +2 -2
  192. psychopy/iohub/datastore/util.py +2 -2
  193. psychopy/iohub/default_config.yaml +1 -1
  194. psychopy/iohub/devices/.DS_Store +0 -0
  195. psychopy/iohub/devices/__init__.py +112 -25
  196. psychopy/iohub/devices/deviceConfigValidation.py +2 -1
  197. psychopy/iohub/devices/experiment/default_experiment.yaml +12 -1
  198. psychopy/iohub/devices/experiment/supported_config_settings.yaml +5 -1
  199. psychopy/iohub/devices/eyetracker/.DS_Store +0 -0
  200. psychopy/iohub/devices/eyetracker/__init__.py +46 -0
  201. psychopy/iohub/devices/eyetracker/calibration/procedure.py +2 -2
  202. psychopy/iohub/devices/eyetracker/hw/gazepoint/__init__.py +14 -2
  203. psychopy/iohub/devices/eyetracker/hw/mouse/eyetracker.py +3 -4
  204. psychopy/iohub/server.py +2 -2
  205. psychopy/iohub/start_iohub_process.py +3 -0
  206. psychopy/iohub/util/__init__.py +62 -70
  207. psychopy/layout.py +5 -5
  208. psychopy/logging.py +8 -1
  209. psychopy/microphone.py +10 -37
  210. psychopy/platform_specific/__init__.py +0 -2
  211. psychopy/platform_specific/darwin.py +1 -3
  212. psychopy/platform_specific/linux.py +31 -33
  213. psychopy/platform_specific/win32.py +38 -13
  214. psychopy/plugins/__init__.py +148 -116
  215. psychopy/plugins/util.py +39 -0
  216. psychopy/preferences/Darwin.spec +4 -2
  217. psychopy/preferences/FreeBSD.spec +4 -2
  218. psychopy/preferences/Linux.spec +4 -2
  219. psychopy/preferences/Windows.spec +4 -2
  220. psychopy/preferences/baseNoArch.spec +4 -2
  221. psychopy/preferences/preferences.py +47 -24
  222. psychopy/projects/pavlovia.py +47 -4
  223. psychopy/scripts/psyexpCompile.py +0 -4
  224. psychopy/session.py +153 -21
  225. psychopy/sound/__init__.py +31 -21
  226. psychopy/sound/_base.py +20 -3
  227. psychopy/sound/audioclip.py +320 -33
  228. psychopy/sound/backend_ptb.py +47 -58
  229. psychopy/sound/backend_pygame.py +1 -1
  230. psychopy/sound/backend_pysound.py +6 -15
  231. psychopy/sound/transcribe.py +53 -0
  232. psychopy/tests/.DS_Store +0 -0
  233. psychopy/tests/data/.DS_Store +0 -0
  234. psychopy/tests/data/TestUnknownPluginComponent_load_resave.psyexp +135 -0
  235. psychopy/tests/data/Test_textbox/test_ori_0_bottom right.png +0 -0
  236. psychopy/tests/data/Test_textbox/test_ori_0_center.png +0 -0
  237. psychopy/tests/data/Test_textbox/test_ori_0_top left.png +0 -0
  238. psychopy/tests/data/Test_textbox/test_ori_120_bottom right.png +0 -0
  239. psychopy/tests/data/Test_textbox/test_ori_120_center.png +0 -0
  240. psychopy/tests/data/Test_textbox/test_ori_120_top left.png +0 -0
  241. psychopy/tests/data/Test_textbox/test_ori_180_bottom right.png +0 -0
  242. psychopy/tests/data/Test_textbox/test_ori_180_center.png +0 -0
  243. psychopy/tests/data/Test_textbox/test_ori_180_top left.png +0 -0
  244. psychopy/tests/data/Test_textbox/test_ori_240_bottom right.png +0 -0
  245. psychopy/tests/data/Test_textbox/test_ori_240_center.png +0 -0
  246. psychopy/tests/data/Test_textbox/test_ori_240_top left.png +0 -0
  247. psychopy/tests/data/correctScript/.DS_Store +0 -0
  248. psychopy/tests/data/test_components/testClearKeyboard/testClearKeyboard.psyexp +200 -0
  249. psychopy/tests/data/test_session/.DS_Store +0 -0
  250. psychopy/tests/data/test_session/root/testFutureTrials/testFutureTrials.psyexp +155 -0
  251. psychopy/tests/data/test_session/root/testTrialNav/trialNav.psyexp +158 -0
  252. psychopy/tests/test_app/.DS_Store +0 -0
  253. psychopy/tests/test_app/conftest.py +2 -2
  254. psychopy/tests/test_app/test_speed.py +4 -1
  255. psychopy/tests/test_data/test_TrialHandler2.py +146 -1
  256. psychopy/tests/test_experiment/.DS_Store +0 -0
  257. psychopy/tests/test_experiment/needs_wx/genComponsTemplate.py +3 -3
  258. psychopy/tests/test_experiment/needs_wx/test_components.py +2 -2
  259. psychopy/tests/test_experiment/test_components/test_KeyboardComponent.py +28 -0
  260. psychopy/tests/test_experiment/test_components/test_UnknownPluginComponent.py +27 -0
  261. psychopy/tests/test_experiment/test_components/test_base_components.py +58 -0
  262. psychopy/tests/test_experiment/test_py2js.py +1 -1
  263. psychopy/tests/test_hardware/test_keyboard.py +184 -16
  264. psychopy/tests/test_hardware/test_ports.py +1 -11
  265. psychopy/tests/test_liaison/test_Liaison.py +47 -0
  266. psychopy/tests/test_misc/test_core.py +5 -0
  267. psychopy/tests/test_session/test_Session.py +5 -1
  268. psychopy/tests/test_tools/test_versionchooser.py +39 -8
  269. psychopy/tests/test_visual/test_all_stimuli.py +0 -97
  270. psychopy/tests/test_visual/test_image.py +6 -5
  271. psychopy/tests/test_visual/test_textbox.py +36 -0
  272. psychopy/tests/utils.py +4 -0
  273. psychopy/tools/filetools.py +1 -1
  274. psychopy/tools/pkgtools.py +160 -137
  275. psychopy/tools/versionchooser.py +10 -10
  276. psychopy/tools/wizard.py +3 -3
  277. psychopy/visual/.DS_Store +0 -0
  278. psychopy/visual/backends/pygletbackend.py +24 -13
  279. psychopy/visual/basevisual.py +5 -11
  280. psychopy/visual/button.py +2 -14
  281. psychopy/visual/helpers.py +5 -5
  282. psychopy/visual/line.py +1 -2
  283. psychopy/visual/movie2.py +7 -816
  284. psychopy/visual/movie3.py +7 -589
  285. psychopy/visual/movies/__init__.py +8 -11
  286. psychopy/visual/movies/frame.py +5 -2
  287. psychopy/visual/movies/players/ffpyplayer_player.py +5 -2
  288. psychopy/visual/noise.py +8 -7
  289. psychopy/visual/patch.py +7 -16
  290. psychopy/visual/progress.py +1 -1
  291. psychopy/visual/radial.py +9 -7
  292. psychopy/visual/ratingscale.py +8 -1415
  293. psychopy/visual/secondorder.py +10 -9
  294. psychopy/visual/shape.py +7 -2
  295. psychopy/visual/text.py +1 -1
  296. psychopy/visual/textbox2/textbox2.py +28 -5
  297. psychopy/web.py +5 -2
  298. {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/METADATA +8 -13
  299. {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/RECORD +313 -219
  300. {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/WHEEL +1 -1
  301. psychopy/app/Resources/click.png +0 -0
  302. psychopy/app/Resources/next.png +0 -0
  303. psychopy/experiment/components/patch/__init__.py +0 -121
  304. psychopy/experiment/components/patch/classic/patch.png +0 -0
  305. psychopy/experiment/components/patch/dark/patch.png +0 -0
  306. psychopy/experiment/components/patch/dark/patch@2x.png +0 -0
  307. psychopy/experiment/components/patch/light/patch.png +0 -0
  308. psychopy/experiment/components/patch/light/patch@2x.png +0 -0
  309. psychopy/experiment/components/ratingScale/__init__.py +0 -337
  310. psychopy/experiment/components/ratingScale/classic/ratingscale.png +0 -0
  311. psychopy/experiment/components/ratingScale/classic/ratingscale@2x.png +0 -0
  312. psychopy/experiment/components/ratingScale/dark/ratingScale@2x.png +0 -0
  313. psychopy/experiment/components/ratingScale/dark/ratingscale.png +0 -0
  314. psychopy/experiment/components/ratingScale/light/ratingScale@2x.png +0 -0
  315. psychopy/experiment/components/ratingScale/light/ratingscale.png +0 -0
  316. psychopy/platform_specific/posix.py +0 -16
  317. psychopy/tests/test_sound/test_microphone.py +0 -217
  318. psychopy/tests/test_visual/test_ratingScale.py +0 -299
  319. /psychopy/{app/Resources → assets}/Psychopy Window Favicon@16w.png +0 -0
  320. /psychopy/{app/Resources → assets}/Psychopy Window Favicon@32w.png +0 -0
  321. /psychopy/{app/Resources → assets}/USB-C.png +0 -0
  322. /psychopy/{app/Resources → assets}/USB.png +0 -0
  323. /psychopy/{app/Resources → assets}/creditCard.png +0 -0
  324. /psychopy/{app/Resources → assets}/default.mp3 +0 -0
  325. /psychopy/{app/Resources → assets}/default.mp4 +0 -0
  326. /psychopy/{app/Resources → assets}/default.png +0 -0
  327. /psychopy/{app/Resources → assets/templates}/instruct1.png +0 -0
  328. /psychopy/{app/Resources → assets/templates}/instruct2.png +0 -0
  329. {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/entry_points.txt +0 -0
  330. {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/licenses/AUTHORS.md +0 -0
  331. {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -150,13 +150,22 @@ class MouseComponent(BaseComponent):
150
150
  " gotValidClick = True\n")
151
151
  buff.writeIndentedLines(code % self.params)
152
152
 
153
- buff.setIndentLevel(+2, relative=True)
154
- code = ''
153
+ # store clicked object if there was one
154
+ code = ""
155
155
  for paramName in self._clickableParamsList:
156
- code += "%s.clicked_%s.append(obj.%s)\n" %(self.params['name'],
157
- paramName, paramName)
156
+ code += (
157
+ f" %(name)s.clicked_{paramName}.append(obj.{paramName})\n"
158
+ )
159
+ buff.writeIndentedLines(code % self.params)
160
+
161
+ # if storing every click and got an invalid click, store None for all params when there was no valid click
162
+ if self.params['saveMouseState'].val not in ['on valid click', 'never']:
163
+ code = "if not gotValidClick:\n"
164
+ for paramName in self._clickableParamsList:
165
+ code += (
166
+ f" %(name)s.clicked_{paramName}.append(None)\n"
167
+ )
158
168
  buff.writeIndentedLines(code % self.params)
159
- buff.setIndentLevel(-2, relative=True)
160
169
 
161
170
  def _writeCorrectAnsCode(self, buff):
162
171
  code = (
@@ -183,7 +192,7 @@ class MouseComponent(BaseComponent):
183
192
  "// check whether click was in correct object\n"
184
193
  "if (gotValidClick) {\n"
185
194
  " corr = 0;\n"
186
- " corrAns = %(correctAns)s;\n"
195
+ " corrAns = eval( %(correctAns)s);\n"
187
196
  " for (let obj of [corrAns]) {\n"
188
197
  " if (obj.contains(%(name)s)) {\n"
189
198
  " corr = 1;\n"
@@ -211,22 +220,35 @@ class MouseComponent(BaseComponent):
211
220
  code = (
212
221
  "// check if the mouse was inside our 'clickable' objects\n"
213
222
  "gotValidClick = false;\n"
214
- "for (const obj of [{clickable}]) {{\n"
215
- " if (obj.contains({name})) {{\n"
216
- " gotValidClick = true;\n")
217
- buff.writeIndentedLines(code.format(name=self.params['name'],
218
- clickable=self.params['clickable'].val))
219
- buff.setIndentLevel(+2, relative=True)
220
- dedent = 2
221
- code = ''
223
+ "%(name)s.clickableObjects = eval(%(clickable)s)\n;"
224
+ "// make sure the mouse's clickable objects are an array\n"
225
+ "if (!Array.isArray(%(name)s.clickableObjects)) {\n"
226
+ " %(name)s.clickableObjects = [%(name)s.clickableObjects];\n"
227
+ "}\n"
228
+ "// iterate through clickable objects and check each\n"
229
+ "for (const obj of %(name)s.clickableObjects) {\n"
230
+ " if (obj.contains(%(name)s)) {\n"
231
+ " gotValidClick = true;\n"
232
+ )
222
233
  for paramName in self._clickableParamsList:
223
- code += "%s.clicked_%s.push(obj.%s)\n" % (self.params['name'],
224
- paramName, paramName)
234
+ code += (
235
+ f" %(name)s.clicked_{paramName}.push(obj.{paramName});\n"
236
+ )
237
+ code += (
238
+ " }\n"
239
+ "}\n"
240
+ )
241
+ buff.writeIndentedLines(code % self.params)
225
242
 
243
+ # if storing every click and got an invalid click, store None for all params when there was no valid click
244
+ if self.params['saveMouseState'].val not in ['on valid click', 'never']:
245
+ code = "if (!gotValidClick) {\n"
246
+ for paramName in self._clickableParamsList:
247
+ code += (
248
+ f" %(name)s.clicked_{paramName}.push(null);\n"
249
+ )
250
+ code += "}\n"
226
251
  buff.writeIndentedLines(code % self.params)
227
- for dents in range(dedent):
228
- buff.setIndentLevel(-1, relative=True)
229
- buff.writeIndented('}\n')
230
252
 
231
253
  def writeInitCode(self, buff):
232
254
  code = ("%(name)s = event.Mouse(win=win)\n"
@@ -746,14 +768,7 @@ class MouseComponent(BaseComponent):
746
768
  mouseDataProps.append("clicked_{}".format(paramName))
747
769
  # use that set of properties to create set of addData commands
748
770
  for property in mouseDataProps:
749
- if store == 'every frame' or forceEnd in ["never", "correct click"]:
750
- code = ("psychoJS.experiment.addData('%s.%s', %s.%s);\n" %
751
- (name, property, name, property))
752
- buff.writeIndented(code)
753
- else:
754
- # we only had one click so don't return a list
755
- code = ("if (%s.%s) {"
756
- " psychoJS.experiment.addData('%s.%s', %s.%s[0])};\n"
757
- % (name, property, name, property, name, property))
758
- buff.writeIndented(code)
771
+ code = ("psychoJS.experiment.addData('%s.%s', %s.%s);\n" %
772
+ (name, property, name, property))
773
+ buff.writeIndented(code)
759
774
  buff.writeIndentedLines("\n")
@@ -80,7 +80,7 @@ class MovieComponent(BaseVisualComponent):
80
80
 
81
81
  msg = _translate("How loud should audio be played?")
82
82
  self.params["volume"] = Param(
83
- volume, valType='num', inputType="float", categ='Playback',
83
+ volume, valType='num', inputType="single", categ='Playback',
84
84
  hint=msg,
85
85
  label=_translate("Volume"))
86
86
 
@@ -26,6 +26,7 @@ class PolygonComponent(BaseVisualComponent):
26
26
  fillColor='white', fillColorSpace='rgb',
27
27
  shape='triangle', nVertices=4, vertices="",
28
28
  pos=(0, 0), size=(0.5, 0.5), ori=0,
29
+ draggable=False,
29
30
  startType='time (s)', startVal=0.0,
30
31
  stopType='duration (s)', stopVal=1.0,
31
32
  startEstim='', durationEstim=''):
@@ -90,6 +91,14 @@ class PolygonComponent(BaseVisualComponent):
90
91
  updates='constant',
91
92
  hint=_translate("Which point on the stimulus should be anchored to its exact position?"),
92
93
  label=_translate("Anchor"))
94
+ self.params['draggable'] = Param(
95
+ draggable, valType="code", inputType="bool", categ="Layout",
96
+ updates="constant",
97
+ label=_translate("Draggable?"),
98
+ hint=_translate(
99
+ "Should this stimulus be moveble by clicking and dragging?"
100
+ )
101
+ )
93
102
 
94
103
  msg = _translate("What shape is this? With 'regular polygon...' you "
95
104
  "can set number of vertices and with 'custom "
@@ -129,6 +138,14 @@ class PolygonComponent(BaseVisualComponent):
129
138
  "first value is used, for triangle and rect the [w,h] is as "
130
139
  "expected,\n but for higher-order polygons it represents the "
131
140
  "[w,h] of the ellipse that the polygon sits on!! ")
141
+
142
+ self.depends.append({
143
+ 'dependsOn': "shape", # if...
144
+ 'condition': "=='line'", # is...
145
+ 'param': "anchor", # then...
146
+ 'true': "hide", # should...
147
+ 'false': "show", # otherwise...
148
+ })
132
149
 
133
150
  del self.params['color']
134
151
 
@@ -155,7 +172,7 @@ class PolygonComponent(BaseVisualComponent):
155
172
  if vertices in ['line', '2']:
156
173
  code = ("%s = visual.Line(\n" % inits['name'] +
157
174
  " win=win, name='%s',%s\n" % (inits['name'], unitsStr) +
158
- " start=(-%(size)s[0]/2.0, 0), end=(+%(size)s[0]/2.0, 0),\n" % inits)
175
+ " size=%(size)s,\n" % inits)
159
176
  elif vertices in ['triangle', '3']:
160
177
  code = ("%s = visual.ShapeStim(\n" % inits['name'] +
161
178
  " win=win, name='%s',%s\n" % (inits['name'], unitsStr) +
@@ -186,9 +203,9 @@ class PolygonComponent(BaseVisualComponent):
186
203
  " win=win, name='%s', vertices=%s,%s\n" % (inits['name'], vertices, unitsStr) +
187
204
  " size=%(size)s,\n" % inits)
188
205
 
189
- code += (" ori=%(ori)s, pos=%(pos)s, anchor=%(anchor)s,\n"
190
- " lineWidth=%(lineWidth)s, "
191
- " colorSpace=%(colorSpace)s, lineColor=%(lineColor)s, fillColor=%(fillColor)s,\n"
206
+ code += (" ori=%(ori)s, pos=%(pos)s, draggable=%(draggable)s, anchor=%(anchor)s,\n"
207
+ " lineWidth=%(lineWidth)s,\n"
208
+ " colorSpace=%(colorSpace)s, lineColor=%(lineColor)s, fillColor=%(fillColor)s,\n"
192
209
  " opacity=%(opacity)s, " % inits)
193
210
 
194
211
  depth = -self.getPosInRoutine()
@@ -276,7 +293,9 @@ class PolygonComponent(BaseVisualComponent):
276
293
  if self.params['interpolate'].val != 'linear':
277
294
  interpolate = 'false'
278
295
 
279
- code += (" ori: {ori}, pos: {pos},\n"
296
+ code += (" ori: {ori}, \n"
297
+ " pos: {pos}, \n"
298
+ " draggable: {draggable}, \n"
280
299
  " anchor: {anchor},\n"
281
300
  " lineWidth: {lineWidth}, \n"
282
301
  " colorSpace: {colorSpace},\n")
@@ -310,5 +329,6 @@ class PolygonComponent(BaseVisualComponent):
310
329
  depth=depth,
311
330
  interpolate=interpolate,
312
331
  nVertices=inits['nVertices'],
313
- vertices=inits['vertices']
332
+ vertices=inits['vertices'],
333
+ draggable=inits['draggable']
314
334
  ))
@@ -24,7 +24,7 @@ class ProgressComponent(BaseVisualComponent):
24
24
  progress=0,
25
25
  color="white", fillColor="None", borderColor="white", colorSpace="rgb",
26
26
  opacity=1, lineWidth=4,
27
- pos=(0, 0), size=(0.5, 0.5), anchor="center left", ori=0, units="height",
27
+ pos=(0, 0), size=(0.5, 0.5), anchor="center-left", ori=0, units="height",
28
28
  disabled=False):
29
29
 
30
30
  self.exp = exp # so we can access the experiment if necess
@@ -301,6 +301,11 @@ class RegionOfInterestComponent(PolygonComponent):
301
301
  f"if {name}.numLooks:\n"
302
302
  f" {currLoop.params['name']}.addData('{name}.timesOn', {name}.timesOn{index})\n"
303
303
  f" {currLoop.params['name']}.addData('{name}.timesOff', {name}.timesOff{index})\n"
304
+ f" # calculate and store dwell times i.e. the duration between look onsets and offsets\n"
305
+ f" {name}.dwellTime = 0.0\n"
306
+ f" for i in range(len({name}.timesOn)):\n"
307
+ f" {name}.dwellTime += {name}.timesOff[i] - {name}.timesOn[i]\n"
308
+ f" {currLoop.params['name']}.addData('{name}.dwellTime', {name}.dwellTime)\n"
304
309
  f"else:\n"
305
310
  f" {currLoop.params['name']}.addData('{name}.timesOn', \"\")\n"
306
311
  f" {currLoop.params['name']}.addData('{name}.timesOff', \"\")\n"
@@ -19,9 +19,10 @@ class RoutineSettingsComponent(BaseComponent):
19
19
  self, exp, parentName,
20
20
  # Basic
21
21
  name='',
22
- skipIf="",
23
- # Description
24
22
  desc="",
23
+ # Flow
24
+ skipIf="",
25
+ forceNonSlip=False,
25
26
  # Window
26
27
  useWindowParams=False,
27
28
  color="$[0,0,0]",
@@ -65,6 +66,17 @@ class RoutineSettingsComponent(BaseComponent):
65
66
  self.params['durationEstim'].categ = "Flow"
66
67
 
67
68
  # --- Flow params ---
69
+ self.order += [
70
+ "forceNonSlip",
71
+ "skipIf",
72
+ ]
73
+ self.params['forceNonSlip'] = Param(
74
+ forceNonSlip, valType="code", inputType="bool", categ="Flow",
75
+ hint=_translate(
76
+ "If this Routine ended by hitting its max duration, reset the timer by subtracting the max duration rather than resetting to 0. Only tick this if you're sure you know how long the Routine is going to take, otherwise you'll get incorrect timestamps in the next Routine!"
77
+ ),
78
+ label=_translate("Non-slip timing")
79
+ )
68
80
  self.params['skipIf'] = Param(
69
81
  skipIf, valType='code', inputType="single", categ='Flow',
70
82
  updates='constant',
@@ -146,17 +158,34 @@ class RoutineSettingsComponent(BaseComponent):
146
158
  def writeRoutineStartCode(self, buff):
147
159
  # Sanitize
148
160
  params = self.params.copy()
149
- # Store Routine start time (UTC)
161
+ if params['stopVal'] in ("None", None, ""):
162
+ params['stopVal'].val = "None"
163
+ # store start times
164
+ code = (
165
+ "# store start times for %(name)s\n"
166
+ "%(name)s.tStartRefresh = win.getFutureFlipTime(clock=globalClock)\n"
167
+ "%(name)s.tStart = globalClock.getTime(format='float')\n"
168
+ "%(name)s.status = STARTED\n"
169
+ )
170
+ buff.writeIndentedLines(code % self.params)
171
+ # add to data file if requested
150
172
  if self.params['saveStartStop']:
151
173
  code = (
152
- "thisExp.addData('%(name)s.started', globalClock.getTime(format='float'))\n"
174
+ "thisExp.addData('%(name)s.started', %(name)s.tStart)\n"
175
+ )
176
+ buff.writeIndentedLines(code % params)
177
+ # calculate expected Routine duration
178
+ if self.params['stopType'] == "duration (s)":
179
+ code = (
180
+ "%(name)s.maxDuration = %(stopVal)s\n"
153
181
  )
154
182
  buff.writeIndentedLines(code % params)
155
183
  # Skip Routine if condition is met
156
184
  if params['skipIf'].val not in ('', None, -1, 'None'):
157
185
  code = (
158
- "# skip this Routine if its 'Skip if' condition is True\n"
159
- "continueRoutine = continueRoutine and not (%(skipIf)s)\n"
186
+ "# skip Routine %(name)s if its 'Skip if' condition is True\n"
187
+ "%(name)s.skipped = continueRoutine and not (%(skipIf)s)\n"
188
+ "continueRoutine = %(name)s.skipped\n"
160
189
  )
161
190
  buff.writeIndentedLines(code % params)
162
191
  # Change window appearance for this Routine (if requested)
@@ -172,6 +201,8 @@ class RoutineSettingsComponent(BaseComponent):
172
201
  def writeRoutineStartCodeJS(self, buff):
173
202
  # Sanitize
174
203
  params = self.params.copy()
204
+ if params['stopVal'] in ("None", None, ""):
205
+ params['stopVal'].val = "None"
175
206
  # Store Routine start time (UTC)
176
207
  if self.params['saveStartStop']:
177
208
  code = (
@@ -183,6 +214,13 @@ class RoutineSettingsComponent(BaseComponent):
183
214
  code = (
184
215
  "// skip this Routine if its 'Skip if' condition is True\n"
185
216
  "continueRoutine = continueRoutine && !(%(skipIf)s);\n"
217
+ "maxDurationReached = false\n"
218
+ )
219
+ buff.writeIndentedLines(code % params)
220
+ # calculate expected Routine duration
221
+ if self.params['stopType'] == "duration (s)":
222
+ code = (
223
+ "%(name)sMaxDuration = %(stopVal)s\n"
186
224
  )
187
225
  buff.writeIndentedLines(code % params)
188
226
  # Change window appearance for this Routine (if requested)
@@ -224,7 +262,8 @@ class RoutineSettingsComponent(BaseComponent):
224
262
  # Stop after given number of seconds
225
263
  code = (
226
264
  f"# is it time to end the Routine? (based on local clock)\n"
227
- f"if tThisFlip > %(stopVal)s-frameTolerance:\n"
265
+ f"if tThisFlip > %(name)s.maxDuration-frameTolerance:\n"
266
+ f" %(name)s.maxDurationReached = True\n"
228
267
  )
229
268
  elif self.params['stopType'].val == 'frame N':
230
269
  # Stop at given frame num
@@ -261,7 +300,8 @@ class RoutineSettingsComponent(BaseComponent):
261
300
  # Stop after given number of seconds
262
301
  code = (
263
302
  f"// is it time to end the Routine? (based on local clock)\n"
264
- f"if (t > %(stopVal)s) {{\n"
303
+ f"if (t > %(name)sMaxDuration) {{\n"
304
+ f" %(name)sMaxDurationReached = true\n"
265
305
  )
266
306
  elif self.params['stopType'].val == 'frame N':
267
307
  # Stop at given frame num
@@ -287,10 +327,17 @@ class RoutineSettingsComponent(BaseComponent):
287
327
 
288
328
  def writeRoutineEndCode(self, buff):
289
329
  params = self.params.copy()
290
- # Store Routine start time (UTC)
330
+ # store stop times
331
+ code = (
332
+ "# store stop times for %(name)s\n"
333
+ "%(name)s.tStop = globalClock.getTime(format='float')\n"
334
+ "%(name)s.tStopRefresh = tThisFlipGlobal\n"
335
+ )
336
+ buff.writeIndentedLines(code % params)
337
+ # add to data file if requested
291
338
  if self.params['saveStartStop']:
292
339
  code = (
293
- "thisExp.addData('%(name)s.stopped', globalClock.getTime(format='float'))\n"
340
+ "thisExp.addData('%(name)s.stopped', %(name)s.tStop)\n"
294
341
  )
295
342
  buff.writeIndentedLines(code % params)
296
343
  # Restore window appearance after this Routine (if changed)