boris-behav-obs 8.12__py3-none-any.whl → 9.7.6__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 boris-behav-obs might be problematic. Click here for more details.
- boris/__init__.py +1 -1
- boris/__main__.py +1 -1
- boris/about.py +28 -39
- boris/add_modifier.py +122 -109
- boris/add_modifier_ui.py +239 -135
- boris/advanced_event_filtering.py +81 -45
- boris/analysis_plugins/__init__.py +0 -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 +228 -229
- 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 +42 -49
- boris/config.py +141 -65
- boris/config_file.py +58 -67
- boris/connections.py +107 -61
- boris/converters.py +13 -37
- boris/converters_ui.py +187 -110
- boris/cooccurence.py +250 -0
- boris/core.py +2373 -1786
- boris/core_qrc.py +15895 -10743
- boris/core_ui.py +943 -798
- boris/db_functions.py +17 -42
- boris/dev.py +109 -8
- boris/dialog.py +482 -236
- boris/duration_widget.py +9 -14
- boris/edit_event.py +61 -31
- boris/edit_event_ui.py +208 -97
- boris/event_operations.py +408 -293
- boris/events_cursor.py +25 -17
- boris/events_snapshots.py +36 -82
- boris/exclusion_matrix.py +4 -9
- boris/export_events.py +184 -223
- boris/export_observation.py +74 -100
- boris/external_processes.py +123 -98
- boris/geometric_measurement.py +644 -290
- 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 +17 -6
- boris/modifier_coding_map_creator.py +1013 -0
- boris/modifiers_coding_map.py +7 -9
- boris/mpv.py +1 -0
- boris/mpv2.py +732 -705
- boris/observation.py +533 -221
- boris/observation_operations.py +1025 -390
- boris/observation_ui.py +572 -362
- boris/observations_list.py +71 -53
- boris/otx_parser.py +74 -68
- boris/param_panel.py +31 -16
- boris/param_panel_ui.py +254 -138
- boris/player_dock_widget.py +90 -60
- boris/plot_data_module.py +25 -33
- boris/plot_events.py +127 -90
- boris/plot_events_rt.py +17 -31
- boris/plot_spectrogram_rt.py +95 -30
- boris/plot_waveform_rt.py +32 -21
- boris/plugins.py +431 -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 +306 -83
- boris/preferences_ui.py +684 -227
- boris/project.py +448 -293
- boris/project_functions.py +671 -238
- boris/project_import_export.py +213 -222
- boris/project_ui.py +674 -438
- boris/qrc_boris.py +6 -3
- boris/qrc_boris5.py +6 -3
- boris/select_modifiers.py +74 -48
- boris/select_observations.py +20 -198
- boris/select_subj_behav.py +67 -39
- boris/state_events.py +52 -35
- boris/subjects_pad.py +6 -9
- boris/synthetic_time_budget.py +45 -28
- boris/time_budget_functions.py +171 -171
- boris/time_budget_widget.py +84 -114
- boris/transitions.py +41 -47
- boris/utilities.py +627 -236
- boris/version.py +3 -3
- boris/video_equalizer.py +16 -14
- boris/video_equalizer_ui.py +199 -130
- boris/video_operations.py +95 -29
- boris/view_df.py +104 -0
- boris/view_df_ui.py +75 -0
- boris/write_event.py +538 -0
- boris_behav_obs-9.7.6.dist-info/METADATA +139 -0
- boris_behav_obs-9.7.6.dist-info/RECORD +109 -0
- {boris_behav_obs-8.12.dist-info → boris_behav_obs-9.7.6.dist-info}/WHEEL +1 -1
- boris_behav_obs-9.7.6.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 -36
- boris/core.ui +0 -1556
- boris/edit_event.ui +0 -233
- boris/icons/logo_eye.ico +0 -0
- boris/map_creator.py +0 -850
- boris/observation.ui +0 -814
- boris/param_panel.ui +0 -379
- boris/preferences.ui +0 -537
- boris/project.ui +0 -1069
- boris/project_server.py +0 -236
- boris/vlc.py +0 -10343
- boris/vlc_local.py +0 -90
- boris_behav_obs-8.12.dist-info/LICENSE.TXT +0 -674
- boris_behav_obs-8.12.dist-info/METADATA +0 -128
- boris_behav_obs-8.12.dist-info/RECORD +0 -108
- boris_behav_obs-8.12.dist-info/entry_points.txt +0 -3
- {boris → boris_behav_obs-9.7.6.dist-info/licenses}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.12.dist-info → boris_behav_obs-9.7.6.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,27 +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
|
-
from . import dialog
|
|
32
30
|
from . import config as cfg
|
|
33
31
|
from . import config_file
|
|
32
|
+
from . import plugins
|
|
34
33
|
|
|
35
34
|
from .preferences_ui import Ui_prefDialog
|
|
36
35
|
|
|
37
|
-
from
|
|
36
|
+
from PySide6.QtWidgets import QDialog, QFileDialog, QListWidgetItem, QMessageBox
|
|
37
|
+
from PySide6.QtCore import Qt
|
|
38
|
+
from PySide6.QtGui import QFont
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
class Preferences(QDialog, Ui_prefDialog):
|
|
41
42
|
def __init__(self, parent=None):
|
|
42
|
-
|
|
43
43
|
super().__init__()
|
|
44
44
|
self.setupUi(self)
|
|
45
45
|
|
|
46
|
+
# plugins
|
|
47
|
+
self.pb_browse_plugins_dir.clicked.connect(self.browse_plugins_dir)
|
|
48
|
+
|
|
46
49
|
self.pbBrowseFFmpegCacheDir.clicked.connect(self.browseFFmpegCacheDir)
|
|
47
50
|
|
|
48
51
|
self.pb_reset_behav_colors.clicked.connect(self.reset_behav_colors)
|
|
@@ -53,7 +56,40 @@ class Preferences(QDialog, Ui_prefDialog):
|
|
|
53
56
|
self.pbCancel.clicked.connect(self.reject)
|
|
54
57
|
|
|
55
58
|
self.flag_refresh = False
|
|
56
|
-
|
|
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}")
|
|
57
93
|
|
|
58
94
|
def refresh_preferences(self):
|
|
59
95
|
"""
|
|
@@ -62,7 +98,7 @@ class Preferences(QDialog, Ui_prefDialog):
|
|
|
62
98
|
if (
|
|
63
99
|
dialog.MessageDialog(
|
|
64
100
|
"BORIS",
|
|
65
|
-
("Refresh will re-initialize
|
|
101
|
+
("Refresh will re-initialize all your preferences and close BORIS"),
|
|
66
102
|
[cfg.CANCEL, "Refresh preferences"],
|
|
67
103
|
)
|
|
68
104
|
== "Refresh preferences"
|
|
@@ -74,8 +110,11 @@ class Preferences(QDialog, Ui_prefDialog):
|
|
|
74
110
|
"""
|
|
75
111
|
allow user select a cache dir for ffmpeg images
|
|
76
112
|
"""
|
|
77
|
-
FFmpegCacheDir = QFileDialog
|
|
78
|
-
self,
|
|
113
|
+
FFmpegCacheDir = QFileDialog.getExistingDirectory(
|
|
114
|
+
self,
|
|
115
|
+
"Select a directory",
|
|
116
|
+
os.path.expanduser("~"),
|
|
117
|
+
options=QFileDialog.ShowDirsOnly,
|
|
79
118
|
)
|
|
80
119
|
if FFmpegCacheDir:
|
|
81
120
|
self.leFFmpegCacheDir.setText(FFmpegCacheDir)
|
|
@@ -102,6 +141,63 @@ def preferences(self):
|
|
|
102
141
|
show preferences window
|
|
103
142
|
"""
|
|
104
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
|
+
|
|
105
201
|
preferencesWindow = Preferences()
|
|
106
202
|
preferencesWindow.tabWidget.setCurrentIndex(0)
|
|
107
203
|
|
|
@@ -125,6 +221,9 @@ def preferences(self):
|
|
|
125
221
|
preferencesWindow.cbConfirmSound.setChecked(self.confirmSound)
|
|
126
222
|
# beep every
|
|
127
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
|
+
|
|
128
227
|
# alert no focal subject
|
|
129
228
|
preferencesWindow.cbAlertNoFocalSubject.setChecked(self.alertNoFocalSubject)
|
|
130
229
|
# tracking cursor above event
|
|
@@ -132,7 +231,7 @@ def preferences(self):
|
|
|
132
231
|
# check for new version
|
|
133
232
|
preferencesWindow.cbCheckForNewVersion.setChecked(self.checkForNewVersion)
|
|
134
233
|
# display subtitles
|
|
135
|
-
preferencesWindow.cb_display_subtitles.setChecked(self.config_param
|
|
234
|
+
preferencesWindow.cb_display_subtitles.setChecked(self.config_param.get(cfg.DISPLAY_SUBTITLES, False))
|
|
136
235
|
# pause before add event
|
|
137
236
|
preferencesWindow.cb_pause_before_addevent.setChecked(self.pause_before_addevent)
|
|
138
237
|
# MPV hwdec
|
|
@@ -143,7 +242,70 @@ def preferences(self):
|
|
|
143
242
|
cfg.MPV_HWDEC_OPTIONS.index(self.config_param.get(cfg.MPV_HWDEC, cfg.MPV_HWDEC_DEFAULT_VALUE))
|
|
144
243
|
)
|
|
145
244
|
except Exception:
|
|
146
|
-
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)
|
|
147
309
|
|
|
148
310
|
# PROJET FILE INDENTATION
|
|
149
311
|
preferencesWindow.combo_project_file_indentation.clear()
|
|
@@ -151,7 +313,10 @@ def preferences(self):
|
|
|
151
313
|
try:
|
|
152
314
|
preferencesWindow.combo_project_file_indentation.setCurrentIndex(
|
|
153
315
|
cfg.PROJECT_FILE_INDENTATION_OPTIONS.index(
|
|
154
|
-
self.config_param.get(
|
|
316
|
+
self.config_param.get(
|
|
317
|
+
cfg.PROJECT_FILE_INDENTATION,
|
|
318
|
+
cfg.PROJECT_FILE_INDENTATION_DEFAULT_VALUE,
|
|
319
|
+
)
|
|
155
320
|
)
|
|
156
321
|
)
|
|
157
322
|
except Exception:
|
|
@@ -169,27 +334,24 @@ def preferences(self):
|
|
|
169
334
|
preferencesWindow.cbSpectrogramColorMap.clear()
|
|
170
335
|
preferencesWindow.cbSpectrogramColorMap.addItems(cfg.SPECTROGRAM_COLOR_MAPS)
|
|
171
336
|
try:
|
|
172
|
-
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(
|
|
173
|
-
cfg.SPECTROGRAM_COLOR_MAPS.index(self.spectrogram_color_map)
|
|
174
|
-
)
|
|
337
|
+
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(cfg.SPECTROGRAM_COLOR_MAPS.index(self.spectrogram_color_map))
|
|
175
338
|
except Exception:
|
|
176
|
-
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(
|
|
177
|
-
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
try:
|
|
181
|
-
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(
|
|
182
|
-
cfg.SPECTROGRAM_COLOR_MAPS.index(self.spectrogram_color_map)
|
|
183
|
-
)
|
|
184
|
-
except Exception:
|
|
185
|
-
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(
|
|
186
|
-
cfg.SPECTROGRAM_COLOR_MAPS.index(cfg.SPECTROGRAM_DEFAULT_COLOR_MAP)
|
|
187
|
-
)
|
|
188
|
-
|
|
339
|
+
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(cfg.SPECTROGRAM_COLOR_MAPS.index(cfg.SPECTROGRAM_DEFAULT_COLOR_MAP))
|
|
340
|
+
# time interval
|
|
189
341
|
try:
|
|
190
342
|
preferencesWindow.sb_time_interval.setValue(self.spectrogram_time_interval)
|
|
191
343
|
except Exception:
|
|
192
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))
|
|
193
355
|
|
|
194
356
|
# behavior colors
|
|
195
357
|
if not self.plot_colors:
|
|
@@ -201,87 +363,148 @@ def preferences(self):
|
|
|
201
363
|
self.behav_category_colors = cfg.CATEGORY_COLORS_LIST
|
|
202
364
|
preferencesWindow.te_category_colors.setPlainText("\n".join(self.behav_category_colors))
|
|
203
365
|
|
|
366
|
+
# interface
|
|
367
|
+
preferencesWindow.sb_toolbar_icon_size.setValue(self.config_param.get(cfg.TOOLBAR_ICON_SIZE, cfg.DEFAULT_TOOLBAR_ICON_SIZE_VALUE))
|
|
368
|
+
|
|
204
369
|
gui_utilities.restore_geometry(preferencesWindow, "preferences", (700, 500))
|
|
205
370
|
|
|
206
|
-
|
|
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
|
|
207
376
|
|
|
208
|
-
|
|
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
|
|
209
380
|
|
|
210
|
-
|
|
211
|
-
# refresh preferences remove the config file
|
|
381
|
+
gui_utilities.save_geometry(preferencesWindow, "preferences")
|
|
212
382
|
|
|
213
|
-
|
|
383
|
+
if preferencesWindow.flag_refresh:
|
|
384
|
+
# refresh preferences remove the config file
|
|
214
385
|
|
|
215
|
-
|
|
216
|
-
self.close()
|
|
217
|
-
# check if refresh canceled for not saved project
|
|
218
|
-
if "refresh_preferences" in self.config_param:
|
|
219
|
-
if (pathlib.Path.home() / ".boris").exists():
|
|
220
|
-
os.remove(pathlib.Path.home() / ".boris")
|
|
221
|
-
sys.exit()
|
|
386
|
+
logging.debug("flag refresh ")
|
|
222
387
|
|
|
223
|
-
|
|
224
|
-
|
|
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()
|
|
225
395
|
|
|
226
|
-
|
|
227
|
-
|
|
396
|
+
if preferencesWindow.cbTimeFormat.currentIndex() == 0:
|
|
397
|
+
self.timeFormat = cfg.S
|
|
228
398
|
|
|
229
|
-
|
|
399
|
+
if preferencesWindow.cbTimeFormat.currentIndex() == 1:
|
|
400
|
+
self.timeFormat = cfg.HHMMSS
|
|
230
401
|
|
|
231
|
-
|
|
402
|
+
self.fast = preferencesWindow.sbffSpeed.value()
|
|
232
403
|
|
|
233
|
-
|
|
404
|
+
self.config_param[cfg.ADAPT_FAST_JUMP] = preferencesWindow.cb_adapt_fast_jump.isChecked()
|
|
234
405
|
|
|
235
|
-
|
|
406
|
+
self.repositioningTimeOffset = preferencesWindow.sbRepositionTimeOffset.value()
|
|
236
407
|
|
|
237
|
-
|
|
238
|
-
if self.automaticBackup:
|
|
239
|
-
self.automaticBackupTimer.start(self.automaticBackup * 60000)
|
|
240
|
-
else:
|
|
241
|
-
self.automaticBackupTimer.stop()
|
|
408
|
+
self.play_rate_step = preferencesWindow.sbSpeedStep.value()
|
|
242
409
|
|
|
243
|
-
|
|
410
|
+
self.automaticBackup = preferencesWindow.sbAutomaticBackup.value()
|
|
411
|
+
if self.automaticBackup:
|
|
412
|
+
self.automaticBackupTimer.start(self.automaticBackup * 60000)
|
|
413
|
+
else:
|
|
414
|
+
self.automaticBackupTimer.stop()
|
|
244
415
|
|
|
245
|
-
|
|
416
|
+
self.behav_seq_separator = preferencesWindow.leSeparator.text()
|
|
246
417
|
|
|
247
|
-
|
|
418
|
+
self.close_the_same_current_event = preferencesWindow.cbCloseSameEvent.isChecked()
|
|
248
419
|
|
|
249
|
-
|
|
420
|
+
self.confirmSound = preferencesWindow.cbConfirmSound.isChecked()
|
|
250
421
|
|
|
251
|
-
|
|
422
|
+
self.beep_every = preferencesWindow.sbBeepEvery.value()
|
|
252
423
|
|
|
253
|
-
|
|
424
|
+
# frame step size
|
|
425
|
+
# self.config_param[cfg.FRAME_STEP_SIZE] = preferencesWindow.sb_frame_step_size.value()
|
|
254
426
|
|
|
255
|
-
|
|
427
|
+
self.alertNoFocalSubject = preferencesWindow.cbAlertNoFocalSubject.isChecked()
|
|
256
428
|
|
|
257
|
-
|
|
429
|
+
self.trackingCursorAboveEvent = preferencesWindow.cbTrackingCursorAboveEvent.isChecked()
|
|
258
430
|
|
|
259
|
-
|
|
431
|
+
self.checkForNewVersion = preferencesWindow.cbCheckForNewVersion.isChecked()
|
|
260
432
|
|
|
261
|
-
|
|
262
|
-
self.config_param[cfg.MPV_HWDEC] = cfg.MPV_HWDEC_OPTIONS[preferencesWindow.cb_hwdec.currentIndex()]
|
|
433
|
+
self.config_param[cfg.DISPLAY_SUBTITLES] = preferencesWindow.cb_display_subtitles.isChecked()
|
|
263
434
|
|
|
264
|
-
|
|
265
|
-
self.config_param[cfg.PROJECT_FILE_INDENTATION] = cfg.PROJECT_FILE_INDENTATION_OPTIONS[
|
|
266
|
-
preferencesWindow.combo_project_file_indentation.currentIndex()
|
|
267
|
-
]
|
|
435
|
+
self.pause_before_addevent = preferencesWindow.cb_pause_before_addevent.isChecked()
|
|
268
436
|
|
|
269
|
-
|
|
270
|
-
self.
|
|
271
|
-
self.display_statusbar_info(self.observationId)
|
|
437
|
+
# MPV hwdec
|
|
438
|
+
self.config_param[cfg.MPV_HWDEC] = cfg.MPV_HWDEC_OPTIONS[preferencesWindow.cb_hwdec.currentIndex()]
|
|
272
439
|
|
|
273
|
-
|
|
440
|
+
# check project integrity
|
|
441
|
+
self.config_param[cfg.CHECK_PROJECT_INTEGRITY] = preferencesWindow.cb_check_integrity_at_opening.isChecked()
|
|
274
442
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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())
|
|
463
|
+
|
|
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
|
+
]
|
|
279
471
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
self.behav_category_colors = preferencesWindow.te_category_colors.toPlainText().split()
|
|
472
|
+
if self.observationId:
|
|
473
|
+
self.load_tw_events(self.observationId)
|
|
474
|
+
self.display_statusbar_info(self.observationId)
|
|
284
475
|
|
|
285
|
-
|
|
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
|
|
286
508
|
|
|
287
|
-
|
|
509
|
+
# activate main window
|
|
510
|
+
self.activateWindow()
|