psychopy 2025.1.0__py3-none-any.whl → 2025.2.1__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 (226) hide show
  1. psychopy/VERSION +1 -1
  2. psychopy/alerts/alertsCatalogue/4810.yaml +19 -0
  3. psychopy/alerts/alertsCatalogue/alertCategories.yaml +4 -0
  4. psychopy/alerts/alertsCatalogue/alertmsg.py +15 -1
  5. psychopy/alerts/alertsCatalogue/generateAlertmsg.py +2 -2
  6. psychopy/app/Resources/classic/add_many.png +0 -0
  7. psychopy/app/Resources/classic/add_many@2x.png +0 -0
  8. psychopy/app/Resources/classic/devices.png +0 -0
  9. psychopy/app/Resources/classic/devices@2x.png +0 -0
  10. psychopy/app/Resources/classic/photometer.png +0 -0
  11. psychopy/app/Resources/classic/photometer@2x.png +0 -0
  12. psychopy/app/Resources/dark/add_many.png +0 -0
  13. psychopy/app/Resources/dark/add_many@2x.png +0 -0
  14. psychopy/app/Resources/dark/devices.png +0 -0
  15. psychopy/app/Resources/dark/devices@2x.png +0 -0
  16. psychopy/app/Resources/dark/photometer.png +0 -0
  17. psychopy/app/Resources/dark/photometer@2x.png +0 -0
  18. psychopy/app/Resources/light/add_many.png +0 -0
  19. psychopy/app/Resources/light/add_many@2x.png +0 -0
  20. psychopy/app/Resources/light/devices.png +0 -0
  21. psychopy/app/Resources/light/devices@2x.png +0 -0
  22. psychopy/app/Resources/light/photometer.png +0 -0
  23. psychopy/app/Resources/light/photometer@2x.png +0 -0
  24. psychopy/app/_psychopyApp.py +35 -13
  25. psychopy/app/builder/builder.py +88 -35
  26. psychopy/app/builder/dialogs/__init__.py +69 -220
  27. psychopy/app/builder/dialogs/dlgsCode.py +29 -8
  28. psychopy/app/builder/dialogs/paramCtrls.py +1468 -904
  29. psychopy/app/builder/validators.py +25 -17
  30. psychopy/app/coder/coder.py +12 -1
  31. psychopy/app/coder/repl.py +5 -2
  32. psychopy/app/colorpicker/__init__.py +1 -1
  33. psychopy/app/deviceManager/__init__.py +1 -0
  34. psychopy/app/deviceManager/addDialog.py +218 -0
  35. psychopy/app/deviceManager/dialog.py +185 -0
  36. psychopy/app/deviceManager/panel.py +191 -0
  37. psychopy/app/deviceManager/utils.py +60 -0
  38. psychopy/app/idle.py +7 -0
  39. psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
  40. psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +12695 -10592
  41. psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
  42. psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.po +10199 -24
  43. psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
  44. psychopy/app/locale/da_DK/LC_MESSAGE/messages.po +10199 -24
  45. psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
  46. psychopy/app/locale/de_DE/LC_MESSAGE/messages.po +11221 -9712
  47. psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
  48. psychopy/app/locale/el_GR/LC_MESSAGE/messages.po +10200 -25
  49. psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
  50. psychopy/app/locale/en_NZ/LC_MESSAGE/messages.po +10200 -25
  51. psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
  52. psychopy/app/locale/en_US/LC_MESSAGE/messages.po +10195 -18
  53. psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
  54. psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +11917 -9101
  55. psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
  56. psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +11924 -9103
  57. psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
  58. psychopy/app/locale/es_US/LC_MESSAGE/messages.po +11917 -9101
  59. psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
  60. psychopy/app/locale/et_EE/LC_MESSAGE/messages.po +11084 -9569
  61. psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
  62. psychopy/app/locale/fa_IR/LC_MESSAGE/messages.po +11590 -5806
  63. psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
  64. psychopy/app/locale/fi_FI/LC_MESSAGE/messages.po +10199 -24
  65. psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
  66. psychopy/app/locale/fr_FR/LC_MESSAGE/messages.po +11091 -9577
  67. psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
  68. psychopy/app/locale/he_IL/LC_MESSAGE/messages.po +11072 -9549
  69. psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
  70. psychopy/app/locale/hi_IN/LC_MESSAGE/messages.po +11071 -9559
  71. psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
  72. psychopy/app/locale/hu_HU/LC_MESSAGE/messages.po +10200 -25
  73. psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
  74. psychopy/app/locale/it_IT/LC_MESSAGE/messages.po +11072 -9560
  75. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
  76. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +1485 -1137
  77. psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
  78. psychopy/app/locale/ko_KR/LC_MESSAGE/messages.po +10199 -24
  79. psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
  80. psychopy/app/locale/ms_MY/LC_MESSAGE/messages.po +11463 -8757
  81. psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
  82. psychopy/app/locale/nl_NL/LC_MESSAGE/messages.po +10200 -25
  83. psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
  84. psychopy/app/locale/nn_NO/LC_MESSAGE/messages.po +10200 -25
  85. psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
  86. psychopy/app/locale/pl_PL/LC_MESSAGE/messages.po +10200 -25
  87. psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
  88. psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +11288 -9434
  89. psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
  90. psychopy/app/locale/ro_RO/LC_MESSAGE/messages.po +10200 -25
  91. psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
  92. psychopy/app/locale/ru_RU/LC_MESSAGE/messages.po +10199 -24
  93. psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
  94. psychopy/app/locale/sv_SE/LC_MESSAGE/messages.po +11441 -8747
  95. psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
  96. psychopy/app/locale/tr_TR/LC_MESSAGE/messages.po +11069 -9545
  97. psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
  98. psychopy/app/locale/zh_CN/LC_MESSAGE/messages.po +12085 -8268
  99. psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
  100. psychopy/app/locale/zh_TW/LC_MESSAGE/messages.po +11929 -8022
  101. psychopy/app/plugin_manager/dialog.py +12 -3
  102. psychopy/app/plugin_manager/packageIndex.py +303 -0
  103. psychopy/app/plugin_manager/packages.py +203 -63
  104. psychopy/app/plugin_manager/plugins.py +120 -240
  105. psychopy/app/preferencesDlg.py +6 -1
  106. psychopy/app/psychopyApp.py +16 -4
  107. psychopy/app/runner/runner.py +10 -2
  108. psychopy/app/runner/scriptProcess.py +8 -3
  109. psychopy/app/stdout/stdOutRich.py +11 -4
  110. psychopy/app/themes/icons.py +3 -0
  111. psychopy/app/utils.py +61 -0
  112. psychopy/colors.py +10 -5
  113. psychopy/data/experiment.py +133 -23
  114. psychopy/data/routine.py +12 -0
  115. psychopy/data/staircase.py +42 -20
  116. psychopy/data/trial.py +20 -12
  117. psychopy/data/utils.py +43 -3
  118. psychopy/demos/builder/Experiments/dragAndDrop/drag_and_drop.psyexp +22 -5
  119. psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solutions.xlsx +0 -0
  120. psychopy/demos/builder/Experiments/stroopVoice/stroopVoice.psyexp +2 -12
  121. psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +3 -8
  122. psychopy/demos/builder/Feature Demos/movies/movie.psyexp +220 -0
  123. psychopy/demos/builder/Feature Demos/movies/readme.md +3 -0
  124. psychopy/demos/builder/Feature Demos/visualValidator/visualValidator.psyexp +1 -2
  125. psychopy/demos/builder/Hardware/camera/camera.psyexp +3 -16
  126. psychopy/demos/builder/Hardware/microphone/microphone.psyexp +3 -16
  127. psychopy/demos/coder/hardware/hdf5_extract.py +133 -0
  128. psychopy/event.py +20 -15
  129. psychopy/experiment/_experiment.py +86 -10
  130. psychopy/experiment/components/__init__.py +3 -10
  131. psychopy/experiment/components/_base.py +9 -20
  132. psychopy/experiment/components/button/__init__.py +1 -1
  133. psychopy/experiment/components/buttonBox/__init__.py +50 -54
  134. psychopy/experiment/components/camera/__init__.py +137 -359
  135. psychopy/experiment/components/keyboard/__init__.py +17 -24
  136. psychopy/experiment/components/microphone/__init__.py +61 -110
  137. psychopy/experiment/components/movie/__init__.py +2 -3
  138. psychopy/experiment/components/serialOut/__init__.py +192 -93
  139. psychopy/experiment/components/settings/__init__.py +45 -27
  140. psychopy/experiment/components/sound/__init__.py +82 -73
  141. psychopy/experiment/components/soundsensor/__init__.py +43 -80
  142. psychopy/experiment/devices.py +303 -0
  143. psychopy/experiment/exports.py +20 -18
  144. psychopy/experiment/flow.py +7 -0
  145. psychopy/experiment/loops.py +47 -29
  146. psychopy/experiment/monitor.py +74 -0
  147. psychopy/experiment/params.py +48 -10
  148. psychopy/experiment/plugins.py +28 -108
  149. psychopy/experiment/py2js_transpiler.py +1 -1
  150. psychopy/experiment/routines/__init__.py +1 -1
  151. psychopy/experiment/routines/_base.py +59 -24
  152. psychopy/experiment/routines/audioValidator/__init__.py +19 -155
  153. psychopy/experiment/routines/visualValidator/__init__.py +25 -25
  154. psychopy/hardware/__init__.py +20 -57
  155. psychopy/hardware/button.py +15 -2
  156. psychopy/hardware/camera/__init__.py +2237 -1394
  157. psychopy/hardware/joystick/__init__.py +1 -1
  158. psychopy/hardware/keyboard.py +5 -8
  159. psychopy/hardware/listener.py +4 -1
  160. psychopy/hardware/manager.py +75 -35
  161. psychopy/hardware/microphone.py +53 -7
  162. psychopy/hardware/monitor.py +144 -0
  163. psychopy/hardware/photometer/__init__.py +156 -117
  164. psychopy/hardware/serialdevice.py +16 -2
  165. psychopy/hardware/soundsensor.py +4 -1
  166. psychopy/iohub/devices/deviceConfigValidation.py +2 -1
  167. psychopy/iohub/devices/eyetracker/hw/gazepoint/__init__.py +2 -2
  168. psychopy/iohub/devices/eyetracker/hw/gazepoint/gp3/__init__.py +1 -0
  169. psychopy/iohub/devices/eyetracker/hw/gazepoint/gp3/eyetracker.py +10 -0
  170. psychopy/iohub/devices/keyboard/darwin.py +8 -5
  171. psychopy/iohub/util/__init__.py +7 -8
  172. psychopy/localization/generateTranslationTemplate.py +208 -116
  173. psychopy/localization/messages.pot +4305 -3502
  174. psychopy/monitors/MonitorCenter.py +174 -74
  175. psychopy/plugins/__init__.py +6 -4
  176. psychopy/preferences/devices.py +80 -0
  177. psychopy/preferences/generateHints.py +2 -1
  178. psychopy/preferences/preferences.py +35 -11
  179. psychopy/scripts/psychopy-pkgutil.py +969 -0
  180. psychopy/scripts/psyexpCompile.py +1 -1
  181. psychopy/session.py +34 -38
  182. psychopy/sound/__init__.py +6 -260
  183. psychopy/sound/audioclip.py +164 -0
  184. psychopy/sound/backend_ptb.py +8 -0
  185. psychopy/sound/backend_pygame.py +10 -0
  186. psychopy/sound/backend_pysound.py +9 -0
  187. psychopy/sound/backends/__init__.py +0 -0
  188. psychopy/sound/microphone.py +3 -0
  189. psychopy/sound/sound.py +58 -0
  190. psychopy/tests/data/correctScript/python/correctNoiseStimComponent.py +1 -1
  191. psychopy/tests/data/duplicateHeaders.csv +2 -0
  192. psychopy/tests/test_app/test_builder/test_BuilderFrame.py +22 -7
  193. psychopy/tests/test_app/test_builder/test_CompileFromBuilder.py +0 -2
  194. psychopy/tests/test_data/test_utils.py +5 -1
  195. psychopy/tests/test_experiment/test_components/test_ButtonBoxComponent.py +22 -2
  196. psychopy/tests/test_hardware/test_ports.py +0 -12
  197. psychopy/tests/test_tools/test_stringtools.py +1 -1
  198. psychopy/tools/attributetools.py +12 -5
  199. psychopy/tools/fontmanager.py +17 -14
  200. psychopy/tools/gltools.py +4 -2
  201. psychopy/tools/movietools.py +43 -2
  202. psychopy/tools/stringtools.py +33 -8
  203. psychopy/tools/versionchooser.py +1 -1
  204. psychopy/validation/audio.py +5 -1
  205. psychopy/validation/visual.py +5 -1
  206. psychopy/visual/basevisual.py +8 -7
  207. psychopy/visual/circle.py +2 -2
  208. psychopy/visual/helpers.py +3 -1
  209. psychopy/visual/image.py +29 -109
  210. psychopy/visual/movies/__init__.py +1800 -313
  211. psychopy/visual/polygon.py +4 -0
  212. psychopy/visual/shape.py +2 -2
  213. psychopy/visual/window.py +35 -12
  214. psychopy/voicekey/__init__.py +41 -669
  215. psychopy/voicekey/labjack_vks.py +7 -48
  216. psychopy/voicekey/parallel_vks.py +7 -42
  217. psychopy/voicekey/vk_tools.py +114 -263
  218. {psychopy-2025.1.0.dist-info → psychopy-2025.2.1.dist-info}/METADATA +20 -13
  219. {psychopy-2025.1.0.dist-info → psychopy-2025.2.1.dist-info}/RECORD +222 -190
  220. {psychopy-2025.1.0.dist-info → psychopy-2025.2.1.dist-info}/WHEEL +1 -1
  221. psychopy/visual/movies/players/__init__.py +0 -62
  222. psychopy/visual/movies/players/ffpyplayer_player.py +0 -1401
  223. psychopy/voicekey/demo_vks.py +0 -12
  224. psychopy/voicekey/signal.py +0 -42
  225. {psychopy-2025.1.0.dist-info → psychopy-2025.2.1.dist-info}/entry_points.txt +0 -0
  226. {psychopy-2025.1.0.dist-info → psychopy-2025.2.1.dist-info}/licenses/LICENSE +0 -0
psychopy/VERSION CHANGED
@@ -1 +1 @@
1
- 2025.1.0
1
+ 2025.2.1
@@ -0,0 +1,19 @@
1
+
2
+ code: 4810
3
+ cat: Devices
4
+ msg: Could not find any config for device {deviceName}, please setup this device up in the Device Manager dialog (from Builder)."
5
+
6
+ # The following are typically used for online help pages, and support reStructured Text.
7
+ label: No config for named device
8
+
9
+ synopsis: |
10
+ Your experiment refers to a device by name which has not been setup in Builder's Device Manager dialog.
11
+
12
+ details: |
13
+ From 2025.2.0, devices are setup in a dedicated Device Manager dialog and then referred to by name in Components. If you're seeing this message, it means there's a Component in your experiment which refers to a named device which has not been setup. This is common when running experiments made by someone else, or made on a different computer, as they will have setup using their devices.
14
+
15
+ solutions: |
16
+ Setup the named device in Builder's Device Manager dialog
17
+
18
+ versions: |
19
+ 2025.2.0
@@ -85,6 +85,10 @@
85
85
  cat: Loops
86
86
  4705: Column name from conditions file clashes with variable name
87
87
  4710: Column name from conditions file likely to clash with derived variable names
88
+
89
+ 4800:
90
+ cat: Devices
91
+ 4810: No config for named device
88
92
 
89
93
  5000:
90
94
  cat: Online studies
@@ -27,6 +27,13 @@ _translate(
27
27
  _translate(
28
28
  "Your stimulus {type} time of {time} seconds cannot be accurately presented for {time} on a {Hz}Hz monitor.")
29
29
 
30
+ # Alert 3210
31
+ _translate("Speaker {deviceName} is set to \"Exclusive low latency\" mode. As resampling is enabled, this mode has little benefit over \"Shared low latency\" mode, with some drawbacks.")
32
+
33
+ # Alert 3610
34
+ _translate(
35
+ "Multiple Components in the same Routine are validated by {validator}, please ensure that the timing of these Components do not overlap.")
36
+
30
37
  # Alert 4051
31
38
  _translate(
32
39
  "Experiment was built in a future version of PsychoPy ({version}), we recommend either updating PsychoPy or changing the \"Use Version\" setting in Experiment Settings to this version.")
@@ -51,6 +58,9 @@ _translate(
51
58
  _translate(
52
59
  "Microphone component `{name}` given blank stop time, using max duration allowed by buffer size ({stopVal}s).")
53
60
 
61
+ # Alert 4130
62
+ _translate("Static Component `{name}` given infinite stop time")
63
+
54
64
  # Alert 4205
55
65
  _translate(
56
66
  "Python Syntax Error in '{codeTab}' tab. See '{code}' on line number {lineNumber} of the '{codeTab}' tab.")
@@ -76,7 +86,7 @@ _translate(
76
86
 
77
87
  # Alert 4325
78
88
  _translate(
79
- "Font `{font} {style}` not available in weight `{weight}`, component `{name}` will default to Noto Sans Regular.")
89
+ "Font `{font} {style}` not available in weight `{weight}`, component `{name}` will default to Open Sans Regular.")
80
90
 
81
91
  # Alert 4330
82
92
  _translate(
@@ -138,6 +148,10 @@ _translate(
138
148
  # Alert 4710
139
149
  _translate("Column name '{param}' is likely to cause name clashes. {msg}.")
140
150
 
151
+ # Alert 4810
152
+ _translate(
153
+ "Could not find any config for device {deviceName}, please setup this device up in the Device Manager dialog (from Builder).\"")
154
+
141
155
  # Alert 5055
142
156
  _translate(
143
157
  "Device parameter of microphone component \"{name}\" will not be used online.")
@@ -3,11 +3,11 @@ from psychopy import core
3
3
  import sys
4
4
 
5
5
  write_mode = 'w'
6
-
6
+ new_line = '\n'
7
7
  alertmsgFile = 'alertmsg.py'
8
8
 
9
9
  try:
10
- fp = open(alertmsgFile, write_mode)
10
+ fp = open(alertmsgFile, write_mode, newline=new_line)
11
11
  fp.write('#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n')
12
12
  fp.write('# This file was generated by generateAlertmsg.py.\n')
13
13
  fp.write('# Following strings are used to localize alerts.\n')
Binary file
Binary file
Binary file
@@ -163,6 +163,8 @@ class _Showgui_Hack():
163
163
 
164
164
  class PsychoPyApp(wx.App, handlers.ThemeMixin):
165
165
  _called_from_test = False # pytest needs to change this
166
+ # are we running a beta release?
167
+ beta = True
166
168
 
167
169
  def __init__(self, arg=0, testMode=False, startView=None, profiling=False, **kwargs):
168
170
  """With a wx.App some things get done here, before App.__init__
@@ -417,7 +419,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
417
419
 
418
420
  if showSplash:
419
421
  # show splash screen
420
- if str(__version__).endswith("beta"):
422
+ if self.beta:
421
423
  splashFile = os.path.join(
422
424
  self.prefs.paths['resources'], 'betasplash.png'
423
425
  )
@@ -520,6 +522,10 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
520
522
  if self.isRetina:
521
523
  self._codeFont.SetPointSize(int(self._codeFont.GetPointSize()*fontScale))
522
524
  self._mainFont.SetPointSize(int(self._mainFont.GetPointSize()*fontScale))
525
+ # apply calculated point size to themed font defaults
526
+ from psychopy.app.themes import fonts
527
+ fonts.AppFont.pointSize = self._mainFont.GetPointSize()
528
+ fonts.CodeFont.pointSize = self._codeFont.GetPointSize()
523
529
  # that gets most of the properties of _codeFont but the FaceName
524
530
  # FaceName is set in the setting of the theme:
525
531
  self.theme = prefs.app['theme']
@@ -605,7 +611,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
605
611
  ).format(thisFile, err))
606
612
 
607
613
  # if we started a busy cursor which never finished, finish it now
608
- if wx.IsBusy():
614
+ if wx.IsBusy() and wx.Platform != '__WXGTK__':
609
615
  wx.EndBusyCursor()
610
616
 
611
617
  # send anonymous info to https://usage.psychopy.org
@@ -821,13 +827,18 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
821
827
  # have to reimport because it is only local to __init__ so far
822
828
  from . import coder
823
829
  if self.coder is None:
824
- title = "PsychoPy Coder (IDE) (v%s)"
825
- wx.BeginBusyCursor()
830
+ title = "PsychoPy Coder (v{version}{beta})".format(
831
+ version=self.version,
832
+ beta="beta" if self.beta else ""
833
+ )
834
+ if wx.Platform != '__WXGTK__':
835
+ wx.BeginBusyCursor()
826
836
  self.coder = coder.CoderFrame(None, -1,
827
- title=title % self.version,
837
+ title=title,
828
838
  files=fileList, app=self)
829
839
  self.updateWindowMenu()
830
- wx.EndBusyCursor()
840
+ if wx.Platform != '__WXGTK__':
841
+ wx.EndBusyCursor()
831
842
  else:
832
843
  # set output window and standard streams
833
844
  self.coder.setOutputWindow(True)
@@ -844,17 +855,22 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
844
855
 
845
856
  def newBuilderFrame(self, event=None, fileName=None):
846
857
  # have to reimport because it is only local to __init__ so far
847
- wx.BeginBusyCursor()
858
+ if wx.Platform != '__WXGTK__':
859
+ wx.BeginBusyCursor()
848
860
  from .builder.builder import BuilderFrame
849
- title = "PsychoPy Builder (v%s)"
861
+ title = "PsychoPy Builder (v{version}{beta})".format(
862
+ version=self.version,
863
+ beta="beta" if self.beta else ""
864
+ )
850
865
  self.builder = BuilderFrame(None, -1,
851
- title=title % self.version,
866
+ title=title,
852
867
  fileName=fileName, app=self)
853
868
  self.builder.Show(True)
854
869
  self.builder.Raise()
855
870
  self.SetTopWindow(self.builder)
856
871
  self.updateWindowMenu()
857
- wx.EndBusyCursor()
872
+ if wx.Platform != '__WXGTK__':
873
+ wx.EndBusyCursor()
858
874
 
859
875
  return self.builder
860
876
 
@@ -908,14 +924,20 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
908
924
  def newRunnerFrame(self, event=None):
909
925
  # have to reimport because it is only local to __init__ so far
910
926
  from .runner.runner import RunnerFrame
911
- title = "PsychoPy Runner (v{})".format(self.version)
912
- wx.BeginBusyCursor()
927
+
928
+ title = 'PsychoPy Runner (v{version}{beta})'.format(
929
+ version=self.version,
930
+ beta="beta" if self.beta else ""
931
+ )
932
+ if wx.Platform != '__WXGTK__':
933
+ wx.BeginBusyCursor()
913
934
  self.runner = RunnerFrame(parent=None,
914
935
  id=-1,
915
936
  title=title,
916
937
  app=self)
917
938
  self.updateWindowMenu()
918
- wx.EndBusyCursor()
939
+ if wx.Platform != '__WXGTK__':
940
+ wx.EndBusyCursor()
919
941
  return self.runner
920
942
 
921
943
  def OnDrop(self, x, y, files):
@@ -30,12 +30,14 @@ from wx.lib import platebtn
30
30
  from wx.html import HtmlWindow
31
31
 
32
32
  import psychopy.app.plugin_manager.dialog
33
+ from .dialogs.paramCtrls import EVT_PARAM_CHANGED
33
34
  from .validators import WarningManager
34
35
  from ..pavlovia_ui import sync, PavloviaMiniBrowser
35
36
  from ..pavlovia_ui.project import ProjectFrame
36
37
  from ..pavlovia_ui.search import SearchFrame
37
38
  from ..pavlovia_ui.user import UserFrame
38
39
  from ..pavlovia_ui.functions import logInPavlovia
40
+ from ..deviceManager import DeviceManagerDlg
39
41
  from ...experiment import getAllElements, getAllCategories
40
42
  from ...experiment.routines import Routine, BaseStandaloneRoutine
41
43
  from psychopy.tools.versionchooser import parseVersionSafely, psychopyVersion
@@ -76,7 +78,11 @@ from psychopy.scripts.psyexpCompile import generateScript
76
78
 
77
79
  # Components which are always hidden
78
80
  alwaysHidden = [
79
- 'BaseComponent', 'BaseStandaloneRoutine', 'BaseValidatorRoutine'
81
+ 'BaseComponent',
82
+ 'BaseDeviceComponent',
83
+ 'BaseStandaloneRoutine',
84
+ 'BaseDeviceRoutine',
85
+ 'BaseValidatorRoutine',
80
86
  ]
81
87
 
82
88
 
@@ -132,37 +138,45 @@ class BuilderFrame(BaseAuiFrame, handlers.ThemeMixin):
132
138
  self.generateScript = generateScript
133
139
 
134
140
  # default window title
135
- self.winTitle = 'PsychoPy Builder (v{})'.format(self.app.version)
141
+ self.winTitle = title
136
142
 
143
+ # get last frame information, or default
137
144
  if fileName in self.appData['frames']:
138
145
  self.frameData = self.appData['frames'][fileName]
139
- else: # work out a new frame size/location
140
- dispW, dispH = self.app.getPrimaryDisplaySize()
141
- default = self.appData['defaultFrame']
142
- default['winW'] = int(dispW * 0.75)
143
- default['winH'] = int(dispH * 0.75)
144
- if default['winX'] + default['winW'] > dispW:
145
- default['winX'] = 5
146
- if default['winY'] + default['winH'] > dispH:
147
- default['winY'] = 5
148
- self.frameData = dict(self.appData['defaultFrame']) # copy
146
+ else:
147
+ self.frameData = dict(self.appData['defaultFrame'])
148
+ # work out best default size from screen size
149
+ i = wx.Display.GetFromPoint(wx.Point(
150
+ int(self.frameData['winX']), int(self.frameData['winY'])
151
+ ))
152
+ try:
153
+ disp = wx.Display(max(i, 0))
154
+ except:
155
+ disp = wx.Display(0)
156
+ dispW, dispH = list(disp.GetGeometry())[2:]
157
+ # set in frameData array
158
+ self.frameData['winW'] = dispW * 0.75
159
+ self.frameData['winH'] = dispH * 0.75
149
160
  # increment default for next frame
150
- default['winX'] += 10
151
- default['winY'] += 10
152
-
153
- # we didn't have the key or the win was minimized / invalid
154
- if self.frameData['winH'] == 0 or self.frameData['winW'] == 0:
155
- self.frameData['winX'], self.frameData['winY'] = (0, 0)
156
- if self.frameData['winY'] < 20:
157
- self.frameData['winY'] = 20
158
-
159
- BaseAuiFrame.__init__(self, parent=parent, id=id, title=title,
160
- pos=(int(self.frameData['winX']),
161
- int(self.frameData['winY'])),
162
- size=(int(self.frameData['winW']),
163
- int(self.frameData['winH'])),
164
- style=style)
165
-
161
+ self.frameData['winX'] += 10
162
+ self.frameData['winY'] += 10
163
+ # handle when last open frame was minimised or invalid
164
+ for key in ("winH", "winW", "winX", "winY"):
165
+ self.frameData[key] = max(self.frameData[key], 20)
166
+ # initialise
167
+ BaseAuiFrame.__init__(
168
+ self,
169
+ parent=parent,
170
+ id=id,
171
+ size=(
172
+ int(self.frameData['winW']), int(self.frameData['winH'])
173
+ ),
174
+ pos=(
175
+ int(self.frameData['winX']), int(self.frameData['winY'])
176
+ ),
177
+ title=title,
178
+ style=style
179
+ )
166
180
  # detect retina displays (then don't use double-buffering)
167
181
  self.isRetina = \
168
182
  self.GetContentScaleFactor() != 1 and wx.Platform == '__WXMAC__'
@@ -191,7 +205,7 @@ class BuilderFrame(BaseAuiFrame, handlers.ThemeMixin):
191
205
  self.SetAcceleratorTable(accelTable)
192
206
 
193
207
  # setup a default exp
194
- if self.filename.is_file():
208
+ if fileName is not None and self.filename.is_file():
195
209
  self.fileOpen(filename=fileName, closeCurrent=False)
196
210
  else:
197
211
  self.lastSavedCopy = None
@@ -242,7 +256,11 @@ class BuilderFrame(BaseAuiFrame, handlers.ThemeMixin):
242
256
  self._mgr.Update()
243
257
  # self.SetSizer(self.mainSizer) # not necessary for aui type controls
244
258
  if self.frameData['auiPerspective']:
245
- self._mgr.LoadPerspective(self.frameData['auiPerspective'])
259
+ backup = self._mgr.SavePerspective()
260
+ try:
261
+ self._mgr.LoadPerspective(self.frameData['auiPerspective'])
262
+ except:
263
+ self._mgr.LoadPerspective(backup)
246
264
  self.SetMinSize(wx.Size(600, 400)) # min size for the whole window
247
265
  self.SetSize(
248
266
  (int(self.frameData['winW']), int(self.frameData['winH'])))
@@ -437,6 +455,11 @@ class BuilderFrame(BaseAuiFrame, handlers.ThemeMixin):
437
455
  _translate("To set information about your monitor"))
438
456
  self.Bind(wx.EVT_MENU, self.app.openMonitorCenter, item)
439
457
 
458
+ item = menu.Append(wx.ID_ANY,
459
+ _translate("Device Manager"),
460
+ _translate("Setup named devices for your Components to refer to"))
461
+ self.Bind(wx.EVT_MENU, self.openDeviceManager, item)
462
+
440
463
  item = menu.Append(wx.ID_ANY,
441
464
  _translate("Compile\t%s") % keys['compileScript'],
442
465
  _translate("Compile the exp to a script"))
@@ -599,6 +622,12 @@ class BuilderFrame(BaseAuiFrame, handlers.ThemeMixin):
599
622
  self.Bind(wx.EVT_MENU, self.app.showNews, id=item.GetId())
600
623
 
601
624
  self.SetMenuBar(menuBar)
625
+
626
+ def openDeviceManager(self, evt=None):
627
+ # create a device manager dialog
628
+ dlg = DeviceManagerDlg(self)
629
+ # show it modal to this window
630
+ dlg.ShowModal()
602
631
 
603
632
  def commandCloseFrame(self, event):
604
633
  """Defines Builder Frame Closing Event"""
@@ -1571,6 +1600,19 @@ class BuilderFrame(BaseAuiFrame, handlers.ThemeMixin):
1571
1600
  return True
1572
1601
 
1573
1602
  def openPluginManager(self, evt=None):
1603
+ # check if the package index is currently being updated, show a message
1604
+ # to tell the user to wait before opening the plugin manager
1605
+ import psychopy.app.plugin_manager.packageIndex as packageIndex
1606
+ if packageIndex.isIndexing():
1607
+ msg = _translate("The package index is currently being updated. "
1608
+ "Please try again later.")
1609
+ wx.MessageBox(
1610
+ msg,
1611
+ _translate("Package indexing in progress"),
1612
+ style=wx.OK | wx.ICON_INFORMATION
1613
+ )
1614
+ return
1615
+
1574
1616
  dlg = psychopy.app.plugin_manager.dialog.EnvironmentManagerDlg(self)
1575
1617
  dlg.Show()
1576
1618
 
@@ -2725,7 +2767,9 @@ class StandaloneRoutineCanvas(scrolledpanel.ScrolledPanel):
2725
2767
  self.sizer = wx.BoxSizer(wx.VERTICAL)
2726
2768
  self.SetSizer(self.sizer)
2727
2769
  # Setup categ notebook
2770
+ self.warnings = WarningManager(self)
2728
2771
  self.ctrls = ParamNotebook(self, experiment=self.frame.exp, element=routine)
2772
+ self.ctrls.Bind(EVT_PARAM_CHANGED, self.updateExperiment)
2729
2773
  self.paramCtrls = self.ctrls.paramCtrls
2730
2774
  self.sizer.Add(self.ctrls, border=12, proportion=1, flag=wx.ALIGN_CENTER | wx.TOP)
2731
2775
  # Make buttons
@@ -2734,10 +2778,9 @@ class StandaloneRoutineCanvas(scrolledpanel.ScrolledPanel):
2734
2778
  self.helpBtn.Bind(wx.EVT_BUTTON, self.onHelp)
2735
2779
  self.btnsSizer.Add(self.helpBtn, border=6, flag=wx.ALL | wx.EXPAND)
2736
2780
  self.btnsSizer.AddStretchSpacer(1)
2737
- # Add validator stuff
2738
- self.warnings = WarningManager(self)
2781
+ # add warnings to sizer
2739
2782
  self.sizer.Add(self.warnings.output, border=3, flag=wx.EXPAND | wx.ALL)
2740
- # Add buttons to sizer
2783
+ # add buttons to sizer
2741
2784
  self.sizer.Add(self.btnsSizer, border=3, proportion=0, flag=wx.EXPAND | wx.ALL)
2742
2785
  # Style
2743
2786
  self.SetupScrolling(scroll_y=True)
@@ -2757,12 +2800,15 @@ class StandaloneRoutineCanvas(scrolledpanel.ScrolledPanel):
2757
2800
  for name, routine in routines.items():
2758
2801
  if routine == self.routine:
2759
2802
  # Update the routine dict keys to use the current name for this routine
2760
- self.frame.exp.routines[self.routine.params['name'].val] = self.frame.exp.routines.pop(name)
2803
+ self.frame.exp.routines[self.routine.name] = self.frame.exp.routines.pop(name)
2804
+ # update experiment namespace
2805
+ self.frame.exp.namespace.remove(name)
2806
+ self.frame.exp.namespace.add(self.routine.name)
2761
2807
  # Redraw the flow panel
2762
2808
  self.frame.flowPanel.canvas.draw()
2763
2809
  # Rename this page
2764
2810
  page = self.frame.routinePanel.GetPageIndex(self)
2765
- self.frame.routinePanel.SetPageText(page, self.routine.params['name'].val)
2811
+ self.frame.routinePanel.SetPageText(page, self.routine.name)
2766
2812
  # Update save button
2767
2813
  self.frame.setIsModified(True)
2768
2814
 
@@ -4546,6 +4592,13 @@ class BuilderRibbon(ribbon.FrameRibbon):
4546
4592
  tooltip=_translate("Monitor settings and calibration"),
4547
4593
  callback=parent.app.openMonitorCenter
4548
4594
  )
4595
+ # device manager
4596
+ self.addButton(
4597
+ section="experiment", name='devices', label=_translate('Device manager'),
4598
+ icon="devices",
4599
+ tooltip=_translate("Map devices from this machine to names in your experiment"),
4600
+ callback=parent.openDeviceManager
4601
+ )
4549
4602
  # settings
4550
4603
  self.addButton(
4551
4604
  section="experiment", name='expsettings', label=_translate('Experiment settings'), icon="expsettings",