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,752 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ '''Class of text stimuli to be displayed in a :class:`~psychopy.visual.Window`
5
+ '''
6
+
7
+ # Part of the PsychoPy library
8
+ # Copyright (C) 2002-2018 Jonathan Peirce (C) 2019-2021 Open Science Tools Ltd.
9
+ # Distributed under the terms of the GNU General Public License (GPL).
10
+
11
+
12
+
13
+
14
+ import os
15
+ import glob
16
+ import warnings
17
+
18
+ # Ensure setting pyglet.options['debug_gl'] to False is done prior to any
19
+ # other calls to pyglet or pyglet submodules, otherwise it may not get picked
20
+ # up by the pyglet GL engine and have no effect.
21
+ # Shaders will work but require OpenGL2.0 drivers AND PyOpenGL3.0+
22
+ import pyglet
23
+ pyglet.options['debug_gl'] = False
24
+ import ctypes
25
+ GL = pyglet.gl
26
+
27
+ import psychopy # so we can get the __path__
28
+ from psychopy import logging
29
+
30
+ # tools must only be imported *after* event or MovieStim breaks on win32
31
+ # (JWP has no idea why!)
32
+ from psychopy.tools.monitorunittools import cm2pix, deg2pix, convertToPix
33
+ from psychopy.tools.attributetools import attributeSetter, setAttribute
34
+ <<<<<<< HEAD
35
+ from psychopy.visual.basevisual import (BaseVisualStim, ColorMixin,
36
+ ContainerMixin, WindowMixin)
37
+ =======
38
+ from psychopy.visual.basevisual import (BaseVisualStim, ForeColorMixin,
39
+ ContainerMixin)
40
+ >>>>>>> release
41
+ from psychopy.colors import Color
42
+
43
+ # for displaying right-to-left (possibly bidirectional) text correctly:
44
+ from bidi import algorithm as bidi_algorithm # sufficient for Hebrew
45
+ # extra step needed to reshape Arabic/Farsi characters depending on
46
+ # their neighbours:
47
+ try:
48
+ import arabic_reshaper
49
+ haveArabic = True
50
+ except ImportError:
51
+ haveArabic = False
52
+
53
+ import numpy
54
+
55
+ try:
56
+ import pygame
57
+ havePygame = True
58
+ except Exception:
59
+ havePygame = False
60
+
61
+ defaultLetterHeight = {'cm': 1.0,
62
+ 'deg': 1.0,
63
+ 'degs': 1.0,
64
+ 'degFlatPos': 1.0,
65
+ 'degFlat': 1.0,
66
+ 'norm': 0.1,
67
+ 'height': 0.2,
68
+ 'pix': 20,
69
+ 'pixels': 20}
70
+ defaultWrapWidth = {'cm': 15.0,
71
+ 'deg': 15.0,
72
+ 'degs': 15.0,
73
+ 'degFlatPos': 15.0,
74
+ 'degFlat': 15.0,
75
+ 'norm': 1,
76
+ 'height': 1,
77
+ 'pix': 500,
78
+ 'pixels': 500}
79
+
80
+
81
+ class TextStim(BaseVisualStim, ForeColorMixin, ContainerMixin):
82
+ """Class of text stimuli to be displayed in a
83
+ :class:`~psychopy.visual.Window`
84
+ """
85
+
86
+ def __init__(self, win,
87
+ text="Hello World",
88
+ font="",
89
+ pos=(0.0, 0.0),
90
+ depth=0,
91
+ rgb=None,
92
+ color=(1.0, 1.0, 1.0),
93
+ colorSpace='rgb',
94
+ opacity=1.0,
95
+ contrast=1.0,
96
+ units="",
97
+ ori=0.0,
98
+ height=None,
99
+ antialias=True,
100
+ bold=False,
101
+ italic=False,
102
+ alignHoriz=None,
103
+ alignVert=None,
104
+ alignText='center',
105
+ anchorHoriz='center',
106
+ anchorVert='center',
107
+ fontFiles=(),
108
+ wrapWidth=None,
109
+ flipHoriz=False,
110
+ flipVert=False,
111
+ languageStyle='LTR',
112
+ name=None,
113
+ autoLog=None):
114
+ """
115
+ **Performance OBS:** in general, TextStim is slower than many other
116
+ visual stimuli, i.e. it takes longer to change some attributes.
117
+ In general, it's the attributes that affect the shapes of the letters:
118
+ ``text``, ``height``, ``font``, ``bold`` etc.
119
+ These make the next .draw() slower because that sets the text again.
120
+ You can make the draw() quick by calling re-setting the text
121
+ (``myTextStim.text = myTextStim.text``) when you've changed the
122
+ parameters.
123
+
124
+ In general, other attributes which merely affect the presentation of
125
+ unchanged shapes are as fast as usual. This includes ``pos``,
126
+ ``opacity`` etc.
127
+
128
+ The following attribute can only be set at initialization (see
129
+ further down for a list of attributes which can be changed after
130
+ initialization):
131
+
132
+ **languageStyle**
133
+ Apply settings to correctly display content from some languages
134
+ that are written right-to-left. Currently there are three (case-
135
+ insensitive) values for this parameter:
136
+
137
+ - ``'LTR'`` is the default, for typical left-to-right, Latin-style
138
+ languages.
139
+ - ``'RTL'`` will correctly display text in right-to-left languages
140
+ such as Hebrew. By applying the bidirectional algorithm, it
141
+ allows mixing portions of left-to-right content (such as numbers
142
+ or Latin script) within the string.
143
+ - ``'Arabic'`` applies the bidirectional algorithm but additionally
144
+ will _reshape_ Arabic characters so they appear in the cursive,
145
+ linked form that depends on neighbouring characters, rather than
146
+ in their isolated form. May also be applied in other scripts,
147
+ such as Farsi or Urdu, that use Arabic-style alphabets.
148
+
149
+ :Parameters:
150
+
151
+ """
152
+
153
+ # what local vars are defined (these are the init params) for use by
154
+ # __repr__
155
+ self._initParams = dir()
156
+ self._initParams.remove('self')
157
+
158
+ """
159
+ October 2018:
160
+ In place to remove the deprecation warning for pyglet.font.Text.
161
+ Temporary fix until pyglet.text.Label use is identical to pyglet.font.Text.
162
+ """
163
+ warnings.filterwarnings(message='.*text.Label*', action='ignore')
164
+
165
+ super(TextStim, self).__init__(
166
+ win, units=units, name=name, autoLog=False)
167
+
168
+ if win.blendMode=='add':
169
+ logging.warning("Pyglet text does not honor the Window setting "
170
+ "`blendMode='add'` so 'avg' will be used for the "
171
+ "text (but objects drawn after can be added)")
172
+ self._needUpdate = True
173
+ self._needVertexUpdate = True
174
+ # use shaders if available by default, this is a good thing
175
+ self.__dict__['antialias'] = antialias
176
+ self.__dict__['font'] = font
177
+ self.__dict__['bold'] = bold
178
+ self.__dict__['italic'] = italic
179
+ # NB just a placeholder - real value set below
180
+ self.__dict__['text'] = ''
181
+ self.__dict__['depth'] = depth
182
+ self.__dict__['ori'] = ori
183
+ self.__dict__['flipHoriz'] = flipHoriz
184
+ self.__dict__['flipVert'] = flipVert
185
+ self.__dict__['languageStyle'] = languageStyle
186
+ self._pygletTextObj = None
187
+ self.pos = pos
188
+ # deprecated attributes
189
+ if alignVert:
190
+ self.__dict__['alignVert'] = alignVert
191
+ logging.warning("TextStim.alignVert is deprecated. Use the "
192
+ "anchorVert attribute instead")
193
+ # for compatibility, alignText was historically 'left'
194
+ anchorVert = alignHoriz
195
+ if alignHoriz:
196
+ self.__dict__['alignHoriz'] = alignHoriz
197
+ logging.warning("TextStim.alignHoriz is deprecated. Use alignText "
198
+ "and anchorHoriz attributes instead")
199
+ # for compatibility, alignText was historically 'left'
200
+ alignText, anchorHoriz = alignHoriz, alignHoriz
201
+ # alignment and anchors
202
+ self.alignText = alignText
203
+ self.anchorHoriz = anchorHoriz
204
+ self.anchorVert = anchorVert
205
+
206
+
207
+ # generate the texture and list holders
208
+ self._listID = GL.glGenLists(1)
209
+ # pygame text needs a surface to render to:
210
+ if not self.win.winType in ["pyglet", "glfw"]:
211
+ self._texID = GL.GLuint()
212
+ GL.glGenTextures(1, ctypes.byref(self._texID))
213
+
214
+ # Color stuff
215
+ self.colorSpace = colorSpace
216
+ self.color = color
217
+ if rgb != None:
218
+ logging.warning("Use of rgb arguments to stimuli are deprecated. Please "
219
+ "use color and colorSpace args instead")
220
+ self.color = Color(rgb, 'rgb')
221
+ self.__dict__['fontFiles'] = []
222
+ self.fontFiles = list(fontFiles) # calls attributeSetter
223
+ self.setHeight(height, log=False) # calls setFont() at some point
224
+ # calls attributeSetter without log
225
+ setAttribute(self, 'wrapWidth', wrapWidth, log=False)
226
+ self.opacity = opacity
227
+ self.contrast = contrast
228
+ # self.width and self._fontHeightPix get set with text and
229
+ # calcSizeRendered is called
230
+ self.setText(text, log=False)
231
+ self._needUpdate = True
232
+
233
+ # set autoLog now that params have been initialised
234
+ wantLog = autoLog is None and self.win.autoLog
235
+ self.__dict__['autoLog'] = autoLog or wantLog
236
+ if self.autoLog:
237
+ logging.exp("Created %s = %s" % (self.name, str(self)))
238
+
239
+ def __del__(self):
240
+ if GL: # because of pytest fail otherwise
241
+ try:
242
+ GL.glDeleteLists(self._listID, 1)
243
+ except (ImportError, ModuleNotFoundError, TypeError):
244
+ pass # if pyglet no longer exists
245
+
246
+ @attributeSetter
247
+ def height(self, height):
248
+ """The height of the letters (Float/int or None = set default).
249
+
250
+ Height includes the entire box that surrounds the letters
251
+ in the font. The width of the letters is then defined by the font.
252
+
253
+ :ref:`Operations <attrib-operations>` supported."""
254
+ # height in pix (needs to be done after units which is done during
255
+ # _Base.__init__)
256
+ if height is None:
257
+ if self.units in defaultLetterHeight:
258
+ height = defaultLetterHeight[self.units]
259
+ else:
260
+ msg = ("TextStim does now know a default letter height "
261
+ "for units %s")
262
+ raise AttributeError(msg % repr(self.units))
263
+ self.__dict__['height'] = height
264
+ self._heightPix = convertToPix(pos=numpy.array([0, 0]),
265
+ vertices=numpy.array([0, self.height]),
266
+ units=self.units, win=self.win)[1]
267
+
268
+ # need to update the font to reflect the change
269
+ self.setFont(self.font, log=False)
270
+ return self.__dict__['height']
271
+
272
+ @property
273
+ def size(self):
274
+ self.size = (self.height*len(self.text), self.height)
275
+ return WindowMixin.size.fget(self)
276
+
277
+ @size.setter
278
+ def size(self, value):
279
+ WindowMixin.size.fset(self, value)
280
+ self.height = getattr(self._size, self.units)[1]
281
+
282
+ def setHeight(self, height, log=None):
283
+ """Usually you can use 'stim.attribute = value' syntax instead,
284
+ but use this method if you need to suppress the log message. """
285
+ setAttribute(self, 'height', height, log)
286
+
287
+ @attributeSetter
288
+ def font(self, font):
289
+ """String. Set the font to be used for text rendering. font should
290
+ be a string specifying the name of the font (in system resources).
291
+ """
292
+ self.__dict__['font'] = None # until we find one
293
+ if self.win.winType in ["pyglet", "glfw"]:
294
+ self._font = pyglet.font.load(font, int(self._heightPix),
295
+ dpi=72, italic=self.italic,
296
+ bold=self.bold)
297
+ self.__dict__['font'] = font
298
+ else:
299
+ if font is None or len(font) == 0:
300
+ self.__dict__['font'] = pygame.font.get_default_font()
301
+ elif font in pygame.font.get_fonts():
302
+ self.__dict__['font'] = font
303
+ elif type(font) == str:
304
+ # try to find a xxx.ttf file for it
305
+ # check for possible matching filenames
306
+ fontFilenames = glob.glob(font + '*')
307
+ if len(fontFilenames) > 0:
308
+ for thisFont in fontFilenames:
309
+ if thisFont[-4:] in ['.TTF', '.ttf']:
310
+ # take the first match
311
+ self.__dict__['font'] = thisFont
312
+ break # stop at the first one we find
313
+ # trhen check if we were successful
314
+ if self.font is None and font != "":
315
+ # we didn't find a ttf filename
316
+ msg = ("Found %s but it doesn't end .ttf. "
317
+ "Using default font.")
318
+ logging.warning(msg % fontFilenames[0])
319
+ self.__dict__['font'] = pygame.font.get_default_font()
320
+
321
+ if self.font is not None and os.path.isfile(self.font):
322
+ self._font = pygame.font.Font(self.font, int(
323
+ self._heightPix), italic=self.italic, bold=self.bold)
324
+ else:
325
+ try:
326
+ self._font = pygame.font.SysFont(
327
+ self.font, int(self._heightPix), italic=self.italic,
328
+ bold=self.bold)
329
+ self.__dict__['font'] = font
330
+ logging.info('using sysFont ' + str(font))
331
+ except Exception:
332
+ self.__dict__['font'] = pygame.font.get_default_font()
333
+ msg = ("Couldn't find font %s on the system. Using %s "
334
+ "instead! Font names should be written as "
335
+ "concatenated names all in lower case.\ne.g. "
336
+ "'arial', 'monotypecorsiva', 'rockwellextra', ...")
337
+ logging.error(msg % (font, self.font))
338
+ self._font = pygame.font.SysFont(
339
+ self.font, int(self._heightPix), italic=self.italic,
340
+ bold=self.bold)
341
+ # re-render text after a font change
342
+ self._needSetText = True
343
+
344
+ def setFont(self, font, log=None):
345
+ """Usually you can use 'stim.attribute = value' syntax instead,
346
+ but use this method if you need to suppress the log message.
347
+ """
348
+ setAttribute(self, 'font', font, log)
349
+
350
+ @attributeSetter
351
+ def text(self, text):
352
+ """The text to be rendered. Use \\\\n to make new lines.
353
+
354
+ Issues: May be slow, and pyglet has a memory leak when setting text.
355
+ For these reasons, this function checks so that it only updates the
356
+ text if it has changed. So scripts can safely set the text on every
357
+ frame, with no need to check if it has actually altered.
358
+ """
359
+ if text == self.text: # only update for a change
360
+ return
361
+ if text is not None:
362
+ text = str(text) # make sure we have unicode object to render
363
+
364
+ # deal with some international text issues. Only relevant for Python:
365
+ # online experiments use web technologies and handle this seamlessly.
366
+ style = self.languageStyle.lower() # be flexible with case
367
+ if style == 'arabic' and haveArabic:
368
+ # reshape Arabic characters from their isolated form so that
369
+ # they flow and join correctly to their neighbours:
370
+ text = arabic_reshaper.reshape(text)
371
+ if style == 'rtl' or style == 'arabic' and haveArabic:
372
+ # deal with right-to-left text presentation by applying the
373
+ # bidirectional algorithm:
374
+ text = bidi_algorithm.get_display(text)
375
+ # no action needed for default 'ltr' (left-to-right) option
376
+
377
+ self.__dict__['text'] = text
378
+
379
+ self._setTextShaders(text)
380
+
381
+ self._needSetText = False
382
+ return self.__dict__['text']
383
+
384
+ def setText(self, text=None, log=None):
385
+ """Usually you can use 'stim.attribute = value' syntax instead,
386
+ but use this method if you need to suppress the log message.
387
+ """
388
+ setAttribute(self, 'text', text, log)
389
+
390
+ def _setTextShaders(self, value=None):
391
+ """Set the text to be rendered using the current font
392
+ """
393
+ if self.win.winType in ["pyglet", "glfw"]:
394
+ rgba255 = self._foreColor.rgba255
395
+ rgba255[3] = rgba255[3]*255
396
+ rgba255 = [int(c) for c in rgba255]
397
+ self._pygletTextObj = pyglet.text.Label(
398
+ self.text, self.font, int(self._heightPix*0.75),
399
+ italic=self.italic,
400
+ bold=self.bold,
401
+ anchor_x=self.anchorHoriz,
402
+ anchor_y=self.anchorVert, # the point we rotate around
403
+ align=self.alignText,
404
+ color=rgba255,
405
+ multiline=True, width=self._wrapWidthPix) # width of the frame
406
+ self.width = self._pygletTextObj.width
407
+ self._fontHeightPix = self._pygletTextObj.height
408
+ else:
409
+ self._surf = self._font.render(value, self.antialias,
410
+ [255, 255, 255])
411
+ self.width, self._fontHeightPix = self._surf.get_size()
412
+
413
+ if self.antialias:
414
+ smoothing = GL.GL_LINEAR
415
+ else:
416
+ smoothing = GL.GL_NEAREST
417
+ # generate the textures from pygame surface
418
+ GL.glEnable(GL.GL_TEXTURE_2D)
419
+ # bind that name to the target
420
+ GL.glBindTexture(GL.GL_TEXTURE_2D, self._texID)
421
+ GL.gluBuild2DMipmaps(GL.GL_TEXTURE_2D, 4, self.width,
422
+ self._fontHeightPix,
423
+ GL.GL_RGBA, GL.GL_UNSIGNED_BYTE,
424
+ pygame.image.tostring(self._surf, "RGBA", 1))
425
+ # linear smoothing if texture is stretched?
426
+ GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER,
427
+ smoothing)
428
+ # but nearest pixel value if it's compressed?
429
+ GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER,
430
+ smoothing)
431
+
432
+ self._needSetText = False
433
+ self._needUpdate = True
434
+
435
+ def _updateListShaders(self):
436
+ """Only used with pygame text - pyglet handles all from the draw()
437
+ """
438
+ if self._needSetText:
439
+ self.setText(log=False)
440
+ GL.glNewList(self._listID, GL.GL_COMPILE)
441
+ # GL.glPushMatrix()
442
+
443
+ # setup the shaderprogram
444
+ # no need to do texture maths so no need for programs?
445
+ # If we're using pyglet then this list won't be called, and for pygame
446
+ # shaders aren't enabled
447
+ GL.glUseProgram(0) # self.win._progSignedTex)
448
+ # GL.glUniform1i(GL.glGetUniformLocation(self.win._progSignedTex,
449
+ # "texture"), 0) # set the texture to be texture unit 0
450
+
451
+ # coords:
452
+ if self.alignHoriz in ['center', 'centre']:
453
+ left = -self.width/2.0
454
+ right = self.width/2.0
455
+ elif self.alignHoriz == 'right':
456
+ left = -self.width
457
+ right = 0.0
458
+ else:
459
+ left = 0.0
460
+ right = self.width
461
+ # how much to move bottom
462
+ if self.alignVert in ['center', 'centre']:
463
+ bottom = -self._fontHeightPix/2.0
464
+ top = self._fontHeightPix/2.0
465
+ elif self.alignVert == 'top':
466
+ bottom = -self._fontHeightPix
467
+ top = 0
468
+ else:
469
+ bottom = 0.0
470
+ top = self._fontHeightPix
471
+ # there seems to be a rounding err in pygame font textures
472
+ Btex, Ttex, Ltex, Rtex = -0.01, 0.98, 0, 1.0
473
+
474
+ # unbind the mask texture regardless
475
+ GL.glActiveTexture(GL.GL_TEXTURE1)
476
+ GL.glEnable(GL.GL_TEXTURE_2D)
477
+ GL.glBindTexture(GL.GL_TEXTURE_2D, 0)
478
+ if self.win.winType in ["pyglet", "glfw"]:
479
+ # unbind the main texture
480
+ GL.glActiveTexture(GL.GL_TEXTURE0)
481
+ # GL.glActiveTextureARB(GL.GL_TEXTURE0_ARB)
482
+ # the texture is specified by pyglet.font.GlyphString.draw()
483
+ GL.glBindTexture(GL.GL_TEXTURE_2D, 0)
484
+ GL.glEnable(GL.GL_TEXTURE_2D)
485
+ else:
486
+ # bind the appropriate main texture
487
+ GL.glActiveTexture(GL.GL_TEXTURE0)
488
+ GL.glBindTexture(GL.GL_TEXTURE_2D, self._texID)
489
+ GL.glEnable(GL.GL_TEXTURE_2D)
490
+
491
+ if self.win.winType in ["pyglet", "glfw"]:
492
+ GL.glActiveTexture(GL.GL_TEXTURE0)
493
+ GL.glEnable(GL.GL_TEXTURE_2D)
494
+ self._pygletTextObj.draw()
495
+ else:
496
+ # draw a 4 sided polygon
497
+ GL.glBegin(GL.GL_QUADS)
498
+ # right bottom
499
+ GL.glMultiTexCoord2f(GL.GL_TEXTURE0, Rtex, Btex)
500
+ GL.glVertex3f(right, bottom, 0)
501
+ # left bottom
502
+ GL.glMultiTexCoord2f(GL.GL_TEXTURE0, Ltex, Btex)
503
+ GL.glVertex3f(left, bottom, 0)
504
+ # left top
505
+ GL.glMultiTexCoord2f(GL.GL_TEXTURE0, Ltex, Ttex)
506
+ GL.glVertex3f(left, top, 0)
507
+ # right top
508
+ GL.glMultiTexCoord2f(GL.GL_TEXTURE0, Rtex, Ttex)
509
+ GL.glVertex3f(right, top, 0)
510
+ GL.glEnd()
511
+
512
+ GL.glDisable(GL.GL_TEXTURE_2D)
513
+ GL.glUseProgram(0)
514
+ # GL.glPopMatrix()
515
+
516
+ GL.glEndList()
517
+ self._needUpdate = False
518
+
519
+ @attributeSetter
520
+ def flipHoriz(self, value):
521
+ """If set to True then the text will be flipped left-to-right. The
522
+ flip is relative to the original, not relative to the current state.
523
+ """
524
+ self.__dict__['flipHoriz'] = value
525
+
526
+ def setFlipHoriz(self, newVal=True, log=None):
527
+ """Usually you can use 'stim.attribute = value' syntax instead,
528
+ but use this method if you need to suppress the log message.
529
+ """
530
+ setAttribute(self, 'flipHoriz', newVal, log)
531
+
532
+ @attributeSetter
533
+ def flipVert(self, value):
534
+ """If set to True then the text will be flipped top-to-bottom. The
535
+ flip is relative to the original, not relative to the current state.
536
+ """
537
+ self.__dict__['flipVert'] = value
538
+
539
+ def setFlipVert(self, newVal=True, log=None):
540
+ """Usually you can use 'stim.attribute = value' syntax instead,
541
+ but use this method if you need to suppress the log message
542
+ """
543
+ setAttribute(self, 'flipVert', newVal, log)
544
+
545
+ def setFlip(self, direction, log=None):
546
+ """(used by Builder to simplify the dialog)
547
+ """
548
+ if direction == 'vert':
549
+ self.setFlipVert(True, log=log)
550
+ elif direction == 'horiz':
551
+ self.setFlipHoriz(True, log=log)
552
+
553
+ @attributeSetter
554
+ def antialias(self, value):
555
+ """Allow antialiasing the text (True or False). Sets text, slow.
556
+ """
557
+ self.__dict__['antialias'] = value
558
+ self._needSetText = True
559
+
560
+ @attributeSetter
561
+ def bold(self, value):
562
+ """Make the text bold (True, False) (better to use a bold font name).
563
+ """
564
+ self.__dict__['bold'] = value
565
+ self.font = self.font # call attributeSetter
566
+
567
+ @attributeSetter
568
+ def italic(self, value):
569
+ """True/False.
570
+ Make the text italic (better to use a italic font name).
571
+ """
572
+ self.__dict__['italic'] = value
573
+ self.font = self.font # call attributeSetter
574
+
575
+ @attributeSetter
576
+ def alignHoriz(self, value):
577
+ """Deprecated in PsychoPy 3.3. Use `alignText` and `anchorHoriz`
578
+ instead
579
+ """
580
+ self.__dict__['alignHoriz'] = value
581
+ self._needSetText = True
582
+
583
+ @attributeSetter
584
+ def alignVert(self, value):
585
+ """Deprecated in PsychoPy 3.3. Use `anchorVert`
586
+ """
587
+ self.__dict__['alignVert'] = value
588
+ self._needSetText = True
589
+
590
+ @attributeSetter
591
+ def alignText(self, value):
592
+ """Aligns the text content within the bounding box ('left', 'right' or
593
+ 'center')
594
+ See also `anchorX` to set alignment of the box itself relative to pos
595
+ """
596
+ self.__dict__['alignText'] = value
597
+ self._needSetText = True
598
+
599
+ @attributeSetter
600
+ def anchorHoriz(self, value):
601
+ """The horizontal alignment ('left', 'right' or 'center')
602
+ """
603
+ self.__dict__['anchorHoriz'] = value
604
+ self._needSetText = True
605
+
606
+ @attributeSetter
607
+ def anchorVert(self, value):
608
+ """The vertical alignment ('top', 'bottom' or 'center') of the box
609
+ relative to the text `pos`.
610
+ """
611
+ self.__dict__['anchorVert'] = value
612
+ self._needSetText = True
613
+
614
+ @attributeSetter
615
+ def fontFiles(self, fontFiles):
616
+ """A list of additional files if the font is not in the standard
617
+ system location (include the full path).
618
+
619
+ OBS: fonts are added every time this value is set. Previous are
620
+ not deleted.
621
+
622
+ E.g.::
623
+
624
+ stim.fontFiles = ['SpringRage.ttf'] # load file(s)
625
+ stim.font = 'SpringRage' # set to font
626
+ """
627
+ self.__dict__['fontFiles'] += fontFiles
628
+ for thisFont in fontFiles:
629
+ pyglet.font.add_file(thisFont)
630
+
631
+ @attributeSetter
632
+ def wrapWidth(self, wrapWidth):
633
+ """Int/float or None (set default).
634
+ The width the text should run before wrapping.
635
+
636
+ :ref:`Operations <attrib-operations>` supported.
637
+ """
638
+ if wrapWidth is None:
639
+ if self.units in defaultWrapWidth:
640
+ wrapWidth = defaultWrapWidth[self.units]
641
+ else:
642
+ msg = "TextStim does now know a default wrap width for units %s"
643
+ raise AttributeError(msg % repr(self.units))
644
+ self.__dict__['wrapWidth'] = wrapWidth
645
+ verts = numpy.array([self.wrapWidth, 0])
646
+ self._wrapWidthPix = convertToPix(pos=numpy.array([0, 0]),
647
+ vertices=verts,
648
+ units=self.units, win=self.win)[0]
649
+ self._needSetText = True
650
+
651
+ @property
652
+ def boundingBox(self):
653
+ """(read only) attribute representing the bounding box of the text
654
+ (w,h). This differs from `width` in that the width represents the
655
+ width of the margins, which might differ from the width of the text
656
+ within them.
657
+
658
+ NOTE: currently always returns the size in pixels
659
+ (this will change to return in stimulus units)
660
+ """
661
+ if hasattr(self._pygletTextObj, 'content_width'):
662
+ w, h = (self._pygletTextObj.content_width,
663
+ self._pygletTextObj.content_height)
664
+ else:
665
+ w, h = (self._pygletTextObj._layout.content_width,
666
+ self._pygletTextObj._layout.content_height)
667
+ return w, h
668
+
669
+ @property
670
+ def posPix(self):
671
+ """This determines the coordinates in pixels of the position for the
672
+ current stimulus, accounting for pos and units. This property should
673
+ automatically update if `pos` is changed"""
674
+ # because this is a property getter we can check /on-access/ if it
675
+ # needs updating :-)
676
+ if self._needVertexUpdate:
677
+ self.__dict__['posPix'] = self._pos.pix
678
+ self._needVertexUpdate = False
679
+ return self.__dict__['posPix']
680
+
681
+ def updateOpacity(self):
682
+ self._setTextShaders(value=self.text)
683
+
684
+ def draw(self, win=None):
685
+ """
686
+ Draw the stimulus in its relevant window. You must call
687
+ this method after every MyWin.flip() if you want the
688
+ stimulus to appear on that frame and then update the screen
689
+ again.
690
+
691
+ If win is specified then override the normal window of this stimulus.
692
+ """
693
+ if win is None:
694
+ win = self.win
695
+ self._selectWindow(win)
696
+ blendMode = win.blendMode # keep track for reset later
697
+
698
+ GL.glPushMatrix()
699
+ # for PyOpenGL this is necessary despite pop/PushMatrix, (not for
700
+ # pyglet)
701
+ GL.glLoadIdentity()
702
+ #scale and rotate
703
+ prevScale = win.setScale('pix') # to units for translations
704
+ # NB depth is set already
705
+ GL.glTranslatef(self.posPix[0], self.posPix[1], 0)
706
+ GL.glRotatef(-self.ori, 0.0, 0.0, 1.0)
707
+ # back to pixels for drawing surface
708
+ win.setScale('pix', None, prevScale)
709
+ GL.glScalef((1, -1)[self.flipHoriz], (1, -1)
710
+ [self.flipVert], 1) # x,y,z; -1=flipped
711
+
712
+ # setup color
713
+ GL.glColor4f(*self._foreColor.render('rgba1'))
714
+
715
+ GL.glUseProgram(self.win._progSignedTexFont)
716
+ # GL.glUniform3iv(GL.glGetUniformLocation(
717
+ # self.win._progSignedTexFont, "rgb"), 1,
718
+ # desiredRGB.ctypes.data_as(ctypes.POINTER(ctypes.c_float)))
719
+ # # set the texture to be texture unit 0
720
+ GL.glUniform3f(
721
+ GL.glGetUniformLocation(self.win._progSignedTexFont, b"rgb"),
722
+ *self._foreColor.render('rgb1'))
723
+
724
+ # should text have a depth or just on top?
725
+ GL.glDisable(GL.GL_DEPTH_TEST)
726
+ # update list if necss and then call it
727
+ if win.winType in ["pyglet", "glfw"]:
728
+ if self._needSetText:
729
+ self.setText()
730
+
731
+ # unbind the mask texture regardless
732
+ GL.glActiveTexture(GL.GL_TEXTURE1)
733
+ GL.glEnable(GL.GL_TEXTURE_2D)
734
+ GL.glBindTexture(GL.GL_TEXTURE_2D, 0)
735
+ # unbind the main texture
736
+ GL.glActiveTexture(GL.GL_TEXTURE0)
737
+ GL.glEnable(GL.GL_TEXTURE_2D)
738
+ # then allow pyglet to bind and use texture during drawing
739
+
740
+ self._pygletTextObj.draw()
741
+ GL.glDisable(GL.GL_TEXTURE_2D)
742
+ else:
743
+ # for pygame we should (and can) use a drawing list
744
+ if self._needUpdate:
745
+ self._updateList()
746
+ GL.glCallList(self._listID)
747
+
748
+ # pyglets text.draw() method alters the blend func so reassert ours
749
+ win.setBlendMode(blendMode, log=False)
750
+ GL.glUseProgram(0)
751
+ # GL.glEnable(GL.GL_DEPTH_TEST) # Enables Depth Testing
752
+ GL.glPopMatrix()