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/state.py
ADDED
|
@@ -0,0 +1,711 @@
|
|
|
1
|
+
from .view import *
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
|
|
4
|
+
class StateMutationInViewBuilderError(Exception):
|
|
5
|
+
pass
|
|
6
|
+
|
|
7
|
+
class DummyBinding():
|
|
8
|
+
def __init__(self, value):
|
|
9
|
+
self.value = value
|
|
10
|
+
|
|
11
|
+
class BaseBinding():
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
class AttrBinding(BaseBinding):
|
|
15
|
+
def __init__(self, state, key):
|
|
16
|
+
try:
|
|
17
|
+
self.viewroot = find_puiview()
|
|
18
|
+
self.viewparent = self.viewroot.frames[-1]
|
|
19
|
+
except:
|
|
20
|
+
pass
|
|
21
|
+
self.state = state
|
|
22
|
+
self.key = key
|
|
23
|
+
dt = type(getattr(self.state, self.key))
|
|
24
|
+
if dt is str:
|
|
25
|
+
self.func = str
|
|
26
|
+
elif dt is int:
|
|
27
|
+
self.func = int
|
|
28
|
+
elif dt is float:
|
|
29
|
+
self.func = float
|
|
30
|
+
else:
|
|
31
|
+
self.func = lambda x:x
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def value(self):
|
|
35
|
+
return getattr(self.state, self.key)
|
|
36
|
+
|
|
37
|
+
@value.setter
|
|
38
|
+
def value(self, value):
|
|
39
|
+
try: # skip validation error
|
|
40
|
+
setattr(self.state, self.key, self.func(value))
|
|
41
|
+
except:
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
def change(self, callback):
|
|
45
|
+
getattr(self.state, "_StateObject__callbacks")[self.key].add(callback)
|
|
46
|
+
|
|
47
|
+
def bind(self, getter, setter):
|
|
48
|
+
getattr(self.state, "_StateObject__binders")[self.key] = None
|
|
49
|
+
setattr(getattr(self.state, "_StateObject__values"), self.key, getter())
|
|
50
|
+
getattr(self.state, "_StateObject__binders")[self.key] = (getter, setter)
|
|
51
|
+
|
|
52
|
+
def emit(self):
|
|
53
|
+
listeners = set()
|
|
54
|
+
for l in getattr(self.state, "_StateObject__listeners").values():
|
|
55
|
+
listeners.update(l)
|
|
56
|
+
_notify(getattr(self.state, "_StateObject__pending"), listeners)
|
|
57
|
+
|
|
58
|
+
class ListBinding(BaseBinding):
|
|
59
|
+
def __init__(self, state, key):
|
|
60
|
+
try:
|
|
61
|
+
self.viewroot = find_puiview()
|
|
62
|
+
self.viewparent = self.viewroot.frames[-1]
|
|
63
|
+
except PuiViewNotFoundError:
|
|
64
|
+
pass
|
|
65
|
+
self.state = state
|
|
66
|
+
self.key = key
|
|
67
|
+
dt = type(self.state[self.key])
|
|
68
|
+
if dt is str:
|
|
69
|
+
self.func = str
|
|
70
|
+
elif dt is int:
|
|
71
|
+
self.func = int
|
|
72
|
+
elif dt is float:
|
|
73
|
+
self.func = float
|
|
74
|
+
else:
|
|
75
|
+
self.func = lambda x:x
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def value(self):
|
|
79
|
+
try: # skip validation error
|
|
80
|
+
return self.state[self.key]
|
|
81
|
+
except:
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
@value.setter
|
|
85
|
+
def value(self, value):
|
|
86
|
+
self.state[self.key] = self.func(value)
|
|
87
|
+
|
|
88
|
+
def change(self, callback):
|
|
89
|
+
getattr(self.state, "_StateList__callbacks")[self.key].add(callback)
|
|
90
|
+
|
|
91
|
+
def bind(self, getter, setter):
|
|
92
|
+
getattr(self.state, "_StateList__binders")[self.key] = None
|
|
93
|
+
self.state[self.key] = getter()
|
|
94
|
+
getattr(self.state, "_StateList__binders")[self.key] = (getter, setter)
|
|
95
|
+
|
|
96
|
+
def emit(self):
|
|
97
|
+
_notify(getattr(self.state, "_StateList__pending"), getattr(self.state, "_StateList__listeners"))
|
|
98
|
+
|
|
99
|
+
class DictBinding(BaseBinding):
|
|
100
|
+
def __init__(self, state, key):
|
|
101
|
+
try:
|
|
102
|
+
self.viewroot = find_puiview()
|
|
103
|
+
self.viewparent = self.viewroot.frames[-1]
|
|
104
|
+
except PuiViewNotFoundError:
|
|
105
|
+
pass
|
|
106
|
+
self.state = state
|
|
107
|
+
self.key = key
|
|
108
|
+
dt = type(self.state[self.key])
|
|
109
|
+
if dt is str:
|
|
110
|
+
self.func = str
|
|
111
|
+
elif dt is int:
|
|
112
|
+
self.func = int
|
|
113
|
+
elif dt is float:
|
|
114
|
+
self.func = float
|
|
115
|
+
else:
|
|
116
|
+
self.func = lambda x:x
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def value(self):
|
|
120
|
+
return self.state[self.key]
|
|
121
|
+
|
|
122
|
+
@value.setter
|
|
123
|
+
def value(self, value):
|
|
124
|
+
try: # skip validation error
|
|
125
|
+
self.state[self.key] = self.func(value)
|
|
126
|
+
except:
|
|
127
|
+
pass
|
|
128
|
+
|
|
129
|
+
def change(self, callback):
|
|
130
|
+
getattr(self.state, "_StateDict__callbacks")[self.key].add(callback)
|
|
131
|
+
|
|
132
|
+
def bind(self, getter, setter):
|
|
133
|
+
getattr(self.state, "_StateDict__binders")[self.key] = None
|
|
134
|
+
self.state[self.key] = getter()
|
|
135
|
+
getattr(self.state, "_StateDict__binders")[self.key] = (getter, setter)
|
|
136
|
+
|
|
137
|
+
def emit(self):
|
|
138
|
+
_notify(getattr(self.state, "_StateDict__pending"), getattr(self.state, "_StateDict__listeners"))
|
|
139
|
+
|
|
140
|
+
def _notify(pending, listeners):
|
|
141
|
+
if pending is None:
|
|
142
|
+
tbd = []
|
|
143
|
+
for l in listeners:
|
|
144
|
+
if l.retired_by:
|
|
145
|
+
tbd.append(l)
|
|
146
|
+
for l in tbd:
|
|
147
|
+
listeners.remove(l)
|
|
148
|
+
for l in list(listeners):
|
|
149
|
+
l.redraw()
|
|
150
|
+
else:
|
|
151
|
+
pending.update(listeners)
|
|
152
|
+
|
|
153
|
+
class BaseState():
|
|
154
|
+
pass
|
|
155
|
+
|
|
156
|
+
def State(data=None):
|
|
157
|
+
if data is None:
|
|
158
|
+
return StateObject()
|
|
159
|
+
if isinstance(data, list):
|
|
160
|
+
return StateList(data)
|
|
161
|
+
if isinstance(data, dict):
|
|
162
|
+
return StateDict(data)
|
|
163
|
+
return StateObject(data)
|
|
164
|
+
|
|
165
|
+
class StateObject(BaseState):
|
|
166
|
+
def __init__(self, values=None):
|
|
167
|
+
self.__listeners = defaultdict(set)
|
|
168
|
+
self.__callbacks = defaultdict(set)
|
|
169
|
+
self.__binders = {}
|
|
170
|
+
self.__pending = None
|
|
171
|
+
if values is None:
|
|
172
|
+
self.__values = BaseState()
|
|
173
|
+
else:
|
|
174
|
+
self.__values = values
|
|
175
|
+
|
|
176
|
+
def __call__(self, key=None):
|
|
177
|
+
if key is None:
|
|
178
|
+
listeners = set()
|
|
179
|
+
for l in self.__listeners.values():
|
|
180
|
+
listeners.update(l)
|
|
181
|
+
_notify(self.__pending, listeners)
|
|
182
|
+
return
|
|
183
|
+
try:
|
|
184
|
+
view = find_puiview()
|
|
185
|
+
self.__listeners[key].add(view)
|
|
186
|
+
except PuiViewNotFoundError:
|
|
187
|
+
pass
|
|
188
|
+
return AttrBinding(self, key)
|
|
189
|
+
|
|
190
|
+
def __enter__(self):
|
|
191
|
+
self.__pending = set()
|
|
192
|
+
return self
|
|
193
|
+
|
|
194
|
+
def __exit__(self, ex_type, value, traceback):
|
|
195
|
+
pending = self.__pending
|
|
196
|
+
self.__pending = None
|
|
197
|
+
_notify(self.__pending, pending)
|
|
198
|
+
|
|
199
|
+
if ex_type is None: # don't consume exception
|
|
200
|
+
return self
|
|
201
|
+
|
|
202
|
+
def __eq__(self, other):
|
|
203
|
+
return self.__values == other
|
|
204
|
+
|
|
205
|
+
# getter
|
|
206
|
+
def __getattr__(self, key):
|
|
207
|
+
if not key.startswith("_"):
|
|
208
|
+
try:
|
|
209
|
+
view = find_puiview()
|
|
210
|
+
self.__listeners[key].add(view)
|
|
211
|
+
except PuiViewNotFoundError:
|
|
212
|
+
view = None
|
|
213
|
+
ret = getattr(self.__values, key)
|
|
214
|
+
if view:
|
|
215
|
+
if isinstance(ret, StateObject):
|
|
216
|
+
ret.__listeners[key].add(view)
|
|
217
|
+
elif isinstance(ret, StateList):
|
|
218
|
+
ret._StateList__listeners.add(view)
|
|
219
|
+
elif isinstance(ret, StateDict):
|
|
220
|
+
ret._StateDict__listeners.add(view)
|
|
221
|
+
return ret
|
|
222
|
+
|
|
223
|
+
# setter
|
|
224
|
+
def __setattr__(self, key, value):
|
|
225
|
+
try:
|
|
226
|
+
find_puiview()
|
|
227
|
+
raise StateMutationInViewBuilderError()
|
|
228
|
+
except PuiViewNotFoundError:
|
|
229
|
+
pass
|
|
230
|
+
if key.startswith("_"):
|
|
231
|
+
object.__setattr__(self, key, value)
|
|
232
|
+
else:
|
|
233
|
+
if self.__binders.get(key):
|
|
234
|
+
self.__binders[key][1](value)
|
|
235
|
+
|
|
236
|
+
if isinstance(value, list):
|
|
237
|
+
value = StateList(value)
|
|
238
|
+
elif isinstance(value, dict):
|
|
239
|
+
value = StateDict(value)
|
|
240
|
+
if not hasattr(self.__values, key) or getattr(self.__values, key) != value:
|
|
241
|
+
setattr(self.__values, key, value)
|
|
242
|
+
_notify(self.__pending, self.__listeners[key])
|
|
243
|
+
for cb in self.__callbacks[key]:
|
|
244
|
+
cb(value)
|
|
245
|
+
|
|
246
|
+
# getter
|
|
247
|
+
def __repr__(self):
|
|
248
|
+
return f"StateObject({self.__values.__repr__()})"
|
|
249
|
+
|
|
250
|
+
class StateList(BaseState):
|
|
251
|
+
def __init__(self, values=None):
|
|
252
|
+
self.__listeners = set()
|
|
253
|
+
self.__callbacks = defaultdict(set)
|
|
254
|
+
self.__binders = {}
|
|
255
|
+
self.__pending = None
|
|
256
|
+
if values is None:
|
|
257
|
+
self.__values = []
|
|
258
|
+
else:
|
|
259
|
+
self.__values = values
|
|
260
|
+
|
|
261
|
+
def __call__(self, key=None):
|
|
262
|
+
if key is None:
|
|
263
|
+
_notify(self.__pending, self.__listeners)
|
|
264
|
+
return
|
|
265
|
+
try:
|
|
266
|
+
view = find_puiview()
|
|
267
|
+
self.__listeners.add(view)
|
|
268
|
+
except PuiViewNotFoundError:
|
|
269
|
+
pass
|
|
270
|
+
return ListBinding(self, key)
|
|
271
|
+
|
|
272
|
+
def __enter__(self):
|
|
273
|
+
self.__pending = set()
|
|
274
|
+
return self
|
|
275
|
+
|
|
276
|
+
def __exit__(self, ex_type, value, traceback):
|
|
277
|
+
pending = self.__pending
|
|
278
|
+
self.__pending = None
|
|
279
|
+
_notify(self.__pending, pending)
|
|
280
|
+
|
|
281
|
+
if ex_type is None: # don't consume exception
|
|
282
|
+
return self
|
|
283
|
+
|
|
284
|
+
def __eq__(self, other):
|
|
285
|
+
return self.__values == other
|
|
286
|
+
|
|
287
|
+
# getter
|
|
288
|
+
def __getitem__(self, key):
|
|
289
|
+
try:
|
|
290
|
+
view = find_puiview()
|
|
291
|
+
self.__listeners.add(view)
|
|
292
|
+
except PuiViewNotFoundError:
|
|
293
|
+
view = None
|
|
294
|
+
|
|
295
|
+
ret = self.__values[key]
|
|
296
|
+
if view:
|
|
297
|
+
if isinstance(ret, StateObject):
|
|
298
|
+
ret._StateObject__listeners.add(view)
|
|
299
|
+
elif isinstance(ret, StateList):
|
|
300
|
+
ret.__listeners.add(view)
|
|
301
|
+
elif isinstance(ret, StateDict):
|
|
302
|
+
ret._StateDict__listeners.add(view)
|
|
303
|
+
return ret
|
|
304
|
+
|
|
305
|
+
# setter
|
|
306
|
+
def __setitem__(self, key, value):
|
|
307
|
+
try:
|
|
308
|
+
find_puiview()
|
|
309
|
+
raise StateMutationInViewBuilderError()
|
|
310
|
+
except PuiViewNotFoundError:
|
|
311
|
+
pass
|
|
312
|
+
if self.__binders.get(key):
|
|
313
|
+
self.__binders[key][1](value)
|
|
314
|
+
new = key >= len(self.__values)
|
|
315
|
+
if new or self.__values[key] != value:
|
|
316
|
+
self.__values[key] = value
|
|
317
|
+
_notify(self.__pending, self.__listeners)
|
|
318
|
+
for cb in self.__callbacks[key]:
|
|
319
|
+
cb(value)
|
|
320
|
+
if new:
|
|
321
|
+
for cb in self.__callbacks[None]:
|
|
322
|
+
cb(value)
|
|
323
|
+
|
|
324
|
+
# getter
|
|
325
|
+
def __bool__(self):
|
|
326
|
+
try:
|
|
327
|
+
view = find_puiview()
|
|
328
|
+
self.__listeners.add(view)
|
|
329
|
+
except PuiViewNotFoundError:
|
|
330
|
+
pass
|
|
331
|
+
return bool(self.__values)
|
|
332
|
+
|
|
333
|
+
# getter
|
|
334
|
+
def __len__(self):
|
|
335
|
+
try:
|
|
336
|
+
view = find_puiview()
|
|
337
|
+
self.__listeners.add(view)
|
|
338
|
+
except PuiViewNotFoundError:
|
|
339
|
+
pass
|
|
340
|
+
return len(self.__values)
|
|
341
|
+
|
|
342
|
+
# getter
|
|
343
|
+
def __iter__(self):
|
|
344
|
+
try:
|
|
345
|
+
view = find_puiview()
|
|
346
|
+
self.__listeners.add(view)
|
|
347
|
+
except PuiViewNotFoundError:
|
|
348
|
+
pass
|
|
349
|
+
return self.__values.__iter__()
|
|
350
|
+
|
|
351
|
+
# getter
|
|
352
|
+
def __repr__(self):
|
|
353
|
+
try:
|
|
354
|
+
view = find_puiview()
|
|
355
|
+
self.__listeners.add(view)
|
|
356
|
+
except PuiViewNotFoundError:
|
|
357
|
+
pass
|
|
358
|
+
return self.__values.__repr__()
|
|
359
|
+
|
|
360
|
+
# setter
|
|
361
|
+
def append(self, obj):
|
|
362
|
+
try:
|
|
363
|
+
find_puiview()
|
|
364
|
+
raise StateMutationInViewBuilderError()
|
|
365
|
+
except PuiViewNotFoundError:
|
|
366
|
+
pass
|
|
367
|
+
self.__values.append(obj)
|
|
368
|
+
_notify(self.__pending, self.__listeners)
|
|
369
|
+
for cb in self.__callbacks[None]:
|
|
370
|
+
cb(self.__values)
|
|
371
|
+
|
|
372
|
+
# setter
|
|
373
|
+
def clear(self):
|
|
374
|
+
try:
|
|
375
|
+
find_puiview()
|
|
376
|
+
raise StateMutationInViewBuilderError()
|
|
377
|
+
except PuiViewNotFoundError:
|
|
378
|
+
pass
|
|
379
|
+
self.__values.clear()
|
|
380
|
+
_notify(self.__pending, self.__listeners)
|
|
381
|
+
for cb in self.__callbacks[None]:
|
|
382
|
+
cb(self.__values)
|
|
383
|
+
|
|
384
|
+
# getter
|
|
385
|
+
def count(self, value):
|
|
386
|
+
try:
|
|
387
|
+
view = find_puiview()
|
|
388
|
+
self.__listeners.add(view)
|
|
389
|
+
except PuiViewNotFoundError:
|
|
390
|
+
pass
|
|
391
|
+
return self.__values.count(value)
|
|
392
|
+
|
|
393
|
+
# setter
|
|
394
|
+
def extend(self, iterable):
|
|
395
|
+
try:
|
|
396
|
+
find_puiview()
|
|
397
|
+
raise StateMutationInViewBuilderError()
|
|
398
|
+
except PuiViewNotFoundError:
|
|
399
|
+
pass
|
|
400
|
+
self.__values.extend(iterable)
|
|
401
|
+
_notify(self.__pending, self.__listeners)
|
|
402
|
+
for cb in self.__callbacks[None]:
|
|
403
|
+
cb(self.__values)
|
|
404
|
+
|
|
405
|
+
# getter
|
|
406
|
+
def index(self, value, *args, **kwargs):
|
|
407
|
+
try:
|
|
408
|
+
view = find_puiview()
|
|
409
|
+
self.__listeners.add(view)
|
|
410
|
+
except PuiViewNotFoundError:
|
|
411
|
+
pass
|
|
412
|
+
return self.__values.index(value, *args, **kwargs)
|
|
413
|
+
|
|
414
|
+
# setter
|
|
415
|
+
def insert(self, index, object):
|
|
416
|
+
try:
|
|
417
|
+
find_puiview()
|
|
418
|
+
raise StateMutationInViewBuilderError()
|
|
419
|
+
except PuiViewNotFoundError:
|
|
420
|
+
pass
|
|
421
|
+
self.__values.insert(index, object)
|
|
422
|
+
_notify(self.__pending, self.__listeners)
|
|
423
|
+
for cb in self.__callbacks[index]:
|
|
424
|
+
cb(object)
|
|
425
|
+
for cb in self.__callbacks[None]:
|
|
426
|
+
cb(self.__values)
|
|
427
|
+
|
|
428
|
+
# getter/setter
|
|
429
|
+
def pop(self, index=-1):
|
|
430
|
+
try:
|
|
431
|
+
find_puiview()
|
|
432
|
+
raise StateMutationInViewBuilderError()
|
|
433
|
+
except PuiViewNotFoundError:
|
|
434
|
+
pass
|
|
435
|
+
r = self.__values.pop(index)
|
|
436
|
+
_notify(self.__pending, self.__listeners)
|
|
437
|
+
for cb in self.__callbacks[index]:
|
|
438
|
+
cb(self.__values)
|
|
439
|
+
for cb in self.__callbacks[None]:
|
|
440
|
+
cb(self.__values)
|
|
441
|
+
return r
|
|
442
|
+
|
|
443
|
+
# setter
|
|
444
|
+
def remove(self, value):
|
|
445
|
+
try:
|
|
446
|
+
find_puiview()
|
|
447
|
+
raise StateMutationInViewBuilderError()
|
|
448
|
+
except PuiViewNotFoundError:
|
|
449
|
+
pass
|
|
450
|
+
self.__values.remove(value)
|
|
451
|
+
_notify(self.__pending, self.__listeners)
|
|
452
|
+
for cb in self.__callbacks[None]:
|
|
453
|
+
cb(self.__values)
|
|
454
|
+
|
|
455
|
+
# setter
|
|
456
|
+
def reverse(self, value):
|
|
457
|
+
try:
|
|
458
|
+
find_puiview()
|
|
459
|
+
raise StateMutationInViewBuilderError()
|
|
460
|
+
except PuiViewNotFoundError:
|
|
461
|
+
pass
|
|
462
|
+
self.__values.reverse(value)
|
|
463
|
+
_notify(self.__pending, self.__listeners)
|
|
464
|
+
for cb in self.__callbacks[None]:
|
|
465
|
+
cb(self.__values)
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
# setter
|
|
469
|
+
def sort(self, *args, **kwargs):
|
|
470
|
+
try:
|
|
471
|
+
find_puiview()
|
|
472
|
+
raise StateMutationInViewBuilderError()
|
|
473
|
+
except PuiViewNotFoundError:
|
|
474
|
+
pass
|
|
475
|
+
self.__values.sort(*args, **kwargs)
|
|
476
|
+
_notify(self.__pending, self.__listeners)
|
|
477
|
+
for cb in self.__callbacks[None]:
|
|
478
|
+
cb(self.__values)
|
|
479
|
+
|
|
480
|
+
# getter
|
|
481
|
+
def get(self, index, default=None):
|
|
482
|
+
try:
|
|
483
|
+
view = find_puiview()
|
|
484
|
+
self.__listeners.add(view)
|
|
485
|
+
except PuiViewNotFoundError:
|
|
486
|
+
pass
|
|
487
|
+
if index >= 0 and index < len(self.__values):
|
|
488
|
+
return self.__values[index]
|
|
489
|
+
else:
|
|
490
|
+
return default
|
|
491
|
+
|
|
492
|
+
# getter
|
|
493
|
+
def range(self):
|
|
494
|
+
return range(len(self.__values))
|
|
495
|
+
|
|
496
|
+
class StateDict(BaseState):
|
|
497
|
+
def __init__(self, values=None):
|
|
498
|
+
self.__listeners = set()
|
|
499
|
+
self.__callbacks = defaultdict(set)
|
|
500
|
+
self.__binders = {}
|
|
501
|
+
self.__pending = None
|
|
502
|
+
if values is None:
|
|
503
|
+
self.__values = {}
|
|
504
|
+
else:
|
|
505
|
+
self.__values = values
|
|
506
|
+
|
|
507
|
+
def __call__(self, key=None):
|
|
508
|
+
if key is None:
|
|
509
|
+
_notify(self.__pending, self.__listeners)
|
|
510
|
+
return
|
|
511
|
+
try:
|
|
512
|
+
view = find_puiview()
|
|
513
|
+
self.__listeners.add(view)
|
|
514
|
+
except PuiViewNotFoundError:
|
|
515
|
+
pass
|
|
516
|
+
return DictBinding(self, key)
|
|
517
|
+
|
|
518
|
+
def __enter__(self):
|
|
519
|
+
self.__pending = set()
|
|
520
|
+
return self
|
|
521
|
+
|
|
522
|
+
def __exit__(self, ex_type, value, traceback):
|
|
523
|
+
pending = self.__pending
|
|
524
|
+
self.__pending = None
|
|
525
|
+
_notify(self.__pending, pending)
|
|
526
|
+
|
|
527
|
+
if ex_type is None: # don't consume exception
|
|
528
|
+
return self
|
|
529
|
+
|
|
530
|
+
def __eq__(self, other):
|
|
531
|
+
return self.__values == other
|
|
532
|
+
|
|
533
|
+
# setter
|
|
534
|
+
def __delitem__(self, key):
|
|
535
|
+
try:
|
|
536
|
+
find_puiview()
|
|
537
|
+
raise StateMutationInViewBuilderError()
|
|
538
|
+
except PuiViewNotFoundError:
|
|
539
|
+
pass
|
|
540
|
+
self.__values.__delitem__(key)
|
|
541
|
+
_notify(self.__pending, self.__listeners)
|
|
542
|
+
for cb in self.__callbacks[None]:
|
|
543
|
+
cb(self.__values)
|
|
544
|
+
|
|
545
|
+
# getter
|
|
546
|
+
def __getitem__(self, key):
|
|
547
|
+
try:
|
|
548
|
+
view = find_puiview()
|
|
549
|
+
self.__listeners.add(view)
|
|
550
|
+
except PuiViewNotFoundError:
|
|
551
|
+
view = None
|
|
552
|
+
ret = self.__values[key]
|
|
553
|
+
if view:
|
|
554
|
+
if isinstance(ret, StateObject):
|
|
555
|
+
ret._StateObject__listeners.add(view)
|
|
556
|
+
elif isinstance(ret, StateList):
|
|
557
|
+
ret._StateList__listeners.add(view)
|
|
558
|
+
elif isinstance(ret, StateDict):
|
|
559
|
+
ret.__listeners.add(view)
|
|
560
|
+
return ret
|
|
561
|
+
|
|
562
|
+
# getter
|
|
563
|
+
def __getattr__(self, key):
|
|
564
|
+
if not key.startswith("_"):
|
|
565
|
+
try:
|
|
566
|
+
view = find_puiview()
|
|
567
|
+
self.__listeners.add(view)
|
|
568
|
+
except PuiViewNotFoundError:
|
|
569
|
+
view = None
|
|
570
|
+
ret = getattr(self.__values, key)
|
|
571
|
+
if view:
|
|
572
|
+
if isinstance(ret, StateObject):
|
|
573
|
+
ret._StateObject__listeners.add(view)
|
|
574
|
+
elif isinstance(ret, StateList):
|
|
575
|
+
ret._StateList__listeners.add(view)
|
|
576
|
+
elif isinstance(ret, StateDict):
|
|
577
|
+
ret.__listeners.add(view)
|
|
578
|
+
return ret
|
|
579
|
+
|
|
580
|
+
# setter
|
|
581
|
+
def __setattr__(self, key, value):
|
|
582
|
+
try:
|
|
583
|
+
find_puiview()
|
|
584
|
+
raise StateMutationInViewBuilderError()
|
|
585
|
+
except PuiViewNotFoundError:
|
|
586
|
+
pass
|
|
587
|
+
if key.startswith("_"):
|
|
588
|
+
object.__setattr__(self, key, value)
|
|
589
|
+
else:
|
|
590
|
+
if self.__binders.get(key):
|
|
591
|
+
self.__binders[key][1](value)
|
|
592
|
+
_notify(self.__pending, self.__listeners)
|
|
593
|
+
return setattr(self.__values, key, value)
|
|
594
|
+
|
|
595
|
+
# getter
|
|
596
|
+
def __bool__(self):
|
|
597
|
+
try:
|
|
598
|
+
view = find_puiview()
|
|
599
|
+
self.__listeners.add(view)
|
|
600
|
+
except PuiViewNotFoundError:
|
|
601
|
+
pass
|
|
602
|
+
return bool(self.__values)
|
|
603
|
+
|
|
604
|
+
# getter
|
|
605
|
+
def __iter__(self):
|
|
606
|
+
try:
|
|
607
|
+
view = find_puiview()
|
|
608
|
+
self.__listeners.add(view)
|
|
609
|
+
except PuiViewNotFoundError:
|
|
610
|
+
pass
|
|
611
|
+
return self.__values.__iter__()
|
|
612
|
+
|
|
613
|
+
# getter
|
|
614
|
+
def __repr__(self):
|
|
615
|
+
try:
|
|
616
|
+
view = find_puiview()
|
|
617
|
+
self.__listeners.add(view)
|
|
618
|
+
except PuiViewNotFoundError:
|
|
619
|
+
pass
|
|
620
|
+
return self.__values.__repr__()
|
|
621
|
+
|
|
622
|
+
# setter
|
|
623
|
+
def __setitem__(self, key, value):
|
|
624
|
+
try:
|
|
625
|
+
find_puiview()
|
|
626
|
+
raise StateMutationInViewBuilderError()
|
|
627
|
+
except PuiViewNotFoundError:
|
|
628
|
+
pass
|
|
629
|
+
if self.__binders.get(key):
|
|
630
|
+
self.__binders[key][1](value)
|
|
631
|
+
if not key in self.__values or self.__values[key] != value:
|
|
632
|
+
self.__values[key] = value
|
|
633
|
+
_notify(self.__pending, self.__listeners)
|
|
634
|
+
for cb in self.__callbacks[key]:
|
|
635
|
+
cb(value)
|
|
636
|
+
for cb in self.__callbacks[None]:
|
|
637
|
+
cb(self.__values)
|
|
638
|
+
|
|
639
|
+
# setter
|
|
640
|
+
def clear(self):
|
|
641
|
+
try:
|
|
642
|
+
find_puiview()
|
|
643
|
+
raise StateMutationInViewBuilderError()
|
|
644
|
+
except PuiViewNotFoundError:
|
|
645
|
+
pass
|
|
646
|
+
self.__values.clear()
|
|
647
|
+
_notify(self.__pending, self.__listeners)
|
|
648
|
+
for cb in self.__callbacks[None]:
|
|
649
|
+
cb(self.__values)
|
|
650
|
+
|
|
651
|
+
# getter
|
|
652
|
+
def get(self, key, default=None):
|
|
653
|
+
try:
|
|
654
|
+
view = find_puiview()
|
|
655
|
+
self.__listeners.add(view)
|
|
656
|
+
except PuiViewNotFoundError:
|
|
657
|
+
pass
|
|
658
|
+
return self.__values.get(key, default)
|
|
659
|
+
|
|
660
|
+
# getter
|
|
661
|
+
def items(self):
|
|
662
|
+
try:
|
|
663
|
+
view = find_puiview()
|
|
664
|
+
self.__listeners.add(view)
|
|
665
|
+
except PuiViewNotFoundError:
|
|
666
|
+
pass
|
|
667
|
+
return self.__values.items()
|
|
668
|
+
|
|
669
|
+
# getter
|
|
670
|
+
def keys(self):
|
|
671
|
+
try:
|
|
672
|
+
view = find_puiview()
|
|
673
|
+
self.__listeners.add(view)
|
|
674
|
+
except PuiViewNotFoundError:
|
|
675
|
+
pass
|
|
676
|
+
return self.__values.keys()
|
|
677
|
+
|
|
678
|
+
# getter/setter
|
|
679
|
+
def pop(self, key, default=None):
|
|
680
|
+
try:
|
|
681
|
+
find_puiview()
|
|
682
|
+
raise StateMutationInViewBuilderError()
|
|
683
|
+
except PuiViewNotFoundError:
|
|
684
|
+
pass
|
|
685
|
+
r = self.__values.pop(key, default)
|
|
686
|
+
_notify(self.__pending, self.__listeners)
|
|
687
|
+
for cb in self.__callbacks[None]:
|
|
688
|
+
cb(self.__values)
|
|
689
|
+
return r
|
|
690
|
+
|
|
691
|
+
# setter
|
|
692
|
+
def setdefault(self, key, default=None):
|
|
693
|
+
try:
|
|
694
|
+
find_puiview()
|
|
695
|
+
raise StateMutationInViewBuilderError()
|
|
696
|
+
except PuiViewNotFoundError:
|
|
697
|
+
pass
|
|
698
|
+
r = self.__values.setdefault(key, default)
|
|
699
|
+
_notify(self.__pending, self.__listeners)
|
|
700
|
+
for cb in self.__callbacks[None]:
|
|
701
|
+
cb(self.__values)
|
|
702
|
+
return r
|
|
703
|
+
|
|
704
|
+
# getter
|
|
705
|
+
def values(self):
|
|
706
|
+
try:
|
|
707
|
+
view = find_puiview()
|
|
708
|
+
self.__listeners.add(view)
|
|
709
|
+
except PuiViewNotFoundError:
|
|
710
|
+
pass
|
|
711
|
+
return self.__values.values()
|