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.

Potentially problematic release.


This version of boris-behav-obs might be problematic. Click here for more details.

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,310 @@
1
+ """
2
+ BORIS
3
+ Behavioral Observation Research Interactive Software
4
+ Copyright 2012-2025 Olivier Friard
5
+
6
+
7
+ This program is free software; you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation; either version 2 of the License, or
10
+ (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program; if not, write to the Free Software
19
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ MA 02110-1301, USA.
21
+
22
+ """
23
+
24
+ import logging
25
+ import pathlib as pl
26
+ import shutil
27
+ from math import log2
28
+
29
+ from PySide6.QtWidgets import QFileDialog
30
+
31
+ from . import config as cfg
32
+ from . import dialog
33
+
34
+
35
+ def deinterlace(self):
36
+ """
37
+ change the deinterlace status of player
38
+ """
39
+
40
+ logging.info("change deinterlace status of player")
41
+
42
+ for dw in self.dw_player:
43
+ dw.player.deinterlace = self.action_deinterlace.isChecked()
44
+
45
+
46
+ def snapshot(self):
47
+ """
48
+ MEDIA obs: take snapshot of current video at current position
49
+ IMAGES obs: save a copy of the current image
50
+
51
+ snapshot is saved on media path following the template: MEDIA-FILE-NAME_TIME-POSITION.png
52
+ """
53
+
54
+ if self.playerType == cfg.MEDIA:
55
+ for i, player in enumerate(self.dw_player):
56
+ if (
57
+ str(i + 1) in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE]
58
+ and self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][str(i + 1)]
59
+ ):
60
+ p = pl.Path(self.dw_player[0].player.playlist[self.dw_player[0].player.playlist_pos]["filename"])
61
+
62
+ snapshot_file_path = str(p.parent / f"{p.stem}_{player.player.time_pos:0.3f}.png")
63
+
64
+ player.player.screenshot_to_file(snapshot_file_path)
65
+ self.statusbar.showMessage(f"Video snapshot saved in {snapshot_file_path}", 0)
66
+
67
+ logging.debug(f"video snapshot saved in {snapshot_file_path}")
68
+
69
+ if self.playerType == cfg.IMAGES:
70
+ output_file_name, _ = QFileDialog().getSaveFileName(
71
+ self, "Save copy of the current image", pl.Path(self.images_list[self.image_idx]).name
72
+ )
73
+ if output_file_name:
74
+ shutil.copyfile(self.images_list[self.image_idx], output_file_name)
75
+ self.statusbar.showMessage(f"Image saved in {output_file_name}", 0)
76
+
77
+ logging.debug(f"video snapshot saved in {output_file_name}")
78
+
79
+
80
+ def zoom_level(self):
81
+ """
82
+ display dialog box for setting the zoom level
83
+ """
84
+ logging.info("change zoom level of player")
85
+
86
+ players_list: list = []
87
+ for idx, dw in enumerate(self.dw_player):
88
+ players_list.append(("dsb", f"Player #{idx + 1}", 0.1, 12, 0.1, 2**dw.player.video_zoom, 1))
89
+
90
+ zl = dialog.Input_dialog(label_caption="Select the zoom level", elements_list=players_list, title="Video zoom level")
91
+ if not zl.exec_():
92
+ return
93
+
94
+ if cfg.ZOOM_LEVEL not in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO]:
95
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.ZOOM_LEVEL] = {}
96
+
97
+ for idx, dw in enumerate(self.dw_player):
98
+ if (
99
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.ZOOM_LEVEL].get(str(idx + 1), dw.player.video_zoom)
100
+ != zl.elements[f"Player #{idx + 1}"].value()
101
+ ):
102
+ dw.player.video_zoom = log2(float(zl.elements[f"Player #{idx + 1}"].value()))
103
+
104
+ logging.debug(f"video zoom changed in {dw.player.video_zoom} for player {idx + 1}")
105
+
106
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.ZOOM_LEVEL][str(idx + 1)] = float(
107
+ zl.elements[f"Player #{idx + 1}"].value()
108
+ )
109
+ display_zoom_level(self)
110
+ self.project_changed()
111
+
112
+
113
+ def change_player_offset(self):
114
+ """
115
+ display dialog box for setting the player time offset
116
+ """
117
+ logging.info("change the player time offset")
118
+
119
+ if cfg.OFFSET not in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO]:
120
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET] = {}
121
+
122
+ players_list: list = []
123
+
124
+ for idx, dw in enumerate(self.dw_player):
125
+ players_list.append(
126
+ (
127
+ "dsb",
128
+ f"Player #{idx + 1}",
129
+ -100000,
130
+ 100000,
131
+ 0.001,
132
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(idx + 1)],
133
+ 3,
134
+ )
135
+ )
136
+
137
+ zl = dialog.Input_dialog(label_caption="Select the time offset", elements_list=players_list, title="Time offset")
138
+ if not zl.exec_():
139
+ return
140
+
141
+ for idx, dw in enumerate(self.dw_player):
142
+ if (
143
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET].get(str(idx + 1), 0)
144
+ != zl.elements[f"Player #{idx + 1}"].value()
145
+ ):
146
+ logging.debug(f"time offset of player changed in {zl.elements[f'Player #{idx + 1}'].value()} for player {idx + 1}")
147
+
148
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(idx + 1)] = float(
149
+ zl.elements[f"Player #{idx + 1}"].value()
150
+ )
151
+
152
+ if self.dw_player[0].player.time_pos is not None:
153
+ cumulative_time_pos = self.getLaps() # for player 1
154
+ self.sync_time(idx, cumulative_time_pos)
155
+
156
+ self.project_changed()
157
+
158
+
159
+ def rotate_displayed_video(self):
160
+ """
161
+ rotate the displayed video
162
+ """
163
+ players_list: list = []
164
+ for idx, dw in enumerate(self.dw_player):
165
+ rotation_angles: list = []
166
+ for choice in (0, 90, 180, 270):
167
+ rotation_angles.append((str(choice), "selected" if choice == dw.player.video_rotate else ""))
168
+ players_list.append(("il", f"Player #{idx + 1}", rotation_angles))
169
+
170
+ w = dialog.Input_dialog(label_caption="Select the rotation angle", elements_list=players_list, title="Video rotation angle")
171
+ if not w.exec_():
172
+ return
173
+ if cfg.ROTATION_ANGLE not in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO]:
174
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.ROTATION_ANGLE] = {}
175
+
176
+ for idx, dw in enumerate(self.dw_player):
177
+ if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.ROTATION_ANGLE].get(
178
+ str(idx + 1), dw.player.video_rotate
179
+ ) != float(w.elements[f"Player #{idx + 1}"].currentText()):
180
+ dw.player.video_rotate = int(w.elements[f"Player #{idx + 1}"].currentText())
181
+
182
+ logging.debug(f"video rotation changed to {dw.player.video_rotate} for player {idx + 1}")
183
+
184
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.ROTATION_ANGLE][str(idx + 1)] = int(
185
+ w.elements[f"Player #{idx + 1}"].currentText()
186
+ )
187
+ self.project_changed()
188
+
189
+
190
+ def display_subtitles(self):
191
+ """
192
+ display dialog for subtitles display
193
+ """
194
+ players_list = []
195
+ for idx, dw in enumerate(self.dw_player):
196
+ if cfg.DISPLAY_MEDIA_SUBTITLES in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO]:
197
+ default = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.DISPLAY_MEDIA_SUBTITLES].get(
198
+ str(idx + 1), dw.player.sub_visibility
199
+ )
200
+ else:
201
+ default = dw.player.sub_visibility
202
+ players_list.append(("cb", f"Player #{idx + 1}", default))
203
+
204
+ st = dialog.Input_dialog("Display subtitles", players_list)
205
+ if not st.exec_():
206
+ return
207
+
208
+ if cfg.DISPLAY_MEDIA_SUBTITLES not in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO]:
209
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.DISPLAY_MEDIA_SUBTITLES] = {}
210
+
211
+ for idx, dw in enumerate(self.dw_player):
212
+ if (
213
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.DISPLAY_MEDIA_SUBTITLES].get(
214
+ str(idx + 1), dw.player.sub_visibility
215
+ )
216
+ != st.elements[f"Player #{idx + 1}"].isChecked()
217
+ ):
218
+ dw.player.sub_visibility = st.elements[f"Player #{idx + 1}"].isChecked()
219
+
220
+ logging.debug(f"subtitle visibility for player {idx + 1}: {dw.player.sub_visibility}")
221
+
222
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.DISPLAY_MEDIA_SUBTITLES][str(idx + 1)] = st.elements[
223
+ f"Player #{idx + 1}"
224
+ ].isChecked()
225
+ self.project_changed()
226
+
227
+
228
+ def display_zoom_level(self) -> None:
229
+ """
230
+ display the zoom level
231
+ """
232
+ msg: str = "Zoom level: <b>"
233
+ for player in self.dw_player:
234
+ vz = player.player.video_zoom
235
+ if vz is None:
236
+ self.lb_zoom_level.setText("-")
237
+ return
238
+ if player.player.video_zoom is not None:
239
+ msg += f"{2**player.player.video_zoom:.1f} "
240
+ else:
241
+ msg += "NA "
242
+ msg += "</b>"
243
+ self.lb_zoom_level.setText(msg)
244
+
245
+
246
+ def display_play_rate(self) -> None:
247
+ """
248
+ display current play rate in status bar widget
249
+ """
250
+
251
+ self.lb_video_info.setText(f"Play rate: <b>x{self.play_rate:.3f}</b>")
252
+
253
+ logging.debug(f"play rate: {self.play_rate:.3f}")
254
+
255
+
256
+ def video_normalspeed_activated(self):
257
+ """
258
+ set playing speed at normal speed (1x)
259
+ """
260
+
261
+ if self.playerType != cfg.MEDIA:
262
+ return
263
+
264
+ self.play_rate = 1
265
+ for i, player in enumerate(self.dw_player):
266
+ if (
267
+ str(i + 1) in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE]
268
+ and self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][str(i + 1)]
269
+ ):
270
+ player.player.speed = self.play_rate
271
+
272
+ display_play_rate(self)
273
+
274
+
275
+ def video_faster_activated(self):
276
+ """
277
+ increase playing speed by play_rate_step value
278
+ """
279
+
280
+ if self.playerType != cfg.MEDIA:
281
+ return
282
+
283
+ if self.play_rate + self.play_rate_step <= 60:
284
+ self.play_rate += self.play_rate_step
285
+ for i, player in enumerate(self.dw_player):
286
+ if (
287
+ str(i + 1) in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE]
288
+ and self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][str(i + 1)]
289
+ ):
290
+ player.player.speed = self.play_rate
291
+ print("speed")
292
+
293
+ display_play_rate(self)
294
+
295
+
296
+ def video_slower_activated(self):
297
+ """
298
+ decrease playing speed by play_rate_step value
299
+ """
300
+
301
+ if self.playerType != cfg.MEDIA:
302
+ return
303
+
304
+ if self.play_rate - self.play_rate_step >= 0.1:
305
+ self.play_rate -= self.play_rate_step
306
+
307
+ for i, player in enumerate(self.dw_player):
308
+ player.player.speed = round(self.play_rate, 3)
309
+
310
+ display_play_rate(self)
boris/view_df.py ADDED
@@ -0,0 +1,104 @@
1
+ from .view_df_ui import Ui_Form
2
+ from PySide6.QtWidgets import QWidget, QFileDialog
3
+ from PySide6.QtCore import Qt, QAbstractTableModel
4
+
5
+ from . import config as cfg
6
+ from pathlib import Path
7
+ from . import dialog
8
+
9
+ try:
10
+ import pyreadr
11
+
12
+ flag_pyreadr_loaded = True
13
+ except ModuleNotFoundError:
14
+ flag_pyreadr_loaded = False
15
+
16
+
17
+ class DataFrameModel(QAbstractTableModel):
18
+ def __init__(self, dataframe):
19
+ super().__init__()
20
+ self._dataframe = dataframe
21
+
22
+ def rowCount(self, parent=None):
23
+ return self._dataframe.shape[0]
24
+
25
+ def columnCount(self, parent=None):
26
+ return self._dataframe.shape[1]
27
+
28
+ def data(self, index, role=Qt.DisplayRole):
29
+ if role == Qt.DisplayRole:
30
+ return str(self._dataframe.iat[index.row(), index.column()])
31
+ return None
32
+
33
+ def headerData(self, section, orientation, role=Qt.DisplayRole):
34
+ if role == Qt.DisplayRole:
35
+ if orientation == Qt.Horizontal:
36
+ return self._dataframe.columns[section]
37
+ elif orientation == Qt.Vertical:
38
+ return self._dataframe.index[section]
39
+ return None
40
+
41
+
42
+ class View_df(QWidget, Ui_Form):
43
+ def __init__(self, plugin_name: str, plugin_version: str, df, parent=None):
44
+ super().__init__()
45
+ self.plugin_name = plugin_name
46
+ self.df = df
47
+
48
+ self.setupUi(self)
49
+ self.lb_plugin_info.setText(f"{plugin_name} v. {plugin_version}")
50
+ self.setWindowTitle(f"{plugin_name} v. {plugin_version}")
51
+
52
+ self.pb_close.clicked.connect(self.close)
53
+ self.pb_save.clicked.connect(self.save)
54
+
55
+ model = DataFrameModel(self.df)
56
+ self.tv_df.setModel(model)
57
+
58
+ def save(self):
59
+ file_formats = (
60
+ cfg.TSV,
61
+ cfg.CSV,
62
+ cfg.ODS,
63
+ cfg.XLSX,
64
+ # cfg.XLS,
65
+ cfg.HTML,
66
+ # cfg.TBS,
67
+ cfg.PANDAS_DF,
68
+ cfg.RDS,
69
+ )
70
+
71
+ file_dialog_options = QFileDialog.Options()
72
+ file_dialog_options |= QFileDialog.DontConfirmOverwrite
73
+
74
+ file_name, filter_ = QFileDialog().getSaveFileName(
75
+ None, f"Save {self.plugin_name}", "", ";;".join(file_formats), options=file_dialog_options
76
+ )
77
+ if not file_name:
78
+ return
79
+
80
+ outputFormat = cfg.FILE_NAME_SUFFIX[filter_]
81
+ if Path(file_name).suffix != "." + outputFormat:
82
+ file_name = f"{file_name}.{outputFormat}"
83
+ if Path(file_name).exists():
84
+ if (
85
+ dialog.MessageDialog(cfg.programName, f"The file {file_name} already exists.", [cfg.CANCEL, cfg.OVERWRITE])
86
+ == cfg.CANCEL
87
+ ):
88
+ return
89
+
90
+ if filter_ == cfg.TSV:
91
+ self.df.to_csv(file_name, sep="\t", index=False)
92
+ if filter_ == cfg.CSV:
93
+ self.df.to_csv(file_name, sep=";", index=False)
94
+ if filter_ == cfg.XLSX:
95
+ self.df.to_excel(file_name, index=False)
96
+ if filter_ == cfg.ODS:
97
+ self.df.to_excel(file_name, index=False, engine="odf")
98
+ if filter_ == cfg.HTML:
99
+ self.df.to_html(file_name, index=False)
100
+ if filter_ == cfg.PANDAS_DF:
101
+ self.df.to_pickle(file_name)
102
+
103
+ if filter_ == cfg.RDS and flag_pyreadr_loaded:
104
+ pyreadr.write_rds(file_name, self.df)
boris/view_df_ui.py ADDED
@@ -0,0 +1,75 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ################################################################################
4
+ ## Form generated from reading UI file 'view_df.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, QHBoxLayout, QHeaderView, QLabel,
19
+ QPushButton, QSizePolicy, QSpacerItem, QTableView,
20
+ QVBoxLayout, QWidget)
21
+
22
+ class Ui_Form(object):
23
+ def setupUi(self, Form):
24
+ if not Form.objectName():
25
+ Form.setObjectName(u"Form")
26
+ Form.resize(400, 300)
27
+ self.verticalLayout_2 = QVBoxLayout(Form)
28
+ self.verticalLayout_2.setObjectName(u"verticalLayout_2")
29
+ self.lb_plugin_info = QLabel(Form)
30
+ self.lb_plugin_info.setObjectName(u"lb_plugin_info")
31
+
32
+ self.verticalLayout_2.addWidget(self.lb_plugin_info)
33
+
34
+ self.verticalLayout = QVBoxLayout()
35
+ self.verticalLayout.setObjectName(u"verticalLayout")
36
+ self.tv_df = QTableView(Form)
37
+ self.tv_df.setObjectName(u"tv_df")
38
+
39
+ self.verticalLayout.addWidget(self.tv_df)
40
+
41
+ self.horizontalLayout = QHBoxLayout()
42
+ self.horizontalLayout.setObjectName(u"horizontalLayout")
43
+ self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
44
+
45
+ self.horizontalLayout.addItem(self.horizontalSpacer)
46
+
47
+ self.pb_save = QPushButton(Form)
48
+ self.pb_save.setObjectName(u"pb_save")
49
+
50
+ self.horizontalLayout.addWidget(self.pb_save)
51
+
52
+ self.pb_close = QPushButton(Form)
53
+ self.pb_close.setObjectName(u"pb_close")
54
+
55
+ self.horizontalLayout.addWidget(self.pb_close)
56
+
57
+
58
+ self.verticalLayout.addLayout(self.horizontalLayout)
59
+
60
+
61
+ self.verticalLayout_2.addLayout(self.verticalLayout)
62
+
63
+
64
+ self.retranslateUi(Form)
65
+
66
+ QMetaObject.connectSlotsByName(Form)
67
+ # setupUi
68
+
69
+ def retranslateUi(self, Form):
70
+ Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None))
71
+ self.lb_plugin_info.setText(QCoreApplication.translate("Form", u"TextLabel", None))
72
+ self.pb_save.setText(QCoreApplication.translate("Form", u"Save results", None))
73
+ self.pb_close.setText(QCoreApplication.translate("Form", u"Close", None))
74
+ # retranslateUi
75
+