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.
- PUI/PySide6/__init__.py +49 -0
- PUI/PySide6/application.py +58 -0
- PUI/PySide6/base.py +285 -0
- PUI/PySide6/button.py +21 -0
- PUI/PySide6/canvas.py +345 -0
- PUI/PySide6/checkbox.py +32 -0
- PUI/PySide6/combobox.py +85 -0
- PUI/PySide6/dialog.py +72 -0
- PUI/PySide6/divider.py +23 -0
- PUI/PySide6/image.py +48 -0
- PUI/PySide6/label.py +33 -0
- PUI/PySide6/layout.py +141 -0
- PUI/PySide6/matplotlib.py +23 -0
- PUI/PySide6/mdi.py +33 -0
- PUI/PySide6/menu.py +85 -0
- PUI/PySide6/modal.py +132 -0
- PUI/PySide6/progressbar.py +17 -0
- PUI/PySide6/radiobutton.py +29 -0
- PUI/PySide6/scroll.py +155 -0
- PUI/PySide6/splitter.py +25 -0
- PUI/PySide6/tab.py +39 -0
- PUI/PySide6/table.py +147 -0
- PUI/PySide6/text.py +35 -0
- PUI/PySide6/textfield.py +62 -0
- PUI/PySide6/toolbar.py +57 -0
- PUI/PySide6/tree.py +290 -0
- PUI/PySide6/window.py +82 -0
- PUI/__init__.py +46 -0
- PUI/common.py +26 -0
- PUI/decorator.py +20 -0
- PUI/dom.py +263 -0
- PUI/flet/__init__.py +22 -0
- PUI/flet/application.py +42 -0
- PUI/flet/base.py +37 -0
- PUI/flet/button.py +20 -0
- PUI/flet/canvas.py +86 -0
- PUI/flet/checkbox.py +23 -0
- PUI/flet/divider.py +14 -0
- PUI/flet/label.py +27 -0
- PUI/flet/layout.py +50 -0
- PUI/flet/progressbar.py +21 -0
- PUI/flet/radiobutton.py +27 -0
- PUI/flet/scroll.py +83 -0
- PUI/flet/tab.py +42 -0
- PUI/flet/text.py +55 -0
- PUI/flet/textfield.py +58 -0
- PUI/flet/window.py +25 -0
- PUI/interfaces.py +97 -0
- PUI/node.py +432 -0
- PUI/state.py +711 -0
- PUI/textual/__init__.py +35 -0
- PUI/textual/application.py +82 -0
- PUI/textual/base.py +148 -0
- PUI/textual/button.py +17 -0
- PUI/textual/checkbox.py +21 -0
- PUI/textual/label.py +36 -0
- PUI/textual/layout.py +52 -0
- PUI/textual/progressbar.py +17 -0
- PUI/textual/radiobutton.py +24 -0
- PUI/textual/scroll.py +74 -0
- PUI/textual/tab.py +75 -0
- PUI/textual/text.py +32 -0
- PUI/textual/textfield.py +55 -0
- PUI/textual/window.py +7 -0
- PUI/timeline.py +36 -0
- PUI/tkinter/__init__.py +43 -0
- PUI/tkinter/application.py +49 -0
- PUI/tkinter/base.py +68 -0
- PUI/tkinter/button.py +15 -0
- PUI/tkinter/canvas.py +52 -0
- PUI/tkinter/checkbox.py +27 -0
- PUI/tkinter/label.py +17 -0
- PUI/tkinter/layout.py +114 -0
- PUI/tkinter/progressbar.py +17 -0
- PUI/tkinter/radiobutton.py +26 -0
- PUI/tkinter/scroll.py +201 -0
- PUI/tkinter/tab.py +52 -0
- PUI/tkinter/text.py +20 -0
- PUI/tkinter/textfield.py +53 -0
- PUI/tkinter/window.py +51 -0
- PUI/utils.py +15 -0
- PUI/view.py +161 -0
- PUI/wx/__init__.py +19 -0
- PUI/wx/application.py +44 -0
- PUI/wx/base.py +246 -0
- PUI/wx/button.py +16 -0
- PUI/wx/canvas.py +255 -0
- PUI/wx/checkbox.py +25 -0
- PUI/wx/combobox.py +81 -0
- PUI/wx/dialog.py +66 -0
- PUI/wx/divider.py +19 -0
- PUI/wx/label.py +18 -0
- PUI/wx/layout.py +52 -0
- PUI/wx/progressbar.py +19 -0
- PUI/wx/radiobutton.py +27 -0
- PUI/wx/scroll.py +55 -0
- PUI/wx/text.py +23 -0
- PUI/wx/textfield.py +66 -0
- PUI/wx/window.py +64 -0
- qpuiq-0.23.dist-info/LICENSE.txt +21 -0
- qpuiq-0.23.dist-info/METADATA +234 -0
- qpuiq-0.23.dist-info/RECORD +104 -0
- qpuiq-0.23.dist-info/WHEEL +5 -0
- qpuiq-0.23.dist-info/top_level.txt +1 -0
PUI/textual/__init__.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from .application import *
|
|
2
|
+
from .button import *
|
|
3
|
+
from .checkbox import *
|
|
4
|
+
from .label import *
|
|
5
|
+
from .layout import *
|
|
6
|
+
from .progressbar import *
|
|
7
|
+
from .radiobutton import *
|
|
8
|
+
from .scroll import *
|
|
9
|
+
from .tab import *
|
|
10
|
+
from .text import *
|
|
11
|
+
from .textfield import *
|
|
12
|
+
from .window import *
|
|
13
|
+
from .. import NotImplementedNode
|
|
14
|
+
|
|
15
|
+
PUIView = TPUIView
|
|
16
|
+
|
|
17
|
+
class DummyWidget(TBase):
|
|
18
|
+
pui_supported = False
|
|
19
|
+
def __init__(self, *args, **kwrgas):
|
|
20
|
+
super().__init__()
|
|
21
|
+
|
|
22
|
+
def update(self, prev):
|
|
23
|
+
if prev and prev.ui:
|
|
24
|
+
self.ui = prev.ui
|
|
25
|
+
else:
|
|
26
|
+
self.ui = widgets.Label("Not Implemented")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
Canvas = DummyWidget
|
|
31
|
+
Combobox = DummyWidget
|
|
32
|
+
ComboboxItem = DummyWidget
|
|
33
|
+
Divider = lambda: None
|
|
34
|
+
|
|
35
|
+
PUI_BACKEND = "textual"
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from typing import Type
|
|
2
|
+
from textual.driver import Driver
|
|
3
|
+
from .. import *
|
|
4
|
+
from .base import *
|
|
5
|
+
from textual.app import App, CSSPathType, ComposeResult
|
|
6
|
+
from textual.containers import Vertical
|
|
7
|
+
from textual.widgets import Button, Checkbox, Input, RadioButton, Tabs
|
|
8
|
+
|
|
9
|
+
class PUITextualApp(App):
|
|
10
|
+
|
|
11
|
+
def __init__(self, puiview, driver_class: Type[Driver] = None, css_path: CSSPathType = None, watch_css: bool = False):
|
|
12
|
+
super().__init__(driver_class, css_path, watch_css)
|
|
13
|
+
self.puiview = puiview
|
|
14
|
+
|
|
15
|
+
def on_mount(self) -> None:
|
|
16
|
+
self.puiview.redraw()
|
|
17
|
+
|
|
18
|
+
def on_button_pressed(self, event: Button.Pressed) -> None:
|
|
19
|
+
event.button.puinode.get_node()._clicked()
|
|
20
|
+
|
|
21
|
+
def on_radio_button_changed(self, event: RadioButton.Changed) -> None:
|
|
22
|
+
event.radio_button.puinode.get_node()._changed(event.value)
|
|
23
|
+
|
|
24
|
+
def on_input_changed(self, event: Input.Changed) -> None:
|
|
25
|
+
event.input.puinode.get_node()._tchanged(event.value)
|
|
26
|
+
|
|
27
|
+
def on_input_submitted(self, event: Input.Submitted) -> None:
|
|
28
|
+
event.input.puinode.get_node()._tsubmitted(event.value)
|
|
29
|
+
|
|
30
|
+
def on_checkbox_changed(self, event: Checkbox.Changed) -> None:
|
|
31
|
+
event.checkbox.puinode.get_node()._changed(event.value)
|
|
32
|
+
|
|
33
|
+
def on_tabs_tab_activated(self, event: Tabs.TabActivated) -> None:
|
|
34
|
+
event.tabs.puinode.get_node()._tab_activated(event)
|
|
35
|
+
|
|
36
|
+
def compose(self) -> ComposeResult:
|
|
37
|
+
yield Vertical(id="frame")
|
|
38
|
+
|
|
39
|
+
class Application(PUIView):
|
|
40
|
+
def __init__(self):
|
|
41
|
+
super().__init__()
|
|
42
|
+
self.ui = PUITextualApp(self)
|
|
43
|
+
|
|
44
|
+
def addChild(self, idx, child):
|
|
45
|
+
if idx>0:
|
|
46
|
+
raise RuntimeError("Textual backend only support single window")
|
|
47
|
+
self.ui.query_one("#frame").mount(child.outer)
|
|
48
|
+
|
|
49
|
+
def redraw(self):
|
|
50
|
+
self.dirty = True
|
|
51
|
+
if self.updating:
|
|
52
|
+
return
|
|
53
|
+
self.updating = True
|
|
54
|
+
self.ui.call_next(self._redraw)
|
|
55
|
+
|
|
56
|
+
def _redraw(self):
|
|
57
|
+
with self.ui.batch_update():
|
|
58
|
+
self.sync()
|
|
59
|
+
self.updating = False
|
|
60
|
+
|
|
61
|
+
def run(self):
|
|
62
|
+
# self.redraw() # need to be after on_mount
|
|
63
|
+
self.start()
|
|
64
|
+
|
|
65
|
+
def start(self):
|
|
66
|
+
self.ui.run()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def PUIApp(func):
|
|
70
|
+
def func_wrapper(*args, **kwargs):
|
|
71
|
+
class PUIAppWrapper(Application):
|
|
72
|
+
def __init__(self, name):
|
|
73
|
+
self.name = name
|
|
74
|
+
super().__init__()
|
|
75
|
+
|
|
76
|
+
def content(self):
|
|
77
|
+
return func(*args, **kwargs)
|
|
78
|
+
|
|
79
|
+
ret = PUIAppWrapper(func.__name__)
|
|
80
|
+
return ret
|
|
81
|
+
|
|
82
|
+
return func_wrapper
|
PUI/textual/base.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from textual import widgets, containers
|
|
3
|
+
|
|
4
|
+
class TBase(PUINode):
|
|
5
|
+
scroll = False
|
|
6
|
+
container_x = False # axis
|
|
7
|
+
container_y = False # axis
|
|
8
|
+
expand_x_prio = 0
|
|
9
|
+
expand_y_prio = 0
|
|
10
|
+
expand_x1_children = 0
|
|
11
|
+
expand_x2_children = 0
|
|
12
|
+
expand_x3_children = 0
|
|
13
|
+
expand_x4_children = 0
|
|
14
|
+
expand_y1_children = 0
|
|
15
|
+
expand_y2_children = 0
|
|
16
|
+
expand_y3_children = 0
|
|
17
|
+
expand_y4_children = 0
|
|
18
|
+
cached_tparent = None
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def expand_x(self):
|
|
22
|
+
parent = self.cached_tparent
|
|
23
|
+
expand = self.expand_x_prio
|
|
24
|
+
if not parent:
|
|
25
|
+
return False
|
|
26
|
+
|
|
27
|
+
# textual handles 1fr as shrinkable, but we need scrolller's content not to shrink
|
|
28
|
+
# See Exp.1 in refs/textual_layout.py
|
|
29
|
+
if parent.scroll:
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
# textual populates auto(1fr) to be 1fr(1fr), but we require expanding not to go over the container
|
|
33
|
+
# See Exp.2 in refs/textual_layout.py
|
|
34
|
+
if not parent.expand_x and expand < 3:
|
|
35
|
+
return False
|
|
36
|
+
|
|
37
|
+
return expand
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def expand_y(self):
|
|
41
|
+
parent = self.cached_tparent
|
|
42
|
+
expand = self.expand_y_prio
|
|
43
|
+
if not parent:
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
# textual handles 1fr as shrinkable, but we need scrolller's content not to shrink
|
|
47
|
+
# See Exp.1 in refs/textual_layout.py
|
|
48
|
+
if parent.scroll:
|
|
49
|
+
return False
|
|
50
|
+
|
|
51
|
+
# textual populates auto(1fr) to be 1fr(1fr), but we require expanding not to go over the container
|
|
52
|
+
# See Exp.2 in refs/textual_layout.py
|
|
53
|
+
if not parent.expand_y and expand < 3:
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
return expand
|
|
57
|
+
|
|
58
|
+
def tremove(self):
|
|
59
|
+
self.ui.remove()
|
|
60
|
+
|
|
61
|
+
def destroy(self, direct):
|
|
62
|
+
self.ui.remove()
|
|
63
|
+
return super().destroy(direct)
|
|
64
|
+
|
|
65
|
+
def update(self, prev):
|
|
66
|
+
super().update(prev)
|
|
67
|
+
|
|
68
|
+
self.cached_tparent = parent = self.tparent
|
|
69
|
+
if parent:
|
|
70
|
+
if self.layout_weight:
|
|
71
|
+
if parent.container_x:
|
|
72
|
+
self.expand_x_prio = 4
|
|
73
|
+
if parent.container_y:
|
|
74
|
+
self.expand_y_prio = 4
|
|
75
|
+
|
|
76
|
+
if self.expand_x_prio >= 1:
|
|
77
|
+
parent.expand_x1_children += 1
|
|
78
|
+
if self.expand_x_prio >= 2:
|
|
79
|
+
parent.expand_x2_children += 1
|
|
80
|
+
if self.expand_x_prio >= 3:
|
|
81
|
+
parent.expand_x3_children += 1
|
|
82
|
+
if self.expand_x_prio >= 4:
|
|
83
|
+
parent.expand_x4_children += 1
|
|
84
|
+
|
|
85
|
+
if self.expand_y_prio >= 1:
|
|
86
|
+
parent.expand_y1_children += 1
|
|
87
|
+
if self.expand_y_prio >= 2:
|
|
88
|
+
parent.expand_y2_children += 1
|
|
89
|
+
if self.expand_y_prio >= 3:
|
|
90
|
+
parent.expand_y3_children += 1
|
|
91
|
+
if self.expand_y_prio >= 4:
|
|
92
|
+
parent.expand_y4_children += 1
|
|
93
|
+
|
|
94
|
+
def postUpdate(self):
|
|
95
|
+
super().postUpdate()
|
|
96
|
+
parent = self.cached_tparent
|
|
97
|
+
if parent:
|
|
98
|
+
if parent.container_x:
|
|
99
|
+
if self.expand_x_prio < 1 and parent.expand_x1_children > 0:
|
|
100
|
+
self.expand_x_prio = 0
|
|
101
|
+
if self.expand_x_prio < 2 and parent.expand_x2_children > 0:
|
|
102
|
+
self.expand_x_prio = 0
|
|
103
|
+
if self.expand_x_prio < 3 and parent.expand_x3_children > 0:
|
|
104
|
+
self.expand_x_prio = 0
|
|
105
|
+
if self.expand_x_prio < 4 and parent.expand_x4_children > 0:
|
|
106
|
+
self.expand_x_prio = 0
|
|
107
|
+
|
|
108
|
+
if parent.container_y:
|
|
109
|
+
if self.expand_y_prio < 1 and parent.expand_y1_children > 0:
|
|
110
|
+
self.expand_y_prio = 0
|
|
111
|
+
if self.expand_y_prio < 2 and parent.expand_y2_children > 0:
|
|
112
|
+
self.expand_y_prio = 0
|
|
113
|
+
if self.expand_y_prio < 3 and parent.expand_y3_children > 0:
|
|
114
|
+
self.expand_y_prio = 0
|
|
115
|
+
if self.expand_y_prio < 4 and parent.expand_y4_children > 0:
|
|
116
|
+
self.expand_y_prio = 0
|
|
117
|
+
|
|
118
|
+
self.t_update_layout()
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def tparent(self):
|
|
122
|
+
parent = self.parent
|
|
123
|
+
while not isinstance(parent, TBase):
|
|
124
|
+
if parent==parent.parent:
|
|
125
|
+
parent = None
|
|
126
|
+
break
|
|
127
|
+
parent = parent.parent
|
|
128
|
+
return parent
|
|
129
|
+
|
|
130
|
+
def t_update_layout(self):
|
|
131
|
+
if not self.ui:
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
width = "auto"
|
|
135
|
+
if self.expand_x:
|
|
136
|
+
width = "1fr"
|
|
137
|
+
|
|
138
|
+
height = "auto"
|
|
139
|
+
if self.expand_y:
|
|
140
|
+
height = "1fr"
|
|
141
|
+
|
|
142
|
+
if self._debug:
|
|
143
|
+
print("layout", self.key, f"{width}:{height} expand_x={self.expand_x}", f"expand_y={self.expand_y}", f"expand_x_prio={self.expand_x_prio}", f"expand_y_prio={self.expand_y_prio}")
|
|
144
|
+
self.ui.styles.width = width
|
|
145
|
+
self.ui.styles.height = height
|
|
146
|
+
|
|
147
|
+
class TPUIView(PUIView):
|
|
148
|
+
pui_virtual = True
|
PUI/textual/button.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
|
|
4
|
+
class Button(TBase):
|
|
5
|
+
def __init__(self, text, callback=None):
|
|
6
|
+
super().__init__()
|
|
7
|
+
self.text = text
|
|
8
|
+
self.callback = callback
|
|
9
|
+
|
|
10
|
+
def update(self, prev):
|
|
11
|
+
if prev and prev.ui:
|
|
12
|
+
self.ui = prev.ui
|
|
13
|
+
self.ui.label = self.text
|
|
14
|
+
else:
|
|
15
|
+
self.ui = widgets.Button(self.text)
|
|
16
|
+
self.ui.puinode = self
|
|
17
|
+
super().update(prev)
|
PUI/textual/checkbox.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
|
|
4
|
+
class Checkbox(TBase):
|
|
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
|
+
else:
|
|
15
|
+
self.ui = widgets.Checkbox(self.text, self.model.value)
|
|
16
|
+
|
|
17
|
+
self.ui.puinode = self
|
|
18
|
+
super().update(prev)
|
|
19
|
+
|
|
20
|
+
def _changed(self, value):
|
|
21
|
+
self.model.value = value
|
PUI/textual/label.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
|
|
4
|
+
class Label(TBase):
|
|
5
|
+
def __init__(self, text, selectable=False):
|
|
6
|
+
super().__init__()
|
|
7
|
+
self.widget = None
|
|
8
|
+
self.text = text
|
|
9
|
+
|
|
10
|
+
def update(self, prev):
|
|
11
|
+
if prev and prev.ui:
|
|
12
|
+
self.ui = prev.ui
|
|
13
|
+
self.widget = prev.widget
|
|
14
|
+
else:
|
|
15
|
+
self.ui = containers.Container()
|
|
16
|
+
if self._onClicked:
|
|
17
|
+
if self.widget is None or not isinstance(self.widget, widgets.Button):
|
|
18
|
+
if self.widget:
|
|
19
|
+
self.widget.remove()
|
|
20
|
+
self.widget = widgets.Button(self.text)
|
|
21
|
+
self.widget.set_styles("border-top: none; border-bottom: none;")
|
|
22
|
+
self.widget.puinode = self
|
|
23
|
+
else:
|
|
24
|
+
self.widget.label = self.text
|
|
25
|
+
else:
|
|
26
|
+
if self.widget is None or not isinstance(self.widget, widgets.Label):
|
|
27
|
+
if self.widget:
|
|
28
|
+
self.widget.remove()
|
|
29
|
+
self.widget = widgets.Label(self.text, markup=False)
|
|
30
|
+
else:
|
|
31
|
+
self.widget.update(self.text)
|
|
32
|
+
super().update(prev)
|
|
33
|
+
|
|
34
|
+
def postUpdate(self):
|
|
35
|
+
super().postUpdate()
|
|
36
|
+
self.ui.mount(self.widget)
|
PUI/textual/layout.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
|
|
4
|
+
class VBox(TBase):
|
|
5
|
+
container_y = True
|
|
6
|
+
expand_x_prio = 1
|
|
7
|
+
expand_y_prio = 2
|
|
8
|
+
def update(self, prev):
|
|
9
|
+
if prev and prev.ui:
|
|
10
|
+
self.ui = prev.ui
|
|
11
|
+
else:
|
|
12
|
+
self.ui = containers.Vertical()
|
|
13
|
+
super().update(prev)
|
|
14
|
+
|
|
15
|
+
def addChild(self, idx, child):
|
|
16
|
+
if isinstance(child, TBase):
|
|
17
|
+
self.inner.mount(child.outer, before=idx)
|
|
18
|
+
|
|
19
|
+
def removeChild(self, idx, child):
|
|
20
|
+
if isinstance(child, TBase):
|
|
21
|
+
child.tremove()
|
|
22
|
+
|
|
23
|
+
class HBox(TBase):
|
|
24
|
+
container_x = True
|
|
25
|
+
expand_x_prio = 2
|
|
26
|
+
expand_y_prio = 1
|
|
27
|
+
def update(self, prev):
|
|
28
|
+
if prev and prev.ui:
|
|
29
|
+
self.ui = prev.ui
|
|
30
|
+
else:
|
|
31
|
+
self.ui = containers.Horizontal()
|
|
32
|
+
super().update(prev)
|
|
33
|
+
|
|
34
|
+
def addChild(self, idx, child):
|
|
35
|
+
if isinstance(child, TBase):
|
|
36
|
+
self.inner.mount(child.outer, before=idx)
|
|
37
|
+
|
|
38
|
+
def removeChild(self, idx, child):
|
|
39
|
+
if isinstance(child, TBase):
|
|
40
|
+
child.tremove()
|
|
41
|
+
|
|
42
|
+
class Spacer(TBase):
|
|
43
|
+
def __init__(self):
|
|
44
|
+
super().__init__()
|
|
45
|
+
self.layout_weight = 1
|
|
46
|
+
|
|
47
|
+
def update(self, prev):
|
|
48
|
+
if prev and prev.ui:
|
|
49
|
+
self.ui = prev.ui
|
|
50
|
+
else:
|
|
51
|
+
self.ui = widgets.Static("")
|
|
52
|
+
super().update(prev)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
|
|
4
|
+
class ProgressBar(TBase):
|
|
5
|
+
def __init__(self, progress, maximum=1):
|
|
6
|
+
super().__init__()
|
|
7
|
+
self.progress = progress*100
|
|
8
|
+
self.maximum = maximum*100
|
|
9
|
+
|
|
10
|
+
def update(self, prev):
|
|
11
|
+
if prev and prev.ui:
|
|
12
|
+
self.ui = prev.ui
|
|
13
|
+
else:
|
|
14
|
+
self.ui = widgets.ProgressBar(total=self.maximum, show_eta=False)
|
|
15
|
+
self.ui.update(total=self.maximum)
|
|
16
|
+
self.ui.progress = self.progress
|
|
17
|
+
super().update(prev)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
|
|
4
|
+
class RadioButton(TBase):
|
|
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.ui = prev.ui
|
|
14
|
+
else:
|
|
15
|
+
self.ui = widgets.RadioButton(self.text)
|
|
16
|
+
self.ui.puinode = self
|
|
17
|
+
self.ui.value = self.value == self.model.value
|
|
18
|
+
super().update(prev)
|
|
19
|
+
|
|
20
|
+
def _changed(self, value):
|
|
21
|
+
if value:
|
|
22
|
+
self.model.value = self.value
|
|
23
|
+
else:
|
|
24
|
+
self.root.redraw()
|
PUI/textual/scroll.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
import math
|
|
4
|
+
|
|
5
|
+
class Scroll(TBase):
|
|
6
|
+
END = -0.0
|
|
7
|
+
scroll = True
|
|
8
|
+
def __init__(self, vertical=None, horizontal=False):
|
|
9
|
+
self.vertical = vertical
|
|
10
|
+
self.horizontal = horizontal
|
|
11
|
+
self.align_x = 0
|
|
12
|
+
self.align_y = 0
|
|
13
|
+
super().__init__()
|
|
14
|
+
|
|
15
|
+
def update(self, prev):
|
|
16
|
+
if prev and prev.ui:
|
|
17
|
+
self.ui = prev.ui
|
|
18
|
+
else:
|
|
19
|
+
self.ui = containers.ScrollableContainer()
|
|
20
|
+
|
|
21
|
+
v = "auto"
|
|
22
|
+
self.container_y = True
|
|
23
|
+
self.expand_y_prio = 3
|
|
24
|
+
if self.vertical is True:
|
|
25
|
+
v = "scroll"
|
|
26
|
+
elif self.vertical is False:
|
|
27
|
+
v = "hidden"
|
|
28
|
+
self.container_y = False
|
|
29
|
+
self.expand_y_prio = 1
|
|
30
|
+
|
|
31
|
+
h = "auto"
|
|
32
|
+
self.container_x = True
|
|
33
|
+
self.expand_x_prio = 3
|
|
34
|
+
if self.horizontal is True:
|
|
35
|
+
h = "scroll"
|
|
36
|
+
elif self.horizontal is False:
|
|
37
|
+
h = "hidden"
|
|
38
|
+
self.container_x = False
|
|
39
|
+
self.expand_x_prio = 1
|
|
40
|
+
|
|
41
|
+
self.ui.set_styles(f"overflow-x: {h}; overflow-y: {v};")
|
|
42
|
+
|
|
43
|
+
super().update(prev)
|
|
44
|
+
|
|
45
|
+
def addChild(self, idx, child):
|
|
46
|
+
if isinstance(child, TBase):
|
|
47
|
+
self.inner.mount(child.outer)
|
|
48
|
+
self.t_update_layout()
|
|
49
|
+
else:
|
|
50
|
+
self.addChild(idx, child.children[0])
|
|
51
|
+
|
|
52
|
+
def removeChild(self, idx, child):
|
|
53
|
+
if isinstance(child, TBase):
|
|
54
|
+
child.tremove()
|
|
55
|
+
else:
|
|
56
|
+
self.removeChild(idx, child.children[0])
|
|
57
|
+
|
|
58
|
+
def scrollX(self, pos=0):
|
|
59
|
+
if math.copysign(1, pos) >= 0:
|
|
60
|
+
self.align_x = 0
|
|
61
|
+
self.hsb_offset = pos
|
|
62
|
+
else:
|
|
63
|
+
self.align_x = 1
|
|
64
|
+
self.hsb_offset = abs(pos)
|
|
65
|
+
return self
|
|
66
|
+
|
|
67
|
+
def scrollY(self, pos=0):
|
|
68
|
+
if math.copysign(1, pos) >= 0:
|
|
69
|
+
self.align_y = 0
|
|
70
|
+
self.vsb_offset = pos
|
|
71
|
+
else:
|
|
72
|
+
self.align_y = 1
|
|
73
|
+
self.vsb_offset = abs(pos)
|
|
74
|
+
return self
|
PUI/textual/tab.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
|
|
4
|
+
class Tabs(TBase):
|
|
5
|
+
NORTH = "n"
|
|
6
|
+
SOUTH = "s"
|
|
7
|
+
EAST = "e"
|
|
8
|
+
WEST = "w"
|
|
9
|
+
pui_terminal = False
|
|
10
|
+
def __init__(self, tabposition=NORTH):
|
|
11
|
+
super().__init__()
|
|
12
|
+
self.tabposition = tabposition
|
|
13
|
+
self.tabs = None
|
|
14
|
+
self.current_tab = None
|
|
15
|
+
self._dirty = False
|
|
16
|
+
|
|
17
|
+
def update(self, prev):
|
|
18
|
+
if prev and prev.ui:
|
|
19
|
+
self.current_tab = prev.current_tab
|
|
20
|
+
self.ui = prev.ui
|
|
21
|
+
self.tabhost = prev.tabhost
|
|
22
|
+
self.frame = prev.frame
|
|
23
|
+
self.tabs = prev.tabs
|
|
24
|
+
self.mounted = prev.mounted
|
|
25
|
+
else:
|
|
26
|
+
self.ui = containers.Vertical()
|
|
27
|
+
self.tabhost = containers.Container()
|
|
28
|
+
self.frame = containers.Container()
|
|
29
|
+
self.mounted = False
|
|
30
|
+
super().update(prev)
|
|
31
|
+
|
|
32
|
+
def addChild(self, idx, child):
|
|
33
|
+
if not self.mounted:
|
|
34
|
+
self.ui.mount(self.tabhost)
|
|
35
|
+
self.ui.mount(self.frame)
|
|
36
|
+
self.mounted = True
|
|
37
|
+
self._dirty = True
|
|
38
|
+
child.outer.display = False
|
|
39
|
+
self.frame.mount(child.outer, before=idx)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def removeChild(self, idx, child):
|
|
43
|
+
self.ui.removeTab(idx)
|
|
44
|
+
self._dirty = True
|
|
45
|
+
child.tremove()
|
|
46
|
+
|
|
47
|
+
def postSync(self):
|
|
48
|
+
if self._dirty:
|
|
49
|
+
if self.tabs:
|
|
50
|
+
self.tabs.remove()
|
|
51
|
+
tabs = []
|
|
52
|
+
for c in self.children:
|
|
53
|
+
tab = widgets.Tab(c.label)
|
|
54
|
+
tab.puinode = c
|
|
55
|
+
tabs.append(tab)
|
|
56
|
+
self.tabs = widgets.Tabs(*tabs)
|
|
57
|
+
self.tabs.puinode = self
|
|
58
|
+
self.tabhost.mount(self.tabs)
|
|
59
|
+
self._dirty = False
|
|
60
|
+
super().postSync()
|
|
61
|
+
|
|
62
|
+
def _tab_activated(self, event: widgets.Tabs.TabActivated):
|
|
63
|
+
node = self.get_node()
|
|
64
|
+
if node.current_tab:
|
|
65
|
+
node.current_tab.outer.display = False
|
|
66
|
+
if event.tab:
|
|
67
|
+
tab = event.tab.puinode.get_node()
|
|
68
|
+
tab.outer.display = True
|
|
69
|
+
self.current_tab = tab
|
|
70
|
+
|
|
71
|
+
class Tab(PUINode):
|
|
72
|
+
pui_virtual = True
|
|
73
|
+
def __init__(self, label):
|
|
74
|
+
super().__init__()
|
|
75
|
+
self.label = label
|
PUI/textual/text.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
|
|
4
|
+
class Text(TBase):
|
|
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
|
+
self.ui.update(self.text)
|
|
13
|
+
else:
|
|
14
|
+
self.ui = widgets.Label(self.text, markup=False)
|
|
15
|
+
super().update(prev)
|
|
16
|
+
|
|
17
|
+
class Html(Text):
|
|
18
|
+
pui_supported = False
|
|
19
|
+
|
|
20
|
+
class MarkDown(TBase):
|
|
21
|
+
weak_expand_x = True
|
|
22
|
+
def __init__(self, text):
|
|
23
|
+
super().__init__()
|
|
24
|
+
self.text = text
|
|
25
|
+
|
|
26
|
+
def update(self, prev):
|
|
27
|
+
if prev and prev.ui:
|
|
28
|
+
self.ui = prev.ui
|
|
29
|
+
self.ui.update(self.text)
|
|
30
|
+
else:
|
|
31
|
+
self.ui = widgets.Markdown(self.text)
|
|
32
|
+
super().update(prev)
|
PUI/textual/textfield.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
|
|
4
|
+
class TextField(TBase):
|
|
5
|
+
content_width = None
|
|
6
|
+
def __init__(self, model, edit_model=None):
|
|
7
|
+
super().__init__()
|
|
8
|
+
self.model = model
|
|
9
|
+
self.edit_model = edit_model
|
|
10
|
+
self.editing = False
|
|
11
|
+
|
|
12
|
+
def update(self, prev):
|
|
13
|
+
model_value = str(self.model.value)
|
|
14
|
+
|
|
15
|
+
if prev and prev.ui:
|
|
16
|
+
self.editing = prev.editing
|
|
17
|
+
self.ui = prev.ui
|
|
18
|
+
self.curr_value = prev.curr_value
|
|
19
|
+
self.changing = prev.changing
|
|
20
|
+
|
|
21
|
+
if self.curr_value.set(model_value) and not self.editing:
|
|
22
|
+
self.changing = True # block changed event from next line
|
|
23
|
+
self.ui.value = model_value
|
|
24
|
+
else:
|
|
25
|
+
self.ui = widgets.Input(model_value)
|
|
26
|
+
self.curr_value = Prop(model_value)
|
|
27
|
+
self.changing = True # block changed event from initialization
|
|
28
|
+
|
|
29
|
+
if self.edit_model and not self.editing:
|
|
30
|
+
self.edit_model.value = model_value
|
|
31
|
+
|
|
32
|
+
self.ui.puinode = self
|
|
33
|
+
super().update(prev)
|
|
34
|
+
|
|
35
|
+
def _tchanged(self, value): # editing
|
|
36
|
+
if self.changing:
|
|
37
|
+
self.changing = False
|
|
38
|
+
return
|
|
39
|
+
node = self.get_node()
|
|
40
|
+
node.editing = True
|
|
41
|
+
if node.edit_model:
|
|
42
|
+
node.edit_model.value = value
|
|
43
|
+
e = PUIEvent()
|
|
44
|
+
e.value = value
|
|
45
|
+
self._input(e)
|
|
46
|
+
|
|
47
|
+
def _tsubmitted(self, value): # finish editing
|
|
48
|
+
node = self.get_node()
|
|
49
|
+
node.editing = False
|
|
50
|
+
node.model.value = value
|
|
51
|
+
if node.edit_model:
|
|
52
|
+
node.edit_model.value = value
|
|
53
|
+
e = PUIEvent()
|
|
54
|
+
e.value = value
|
|
55
|
+
self._change(e)
|