boris-behav-obs 8.16.5__py3-none-any.whl → 9.7.12__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.
- boris/__init__.py +1 -1
- boris/__main__.py +1 -1
- boris/about.py +28 -40
- boris/add_modifier.py +88 -80
- boris/add_modifier_ui.py +266 -144
- boris/advanced_event_filtering.py +23 -29
- boris/analysis_plugins/__init__.py +0 -0
- boris/analysis_plugins/_export_to_feral.py +225 -0
- boris/analysis_plugins/_latency.py +59 -0
- boris/analysis_plugins/irr_cohen_kappa.py +109 -0
- boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +112 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa.py +157 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +162 -0
- boris/analysis_plugins/list_of_dataframe_columns.py +22 -0
- boris/analysis_plugins/number_of_occurences.py +22 -0
- boris/analysis_plugins/number_of_occurences_by_independent_variable.py +54 -0
- boris/analysis_plugins/time_budget.py +61 -0
- boris/behav_coding_map_creator.py +235 -236
- boris/behavior_binary_table.py +33 -50
- boris/behaviors_coding_map.py +17 -18
- boris/boris_cli.py +6 -25
- boris/cmd_arguments.py +12 -1
- boris/coding_pad.py +19 -36
- boris/config.py +109 -50
- boris/config_file.py +58 -67
- boris/connections.py +105 -58
- boris/converters.py +13 -37
- boris/converters_ui.py +187 -110
- boris/cooccurence.py +250 -0
- boris/core.py +2174 -1303
- boris/core_qrc.py +15892 -10829
- boris/core_ui.py +941 -806
- boris/db_functions.py +17 -42
- boris/dev.py +27 -7
- boris/dialog.py +461 -242
- boris/duration_widget.py +9 -14
- boris/edit_event.py +61 -31
- boris/edit_event_ui.py +208 -97
- boris/event_operations.py +405 -281
- boris/events_cursor.py +25 -17
- boris/events_snapshots.py +36 -82
- boris/exclusion_matrix.py +4 -9
- boris/export_events.py +180 -203
- boris/export_observation.py +60 -73
- boris/external_processes.py +123 -98
- boris/geometric_measurement.py +427 -218
- boris/gui_utilities.py +91 -14
- boris/image_overlay.py +4 -4
- boris/import_observations.py +190 -98
- boris/ipc_mpv.py +325 -0
- boris/irr.py +20 -57
- boris/latency.py +31 -24
- boris/measurement_widget.py +14 -18
- boris/media_file.py +17 -19
- boris/menu_options.py +16 -6
- boris/modifier_coding_map_creator.py +1013 -0
- boris/modifiers_coding_map.py +7 -9
- boris/mpv2.py +128 -35
- boris/observation.py +501 -211
- boris/observation_operations.py +1037 -393
- boris/observation_ui.py +573 -363
- boris/observations_list.py +51 -58
- boris/otx_parser.py +74 -68
- boris/param_panel.py +45 -59
- boris/param_panel_ui.py +254 -138
- boris/player_dock_widget.py +91 -56
- boris/plot_data_module.py +20 -53
- boris/plot_events.py +56 -153
- boris/plot_events_rt.py +16 -30
- boris/plot_spectrogram_rt.py +83 -56
- boris/plot_waveform_rt.py +27 -49
- boris/plugins.py +468 -0
- boris/portion/__init__.py +18 -8
- boris/portion/const.py +35 -18
- boris/portion/dict.py +5 -5
- boris/portion/func.py +2 -2
- boris/portion/interval.py +21 -41
- boris/portion/io.py +41 -32
- boris/preferences.py +307 -123
- boris/preferences_ui.py +686 -227
- boris/project.py +294 -271
- boris/project_functions.py +626 -537
- boris/project_import_export.py +204 -213
- boris/project_ui.py +673 -441
- boris/qrc_boris.py +6 -3
- boris/qrc_boris5.py +6 -3
- boris/select_modifiers.py +62 -90
- boris/select_observations.py +19 -197
- boris/select_subj_behav.py +67 -39
- boris/state_events.py +51 -33
- boris/subjects_pad.py +7 -9
- boris/synthetic_time_budget.py +42 -26
- boris/time_budget_functions.py +169 -169
- boris/time_budget_widget.py +77 -89
- boris/transitions.py +41 -41
- boris/utilities.py +594 -226
- boris/version.py +3 -3
- boris/video_equalizer.py +16 -14
- boris/video_equalizer_ui.py +199 -130
- boris/video_operations.py +86 -28
- boris/view_df.py +104 -0
- boris/view_df_ui.py +75 -0
- boris/write_event.py +240 -136
- boris_behav_obs-9.7.12.dist-info/METADATA +139 -0
- boris_behav_obs-9.7.12.dist-info/RECORD +110 -0
- {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.12.dist-info}/WHEEL +1 -1
- boris_behav_obs-9.7.12.dist-info/entry_points.txt +2 -0
- boris/README.TXT +0 -22
- boris/add_modifier.ui +0 -323
- boris/converters.ui +0 -289
- boris/core.qrc +0 -37
- boris/core.ui +0 -1571
- boris/edit_event.ui +0 -233
- boris/icons/logo_eye.ico +0 -0
- boris/map_creator.py +0 -982
- boris/observation.ui +0 -814
- boris/param_panel.ui +0 -379
- boris/preferences.ui +0 -537
- boris/project.ui +0 -1074
- boris/vlc_local.py +0 -90
- boris_behav_obs-8.16.5.dist-info/LICENSE.TXT +0 -674
- boris_behav_obs-8.16.5.dist-info/METADATA +0 -134
- boris_behav_obs-8.16.5.dist-info/RECORD +0 -107
- boris_behav_obs-8.16.5.dist-info/entry_points.txt +0 -2
- {boris → boris_behav_obs-9.7.12.dist-info/licenses}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.12.dist-info}/top_level.txt +0 -0
boris/preferences.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2025 Olivier Friard
|
|
5
5
|
|
|
6
6
|
This file is part of BORIS.
|
|
7
7
|
|
|
@@ -22,26 +22,30 @@ This file is part of BORIS.
|
|
|
22
22
|
|
|
23
23
|
import logging
|
|
24
24
|
import os
|
|
25
|
-
import
|
|
25
|
+
from pathlib import Path
|
|
26
26
|
import sys
|
|
27
|
-
|
|
28
27
|
from . import dialog
|
|
29
28
|
from . import gui_utilities
|
|
30
29
|
from . import menu_options
|
|
31
30
|
from . import config as cfg
|
|
32
31
|
from . import config_file
|
|
32
|
+
from . import plugins
|
|
33
33
|
|
|
34
34
|
from .preferences_ui import Ui_prefDialog
|
|
35
35
|
|
|
36
|
-
from
|
|
36
|
+
from PySide6.QtWidgets import QDialog, QFileDialog, QListWidgetItem, QMessageBox
|
|
37
|
+
from PySide6.QtCore import Qt
|
|
38
|
+
from PySide6.QtGui import QFont
|
|
37
39
|
|
|
38
40
|
|
|
39
41
|
class Preferences(QDialog, Ui_prefDialog):
|
|
40
42
|
def __init__(self, parent=None):
|
|
41
|
-
|
|
42
43
|
super().__init__()
|
|
43
44
|
self.setupUi(self)
|
|
44
45
|
|
|
46
|
+
# plugins
|
|
47
|
+
self.pb_browse_plugins_dir.clicked.connect(self.browse_plugins_dir)
|
|
48
|
+
|
|
45
49
|
self.pbBrowseFFmpegCacheDir.clicked.connect(self.browseFFmpegCacheDir)
|
|
46
50
|
|
|
47
51
|
self.pb_reset_behav_colors.clicked.connect(self.reset_behav_colors)
|
|
@@ -52,7 +56,40 @@ class Preferences(QDialog, Ui_prefDialog):
|
|
|
52
56
|
self.pbCancel.clicked.connect(self.reject)
|
|
53
57
|
|
|
54
58
|
self.flag_refresh = False
|
|
55
|
-
|
|
59
|
+
|
|
60
|
+
# Create a monospace QFont
|
|
61
|
+
monospace_font = QFont("Courier New") # or "Monospace", "Consolas", "Liberation Mono", etc.
|
|
62
|
+
monospace_font.setStyleHint(QFont.Monospace)
|
|
63
|
+
monospace_font.setPointSize(12)
|
|
64
|
+
self.pte_plugin_code.setFont(monospace_font)
|
|
65
|
+
|
|
66
|
+
def browse_plugins_dir(self):
|
|
67
|
+
"""
|
|
68
|
+
get the personal plugins directory
|
|
69
|
+
"""
|
|
70
|
+
directory = QFileDialog.getExistingDirectory(None, "Select the plugins directory", self.le_personal_plugins_dir.text())
|
|
71
|
+
if not directory:
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
self.le_personal_plugins_dir.setText(directory)
|
|
75
|
+
self.lw_personal_plugins.clear()
|
|
76
|
+
for file_ in Path(directory).glob("*.py"):
|
|
77
|
+
if file_.name.startswith("_"):
|
|
78
|
+
continue
|
|
79
|
+
plugin_name = plugins.get_plugin_name(file_)
|
|
80
|
+
if plugin_name is None:
|
|
81
|
+
continue
|
|
82
|
+
# check if personal plugin name is in BORIS plugins (case sensitive)
|
|
83
|
+
if plugin_name in [self.lv_all_plugins.item(i).text() for i in range(self.lv_all_plugins.count())]:
|
|
84
|
+
continue
|
|
85
|
+
item = QListWidgetItem(plugin_name)
|
|
86
|
+
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
|
87
|
+
item.setCheckState(Qt.Checked)
|
|
88
|
+
item.setData(100, str(file_))
|
|
89
|
+
self.lw_personal_plugins.addItem(item)
|
|
90
|
+
|
|
91
|
+
if self.lw_personal_plugins.count() == 0:
|
|
92
|
+
QMessageBox.warning(self, cfg.programName, f"No plugin found in {directory}")
|
|
56
93
|
|
|
57
94
|
def refresh_preferences(self):
|
|
58
95
|
"""
|
|
@@ -61,7 +98,7 @@ class Preferences(QDialog, Ui_prefDialog):
|
|
|
61
98
|
if (
|
|
62
99
|
dialog.MessageDialog(
|
|
63
100
|
"BORIS",
|
|
64
|
-
("Refresh will re-initialize
|
|
101
|
+
("Refresh will re-initialize all your preferences and close BORIS"),
|
|
65
102
|
[cfg.CANCEL, "Refresh preferences"],
|
|
66
103
|
)
|
|
67
104
|
== "Refresh preferences"
|
|
@@ -73,11 +110,11 @@ class Preferences(QDialog, Ui_prefDialog):
|
|
|
73
110
|
"""
|
|
74
111
|
allow user select a cache dir for ffmpeg images
|
|
75
112
|
"""
|
|
76
|
-
FFmpegCacheDir = QFileDialog
|
|
113
|
+
FFmpegCacheDir = QFileDialog.getExistingDirectory(
|
|
77
114
|
self,
|
|
78
115
|
"Select a directory",
|
|
79
116
|
os.path.expanduser("~"),
|
|
80
|
-
options=QFileDialog
|
|
117
|
+
options=QFileDialog.ShowDirsOnly,
|
|
81
118
|
)
|
|
82
119
|
if FFmpegCacheDir:
|
|
83
120
|
self.leFFmpegCacheDir.setText(FFmpegCacheDir)
|
|
@@ -104,6 +141,63 @@ def preferences(self):
|
|
|
104
141
|
show preferences window
|
|
105
142
|
"""
|
|
106
143
|
|
|
144
|
+
def show_plugin_info(item):
|
|
145
|
+
"""
|
|
146
|
+
display information about the clicked plugin
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
if item.text() not in self.config_param[cfg.ANALYSIS_PLUGINS]:
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
plugin_path = item.data(100)
|
|
153
|
+
|
|
154
|
+
# Python plugins
|
|
155
|
+
if Path(plugin_path).suffix == ".py":
|
|
156
|
+
import importlib
|
|
157
|
+
|
|
158
|
+
module_name = Path(plugin_path).stem
|
|
159
|
+
spec = importlib.util.spec_from_file_location(module_name, plugin_path)
|
|
160
|
+
plugin_module = importlib.util.module_from_spec(spec)
|
|
161
|
+
spec.loader.exec_module(plugin_module)
|
|
162
|
+
attributes_list = dir(plugin_module)
|
|
163
|
+
|
|
164
|
+
out: list = []
|
|
165
|
+
out.append((plugin_module.__plugin_name__ + "\n") if "__plugin_name__" in attributes_list else "No plugin name provided")
|
|
166
|
+
out.append(plugin_module.__author__ if "__author__" in attributes_list else "No author provided")
|
|
167
|
+
version_str: str = ""
|
|
168
|
+
if "__version__" in attributes_list:
|
|
169
|
+
version_str += str(plugin_module.__version__)
|
|
170
|
+
if "__version_date__" in attributes_list:
|
|
171
|
+
version_str += " " if version_str else ""
|
|
172
|
+
version_str += f"({plugin_module.__version_date__})"
|
|
173
|
+
|
|
174
|
+
out.append(f"Version: {version_str}\n" if version_str else "No version provided")
|
|
175
|
+
|
|
176
|
+
# out.append(plugin_module.run.__doc__.strip())
|
|
177
|
+
# description
|
|
178
|
+
if "__description__" in attributes_list:
|
|
179
|
+
out.append("Description:\n")
|
|
180
|
+
out.append(plugin_module.__description__ if "__description__" in attributes_list else "No description provided")
|
|
181
|
+
|
|
182
|
+
preferencesWindow.pte_plugin_description.setPlainText("\n".join(out))
|
|
183
|
+
|
|
184
|
+
# R plugins
|
|
185
|
+
if Path(plugin_path).suffix == ".R":
|
|
186
|
+
plugin_description = plugins.get_r_plugin_description(plugin_path)
|
|
187
|
+
if plugin_description is not None:
|
|
188
|
+
preferencesWindow.pte_plugin_description.setPlainText("\n".join(plugin_description.split("\\n")))
|
|
189
|
+
else:
|
|
190
|
+
preferencesWindow.pte_plugin_description.setPlainText("No description provided")
|
|
191
|
+
|
|
192
|
+
# display plugin code
|
|
193
|
+
try:
|
|
194
|
+
with open(plugin_path, "r") as f_in:
|
|
195
|
+
plugin_code = f_in.read()
|
|
196
|
+
except Exception:
|
|
197
|
+
plugin_code = "Not available"
|
|
198
|
+
|
|
199
|
+
preferencesWindow.pte_plugin_code.setPlainText(plugin_code)
|
|
200
|
+
|
|
107
201
|
preferencesWindow = Preferences()
|
|
108
202
|
preferencesWindow.tabWidget.setCurrentIndex(0)
|
|
109
203
|
|
|
@@ -114,9 +208,7 @@ def preferences(self):
|
|
|
114
208
|
preferencesWindow.cbTimeFormat.setCurrentIndex(1)
|
|
115
209
|
|
|
116
210
|
preferencesWindow.sbffSpeed.setValue(self.fast)
|
|
117
|
-
preferencesWindow.cb_adapt_fast_jump.setChecked(
|
|
118
|
-
self.config_param.get(cfg.ADAPT_FAST_JUMP, False)
|
|
119
|
-
)
|
|
211
|
+
preferencesWindow.cb_adapt_fast_jump.setChecked(self.config_param.get(cfg.ADAPT_FAST_JUMP, False))
|
|
120
212
|
preferencesWindow.sbRepositionTimeOffset.setValue(self.repositioningTimeOffset)
|
|
121
213
|
preferencesWindow.sbSpeedStep.setValue(self.play_rate_step)
|
|
122
214
|
# automatic backup
|
|
@@ -129,18 +221,17 @@ def preferences(self):
|
|
|
129
221
|
preferencesWindow.cbConfirmSound.setChecked(self.confirmSound)
|
|
130
222
|
# beep every
|
|
131
223
|
preferencesWindow.sbBeepEvery.setValue(self.beep_every)
|
|
224
|
+
# frame step size
|
|
225
|
+
# preferencesWindow.sb_frame_step_size.setValue(self.config_param.get(cfg.FRAME_STEP_SIZE, cfg.FRAME_STEP_SIZE_DEFAULT_VALUE))
|
|
226
|
+
|
|
132
227
|
# alert no focal subject
|
|
133
228
|
preferencesWindow.cbAlertNoFocalSubject.setChecked(self.alertNoFocalSubject)
|
|
134
229
|
# tracking cursor above event
|
|
135
|
-
preferencesWindow.cbTrackingCursorAboveEvent.setChecked(
|
|
136
|
-
self.trackingCursorAboveEvent
|
|
137
|
-
)
|
|
230
|
+
preferencesWindow.cbTrackingCursorAboveEvent.setChecked(self.trackingCursorAboveEvent)
|
|
138
231
|
# check for new version
|
|
139
232
|
preferencesWindow.cbCheckForNewVersion.setChecked(self.checkForNewVersion)
|
|
140
233
|
# display subtitles
|
|
141
|
-
preferencesWindow.cb_display_subtitles.setChecked(
|
|
142
|
-
self.config_param[cfg.DISPLAY_SUBTITLES]
|
|
143
|
-
)
|
|
234
|
+
preferencesWindow.cb_display_subtitles.setChecked(self.config_param.get(cfg.DISPLAY_SUBTITLES, False))
|
|
144
235
|
# pause before add event
|
|
145
236
|
preferencesWindow.cb_pause_before_addevent.setChecked(self.pause_before_addevent)
|
|
146
237
|
# MPV hwdec
|
|
@@ -148,18 +239,77 @@ def preferences(self):
|
|
|
148
239
|
preferencesWindow.cb_hwdec.addItems(cfg.MPV_HWDEC_OPTIONS)
|
|
149
240
|
try:
|
|
150
241
|
preferencesWindow.cb_hwdec.setCurrentIndex(
|
|
151
|
-
cfg.MPV_HWDEC_OPTIONS.index(
|
|
152
|
-
self.config_param.get(cfg.MPV_HWDEC, cfg.MPV_HWDEC_DEFAULT_VALUE)
|
|
153
|
-
)
|
|
242
|
+
cfg.MPV_HWDEC_OPTIONS.index(self.config_param.get(cfg.MPV_HWDEC, cfg.MPV_HWDEC_DEFAULT_VALUE))
|
|
154
243
|
)
|
|
155
244
|
except Exception:
|
|
156
|
-
preferencesWindow.cb_hwdec.setCurrentIndex(cfg.MPV_HWDEC_DEFAULT_VALUE)
|
|
245
|
+
preferencesWindow.cb_hwdec.setCurrentIndex(cfg.MPV_HWDEC_OPTIONS.index(cfg.MPV_HWDEC_DEFAULT_VALUE))
|
|
246
|
+
# check integrity
|
|
247
|
+
preferencesWindow.cb_check_integrity_at_opening.setChecked(self.config_param.get(cfg.CHECK_PROJECT_INTEGRITY, True))
|
|
248
|
+
|
|
249
|
+
# BORIS plugins
|
|
250
|
+
preferencesWindow.lv_all_plugins.itemClicked.connect(show_plugin_info)
|
|
251
|
+
|
|
252
|
+
preferencesWindow.lv_all_plugins.clear()
|
|
253
|
+
|
|
254
|
+
for file_ in (Path(__file__).parent / "analysis_plugins").glob("*.py"):
|
|
255
|
+
if file_.name.startswith("_"):
|
|
256
|
+
continue
|
|
257
|
+
plugin_name = plugins.get_plugin_name(file_)
|
|
258
|
+
if plugin_name is not None:
|
|
259
|
+
item = QListWidgetItem(plugin_name)
|
|
260
|
+
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
|
261
|
+
if plugin_name in self.config_param.get(cfg.EXCLUDED_PLUGINS, set()):
|
|
262
|
+
item.setCheckState(Qt.Unchecked)
|
|
263
|
+
else:
|
|
264
|
+
item.setCheckState(Qt.Checked)
|
|
265
|
+
item.setData(100, str(file_))
|
|
266
|
+
preferencesWindow.lv_all_plugins.addItem(item)
|
|
267
|
+
|
|
268
|
+
# personal plugins
|
|
269
|
+
preferencesWindow.le_personal_plugins_dir.setText(self.config_param.get(cfg.PERSONAL_PLUGINS_DIR, ""))
|
|
270
|
+
preferencesWindow.lw_personal_plugins.itemClicked.connect(show_plugin_info)
|
|
271
|
+
|
|
272
|
+
preferencesWindow.lw_personal_plugins.clear()
|
|
273
|
+
if self.config_param.get(cfg.PERSONAL_PLUGINS_DIR, ""):
|
|
274
|
+
# Python plugins
|
|
275
|
+
for file_ in Path(self.config_param[cfg.PERSONAL_PLUGINS_DIR]).glob("*.py"):
|
|
276
|
+
if file_.name.startswith("_"):
|
|
277
|
+
continue
|
|
278
|
+
plugin_name = plugins.get_plugin_name(file_)
|
|
279
|
+
if plugin_name is None:
|
|
280
|
+
continue
|
|
281
|
+
# check if personal plugin name is in BORIS plugins (case sensitive)
|
|
282
|
+
if plugin_name in [preferencesWindow.lv_all_plugins.item(i).text() for i in range(preferencesWindow.lv_all_plugins.count())]:
|
|
283
|
+
continue
|
|
284
|
+
item = QListWidgetItem(plugin_name)
|
|
285
|
+
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
|
286
|
+
if plugin_name in self.config_param.get(cfg.EXCLUDED_PLUGINS, set()):
|
|
287
|
+
item.setCheckState(Qt.Unchecked)
|
|
288
|
+
else:
|
|
289
|
+
item.setCheckState(Qt.Checked)
|
|
290
|
+
item.setData(100, str(file_))
|
|
291
|
+
preferencesWindow.lw_personal_plugins.addItem(item)
|
|
292
|
+
|
|
293
|
+
# R plugins
|
|
294
|
+
for file_ in Path(self.config_param[cfg.PERSONAL_PLUGINS_DIR]).glob("*.R"):
|
|
295
|
+
plugin_name = plugins.get_r_plugin_name(file_)
|
|
296
|
+
if plugin_name is None:
|
|
297
|
+
continue
|
|
298
|
+
# check if personal plugin name is in BORIS plugins (case sensitive)
|
|
299
|
+
if plugin_name in [preferencesWindow.lv_all_plugins.item(i).text() for i in range(preferencesWindow.lv_all_plugins.count())]:
|
|
300
|
+
continue
|
|
301
|
+
item = QListWidgetItem(plugin_name)
|
|
302
|
+
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
|
303
|
+
if plugin_name in self.config_param.get(cfg.EXCLUDED_PLUGINS, set()):
|
|
304
|
+
item.setCheckState(Qt.Unchecked)
|
|
305
|
+
else:
|
|
306
|
+
item.setCheckState(Qt.Checked)
|
|
307
|
+
item.setData(100, str(file_))
|
|
308
|
+
preferencesWindow.lw_personal_plugins.addItem(item)
|
|
157
309
|
|
|
158
310
|
# PROJET FILE INDENTATION
|
|
159
311
|
preferencesWindow.combo_project_file_indentation.clear()
|
|
160
|
-
preferencesWindow.combo_project_file_indentation.addItems(
|
|
161
|
-
cfg.PROJECT_FILE_INDENTATION_COMBO_OPTIONS
|
|
162
|
-
)
|
|
312
|
+
preferencesWindow.combo_project_file_indentation.addItems(cfg.PROJECT_FILE_INDENTATION_COMBO_OPTIONS)
|
|
163
313
|
try:
|
|
164
314
|
preferencesWindow.combo_project_file_indentation.setCurrentIndex(
|
|
165
315
|
cfg.PROJECT_FILE_INDENTATION_OPTIONS.index(
|
|
@@ -172,9 +322,7 @@ def preferences(self):
|
|
|
172
322
|
except Exception:
|
|
173
323
|
preferencesWindow.combo_project_file_indentation.setCurrentText(
|
|
174
324
|
cfg.PROJECT_FILE_INDENTATION_COMBO_OPTIONS[
|
|
175
|
-
cfg.PROJECT_FILE_INDENTATION_OPTIONS.index(
|
|
176
|
-
cfg.PROJECT_FILE_INDENTATION_DEFAULT_VALUE
|
|
177
|
-
)
|
|
325
|
+
cfg.PROJECT_FILE_INDENTATION_OPTIONS.index(cfg.PROJECT_FILE_INDENTATION_DEFAULT_VALUE)
|
|
178
326
|
]
|
|
179
327
|
)
|
|
180
328
|
|
|
@@ -186,29 +334,24 @@ def preferences(self):
|
|
|
186
334
|
preferencesWindow.cbSpectrogramColorMap.clear()
|
|
187
335
|
preferencesWindow.cbSpectrogramColorMap.addItems(cfg.SPECTROGRAM_COLOR_MAPS)
|
|
188
336
|
try:
|
|
189
|
-
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(
|
|
190
|
-
cfg.SPECTROGRAM_COLOR_MAPS.index(self.spectrogram_color_map)
|
|
191
|
-
)
|
|
337
|
+
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(cfg.SPECTROGRAM_COLOR_MAPS.index(self.spectrogram_color_map))
|
|
192
338
|
except Exception:
|
|
193
|
-
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(
|
|
194
|
-
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
try:
|
|
198
|
-
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(
|
|
199
|
-
cfg.SPECTROGRAM_COLOR_MAPS.index(self.spectrogram_color_map)
|
|
200
|
-
)
|
|
201
|
-
except Exception:
|
|
202
|
-
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(
|
|
203
|
-
cfg.SPECTROGRAM_COLOR_MAPS.index(cfg.SPECTROGRAM_DEFAULT_COLOR_MAP)
|
|
204
|
-
)
|
|
205
|
-
|
|
339
|
+
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(cfg.SPECTROGRAM_COLOR_MAPS.index(cfg.SPECTROGRAM_DEFAULT_COLOR_MAP))
|
|
340
|
+
# time interval
|
|
206
341
|
try:
|
|
207
342
|
preferencesWindow.sb_time_interval.setValue(self.spectrogram_time_interval)
|
|
208
343
|
except Exception:
|
|
209
|
-
preferencesWindow.sb_time_interval.setValue(
|
|
210
|
-
|
|
211
|
-
|
|
344
|
+
preferencesWindow.sb_time_interval.setValue(cfg.SPECTROGRAM_DEFAULT_TIME_INTERVAL)
|
|
345
|
+
# window type
|
|
346
|
+
preferencesWindow.cb_window_type.setCurrentText(self.config_param.get(cfg.SPECTROGRAM_WINDOW_TYPE, cfg.SPECTROGRAM_DEFAULT_WINDOW_TYPE))
|
|
347
|
+
# NFFT
|
|
348
|
+
preferencesWindow.cb_NFFT.setCurrentText(self.config_param.get(cfg.SPECTROGRAM_NFFT, cfg.SPECTROGRAM_DEFAULT_NFFT))
|
|
349
|
+
# noverlap
|
|
350
|
+
preferencesWindow.sb_noverlap.setValue(self.config_param.get(cfg.SPECTROGRAM_NOVERLAP, cfg.SPECTROGRAM_DEFAULT_NOVERLAP))
|
|
351
|
+
# vmin
|
|
352
|
+
preferencesWindow.sb_vmin.setValue(self.config_param.get(cfg.SPECTROGRAM_VMIN, cfg.SPECTROGRAM_DEFAULT_VMIN))
|
|
353
|
+
# vmax
|
|
354
|
+
preferencesWindow.sb_vmax.setValue(self.config_param.get(cfg.SPECTROGRAM_VMAX, cfg.SPECTROGRAM_DEFAULT_VMAX))
|
|
212
355
|
|
|
213
356
|
# behavior colors
|
|
214
357
|
if not self.plot_colors:
|
|
@@ -218,109 +361,150 @@ def preferences(self):
|
|
|
218
361
|
# category colors
|
|
219
362
|
if not self.behav_category_colors:
|
|
220
363
|
self.behav_category_colors = cfg.CATEGORY_COLORS_LIST
|
|
221
|
-
preferencesWindow.te_category_colors.setPlainText(
|
|
222
|
-
|
|
223
|
-
|
|
364
|
+
preferencesWindow.te_category_colors.setPlainText("\n".join(self.behav_category_colors))
|
|
365
|
+
|
|
366
|
+
# interface
|
|
367
|
+
preferencesWindow.sb_toolbar_icon_size.setValue(self.config_param.get(cfg.TOOLBAR_ICON_SIZE, cfg.DEFAULT_TOOLBAR_ICON_SIZE_VALUE))
|
|
224
368
|
|
|
225
369
|
gui_utilities.restore_geometry(preferencesWindow, "preferences", (700, 500))
|
|
226
370
|
|
|
227
|
-
|
|
371
|
+
while True:
|
|
372
|
+
if preferencesWindow.exec():
|
|
373
|
+
if preferencesWindow.sb_vmin.value() >= preferencesWindow.sb_vmax.value():
|
|
374
|
+
QMessageBox.warning(self, cfg.programName, "Spectrogram parameters: the vmin value must be lower than the vmax value.")
|
|
375
|
+
continue
|
|
228
376
|
|
|
229
|
-
|
|
377
|
+
if preferencesWindow.sb_noverlap.value() >= int(preferencesWindow.cb_NFFT.currentText()):
|
|
378
|
+
QMessageBox.warning(self, cfg.programName, "Spectrogram parameters: the noverlap value must be lower than the NFFT value.")
|
|
379
|
+
continue
|
|
230
380
|
|
|
231
|
-
|
|
232
|
-
# refresh preferences remove the config file
|
|
381
|
+
gui_utilities.save_geometry(preferencesWindow, "preferences")
|
|
233
382
|
|
|
234
|
-
|
|
383
|
+
if preferencesWindow.flag_refresh:
|
|
384
|
+
# refresh preferences remove the config file
|
|
235
385
|
|
|
236
|
-
|
|
237
|
-
self.close()
|
|
238
|
-
# check if refresh canceled for not saved project
|
|
239
|
-
if "refresh_preferences" in self.config_param:
|
|
240
|
-
if (pathlib.Path.home() / ".boris").exists():
|
|
241
|
-
os.remove(pathlib.Path.home() / ".boris")
|
|
242
|
-
sys.exit()
|
|
386
|
+
logging.debug("flag refresh ")
|
|
243
387
|
|
|
244
|
-
|
|
245
|
-
|
|
388
|
+
self.config_param["refresh_preferences"] = True
|
|
389
|
+
self.close()
|
|
390
|
+
# check if refresh canceled for not saved project
|
|
391
|
+
if "refresh_preferences" in self.config_param:
|
|
392
|
+
if (Path.home() / ".boris").exists():
|
|
393
|
+
os.remove(Path.home() / ".boris")
|
|
394
|
+
sys.exit()
|
|
246
395
|
|
|
247
|
-
|
|
248
|
-
|
|
396
|
+
if preferencesWindow.cbTimeFormat.currentIndex() == 0:
|
|
397
|
+
self.timeFormat = cfg.S
|
|
249
398
|
|
|
250
|
-
|
|
399
|
+
if preferencesWindow.cbTimeFormat.currentIndex() == 1:
|
|
400
|
+
self.timeFormat = cfg.HHMMSS
|
|
251
401
|
|
|
252
|
-
|
|
253
|
-
cfg.ADAPT_FAST_JUMP
|
|
254
|
-
] = preferencesWindow.cb_adapt_fast_jump.isChecked()
|
|
402
|
+
self.fast = preferencesWindow.sbffSpeed.value()
|
|
255
403
|
|
|
256
|
-
|
|
404
|
+
self.config_param[cfg.ADAPT_FAST_JUMP] = preferencesWindow.cb_adapt_fast_jump.isChecked()
|
|
257
405
|
|
|
258
|
-
|
|
406
|
+
self.repositioningTimeOffset = preferencesWindow.sbRepositionTimeOffset.value()
|
|
259
407
|
|
|
260
|
-
|
|
261
|
-
if self.automaticBackup:
|
|
262
|
-
self.automaticBackupTimer.start(self.automaticBackup * 60000)
|
|
263
|
-
else:
|
|
264
|
-
self.automaticBackupTimer.stop()
|
|
408
|
+
self.play_rate_step = preferencesWindow.sbSpeedStep.value()
|
|
265
409
|
|
|
266
|
-
|
|
410
|
+
self.automaticBackup = preferencesWindow.sbAutomaticBackup.value()
|
|
411
|
+
if self.automaticBackup:
|
|
412
|
+
self.automaticBackupTimer.start(self.automaticBackup * 60000)
|
|
413
|
+
else:
|
|
414
|
+
self.automaticBackupTimer.stop()
|
|
267
415
|
|
|
268
|
-
|
|
269
|
-
preferencesWindow.cbCloseSameEvent.isChecked()
|
|
270
|
-
)
|
|
416
|
+
self.behav_seq_separator = preferencesWindow.leSeparator.text()
|
|
271
417
|
|
|
272
|
-
|
|
418
|
+
self.close_the_same_current_event = preferencesWindow.cbCloseSameEvent.isChecked()
|
|
273
419
|
|
|
274
|
-
|
|
420
|
+
self.confirmSound = preferencesWindow.cbConfirmSound.isChecked()
|
|
275
421
|
|
|
276
|
-
|
|
422
|
+
self.beep_every = preferencesWindow.sbBeepEvery.value()
|
|
277
423
|
|
|
278
|
-
|
|
279
|
-
preferencesWindow.
|
|
280
|
-
)
|
|
424
|
+
# frame step size
|
|
425
|
+
# self.config_param[cfg.FRAME_STEP_SIZE] = preferencesWindow.sb_frame_step_size.value()
|
|
281
426
|
|
|
282
|
-
|
|
427
|
+
self.alertNoFocalSubject = preferencesWindow.cbAlertNoFocalSubject.isChecked()
|
|
283
428
|
|
|
284
|
-
|
|
285
|
-
cfg.DISPLAY_SUBTITLES
|
|
286
|
-
] = preferencesWindow.cb_display_subtitles.isChecked()
|
|
429
|
+
self.trackingCursorAboveEvent = preferencesWindow.cbTrackingCursorAboveEvent.isChecked()
|
|
287
430
|
|
|
288
|
-
|
|
289
|
-
preferencesWindow.cb_pause_before_addevent.isChecked()
|
|
290
|
-
)
|
|
431
|
+
self.checkForNewVersion = preferencesWindow.cbCheckForNewVersion.isChecked()
|
|
291
432
|
|
|
292
|
-
|
|
293
|
-
self.config_param[cfg.MPV_HWDEC] = cfg.MPV_HWDEC_OPTIONS[
|
|
294
|
-
preferencesWindow.cb_hwdec.currentIndex()
|
|
295
|
-
]
|
|
433
|
+
self.config_param[cfg.DISPLAY_SUBTITLES] = preferencesWindow.cb_display_subtitles.isChecked()
|
|
296
434
|
|
|
297
|
-
|
|
298
|
-
self.config_param[
|
|
299
|
-
cfg.PROJECT_FILE_INDENTATION
|
|
300
|
-
] = cfg.PROJECT_FILE_INDENTATION_OPTIONS[
|
|
301
|
-
preferencesWindow.combo_project_file_indentation.currentIndex()
|
|
302
|
-
]
|
|
435
|
+
self.pause_before_addevent = preferencesWindow.cb_pause_before_addevent.isChecked()
|
|
303
436
|
|
|
304
|
-
|
|
305
|
-
self.
|
|
306
|
-
self.display_statusbar_info(self.observationId)
|
|
437
|
+
# MPV hwdec
|
|
438
|
+
self.config_param[cfg.MPV_HWDEC] = cfg.MPV_HWDEC_OPTIONS[preferencesWindow.cb_hwdec.currentIndex()]
|
|
307
439
|
|
|
308
|
-
|
|
440
|
+
# check project integrity
|
|
441
|
+
self.config_param[cfg.CHECK_PROJECT_INTEGRITY] = preferencesWindow.cb_check_integrity_at_opening.isChecked()
|
|
309
442
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
443
|
+
# update BORIS analysis plugins
|
|
444
|
+
self.config_param[cfg.ANALYSIS_PLUGINS] = {}
|
|
445
|
+
self.config_param[cfg.EXCLUDED_PLUGINS] = set()
|
|
446
|
+
for i in range(preferencesWindow.lv_all_plugins.count()):
|
|
447
|
+
if preferencesWindow.lv_all_plugins.item(i).checkState() == Qt.Checked:
|
|
448
|
+
self.config_param[cfg.ANALYSIS_PLUGINS][preferencesWindow.lv_all_plugins.item(i).text()] = (
|
|
449
|
+
preferencesWindow.lv_all_plugins.item(i).data(100)
|
|
450
|
+
)
|
|
451
|
+
else:
|
|
452
|
+
self.config_param[cfg.EXCLUDED_PLUGINS].add(preferencesWindow.lv_all_plugins.item(i).text())
|
|
453
|
+
|
|
454
|
+
# update personal plugins
|
|
455
|
+
self.config_param[cfg.PERSONAL_PLUGINS_DIR] = preferencesWindow.le_personal_plugins_dir.text()
|
|
456
|
+
for i in range(preferencesWindow.lw_personal_plugins.count()):
|
|
457
|
+
if preferencesWindow.lw_personal_plugins.item(i).checkState() == Qt.Checked:
|
|
458
|
+
self.config_param[cfg.ANALYSIS_PLUGINS][preferencesWindow.lw_personal_plugins.item(i).text()] = (
|
|
459
|
+
preferencesWindow.lw_personal_plugins.item(i).data(100)
|
|
460
|
+
)
|
|
461
|
+
else:
|
|
462
|
+
self.config_param[cfg.EXCLUDED_PLUGINS].add(preferencesWindow.lw_personal_plugins.item(i).text())
|
|
323
463
|
|
|
324
|
-
|
|
464
|
+
plugins.load_plugins(self)
|
|
465
|
+
plugins.add_plugins_to_menu(self)
|
|
466
|
+
|
|
467
|
+
# project file indentation
|
|
468
|
+
self.config_param[cfg.PROJECT_FILE_INDENTATION] = cfg.PROJECT_FILE_INDENTATION_OPTIONS[
|
|
469
|
+
preferencesWindow.combo_project_file_indentation.currentIndex()
|
|
470
|
+
]
|
|
471
|
+
|
|
472
|
+
if self.observationId:
|
|
473
|
+
self.load_tw_events(self.observationId)
|
|
474
|
+
self.display_statusbar_info(self.observationId)
|
|
475
|
+
|
|
476
|
+
self.ffmpeg_cache_dir = preferencesWindow.leFFmpegCacheDir.text()
|
|
477
|
+
|
|
478
|
+
# spectrogram
|
|
479
|
+
self.spectrogram_color_map = preferencesWindow.cbSpectrogramColorMap.currentText()
|
|
480
|
+
self.spectrogram_time_interval = preferencesWindow.sb_time_interval.value()
|
|
481
|
+
# window type
|
|
482
|
+
self.config_param[cfg.SPECTROGRAM_WINDOW_TYPE] = preferencesWindow.cb_window_type.currentText()
|
|
483
|
+
# NFFT
|
|
484
|
+
self.config_param[cfg.SPECTROGRAM_NFFT] = preferencesWindow.cb_NFFT.currentText()
|
|
485
|
+
# noverlap
|
|
486
|
+
self.config_param[cfg.SPECTROGRAM_NOVERLAP] = preferencesWindow.sb_noverlap.value()
|
|
487
|
+
# vmin
|
|
488
|
+
self.config_param[cfg.SPECTROGRAM_VMIN] = preferencesWindow.sb_vmin.value()
|
|
489
|
+
# vmax
|
|
490
|
+
self.config_param[cfg.SPECTROGRAM_VMAX] = preferencesWindow.sb_vmax.value()
|
|
491
|
+
|
|
492
|
+
# behav colors
|
|
493
|
+
self.plot_colors = preferencesWindow.te_behav_colors.toPlainText().split()
|
|
494
|
+
# category colors
|
|
495
|
+
self.behav_category_colors = preferencesWindow.te_category_colors.toPlainText().split()
|
|
496
|
+
|
|
497
|
+
# interface
|
|
498
|
+
self.config_param[cfg.TOOLBAR_ICON_SIZE] = preferencesWindow.sb_toolbar_icon_size.value()
|
|
499
|
+
|
|
500
|
+
menu_options.update_menu(self)
|
|
501
|
+
|
|
502
|
+
config_file.save(self)
|
|
503
|
+
|
|
504
|
+
break
|
|
505
|
+
|
|
506
|
+
else:
|
|
507
|
+
break
|
|
325
508
|
|
|
326
|
-
|
|
509
|
+
# activate main window
|
|
510
|
+
self.activateWindow()
|