batframework 1.0.8a2__py3-none-any.whl → 1.0.8a3__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.
- batFramework/__init__.py +53 -50
- batFramework/action.py +126 -99
- batFramework/actionContainer.py +53 -9
- batFramework/animatedSprite.py +115 -65
- batFramework/audioManager.py +69 -26
- batFramework/camera.py +259 -69
- batFramework/constants.py +16 -54
- batFramework/cutscene.py +36 -29
- batFramework/cutsceneBlocks.py +37 -42
- batFramework/dynamicEntity.py +9 -7
- batFramework/easingController.py +58 -0
- batFramework/entity.py +48 -97
- batFramework/enums.py +113 -0
- batFramework/fontManager.py +65 -0
- batFramework/gui/__init__.py +10 -2
- batFramework/gui/button.py +9 -78
- batFramework/gui/clickableWidget.py +219 -0
- batFramework/gui/constraints/__init__.py +1 -0
- batFramework/gui/constraints/constraints.py +590 -0
- batFramework/gui/container.py +174 -32
- batFramework/gui/debugger.py +131 -43
- batFramework/gui/dialogueBox.py +99 -0
- batFramework/gui/draggableWidget.py +40 -0
- batFramework/gui/image.py +54 -18
- batFramework/gui/indicator.py +38 -21
- batFramework/gui/interactiveWidget.py +177 -13
- batFramework/gui/label.py +288 -74
- batFramework/gui/layout.py +219 -60
- batFramework/gui/meter.py +71 -0
- batFramework/gui/radioButton.py +84 -0
- batFramework/gui/root.py +128 -38
- batFramework/gui/shape.py +253 -57
- batFramework/gui/slider.py +246 -0
- batFramework/gui/style.py +10 -0
- batFramework/gui/styleManager.py +48 -0
- batFramework/gui/textInput.py +137 -0
- batFramework/gui/toggle.py +115 -51
- batFramework/gui/widget.py +329 -254
- batFramework/manager.py +40 -19
- batFramework/object.py +114 -0
- batFramework/particle.py +101 -0
- batFramework/renderGroup.py +67 -0
- batFramework/resourceManager.py +84 -0
- batFramework/scene.py +242 -114
- batFramework/sceneManager.py +145 -107
- batFramework/scrollingSprite.py +115 -0
- batFramework/sprite.py +51 -0
- batFramework/stateMachine.py +2 -2
- batFramework/tileset.py +46 -0
- batFramework/time.py +117 -57
- batFramework/transition.py +184 -126
- batFramework/utils.py +31 -156
- batframework-1.0.8a3.dist-info/LICENCE +21 -0
- batframework-1.0.8a3.dist-info/METADATA +55 -0
- batframework-1.0.8a3.dist-info/RECORD +58 -0
- batFramework/debugger.py +0 -48
- batFramework/easing.py +0 -71
- batFramework/gui/constraints.py +0 -204
- batFramework/gui/frame.py +0 -19
- batFramework/particles.py +0 -77
- batFramework/transitionManager.py +0 -0
- batframework-1.0.8a2.dist-info/METADATA +0 -58
- batframework-1.0.8a2.dist-info/RECORD +0 -42
- {batframework-1.0.8a2.dist-info → batframework-1.0.8a3.dist-info}/WHEEL +0 -0
- {batframework-1.0.8a2.dist-info → batframework-1.0.8a3.dist-info}/top_level.txt +0 -0
batFramework/gui/widget.py
CHANGED
@@ -1,307 +1,382 @@
|
|
1
|
-
from
|
2
|
-
from
|
3
|
-
if TYPE_CHECKING:
|
4
|
-
from .constraints import Constraint
|
5
|
-
from .root import Root
|
6
|
-
from typing import Self
|
7
|
-
|
1
|
+
from typing import TYPE_CHECKING, Self, Callable
|
2
|
+
from collections.abc import Iterable
|
8
3
|
import batFramework as bf
|
9
4
|
import pygame
|
10
|
-
from math import ceil
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
class Widget(bf.Entity):
|
15
|
-
def __init__(self,convert_alpha=True)->None:
|
16
|
-
super().__init__(convert_alpha=convert_alpha)
|
17
|
-
self.autoresize = False
|
18
|
-
self.parent : None|Self = None
|
19
|
-
self.is_root :bool = False
|
20
|
-
self.children : list["Widget"] = []
|
21
|
-
self.focusable :bool= False
|
22
|
-
self.constraints : list[Constraint] = []
|
23
|
-
self.gui_depth : int = 0
|
24
|
-
if self.surface : self.surface.fill("white")
|
25
|
-
self.set_debug_color("red")
|
26
|
-
self.padding :tuple[float|int,...]= (0,0,0,0)
|
27
|
-
|
28
|
-
def set_padding(self,value : float|int|tuple|list)->Self:
|
29
|
-
old_raw_size = (
|
30
|
-
self.rect.w - self.padding[0] - self.padding[2],
|
31
|
-
self.rect.h - self.padding[1] - self.padding[3]
|
32
|
-
)
|
33
|
-
if isinstance(value,list) or isinstance(value,tuple):
|
34
|
-
if len(value) > 4 : return self
|
35
|
-
if any(v<0 for v in value) : return self
|
36
|
-
if len(value) == 2:
|
37
|
-
self.padding = (value[0],value[1],value[0],value[1])
|
38
|
-
else:
|
39
|
-
self.padding = (*value, *self.padding[len(value):])
|
40
|
-
else:
|
41
|
-
self.padding = (value,)*4
|
42
5
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
6
|
+
if TYPE_CHECKING:
|
7
|
+
from .constraints.constraints import Constraint
|
8
|
+
from .root import Root
|
9
|
+
MAX_CONSTRAINTS = 10
|
10
|
+
|
11
|
+
|
12
|
+
class WidgetMeta(type):
|
13
|
+
def __call__(cls, *args, **kwargs):
|
14
|
+
"""Called when you call MyNewClass()"""
|
15
|
+
obj = type.__call__(cls, *args, **kwargs)
|
16
|
+
# obj.new_init()
|
17
|
+
bf.StyleManager().register_widget(obj)
|
18
|
+
return obj
|
19
|
+
|
20
|
+
|
21
|
+
class Widget(bf.Entity, metaclass=WidgetMeta):
|
22
|
+
def __init__(self, *args, **kwargs) -> None:
|
23
|
+
super().__init__(*args, **kwargs)
|
24
|
+
self.children: list["Widget"] = []
|
25
|
+
self.constraints: list[Constraint] = []
|
26
|
+
self.parent: "Widget" = None
|
27
|
+
self.do_sort_children = False
|
28
|
+
self.clip_children: bool = True
|
29
|
+
self.padding = (0, 0, 0, 0)
|
30
|
+
self.dirty_surface: bool = True # if true will call paint before drawing
|
31
|
+
self.dirty_shape: bool = (
|
32
|
+
True # if true will call (build+paint) before drawing
|
55
33
|
)
|
56
|
-
|
57
|
-
|
34
|
+
self.dirty_constraints: bool = False
|
35
|
+
self.is_root: bool = False
|
36
|
+
self.autoresize_w, self.autoresize_h = True, True
|
37
|
+
self.__constraint_iteration = 0
|
58
38
|
|
59
|
-
def
|
60
|
-
|
39
|
+
def show(self) -> Self:
|
40
|
+
self.visit(lambda w: w.set_visible(True))
|
41
|
+
return self
|
61
42
|
|
62
|
-
def
|
63
|
-
|
43
|
+
def hide(self) -> Self:
|
44
|
+
self.visit(lambda w: w.set_visible(False))
|
45
|
+
return self
|
64
46
|
|
65
|
-
def
|
66
|
-
|
47
|
+
def set_clip_children(self, value: bool) -> Self:
|
48
|
+
self.clip_children = value
|
49
|
+
self.dirty_surface = True
|
50
|
+
return self
|
67
51
|
|
68
|
-
def
|
69
|
-
return
|
52
|
+
def __str__(self) -> str:
|
53
|
+
return "Widget"
|
70
54
|
|
71
|
-
def
|
72
|
-
|
55
|
+
def set_autoresize(self, value: bool) -> Self:
|
56
|
+
self.autoresize_w = self.autoresize_h = value
|
57
|
+
self.dirty_shape = True
|
58
|
+
return self
|
73
59
|
|
74
|
-
def
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
self.get_content_width(),
|
79
|
-
self.get_content_height()
|
80
|
-
)
|
60
|
+
def set_autoresize_w(self, value: bool) -> Self:
|
61
|
+
self.autoresize_w = value
|
62
|
+
self.dirty_shape = True
|
63
|
+
return self
|
81
64
|
|
82
|
-
def
|
83
|
-
|
65
|
+
def set_autoresize_h(self, value: bool) -> Self:
|
66
|
+
self.autoresize_h = value
|
67
|
+
self.dirty_shape = True
|
68
|
+
return self
|
84
69
|
|
85
|
-
def
|
86
|
-
|
70
|
+
def set_render_order(self, render_order: int) -> Self:
|
71
|
+
super().set_render_order(render_order)
|
72
|
+
if self.parent:
|
73
|
+
self.parent.do_sort_children = True
|
74
|
+
return self
|
87
75
|
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
76
|
+
def inflate_rect_by_padding(
|
77
|
+
self, rect: pygame.Rect | pygame.FRect
|
78
|
+
) -> pygame.Rect | pygame.FRect:
|
79
|
+
return pygame.FRect(
|
80
|
+
rect[0] - self.padding[0],
|
81
|
+
rect[1] - self.padding[1],
|
82
|
+
rect[2] + self.padding[0] + self.padding[2],
|
83
|
+
rect[3] + self.padding[1] + self.padding[3],
|
84
|
+
)
|
94
85
|
|
95
|
-
def
|
96
|
-
if
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
if self.rect.collidepoint(x,y) and self.visible:
|
86
|
+
def set_position(self, x, y) -> Self:
|
87
|
+
if x is None:
|
88
|
+
x = self.rect.x
|
89
|
+
if y is None:
|
90
|
+
y = self.rect.y
|
91
|
+
if (x, y) == self.rect.topleft:
|
102
92
|
return self
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
return next((c for c in self.constraints if c.name == name), None)
|
107
|
-
|
108
|
-
def add_constraints(self,*constraints:Constraint)->Self:
|
109
|
-
for c in constraints:
|
110
|
-
self.add_constraint(c,False)
|
111
|
-
self.apply_constraints()
|
93
|
+
dx, dy = x - self.rect.x, y - self.rect.y
|
94
|
+
self.rect.topleft = x, y
|
95
|
+
_ = [c.set_position(c.rect.x + dx, c.rect.y + dy) for c in self.children]
|
112
96
|
return self
|
113
|
-
|
114
|
-
def
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
self.
|
97
|
+
|
98
|
+
def set_center(self, x, y) -> Self:
|
99
|
+
if x is None:
|
100
|
+
x = self.rect.centerx
|
101
|
+
if y is None:
|
102
|
+
y = self.rect.centery
|
103
|
+
if (x, y) == self.rect.center:
|
104
|
+
return self
|
105
|
+
dx, dy = x - self.rect.centerx, y - self.rect.centery
|
106
|
+
self.rect.center = x, y
|
107
|
+
_ = [
|
108
|
+
c.set_center(c.rect.centerx + dx, c.rect.centery + dy)
|
109
|
+
for c in self.children
|
110
|
+
]
|
120
111
|
return self
|
121
112
|
|
122
|
-
def
|
123
|
-
|
113
|
+
def set_parent_scene(self, parent_scene: bf.Scene) -> Self:
|
114
|
+
super().set_parent_scene(parent_scene)
|
115
|
+
if parent_scene is None:
|
116
|
+
bf.StyleManager().remove_widget(self)
|
124
117
|
|
125
|
-
|
126
|
-
|
127
|
-
self
|
128
|
-
for child in self.children : child.apply_all_constraints()
|
129
|
-
|
130
|
-
def apply_constraints(self, max_iterations: int = 10) -> None:
|
131
|
-
if not self.parent:
|
132
|
-
# print(f"Warning : can't apply constraints on {self.to_string()} without parent widget")
|
133
|
-
return
|
134
|
-
if not self.constraints:
|
135
|
-
return
|
136
|
-
# Sort constraints based on priority
|
137
|
-
self.constraints.sort(key=lambda c: c.priority)
|
118
|
+
for c in self.children:
|
119
|
+
c.set_parent_scene(parent_scene)
|
120
|
+
return self
|
138
121
|
|
139
|
-
|
140
|
-
|
122
|
+
def set_parent(self, parent: "Widget") -> Self:
|
123
|
+
if parent == self.parent:
|
124
|
+
return self
|
125
|
+
if self.parent is not None:
|
126
|
+
self.parent.remove(self)
|
127
|
+
self.parent = parent
|
128
|
+
return self
|
141
129
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
130
|
+
def set_padding(self, value: float | int | tuple | list) -> Self:
|
131
|
+
if isinstance(value, Iterable):
|
132
|
+
if len(value) > 4:
|
133
|
+
pass
|
134
|
+
elif any(v < 0 for v in value):
|
135
|
+
pass
|
136
|
+
elif len(value) == 2:
|
137
|
+
self.padding = (value[0], value[1], value[0], value[1])
|
138
|
+
else:
|
139
|
+
self.padding = (*value, *self.padding[len(value) :])
|
140
|
+
else:
|
141
|
+
self.padding = (value,) * 4
|
153
142
|
|
154
|
-
|
155
|
-
|
156
|
-
if self.is_root: return self
|
157
|
-
if self.parent_scene is not None : return self.parent_scene.root
|
158
|
-
return None if self.parent is None else self.parent.get_root()
|
143
|
+
self.dirty_shape = True
|
144
|
+
return self
|
159
145
|
|
160
|
-
def
|
161
|
-
|
146
|
+
def get_padded_rect(self) -> pygame.FRect:
|
147
|
+
r = self.rect.inflate(
|
148
|
+
-self.padding[0] - self.padding[2], -self.padding[1] - self.padding[3]
|
149
|
+
)
|
150
|
+
# r.normalize()
|
151
|
+
return r
|
162
152
|
|
153
|
+
def get_min_required_size(self) -> tuple[float, float]:
|
154
|
+
return self.rect.size
|
163
155
|
|
164
|
-
def
|
165
|
-
return self.rect.
|
156
|
+
def get_padded_width(self) -> float:
|
157
|
+
return self.rect.w - self.padding[0] - self.padding[2]
|
166
158
|
|
159
|
+
def get_padded_height(self) -> float:
|
160
|
+
return self.rect.h - self.padding[1] - self.padding[3]
|
167
161
|
|
168
|
-
def
|
169
|
-
|
170
|
-
yield (self.get_content_rect(),"yellow")
|
171
|
-
for child in self.children:
|
172
|
-
yield from child.get_bounding_box()
|
162
|
+
def get_padded_left(self) -> float:
|
163
|
+
return self.rect.left + self.padding[0]
|
173
164
|
|
174
|
-
def
|
175
|
-
self.
|
176
|
-
self.build()
|
177
|
-
return self
|
165
|
+
def get_padded_right(self) -> float:
|
166
|
+
return self.rect.right + self.padding[2]
|
178
167
|
|
179
|
-
def
|
180
|
-
|
181
|
-
self.parent.remove_child(self)
|
182
|
-
self.parent = parent
|
183
|
-
self.apply_all_constraints()
|
184
|
-
# SETTERS
|
185
|
-
|
186
|
-
def set_root(self) -> Self:
|
187
|
-
self.is_root = True
|
188
|
-
return self
|
168
|
+
def get_padded_center(self) -> tuple[float, float]:
|
169
|
+
return self.get_padded_rect().center
|
189
170
|
|
190
|
-
def
|
191
|
-
|
192
|
-
for child in self.children :
|
193
|
-
child.set_parent_scene(scene)
|
171
|
+
def get_padded_top(self) -> float:
|
172
|
+
return self.rect.y + self.padding[1]
|
194
173
|
|
195
|
-
def
|
196
|
-
|
197
|
-
self.rect.x = x
|
198
|
-
for child in self.children:
|
199
|
-
child.set_x(child.rect.x + delta)
|
200
|
-
self.apply_constraints()
|
201
|
-
return self
|
174
|
+
def get_padded_bottom(self) -> float:
|
175
|
+
return self.rect.bottom - self.padding[3]
|
202
176
|
|
203
|
-
def
|
204
|
-
|
205
|
-
|
177
|
+
def get_debug_outlines(self):
|
178
|
+
if not self.visible:
|
179
|
+
return
|
180
|
+
yield (self.rect, self.debug_color)
|
181
|
+
if any(self.padding):
|
182
|
+
yield (self.get_padded_rect(), self.debug_color)
|
206
183
|
for child in self.children:
|
207
|
-
child.
|
208
|
-
|
209
|
-
|
184
|
+
yield from child.get_debug_outlines()
|
185
|
+
|
186
|
+
def add_constraints(self, *constraints: "Constraint") -> Self:
|
187
|
+
self.constraints.extend(constraints)
|
188
|
+
seen = set()
|
189
|
+
result = []
|
190
|
+
for c in self.constraints:
|
191
|
+
if c.name not in seen:
|
192
|
+
result.append(c)
|
193
|
+
seen.add(c.name)
|
194
|
+
self.constraints = result
|
195
|
+
self.constraints.sort(key=lambda c: c.priority)
|
196
|
+
self.dirty_constraints = True
|
210
197
|
return self
|
211
198
|
|
212
|
-
def
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
199
|
+
def resolve_constraints(self) -> None:
|
200
|
+
if self.parent is None or not self.constraints:
|
201
|
+
self.dirty_constraints = False
|
202
|
+
return
|
203
|
+
all_good = False
|
204
|
+
constraint_iteration = 0
|
205
|
+
while not all_good:
|
206
|
+
for constraint in self.constraints:
|
207
|
+
if not constraint.evaluate(self.parent, self):
|
208
|
+
constraint.apply(self.parent, self)
|
209
|
+
# print(constraint.name,"Applied")
|
210
|
+
constraint_iteration += 1
|
211
|
+
if all(c.evaluate(self.parent, self) for c in self.constraints):
|
212
|
+
all_good = True
|
213
|
+
break
|
214
|
+
elif self.__constraint_iteration > MAX_CONSTRAINTS:
|
215
|
+
print(
|
216
|
+
self,
|
217
|
+
"CONSTRAINTS ERROR",
|
218
|
+
list(
|
219
|
+
c.name
|
220
|
+
for c in self.constraints
|
221
|
+
if not c.evaluate(self.parent, self)
|
222
|
+
),
|
223
|
+
)
|
224
|
+
self.dirty_constraints = False
|
225
|
+
return
|
226
|
+
# print("DONE")
|
227
|
+
self.dirty_constraints = False
|
228
|
+
|
229
|
+
def remove_constraints(self, *names: str) -> Self:
|
230
|
+
self.constraints = [c for c in self.constraints if c.name not in names]
|
228
231
|
return self
|
229
232
|
|
233
|
+
def has_constraint(self, name: str) -> bool:
|
234
|
+
return any(c.name == name for c in self.constraints)
|
230
235
|
|
231
|
-
def
|
232
|
-
self.
|
233
|
-
|
234
|
-
return self
|
235
|
-
|
236
|
-
|
237
|
-
# Other Methods
|
236
|
+
def get_root(self) -> "Root":
|
237
|
+
if self.is_root:
|
238
|
+
return self
|
239
|
+
return self.parent.get_root()
|
238
240
|
|
239
|
-
def
|
240
|
-
|
241
|
-
|
242
|
-
|
241
|
+
def top_at(self, x: float | int, y: float | int) -> "None|Widget":
|
242
|
+
if self.children:
|
243
|
+
for child in reversed(self.children):
|
244
|
+
if child.visible:
|
245
|
+
r = child.top_at(x, y)
|
246
|
+
if r is not None:
|
247
|
+
return r
|
248
|
+
return self if self.visible and self.rect.collidepoint(x, y) else None
|
249
|
+
|
250
|
+
def add(self, *children: "Widget") -> Self:
|
251
|
+
self.children.extend(children)
|
252
|
+
i = len(self.children)
|
253
|
+
for child in children:
|
254
|
+
child.set_render_order(i).set_parent(self).set_parent_scene(
|
255
|
+
self.parent_scene
|
256
|
+
)
|
257
|
+
i += 1
|
258
|
+
if self.parent:
|
259
|
+
self.parent.do_sort_children = True
|
260
|
+
return self
|
243
261
|
|
244
|
-
def
|
245
|
-
|
246
|
-
|
262
|
+
def remove(self, *children: "Widget") -> Self:
|
263
|
+
for child in self.children:
|
264
|
+
if child in children:
|
265
|
+
self.children.remove(child)
|
266
|
+
child.set_parent(None).set_parent_scene(None)
|
267
|
+
if self.parent:
|
268
|
+
self.parent.do_sort_children = True
|
247
269
|
|
270
|
+
def set_size_if_autoresize(self, size: tuple[float, float]) -> Self:
|
271
|
+
size = list(size)
|
272
|
+
size[0] = size[0] if self.autoresize_w else None
|
273
|
+
size[1] = size[1] if self.autoresize_h else None
|
248
274
|
|
249
|
-
|
250
|
-
return "Widget"
|
275
|
+
self.set_size(size)
|
251
276
|
|
277
|
+
return self
|
252
278
|
|
253
|
-
def
|
254
|
-
|
255
|
-
|
279
|
+
def set_size(self, size: tuple) -> Self:
|
280
|
+
size = list(size)
|
281
|
+
if size[0] is None:
|
282
|
+
size[0] = self.rect.w
|
283
|
+
if size[1] is None:
|
284
|
+
size[1] = self.rect.h
|
285
|
+
if size == self.rect.size:
|
286
|
+
return self
|
287
|
+
self.rect.size = size
|
288
|
+
self.dirty_shape = True
|
289
|
+
return self
|
256
290
|
|
257
|
-
|
291
|
+
def process_event(self, event: pygame.Event) -> bool:
|
292
|
+
# First propagate to children
|
293
|
+
for child in self.children:
|
294
|
+
child.process_event(event)
|
295
|
+
# return True if the method is blocking (no propagation to next children of the scene)
|
296
|
+
super().process_event(event)
|
297
|
+
|
298
|
+
def update(self, dt) -> None:
|
299
|
+
if self.do_sort_children:
|
300
|
+
self.children.sort(key=lambda c: c.render_order)
|
301
|
+
self.do_sort_children = False
|
302
|
+
_ = [c.update(dt) for c in self.children]
|
303
|
+
super().update(dt)
|
304
|
+
|
305
|
+
def build(self) -> None:
|
306
|
+
new_size = tuple(map(int, self.rect.size))
|
307
|
+
if self.surface.get_size() != new_size:
|
308
|
+
new_size = [max(0, i) for i in new_size]
|
309
|
+
self.surface = pygame.Surface(new_size, self.surface_flags)
|
310
|
+
if self.convert_alpha:
|
311
|
+
self.surface = self.surface.convert_alpha()
|
312
|
+
|
313
|
+
def paint(self) -> None:
|
314
|
+
self.surface.fill((0, 0, 0, 0))
|
315
|
+
return self
|
258
316
|
|
259
|
-
def
|
260
|
-
|
261
|
-
self
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
317
|
+
def visit(self, func: Callable, top_down: bool = True, *args, **kwargs) -> None:
|
318
|
+
if top_down:
|
319
|
+
func(self, *args, **kwargs)
|
320
|
+
for child in self.children:
|
321
|
+
child.visit(func, top_down)
|
322
|
+
if not top_down:
|
323
|
+
func(self, *args, **kwargs)
|
266
324
|
|
267
|
-
def
|
268
|
-
self
|
269
|
-
|
270
|
-
|
271
|
-
|
325
|
+
def visit_up(self, func, *args, **kwargs) -> None:
|
326
|
+
if func(self, *args, **kwargs):
|
327
|
+
return
|
328
|
+
if self.parent:
|
329
|
+
self.parent.visit_up(func, *args, **kwargs)
|
330
|
+
|
331
|
+
def selective_up(self, widget: "Widget"):
|
332
|
+
# if returns True then stop climbing widget tree
|
333
|
+
if widget.parent and widget.parent.dirty_constraints:
|
334
|
+
return False
|
335
|
+
widget.visit(self.selective_down)
|
336
|
+
return True
|
337
|
+
|
338
|
+
def selective_down(self, widget: "Widget"):
|
339
|
+
if widget.constraints:
|
340
|
+
widget.resolve_constraints()
|
341
|
+
else:
|
342
|
+
widget.dirty_constraints = False
|
343
|
+
if widget.dirty_shape:
|
344
|
+
widget.build()
|
345
|
+
widget.dirty_shape = False
|
346
|
+
self.dirty_surface = True
|
347
|
+
|
348
|
+
def draw(self, camera: bf.Camera) -> None:
|
349
|
+
if self.dirty_shape:
|
350
|
+
self.dirty_constraints = True
|
351
|
+
self.dirty_surface = True
|
352
|
+
self.build()
|
353
|
+
self.dirty_shape = False
|
354
|
+
for child in self.children:
|
355
|
+
child.dirty_constraints = True
|
356
|
+
|
357
|
+
if self.dirty_constraints:
|
358
|
+
if self.parent and self.parent.dirty_constraints:
|
359
|
+
self.parent.visit_up(self.selective_up)
|
360
|
+
else:
|
361
|
+
self.visit(lambda c: c.resolve_constraints())
|
272
362
|
|
363
|
+
if self.dirty_surface:
|
364
|
+
self.paint()
|
365
|
+
self.dirty_surface = False
|
273
366
|
|
367
|
+
super().draw(camera)
|
274
368
|
|
369
|
+
if self.clip_children:
|
275
370
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
if child.process_event(event):
|
281
|
-
return True
|
282
|
-
#return True if the method is blocking (no propagation to next children of the scene)
|
283
|
-
return super().process_event(event)
|
371
|
+
new_clip = camera.world_to_screen(self.get_padded_rect())
|
372
|
+
old_clip = camera.surface.get_clip()
|
373
|
+
new_clip = new_clip.clip(old_clip)
|
374
|
+
camera.surface.set_clip(new_clip)
|
284
375
|
|
376
|
+
_ = [
|
377
|
+
child.draw(camera)
|
378
|
+
for child in sorted(self.children, key=lambda c: c.render_order)
|
379
|
+
]
|
285
380
|
|
286
|
-
|
287
|
-
|
288
|
-
child.update(dt)
|
289
|
-
|
290
|
-
def draw(self, camera: bf.Camera) -> int:
|
291
|
-
self.children.sort(key=lambda e: (e.z_depth,e.render_order))
|
292
|
-
return super().draw(camera) + sum([child.draw(camera) for child in self.children])
|
293
|
-
|
294
|
-
def build(self)->None:
|
295
|
-
"""
|
296
|
-
This function is called each time the widget's surface has to be updated
|
297
|
-
It usually has to be overriden if inherited to suit the needs of the new class
|
298
|
-
"""
|
299
|
-
if not self.surface: return
|
300
|
-
if self.surface.get_size() != self.get_size_int():
|
301
|
-
self.surface = pygame.Surface(self.get_size_int())
|
302
|
-
if self.parent : self.parent.children_modified()
|
303
|
-
|
304
|
-
def children_modified(self)->None:
|
305
|
-
self.apply_constraints()
|
306
|
-
if self.parent and not self.is_root:
|
307
|
-
self.parent.children_modified()
|
381
|
+
if self.clip_children:
|
382
|
+
camera.surface.set_clip(old_clip)
|