boris-behav-obs 9.7.7__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.
Files changed (109) hide show
  1. boris/__init__.py +26 -0
  2. boris/__main__.py +25 -0
  3. boris/about.py +143 -0
  4. boris/add_modifier.py +635 -0
  5. boris/add_modifier_ui.py +303 -0
  6. boris/advanced_event_filtering.py +455 -0
  7. boris/analysis_plugins/__init__.py +0 -0
  8. boris/analysis_plugins/_latency.py +59 -0
  9. boris/analysis_plugins/irr_cohen_kappa.py +109 -0
  10. boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +112 -0
  11. boris/analysis_plugins/irr_weighted_cohen_kappa.py +157 -0
  12. boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +162 -0
  13. boris/analysis_plugins/list_of_dataframe_columns.py +22 -0
  14. boris/analysis_plugins/number_of_occurences.py +22 -0
  15. boris/analysis_plugins/number_of_occurences_by_independent_variable.py +54 -0
  16. boris/analysis_plugins/time_budget.py +61 -0
  17. boris/behav_coding_map_creator.py +1110 -0
  18. boris/behavior_binary_table.py +305 -0
  19. boris/behaviors_coding_map.py +239 -0
  20. boris/boris_cli.py +340 -0
  21. boris/cmd_arguments.py +49 -0
  22. boris/coding_pad.py +280 -0
  23. boris/config.py +785 -0
  24. boris/config_file.py +356 -0
  25. boris/connections.py +409 -0
  26. boris/converters.py +333 -0
  27. boris/converters_ui.py +225 -0
  28. boris/cooccurence.py +250 -0
  29. boris/core.py +5901 -0
  30. boris/core_qrc.py +15958 -0
  31. boris/core_ui.py +1107 -0
  32. boris/db_functions.py +324 -0
  33. boris/dev.py +134 -0
  34. boris/dialog.py +1108 -0
  35. boris/duration_widget.py +238 -0
  36. boris/edit_event.py +245 -0
  37. boris/edit_event_ui.py +233 -0
  38. boris/event_operations.py +1040 -0
  39. boris/events_cursor.py +61 -0
  40. boris/events_snapshots.py +596 -0
  41. boris/exclusion_matrix.py +141 -0
  42. boris/export_events.py +1006 -0
  43. boris/export_observation.py +1203 -0
  44. boris/external_processes.py +332 -0
  45. boris/geometric_measurement.py +941 -0
  46. boris/gui_utilities.py +135 -0
  47. boris/image_overlay.py +72 -0
  48. boris/import_observations.py +242 -0
  49. boris/ipc_mpv.py +325 -0
  50. boris/irr.py +634 -0
  51. boris/latency.py +244 -0
  52. boris/measurement_widget.py +161 -0
  53. boris/media_file.py +115 -0
  54. boris/menu_options.py +213 -0
  55. boris/modifier_coding_map_creator.py +1013 -0
  56. boris/modifiers_coding_map.py +157 -0
  57. boris/mpv.py +2016 -0
  58. boris/mpv2.py +2193 -0
  59. boris/observation.py +1453 -0
  60. boris/observation_operations.py +2538 -0
  61. boris/observation_ui.py +679 -0
  62. boris/observations_list.py +337 -0
  63. boris/otx_parser.py +442 -0
  64. boris/param_panel.py +201 -0
  65. boris/param_panel_ui.py +305 -0
  66. boris/player_dock_widget.py +198 -0
  67. boris/plot_data_module.py +536 -0
  68. boris/plot_events.py +634 -0
  69. boris/plot_events_rt.py +237 -0
  70. boris/plot_spectrogram_rt.py +316 -0
  71. boris/plot_waveform_rt.py +230 -0
  72. boris/plugins.py +431 -0
  73. boris/portion/__init__.py +31 -0
  74. boris/portion/const.py +95 -0
  75. boris/portion/dict.py +365 -0
  76. boris/portion/func.py +52 -0
  77. boris/portion/interval.py +581 -0
  78. boris/portion/io.py +181 -0
  79. boris/preferences.py +510 -0
  80. boris/preferences_ui.py +770 -0
  81. boris/project.py +2007 -0
  82. boris/project_functions.py +2041 -0
  83. boris/project_import_export.py +1096 -0
  84. boris/project_ui.py +794 -0
  85. boris/qrc_boris.py +10389 -0
  86. boris/qrc_boris5.py +2579 -0
  87. boris/select_modifiers.py +312 -0
  88. boris/select_observations.py +210 -0
  89. boris/select_subj_behav.py +286 -0
  90. boris/state_events.py +197 -0
  91. boris/subjects_pad.py +106 -0
  92. boris/synthetic_time_budget.py +290 -0
  93. boris/time_budget_functions.py +1136 -0
  94. boris/time_budget_widget.py +1039 -0
  95. boris/transitions.py +365 -0
  96. boris/utilities.py +1810 -0
  97. boris/version.py +24 -0
  98. boris/video_equalizer.py +159 -0
  99. boris/video_equalizer_ui.py +248 -0
  100. boris/video_operations.py +310 -0
  101. boris/view_df.py +104 -0
  102. boris/view_df_ui.py +75 -0
  103. boris/write_event.py +538 -0
  104. boris_behav_obs-9.7.7.dist-info/METADATA +139 -0
  105. boris_behav_obs-9.7.7.dist-info/RECORD +109 -0
  106. boris_behav_obs-9.7.7.dist-info/WHEEL +5 -0
  107. boris_behav_obs-9.7.7.dist-info/entry_points.txt +2 -0
  108. boris_behav_obs-9.7.7.dist-info/licenses/LICENSE.TXT +674 -0
  109. boris_behav_obs-9.7.7.dist-info/top_level.txt +1 -0
@@ -0,0 +1,305 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ################################################################################
4
+ ## Form generated from reading UI file 'param_panel.ui'
5
+ ##
6
+ ## Created by: Qt User Interface Compiler version 6.8.0
7
+ ##
8
+ ## WARNING! All changes made in this file will be lost when recompiling UI file!
9
+ ################################################################################
10
+
11
+ from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
12
+ QMetaObject, QObject, QPoint, QRect,
13
+ QSize, QTime, QUrl, Qt)
14
+ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
15
+ QFont, QFontDatabase, QGradient, QIcon,
16
+ QImage, QKeySequence, QLinearGradient, QPainter,
17
+ QPalette, QPixmap, QRadialGradient, QTransform)
18
+ from PySide6.QtWidgets import (QApplication, QCheckBox, QDialog, QFrame,
19
+ QHBoxLayout, QLabel, QListWidget, QListWidgetItem,
20
+ QPushButton, QRadioButton, QSizePolicy, QSpacerItem,
21
+ QSpinBox, QVBoxLayout, QWidget)
22
+
23
+ class Ui_Dialog(object):
24
+ def setupUi(self, Dialog):
25
+ if not Dialog.objectName():
26
+ Dialog.setObjectName(u"Dialog")
27
+ Dialog.resize(1037, 890)
28
+ self.verticalLayout_4 = QVBoxLayout(Dialog)
29
+ self.verticalLayout_4.setObjectName(u"verticalLayout_4")
30
+ self.verticalLayout_2 = QVBoxLayout()
31
+ self.verticalLayout_2.setObjectName(u"verticalLayout_2")
32
+ self.lbSubjects = QLabel(Dialog)
33
+ self.lbSubjects.setObjectName(u"lbSubjects")
34
+
35
+ self.verticalLayout_2.addWidget(self.lbSubjects)
36
+
37
+ self.horizontalLayout_3 = QHBoxLayout()
38
+ self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
39
+ self.pbSelectAllSubjects = QPushButton(Dialog)
40
+ self.pbSelectAllSubjects.setObjectName(u"pbSelectAllSubjects")
41
+
42
+ self.horizontalLayout_3.addWidget(self.pbSelectAllSubjects)
43
+
44
+ self.pbUnselectAllSubjects = QPushButton(Dialog)
45
+ self.pbUnselectAllSubjects.setObjectName(u"pbUnselectAllSubjects")
46
+
47
+ self.horizontalLayout_3.addWidget(self.pbUnselectAllSubjects)
48
+
49
+ self.pbReverseSubjectsSelection = QPushButton(Dialog)
50
+ self.pbReverseSubjectsSelection.setObjectName(u"pbReverseSubjectsSelection")
51
+
52
+ self.horizontalLayout_3.addWidget(self.pbReverseSubjectsSelection)
53
+
54
+ self.horizontalSpacer_4 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
55
+
56
+ self.horizontalLayout_3.addItem(self.horizontalSpacer_4)
57
+
58
+
59
+ self.verticalLayout_2.addLayout(self.horizontalLayout_3)
60
+
61
+ self.lwSubjects = QListWidget(Dialog)
62
+ self.lwSubjects.setObjectName(u"lwSubjects")
63
+
64
+ self.verticalLayout_2.addWidget(self.lwSubjects)
65
+
66
+ self.lbBehaviors = QLabel(Dialog)
67
+ self.lbBehaviors.setObjectName(u"lbBehaviors")
68
+
69
+ self.verticalLayout_2.addWidget(self.lbBehaviors)
70
+
71
+ self.horizontalLayout_4 = QHBoxLayout()
72
+ self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
73
+ self.pbSelectAllBehaviors = QPushButton(Dialog)
74
+ self.pbSelectAllBehaviors.setObjectName(u"pbSelectAllBehaviors")
75
+
76
+ self.horizontalLayout_4.addWidget(self.pbSelectAllBehaviors)
77
+
78
+ self.pbUnselectAllBehaviors = QPushButton(Dialog)
79
+ self.pbUnselectAllBehaviors.setObjectName(u"pbUnselectAllBehaviors")
80
+
81
+ self.horizontalLayout_4.addWidget(self.pbUnselectAllBehaviors)
82
+
83
+ self.pbReverseBehaviorsSelection = QPushButton(Dialog)
84
+ self.pbReverseBehaviorsSelection.setObjectName(u"pbReverseBehaviorsSelection")
85
+
86
+ self.horizontalLayout_4.addWidget(self.pbReverseBehaviorsSelection)
87
+
88
+ self.horizontalSpacer_5 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
89
+
90
+ self.horizontalLayout_4.addItem(self.horizontalSpacer_5)
91
+
92
+
93
+ self.verticalLayout_2.addLayout(self.horizontalLayout_4)
94
+
95
+ self.lwBehaviors = QListWidget(Dialog)
96
+ self.lwBehaviors.setObjectName(u"lwBehaviors")
97
+
98
+ self.verticalLayout_2.addWidget(self.lwBehaviors)
99
+
100
+ self.horizontalLayout_9 = QHBoxLayout()
101
+ self.horizontalLayout_9.setObjectName(u"horizontalLayout_9")
102
+ self.cbIncludeModifiers = QCheckBox(Dialog)
103
+ self.cbIncludeModifiers.setObjectName(u"cbIncludeModifiers")
104
+
105
+ self.horizontalLayout_9.addWidget(self.cbIncludeModifiers)
106
+
107
+ self.cb_exclude_non_coded_modifiers = QCheckBox(Dialog)
108
+ self.cb_exclude_non_coded_modifiers.setObjectName(u"cb_exclude_non_coded_modifiers")
109
+ self.cb_exclude_non_coded_modifiers.setChecked(True)
110
+
111
+ self.horizontalLayout_9.addWidget(self.cb_exclude_non_coded_modifiers)
112
+
113
+ self.cbExcludeBehaviors = QCheckBox(Dialog)
114
+ self.cbExcludeBehaviors.setObjectName(u"cbExcludeBehaviors")
115
+
116
+ self.horizontalLayout_9.addWidget(self.cbExcludeBehaviors)
117
+
118
+ self.horizontalSpacer_7 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
119
+
120
+ self.horizontalLayout_9.addItem(self.horizontalSpacer_7)
121
+
122
+
123
+ self.verticalLayout_2.addLayout(self.horizontalLayout_9)
124
+
125
+ self.frm_time_bin_size = QFrame(Dialog)
126
+ self.frm_time_bin_size.setObjectName(u"frm_time_bin_size")
127
+ self.frm_time_bin_size.setFrameShape(QFrame.StyledPanel)
128
+ self.frm_time_bin_size.setFrameShadow(QFrame.Raised)
129
+ self.horizontalLayout_8 = QHBoxLayout(self.frm_time_bin_size)
130
+ self.horizontalLayout_8.setObjectName(u"horizontalLayout_8")
131
+ self.horizontalLayout_7 = QHBoxLayout()
132
+ self.horizontalLayout_7.setObjectName(u"horizontalLayout_7")
133
+ self.lb_time_bin_size = QLabel(self.frm_time_bin_size)
134
+ self.lb_time_bin_size.setObjectName(u"lb_time_bin_size")
135
+
136
+ self.horizontalLayout_7.addWidget(self.lb_time_bin_size)
137
+
138
+ self.sb_time_bin_size = QSpinBox(self.frm_time_bin_size)
139
+ self.sb_time_bin_size.setObjectName(u"sb_time_bin_size")
140
+ self.sb_time_bin_size.setMaximum(86400)
141
+ self.sb_time_bin_size.setSingleStep(10)
142
+
143
+ self.horizontalLayout_7.addWidget(self.sb_time_bin_size)
144
+
145
+ self.horizontalSpacer_8 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
146
+
147
+ self.horizontalLayout_7.addItem(self.horizontalSpacer_8)
148
+
149
+
150
+ self.horizontalLayout_8.addLayout(self.horizontalLayout_7)
151
+
152
+
153
+ self.verticalLayout_2.addWidget(self.frm_time_bin_size)
154
+
155
+ self.frm_time = QFrame(Dialog)
156
+ self.frm_time.setObjectName(u"frm_time")
157
+ self.frm_time.setFrameShape(QFrame.StyledPanel)
158
+ self.frm_time.setFrameShadow(QFrame.Raised)
159
+ self.verticalLayout_3 = QVBoxLayout(self.frm_time)
160
+ self.verticalLayout_3.setObjectName(u"verticalLayout_3")
161
+ self.lb_time_interval = QLabel(self.frm_time)
162
+ self.lb_time_interval.setObjectName(u"lb_time_interval")
163
+
164
+ self.verticalLayout_3.addWidget(self.lb_time_interval)
165
+
166
+ self.horizontalLayout_5 = QHBoxLayout()
167
+ self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
168
+ self.rb_observed_events = QRadioButton(self.frm_time)
169
+ self.rb_observed_events.setObjectName(u"rb_observed_events")
170
+
171
+ self.horizontalLayout_5.addWidget(self.rb_observed_events)
172
+
173
+ self.rb_user_defined = QRadioButton(self.frm_time)
174
+ self.rb_user_defined.setObjectName(u"rb_user_defined")
175
+
176
+ self.horizontalLayout_5.addWidget(self.rb_user_defined)
177
+
178
+ self.rb_obs_interval = QRadioButton(self.frm_time)
179
+ self.rb_obs_interval.setObjectName(u"rb_obs_interval")
180
+
181
+ self.horizontalLayout_5.addWidget(self.rb_obs_interval)
182
+
183
+ self.rb_media_duration = QRadioButton(self.frm_time)
184
+ self.rb_media_duration.setObjectName(u"rb_media_duration")
185
+ self.rb_media_duration.setCheckable(True)
186
+ self.rb_media_duration.setChecked(False)
187
+
188
+ self.horizontalLayout_5.addWidget(self.rb_media_duration)
189
+
190
+ self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
191
+
192
+ self.horizontalLayout_5.addItem(self.horizontalSpacer_3)
193
+
194
+
195
+ self.verticalLayout_3.addLayout(self.horizontalLayout_5)
196
+
197
+ self.frm_time_interval = QFrame(self.frm_time)
198
+ self.frm_time_interval.setObjectName(u"frm_time_interval")
199
+ self.frm_time_interval.setFrameShape(QFrame.StyledPanel)
200
+ self.frm_time_interval.setFrameShadow(QFrame.Raised)
201
+ self.verticalLayout = QVBoxLayout(self.frm_time_interval)
202
+ self.verticalLayout.setObjectName(u"verticalLayout")
203
+ self.horizontalLayout = QHBoxLayout()
204
+ self.horizontalLayout.setObjectName(u"horizontalLayout")
205
+ self.lbStartTime = QLabel(self.frm_time_interval)
206
+ self.lbStartTime.setObjectName(u"lbStartTime")
207
+
208
+ self.horizontalLayout.addWidget(self.lbStartTime)
209
+
210
+ self.label_2 = QLabel(self.frm_time_interval)
211
+ self.label_2.setObjectName(u"label_2")
212
+
213
+ self.horizontalLayout.addWidget(self.label_2)
214
+
215
+ self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
216
+
217
+ self.horizontalLayout.addItem(self.horizontalSpacer_2)
218
+
219
+
220
+ self.verticalLayout.addLayout(self.horizontalLayout)
221
+
222
+ self.horizontalLayout_6 = QHBoxLayout()
223
+ self.horizontalLayout_6.setObjectName(u"horizontalLayout_6")
224
+ self.lbEndTime = QLabel(self.frm_time_interval)
225
+ self.lbEndTime.setObjectName(u"lbEndTime")
226
+
227
+ self.horizontalLayout_6.addWidget(self.lbEndTime)
228
+
229
+ self.label_3 = QLabel(self.frm_time_interval)
230
+ self.label_3.setObjectName(u"label_3")
231
+
232
+ self.horizontalLayout_6.addWidget(self.label_3)
233
+
234
+ self.horizontalSpacer_6 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
235
+
236
+ self.horizontalLayout_6.addItem(self.horizontalSpacer_6)
237
+
238
+
239
+ self.verticalLayout.addLayout(self.horizontalLayout_6)
240
+
241
+ self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
242
+
243
+ self.verticalLayout.addItem(self.verticalSpacer)
244
+
245
+
246
+ self.verticalLayout_3.addWidget(self.frm_time_interval)
247
+
248
+
249
+ self.verticalLayout_2.addWidget(self.frm_time)
250
+
251
+ self.horizontalLayout_2 = QHBoxLayout()
252
+ self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
253
+ self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
254
+
255
+ self.horizontalLayout_2.addItem(self.horizontalSpacer)
256
+
257
+ self.pbCancel = QPushButton(Dialog)
258
+ self.pbCancel.setObjectName(u"pbCancel")
259
+
260
+ self.horizontalLayout_2.addWidget(self.pbCancel)
261
+
262
+ self.pbOK = QPushButton(Dialog)
263
+ self.pbOK.setObjectName(u"pbOK")
264
+
265
+ self.horizontalLayout_2.addWidget(self.pbOK)
266
+
267
+
268
+ self.verticalLayout_2.addLayout(self.horizontalLayout_2)
269
+
270
+
271
+ self.verticalLayout_4.addLayout(self.verticalLayout_2)
272
+
273
+
274
+ self.retranslateUi(Dialog)
275
+
276
+ QMetaObject.connectSlotsByName(Dialog)
277
+ # setupUi
278
+
279
+ def retranslateUi(self, Dialog):
280
+ Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Parameters", None))
281
+ self.lbSubjects.setText(QCoreApplication.translate("Dialog", u"Subjects", None))
282
+ self.pbSelectAllSubjects.setText(QCoreApplication.translate("Dialog", u"Select all", None))
283
+ self.pbUnselectAllSubjects.setText(QCoreApplication.translate("Dialog", u"Unselect all", None))
284
+ self.pbReverseSubjectsSelection.setText(QCoreApplication.translate("Dialog", u"Reverse selection", None))
285
+ self.lbBehaviors.setText(QCoreApplication.translate("Dialog", u"Behaviors", None))
286
+ self.pbSelectAllBehaviors.setText(QCoreApplication.translate("Dialog", u"Select all", None))
287
+ self.pbUnselectAllBehaviors.setText(QCoreApplication.translate("Dialog", u"Unselect all", None))
288
+ self.pbReverseBehaviorsSelection.setText(QCoreApplication.translate("Dialog", u"Reverse selection", None))
289
+ self.cbIncludeModifiers.setText(QCoreApplication.translate("Dialog", u"Include modifiers", None))
290
+ self.cb_exclude_non_coded_modifiers.setText(QCoreApplication.translate("Dialog", u"Exclude non coded modifiers", None))
291
+ self.cbExcludeBehaviors.setText(QCoreApplication.translate("Dialog", u"Exclude behaviors without events", None))
292
+ self.lb_time_bin_size.setText(QCoreApplication.translate("Dialog", u"Time bin size (s)", None))
293
+ self.lb_time_interval.setText(QCoreApplication.translate("Dialog", u"Time interval", None))
294
+ self.rb_observed_events.setText(QCoreApplication.translate("Dialog", u"Observed events", None))
295
+ self.rb_user_defined.setText(QCoreApplication.translate("Dialog", u"User defined", None))
296
+ self.rb_obs_interval.setText(QCoreApplication.translate("Dialog", u"Interval of observation", None))
297
+ self.rb_media_duration.setText(QCoreApplication.translate("Dialog", u"Media file(s) duration", None))
298
+ self.lbStartTime.setText(QCoreApplication.translate("Dialog", u"Start time", None))
299
+ self.label_2.setText("")
300
+ self.lbEndTime.setText(QCoreApplication.translate("Dialog", u"End time", None))
301
+ self.label_3.setText("")
302
+ self.pbCancel.setText(QCoreApplication.translate("Dialog", u"Cancel", None))
303
+ self.pbOK.setText(QCoreApplication.translate("Dialog", u"OK", None))
304
+ # retranslateUi
305
+
@@ -0,0 +1,198 @@
1
+ """
2
+ BORIS
3
+ Behavioral Observation Research Interactive Software
4
+ Copyright 2012-2025 Olivier Friard
5
+
6
+ This file is part of BORIS.
7
+
8
+ BORIS is free software; you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License as published by
10
+ the Free Software Foundation; either version 3 of the License, or
11
+ any later version.
12
+
13
+ BORIS is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU General Public License for more details.
17
+
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/licenses/>.
20
+
21
+ """
22
+
23
+ import sys
24
+ import logging
25
+ import functools
26
+
27
+ if (sys.platform.startswith("win") or sys.platform.startswith("linux")) and ("-i" not in sys.argv) and ("--ipc" not in sys.argv):
28
+ from . import mpv2 as mpv
29
+ else:
30
+ import ipc_mpv
31
+ import config as cfg
32
+ import gui_utilities
33
+
34
+
35
+ from PySide6.QtWidgets import (
36
+ QLabel,
37
+ QDockWidget,
38
+ QWidget,
39
+ QHBoxLayout,
40
+ QVBoxLayout,
41
+ QSlider,
42
+ QSizePolicy,
43
+ QStackedWidget,
44
+ QToolButton,
45
+ )
46
+ from PySide6.QtCore import Signal, QEvent, Qt
47
+ from PySide6.QtGui import QIcon, QAction
48
+
49
+
50
+ class Clickable_label(QLabel):
51
+ """
52
+ QLabel class for visualiziong frames for geometric measurments
53
+ Label emits a signal when clicked
54
+ """
55
+
56
+ mouse_pressed_signal = Signal(int, QEvent)
57
+
58
+ def __init__(self, id_, parent=None):
59
+ QLabel.__init__(self, parent)
60
+ self.id_ = id_
61
+
62
+ def mousePressEvent(self, event):
63
+ """
64
+ label clicked
65
+ """
66
+ logging.debug(f"mousepress event: label {self.id_} clicked {event.pos()}")
67
+
68
+ """
69
+ super().mousePressEvent(event)
70
+ x, y = event.pos().x(), event.pos().y()
71
+ draw_on_pixmap(self, x, y) # Example usage
72
+ """
73
+
74
+ self.mouse_pressed_signal.emit(self.id_, event)
75
+
76
+
77
+ def mpv_logger(player_id, loglevel, component, message):
78
+ """
79
+ redirect MPV log messages to general logging system
80
+ """
81
+
82
+ logging.debug(f"MPV player #{player_id}: [{loglevel}] {component}: {message}")
83
+
84
+
85
+ class DW_player(QDockWidget):
86
+ """
87
+ Define the player class
88
+ """
89
+
90
+ key_pressed_signal = Signal(QEvent)
91
+ volume_slider_moved_signal = Signal(int, int)
92
+ mute_action_triggered_signal = Signal(int)
93
+ view_signal = Signal(int, str, int)
94
+ resize_signal = Signal(int)
95
+
96
+ def __init__(self, id_, parent=None):
97
+ super().__init__(parent)
98
+ # print("ipc", parent.MPV_IPC_MODE)
99
+ self.id_ = id_
100
+ self.setWindowTitle(f"Player #{id_ + 1}")
101
+ self.setObjectName(f"player{id_ + 1}")
102
+
103
+ self.stack1 = QWidget()
104
+ self.hlayout = QHBoxLayout()
105
+
106
+ self.videoframe = QWidget(self)
107
+
108
+ if parent.MPV_IPC_MODE:
109
+ self.player = ipc_mpv.IPC_MPV(socket_path=f"{cfg.MPV_SOCKET}{self.id_}")
110
+ else:
111
+ self.player = mpv.MPV(
112
+ wid=str(int(self.videoframe.winId())),
113
+ vo="x11" if sys.platform.startswith("linux") else "",
114
+ log_handler=functools.partial(mpv_logger, self.id_),
115
+ loglevel="debug",
116
+ )
117
+
118
+ self.player.screenshot_format = "png"
119
+ self.hlayout.addWidget(self.videoframe)
120
+
121
+ # layout volume slider and mute button
122
+ self.vlayout = QVBoxLayout()
123
+
124
+ # volume slider
125
+ self.volume_slider = QSlider(Qt.Vertical, self)
126
+ self.volume_slider.setFocusPolicy(Qt.NoFocus)
127
+ self.volume_slider.setMaximum(100)
128
+ self.volume_slider.setValue(50)
129
+ self.volume_slider.sliderMoved.connect(self.volume_slider_moved)
130
+
131
+ self.vlayout.addWidget(self.volume_slider)
132
+
133
+ # mute button
134
+ self.mute_button = QToolButton()
135
+ self.mute_button.setFocusPolicy(Qt.NoFocus)
136
+ self.mute_button.setAutoRaise(True)
137
+ self.mute_action = QAction()
138
+
139
+ theme_mode = gui_utilities.theme_mode()
140
+
141
+ self.mute_action.setIcon(QIcon(f":/volume_xmark_{theme_mode}"))
142
+ self.mute_action.triggered.connect(self.mute_action_triggered)
143
+ self.mute_button.setDefaultAction(self.mute_action)
144
+
145
+ self.vlayout.addWidget(self.mute_button)
146
+
147
+ self.hlayout.addLayout(self.vlayout)
148
+
149
+ self.stack1.setLayout(self.hlayout)
150
+
151
+ self.stack2 = QWidget()
152
+ self.hlayout2 = QHBoxLayout()
153
+ self.frame_viewer = Clickable_label(id_)
154
+
155
+ self.frame_viewer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
156
+ self.frame_viewer.setAlignment(Qt.AlignCenter)
157
+ self.frame_viewer.setStyleSheet("QLabel {background-color: black;}")
158
+
159
+ self.hlayout2.addWidget(self.frame_viewer)
160
+ self.stack2.setLayout(self.hlayout2)
161
+
162
+ self.stack = QStackedWidget(self)
163
+ self.stack.addWidget(self.stack1)
164
+ self.stack.addWidget(self.stack2)
165
+
166
+ self.setWidget(self.stack)
167
+
168
+ self.stack.setCurrentIndex(0)
169
+
170
+ def volume_slider_moved(self):
171
+ """
172
+ emit signal when volume slider moved
173
+ """
174
+ self.volume_slider_moved_signal.emit(self.id_, self.volume_slider.value())
175
+
176
+ def mute_action_triggered(self):
177
+ """
178
+ emit signal when mute action is triggered
179
+ """
180
+ theme_mode = gui_utilities.theme_mode()
181
+ if self.player.mute:
182
+ self.mute_action.setIcon(QIcon(f":/volume_xmark_{theme_mode}"))
183
+ else:
184
+ self.mute_action.setIcon(QIcon(f":/volume_off_{theme_mode}"))
185
+ self.mute_action_triggered_signal.emit(self.id_)
186
+
187
+ def keyPressEvent(self, event):
188
+ """
189
+ emit signal when key pressed on dock widget
190
+ """
191
+ self.key_pressed_signal.emit(event)
192
+
193
+ def resizeEvent(self, _):
194
+ """
195
+ emits signal when dockwidget resized
196
+ """
197
+
198
+ self.resize_signal.emit(self.id_)