spiceitup 2.0.0__tar.gz → 2.0.1__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 (69) hide show
  1. {spiceitup-2.0.0 → spiceitup-2.0.1}/PKG-INFO +7 -2
  2. {spiceitup-2.0.0 → spiceitup-2.0.1}/setup.py +15 -4
  3. spiceitup-2.0.1/spiceitup/__init__.py +7 -0
  4. {spiceitup-2.0.0 → spiceitup-2.0.1}/spiceitup/__main__.py +2 -1
  5. spiceitup-2.0.1/spiceitup/layout/__init__.py +0 -0
  6. spiceitup-2.0.1/spiceitup/layout/flow_layout.py +91 -0
  7. spiceitup-2.0.1/spiceitup/layout/flow_layout_edited.py +98 -0
  8. spiceitup-2.0.1/spiceitup/layout/flow_layout_old.py +96 -0
  9. spiceitup-2.0.1/spiceitup/logs/__init__.py +0 -0
  10. spiceitup-2.0.1/spiceitup/logs/log.py +41 -0
  11. spiceitup-2.0.1/spiceitup/main/__init__.py +0 -0
  12. spiceitup-2.0.1/spiceitup/main/footer.py +229 -0
  13. spiceitup-2.0.1/spiceitup/main/header.py +154 -0
  14. spiceitup-2.0.1/spiceitup/main/menu.py +624 -0
  15. spiceitup-2.0.1/spiceitup/main/menu_bar.py +184 -0
  16. spiceitup-2.0.1/spiceitup/main/w.py +28 -0
  17. spiceitup-2.0.1/spiceitup/main/winc.py +508 -0
  18. spiceitup-2.0.1/spiceitup/plot/__init__.py +0 -0
  19. spiceitup-2.0.1/spiceitup/plot/plot_line.py +182 -0
  20. spiceitup-2.0.1/spiceitup/plot/plot_map.py +539 -0
  21. spiceitup-2.0.1/spiceitup/processing/__init__.py +0 -0
  22. spiceitup-2.0.1/spiceitup/processing/dh.py +376 -0
  23. spiceitup-2.0.1/spiceitup/processing/fit.py +55 -0
  24. spiceitup-2.0.1/spiceitup/processing/threads/__init__.py +0 -0
  25. spiceitup-2.0.1/spiceitup/processing/threads/run_thread.py +137 -0
  26. spiceitup-2.0.1/spiceitup/processing/threads/thread_worker.py +20 -0
  27. spiceitup-2.0.1/spiceitup/processing/threads/workers/__init__.py +0 -0
  28. spiceitup-2.0.1/spiceitup/processing/threads/workers/compute_average.py +34 -0
  29. spiceitup-2.0.1/spiceitup/processing/threads/workers/generate_fit_maps.py +65 -0
  30. spiceitup-2.0.1/spiceitup/processing/threads/workers/load_plot_map.py +21 -0
  31. spiceitup-2.0.1/spiceitup/processing/threads/workers/make_process_available.py +17 -0
  32. spiceitup-2.0.1/spiceitup/processing/threads/workers/out_of_sync.py +30 -0
  33. spiceitup-2.0.1/spiceitup/processing/threads/workers/update_levels.py +37 -0
  34. spiceitup-2.0.1/spiceitup/processing/threads/workers/update_profile.py +77 -0
  35. {spiceitup-2.0.0 → spiceitup-2.0.1}/spiceitup/run.py +2 -2
  36. spiceitup-2.0.1/spiceitup/settings/__init__.py +0 -0
  37. spiceitup-2.0.1/spiceitup/settings/const.py +131 -0
  38. spiceitup-2.0.1/spiceitup/style/style.css +32 -0
  39. spiceitup-2.0.1/spiceitup/style/style_debug.css +13 -0
  40. spiceitup-2.0.1/spiceitup/toolbox/__init__.py +0 -0
  41. spiceitup-2.0.1/spiceitup/toolbox/binning.py +60 -0
  42. spiceitup-2.0.1/spiceitup/toolbox/clickable_qlabel.py +9 -0
  43. spiceitup-2.0.1/spiceitup/toolbox/filter2D_tests.py +27 -0
  44. spiceitup-2.0.1/spiceitup/toolbox/level_methods.py +23 -0
  45. spiceitup-2.0.1/spiceitup/toolbox/multithreading.py +22 -0
  46. spiceitup-2.0.1/spiceitup/toolbox/pyqtgraph_examples.py +10 -0
  47. spiceitup-2.0.1/spiceitup/toolbox/pyqtgraph_plot_example.py +104 -0
  48. spiceitup-2.0.1/spiceitup/toolbox/scipy_fit.py +29 -0
  49. spiceitup-2.0.1/spiceitup/toolbox/scipy_fit_gaussian.py +39 -0
  50. spiceitup-2.0.1/spiceitup/toolbox/show_icons.py +29 -0
  51. spiceitup-2.0.1/spiceitup/toolbox/signal_thread_ex.py +16 -0
  52. spiceitup-2.0.1/spiceitup/toolbox/small_pyqtgraph.py +91 -0
  53. spiceitup-2.0.1/spiceitup/toolbox/small_pyqtgraph2.py +94 -0
  54. spiceitup-2.0.1/spiceitup/toolbox/test.py +63 -0
  55. spiceitup-2.0.1/spiceitup/utils/__init__.py +0 -0
  56. spiceitup-2.0.1/spiceitup/utils/internal_utils.py +188 -0
  57. spiceitup-2.0.1/spiceitup/utils/special_chars.py +5 -0
  58. {spiceitup-2.0.0 → spiceitup-2.0.1}/spiceitup.egg-info/PKG-INFO +7 -2
  59. spiceitup-2.0.1/spiceitup.egg-info/SOURCES.txt +65 -0
  60. spiceitup-2.0.1/spiceitup.egg-info/requires.txt +6 -0
  61. spiceitup-2.0.0/spiceitup.egg-info/SOURCES.txt +0 -12
  62. spiceitup-2.0.0/spiceitup.egg-info/requires.txt +0 -1
  63. {spiceitup-2.0.0 → spiceitup-2.0.1}/README.md +0 -0
  64. {spiceitup-2.0.0 → spiceitup-2.0.1}/pyproject.toml +0 -0
  65. {spiceitup-2.0.0 → spiceitup-2.0.1}/setup.cfg +0 -0
  66. {spiceitup-2.0.0 → spiceitup-2.0.1}/spiceitup/main_call.py +0 -0
  67. {spiceitup-2.0.0 → spiceitup-2.0.1}/spiceitup.egg-info/dependency_links.txt +0 -0
  68. {spiceitup-2.0.0 → spiceitup-2.0.1}/spiceitup.egg-info/entry_points.txt +0 -0
  69. {spiceitup-2.0.0 → spiceitup-2.0.1}/spiceitup.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spiceitup
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: Quicklook tool for level 2 SPICE imaging
5
5
  Home-page: https://git.ias.u-psud.fr/spice/data_quicklook
6
6
  Author: David Picard
@@ -9,7 +9,12 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Requires-Python: >=3.7
11
11
  Description-Content-Type: text/markdown
12
- Requires-Dist: requirements.txt
12
+ Requires-Dist: PyQt6
13
+ Requires-Dist: sunraster
14
+ Requires-Dist: pyqtgraph
15
+ Requires-Dist: qdarkgraystyle
16
+ Requires-Dist: scipy
17
+ Requires-Dist: opencv-python-headless
13
18
  Dynamic: author
14
19
  Dynamic: author-email
15
20
  Dynamic: classifier
@@ -1,19 +1,30 @@
1
1
  import os
2
-
2
+ from pathlib import Path
3
3
  from importlib_metadata import entry_points
4
4
  from setuptools import setup, find_packages
5
5
 
6
6
  setup(
7
7
  name='spiceitup',
8
- version='2.0.0',
8
+ version='2.0.1',
9
9
  description='Quicklook tool for level 2 SPICE imaging',
10
10
  long_description=open('README.md').read(),
11
11
  long_description_content_type='text/markdown',
12
12
  author='David Picard',
13
13
  author_email='david.picard@universite-paris-saclay.fr',
14
14
  url='https://git.ias.u-psud.fr/spice/data_quicklook',
15
- packages=['spiceitup'],
16
- install_requires='requirements.txt',
15
+ packages=find_packages(),
16
+ include_package_data=True,
17
+ package_data={
18
+ "spiceitup": ["style/*.css"],
19
+ },
20
+ install_requires=[
21
+ "PyQt6",
22
+ "sunraster",
23
+ "pyqtgraph",
24
+ "qdarkgraystyle",
25
+ "scipy",
26
+ "opencv-python-headless"
27
+ ],
17
28
  classifiers=[
18
29
  'Programming Language :: Python :: 3',
19
30
  'License :: OSI Approved :: MIT License',
@@ -0,0 +1,7 @@
1
+ import os
2
+ import sys
3
+
4
+ _PACKAGE_DIR = os.path.dirname(os.path.abspath(__file__))
5
+
6
+ if _PACKAGE_DIR not in sys.path:
7
+ sys.path.insert(0, _PACKAGE_DIR)
@@ -1,5 +1,6 @@
1
1
  # handles call from pip install
2
-
2
+ import sys
3
+ import os
3
4
  from main_call import main
4
5
 
5
6
  if __name__ == '__main__':
File without changes
@@ -0,0 +1,91 @@
1
+ from PyQt6.QtCore import QPoint, QRect, QSize, Qt
2
+ from PyQt6.QtWidgets import (QApplication, QLayout, QPushButton, QSizePolicy, QWidget, QGridLayout)
3
+
4
+ class FlowLayout(QLayout):
5
+
6
+ def __init__(self, parent = None, margin = 0, spacing = -1):
7
+ super(FlowLayout, self).__init__(parent)
8
+
9
+ if parent is not None:
10
+ self.setContentsMargins(margin, margin, margin, margin)
11
+
12
+ self.setSpacing(spacing)
13
+
14
+ self.itemList = []
15
+
16
+ def __del__(self):
17
+ item = self.takeAt(0)
18
+ while item:
19
+ item = self.takeAt(0)
20
+
21
+ def addItem(self, item):
22
+ self.itemList.append(item)
23
+
24
+ def count(self):
25
+ return len(self.itemList)
26
+
27
+ def itemAt(self, index):
28
+ if index >= 0 and index < len(self.itemList):
29
+ return self.itemList[index]
30
+
31
+ return None
32
+
33
+ def takeAt(self, index):
34
+ if index >= 0 and index < len(self.itemList):
35
+ return self.itemList.pop(index)
36
+
37
+ return None
38
+
39
+ def expandingDirections(self):
40
+ return Qt.Orientations(Qt.Orientation(0))
41
+
42
+ def hasHeightForWidth(self):
43
+ return True
44
+
45
+ def heightForWidth(self, width):
46
+ height = self.doLayout(QRect(0, 0, width, 0), True)
47
+ return height
48
+
49
+ def setGeometry(self, rect):
50
+ super(FlowLayout, self).setGeometry(rect)
51
+ self.doLayout(rect, False)
52
+
53
+ def sizeHint(self):
54
+ return self.minimumSize()
55
+
56
+ def minimumSize(self):
57
+ size = QSize()
58
+
59
+ for item in self.itemList:
60
+ size = size.expandedTo(item.minimumSize())
61
+
62
+ margin, _, _, _ = self.getContentsMargins()
63
+
64
+ size += QSize(2 * margin, 2 * margin)
65
+ return size
66
+
67
+ def doLayout(self, rect, testOnly):
68
+ x = rect.x()
69
+ y = rect.y()
70
+ lineHeight = 0
71
+
72
+ for item in self.itemList:
73
+ wid = item.widget()
74
+ spaceX = self.spacing() + wid.style().layoutSpacing(QSizePolicy.ControlType.PushButton,
75
+ QSizePolicy.ControlType.PushButton, Qt.Orientation.Horizontal)
76
+ spaceY = self.spacing() + wid.style().layoutSpacing(QSizePolicy.ControlType.PushButton,
77
+ QSizePolicy.ControlType.PushButton, Qt.Orientation.Vertical)
78
+ nextX = x + item.sizeHint().width() + spaceX
79
+ if nextX - spaceX > rect.right() and lineHeight > 0:
80
+ x = rect.x()
81
+ y = y + lineHeight + spaceY
82
+ nextX = x + item.sizeHint().width() + spaceX
83
+ lineHeight = 0
84
+
85
+ if not testOnly:
86
+ item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
87
+
88
+ x = nextX
89
+ lineHeight = max(lineHeight, item.sizeHint().height())
90
+
91
+ return y + lineHeight - rect.y()
@@ -0,0 +1,98 @@
1
+ from PyQt6.QtCore import QPoint, QRect, QSize, Qt
2
+ from PyQt6.QtWidgets import (QApplication, QLayout, QPushButton, QSizePolicy, QWidget, QGridLayout)
3
+
4
+ class FlowLayout(QLayout):
5
+ q_plot_size = None
6
+
7
+ def __init__(self, parent = None, margin = 0, spacing = -1, q_plot_size = None):
8
+ # plot_size must be a QSize object
9
+ super(FlowLayout, self).__init__(parent)
10
+
11
+ if q_plot_size is not None:
12
+ self.q_plot_size = q_plot_size
13
+ self.q_plot_size.setHeight(int(self.q_plot_size.width() * 1.3)) # because of win title
14
+ self.q_plot_size.setWidth(self.q_plot_size.width() * 2) # because 2 plots x,y and lambda,y
15
+
16
+ if parent is not None:
17
+ self.setContentsMargins(margin, margin, margin, margin)
18
+
19
+ self.setSpacing(spacing)
20
+
21
+ self.itemList = []
22
+
23
+ def __del__(self):
24
+ item = self.takeAt(0)
25
+ while item:
26
+ item = self.takeAt(0)
27
+
28
+ def addItem(self, item):
29
+ self.itemList.append(item)
30
+
31
+ def count(self):
32
+ return len(self.itemList)
33
+
34
+ def itemAt(self, index):
35
+ if index >= 0 and index < len(self.itemList):
36
+ return self.itemList[index]
37
+
38
+ return None
39
+
40
+ def takeAt(self, index):
41
+ if index >= 0 and index < len(self.itemList):
42
+ return self.itemList.pop(index)
43
+
44
+ return None
45
+
46
+ def expandingDirections(self):
47
+ return Qt.Orientations(Qt.Orientation(0))
48
+
49
+ def hasHeightForWidth(self):
50
+ return True
51
+
52
+ def heightForWidth(self, width):
53
+ height = self.doLayout(QRect(0, 0, width, 0), True)
54
+ return height
55
+
56
+ def setGeometry(self, rect):
57
+ super(FlowLayout, self).setGeometry(rect)
58
+ self.doLayout(rect, False)
59
+
60
+ def sizeHint(self):
61
+ return self.minimumSize()
62
+
63
+ def minimumSize(self):
64
+ size = QSize()
65
+
66
+ for item in self.itemList:
67
+ size = size.expandedTo(item.minimumSize())
68
+
69
+ margin, _, _, _ = self.getContentsMargins()
70
+
71
+ size += QSize(2 * margin, 2 * margin)
72
+ return size
73
+
74
+ def doLayout(self, rect, testOnly):
75
+ x = rect.x()
76
+ y = rect.y()
77
+ lineHeight = 0
78
+
79
+ for item in self.itemList:
80
+ wid = item.widget()
81
+ spaceX = self.spacing() + wid.style().layoutSpacing(QSizePolicy.ControlType.PushButton,
82
+ QSizePolicy.ControlType.PushButton, Qt.Orientation.Horizontal)
83
+ spaceY = self.spacing() + wid.style().layoutSpacing(QSizePolicy.ControlType.PushButton,
84
+ QSizePolicy.ControlType.PushButton, Qt.Orientation.Vertical)
85
+ nextX = x + self.q_plot_size.width() + spaceX #nextX = x + item.sizeHint().width() + spaceX
86
+ if nextX - spaceX > rect.right() and lineHeight > 0:
87
+ x = rect.x()
88
+ y = y + lineHeight + spaceY
89
+ nextX = x + self.q_plot_size.width() + spaceX #nextX = x + item.sizeHint().width() + spaceX
90
+ lineHeight = 0
91
+
92
+ if not testOnly:
93
+ item.setGeometry(QRect(QPoint(x, y), self.q_plot_size)) #item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
94
+
95
+ x = nextX
96
+ lineHeight = max(lineHeight, self.q_plot_size.height()) #lineHeight = max(lineHeight, item.sizeHint().height())
97
+
98
+ return y + lineHeight - rect.y()
@@ -0,0 +1,96 @@
1
+ from PyQt6.QtCore import QPoint, QRect, QSize, Qt
2
+ from PyQt6.QtWidgets import (QApplication, QLayout, QPushButton, QSizePolicy, QWidget, QGridLayout)
3
+
4
+ class FlowLayout(QLayout):
5
+ q_plot_size = None
6
+
7
+ def __init__(self, parent = None, margin = 0, spacing = -1, q_plot_size = None):
8
+ # plot_size must be a QSize object
9
+ super(FlowLayout, self).__init__(parent)
10
+
11
+ if q_plot_size is not None:
12
+ self.q_plot_size = q_plot_size
13
+
14
+ if parent is not None:
15
+ self.setContentsMargins(margin, margin, margin, margin)
16
+
17
+ self.setSpacing(spacing)
18
+
19
+ self.itemList = []
20
+
21
+ def __del__(self):
22
+ item = self.takeAt(0)
23
+ while item:
24
+ item = self.takeAt(0)
25
+
26
+ def addItem(self, item):
27
+ self.itemList.append(item)
28
+
29
+ def count(self):
30
+ return len(self.itemList)
31
+
32
+ def itemAt(self, index):
33
+ if index >= 0 and index < len(self.itemList):
34
+ return self.itemList[index]
35
+
36
+ return None
37
+
38
+ def takeAt(self, index):
39
+ if index >= 0 and index < len(self.itemList):
40
+ return self.itemList.pop(index)
41
+
42
+ return None
43
+
44
+ def expandingDirections(self):
45
+ return Qt.Orientations(Qt.Orientation(0))
46
+
47
+ def hasHeightForWidth(self):
48
+ return True
49
+
50
+ def heightForWidth(self, width):
51
+ height = self.doLayout(QRect(0, 0, width, 0), True)
52
+ return height
53
+
54
+ def setGeometry(self, rect):
55
+ super(FlowLayout, self).setGeometry(rect)
56
+ self.doLayout(rect, False)
57
+
58
+ def sizeHint(self):
59
+ return self.minimumSize()
60
+
61
+ def minimumSize(self):
62
+ size = QSize()
63
+
64
+ for item in self.itemList:
65
+ size = size.expandedTo(item.minimumSize())
66
+
67
+ margin, _, _, _ = self.getContentsMargins()
68
+
69
+ size += QSize(2 * margin, 2 * margin)
70
+ return size
71
+
72
+ def doLayout(self, rect, testOnly):
73
+ x = rect.x()
74
+ y = rect.y()
75
+ lineHeight = 0
76
+
77
+ for item in self.itemList:
78
+ wid = item.widget()
79
+ spaceX = self.spacing() + wid.style().layoutSpacing(QSizePolicy.ControlType.PushButton,
80
+ QSizePolicy.ControlType.PushButton, Qt.Orientation.Horizontal)
81
+ spaceY = self.spacing() + wid.style().layoutSpacing(QSizePolicy.ControlType.PushButton,
82
+ QSizePolicy.ControlType.PushButton, Qt.Orientation.Vertical)
83
+ nextX = x + item.sizeHint().width() + spaceX
84
+ if nextX - spaceX > rect.right() and lineHeight > 0:
85
+ x = rect.x()
86
+ y = y + lineHeight + spaceY
87
+ nextX = x + item.sizeHint().width() + spaceX
88
+ lineHeight = 0
89
+
90
+ if not testOnly:
91
+ item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
92
+
93
+ x = nextX
94
+ lineHeight = max(lineHeight, item.sizeHint().height())
95
+
96
+ return y + lineHeight - rect.y()
File without changes
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from datetime import datetime
4
+ from settings.const import Const
5
+
6
+ from utils.internal_utils import get_ms
7
+
8
+
9
+ class Log:
10
+
11
+ @staticmethod
12
+ def p(*msgs, msg_type='info'):
13
+ """Prints in log"""
14
+ prefix = 'INFO'
15
+ if msg_type == 'warn':
16
+ prefix = 'WARNING'
17
+ elif msg_type == 'error':
18
+ prefix = 'ERROR'
19
+
20
+ today_dt = datetime.now()
21
+ today_str = today_dt.strftime(Const.date_format)
22
+
23
+ try:
24
+ with open(Const.log_file, 'a') as f:
25
+ for msg in msgs:
26
+ f.write(today_str + ' ' + prefix + ': ' + str(msg) + '\n')
27
+ except PermissionError:
28
+ print('Permission denined when appening in ' + Const.log_file)
29
+
30
+
31
+ @staticmethod
32
+ def p_ms(msg, first_time_ms=0):
33
+ """Prints current time in milliseconds in log file.
34
+ A first_time_ms can be removed in order to investigate more easily the time
35
+ latency between instructions"""
36
+ Log.p(str(get_ms() - first_time_ms) + ': ' + msg)
37
+
38
+
39
+ @staticmethod
40
+ def p_duration(first_time_ms):
41
+ Log.p('Duration since first time: ' + str(get_ms() - first_time_ms) + ' ms')
File without changes
@@ -0,0 +1,229 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ from datetime import datetime
4
+ from functools import partial
5
+
6
+ from PyQt6.QtCore import Qt
7
+ from PyQt6.QtWidgets import *
8
+
9
+ from logs.log import Log
10
+ from processing.threads.run_thread import RunThread
11
+ from settings.const import Const
12
+
13
+ class Footer(QFrame):
14
+ main = None
15
+ f_container = None
16
+ progress_lines = []
17
+
18
+ def __init__(self, main):
19
+ super(Footer, self).__init__()
20
+ self.main = main
21
+ self.setFrameShape(QFrame.Shape.StyledPanel)
22
+
23
+ l_footer = QVBoxLayout(self)
24
+ self.f_container = QFrame()
25
+
26
+ w_scroll = QScrollArea()
27
+ w_scroll.setWidget(self.f_container)
28
+ w_scroll.setWidgetResizable(True)
29
+ l_footer.addWidget(w_scroll)
30
+
31
+ self.l_grid = QGridLayout()
32
+ self.l_grid.setVerticalSpacing(5)
33
+
34
+ self.f_container.setLayout(self.l_grid)
35
+
36
+ def show_progress_line(self, index):
37
+ for key, widget in self.progress_lines[index].items():
38
+ if not isinstance(widget, int) and not isinstance(widget, str): # exclude index/line and title text
39
+ widget.show()
40
+
41
+ def hide_progress_line(self, index):
42
+ for key, widget in self.progress_lines[index].items():
43
+ if not isinstance(widget, int) and not isinstance(widget, str): # exclude index/line and title text
44
+ widget.hide()
45
+
46
+ def get_color(self, val):
47
+ color = Const.progress_bar_color
48
+ if val == 100:
49
+ color = Const.progress_bar_color_done
50
+ return color
51
+
52
+ def get_text_color(self, val):
53
+ color = Const.progress_bar_color
54
+ if val == 100:
55
+ color = Const.green_text
56
+ return color
57
+
58
+ def get_progress_line_index(self, id_):
59
+ for index, pl in enumerate(self.progress_lines):
60
+ if pl['id'] == id_:
61
+ return index
62
+
63
+ def update_progress_line_by_id(self, id_, val):
64
+ index = self.get_progress_line_index(id_)
65
+ self.update_progress_line(index, val)
66
+
67
+ def interrupt_progress_line_by_id(self, id_):
68
+ index = self.get_progress_line_index(id_)
69
+ self.interrupt_progress_line(index)
70
+
71
+ def interrupt_processes(self):
72
+ for index, pl in enumerate(self.progress_lines):
73
+ if pl['val'] < 100:
74
+ self.interrupt_progress_line(index)
75
+
76
+ def interrupt_progress_line(self, index):
77
+ color = Const.progress_bar_interrupt_color
78
+ text_color = Const.red_text
79
+ self.progress_lines[index]['interrupted'] = True
80
+ self.progress_lines[index]['pb'].setStyleSheet('QProgressBar::chunk { background-color: ' +
81
+ color + ';}')
82
+ self.progress_lines[index]['pb2'].setStyleSheet('QProgressBar::chunk { background-color: ' +
83
+ color + ';}')
84
+ self.progress_lines[index]['q_title'].setText('<font color="' + text_color + '">' +
85
+ self.progress_lines[index]['title'] + '</font>')
86
+ val = self.progress_lines[index]['val']
87
+ val_str = '-'
88
+ if val != 1:
89
+ val_str = str(val) + ' %'
90
+ self.progress_lines[index]['q_pc'].setText('<font color="' + text_color + '"><b>' +
91
+ val_str + '</b></font>')
92
+ self.progress_lines[index]['b_cancel'].setText('Cancelled')
93
+
94
+ def update_progress_line(self, index, val, new_line=False): # Use update_progress_line_by_id from outside instead
95
+ # because lines are continuously changing here (adding one moves the other ones)
96
+ if self.progress_lines[index]['interrupted'] and not new_line and val < 100:
97
+ color = Const.progress_bar_interrupt_color
98
+ text_color = Const.red_text
99
+ else:
100
+ color = self.get_color(val)
101
+ text_color = self.get_text_color(val)
102
+ self.progress_lines[index]['pb'].setStyleSheet('QProgressBar::chunk { background-color: ' +
103
+ color + ';}')
104
+ self.progress_lines[index]['pb2'].setStyleSheet('QProgressBar::chunk { background-color: ' +
105
+ color + ';}')
106
+ if val > 100:
107
+ Log.p('Warning: value greater than 100% given (' + str(val) + '), set to 100.')
108
+ val = 100
109
+
110
+ # Setting up both sliders
111
+ val1 = val * 2
112
+ if val1 > 100:
113
+ val1 = 100
114
+ val2 = 2 * (val - 50)
115
+ if val2 < 0:
116
+ val2 = 0
117
+ val_str = '-'
118
+ if val != 1:
119
+ val_str = str(val) + ' %'
120
+ self.progress_lines[index]['pb'].setValue(val1)
121
+ self.progress_lines[index]['pb2'].setValue(val2)
122
+ self.progress_lines[index]['q_title'].setText('<font color="' + text_color + '">' +
123
+ self.progress_lines[index]['title'] + '</font>')
124
+ self.progress_lines[index]['q_pc'].setText('<font color="' + text_color + '"><b>' +
125
+ val_str + '</b></font>')
126
+ self.progress_lines[index]['val'] = val
127
+
128
+ if not new_line:
129
+ pl_from = self.progress_lines[index]
130
+ pl_from['val'] = val
131
+ self.update_cancel_button(pl_from, self.progress_lines[index])
132
+ rt = self.progress_lines[index]['rt']
133
+ b_cancel = self.progress_lines[index]['b_cancel']
134
+ try:
135
+ b_cancel.clicked.disconnect()
136
+ except TypeError: # this one was not connected
137
+ pass
138
+ b_cancel.clicked.connect(partial(Footer.interrupt,
139
+ b_cancel,
140
+ rt))
141
+
142
+ def change_line(self, index, pl):
143
+ val = self.progress_lines[index]['val']
144
+ if pl['interrupted']:
145
+ text_color = Const.red_text
146
+ else:
147
+ text_color = self.get_text_color(val)
148
+ self.progress_lines[index]['title'] = pl['title']
149
+ self.progress_lines[index]['q_title'].setText('<font color="' + text_color + '">' +
150
+ pl['title'] + '</font>')
151
+ self.progress_lines[index]['interrupted'] = pl['interrupted']
152
+ self.progress_lines[index]['with_cancel'] = pl['with_cancel']
153
+ self.update_cancel_button(pl, self.progress_lines[index])
154
+ self.progress_lines[index]['rt'] = pl['rt']
155
+
156
+ def update_cancel_button(self, pl_from, pl_to):
157
+ if pl_to['val'] is not None:
158
+ is_done = pl_to['val'] >= 100
159
+ must_be_enabled = pl_from['with_cancel'] and not pl_from['interrupted'] and not is_done
160
+ pl_to['b_cancel'].setEnabled(must_be_enabled)
161
+ cancel_text = 'Cancel'
162
+ if is_done:
163
+ cancel_text = 'Done'
164
+ elif pl_from['interrupted']:
165
+ cancel_text = 'Cancelled'
166
+ button_css = Const.footer_button + ' '
167
+ button_css += Const.button_enabled if must_be_enabled else Const.button_disabled
168
+ pl_to['b_cancel'].setStyleSheet(button_css)
169
+ pl_to['b_cancel'].setText(cancel_text)
170
+
171
+ @staticmethod
172
+ def interrupt(b_cancel, rt):
173
+ b_cancel.setText('Cancelled')
174
+ b_cancel.setEnabled(False)
175
+ b_cancel.setStyleSheet(Const.footer_button + ' ' + Const.button_disabled)
176
+ rt.interrupt()
177
+
178
+ def create_progress_line(self, rt, title, with_cancel=True):
179
+ now = datetime.now()
180
+ title = 'At ' + now.strftime('%H:%M:%S') + ' - ' + title
181
+ q_title = QLabel()
182
+ q_pc = QLabel('')
183
+ q_pc.setAlignment(Qt.AlignmentFlag.AlignCenter)
184
+ pb = QProgressBar()
185
+ pb.setFixedHeight(Const.progress_bar_height)
186
+ pb.setTextVisible(False)
187
+ pb2 = QProgressBar()
188
+ pb2.setFixedHeight(Const.progress_bar_height)
189
+ pb2.setTextVisible(False)
190
+ b_cancel = QPushButton('Cancel')
191
+ if with_cancel:
192
+ b_cancel.setStyleSheet(Const.footer_button + ' ' + Const.button_enabled)
193
+ else:
194
+ b_cancel.setStyleSheet(Const.footer_button + ' ' + Const.button_disabled)
195
+ b_cancel.setEnabled(False)
196
+
197
+ new_index = len(self.progress_lines)
198
+
199
+ self.l_grid.addWidget(q_title, new_index, 0)
200
+ self.l_grid.addWidget(pb, new_index, 1)
201
+ self.l_grid.addWidget(q_pc, new_index, 2)
202
+ self.l_grid.addWidget(pb2, new_index, 3)
203
+ self.l_grid.addWidget(b_cancel, new_index, 4)
204
+
205
+ # will be erased but create permanent objects (bars, labels, button)
206
+ self.progress_lines.append({'id': '', 'title': '', 'q_title': q_title, 'with_cancel': None,
207
+ 'pb': pb, 'q_pc': q_pc, 'pb2': pb2, 'val': None,
208
+ 'interrupted': None, 'b_cancel': b_cancel, 'rt': None})
209
+
210
+ if new_index > 0:
211
+ # Push other lines to free the first line
212
+ for i in reversed(range(new_index)):
213
+ # Copying i into (i + 1)
214
+ self.progress_lines[i + 1]['id'] = self.progress_lines[i]['id']
215
+ self.change_line(i + 1, self.progress_lines[i])
216
+ self.update_progress_line(i + 1, self.progress_lines[i]['val'])
217
+
218
+ # Now line 0 is available
219
+ self.update_progress_line(0, 0, True)
220
+ self.change_line(0, {'title': title, 'interrupted': False, 'with_cancel': with_cancel,
221
+ 'b_cancel': b_cancel, 'rt': rt})
222
+ self.progress_lines[0]['id'] = new_index
223
+ if with_cancel:
224
+ self.progress_lines[0]['b_cancel'].clicked.connect(partial(Footer.interrupt,
225
+ self.progress_lines[0]['b_cancel'],
226
+ rt))
227
+
228
+ return new_index # created id
229
+