psychopy 2024.2.1__py3-none-any.whl → 2024.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.

Potentially problematic release.


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

Files changed (276) hide show
  1. psychopy/.DS_Store +0 -0
  2. psychopy/GIT_SHA +1 -1
  3. psychopy/VERSION +1 -1
  4. psychopy/__init__.py +10 -1
  5. psychopy/__init__.py.orig +65 -0
  6. psychopy/app/{locale/ar_001/.DS_Store → .DS_Store} +0 -0
  7. psychopy/app/Resources/.DS_Store +0 -0
  8. psychopy/app/_psychopyApp.py +11 -3
  9. psychopy/app/appData.spec +1 -1
  10. psychopy/app/builder/builder.py +1 -1
  11. psychopy/app/builder/builder.py.orig +3932 -0
  12. psychopy/app/builder/dialogs/__init__.py.orig +1679 -0
  13. psychopy/app/builder/dialogs/paramCtrls.py +1 -1
  14. psychopy/app/builder/dialogs/paramCtrls.py.orig +713 -0
  15. psychopy/app/colorpicker/__init__.py.orig +411 -0
  16. psychopy/app/cortex.log +0 -0
  17. psychopy/app/jobs.py +8 -1
  18. psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +2452 -1731
  19. psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN.mo +0 -0
  20. psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN.po +6127 -0
  21. psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN_allFlagged.mo +0 -0
  22. psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN_allFlagged.po +7366 -0
  23. psychopy/app/plugin_manager/dialog.py +9 -7
  24. psychopy/app/ribbon.py +2 -1
  25. psychopy/app/runner/runner.py +7 -5
  26. psychopy/clock.py +8 -4
  27. psychopy/core.py.orig +169 -0
  28. psychopy/demos/builder/Design Templates/randomisedBlocks/html/index.html +23 -0
  29. psychopy/demos/builder/Design Templates/randomisedBlocks/html/randomisedBlocks-legacy-browsers.js +423 -0
  30. psychopy/demos/builder/Design Templates/randomisedBlocks/html/randomisedBlocks.js +427 -0
  31. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/chooseBlock.xlsx +0 -0
  32. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/facesBlock.xlsx +0 -0
  33. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/housesBlock.xlsx +0 -0
  34. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face01.jpg +0 -0
  35. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face02.jpg +0 -0
  36. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face03.jpg +0 -0
  37. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house01.jpg +0 -0
  38. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house02.jpg +0 -0
  39. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house03.jpg +0 -0
  40. psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks.py +330 -0
  41. psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks_lastrun.py +330 -0
  42. psychopy/demos/builder/Feature Demos/eyetracking/eyetracking.xml +298 -0
  43. psychopy/demos/builder/Feature Demos/eyetracking/eyetracking.xsd +120 -0
  44. psychopy/demos/builder/Tools/.DS_Store +0 -0
  45. psychopy/demos/builder/Tools/gammaCalibration/.DS_Store +0 -0
  46. psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.csv +38 -0
  47. psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.log +3418 -0
  48. psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.psydat +0 -0
  49. psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.csv +2 -0
  50. psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.log +15 -0
  51. psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.psydat +0 -0
  52. psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual.psyexp +323 -0
  53. psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual.py +562 -0
  54. psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual_lastrun.py +562 -0
  55. psychopy/demos/builder/Tools/gammaCalibration/questStairs.xlsx +0 -0
  56. psychopy/demos/builder/Tools/gammaCalibration/readme.md +0 -0
  57. psychopy/demos/builder/Tools/gammaCalibration/resources/low_contrast.png +0 -0
  58. psychopy/demos/builder/Tools/gammaCalibration/resources/make_2nd_order_tex.py +59 -0
  59. psychopy/demos/builder/Tools/gammaCalibration/resources/second_order_tex.png +0 -0
  60. psychopy/demos/coder/.DS_Store +0 -0
  61. psychopy/demos/coder/experiment control/info_gamma.pickle +0 -0
  62. psychopy/demos/coder/iohub/.iohpid +1 -0
  63. psychopy/demos/coder/iohub/eyetracking/.iohpid +1 -0
  64. psychopy/demos/coder/iohub/wintab/.DS_Store +0 -0
  65. psychopy/demos/coder/stimuli/.DS_Store +0 -0
  66. psychopy/demos/coder/stimuli/radialGratingContracting.py +29 -0
  67. psychopy/experiment/_experiment.py.orig +1032 -0
  68. psychopy/experiment/components/.DS_Store +0 -0
  69. psychopy/experiment/components/_base.py +13 -4
  70. psychopy/experiment/components/_base.py.orig +823 -0
  71. psychopy/experiment/components/form/.DS_Store +0 -0
  72. psychopy/experiment/components/microphone/__init__.py +10 -1
  73. psychopy/experiment/components/microphone/__init__.py.orig +490 -0
  74. psychopy/experiment/components/polygon/__init__.py +21 -22
  75. psychopy/experiment/components/settings/__init__.py +13 -14
  76. psychopy/experiment/components/settings/__init__.py.orig +1337 -0
  77. psychopy/experiment/components/textbox/__init__.py.orig +310 -0
  78. psychopy/experiment/components/webcam/.DS_Store +0 -0
  79. psychopy/experiment/components/webcam/light/.DS_Store +0 -0
  80. psychopy/experiment/flow.py +10 -8
  81. psychopy/experiment/loops.py.orig +829 -0
  82. psychopy/experiment/params.py +8 -3
  83. psychopy/experiment/params.py.orig +408 -0
  84. psychopy/experiment/routine.py.orig +503 -0
  85. psychopy/experiment/routines/_base.py +15 -6
  86. psychopy/experiment/routines/counterbalance/__init__.py +1 -0
  87. psychopy/gui/qtgui.py +14 -7
  88. psychopy/gui/util.py +10 -14
  89. psychopy/gui/wxgui.py +10 -4
  90. psychopy/hardware/.DS_Store +0 -0
  91. psychopy/hardware/brainproducts.py.orig +680 -0
  92. psychopy/hardware/iolab.py.orig +238 -0
  93. psychopy/hardware/manager.py +1 -1
  94. psychopy/hardware/photodiode.py +59 -27
  95. psychopy/hardware/serialport.py +51 -0
  96. psychopy/hardware/speaker.py +4 -4
  97. psychopy/iohub/datastore/__init__.py.orig +443 -0
  98. psychopy/iohub/datastore/util.py.orig +692 -0
  99. psychopy/iohub/devices/mouse/darwin.py.orig +427 -0
  100. psychopy/iohub/devices/mouse/linux2.py.orig +198 -0
  101. psychopy/preferences/.DS_Store +0 -0
  102. psychopy/projects/pavlovia.py +10 -3
  103. psychopy/projects/pavlovia.py.orig +1295 -0
  104. psychopy/sound/backend_ptb.py +22 -5
  105. psychopy/sound/transcribe.py +24 -4
  106. psychopy/tests/.DS_Store +0 -0
  107. psychopy/tests/data/.DS_Store +0 -0
  108. psychopy/tests/data/TestCircle_fill_local.png +0 -0
  109. psychopy/tests/data/__test.png +0 -0
  110. psychopy/tests/data/aperture1_normHexbackground_local.png +0 -0
  111. psychopy/tests/data/aperture1_norm_local.png +0 -0
  112. psychopy/tests/data/aperture2_normHexbackground_local.png +0 -0
  113. psychopy/tests/data/beatandrcos_height_local.png +0 -0
  114. psychopy/tests/data/beatandrcos_normAddBlend_local.png +0 -0
  115. psychopy/tests/data/beatandrcos_normHexbackground_local.png +0 -0
  116. psychopy/tests/data/beatandrcos_norm_local.png +0 -0
  117. psychopy/tests/data/beatandrcos_stencil_local.png +0 -0
  118. psychopy/tests/data/blend_add_height_local.png +0 -0
  119. psychopy/tests/data/blend_add_normAddBlend_local.png +0 -0
  120. psychopy/tests/data/blend_add_normHexbackground_local.png +0 -0
  121. psychopy/tests/data/blend_add_normNoShade_local.png +0 -0
  122. psychopy/tests/data/blend_add_norm_local.png +0 -0
  123. psychopy/tests/data/blend_add_stencil_local.png +0 -0
  124. psychopy/tests/data/bufferimg_gabor_height_local.png +0 -0
  125. psychopy/tests/data/bufferimg_gabor_normAddBlend_local.png +0 -0
  126. psychopy/tests/data/bufferimg_gabor_normHexbackground_local.png +0 -0
  127. psychopy/tests/data/bufferimg_gabor_normNoShade_local.png +0 -0
  128. psychopy/tests/data/bufferimg_gabor_norm_local.png +0 -0
  129. psychopy/tests/data/bufferimg_gabor_stencil_local.png +0 -0
  130. psychopy/tests/data/circleHex_height_local.png +0 -0
  131. psychopy/tests/data/circleHex_normAddBlend_local.png +0 -0
  132. psychopy/tests/data/circleHex_normHexbackground_local.png +0 -0
  133. psychopy/tests/data/circleHex_normNoShade_local.png +0 -0
  134. psychopy/tests/data/circleHex_norm_local.png +0 -0
  135. psychopy/tests/data/circleHex_stencil_local.png +0 -0
  136. psychopy/tests/data/color_comparison_local.png +0 -0
  137. psychopy/tests/data/corrFullRandom_local.csv +16 -0
  138. psychopy/tests/data/corrFullRandom_local.tsv +6 -0
  139. psychopy/tests/data/correctScript/.DS_Store +0 -0
  140. psychopy/tests/data/dots_height_local.png +0 -0
  141. psychopy/tests/data/dots_normAddBlend_local.png +0 -0
  142. psychopy/tests/data/dots_normHexbackground_local.png +0 -0
  143. psychopy/tests/data/dots_normNoShade_local.png +0 -0
  144. psychopy/tests/data/dots_norm_local.png +0 -0
  145. psychopy/tests/data/dots_stencil_local.png +0 -0
  146. psychopy/tests/data/elarray1_height_local.png +0 -0
  147. psychopy/tests/data/elarray1_normAddBlend_local.png +0 -0
  148. psychopy/tests/data/elarray1_normHexbackground_local.png +0 -0
  149. psychopy/tests/data/elarray1_norm_local.png +0 -0
  150. psychopy/tests/data/elarray1_stencil_local.png +0 -0
  151. psychopy/tests/data/envelopeandrcos_height_local.png +0 -0
  152. psychopy/tests/data/envelopeandrcos_normAddBlend_local.png +0 -0
  153. psychopy/tests/data/envelopeandrcos_normHexbackground_local.png +0 -0
  154. psychopy/tests/data/envelopeandrcos_norm_local.png +0 -0
  155. psychopy/tests/data/envelopeandrcos_stencil_local.png +0 -0
  156. psychopy/tests/data/envelopepowerandrcos_height_local.png +0 -0
  157. psychopy/tests/data/envelopepowerandrcos_normAddBlend_local.png +0 -0
  158. psychopy/tests/data/envelopepowerandrcos_normHexbackground_local.png +0 -0
  159. psychopy/tests/data/envelopepowerandrcos_norm_local.png +0 -0
  160. psychopy/tests/data/envelopepowerandrcos_stencil_local.png +0 -0
  161. psychopy/tests/data/gabor1_height_local.png +0 -0
  162. psychopy/tests/data/gabor1_normAddBlend_local.png +0 -0
  163. psychopy/tests/data/gabor1_normHexbackground_local.png +0 -0
  164. psychopy/tests/data/gabor1_normNoShade_local.png +0 -0
  165. psychopy/tests/data/gabor1_norm_local.png +0 -0
  166. psychopy/tests/data/gabor1_stencil_local.png +0 -0
  167. psychopy/tests/data/greyscale_normHexbackground_local.png +0 -0
  168. psychopy/tests/data/imageAndGauss_height_local.png +0 -0
  169. psychopy/tests/data/imageAndGauss_normAddBlend_local.png +0 -0
  170. psychopy/tests/data/imageAndGauss_normHexbackground_local.png +0 -0
  171. psychopy/tests/data/imageAndGauss_normNoShade_local.png +0 -0
  172. psychopy/tests/data/imageAndGauss_norm_local.png +0 -0
  173. psychopy/tests/data/imageAndGauss_stencil_local.png +0 -0
  174. psychopy/tests/data/movFrame1_stencil_local.png +0 -0
  175. psychopy/tests/data/noiseAndRcos_height_local.png +0 -0
  176. psychopy/tests/data/noiseAndRcos_normAddBlend_local.png +0 -0
  177. psychopy/tests/data/noiseAndRcos_normHexbackground_local.png +0 -0
  178. psychopy/tests/data/noiseAndRcos_normNoShade_local.png +0 -0
  179. psychopy/tests/data/noiseAndRcos_norm_local.png +0 -0
  180. psychopy/tests/data/noiseAndRcos_stencil_local.png +0 -0
  181. psychopy/tests/data/noiseFiltersAndRcos_height_local.png +0 -0
  182. psychopy/tests/data/noiseFiltersAndRcos_normAddBlend_local.png +0 -0
  183. psychopy/tests/data/noiseFiltersAndRcos_normHexbackground_local.png +0 -0
  184. psychopy/tests/data/noiseFiltersAndRcos_normNoShade_local.png +0 -0
  185. psychopy/tests/data/noiseFiltersAndRcos_norm_local.png +0 -0
  186. psychopy/tests/data/noiseFiltersAndRcos_stencil_local.png +0 -0
  187. psychopy/tests/data/numpyImage_height_local.png +0 -0
  188. psychopy/tests/data/numpyImage_normAddBlend_local.png +0 -0
  189. psychopy/tests/data/numpyImage_normHexbackground_local.png +0 -0
  190. psychopy/tests/data/numpyImage_normNoShade_local.png +0 -0
  191. psychopy/tests/data/numpyImage_norm_local.png +0 -0
  192. psychopy/tests/data/numpyImage_stencil_local.png +0 -0
  193. psychopy/tests/data/shape2_1_normAddBlend_local.png +0 -0
  194. psychopy/tests/data/shape2_1_normHexbackground_local.png +0 -0
  195. psychopy/tests/data/shape2_1_normNoShade_local.png +0 -0
  196. psychopy/tests/data/shape2_1_norm_local.png +0 -0
  197. psychopy/tests/data/shape2_1_stencil_local.png +0 -0
  198. psychopy/tests/data/testLoopsBlocks.psyexp_local.py +328 -0
  199. psychopy/tests/data/text1_height_local.png +0 -0
  200. psychopy/tests/data/text1_normAddBlend_local.png +0 -0
  201. psychopy/tests/data/text1_normHexbackground_local.png +0 -0
  202. psychopy/tests/data/text1_norm_local.png +0 -0
  203. psychopy/tests/data/text1_stencil_local.png +0 -0
  204. psychopy/tests/data/text2_height.png +0 -0
  205. psychopy/tests/data/text2_normAddBlend.png +0 -0
  206. psychopy/tests/data/text2_normHexbackground.png +0 -0
  207. psychopy/tests/data/text2_stencil.png +0 -0
  208. psychopy/tests/data/wedge1_height_local.png +0 -0
  209. psychopy/tests/data/wedge1_normAddBlend_local.png +0 -0
  210. psychopy/tests/data/wedge1_normHexbackground_local.png +0 -0
  211. psychopy/tests/data/wedge1_normNoShade_local.png +0 -0
  212. psychopy/tests/data/wedge1_norm_local.png +0 -0
  213. psychopy/tests/data/wedge1_stencil_local.png +0 -0
  214. psychopy/tests/test_app/.DS_Store +0 -0
  215. psychopy/tests/test_app/test_builder/.DS_Store +0 -0
  216. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.csv +9 -0
  217. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.log +177 -0
  218. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.psydat +0 -0
  219. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.xlsx +0 -0
  220. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.csv +9 -0
  221. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.log +168 -0
  222. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.psydat +0 -0
  223. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.xlsx +0 -0
  224. psychopy/tests/test_data/.DS_Store +0 -0
  225. psychopy/tests/test_hardware/test_CRS_BitsSharp.py.orig +68 -0
  226. psychopy/tests/test_tools/test_arraytools.py +112 -0
  227. psychopy/tests/test_visual/test_image.py.orig +219 -0
  228. psychopy/tools/arraytools.py +47 -0
  229. psychopy/tools/versionchooser.py +1 -1
  230. psychopy/visual/backends/pygletbackend.py +26 -8
  231. psychopy/visual/basevisual.py.orig +1723 -0
  232. psychopy/visual/form.py.orig +1181 -0
  233. psychopy/visual/text.py.orig +752 -0
  234. psychopy/visual/textbox2/textbox2.py.orig +1315 -0
  235. psychopy/visual/window.py +13 -5
  236. psychopy/visual/windowwarp.py.orig +463 -0
  237. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/METADATA +9 -9
  238. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/RECORD +244 -78
  239. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/WHEEL +1 -1
  240. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/entry_points.txt +2 -0
  241. psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
  242. psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
  243. psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
  244. psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
  245. psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
  246. psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
  247. psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
  248. psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
  249. psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
  250. psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
  251. psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
  252. psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
  253. psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
  254. psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
  255. psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
  256. psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
  257. psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
  258. psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
  259. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
  260. psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
  261. psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
  262. psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
  263. psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
  264. psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
  265. psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
  266. psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
  267. psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
  268. psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
  269. psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
  270. psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
  271. psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
  272. psychopy-2024.2.1.dist-info/licenses/AUTHORS.md +0 -138
  273. /psychopy/{app/locale/ar_001/LC_MESSAGE → demos/builder}/.DS_Store +0 -0
  274. /psychopy/{app/locale/es_ES/LC_MESSAGE → demos/builder/Experiments}/.DS_Store +0 -0
  275. /psychopy/{visual → demos/builder/Tools/gammaCalibration/data}/.DS_Store +0 -0
  276. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,503 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # Part of the PsychoPy library
5
+ # Copyright (C) 2002-2018 Jonathan Peirce (C) 2019-2020 Open Science Tools Ltd.
6
+ # Distributed under the terms of the GNU General Public License (GPL).
7
+
8
+ """Describes the Flow of an experiment
9
+ """
10
+
11
+ from __future__ import absolute_import, print_function
12
+
13
+ from psychopy.constants import FOREVER
14
+
15
+
16
+ class Routine(list):
17
+ """
18
+ A Routine determines a single sequence of events, such
19
+ as the presentation of trial. Multiple Routines might be
20
+ used to comprise an Experiment (e.g. one for presenting
21
+ instructions, one for trials, one for debriefing subjects).
22
+
23
+ In practice a Routine is simply a python list of Components,
24
+ each of which knows when it starts and stops.
25
+ """
26
+
27
+ def __init__(self, name, exp, components=()):
28
+ super(Routine, self).__init__()
29
+ self.params = {'name': name}
30
+ self.name = name
31
+ self.exp = exp
32
+ self._clockName = None # for scripts e.g. "t = trialClock.GetTime()"
33
+ self.type = 'Routine'
34
+ list.__init__(self, list(components))
35
+
36
+ def __repr__(self):
37
+ _rep = "psychopy.experiment.Routine(name='%s', exp=%s, components=%s)"
38
+ return _rep % (self.name, self.exp, str(list(self)))
39
+
40
+ @property
41
+ def name(self):
42
+ return self.params['name']
43
+
44
+ @name.setter
45
+ def name(self, name):
46
+ self.params['name'] = name
47
+
48
+ def integrityCheck(self):
49
+ """Run tests on self and on all the Components inside"""
50
+ for entry in self:
51
+ if hasattr(entry, "integrityCheck"):
52
+ entry.integrityCheck()
53
+
54
+ def addComponent(self, component):
55
+ """Add a component to the end of the routine"""
56
+ self.append(component)
57
+
58
+ def removeComponent(self, component):
59
+ """Remove a component from the end of the routine"""
60
+ name = component.params['name']
61
+ self.remove(component)
62
+ # check if the component was using any Static Components for updates
63
+ for thisParamName, thisParam in list(component.params.items()):
64
+ if (hasattr(thisParam, 'updates') and
65
+ thisParam.updates and
66
+ 'during:' in thisParam.updates):
67
+ # remove the part that says 'during'
68
+ updates = thisParam.updates.split(': ')[1]
69
+ routine, static = updates.split('.')
70
+ comp = self.exp.routines[routine].getComponentFromName(static)
71
+ comp.remComponentUpdate(routine, name, thisParamName)
72
+
73
+ def getStatics(self):
74
+ """Return a list of Static components
75
+ """
76
+ statics = []
77
+ for comp in self:
78
+ if comp.type == 'Static':
79
+ statics.append(comp)
80
+ return statics
81
+
82
+ def writePreCode(self, buff):
83
+ """This is start of the script (before window is created)
84
+ """
85
+ for thisCompon in self:
86
+ # check just in case; try to ensure backwards compatibility _base
87
+ if hasattr(thisCompon, 'writePreCode'):
88
+ thisCompon.writePreCode(buff)
89
+
90
+ def writePreCodeJS(self, buff):
91
+ """This is start of the script (before window is created)
92
+ """
93
+ for thisCompon in self:
94
+ # check just in case; try to ensure backwards compatibility _base
95
+ if hasattr(thisCompon, 'writePreCodeJS'):
96
+ thisCompon.writePreCodeJS(buff)
97
+
98
+ def writeStartCode(self, buff):
99
+ """This is start of the *experiment* (after window is created)
100
+ """
101
+ for thisCompon in self:
102
+ # check just in case; try to ensure backwards compatibility _base
103
+ if hasattr(thisCompon, 'writeStartCode'):
104
+ thisCompon.writeStartCode(buff)
105
+
106
+ def writeStartCodeJS(self, buff):
107
+ """This is start of the *experiment*
108
+ """
109
+ # few components will have this
110
+ for thisCompon in self:
111
+ # check just in case; try to ensure backwards compatibility _base
112
+ if hasattr(thisCompon, 'writeStartCodeJS'):
113
+ thisCompon.writeStartCodeJS(buff)
114
+
115
+ def writeRunOnceInitCode(self, buff):
116
+ """ Run once init code goes at the beginning of the script (before
117
+ Window creation) and the code will be run only once no matter how many
118
+ similar components request it
119
+ """
120
+ for thisCompon in self:
121
+ # check just in case; try to ensure backwards compatibility _base
122
+ if hasattr(thisCompon, 'writeRunOnceInitCode'):
123
+ thisCompon.writeRunOnceInitCode(buff)
124
+
125
+ def writeInitCode(self, buff):
126
+ code = '\n# Initialize components for Routine "%s"\n'
127
+ buff.writeIndentedLines(code % self.name)
128
+ self._clockName = self.name + "Clock"
129
+ buff.writeIndented('%s = core.Clock()\n' % self._clockName)
130
+ for thisCompon in self:
131
+ thisCompon.writeInitCode(buff)
132
+
133
+ def writeInitCodeJS(self, buff):
134
+ code = '// Initialize components for Routine "%s"\n'
135
+ buff.writeIndentedLines(code % self.name)
136
+ self._clockName = self.name + "Clock"
137
+ buff.writeIndented('%s = new util.Clock();\n' % self._clockName)
138
+ for thisCompon in self:
139
+ if hasattr(thisCompon, 'writeInitCodeJS'):
140
+ thisCompon.writeInitCodeJS(buff)
141
+
142
+ def writeMainCode(self, buff):
143
+ """This defines the code for the frames of a single routine
144
+ """
145
+ # create the frame loop for this routine
146
+ code = ('\n# ------Prepare to start Routine "%s"-------\n')
147
+ buff.writeIndentedLines(code % (self.name))
148
+ code = 'continueRoutine = True\n'
149
+ buff.writeIndentedLines(code)
150
+
151
+ # can we use non-slip timing?
152
+ maxTime, useNonSlip = self.getMaxTime()
153
+ if useNonSlip:
154
+ buff.writeIndented('routineTimer.add(%f)\n' % (maxTime))
155
+
156
+ code = "# update component parameters for each repeat\n"
157
+ buff.writeIndentedLines(code)
158
+ # This is the beginning of the routine, before the loop starts
159
+ for event in self:
160
+ event.writeRoutineStartCode(buff)
161
+
162
+ code = '# keep track of which components have finished\n'
163
+ buff.writeIndentedLines(code)
164
+ # Get list of components, but leave out Variable components, which may not support attributes
165
+ compStr = ', '.join([c.params['name'].val for c in self
166
+ if 'startType' in c.params and c.type != 'Variable'])
167
+ buff.writeIndented('%sComponents = [%s]\n' % (self.name, compStr))
168
+
169
+ code = ("for thisComponent in {name}Components:\n"
170
+ " thisComponent.tStart = None\n"
171
+ " thisComponent.tStop = None\n"
172
+ " thisComponent.tStartRefresh = None\n"
173
+ " thisComponent.tStopRefresh = None\n"
174
+ " if hasattr(thisComponent, 'status'):\n"
175
+ " thisComponent.status = NOT_STARTED\n"
176
+ "# reset timers\n"
177
+ 't = 0\n'
178
+ '_timeToFirstFrame = win.getFutureFlipTime(clock="now")\n'
179
+ '{clockName}.reset(-_timeToFirstFrame) # t0 is time of first possible flip\n'
180
+ 'frameN = -1\n'
181
+ '\n# -------Run Routine "{name}"-------\n')
182
+ buff.writeIndentedLines(code.format(name=self.name,
183
+ clockName=self._clockName))
184
+ if useNonSlip:
185
+ code = 'while continueRoutine and routineTimer.getTime() > 0:\n'
186
+ else:
187
+ code = 'while continueRoutine:\n'
188
+ buff.writeIndented(code)
189
+
190
+ buff.setIndentLevel(1, True)
191
+ # on each frame
192
+ code = ('# get current time\n'
193
+ 't = {clockName}.getTime()\n'
194
+ 'tThisFlip = win.getFutureFlipTime(clock={clockName})\n'
195
+ 'tThisFlipGlobal = win.getFutureFlipTime(clock=None)\n'
196
+ 'frameN = frameN + 1 # number of completed frames '
197
+ '(so 0 is the first frame)\n')
198
+ buff.writeIndentedLines(code.format(clockName=self._clockName))
199
+
200
+ # write the code for each component during frame
201
+ buff.writeIndentedLines('# update/draw components on each frame\n')
202
+ # just 'normal' components
203
+ for event in self:
204
+ if event.type == 'Static':
205
+ continue # we'll do those later
206
+ event.writeFrameCode(buff)
207
+ # update static component code last
208
+ for event in self.getStatics():
209
+ event.writeFrameCode(buff)
210
+
211
+ # allow subject to quit via Esc key?
212
+ if self.exp.settings.params['Enable Escape'].val:
213
+ code = ('\n# check for quit (typically the Esc key)\n'
214
+ 'if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]):\n'
215
+ ' core.quit()\n')
216
+ buff.writeIndentedLines(code)
217
+
218
+ # are we done yet?
219
+ code = (
220
+ '\n# check if all components have finished\n'
221
+ 'if not continueRoutine: # a component has requested a '
222
+ 'forced-end of Routine\n'
223
+ ' break\n'
224
+ 'continueRoutine = False # will revert to True if at least '
225
+ 'one component still running\n'
226
+ 'for thisComponent in %sComponents:\n'
227
+ ' if hasattr(thisComponent, "status") and '
228
+ 'thisComponent.status != FINISHED:\n'
229
+ ' continueRoutine = True\n'
230
+ ' break # at least one component has not yet finished\n')
231
+ buff.writeIndentedLines(code % self.name)
232
+
233
+ # update screen
234
+ code = ('\n# refresh the screen\n'
235
+ "if continueRoutine: # don't flip if this routine is over "
236
+ "or we'll get a blank screen\n"
237
+ ' win.flip()\n')
238
+ buff.writeIndentedLines(code)
239
+
240
+ # that's done decrement indent to end loop
241
+ buff.setIndentLevel(-1, True)
242
+
243
+ # write the code for each component for the end of the routine
244
+ code = ('\n# -------Ending Routine "%s"-------\n'
245
+ 'for thisComponent in %sComponents:\n'
246
+ ' if hasattr(thisComponent, "setAutoDraw"):\n'
247
+ ' thisComponent.setAutoDraw(False)\n')
248
+ buff.writeIndentedLines(code % (self.name, self.name))
249
+ for event in self:
250
+ event.writeRoutineEndCode(buff)
251
+
252
+ # reset routineTimer at the *very end* of all non-nonSlip routines
253
+ if not useNonSlip:
254
+ code = ('# the Routine "%s" was not non-slip safe, so reset '
255
+ 'the non-slip timer\n'
256
+ 'routineTimer.reset()\n')
257
+ buff.writeIndentedLines(code % self.name)
258
+
259
+
260
+ def writeRoutineBeginCodeJS(self, buff, modular):
261
+
262
+ # create the frame loop for this routine
263
+
264
+ code = ("\nfunction %(name)sRoutineBegin(snapshot) {\n" % self.params)
265
+ buff.writeIndentedLines(code)
266
+ buff.setIndentLevel(1, relative=True)
267
+ buff.writeIndentedLines("return function () {\n")
268
+ buff.setIndentLevel(1, relative=True)
269
+
270
+ code = ("//------Prepare to start Routine '%(name)s'-------\n"
271
+ "t = 0;\n"
272
+ "%(name)sClock.reset(); // clock\n"
273
+ "frameN = -1;\n"
274
+ "continueRoutine = true; // until we're told otherwise\n"
275
+ % self.params)
276
+ buff.writeIndentedLines(code)
277
+ # can we use non-slip timing?
278
+ maxTime, useNonSlip = self.getMaxTime()
279
+ if useNonSlip:
280
+ buff.writeIndented('routineTimer.add(%f);\n' % (maxTime))
281
+
282
+ code = "// update component parameters for each repeat\n"
283
+ buff.writeIndentedLines(code)
284
+ # This is the beginning of the routine, before the loop starts
285
+ for thisCompon in self:
286
+ if "PsychoJS" in thisCompon.targets:
287
+ thisCompon.writeRoutineStartCodeJS(buff)
288
+
289
+ code = ("// keep track of which components have finished\n"
290
+ "%(name)sComponents = [];\n" % self.params)
291
+ buff.writeIndentedLines(code)
292
+ for thisCompon in self:
293
+ if (('startType' in thisCompon.params) and ("PsychoJS" in thisCompon.targets)):
294
+ code = ("%sComponents.push(%s);\n" % (self.name, thisCompon.params['name']))
295
+ buff.writeIndentedLines(code)
296
+
297
+ if modular:
298
+ code = ("\nfor (const thisComponent of %(name)sComponents)\n"
299
+ " if ('status' in thisComponent)\n"
300
+ " thisComponent.status = PsychoJS.Status.NOT_STARTED;\n" % self.params)
301
+ else:
302
+ code = ("\n%(name)sComponents.forEach( function(thisComponent) {\n"
303
+ " if ('status' in thisComponent)\n"
304
+ " thisComponent.status = PsychoJS.Status.NOT_STARTED;\n"
305
+ " });\n" % self.params)
306
+ buff.writeIndentedLines(code)
307
+
308
+ # are we done yet?
309
+ <<<<<<< HEAD
310
+ code = ("// check if the Routine should terminate\n"
311
+ "if (!continueRoutine) {"
312
+ " // a component has requested a forced-end of Routine\n"
313
+ " return Scheduler.Event.NEXT;\n"
314
+ "}\n")
315
+ =======
316
+ code = ("return Scheduler.Event.NEXT;\n")
317
+ >>>>>>> d5c7d5c77... BF: beginRoutineJS code was broekn if continueRoutine==False
318
+ buff.writeIndentedLines(code)
319
+
320
+ buff.setIndentLevel(-1, relative=True)
321
+ buff.writeIndentedLines("}\n")
322
+ buff.setIndentLevel(-1, relative=True)
323
+ buff.writeIndentedLines("}\n")
324
+
325
+ def writeEachFrameCodeJS(self, buff, modular):
326
+ # can we use non-slip timing?
327
+ maxTime, useNonSlip = self.getMaxTime()
328
+
329
+ # write code for each frame
330
+
331
+ code = ("\nfunction %(name)sRoutineEachFrame(snapshot) {\n" % self.params)
332
+ buff.writeIndentedLines(code)
333
+ buff.setIndentLevel(1, relative=True)
334
+ buff.writeIndentedLines("return function () {\n")
335
+ buff.setIndentLevel(1, relative=True)
336
+
337
+ code = ("//------Loop for each frame of Routine '%(name)s'-------\n"
338
+ "// get current time\n"
339
+ "t = %(name)sClock.getTime();\n"
340
+ "frameN = frameN + 1;"
341
+ "// number of completed frames (so 0 is the first frame)\n" % self.params)
342
+ buff.writeIndentedLines(code)
343
+ # write the code for each component during frame
344
+ buff.writeIndentedLines('// update/draw components on each frame\n')
345
+ # just 'normal' components
346
+ for comp in self:
347
+ if "PsychoJS" in comp.targets and comp.type != 'Static':
348
+ comp.writeFrameCodeJS(buff)
349
+ # update static component code last
350
+ for comp in self.getStatics():
351
+ if "PsychoJS" in comp.targets:
352
+ comp.writeFrameCodeJS(buff)
353
+
354
+ if self.exp.settings.params['Enable Escape'].val:
355
+ code = ("// check for quit (typically the Esc key)\n"
356
+ "if (psychoJS.experiment.experimentEnded || psychoJS.eventManager.getKeys({keyList:['escape']}).length > 0) {\n"
357
+ " return quitPsychoJS('The [Escape] key was pressed. Goodbye!', false);\n"
358
+ "}\n\n")
359
+ buff.writeIndentedLines(code)
360
+
361
+ # are we done yet?
362
+ code = ("// check if the Routine should terminate\n"
363
+ "if (!continueRoutine) {"
364
+ " // a component has requested a forced-end of Routine\n"
365
+ " return Scheduler.Event.NEXT;\n"
366
+ "}\n\n"
367
+ "continueRoutine = false; "
368
+ "// reverts to True if at least one component still running\n")
369
+ buff.writeIndentedLines(code)
370
+
371
+ if modular:
372
+ code = ("for (const thisComponent of %(name)sComponents)\n"
373
+ " if ('status' in thisComponent && thisComponent.status !== PsychoJS.Status.FINISHED) {\n"
374
+ " continueRoutine = true;\n"
375
+ " break;\n"
376
+ " }\n")
377
+ else:
378
+ code = ("%(name)sComponents.forEach( function(thisComponent) {\n"
379
+ " if ('status' in thisComponent && thisComponent.status !== PsychoJS.Status.FINISHED) {\n"
380
+ " continueRoutine = true;\n"
381
+ " }\n"
382
+ "});\n")
383
+ buff.writeIndentedLines(code % self.params)
384
+
385
+ buff.writeIndentedLines("\n// refresh the screen if continuing\n")
386
+ if useNonSlip:
387
+ buff.writeIndentedLines("if (continueRoutine "
388
+ "&& routineTimer.getTime() > 0) {")
389
+ else:
390
+ buff.writeIndentedLines("if (continueRoutine) {")
391
+ code = (" return Scheduler.Event.FLIP_REPEAT;\n"
392
+ "} else {\n"
393
+ " return Scheduler.Event.NEXT;\n"
394
+ "}\n")
395
+ buff.writeIndentedLines(code)
396
+ buff.setIndentLevel(-1, relative=True)
397
+ buff.writeIndentedLines("};\n")
398
+ buff.setIndentLevel(-1, relative=True)
399
+ buff.writeIndentedLines("}\n")
400
+
401
+ def writeRoutineEndCodeJS(self, buff, modular):
402
+ # can we use non-slip timing?
403
+ maxTime, useNonSlip = self.getMaxTime()
404
+
405
+ code = ("\nfunction %(name)sRoutineEnd(snapshot) {\n" % self.params)
406
+ buff.writeIndentedLines(code)
407
+ buff.setIndentLevel(1, relative=True)
408
+ buff.writeIndentedLines("return function () {\n")
409
+ buff.setIndentLevel(1, relative=True)
410
+
411
+ if modular:
412
+ code = ("//------Ending Routine '%(name)s'-------\n"
413
+ "for (const thisComponent of %(name)sComponents) {\n"
414
+ " if (typeof thisComponent.setAutoDraw === 'function') {\n"
415
+ " thisComponent.setAutoDraw(false);\n"
416
+ " }\n"
417
+ "}\n")
418
+ else:
419
+ code = ("//------Ending Routine '%(name)s'-------\n"
420
+ "%(name)sComponents.forEach( function(thisComponent) {\n"
421
+ " if (typeof thisComponent.setAutoDraw === 'function') {\n"
422
+ " thisComponent.setAutoDraw(false);\n"
423
+ " }\n"
424
+ "});\n")
425
+ buff.writeIndentedLines(code % self.params)
426
+ # add the EndRoutine code for each component
427
+ for compon in self:
428
+ if "PsychoJS" in compon.targets:
429
+ compon.writeRoutineEndCodeJS(buff)
430
+
431
+ # reset routineTimer at the *very end* of all non-nonSlip routines
432
+ if not useNonSlip:
433
+ code = ('// the Routine "%s" was not non-slip safe, so reset '
434
+ 'the non-slip timer\n'
435
+ 'routineTimer.reset();\n\n')
436
+ buff.writeIndentedLines(code % self.name)
437
+
438
+ buff.writeIndented('return Scheduler.Event.NEXT;\n')
439
+ buff.setIndentLevel(-1, relative=True)
440
+ buff.writeIndentedLines("};\n")
441
+ buff.setIndentLevel(-1, relative=True)
442
+ buff.writeIndentedLines("}\n")
443
+
444
+ def writeExperimentEndCode(self, buff):
445
+ """Some components have
446
+ """
447
+ # This is the beginning of the routine, before the loop starts
448
+ for component in self:
449
+ component.writeExperimentEndCode(buff)
450
+
451
+ def writeExperimentEndCodeJS(self, buff):
452
+ """This defines the code for the frames of a single routine
453
+ """
454
+ # This is the beginning of the routine, before the loop starts
455
+ for component in self:
456
+ if 'writeExperimentEndCodeJS' in dir(component):
457
+ component.writeExperimentEndCodeJS(buff)
458
+
459
+ def getType(self):
460
+ return 'Routine'
461
+
462
+ def getComponentFromName(self, name):
463
+ for comp in self:
464
+ if comp.params['name'].val == name:
465
+ return comp
466
+ return None
467
+
468
+ def getComponentFromType(self, type):
469
+ for comp in self:
470
+ if comp.type == type:
471
+ return comp
472
+ return None
473
+
474
+ def hasOnlyStaticComp(self):
475
+ return all([comp.type == 'Static' for comp in self])
476
+
477
+ def getMaxTime(self):
478
+ """What the last (predetermined) stimulus time to be presented. If
479
+ there are no components or they have code-based times then will
480
+ default to 10secs
481
+ """
482
+ maxTime = 0
483
+ nonSlipSafe = True # if possible
484
+ for component in self:
485
+ if 'startType' in component.params:
486
+ start, duration, nonSlip = component.getStartAndDuration()
487
+ if not nonSlip:
488
+ nonSlipSafe = False
489
+ if duration == FOREVER:
490
+ # only the *start* of an unlimited event should contribute
491
+ # to maxTime
492
+ duration = 1 # plus some minimal duration so it's visible
493
+ # now see if we have a end t value that beats the previous max
494
+ try:
495
+ # will fail if either value is not defined:
496
+ thisT = start + duration
497
+ except Exception:
498
+ thisT = 0
499
+ maxTime = max(maxTime, thisT)
500
+ if maxTime == 0: # if there are no components
501
+ maxTime = 10
502
+ nonSlipSafe = False
503
+ return maxTime, nonSlipSafe
@@ -824,7 +824,6 @@ class Routine(list):
824
824
  code = ("TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date\n\n"
825
825
  "//--- Prepare to start Routine '%(name)s' ---\n"
826
826
  "t = 0;\n"
827
- "%(name)sClock.reset(); // clock\n"
828
827
  "frameN = -1;\n"
829
828
  "continueRoutine = true; // until we're told otherwise\n"
830
829
  % self.params)
@@ -832,7 +831,17 @@ class Routine(list):
832
831
  # can we use non-slip timing?
833
832
  maxTime, useNonSlip = self.getMaxTime()
834
833
  if useNonSlip:
835
- buff.writeIndented('routineTimer.add(%f);\n' % (maxTime))
834
+ code = (
835
+ "%(name)sClock.reset(routineTimer.getTime());\n"
836
+ "routineTimer.add({maxTime:f});\n"
837
+ ).format(maxTime=maxTime)
838
+ buff.writeIndentedLines(code % self.params)
839
+ else:
840
+ code = (
841
+ "%(name)sClock.reset();\n"
842
+ "routineTimer.reset();\n"
843
+ )
844
+ buff.writeIndentedLines(code % self.params)
836
845
  # keep track of whether max duration is reached
837
846
  code = (
838
847
  "%(name)sMaxDurationReached = false;\n"
@@ -1008,9 +1017,9 @@ class Routine(list):
1008
1017
  if useNonSlip:
1009
1018
  code = (
1010
1019
  "if (%(name)sMaxDurationReached) {{\n"
1011
- " routineTimer.add(%(name)sMaxDuration);\n"
1020
+ " %(name)sClock.add(%(name)sMaxDuration);\n"
1012
1021
  "}} else {{\n"
1013
- " routineTimer.add(-{:f});\n"
1022
+ " %(name)sClock.add({:f});\n"
1014
1023
  "}}\n"
1015
1024
  ).format(maxTime)
1016
1025
  buff.writeIndented(code % self.params)
@@ -1078,8 +1087,8 @@ class Routine(list):
1078
1087
  nonSlipSafe = False
1079
1088
  if duration == FOREVER:
1080
1089
  # only the *start* of an unlimited event should contribute
1081
- # to maxTime
1082
- duration = 0 # plus some minimal duration so it's visible
1090
+ # to maxTime, plus some minimal duration so it's visible
1091
+ duration = 0 if self.settings.params['forceNonSlip'] else 1
1083
1092
  # now see if we have a end t value that beats the previous max
1084
1093
  try:
1085
1094
  # will fail if either value is not defined:
@@ -12,6 +12,7 @@ class CounterbalanceRoutine(BaseStandaloneRoutine):
12
12
  tooltip = _translate(
13
13
  "Counterbalance Routine: use the Shelf to choose a value taking into account previous runs of this experiment."
14
14
  )
15
+ beta = True
15
16
 
16
17
  def __init__(
17
18
  self, exp, name='counterbalance',
psychopy/gui/qtgui.py CHANGED
@@ -8,6 +8,7 @@
8
8
  # Distributed under the terms of the GNU General Public License (GPL).
9
9
  import importlib
10
10
  from psychopy import logging, data
11
+ from psychopy.tools.arraytools import IndexDict
11
12
  from . import util
12
13
 
13
14
  haveQt = False # until we confirm otherwise
@@ -167,7 +168,7 @@ class Dlg(QtWidgets.QDialog):
167
168
  self.inputFields = []
168
169
  self.inputFieldTypes = {}
169
170
  self.inputFieldNames = []
170
- self.data = {}
171
+ self.data = IndexDict()
171
172
  self.irow = 0
172
173
  self.pos = pos
173
174
  # QtWidgets.QToolTip.setFont(QtGui.QFont('SansSerif', 10))
@@ -229,8 +230,8 @@ class Dlg(QtWidgets.QDialog):
229
230
 
230
231
  return textLabel
231
232
 
232
- def addField(self, key, label='', initial='', color='', choices=None, tip='',
233
- required=False, enabled=True):
233
+ def addField(self, key, initial='', color='', choices=None, tip='',
234
+ required=False, enabled=True, label=None):
234
235
  """Adds a (labelled) input field to the dialogue box,
235
236
  optional text color and tooltip.
236
237
 
@@ -240,6 +241,10 @@ class Dlg(QtWidgets.QDialog):
240
241
 
241
242
  Returns a handle to the field (but not to the label).
242
243
  """
244
+ # if not given a label, use key (sans-pipe syntax)
245
+ if label is None:
246
+ label, _ = util.parsePipeSyntax(key)
247
+
243
248
  self.inputFieldNames.append(label)
244
249
  if choices:
245
250
  self.inputFieldTypes[label] = str
@@ -345,9 +350,9 @@ class Dlg(QtWidgets.QDialog):
345
350
  # set required (attribute is checked later by validate fcn)
346
351
  inputBox.required = required
347
352
 
348
- if len(color):
353
+ if color is not None and len(color):
349
354
  inputBox.setPalette(inputLabel.palette())
350
- if len(tip):
355
+ if tip is not None and len(tip):
351
356
  inputBox.setToolTip(tip)
352
357
  inputBox.setEnabled(enabled)
353
358
  self.layout.addWidget(inputBox, self.irow, 1)
@@ -367,8 +372,10 @@ class Dlg(QtWidgets.QDialog):
367
372
  """Adds a field to the dialog box (like addField) but the field cannot
368
373
  be edited. e.g. Display experiment version.
369
374
  """
370
- return self.addField(key, label, initial, color, choices, tip,
371
- enabled=False)
375
+ return self.addField(
376
+ key=key, label=label, initial=initial, color=color, choices=choices, tip=tip,
377
+ enabled=False
378
+ )
372
379
 
373
380
  def addReadmoreCtrl(self):
374
381
  line = ReadmoreCtrl(self, label=_translate("Configuration fields..."))
psychopy/gui/util.py CHANGED
@@ -9,19 +9,9 @@ def makeDisplayParams(expInfo, sortKeys=True, labels=None, tooltips=None, fixed=
9
9
  labels = {}
10
10
  if tooltips is None:
11
11
  tooltips = {}
12
- # convert fixed list to pipe syntax
13
- if fixed is not None:
14
- if isinstance(fixed, str):
15
- fixed = [fixed]
16
- for key in fixed:
17
- if key in expInfo:
18
- expInfo[f"{key}|fix"] = expInfo.pop(key)
19
- # convert order list to pipe syntax
20
- if order is not None:
21
- for key in order:
22
- i = order.index(key)
23
- if key in expInfo:
24
- expInfo[f"{key}|{i}"] = expInfo.pop(key)
12
+ # make sure fixed is a list
13
+ if isinstance(fixed, str):
14
+ fixed = [fixed]
25
15
  # get keys as a list
26
16
  keys = list(expInfo)
27
17
  # sort alphabetically if requested
@@ -43,11 +33,17 @@ def makeDisplayParams(expInfo, sortKeys=True, labels=None, tooltips=None, fixed=
43
33
  tip = ""
44
34
  if key in tooltips:
45
35
  tip = tooltips[key]
46
- # work out index
36
+ # work out index from flags
47
37
  i = None
48
38
  for flag in flags:
49
39
  if flag.isnumeric():
50
40
  i = int(flag)
41
+ # if given, manually set order should override flags
42
+ if order is not None and key in order:
43
+ i = order.index(key)
44
+ # work out fixed
45
+ if "fix" not in flags and fixed is not None and key in fixed:
46
+ flags.append("fix")
51
47
  # construct display param
52
48
  param = {
53
49
  'key': key,