boris-behav-obs 9.7.12__py3-none-any.whl → 9.8.2__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 +4 -3
- boris/add_modifier.py +1 -1
- boris/advanced_event_filtering.py +1 -1
- boris/analysis_plugins/export_to_feral.py +336 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa.py +2 -2
- boris/behav_coding_map_creator.py +1 -1
- boris/behavior_binary_table.py +1 -1
- boris/behaviors_coding_map.py +1 -1
- boris/boris_cli.py +1 -1
- boris/cmd_arguments.py +1 -1
- boris/coding_pad.py +1 -1
- boris/config.py +15 -3
- boris/config_file.py +18 -19
- boris/connections.py +12 -13
- boris/converters.py +1 -1
- boris/converters_ui.py +2 -3
- boris/cooccurence.py +1 -1
- boris/core.py +168 -166
- boris/core_qrc.py +1830 -1967
- boris/core_ui.py +1 -1
- boris/db_functions.py +5 -14
- boris/dialog.py +24 -24
- boris/edit_event.py +1 -1
- boris/event_operations.py +1 -1
- boris/events_cursor.py +1 -1
- boris/events_snapshots.py +133 -78
- boris/exclusion_matrix.py +1 -1
- boris/export_events.py +49 -43
- boris/export_observation.py +1 -1
- boris/external_processes.py +1 -1
- boris/geometric_measurement.py +1 -1
- boris/gui_utilities.py +1 -1
- boris/image_overlay.py +1 -1
- boris/import_observations.py +1 -1
- boris/ipc_mpv.py +1 -1
- boris/irr.py +1 -1
- boris/latency.py +1 -1
- boris/measurement_widget.py +1 -1
- boris/media_file.py +1 -1
- boris/menu_options.py +14 -12
- boris/modifier_coding_map_creator.py +1 -1
- boris/modifiers_coding_map.py +1 -1
- boris/observation.py +13 -14
- boris/observation_operations.py +1 -1
- boris/observations_list.py +1 -1
- boris/otx_parser.py +1 -1
- boris/param_panel.py +1 -1
- boris/player_dock_widget.py +1 -1
- boris/plot_data_module.py +1 -1
- boris/plot_events.py +1 -1
- boris/plot_events_rt.py +1 -1
- boris/plot_spectrogram_rt.py +42 -73
- boris/plot_waveform_rt.py +1 -1
- boris/plugins.py +1 -1
- boris/preferences.py +35 -4
- boris/preferences_ui.py +48 -18
- boris/project.py +1 -1
- boris/project_functions.py +19 -22
- boris/project_import_export.py +1 -1
- boris/select_modifiers.py +1 -1
- boris/select_observations.py +22 -23
- boris/select_subj_behav.py +4 -4
- boris/state_events.py +1 -1
- boris/subjects_pad.py +1 -1
- boris/synthetic_time_budget.py +1 -1
- boris/time_budget_functions.py +1 -1
- boris/time_budget_widget.py +1 -1
- boris/transitions.py +1 -1
- boris/utilities.py +1 -1
- boris/version.py +3 -3
- boris/video_equalizer.py +1 -1
- boris/video_operations.py +1 -1
- boris/view_df.py +28 -4
- boris/write_event.py +1 -1
- {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.8.2.dist-info}/METADATA +2 -2
- boris_behav_obs-9.8.2.dist-info/RECORD +110 -0
- {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.8.2.dist-info}/WHEEL +1 -1
- boris/analysis_plugins/_export_to_feral.py +0 -225
- boris_behav_obs-9.7.12.dist-info/RECORD +0 -110
- {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.8.2.dist-info}/entry_points.txt +0 -0
- {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.8.2.dist-info}/licenses/LICENSE.TXT +0 -0
- {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.8.2.dist-info}/top_level.txt +0 -0
boris/core.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2026 Olivier Friard
|
|
5
5
|
|
|
6
6
|
This file is part of BORIS.
|
|
7
7
|
|
|
@@ -25,37 +25,36 @@ import os
|
|
|
25
25
|
import sys
|
|
26
26
|
from pathlib import Path
|
|
27
27
|
|
|
28
|
-
# os.environ["PATH"] = os.path.dirname(__file__) + os.sep + "misc" + os.pathsep + os.environ["PATH"]
|
|
29
|
-
|
|
30
28
|
os.environ["PATH"] = str(Path(__file__).parent / "misc") + os.pathsep + os.environ["PATH"]
|
|
31
29
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".")))
|
|
32
30
|
|
|
33
31
|
import datetime
|
|
32
|
+
import gzip
|
|
34
33
|
import json
|
|
34
|
+
import locale
|
|
35
35
|
import logging
|
|
36
|
+
import math
|
|
36
37
|
import platform
|
|
37
38
|
import re
|
|
38
|
-
import
|
|
39
|
-
import PIL.ImageEnhance
|
|
40
|
-
from PIL.ImageQt import Image
|
|
39
|
+
import shutil
|
|
41
40
|
import subprocess
|
|
42
|
-
import locale
|
|
43
41
|
import tempfile
|
|
44
|
-
import math
|
|
45
42
|
import time
|
|
46
43
|
import urllib.request
|
|
47
|
-
|
|
48
|
-
from decimal import ROUND_DOWN
|
|
49
|
-
import gzip
|
|
44
|
+
import zipfile
|
|
50
45
|
from collections import deque
|
|
46
|
+
from decimal import ROUND_DOWN
|
|
47
|
+
from decimal import Decimal as dec
|
|
48
|
+
|
|
51
49
|
import matplotlib
|
|
52
|
-
import
|
|
53
|
-
import
|
|
50
|
+
import PIL.Image
|
|
51
|
+
import PIL.ImageEnhance
|
|
52
|
+
from PIL.ImageQt import Image
|
|
54
53
|
|
|
55
54
|
matplotlib.use("QtAgg")
|
|
56
55
|
|
|
57
|
-
from PySide6.QtCore import
|
|
58
|
-
from PySide6.QtGui import
|
|
56
|
+
from PySide6.QtCore import QAbstractTableModel, QDateTime, QElapsedTimer, QEvent, QPoint, QSettings, Qt, QUrl, Signal
|
|
57
|
+
from PySide6.QtGui import QAction, QColor, QDesktopServices, QFont, QIcon, QKeyEvent, QPainter, QPixmap, QPolygon
|
|
59
58
|
from PySide6.QtMultimedia import QSoundEffect
|
|
60
59
|
from PySide6.QtWidgets import (
|
|
61
60
|
QAbstractItemView,
|
|
@@ -74,7 +73,6 @@ from PySide6.QtWidgets import (
|
|
|
74
73
|
QTableWidgetItem,
|
|
75
74
|
)
|
|
76
75
|
|
|
77
|
-
|
|
78
76
|
from . import cmd_arguments
|
|
79
77
|
|
|
80
78
|
# parse command line arguments
|
|
@@ -94,39 +92,39 @@ else:
|
|
|
94
92
|
level=logging.INFO,
|
|
95
93
|
)
|
|
96
94
|
|
|
97
|
-
from . import
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
95
|
+
from . import (
|
|
96
|
+
advanced_event_filtering,
|
|
97
|
+
config_file,
|
|
98
|
+
core_qrc,
|
|
99
|
+
dialog,
|
|
100
|
+
event_operations,
|
|
101
|
+
events_cursor,
|
|
102
|
+
geometric_measurement,
|
|
103
|
+
gui_utilities,
|
|
104
|
+
modifier_coding_map_creator,
|
|
105
|
+
modifiers_coding_map,
|
|
106
|
+
observation_operations,
|
|
107
|
+
otx_parser,
|
|
108
|
+
param_panel,
|
|
109
|
+
plot_events,
|
|
110
|
+
plot_events_rt,
|
|
111
|
+
plot_spectrogram_rt,
|
|
112
|
+
plot_waveform_rt,
|
|
113
|
+
plugins,
|
|
114
|
+
project,
|
|
115
|
+
project_functions,
|
|
116
|
+
select_observations,
|
|
117
|
+
select_subj_behav,
|
|
118
|
+
subjects_pad,
|
|
119
|
+
version,
|
|
120
|
+
video_operations,
|
|
121
|
+
write_event,
|
|
122
|
+
)
|
|
120
123
|
from . import config as cfg
|
|
121
|
-
from . import video_operations
|
|
122
|
-
from . import project
|
|
123
|
-
from . import menu_options as menu_options
|
|
124
124
|
from . import connections as connections
|
|
125
|
-
from . import
|
|
126
|
-
from . import
|
|
127
|
-
from . import
|
|
128
|
-
from . import write_event
|
|
129
|
-
|
|
125
|
+
from . import menu_options as menu_options
|
|
126
|
+
from . import utilities as util
|
|
127
|
+
from .core_ui import Ui_MainWindow
|
|
130
128
|
|
|
131
129
|
logging.debug("test")
|
|
132
130
|
|
|
@@ -177,8 +175,8 @@ class TableModel(QAbstractTableModel):
|
|
|
177
175
|
self.observation_type = observation_type
|
|
178
176
|
|
|
179
177
|
def headerData(self, section: int, orientation: Qt.Orientation, role: int):
|
|
180
|
-
if role == Qt.DisplayRole:
|
|
181
|
-
if orientation == Qt.Horizontal:
|
|
178
|
+
if role == Qt.ItemDataRole.DisplayRole:
|
|
179
|
+
if orientation == Qt.Orientation.Horizontal:
|
|
182
180
|
return self.header[section]
|
|
183
181
|
else:
|
|
184
182
|
return str(section + 1)
|
|
@@ -189,8 +187,8 @@ class TableModel(QAbstractTableModel):
|
|
|
189
187
|
def columnCount(self, parent=None):
|
|
190
188
|
return len(self._data[0]) if self.rowCount() else 0
|
|
191
189
|
|
|
192
|
-
def data(self, index, role=Qt.DisplayRole):
|
|
193
|
-
if role == Qt.DisplayRole:
|
|
190
|
+
def data(self, index, role=Qt.ItemDataRole.DisplayRole):
|
|
191
|
+
if role == Qt.ItemDataRole.DisplayRole:
|
|
194
192
|
row = index.row()
|
|
195
193
|
if 0 <= row < self.rowCount():
|
|
196
194
|
column = index.column()
|
|
@@ -348,7 +346,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
348
346
|
super(MainWindow, self).__init__(parent)
|
|
349
347
|
self.setupUi(self)
|
|
350
348
|
|
|
351
|
-
self.pb_live_obs.setFocusPolicy(Qt.NoFocus)
|
|
349
|
+
self.pb_live_obs.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
|
352
350
|
|
|
353
351
|
self.ffmpeg_bin = ffmpeg_bin
|
|
354
352
|
# set icons
|
|
@@ -379,7 +377,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
379
377
|
|
|
380
378
|
self.lbLogoBoris.setPixmap(QPixmap(":/logo"))
|
|
381
379
|
self.lbLogoBoris.setScaledContents(False)
|
|
382
|
-
self.lbLogoBoris.setAlignment(Qt.AlignCenter)
|
|
380
|
+
self.lbLogoBoris.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
383
381
|
|
|
384
382
|
self.toolBar.setEnabled(True)
|
|
385
383
|
|
|
@@ -413,13 +411,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
413
411
|
|
|
414
412
|
# observation time interval
|
|
415
413
|
self.lb_obs_time_interval = QLabel()
|
|
416
|
-
self.lb_obs_time_interval.setFrameStyle(QFrame.StyledPanel)
|
|
414
|
+
self.lb_obs_time_interval.setFrameStyle(QFrame.Shape.StyledPanel)
|
|
417
415
|
self.lb_obs_time_interval.setMinimumWidth(160)
|
|
418
416
|
self.statusbar.addPermanentWidget(self.lb_obs_time_interval)
|
|
419
417
|
|
|
420
418
|
# time offset
|
|
421
419
|
self.lbTimeOffset = QLabel()
|
|
422
|
-
self.lbTimeOffset.setFrameStyle(QFrame.StyledPanel)
|
|
420
|
+
self.lbTimeOffset.setFrameStyle(QFrame.Shape.StyledPanel)
|
|
423
421
|
self.lbTimeOffset.setMinimumWidth(160)
|
|
424
422
|
self.statusbar.addPermanentWidget(self.lbTimeOffset)
|
|
425
423
|
|
|
@@ -431,7 +429,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
431
429
|
self.tv_events.setItemDelegate(events_cursor.StyledItemDelegateTriangle(self.events_current_row))
|
|
432
430
|
|
|
433
431
|
connections.connections(self)
|
|
434
|
-
self.config_param = cfg.INIT_PARAM
|
|
432
|
+
self.config_param = dict(cfg.INIT_PARAM)
|
|
435
433
|
config_file.read(self)
|
|
436
434
|
menu_options.update_menu(self)
|
|
437
435
|
|
|
@@ -450,9 +448,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
450
448
|
for w in (self.dwEvents, self.dwEthogram, self.dwSubjects):
|
|
451
449
|
if self.action_block_dockwidgets.isChecked():
|
|
452
450
|
w.setFloating(False)
|
|
453
|
-
w.setFeatures(QDockWidget.NoDockWidgetFeatures)
|
|
451
|
+
w.setFeatures(QDockWidget.DockWidgetFeature.NoDockWidgetFeatures)
|
|
454
452
|
else:
|
|
455
|
-
w.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable)
|
|
453
|
+
w.setFeatures(QDockWidget.DockWidgetFeature.DockWidgetMovable | QDockWidget.DockWidgetFeature.DockWidgetFloatable)
|
|
456
454
|
|
|
457
455
|
def advanced_event_filtering(self):
|
|
458
456
|
"""
|
|
@@ -524,7 +522,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
524
522
|
"Removing the path of media files and image directories from the project file is irreversible.<br>"
|
|
525
523
|
"Are you sure to continue?"
|
|
526
524
|
),
|
|
527
|
-
|
|
525
|
+
(cfg.YES, cfg.NO),
|
|
528
526
|
)
|
|
529
527
|
== cfg.NO
|
|
530
528
|
):
|
|
@@ -542,13 +540,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
542
540
|
dialog.MessageDialog(
|
|
543
541
|
cfg.programName,
|
|
544
542
|
("Removing the path of external data files is irreversible.<br>Are you sure to continue?"),
|
|
545
|
-
|
|
543
|
+
(cfg.YES, cfg.NO),
|
|
546
544
|
)
|
|
547
545
|
== cfg.NO
|
|
548
546
|
):
|
|
549
547
|
return
|
|
550
548
|
|
|
551
|
-
if project_functions.remove_data_files_path(self.pj
|
|
549
|
+
if project_functions.remove_data_files_path(self.pj):
|
|
552
550
|
self.project_changed()
|
|
553
551
|
|
|
554
552
|
def set_media_files_path_relative_to_project_dir(self):
|
|
@@ -560,7 +558,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
560
558
|
dialog.MessageDialog(
|
|
561
559
|
cfg.programName,
|
|
562
560
|
("Are you sure to continue?"),
|
|
563
|
-
|
|
561
|
+
(cfg.YES, cfg.NO),
|
|
564
562
|
)
|
|
565
563
|
== cfg.NO
|
|
566
564
|
):
|
|
@@ -577,7 +575,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
577
575
|
dialog.MessageDialog(
|
|
578
576
|
cfg.programName,
|
|
579
577
|
("Are you sure to continue?"),
|
|
580
|
-
|
|
578
|
+
(cfg.YES, cfg.NO),
|
|
581
579
|
)
|
|
582
580
|
== cfg.NO
|
|
583
581
|
):
|
|
@@ -697,7 +695,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
697
695
|
QMessageBox.warning(self, cfg.programName, "No subjects to show")
|
|
698
696
|
return
|
|
699
697
|
self.subjects_pad = subjects_pad.SubjectsPad(self.pj, filtered_subjects)
|
|
700
|
-
self.subjects_pad.setWindowFlags(Qt.WindowStaysOnTopHint)
|
|
698
|
+
self.subjects_pad.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
|
|
701
699
|
self.subjects_pad.sendEventSignal.connect(self.signal_from_subjects_pad)
|
|
702
700
|
self.subjects_pad.click_signal.connect(self.click_signal_from_subjects_pad)
|
|
703
701
|
self.subjects_pad.close_signal.connect(self.close_signal_from_subjects_pad)
|
|
@@ -918,7 +916,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
918
916
|
w = dialog.Info_widget()
|
|
919
917
|
w.lwi.setVisible(False)
|
|
920
918
|
w.resize(350, 100)
|
|
921
|
-
w.setWindowFlags(Qt.WindowStaysOnTopHint)
|
|
919
|
+
w.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
|
|
922
920
|
w.setWindowTitle(cfg.programName)
|
|
923
921
|
w.label.setText("Extracting WAV from media files...")
|
|
924
922
|
|
|
@@ -1000,7 +998,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1000
998
|
f"You choose to visualize the {plot_type} during this observation.<br>"
|
|
1001
999
|
f"{plot_type} generation can take some time for long media, be patient"
|
|
1002
1000
|
),
|
|
1003
|
-
|
|
1001
|
+
(cfg.YES, cfg.NO),
|
|
1004
1002
|
)
|
|
1005
1003
|
== cfg.NO
|
|
1006
1004
|
):
|
|
@@ -1018,8 +1016,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1018
1016
|
|
|
1019
1017
|
self.spectro = plot_spectrogram_rt.Plot_spectrogram_RT()
|
|
1020
1018
|
|
|
1021
|
-
self.spectro.setWindowFlags(Qt.WindowStaysOnTopHint)
|
|
1022
|
-
self.spectro.setWindowFlags(self.spectro.windowFlags() & ~Qt.WindowMinimizeButtonHint)
|
|
1019
|
+
self.spectro.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
|
|
1020
|
+
self.spectro.setWindowFlags(self.spectro.windowFlags() & ~Qt.WindowType.WindowMinimizeButtonHint)
|
|
1023
1021
|
|
|
1024
1022
|
self.spectro.interval = self.spectrogram_time_interval
|
|
1025
1023
|
self.spectro.cursor_color = cfg.REALTIME_PLOT_CURSOR_COLOR
|
|
@@ -1039,8 +1037,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1039
1037
|
self,
|
|
1040
1038
|
cfg.programName,
|
|
1041
1039
|
f"Error in spectrogram generation: {r['error']}",
|
|
1042
|
-
QMessageBox.Ok
|
|
1043
|
-
QMessageBox.NoButton,
|
|
1040
|
+
QMessageBox.StandardButton.Ok,
|
|
1041
|
+
QMessageBox.StandardButton.NoButton,
|
|
1044
1042
|
)
|
|
1045
1043
|
del self.spectro
|
|
1046
1044
|
return
|
|
@@ -1091,7 +1089,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1091
1089
|
"You choose to visualize the waveform during this observation.<br>"
|
|
1092
1090
|
"The waveform generation can take some time for long media, be patient"
|
|
1093
1091
|
),
|
|
1094
|
-
|
|
1092
|
+
(cfg.YES, cfg.NO),
|
|
1095
1093
|
)
|
|
1096
1094
|
== cfg.NO
|
|
1097
1095
|
):
|
|
@@ -1109,7 +1107,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1109
1107
|
|
|
1110
1108
|
self.waveform = plot_waveform_rt.Plot_waveform_RT()
|
|
1111
1109
|
|
|
1112
|
-
self.waveform.setWindowFlags(Qt.WindowStaysOnTopHint)
|
|
1110
|
+
self.waveform.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
|
|
1113
1111
|
self.waveform.setWindowFlags(self.waveform.windowFlags() & ~Qt.WindowMinimizeButtonHint)
|
|
1114
1112
|
|
|
1115
1113
|
self.waveform.interval = self.spectrogram_time_interval
|
|
@@ -1122,8 +1120,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1122
1120
|
self,
|
|
1123
1121
|
cfg.programName,
|
|
1124
1122
|
f"Error in waveform generation: {r['error']}",
|
|
1125
|
-
QMessageBox.Ok
|
|
1126
|
-
QMessageBox.NoButton,
|
|
1123
|
+
QMessageBox.StandardButton.Ok,
|
|
1124
|
+
QMessageBox.StandardButton.NoButton,
|
|
1127
1125
|
)
|
|
1128
1126
|
del self.waveform
|
|
1129
1127
|
return
|
|
@@ -1146,7 +1144,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1146
1144
|
|
|
1147
1145
|
self.plot_events = plot_events_rt.Plot_events_RT()
|
|
1148
1146
|
|
|
1149
|
-
self.plot_events.setWindowFlags(Qt.WindowStaysOnTopHint)
|
|
1147
|
+
self.plot_events.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
|
|
1150
1148
|
self.plot_events.setWindowFlags(self.plot_events.windowFlags() & ~Qt.WindowMinimizeButtonHint)
|
|
1151
1149
|
|
|
1152
1150
|
self.plot_events.groupby = "behaviors"
|
|
@@ -1285,8 +1283,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1285
1283
|
self,
|
|
1286
1284
|
cfg.programName,
|
|
1287
1285
|
"No project found",
|
|
1288
|
-
QMessageBox.Ok
|
|
1289
|
-
QMessageBox.NoButton,
|
|
1286
|
+
QMessageBox.StandardButton.Ok,
|
|
1287
|
+
QMessageBox.StandardButton.NoButton,
|
|
1290
1288
|
)
|
|
1291
1289
|
return
|
|
1292
1290
|
|
|
@@ -1301,7 +1299,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1301
1299
|
f"with the same name (<b>{behav_coding_map['name']}</b>).<br>"
|
|
1302
1300
|
"What do you want to do?"
|
|
1303
1301
|
),
|
|
1304
|
-
|
|
1302
|
+
("Replace the coding map", cfg.CANCEL),
|
|
1305
1303
|
)
|
|
1306
1304
|
if response == cfg.CANCEL:
|
|
1307
1305
|
return
|
|
@@ -1626,7 +1624,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1626
1624
|
self.currentSubject = subject
|
|
1627
1625
|
self.lbFocalSubject.setText(f" Focal subject: <b>{self.currentSubject}</b>")
|
|
1628
1626
|
|
|
1629
|
-
def getCurrentMediaByFrame(self, player: str, requiredFrame: int, fps: float):
|
|
1627
|
+
def getCurrentMediaByFrame(self, player: str, requiredFrame: int, fps: float) -> tuple[str, int]:
|
|
1630
1628
|
"""
|
|
1631
1629
|
Args:
|
|
1632
1630
|
player (str): player
|
|
@@ -1637,7 +1635,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1637
1635
|
currentMedia
|
|
1638
1636
|
frameCurrentMedia
|
|
1639
1637
|
"""
|
|
1640
|
-
currentMedia
|
|
1638
|
+
currentMedia: str = ""
|
|
1639
|
+
frameCurrentMedia: int = 0
|
|
1641
1640
|
frameMs = 1000 / fps
|
|
1642
1641
|
for idx, media in enumerate(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][player]):
|
|
1643
1642
|
if requiredFrame * frameMs < sum(self.dw_player[int(player) - 1].media_durations[0 : idx + 1]):
|
|
@@ -1646,7 +1645,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1646
1645
|
break
|
|
1647
1646
|
return currentMedia, round(frameCurrentMedia)
|
|
1648
1647
|
|
|
1649
|
-
def extract_frame(self, dw):
|
|
1648
|
+
def extract_frame(self, dw) -> None:
|
|
1650
1649
|
"""
|
|
1651
1650
|
for MEDIA obs: extract frame from video and visualize it in frame_viewer
|
|
1652
1651
|
for IMAGES obs: load picture and visualize it in frame_viewer, extract EXIF Date/Time Original tag if available
|
|
@@ -1658,7 +1657,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1658
1657
|
time.sleep(0.3) # required for correct frame number
|
|
1659
1658
|
|
|
1660
1659
|
dw.frame_viewer.setPixmap(
|
|
1661
|
-
util.pil2pixmap(dw.player.screenshot_raw()).scaled(
|
|
1660
|
+
util.pil2pixmap(dw.player.screenshot_raw()).scaled(
|
|
1661
|
+
dw.frame_viewer.size(), Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation
|
|
1662
|
+
)
|
|
1662
1663
|
)
|
|
1663
1664
|
|
|
1664
1665
|
if self.playerType == cfg.IMAGES:
|
|
@@ -1667,8 +1668,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1667
1668
|
None,
|
|
1668
1669
|
cfg.programName,
|
|
1669
1670
|
("The picture directory has changed since the creation of observation."),
|
|
1670
|
-
QMessageBox.Ok
|
|
1671
|
-
QMessageBox.NoButton,
|
|
1671
|
+
QMessageBox.StandardButton.Ok,
|
|
1672
|
+
QMessageBox.StandardButton.NoButton,
|
|
1672
1673
|
)
|
|
1673
1674
|
return
|
|
1674
1675
|
|
|
@@ -1727,23 +1728,23 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1727
1728
|
# show current states in subjects table
|
|
1728
1729
|
self.show_current_states_in_subjects_table()
|
|
1729
1730
|
|
|
1730
|
-
def frame_image_clicked(self, n_player, event):
|
|
1731
|
+
def frame_image_clicked(self, n_player, event) -> None:
|
|
1731
1732
|
geometric_measurement.image_clicked(self, n_player, event)
|
|
1732
1733
|
|
|
1733
|
-
def timer_plot_data_out(self, w):
|
|
1734
|
+
def timer_plot_data_out(self, w) -> None:
|
|
1734
1735
|
"""
|
|
1735
1736
|
update plot in w (Plot_data class)
|
|
1736
1737
|
triggered by timers in self.ext_data_timer_list
|
|
1737
1738
|
"""
|
|
1738
1739
|
w.update_plot(self.getLaps())
|
|
1739
1740
|
|
|
1740
|
-
def signal_from_widget(self, event):
|
|
1741
|
+
def signal_from_widget(self, event) -> None:
|
|
1741
1742
|
"""
|
|
1742
1743
|
receive signal from widget
|
|
1743
1744
|
"""
|
|
1744
1745
|
self.keyPressEvent(event)
|
|
1745
1746
|
|
|
1746
|
-
def reload_frame(self):
|
|
1747
|
+
def reload_frame(self) -> None:
|
|
1747
1748
|
"""
|
|
1748
1749
|
receive signal to reload frames from geometric measurements
|
|
1749
1750
|
"""
|
|
@@ -1759,7 +1760,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1759
1760
|
|
|
1760
1761
|
geometric_measurement.redraw_measurements(self)
|
|
1761
1762
|
|
|
1762
|
-
def save_picture_with_measurements(self, mode: str):
|
|
1763
|
+
def save_picture_with_measurements(self, mode: str) -> None:
|
|
1763
1764
|
"""
|
|
1764
1765
|
receive signal to save picture from geometric measurements
|
|
1765
1766
|
"""
|
|
@@ -1806,7 +1807,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1806
1807
|
self,
|
|
1807
1808
|
"Select a directory to save the frames",
|
|
1808
1809
|
os.path.expanduser("~"),
|
|
1809
|
-
options=QFileDialog.ShowDirsOnly,
|
|
1810
|
+
options=QFileDialog.Option.ShowDirsOnly,
|
|
1810
1811
|
)
|
|
1811
1812
|
if not output_dir:
|
|
1812
1813
|
return
|
|
@@ -1944,7 +1945,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1944
1945
|
|
|
1945
1946
|
pixmap.save(str(Path(output_dir) / file_name.with_suffix(".jpg")), "JPG")
|
|
1946
1947
|
|
|
1947
|
-
def resize_dw(self, dw_id):
|
|
1948
|
+
def resize_dw(self, dw_id) -> None:
|
|
1948
1949
|
"""
|
|
1949
1950
|
dockwidget was resized. Adapt overlay if any
|
|
1950
1951
|
"""
|
|
@@ -2188,8 +2189,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2188
2189
|
None,
|
|
2189
2190
|
cfg.programName,
|
|
2190
2191
|
("This function is not yet implemented"),
|
|
2191
|
-
QMessageBox.Ok
|
|
2192
|
-
QMessageBox.NoButton,
|
|
2192
|
+
QMessageBox.StandardButton.Ok,
|
|
2193
|
+
QMessageBox.StandardButton.NoButton,
|
|
2193
2194
|
)
|
|
2194
2195
|
|
|
2195
2196
|
return
|
|
@@ -2280,7 +2281,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2280
2281
|
self.tv_events.setModel(model)
|
|
2281
2282
|
|
|
2282
2283
|
# column width
|
|
2283
|
-
self.tv_events.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
|
|
2284
|
+
self.tv_events.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Interactive)
|
|
2284
2285
|
|
|
2285
2286
|
def load_tw_events(self, obs_id) -> None:
|
|
2286
2287
|
"""
|
|
@@ -2544,8 +2545,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2544
2545
|
None,
|
|
2545
2546
|
cfg.programName,
|
|
2546
2547
|
("This function is not available for observations with events that do not have timestamp"),
|
|
2547
|
-
QMessageBox.Ok
|
|
2548
|
-
QMessageBox.NoButton,
|
|
2548
|
+
QMessageBox.StandardButton.Ok,
|
|
2549
|
+
QMessageBox.StandardButton.NoButton,
|
|
2549
2550
|
)
|
|
2550
2551
|
return
|
|
2551
2552
|
|
|
@@ -2557,7 +2558,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2557
2558
|
self,
|
|
2558
2559
|
"Choose a directory to save the plots",
|
|
2559
2560
|
os.path.expanduser("~"),
|
|
2560
|
-
options=QFileDialog.ShowDirsOnly,
|
|
2561
|
+
options=QFileDialog.Option.ShowDirsOnly,
|
|
2561
2562
|
)
|
|
2562
2563
|
|
|
2563
2564
|
if not plot_directory:
|
|
@@ -2660,8 +2661,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2660
2661
|
None,
|
|
2661
2662
|
cfg.programName,
|
|
2662
2663
|
("The duration of one or more observation is not available"),
|
|
2663
|
-
QMessageBox.Ok
|
|
2664
|
-
QMessageBox.NoButton,
|
|
2664
|
+
QMessageBox.StandardButton.Ok,
|
|
2665
|
+
QMessageBox.StandardButton.NoButton,
|
|
2665
2666
|
)
|
|
2666
2667
|
return
|
|
2667
2668
|
|
|
@@ -2673,8 +2674,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2673
2674
|
None,
|
|
2674
2675
|
cfg.programName,
|
|
2675
2676
|
("This function is not available for observations with events that do not have timestamp"),
|
|
2676
|
-
QMessageBox.Ok
|
|
2677
|
-
QMessageBox.NoButton,
|
|
2677
|
+
QMessageBox.StandardButton.Ok,
|
|
2678
|
+
QMessageBox.StandardButton.NoButton,
|
|
2678
2679
|
)
|
|
2679
2680
|
return
|
|
2680
2681
|
|
|
@@ -2709,7 +2710,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2709
2710
|
self,
|
|
2710
2711
|
"Choose a directory to save the plots",
|
|
2711
2712
|
os.path.expanduser("~"),
|
|
2712
|
-
options=QFileDialog.ShowDirsOnly,
|
|
2713
|
+
options=QFileDialog.Option.ShowDirsOnly,
|
|
2713
2714
|
)
|
|
2714
2715
|
if not plot_directory:
|
|
2715
2716
|
return
|
|
@@ -2777,7 +2778,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2777
2778
|
dialog.MessageDialog(
|
|
2778
2779
|
cfg.programName,
|
|
2779
2780
|
"There is a current observation. What do you want to do?",
|
|
2780
|
-
|
|
2781
|
+
("Close observation", "Continue observation"),
|
|
2781
2782
|
)
|
|
2782
2783
|
== "Close observation"
|
|
2783
2784
|
):
|
|
@@ -2789,7 +2790,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2789
2790
|
response = dialog.MessageDialog(
|
|
2790
2791
|
cfg.programName,
|
|
2791
2792
|
"What to do about the current unsaved project?",
|
|
2792
|
-
|
|
2793
|
+
(cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
|
|
2793
2794
|
)
|
|
2794
2795
|
|
|
2795
2796
|
if response == cfg.SAVE:
|
|
@@ -2849,7 +2850,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2849
2850
|
"In this project all the behavior and subject keys are upper case.<br>"
|
|
2850
2851
|
"Do you want to convert them in lower case?"
|
|
2851
2852
|
),
|
|
2852
|
-
|
|
2853
|
+
(cfg.YES, cfg.NO),
|
|
2853
2854
|
)
|
|
2854
2855
|
== cfg.YES
|
|
2855
2856
|
):
|
|
@@ -2901,7 +2902,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2901
2902
|
dialog.MessageDialog(
|
|
2902
2903
|
cfg.programName,
|
|
2903
2904
|
"There is a current observation. What do you want to do?",
|
|
2904
|
-
|
|
2905
|
+
("Close observation", "Continue observation"),
|
|
2905
2906
|
)
|
|
2906
2907
|
== "Close observation"
|
|
2907
2908
|
):
|
|
@@ -2913,7 +2914,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2913
2914
|
response = dialog.MessageDialog(
|
|
2914
2915
|
cfg.programName,
|
|
2915
2916
|
"What to do about the current unsaved project?",
|
|
2916
|
-
|
|
2917
|
+
(cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
|
|
2917
2918
|
)
|
|
2918
2919
|
|
|
2919
2920
|
if response == cfg.SAVE:
|
|
@@ -2964,7 +2965,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2964
2965
|
response = dialog.MessageDialog(
|
|
2965
2966
|
cfg.programName,
|
|
2966
2967
|
"There is a current observation. What do you want to do?",
|
|
2967
|
-
|
|
2968
|
+
("Close observation", "Continue observation"),
|
|
2968
2969
|
)
|
|
2969
2970
|
if response == "Close observation":
|
|
2970
2971
|
observation_operations.close_observation(self)
|
|
@@ -2975,7 +2976,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2975
2976
|
response = dialog.MessageDialog(
|
|
2976
2977
|
cfg.programName,
|
|
2977
2978
|
"What to do about the current unsaved project?",
|
|
2978
|
-
|
|
2979
|
+
(cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
|
|
2979
2980
|
)
|
|
2980
2981
|
if response == cfg.SAVE:
|
|
2981
2982
|
if self.save_project_activated() == "not saved":
|
|
@@ -3019,7 +3020,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3019
3020
|
response = dialog.MessageDialog(
|
|
3020
3021
|
cfg.programName,
|
|
3021
3022
|
"The current observation will be closed. Do you want to continue?",
|
|
3022
|
-
|
|
3023
|
+
(cfg.YES, cfg.NO),
|
|
3023
3024
|
)
|
|
3024
3025
|
if response == cfg.NO:
|
|
3025
3026
|
self.show_data_files()
|
|
@@ -3032,7 +3033,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3032
3033
|
response = dialog.MessageDialog(
|
|
3033
3034
|
cfg.programName,
|
|
3034
3035
|
"What to do with the current unsaved project?",
|
|
3035
|
-
|
|
3036
|
+
(cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
|
|
3036
3037
|
)
|
|
3037
3038
|
|
|
3038
3039
|
if response == cfg.SAVE:
|
|
@@ -3233,7 +3234,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3233
3234
|
|
|
3234
3235
|
del newProjectWindow
|
|
3235
3236
|
|
|
3236
|
-
def save_project_json(self, project_file_name: str) -> int:
|
|
3237
|
+
def save_project_json(self, project_file_name: str) -> int | None:
|
|
3237
3238
|
"""
|
|
3238
3239
|
save project to JSON file
|
|
3239
3240
|
convert Decimal type in float
|
|
@@ -3299,21 +3300,21 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3299
3300
|
None,
|
|
3300
3301
|
cfg.programName,
|
|
3301
3302
|
"Permission denied to save the project file. Try another directory",
|
|
3302
|
-
QMessageBox.Ok
|
|
3303
|
-
QMessageBox.NoButton,
|
|
3303
|
+
QMessageBox.StandardButton.Ok,
|
|
3304
|
+
QMessageBox.StandardButton.NoButton,
|
|
3304
3305
|
)
|
|
3305
3306
|
self.save_project_json_started = False
|
|
3306
3307
|
return 1
|
|
3307
3308
|
|
|
3308
3309
|
except OSError:
|
|
3309
3310
|
_, value, _ = sys.exc_info()
|
|
3310
|
-
QMessageBox.critical(None, cfg.programName, f"Error saving the project file: {value}", QMessageBox.Ok)
|
|
3311
|
+
QMessageBox.critical(None, cfg.programName, f"Error saving the project file: {value}", QMessageBox.StandardButton.Ok)
|
|
3311
3312
|
self.save_project_json_started = False
|
|
3312
3313
|
return 4
|
|
3313
3314
|
|
|
3314
3315
|
except Exception:
|
|
3315
3316
|
_, value, _ = sys.exc_info()
|
|
3316
|
-
QMessageBox.critical(None, cfg.programName, f"Error saving the project file: {value}", QMessageBox.Ok)
|
|
3317
|
+
QMessageBox.critical(None, cfg.programName, f"Error saving the project file: {value}", QMessageBox.StandardButton.Ok)
|
|
3317
3318
|
self.save_project_json_started = False
|
|
3318
3319
|
return 2
|
|
3319
3320
|
|
|
@@ -3344,7 +3345,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3344
3345
|
dialog.MessageDialog(
|
|
3345
3346
|
cfg.programName,
|
|
3346
3347
|
f"The file {project_new_file_name} already exists.",
|
|
3347
|
-
|
|
3348
|
+
(cfg.CANCEL, cfg.OVERWRITE),
|
|
3348
3349
|
)
|
|
3349
3350
|
== cfg.CANCEL
|
|
3350
3351
|
):
|
|
@@ -3360,7 +3361,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3360
3361
|
dialog.MessageDialog(
|
|
3361
3362
|
cfg.programName,
|
|
3362
3363
|
f"The file {project_new_file_name} already exists.",
|
|
3363
|
-
|
|
3364
|
+
(cfg.CANCEL, cfg.OVERWRITE),
|
|
3364
3365
|
)
|
|
3365
3366
|
== cfg.CANCEL
|
|
3366
3367
|
):
|
|
@@ -3440,7 +3441,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3440
3441
|
dialog.MessageDialog(
|
|
3441
3442
|
cfg.programName,
|
|
3442
3443
|
f"The file {self.projectFileName} already exists.",
|
|
3443
|
-
|
|
3444
|
+
(cfg.CANCEL, cfg.OVERWRITE),
|
|
3444
3445
|
)
|
|
3445
3446
|
== cfg.CANCEL
|
|
3446
3447
|
):
|
|
@@ -3459,7 +3460,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3459
3460
|
dialog.MessageDialog(
|
|
3460
3461
|
cfg.programName,
|
|
3461
3462
|
f"The file {self.projectFileName} already exists.",
|
|
3462
|
-
|
|
3463
|
+
(cfg.CANCEL, cfg.OVERWRITE),
|
|
3463
3464
|
)
|
|
3464
3465
|
== cfg.CANCEL
|
|
3465
3466
|
):
|
|
@@ -3622,8 +3623,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3622
3623
|
None,
|
|
3623
3624
|
cfg.programName,
|
|
3624
3625
|
("This function is not available for observations with events that do not have timestamp"),
|
|
3625
|
-
QMessageBox.Ok
|
|
3626
|
-
QMessageBox.NoButton,
|
|
3626
|
+
QMessageBox.StandardButton.Ok,
|
|
3627
|
+
QMessageBox.StandardButton.NoButton,
|
|
3627
3628
|
)
|
|
3628
3629
|
return
|
|
3629
3630
|
|
|
@@ -3656,7 +3657,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3656
3657
|
self,
|
|
3657
3658
|
"Choose a directory to save subtitles",
|
|
3658
3659
|
os.path.expanduser("~"),
|
|
3659
|
-
options=QFileDialog.ShowDirsOnly,
|
|
3660
|
+
options=QFileDialog.Option.ShowDirsOnly,
|
|
3660
3661
|
)
|
|
3661
3662
|
if not export_dir:
|
|
3662
3663
|
return
|
|
@@ -3667,8 +3668,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3667
3668
|
None,
|
|
3668
3669
|
cfg.programName,
|
|
3669
3670
|
f"Error creating subtitles: {msg}",
|
|
3670
|
-
QMessageBox.Ok
|
|
3671
|
-
QMessageBox.NoButton,
|
|
3671
|
+
QMessageBox.StandardButton.Ok,
|
|
3672
|
+
QMessageBox.StandardButton.NoButton,
|
|
3672
3673
|
)
|
|
3673
3674
|
|
|
3674
3675
|
def next_frame(self) -> None:
|
|
@@ -3900,7 +3901,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3900
3901
|
msg_box = QMessageBox(
|
|
3901
3902
|
QMessageBox.Critical, cfg.programName, f"The code <b>{code}</b> of behavior coding map does not exist in ethogram."
|
|
3902
3903
|
)
|
|
3903
|
-
msg_box.setWindowFlags(msg_box.windowFlags() | Qt.WindowStaysOnTopHint)
|
|
3904
|
+
msg_box.setWindowFlags(msg_box.windowFlags() | Qt.WindowType.WindowStaysOnTopHint)
|
|
3904
3905
|
msg_box.exec()
|
|
3905
3906
|
return
|
|
3906
3907
|
|
|
@@ -4062,17 +4063,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
4062
4063
|
|
|
4063
4064
|
Args:
|
|
4064
4065
|
n_player (int): player
|
|
4065
|
-
new_time (
|
|
4066
|
+
new_time (float): new time in ms
|
|
4066
4067
|
"""
|
|
4068
|
+
new_time_dec = dec(new_time)
|
|
4067
4069
|
|
|
4068
4070
|
if self.dw_player[n_player].player.playlist_count == 1:
|
|
4069
4071
|
if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]:
|
|
4070
4072
|
if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)] > 0:
|
|
4071
|
-
if
|
|
4073
|
+
if new_time_dec < self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]:
|
|
4072
4074
|
# hide video and mute audio if time < offset
|
|
4073
4075
|
self.media_player_enabled(n_player, enable=False)
|
|
4074
4076
|
else:
|
|
4075
|
-
if
|
|
4077
|
+
if new_time_dec - dec(
|
|
4076
4078
|
self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]
|
|
4077
4079
|
) > sum(self.dw_player[n_player].media_durations):
|
|
4078
4080
|
# hide video and mute audio if required time > video time + offset
|
|
@@ -4081,26 +4083,27 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
4081
4083
|
# show video and enable audio
|
|
4082
4084
|
self.media_player_enabled(n_player, enable=True)
|
|
4083
4085
|
self.seek_mediaplayer(
|
|
4084
|
-
|
|
4086
|
+
new_time_dec
|
|
4085
4087
|
- dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]),
|
|
4086
4088
|
player=n_player,
|
|
4087
4089
|
)
|
|
4088
4090
|
|
|
4089
4091
|
elif self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)] < 0:
|
|
4090
|
-
if
|
|
4091
|
-
self.
|
|
4092
|
-
):
|
|
4092
|
+
if new_time_dec - dec(
|
|
4093
|
+
self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]
|
|
4094
|
+
) > sum(self.dw_player[n_player].media_durations):
|
|
4093
4095
|
# hide video and mute audio if required time > video time + offset
|
|
4094
4096
|
self.media_player_enabled(n_player, enable=False)
|
|
4095
4097
|
else:
|
|
4096
4098
|
self.media_player_enabled(n_player, enable=True)
|
|
4097
4099
|
self.seek_mediaplayer(
|
|
4098
|
-
|
|
4100
|
+
new_time_dec
|
|
4101
|
+
- dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]),
|
|
4099
4102
|
player=n_player,
|
|
4100
4103
|
)
|
|
4101
4104
|
|
|
4102
4105
|
else: # no offset
|
|
4103
|
-
self.seek_mediaplayer(
|
|
4106
|
+
self.seek_mediaplayer(new_time_dec, player=n_player)
|
|
4104
4107
|
|
|
4105
4108
|
elif self.dw_player[n_player].player.playlist_count > 1:
|
|
4106
4109
|
# check if new time is before the end of last video
|
|
@@ -4297,9 +4300,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
4297
4300
|
self.mem_media_name = current_media_name
|
|
4298
4301
|
self.mem_playlist_index = current_playlist_index
|
|
4299
4302
|
|
|
4300
|
-
playlist_length = len(self.dw_player[0].player.playlist)
|
|
4301
|
-
|
|
4302
4303
|
# update observation info
|
|
4304
|
+
playlist_length = len(playlist) if playlist else 0
|
|
4303
4305
|
msg = ""
|
|
4304
4306
|
if self.dw_player[0].player.time_pos is not None: # check if video
|
|
4305
4307
|
msg = f"Current media name: <b>{current_media_name}</b> (#{self.dw_player[0].player.playlist_pos + 1} / {playlist_length})<br>"
|
|
@@ -4920,21 +4922,21 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
4920
4922
|
self.update_project_zoom_pan_values()
|
|
4921
4923
|
|
|
4922
4924
|
# frame-by-frame mode
|
|
4923
|
-
if ek == 47 or (ek == Qt.Key_Left and modifier != cfg.CTRL_KEY): # / one frame back
|
|
4925
|
+
if ek == 47 or (ek == Qt.Key.Key_Left and modifier != cfg.CTRL_KEY): # / one frame back
|
|
4924
4926
|
self.previous_frame()
|
|
4925
4927
|
return
|
|
4926
4928
|
|
|
4927
|
-
if ek == 42 or (ek == Qt.Key_Right and modifier != cfg.CTRL_KEY): # * read next frame
|
|
4929
|
+
if ek == 42 or (ek == Qt.Key.Key_Right and modifier != cfg.CTRL_KEY): # * read next frame
|
|
4928
4930
|
self.next_frame()
|
|
4929
4931
|
return
|
|
4930
4932
|
|
|
4931
4933
|
if self.playerType in (cfg.MEDIA, cfg.IMAGES):
|
|
4932
4934
|
# next media file (page up)
|
|
4933
|
-
if ek == Qt.Key_PageUp:
|
|
4935
|
+
if ek == Qt.Key.Key_PageUp:
|
|
4934
4936
|
self.next_media_file()
|
|
4935
4937
|
|
|
4936
4938
|
# previous media file (page down)
|
|
4937
|
-
if ek == Qt.Key_PageDown:
|
|
4939
|
+
if ek == Qt.Key.Key_PageDown:
|
|
4938
4940
|
self.previous_media_file()
|
|
4939
4941
|
|
|
4940
4942
|
if not self.pj[cfg.ETHOGRAM]:
|
|
@@ -4977,20 +4979,20 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
4977
4979
|
return
|
|
4978
4980
|
|
|
4979
4981
|
if (
|
|
4980
|
-
((ek in range(33, 256)) and (ek not in [Qt.Key_Plus, Qt.Key_Minus]))
|
|
4982
|
+
((ek in range(33, 256)) and (ek not in [Qt.Key.Key_Plus, Qt.Key.Key_Minus]))
|
|
4981
4983
|
or (ek in cfg.function_keys)
|
|
4982
|
-
or (ek == Qt.Key_Enter and event.text())
|
|
4984
|
+
or (ek == Qt.Key.Key_Enter and event.text())
|
|
4983
4985
|
): # click from coding pad or subjects pad
|
|
4984
4986
|
if ek in cfg.function_keys:
|
|
4985
4987
|
ek_unichr = cfg.function_keys[ek]
|
|
4986
|
-
elif ek != Qt.Key_Enter:
|
|
4988
|
+
elif ek != Qt.Key.Key_Enter:
|
|
4987
4989
|
ek_unichr = ek_text
|
|
4988
|
-
elif ek == Qt.Key_Enter and event.text(): # click from coding pad or subjects pad
|
|
4990
|
+
elif ek == Qt.Key.Key_Enter and event.text(): # click from coding pad or subjects pad
|
|
4989
4991
|
ek_unichr = ek_text
|
|
4990
4992
|
|
|
4991
4993
|
logging.debug(f"{ek_unichr = }")
|
|
4992
4994
|
|
|
4993
|
-
if ek == Qt.Key_Enter and event.text(): # click from coding pad or subjects pad
|
|
4995
|
+
if ek == Qt.Key.Key_Enter and event.text(): # click from coding pad or subjects pad
|
|
4994
4996
|
ek_unichr = ""
|
|
4995
4997
|
|
|
4996
4998
|
if "#subject#" in event.text():
|
|
@@ -5032,7 +5034,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5032
5034
|
r = dialog.MessageDialog(
|
|
5033
5035
|
cfg.programName,
|
|
5034
5036
|
"This key defines a behavior and a subject. Choose one",
|
|
5035
|
-
|
|
5037
|
+
("&Behavior", "&Subject", cfg.CANCEL),
|
|
5036
5038
|
)
|
|
5037
5039
|
if r == cfg.CANCEL:
|
|
5038
5040
|
return
|
|
@@ -5085,7 +5087,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5085
5087
|
"The focal subject is not defined. Do you want to continue?\n"
|
|
5086
5088
|
"Use Preferences menu option to modify this behaviour."
|
|
5087
5089
|
),
|
|
5088
|
-
|
|
5090
|
+
(cfg.YES, cfg.NO),
|
|
5089
5091
|
)
|
|
5090
5092
|
|
|
5091
5093
|
if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE] == cfg.MEDIA and flagPlayerPlaying:
|
|
@@ -5257,7 +5259,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5257
5259
|
dialog.MessageDialog(
|
|
5258
5260
|
cfg.programName,
|
|
5259
5261
|
f"<b>{self.find_dialog.findText.text()}</b> not found. Search from beginning?",
|
|
5260
|
-
|
|
5262
|
+
(cfg.YES, cfg.NO),
|
|
5261
5263
|
)
|
|
5262
5264
|
== cfg.YES
|
|
5263
5265
|
):
|
|
@@ -5278,15 +5280,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5278
5280
|
self.find_replace_dialog.close()
|
|
5279
5281
|
return
|
|
5280
5282
|
if self.find_replace_dialog.combo_fields.currentIndex() == 0: # choose a field
|
|
5281
|
-
dialog.MessageDialog(cfg.programName, "Choose a field.",
|
|
5283
|
+
dialog.MessageDialog(cfg.programName, "Choose a field.", (cfg.OK,))
|
|
5282
5284
|
return
|
|
5283
5285
|
|
|
5284
5286
|
if not self.find_replace_dialog.findText.text():
|
|
5285
|
-
dialog.MessageDialog(cfg.programName, "There is nothing to find.",
|
|
5287
|
+
dialog.MessageDialog(cfg.programName, "There is nothing to find.", (cfg.OK,))
|
|
5286
5288
|
return
|
|
5287
5289
|
|
|
5288
5290
|
if self.find_replace_dialog.cbFindInSelectedEvents.isChecked() and not len(self.find_replace_dialog.rowsToFind):
|
|
5289
|
-
dialog.MessageDialog(cfg.programName, "There are no selected events",
|
|
5291
|
+
dialog.MessageDialog(cfg.programName, "There are no selected events", (cfg.OK,))
|
|
5290
5292
|
return
|
|
5291
5293
|
|
|
5292
5294
|
fields_list: list = []
|
|
@@ -5294,7 +5296,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5294
5296
|
# check if find and replace contain valid behavior codes
|
|
5295
5297
|
for bh in (self.find_replace_dialog.findText.text(), self.find_replace_dialog.replaceText.text()):
|
|
5296
5298
|
if bh not in util.all_subjects(self.pj[cfg.SUBJECTS]):
|
|
5297
|
-
dialog.MessageDialog(cfg.programName, f"<b>{bh}</b> is not a valid subject name",
|
|
5299
|
+
dialog.MessageDialog(cfg.programName, f"<b>{bh}</b> is not a valid subject name", (cfg.OK,))
|
|
5298
5300
|
return
|
|
5299
5301
|
fields_list.append(cfg.PJ_OBS_FIELDS[self.playerType][cfg.SUBJECT])
|
|
5300
5302
|
|
|
@@ -5302,7 +5304,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5302
5304
|
# check if find and replace contain valid behavior codes
|
|
5303
5305
|
for bh in (self.find_replace_dialog.findText.text(), self.find_replace_dialog.replaceText.text()):
|
|
5304
5306
|
if bh not in util.all_behaviors(self.pj[cfg.ETHOGRAM]):
|
|
5305
|
-
dialog.MessageDialog(cfg.programName, f"<b>{bh}</b> is not a valid behavior code",
|
|
5307
|
+
dialog.MessageDialog(cfg.programName, f"<b>{bh}</b> is not a valid behavior code", (cfg.OK,))
|
|
5306
5308
|
return
|
|
5307
5309
|
fields_list.append(cfg.PJ_OBS_FIELDS[self.playerType][cfg.BEHAVIOR_CODE])
|
|
5308
5310
|
|
|
@@ -5400,7 +5402,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5400
5402
|
self.find_replace_dialog.close()
|
|
5401
5403
|
|
|
5402
5404
|
if msg == "FIND_REPLACE_ALL":
|
|
5403
|
-
dialog.MessageDialog(cfg.programName, f"{number_replacement} substitution(s).",
|
|
5405
|
+
dialog.MessageDialog(cfg.programName, f"{number_replacement} substitution(s).", (cfg.OK,))
|
|
5404
5406
|
self.find_replace_dialog.close()
|
|
5405
5407
|
|
|
5406
5408
|
def closeEvent(self, event):
|
|
@@ -5430,7 +5432,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5430
5432
|
dialog.MessageDialog(
|
|
5431
5433
|
cfg.programName,
|
|
5432
5434
|
"BORIS is doing some job. What do you want to do?",
|
|
5433
|
-
|
|
5435
|
+
("Wait", "Quit BORIS"),
|
|
5434
5436
|
)
|
|
5435
5437
|
== "Wait"
|
|
5436
5438
|
):
|
|
@@ -5449,7 +5451,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5449
5451
|
response = dialog.MessageDialog(
|
|
5450
5452
|
cfg.programName,
|
|
5451
5453
|
"What to do about the current unsaved project?",
|
|
5452
|
-
|
|
5454
|
+
(cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
|
|
5453
5455
|
)
|
|
5454
5456
|
|
|
5455
5457
|
if response == cfg.SAVE:
|
|
@@ -5776,8 +5778,8 @@ def main():
|
|
|
5776
5778
|
None,
|
|
5777
5779
|
cfg.programName,
|
|
5778
5780
|
"FFmpeg is not available.<br>Go to http://www.ffmpeg.org to download it",
|
|
5779
|
-
QMessageBox.Ok | QMessageBox.Default,
|
|
5780
|
-
QMessageBox.NoButton,
|
|
5781
|
+
QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Default,
|
|
5782
|
+
QMessageBox.StandardButton.NoButton,
|
|
5781
5783
|
)
|
|
5782
5784
|
sys.exit(3)
|
|
5783
5785
|
|
|
@@ -5830,7 +5832,7 @@ def main():
|
|
|
5830
5832
|
config_param: dict = {}
|
|
5831
5833
|
ini_file_path = Path.home() / Path(".boris")
|
|
5832
5834
|
if ini_file_path.is_file():
|
|
5833
|
-
settings = QSettings(str(ini_file_path), QSettings.IniFormat)
|
|
5835
|
+
settings = QSettings(str(ini_file_path), QSettings.Format.IniFormat)
|
|
5834
5836
|
try:
|
|
5835
5837
|
config_param = settings.value("config")
|
|
5836
5838
|
except Exception:
|
|
@@ -5863,8 +5865,8 @@ def main():
|
|
|
5863
5865
|
None,
|
|
5864
5866
|
cfg.programName,
|
|
5865
5867
|
("The mpv command is not available on the path"),
|
|
5866
|
-
QMessageBox.Ok | QMessageBox.Default,
|
|
5867
|
-
QMessageBox.NoButton,
|
|
5868
|
+
QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Default,
|
|
5869
|
+
QMessageBox.StandardButton.NoButton,
|
|
5868
5870
|
)
|
|
5869
5871
|
sys.exit()
|
|
5870
5872
|
|
|
@@ -5873,8 +5875,8 @@ def main():
|
|
|
5873
5875
|
None,
|
|
5874
5876
|
cfg.programName,
|
|
5875
5877
|
("This version of BORIS for macOS is still EXPERIMENTAL and should be used at your own risk."),
|
|
5876
|
-
QMessageBox.Ok | QMessageBox.Default,
|
|
5877
|
-
QMessageBox.NoButton,
|
|
5878
|
+
QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Default,
|
|
5879
|
+
QMessageBox.StandardButton.NoButton,
|
|
5878
5880
|
)
|
|
5879
5881
|
|
|
5880
5882
|
window.show()
|
|
@@ -5887,8 +5889,8 @@ def main():
|
|
|
5887
5889
|
None,
|
|
5888
5890
|
cfg.programName,
|
|
5889
5891
|
(f"Error opening observation: <b>{observation_to_open}</b><br>{r.split(':')[1]}"),
|
|
5890
|
-
QMessageBox.Ok | QMessageBox.Default,
|
|
5891
|
-
QMessageBox.NoButton,
|
|
5892
|
+
QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Default,
|
|
5893
|
+
QMessageBox.StandardButton.NoButton,
|
|
5892
5894
|
)
|
|
5893
5895
|
|
|
5894
5896
|
if not options.nosplashscreen and (sys.platform != "darwin"):
|