qpuiq 0.10__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.

Potentially problematic release.


This version of qpuiq might be problematic. Click here for more details.

Files changed (103) hide show
  1. PUI/PySide6/__init__.py +49 -0
  2. PUI/PySide6/application.py +58 -0
  3. PUI/PySide6/base.py +222 -0
  4. PUI/PySide6/button.py +21 -0
  5. PUI/PySide6/canvas.py +288 -0
  6. PUI/PySide6/checkbox.py +32 -0
  7. PUI/PySide6/combobox.py +75 -0
  8. PUI/PySide6/dialog.py +72 -0
  9. PUI/PySide6/divider.py +23 -0
  10. PUI/PySide6/image.py +30 -0
  11. PUI/PySide6/label.py +33 -0
  12. PUI/PySide6/layout.py +72 -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 +153 -0
  20. PUI/PySide6/splitter.py +25 -0
  21. PUI/PySide6/tab.py +39 -0
  22. PUI/PySide6/table.py +89 -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 +120 -0
  27. PUI/PySide6/window.py +81 -0
  28. PUI/__init__.py +46 -0
  29. PUI/common.py +20 -0
  30. PUI/decorator.py +20 -0
  31. PUI/dom.py +238 -0
  32. PUI/flet/__init__.py +21 -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/label.py +27 -0
  39. PUI/flet/layout.py +50 -0
  40. PUI/flet/progressbar.py +21 -0
  41. PUI/flet/radiobutton.py +27 -0
  42. PUI/flet/scroll.py +83 -0
  43. PUI/flet/tab.py +42 -0
  44. PUI/flet/text.py +55 -0
  45. PUI/flet/textfield.py +58 -0
  46. PUI/flet/window.py +25 -0
  47. PUI/interfaces.py +97 -0
  48. PUI/node.py +407 -0
  49. PUI/state.py +698 -0
  50. PUI/textual/__init__.py +34 -0
  51. PUI/textual/application.py +82 -0
  52. PUI/textual/base.py +113 -0
  53. PUI/textual/button.py +17 -0
  54. PUI/textual/checkbox.py +21 -0
  55. PUI/textual/label.py +36 -0
  56. PUI/textual/layout.py +48 -0
  57. PUI/textual/progressbar.py +17 -0
  58. PUI/textual/radiobutton.py +24 -0
  59. PUI/textual/scroll.py +72 -0
  60. PUI/textual/tab.py +75 -0
  61. PUI/textual/text.py +32 -0
  62. PUI/textual/textfield.py +49 -0
  63. PUI/textual/window.py +7 -0
  64. PUI/timeline.py +36 -0
  65. PUI/tkinter/__init__.py +43 -0
  66. PUI/tkinter/application.py +49 -0
  67. PUI/tkinter/base.py +68 -0
  68. PUI/tkinter/button.py +15 -0
  69. PUI/tkinter/canvas.py +49 -0
  70. PUI/tkinter/checkbox.py +27 -0
  71. PUI/tkinter/label.py +17 -0
  72. PUI/tkinter/layout.py +114 -0
  73. PUI/tkinter/progressbar.py +17 -0
  74. PUI/tkinter/radiobutton.py +26 -0
  75. PUI/tkinter/scroll.py +201 -0
  76. PUI/tkinter/tab.py +52 -0
  77. PUI/tkinter/text.py +20 -0
  78. PUI/tkinter/textfield.py +53 -0
  79. PUI/tkinter/window.py +51 -0
  80. PUI/utils.py +15 -0
  81. PUI/view.py +161 -0
  82. PUI/wx/__init__.py +19 -0
  83. PUI/wx/application.py +44 -0
  84. PUI/wx/base.py +202 -0
  85. PUI/wx/button.py +16 -0
  86. PUI/wx/canvas.py +255 -0
  87. PUI/wx/checkbox.py +25 -0
  88. PUI/wx/combobox.py +72 -0
  89. PUI/wx/dialog.py +66 -0
  90. PUI/wx/divider.py +19 -0
  91. PUI/wx/label.py +18 -0
  92. PUI/wx/layout.py +46 -0
  93. PUI/wx/progressbar.py +17 -0
  94. PUI/wx/radiobutton.py +27 -0
  95. PUI/wx/scroll.py +44 -0
  96. PUI/wx/text.py +23 -0
  97. PUI/wx/textfield.py +56 -0
  98. PUI/wx/window.py +58 -0
  99. qpuiq-0.10.dist-info/LICENSE.txt +21 -0
  100. qpuiq-0.10.dist-info/METADATA +227 -0
  101. qpuiq-0.10.dist-info/RECORD +103 -0
  102. qpuiq-0.10.dist-info/WHEEL +5 -0
  103. qpuiq-0.10.dist-info/top_level.txt +1 -0
PUI/__init__.py ADDED
@@ -0,0 +1,46 @@
1
+ __version__ = "0.10"
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,20 @@
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
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,238 @@
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 child.pui_virtual:
21
+ ret = [child]
22
+ for c in child.children:
23
+ ret.extend(dom_remove_node(dom_parent, dom_offset, c))
24
+ return ret
25
+ else:
26
+ dom_parent.removeChild(dom_offset , child)
27
+ return [child]
28
+
29
+ def dom_add_nodes(dom_parent, dom_offset, children):
30
+ for childIdx, c in enumerate([n for n in children if not n.pui_virtual]):
31
+ dom_parent.addChild(dom_offset+childIdx, c)
32
+
33
+ def countDomChildren(nodes):
34
+ num = 0
35
+ for c in nodes:
36
+ if c.pui_virtual:
37
+ num += countDomChildren(c.children)
38
+ elif not c.pui_outoforder:
39
+ num += 1
40
+ return num
41
+
42
+ def sync(node, dom_parent, dom_offset, oldVDOM, newVDOM, depth=0):
43
+ orig_dom_children_num = dom_children_num = countDomChildren(oldVDOM)
44
+ dom_children_curr = 0
45
+
46
+ if DEBUG:
47
+ print(f"{(depth)*' '}Syncing {node.key}@{id(node)} parent={dom_parent.key}@{id(dom_parent)} dom_offset={dom_offset} dom_children_num={dom_children_num} old={len(oldVDOM)} new={len(newVDOM)}")
48
+
49
+ if node.pui_grid_layout:
50
+ sortGridDOMInPlace(oldVDOM)
51
+ sortGridDOMInPlace(newVDOM)
52
+
53
+ if DEBUG:
54
+ print(f"{(depth+1)*' '}===OLD===")
55
+ for c in oldVDOM:
56
+ print(f"{(depth+1)*' '}{c.key} virtual={c.pui_virtual} ui={c.ui}")
57
+
58
+ print(f"{(depth+1)*' '}===NEW===")
59
+ for c in newVDOM:
60
+ print(f"{(depth+1)*' '}{c.key} virtual={c.pui_virtual}")
61
+
62
+ oldVMap = [x.key for x in oldVDOM]
63
+ newVMap = [x.key for x in newVDOM]
64
+
65
+ node.preSync()
66
+
67
+ toBeDeleted = []
68
+ for childIdx, new in enumerate(newVDOM):
69
+ if DEBUG:
70
+ print(f"{(depth+1)*' '}sync child {childIdx}, {new.key} dom_parent={dom_parent.key} virtual={new.pui_virtual}")
71
+ new.pui_dom_parent = dom_parent
72
+
73
+ while True:
74
+ # Step 1. just matched
75
+ if childIdx < len(oldVDOM) and oldVMap[childIdx] == new.key: # matched
76
+ if DEBUG:
77
+ print(f"{(depth+1)*' '}S1. MATCHED {childIdx} {new.key}")
78
+ old = oldVDOM[childIdx]
79
+
80
+ if old.pui_isview: # must also be virtual
81
+ n = countDomChildren(old.children)
82
+ dom_children_curr += n
83
+ if DEBUG:
84
+ print(f"{(depth+1)*' '} dom_children_curr += {n} => {dom_children_curr} dom_children_num={dom_children_num}")
85
+
86
+ old.parent = new.parent
87
+ old.pui_dom_parent = new.pui_dom_parent
88
+ newVDOM[childIdx] = old
89
+ new.destroy(True) # deregister old view from PUIView.__ALLVIEWS__
90
+ else:
91
+ try:
92
+ new.update(old)
93
+ except:
94
+ import traceback
95
+ print("## <ERROR OF update() >")
96
+ print(new.key)
97
+ traceback.print_exc()
98
+ print("## </ERROR OF update()>")
99
+
100
+ if new.pui_virtual:
101
+ num, delta = sync(new, node, dom_offset + dom_children_curr, old.children, new.children, depth+1)
102
+ dom_children_curr += num
103
+ dom_children_num += delta
104
+ if DEBUG:
105
+ print(f"{(depth+2)*' '}dom_children_curr += {num} => {dom_children_curr} dom_children_num += {delta} => {dom_children_num}")
106
+ else:
107
+ if not new.pui_outoforder:
108
+ dom_children_curr += 1
109
+ if DEBUG:
110
+ print(f"{(depth+2)*' '}dom_children_curr += 1 => {dom_children_curr} dom_children_num={dom_children_num}")
111
+
112
+ if not new.pui_terminal:
113
+ sync(new, new, 0, old.children, new.children, depth+1)
114
+
115
+ break # finish
116
+
117
+ # Step 2. trim removed nodes after common prefix
118
+ trimmed = False
119
+ while childIdx < len(oldVDOM) and not oldVDOM[childIdx].key in newVMap[childIdx:]: # trim old nodes
120
+ if DEBUG:
121
+ print(f"{(depth+1)*' '}S2. TRIM {childIdx} {oldVDOM[childIdx].key}")
122
+ old = oldVDOM.pop(childIdx)
123
+ oldVMap.pop(childIdx)
124
+ nodes = dom_remove_node(dom_parent, dom_offset + dom_children_curr, old)
125
+ n = len([n for n in nodes if not n.pui_virtual and not n.pui_outoforder])
126
+ dom_children_num -= n
127
+ if DEBUG:
128
+ print(f"{(depth+2)*' '}dom_children_num -= {n} => {dom_children_num}")
129
+ toBeDeleted.extend(nodes)
130
+ trimmed = True
131
+
132
+ if trimmed:
133
+ continue # restart
134
+
135
+ # Step 3. setup target node
136
+
137
+ try:
138
+ matchedIdx = oldVMap[childIdx+1:].index(new.key) + childIdx + 1
139
+ except ValueError:
140
+ matchedIdx = None
141
+
142
+ ## Step 3-1. new node
143
+ if matchedIdx is None:
144
+ if DEBUG:
145
+ print(f"{(depth+1)*' '}S3-1. NEW {childIdx} {new.key}")
146
+ # always populate new node regardless of isview or not
147
+ try:
148
+ new.update(None)
149
+ except:
150
+ import traceback
151
+ print("## <ERROR OF update() >")
152
+ print(new.key)
153
+ traceback.print_exc()
154
+ print("## </ERROR OF update()>")
155
+
156
+ if new.pui_virtual:
157
+ num, delta = sync(new, dom_parent, dom_offset + dom_children_curr, [], new.children, depth+1)
158
+ dom_children_curr += num
159
+ dom_children_num += num
160
+ if DEBUG:
161
+ print(f"{(depth+2)*' '}dom_children_curr += {num} => {dom_children_curr} dom_children_num += {num} => {dom_children_num}")
162
+ else:
163
+ if DEBUG:
164
+ print(f"{(depth+1)*' '}addChild", dom_parent.key, dom_offset + dom_children_curr, new.key)
165
+ dom_parent.addChild(dom_offset + dom_children_curr, new)
166
+
167
+ if not new.pui_outoforder:
168
+ dom_children_curr += 1
169
+ dom_children_num += 1
170
+ if DEBUG:
171
+ print(f"{(depth+2)*' '}dom_children_curr += 1 => {dom_children_curr} dom_children_num += 1 => {dom_children_num}")
172
+
173
+ if not new.pui_terminal:
174
+ sync(new, new, 0, [], new.children, depth+1)
175
+
176
+ oldVDOM.insert(childIdx, new) # put new node back for later findDomOffsetForNode
177
+ oldVMap.insert(childIdx, new.key)
178
+
179
+ ## Step 3-2. existed node
180
+ else:
181
+ # if the target node is in just next position, requeue the blocker to prevent repositioning every nodes coming after
182
+ # eg. when an element is removed from a long list, do single 3-2-1 instead of many 3-2-2
183
+
184
+ ### Step 3-2-1. yield the next position for the target node
185
+ if matchedIdx == childIdx + 1:
186
+ if DEBUG:
187
+ print(f"{(depth+1)*' '}S3-2-1. YIELD {childIdx} {new.key}")
188
+ oldVMap.pop(childIdx)
189
+ toBeRequeued = oldVDOM.pop(childIdx)
190
+ nodes = dom_remove_node(dom_parent, dom_offset + dom_children_curr, toBeRequeued)
191
+ n = len([n for n in nodes if not n.pui_virtual and not n.pui_outoforder])
192
+ dom_add_nodes(dom_parent, dom_children_num - n, nodes)
193
+ oldVMap.append(toBeRequeued.key)
194
+ oldVDOM.append(toBeRequeued)
195
+
196
+ ### Step 3-2-2. move target node
197
+ else:
198
+ if DEBUG:
199
+ print(f"{(depth+1)*' '}S3-2-2. MOVE {childIdx} {new.key}")
200
+ oldVMap.pop(matchedIdx)
201
+ old = oldVDOM.pop(matchedIdx)
202
+ found, offset = dom_parent.findDomOffsetForNode(old)
203
+ if not found:
204
+ raise VDomError(f"findDomOffsetForNode() failed for {old.key} on {dom_parent.key}")
205
+ nodes = dom_remove_node(dom_parent, offset, old)
206
+ dom_add_nodes(dom_parent, dom_offset + dom_children_curr, nodes)
207
+
208
+ oldVDOM.insert(childIdx, new) # put new node back for later findDomOffsetForNode
209
+ oldVMap.insert(childIdx, new.key)
210
+
211
+ continue # restart, sync will be peformed in next step 1
212
+
213
+ break # finish
214
+
215
+ # Step 4. trim removed trail
216
+ nl = len(newVDOM)
217
+ while len(oldVDOM) > nl:
218
+ old = oldVDOM.pop(nl)
219
+ oldVMap.pop(nl)
220
+ nodes = dom_remove_node(dom_parent, dom_offset + nl, old)
221
+ dom_children_num -= len([n for n in nodes if not n.pui_virtual and not n.pui_outoforder])
222
+ toBeDeleted.extend(nodes)
223
+
224
+ for c in newVDOM:
225
+ c.postUpdate()
226
+
227
+ node.postSync()
228
+
229
+ # release deleted nodes
230
+ for old in toBeDeleted:
231
+ recur_delete(node, old, True)
232
+
233
+ if DEBUG:
234
+ print(f"{(depth)*' '}sync end {node.key} -> {dom_children_curr},{dom_children_num}")
235
+
236
+ if dom_children_curr != dom_children_num:
237
+ raise VDomError(f"dom_children_curr != dom_children_num for {node.key} -> {dom_children_curr},{dom_children_num}")
238
+ return dom_children_curr, dom_children_num - orig_dom_children_num
PUI/flet/__init__.py ADDED
@@ -0,0 +1,21 @@
1
+ from .application import *
2
+ from .button import *
3
+ from .canvas import *
4
+ from .checkbox import *
5
+ from .label import *
6
+ from .layout import *
7
+ from .progressbar import *
8
+ from .radiobutton import *
9
+ from .scroll import *
10
+ from .tab import *
11
+ from .text import *
12
+ from .textfield import *
13
+ from .window import *
14
+ from .. import NotImplementedNode
15
+
16
+ Combobox = NotImplementedNode
17
+ ComboboxItem = NotImplementedNode
18
+
19
+ PUIView = FView
20
+
21
+ 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/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)
@@ -0,0 +1,21 @@
1
+ from .. import *
2
+ from .base import *
3
+
4
+ class ProgressBar(FBase):
5
+ def __init__(self, progress, maximum=1):
6
+ super().__init__()
7
+ self.progress = progress
8
+ self.maximum = maximum
9
+
10
+ def update(self, prev):
11
+ if prev and prev.ui:
12
+ self.ui = prev.ui
13
+ else:
14
+ self.ui = ft.ProgressBar(width=300) # XXX
15
+ self.ui.value = max(self.progress / self.maximum, 0)
16
+ self.ui.expand = self.layout_weight
17
+ try:
18
+ self.ui.update()
19
+ except:
20
+ pass
21
+ super().update(prev)
@@ -0,0 +1,27 @@
1
+ from .. import *
2
+ from .base import *
3
+
4
+ class RadioButton(FBase):
5
+ def __init__(self, text, value, model):
6
+ super().__init__()
7
+ self.text = text
8
+ self.value = value
9
+ self.model = model
10
+
11
+ def update(self, prev):
12
+ if prev and prev.ui:
13
+ self.radio = prev.radio
14
+ self.ui = prev.ui
15
+ self.radio.value = self.value
16
+ self.ui.value = self.model.value
17
+ self.ui.on_change = self._changed
18
+ self.ui.update()
19
+ else:
20
+ self.radio = ft.Radio(value=self.value, label=self.text)
21
+ self.ui = ft.RadioGroup(content=self.radio, on_change=self._changed)
22
+ super().update(prev)
23
+
24
+ def _changed(self, event):
25
+ node = self.get_node()
26
+ if event.control.value:
27
+ self.model.value = node.value