qpuiq 0.23__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 (104) hide show
  1. PUI/PySide6/__init__.py +49 -0
  2. PUI/PySide6/application.py +58 -0
  3. PUI/PySide6/base.py +285 -0
  4. PUI/PySide6/button.py +21 -0
  5. PUI/PySide6/canvas.py +345 -0
  6. PUI/PySide6/checkbox.py +32 -0
  7. PUI/PySide6/combobox.py +85 -0
  8. PUI/PySide6/dialog.py +72 -0
  9. PUI/PySide6/divider.py +23 -0
  10. PUI/PySide6/image.py +48 -0
  11. PUI/PySide6/label.py +33 -0
  12. PUI/PySide6/layout.py +141 -0
  13. PUI/PySide6/matplotlib.py +23 -0
  14. PUI/PySide6/mdi.py +33 -0
  15. PUI/PySide6/menu.py +85 -0
  16. PUI/PySide6/modal.py +132 -0
  17. PUI/PySide6/progressbar.py +17 -0
  18. PUI/PySide6/radiobutton.py +29 -0
  19. PUI/PySide6/scroll.py +155 -0
  20. PUI/PySide6/splitter.py +25 -0
  21. PUI/PySide6/tab.py +39 -0
  22. PUI/PySide6/table.py +147 -0
  23. PUI/PySide6/text.py +35 -0
  24. PUI/PySide6/textfield.py +62 -0
  25. PUI/PySide6/toolbar.py +57 -0
  26. PUI/PySide6/tree.py +290 -0
  27. PUI/PySide6/window.py +82 -0
  28. PUI/__init__.py +46 -0
  29. PUI/common.py +26 -0
  30. PUI/decorator.py +20 -0
  31. PUI/dom.py +263 -0
  32. PUI/flet/__init__.py +22 -0
  33. PUI/flet/application.py +42 -0
  34. PUI/flet/base.py +37 -0
  35. PUI/flet/button.py +20 -0
  36. PUI/flet/canvas.py +86 -0
  37. PUI/flet/checkbox.py +23 -0
  38. PUI/flet/divider.py +14 -0
  39. PUI/flet/label.py +27 -0
  40. PUI/flet/layout.py +50 -0
  41. PUI/flet/progressbar.py +21 -0
  42. PUI/flet/radiobutton.py +27 -0
  43. PUI/flet/scroll.py +83 -0
  44. PUI/flet/tab.py +42 -0
  45. PUI/flet/text.py +55 -0
  46. PUI/flet/textfield.py +58 -0
  47. PUI/flet/window.py +25 -0
  48. PUI/interfaces.py +97 -0
  49. PUI/node.py +432 -0
  50. PUI/state.py +711 -0
  51. PUI/textual/__init__.py +35 -0
  52. PUI/textual/application.py +82 -0
  53. PUI/textual/base.py +148 -0
  54. PUI/textual/button.py +17 -0
  55. PUI/textual/checkbox.py +21 -0
  56. PUI/textual/label.py +36 -0
  57. PUI/textual/layout.py +52 -0
  58. PUI/textual/progressbar.py +17 -0
  59. PUI/textual/radiobutton.py +24 -0
  60. PUI/textual/scroll.py +74 -0
  61. PUI/textual/tab.py +75 -0
  62. PUI/textual/text.py +32 -0
  63. PUI/textual/textfield.py +55 -0
  64. PUI/textual/window.py +7 -0
  65. PUI/timeline.py +36 -0
  66. PUI/tkinter/__init__.py +43 -0
  67. PUI/tkinter/application.py +49 -0
  68. PUI/tkinter/base.py +68 -0
  69. PUI/tkinter/button.py +15 -0
  70. PUI/tkinter/canvas.py +52 -0
  71. PUI/tkinter/checkbox.py +27 -0
  72. PUI/tkinter/label.py +17 -0
  73. PUI/tkinter/layout.py +114 -0
  74. PUI/tkinter/progressbar.py +17 -0
  75. PUI/tkinter/radiobutton.py +26 -0
  76. PUI/tkinter/scroll.py +201 -0
  77. PUI/tkinter/tab.py +52 -0
  78. PUI/tkinter/text.py +20 -0
  79. PUI/tkinter/textfield.py +53 -0
  80. PUI/tkinter/window.py +51 -0
  81. PUI/utils.py +15 -0
  82. PUI/view.py +161 -0
  83. PUI/wx/__init__.py +19 -0
  84. PUI/wx/application.py +44 -0
  85. PUI/wx/base.py +246 -0
  86. PUI/wx/button.py +16 -0
  87. PUI/wx/canvas.py +255 -0
  88. PUI/wx/checkbox.py +25 -0
  89. PUI/wx/combobox.py +81 -0
  90. PUI/wx/dialog.py +66 -0
  91. PUI/wx/divider.py +19 -0
  92. PUI/wx/label.py +18 -0
  93. PUI/wx/layout.py +52 -0
  94. PUI/wx/progressbar.py +19 -0
  95. PUI/wx/radiobutton.py +27 -0
  96. PUI/wx/scroll.py +55 -0
  97. PUI/wx/text.py +23 -0
  98. PUI/wx/textfield.py +66 -0
  99. PUI/wx/window.py +64 -0
  100. qpuiq-0.23.dist-info/LICENSE.txt +21 -0
  101. qpuiq-0.23.dist-info/METADATA +234 -0
  102. qpuiq-0.23.dist-info/RECORD +104 -0
  103. qpuiq-0.23.dist-info/WHEEL +5 -0
  104. qpuiq-0.23.dist-info/top_level.txt +1 -0
PUI/__init__.py ADDED
@@ -0,0 +1,46 @@
1
+ __version__ = "0.23"
2
+
3
+ from .node import *
4
+ from .view import *
5
+ from .state import *
6
+ from .timeline import *
7
+ from .decorator import *
8
+ from .common import *
9
+ from .interfaces import *
10
+
11
+ try:
12
+ import jurigged
13
+ w = jurigged.watch("/")
14
+ def postrun(path, cf):
15
+ PUIView.reload()
16
+ w.postrun.register(postrun)
17
+ except ImportError:
18
+ pass
19
+
20
+ class Prop():
21
+ def __init__(self, value=None):
22
+ self.value = value
23
+
24
+ def set(self, value):
25
+ changed = (self.value != value)
26
+ self.value = value
27
+ return changed
28
+
29
+ class NotImplementedNode():
30
+ def __init__(self, *args, **kwargs):
31
+ print("Not Implemented")
32
+ import traceback
33
+ import inspect
34
+ traceback.print_stack(inspect.currentframe().f_back, 1)
35
+
36
+ def __enter__(self):
37
+ return self
38
+
39
+ def __exit__(self, *args):
40
+ pass
41
+
42
+ def layout(self, *args, **kwargs):
43
+ return self
44
+
45
+ def style(self, *args, **kwargs):
46
+ return self
PUI/common.py ADDED
@@ -0,0 +1,26 @@
1
+ from enum import Enum
2
+ from enum import IntEnum
3
+ class Anchor(Enum):
4
+ LEFT_TOP = ("left" ,"top")
5
+ LEFT_CENTER = ("left" ,"center")
6
+ LEFT_BOTTOM = ("left" ,"bottom")
7
+ CENTER_TOP = ("center" ,"top")
8
+ CENTER = ("center" ,"center")
9
+ CENTER_BOTTOM = ("center" ,"bottom")
10
+ RIGHT_TOP = ("right" ,"top")
11
+ RIGHT_CENTER = ("right" ,"center")
12
+ RIGHT_BOTTOM = ("right" ,"bottom")
13
+
14
+ class MouseButton(IntEnum):
15
+ NONE = 0
16
+ LEFT = 1
17
+ RIGHT = 2
18
+ MIDDLE = 4
19
+ X1 = 8
20
+ X2 = 16
21
+
22
+ class KeyModifier(IntEnum):
23
+ SHIFT = 1
24
+ CTRL = 2
25
+ ALT = 4
26
+ META = 8
PUI/decorator.py ADDED
@@ -0,0 +1,20 @@
1
+ from .view import *
2
+
3
+ def PUI(func):
4
+ """
5
+ PUI.PUI triggers update() directly by redraw()
6
+ """
7
+ def func_wrapper(*args, **kwargs):
8
+ class PUIViewWrapper(PUIView):
9
+ pui_virtual = True
10
+ def __init__(self, name):
11
+ self.name = name
12
+ super().__init__()
13
+
14
+ def content(self):
15
+ return func(*args, **kwargs)
16
+
17
+ ret = PUIViewWrapper(func.__name__)
18
+ return ret
19
+
20
+ return func_wrapper
PUI/dom.py ADDED
@@ -0,0 +1,263 @@
1
+ DEBUG = False
2
+
3
+ class VDomError(Exception):
4
+ pass
5
+
6
+ def recur_delete(node, child, direct):
7
+ child.destroyed = True
8
+ for sc in child.children:
9
+ if sc is not None:
10
+ recur_delete(child, sc, False)
11
+ if DEBUG:
12
+ print("recur_delete", node.key, child.key, direct)
13
+ child.destroy(direct)
14
+
15
+ def sortGridDOMInPlace(dom):
16
+ dom[:] = [c for c in dom if c.grid_row is not None and c.grid_column is not None]
17
+ dom.sort(key=lambda c:(c.grid_row, c.grid_column, c.grid_rowspan, c.grid_columnspan))
18
+
19
+ def dom_remove_node(dom_parent, dom_offset, child):
20
+ if DEBUG:
21
+ print(f"dom_remove_node key={child.key} virtual={child.pui_virtual} children={len(child.children)} dom_parent={dom_parent.key} dom_offset={dom_offset}")
22
+ if child.pui_virtual:
23
+ ret = [child]
24
+ for c in child.children:
25
+ ret.extend(dom_remove_node(dom_parent, dom_offset, c))
26
+ return ret
27
+ else:
28
+ dom_parent.removeChild(dom_offset , child)
29
+ return [child]
30
+
31
+ def dom_add_nodes(dom_parent, dom_offset, children):
32
+ for childIdx, c in enumerate([n for n in children if not n.pui_virtual]):
33
+ dom_parent.addChild(dom_offset+childIdx, c)
34
+
35
+ def countDomChildren(nodes):
36
+ num = 0
37
+ for c in nodes:
38
+ if c.pui_virtual:
39
+ num += countDomChildren(c.children)
40
+ elif not c.pui_outoforder:
41
+ num += 1
42
+ return num
43
+
44
+ def sync(node, dom_parent, dom_offset, oldVDOM, newVDOM, depth=0):
45
+ orig_dom_children_num = dom_children_num = countDomChildren(oldVDOM)
46
+ dom_children_curr = 0
47
+
48
+ if DEBUG:
49
+ print(f"{(depth)*' '}Syncing {node.key}@{id(node)}#tag={node._tag} parent={dom_parent.key}@{id(dom_parent)}#tag={dom_parent._tag} dom_offset={dom_offset} dom_children_num={dom_children_num} old={len(oldVDOM)} new={len(newVDOM)}")
50
+
51
+ if node.pui_grid_layout:
52
+ sortGridDOMInPlace(oldVDOM)
53
+ sortGridDOMInPlace(newVDOM)
54
+ else:
55
+ oldOrdered = [c for c in oldVDOM if not c.pui_outoforder]
56
+ oldOutOfOrdered = [c for c in oldVDOM if c.pui_outoforder]
57
+ newOrdered = [c for c in newVDOM if not c.pui_outoforder]
58
+ newOutOfOrdered = [c for c in newVDOM if c.pui_outoforder]
59
+
60
+ if node.pui_reversed_order:
61
+ oldOrdered.reverse()
62
+ newOrdered.reverse()
63
+
64
+ oldVDOM.clear()
65
+ oldVDOM.extend(oldOrdered + oldOutOfOrdered)
66
+ newVDOM.clear()
67
+ newVDOM.extend(newOrdered + newOutOfOrdered)
68
+
69
+ if DEBUG:
70
+ print(f"{(depth+1)*' '}===OLD===")
71
+ for c in oldVDOM:
72
+ print(f"{(depth+1)*' '}{c.key}#tag={c._tag} virtual={c.pui_virtual} children={len(c.children)} ui={c.ui}")
73
+
74
+ print(f"{(depth+1)*' '}===NEW===")
75
+ for c in newVDOM:
76
+ print(f"{(depth+1)*' '}{c.key}#tag={c._tag} virtual={c.pui_virtual} children={len(c.children)}")
77
+ print(f"{(depth+1)*' '}=========")
78
+
79
+ oldVMap = [x.key for x in oldVDOM]
80
+ newVMap = [x.key for x in newVDOM]
81
+
82
+ node.preSync()
83
+
84
+ toBeDeleted = []
85
+ for childIdx, new in enumerate(newVDOM):
86
+ if DEBUG:
87
+ print(f"{(depth+1)*' '}sync child {childIdx}, {new.key} dom_parent={dom_parent.key} virtual={new.pui_virtual}")
88
+ new.pui_dom_parent = dom_parent
89
+
90
+ while True:
91
+ # Step 1. just matched
92
+ if childIdx < len(oldVDOM) and oldVMap[childIdx] == new.key: # matched
93
+ if DEBUG:
94
+ print(f"{(depth+1)*' '}S1. MATCHED {childIdx} {new.key}")
95
+ old = oldVDOM[childIdx]
96
+
97
+ if old.pui_isview: # must also be virtual
98
+ n = countDomChildren(old.children)
99
+ dom_children_curr += n
100
+ if DEBUG:
101
+ print(f"{(depth+1)*' '} dom_children_curr += {n} => {dom_children_curr} dom_children_num={dom_children_num}")
102
+
103
+ old.parent = new.parent
104
+ old.pui_dom_parent = new.pui_dom_parent
105
+ newVDOM[childIdx] = old
106
+ new.destroy(True) # deregister old view from PUIView.__ALLVIEWS__
107
+ else:
108
+ try:
109
+ new.update(old)
110
+ except:
111
+ import traceback
112
+ print("## <ERROR OF update() >")
113
+ print(new.key)
114
+ traceback.print_exc()
115
+ print("## </ERROR OF update()>")
116
+
117
+ if new.pui_virtual:
118
+ num, delta = sync(new, node, dom_offset + dom_children_curr, old.children, new.children, depth+1)
119
+ dom_children_curr += num
120
+ dom_children_num += delta
121
+ if DEBUG:
122
+ print(f"{(depth+2)*' '}dom_children_curr += {num} => {dom_children_curr} dom_children_num += {delta} => {dom_children_num}")
123
+ else:
124
+ if not new.pui_outoforder:
125
+ dom_children_curr += 1
126
+ if DEBUG:
127
+ print(f"{(depth+2)*' '}dom_children_curr += 1 => {dom_children_curr} dom_children_num={dom_children_num}")
128
+
129
+ if not new.pui_terminal:
130
+ sync(new, old, 0, old.children, new.children, depth+1)
131
+
132
+ break # finish
133
+
134
+ # Step 2. trim removed nodes after common prefix
135
+ trimmed = False
136
+ while childIdx < len(oldVDOM) and not oldVDOM[childIdx].key in newVMap[childIdx:]: # trim old nodes
137
+ if DEBUG:
138
+ print(f"{(depth+1)*' '}S2. TRIM {childIdx} {oldVDOM[childIdx].key}")
139
+ old = oldVDOM.pop(childIdx)
140
+ oldVMap.pop(childIdx)
141
+ nodes = dom_remove_node(dom_parent, dom_offset + dom_children_curr, old)
142
+ n = len([n for n in nodes if not n.pui_virtual and not n.pui_outoforder])
143
+ dom_children_num -= n
144
+ if DEBUG:
145
+ print(f"{(depth+2)*' '}dom_children_num -= {n} => {dom_children_num}")
146
+ toBeDeleted.extend(nodes)
147
+ trimmed = True
148
+
149
+ if trimmed:
150
+ continue # restart
151
+
152
+ # Step 3. setup target node
153
+
154
+ matchedIdx = None
155
+ if new.pui_movable:
156
+ try:
157
+ matchedIdx = oldVMap[childIdx+1:].index(new.key) + childIdx + 1
158
+ except ValueError:
159
+ pass
160
+
161
+ ## Step 3-1. new node
162
+ if matchedIdx is None:
163
+ if DEBUG:
164
+ print(f"{(depth+1)*' '}S3-1. NEW {childIdx} {new.key}")
165
+ # always populate new node regardless of isview or not
166
+ try:
167
+ new.update(None)
168
+ except:
169
+ import traceback
170
+ print("## <ERROR OF update() >")
171
+ print(new.key)
172
+ traceback.print_exc()
173
+ print("## </ERROR OF update()>")
174
+
175
+ if new.pui_virtual:
176
+ num, delta = sync(new, dom_parent, dom_offset + dom_children_curr, [], new.children, depth+1)
177
+ dom_children_curr += num
178
+ dom_children_num += num
179
+ if DEBUG:
180
+ print(f"{(depth+2)*' '}dom_children_curr += {num} => {dom_children_curr} dom_children_num += {num} => {dom_children_num}")
181
+ else:
182
+ if DEBUG:
183
+ print(f"{(depth+1)*' '}addChild", dom_parent.key, dom_offset + dom_children_curr, new.key)
184
+ dom_parent.addChild(dom_offset + dom_children_curr, new)
185
+
186
+ if not new.pui_outoforder:
187
+ dom_children_curr += 1
188
+ dom_children_num += 1
189
+ if DEBUG:
190
+ print(f"{(depth+2)*' '}dom_children_curr += 1 => {dom_children_curr} dom_children_num += 1 => {dom_children_num}")
191
+
192
+ if not new.pui_terminal:
193
+ sync(new, new, 0, [], new.children, depth+1)
194
+
195
+ oldVDOM.insert(childIdx, new) # put new node back for later findDomOffsetForNode
196
+ oldVMap.insert(childIdx, new.key)
197
+
198
+ ## Step 3-2. existed node
199
+ else:
200
+ # if the target node is in just next position, requeue the blocker to prevent repositioning every nodes coming after
201
+ # eg. when an element is removed from a long list, do single 3-2-1 instead of many 3-2-2
202
+
203
+ ### Step 3-2-1. yield the next position for the target node
204
+ if matchedIdx == childIdx + 1:
205
+ if DEBUG:
206
+ print(f"{(depth+1)*' '}S3-2-1. YIELD {childIdx} {new.key}")
207
+ oldVMap.pop(childIdx)
208
+ toBeRequeued = oldVDOM.pop(childIdx)
209
+ nodes = dom_remove_node(dom_parent, dom_offset + dom_children_curr, toBeRequeued)
210
+ n = len([n for n in nodes if not n.pui_virtual and not n.pui_outoforder])
211
+ dom_add_nodes(dom_parent, dom_children_num - n, nodes)
212
+ oldVMap.append(toBeRequeued.key)
213
+ oldVDOM.append(toBeRequeued)
214
+
215
+ ### Step 3-2-2. move target node
216
+ else:
217
+ if DEBUG:
218
+ print(f"{(depth+1)*' '}S3-2-2. MOVE {childIdx} {new.key}")
219
+ found, offset = dom_parent.findDomOffsetForNode(old)
220
+ if not found:
221
+ raise VDomError(f"S3-2-2: findDomOffsetForNode() failed for {old.key}#tag={old._tag} on {dom_parent.key}#tag={dom_parent._tag} {dom_parent.children}")
222
+ oldVMap.pop(matchedIdx)
223
+ old = oldVDOM.pop(matchedIdx)
224
+ nodes = dom_remove_node(dom_parent, offset, old)
225
+ dom_add_nodes(dom_parent, dom_offset + dom_children_curr, nodes)
226
+
227
+ oldVDOM.insert(childIdx, new) # put new node back for later findDomOffsetForNode
228
+ oldVMap.insert(childIdx, new.key)
229
+
230
+ continue # restart, sync will be peformed in next step 1
231
+
232
+ break # finish
233
+
234
+ # Step 4. trim removed trail
235
+ if DEBUG:
236
+ print(f"{(depth+1)*' '}S4. TRIM")
237
+ nl = len(newVDOM)
238
+ if DEBUG:
239
+ print(f"{(depth+1)*' '}S4. TRIM", f"dom_offset={dom_offset}", len(oldVDOM), "=>", len(newVDOM))
240
+ while len(oldVDOM) > nl:
241
+ old = oldVDOM.pop(nl)
242
+ if DEBUG:
243
+ print(f"{(depth+2)*' '}", f"key={old.key} virtual={old.pui_virtual} children={len(old.children)}")
244
+ oldVMap.pop(nl)
245
+ nodes = dom_remove_node(dom_parent, dom_offset + nl, old)
246
+ dom_children_num -= len([n for n in nodes if not n.pui_virtual and not n.pui_outoforder])
247
+ toBeDeleted.append(old)
248
+
249
+ for c in newVDOM:
250
+ c.postUpdate()
251
+
252
+ node.postSync()
253
+
254
+ # release deleted nodes
255
+ for old in toBeDeleted:
256
+ recur_delete(node, old, True)
257
+
258
+ if DEBUG:
259
+ print(f"{(depth)*' '}sync end {node.key} -> {dom_children_curr},{dom_children_num}")
260
+
261
+ if dom_children_curr != dom_children_num:
262
+ raise VDomError(f"dom_children_curr != dom_children_num for {node.key} -> {dom_children_curr},{dom_children_num}")
263
+ return dom_children_curr, dom_children_num - orig_dom_children_num
PUI/flet/__init__.py ADDED
@@ -0,0 +1,22 @@
1
+ from .application import *
2
+ from .button import *
3
+ from .canvas import *
4
+ from .checkbox import *
5
+ from .divider import *
6
+ from .label import *
7
+ from .layout import *
8
+ from .progressbar import *
9
+ from .radiobutton import *
10
+ from .scroll import *
11
+ from .tab import *
12
+ from .text import *
13
+ from .textfield import *
14
+ from .window import *
15
+ from .. import NotImplementedNode
16
+
17
+ Combobox = NotImplementedNode
18
+ ComboboxItem = NotImplementedNode
19
+
20
+ PUIView = FView
21
+
22
+ PUI_BACKEND = "flet"
@@ -0,0 +1,42 @@
1
+ from .. import *
2
+ from .base import *
3
+
4
+ class Application(PUIView):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.ready = False
8
+
9
+ def sync(self):
10
+ if not self.ready:
11
+ return
12
+ super().sync()
13
+
14
+ def flet_app(self, page: ft.Page):
15
+ self.ui = page
16
+ self.ready = True
17
+ self.sync()
18
+
19
+ def addChild(self, idx, child):
20
+ if idx > 0:
21
+ print("Flet backend only support single window")
22
+
23
+ def removeChild(self, idx, child):
24
+ pass
25
+
26
+ def start(self):
27
+ ft.app(self.flet_app)
28
+
29
+ def PUIApp(func):
30
+ def func_wrapper(*args, **kwargs):
31
+ class PUIAppWrapper(Application):
32
+ def __init__(self, name):
33
+ self.name = name
34
+ super().__init__()
35
+
36
+ def content(self):
37
+ return func(*args, **kwargs)
38
+
39
+ ret = PUIAppWrapper(func.__name__)
40
+ return ret
41
+
42
+ return func_wrapper
PUI/flet/base.py ADDED
@@ -0,0 +1,37 @@
1
+ from .. import *
2
+ import flet as ft
3
+
4
+ def _apply_params(ui, params):
5
+ for k,v in params.items():
6
+ setattr(ui, k, v)
7
+
8
+ class FView(PUIView):
9
+ pui_virtual = True
10
+
11
+ class FBase(PUINode):
12
+ def __init__(self, *args):
13
+ super().__init__(*args)
14
+ self.child_weight = None
15
+ if self.fparent:
16
+ self.layout_weight = self.fparent.child_weight
17
+
18
+ self.flet_params = {}
19
+
20
+ def flet(self, **kwargs):
21
+ for k,v in kwargs.items():
22
+ self.flet_params[k] = v
23
+ return self
24
+
25
+ def update(self, prev):
26
+ _apply_params(self.ui, self.flet_params)
27
+ super().update(prev)
28
+
29
+ @property
30
+ def fparent(self):
31
+ parent = self.parent
32
+ while True:
33
+ if isinstance(parent, FBase):
34
+ return parent
35
+ if parent.parent == parent:
36
+ return None
37
+ parent = parent.parent
PUI/flet/button.py ADDED
@@ -0,0 +1,20 @@
1
+ from .. import *
2
+ from .base import *
3
+
4
+ class Button(FBase):
5
+ def __init__(self, text):
6
+ super().__init__()
7
+ self.text = text
8
+
9
+ def update(self, prev):
10
+ if prev and prev.ui:
11
+ self.ui = prev.ui
12
+ self.ui.text = self.text
13
+ self.ui.on_click = self._clicked
14
+ try:
15
+ self.ui.update()
16
+ except:
17
+ pass
18
+ else:
19
+ self.ui = ft.ElevatedButton(text=self.text, on_click=self._clicked)
20
+ self.ui.expand = self.layout_weight
PUI/flet/canvas.py ADDED
@@ -0,0 +1,86 @@
1
+ from .. import *
2
+ from .base import *
3
+ import flet.canvas as cv
4
+
5
+ class Canvas(FBase):
6
+ def __init__(self, painter, *args):
7
+ super().__init__()
8
+ self.ui = None
9
+ self.painter = painter
10
+ self.args = args
11
+
12
+ def update(self, prev):
13
+ if prev and prev.ui:
14
+ self.ui = prev.ui
15
+ self.ui.puinode = self
16
+ else:
17
+ self.ui = cv.Canvas()
18
+ if self.layout_width:
19
+ self.ui.width = self.layout_width
20
+ else:
21
+ self.ui.width = float("inf")
22
+ if self.layout_height:
23
+ self.ui.height = self.layout_height
24
+ else:
25
+ self.ui.height = float("inf")
26
+ self.ui.shapes.clear()
27
+ self.painter(self, *self.args)
28
+ try:
29
+ self.ui.update()
30
+ except:
31
+ pass
32
+ super().update(prev)
33
+
34
+ def drawText(self, x, y, text, w=None, h=None, rotate=0, anchor=Anchor.LEFT_TOP):
35
+ if rotate !=0:
36
+ print("drawText: rotate not implemented")
37
+ self.ui.shapes.append(
38
+ cv.Text(
39
+ x,
40
+ y,
41
+ text,
42
+ )
43
+ )
44
+
45
+ def drawLine(self, x1, y1, x2, y2, color=None, width=None):
46
+ params = {}
47
+ if not color is None:
48
+ params["color"] = f"#{color:06X}"
49
+ if not width is None:
50
+ params["stroke_width"] = width
51
+ self.ui.shapes.append(
52
+ cv.Line(
53
+ x1,
54
+ y1,
55
+ x2,
56
+ y2,
57
+ ft.Paint(**params, style=ft.PaintingStyle.STROKE)
58
+ ),
59
+ )
60
+
61
+ def drawPolyline(self, coords, color=None, width=None):
62
+ params = {}
63
+ if not color is None:
64
+ params["color"] = f"#{color:06X}"
65
+ if not width is None:
66
+ params["stroke_width"] = width
67
+ paint = ft.Paint(**params, style=ft.PaintingStyle.STROKE)
68
+ for i in range(1, len(coords)):
69
+ self.ui.shapes.append(
70
+ cv.Line(
71
+ coords[i-1][0],
72
+ coords[i-1][1],
73
+ coords[i][0],
74
+ coords[i][1],
75
+ paint
76
+ ),
77
+ )
78
+
79
+ def drawPolygon(self, coords, fill=None, stroke=None, width=1):
80
+ print("drawPolygon not implemented")
81
+
82
+ def drawRect(self, x1, y1, x2, y2, fill=None, stroke=None, width=1):
83
+ print("drawRect not implemented")
84
+
85
+ def drawEllipse(self, x, y, rx, ry, fill=None, stroke=None, width=1):
86
+ print("drawEllipse not implemented")
PUI/flet/checkbox.py ADDED
@@ -0,0 +1,23 @@
1
+ from .. import *
2
+ from .base import *
3
+
4
+ class Checkbox(FBase):
5
+ def __init__(self, text, model):
6
+ super().__init__()
7
+ self.text = text
8
+ self.model = model
9
+
10
+ def update(self, prev):
11
+ if prev and prev.ui:
12
+ self.ui = prev.ui
13
+ self.ui.value = self.model.value
14
+ self.ui.on_change = self._changed
15
+ self.ui.update()
16
+ else:
17
+ self.ui = ft.Checkbox(label=self.text, value=self.model.value, on_change=self._changed)
18
+
19
+ super().update(prev)
20
+
21
+ def _changed(self, event):
22
+ node = self.get_node()
23
+ self.model.value = node.ui.value
PUI/flet/divider.py ADDED
@@ -0,0 +1,14 @@
1
+ from .. import *
2
+ from .base import *
3
+
4
+ class Divider(FBase):
5
+ def update(self, prev):
6
+ if prev and prev.ui:
7
+ self.ui = prev.ui
8
+ try:
9
+ self.ui.update()
10
+ except:
11
+ pass
12
+ else:
13
+ self.ui = ft.Divider()
14
+ self.ui.expand = self.layout_weight
PUI/flet/label.py ADDED
@@ -0,0 +1,27 @@
1
+ from .. import *
2
+ from .base import *
3
+
4
+ class Label(FBase):
5
+ def __init__(self, text, selectable=False):
6
+ super().__init__()
7
+ self.text = text
8
+
9
+ def update(self, prev):
10
+ if prev and prev.ui:
11
+ self.ui = prev.ui
12
+ else:
13
+ self.ui = ft.Text(spans=[])
14
+ self.ui.expand = self.layout_weight
15
+ if self._onClicked:
16
+ self.ui.spans = [
17
+ ft.TextSpan(self.text, on_click=self._clicked)
18
+ ]
19
+ else:
20
+ self.ui.spans = [
21
+ ft.TextSpan(self.text)
22
+ ]
23
+ try:
24
+ self.ui.update()
25
+ except:
26
+ pass
27
+ super().update(prev)
PUI/flet/layout.py ADDED
@@ -0,0 +1,50 @@
1
+ from .. import *
2
+ from .base import *
3
+
4
+ class HBox(FBase):
5
+ def update(self, prev):
6
+ if prev and prev.ui:
7
+ self.ui = prev.ui
8
+ else:
9
+ self.ui = ft.Row()
10
+ self.ui.expand = self.layout_weight
11
+ super().update(prev)
12
+
13
+ def addChild(self, idx, child):
14
+ self.ui.controls.insert(idx, child.outer)
15
+ try:
16
+ self.ui.update()
17
+ except:
18
+ pass
19
+
20
+ def removeChild(self, idx, child):
21
+ self.ui.controls.pop(idx)
22
+ self.ui.update()
23
+
24
+ class VBox(FBase):
25
+ def update(self, prev):
26
+ if prev and prev.ui:
27
+ self.ui = prev.ui
28
+ else:
29
+ self.ui = ft.Column()
30
+ self.ui.expand = self.layout_weight
31
+ super().update(prev)
32
+
33
+ def addChild(self, idx, child):
34
+ self.ui.controls.insert(idx, child.outer)
35
+ try:
36
+ self.ui.update()
37
+ except:
38
+ pass
39
+
40
+ def removeChild(self, idx, child):
41
+ self.ui.controls.pop(idx)
42
+ self.ui.update()
43
+
44
+ class Spacer(FBase):
45
+ def update(self, prev):
46
+ if prev and prev.ui:
47
+ self.ui = prev.ui
48
+ else:
49
+ self.ui = ft.Container()
50
+ super().update(prev)