py10x-universe 0.1.3__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 (214) hide show
  1. core_10x/__init__.py +42 -0
  2. core_10x/backbone/__init__.py +0 -0
  3. core_10x/backbone/backbone_store.py +59 -0
  4. core_10x/backbone/backbone_traitable.py +30 -0
  5. core_10x/backbone/backbone_user.py +66 -0
  6. core_10x/backbone/bound_data_domain.py +49 -0
  7. core_10x/backbone/namespace.py +101 -0
  8. core_10x/backbone/vault.py +38 -0
  9. core_10x/code_samples/__init__.py +0 -0
  10. core_10x/code_samples/_package_manifest.py +3 -0
  11. core_10x/code_samples/directories.py +181 -0
  12. core_10x/code_samples/person.py +76 -0
  13. core_10x/concrete_traits.py +356 -0
  14. core_10x/conftest.py +12 -0
  15. core_10x/curve.py +321 -0
  16. core_10x/data_domain.py +48 -0
  17. core_10x/data_domain_binder.py +45 -0
  18. core_10x/directory.py +250 -0
  19. core_10x/entity.py +8 -0
  20. core_10x/entity_filter.py +5 -0
  21. core_10x/environment_variables.py +147 -0
  22. core_10x/exec_control.py +84 -0
  23. core_10x/experimental/__init__.py +0 -0
  24. core_10x/experimental/data_protocol_ex.py +34 -0
  25. core_10x/global_cache.py +121 -0
  26. core_10x/manual_tests/__init__.py +0 -0
  27. core_10x/manual_tests/calendar_test.py +35 -0
  28. core_10x/manual_tests/ctor_update_bug.py +58 -0
  29. core_10x/manual_tests/debug_graph_on.py +17 -0
  30. core_10x/manual_tests/debug_graphoff_inside_graph_on.py +28 -0
  31. core_10x/manual_tests/enum_bits_test.py +17 -0
  32. core_10x/manual_tests/env_vars_trivial_test.py +12 -0
  33. core_10x/manual_tests/existing_traitable.py +33 -0
  34. core_10x/manual_tests/k10x_test1.py +13 -0
  35. core_10x/manual_tests/named_constant_test.py +121 -0
  36. core_10x/manual_tests/nucleus_trivial_test.py +42 -0
  37. core_10x/manual_tests/polars_test.py +14 -0
  38. core_10x/manual_tests/py_class_test.py +4 -0
  39. core_10x/manual_tests/rc_test.py +42 -0
  40. core_10x/manual_tests/rdate_test.py +12 -0
  41. core_10x/manual_tests/reference_serialization_bug.py +19 -0
  42. core_10x/manual_tests/resource_trivial_test.py +10 -0
  43. core_10x/manual_tests/store_uri_test.py +6 -0
  44. core_10x/manual_tests/trait_definition_test.py +19 -0
  45. core_10x/manual_tests/trait_filter_test.py +15 -0
  46. core_10x/manual_tests/trait_flag_modification_test.py +42 -0
  47. core_10x/manual_tests/trait_modification_bug.py +26 -0
  48. core_10x/manual_tests/traitable_as_of_test.py +82 -0
  49. core_10x/manual_tests/traitable_heir_test.py +39 -0
  50. core_10x/manual_tests/traitable_history_test.py +41 -0
  51. core_10x/manual_tests/traitable_serialization_test.py +54 -0
  52. core_10x/manual_tests/traitable_trivial_test.py +71 -0
  53. core_10x/manual_tests/trivial_graph_test.py +16 -0
  54. core_10x/manual_tests/ts_class_association_test.py +64 -0
  55. core_10x/manual_tests/ts_trivial_test.py +35 -0
  56. core_10x/named_constant.py +425 -0
  57. core_10x/nucleus.py +81 -0
  58. core_10x/package_manifest.py +85 -0
  59. core_10x/package_refactoring.py +153 -0
  60. core_10x/py_class.py +431 -0
  61. core_10x/rc.py +155 -0
  62. core_10x/rdate.py +339 -0
  63. core_10x/resource.py +189 -0
  64. core_10x/roman_number.py +67 -0
  65. core_10x/testlib/__init__.py +0 -0
  66. core_10x/testlib/test_store.py +240 -0
  67. core_10x/testlib/traitable_history_tests.py +787 -0
  68. core_10x/testlib/ts_tests.py +280 -0
  69. core_10x/trait.py +377 -0
  70. core_10x/trait_definition.py +176 -0
  71. core_10x/trait_filter.py +205 -0
  72. core_10x/trait_method_error.py +36 -0
  73. core_10x/traitable.py +1082 -0
  74. core_10x/traitable_cli.py +153 -0
  75. core_10x/traitable_heir.py +33 -0
  76. core_10x/traitable_id.py +31 -0
  77. core_10x/ts_store.py +172 -0
  78. core_10x/ts_store_type.py +26 -0
  79. core_10x/ts_union.py +147 -0
  80. core_10x/ui_hint.py +153 -0
  81. core_10x/unit_tests/test_concrete_traits.py +156 -0
  82. core_10x/unit_tests/test_converters.py +51 -0
  83. core_10x/unit_tests/test_curve.py +157 -0
  84. core_10x/unit_tests/test_directory.py +54 -0
  85. core_10x/unit_tests/test_documentation.py +172 -0
  86. core_10x/unit_tests/test_environment_variables.py +15 -0
  87. core_10x/unit_tests/test_filters.py +239 -0
  88. core_10x/unit_tests/test_graph.py +348 -0
  89. core_10x/unit_tests/test_named_constant.py +98 -0
  90. core_10x/unit_tests/test_rc.py +11 -0
  91. core_10x/unit_tests/test_rdate.py +484 -0
  92. core_10x/unit_tests/test_trait_method_error.py +80 -0
  93. core_10x/unit_tests/test_trait_modification.py +19 -0
  94. core_10x/unit_tests/test_traitable.py +959 -0
  95. core_10x/unit_tests/test_traitable_history.py +1 -0
  96. core_10x/unit_tests/test_ts_store.py +1 -0
  97. core_10x/unit_tests/test_ts_union.py +369 -0
  98. core_10x/unit_tests/test_ui_nodes.py +81 -0
  99. core_10x/unit_tests/test_xxcalendar.py +471 -0
  100. core_10x/vault/__init__.py +0 -0
  101. core_10x/vault/sec_keys.py +133 -0
  102. core_10x/vault/security_keys_old.py +168 -0
  103. core_10x/vault/vault.py +56 -0
  104. core_10x/vault/vault_traitable.py +56 -0
  105. core_10x/vault/vault_user.py +70 -0
  106. core_10x/xdate_time.py +136 -0
  107. core_10x/xnone.py +71 -0
  108. core_10x/xxcalendar.py +228 -0
  109. infra_10x/__init__.py +0 -0
  110. infra_10x/manual_tests/__init__.py +0 -0
  111. infra_10x/manual_tests/test_misc.py +16 -0
  112. infra_10x/manual_tests/test_prepare_filter_and_pipeline.py +25 -0
  113. infra_10x/mongodb_admin.py +111 -0
  114. infra_10x/mongodb_store.py +346 -0
  115. infra_10x/mongodb_utils.py +129 -0
  116. infra_10x/unit_tests/conftest.py +13 -0
  117. infra_10x/unit_tests/test_mongo_db.py +36 -0
  118. infra_10x/unit_tests/test_mongo_history.py +1 -0
  119. py10x_universe-0.1.3.dist-info/METADATA +406 -0
  120. py10x_universe-0.1.3.dist-info/RECORD +214 -0
  121. py10x_universe-0.1.3.dist-info/WHEEL +4 -0
  122. py10x_universe-0.1.3.dist-info/licenses/LICENSE +21 -0
  123. ui_10x/__init__.py +0 -0
  124. ui_10x/apps/__init__.py +0 -0
  125. ui_10x/apps/collection_editor_app.py +100 -0
  126. ui_10x/choice.py +212 -0
  127. ui_10x/collection_editor.py +135 -0
  128. ui_10x/concrete_trait_widgets.py +220 -0
  129. ui_10x/conftest.py +8 -0
  130. ui_10x/entity_stocker.py +173 -0
  131. ui_10x/examples/__init__.py +0 -0
  132. ui_10x/examples/_guess_word_data.py +14076 -0
  133. ui_10x/examples/collection_editor.py +17 -0
  134. ui_10x/examples/date_selector.py +14 -0
  135. ui_10x/examples/entity_stocker.py +18 -0
  136. ui_10x/examples/guess_word.py +392 -0
  137. ui_10x/examples/message_box.py +20 -0
  138. ui_10x/examples/multi_choice.py +17 -0
  139. ui_10x/examples/py_data_browser.py +66 -0
  140. ui_10x/examples/radiobox.py +29 -0
  141. ui_10x/examples/single_choice.py +31 -0
  142. ui_10x/examples/style_sheet.py +47 -0
  143. ui_10x/examples/trivial_entity_editor.py +18 -0
  144. ui_10x/platform.py +20 -0
  145. ui_10x/platform_interface.py +517 -0
  146. ui_10x/py_data_browser.py +249 -0
  147. ui_10x/qt6/__init__.py +0 -0
  148. ui_10x/qt6/conftest.py +8 -0
  149. ui_10x/qt6/manual_tests/__init__.py +0 -0
  150. ui_10x/qt6/manual_tests/basic_test.py +35 -0
  151. ui_10x/qt6/platform_implementation.py +275 -0
  152. ui_10x/qt6/utils.py +665 -0
  153. ui_10x/rio/__init__.py +0 -0
  154. ui_10x/rio/apps/examples/examples/__init__.py +22 -0
  155. ui_10x/rio/apps/examples/examples/components/__init__.py +3 -0
  156. ui_10x/rio/apps/examples/examples/components/collection_editor.py +15 -0
  157. ui_10x/rio/apps/examples/examples/pages/collection_editor.py +21 -0
  158. ui_10x/rio/apps/examples/examples/pages/login_page.py +88 -0
  159. ui_10x/rio/apps/examples/examples/pages/style_sheet.py +21 -0
  160. ui_10x/rio/apps/examples/rio.toml +14 -0
  161. ui_10x/rio/component_builder.py +497 -0
  162. ui_10x/rio/components/__init__.py +9 -0
  163. ui_10x/rio/components/group_box.py +31 -0
  164. ui_10x/rio/components/labeled_checkbox.py +18 -0
  165. ui_10x/rio/components/line_edit.py +37 -0
  166. ui_10x/rio/components/radio_button.py +32 -0
  167. ui_10x/rio/components/separator.py +24 -0
  168. ui_10x/rio/components/splitter.py +121 -0
  169. ui_10x/rio/components/tree_view.py +75 -0
  170. ui_10x/rio/conftest.py +35 -0
  171. ui_10x/rio/internals/__init__.py +0 -0
  172. ui_10x/rio/internals/app.py +192 -0
  173. ui_10x/rio/manual_tests/__init__.py +0 -0
  174. ui_10x/rio/manual_tests/basic_test.py +24 -0
  175. ui_10x/rio/manual_tests/splitter.py +27 -0
  176. ui_10x/rio/platform_implementation.py +91 -0
  177. ui_10x/rio/style_sheet.py +53 -0
  178. ui_10x/rio/unit_tests/test_collection_editor.py +68 -0
  179. ui_10x/rio/unit_tests/test_internals.py +630 -0
  180. ui_10x/rio/unit_tests/test_style_sheet.py +37 -0
  181. ui_10x/rio/widgets/__init__.py +46 -0
  182. ui_10x/rio/widgets/application.py +109 -0
  183. ui_10x/rio/widgets/button.py +48 -0
  184. ui_10x/rio/widgets/button_group.py +60 -0
  185. ui_10x/rio/widgets/calendar.py +23 -0
  186. ui_10x/rio/widgets/checkbox.py +24 -0
  187. ui_10x/rio/widgets/dialog.py +137 -0
  188. ui_10x/rio/widgets/group_box.py +27 -0
  189. ui_10x/rio/widgets/layout.py +34 -0
  190. ui_10x/rio/widgets/line_edit.py +37 -0
  191. ui_10x/rio/widgets/list.py +105 -0
  192. ui_10x/rio/widgets/message_box.py +70 -0
  193. ui_10x/rio/widgets/scroll_area.py +31 -0
  194. ui_10x/rio/widgets/spacer.py +6 -0
  195. ui_10x/rio/widgets/splitter.py +45 -0
  196. ui_10x/rio/widgets/text_edit.py +28 -0
  197. ui_10x/rio/widgets/tree.py +89 -0
  198. ui_10x/rio/widgets/unit_tests/test_button.py +101 -0
  199. ui_10x/rio/widgets/unit_tests/test_button_group.py +33 -0
  200. ui_10x/rio/widgets/unit_tests/test_calendar.py +114 -0
  201. ui_10x/rio/widgets/unit_tests/test_checkbox.py +109 -0
  202. ui_10x/rio/widgets/unit_tests/test_group_box.py +158 -0
  203. ui_10x/rio/widgets/unit_tests/test_label.py +43 -0
  204. ui_10x/rio/widgets/unit_tests/test_line_edit.py +140 -0
  205. ui_10x/rio/widgets/unit_tests/test_list.py +146 -0
  206. ui_10x/table_header_view.py +305 -0
  207. ui_10x/table_view.py +174 -0
  208. ui_10x/trait_editor.py +189 -0
  209. ui_10x/trait_widget.py +131 -0
  210. ui_10x/traitable_editor.py +200 -0
  211. ui_10x/traitable_view.py +131 -0
  212. ui_10x/unit_tests/conftest.py +8 -0
  213. ui_10x/unit_tests/test_platform.py +9 -0
  214. ui_10x/utils.py +661 -0
@@ -0,0 +1,249 @@
1
+ from datetime import date, datetime
2
+
3
+ from core_10x.rc import RC, RC_TRUE
4
+ from core_10x.xnone import XNone
5
+
6
+ from ui_10x.utils import UxDialog, ux
7
+
8
+
9
+ class PyDataBrowser:
10
+ class Item(ux.TreeItem):
11
+ def __init__(self, parent_node, key, value):
12
+ super().__init__(parent_node)
13
+ self.key = key
14
+ self.value = value
15
+ self.new_value = value
16
+
17
+ def path(self) -> list:
18
+ res = []
19
+ node = self
20
+ while node:
21
+ res.insert(0, node.key)
22
+ node = node.parent()
23
+
24
+ return res
25
+
26
+ def accept_edit(self, results):
27
+ n = self.child_count()
28
+ if not n:
29
+ if self.value != self.new_value:
30
+ path = self.path()
31
+ x = results
32
+ for key in path[:-1]:
33
+ x = x[key]
34
+ x[path[-1]] = self.new_value
35
+ else:
36
+ for i in range(n):
37
+ child = self.child(i)
38
+ child.accept_edit(results)
39
+
40
+ def __init__(
41
+ self,
42
+ data,
43
+ on_select = None,
44
+ edit = False,
45
+ custom_editor = None,
46
+ max_label_len = 50,
47
+ max_value_len = 70
48
+ ):
49
+ """
50
+ Browse any python data.
51
+ :param data:
52
+ :param on_select: a callable on item selection. If given, will call on_select( the_browser, path_to_item: list, item_value )
53
+ :param edit: allow editing if True
54
+ :param custom_editor: if given, is used for editing - fn( the_browser, item: PyDataBrowser: Item )
55
+ :param max_label_len: max label width (if exceeds, gets truncated showing '...' and the end)
56
+ :param max_value_len: max value width (if exceeds, gets truncated showing '...' and the end)
57
+ Tooltip (full label/value, if possible) is shown as usual
58
+ """
59
+ self.data = data
60
+ self.edit = edit
61
+ self.custom_editor = custom_editor
62
+ self.select_cb = on_select
63
+ self.max_label_len = max_label_len
64
+ self.max_value_len = max_value_len
65
+
66
+ def fill(self, value, node: ux.TreeItem, label = True):
67
+ if label:
68
+ i = 0
69
+ n = self.max_label_len
70
+ tip = True
71
+ else:
72
+ i = 1
73
+ n = self.max_value_len
74
+ tip = isinstance(value, str)
75
+ text = str(value)
76
+ if len(text) > n:
77
+ show = text[: n] + '...'
78
+ else:
79
+ show = text
80
+ node.set_text(i, show)
81
+ if tip:
82
+ node.set_tool_tip(i, text)
83
+
84
+ s_bool_vmap = {
85
+ 'True': True,
86
+ 'False': False,
87
+ '1': True,
88
+ '0': False
89
+ }
90
+
91
+ s_use_as_is = {
92
+ type: None,
93
+ type(None): None,
94
+ type(XNone): None,
95
+ bool: lambda x: PyDataBrowser.s_bool_vmap.get(x, bool(x)),
96
+ str: lambda x: x,
97
+ int: lambda x: int(x),
98
+ float: lambda x: float(x),
99
+ datetime: lambda x: datetime.strptime(x, '%Y-%m-%d %H:%M:%S'),
100
+ date: lambda x: datetime.strptime(x, '%Y-%m-%d').date(),
101
+ }
102
+
103
+ s_dict_handler = lambda data: data.items()
104
+ s_list_handler = lambda data: enumerate(data)
105
+ s_type_handlers = {
106
+ tuple: s_list_handler,
107
+ list: s_list_handler,
108
+ dict: s_dict_handler,
109
+ }
110
+ def create_tree(self, key, item, parent_node):
111
+ node = self.Item(parent_node, key, item)
112
+ self.fill(key, node, label = True)
113
+ self.fill(item, node, label = False)
114
+
115
+ dtype = type(item)
116
+ if dtype in self.s_use_as_is:
117
+ pass
118
+ else:
119
+ handler = self.s_type_handlers.get(dtype)
120
+ if not handler:
121
+ try:
122
+ text = item.__repr__()
123
+ node.set_text(1, text)
124
+ except Exception:
125
+ node.set_text(1, '???')
126
+ return
127
+
128
+ try:
129
+ item = item.to_dict()
130
+ handler = self.__class__.s_dict_handler
131
+ except Exception:
132
+ return
133
+
134
+ for key, value in handler(item):
135
+ self.create_tree(key, value, node)
136
+
137
+ def widget(self) -> ux.TreeWidget:
138
+ self.tree = tree = ux.TreeWidget()
139
+ tree.set_column_count(2)
140
+ tree.set_header_labels(['Key', 'Value'])
141
+
142
+ data = self.data
143
+ dtype = type(data)
144
+ handler = self.s_type_handlers.get(dtype)
145
+ if not handler:
146
+ data = { str(dtype): data }
147
+ handler = self.s_dict_handler
148
+
149
+ for key, item in handler(data):
150
+ self.create_tree(key, item, tree)
151
+
152
+ if len(data) == 1:
153
+ tree.top_level_item(0).set_expanded(True)
154
+
155
+ tree.resize_column_to_contents(0)
156
+ tree.resize_column_to_contents(1)
157
+
158
+ tree.item_expanded_connect(lambda item: tree.resize_column_to_contents(0))
159
+ tree.item_pressed_connect(self.on_item_pressed)
160
+ tree.item_changed_connect(self.on_item_changed)
161
+
162
+ return tree
163
+
164
+ def on_item_pressed(self, item: Item, col: int):
165
+ if item:
166
+ if col == 0 or not self.edit:
167
+ if self.select_cb:
168
+ self.select_cb(self, item.path(), item.value)
169
+ return
170
+
171
+ if self.custom_editor:
172
+ self.custom_editor(self, item)
173
+ else:
174
+ if not item.child_count():
175
+ self.generic_editor(item)
176
+
177
+ def on_item_changed(self, item: Item, col: int):
178
+ if col != 1:
179
+ return
180
+
181
+ dtype = type(item.value)
182
+ from_str_handler = self.s_use_as_is.get(dtype)
183
+ if from_str_handler:
184
+ text = item.text(col)
185
+ try:
186
+ item.new_value = from_str_handler(text)
187
+ except Exception:
188
+ pass
189
+
190
+ def generic_editor(self, item: Item):
191
+ self.tree.open_persistent_editor(item, 1)
192
+ self.tree.edit_item(item, 1)
193
+
194
+ def accept_edit(self) -> RC:
195
+ for i in range(self.tree.top_level_item_count()):
196
+ item = self.tree.top_level_item(i)
197
+ item.accept_edit(self.data)
198
+ return RC_TRUE
199
+
200
+ @classmethod
201
+ def show(cls, data, on_select = None, title = '', w = 1000, h = 800):
202
+ if not title:
203
+ title = 'Python Data Browser'
204
+
205
+ br = cls(data, on_select = on_select)
206
+ d = UxDialog(
207
+ br.widget(),
208
+ title = title,
209
+ ok = '',
210
+ cancel = 'Close',
211
+ min_width = w,
212
+ min_height = h
213
+ )
214
+ d.exec()
215
+
216
+ @classmethod
217
+ def edit(cls, data, on_select = None, custom_editor = None, title = '', w = 1000, h = 800) -> bool:
218
+ if not title:
219
+ title = 'Python Data Editor'
220
+
221
+ br = cls(data, on_select = on_select, edit = True, custom_editor = custom_editor)
222
+ d = UxDialog(
223
+ br.widget(),
224
+ accept_callback = br.accept_edit,
225
+ title = title,
226
+ min_width = w,
227
+ min_height = h
228
+ )
229
+ rc = d.exec()
230
+ return bool(rc)
231
+
232
+ @classmethod
233
+ def path_to_str(cls, path: list, delims = ('/', '/')) -> str:
234
+ res = []
235
+ for i, key in enumerate(path):
236
+ delim = delims[ isinstance(key, int) ]
237
+ n = len(delim)
238
+ if n == 0:
239
+ continue
240
+
241
+ if n == 1:
242
+ key = f'{delim}{key}' if i > 0 else str(key)
243
+ else:
244
+ key = f'{delim[0]}{key}{delim[1]}'
245
+
246
+ res.append(key)
247
+
248
+ return ''.join(res)
249
+
ui_10x/qt6/__init__.py ADDED
File without changes
ui_10x/qt6/conftest.py ADDED
@@ -0,0 +1,8 @@
1
+ import pytest
2
+
3
+
4
+ @pytest.fixture(autouse=True)
5
+ def setup_ui_platform(monkeypatch):
6
+ monkeypatch.setenv("UI_PLATFORM", "Qt6")
7
+ yield
8
+ monkeypatch.undo()
File without changes
@@ -0,0 +1,35 @@
1
+ # from PyQt6.QtWidgets import QWidget, QLayout, QBoxLayout, QVBoxLayout, QHBoxLayout, QFormLayout, QApplication
2
+ # from PyQt6.QtWidgets import QLabel, QCalendarWidget, QMessageBox, QGroupBox, QButtonGroup, QRadioButton
3
+ # from PyQt6.QtWidgets import QListWidgetItem, QListWidget, QLineEdit, QPlainTextEdit, QTreeWidgetItem, QTreeWidget, QCheckBox, QComboBox
4
+ # from PyQt6.QtWidgets import QFrame, QSplitter, QDialog, QScrollArea, QPushButton, QStyle, QSizePolicy
5
+ # from PyQt6.QtCore import Qt, QObject, QThread, pyqtSignal, QBuffer, QIODevice, QPoint #, QByteArray
6
+ # from PyQt6.QtGui import QColor, QGuiApplication, QPixmap, QMouseEvent
7
+ #
8
+ # import platform
9
+ #
10
+ #
11
+ # Object = QObject
12
+ #
13
+ # signal_decl = pyqtSignal
14
+ #
15
+ # class MouseEvent(QMouseEvent):
16
+ # def is_left_button(self) -> bool: return self.button() == Qt.MouseButton.LeftButton
17
+ # def is_right_button(self) -> bool: return self.button() == Qt.MouseButton.RightButton
18
+
19
+ from ui_10x.platform import ux
20
+
21
+ if __name__ == '__main__':
22
+ app = ux.init()
23
+
24
+ w = ux.Label('a')
25
+ w = ux.PushButton('b')
26
+ w = ux.LineEdit()
27
+ w = ux.RadioButton()
28
+ w = ux.CheckBox('Check')
29
+ w = ux.ListWidget()
30
+ w = ux.TreeWidget()
31
+
32
+
33
+
34
+
35
+
@@ -0,0 +1,275 @@
1
+ from __future__ import annotations
2
+ from typing import Callable, Any
3
+
4
+ from PyQt6.QtWidgets import QWidget, QLayout, QBoxLayout, QVBoxLayout, QHBoxLayout, QFormLayout, QApplication
5
+ from PyQt6.QtWidgets import QLabel, QCalendarWidget, QMessageBox, QGroupBox, QButtonGroup, QRadioButton
6
+ from PyQt6.QtWidgets import QListWidgetItem, QListWidget, QLineEdit, QPlainTextEdit, QTreeWidgetItem, QTreeWidget, QCheckBox, QComboBox
7
+ from PyQt6.QtWidgets import QFrame, QSplitter, QDialog, QScrollArea, QPushButton, QStyle, QSizePolicy, QStyleOptionHeader
8
+ from PyQt6.QtCore import Qt, QObject, QThread, pyqtSignal, QBuffer, QIODevice, QPoint #, QByteArray
9
+ from PyQt6.QtGui import QColor, QGuiApplication, QPixmap, QMouseEvent, QFontMetrics, QPalette, QPainter
10
+
11
+ import platform
12
+
13
+ from core_10x.global_cache import cache
14
+
15
+ def missing_attr(self, item):
16
+ t = item.title()
17
+ item = t[0].lower() + t[1:].replace('_', '')
18
+ return QObject.__getattribute__(self, item)
19
+
20
+ Object = QObject
21
+
22
+ QueuedConnection = Qt.ConnectionType.QueuedConnection
23
+ AutoConnection = Qt.ConnectionType.AutoConnection
24
+ DirectConnection = Qt.ConnectionType.DirectConnection
25
+ UniqueConnection = Qt.ConnectionType.UniqueConnection
26
+ BlockingQueuedConnection = Qt.ConnectionType.BlockingQueuedConnection
27
+
28
+ signal_decl = pyqtSignal
29
+
30
+ MouseEvent = QMouseEvent
31
+ MouseEvent.is_left_button = lambda self: self.button() == Qt.MouseButton.LeftButton
32
+ MouseEvent.is_right_button = lambda self: self.button() == Qt.MouseButton.RightButton
33
+
34
+ Point = QPoint
35
+
36
+ SizePolicy = QSizePolicy
37
+ SizePolicy.MINIMUM_EXPANDING = QSizePolicy.Policy.MinimumExpanding
38
+ SizePolicy.PREFERRED = QSizePolicy.Policy.Preferred
39
+
40
+ Color = QColor
41
+
42
+ FontMetrics = QFontMetrics
43
+ FontMetrics.__getattr__ = missing_attr
44
+
45
+ Widget = QWidget
46
+ Widget.__getattr__ = missing_attr
47
+
48
+ Horizontal = Qt.Orientation.Horizontal
49
+ Vertical = Qt.Orientation.Vertical
50
+
51
+ Layout = QLayout
52
+
53
+ BoxLayout = QBoxLayout
54
+ BoxLayout.__getattr__ = missing_attr
55
+
56
+ HBoxLayout = QHBoxLayout
57
+ VBoxLayout = QVBoxLayout
58
+
59
+ FormLayout = QFormLayout
60
+ FormLayout.__getattr__ = missing_attr
61
+
62
+ Label = QLabel
63
+ Label.set_text = QLabel.setText
64
+
65
+ Splitter = QSplitter
66
+
67
+ Style = QStyle
68
+ Style.State_Active = QStyle.StateFlag.State_Active
69
+
70
+ Style.__getattr__ = missing_attr
71
+
72
+ PushButton = QPushButton
73
+ PushButton.clicked_connect = lambda self, bound_method: self.clicked.connect(bound_method)
74
+
75
+ LineEdit = QLineEdit
76
+ LineEdit.text_edited_connect = lambda self, bound_method: self.textEdited.connect(bound_method)
77
+ LineEdit.editing_finished_connect = lambda self, bound_method: self.editingFinished.connect(bound_method)
78
+ LineEdit.set_password_mode = lambda self: self.setEchoMode(QLineEdit.EchoMode.Password)
79
+
80
+ TextEdit = QPlainTextEdit
81
+
82
+ CheckBox = QCheckBox
83
+ CheckBox.state_changed_connect = lambda self, bound_method: self.stateChanged.connect(bound_method)
84
+
85
+ ComboBox = QComboBox
86
+
87
+ GroupBox = QGroupBox
88
+
89
+ RadioButton = QRadioButton
90
+
91
+ ButtonGroup = QButtonGroup
92
+ ButtonGroup.__getattr__ = missing_attr
93
+
94
+ ListItem = QListWidgetItem
95
+ ListItem.__getattr__ = missing_attr
96
+
97
+ MatchExactly = Qt.MatchFlag.MatchExactly
98
+
99
+ ListWidget = QListWidget
100
+ ListWidget.clicked_connect = lambda self, bound_method: self.clicked.connect(bound_method)
101
+
102
+ TreeItem = QTreeWidgetItem
103
+ TreeItem.__getattr__ = missing_attr
104
+
105
+ TreeWidget = QTreeWidget
106
+ TreeWidget.item_clicked_connect = lambda self, bound_method: self.itemClicked.connect(bound_method)
107
+ TreeWidget.item_expanded_connect = lambda self, bound_method: self.itemExpanded.connect(bound_method)
108
+ TreeWidget.item_pressed_connect = lambda self, bound_method: self.itemPressed.connect(bound_method)
109
+ TreeWidget.item_changed_connect = lambda self, bound_method: self.itemChanged.connect(bound_method)
110
+
111
+ CalendarWidget = QCalendarWidget
112
+ CalendarWidget.selected_date = lambda self: self.selectedDate().toPyDate()
113
+
114
+ class Dialog(QDialog):
115
+ s_open_dialogs = set()
116
+ def __init__(self,parent=None,*args,**kwargs):
117
+ super().__init__(parent or init().activeModalWidget(),*args,**kwargs)
118
+
119
+ def _on_finished(self):
120
+ open_dialogs = self.s_open_dialogs
121
+ in_open_dialogs = self in open_dialogs
122
+ print(f'finishing {self}: {in_open_dialogs}')
123
+
124
+ if in_open_dialogs:
125
+ self.s_open_dialogs.remove(self)
126
+
127
+ def show(self):
128
+ print(f'showing {self}')
129
+ self.s_open_dialogs.add(self)
130
+ self.finished.connect(self._on_finished)
131
+ super().show()
132
+ self.raise_()
133
+ self.activateWindow()
134
+ self.s_open_dialogs.add(self)
135
+
136
+
137
+ class MessageBox(QMessageBox):
138
+ s_boxes_by_parent = {}
139
+ def __init__(self, on_close: Callable[[Any],None] = None, parent: Widget = None):
140
+ super().__init__(parent)
141
+ self._on_close = on_close
142
+ self.finished.connect(self._handle_finished)
143
+
144
+ # Set the default values for the message box
145
+ self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowCloseButtonHint|Qt.WindowType.WindowStaysOnTopHint)
146
+ self.setStandardButtons(QMessageBox.StandardButton.Ok)
147
+ self.setDefaultButton(QMessageBox.StandardButton.Ok)
148
+ self.setEscapeButton(QMessageBox.StandardButton.Ok)
149
+
150
+ self.setModal(True)
151
+ self.s_boxes_by_parent[self.parent()] = self
152
+
153
+ def _handle_finished(self, result):
154
+ if self._on_close:
155
+ self._on_close(result)
156
+ self.s_boxes_by_parent.pop(self.parent())
157
+ self.deleteLater()
158
+
159
+ @classmethod
160
+ def _create_message_box(cls, parent: Widget, title, message, on_close: Callable[[Any],None], icon) -> MessageBox:
161
+ msg_box = cls(on_close,parent)
162
+ msg_box.setWindowTitle(title)
163
+ msg_box.setText(message)
164
+ msg_box.setIcon(icon)
165
+ return msg_box
166
+
167
+ @classmethod
168
+ def question(cls, parent: Widget, title: str, message: str, on_close: Callable[[Any],None]) -> MessageBox.StandardButton:
169
+ msg_box = cls._create_message_box(
170
+ parent=parent,
171
+ title=title,
172
+ message=message,
173
+ on_close=on_close,
174
+ icon=QMessageBox.Icon.Question,
175
+ )
176
+
177
+ msg_box.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
178
+ msg_box.setDefaultButton(QMessageBox.StandardButton.No)
179
+ msg_box.setEscapeButton(QMessageBox.StandardButton.No)
180
+
181
+ if on_close:
182
+ msg_box.show()
183
+ else:
184
+ return msg_box.exec()
185
+
186
+ @classmethod
187
+ def warning(cls, parent: Widget, title: str, message: str, on_close: Callable[[Any],None]) -> MessageBox.StandardButton:
188
+ msg_box = cls._create_message_box(
189
+ parent=parent,
190
+ title=title,
191
+ message=message,
192
+ on_close=on_close,
193
+ icon=QMessageBox.Icon.Warning,
194
+ )
195
+
196
+ if on_close:
197
+ msg_box.show()
198
+ else:
199
+ return msg_box.exec()
200
+
201
+ @classmethod
202
+ def information(cls, parent: Widget, title: str, message: str, on_close: Callable[[Any],None]) -> MessageBox.StandardButton:
203
+ msg_box = cls._create_message_box(
204
+ parent=parent,
205
+ title=title,
206
+ message=message,
207
+ on_close=on_close,
208
+ icon=QMessageBox.Icon.Information,
209
+ )
210
+
211
+ if on_close:
212
+ msg_box.show()
213
+ else:
214
+ return msg_box.exec()
215
+
216
+ @classmethod
217
+ def is_yes_button(cls, sb: QMessageBox.StandardButton) -> bool:
218
+ return sb == QMessageBox.StandardButton.Yes
219
+
220
+
221
+ Application = QApplication
222
+
223
+ class TEXT_ALIGN:
224
+ TOP = Qt.AlignmentFlag.AlignTop
225
+ V_CENTER = Qt.AlignmentFlag.AlignVCenter
226
+ BOTTOM = Qt.AlignmentFlag.AlignBottom
227
+ LEFT = Qt.AlignmentFlag.AlignLeft
228
+ CENTER = Qt.AlignmentFlag.AlignCenter
229
+ RIGHT = Qt.AlignmentFlag.AlignRight
230
+
231
+ class SCROLL:
232
+ OFF = Qt.ScrollBarPolicy.ScrollBarAlwaysOff
233
+ ON = Qt.ScrollBarPolicy.ScrollBarAlwaysOn
234
+ AS_NEEDED = Qt.ScrollBarPolicy.ScrollBarAsNeeded
235
+
236
+ ScrollArea = QScrollArea
237
+
238
+ ForegroundRole = Qt.ItemDataRole.ForegroundRole
239
+ BackroundRole = Qt.ItemDataRole.BackgroundRole
240
+
241
+ Palette = QPalette
242
+ Palette.ButtonText = QPalette.ColorRole.ButtonText
243
+ Palette.Button = QPalette.ColorRole.Button
244
+ Palette.Window = QPalette.ColorRole.Window
245
+
246
+ StyleOptionHeader = QStyleOptionHeader
247
+ Separator = QLabel
248
+
249
+ @cache
250
+ def init(style = '') -> QApplication:
251
+ if not style:
252
+ style = platform.system()
253
+
254
+ app = QApplication([])
255
+ app.setStyle(style)
256
+ return app
257
+
258
+ def to_clipboard(text: str, **kwargs):
259
+ cp = QGuiApplication.clipboard()
260
+ cp.setText(text)
261
+
262
+ def from_clipboard(**kwargs) -> str:
263
+ cp = QGuiApplication.clipboard()
264
+ return cp.text()
265
+
266
+ def separator(horizontal = True) -> Separator:
267
+ direction = QFrame.Shape.HLine if horizontal else QFrame.Shape.VLine
268
+ sep = QLabel()
269
+ sep.setFrameStyle(direction | QFrame.Shadow.Sunken)
270
+ return sep
271
+
272
+ def is_ui_thread() -> bool:
273
+ return QThread.currentThread() is QGuiApplication.instance().thread()
274
+
275
+