pyqttoolkit 0.9.1__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 (133) hide show
  1. pyqttoolkit/__init__.py +20 -0
  2. pyqttoolkit/_version.py +21 -0
  3. pyqttoolkit/application/__init__.py +18 -0
  4. pyqttoolkit/application/application.py +86 -0
  5. pyqttoolkit/application/garbage_collector.py +65 -0
  6. pyqttoolkit/colors/__init__.py +84 -0
  7. pyqttoolkit/config/__init__.py +20 -0
  8. pyqttoolkit/config/base.py +22 -0
  9. pyqttoolkit/config/composite.py +31 -0
  10. pyqttoolkit/config/default.py +27 -0
  11. pyqttoolkit/config/environment.py +35 -0
  12. pyqttoolkit/config/multi_json_file.py +93 -0
  13. pyqttoolkit/config/with_signal.py +30 -0
  14. pyqttoolkit/config/with_value_changed.py +31 -0
  15. pyqttoolkit/data/__init__.py +21 -0
  16. pyqttoolkit/data/bits.py +23 -0
  17. pyqttoolkit/data/cache.py +64 -0
  18. pyqttoolkit/data/interval.py +26 -0
  19. pyqttoolkit/data/message.py +29 -0
  20. pyqttoolkit/data/names.py +24 -0
  21. pyqttoolkit/datetime/__init__.py +16 -0
  22. pyqttoolkit/datetime/datetime.py +51 -0
  23. pyqttoolkit/datetime/qdatetime.py +53 -0
  24. pyqttoolkit/dependencies/__init__.py +56 -0
  25. pyqttoolkit/errors/__init__.py +19 -0
  26. pyqttoolkit/exceptions/__init__.py +18 -0
  27. pyqttoolkit/filesystem/__init__.py +24 -0
  28. pyqttoolkit/logs/__init__.py +140 -0
  29. pyqttoolkit/metadata/__init__.py +23 -0
  30. pyqttoolkit/metadata/dataframe_metadata_manager.py +105 -0
  31. pyqttoolkit/metadata/dict_metadata_manager.py +63 -0
  32. pyqttoolkit/metadata/id_generator.py +20 -0
  33. pyqttoolkit/metadata/metadata_manager_base.py +54 -0
  34. pyqttoolkit/models/__init__.py +26 -0
  35. pyqttoolkit/models/code_text.py +43 -0
  36. pyqttoolkit/models/dataframetable.py +135 -0
  37. pyqttoolkit/models/dictpropertytree.py +155 -0
  38. pyqttoolkit/models/dicttable.py +140 -0
  39. pyqttoolkit/models/json_text.py +52 -0
  40. pyqttoolkit/models/list_model.py +52 -0
  41. pyqttoolkit/models/module.py +26 -0
  42. pyqttoolkit/models/roles.py +23 -0
  43. pyqttoolkit/models/series_data.py +68 -0
  44. pyqttoolkit/models/span.py +36 -0
  45. pyqttoolkit/models/validation.py +27 -0
  46. pyqttoolkit/modules/__init__.py +18 -0
  47. pyqttoolkit/modules/events/__init__.py +19 -0
  48. pyqttoolkit/modules/events/add_signal.py +31 -0
  49. pyqttoolkit/modules/events/module_opening.py +21 -0
  50. pyqttoolkit/modules/events/rejectable.py +29 -0
  51. pyqttoolkit/modules/launcher_config.py +55 -0
  52. pyqttoolkit/modules/module.py +111 -0
  53. pyqttoolkit/properties/__init__.py +18 -0
  54. pyqttoolkit/properties/auto.py +221 -0
  55. pyqttoolkit/properties/throttled.py +77 -0
  56. pyqttoolkit/scripting/__init__.py +19 -0
  57. pyqttoolkit/scripting/script_context.py +36 -0
  58. pyqttoolkit/scripting/script_runner.py +132 -0
  59. pyqttoolkit/scripting/script_template.py +42 -0
  60. pyqttoolkit/services/__init__.py +32 -0
  61. pyqttoolkit/services/autosave.py +41 -0
  62. pyqttoolkit/services/email.py +25 -0
  63. pyqttoolkit/services/event_registry.py +52 -0
  64. pyqttoolkit/services/file_dialog.py +71 -0
  65. pyqttoolkit/services/hotkey_manager.py +137 -0
  66. pyqttoolkit/services/link_manager.py +135 -0
  67. pyqttoolkit/services/message_board.py +90 -0
  68. pyqttoolkit/services/module_service.py +154 -0
  69. pyqttoolkit/services/object_converter.py +45 -0
  70. pyqttoolkit/services/project_updater.py +149 -0
  71. pyqttoolkit/services/task_runner.py +281 -0
  72. pyqttoolkit/services/theme_manager.py +46 -0
  73. pyqttoolkit/services/tool_window_service.py +46 -0
  74. pyqttoolkit/viewmanagers/__init__.py +17 -0
  75. pyqttoolkit/viewmanagers/tool.py +23 -0
  76. pyqttoolkit/views/__init__.py +50 -0
  77. pyqttoolkit/views/bulk_value_selector.py +112 -0
  78. pyqttoolkit/views/check_box.py +36 -0
  79. pyqttoolkit/views/code/__init__.py +18 -0
  80. pyqttoolkit/views/code/code_edit.py +268 -0
  81. pyqttoolkit/views/code/python_syntax.py +226 -0
  82. pyqttoolkit/views/combo_box.py +101 -0
  83. pyqttoolkit/views/count_selector.py +59 -0
  84. pyqttoolkit/views/datetime.py +111 -0
  85. pyqttoolkit/views/datetime_range_selector.py +231 -0
  86. pyqttoolkit/views/default_text_line_edit.py +50 -0
  87. pyqttoolkit/views/delegates.py +117 -0
  88. pyqttoolkit/views/dtype_edit.py +117 -0
  89. pyqttoolkit/views/editable_combo_box.py +45 -0
  90. pyqttoolkit/views/file_selector.py +51 -0
  91. pyqttoolkit/views/icon.py +67 -0
  92. pyqttoolkit/views/icon_button.py +129 -0
  93. pyqttoolkit/views/json_edit.py +21 -0
  94. pyqttoolkit/views/labelled.py +29 -0
  95. pyqttoolkit/views/layout/__init__.py +21 -0
  96. pyqttoolkit/views/layout/collabsible.py +59 -0
  97. pyqttoolkit/views/layout/group_box.py +48 -0
  98. pyqttoolkit/views/layout/group_panel.py +188 -0
  99. pyqttoolkit/views/layout/lines.py +30 -0
  100. pyqttoolkit/views/layout/link.py +38 -0
  101. pyqttoolkit/views/line_edit.py +61 -0
  102. pyqttoolkit/views/linkable.py +49 -0
  103. pyqttoolkit/views/list_view.py +43 -0
  104. pyqttoolkit/views/main_window.py +91 -0
  105. pyqttoolkit/views/metadata_selector.py +84 -0
  106. pyqttoolkit/views/modulewindow.py +81 -0
  107. pyqttoolkit/views/plot/__init__.py +26 -0
  108. pyqttoolkit/views/plot/legend_control.py +121 -0
  109. pyqttoolkit/views/plot/matplotlib/__init__.py +23 -0
  110. pyqttoolkit/views/plot/matplotlib/base.py +1056 -0
  111. pyqttoolkit/views/plot/matplotlib/colorbar.py +75 -0
  112. pyqttoolkit/views/plot/matplotlib/colormap.py +48 -0
  113. pyqttoolkit/views/plot/matplotlib/font.py +55 -0
  114. pyqttoolkit/views/plot/plot_options.py +211 -0
  115. pyqttoolkit/views/plot/plot_toolbar_options.py +133 -0
  116. pyqttoolkit/views/plot/size.py +41 -0
  117. pyqttoolkit/views/plot/tool_type.py +26 -0
  118. pyqttoolkit/views/plot/toolbar.py +100 -0
  119. pyqttoolkit/views/popout.py +41 -0
  120. pyqttoolkit/views/popup.py +41 -0
  121. pyqttoolkit/views/property_tree.py +26 -0
  122. pyqttoolkit/views/shrunk_push_button.py +34 -0
  123. pyqttoolkit/views/steppable_combo_box.py +67 -0
  124. pyqttoolkit/views/styleable.py +37 -0
  125. pyqttoolkit/views/table.py +146 -0
  126. pyqttoolkit/views/text_edit.py +31 -0
  127. pyqttoolkit/views/tool_window.py +35 -0
  128. pyqttoolkit-0.9.1.dist-info/METADATA +69 -0
  129. pyqttoolkit-0.9.1.dist-info/RECORD +133 -0
  130. pyqttoolkit-0.9.1.dist-info/WHEEL +5 -0
  131. pyqttoolkit-0.9.1.dist-info/licenses/LICENSE.txt +674 -0
  132. pyqttoolkit-0.9.1.dist-info/licenses/LICENSE_SHORT +16 -0
  133. pyqttoolkit-0.9.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,149 @@
1
+ # pyqttoolkit
2
+ # Copyright (C) 2018-2019, Simmovation Ltd.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software Foundation,
16
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+ """:mod:`project_updater`
18
+ Defines the ProjectUpdater class, which enables the project to be updated
19
+ """
20
+ import inspect
21
+ from threading import Lock
22
+
23
+ from PyQt5.QtCore import QObject, pyqtSignal, QEvent, QSemaphore, QThread
24
+ from PyQt5.QtWidgets import QApplication
25
+
26
+ def _check_attribute(name, fields, project):
27
+ if not name in fields:
28
+ raise ValueError(f'Could not access property {name} of project {type(project)}')
29
+
30
+
31
+ class ProjectProxy:
32
+ _storage = {}
33
+
34
+ def __init__(self, project):
35
+ ProjectProxy._storage[self] = {}
36
+ ProjectProxy._storage[self]['_fields'] = []
37
+ for name, obj in inspect.getmembers(type(project)):
38
+ if inspect.isdatadescriptor(obj):
39
+ ProjectProxy._storage[self]['_fields'].append(name)
40
+ ProjectProxy._storage[self]['_updates'] = {}
41
+ ProjectProxy._storage[self]['_project'] = project
42
+
43
+ def __enter__(self):
44
+ return self
45
+
46
+ def __exit__(self, exc_type, exc_value, traceback):
47
+ del ProjectProxy._storage[self]
48
+
49
+ def __setattr__(self, name, value):
50
+ _check_attribute(name, ProjectProxy._storage[self]['_fields'], ProjectProxy._storage[self]['_project'])
51
+ ProjectProxy._storage[self]['_updates'][name] = value
52
+
53
+ def __getattribute__(self, name):
54
+ if name == 'updates':
55
+ return ProjectProxy._storage[self]['_updates']
56
+ _check_attribute(name, ProjectProxy._storage[self]['_fields'], ProjectProxy._storage[self]['_project'])
57
+ return getattr(ProjectProxy._storage[self]['_project'], name)
58
+
59
+
60
+ class PropertyUpdatedEvent(QEvent):
61
+ def __init__(self, prop):
62
+ super().__init__(QEvent.User)
63
+ self._prop = prop
64
+
65
+ @property
66
+ def prop(self):
67
+ return self._prop
68
+
69
+ class UpdateCompleteEvent(QEvent):
70
+ def __init__(self, handler, result):
71
+ super().__init__(QEvent.User)
72
+ self._handler = handler
73
+ self._result = result
74
+
75
+ def exec(self):
76
+ self._handler(self._result)
77
+
78
+ class UpdateEvent(QEvent):
79
+ def __init__(self, updater):
80
+ super().__init__(QEvent.User)
81
+ self._updater = updater
82
+ self._result = None
83
+ self._semaphore = QSemaphore(1)
84
+ if QApplication.instance().thread() != QThread.currentThread():
85
+ self._semaphore.acquire()
86
+
87
+ def exec(self):
88
+ try:
89
+ self._result = self._updater(None)
90
+ finally:
91
+ self._semaphore.release()
92
+
93
+ def result(self):
94
+ self._semaphore.acquire()
95
+ return self._result
96
+
97
+ class ProjectUpdater(QObject):
98
+ """class::ProjectUpdater
99
+ Allows the project to be updated
100
+ """
101
+ def __init__(self, project_manager):
102
+ QObject.__init__(self, project_manager)
103
+ self._project_manager = project_manager
104
+ self._is_dirty = False
105
+ self._lock = Lock()
106
+
107
+ projectUpdated = pyqtSignal(str)
108
+
109
+ @property
110
+ def dirty(self):
111
+ return self._is_dirty
112
+
113
+ @dirty.setter
114
+ def dirty(self, value):
115
+ self._is_dirty = value
116
+
117
+ @property
118
+ def update_lock(self):
119
+ return self._lock
120
+
121
+ def update_project(self, update_function, updated_properties=None, on_completed=None):
122
+ """function::update_project(self, update_function)
123
+ Calls the update_function to perform the desired updates
124
+ """
125
+ self.dirty = True
126
+ result = update_function(None)
127
+ if updated_properties:
128
+ for prop in updated_properties:
129
+ self._on_project_updated(prop)
130
+ else:
131
+ self._on_project_updated(None)
132
+ if on_completed:
133
+ QApplication.postEvent(self, UpdateCompleteEvent(on_completed, result))
134
+
135
+ def _on_project_updated(self, prop):
136
+ QApplication.postEvent(self, PropertyUpdatedEvent(prop))
137
+
138
+ def event(self, event):
139
+ if isinstance(event, PropertyUpdatedEvent):
140
+ self.projectUpdated.emit(event.prop)
141
+ return True
142
+ if isinstance(event, UpdateCompleteEvent):
143
+ event.exec()
144
+ return True
145
+ if isinstance(event, UpdateEvent):
146
+ with self.update_lock:
147
+ event.exec()
148
+ return True
149
+ return super().event(event)
@@ -0,0 +1,281 @@
1
+ # pyqttoolkit
2
+ # Copyright (C) 2018-2019, Simmovation Ltd.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software Foundation,
16
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+ """:mod:`task_runner`
18
+ Defines the task runner
19
+ """
20
+ import logging
21
+ import inspect
22
+
23
+ from PyQt5.QtCore import QObject, pyqtSignal, QEvent
24
+ from PyQt5.QtWidgets import QApplication
25
+
26
+ from concurrent.futures import ThreadPoolExecutor
27
+
28
+ from ..properties import AutoProperty
29
+ from ..exceptions import TaskCancelled
30
+
31
+ LOGGER = logging.getLogger(__name__)
32
+
33
+ class BusyArgs(QObject):
34
+ def __init__(self, busy, indeterminate=True, cancellable=False, description=None):
35
+ QObject.__init__(self, None)
36
+ self._busy = busy
37
+ self._indeterminate = indeterminate
38
+ self._cancellable = cancellable
39
+ self._description = description
40
+ self._progress = 0
41
+
42
+ cancelled = pyqtSignal()
43
+ cancelComplete = pyqtSignal()
44
+ progressChanged = pyqtSignal(float, str)
45
+
46
+ @property
47
+ def description(self):
48
+ return self._description
49
+
50
+ @property
51
+ def progress(self):
52
+ return self._progress
53
+
54
+ def updateProgress(self, progress, description):
55
+ self._progress = max(99, float(progress))
56
+ self._description = description
57
+ self.progressChanged.emit(progress, description)
58
+
59
+ @property
60
+ def busy(self):
61
+ return self._busy
62
+
63
+ @property
64
+ def indeterminate(self):
65
+ return self._indeterminate
66
+
67
+ @property
68
+ def cancellable(self):
69
+ return self._cancellable
70
+
71
+ def cancel(self):
72
+ if self._cancellable:
73
+ self.cancelled.emit()
74
+
75
+
76
+ class Worker:
77
+ def __init__(self, task_runner, f, args, busy_args, on_completed, on_cancelled, on_error, error_description):
78
+ self._task_runner = task_runner
79
+ self._f = f
80
+ self._args = args
81
+ self._busy_args = busy_args
82
+ self._on_completed = on_completed
83
+ self._on_cancelled = on_cancelled
84
+ self._on_error = on_error
85
+ self._error_description = error_description
86
+
87
+ def run(self):
88
+ if self._busy_args:
89
+ QApplication.postEvent(self._task_runner, BusyEvent(self._busy_args))
90
+ try:
91
+ result = self._f(*self._args.args, **self._args.kwargs)
92
+ except TaskCancelled:
93
+ QApplication.postEvent(self._task_runner, CancelledEvent(self._on_cancelled))
94
+ #pylint: disable=broad-except
95
+ except Exception as e:
96
+ QApplication.postEvent(self._task_runner, ErrorEvent(e, self._on_error, self._error_description))
97
+ #pylint: enable=broad-except
98
+ else:
99
+ QApplication.postEvent(self._task_runner, ResultEvent(result, self._on_completed))
100
+
101
+ class ProgressUpdatedEvent(QEvent):
102
+ def __init__(self, progress, message):
103
+ super().__init__(QEvent.User)
104
+ self._progress = progress
105
+ self._message = message
106
+
107
+ @property
108
+ def progress(self):
109
+ return self._progress
110
+
111
+ @property
112
+ def message(self):
113
+ return self._message
114
+
115
+ class CancelledEvent(QEvent):
116
+ def __init__(self, on_cancelled):
117
+ super().__init__(QEvent.User)
118
+ self._on_cancelled = on_cancelled
119
+
120
+ @property
121
+ def on_cancelled(self):
122
+ return self._on_cancelled
123
+
124
+ class ResultEvent(QEvent):
125
+ def __init__(self, result, on_completed=None):
126
+ super().__init__(QEvent.User)
127
+ self._result = result
128
+ self._on_completed = on_completed
129
+
130
+ @property
131
+ def result(self):
132
+ return self._result
133
+
134
+ @property
135
+ def on_completed(self):
136
+ return self._on_completed
137
+
138
+ class ErrorEvent(QEvent):
139
+ def __init__(self, exception, on_error, error_description):
140
+ super().__init__(QEvent.User)
141
+ self._exception = exception
142
+ self._on_error = on_error
143
+ self._error_description = error_description
144
+
145
+ @property
146
+ def exception(self):
147
+ return self._exception
148
+
149
+ @property
150
+ def on_error(self):
151
+ return self._on_error
152
+
153
+ @property
154
+ def error_description(self):
155
+ return self._error_description
156
+
157
+ class BusyEvent(QEvent):
158
+ def __init__(self, busy_args):
159
+ super().__init__(QEvent.User)
160
+ self._busy_args = busy_args
161
+
162
+ @property
163
+ def args(self):
164
+ return self._busy_args
165
+
166
+ class TaskArgs:
167
+ def __init__(self, args, kwargs):
168
+ self.args = args
169
+ self.kwargs = kwargs
170
+
171
+ class TaskRunner(QObject):
172
+ """class::TaskRunner
173
+ Runs tasks on a background thread
174
+ """
175
+ def __init__(self, parent):
176
+ QObject.__init__(self, parent)
177
+ self._is_cancelled = False
178
+ self._executor = ThreadPoolExecutor(max_workers=1, thread_name_prefix='TaskRunner_Thread')
179
+
180
+ def shutdown(self, wait=True):
181
+ # Tests and short-lived apps need an explicit way to join worker
182
+ # threads before QApplication teardown.
183
+ self._executor.shutdown(wait=wait)
184
+
185
+ def run_task(self, task_function, task_args=None, on_completed=None, on_cancelled=None, on_error=None, description=None, error_description=None, show_progress=True, cancellable=False, force_indeterminate_start=False, **kwargs):
186
+ """function::runTask(self, task_function, task_args, on_completed, on_error)
187
+ :param task_function: The function to execute
188
+ :param task_args: The arguments to pass to the function
189
+ :param on_completed: The function to execute when the task completes
190
+ :param on_error: The function to execute when the task errors
191
+ """
192
+ LOGGER.info('Starting task "%s"...', description)
193
+ task_args = task_args or []
194
+
195
+ kwargs = {}
196
+
197
+ parameters = inspect.signature(task_function).parameters
198
+
199
+ if 'update_progress' in parameters:
200
+ kwargs['update_progress'] = self.update_progress
201
+ indeterminate = force_indeterminate_start
202
+ else:
203
+ indeterminate = True
204
+
205
+ busy_args = BusyArgs(True, indeterminate, cancellable, description) if show_progress else None
206
+
207
+ worker = Worker(
208
+ self, task_function, TaskArgs(task_args, kwargs),
209
+ busy_args=busy_args, on_completed=on_completed,
210
+ on_cancelled=on_cancelled, on_error=on_error,
211
+ error_description=error_description
212
+ )
213
+ self._executor.submit(worker.run)
214
+
215
+ def update_progress(self, percent, message):
216
+ QApplication.postEvent(self, ProgressUpdatedEvent(float(percent), message))
217
+
218
+ def event(self, event):
219
+ if isinstance(event, ProgressUpdatedEvent):
220
+ if self.busy is not None:
221
+ self.busy.updateProgress(float(event.progress), event.message)
222
+ return True
223
+ elif isinstance(event, BusyEvent):
224
+ self.busy = event.args
225
+ self.busy.cancelled.connect(self.cancel)
226
+ return True
227
+ elif isinstance(event, ResultEvent):
228
+ LOGGER.info('Task complete')
229
+ self.reset()
230
+ if event.on_completed is not None:
231
+ event.on_completed(event.result)
232
+ self.taskCompleted.emit()
233
+ return True
234
+ elif isinstance(event, CancelledEvent):
235
+ LOGGER.info('Task cancelled')
236
+ self.reset()
237
+ self.busy.cancelComplete.emit()
238
+ self.taskCancelled.emit()
239
+ if event.on_cancelled is not None:
240
+ event.on_cancelled()
241
+ return True
242
+ elif isinstance(event, ErrorEvent):
243
+ LOGGER.info('Task error')
244
+ self.reset()
245
+ LOGGER.info('Error running task: %s', event.exception)
246
+ if event.error_description is not None:
247
+ self.error.emit(event.error_description)
248
+ self.taskErrored.emit()
249
+ elif event.on_error is not None:
250
+ event.on_error(event.exception)
251
+ self.taskErrored.emit()
252
+ else:
253
+ raise event.exception
254
+ return True
255
+ return super().event(event)
256
+
257
+ def cancel(self):
258
+ if not self._is_cancelled:
259
+ if self.busy:
260
+ self.busy.updateProgress(self.busy.progress, self.tr('Cancelling...'))
261
+ self._is_cancelled = True
262
+
263
+ def isCancelled(self):
264
+ return self._is_cancelled
265
+
266
+ def raiseForCancelled(self):
267
+ if self._is_cancelled:
268
+ raise TaskCancelled()
269
+
270
+ def reset(self):
271
+ self.busy = BusyArgs(False, description=None)
272
+ self._is_cancelled = False
273
+
274
+ busyChanged = pyqtSignal(BusyArgs)
275
+ error = pyqtSignal(str)
276
+ cancelComplete = pyqtSignal()
277
+ taskCompleted = pyqtSignal()
278
+ taskCancelled = pyqtSignal()
279
+ taskErrored = pyqtSignal()
280
+
281
+ busy = AutoProperty(BusyArgs)
@@ -0,0 +1,46 @@
1
+ # pyqttoolkit
2
+ # Copyright (C) 2018-2019, Simmovation Ltd.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software Foundation,
16
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+ class ThemeManager:
18
+ default_theme = {
19
+ 'button_foreground': (0, 0, 0),
20
+ 'button_background_hover': (255, 255, 255),
21
+ 'highlight': (255, 96, 154),
22
+ 'highlight_hover': (255, 163, 196),
23
+ 'highlight_pressed': (255, 147, 186),
24
+ 'highlight': (255, 96, 154),
25
+ 'module_background': (200, 200, 200),
26
+ 'module_text': (0, 0, 0)
27
+ }
28
+
29
+ def __init__(self, application_configuration):
30
+ self._config = application_configuration
31
+
32
+ def get_color(self, key):
33
+ selected_theme = self._get_selected_theme()
34
+ color = self._config.get_value(f'application.themes.{selected_theme}.{key}') if selected_theme else None
35
+ return tuple(color) if color else self.default_theme.get(key)
36
+
37
+ def _get_selected_theme(self):
38
+ return self._config.get_value(f'application.themes.selected_theme') or None
39
+
40
+ @staticmethod
41
+ def get(widget):
42
+ while widget is not None and not hasattr(widget, 'themeManager'):
43
+ widget = widget.parent()
44
+ if widget is not None and hasattr(widget, 'themeManager'):
45
+ return widget.themeManager
46
+ return None
@@ -0,0 +1,46 @@
1
+ # pyqttoolkit
2
+ # Copyright (C) 2018-2019, Simmovation Ltd.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software Foundation,
16
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ from PyQt5.QtWidgets import QWidget
19
+
20
+ from pyqttoolkit.views import ToolWindow
21
+ from pyqttoolkit.viewmanagers import ToolViewManager
22
+
23
+ class ToolWindowService:
24
+ def __init__(self, dependency_contianer):
25
+ self._dependency_container = dependency_contianer
26
+ self._active_tools = []
27
+
28
+ def open(self, parent, model, name, *args, extras=None):
29
+ extras = {'parent': None, **(extras or {})}
30
+ view = self._dependency_container.resolve_for(type(model), QWidget, extras, *args)
31
+ if hasattr(model, 'showButtons'):
32
+ show_buttons = model.showButtons
33
+ else:
34
+ show_buttons = True
35
+
36
+ tool_window = ToolWindow(parent, view, name, show_buttons)
37
+ view_manager = self._dependency_container.resolve_for(type(model), ToolViewManager, {'view': view, 'model': model})
38
+ tool_window.accepted.connect(self._tool_window_accepted(tool_window, view_manager))
39
+ self._active_tools.append((tool_window, view_manager))
40
+ tool_window.show()
41
+
42
+ def _tool_window_accepted(self, tool_window, view_manager):
43
+ def _handler():
44
+ view_manager.save()
45
+ self._active_tools.remove((tool_window, view_manager))
46
+ return _handler
@@ -0,0 +1,17 @@
1
+ # pyqttoolkit
2
+ # Copyright (C) 2018-2019, Simmovation Ltd.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software Foundation,
16
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+ from .tool import ToolViewManager
@@ -0,0 +1,23 @@
1
+ # pyqttoolkit
2
+ # Copyright (C) 2018-2019, Simmovation Ltd.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software Foundation,
16
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+ class ToolViewManager:
18
+ def __init__(self, view, model):
19
+ self._view = view
20
+ self._model = model
21
+
22
+ def save(self):
23
+ raise NotImplementedError()
@@ -0,0 +1,50 @@
1
+ # pyqttoolkit
2
+ # Copyright (C) 2018-2019, Simmovation Ltd.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software Foundation,
16
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+ """:mod:`components`
18
+ Components module
19
+ """
20
+ from .modulewindow import ModuleWindow
21
+ from .editable_combo_box import EditableComboBox
22
+ from .shrunk_push_button import ShrunkPushButton, VShrunkPushButton
23
+ from .tool_window import ToolWindow
24
+ from .combo_box import ComboBox, BindableComboBox, typed_bindable_combo_box
25
+ from .steppable_combo_box import SteppableComboBox
26
+ from .linkable import LinkableWidget
27
+ from .datetime import DateTimeEdit
28
+ from .line_edit import LineEdit, BindableLineEdit
29
+ from .table import TableView
30
+ from .property_tree import PropertyTreeView
31
+ from .json_edit import JsonEdit
32
+ from .file_selector import FileSelector
33
+ from .code import CodeEdit, PythonCodeEdit
34
+ from .text_edit import TextEdit
35
+ from .metadata_selector import MetadataSelector, MetadataSelectorDropDown
36
+ from .default_text_line_edit import DefaultTextLineEdit
37
+ from .icon_button import IconButton, BindableIconButton
38
+ from .main_window import MainWindow
39
+ from .icon import Icon
40
+ from .dtype_edit import FloatEdit, IntEdit, InfFloatLineEdit, AutoFloatLineEdit
41
+ from .check_box import BindableCheckBox
42
+ from .bulk_value_selector import BulkValueSelectorWidget
43
+ from .datetime_range_selector import DatetimeRangeSelectorWidget
44
+ from .count_selector import CountSelectorWidget
45
+ from .list_view import ListView
46
+ from .styleable import make_styleable
47
+ from .popout import PopoutWidget
48
+ from .popup import Popup
49
+ from .delegates import ComboBoxItemDelegate, DateTimeItemDelegate, BulkValueSelectorItemDelegate
50
+ from .labelled import make_labelled