boris-behav-obs 8.16.5__py3-none-any.whl → 9.7.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- boris/__init__.py +1 -1
- boris/__main__.py +1 -1
- boris/about.py +24 -36
- boris/add_modifier.py +88 -80
- boris/add_modifier_ui.py +235 -131
- boris/advanced_event_filtering.py +23 -29
- 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 +16 -34
- boris/config.py +102 -50
- boris/config_file.py +55 -64
- boris/connections.py +105 -58
- boris/converters.py +13 -37
- boris/converters_ui.py +187 -110
- boris/cooccurence.py +250 -0
- boris/core.py +2108 -1275
- 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 +304 -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 +493 -210
- boris/observation_operations.py +1010 -391
- 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 +18 -53
- boris/plot_events.py +56 -153
- boris/plot_events_rt.py +16 -30
- boris/plot_spectrogram_rt.py +80 -56
- boris/plot_waveform_rt.py +23 -48
- 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 +298 -123
- boris/preferences_ui.py +664 -225
- boris/project.py +293 -270
- boris/project_functions.py +610 -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 +6 -8
- 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 +562 -222
- boris/version.py +3 -3
- boris/video_equalizer.py +16 -14
- boris/video_equalizer_ui.py +199 -130
- boris/video_operations.py +78 -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.1.dist-info/METADATA +140 -0
- boris_behav_obs-9.7.1.dist-info/RECORD +109 -0
- {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.1.dist-info}/WHEEL +1 -1
- boris_behav_obs-9.7.1.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.1.dist-info/licenses}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.1.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
|
|
@@ -132,15 +224,11 @@ def preferences(self):
|
|
|
132
224
|
# alert no focal subject
|
|
133
225
|
preferencesWindow.cbAlertNoFocalSubject.setChecked(self.alertNoFocalSubject)
|
|
134
226
|
# tracking cursor above event
|
|
135
|
-
preferencesWindow.cbTrackingCursorAboveEvent.setChecked(
|
|
136
|
-
self.trackingCursorAboveEvent
|
|
137
|
-
)
|
|
227
|
+
preferencesWindow.cbTrackingCursorAboveEvent.setChecked(self.trackingCursorAboveEvent)
|
|
138
228
|
# check for new version
|
|
139
229
|
preferencesWindow.cbCheckForNewVersion.setChecked(self.checkForNewVersion)
|
|
140
230
|
# display subtitles
|
|
141
|
-
preferencesWindow.cb_display_subtitles.setChecked(
|
|
142
|
-
self.config_param[cfg.DISPLAY_SUBTITLES]
|
|
143
|
-
)
|
|
231
|
+
preferencesWindow.cb_display_subtitles.setChecked(self.config_param.get(cfg.DISPLAY_SUBTITLES, False))
|
|
144
232
|
# pause before add event
|
|
145
233
|
preferencesWindow.cb_pause_before_addevent.setChecked(self.pause_before_addevent)
|
|
146
234
|
# MPV hwdec
|
|
@@ -148,18 +236,77 @@ def preferences(self):
|
|
|
148
236
|
preferencesWindow.cb_hwdec.addItems(cfg.MPV_HWDEC_OPTIONS)
|
|
149
237
|
try:
|
|
150
238
|
preferencesWindow.cb_hwdec.setCurrentIndex(
|
|
151
|
-
cfg.MPV_HWDEC_OPTIONS.index(
|
|
152
|
-
self.config_param.get(cfg.MPV_HWDEC, cfg.MPV_HWDEC_DEFAULT_VALUE)
|
|
153
|
-
)
|
|
239
|
+
cfg.MPV_HWDEC_OPTIONS.index(self.config_param.get(cfg.MPV_HWDEC, cfg.MPV_HWDEC_DEFAULT_VALUE))
|
|
154
240
|
)
|
|
155
241
|
except Exception:
|
|
156
|
-
preferencesWindow.cb_hwdec.setCurrentIndex(cfg.MPV_HWDEC_DEFAULT_VALUE)
|
|
242
|
+
preferencesWindow.cb_hwdec.setCurrentIndex(cfg.MPV_HWDEC_OPTIONS.index(cfg.MPV_HWDEC_DEFAULT_VALUE))
|
|
243
|
+
# check integrity
|
|
244
|
+
preferencesWindow.cb_check_integrity_at_opening.setChecked(self.config_param.get(cfg.CHECK_PROJECT_INTEGRITY, True))
|
|
245
|
+
|
|
246
|
+
# BORIS plugins
|
|
247
|
+
preferencesWindow.lv_all_plugins.itemClicked.connect(show_plugin_info)
|
|
248
|
+
|
|
249
|
+
preferencesWindow.lv_all_plugins.clear()
|
|
250
|
+
|
|
251
|
+
for file_ in (Path(__file__).parent / "analysis_plugins").glob("*.py"):
|
|
252
|
+
if file_.name.startswith("_"):
|
|
253
|
+
continue
|
|
254
|
+
plugin_name = plugins.get_plugin_name(file_)
|
|
255
|
+
if plugin_name is not None:
|
|
256
|
+
item = QListWidgetItem(plugin_name)
|
|
257
|
+
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
|
258
|
+
if plugin_name in self.config_param.get(cfg.EXCLUDED_PLUGINS, set()):
|
|
259
|
+
item.setCheckState(Qt.Unchecked)
|
|
260
|
+
else:
|
|
261
|
+
item.setCheckState(Qt.Checked)
|
|
262
|
+
item.setData(100, str(file_))
|
|
263
|
+
preferencesWindow.lv_all_plugins.addItem(item)
|
|
264
|
+
|
|
265
|
+
# personal plugins
|
|
266
|
+
preferencesWindow.le_personal_plugins_dir.setText(self.config_param.get(cfg.PERSONAL_PLUGINS_DIR, ""))
|
|
267
|
+
preferencesWindow.lw_personal_plugins.itemClicked.connect(show_plugin_info)
|
|
268
|
+
|
|
269
|
+
preferencesWindow.lw_personal_plugins.clear()
|
|
270
|
+
if self.config_param.get(cfg.PERSONAL_PLUGINS_DIR, ""):
|
|
271
|
+
# Python plugins
|
|
272
|
+
for file_ in Path(self.config_param[cfg.PERSONAL_PLUGINS_DIR]).glob("*.py"):
|
|
273
|
+
if file_.name.startswith("_"):
|
|
274
|
+
continue
|
|
275
|
+
plugin_name = plugins.get_plugin_name(file_)
|
|
276
|
+
if plugin_name is None:
|
|
277
|
+
continue
|
|
278
|
+
# check if personal plugin name is in BORIS plugins (case sensitive)
|
|
279
|
+
if plugin_name in [preferencesWindow.lv_all_plugins.item(i).text() for i in range(preferencesWindow.lv_all_plugins.count())]:
|
|
280
|
+
continue
|
|
281
|
+
item = QListWidgetItem(plugin_name)
|
|
282
|
+
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
|
283
|
+
if plugin_name in self.config_param.get(cfg.EXCLUDED_PLUGINS, set()):
|
|
284
|
+
item.setCheckState(Qt.Unchecked)
|
|
285
|
+
else:
|
|
286
|
+
item.setCheckState(Qt.Checked)
|
|
287
|
+
item.setData(100, str(file_))
|
|
288
|
+
preferencesWindow.lw_personal_plugins.addItem(item)
|
|
289
|
+
|
|
290
|
+
# R plugins
|
|
291
|
+
for file_ in Path(self.config_param[cfg.PERSONAL_PLUGINS_DIR]).glob("*.R"):
|
|
292
|
+
plugin_name = plugins.get_r_plugin_name(file_)
|
|
293
|
+
if plugin_name is None:
|
|
294
|
+
continue
|
|
295
|
+
# check if personal plugin name is in BORIS plugins (case sensitive)
|
|
296
|
+
if plugin_name in [preferencesWindow.lv_all_plugins.item(i).text() for i in range(preferencesWindow.lv_all_plugins.count())]:
|
|
297
|
+
continue
|
|
298
|
+
item = QListWidgetItem(plugin_name)
|
|
299
|
+
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
|
300
|
+
if plugin_name in self.config_param.get(cfg.EXCLUDED_PLUGINS, set()):
|
|
301
|
+
item.setCheckState(Qt.Unchecked)
|
|
302
|
+
else:
|
|
303
|
+
item.setCheckState(Qt.Checked)
|
|
304
|
+
item.setData(100, str(file_))
|
|
305
|
+
preferencesWindow.lw_personal_plugins.addItem(item)
|
|
157
306
|
|
|
158
307
|
# PROJET FILE INDENTATION
|
|
159
308
|
preferencesWindow.combo_project_file_indentation.clear()
|
|
160
|
-
preferencesWindow.combo_project_file_indentation.addItems(
|
|
161
|
-
cfg.PROJECT_FILE_INDENTATION_COMBO_OPTIONS
|
|
162
|
-
)
|
|
309
|
+
preferencesWindow.combo_project_file_indentation.addItems(cfg.PROJECT_FILE_INDENTATION_COMBO_OPTIONS)
|
|
163
310
|
try:
|
|
164
311
|
preferencesWindow.combo_project_file_indentation.setCurrentIndex(
|
|
165
312
|
cfg.PROJECT_FILE_INDENTATION_OPTIONS.index(
|
|
@@ -172,9 +319,7 @@ def preferences(self):
|
|
|
172
319
|
except Exception:
|
|
173
320
|
preferencesWindow.combo_project_file_indentation.setCurrentText(
|
|
174
321
|
cfg.PROJECT_FILE_INDENTATION_COMBO_OPTIONS[
|
|
175
|
-
cfg.PROJECT_FILE_INDENTATION_OPTIONS.index(
|
|
176
|
-
cfg.PROJECT_FILE_INDENTATION_DEFAULT_VALUE
|
|
177
|
-
)
|
|
322
|
+
cfg.PROJECT_FILE_INDENTATION_OPTIONS.index(cfg.PROJECT_FILE_INDENTATION_DEFAULT_VALUE)
|
|
178
323
|
]
|
|
179
324
|
)
|
|
180
325
|
|
|
@@ -186,29 +331,24 @@ def preferences(self):
|
|
|
186
331
|
preferencesWindow.cbSpectrogramColorMap.clear()
|
|
187
332
|
preferencesWindow.cbSpectrogramColorMap.addItems(cfg.SPECTROGRAM_COLOR_MAPS)
|
|
188
333
|
try:
|
|
189
|
-
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(
|
|
190
|
-
cfg.SPECTROGRAM_COLOR_MAPS.index(self.spectrogram_color_map)
|
|
191
|
-
)
|
|
192
|
-
except Exception:
|
|
193
|
-
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(
|
|
194
|
-
cfg.SPECTROGRAM_COLOR_MAPS.index(cfg.SPECTROGRAM_DEFAULT_COLOR_MAP)
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
try:
|
|
198
|
-
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(
|
|
199
|
-
cfg.SPECTROGRAM_COLOR_MAPS.index(self.spectrogram_color_map)
|
|
200
|
-
)
|
|
334
|
+
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(cfg.SPECTROGRAM_COLOR_MAPS.index(self.spectrogram_color_map))
|
|
201
335
|
except Exception:
|
|
202
|
-
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(
|
|
203
|
-
|
|
204
|
-
)
|
|
205
|
-
|
|
336
|
+
preferencesWindow.cbSpectrogramColorMap.setCurrentIndex(cfg.SPECTROGRAM_COLOR_MAPS.index(cfg.SPECTROGRAM_DEFAULT_COLOR_MAP))
|
|
337
|
+
# time interval
|
|
206
338
|
try:
|
|
207
339
|
preferencesWindow.sb_time_interval.setValue(self.spectrogram_time_interval)
|
|
208
340
|
except Exception:
|
|
209
|
-
preferencesWindow.sb_time_interval.setValue(
|
|
210
|
-
|
|
211
|
-
|
|
341
|
+
preferencesWindow.sb_time_interval.setValue(cfg.SPECTROGRAM_DEFAULT_TIME_INTERVAL)
|
|
342
|
+
# window type
|
|
343
|
+
preferencesWindow.cb_window_type.setCurrentText(self.config_param.get(cfg.SPECTROGRAM_WINDOW_TYPE, cfg.SPECTROGRAM_DEFAULT_WINDOW_TYPE))
|
|
344
|
+
# NFFT
|
|
345
|
+
preferencesWindow.cb_NFFT.setCurrentText(self.config_param.get(cfg.SPECTROGRAM_NFFT, cfg.SPECTROGRAM_DEFAULT_NFFT))
|
|
346
|
+
# noverlap
|
|
347
|
+
preferencesWindow.sb_noverlap.setValue(self.config_param.get(cfg.SPECTROGRAM_NOVERLAP, cfg.SPECTROGRAM_DEFAULT_NOVERLAP))
|
|
348
|
+
# vmin
|
|
349
|
+
preferencesWindow.sb_vmin.setValue(self.config_param.get(cfg.SPECTROGRAM_VMIN, cfg.SPECTROGRAM_DEFAULT_VMIN))
|
|
350
|
+
# vmax
|
|
351
|
+
preferencesWindow.sb_vmax.setValue(self.config_param.get(cfg.SPECTROGRAM_VMAX, cfg.SPECTROGRAM_DEFAULT_VMAX))
|
|
212
352
|
|
|
213
353
|
# behavior colors
|
|
214
354
|
if not self.plot_colors:
|
|
@@ -218,109 +358,144 @@ def preferences(self):
|
|
|
218
358
|
# category colors
|
|
219
359
|
if not self.behav_category_colors:
|
|
220
360
|
self.behav_category_colors = cfg.CATEGORY_COLORS_LIST
|
|
221
|
-
preferencesWindow.te_category_colors.setPlainText(
|
|
222
|
-
|
|
223
|
-
|
|
361
|
+
preferencesWindow.te_category_colors.setPlainText("\n".join(self.behav_category_colors))
|
|
362
|
+
|
|
363
|
+
# interface
|
|
364
|
+
preferencesWindow.sb_toolbar_icon_size.setValue(self.config_param.get(cfg.TOOLBAR_ICON_SIZE, cfg.DEFAULT_TOOLBAR_ICON_SIZE_VALUE))
|
|
224
365
|
|
|
225
366
|
gui_utilities.restore_geometry(preferencesWindow, "preferences", (700, 500))
|
|
226
367
|
|
|
227
|
-
|
|
368
|
+
while True:
|
|
369
|
+
if preferencesWindow.exec():
|
|
370
|
+
if preferencesWindow.sb_vmin.value() >= preferencesWindow.sb_vmax.value():
|
|
371
|
+
QMessageBox.warning(self, cfg.programName, "Spectrogram parameters: the vmin value must be lower than the vmax value.")
|
|
372
|
+
continue
|
|
228
373
|
|
|
229
|
-
|
|
374
|
+
if preferencesWindow.sb_noverlap.value() >= int(preferencesWindow.cb_NFFT.currentText()):
|
|
375
|
+
QMessageBox.warning(self, cfg.programName, "Spectrogram parameters: the noverlap value must be lower than the NFFT value.")
|
|
376
|
+
continue
|
|
230
377
|
|
|
231
|
-
|
|
232
|
-
# refresh preferences remove the config file
|
|
378
|
+
gui_utilities.save_geometry(preferencesWindow, "preferences")
|
|
233
379
|
|
|
234
|
-
|
|
380
|
+
if preferencesWindow.flag_refresh:
|
|
381
|
+
# refresh preferences remove the config file
|
|
235
382
|
|
|
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()
|
|
383
|
+
logging.debug("flag refresh ")
|
|
243
384
|
|
|
244
|
-
|
|
245
|
-
|
|
385
|
+
self.config_param["refresh_preferences"] = True
|
|
386
|
+
self.close()
|
|
387
|
+
# check if refresh canceled for not saved project
|
|
388
|
+
if "refresh_preferences" in self.config_param:
|
|
389
|
+
if (Path.home() / ".boris").exists():
|
|
390
|
+
os.remove(Path.home() / ".boris")
|
|
391
|
+
sys.exit()
|
|
246
392
|
|
|
247
|
-
|
|
248
|
-
|
|
393
|
+
if preferencesWindow.cbTimeFormat.currentIndex() == 0:
|
|
394
|
+
self.timeFormat = cfg.S
|
|
249
395
|
|
|
250
|
-
|
|
396
|
+
if preferencesWindow.cbTimeFormat.currentIndex() == 1:
|
|
397
|
+
self.timeFormat = cfg.HHMMSS
|
|
251
398
|
|
|
252
|
-
|
|
253
|
-
cfg.ADAPT_FAST_JUMP
|
|
254
|
-
] = preferencesWindow.cb_adapt_fast_jump.isChecked()
|
|
399
|
+
self.fast = preferencesWindow.sbffSpeed.value()
|
|
255
400
|
|
|
256
|
-
|
|
401
|
+
self.config_param[cfg.ADAPT_FAST_JUMP] = preferencesWindow.cb_adapt_fast_jump.isChecked()
|
|
257
402
|
|
|
258
|
-
|
|
403
|
+
self.repositioningTimeOffset = preferencesWindow.sbRepositionTimeOffset.value()
|
|
259
404
|
|
|
260
|
-
|
|
261
|
-
if self.automaticBackup:
|
|
262
|
-
self.automaticBackupTimer.start(self.automaticBackup * 60000)
|
|
263
|
-
else:
|
|
264
|
-
self.automaticBackupTimer.stop()
|
|
405
|
+
self.play_rate_step = preferencesWindow.sbSpeedStep.value()
|
|
265
406
|
|
|
266
|
-
|
|
407
|
+
self.automaticBackup = preferencesWindow.sbAutomaticBackup.value()
|
|
408
|
+
if self.automaticBackup:
|
|
409
|
+
self.automaticBackupTimer.start(self.automaticBackup * 60000)
|
|
410
|
+
else:
|
|
411
|
+
self.automaticBackupTimer.stop()
|
|
267
412
|
|
|
268
|
-
|
|
269
|
-
preferencesWindow.cbCloseSameEvent.isChecked()
|
|
270
|
-
)
|
|
413
|
+
self.behav_seq_separator = preferencesWindow.leSeparator.text()
|
|
271
414
|
|
|
272
|
-
|
|
415
|
+
self.close_the_same_current_event = preferencesWindow.cbCloseSameEvent.isChecked()
|
|
273
416
|
|
|
274
|
-
|
|
417
|
+
self.confirmSound = preferencesWindow.cbConfirmSound.isChecked()
|
|
275
418
|
|
|
276
|
-
|
|
419
|
+
self.beep_every = preferencesWindow.sbBeepEvery.value()
|
|
277
420
|
|
|
278
|
-
|
|
279
|
-
preferencesWindow.cbTrackingCursorAboveEvent.isChecked()
|
|
280
|
-
)
|
|
421
|
+
self.alertNoFocalSubject = preferencesWindow.cbAlertNoFocalSubject.isChecked()
|
|
281
422
|
|
|
282
|
-
|
|
423
|
+
self.trackingCursorAboveEvent = preferencesWindow.cbTrackingCursorAboveEvent.isChecked()
|
|
283
424
|
|
|
284
|
-
|
|
285
|
-
cfg.DISPLAY_SUBTITLES
|
|
286
|
-
] = preferencesWindow.cb_display_subtitles.isChecked()
|
|
425
|
+
self.checkForNewVersion = preferencesWindow.cbCheckForNewVersion.isChecked()
|
|
287
426
|
|
|
288
|
-
|
|
289
|
-
preferencesWindow.cb_pause_before_addevent.isChecked()
|
|
290
|
-
)
|
|
427
|
+
self.config_param[cfg.DISPLAY_SUBTITLES] = preferencesWindow.cb_display_subtitles.isChecked()
|
|
291
428
|
|
|
292
|
-
|
|
293
|
-
self.config_param[cfg.MPV_HWDEC] = cfg.MPV_HWDEC_OPTIONS[
|
|
294
|
-
preferencesWindow.cb_hwdec.currentIndex()
|
|
295
|
-
]
|
|
429
|
+
self.pause_before_addevent = preferencesWindow.cb_pause_before_addevent.isChecked()
|
|
296
430
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
cfg.PROJECT_FILE_INDENTATION
|
|
300
|
-
] = cfg.PROJECT_FILE_INDENTATION_OPTIONS[
|
|
301
|
-
preferencesWindow.combo_project_file_indentation.currentIndex()
|
|
302
|
-
]
|
|
431
|
+
# MPV hwdec
|
|
432
|
+
self.config_param[cfg.MPV_HWDEC] = cfg.MPV_HWDEC_OPTIONS[preferencesWindow.cb_hwdec.currentIndex()]
|
|
303
433
|
|
|
304
|
-
|
|
305
|
-
self.
|
|
306
|
-
self.display_statusbar_info(self.observationId)
|
|
434
|
+
# check project integrity
|
|
435
|
+
self.config_param[cfg.CHECK_PROJECT_INTEGRITY] = preferencesWindow.cb_check_integrity_at_opening.isChecked()
|
|
307
436
|
|
|
308
|
-
|
|
437
|
+
# update BORIS analysis plugins
|
|
438
|
+
self.config_param[cfg.ANALYSIS_PLUGINS] = {}
|
|
439
|
+
self.config_param[cfg.EXCLUDED_PLUGINS] = set()
|
|
440
|
+
for i in range(preferencesWindow.lv_all_plugins.count()):
|
|
441
|
+
if preferencesWindow.lv_all_plugins.item(i).checkState() == Qt.Checked:
|
|
442
|
+
self.config_param[cfg.ANALYSIS_PLUGINS][preferencesWindow.lv_all_plugins.item(i).text()] = (
|
|
443
|
+
preferencesWindow.lv_all_plugins.item(i).data(100)
|
|
444
|
+
)
|
|
445
|
+
else:
|
|
446
|
+
self.config_param[cfg.EXCLUDED_PLUGINS].add(preferencesWindow.lv_all_plugins.item(i).text())
|
|
309
447
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
preferencesWindow.
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
)
|
|
448
|
+
# update personal plugins
|
|
449
|
+
self.config_param[cfg.PERSONAL_PLUGINS_DIR] = preferencesWindow.le_personal_plugins_dir.text()
|
|
450
|
+
for i in range(preferencesWindow.lw_personal_plugins.count()):
|
|
451
|
+
if preferencesWindow.lw_personal_plugins.item(i).checkState() == Qt.Checked:
|
|
452
|
+
self.config_param[cfg.ANALYSIS_PLUGINS][preferencesWindow.lw_personal_plugins.item(i).text()] = (
|
|
453
|
+
preferencesWindow.lw_personal_plugins.item(i).data(100)
|
|
454
|
+
)
|
|
455
|
+
else:
|
|
456
|
+
self.config_param[cfg.EXCLUDED_PLUGINS].add(preferencesWindow.lw_personal_plugins.item(i).text())
|
|
457
|
+
|
|
458
|
+
plugins.load_plugins(self)
|
|
459
|
+
plugins.add_plugins_to_menu(self)
|
|
323
460
|
|
|
324
|
-
|
|
461
|
+
# project file indentation
|
|
462
|
+
self.config_param[cfg.PROJECT_FILE_INDENTATION] = cfg.PROJECT_FILE_INDENTATION_OPTIONS[
|
|
463
|
+
preferencesWindow.combo_project_file_indentation.currentIndex()
|
|
464
|
+
]
|
|
465
|
+
|
|
466
|
+
if self.observationId:
|
|
467
|
+
self.load_tw_events(self.observationId)
|
|
468
|
+
self.display_statusbar_info(self.observationId)
|
|
469
|
+
|
|
470
|
+
self.ffmpeg_cache_dir = preferencesWindow.leFFmpegCacheDir.text()
|
|
471
|
+
|
|
472
|
+
# spectrogram
|
|
473
|
+
self.spectrogram_color_map = preferencesWindow.cbSpectrogramColorMap.currentText()
|
|
474
|
+
self.spectrogram_time_interval = preferencesWindow.sb_time_interval.value()
|
|
475
|
+
# window type
|
|
476
|
+
self.config_param[cfg.SPECTROGRAM_WINDOW_TYPE] = preferencesWindow.cb_window_type.currentText()
|
|
477
|
+
# NFFT
|
|
478
|
+
self.config_param[cfg.SPECTROGRAM_NFFT] = preferencesWindow.cb_NFFT.currentText()
|
|
479
|
+
# noverlap
|
|
480
|
+
self.config_param[cfg.SPECTROGRAM_NOVERLAP] = preferencesWindow.sb_noverlap.value()
|
|
481
|
+
# vmin
|
|
482
|
+
self.config_param[cfg.SPECTROGRAM_VMIN] = preferencesWindow.sb_vmin.value()
|
|
483
|
+
# vmax
|
|
484
|
+
self.config_param[cfg.SPECTROGRAM_VMAX] = preferencesWindow.sb_vmax.value()
|
|
485
|
+
|
|
486
|
+
# behav colors
|
|
487
|
+
self.plot_colors = preferencesWindow.te_behav_colors.toPlainText().split()
|
|
488
|
+
# category colors
|
|
489
|
+
self.behav_category_colors = preferencesWindow.te_category_colors.toPlainText().split()
|
|
325
490
|
|
|
326
|
-
|
|
491
|
+
# interface
|
|
492
|
+
self.config_param[cfg.TOOLBAR_ICON_SIZE] = preferencesWindow.sb_toolbar_icon_size.value()
|
|
493
|
+
|
|
494
|
+
menu_options.update_menu(self)
|
|
495
|
+
|
|
496
|
+
config_file.save(self)
|
|
497
|
+
|
|
498
|
+
break
|
|
499
|
+
|
|
500
|
+
else:
|
|
501
|
+
break
|