psychopy 2025.1.1__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.
- psychopy/VERSION +1 -1
- psychopy/alerts/alertsCatalogue/4810.yaml +19 -0
- psychopy/alerts/alertsCatalogue/alertCategories.yaml +4 -0
- psychopy/alerts/alertsCatalogue/alertmsg.py +15 -1
- psychopy/alerts/alertsCatalogue/generateAlertmsg.py +2 -2
- psychopy/app/Resources/classic/add_many.png +0 -0
- psychopy/app/Resources/classic/add_many@2x.png +0 -0
- psychopy/app/Resources/classic/devices.png +0 -0
- psychopy/app/Resources/classic/devices@2x.png +0 -0
- psychopy/app/Resources/classic/photometer.png +0 -0
- psychopy/app/Resources/classic/photometer@2x.png +0 -0
- psychopy/app/Resources/dark/add_many.png +0 -0
- psychopy/app/Resources/dark/add_many@2x.png +0 -0
- psychopy/app/Resources/dark/devices.png +0 -0
- psychopy/app/Resources/dark/devices@2x.png +0 -0
- psychopy/app/Resources/dark/photometer.png +0 -0
- psychopy/app/Resources/dark/photometer@2x.png +0 -0
- psychopy/app/Resources/light/add_many.png +0 -0
- psychopy/app/Resources/light/add_many@2x.png +0 -0
- psychopy/app/Resources/light/devices.png +0 -0
- psychopy/app/Resources/light/devices@2x.png +0 -0
- psychopy/app/Resources/light/photometer.png +0 -0
- psychopy/app/Resources/light/photometer@2x.png +0 -0
- psychopy/app/_psychopyApp.py +35 -13
- psychopy/app/builder/builder.py +88 -35
- psychopy/app/builder/dialogs/__init__.py +69 -220
- psychopy/app/builder/dialogs/dlgsCode.py +29 -8
- psychopy/app/builder/dialogs/paramCtrls.py +1468 -904
- psychopy/app/builder/validators.py +25 -17
- psychopy/app/coder/coder.py +12 -1
- psychopy/app/coder/repl.py +5 -2
- psychopy/app/colorpicker/__init__.py +1 -1
- psychopy/app/deviceManager/__init__.py +1 -0
- psychopy/app/deviceManager/addDialog.py +218 -0
- psychopy/app/deviceManager/dialog.py +185 -0
- psychopy/app/deviceManager/panel.py +191 -0
- psychopy/app/deviceManager/utils.py +60 -0
- psychopy/app/idle.py +7 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +12695 -10592
- psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.po +10199 -24
- psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/da_DK/LC_MESSAGE/messages.po +10199 -24
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.po +11221 -9712
- psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/el_GR/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_NZ/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_US/LC_MESSAGE/messages.po +10195 -18
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +11917 -9101
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +11924 -9103
- psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_US/LC_MESSAGE/messages.po +11917 -9101
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.po +11084 -9569
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.po +11590 -5806
- psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fi_FI/LC_MESSAGE/messages.po +10199 -24
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.po +11091 -9577
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.po +11072 -9549
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.po +11071 -9559
- psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hu_HU/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.po +11072 -9560
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +1485 -1137
- psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ko_KR/LC_MESSAGE/messages.po +10199 -24
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.po +11463 -8757
- psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nl_NL/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nn_NO/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pl_PL/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +11288 -9434
- psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ro_RO/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ru_RU/LC_MESSAGE/messages.po +10199 -24
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.po +11441 -8747
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.po +11069 -9545
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.po +12085 -8268
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.po +11929 -8022
- psychopy/app/plugin_manager/dialog.py +12 -3
- psychopy/app/plugin_manager/packageIndex.py +303 -0
- psychopy/app/plugin_manager/packages.py +203 -63
- psychopy/app/plugin_manager/plugins.py +120 -240
- psychopy/app/preferencesDlg.py +6 -1
- psychopy/app/psychopyApp.py +16 -4
- psychopy/app/runner/runner.py +10 -2
- psychopy/app/runner/scriptProcess.py +8 -3
- psychopy/app/stdout/stdOutRich.py +11 -4
- psychopy/app/themes/icons.py +3 -0
- psychopy/app/utils.py +61 -0
- psychopy/data/experiment.py +133 -23
- psychopy/data/routine.py +12 -0
- psychopy/data/staircase.py +42 -20
- psychopy/data/trial.py +20 -12
- psychopy/data/utils.py +42 -2
- psychopy/demos/builder/Experiments/dragAndDrop/drag_and_drop.psyexp +22 -5
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solutions.xlsx +0 -0
- psychopy/demos/builder/Experiments/stroopVoice/stroopVoice.psyexp +2 -12
- psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +3 -8
- psychopy/demos/builder/Feature Demos/movies/movie.psyexp +220 -0
- psychopy/demos/builder/Feature Demos/movies/readme.md +3 -0
- psychopy/demos/builder/Feature Demos/visualValidator/visualValidator.psyexp +1 -2
- psychopy/demos/builder/Hardware/camera/camera.psyexp +3 -16
- psychopy/demos/builder/Hardware/microphone/microphone.psyexp +3 -16
- psychopy/demos/coder/hardware/hdf5_extract.py +133 -0
- psychopy/event.py +20 -15
- psychopy/experiment/_experiment.py +86 -10
- psychopy/experiment/components/__init__.py +3 -10
- psychopy/experiment/components/_base.py +9 -20
- psychopy/experiment/components/button/__init__.py +1 -1
- psychopy/experiment/components/buttonBox/__init__.py +50 -54
- psychopy/experiment/components/camera/__init__.py +137 -359
- psychopy/experiment/components/keyboard/__init__.py +17 -24
- psychopy/experiment/components/microphone/__init__.py +61 -110
- psychopy/experiment/components/movie/__init__.py +2 -3
- psychopy/experiment/components/serialOut/__init__.py +192 -93
- psychopy/experiment/components/settings/__init__.py +45 -27
- psychopy/experiment/components/sound/__init__.py +82 -73
- psychopy/experiment/components/soundsensor/__init__.py +43 -80
- psychopy/experiment/devices.py +303 -0
- psychopy/experiment/exports.py +20 -18
- psychopy/experiment/flow.py +7 -0
- psychopy/experiment/loops.py +47 -29
- psychopy/experiment/monitor.py +74 -0
- psychopy/experiment/params.py +48 -10
- psychopy/experiment/plugins.py +28 -108
- psychopy/experiment/py2js_transpiler.py +1 -1
- psychopy/experiment/routines/__init__.py +1 -1
- psychopy/experiment/routines/_base.py +59 -24
- psychopy/experiment/routines/audioValidator/__init__.py +19 -155
- psychopy/experiment/routines/visualValidator/__init__.py +25 -25
- psychopy/hardware/__init__.py +20 -57
- psychopy/hardware/button.py +15 -2
- psychopy/hardware/camera/__init__.py +2237 -1394
- psychopy/hardware/joystick/__init__.py +1 -1
- psychopy/hardware/keyboard.py +5 -8
- psychopy/hardware/listener.py +4 -1
- psychopy/hardware/manager.py +75 -35
- psychopy/hardware/microphone.py +52 -6
- psychopy/hardware/monitor.py +144 -0
- psychopy/hardware/photometer/__init__.py +156 -117
- psychopy/hardware/serialdevice.py +16 -2
- psychopy/hardware/soundsensor.py +4 -1
- psychopy/iohub/devices/deviceConfigValidation.py +2 -1
- psychopy/iohub/devices/keyboard/darwin.py +8 -5
- psychopy/iohub/util/__init__.py +7 -8
- psychopy/localization/generateTranslationTemplate.py +208 -116
- psychopy/localization/messages.pot +4305 -3502
- psychopy/monitors/MonitorCenter.py +174 -74
- psychopy/plugins/__init__.py +6 -4
- psychopy/preferences/devices.py +80 -0
- psychopy/preferences/generateHints.py +2 -1
- psychopy/preferences/preferences.py +35 -11
- psychopy/scripts/psychopy-pkgutil.py +969 -0
- psychopy/scripts/psyexpCompile.py +1 -1
- psychopy/session.py +34 -38
- psychopy/sound/__init__.py +6 -260
- psychopy/sound/audioclip.py +164 -0
- psychopy/sound/backend_ptb.py +8 -0
- psychopy/sound/backend_pygame.py +10 -0
- psychopy/sound/backend_pysound.py +9 -0
- psychopy/sound/backends/__init__.py +0 -0
- psychopy/sound/microphone.py +3 -0
- psychopy/sound/sound.py +58 -0
- psychopy/tests/data/correctScript/python/correctNoiseStimComponent.py +1 -1
- psychopy/tests/data/duplicateHeaders.csv +2 -0
- psychopy/tests/test_app/test_builder/test_BuilderFrame.py +22 -7
- psychopy/tests/test_app/test_builder/test_CompileFromBuilder.py +0 -2
- psychopy/tests/test_data/test_utils.py +5 -1
- psychopy/tests/test_experiment/test_components/test_ButtonBoxComponent.py +22 -2
- psychopy/tests/test_hardware/test_ports.py +0 -12
- psychopy/tests/test_tools/test_stringtools.py +1 -1
- psychopy/tools/attributetools.py +12 -5
- psychopy/tools/fontmanager.py +17 -14
- psychopy/tools/movietools.py +43 -2
- psychopy/tools/stringtools.py +33 -8
- psychopy/tools/versionchooser.py +1 -1
- psychopy/validation/audio.py +5 -1
- psychopy/validation/visual.py +5 -1
- psychopy/visual/basevisual.py +8 -7
- psychopy/visual/circle.py +2 -2
- psychopy/visual/image.py +29 -109
- psychopy/visual/movies/__init__.py +1800 -313
- psychopy/visual/polygon.py +4 -0
- psychopy/visual/shape.py +2 -2
- psychopy/visual/window.py +34 -11
- psychopy/voicekey/__init__.py +41 -669
- psychopy/voicekey/labjack_vks.py +7 -48
- psychopy/voicekey/parallel_vks.py +7 -42
- psychopy/voicekey/vk_tools.py +114 -263
- {psychopy-2025.1.1.dist-info → psychopy-2025.2.1.dist-info}/METADATA +17 -11
- {psychopy-2025.1.1.dist-info → psychopy-2025.2.1.dist-info}/RECORD +216 -184
- {psychopy-2025.1.1.dist-info → psychopy-2025.2.1.dist-info}/WHEEL +1 -1
- psychopy/visual/movies/players/__init__.py +0 -62
- psychopy/visual/movies/players/ffpyplayer_player.py +0 -1401
- psychopy/voicekey/demo_vks.py +0 -12
- psychopy/voicekey/signal.py +0 -42
- {psychopy-2025.1.1.dist-info → psychopy-2025.2.1.dist-info}/entry_points.txt +0 -0
- {psychopy-2025.1.1.dist-info → psychopy-2025.2.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -17,6 +17,7 @@ from collections import OrderedDict
|
|
|
17
17
|
import numpy
|
|
18
18
|
import re
|
|
19
19
|
import wx
|
|
20
|
+
from wx.lib import scrolledpanel
|
|
20
21
|
|
|
21
22
|
import psychopy.experiment.utils
|
|
22
23
|
from psychopy.experiment import Param
|
|
@@ -77,6 +78,10 @@ class ParamCtrls():
|
|
|
77
78
|
self.dlg = dlg
|
|
78
79
|
self.dpi = self.dlg.dpi
|
|
79
80
|
self.valueWidth = self.dpi * 3.5
|
|
81
|
+
# get warnings handler
|
|
82
|
+
warnings = None
|
|
83
|
+
if hasattr(dlg, "warnings"):
|
|
84
|
+
warnings = dlg.warnings
|
|
80
85
|
# try to find the experiment
|
|
81
86
|
self.exp = None
|
|
82
87
|
tryForExp = self.dlg
|
|
@@ -89,7 +94,13 @@ class ParamCtrls():
|
|
|
89
94
|
tryForExp = tryForExp.parent # try going up a level
|
|
90
95
|
except Exception:
|
|
91
96
|
tryForExp.parent
|
|
92
|
-
|
|
97
|
+
# get the element to which this set of param ctrls pertains
|
|
98
|
+
self.element = None
|
|
99
|
+
if isinstance(parent, ParamNotebook.CategoryPage):
|
|
100
|
+
# if a category page, get element from notebook
|
|
101
|
+
self.element = parent.parent.element
|
|
102
|
+
elif isinstance(parent, DlgLoopProperties.LoopParamsPanel):
|
|
103
|
+
self.element = parent.loop
|
|
93
104
|
# param has the fields:
|
|
94
105
|
# val, valType, allowedVals=[],allowedTypes=[],
|
|
95
106
|
# hint="", updates=None, allowedUpdates=None
|
|
@@ -114,162 +125,11 @@ class ParamCtrls():
|
|
|
114
125
|
versions = vc._versionFilter(
|
|
115
126
|
vc.availableVersions(local=False), wx.__version__)
|
|
116
127
|
param.allowedVals = (options + [''] + versions)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
self.
|
|
121
|
-
|
|
122
|
-
val=str(param.val),
|
|
123
|
-
valType=param.valType,
|
|
124
|
-
fieldName=fieldName,
|
|
125
|
-
size=wx.Size(int(self.valueWidth), 24))
|
|
126
|
-
elif param.inputType == 'multi':
|
|
127
|
-
if param.valType == "extendedCode":
|
|
128
|
-
# Create multiline code control
|
|
129
|
-
self.valueCtrl = paramCtrls.CodeCtrl(
|
|
130
|
-
parent,
|
|
131
|
-
val=str(param.val),
|
|
132
|
-
valType=param.valType,
|
|
133
|
-
fieldName=fieldName,
|
|
134
|
-
size=wx.Size(int(self.valueWidth), 144))
|
|
135
|
-
else:
|
|
136
|
-
# Create multiline string control
|
|
137
|
-
self.valueCtrl = paramCtrls.MultiLineCtrl(
|
|
138
|
-
parent,
|
|
139
|
-
val=str(param.val),
|
|
140
|
-
valType=param.valType,
|
|
141
|
-
fieldName=fieldName,
|
|
142
|
-
size=wx.Size(int(self.valueWidth), 144))
|
|
143
|
-
# Set focus if field is text of a Textbox or Text component
|
|
144
|
-
if fieldName == 'text':
|
|
145
|
-
self.valueCtrl.SetFocus()
|
|
146
|
-
elif param.inputType == 'spin':
|
|
147
|
-
# Create single line string control
|
|
148
|
-
self.valueCtrl = paramCtrls.SingleLineCtrl(
|
|
149
|
-
parent,
|
|
150
|
-
val=str(param.val),
|
|
151
|
-
valType=param.valType,
|
|
152
|
-
fieldName=fieldName,
|
|
153
|
-
size=wx.Size(int(self.valueWidth), 24))
|
|
154
|
-
# Will have to disable spinCtrl until we have a dropdown for inputType, sadly
|
|
155
|
-
# self.valueCtrl = paramCtrls.IntCtrl(parent,
|
|
156
|
-
# val=param.val, valType=param.valType,
|
|
157
|
-
# fieldName=fieldName,size=wx.Size(self.valueWidth, 24),
|
|
158
|
-
# limits=param.allowedVals)
|
|
159
|
-
elif param.inputType == 'choice':
|
|
160
|
-
self.valueCtrl = paramCtrls.ChoiceCtrl(
|
|
161
|
-
parent,
|
|
162
|
-
val=str(param.val),
|
|
163
|
-
valType=param.valType,
|
|
164
|
-
choices=param.allowedVals,
|
|
165
|
-
labels=param.allowedLabels,
|
|
166
|
-
fieldName=fieldName)
|
|
167
|
-
elif param.inputType == 'multiChoice':
|
|
168
|
-
self.valueCtrl = paramCtrls.MultiChoiceCtrl(
|
|
169
|
-
parent,
|
|
170
|
-
valType=param.valType,
|
|
171
|
-
vals=param.val,
|
|
172
|
-
choices=param.allowedVals,
|
|
173
|
-
fieldName=fieldName,
|
|
174
|
-
size=wx.Size(int(self.valueWidth), -1))
|
|
175
|
-
elif param.inputType == 'richChoice':
|
|
176
|
-
self.valueCtrl = paramCtrls.RichChoiceCtrl(
|
|
177
|
-
parent,
|
|
178
|
-
valType=param.valType,
|
|
179
|
-
vals=param.val,
|
|
180
|
-
choices=param.allowedVals,
|
|
181
|
-
labels=param.allowedLabels,
|
|
182
|
-
fieldName=fieldName,
|
|
183
|
-
size=wx.Size(int(self.valueWidth), -1))
|
|
184
|
-
elif param.inputType == 'bool':
|
|
185
|
-
self.valueCtrl = paramCtrls.BoolCtrl(
|
|
186
|
-
parent,
|
|
187
|
-
name=fieldName,
|
|
188
|
-
size=wx.Size(int(self.valueWidth), 24))
|
|
189
|
-
self.valueCtrl.SetValue(bool(param))
|
|
190
|
-
elif param.inputType == 'file' or browse:
|
|
191
|
-
self.valueCtrl = paramCtrls.FileCtrl(
|
|
192
|
-
parent,
|
|
193
|
-
val=str(param.val),
|
|
194
|
-
valType=param.valType,
|
|
195
|
-
fieldName=fieldName,
|
|
196
|
-
size=wx.Size(int(self.valueWidth), 24))
|
|
197
|
-
self.valueCtrl.allowedVals = param.allowedVals
|
|
198
|
-
elif param.inputType == 'font':
|
|
199
|
-
self.valueCtrl = paramCtrls.FontCtrl(
|
|
200
|
-
parent,
|
|
201
|
-
val=str(param.val),
|
|
202
|
-
valType=param.valType,
|
|
203
|
-
fieldName=fieldName,
|
|
204
|
-
size=wx.Size(int(self.valueWidth), 24))
|
|
205
|
-
elif param.inputType == 'survey':
|
|
206
|
-
self.valueCtrl = paramCtrls.SurveyCtrl(
|
|
207
|
-
parent,
|
|
208
|
-
val=str(param.val),
|
|
209
|
-
valType=param.valType,
|
|
210
|
-
fieldName=fieldName,
|
|
211
|
-
size=wx.Size(int(self.valueWidth), 24))
|
|
212
|
-
self.valueCtrl.allowedVals = param.allowedVals
|
|
213
|
-
elif param.inputType == 'fileList':
|
|
214
|
-
self.valueCtrl = paramCtrls.FileListCtrl(
|
|
215
|
-
parent,
|
|
216
|
-
choices=param.val,
|
|
217
|
-
valType=param.valType,
|
|
218
|
-
size=wx.Size(int(self.valueWidth), 100),
|
|
219
|
-
pathtype="rel")
|
|
220
|
-
elif param.inputType == 'table':
|
|
221
|
-
self.valueCtrl = paramCtrls.TableCtrl(
|
|
222
|
-
parent,
|
|
223
|
-
param=param,
|
|
224
|
-
fieldName=fieldName,
|
|
225
|
-
size=wx.Size(int(self.valueWidth), 24))
|
|
226
|
-
elif param.inputType == 'color':
|
|
227
|
-
self.valueCtrl = paramCtrls.ColorCtrl(
|
|
228
|
-
parent,
|
|
229
|
-
val=param.val,
|
|
230
|
-
valType=param.valType,
|
|
231
|
-
fieldName=fieldName,
|
|
232
|
-
size=wx.Size(int(self.valueWidth), 24))
|
|
233
|
-
elif param.inputType == 'dict':
|
|
234
|
-
self.valueCtrl = paramCtrls.DictCtrl(
|
|
235
|
-
parent,
|
|
236
|
-
val=param.val,
|
|
237
|
-
labels=param.allowedLabels,
|
|
238
|
-
valType=param.valType,
|
|
239
|
-
fieldName=fieldName)
|
|
240
|
-
elif param.inputType == 'inv':
|
|
241
|
-
self.valueCtrl = paramCtrls.InvalidCtrl(
|
|
242
|
-
parent,
|
|
243
|
-
val=str(param.val),
|
|
244
|
-
valType=param.valType,
|
|
245
|
-
fieldName=fieldName,
|
|
246
|
-
size=wx.Size(int(self.valueWidth), 24))
|
|
247
|
-
else:
|
|
248
|
-
self.valueCtrl = paramCtrls.SingleLineCtrl(
|
|
249
|
-
parent,
|
|
250
|
-
val=str(param.val),
|
|
251
|
-
valType=param.valType,
|
|
252
|
-
fieldName=fieldName,
|
|
253
|
-
size=wx.Size(int(self.valueWidth), 24))
|
|
254
|
-
logging.warn(
|
|
255
|
-
f"Parameter {fieldName} has unrecognised inputType \"{param.inputType}\"")
|
|
256
|
-
|
|
257
|
-
# if fieldName == 'Experiment info':
|
|
258
|
-
# # for expInfo convert from a string to the list-of-dicts
|
|
259
|
-
# val = self.expInfoToListWidget(param.val)
|
|
260
|
-
# self.valueCtrl = dialogs.ListWidget(
|
|
261
|
-
# parent, val, order=['Field', 'Default'])
|
|
262
|
-
if hasattr(self.valueCtrl, 'SetToolTip'):
|
|
263
|
-
self.valueCtrl.SetToolTip(wx.ToolTip(_translate(param.hint)))
|
|
264
|
-
if not callable(param.allowedVals) and len(param.allowedVals) == 1 or param.readOnly:
|
|
265
|
-
self.valueCtrl.Disable() # visible but can't be changed
|
|
266
|
-
|
|
267
|
-
# add a Validator to the valueCtrl
|
|
268
|
-
if fieldName == "name":
|
|
269
|
-
self.valueCtrl.SetValidator(NameValidator())
|
|
270
|
-
elif param.inputType in ("single", "multi"):
|
|
271
|
-
# only want anything that is valType code, or can be with $
|
|
272
|
-
self.valueCtrl.SetValidator(CodeSnippetValidator(fieldName, param.label))
|
|
128
|
+
|
|
129
|
+
# create a param ctrl
|
|
130
|
+
self.valueCtrl = paramCtrls.ParamCtrl(
|
|
131
|
+
parent, field=fieldName, param=param, element=self.element, warnings=warnings
|
|
132
|
+
)
|
|
273
133
|
|
|
274
134
|
# create the type control
|
|
275
135
|
if len(param.allowedTypes):
|
|
@@ -305,6 +165,8 @@ class ParamCtrls():
|
|
|
305
165
|
allowedUpdates.append(msg + fullName)
|
|
306
166
|
updateLabels.append(localizedMsg + fullName)
|
|
307
167
|
self.updateCtrl = wx.Choice(parent, choices=updateLabels)
|
|
168
|
+
# bind method to update value ctrl's param on updating updateCtrl
|
|
169
|
+
self.updateCtrl.Bind(wx.EVT_CHOICE, self.onChangeUpdate)
|
|
308
170
|
# stash non-localized choices to allow retrieval by index:
|
|
309
171
|
self.updateCtrl._choices = copy.copy(allowedUpdates)
|
|
310
172
|
# If parameter isn't in list, default to the first choice
|
|
@@ -442,6 +304,16 @@ class ParamCtrls():
|
|
|
442
304
|
expInfoStr = repr(expInfo)
|
|
443
305
|
return expInfoStr
|
|
444
306
|
|
|
307
|
+
def onChangeUpdate(self, evt=None):
|
|
308
|
+
"""
|
|
309
|
+
On changes to the update ctrl, set updates on the param associated with the valuectrl
|
|
310
|
+
"""
|
|
311
|
+
if self.updateCtrl is not None and self.valueCtrl is not None:
|
|
312
|
+
# set updates on value ctrl's param
|
|
313
|
+
self.valueCtrl.param.updates = self.updateCtrl.GetStringSelection()
|
|
314
|
+
# trigger onchange to update appearance
|
|
315
|
+
self.valueCtrl.onChange()
|
|
316
|
+
|
|
445
317
|
def setChangesCallback(self, callbackFunction):
|
|
446
318
|
"""Set a callback to detect any changes in this value (whether it's
|
|
447
319
|
a checkbox event or a text event etc
|
|
@@ -464,7 +336,7 @@ class ParamCtrls():
|
|
|
464
336
|
self.valueCtrl.Bind(wx.EVT_CHECKBOX, callbackFunction)
|
|
465
337
|
elif isinstance(self.valueCtrl, paramCtrls.CodeCtrl):
|
|
466
338
|
self.valueCtrl.Bind(wx.EVT_KEY_UP, callbackFunction)
|
|
467
|
-
elif isinstance(self.valueCtrl, (paramCtrls.DictCtrl, paramCtrls.FileListCtrl)):
|
|
339
|
+
elif isinstance(self.valueCtrl, (paramCtrls.BaseParamCtrl, paramCtrls.DictCtrl, paramCtrls.FileListCtrl)):
|
|
468
340
|
pass
|
|
469
341
|
else:
|
|
470
342
|
print("setChangesCallback doesn't know how to handle ctrl {}"
|
|
@@ -557,9 +429,12 @@ class StartStopCtrls(wx.GridBagSizer):
|
|
|
557
429
|
|
|
558
430
|
|
|
559
431
|
class ParamNotebook(wx.Notebook, handlers.ThemeMixin):
|
|
560
|
-
class CategoryPage(
|
|
432
|
+
class CategoryPage(scrolledpanel.ScrolledPanel, handlers.ThemeMixin):
|
|
561
433
|
def __init__(self, parent, dlg, params, categ=None):
|
|
562
434
|
wx.Panel.__init__(self, parent, size=(600, -1))
|
|
435
|
+
self.SetupScrolling()
|
|
436
|
+
self.SetMaxSize((-1, 1080))
|
|
437
|
+
self.SetMinSize((720, 512))
|
|
563
438
|
self.parent = parent
|
|
564
439
|
self.parent = parent
|
|
565
440
|
self.dlg = dlg
|
|
@@ -607,6 +482,8 @@ class ParamNotebook(wx.Notebook, handlers.ThemeMixin):
|
|
|
607
482
|
def addParam(self, name, param):
|
|
608
483
|
# Make ctrl
|
|
609
484
|
self.ctrls[name] = ParamCtrls(self.dlg, param.label, param, self, name)
|
|
485
|
+
# Bind change event
|
|
486
|
+
self.ctrls[name].valueCtrl.Bind(paramCtrls.EVT_PARAM_CHANGED, self.emitChangeEvent)
|
|
610
487
|
# Add value ctrl
|
|
611
488
|
_flag = wx.EXPAND | wx.ALL
|
|
612
489
|
if hasattr(self.ctrls[name].valueCtrl, '_szr'):
|
|
@@ -718,6 +595,9 @@ class ParamNotebook(wx.Notebook, handlers.ThemeMixin):
|
|
|
718
595
|
if isinstance(self.dlg, wx.Dialog):
|
|
719
596
|
self.dlg.Fit()
|
|
720
597
|
self.Refresh()
|
|
598
|
+
|
|
599
|
+
def emitChangeEvent(self, evt):
|
|
600
|
+
wx.PostEvent(self, evt)
|
|
721
601
|
|
|
722
602
|
def doValidate(self, event=None):
|
|
723
603
|
self.Validate()
|
|
@@ -758,8 +638,13 @@ class ParamNotebook(wx.Notebook, handlers.ThemeMixin):
|
|
|
758
638
|
for categ, params in paramsByCateg.items():
|
|
759
639
|
page = self.CategoryPage(self, self.parent, params, categ=categ)
|
|
760
640
|
self.paramCtrls.update(page.ctrls)
|
|
641
|
+
# Bind change event
|
|
642
|
+
page.Bind(paramCtrls.EVT_PARAM_CHANGED, self.emitChangeEvent)
|
|
761
643
|
# Add page to notebook
|
|
762
644
|
self.AddPage(page, _translate(categ))
|
|
645
|
+
|
|
646
|
+
def emitChangeEvent(self, evt):
|
|
647
|
+
wx.PostEvent(self, evt)
|
|
763
648
|
|
|
764
649
|
def checkDepends(self, event=None):
|
|
765
650
|
"""
|
|
@@ -884,6 +769,7 @@ class _BaseParamsDlg(wx.Dialog):
|
|
|
884
769
|
self.params = params = element.params # dict
|
|
885
770
|
self.title = title
|
|
886
771
|
self.timeout = timeout
|
|
772
|
+
self.warnings = WarningManager(self)
|
|
887
773
|
if (not editing and
|
|
888
774
|
title != 'Experiment Settings' and
|
|
889
775
|
'name' in self.params):
|
|
@@ -999,7 +885,6 @@ class _BaseParamsDlg(wx.Dialog):
|
|
|
999
885
|
CANCEL = wx.Button(self, wx.ID_CANCEL, _translate(" Cancel "))
|
|
1000
886
|
|
|
1001
887
|
# Add validator stuff
|
|
1002
|
-
self.warnings = WarningManager(self)
|
|
1003
888
|
self.mainSizer.Add(self.warnings.output, border=3, flag=wx.EXPAND | wx.ALL)
|
|
1004
889
|
self.Validate() # disables OKbtn if bad name, syntax error, etc
|
|
1005
890
|
|
|
@@ -1058,8 +943,8 @@ class _BaseParamsDlg(wx.Dialog):
|
|
|
1058
943
|
"""
|
|
1059
944
|
# run "on ok" validation for each ctrl
|
|
1060
945
|
for ctrl in self.paramCtrls.values():
|
|
1061
|
-
if hasattr(ctrl, "valueCtrl") and hasattr(ctrl.valueCtrl, "
|
|
1062
|
-
ctrl.valueCtrl.
|
|
946
|
+
if hasattr(ctrl, "valueCtrl") and hasattr(ctrl.valueCtrl, "onElementOk"):
|
|
947
|
+
ctrl.valueCtrl.onElementOk()
|
|
1063
948
|
|
|
1064
949
|
event.Skip()
|
|
1065
950
|
|
|
@@ -1205,6 +1090,12 @@ class _BaseParamsDlg(wx.Dialog):
|
|
|
1205
1090
|
class DlgLoopProperties(_BaseParamsDlg):
|
|
1206
1091
|
_style = wx.DEFAULT_DIALOG_STYLE | wx.DIALOG_NO_PARENT | wx.RESIZE_BORDER
|
|
1207
1092
|
|
|
1093
|
+
class LoopParamsPanel(wx.Panel):
|
|
1094
|
+
def __init__(self, parent, loop):
|
|
1095
|
+
wx.Panel.__init__(self, parent)
|
|
1096
|
+
# store loop object
|
|
1097
|
+
self.loop = loop
|
|
1098
|
+
|
|
1208
1099
|
def __init__(self, frame, title="Loop Properties", loop=None,
|
|
1209
1100
|
helpUrl=None, pos=wx.DefaultPosition, size=wx.DefaultSize,
|
|
1210
1101
|
style=_style, depends=[], timeout=None):
|
|
@@ -1233,6 +1124,8 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1233
1124
|
self.conditions = None
|
|
1234
1125
|
self.conditionsFile = None
|
|
1235
1126
|
self.condNamesInFile = []
|
|
1127
|
+
self.warnings = WarningManager(self)
|
|
1128
|
+
self.loop = loop
|
|
1236
1129
|
# create a valid new name; save old name in case we need to revert
|
|
1237
1130
|
namespace = frame.exp.namespace
|
|
1238
1131
|
defaultName = namespace.makeValid('trials')
|
|
@@ -1401,7 +1294,7 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1401
1294
|
return str(self.expPath / self._conditionsFile)
|
|
1402
1295
|
|
|
1403
1296
|
def makeGlobalCtrls(self):
|
|
1404
|
-
panel =
|
|
1297
|
+
panel = self.LoopParamsPanel(parent=self, loop=self.loop)
|
|
1405
1298
|
panelSizer = wx.GridBagSizer(0, 0)
|
|
1406
1299
|
panel.SetSizer(panelSizer)
|
|
1407
1300
|
row = 0
|
|
@@ -1424,8 +1317,9 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1424
1317
|
row += 1
|
|
1425
1318
|
panelSizer.AddGrowableCol(1, 1)
|
|
1426
1319
|
self.globalCtrls['name'].valueCtrl.Bind(wx.EVT_TEXT, self.Validate)
|
|
1427
|
-
self.Bind(
|
|
1428
|
-
|
|
1320
|
+
self.globalCtrls['loopType'].valueCtrl.Bind(
|
|
1321
|
+
paramCtrls.EVT_PARAM_CHANGED, self.onTypeChanged,
|
|
1322
|
+
)
|
|
1429
1323
|
return panel
|
|
1430
1324
|
|
|
1431
1325
|
def makeConstantsCtrls(self):
|
|
@@ -1434,7 +1328,7 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1434
1328
|
handler = self.trialHandler
|
|
1435
1329
|
# loop through the params
|
|
1436
1330
|
keys = list(handler.params.keys())
|
|
1437
|
-
panel =
|
|
1331
|
+
panel = self.LoopParamsPanel(parent=self, loop=self.loop)
|
|
1438
1332
|
panel.app=self.app
|
|
1439
1333
|
panelSizer = wx.GridBagSizer(0, 0)
|
|
1440
1334
|
panel.SetSizer(panelSizer)
|
|
@@ -1500,7 +1394,7 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1500
1394
|
row += 1
|
|
1501
1395
|
# Link conditions file browse button to its own special method
|
|
1502
1396
|
if fieldName == 'conditionsFile':
|
|
1503
|
-
ctrls.valueCtrl.
|
|
1397
|
+
ctrls.valueCtrl.fileBtn.Bind(wx.EVT_BUTTON, self.onBrowseTrialsFile)
|
|
1504
1398
|
ctrls.setChangesCallback(self.setNeedUpdate)
|
|
1505
1399
|
# store info about the field
|
|
1506
1400
|
self.constantsCtrls[fieldName] = ctrls
|
|
@@ -1509,7 +1403,7 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1509
1403
|
|
|
1510
1404
|
def makeMultiStairCtrls(self):
|
|
1511
1405
|
# a list of controls for the random/sequential versions
|
|
1512
|
-
panel =
|
|
1406
|
+
panel = self.LoopParamsPanel(parent=self, loop=self.loop)
|
|
1513
1407
|
panel.app = self.app
|
|
1514
1408
|
panelSizer = wx.GridBagSizer(0, 0)
|
|
1515
1409
|
panel.SetSizer(panelSizer)
|
|
@@ -1579,7 +1473,7 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1579
1473
|
row += 1
|
|
1580
1474
|
# Bind file button with its own special method
|
|
1581
1475
|
if fieldName == 'conditionsFile':
|
|
1582
|
-
ctrls.valueCtrl.
|
|
1476
|
+
ctrls.valueCtrl.fileBtn.Bind(wx.EVT_BUTTON, self.onBrowseTrialsFile)
|
|
1583
1477
|
# store info about the field
|
|
1584
1478
|
self.multiStairCtrls[fieldName] = ctrls
|
|
1585
1479
|
panelSizer.AddGrowableCol(1, 1)
|
|
@@ -1588,7 +1482,7 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1588
1482
|
def makeStaircaseCtrls(self):
|
|
1589
1483
|
"""Setup the controls for a StairHandler
|
|
1590
1484
|
"""
|
|
1591
|
-
panel =
|
|
1485
|
+
panel = self.LoopParamsPanel(parent=self, loop=self.loop)
|
|
1592
1486
|
panelSizer = wx.GridBagSizer(0, 0)
|
|
1593
1487
|
panel.SetSizer(panelSizer)
|
|
1594
1488
|
row = 0
|
|
@@ -1699,7 +1593,7 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1699
1593
|
self.setCtrls(value)
|
|
1700
1594
|
|
|
1701
1595
|
def onTypeChanged(self, evt=None):
|
|
1702
|
-
newType =
|
|
1596
|
+
newType = self.globalCtrls['loopType'].valueCtrl.getValue()
|
|
1703
1597
|
if newType == self.currentType:
|
|
1704
1598
|
return
|
|
1705
1599
|
self.setCtrls(newType)
|
|
@@ -1711,7 +1605,7 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1711
1605
|
style=wx.FD_OPEN, defaultDir=str(self.expPath))
|
|
1712
1606
|
if dlg.ShowModal() == wx.ID_OK:
|
|
1713
1607
|
self.conditionsFile = dlg.GetPath()
|
|
1714
|
-
self.currentCtrls['conditionsFile'].valueCtrl.
|
|
1608
|
+
self.currentCtrls['conditionsFile'].valueCtrl.setValue(
|
|
1715
1609
|
self.conditionsFile
|
|
1716
1610
|
)
|
|
1717
1611
|
self.updateSummary()
|
|
@@ -1728,7 +1622,7 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1728
1622
|
or message, as appropriate. Upon completion this will disable the update button as
|
|
1729
1623
|
we are now up to date.
|
|
1730
1624
|
"""
|
|
1731
|
-
self.conditionsFile = self.currentCtrls['conditionsFile'].valueCtrl.
|
|
1625
|
+
self.conditionsFile = self.currentCtrls['conditionsFile'].valueCtrl.getValue()
|
|
1732
1626
|
# Check whether the file and path are the same as previously
|
|
1733
1627
|
isSameFilePathAndName = self.conditionsFileAbs == self.conditionsFileOrig
|
|
1734
1628
|
# Start off with no message and assumed valid
|
|
@@ -1901,17 +1795,10 @@ class DlgExperimentProperties(_BaseParamsDlg):
|
|
|
1901
1795
|
self.app = frame.app
|
|
1902
1796
|
self.dpi = self.app.dpi
|
|
1903
1797
|
|
|
1904
|
-
# for input devices:
|
|
1905
|
-
# do this just to set the initial values to be
|
|
1906
|
-
self.paramCtrls['Full-screen window'].setChangesCallback(self.onFullScrChange)
|
|
1907
|
-
self.onFullScrChange(event=None)
|
|
1908
|
-
self.Bind(wx.EVT_CHECKBOX, self.onFullScrChange,
|
|
1909
|
-
self.paramCtrls['Full-screen window'].valueCtrl)
|
|
1910
|
-
|
|
1911
1798
|
# Add button to show screen numbers
|
|
1912
1799
|
scrNumCtrl = self.paramCtrls['Screen'].valueCtrl
|
|
1913
|
-
self.screenNsBtn = wx.Button(scrNumCtrl
|
|
1914
|
-
scrNumCtrl.
|
|
1800
|
+
self.screenNsBtn = wx.Button(scrNumCtrl, label=_translate("Show screen numbers"))
|
|
1801
|
+
scrNumCtrl.sizer.Add(self.screenNsBtn, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT)
|
|
1915
1802
|
scrNumCtrl.Layout()
|
|
1916
1803
|
self.screenNsBtn.Bind(wx.EVT_BUTTON, self.showScreenNumbers)
|
|
1917
1804
|
|
|
@@ -1925,44 +1812,6 @@ class DlgExperimentProperties(_BaseParamsDlg):
|
|
|
1925
1812
|
|
|
1926
1813
|
self.Destroy()
|
|
1927
1814
|
|
|
1928
|
-
def onFullScrChange(self, event=None):
|
|
1929
|
-
"""full-screen has been checked / unchecked.
|
|
1930
|
-
Show or hide the window size field accordingly
|
|
1931
|
-
"""
|
|
1932
|
-
if self.paramCtrls['Full-screen window'].valueCtrl.GetValue():
|
|
1933
|
-
# get screen size for requested display
|
|
1934
|
-
numDisplays = wx.Display.GetCount()
|
|
1935
|
-
try:
|
|
1936
|
-
screenValue = int(
|
|
1937
|
-
self.paramCtrls['Screen'].valueCtrl.GetValue())
|
|
1938
|
-
except ValueError:
|
|
1939
|
-
# param control currently contains no integer value
|
|
1940
|
-
screenValue = 1
|
|
1941
|
-
if screenValue < 1 or screenValue > numDisplays:
|
|
1942
|
-
logging.error("User requested non-existent screen")
|
|
1943
|
-
screenN = 0
|
|
1944
|
-
else:
|
|
1945
|
-
screenN = screenValue - 1
|
|
1946
|
-
size = list(wx.Display(screenN).GetGeometry()[2:])
|
|
1947
|
-
# set vals and disable changes
|
|
1948
|
-
field = 'Window size (pixels)'
|
|
1949
|
-
self.paramCtrls[field].valueCtrl.SetValue(str(size))
|
|
1950
|
-
self.paramCtrls[field].param.val = size
|
|
1951
|
-
self.paramCtrls[field].valueCtrl.Disable()
|
|
1952
|
-
self.paramCtrls[field].nameCtrl.Disable()
|
|
1953
|
-
# enable show/hide mouse
|
|
1954
|
-
self.paramCtrls['Show mouse'].valueCtrl.Enable()
|
|
1955
|
-
self.paramCtrls['Show mouse'].nameCtrl.Enable()
|
|
1956
|
-
else:
|
|
1957
|
-
self.paramCtrls['Window size (pixels)'].valueCtrl.Enable()
|
|
1958
|
-
self.paramCtrls['Window size (pixels)'].nameCtrl.Enable()
|
|
1959
|
-
# set show mouse to visible and disable control
|
|
1960
|
-
self.paramCtrls['Show mouse'].valueCtrl.Disable()
|
|
1961
|
-
self.paramCtrls['Show mouse'].nameCtrl.Disable()
|
|
1962
|
-
self.mainSizer.Layout()
|
|
1963
|
-
self.Fit()
|
|
1964
|
-
self.Refresh()
|
|
1965
|
-
|
|
1966
1815
|
|
|
1967
1816
|
class DlgNewRoutine(wx.Dialog):
|
|
1968
1817
|
|
|
@@ -16,14 +16,12 @@ from collections import OrderedDict
|
|
|
16
16
|
from psychopy.experiment.components.code import CodeComponent
|
|
17
17
|
from ..validators import WarningManager
|
|
18
18
|
from ...themes import handlers
|
|
19
|
-
|
|
20
|
-
from importlib.util import find_spec as loader
|
|
21
|
-
hasMetapensiero = loader("metapensiero") is not None
|
|
19
|
+
import importlib
|
|
22
20
|
|
|
23
21
|
from .. import validators
|
|
24
22
|
from psychopy.localization import _translate
|
|
25
23
|
from psychopy.app.coder.codeEditorBase import BaseCodeEditor
|
|
26
|
-
from psychopy.experiment
|
|
24
|
+
from psychopy.experiment import py2js_transpiler
|
|
27
25
|
|
|
28
26
|
|
|
29
27
|
class DlgCodeComponentProperties(wx.Dialog):
|
|
@@ -68,6 +66,29 @@ class DlgCodeComponentProperties(wx.Dialog):
|
|
|
68
66
|
# then we're adding a new component so ensure a valid name:
|
|
69
67
|
makeValid = self.frame.exp.namespace.makeValid
|
|
70
68
|
self.params['name'].val = makeValid(self.params['name'].val)
|
|
69
|
+
|
|
70
|
+
# if metapensiero isn't installed, install to the user folder now
|
|
71
|
+
if py2js_transpiler.translates is None:
|
|
72
|
+
# ask before installing
|
|
73
|
+
dlg = wx.MessageDialog(
|
|
74
|
+
self,
|
|
75
|
+
message=_translate(
|
|
76
|
+
"Could not detect the necessary Python library for translating code. Install "
|
|
77
|
+
"it now?"
|
|
78
|
+
),
|
|
79
|
+
style=wx.YES | wx.NO
|
|
80
|
+
)
|
|
81
|
+
if dlg.ShowModal() == wx.ID_YES:
|
|
82
|
+
# install if they say yes
|
|
83
|
+
from psychopy.tools import pkgtools
|
|
84
|
+
pkgtools.installPackage(
|
|
85
|
+
"git+https://gitlab.com/peircej/metapensiero.pj"
|
|
86
|
+
)
|
|
87
|
+
# try to import again now that it exists
|
|
88
|
+
try:
|
|
89
|
+
py2js_transpiler.translates = importlib.import_module("metapensiero.pj.api")
|
|
90
|
+
except ModuleNotFoundError:
|
|
91
|
+
pass
|
|
71
92
|
|
|
72
93
|
self.codeNotebook = wx.Notebook(self)
|
|
73
94
|
# in AUI notebook the labels are blurry on retina mac
|
|
@@ -98,7 +119,7 @@ class DlgCodeComponentProperties(wx.Dialog):
|
|
|
98
119
|
_selectedCodeTypeIndex = _codeTypes.index(_selectedCodeType)
|
|
99
120
|
self.codeTypeMenu = wx.Choice(self, choices=_codeTypes)
|
|
100
121
|
# If user does not have metapensiero but codetype is auto-js, revert to (Py?)
|
|
101
|
-
if not
|
|
122
|
+
if not py2js_transpiler.translates is not None and _selectedCodeType.lower() == 'auto->js':
|
|
102
123
|
_selectedCodeTypeIndex -= 1
|
|
103
124
|
# Set selection to value stored in self params
|
|
104
125
|
self.codeTypeMenu.SetSelection(_selectedCodeTypeIndex)
|
|
@@ -233,7 +254,7 @@ class DlgCodeComponentProperties(wx.Dialog):
|
|
|
233
254
|
"""
|
|
234
255
|
prevCodeType, param = self.codeChoice
|
|
235
256
|
# If user doesn't have metapensiero and current choice is auto-js...
|
|
236
|
-
if not
|
|
257
|
+
if not py2js_transpiler.translates is not None and param.val.lower() == "auto->js" :
|
|
237
258
|
# Throw up error dlg instructing to get metapensiero
|
|
238
259
|
msg = _translate("\nPy to JS auto-translation requires the metapensiero library.\n"
|
|
239
260
|
"Available for Python 3.5+.\n")
|
|
@@ -312,7 +333,7 @@ class DlgCodeComponentProperties(wx.Dialog):
|
|
|
312
333
|
|
|
313
334
|
try:
|
|
314
335
|
if pythonCode:
|
|
315
|
-
jsCode = translatePythonToJavaScript(pythonCode, namespace=None)
|
|
336
|
+
jsCode = py2js_transpiler.translatePythonToJavaScript(pythonCode, namespace=None)
|
|
316
337
|
|
|
317
338
|
if codeChangeTest:
|
|
318
339
|
return jsCode
|
|
@@ -488,7 +509,7 @@ class CodeBox(BaseCodeEditor, handlers.ThemeMixin):
|
|
|
488
509
|
BaseCodeEditor.__init__(self, parent, ID, pos, size, style)
|
|
489
510
|
|
|
490
511
|
self.parent = parent
|
|
491
|
-
self.app = parent.app
|
|
512
|
+
# self.app = parent.app
|
|
492
513
|
self.prefs = prefs.coder
|
|
493
514
|
self.appData = prefs.appData
|
|
494
515
|
self.paths = prefs.paths
|