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/__init__.py
CHANGED
boris/__main__.py
CHANGED
boris/about.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 program is free software; you can redistribute it and/or modify
|
|
7
7
|
it under the terms of the GNU General Public License as published by
|
|
@@ -30,24 +30,9 @@ from . import version
|
|
|
30
30
|
from . import config as cfg
|
|
31
31
|
from . import utilities as util
|
|
32
32
|
|
|
33
|
-
try:
|
|
34
|
-
from . import mpv2 as mpv
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
try:
|
|
39
|
-
if "libmpv.so.1" in mpv.sofile:
|
|
40
|
-
from . import mpv as mpv
|
|
41
|
-
except AttributeError:
|
|
42
|
-
if "mpv-1.dll" in mpv.dll:
|
|
43
|
-
from . import mpv as mpv
|
|
44
|
-
|
|
45
|
-
except RuntimeError: # libmpv found but version too old
|
|
46
|
-
from . import mpv as mpv
|
|
47
|
-
|
|
48
|
-
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR
|
|
49
|
-
from PyQt5.QtGui import QPixmap
|
|
50
|
-
from PyQt5.QtWidgets import QMessageBox
|
|
34
|
+
from PySide6.QtGui import QPixmap
|
|
35
|
+
from PySide6.QtWidgets import QMessageBox
|
|
51
36
|
|
|
52
37
|
|
|
53
38
|
def actionAbout_activated(self):
|
|
@@ -55,15 +40,16 @@ def actionAbout_activated(self):
|
|
|
55
40
|
About dialog
|
|
56
41
|
"""
|
|
57
42
|
|
|
58
|
-
programs_versions = ["MPV media player"]
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
f"
|
|
43
|
+
programs_versions: list = ["MPV media player"]
|
|
44
|
+
|
|
45
|
+
mpv_lib_version, mpv_lib_file_path, mpv_api_version = util.mpv_lib_version()
|
|
46
|
+
programs_versions.append(
|
|
47
|
+
(
|
|
48
|
+
f"Library version: {mpv_lib_version} file: {mpv_lib_file_path}\n"
|
|
49
|
+
f"MPV API version: {mpv_api_version}\n"
|
|
50
|
+
f"python-mpv version: {util.python_mpv_script_version()}"
|
|
66
51
|
)
|
|
52
|
+
)
|
|
67
53
|
|
|
68
54
|
# ffmpeg
|
|
69
55
|
if self.ffmpeg_bin == "ffmpeg" and sys.platform.startswith("linux"):
|
|
@@ -91,9 +77,7 @@ def actionAbout_activated(self):
|
|
|
91
77
|
# graphviz
|
|
92
78
|
gv_result = subprocess.getoutput("dot -V")
|
|
93
79
|
|
|
94
|
-
programs_versions.extend(
|
|
95
|
-
["\nGraphViz", gv_result if "graphviz" in gv_result else "not installed", "https://www.graphviz.org/"]
|
|
96
|
-
)
|
|
80
|
+
programs_versions.extend(["\nGraphViz", gv_result if "graphviz" in gv_result else "not installed", "https://www.graphviz.org/"])
|
|
97
81
|
|
|
98
82
|
about_dialog = QMessageBox()
|
|
99
83
|
about_dialog.setIconPixmap(QPixmap(":/boris_unito"))
|
|
@@ -106,28 +90,29 @@ def actionAbout_activated(self):
|
|
|
106
90
|
about_dialog.setInformativeText(
|
|
107
91
|
(
|
|
108
92
|
f"<b>{cfg.programName}</b> v. {version.__version__} - {version.__version_date__}"
|
|
109
|
-
"<p>Copyright © 2012-
|
|
93
|
+
"<p>Copyright © 2012-2025 Olivier Friard - Marco Gamba<br>"
|
|
110
94
|
"Department of Life Sciences and Systems Biology<br>"
|
|
111
95
|
"University of Torino - Italy<br>"
|
|
112
96
|
"<br>"
|
|
113
|
-
'BORIS is released under the <a href="
|
|
114
|
-
'See <a href="
|
|
97
|
+
'BORIS is released under the <a href="https://www.gnu.org/copyleft/gpl.html">GNU General Public License</a><br>'
|
|
98
|
+
'See <a href="https://www.boris.unito.it">www.boris.unito.it</a> for more details.<br>'
|
|
115
99
|
"<br>"
|
|
116
100
|
"The authors would like to acknowledge Valentina Matteucci for her precious help."
|
|
117
101
|
"<hr>"
|
|
118
102
|
"How to cite BORIS:<br>"
|
|
119
103
|
"Friard, O. and Gamba, M. (2016), BORIS: a free, versatile open-source event-logging software for video/audio "
|
|
120
104
|
"coding and live observations. Methods Ecol Evol, 7: 1325–1330.<br>"
|
|
121
|
-
'<a href="
|
|
105
|
+
'<a href="https://besjournals.onlinelibrary.wiley.com/doi/full/10.1111/2041-210X.12584">DOI:10.1111/2041-210X.12584</a>'
|
|
122
106
|
)
|
|
123
107
|
)
|
|
108
|
+
"""
|
|
124
109
|
n = "\n"
|
|
125
110
|
current_system = platform.uname()
|
|
126
111
|
details = (
|
|
127
112
|
f"Operating system: {current_system.system} {current_system.release} {current_system.version} \n"
|
|
128
113
|
f"CPU: {current_system.machine} {current_system.processor}\n\n"
|
|
129
114
|
f"Python {platform.python_version()} ({'64-bit' if sys.maxsize > 2**32 else '32-bit'})"
|
|
130
|
-
f"
|
|
115
|
+
f"Qt {qVersion()} - PySide {PySide6.__version__}\n"
|
|
131
116
|
)
|
|
132
117
|
|
|
133
118
|
r, memory = util.mem_info()
|
|
@@ -136,8 +121,11 @@ def actionAbout_activated(self):
|
|
|
136
121
|
f"Memory (RAM) Total: {memory.get('total_memory', 'Not available'):.2f} Mb "
|
|
137
122
|
f"Free: {memory.get('free_memory', 'Not available'):.2f} Mb\n\n"
|
|
138
123
|
)
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
details = util.get_systeminfo()
|
|
139
127
|
|
|
140
|
-
details += n.join(programs_versions)
|
|
128
|
+
details += "\n".join(programs_versions)
|
|
141
129
|
"""
|
|
142
130
|
memory_in_use = f"{utilities.rss_memory_used(self.pid)} Mb" if utilities.rss_memory_used(self.pid) != -1 else "Not available"
|
|
143
131
|
percent_memory_in_use = (f"({utilities.rss_memory_percent_used(self.pid):.1f} % of total memory)"
|
|
@@ -152,4 +140,4 @@ def actionAbout_activated(self):
|
|
|
152
140
|
|
|
153
141
|
about_dialog.setDetailedText(details)
|
|
154
142
|
|
|
155
|
-
_ = about_dialog.
|
|
143
|
+
_ = about_dialog.exec()
|
boris/add_modifier.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
|
|
|
@@ -16,15 +16,15 @@ This file is part of BORIS.
|
|
|
16
16
|
GNU General Public License for more details.
|
|
17
17
|
|
|
18
18
|
You should have received a copy of the GNU General Public License
|
|
19
|
-
along with this program; if not see <http://www.gnu.org/
|
|
19
|
+
along with this program; if not see <http://www.gnu.org/licPbehav_enses/>.
|
|
20
20
|
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
import logging
|
|
24
24
|
import json
|
|
25
25
|
|
|
26
|
-
from
|
|
27
|
-
from
|
|
26
|
+
from PySide6.QtGui import QIcon
|
|
27
|
+
from PySide6.QtWidgets import QDialog, QWidget, QFileDialog, QMessageBox
|
|
28
28
|
|
|
29
29
|
from . import dialog
|
|
30
30
|
from .add_modifier_ui import Ui_Dialog
|
|
@@ -33,12 +33,10 @@ from .utilities import sorted_keys
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
class addModifierDialog(QDialog, Ui_Dialog):
|
|
36
|
-
|
|
37
36
|
tabMem = -1
|
|
38
37
|
itemPositionMem = -1
|
|
39
38
|
|
|
40
|
-
def __init__(self, modifiers_str, subjects=[], parent=None):
|
|
41
|
-
|
|
39
|
+
def __init__(self, modifiers_str: str, subjects: list = [], ask_at_stop_enabled: bool = False, parent=None):
|
|
42
40
|
super().__init__()
|
|
43
41
|
self.setupUi(self)
|
|
44
42
|
|
|
@@ -46,10 +44,12 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
46
44
|
if not self.subjects:
|
|
47
45
|
self.pb_add_subjects.setEnabled(False)
|
|
48
46
|
|
|
47
|
+
self.ask_at_stop_enabled = ask_at_stop_enabled
|
|
48
|
+
|
|
49
49
|
self.pbAddModifier.clicked.connect(self.addModifier)
|
|
50
50
|
self.pbAddModifier.setIcon(QIcon(":/frame_forward"))
|
|
51
|
-
self.pbAddSet.clicked.connect(self.
|
|
52
|
-
self.pbRemoveSet.clicked.connect(self.
|
|
51
|
+
self.pbAddSet.clicked.connect(self.add_set_of_modifiers)
|
|
52
|
+
self.pbRemoveSet.clicked.connect(self.remove_set_of_modifiers)
|
|
53
53
|
self.pbModifyModifier.clicked.connect(self.modifyModifier)
|
|
54
54
|
self.pbModifyModifier.setIcon(QIcon(":/frame_backward"))
|
|
55
55
|
|
|
@@ -62,22 +62,27 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
62
62
|
self.pb_add_subjects.clicked.connect(self.add_subjects)
|
|
63
63
|
self.pb_load_file.clicked.connect(self.add_modifiers_from_file)
|
|
64
64
|
|
|
65
|
-
self.pbOK.clicked.connect(lambda: self.pb_pushed(
|
|
66
|
-
self.pbCancel.clicked.connect(lambda: self.pb_pushed(
|
|
65
|
+
self.pbOK.clicked.connect(lambda: self.pb_pushed(cfg.OK))
|
|
66
|
+
self.pbCancel.clicked.connect(lambda: self.pb_pushed(cfg.CANCEL))
|
|
67
67
|
|
|
68
68
|
self.le_name.textChanged.connect(self.set_name_changed)
|
|
69
69
|
self.le_description.textChanged.connect(self.set_description_changed)
|
|
70
70
|
|
|
71
71
|
self.cbType.currentIndexChanged.connect(self.type_changed)
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
# self.cb_ask_at_stop.clicked.connect(self.ask_at_stop_changed)
|
|
74
|
+
|
|
75
|
+
dummy_dict: dict = json.loads(modifiers_str) if modifiers_str else {}
|
|
76
|
+
modif_values: list = []
|
|
75
77
|
for idx in sorted_keys(dummy_dict):
|
|
76
78
|
modif_values.append(dummy_dict[idx])
|
|
77
79
|
|
|
78
|
-
self.modifiers_sets_dict = {}
|
|
80
|
+
self.modifiers_sets_dict: dict = {}
|
|
79
81
|
for modif in modif_values:
|
|
80
82
|
self.modifiers_sets_dict[str(len(self.modifiers_sets_dict))] = dict(modif)
|
|
83
|
+
if self.ask_at_stop_enabled:
|
|
84
|
+
if dict(modif).get("ask at stop", False):
|
|
85
|
+
self.cb_ask_at_stop.setChecked(True)
|
|
81
86
|
|
|
82
87
|
self.tabWidgetModifiersSets.currentChanged.connect(self.tabWidgetModifiersSets_changed)
|
|
83
88
|
|
|
@@ -104,6 +109,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
104
109
|
self.pb_add_subjects,
|
|
105
110
|
self.pb_load_file,
|
|
106
111
|
self.pb_sort_modifiers,
|
|
112
|
+
self.cb_ask_at_stop,
|
|
107
113
|
):
|
|
108
114
|
w.setVisible(False)
|
|
109
115
|
for w in (self.leModifier, self.leCode, self.pbAddModifier, self.pbModifyModifier):
|
|
@@ -113,24 +119,19 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
113
119
|
self.tabMem = 0
|
|
114
120
|
|
|
115
121
|
def pb_pushed(self, button):
|
|
116
|
-
|
|
117
122
|
if self.leModifier.text():
|
|
118
123
|
if (
|
|
119
124
|
dialog.MessageDialog(
|
|
120
125
|
cfg.programName,
|
|
121
|
-
(
|
|
122
|
-
|
|
123
|
-
"If you close the window it will be lost.<br>"
|
|
124
|
-
"Do you want to change modifiers set"
|
|
125
|
-
),
|
|
126
|
-
["Close", cfg.CANCEL],
|
|
126
|
+
("You are working on a behavior.<br>If you close the window it will be lost.<br>Do you want to change modifiers set"),
|
|
127
|
+
[cfg.CLOSE, cfg.CANCEL],
|
|
127
128
|
)
|
|
128
129
|
== cfg.CANCEL
|
|
129
130
|
):
|
|
130
131
|
return
|
|
131
|
-
if button ==
|
|
132
|
+
if button == cfg.OK:
|
|
132
133
|
self.accept()
|
|
133
|
-
if button ==
|
|
134
|
+
if button == cfg.CANCEL:
|
|
134
135
|
self.reject()
|
|
135
136
|
|
|
136
137
|
def add_subjects(self):
|
|
@@ -153,43 +154,38 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
153
154
|
add modifiers from file
|
|
154
155
|
"""
|
|
155
156
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
self.lwModifiers.item(x).text() for x in range(self.lwModifiers.count())
|
|
189
|
-
]
|
|
190
|
-
except Exception:
|
|
191
|
-
QMessageBox.warning(self, cfg.programName, f"Error reading modifiers from file:<br>{file_name}")
|
|
192
|
-
logging.warning(f"Error reading modifiers from file<br>{file_name}")
|
|
157
|
+
file_name, _ = QFileDialog.getOpenFileName(self, "Load modifiers from file", "", "All files (*)")
|
|
158
|
+
if not file_name:
|
|
159
|
+
return
|
|
160
|
+
try:
|
|
161
|
+
with open(file_name) as f_in:
|
|
162
|
+
for line in f_in:
|
|
163
|
+
if line.strip():
|
|
164
|
+
for c in cfg.CHAR_FORBIDDEN_IN_MODIFIERS:
|
|
165
|
+
if c in line.strip():
|
|
166
|
+
QMessageBox.critical(
|
|
167
|
+
self,
|
|
168
|
+
cfg.programName,
|
|
169
|
+
(
|
|
170
|
+
f"The character <b>{c}</b> is not allowed.<br>"
|
|
171
|
+
"The following characters are not allowed in modifiers:<br>"
|
|
172
|
+
f"<b>{cfg.CHAR_FORBIDDEN_IN_MODIFIERS}</b>"
|
|
173
|
+
),
|
|
174
|
+
)
|
|
175
|
+
break
|
|
176
|
+
else:
|
|
177
|
+
if line.strip() not in [self.lwModifiers.item(x).text() for x in range(self.lwModifiers.count())]:
|
|
178
|
+
if self.itemPositionMem != -1:
|
|
179
|
+
self.lwModifiers.insertItem(self.itemPositionMem, line.strip())
|
|
180
|
+
else:
|
|
181
|
+
self.lwModifiers.addItem(line.strip())
|
|
182
|
+
|
|
183
|
+
self.modifiers_sets_dict[str(self.tabWidgetModifiersSets.currentIndex())]["values"] = [
|
|
184
|
+
self.lwModifiers.item(x).text() for x in range(self.lwModifiers.count())
|
|
185
|
+
]
|
|
186
|
+
except Exception:
|
|
187
|
+
QMessageBox.warning(self, cfg.programName, f"Error reading modifiers from file:<br>{file_name}")
|
|
188
|
+
logging.warning(f"Error reading modifiers from file<br>{file_name}")
|
|
193
189
|
|
|
194
190
|
def sort_modifiers(self):
|
|
195
191
|
"""
|
|
@@ -222,9 +218,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
222
218
|
"""
|
|
223
219
|
if not self.modifiers_sets_dict:
|
|
224
220
|
self.modifiers_sets_dict["0"] = {"name": "", "description": "", "type": cfg.SINGLE_SELECTION, "values": []}
|
|
225
|
-
self.modifiers_sets_dict[str(self.tabWidgetModifiersSets.currentIndex())][
|
|
226
|
-
"description"
|
|
227
|
-
] = self.le_description.text().strip()
|
|
221
|
+
self.modifiers_sets_dict[str(self.tabWidgetModifiersSets.currentIndex())]["description"] = self.le_description.text().strip()
|
|
228
222
|
|
|
229
223
|
def type_changed(self):
|
|
230
224
|
"""
|
|
@@ -257,6 +251,12 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
257
251
|
else:
|
|
258
252
|
self.lb_name.setText("Set name")
|
|
259
253
|
|
|
254
|
+
# def ask_at_stop_changed(self):
|
|
255
|
+
# """
|
|
256
|
+
# value changed
|
|
257
|
+
# """
|
|
258
|
+
# self.modifiers_sets_dict[str(self.tabWidgetModifiersSets.currentIndex())]["ask at stop"] = self.cb_ask_at_stop.isChecked()
|
|
259
|
+
|
|
260
260
|
def moveSetLeft(self):
|
|
261
261
|
"""
|
|
262
262
|
move selected modifiers set left
|
|
@@ -277,7 +277,6 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
277
277
|
move selected modifiers set right
|
|
278
278
|
"""
|
|
279
279
|
if self.tabWidgetModifiersSets.currentIndex() < self.tabWidgetModifiersSets.count() - 1:
|
|
280
|
-
|
|
281
280
|
(
|
|
282
281
|
self.modifiers_sets_dict[str(self.tabWidgetModifiersSets.currentIndex() + 1)],
|
|
283
282
|
self.modifiers_sets_dict[str(self.tabWidgetModifiersSets.currentIndex())],
|
|
@@ -315,7 +314,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
315
314
|
self.lwModifiers.item(x).text() for x in range(self.lwModifiers.count())
|
|
316
315
|
]
|
|
317
316
|
|
|
318
|
-
def
|
|
317
|
+
def add_set_of_modifiers(self):
|
|
319
318
|
"""
|
|
320
319
|
Add a set of modifiers
|
|
321
320
|
"""
|
|
@@ -326,6 +325,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
326
325
|
"name": "",
|
|
327
326
|
"description": "",
|
|
328
327
|
"type": cfg.SINGLE_SELECTION,
|
|
328
|
+
"ask at stop": False,
|
|
329
329
|
"values": [],
|
|
330
330
|
}
|
|
331
331
|
self.tabWidgetModifiersSets.addTab(QWidget(), f"Set #{len(self.modifiers_sets_dict)}")
|
|
@@ -353,6 +353,8 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
353
353
|
self.pb_sort_modifiers,
|
|
354
354
|
):
|
|
355
355
|
w.setVisible(True)
|
|
356
|
+
self.cb_ask_at_stop.setVisible(self.ask_at_stop_enabled)
|
|
357
|
+
|
|
356
358
|
for w in (self.leModifier, self.leCode, self.pbAddModifier, self.pbModifyModifier):
|
|
357
359
|
w.setEnabled(True)
|
|
358
360
|
return
|
|
@@ -362,6 +364,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
362
364
|
"name": "",
|
|
363
365
|
"description": "",
|
|
364
366
|
"type": cfg.SINGLE_SELECTION,
|
|
367
|
+
"ask at stop": False,
|
|
365
368
|
"values": [],
|
|
366
369
|
}
|
|
367
370
|
self.tabWidgetModifiersSets.addTab(QWidget(), f"Set #{len(self.modifiers_sets_dict)}")
|
|
@@ -375,16 +378,13 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
375
378
|
"It is not possible to add a modifiers' set while the current modifiers' set is empty.",
|
|
376
379
|
)
|
|
377
380
|
|
|
378
|
-
def
|
|
381
|
+
def remove_set_of_modifiers(self):
|
|
379
382
|
"""
|
|
380
383
|
remove set of modifiers
|
|
381
384
|
"""
|
|
382
385
|
|
|
383
386
|
if self.tabWidgetModifiersSets.currentIndex() != -1:
|
|
384
|
-
if (
|
|
385
|
-
dialog.MessageDialog(cfg.programName, "Confirm deletion of this set of modifiers?", [cfg.YES, cfg.NO])
|
|
386
|
-
== cfg.YES
|
|
387
|
-
):
|
|
387
|
+
if dialog.MessageDialog(cfg.programName, "Confirm deletion of this set of modifiers?", [cfg.YES, cfg.NO]) == cfg.YES:
|
|
388
388
|
index_to_delete = self.tabWidgetModifiersSets.currentIndex()
|
|
389
389
|
|
|
390
390
|
for k in range(index_to_delete, len(self.modifiers_sets_dict) - 1):
|
|
@@ -417,14 +417,15 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
417
417
|
self.pbRemoveSet,
|
|
418
418
|
self.pbMoveSetLeft,
|
|
419
419
|
self.pbMoveSetRight,
|
|
420
|
+
self.cb_ask_at_stop,
|
|
420
421
|
):
|
|
421
422
|
w.setVisible(False)
|
|
422
|
-
for w in
|
|
423
|
+
for w in (self.leModifier, self.leCode, self.pbAddModifier, self.pbModifyModifier):
|
|
423
424
|
w.setEnabled(False)
|
|
424
425
|
|
|
425
426
|
if not len(self.modifiers_sets_dict):
|
|
426
427
|
# set invisible and unavailable buttons and others elements
|
|
427
|
-
for w in
|
|
428
|
+
for w in (
|
|
428
429
|
self.lb_name,
|
|
429
430
|
self.le_name,
|
|
430
431
|
self.lbType,
|
|
@@ -442,7 +443,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
442
443
|
self.pb_add_subjects,
|
|
443
444
|
self.pb_load_file,
|
|
444
445
|
self.pb_sort_modifiers,
|
|
445
|
-
|
|
446
|
+
):
|
|
446
447
|
w.setVisible(False)
|
|
447
448
|
for w in [self.leModifier, self.leCode, self.pbAddModifier, self.pbModifyModifier]:
|
|
448
449
|
w.setEnabled(False)
|
|
@@ -505,7 +506,6 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
505
506
|
return
|
|
506
507
|
|
|
507
508
|
if txt:
|
|
508
|
-
|
|
509
509
|
if txt in [self.lwModifiers.item(x).text() for x in range(self.lwModifiers.count())]:
|
|
510
510
|
QMessageBox.critical(self, cfg.programName, f"The modifier <b>{txt}</b> is already in the list")
|
|
511
511
|
return
|
|
@@ -515,6 +515,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
515
515
|
"name": "",
|
|
516
516
|
"description": "",
|
|
517
517
|
"type": cfg.SINGLE_SELECTION,
|
|
518
|
+
"ask at stop": False,
|
|
518
519
|
"values": [],
|
|
519
520
|
}
|
|
520
521
|
|
|
@@ -545,16 +546,14 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
545
546
|
"name": "",
|
|
546
547
|
"description": "",
|
|
547
548
|
"type": cfg.SINGLE_SELECTION,
|
|
549
|
+
"ask at stop": False,
|
|
548
550
|
"values": [],
|
|
549
551
|
}
|
|
550
552
|
|
|
551
553
|
if "(" + self.leCode.text().strip() + ")" in " ".join(
|
|
552
554
|
self.modifiers_sets_dict[str(self.tabWidgetModifiersSets.currentIndex())]["values"]
|
|
553
555
|
):
|
|
554
|
-
|
|
555
|
-
QMessageBox.critical(
|
|
556
|
-
self, cfg.programName, f"The shortcut code <b>{self.leCode.text().strip()}</b> already exists!"
|
|
557
|
-
)
|
|
556
|
+
QMessageBox.critical(self, cfg.programName, f"The shortcut code <b>{self.leCode.text().strip()}</b> already exists!")
|
|
558
557
|
self.leCode.setFocus()
|
|
559
558
|
return
|
|
560
559
|
txt += f" ({self.leCode.text().strip()})"
|
|
@@ -600,6 +599,8 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
600
599
|
self.lwModifiers.clear()
|
|
601
600
|
self.leCode.clear()
|
|
602
601
|
self.leModifier.clear()
|
|
602
|
+
# if self.ask_at_stop_enabled:
|
|
603
|
+
# self.cb_ask_at_stop.setChecked(False)
|
|
603
604
|
|
|
604
605
|
self.tabMem = tabIndex
|
|
605
606
|
|
|
@@ -607,14 +608,21 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
607
608
|
self.le_name.setText(self.modifiers_sets_dict[str(tabIndex)]["name"])
|
|
608
609
|
self.le_description.setText(self.modifiers_sets_dict[str(tabIndex)].get("description", ""))
|
|
609
610
|
self.cbType.setCurrentIndex(self.modifiers_sets_dict[str(tabIndex)]["type"])
|
|
611
|
+
# if self.ask_at_stop_enabled:
|
|
612
|
+
# self.cb_ask_at_stop.setChecked(self.modifiers_sets_dict[str(tabIndex)].get("ask at stop", False))
|
|
613
|
+
|
|
610
614
|
self.lwModifiers.addItems(self.modifiers_sets_dict[str(tabIndex)]["values"])
|
|
611
615
|
|
|
612
|
-
def
|
|
616
|
+
def get_modifiers(self) -> str:
|
|
613
617
|
"""
|
|
614
618
|
returns modifiers as string
|
|
615
619
|
"""
|
|
616
|
-
keys_to_delete = []
|
|
620
|
+
keys_to_delete: list = []
|
|
617
621
|
for idx in self.modifiers_sets_dict:
|
|
622
|
+
# add ask_at_stop value (boolean) to each set of modifiers
|
|
623
|
+
if self.ask_at_stop_enabled:
|
|
624
|
+
self.modifiers_sets_dict[idx]["ask at stop"] = self.cb_ask_at_stop.isChecked()
|
|
625
|
+
# delete modifiers without values for selection
|
|
618
626
|
if (
|
|
619
627
|
self.modifiers_sets_dict[idx]["type"] in (cfg.SINGLE_SELECTION, cfg.MULTI_SELECTION)
|
|
620
628
|
and not self.modifiers_sets_dict[idx]["values"]
|