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
@@ -0,0 +1,191 @@
1
+ from psychopy.app import utils
2
+ from psychopy.app.builder.dialogs.paramCtrls import EVT_PARAM_CHANGED, ParamCtrl
3
+ from psychopy.app.builder.validators import WarningManager
4
+ from psychopy.app.themes import fonts
5
+
6
+
7
+ import wx
8
+ from wx.lib.scrolledpanel import ScrolledPanel
9
+ import wx.propgrid
10
+
11
+
12
+ class DevicePanel(ScrolledPanel):
13
+ def __init__(self, parent, dlg, device):
14
+ ScrolledPanel.__init__(self, parent, style=wx.DEFAULT | wx.VSCROLL)
15
+ self.SetMinSize((512, -1))
16
+ # store parentage
17
+ self.parent = parent
18
+ self.dlg = dlg
19
+ # setup warnings
20
+ self.warnings = WarningManager(self)
21
+ # store device
22
+ self.device = device
23
+ # setup sizer
24
+ self.border = wx.BoxSizer(wx.VERTICAL)
25
+ self.SetSizer(self.border)
26
+ self.sizer = wx.BoxSizer(wx.VERTICAL)
27
+ self.border.Add(
28
+ self.sizer, proportion=1, border=0, flag=wx.EXPAND | wx.ALL
29
+ )
30
+ # sort params by categ then order
31
+ sortedParams = {}
32
+ for key in device.order:
33
+ if key in device.params:
34
+ # make sure there's a page for this category
35
+ categ = device.params[key].categ
36
+ if categ not in sortedParams:
37
+ sortedParams[categ] = {}
38
+ # add param to categ
39
+ sortedParams[categ][key] = device.params[key]
40
+ for key in device.params:
41
+ # make sure there's a page for this category
42
+ categ = device.params[key].categ
43
+ if categ not in sortedParams:
44
+ sortedParams[categ] = {}
45
+ # add param to categ
46
+ if key not in sortedParams[categ]:
47
+ sortedParams[categ][key] = device.params[key]
48
+ # param ctrls
49
+ self.paramCtrls = {}
50
+ for categ in sortedParams:
51
+ # if categ if Basic, add to root sizer
52
+ toggle = None
53
+ if categ == "Basic":
54
+ categSizer = self.sizer
55
+ else:
56
+ # otherwise, make a show/hider
57
+ categSizer = wx.BoxSizer(wx.VERTICAL)
58
+ toggle = utils.ShowHideBtn(
59
+ self, target=categSizer, label=categ
60
+ )
61
+ self.sizer.Add(
62
+ toggle, border=6, flag=wx.EXPAND | wx.ALL
63
+ )
64
+ self.sizer.Add(
65
+ categSizer, border=0, flag=wx.EXPAND | wx.ALL
66
+ )
67
+ for name, param in sortedParams[categ].items():
68
+ # make param ctrl
69
+ self.paramCtrls[name] = ctrl = ParamCtrl(
70
+ self,
71
+ field=name,
72
+ param=param,
73
+ element=device,
74
+ warnings=self.warnings
75
+ )
76
+ ctrl.Bind(EVT_PARAM_CHANGED, self.onParamEdit)
77
+ # make label
78
+ lbl = wx.StaticText(
79
+ self, label=param.label
80
+ )
81
+ # make sizer for this ctrl
82
+ if type(ctrl).__name__ in ("BoolCtrl"):
83
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
84
+ # add crl
85
+ sizer.Add(
86
+ ctrl, border=6, flag=wx.EXPAND | wx.RIGHT
87
+ )
88
+ # add label
89
+ sizer.Add(
90
+ lbl, flag=wx.ALIGN_CENTER
91
+ )
92
+ else:
93
+ sizer = wx.BoxSizer(wx.VERTICAL)
94
+ # add label
95
+ sizer.Add(
96
+ lbl, border=3, flag=wx.EXPAND | wx.BOTTOM
97
+ )
98
+ sizer.Add(
99
+ ctrl, flag=wx.EXPAND
100
+ )
101
+ # add ctrl
102
+ # add sizer to panel
103
+ categSizer.Add(
104
+ sizer, border=6, flag=wx.EXPAND | wx.ALL
105
+ )
106
+ # store name param ctrl
107
+ if name == "deviceLabel":
108
+ self.nameCtrl = self.paramCtrls[name]
109
+ # bump up the font size
110
+ self.nameCtrl.ctrl.SetFont(fonts.AppFont(
111
+ pointSize=int(fonts.AppFont.pointSize*1.5),
112
+ bold=True
113
+ ).obj)
114
+ # hide label
115
+ lbl.Hide()
116
+ # start other categories off hidden
117
+ if toggle:
118
+ toggle.setValue(False)
119
+ # profile label
120
+ self.profileLbl = wx.StaticText(self, label="Device information")
121
+ self.sizer.Add(
122
+ self.profileLbl, border=6, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP
123
+ )
124
+ # profile ctrl
125
+ self.profileCtrl = wx.propgrid.PropertyGrid(self)
126
+ for key, val in device.profile.items():
127
+ prop = wx.propgrid.StringProperty(key, key, str(val))
128
+ self.profileCtrl.Append(prop)
129
+ prop.ChangeFlag(wx.propgrid.PG_PROP_READONLY, True)
130
+ self.profileCtrl.FitColumns()
131
+ self.profileCtrl.SetMinSize((-1, 128))
132
+ self.sizer.Add(
133
+ self.profileCtrl, border=6, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM
134
+ )
135
+ # delete button
136
+ self.deleteBtn = wx.Button(self, label="Remove device")
137
+ self.deleteBtn.SetMinSize((-1, 24))
138
+ self.deleteBtn.Bind(wx.EVT_BUTTON, self.onDelete)
139
+ self.sizer.Add(
140
+ self.deleteBtn, border=6, flag=wx.ALIGN_RIGHT | wx.ALL
141
+ )
142
+ # warnings panel
143
+ self.sizer.Add(
144
+ self.warnings.output, border=6, flag=wx.EXPAND | wx.ALL
145
+ )
146
+
147
+ # populate from device
148
+ self.populate()
149
+ self.SetupScrolling()
150
+
151
+ def onDelete(self, evt=None):
152
+ # remove from devices
153
+ del self.dlg.devices[self.device.name]
154
+ # remove page
155
+ self.dlg.profilesNotebook.DeletePage(
156
+ self.dlg.profilesNotebook.FindPage(self)
157
+ )
158
+ del self.dlg.pages[self.device.name]
159
+ # repopulate without this page
160
+ self.dlg.populate()
161
+
162
+ def onParamEdit(self, evt=None):
163
+ # get calling ctrl and param
164
+ ctrl = evt.GetEventObject()
165
+ param = ctrl.param
166
+ # if renaming, pass it to the dialog so the control updates
167
+ if ctrl is self.nameCtrl:
168
+ self.dlg.renameDevice(
169
+ oldname=self.device.name,
170
+ newname=self.nameCtrl.getValue()
171
+ )
172
+ return
173
+ # set value from ctrl
174
+ param.val = ctrl.getValue()
175
+ # validate dlg
176
+ self.dlg.validate()
177
+
178
+ def onElementOk(self, evt=None):
179
+ for name, ctrl in self.paramCtrls.items():
180
+ # do ctrl's usual ok function
181
+ ctrl.onElementOk(evt)
182
+ # update param
183
+ self.device.params[name] = ctrl.param
184
+ self.device.params[name].val = ctrl.getValue()
185
+
186
+ def populate(self):
187
+ # update params
188
+ for name, ctrl in self.paramCtrls.items():
189
+ ctrl.setValue(self.device.params[name].val)
190
+
191
+ self.Layout()
@@ -0,0 +1,60 @@
1
+ from pathlib import Path
2
+ import wx
3
+
4
+ from psychopy.app.themes import icons
5
+
6
+
7
+ class DeviceImageList(wx.ImageList):
8
+ """
9
+ Image list of device icons, allowing indices to be accessed by the device class
10
+ """
11
+ def __init__(
12
+ self,
13
+ width=16,
14
+ height=16,
15
+ mask=True,
16
+ initialCount=1
17
+ ):
18
+ # initialise as normal
19
+ wx.ImageList.__init__(
20
+ self,
21
+ width=width,
22
+ height=height,
23
+ mask=mask,
24
+ initialCount=initialCount
25
+ )
26
+ # create index cache
27
+ self.indices = {}
28
+
29
+ def getIcon(self, device):
30
+ """
31
+ Get the corresponding icon index of the icon for a given device based on its class.
32
+
33
+ Parameters
34
+ ----------
35
+ device : psychopy.experiment.devices.DeviceBackend or type
36
+ Device object (or device class) to get the icon for
37
+ """
38
+ # get device class
39
+ if not isinstance(device, type):
40
+ device = type(device)
41
+ # try to get from indices cache
42
+ if device in self.indices:
43
+ return self.indices[device]
44
+ # get icon file
45
+ file = device.getIconFile()
46
+ # load icon from file (if exists)
47
+ if file and Path(file).is_file():
48
+ bmp = icons.BaseIcon.resizeBitmap(
49
+ wx.Bitmap(str(device.getIconFile())),
50
+ size=self.GetSize()
51
+ )
52
+ i = self.Add(bmp)
53
+ # cache and return
54
+ self.indices[device] = i
55
+
56
+ return i
57
+
58
+ # all else fails, use blank
59
+ return -1
60
+
psychopy/app/idle.py CHANGED
@@ -13,6 +13,7 @@ import wx
13
13
  from psychopy import prefs, logging
14
14
  from psychopy.constants import NOT_STARTED, STARTED, SKIP, FINISHED
15
15
  from . import connections
16
+ from psychopy.app.plugin_manager.packageIndex import refreshPackageIndexTask
16
17
  from psychopy.tools import versionchooser as vc
17
18
  from ..app import pavlovia_ui
18
19
  _t0 = time.time()
@@ -78,6 +79,12 @@ tasks['getPavloviaUser'] = {
78
79
  'tstart': None, 'tEnd': None,
79
80
  'thread': False,
80
81
  }
82
+ tasks['refreshPackageIndex'] = {
83
+ 'status': NOT_STARTED,
84
+ 'func': refreshPackageIndexTask,
85
+ 'tstart': None, 'tEnd': None,
86
+ 'thread': True,
87
+ }
81
88
 
82
89
  currentTask = None
83
90