boris-behav-obs 9.7.5__tar.gz → 9.7.8__tar.gz

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 (126) hide show
  1. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/PKG-INFO +2 -2
  2. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/README.md +1 -1
  3. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/add_modifier_ui.py +47 -29
  4. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/config.py +1 -1
  5. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/core.py +71 -38
  6. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/ipc_mpv.py +50 -2
  7. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/observation.py +1 -2
  8. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/observation_operations.py +22 -5
  9. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/preferences.py +5 -2
  10. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/project.py +1 -1
  11. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/project_functions.py +23 -15
  12. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/utilities.py +9 -7
  13. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/version.py +2 -2
  14. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/video_operations.py +4 -1
  15. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris_behav_obs.egg-info/PKG-INFO +2 -2
  16. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/pyproject.toml +1 -1
  17. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/LICENSE.TXT +0 -0
  18. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/MANIFEST.in +0 -0
  19. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/README.TXT +0 -0
  20. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/__init__.py +0 -0
  21. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/__main__.py +0 -0
  22. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/about.py +0 -0
  23. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/add_modifier.py +0 -0
  24. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/advanced_event_filtering.py +0 -0
  25. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/analysis_plugins/__init__.py +0 -0
  26. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/analysis_plugins/_latency.py +0 -0
  27. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/analysis_plugins/irr_cohen_kappa.py +0 -0
  28. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +0 -0
  29. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/analysis_plugins/irr_weighted_cohen_kappa.py +0 -0
  30. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +0 -0
  31. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/analysis_plugins/list_of_dataframe_columns.py +0 -0
  32. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/analysis_plugins/number_of_occurences.py +0 -0
  33. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/analysis_plugins/number_of_occurences_by_independent_variable.py +0 -0
  34. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/analysis_plugins/time_budget.py +0 -0
  35. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/behav_coding_map_creator.py +0 -0
  36. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/behavior_binary_table.py +0 -0
  37. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/behaviors_coding_map.py +0 -0
  38. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/boris_cli.py +0 -0
  39. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/cmd_arguments.py +0 -0
  40. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/coding_pad.py +0 -0
  41. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/config_file.py +0 -0
  42. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/connections.py +0 -0
  43. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/converters.py +0 -0
  44. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/converters_ui.py +0 -0
  45. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/cooccurence.py +0 -0
  46. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/core_qrc.py +0 -0
  47. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/core_ui.py +0 -0
  48. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/db_functions.py +0 -0
  49. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/dev.py +0 -0
  50. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/dialog.py +0 -0
  51. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/duration_widget.py +0 -0
  52. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/edit_event.py +0 -0
  53. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/edit_event_ui.py +0 -0
  54. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/event_operations.py +0 -0
  55. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/events_cursor.py +0 -0
  56. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/events_snapshots.py +0 -0
  57. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/exclusion_matrix.py +0 -0
  58. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/export_events.py +0 -0
  59. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/export_observation.py +0 -0
  60. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/external_processes.py +0 -0
  61. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/geometric_measurement.py +0 -0
  62. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/gui_utilities.py +0 -0
  63. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/image_overlay.py +0 -0
  64. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/import_observations.py +0 -0
  65. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/irr.py +0 -0
  66. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/latency.py +0 -0
  67. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/measurement_widget.py +0 -0
  68. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/media_file.py +0 -0
  69. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/menu_options.py +0 -0
  70. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/modifier_coding_map_creator.py +0 -0
  71. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/modifiers_coding_map.py +0 -0
  72. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/mpv.py +0 -0
  73. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/mpv2.py +0 -0
  74. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/observation_ui.py +0 -0
  75. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/observations_list.py +0 -0
  76. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/otx_parser.py +0 -0
  77. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/param_panel.py +0 -0
  78. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/param_panel_ui.py +0 -0
  79. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/player_dock_widget.py +0 -0
  80. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/plot_data_module.py +0 -0
  81. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/plot_events.py +0 -0
  82. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/plot_events_rt.py +0 -0
  83. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/plot_spectrogram_rt.py +0 -0
  84. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/plot_waveform_rt.py +0 -0
  85. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/plugins.py +0 -0
  86. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/portion/__init__.py +0 -0
  87. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/portion/const.py +0 -0
  88. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/portion/dict.py +0 -0
  89. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/portion/func.py +0 -0
  90. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/portion/interval.py +0 -0
  91. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/portion/io.py +0 -0
  92. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/preferences_ui.py +0 -0
  93. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/project_import_export.py +0 -0
  94. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/project_ui.py +0 -0
  95. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/qrc_boris.py +0 -0
  96. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/qrc_boris5.py +0 -0
  97. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/select_modifiers.py +0 -0
  98. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/select_observations.py +0 -0
  99. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/select_subj_behav.py +0 -0
  100. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/state_events.py +0 -0
  101. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/subjects_pad.py +0 -0
  102. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/synthetic_time_budget.py +0 -0
  103. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/time_budget_functions.py +0 -0
  104. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/time_budget_widget.py +0 -0
  105. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/transitions.py +0 -0
  106. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/video_equalizer.py +0 -0
  107. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/video_equalizer_ui.py +0 -0
  108. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/view_df.py +0 -0
  109. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/view_df_ui.py +0 -0
  110. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris/write_event.py +0 -0
  111. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris_behav_obs.egg-info/SOURCES.txt +0 -0
  112. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris_behav_obs.egg-info/dependency_links.txt +0 -0
  113. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris_behav_obs.egg-info/entry_points.txt +0 -0
  114. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris_behav_obs.egg-info/requires.txt +0 -0
  115. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/boris_behav_obs.egg-info/top_level.txt +0 -0
  116. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/setup.cfg +0 -0
  117. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/tests/test_db_functions.py +0 -0
  118. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/tests/test_export_observation.py +0 -0
  119. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/tests/test_irr.py +0 -0
  120. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/tests/test_observation_gui.py +0 -0
  121. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/tests/test_otx_parser.py +0 -0
  122. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/tests/test_preferences_gui.py +0 -0
  123. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/tests/test_project_functions.py +0 -0
  124. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/tests/test_time_budget.py +0 -0
  125. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/tests/test_utilities.py +0 -0
  126. {boris_behav_obs-9.7.5 → boris_behav_obs-9.7.8}/tests/test_utilities2.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boris-behav-obs
3
- Version: 9.7.5
3
+ Version: 9.7.8
4
4
  Summary: BORIS - Behavioral Observation Research Interactive Software
5
5
  Author-email: Olivier Friard <olivier.friard@unito.it>
6
6
  License-Expression: GPL-3.0-only
@@ -51,7 +51,7 @@ It provides also some analysis tools like time budget and some plotting function
51
51
  <!-- The BO-RIS paper has more than [![BORIS citations counter](https://penelope.unito.it/friard/boris_scopus_citations.png) citations](https://www.boris.unito.it/citations) in peer-reviewed scientific publications. -->
52
52
 
53
53
 
54
- The BORIS paper has more than 2423 citations in peer-reviewed scientific publications.
54
+ The BORIS paper has more than 2442 citations in peer-reviewed scientific publications.
55
55
 
56
56
 
57
57
 
@@ -13,7 +13,7 @@ It provides also some analysis tools like time budget and some plotting function
13
13
  <!-- The BO-RIS paper has more than [![BORIS citations counter](https://penelope.unito.it/friard/boris_scopus_citations.png) citations](https://www.boris.unito.it/citations) in peer-reviewed scientific publications. -->
14
14
 
15
15
 
16
- The BORIS paper has more than 2423 citations in peer-reviewed scientific publications.
16
+ The BORIS paper has more than 2442 citations in peer-reviewed scientific publications.
17
17
 
18
18
 
19
19
 
@@ -3,7 +3,7 @@
3
3
  ################################################################################
4
4
  ## Form generated from reading UI file 'add_modifier.ui'
5
5
  ##
6
- ## Created by: Qt User Interface Compiler version 6.8.0
6
+ ## Created by: Qt User Interface Compiler version 6.10.0
7
7
  ##
8
8
  ## WARNING! All changes made in this file will be lost when recompiling UI file!
9
9
  ################################################################################
@@ -24,18 +24,16 @@ class Ui_Dialog(object):
24
24
  def setupUi(self, Dialog):
25
25
  if not Dialog.objectName():
26
26
  Dialog.setObjectName(u"Dialog")
27
- Dialog.resize(1088, 654)
28
- self.verticalLayout_5 = QVBoxLayout(Dialog)
29
- self.verticalLayout_5.setObjectName(u"verticalLayout_5")
27
+ Dialog.resize(1339, 789)
28
+ self.verticalLayout_4 = QVBoxLayout(Dialog)
29
+ self.verticalLayout_4.setObjectName(u"verticalLayout_4")
30
30
  self.cb_ask_at_stop = QCheckBox(Dialog)
31
31
  self.cb_ask_at_stop.setObjectName(u"cb_ask_at_stop")
32
32
 
33
- self.verticalLayout_5.addWidget(self.cb_ask_at_stop)
33
+ self.verticalLayout_4.addWidget(self.cb_ask_at_stop)
34
34
 
35
- self.verticalLayout_4 = QVBoxLayout()
36
- self.verticalLayout_4.setObjectName(u"verticalLayout_4")
37
- self.horizontalLayout_5 = QHBoxLayout()
38
- self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
35
+ self.horizontalLayout_8 = QHBoxLayout()
36
+ self.horizontalLayout_8.setObjectName(u"horizontalLayout_8")
39
37
  self.verticalLayout_2 = QVBoxLayout()
40
38
  self.verticalLayout_2.setObjectName(u"verticalLayout_2")
41
39
  self.lbModifier = QLabel(Dialog)
@@ -69,7 +67,7 @@ class Ui_Dialog(object):
69
67
  self.verticalLayout_2.addItem(self.verticalSpacer)
70
68
 
71
69
 
72
- self.horizontalLayout_5.addLayout(self.verticalLayout_2)
70
+ self.horizontalLayout_8.addLayout(self.verticalLayout_2)
73
71
 
74
72
  self.verticalLayout_3 = QVBoxLayout()
75
73
  self.verticalLayout_3.setObjectName(u"verticalLayout_3")
@@ -88,7 +86,7 @@ class Ui_Dialog(object):
88
86
  self.verticalLayout_3.addItem(self.verticalSpacer_2)
89
87
 
90
88
 
91
- self.horizontalLayout_5.addLayout(self.verticalLayout_3)
89
+ self.horizontalLayout_8.addLayout(self.verticalLayout_3)
92
90
 
93
91
  self.verticalLayout = QVBoxLayout()
94
92
  self.verticalLayout.setObjectName(u"verticalLayout")
@@ -102,30 +100,42 @@ class Ui_Dialog(object):
102
100
 
103
101
  self.verticalLayout.addWidget(self.tabWidgetModifiersSets)
104
102
 
103
+ self.horizontalLayout_5 = QHBoxLayout()
104
+ self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
105
105
  self.lb_name = QLabel(Dialog)
106
106
  self.lb_name.setObjectName(u"lb_name")
107
107
 
108
- self.verticalLayout.addWidget(self.lb_name)
108
+ self.horizontalLayout_5.addWidget(self.lb_name)
109
109
 
110
110
  self.le_name = QLineEdit(Dialog)
111
111
  self.le_name.setObjectName(u"le_name")
112
112
 
113
- self.verticalLayout.addWidget(self.le_name)
113
+ self.horizontalLayout_5.addWidget(self.le_name)
114
114
 
115
+
116
+ self.verticalLayout.addLayout(self.horizontalLayout_5)
117
+
118
+ self.horizontalLayout_6 = QHBoxLayout()
119
+ self.horizontalLayout_6.setObjectName(u"horizontalLayout_6")
115
120
  self.lb_description = QLabel(Dialog)
116
121
  self.lb_description.setObjectName(u"lb_description")
117
122
 
118
- self.verticalLayout.addWidget(self.lb_description)
123
+ self.horizontalLayout_6.addWidget(self.lb_description)
119
124
 
120
125
  self.le_description = QLineEdit(Dialog)
121
126
  self.le_description.setObjectName(u"le_description")
122
127
 
123
- self.verticalLayout.addWidget(self.le_description)
128
+ self.horizontalLayout_6.addWidget(self.le_description)
129
+
124
130
 
131
+ self.verticalLayout.addLayout(self.horizontalLayout_6)
132
+
133
+ self.horizontalLayout_7 = QHBoxLayout()
134
+ self.horizontalLayout_7.setObjectName(u"horizontalLayout_7")
125
135
  self.lbType = QLabel(Dialog)
126
136
  self.lbType.setObjectName(u"lbType")
127
137
 
128
- self.verticalLayout.addWidget(self.lbType)
138
+ self.horizontalLayout_7.addWidget(self.lbType)
129
139
 
130
140
  self.cbType = QComboBox(Dialog)
131
141
  self.cbType.addItem("")
@@ -134,7 +144,14 @@ class Ui_Dialog(object):
134
144
  self.cbType.addItem("")
135
145
  self.cbType.setObjectName(u"cbType")
136
146
 
137
- self.verticalLayout.addWidget(self.cbType)
147
+ self.horizontalLayout_7.addWidget(self.cbType)
148
+
149
+ self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
150
+
151
+ self.horizontalLayout_7.addItem(self.horizontalSpacer_3)
152
+
153
+
154
+ self.verticalLayout.addLayout(self.horizontalLayout_7)
138
155
 
139
156
  self.lbValues = QLabel(Dialog)
140
157
  self.lbValues.setObjectName(u"lbValues")
@@ -198,28 +215,32 @@ class Ui_Dialog(object):
198
215
 
199
216
  self.horizontalLayout_4 = QHBoxLayout()
200
217
  self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
201
-
202
- self.verticalLayout.addLayout(self.horizontalLayout_4)
203
-
204
218
  self.pb_add_subjects = QPushButton(Dialog)
205
219
  self.pb_add_subjects.setObjectName(u"pb_add_subjects")
206
220
 
207
- self.verticalLayout.addWidget(self.pb_add_subjects)
221
+ self.horizontalLayout_4.addWidget(self.pb_add_subjects)
208
222
 
209
223
  self.pb_load_file = QPushButton(Dialog)
210
224
  self.pb_load_file.setObjectName(u"pb_load_file")
211
225
 
212
- self.verticalLayout.addWidget(self.pb_load_file)
226
+ self.horizontalLayout_4.addWidget(self.pb_load_file)
227
+
228
+ self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
229
+
230
+ self.horizontalLayout_4.addItem(self.horizontalSpacer_2)
231
+
232
+
233
+ self.verticalLayout.addLayout(self.horizontalLayout_4)
213
234
 
214
235
  self.verticalSpacer_3 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
215
236
 
216
237
  self.verticalLayout.addItem(self.verticalSpacer_3)
217
238
 
218
239
 
219
- self.horizontalLayout_5.addLayout(self.verticalLayout)
240
+ self.horizontalLayout_8.addLayout(self.verticalLayout)
220
241
 
221
242
 
222
- self.verticalLayout_4.addLayout(self.horizontalLayout_5)
243
+ self.verticalLayout_4.addLayout(self.horizontalLayout_8)
223
244
 
224
245
  self.horizontalLayout_2 = QHBoxLayout()
225
246
  self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
@@ -241,9 +262,6 @@ class Ui_Dialog(object):
241
262
  self.verticalLayout_4.addLayout(self.horizontalLayout_2)
242
263
 
243
264
 
244
- self.verticalLayout_5.addLayout(self.verticalLayout_4)
245
-
246
-
247
265
  self.retranslateUi(Dialog)
248
266
 
249
267
  self.tabWidgetModifiersSets.setCurrentIndex(-1)
@@ -256,8 +274,8 @@ class Ui_Dialog(object):
256
274
  Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Set modifiers", None))
257
275
  self.cb_ask_at_stop.setText(QCoreApplication.translate("Dialog", u"Ask for modifier(s) when behavior stops", None))
258
276
  self.lbModifier.setText(QCoreApplication.translate("Dialog", u"Modifier", None))
259
- self.lbCode.setText(QCoreApplication.translate("Dialog", u"Key code", None))
260
- self.lbCodeHelp.setText(QCoreApplication.translate("Dialog", u"Key code is case sensitive. Type one character or a function key (F1, F2... F12)", None))
277
+ self.lbCode.setText(QCoreApplication.translate("Dialog", u"Shortcut", None))
278
+ self.lbCodeHelp.setText(QCoreApplication.translate("Dialog", u"The shortcut is case sensitive. Type one character or a function key (F1, F2... F12)", None))
261
279
  self.pbAddModifier.setText(QCoreApplication.translate("Dialog", u"->", None))
262
280
  self.pbModifyModifier.setText(QCoreApplication.translate("Dialog", u"<-", None))
263
281
  self.lb_name.setText(QCoreApplication.translate("Dialog", u"Set name", None))
@@ -132,7 +132,7 @@ POINT_EVENT_PLOT_COLOR = "black"
132
132
 
133
133
  CHAR_FORBIDDEN_IN_MODIFIERS = "(|),`~"
134
134
 
135
- FAST_FORWARD_DEFAULT_VALUE:float = 10.0
135
+ FAST_FORWARD_DEFAULT_VALUE: float = 10.0
136
136
 
137
137
  ADAPT_FAST_JUMP = "adapt_fast_jump"
138
138
  ADAPT_FAST_JUMP_DEFAULT = False
@@ -41,6 +41,7 @@ from PIL.ImageQt import Image
41
41
  import subprocess
42
42
  import locale
43
43
  import tempfile
44
+ import math
44
45
  import time
45
46
  import urllib.request
46
47
  from decimal import Decimal as dec
@@ -53,17 +54,7 @@ import shutil
53
54
 
54
55
  matplotlib.use("QtAgg")
55
56
 
56
- from PySide6.QtCore import (
57
- Qt,
58
- QPoint,
59
- Signal,
60
- QEvent,
61
- QDateTime,
62
- QUrl,
63
- QAbstractTableModel,
64
- QElapsedTimer,
65
- QSettings,
66
- )
57
+ from PySide6.QtCore import Qt, QPoint, Signal, QEvent, QDateTime, QUrl, QAbstractTableModel, QElapsedTimer, QSettings, QTimer
67
58
  from PySide6.QtGui import QIcon, QPixmap, QFont, QKeyEvent, QDesktopServices, QColor, QPainter, QPolygon, QAction
68
59
  from PySide6.QtMultimedia import QSoundEffect
69
60
  from PySide6.QtWidgets import (
@@ -1509,15 +1500,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1509
1500
  logging.debug("previous media file")
1510
1501
 
1511
1502
  if self.playerType == cfg.MEDIA:
1512
- if len(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1]) == 1:
1513
- return
1503
+ #if len(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1]) == 1:
1504
+ # self.seek_mediaplayer(dec(0))
1505
+ # return
1514
1506
 
1515
1507
  # check if media not first media
1516
1508
  if self.dw_player[0].player.playlist_pos > 0:
1517
1509
  self.dw_player[0].player.playlist_prev()
1518
1510
 
1519
1511
  elif self.dw_player[0].player.playlist_count == 1:
1520
- self.statusbar.showMessage("There is only one media file", 5000)
1512
+ self.seek_mediaplayer(dec(0))
1513
+ #self.statusbar.showMessage("There is only one media file", 5000)
1521
1514
 
1522
1515
  if hasattr(self, "spectro"):
1523
1516
  self.spectro.memChunk = -1
@@ -3951,13 +3944,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3951
3944
  if self.dw_player[0].player.duration is None:
3952
3945
  return
3953
3946
  print(f"{slider_position=}")
3954
-
3947
+
3955
3948
  d = self.dw_player[0].player.duration
3956
3949
  print(f"{d=}")
3957
3950
  if d is None:
3958
3951
  return
3959
3952
  video_position = slider_position * d
3960
- #video_position = slider_position * self.dw_player[0].player.duration
3953
+ # video_position = slider_position * self.dw_player[0].player.duration
3961
3954
  # self.dw_player[0].player.command("seek", str(video_position), "absolute")
3962
3955
  self.dw_player[0].player.seek(video_position, "absolute")
3963
3956
 
@@ -4152,6 +4145,21 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4152
4145
  self.dw_player[n_player].player.playlist_pos = self.dw_player[n_player].player.playlist_count - 1
4153
4146
  self.seek_mediaplayer(self.dw_player[n_player].media_durations[-1], player=n_player)
4154
4147
 
4148
+ def activate_main_window(self):
4149
+ """
4150
+ activate main window in order to capture keyboard events
4151
+ called only in IPC mode
4152
+ """
4153
+ # check if eof reached
4154
+ #print(f"{self.dw_player[0].player.playlist_pos=}")
4155
+ #print(f"{self.dw_player[0].player.playlist_count=}")
4156
+ if self.dw_player[0].player.eof_reached and self.dw_player[0].player.core_idle:
4157
+ logging.debug("end of playlist reached")
4158
+ if self.dw_player[0].player.playlist_pos is not None and self.dw_player[0].player.playlist_count is not None:
4159
+ if self.dw_player[0].player.playlist_pos == self.dw_player[0].player.playlist_count - 1:
4160
+ self.pause_video()
4161
+ self.activateWindow()
4162
+
4155
4163
  def mpv_timer_out(self, value: float | None = None, scroll_slider=True):
4156
4164
  """
4157
4165
  print the media current position and total length for MPV player
@@ -4211,8 +4219,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4211
4219
  ct = self.getLaps(n_player=n_player)
4212
4220
 
4213
4221
  # sync players 2..8 if time diff >= 1 s
4214
- if abs(ct0 - (ct + dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]))) >= 1:
4215
- self.sync_time(n_player, ct0) # self.seek_mediaplayer(ct0, n_player)
4222
+ if not math.isnan(ct) and not math.isnan(ct0):
4223
+ if abs(ct0 - (ct + dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]))) >= 1:
4224
+ self.sync_time(n_player, ct0) # self.seek_mediaplayer(ct0, n_player)
4216
4225
 
4217
4226
  currentTimeOffset = dec(cumulative_time_pos + self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TIME_OFFSET])
4218
4227
 
@@ -4243,9 +4252,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4243
4252
  self.show_current_states_in_subjects_table()
4244
4253
 
4245
4254
  # current media name
4246
- if self.dw_player[0].player.playlist_pos is not None:
4247
- current_media_name = Path(self.dw_player[0].player.playlist[self.dw_player[0].player.playlist_pos]["filename"]).name
4248
- current_playlist_index = self.dw_player[0].player.playlist_pos
4255
+ playlist = self.dw_player[0].player.playlist
4256
+ playlist_pos = self.dw_player[0].player.playlist_pos
4257
+ if playlist is not None and playlist_pos is not None:
4258
+ current_media_name = Path(playlist[playlist_pos]["filename"]).name
4259
+ current_playlist_index = playlist_pos
4249
4260
  else:
4250
4261
  current_media_name = ""
4251
4262
  current_playlist_index = None
@@ -4603,6 +4614,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4603
4614
 
4604
4615
  if self.playerType == cfg.MEDIA:
4605
4616
  # cumulative time
4617
+ if self.dw_player[n_player].player.time_pos is None:
4618
+ return dec("NaN")
4606
4619
  mem_laps = sum(self.dw_player[n_player].media_durations[0 : self.dw_player[n_player].player.playlist_pos]) + (
4607
4620
  0 if self.dw_player[n_player].player.time_pos is None else self.dw_player[n_player].player.time_pos * 1000
4608
4621
  )
@@ -4622,7 +4635,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4622
4635
  """
4623
4636
 
4624
4637
  if not self.observationId:
4625
- return dec("0")
4638
+ return dec("0"), dec("0")
4626
4639
 
4627
4640
  if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE] == cfg.LIVE:
4628
4641
  if "finished" in self.pb_live_obs.text():
@@ -5458,7 +5471,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5458
5471
  check if first player ended
5459
5472
  """
5460
5473
 
5461
- print("play_video")
5474
+ logging.debug("play_video")
5462
5475
 
5463
5476
  if self.geometric_measurements_mode:
5464
5477
  return
@@ -5466,6 +5479,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5466
5479
  if self.playerType != cfg.MEDIA:
5467
5480
  return
5468
5481
 
5482
+ # check if playlist is ended. If it is ended restart playlist from beginning
5483
+ if self.dw_player[0].player.eof_reached and self.dw_player[0].player.core_idle:
5484
+ if self.dw_player[0].player.playlist_pos is not None and self.dw_player[0].player.playlist_count is not None:
5485
+ if self.dw_player[0].player.playlist_pos == self.dw_player[0].player.playlist_count - 1:
5486
+ self.seek_mediaplayer(dec(0))
5487
+
5488
+
5469
5489
  # check if player 1 is ended
5470
5490
  for i, dw in enumerate(self.dw_player):
5471
5491
  if (
@@ -5476,9 +5496,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5476
5496
 
5477
5497
  self.lb_player_status.clear()
5478
5498
 
5479
- # if self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.VISUALIZE_WAVEFORM, False) \
5480
- # or self.pj[cfg.OBSERVATIONS][self.observationId].get(VISUALIZE_SPECTROGRAM, False):
5481
-
5482
5499
  self.statusbar.showMessage("", 0)
5483
5500
 
5484
5501
  if self.ipc_mpv_timer is not None:
@@ -5555,16 +5572,19 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5555
5572
 
5556
5573
  decrement = self.fast * self.play_rate if self.config_param.get(cfg.ADAPT_FAST_JUMP, cfg.ADAPT_FAST_JUMP_DEFAULT) else self.fast
5557
5574
 
5558
- new_time = (
5559
- sum(self.dw_player[0].media_durations[0 : self.dw_player[0].player.playlist_pos]) / 1000
5560
- + self.dw_player[0].player.playback_time
5561
- - decrement
5562
- )
5575
+ try:
5576
+ new_time = (
5577
+ sum(self.dw_player[0].media_durations[0 : self.dw_player[0].player.playlist_pos]) / 1000
5578
+ + self.dw_player[0].player.playback_time
5579
+ - decrement
5580
+ )
5581
+ except Exception:
5582
+ return
5563
5583
 
5564
5584
  if new_time < decrement:
5565
5585
  new_time = 0
5566
5586
 
5567
- self.seek_mediaplayer(new_time)
5587
+ self.seek_mediaplayer(dec(new_time))
5568
5588
 
5569
5589
  self.update_visualizations()
5570
5590
 
@@ -5578,13 +5598,16 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5578
5598
 
5579
5599
  logging.info(f"Jump forward for {increment} seconds")
5580
5600
 
5581
- new_time = (
5582
- sum(self.dw_player[0].media_durations[0 : self.dw_player[0].player.playlist_pos]) / 1000
5583
- + self.dw_player[0].player.playback_time
5584
- + increment
5585
- )
5601
+ try:
5602
+ new_time = (
5603
+ sum(self.dw_player[0].media_durations[0 : self.dw_player[0].player.playlist_pos]) / 1000
5604
+ + self.dw_player[0].player.playback_time
5605
+ + increment
5606
+ )
5607
+ except Exception:
5608
+ return
5586
5609
 
5587
- self.seek_mediaplayer(new_time)
5610
+ self.seek_mediaplayer(dec(new_time))
5588
5611
 
5589
5612
  self.update_visualizations()
5590
5613
 
@@ -5840,6 +5863,15 @@ def main():
5840
5863
  )
5841
5864
  sys.exit()
5842
5865
 
5866
+ if sys.platform.startswith("darwin"):
5867
+ QMessageBox.warning(
5868
+ None,
5869
+ cfg.programName,
5870
+ (f"This version of BORIS for macOS is still EXPERIMENTAL and should be used at your own risk."),
5871
+ QMessageBox.Ok | QMessageBox.Default,
5872
+ QMessageBox.NoButton,
5873
+ )
5874
+
5843
5875
  window.show()
5844
5876
  window.raise_() # for overlapping widget (?)
5845
5877
 
@@ -5866,3 +5898,4 @@ def main():
5866
5898
  del window
5867
5899
 
5868
5900
  sys.exit(return_code)
5901
+
@@ -1,8 +1,29 @@
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
+
1
23
  import socket
2
24
  import json
3
25
  import subprocess
4
26
 
5
- # from PySide6.QtCore import QTimer
6
27
  import logging
7
28
  import config as cfg
8
29
 
@@ -41,7 +62,8 @@ class IPC_MPV:
41
62
  "--osc=no", # no on screen commands
42
63
  "--input-ipc-server=" + self.socket_path,
43
64
  # "--wid=" + str(int(self.winId())), # Embed in the widget
44
- "--idle", # Keeps mpv running with no video
65
+ "--idle=yes", # Keeps mpv running with no video
66
+ "--keep-open=always",
45
67
  "--input-default-bindings=no",
46
68
  "--input-vo-keyboard=no",
47
69
  ],
@@ -117,6 +139,14 @@ class IPC_MPV:
117
139
  def playlist(self):
118
140
  return self.send_command({"command": ["get_property", "playlist"]})
119
141
 
142
+ def playlist_next(self):
143
+ self.send_command({"command": ["playlist-next"]})
144
+ return
145
+
146
+ def playlist_prev(self):
147
+ self.send_command({"command": ["playlist-prev"]})
148
+ return
149
+
120
150
  @property
121
151
  def playlist_pos(self):
122
152
  return self.send_command({"command": ["get_property", "playlist-pos"]})
@@ -265,6 +295,24 @@ class IPC_MPV:
265
295
  def core_idle(self):
266
296
  return self.send_command({"command": ["get_property", "core-idle"]})
267
297
 
298
+ @property
299
+ def video_pan_x(self):
300
+ return self.send_command({"command": ["get_property", "video-pan-x"]})
301
+
302
+ @video_pan_x.setter
303
+ def video_pan_x(self, value):
304
+ self.send_command({"command": ["set_property", "video-pan-x", value]})
305
+ return
306
+
307
+ @property
308
+ def video_pan_y(self):
309
+ return self.send_command({"command": ["get_property", "video-pan-y"]})
310
+
311
+ @video_pan_y.setter
312
+ def video_pan_y(self, value):
313
+ self.send_command({"command": ["set_property", "video-pan-y", value]})
314
+ return
315
+
268
316
  """
269
317
  @property
270
318
  def xxx(self):
@@ -42,7 +42,7 @@ from PySide6.QtWidgets import (
42
42
  QApplication,
43
43
  QMenu,
44
44
  QListWidgetItem,
45
- QHeaderView
45
+ QHeaderView,
46
46
  )
47
47
 
48
48
  from . import config as cfg
@@ -232,7 +232,6 @@ class Observation(QDialog, Ui_Form):
232
232
 
233
233
  self.twVideo1.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
234
234
 
235
-
236
235
  self.mediaDurations, self.mediaFPS, self.mediaHasVideo, self.mediaHasAudio, self.media_creation_time = {}, {}, {}, {}, {}
237
236
 
238
237
  for w in (
@@ -113,6 +113,8 @@ def observations_list(self):
113
113
  result, selected_obs = select_observations.select_observations2(self, cfg.SINGLE)
114
114
 
115
115
  if not selected_obs:
116
+ # activate main window
117
+ self.activateWindow()
116
118
  return
117
119
 
118
120
  if self.observationId:
@@ -122,10 +124,14 @@ def observations_list(self):
122
124
  )
123
125
  if response == cfg.NO:
124
126
  self.show_data_files()
127
+ # activate main window
128
+ self.activateWindow()
129
+
125
130
  return ""
126
131
  else:
127
132
  close_observation(self)
128
133
 
134
+
129
135
  QtTest.QTest.qWait(1000)
130
136
 
131
137
  if result == cfg.OPEN:
@@ -145,6 +151,8 @@ def observations_list(self):
145
151
  )
146
152
 
147
153
  logging.debug("end observations list")
154
+ # activate main window
155
+ self.activateWindow()
148
156
 
149
157
 
150
158
  def open_observation(self, mode: str) -> str:
@@ -1151,6 +1159,9 @@ def close_observation(self):
1151
1159
  logging.info("Stop plot timer")
1152
1160
  self.plot_timer.stop()
1153
1161
 
1162
+ if self.MPV_IPC_MODE:
1163
+ self.main_window_activation_timer.stop()
1164
+
1154
1165
  for i, player in enumerate(self.dw_player):
1155
1166
  if (
1156
1167
  str(i + 1) in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE]
@@ -1340,8 +1351,6 @@ def initialize_new_media_observation(self) -> bool:
1340
1351
  self.playerType = cfg.VIEWER_MEDIA
1341
1352
  return True
1342
1353
 
1343
- # print(f"{self.process=}")
1344
-
1345
1354
  self.playerType = cfg.MEDIA
1346
1355
  self.fps = 0
1347
1356
 
@@ -1365,7 +1374,7 @@ def initialize_new_media_observation(self) -> bool:
1365
1374
 
1366
1375
  # add all media files to media lists
1367
1376
  self.setDockOptions(QMainWindow.AnimatedDocks | QMainWindow.AllowNestedDocks)
1368
- self.dw_player: list = []
1377
+ self.dw_player = []
1369
1378
 
1370
1379
  # check if media creation time used as offset
1371
1380
  # TODO check if cfg.MEDIA_CREATION_TIME dict is present
@@ -1831,8 +1840,8 @@ def initialize_new_media_observation(self) -> bool:
1831
1840
  self.dw_player[i].resize_signal.connect(self.resize_dw)
1832
1841
 
1833
1842
  # add durations list
1834
- self.dw_player[i].media_durations: list = []
1835
- self.dw_player[i].cumul_media_durations: List[int] = [0] # [idx for idx,x in enumerate(l) if l[idx-1]<pos<=x]
1843
+ self.dw_player[i].media_durations = []
1844
+ self.dw_player[i].cumul_media_durations = [0] # [idx for idx,x in enumerate(l) if l[idx-1]<pos<=x]
1836
1845
 
1837
1846
  # add fps list
1838
1847
  self.dw_player[i].fps = {}
@@ -1844,6 +1853,14 @@ def initialize_new_media_observation(self) -> bool:
1844
1853
  if r:
1845
1854
  break
1846
1855
 
1856
+ # start timer for activating the main window
1857
+ self.main_window_activation_timer = QTimer()
1858
+ self.main_window_activation_timer.setInterval(500)
1859
+ #self.main_window_activation_timer.timeout.connect(self.activateWindow)
1860
+ self.main_window_activation_timer.timeout.connect(self.activate_main_window)
1861
+ self.main_window_activation_timer.start()
1862
+
1863
+
1847
1864
  for mediaFile in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][n_player]:
1848
1865
  logging.debug(f"media file: {mediaFile}")
1849
1866
 
@@ -222,7 +222,7 @@ def preferences(self):
222
222
  # beep every
223
223
  preferencesWindow.sbBeepEvery.setValue(self.beep_every)
224
224
  # frame step size
225
- #preferencesWindow.sb_frame_step_size.setValue(self.config_param.get(cfg.FRAME_STEP_SIZE, cfg.FRAME_STEP_SIZE_DEFAULT_VALUE))
225
+ # preferencesWindow.sb_frame_step_size.setValue(self.config_param.get(cfg.FRAME_STEP_SIZE, cfg.FRAME_STEP_SIZE_DEFAULT_VALUE))
226
226
 
227
227
  # alert no focal subject
228
228
  preferencesWindow.cbAlertNoFocalSubject.setChecked(self.alertNoFocalSubject)
@@ -422,7 +422,7 @@ def preferences(self):
422
422
  self.beep_every = preferencesWindow.sbBeepEvery.value()
423
423
 
424
424
  # frame step size
425
- #self.config_param[cfg.FRAME_STEP_SIZE] = preferencesWindow.sb_frame_step_size.value()
425
+ # self.config_param[cfg.FRAME_STEP_SIZE] = preferencesWindow.sb_frame_step_size.value()
426
426
 
427
427
  self.alertNoFocalSubject = preferencesWindow.cbAlertNoFocalSubject.isChecked()
428
428
 
@@ -505,3 +505,6 @@ def preferences(self):
505
505
 
506
506
  else:
507
507
  break
508
+
509
+ # activate main window
510
+ self.activateWindow()
@@ -1977,7 +1977,7 @@ class projectDialog(QDialog, Ui_dlgProject):
1977
1977
  self.pj[cfg.INDEPENDENT_VARIABLES] = dict(self.indVar)
1978
1978
 
1979
1979
  # converters
1980
- converters:dict = {}
1980
+ converters: dict = {}
1981
1981
  for row in range(self.tw_converters.rowCount()):
1982
1982
  converters[self.tw_converters.item(row, 0).text()] = {
1983
1983
  "name": self.tw_converters.item(row, 0).text(),