psychopy 2024.1.3__py3-none-any.whl → 2024.2.0__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/.DS_Store +0 -0
- psychopy/CHANGELOG.txt +206 -0
- psychopy/GIT_SHA +1 -0
- psychopy/VERSION +1 -0
- psychopy/__init__.py +77 -15
- psychopy/app/Resources/classic/plugin16.png +0 -0
- psychopy/app/Resources/classic/plugin16@2x.png +0 -0
- psychopy/app/Resources/dark/plugin16.png +0 -0
- psychopy/app/Resources/dark/plugin16@2x.png +0 -0
- psychopy/app/Resources/light/plugin16.png +0 -0
- psychopy/app/Resources/light/plugin16@2x.png +0 -0
- psychopy/app/__init__.py +76 -2
- psychopy/app/_psychopyApp.py +126 -101
- psychopy/app/builder/builder.py +14 -10
- psychopy/app/builder/dialogs/__init__.py +8 -8
- psychopy/app/builder/dialogs/dlgsConditions.py +12 -13
- psychopy/app/builder/dialogs/paramCtrls.py +24 -57
- psychopy/app/builder/localizedStrings.py +11 -9
- psychopy/app/builder/validators.py +2 -2
- psychopy/app/coder/codeEditorBase.py +8 -8
- psychopy/app/coder/coder.py +4 -4
- psychopy/app/connections/sendusage.py +2 -2
- psychopy/app/connections/updates.py +9 -9
- psychopy/app/dialogs.py +34 -2
- psychopy/app/idle.py +31 -0
- psychopy/app/jobs.py +21 -3
- psychopy/app/linuxconfig/__init__.py +9 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +4602 -2540
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +56 -54
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +53 -43
- psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_US/LC_MESSAGE/messages.po +56 -54
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +1258 -1176
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +9415 -5
- psychopy/app/pavlovia_ui/_base.py +33 -3
- psychopy/app/pavlovia_ui/search.py +0 -1
- psychopy/app/plugin_manager/dialog.py +104 -51
- psychopy/app/plugin_manager/packages.py +5 -0
- psychopy/app/plugin_manager/plugins.py +152 -67
- psychopy/app/preferencesDlg.py +8 -8
- psychopy/app/psychopyApp.py +11 -5
- psychopy/app/ribbon.py +124 -14
- psychopy/app/runner/runner.py +6 -1
- psychopy/app/stdout/stdOutRich.py +27 -11
- psychopy/app/themes/icons.py +52 -2
- psychopy/assets/__init__.py +0 -0
- psychopy/assets/click.png +0 -0
- psychopy/assets/clicknext.png +0 -0
- psychopy/assets/next.png +0 -0
- psychopy/assets/psychopy.ico +0 -0
- psychopy/assets/psychopy.png +0 -0
- psychopy/assets/templates/__init__.py +0 -0
- psychopy/assets/touch.png +0 -0
- psychopy/assets/touchnext.png +0 -0
- psychopy/assets/window.ico +0 -0
- psychopy/changes/2023.1.0.md +9 -0
- psychopy/changes/2024.1.0.md +16 -0
- psychopy/changes/__init__.py +0 -0
- psychopy/clock.py +2 -2
- psychopy/colors.py +2 -1
- psychopy/compatibility.py +53 -1
- psychopy/contrib/.DS_Store +0 -0
- psychopy/contrib/configobj/__init__.py +10 -8
- psychopy/data/__init__.py +3 -2
- psychopy/data/base.py +5 -5
- psychopy/data/experiment.py +130 -4
- psychopy/data/routine.py +56 -0
- psychopy/data/staircase.py +2 -2
- psychopy/data/trial.py +559 -97
- psychopy/data/utils.py +56 -21
- psychopy/demos/.DS_Store +0 -0
- psychopy/demos/builder/.DS_Store +0 -0
- psychopy/demos/builder/Design Templates/.DS_Store +0 -0
- psychopy/demos/builder/Experiments/.DS_Store +0 -0
- psychopy/demos/builder/Feature Demos/.DS_Store +0 -0
- psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +375 -0
- psychopy/demos/builder/Feature Demos/buttonBox/readme.md +5 -0
- psychopy/demos/builder/Feature Demos/pilotMode/pilotMode.psyexp +433 -0
- psychopy/demos/builder/Feature Demos/pilotMode/readme.md +7 -0
- psychopy/demos/builder/Feature Demos/progress/progressBar.psyexp +4 -4
- psychopy/demos/builder/Hardware/.DS_Store +0 -0
- psychopy/demos/builder/Helper Tools/.DS_Store +0 -0
- psychopy/demos/coder/.DS_Store +0 -0
- psychopy/demos/coder/hardware/testSoundLatency.py +2 -2
- psychopy/demos/coder/iohub/.DS_Store +0 -0
- psychopy/demos/coder/misc/hdf5_2_csv +33 -0
- psychopy/event.py +30 -29
- psychopy/experiment/.DS_Store +0 -0
- psychopy/experiment/_experiment.py +6 -6
- psychopy/experiment/components/.DS_Store +0 -0
- psychopy/experiment/components/__init__.py +6 -3
- psychopy/experiment/components/_base.py +286 -131
- psychopy/experiment/components/aperture/.DS_Store +0 -0
- psychopy/experiment/components/brush/.DS_Store +0 -0
- psychopy/experiment/components/button/.DS_Store +0 -0
- psychopy/experiment/components/button/__init__.py +5 -1
- psychopy/experiment/components/buttonBox/.DS_Store +0 -0
- psychopy/experiment/components/buttonBox/__init__.py +21 -12
- psychopy/experiment/components/camera/.DS_Store +0 -0
- psychopy/experiment/components/code/.DS_Store +0 -0
- psychopy/experiment/components/dots/.DS_Store +0 -0
- psychopy/experiment/components/eyetracker_record/.DS_Store +0 -0
- psychopy/experiment/components/eyetracker_record/__init__.py +92 -30
- psychopy/experiment/components/form/.DS_Store +0 -0
- psychopy/experiment/components/form/__init__.py +6 -2
- psychopy/experiment/components/grating/.DS_Store +0 -0
- psychopy/experiment/components/grating/__init__.py +14 -3
- psychopy/experiment/components/image/.DS_Store +0 -0
- psychopy/experiment/components/image/__init__.py +14 -3
- psychopy/experiment/components/joyButtons/.DS_Store +0 -0
- psychopy/experiment/components/joystick/.DS_Store +0 -0
- psychopy/experiment/components/keyboard/.DS_Store +0 -0
- psychopy/experiment/components/keyboard/__init__.py +22 -10
- psychopy/experiment/components/microphone/.DS_Store +0 -0
- psychopy/experiment/components/microphone/__init__.py +59 -39
- psychopy/experiment/components/mouse/.DS_Store +0 -0
- psychopy/experiment/components/mouse/__init__.py +44 -29
- psychopy/experiment/components/movie/.DS_Store +0 -0
- psychopy/experiment/components/movie/__init__.py +1 -1
- psychopy/experiment/components/panorama/.DS_Store +0 -0
- psychopy/experiment/components/parallelOut/.DS_Store +0 -0
- psychopy/experiment/components/patch/.DS_Store +0 -0
- psychopy/experiment/components/polygon/.DS_Store +0 -0
- psychopy/experiment/components/polygon/__init__.py +26 -6
- psychopy/experiment/components/progress/.DS_Store +0 -0
- psychopy/experiment/components/progress/__init__.py +1 -1
- psychopy/experiment/components/ratingScale/.DS_Store +0 -0
- psychopy/experiment/components/resourceManager/.DS_Store +0 -0
- psychopy/experiment/components/roi/.DS_Store +0 -0
- psychopy/experiment/components/roi/__init__.py +5 -0
- psychopy/experiment/components/routineSettings/.DS_Store +0 -0
- psychopy/experiment/components/routineSettings/__init__.py +57 -10
- psychopy/experiment/components/serialOut/.DS_Store +0 -0
- psychopy/experiment/components/settings/.DS_Store +0 -0
- psychopy/experiment/components/settings/__init__.py +117 -42
- psychopy/experiment/components/slider/.DS_Store +0 -0
- psychopy/experiment/components/sound/.DS_Store +0 -0
- psychopy/experiment/components/sound/__init__.py +54 -19
- psychopy/experiment/components/static/.DS_Store +0 -0
- psychopy/experiment/components/static/__init__.py +1 -1
- psychopy/experiment/components/text/.DS_Store +0 -0
- psychopy/experiment/components/text/__init__.py +28 -3
- psychopy/experiment/components/textbox/.DS_Store +0 -0
- psychopy/experiment/components/textbox/__init__.py +12 -2
- psychopy/experiment/components/unknown/.DS_Store +0 -0
- psychopy/experiment/components/unknown/__init__.py +1 -2
- psychopy/experiment/components/unknownPlugin/.DS_Store +0 -0
- psychopy/experiment/components/unknownPlugin/__init__.py +2 -2
- psychopy/experiment/components/variable/.DS_Store +0 -0
- psychopy/experiment/flow.py +11 -4
- psychopy/experiment/loops.py +85 -37
- psychopy/experiment/params.py +74 -32
- psychopy/experiment/py2js_transpiler.py +8 -1
- psychopy/experiment/routines/.DS_Store +0 -0
- psychopy/experiment/routines/_base.py +102 -22
- psychopy/experiment/routines/counterbalance/.DS_Store +0 -0
- psychopy/experiment/routines/counterbalance/__init__.py +5 -1
- psychopy/experiment/routines/eyetracker_calibrate/.DS_Store +0 -0
- psychopy/experiment/routines/eyetracker_validate/.DS_Store +0 -0
- psychopy/experiment/routines/pavlovia_survey/.DS_Store +0 -0
- psychopy/experiment/routines/photodiodeValidator/.DS_Store +0 -0
- psychopy/experiment/routines/photodiodeValidator/__init__.py +7 -6
- psychopy/experiment/routines/unknown/.DS_Store +0 -0
- psychopy/gui/wxgui.py +4 -4
- psychopy/hardware/.DS_Store +0 -0
- psychopy/hardware/__init__.py +1 -1
- psychopy/hardware/base.py +12 -0
- psychopy/hardware/camera/__init__.py +1 -15
- psychopy/hardware/cedrus.py +10 -11
- psychopy/hardware/crs/colorcal.py +13 -22
- psychopy/hardware/crs/optical.py +10 -20
- psychopy/hardware/emulator.py +17 -14
- psychopy/hardware/eyetracker.py +42 -118
- psychopy/hardware/gammasci.py +4 -15
- psychopy/hardware/keyboard.py +102 -11
- psychopy/hardware/listener.py +3 -0
- psychopy/hardware/microphone.py +148 -18
- psychopy/hardware/minolta.py +8 -15
- psychopy/hardware/photodiode.py +191 -16
- psychopy/hardware/photometer/__init__.py +11 -19
- psychopy/hardware/pr.py +8 -15
- psychopy/hardware/speaker.py +39 -4
- psychopy/info.py +0 -71
- psychopy/iohub/.DS_Store +0 -0
- psychopy/iohub/__init__.py +1 -1
- psychopy/iohub/client/__init__.py +30 -20
- psychopy/iohub/client/keyboard.py +24 -24
- psychopy/iohub/datastore/__init__.py +2 -2
- psychopy/iohub/datastore/util.py +2 -2
- psychopy/iohub/default_config.yaml +1 -1
- psychopy/iohub/devices/.DS_Store +0 -0
- psychopy/iohub/devices/__init__.py +112 -25
- psychopy/iohub/devices/deviceConfigValidation.py +2 -1
- psychopy/iohub/devices/experiment/default_experiment.yaml +12 -1
- psychopy/iohub/devices/experiment/supported_config_settings.yaml +5 -1
- psychopy/iohub/devices/eyetracker/.DS_Store +0 -0
- psychopy/iohub/devices/eyetracker/__init__.py +46 -0
- psychopy/iohub/devices/eyetracker/calibration/procedure.py +2 -2
- psychopy/iohub/devices/eyetracker/hw/gazepoint/__init__.py +14 -2
- psychopy/iohub/devices/eyetracker/hw/mouse/eyetracker.py +3 -4
- psychopy/iohub/server.py +2 -2
- psychopy/iohub/start_iohub_process.py +3 -0
- psychopy/iohub/util/__init__.py +62 -70
- psychopy/layout.py +5 -5
- psychopy/logging.py +8 -1
- psychopy/microphone.py +10 -37
- psychopy/platform_specific/__init__.py +0 -2
- psychopy/platform_specific/darwin.py +1 -3
- psychopy/platform_specific/linux.py +31 -33
- psychopy/platform_specific/win32.py +38 -13
- psychopy/plugins/__init__.py +148 -116
- psychopy/plugins/util.py +39 -0
- psychopy/preferences/Darwin.spec +4 -2
- psychopy/preferences/FreeBSD.spec +4 -2
- psychopy/preferences/Linux.spec +4 -2
- psychopy/preferences/Windows.spec +4 -2
- psychopy/preferences/baseNoArch.spec +4 -2
- psychopy/preferences/preferences.py +47 -24
- psychopy/projects/pavlovia.py +47 -4
- psychopy/scripts/psyexpCompile.py +0 -4
- psychopy/session.py +153 -21
- psychopy/sound/__init__.py +31 -21
- psychopy/sound/_base.py +20 -3
- psychopy/sound/audioclip.py +320 -33
- psychopy/sound/backend_ptb.py +47 -58
- psychopy/sound/backend_pygame.py +1 -1
- psychopy/sound/backend_pysound.py +6 -15
- psychopy/sound/transcribe.py +53 -0
- psychopy/tests/.DS_Store +0 -0
- psychopy/tests/data/.DS_Store +0 -0
- psychopy/tests/data/TestUnknownPluginComponent_load_resave.psyexp +135 -0
- psychopy/tests/data/Test_textbox/test_ori_0_bottom right.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_0_center.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_0_top left.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_120_bottom right.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_120_center.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_120_top left.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_180_bottom right.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_180_center.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_180_top left.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_240_bottom right.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_240_center.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_240_top left.png +0 -0
- psychopy/tests/data/correctScript/.DS_Store +0 -0
- psychopy/tests/data/test_components/testClearKeyboard/testClearKeyboard.psyexp +200 -0
- psychopy/tests/data/test_session/.DS_Store +0 -0
- psychopy/tests/data/test_session/root/testFutureTrials/testFutureTrials.psyexp +155 -0
- psychopy/tests/data/test_session/root/testTrialNav/trialNav.psyexp +158 -0
- psychopy/tests/test_app/.DS_Store +0 -0
- psychopy/tests/test_app/conftest.py +2 -2
- psychopy/tests/test_app/test_speed.py +4 -1
- psychopy/tests/test_data/test_TrialHandler2.py +146 -1
- psychopy/tests/test_experiment/.DS_Store +0 -0
- psychopy/tests/test_experiment/needs_wx/genComponsTemplate.py +3 -3
- psychopy/tests/test_experiment/needs_wx/test_components.py +2 -2
- psychopy/tests/test_experiment/test_components/test_KeyboardComponent.py +28 -0
- psychopy/tests/test_experiment/test_components/test_UnknownPluginComponent.py +27 -0
- psychopy/tests/test_experiment/test_components/test_base_components.py +58 -0
- psychopy/tests/test_experiment/test_py2js.py +1 -1
- psychopy/tests/test_hardware/test_keyboard.py +184 -16
- psychopy/tests/test_hardware/test_ports.py +1 -11
- psychopy/tests/test_liaison/test_Liaison.py +47 -0
- psychopy/tests/test_misc/test_core.py +5 -0
- psychopy/tests/test_session/test_Session.py +5 -1
- psychopy/tests/test_tools/test_versionchooser.py +39 -8
- psychopy/tests/test_visual/test_all_stimuli.py +0 -97
- psychopy/tests/test_visual/test_image.py +6 -5
- psychopy/tests/test_visual/test_textbox.py +36 -0
- psychopy/tests/utils.py +4 -0
- psychopy/tools/filetools.py +1 -1
- psychopy/tools/pkgtools.py +160 -137
- psychopy/tools/versionchooser.py +10 -10
- psychopy/tools/wizard.py +3 -3
- psychopy/visual/.DS_Store +0 -0
- psychopy/visual/backends/pygletbackend.py +24 -13
- psychopy/visual/basevisual.py +5 -11
- psychopy/visual/button.py +2 -14
- psychopy/visual/helpers.py +5 -5
- psychopy/visual/line.py +1 -2
- psychopy/visual/movie2.py +7 -816
- psychopy/visual/movie3.py +7 -589
- psychopy/visual/movies/__init__.py +8 -11
- psychopy/visual/movies/frame.py +5 -2
- psychopy/visual/movies/players/ffpyplayer_player.py +5 -2
- psychopy/visual/noise.py +8 -7
- psychopy/visual/patch.py +7 -16
- psychopy/visual/progress.py +1 -1
- psychopy/visual/radial.py +9 -7
- psychopy/visual/ratingscale.py +8 -1415
- psychopy/visual/secondorder.py +10 -9
- psychopy/visual/shape.py +7 -2
- psychopy/visual/text.py +1 -1
- psychopy/visual/textbox2/textbox2.py +28 -5
- psychopy/web.py +5 -2
- {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/METADATA +8 -13
- {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/RECORD +313 -219
- {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/WHEEL +1 -1
- psychopy/app/Resources/click.png +0 -0
- psychopy/app/Resources/next.png +0 -0
- psychopy/experiment/components/patch/__init__.py +0 -121
- psychopy/experiment/components/patch/classic/patch.png +0 -0
- psychopy/experiment/components/patch/dark/patch.png +0 -0
- psychopy/experiment/components/patch/dark/patch@2x.png +0 -0
- psychopy/experiment/components/patch/light/patch.png +0 -0
- psychopy/experiment/components/patch/light/patch@2x.png +0 -0
- psychopy/experiment/components/ratingScale/__init__.py +0 -337
- psychopy/experiment/components/ratingScale/classic/ratingscale.png +0 -0
- psychopy/experiment/components/ratingScale/classic/ratingscale@2x.png +0 -0
- psychopy/experiment/components/ratingScale/dark/ratingScale@2x.png +0 -0
- psychopy/experiment/components/ratingScale/dark/ratingscale.png +0 -0
- psychopy/experiment/components/ratingScale/light/ratingScale@2x.png +0 -0
- psychopy/experiment/components/ratingScale/light/ratingscale.png +0 -0
- psychopy/platform_specific/posix.py +0 -16
- psychopy/tests/test_sound/test_microphone.py +0 -217
- psychopy/tests/test_visual/test_ratingScale.py +0 -299
- /psychopy/{app/Resources → assets}/Psychopy Window Favicon@16w.png +0 -0
- /psychopy/{app/Resources → assets}/Psychopy Window Favicon@32w.png +0 -0
- /psychopy/{app/Resources → assets}/USB-C.png +0 -0
- /psychopy/{app/Resources → assets}/USB.png +0 -0
- /psychopy/{app/Resources → assets}/creditCard.png +0 -0
- /psychopy/{app/Resources → assets}/default.mp3 +0 -0
- /psychopy/{app/Resources → assets}/default.mp4 +0 -0
- /psychopy/{app/Resources → assets}/default.png +0 -0
- /psychopy/{app/Resources → assets/templates}/instruct1.png +0 -0
- /psychopy/{app/Resources → assets/templates}/instruct2.png +0 -0
- {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/entry_points.txt +0 -0
- {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/licenses/AUTHORS.md +0 -0
- {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/licenses/LICENSE +0 -0
psychopy/app/_psychopyApp.py
CHANGED
|
@@ -23,7 +23,7 @@ profiling = False # turning on will save profile files in currDir
|
|
|
23
23
|
|
|
24
24
|
import psychopy
|
|
25
25
|
from psychopy import prefs
|
|
26
|
-
from
|
|
26
|
+
from packaging.version import Version
|
|
27
27
|
from . import urls
|
|
28
28
|
from . import frametracker
|
|
29
29
|
from . import themes
|
|
@@ -96,21 +96,25 @@ class MenuFrame(wx.Frame, themes.handlers.ThemeMixin):
|
|
|
96
96
|
|
|
97
97
|
self.viewMenu = wx.Menu()
|
|
98
98
|
self.menuBar.Append(self.viewMenu, _translate('&View'))
|
|
99
|
-
mtxt = _translate("&Open Builder view\t
|
|
100
|
-
self.app.IDs.openBuilderView = self.viewMenu.Append(
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
mtxt = _translate("&Open Builder view\t")
|
|
100
|
+
self.app.IDs.openBuilderView = self.viewMenu.Append(
|
|
101
|
+
wx.ID_ANY,
|
|
102
|
+
mtxt,
|
|
103
|
+
_translate("Open a new Builder view")).GetId()
|
|
103
104
|
self.Bind(wx.EVT_MENU, self.app.showBuilder,
|
|
104
105
|
id=self.app.IDs.openBuilderView)
|
|
105
|
-
mtxt = _translate("&Open Coder view\t
|
|
106
|
-
self.app.IDs.openCoderView = self.viewMenu.Append(
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
mtxt = _translate("&Open Coder view\t")
|
|
107
|
+
self.app.IDs.openCoderView = self.viewMenu.Append(
|
|
108
|
+
wx.ID_ANY,
|
|
109
|
+
mtxt,
|
|
110
|
+
_translate("Open a new Coder view")).GetId()
|
|
109
111
|
self.Bind(wx.EVT_MENU, self.app.showCoder,
|
|
110
112
|
id=self.app.IDs.openCoderView)
|
|
111
113
|
mtxt = _translate("&Quit\t%s")
|
|
112
|
-
item = self.viewMenu.Append(
|
|
113
|
-
|
|
114
|
+
item = self.viewMenu.Append(
|
|
115
|
+
wx.ID_EXIT,
|
|
116
|
+
mtxt % self.app.keys['quit'],
|
|
117
|
+
_translate("Terminate the program"))
|
|
114
118
|
self.Bind(wx.EVT_MENU, self.app.quit, id=item.GetId())
|
|
115
119
|
self.SetMenuBar(self.menuBar)
|
|
116
120
|
self.Show()
|
|
@@ -149,9 +153,9 @@ class _Showgui_Hack():
|
|
|
149
153
|
if not os.path.isfile(noopPath):
|
|
150
154
|
code = """from psychopy import gui
|
|
151
155
|
dlg = gui.Dlg().Show() # non-blocking
|
|
152
|
-
try:
|
|
156
|
+
try:
|
|
153
157
|
dlg.Destroy() # might as well
|
|
154
|
-
except Exception:
|
|
158
|
+
except Exception:
|
|
155
159
|
pass"""
|
|
156
160
|
with open(noopPath, 'wb') as fd:
|
|
157
161
|
fd.write(bytes(code))
|
|
@@ -162,7 +166,7 @@ class _Showgui_Hack():
|
|
|
162
166
|
class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
163
167
|
_called_from_test = False # pytest needs to change this
|
|
164
168
|
|
|
165
|
-
def __init__(self, arg=0, testMode=False, **kwargs):
|
|
169
|
+
def __init__(self, arg=0, testMode=False, startView=None, **kwargs):
|
|
166
170
|
"""With a wx.App some things get done here, before App.__init__
|
|
167
171
|
then some further code is launched in OnInit() which occurs after
|
|
168
172
|
"""
|
|
@@ -209,7 +213,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
209
213
|
# allocated when `OnInit` is called.
|
|
210
214
|
self._sharedMemory = None
|
|
211
215
|
self._singleInstanceChecker = None # checker for instances
|
|
212
|
-
self.
|
|
216
|
+
self._lastInstanceCheckTime = -1.0
|
|
213
217
|
# Size of the memory map buffer, needs to be large enough to hold UTF-8
|
|
214
218
|
# encoded long file paths.
|
|
215
219
|
self.mmap_sz = 2048
|
|
@@ -241,7 +245,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
241
245
|
self.locale.AddCatalog(self.GetAppName())
|
|
242
246
|
|
|
243
247
|
logging.flush()
|
|
244
|
-
self.onInit(testMode=testMode, **kwargs)
|
|
248
|
+
self.onInit(testMode=testMode, startView=startView, **kwargs)
|
|
245
249
|
if profiling:
|
|
246
250
|
profile.disable()
|
|
247
251
|
print("time to load app = {:.2f}".format(time.time()-t0))
|
|
@@ -250,9 +254,9 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
250
254
|
|
|
251
255
|
# if we're on linux, check if we have the permissions file setup
|
|
252
256
|
from psychopy.app.linuxconfig import (
|
|
253
|
-
LinuxConfigDialog,
|
|
257
|
+
LinuxConfigDialog, linuxRushAllowed)
|
|
254
258
|
|
|
255
|
-
if not
|
|
259
|
+
if not linuxRushAllowed():
|
|
256
260
|
linuxConfDlg = LinuxConfigDialog(
|
|
257
261
|
None, timeout=1000 if self.testMode else None)
|
|
258
262
|
linuxConfDlg.ShowModal()
|
|
@@ -364,7 +368,6 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
364
368
|
Since panels are created before loading plugins, calling this method is
|
|
365
369
|
required after loading plugins which contain components to have them
|
|
366
370
|
appear.
|
|
367
|
-
|
|
368
371
|
"""
|
|
369
372
|
if not hasattr(self, 'builder') or self.builder is None:
|
|
370
373
|
return # nop if we haven't realized the builder UI yet
|
|
@@ -375,7 +378,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
375
378
|
for builderFrame in self.builder:
|
|
376
379
|
builderFrame.componentButtons.populate()
|
|
377
380
|
|
|
378
|
-
def onInit(self, showSplash=True, testMode=False, safeMode=False):
|
|
381
|
+
def onInit(self, showSplash=True, testMode=False, safeMode=False, startView=None):
|
|
379
382
|
"""This is launched immediately *after* the app initialises with
|
|
380
383
|
wxPython.
|
|
381
384
|
|
|
@@ -421,7 +424,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
421
424
|
# SLOW IMPORTS - these need to be imported after splash screen starts
|
|
422
425
|
# but then that they end up being local so keep track in self
|
|
423
426
|
|
|
424
|
-
from psychopy.compatibility import checkCompatibility
|
|
427
|
+
from psychopy.compatibility import checkCompatibility, checkUpdatesInfo
|
|
425
428
|
# import coder and builder here but only use them later
|
|
426
429
|
from psychopy.app import coder, builder, runner, dialogs
|
|
427
430
|
|
|
@@ -457,7 +460,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
457
460
|
self.dpi = int(wx.GetDisplaySize()[0] /
|
|
458
461
|
float(wx.GetDisplaySizeMM()[0]) * 25.4)
|
|
459
462
|
# detect retina displays
|
|
460
|
-
self.isRetina = self.dpi>80 and wx.Platform == '__WXMAC__'
|
|
463
|
+
self.isRetina = self.dpi > 80 and wx.Platform == '__WXMAC__'
|
|
461
464
|
if self.isRetina:
|
|
462
465
|
fontScale = 1.2 # fonts are looking tiny on macos (only retina?) right now
|
|
463
466
|
# mark icons as being retina
|
|
@@ -513,43 +516,51 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
513
516
|
# self._codeFont.SetPointSize(
|
|
514
517
|
# self._mainFont.GetPointSize()) # unify font size
|
|
515
518
|
|
|
519
|
+
# load plugins so they're available before frames are created
|
|
520
|
+
if splash:
|
|
521
|
+
splash.SetText(_translate(" Loading plugins..."))
|
|
522
|
+
from psychopy.plugins import activatePlugins
|
|
523
|
+
activatePlugins()
|
|
524
|
+
|
|
516
525
|
# create both frame for coder/builder as necess
|
|
517
526
|
if splash:
|
|
518
527
|
splash.SetText(_translate(" Creating frames..."))
|
|
519
|
-
|
|
520
|
-
#
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
if
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
if
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
528
|
+
|
|
529
|
+
# get starting windows
|
|
530
|
+
if startView in (None, []):
|
|
531
|
+
# if no window specified, use default from prefs
|
|
532
|
+
if self.prefs.app['defaultView'] == 'all':
|
|
533
|
+
startView = ["builder", "coder", "runner"]
|
|
534
|
+
elif self.prefs.app['defaultView'] == "last":
|
|
535
|
+
startView = self.prefs.appData['lastFrame'].split("-")
|
|
536
|
+
elif self.prefs.app['defaultView'] in ["builder", "coder", "runner"]:
|
|
537
|
+
startView = self.prefs.app['defaultView']
|
|
538
|
+
else:
|
|
539
|
+
startView = ["builder"]
|
|
540
|
+
# if specified as a single string, convert to list
|
|
541
|
+
if isinstance(startView, str):
|
|
542
|
+
startView = [startView]
|
|
543
|
+
|
|
544
|
+
# get files to open from commandline args
|
|
545
|
+
for arg in sys.argv:
|
|
546
|
+
if arg.endswith(".psyexp"):
|
|
547
|
+
exps.append(arg)
|
|
548
|
+
if arg.endswith(".py"):
|
|
549
|
+
scripts.append(arg)
|
|
550
|
+
if "runner" not in startView and arg.endswith(".psyrun"):
|
|
551
|
+
runlist.append(arg)
|
|
552
|
+
|
|
553
|
+
# show frames according to files
|
|
554
|
+
if exps and "builder" not in startView:
|
|
555
|
+
startView.append("builder")
|
|
556
|
+
if scripts and "coder" not in startView:
|
|
557
|
+
startView.append("coder")
|
|
558
|
+
if runlist and "runner" not in startView:
|
|
559
|
+
startView.append("runner")
|
|
560
|
+
|
|
561
|
+
# create windows
|
|
562
|
+
if "runner" in startView:
|
|
563
|
+
# open Runner if requested
|
|
553
564
|
try:
|
|
554
565
|
self.showRunner(fileList=runlist)
|
|
555
566
|
except Exception as err:
|
|
@@ -565,7 +576,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
565
576
|
"\n".join(traceback.format_exception(err))
|
|
566
577
|
)
|
|
567
578
|
|
|
568
|
-
if
|
|
579
|
+
if "coder" in startView:
|
|
569
580
|
# open Coder if requested
|
|
570
581
|
try:
|
|
571
582
|
self.showCoder(fileList=scripts)
|
|
@@ -580,7 +591,8 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
580
591
|
"\n".join(traceback.format_exception(err))
|
|
581
592
|
)
|
|
582
593
|
self.showCoder()
|
|
583
|
-
|
|
594
|
+
|
|
595
|
+
if "builder" in startView:
|
|
584
596
|
# open Builder if requested
|
|
585
597
|
try:
|
|
586
598
|
self.showBuilder(fileList=exps)
|
|
@@ -593,11 +605,12 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
593
605
|
"Requested: {}\n"
|
|
594
606
|
"Err: {}"
|
|
595
607
|
).format(exps, err))
|
|
596
|
-
|
|
597
|
-
if
|
|
608
|
+
|
|
609
|
+
if "direct" in startView:
|
|
598
610
|
self.showRunner()
|
|
599
|
-
for exp in [file for file in
|
|
611
|
+
for exp in [file for file in sys.argv if file.endswith('.psyexp') or file.endswith('.py')]:
|
|
600
612
|
self.runner.panel.runFile(exp)
|
|
613
|
+
|
|
601
614
|
# if we started a busy cursor which never finished, finish it now
|
|
602
615
|
if wx.IsBusy():
|
|
603
616
|
wx.EndBusyCursor()
|
|
@@ -611,6 +624,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
611
624
|
|
|
612
625
|
prefsConn = self.prefs.connections
|
|
613
626
|
|
|
627
|
+
# check for potential compatability issues
|
|
614
628
|
ok, msg = checkCompatibility(last, self.version, self.prefs, fix=True)
|
|
615
629
|
# tell the user what has changed
|
|
616
630
|
if not ok and not self.firstRun and not self.testMode:
|
|
@@ -619,11 +633,20 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
619
633
|
title=title)
|
|
620
634
|
dlg.ShowModal()
|
|
621
635
|
|
|
636
|
+
# check for non-issue updates
|
|
637
|
+
messages = checkUpdatesInfo(old=last, new=self.version)
|
|
638
|
+
if messages:
|
|
639
|
+
dlg = dialogs.RichMessageDialog(
|
|
640
|
+
parent=None,
|
|
641
|
+
message="\n\n".join(messages)
|
|
642
|
+
)
|
|
643
|
+
dlg.Show()
|
|
644
|
+
|
|
622
645
|
if self.prefs.app['showStartupTips'] and not self.testMode:
|
|
623
646
|
tipFile = os.path.join(
|
|
624
647
|
self.prefs.paths['resources'], _translate("tips.txt"))
|
|
625
648
|
tipIndex = self.prefs.appData['tipIndex']
|
|
626
|
-
if
|
|
649
|
+
if Version(wx.__version__) >= Version('4.0.0a1'):
|
|
627
650
|
tp = wx.adv.CreateFileTipProvider(tipFile, tipIndex)
|
|
628
651
|
showTip = wx.adv.ShowTip(None, tp)
|
|
629
652
|
else:
|
|
@@ -639,7 +662,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
639
662
|
|
|
640
663
|
# doing this once subsequently enables the app to open & switch among
|
|
641
664
|
# wx-windows on some platforms (Mac 10.9.4) with wx-3.0:
|
|
642
|
-
v =
|
|
665
|
+
v = Version
|
|
643
666
|
if sys.platform == 'darwin':
|
|
644
667
|
if v('3.0') <= v(wx.__version__) < v('4.0'):
|
|
645
668
|
_Showgui_Hack() # returns ~immediately, no display
|
|
@@ -653,21 +676,6 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
653
676
|
if self.coder:
|
|
654
677
|
self.coder.setOutputWindow() # takes control of sys.stdout
|
|
655
678
|
|
|
656
|
-
# if the program gets here, there are no other instances running
|
|
657
|
-
self._timer = wx.PyTimer(self._bgCheckAndLoad)
|
|
658
|
-
self._timer.Start(250)
|
|
659
|
-
|
|
660
|
-
# load plugins after the app has been mostly realized
|
|
661
|
-
if splash:
|
|
662
|
-
splash.SetText(_translate(" Loading plugins..."))
|
|
663
|
-
|
|
664
|
-
# Load plugins here after everything is realized, make sure that we
|
|
665
|
-
# refresh UI elements which are affected by plugins (e.g. the component
|
|
666
|
-
# panel in Builder).
|
|
667
|
-
from psychopy.plugins import activatePlugins
|
|
668
|
-
activatePlugins()
|
|
669
|
-
self._refreshComponentPanels()
|
|
670
|
-
|
|
671
679
|
# flush any errors to the last run log file
|
|
672
680
|
logging.flush()
|
|
673
681
|
sys.stdout.flush()
|
|
@@ -677,16 +685,17 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
677
685
|
|
|
678
686
|
return True
|
|
679
687
|
|
|
680
|
-
def _bgCheckAndLoad(self):
|
|
681
|
-
"""Check shared memory for messages from other instances.
|
|
682
|
-
|
|
688
|
+
def _bgCheckAndLoad(self, *args):
|
|
689
|
+
"""Check shared memory for messages from other instances.
|
|
690
|
+
|
|
691
|
+
This only is called periodically in the first and only instance of
|
|
692
|
+
PsychoPy running on the machine. This is called within the app's main
|
|
693
|
+
idle event method, with a frequency no more that once per second.
|
|
683
694
|
|
|
684
695
|
"""
|
|
685
696
|
if not self._appLoaded: # only open files if we have a UI
|
|
686
697
|
return
|
|
687
698
|
|
|
688
|
-
self._timer.Stop()
|
|
689
|
-
|
|
690
699
|
self._sharedMemory.seek(0)
|
|
691
700
|
if self._sharedMemory.read(1) == b'+': # available data
|
|
692
701
|
data = self._sharedMemory.read(self.mmap_sz - 1)
|
|
@@ -706,8 +715,6 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
706
715
|
else:
|
|
707
716
|
topWindow.Raise()
|
|
708
717
|
|
|
709
|
-
self._timer.Start(1000) # 1 second interval
|
|
710
|
-
|
|
711
718
|
@property
|
|
712
719
|
def appLoaded(self):
|
|
713
720
|
"""`True` if the app has been fully loaded (`bool`)."""
|
|
@@ -846,8 +853,8 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
846
853
|
from .builder.builder import BuilderFrame
|
|
847
854
|
title = "PsychoPy Builder (v%s)"
|
|
848
855
|
self.builder = BuilderFrame(None, -1,
|
|
849
|
-
|
|
850
|
-
|
|
856
|
+
title=title % self.version,
|
|
857
|
+
fileName=fileName, app=self)
|
|
851
858
|
self.builder.Show(True)
|
|
852
859
|
self.builder.Raise()
|
|
853
860
|
self.SetTopWindow(self.builder)
|
|
@@ -887,9 +894,9 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
887
894
|
title = "PsychoPy Runner (v{})".format(self.version)
|
|
888
895
|
wx.BeginBusyCursor()
|
|
889
896
|
self.runner = RunnerFrame(parent=None,
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
897
|
+
id=-1,
|
|
898
|
+
title=title,
|
|
899
|
+
app=self)
|
|
893
900
|
self.updateWindowMenu()
|
|
894
901
|
wx.EndBusyCursor()
|
|
895
902
|
return self.runner
|
|
@@ -967,7 +974,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
967
974
|
import socket
|
|
968
975
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
969
976
|
sock.settimeout(1.0)
|
|
970
|
-
iohubAddress = '127.0.0.1',
|
|
977
|
+
iohubAddress = '127.0.0.1', 9036
|
|
971
978
|
import msgpack
|
|
972
979
|
txData = msgpack.Packer().pack(('STOP_IOHUB_SERVER',))
|
|
973
980
|
return sock.sendto(txData, iohubAddress)
|
|
@@ -1009,13 +1016,16 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
1009
1016
|
return # user cancelled quit
|
|
1010
1017
|
|
|
1011
1018
|
# save info about current frames for next run
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
+
openFrames = []
|
|
1020
|
+
for frame in self.getAllFrames():
|
|
1021
|
+
if type(frame).__name__ == "BuilderFrame" and "builder" not in openFrames:
|
|
1022
|
+
openFrames.append("builder")
|
|
1023
|
+
if type(frame).__name__ == "CoderFrame" and "coder" not in openFrames:
|
|
1024
|
+
openFrames.append("coder")
|
|
1025
|
+
if type(frame).__name__ == "RunnerFrame" and "runner" not in openFrames:
|
|
1026
|
+
openFrames.append("runner")
|
|
1027
|
+
self.prefs.appData['lastFrame'] = "-".join(openFrames)
|
|
1028
|
+
# save current version for next run
|
|
1019
1029
|
self.prefs.appData['lastVersion'] = self.version
|
|
1020
1030
|
# update app data while closing each frame
|
|
1021
1031
|
# start with an empty list to be appended by each frame
|
|
@@ -1032,7 +1042,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
1032
1042
|
pass # we don't care if this fails - we're quitting anyway
|
|
1033
1043
|
# must do this before destroying the frame?
|
|
1034
1044
|
self.prefs.saveAppData()
|
|
1035
|
-
#self.Destroy()
|
|
1045
|
+
# self.Destroy()
|
|
1036
1046
|
|
|
1037
1047
|
# Reset streams back to default
|
|
1038
1048
|
sys.stdout = sys.__stdout__
|
|
@@ -1059,7 +1069,7 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
1059
1069
|
"For stimulus generation and experimental control in Python.\n"
|
|
1060
1070
|
"PsychoPy depends on your feedback. If something doesn't work\n"
|
|
1061
1071
|
"then let us know at psychopy-users@googlegroups.com")
|
|
1062
|
-
if
|
|
1072
|
+
if Version(wx.__version__) >= Version('4.0a1'):
|
|
1063
1073
|
info = wx.adv.AboutDialogInfo()
|
|
1064
1074
|
showAbout = wx.adv.AboutBox
|
|
1065
1075
|
else:
|
|
@@ -1178,8 +1188,23 @@ class PsychoPyApp(wx.App, handlers.ThemeMixin):
|
|
|
1178
1188
|
self._allFrames.remove(entry)
|
|
1179
1189
|
|
|
1180
1190
|
def onIdle(self, evt):
|
|
1191
|
+
"""Run idle tasks, including background checks for new instances.
|
|
1192
|
+
|
|
1193
|
+
Some of these run once while others are added as tasks to be run
|
|
1194
|
+
repeatedly.
|
|
1195
|
+
|
|
1196
|
+
"""
|
|
1181
1197
|
from . import idle
|
|
1182
|
-
idle.doIdleTasks(app=self)
|
|
1198
|
+
idle.doIdleTasks(app=self) # run once
|
|
1199
|
+
|
|
1200
|
+
# do the background check for new instances, check each second
|
|
1201
|
+
tNow = time.time()
|
|
1202
|
+
if tNow - self._lastInstanceCheckTime > 1.0: # every second
|
|
1203
|
+
if not self.testMode:
|
|
1204
|
+
self._bgCheckAndLoad()
|
|
1205
|
+
|
|
1206
|
+
self._lastInstanceCheckTime = time.time()
|
|
1207
|
+
|
|
1183
1208
|
evt.Skip()
|
|
1184
1209
|
|
|
1185
1210
|
@property
|
psychopy/app/builder/builder.py
CHANGED
|
@@ -23,7 +23,7 @@ import numpy
|
|
|
23
23
|
import requests
|
|
24
24
|
import io
|
|
25
25
|
|
|
26
|
-
from
|
|
26
|
+
from packaging.version import Version
|
|
27
27
|
import wx.stc
|
|
28
28
|
from wx.lib import scrolledpanel
|
|
29
29
|
from wx.lib import platebtn
|
|
@@ -50,7 +50,7 @@ try:
|
|
|
50
50
|
except ImportError:
|
|
51
51
|
from wx import PseudoDC
|
|
52
52
|
|
|
53
|
-
if
|
|
53
|
+
if Version(wx.__version__) < Version('4.0.3'):
|
|
54
54
|
wx.NewIdRef = wx.NewId
|
|
55
55
|
|
|
56
56
|
from psychopy.localization import _translate
|
|
@@ -64,7 +64,7 @@ from psychopy.tools.filetools import mergeFolder
|
|
|
64
64
|
from .dialogs import (DlgComponentProperties, DlgExperimentProperties,
|
|
65
65
|
DlgCodeComponentProperties, DlgLoopProperties,
|
|
66
66
|
ParamNotebook, DlgNewRoutine, BuilderFindDlg)
|
|
67
|
-
from ..utils import (BasePsychopyToolbar, HoverButton, WindowFrozen,
|
|
67
|
+
from ..utils import (BasePsychopyToolbar, HoverButton, ThemedPanel, WindowFrozen,
|
|
68
68
|
FileDropTarget, FrameSwitcher, updateDemosMenu,
|
|
69
69
|
ToggleButtonArray, HoverMixin)
|
|
70
70
|
|
|
@@ -863,6 +863,10 @@ class BuilderFrame(BaseAuiFrame, handlers.ThemeMixin):
|
|
|
863
863
|
self.filename = newPath
|
|
864
864
|
self.fileExists = True
|
|
865
865
|
self.fileSave(event=None, filename=newPath)
|
|
866
|
+
# enable/disable reveal button
|
|
867
|
+
if hasattr(self, "menuIDs"):
|
|
868
|
+
self.fileMenu.Enable(self.menuIDs.ID_REVEAL, True)
|
|
869
|
+
# update pavlovia project
|
|
866
870
|
self.project = pavlovia.getProject(filename)
|
|
867
871
|
returnVal = 1
|
|
868
872
|
dlg.Destroy()
|
|
@@ -1632,10 +1636,6 @@ class BuilderFrame(BaseAuiFrame, handlers.ThemeMixin):
|
|
|
1632
1636
|
# Run debug function from runner
|
|
1633
1637
|
self.app.runner.panel.runOnlineDebug(evt=evt)
|
|
1634
1638
|
|
|
1635
|
-
def setPavloviaUser(self, user):
|
|
1636
|
-
# TODO: update user icon on button to user avatar
|
|
1637
|
-
pass
|
|
1638
|
-
|
|
1639
1639
|
@property
|
|
1640
1640
|
def project(self):
|
|
1641
1641
|
"""A PavloviaProject object if one is known for this experiment
|
|
@@ -3289,6 +3289,8 @@ class ComponentsPanel(scrolledpanel.ScrolledPanel, handlers.ThemeMixin):
|
|
|
3289
3289
|
self.pluginBtn.SetBitmapPressed(icon)
|
|
3290
3290
|
self.pluginBtn.SetBitmapFocus(icon)
|
|
3291
3291
|
|
|
3292
|
+
self.Refresh()
|
|
3293
|
+
|
|
3292
3294
|
def addToFavorites(self, comp):
|
|
3293
3295
|
name = comp.__name__
|
|
3294
3296
|
# Mark component as a favorite
|
|
@@ -3478,7 +3480,7 @@ class FlowPanel(wx.Panel, handlers.ThemeMixin):
|
|
|
3478
3480
|
self.sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
3479
3481
|
self.SetSizer(self.sizer)
|
|
3480
3482
|
# buttons panel
|
|
3481
|
-
self.btnPanel =
|
|
3483
|
+
self.btnPanel = ThemedPanel(self)
|
|
3482
3484
|
self.btnPanel.sizer = wx.BoxSizer(wx.VERTICAL)
|
|
3483
3485
|
self.btnPanel.SetSizer(self.btnPanel.sizer)
|
|
3484
3486
|
self.sizer.Add(self.btnPanel, border=6, flag=wx.EXPAND | wx.ALL)
|
|
@@ -3539,7 +3541,7 @@ class FlowCanvas(wx.ScrolledWindow, handlers.ThemeMixin):
|
|
|
3539
3541
|
|
|
3540
3542
|
# create a PseudoDC to record our drawing
|
|
3541
3543
|
self.pdc = PseudoDC()
|
|
3542
|
-
if
|
|
3544
|
+
if Version(wx.__version__) < Version('4.0.0a1'):
|
|
3543
3545
|
self.pdc.DrawRoundedRectangle = self.pdc.DrawRoundedRectangleRect
|
|
3544
3546
|
self.pen_cache = {}
|
|
3545
3547
|
self.brush_cache = {}
|
|
@@ -4625,6 +4627,9 @@ class BuilderRibbon(ribbon.FrameRibbon):
|
|
|
4625
4627
|
|
|
4626
4628
|
self.addSeparator()
|
|
4627
4629
|
|
|
4630
|
+
# --- Plugin sections ---
|
|
4631
|
+
self.addPluginSections("psychopy.app.builder")
|
|
4632
|
+
|
|
4628
4633
|
# --- Views ---
|
|
4629
4634
|
self.addStretchSpacer()
|
|
4630
4635
|
self.addSeparator()
|
|
@@ -4651,7 +4656,6 @@ class BuilderRibbon(ribbon.FrameRibbon):
|
|
|
4651
4656
|
callback=parent.app.showRunner
|
|
4652
4657
|
)
|
|
4653
4658
|
|
|
4654
|
-
|
|
4655
4659
|
def extractText(stream):
|
|
4656
4660
|
"""Take a byte stream (or any file object of type b?) and return
|
|
4657
4661
|
|
|
@@ -212,8 +212,7 @@ class ParamCtrls():
|
|
|
212
212
|
elif param.inputType == 'table':
|
|
213
213
|
self.valueCtrl = paramCtrls.TableCtrl(
|
|
214
214
|
parent,
|
|
215
|
-
|
|
216
|
-
valType=param.valType,
|
|
215
|
+
param=param,
|
|
217
216
|
fieldName=fieldName,
|
|
218
217
|
size=wx.Size(int(self.valueWidth), 24))
|
|
219
218
|
elif param.inputType == 'color':
|
|
@@ -308,7 +307,7 @@ class ParamCtrls():
|
|
|
308
307
|
# set by integer index, not string value
|
|
309
308
|
self.updateCtrl.SetSelection(index)
|
|
310
309
|
|
|
311
|
-
if
|
|
310
|
+
if self.updateCtrl is not None and len(self.updateCtrl.GetItems()) == 1:
|
|
312
311
|
self.updateCtrl.Disable() # visible but can't be changed
|
|
313
312
|
|
|
314
313
|
def _getCtrlValue(self, ctrl):
|
|
@@ -479,6 +478,7 @@ class StartStopCtrls(wx.GridBagSizer):
|
|
|
479
478
|
# Add ctrl
|
|
480
479
|
self.ctrls[name] = wx.TextCtrl(parent,
|
|
481
480
|
value=str(param.val), size=wx.Size(-1, 24))
|
|
481
|
+
self.ctrls[name].SetToolTip(param.hint)
|
|
482
482
|
self.ctrls[name].Bind(wx.EVT_TEXT, self.updateCodeFont)
|
|
483
483
|
self.updateCodeFont(self.ctrls[name])
|
|
484
484
|
self.label = wx.StaticText(parent, label=param.label)
|
|
@@ -522,6 +522,9 @@ class StartStopCtrls(wx.GridBagSizer):
|
|
|
522
522
|
self.estimLabel.Show(visible)
|
|
523
523
|
if hasattr(self, "label"):
|
|
524
524
|
self.label.Show(visible)
|
|
525
|
+
# show/hide dollars
|
|
526
|
+
if hasattr(self, "dollar"):
|
|
527
|
+
self.dollar.Show(visible)
|
|
525
528
|
# Set value to None if hidden (specific to start/stop)
|
|
526
529
|
if not visible:
|
|
527
530
|
if "startVal" in self.ctrls:
|
|
@@ -1675,7 +1678,7 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1675
1678
|
style=wx.FD_OPEN, defaultDir=str(self.expPath))
|
|
1676
1679
|
if dlg.ShowModal() == wx.ID_OK:
|
|
1677
1680
|
self.conditionsFile = dlg.GetPath()
|
|
1678
|
-
self.
|
|
1681
|
+
self.currentCtrls['conditionsFile'].valueCtrl.SetValue(
|
|
1679
1682
|
self.conditionsFile
|
|
1680
1683
|
)
|
|
1681
1684
|
self.updateSummary()
|
|
@@ -1692,10 +1695,7 @@ class DlgLoopProperties(_BaseParamsDlg):
|
|
|
1692
1695
|
or message, as appropriate. Upon completion this will disable the update button as
|
|
1693
1696
|
we are now up to date.
|
|
1694
1697
|
"""
|
|
1695
|
-
|
|
1696
|
-
self.conditionsFile = self.multiStairCtrls['conditionsFile'].valueCtrl.GetValue()
|
|
1697
|
-
else:
|
|
1698
|
-
self.conditionsFile = self.constantsCtrls['conditionsFile'].valueCtrl.GetValue()
|
|
1698
|
+
self.conditionsFile = self.currentCtrls['conditionsFile'].valueCtrl.GetValue()
|
|
1699
1699
|
# Check whether the file and path are the same as previously
|
|
1700
1700
|
isSameFilePathAndName = self.conditionsFileAbs == self.conditionsFileOrig
|
|
1701
1701
|
# Start off with no message and assumed valid
|
|
@@ -12,7 +12,7 @@ import sys
|
|
|
12
12
|
import pickle
|
|
13
13
|
import wx
|
|
14
14
|
from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
|
|
15
|
-
from
|
|
15
|
+
from packaging.version import Version
|
|
16
16
|
|
|
17
17
|
from psychopy import gui
|
|
18
18
|
from psychopy.experiment.utils import valid_var_re
|
|
@@ -116,7 +116,7 @@ class DlgConditions(wx.Dialog):
|
|
|
116
116
|
except wx._core.PyNoAppError: # only needed during development?
|
|
117
117
|
self.madeApp = True
|
|
118
118
|
global app
|
|
119
|
-
if
|
|
119
|
+
if Version(wx.__version__) < Version('2.9'):
|
|
120
120
|
app = wx.PySimpleApp()
|
|
121
121
|
else:
|
|
122
122
|
app = wx.App(False)
|
|
@@ -383,46 +383,45 @@ class DlgConditions(wx.Dialog):
|
|
|
383
383
|
thisVal = repr(thisVal) # handles quoting ', ", ''' etc
|
|
384
384
|
# convert to requested type:
|
|
385
385
|
try:
|
|
386
|
-
# todo: replace exec() with eval()
|
|
387
386
|
if self.hasHeader and row == 0:
|
|
388
387
|
# header always str
|
|
389
388
|
val = self.inputFields[row][col].GetValue()
|
|
390
389
|
lastRow.append(str(val))
|
|
391
390
|
elif thisType in ['float', 'int', 'long']:
|
|
392
|
-
|
|
391
|
+
eval("lastRow.append(" + thisType +
|
|
393
392
|
'(' + thisVal + "))")
|
|
394
393
|
elif thisType in ['list']:
|
|
395
394
|
thisVal = thisVal.lstrip('[').strip(']')
|
|
396
|
-
|
|
395
|
+
eval("lastRow.append(" + thisType +
|
|
397
396
|
'([' + thisVal + "]))")
|
|
398
397
|
elif thisType in ['tuple']:
|
|
399
398
|
thisVal = thisVal.lstrip('(').strip(')')
|
|
400
399
|
if thisVal:
|
|
401
|
-
|
|
400
|
+
eval("lastRow.append((" +
|
|
402
401
|
thisVal.strip(',') + ",))")
|
|
403
402
|
else:
|
|
404
403
|
lastRow.append(tuple(()))
|
|
405
404
|
elif thisType in ['array']:
|
|
406
405
|
thisVal = thisVal.lstrip('[').strip(']')
|
|
407
|
-
|
|
406
|
+
eval("lastRow.append(numpy.array" +
|
|
408
407
|
'("[' + thisVal + ']"))')
|
|
409
408
|
elif thisType in ['utf-8', 'bool']:
|
|
410
409
|
if thisType == 'utf-8':
|
|
411
410
|
thisType = 'unicode'
|
|
412
|
-
|
|
411
|
+
eval("lastRow.append(" + thisType +
|
|
413
412
|
'(' + thisVal + '))')
|
|
414
413
|
elif thisType in ['str']:
|
|
415
|
-
|
|
414
|
+
eval("lastRow.append(str(" + thisVal + "))")
|
|
416
415
|
elif thisType in ['file']:
|
|
417
|
-
|
|
416
|
+
eval("lastRow.append(repr(" + thisVal + "))")
|
|
418
417
|
else:
|
|
419
|
-
|
|
418
|
+
eval("lastRow.append(" + str(thisVal) + ')')
|
|
420
419
|
except ValueError as msg:
|
|
421
420
|
print('ValueError:', msg, '; using unicode')
|
|
422
|
-
|
|
421
|
+
eval("lastRow.append(" + str(thisVal) + ')')
|
|
423
422
|
except NameError as msg:
|
|
424
423
|
print('NameError:', msg, '; using unicode')
|
|
425
|
-
|
|
424
|
+
eval("lastRow.append(" + repr(thisVal) + ')')
|
|
426
425
|
self.data.append(lastRow)
|
|
427
426
|
if self.trim:
|
|
428
427
|
# the corresponding data have already been removed
|