responds-forms 0.4__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.
- cartas/__init__.py +2060 -0
- cartas/origin.py +1196 -0
- pyflutter_ui/__init__.py +30 -0
- pyflutter_ui/app.py +289 -0
- pyflutter_ui/file_picker.py +274 -0
- pyflutter_ui/navigator.py +93 -0
- pyflutter_ui/scheduler.py +154 -0
- pyflutter_ui/theme.py +1058 -0
- pyflutter_ui/ui/__init__.py +27 -0
- pyflutter_ui/ui/buttons.py +219 -0
- pyflutter_ui/ui/container.py +119 -0
- pyflutter_ui/ui/core.py +820 -0
- pyflutter_ui/ui/list_builder.py +396 -0
- pyflutter_ui/ui/progress.py +80 -0
- pyflutter_ui/ui/tables.py +109 -0
- pyflutter_ui/ui/widgets.py +1418 -0
- responds_forms-0.4.dist-info/METADATA +15 -0
- responds_forms-0.4.dist-info/RECORD +38 -0
- responds_forms-0.4.dist-info/WHEEL +4 -0
- responds_ui/__init__.py +1 -0
- responds_ui/__main__.py +25 -0
- responds_ui/assets/forms_config.json +57 -0
- responds_ui/config_app.py +109 -0
- responds_ui/lib_toi.py +864 -0
- responds_ui/page_forms/Diagnorstico.txt +108 -0
- responds_ui/page_forms/__init__.py +5 -0
- responds_ui/page_forms/common.py +192 -0
- responds_ui/page_forms/config.py +68 -0
- responds_ui/page_forms/controller_forms.py +390 -0
- responds_ui/page_forms/diagnose_forms.py +64 -0
- responds_ui/page_forms/master_forms.py +113 -0
- responds_ui/page_forms/model_forms.py +329 -0
- responds_ui/page_forms/service.py +347 -0
- responds_ui/page_forms/view_forms.py +164 -0
- responds_ui/table_widget.py +140 -0
- responds_ui/util.py +74 -0
- responds_ui/version.py +2 -0
- whatsapp_files/__init__.py +1092 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pyflutter_ui.ui.core import (
|
|
4
|
+
Element, inflate_widget, StatelessWidget, BuildContext, FlutterWidget,
|
|
5
|
+
)
|
|
6
|
+
from pyflutter_ui.ui.progress import LinearProgress
|
|
7
|
+
from pyflutter_ui.ui.widgets import Column
|
|
8
|
+
from tkinter import ttk
|
|
9
|
+
import tkinter as tk
|
|
10
|
+
from typing import Callable, Generic, cast, TypeVar
|
|
11
|
+
|
|
12
|
+
T = TypeVar('T')
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# ============================================================
|
|
16
|
+
# SCROLL VIEW
|
|
17
|
+
# ============================================================
|
|
18
|
+
|
|
19
|
+
class ScrollView(StatelessWidget):
|
|
20
|
+
|
|
21
|
+
def __init__(self, child: FlutterWidget, *, key: str | None = None) -> None:
|
|
22
|
+
super().__init__(key)
|
|
23
|
+
self.child: FlutterWidget = child
|
|
24
|
+
|
|
25
|
+
def build(self, context: BuildContext) -> FlutterWidget:
|
|
26
|
+
return self
|
|
27
|
+
|
|
28
|
+
def create_element(self) -> Element:
|
|
29
|
+
return ScrollViewElement(self)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ScrollViewElement(Element[ttk.Frame]):
|
|
33
|
+
|
|
34
|
+
def __init__(self, widget: ScrollView) -> None:
|
|
35
|
+
super().__init__(widget)
|
|
36
|
+
|
|
37
|
+
def update(self, new_widget: FlutterWidget) -> None:
|
|
38
|
+
context = self.get_context() # salva ANTES de trocar o widget
|
|
39
|
+
self.widget_flutter = cast(ScrollView, new_widget)
|
|
40
|
+
self.widget_flutter.context = context
|
|
41
|
+
if context:
|
|
42
|
+
self.unmount()
|
|
43
|
+
self.mount(context)
|
|
44
|
+
|
|
45
|
+
def get_widget_flutter(self) -> ScrollView:
|
|
46
|
+
return self.widget_flutter
|
|
47
|
+
|
|
48
|
+
def mount(self, context: BuildContext) -> ttk.Frame:
|
|
49
|
+
super().mount(context)
|
|
50
|
+
container = ttk.Frame(context.parent_tk_widget)
|
|
51
|
+
container.pack(fill="both", expand=True)
|
|
52
|
+
canvas = tk.Canvas(container)
|
|
53
|
+
|
|
54
|
+
scrollbar = ttk.Scrollbar(
|
|
55
|
+
container, orient="vertical", command=canvas.yview
|
|
56
|
+
)
|
|
57
|
+
content = ttk.Frame(canvas)
|
|
58
|
+
|
|
59
|
+
content.bind(
|
|
60
|
+
"<Configure>",
|
|
61
|
+
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
|
|
62
|
+
)
|
|
63
|
+
canvas.create_window((0, 0), window=content, anchor="nw")
|
|
64
|
+
canvas.configure(yscrollcommand=scrollbar.set)
|
|
65
|
+
canvas.pack(side="left", fill="both", expand=True)
|
|
66
|
+
scrollbar.pack(side="right", fill="y")
|
|
67
|
+
|
|
68
|
+
self._child_element = self.get_widget_flutter().child.create_element()
|
|
69
|
+
child_context = BuildContext(
|
|
70
|
+
app=context.app,
|
|
71
|
+
parent_widget=content,
|
|
72
|
+
parent_context=context
|
|
73
|
+
)
|
|
74
|
+
self._child_element.mount(child_context)
|
|
75
|
+
|
|
76
|
+
self.widget_tk = container
|
|
77
|
+
return container
|
|
78
|
+
|
|
79
|
+
def unmount(self) -> None:
|
|
80
|
+
if self._child_element is not None:
|
|
81
|
+
self._child_element.unmount()
|
|
82
|
+
self._child_element = None
|
|
83
|
+
super().unmount()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# ============================================================
|
|
87
|
+
# SCROLLABLE COLUMN
|
|
88
|
+
# ============================================================
|
|
89
|
+
|
|
90
|
+
class ScrollableColumn(StatelessWidget):
|
|
91
|
+
|
|
92
|
+
def __init__(
|
|
93
|
+
self,
|
|
94
|
+
children: list[FlutterWidget],
|
|
95
|
+
*,
|
|
96
|
+
scrollbar: bool = True,
|
|
97
|
+
mousewheel: bool = True,
|
|
98
|
+
padding: int = 0,
|
|
99
|
+
key: str | None = None
|
|
100
|
+
) -> None:
|
|
101
|
+
super().__init__(key)
|
|
102
|
+
|
|
103
|
+
self.children = children
|
|
104
|
+
self.scrollbar = scrollbar
|
|
105
|
+
self.mousewheel = mousewheel
|
|
106
|
+
self.padding = padding
|
|
107
|
+
|
|
108
|
+
def build(
|
|
109
|
+
self,
|
|
110
|
+
context: BuildContext
|
|
111
|
+
) -> FlutterWidget:
|
|
112
|
+
return self
|
|
113
|
+
|
|
114
|
+
def create_element(self) -> Element:
|
|
115
|
+
return ScrollableColumnElement(self)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class ScrollableColumnElement(Element[ttk.Frame]):
|
|
119
|
+
|
|
120
|
+
def __init__(self, widget: ScrollableColumn) -> None:
|
|
121
|
+
super().__init__(widget)
|
|
122
|
+
|
|
123
|
+
self._child_elements: list[Element] = []
|
|
124
|
+
self._canvas: tk.Canvas | None = None
|
|
125
|
+
self._content: ttk.Frame | None = None
|
|
126
|
+
self._canvas_window = None
|
|
127
|
+
|
|
128
|
+
def get_widget_flutter(self) -> ScrollableColumn:
|
|
129
|
+
return self.widget_flutter
|
|
130
|
+
|
|
131
|
+
def mount(self, context: BuildContext) -> ttk.Frame:
|
|
132
|
+
super().mount(context)
|
|
133
|
+
|
|
134
|
+
# ====================================================
|
|
135
|
+
# CONTAINER PRINCIPAL
|
|
136
|
+
# ====================================================
|
|
137
|
+
container = ttk.Frame(context.parent_tk_widget)
|
|
138
|
+
container.pack(fill="both", expand=True)
|
|
139
|
+
|
|
140
|
+
# ====================================================
|
|
141
|
+
# CANVAS
|
|
142
|
+
# ====================================================
|
|
143
|
+
canvas = tk.Canvas(container, highlightthickness=0, borderwidth=0)
|
|
144
|
+
self._canvas = canvas
|
|
145
|
+
|
|
146
|
+
# ====================================================
|
|
147
|
+
# SCROLLBAR
|
|
148
|
+
# ====================================================
|
|
149
|
+
|
|
150
|
+
scrollbar = None
|
|
151
|
+
|
|
152
|
+
if self.get_widget_flutter().scrollbar:
|
|
153
|
+
scrollbar = ttk.Scrollbar(container, orient="vertical", command=canvas.yview)
|
|
154
|
+
scrollbar.pack(side="right", fill="y")
|
|
155
|
+
canvas.configure(yscrollcommand=scrollbar.set)
|
|
156
|
+
|
|
157
|
+
# ====================================================
|
|
158
|
+
# ÁREA DE CONTEÚDO
|
|
159
|
+
# ====================================================
|
|
160
|
+
self._content = ttk.Frame(canvas)
|
|
161
|
+
self._canvas_window = canvas.create_window(
|
|
162
|
+
(0, 0),
|
|
163
|
+
window=self._content,
|
|
164
|
+
anchor="nw"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# ====================================================
|
|
168
|
+
# ATUALIZA SCROLL REGION
|
|
169
|
+
# ====================================================
|
|
170
|
+
def update_scroll_region(event=None):
|
|
171
|
+
if not canvas.winfo_exists():
|
|
172
|
+
return
|
|
173
|
+
canvas.configure(scrollregion=canvas.bbox("all"))
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
self._content.bind("<Configure>", update_scroll_region)
|
|
177
|
+
|
|
178
|
+
# ====================================================
|
|
179
|
+
# MANTÉM A LARGURA DO CONTEÚDO IGUAL À DO CANVAS
|
|
180
|
+
# ====================================================
|
|
181
|
+
def update_content_width(event):
|
|
182
|
+
if not canvas.winfo_exists():
|
|
183
|
+
return
|
|
184
|
+
canvas.itemconfigure(self._canvas_window, width=event.width)
|
|
185
|
+
canvas.configure(scrollregion=canvas.bbox("all"))
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
canvas.bind("<Configure>", update_content_width)
|
|
189
|
+
|
|
190
|
+
# ====================================================
|
|
191
|
+
# CANVAS
|
|
192
|
+
# ====================================================
|
|
193
|
+
canvas.pack(side="left", fill="both", expand=True)
|
|
194
|
+
|
|
195
|
+
# ====================================================
|
|
196
|
+
# MOUSE WHEEL
|
|
197
|
+
# ====================================================
|
|
198
|
+
|
|
199
|
+
if self.get_widget_flutter().mousewheel:
|
|
200
|
+
|
|
201
|
+
def mousewheel(event):
|
|
202
|
+
|
|
203
|
+
if event.delta != 0:
|
|
204
|
+
canvas.yview_scroll(int(-event.delta / 120), "units")
|
|
205
|
+
|
|
206
|
+
canvas.bind("<MouseWheel>", mousewheel)
|
|
207
|
+
self._content.bind("<MouseWheel>", mousewheel)
|
|
208
|
+
|
|
209
|
+
# Linux
|
|
210
|
+
canvas.bind("<Button-4>", lambda event: canvas.yview_scroll(-1, "units"))
|
|
211
|
+
|
|
212
|
+
canvas.bind(
|
|
213
|
+
"<Button-5>",
|
|
214
|
+
lambda event: canvas.yview_scroll(1, "units")
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
self._content.bind(
|
|
218
|
+
"<Button-4>",
|
|
219
|
+
lambda event: canvas.yview_scroll(-1, "units")
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
self._content.bind(
|
|
223
|
+
"<Button-5>",
|
|
224
|
+
lambda event: canvas.yview_scroll(1, "units")
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# ====================================================
|
|
228
|
+
# CONTEÚDO VERTICAL
|
|
229
|
+
# ====================================================
|
|
230
|
+
|
|
231
|
+
content_inner = ttk.Frame(self._content)
|
|
232
|
+
|
|
233
|
+
content_inner.pack(
|
|
234
|
+
fill="x",
|
|
235
|
+
expand=False,
|
|
236
|
+
padx=self.get_widget_flutter().padding,
|
|
237
|
+
pady=self.get_widget_flutter().padding
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# ====================================================
|
|
241
|
+
# MONTA OS WIDGETS
|
|
242
|
+
# ====================================================
|
|
243
|
+
|
|
244
|
+
for child in self.get_widget_flutter().children:
|
|
245
|
+
|
|
246
|
+
child_element = inflate_widget(child)
|
|
247
|
+
child_context = context.create_child_context(content_inner)
|
|
248
|
+
child_element.mount(child_context)
|
|
249
|
+
self._child_elements.append(child_element)
|
|
250
|
+
|
|
251
|
+
# ====================================================
|
|
252
|
+
# FORÇA ATUALIZAÇÃO DO SCROLL REGION
|
|
253
|
+
# ====================================================
|
|
254
|
+
self._content.update_idletasks()
|
|
255
|
+
canvas.configure(scrollregion=canvas.bbox("all"))
|
|
256
|
+
self.widget_tk = container
|
|
257
|
+
return container
|
|
258
|
+
|
|
259
|
+
def update(self, new_widget: FlutterWidget) -> None:
|
|
260
|
+
|
|
261
|
+
context = self._parent_context
|
|
262
|
+
self.widget_flutter = cast(ScrollableColumn, new_widget)
|
|
263
|
+
|
|
264
|
+
if context is not None:
|
|
265
|
+
self.unmount()
|
|
266
|
+
self.mount(context)
|
|
267
|
+
|
|
268
|
+
def unmount(self) -> None:
|
|
269
|
+
|
|
270
|
+
for child_element in self._child_elements:
|
|
271
|
+
|
|
272
|
+
try:
|
|
273
|
+
child_element.unmount()
|
|
274
|
+
except Exception:
|
|
275
|
+
pass
|
|
276
|
+
|
|
277
|
+
self._child_elements.clear()
|
|
278
|
+
|
|
279
|
+
self._canvas = None
|
|
280
|
+
self._content = None
|
|
281
|
+
self._canvas_window = None
|
|
282
|
+
super().unmount()
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
class ScrollableColumnOrProgress(StatelessWidget):
|
|
286
|
+
"""
|
|
287
|
+
Exibe uma lista vertical e rolável de FlutterWidgets.
|
|
288
|
+
|
|
289
|
+
Enquanto `running` for True:
|
|
290
|
+
exibe o LinearProgress.
|
|
291
|
+
|
|
292
|
+
Enquanto `running` for False:
|
|
293
|
+
exibe os widgets dentro de um ScrollView.
|
|
294
|
+
|
|
295
|
+
Os widgets podem ser qualquer FlutterWidget:
|
|
296
|
+
Text
|
|
297
|
+
Button
|
|
298
|
+
Row
|
|
299
|
+
Column
|
|
300
|
+
Card
|
|
301
|
+
Container
|
|
302
|
+
etc.
|
|
303
|
+
"""
|
|
304
|
+
|
|
305
|
+
def __init__(
|
|
306
|
+
self,
|
|
307
|
+
running: bool,
|
|
308
|
+
children: list[FlutterWidget],
|
|
309
|
+
*,
|
|
310
|
+
padding: int = 0,
|
|
311
|
+
) -> None:
|
|
312
|
+
super().__init__()
|
|
313
|
+
|
|
314
|
+
self.running = running
|
|
315
|
+
self.children = children
|
|
316
|
+
self.padding = padding
|
|
317
|
+
|
|
318
|
+
def build(self, context: BuildContext) -> FlutterWidget:
|
|
319
|
+
|
|
320
|
+
if self.running:
|
|
321
|
+
return LinearProgress(indeterminate=True)
|
|
322
|
+
|
|
323
|
+
return ScrollView(
|
|
324
|
+
Column(self.children)
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
# ============================================================
|
|
329
|
+
# LIST BUILDER
|
|
330
|
+
# ============================================================
|
|
331
|
+
|
|
332
|
+
class ListBuilder(StatelessWidget, Generic[T]):
|
|
333
|
+
|
|
334
|
+
def __init__(
|
|
335
|
+
self,
|
|
336
|
+
items: list[T],
|
|
337
|
+
item_builder: Callable[[BuildContext, int, T], FlutterWidget]
|
|
338
|
+
) -> None:
|
|
339
|
+
super().__init__()
|
|
340
|
+
self.items: list[T] = items
|
|
341
|
+
self.item_builder: Callable[[BuildContext, int, T], FlutterWidget] = item_builder
|
|
342
|
+
|
|
343
|
+
def build(self, context: BuildContext) -> ListBuilder[T]:
|
|
344
|
+
return self
|
|
345
|
+
|
|
346
|
+
def create_element(self) -> ListBuilderElement:
|
|
347
|
+
return ListBuilderElement(self)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
class ListBuilderElement(Element[ttk.Frame]):
|
|
351
|
+
|
|
352
|
+
def __init__(self, widget: ListBuilder) -> None:
|
|
353
|
+
super().__init__(widget)
|
|
354
|
+
self._child_elements: list[Element] = []
|
|
355
|
+
self._parent_context: BuildContext | None = None
|
|
356
|
+
|
|
357
|
+
def get_widget(self) -> ListBuilder:
|
|
358
|
+
return self.widget
|
|
359
|
+
|
|
360
|
+
def mount(self, context: BuildContext) -> ttk.Frame:
|
|
361
|
+
super().mount(context)
|
|
362
|
+
self._parent_context = context
|
|
363
|
+
|
|
364
|
+
if not context.parent_tk_widget.winfo_exists():
|
|
365
|
+
return None
|
|
366
|
+
|
|
367
|
+
frame = ttk.Frame(context.parent_tk_widget)
|
|
368
|
+
frame.pack(fill="both", expand=True)
|
|
369
|
+
|
|
370
|
+
self._child_elements = []
|
|
371
|
+
for index, item in enumerate(self.get_widget().items):
|
|
372
|
+
widget = self.get_widget().item_builder(context, index, item)
|
|
373
|
+
child_element = widget.create_element()
|
|
374
|
+
child_context = BuildContext(
|
|
375
|
+
app=context.app, parent_widget=frame, parent_context=context
|
|
376
|
+
)
|
|
377
|
+
child_element.mount(child_context)
|
|
378
|
+
self._child_elements.append(child_element)
|
|
379
|
+
|
|
380
|
+
self.tk_widget = frame
|
|
381
|
+
return frame
|
|
382
|
+
|
|
383
|
+
def update(self, new_widget: FlutterWidget) -> None:
|
|
384
|
+
context = self._parent_context
|
|
385
|
+
self.widget = new_widget
|
|
386
|
+
if context is not None and context.parent_tk_widget.winfo_exists():
|
|
387
|
+
self.unmount()
|
|
388
|
+
self.mount(context)
|
|
389
|
+
|
|
390
|
+
def unmount(self) -> None:
|
|
391
|
+
for child_element in self._child_elements:
|
|
392
|
+
child_element.unmount()
|
|
393
|
+
self._child_elements = []
|
|
394
|
+
super().unmount()
|
|
395
|
+
|
|
396
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# progress.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from tkinter import ttk
|
|
4
|
+
|
|
5
|
+
from pyflutter_ui.ui.core import (
|
|
6
|
+
BuildContext, Element, FlutterWidget, StatelessWidget, )
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# ============================================================
|
|
10
|
+
# LINEAR PROGRESS
|
|
11
|
+
# ============================================================
|
|
12
|
+
|
|
13
|
+
class LinearProgress(StatelessWidget):
|
|
14
|
+
|
|
15
|
+
def __init__(self, value: float = 0.0, indeterminate: bool = False) -> None:
|
|
16
|
+
super().__init__()
|
|
17
|
+
self.value = value
|
|
18
|
+
self.indeterminate = indeterminate
|
|
19
|
+
|
|
20
|
+
def build(self, context: BuildContext) -> FlutterWidget:
|
|
21
|
+
return self
|
|
22
|
+
|
|
23
|
+
def create_element(self) -> Element:
|
|
24
|
+
return LinearProgressElement(self)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class LinearProgressElement(Element[ttk.Progressbar]):
|
|
28
|
+
|
|
29
|
+
def __init__(self, widget: LinearProgress) -> None:
|
|
30
|
+
super().__init__(widget)
|
|
31
|
+
|
|
32
|
+
def get_widget_flutter(self) -> LinearProgress:
|
|
33
|
+
return self.widget_flutter
|
|
34
|
+
|
|
35
|
+
def mount(self, context: BuildContext) -> ttk.Progressbar:
|
|
36
|
+
super().mount(context)
|
|
37
|
+
mode = "indeterminate" if self.get_widget_flutter().indeterminate else "determinate"
|
|
38
|
+
progress = ttk.Progressbar(context.parent_tk_widget, mode=mode)
|
|
39
|
+
|
|
40
|
+
if self.get_widget_flutter().indeterminate:
|
|
41
|
+
progress.start(9)
|
|
42
|
+
else:
|
|
43
|
+
progress["value"] = max(0, min(100, self.widget_flutter.value * 100))
|
|
44
|
+
|
|
45
|
+
progress.pack(fill="x", expand=True, padx=1, pady=1)
|
|
46
|
+
self.widget_tk = progress
|
|
47
|
+
return progress
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# ============================================================
|
|
51
|
+
# CIRCULAR PROGRESS
|
|
52
|
+
# ============================================================
|
|
53
|
+
class CircularProgress(StatelessWidget):
|
|
54
|
+
|
|
55
|
+
def __init__(self) -> None:
|
|
56
|
+
super().__init__()
|
|
57
|
+
|
|
58
|
+
def build(self, context: BuildContext) -> FlutterWidget:
|
|
59
|
+
return self
|
|
60
|
+
|
|
61
|
+
def create_element(self) -> Element:
|
|
62
|
+
return CircularProgressElement(self)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class CircularProgressElement(Element[ttk.Progressbar]):
|
|
66
|
+
|
|
67
|
+
def __init__(self, widget: CircularProgress) -> None:
|
|
68
|
+
super().__init__(widget)
|
|
69
|
+
|
|
70
|
+
def get_widget_flutter(self) -> CircularProgress:
|
|
71
|
+
return self.widget_flutter
|
|
72
|
+
|
|
73
|
+
def mount(self, context: BuildContext) -> ttk.Progressbar:
|
|
74
|
+
super().mount(context)
|
|
75
|
+
progress = ttk.Progressbar(context.parent_tk_widget, mode="indeterminate", length=40)
|
|
76
|
+
progress.start()
|
|
77
|
+
progress.pack()
|
|
78
|
+
self.widget_tk = progress
|
|
79
|
+
return progress
|
|
80
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# tables.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from tkinter import ttk
|
|
5
|
+
from typing import Callable, cast
|
|
6
|
+
|
|
7
|
+
from pyflutter_ui.ui.core import (
|
|
8
|
+
BuildContext, Element, FlutterWidget, StatelessWidget,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
# ============================================================
|
|
12
|
+
# TABLEVIEW
|
|
13
|
+
# ============================================================
|
|
14
|
+
|
|
15
|
+
class TableView(StatelessWidget):
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self, *,
|
|
19
|
+
columns: list[str],
|
|
20
|
+
rows: list[list[object]],
|
|
21
|
+
headings: dict[str, str] | None = None,
|
|
22
|
+
on_select: Callable[[list[object]], None] | None = None,
|
|
23
|
+
height: int = 10
|
|
24
|
+
) -> None:
|
|
25
|
+
super().__init__()
|
|
26
|
+
|
|
27
|
+
self.columns = columns
|
|
28
|
+
self.rows = rows
|
|
29
|
+
self.headings = headings or {}
|
|
30
|
+
self.on_select = on_select
|
|
31
|
+
self.height = height
|
|
32
|
+
|
|
33
|
+
def build(self, context: BuildContext) -> TableView:
|
|
34
|
+
return self
|
|
35
|
+
|
|
36
|
+
def create_element(self) -> Element:
|
|
37
|
+
return TreeViewElement(self)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TreeViewElement(Element[ttk.Treeview]):
|
|
41
|
+
|
|
42
|
+
def __init__(self, widget: TableView) -> None:
|
|
43
|
+
super().__init__(widget)
|
|
44
|
+
|
|
45
|
+
def get_widget_flutter(self) -> TableView:
|
|
46
|
+
return self.widget_flutter
|
|
47
|
+
|
|
48
|
+
def update(self, new_widget: FlutterWidget) -> None:
|
|
49
|
+
|
|
50
|
+
self.widget_flutter = cast(TableView, new_widget)
|
|
51
|
+
if self.widget_tk is None:
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
tree = cast(ttk.Treeview, self.widget_tk)
|
|
55
|
+
|
|
56
|
+
for item in tree.get_children():
|
|
57
|
+
tree.delete(item)
|
|
58
|
+
|
|
59
|
+
for row in self.widget_flutter.rows:
|
|
60
|
+
tree.insert("", "end", values=[str(v) for v in row])
|
|
61
|
+
|
|
62
|
+
def mount(self, context: BuildContext) -> ttk.Treeview:
|
|
63
|
+
super().mount(context)
|
|
64
|
+
|
|
65
|
+
frame = ttk.Frame(context.parent_tk_widget)
|
|
66
|
+
frame.pack(fill="both", expand=True)
|
|
67
|
+
|
|
68
|
+
# Scrollbar horizontal — precisa ser criada ANTES do tree.pack
|
|
69
|
+
scrollbar_x = ttk.Scrollbar(frame, orient="horizontal")
|
|
70
|
+
scrollbar_y = ttk.Scrollbar(frame, orient="vertical")
|
|
71
|
+
|
|
72
|
+
tree = ttk.Treeview(
|
|
73
|
+
frame,
|
|
74
|
+
columns=self.get_widget_flutter().columns,
|
|
75
|
+
show="headings",
|
|
76
|
+
height=self.get_widget_flutter().height,
|
|
77
|
+
xscrollcommand=scrollbar_x.set,
|
|
78
|
+
yscrollcommand=scrollbar_y.set,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
scrollbar_x.configure(command=tree.xview)
|
|
82
|
+
scrollbar_y.configure(command=tree.yview)
|
|
83
|
+
|
|
84
|
+
for column in self.get_widget_flutter().columns:
|
|
85
|
+
label = self.get_widget_flutter().headings.get(column, column)
|
|
86
|
+
tree.heading(column, text=label)
|
|
87
|
+
# minwidth garante que haja conteúdo para rolar na horizontal
|
|
88
|
+
tree.column(column, anchor="w", width=120, minwidth=80, stretch=False)
|
|
89
|
+
|
|
90
|
+
for row in self.get_widget_flutter().rows:
|
|
91
|
+
tree.insert("", "end", values=[str(v) for v in row])
|
|
92
|
+
|
|
93
|
+
# Ordem de pack importa: scrollbars nas bordas, tree no centro
|
|
94
|
+
scrollbar_y.pack(side="right", fill="y")
|
|
95
|
+
scrollbar_x.pack(side="bottom", fill="x")
|
|
96
|
+
tree.pack(side="left", fill="both", expand=True)
|
|
97
|
+
|
|
98
|
+
if self.get_widget_flutter().on_select:
|
|
99
|
+
def _on_select(event):
|
|
100
|
+
selection = tree.selection()
|
|
101
|
+
if not selection:
|
|
102
|
+
return
|
|
103
|
+
values = list(tree.item(selection[0], "values"))
|
|
104
|
+
self.get_widget_flutter().on_select(values)
|
|
105
|
+
|
|
106
|
+
tree.bind("<<TreeviewSelect>>", _on_select)
|
|
107
|
+
|
|
108
|
+
self.widget_tk = tree
|
|
109
|
+
return tree
|