sgtlib 3.3.9__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 (72) hide show
  1. StructuralGT/__init__.py +31 -0
  2. StructuralGT/apps/__init__.py +0 -0
  3. StructuralGT/apps/cli_main.py +258 -0
  4. StructuralGT/apps/gui_main.py +69 -0
  5. StructuralGT/apps/gui_mcw/__init__.py +0 -0
  6. StructuralGT/apps/gui_mcw/checkbox_model.py +91 -0
  7. StructuralGT/apps/gui_mcw/controller.py +1073 -0
  8. StructuralGT/apps/gui_mcw/image_provider.py +74 -0
  9. StructuralGT/apps/gui_mcw/imagegrid_model.py +75 -0
  10. StructuralGT/apps/gui_mcw/qthread_worker.py +102 -0
  11. StructuralGT/apps/gui_mcw/table_model.py +79 -0
  12. StructuralGT/apps/gui_mcw/tree_model.py +154 -0
  13. StructuralGT/apps/sgt_qml/CenterMainContent.qml +19 -0
  14. StructuralGT/apps/sgt_qml/LeftContent.qml +48 -0
  15. StructuralGT/apps/sgt_qml/MainWindow.qml +762 -0
  16. StructuralGT/apps/sgt_qml/RightLoggingPanel.qml +125 -0
  17. StructuralGT/apps/sgt_qml/assets/icons/.DS_Store +0 -0
  18. StructuralGT/apps/sgt_qml/assets/icons/back_icon.png +0 -0
  19. StructuralGT/apps/sgt_qml/assets/icons/brightness_icon.png +0 -0
  20. StructuralGT/apps/sgt_qml/assets/icons/cancel_icon.png +0 -0
  21. StructuralGT/apps/sgt_qml/assets/icons/crop_icon.png +0 -0
  22. StructuralGT/apps/sgt_qml/assets/icons/edit_icon.png +0 -0
  23. StructuralGT/apps/sgt_qml/assets/icons/graph_icon.png +0 -0
  24. StructuralGT/apps/sgt_qml/assets/icons/hide_panel.png +0 -0
  25. StructuralGT/apps/sgt_qml/assets/icons/next_icon.png +0 -0
  26. StructuralGT/apps/sgt_qml/assets/icons/notify_icon.png +0 -0
  27. StructuralGT/apps/sgt_qml/assets/icons/rescale_icon.png +0 -0
  28. StructuralGT/apps/sgt_qml/assets/icons/show_panel.png +0 -0
  29. StructuralGT/apps/sgt_qml/assets/icons/square_icon.png +0 -0
  30. StructuralGT/apps/sgt_qml/assets/icons/undo_icon.png +0 -0
  31. StructuralGT/apps/sgt_qml/components/ImageFilters.qml +82 -0
  32. StructuralGT/apps/sgt_qml/components/ImageProperties.qml +112 -0
  33. StructuralGT/apps/sgt_qml/components/ProjectNav.qml +127 -0
  34. StructuralGT/apps/sgt_qml/widgets/BinaryFilterWidget.qml +151 -0
  35. StructuralGT/apps/sgt_qml/widgets/BrightnessControlWidget.qml +103 -0
  36. StructuralGT/apps/sgt_qml/widgets/CreateProjectWidget.qml +112 -0
  37. StructuralGT/apps/sgt_qml/widgets/GTWidget.qml +94 -0
  38. StructuralGT/apps/sgt_qml/widgets/GraphComputeWidget.qml +77 -0
  39. StructuralGT/apps/sgt_qml/widgets/GraphExtractWidget.qml +175 -0
  40. StructuralGT/apps/sgt_qml/widgets/GraphPropertyWidget.qml +77 -0
  41. StructuralGT/apps/sgt_qml/widgets/ImageFilterWidget.qml +137 -0
  42. StructuralGT/apps/sgt_qml/widgets/ImagePropertyWidget.qml +78 -0
  43. StructuralGT/apps/sgt_qml/widgets/ImageViewWidget.qml +585 -0
  44. StructuralGT/apps/sgt_qml/widgets/MenuBarWidget.qml +137 -0
  45. StructuralGT/apps/sgt_qml/widgets/MicroscopyPropertyWidget.qml +80 -0
  46. StructuralGT/apps/sgt_qml/widgets/ProjectWidget.qml +141 -0
  47. StructuralGT/apps/sgt_qml/widgets/RescaleControlWidget.qml +83 -0
  48. StructuralGT/apps/sgt_qml/widgets/RibbonWidget.qml +406 -0
  49. StructuralGT/apps/sgt_qml/widgets/StatusBarWidget.qml +173 -0
  50. StructuralGT/compute/__init__.py +0 -0
  51. StructuralGT/compute/c_lang/include/sgt_base.h +21 -0
  52. StructuralGT/compute/graph_analyzer.py +1499 -0
  53. StructuralGT/entrypoints.py +49 -0
  54. StructuralGT/imaging/__init__.py +0 -0
  55. StructuralGT/imaging/base_image.py +403 -0
  56. StructuralGT/imaging/image_processor.py +780 -0
  57. StructuralGT/modules.py +29 -0
  58. StructuralGT/networks/__init__.py +0 -0
  59. StructuralGT/networks/fiber_network.py +490 -0
  60. StructuralGT/networks/graph_skeleton.py +425 -0
  61. StructuralGT/networks/sknw_mod.py +199 -0
  62. StructuralGT/utils/__init__.py +0 -0
  63. StructuralGT/utils/config_loader.py +244 -0
  64. StructuralGT/utils/configs.ini +97 -0
  65. StructuralGT/utils/progress_update.py +67 -0
  66. StructuralGT/utils/sgt_utils.py +291 -0
  67. sgtlib-3.3.9.dist-info/METADATA +789 -0
  68. sgtlib-3.3.9.dist-info/RECORD +72 -0
  69. sgtlib-3.3.9.dist-info/WHEEL +5 -0
  70. sgtlib-3.3.9.dist-info/entry_points.txt +3 -0
  71. sgtlib-3.3.9.dist-info/licenses/LICENSE +674 -0
  72. sgtlib-3.3.9.dist-info/top_level.txt +1 -0
@@ -0,0 +1,31 @@
1
+ """
2
+ **StructuralGT**
3
+
4
+ A software package for performing Graph Theory on microscopic TEM images. This software is a \
5
+ modified version of StructuralGT by Drew A. Vecchio: https://github.com/drewvecchio/StructuralGT.
6
+
7
+ Copyright (C) 2025, the Regents of the University of Michigan.
8
+
9
+ This program is free software: you can redistribute it and/or modify \
10
+ it under the terms of the GNU General Public License as published by \
11
+ the Free Software Foundation, either version 3 of the License, or \
12
+ (at your option) any later version. This program is distributed in \
13
+ the hope that it will be useful, but WITHOUT ANY WARRANTY; without \
14
+ even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. \
15
+ See the GNU General Public License for more details. You should have received a copy \
16
+ of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ Development Lead: Dickson Owuor
19
+
20
+ Contributors: Nicholas A. Kotov
21
+
22
+ Contact email: owuordickson@gmail.com
23
+ """
24
+
25
+
26
+ # Project Details
27
+ __version__ = "3.3.9"
28
+ __install_version__ = "3.3.9"
29
+ __title__ = f"StructuralGT (v{__version__})"
30
+ __author__ = "Dickson Owuor"
31
+ __credits__ = "The Regents of the University of Michigan"
File without changes
@@ -0,0 +1,258 @@
1
+ # SPDX-License-Identifier: GNU GPL v3
2
+
3
+ """
4
+ Terminal interface implementations
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import logging
10
+ from optparse import OptionParser
11
+
12
+ from ..utils.sgt_utils import verify_path, AbortException
13
+ from ..utils.config_loader import strict_read_config_file
14
+ from ..imaging.image_processor import ImageProcessor, ALLOWED_IMG_EXTENSIONS
15
+ from ..compute.graph_analyzer import GraphAnalyzer
16
+
17
+ logger = logging.getLogger("SGT App")
18
+ # logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s", stream=sys.stdout)
19
+
20
+ class TerminalApp:
21
+ """Exposes the terminal interface for StructuralGT."""
22
+
23
+ def __init__(self, config_path: str):
24
+ """
25
+ Exposes methods for running StructuralGT tasks
26
+ :param config_path: the path to the configuration file
27
+ """
28
+ # Create graph objects
29
+ self.config_file = config_path
30
+ self.allow_auto_scale = True
31
+ self.sgt_objs = {}
32
+
33
+ def create_sgt_object(self, img_path, out_dir):
34
+ """
35
+ A function that processes a selected image file and creates an analyzer object with default configurations.
36
+
37
+ Args:
38
+ img_path (str): file path to image
39
+ out_dir (str): file path to the output folder.
40
+
41
+ Returns:
42
+ """
43
+
44
+ success, result = verify_path(img_path)
45
+ if success:
46
+ img_path = result
47
+ if out_dir != "":
48
+ path_ok, new_path = verify_path(out_dir)
49
+ out_dir = new_path if path_ok else ""
50
+ else:
51
+ logging.info(result, extra={'user': 'SGT Logs'})
52
+ return False
53
+
54
+ # Create an SGT object as a GraphAnalyzer object.
55
+ try:
56
+ ntwk_p, img_file = ImageProcessor.create_imp_object(img_path, out_dir, self.config_file, self.allow_auto_scale)
57
+ sgt_obj = GraphAnalyzer(ntwk_p)
58
+ self.sgt_objs[img_file] = sgt_obj
59
+ return True
60
+ except Exception as err:
61
+ logging.exception("File Error: %s", err, extra={'user': 'SGT Logs'})
62
+ return False
63
+
64
+ def get_selected_sgt_obj(self, obj_index: int = 0):
65
+ """
66
+ Retrieve the SGT object at a specified index.
67
+ Args:
68
+ obj_index: index of the SGT object to retrieve
69
+ """
70
+ try:
71
+ keys_list = list(self.sgt_objs.keys())
72
+ key_at_index = keys_list[obj_index]
73
+ sgt_obj = self.sgt_objs[key_at_index]
74
+ return sgt_obj
75
+ except IndexError:
76
+ logging.info("No Image Error: Please import/add an image.", extra={'user': 'SGT Logs'})
77
+ return None
78
+
79
+ def add_single_image(self, image_path, output_dir):
80
+ """
81
+ Verify and validate an image path, use it to create an SGT object
82
+
83
+ :param image_path: image path to be processed
84
+ :param output_dir: output directory for saving output files
85
+ :return: bool result of SGT object creation
86
+ """
87
+ is_created = self.create_sgt_object(image_path, output_dir)
88
+ if not is_created:
89
+ logging.info("Fatal Error: Unable to create SGT object", extra={'user': 'SGT Logs'})
90
+ return is_created
91
+
92
+ def add_multiple_images(self, img_dir_path, output_dir):
93
+ """
94
+ Verify and validate multiple image paths, use each to create an SGT object.
95
+ """
96
+
97
+ success, result = verify_path(img_dir_path)
98
+ if success:
99
+ img_dir_path = result
100
+ else:
101
+ logging.info(result, extra={'user': 'SGT Logs'})
102
+ return False
103
+
104
+ files = os.listdir(img_dir_path)
105
+ files = sorted(files)
106
+ for a_file in files:
107
+ allowed_extensions = tuple(ext[1:] if ext.startswith('*.') else ext for ext in ALLOWED_IMG_EXTENSIONS)
108
+ if a_file.endswith(allowed_extensions):
109
+ img_path = os.path.join(str(img_dir_path), a_file)
110
+ self.create_sgt_object(img_path, output_dir)
111
+
112
+ if len(self.sgt_objs) <= 0:
113
+ logging.info("File Error: Files have to be either .tif .png .jpg .jpeg", extra={'user': 'SGT Logs'})
114
+ return False
115
+ else:
116
+ return True
117
+
118
+ def task_extract_graph(self, selected_index: int = 0):
119
+ """"""
120
+ sgt_obj = self.get_selected_sgt_obj(obj_index=selected_index)
121
+ ntwk_p = sgt_obj.ntwk_p
122
+ try:
123
+ ntwk_p.abort = False
124
+ ntwk_p.add_listener(TerminalApp.update_progress)
125
+ ntwk_p.apply_img_filters()
126
+ ntwk_p.build_graph_network()
127
+ ntwk_p.remove_listener(TerminalApp.update_progress)
128
+ if ntwk_p.abort:
129
+ raise AbortException("Process aborted")
130
+ TerminalApp.update_progress(100, "Graph successfully extracted!")
131
+ return ntwk_p
132
+ except AbortException as err:
133
+ logging.exception("Task Aborted: %s", err, extra={'user': 'SGT Logs'})
134
+ # Clean up listeners before exiting
135
+ ntwk_p.remove_listener(TerminalApp.update_progress)
136
+ # Emit failure signal (aborted)
137
+ msg = "Graph extraction aborted due to error! Change image filters and/or graph settings and try again. If error persists then close the app and try again"
138
+ logging.info(f"Extract Graph Aborted: {msg}", extra={'user': 'SGT Logs'})
139
+ return None
140
+
141
+ def task_compute_gt(self, selected_index: int = 0):
142
+ """"""
143
+ sgt_obj = self.get_selected_sgt_obj(obj_index=selected_index)
144
+ success, new_sgt = GraphAnalyzer.safe_run_analyzer(sgt_obj, TerminalApp.update_progress)
145
+ if success:
146
+ GraphAnalyzer.write_to_pdf(new_sgt, TerminalApp.update_progress)
147
+ return new_sgt
148
+ else:
149
+ msg = "Either task was aborted by user or a fatal error occurred while computing GT parameters. Change image filters and/or graph settings and try again. If error persists then close the app and try again."
150
+ logging.info(f"SGT Computations Failed: {msg}", extra={'user': 'SGT Logs'})
151
+ return None
152
+
153
+ def task_compute_multi_gt(self):
154
+ """"""
155
+ new_sgt_objs = GraphAnalyzer.safe_run_multi_analyzer(self.sgt_objs, TerminalApp.update_progress)
156
+ if new_sgt_objs is None:
157
+ msg = "Either task was aborted by user or a fatal error occurred while computing GT parameters. Change image filters and/or graph settings and try again. If error persists then close the app and try again."
158
+ logging.info(f"SGT Computations Failed: {msg}", extra={'user': 'SGT Logs'})
159
+ return new_sgt_objs
160
+
161
+ @staticmethod
162
+ def update_progress(progress_val, msg):
163
+ """
164
+ Simple method to display progress updates.
165
+
166
+ Args:
167
+ progress_val (int): progress value
168
+ msg (str): progress message
169
+ Returns:
170
+ None:
171
+ """
172
+
173
+ if 0 <= progress_val <= 100:
174
+ print(f"{progress_val} %: {msg}")
175
+ logging.info(f"{progress_val} %: {msg}", extra={'user': 'SGT Logs'})
176
+ elif progress_val > 100:
177
+ print(f"{msg}")
178
+ logging.info(f"{msg}", extra={'user': 'SGT Logs'})
179
+ else:
180
+ print(f"Error: {msg}")
181
+ logging.exception(f"{msg}", extra={'user': 'SGT Logs'})
182
+
183
+ @classmethod
184
+ def execute(cls):
185
+ """Initializes and starts the terminal/CMD the StructuralGT application."""
186
+
187
+ # Retrieve user settings
188
+ opt_parser = OptionParser()
189
+ opt_parser.add_option('-f', '--inputFile',
190
+ dest='img_path',
191
+ help='path to image file',
192
+ default="",
193
+ type='string')
194
+ opt_parser.add_option('-d', '--inputDir',
195
+ dest='img_dir_path',
196
+ help='path to folder containing images',
197
+ default="",
198
+ type='string')
199
+ opt_parser.add_option('-o', '--outputDir',
200
+ dest='output_dir',
201
+ help='path to folder for saving output files. If not provided, output files will be saved in input dir.',
202
+ default="",
203
+ type='string')
204
+ opt_parser.add_option('-s', '--allowAutoScale',
205
+ dest='auto_scale',
206
+ help='allow automatic scaling of images',
207
+ default=1,
208
+ type='int')
209
+ opt_parser.add_option('-t', '--runTask',
210
+ dest='run_task',
211
+ help='you can run the following tasks: (1) extract graph; (2) compute GT metrics.',
212
+ default=2,
213
+ type='int')
214
+ opt_parser.add_option('-c', '--config',
215
+ dest='config_file',
216
+ help='path to config file',
217
+ default="",
218
+ type='string')
219
+ # opt_parser.add_option('-m', '--runMultiGT',
220
+ # dest='run_multi_gt',
221
+ # help='run compute GT parameters on multiple images',
222
+ # default=0,
223
+ # type='int')
224
+ # opt_parser.add_option('-i', '--selectedImgIndex',
225
+ # dest='sel_img_idx',
226
+ # help='index of selected image',
227
+ # default=0,
228
+ # type='int')
229
+ (cfg, args) = opt_parser.parse_args()
230
+ cfg.auto_scale = bool(cfg.auto_scale)
231
+ # cfg.run_multi_gt = bool(cfg.run_multi_gt)
232
+
233
+ # Create Terminal App
234
+ term_app = cls(cfg.config_file)
235
+
236
+ # 1. Verify config file
237
+ config_file_ok = strict_read_config_file(cfg.config_file, term_app.update_progress)
238
+ if not config_file_ok:
239
+ sys.exit('Usage: StructuralGT-cli -f datasets/InVitroBioFilm.png -c datasets/sgt_configs.ini -t 2 -o results/')
240
+
241
+ # 2. Get images and process them
242
+ if cfg.img_path != "":
243
+ term_app.add_single_image(cfg.img_path, cfg.output_dir)
244
+ elif cfg.img_dir_path != "":
245
+ term_app.add_multiple_images(cfg.img_dir_path, cfg.output_dir)
246
+ else:
247
+ term_app.update_progress(-1, "No image path/image folder provided! System will exit.")
248
+ sys.exit('System exit')
249
+
250
+ # 3. Execute specific task
251
+ if cfg.run_task == 1:
252
+ term_app.task_extract_graph()
253
+ elif cfg.run_task == 2:
254
+ run_multi_gt = True if cfg.img_dir_path != "" else False
255
+ term_app.task_compute_multi_gt() if run_multi_gt else term_app.task_compute_gt()
256
+ else:
257
+ term_app.update_progress(-1, "Invalid GT task selected! System will exit.")
258
+ sys.exit('System exit')
@@ -0,0 +1,69 @@
1
+ # SPDX-License-Identifier: GNU GPL v3
2
+
3
+ """
4
+ Pyside6 implementation of StructuralGT user interface.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ from PySide6.QtCore import QObject
10
+ from PySide6.QtWidgets import QApplication
11
+ from PySide6.QtQml import QQmlApplicationEngine
12
+
13
+ from .gui_mcw.controller import MainController
14
+ from .gui_mcw.image_provider import ImageProvider
15
+
16
+
17
+ class MainWindow(QObject):
18
+ def __init__(self):
19
+ super().__init__()
20
+ self.app = QApplication(sys.argv)
21
+ self.ui_engine = QQmlApplicationEngine()
22
+
23
+ # Register Controller for Dynamic Updates
24
+ controller = MainController(qml_app=self.app)
25
+ # Register Image Provider
26
+ self.image_provider = ImageProvider(controller)
27
+
28
+ # Test Image
29
+ # img_path = "../../../../../datasets/InVitroBioFilm.png"
30
+ # controller.imageChangedSignal.emit(0, img_path)
31
+
32
+ # Set Models in QML Context
33
+ self.ui_engine.rootContext().setContextProperty("imgThumbnailModel", controller.imgThumbnailModel)
34
+ self.ui_engine.rootContext().setContextProperty("imagePropsModel", controller.imagePropsModel)
35
+ self.ui_engine.rootContext().setContextProperty("graphPropsModel", controller.graphPropsModel)
36
+ self.ui_engine.rootContext().setContextProperty("graphComputeModel", controller.graphComputeModel)
37
+ self.ui_engine.rootContext().setContextProperty("microscopyPropsModel", controller.microscopyPropsModel)
38
+
39
+ self.ui_engine.rootContext().setContextProperty("gteTreeModel", controller.gteTreeModel)
40
+ self.ui_engine.rootContext().setContextProperty("gtcListModel", controller.gtcListModel)
41
+ self.ui_engine.rootContext().setContextProperty("exportGraphModel", controller.exportGraphModel)
42
+ self.ui_engine.rootContext().setContextProperty("imgBatchModel", controller.imgBatchModel)
43
+ self.ui_engine.rootContext().setContextProperty("imgControlModel", controller.imgControlModel)
44
+ self.ui_engine.rootContext().setContextProperty("imgBinFilterModel", controller.imgBinFilterModel)
45
+ self.ui_engine.rootContext().setContextProperty("imgFilterModel", controller.imgFilterModel)
46
+ self.ui_engine.rootContext().setContextProperty("imgScaleOptionModel", controller.imgScaleOptionModel)
47
+ self.ui_engine.rootContext().setContextProperty("saveImgModel", controller.saveImgModel)
48
+ self.ui_engine.rootContext().setContextProperty("img3dGridModel", controller.img3dGridModel)
49
+ self.ui_engine.rootContext().setContextProperty("mainController", controller)
50
+ self.ui_engine.addImageProvider("imageProvider", self.image_provider)
51
+
52
+ # Load UI
53
+ # Get the directory of the current script
54
+ qml_dir = os.path.dirname(os.path.abspath(__file__))
55
+ qml_name = 'sgt_qml/MainWindow.qml'
56
+ qml_path = os.path.join(qml_dir, qml_name)
57
+ self.ui_engine.load(qml_path)
58
+ if not self.ui_engine.rootObjects():
59
+ sys.exit(-1)
60
+
61
+
62
+ def pyside_app():
63
+ """
64
+ Initialize and run the PySide GUI application.
65
+ Returns:
66
+
67
+ """
68
+ main_window = MainWindow()
69
+ sys.exit(main_window.app.exec())
File without changes
@@ -0,0 +1,91 @@
1
+ from PySide6.QtCore import Qt, QAbstractListModel, QModelIndex, QPersistentModelIndex
2
+
3
+ # Define a simple QAbstractListModel
4
+ class CheckBoxModel(QAbstractListModel):
5
+ IdRole = Qt.ItemDataRole.UserRole + 1
6
+ TypeRole = Qt.ItemDataRole.UserRole + 2
7
+ TextRole = Qt.ItemDataRole.UserRole + 3
8
+ ValueRole = Qt.ItemDataRole.UserRole + 4
9
+ DataIdRole = Qt.ItemDataRole.UserRole + 5
10
+ DataValueRole = Qt.ItemDataRole.UserRole + 6
11
+ MinValueRole = Qt.ItemDataRole.UserRole + 7
12
+ MaxValueRole = Qt.ItemDataRole.UserRole + 8
13
+ StepSizeRole = Qt.ItemDataRole.UserRole + 9
14
+ VisibleRole = Qt.ItemDataRole.UserRole + 10
15
+
16
+ def __init__(self, data, parent=None):
17
+ super().__init__(parent)
18
+ self.list_data = data
19
+
20
+ def rowCount(self, parent=None):
21
+ return len(self.list_data)
22
+
23
+ def data(self, index, role=Qt.ItemDataRole.DisplayRole):
24
+ if not index.isValid() or index.row() >= len(self.list_data):
25
+ return None
26
+ item = self.list_data[index.row()]
27
+ if role == self.IdRole:
28
+ return item["id"]
29
+ elif role == self.TypeRole:
30
+ return item["type"]
31
+ elif role == self.TextRole:
32
+ return item["text"]
33
+ elif role == self.ValueRole:
34
+ return item["value"]
35
+ elif role == self.DataIdRole:
36
+ return item["dataId"]
37
+ elif role == self.DataValueRole:
38
+ return item["dataValue"]
39
+ elif role == self.MinValueRole:
40
+ return item["minValue"]
41
+ elif role == self.MaxValueRole:
42
+ return item["maxValue"]
43
+ elif role == self.StepSizeRole:
44
+ return item["stepSize"]
45
+ elif role == self.VisibleRole:
46
+ return item["visible"]
47
+ return None
48
+
49
+ def setData(self, index, value, role=Qt.ItemDataRole.DisplayRole):
50
+ """
51
+
52
+ Args:
53
+ index (QModelIndex | QPersistentModelIndex):
54
+ value (int|float):
55
+ role (int):
56
+ """
57
+ if not index.isValid() or index.row() >= len(self.list_data):
58
+ return False
59
+
60
+ if role == self.ValueRole:
61
+ self.list_data[index.row()]["value"] = value
62
+ self.dataChanged.emit(index, index, [role])
63
+ return True
64
+ if role == self.DataValueRole:
65
+ self.list_data[index.row()]["dataValue"] = value
66
+ self.dataChanged.emit(index, index, [role])
67
+ return True
68
+ return False
69
+
70
+ def reset_data(self, new_data):
71
+ self.beginResetModel()
72
+ self.list_data = new_data
73
+ self.endResetModel()
74
+ self.dataChanged.emit(self.index(0,0), self.index(len(new_data), 0),
75
+ [self.IdRole, self.TypeRole, self.TextRole, self.ValueRole, self.DataIdRole,
76
+ self.DataValueRole, self.MinValueRole, self.MaxValueRole, self.StepSizeRole,
77
+ self.VisibleRole])
78
+
79
+ def roleNames(self):
80
+ return {
81
+ self.IdRole: b"id",
82
+ self.TypeRole: b"type",
83
+ self.TextRole: b"text",
84
+ self.ValueRole: b"value",
85
+ self.DataIdRole: b"dataId",
86
+ self.DataValueRole: b"dataValue",
87
+ self.MinValueRole: b"minValue",
88
+ self.MaxValueRole: b"maxValue",
89
+ self.StepSizeRole: b"stepSize",
90
+ self.VisibleRole: b"visible"
91
+ }