batframework 1.0.8a2__py3-none-any.whl → 1.0.8a4__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 +117 -73
- batFramework/audioManager.py +69 -26
- batFramework/camera.py +259 -69
- batFramework/constants.py +16 -54
- batFramework/cutscene.py +39 -29
- batFramework/cutsceneBlocks.py +36 -43
- batFramework/dynamicEntity.py +17 -9
- 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 +221 -0
- batFramework/gui/constraints/__init__.py +1 -0
- batFramework/gui/constraints/constraints.py +730 -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 +292 -74
- batFramework/gui/layout.py +219 -60
- batFramework/gui/meter.py +71 -0
- batFramework/gui/radioButton.py +84 -0
- batFramework/gui/root.py +134 -38
- batFramework/gui/shape.py +259 -57
- batFramework/gui/slider.py +230 -0
- batFramework/gui/style.py +10 -0
- batFramework/gui/styleManager.py +48 -0
- batFramework/gui/textInput.py +137 -0
- batFramework/gui/toggle.py +103 -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 +100 -0
- batFramework/scene.py +281 -123
- batFramework/sceneManager.py +141 -108
- batFramework/scrollingSprite.py +114 -0
- batFramework/sprite.py +51 -0
- batFramework/stateMachine.py +2 -2
- batFramework/tileset.py +46 -0
- batFramework/time.py +123 -58
- batFramework/transition.py +195 -124
- batFramework/utils.py +87 -151
- batframework-1.0.8a4.dist-info/LICENCE +21 -0
- batframework-1.0.8a4.dist-info/METADATA +55 -0
- batframework-1.0.8a4.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.8a4.dist-info}/WHEEL +0 -0
- {batframework-1.0.8a2.dist-info → batframework-1.0.8a4.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
|
-
|
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
|
46
33
|
)
|
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
|
38
|
+
|
39
|
+
def show(self) -> Self:
|
40
|
+
self.visit(lambda w: w.set_visible(True))
|
47
41
|
return self
|
48
|
-
|
49
|
-
def inflate_rect_by_padding(self,rect:pygame.FRect)->pygame.FRect:
|
50
|
-
return pygame.FRect(
|
51
|
-
rect[0] - self.padding[0],
|
52
|
-
rect[1] - self.padding[1],
|
53
|
-
rect[2] + self.padding[0]+self.padding[2],
|
54
|
-
rect[3] + self.padding[1]+self.padding[3]
|
55
|
-
)
|
56
|
-
def get_content_left(self)->float:
|
57
|
-
return self.rect.left + self.padding[0]
|
58
42
|
|
59
|
-
def
|
60
|
-
|
43
|
+
def hide(self) -> Self:
|
44
|
+
self.visit(lambda w: w.set_visible(False))
|
45
|
+
return self
|
61
46
|
|
62
|
-
def
|
63
|
-
|
47
|
+
def set_clip_children(self, value: bool) -> Self:
|
48
|
+
self.clip_children = value
|
49
|
+
self.dirty_surface = True
|
50
|
+
return self
|
64
51
|
|
65
|
-
def
|
66
|
-
return
|
52
|
+
def __str__(self) -> str:
|
53
|
+
return "Widget"
|
67
54
|
|
68
|
-
def
|
69
|
-
|
55
|
+
def set_autoresize(self, value: bool) -> Self:
|
56
|
+
self.autoresize_w = self.autoresize_h = value
|
57
|
+
self.dirty_shape = True
|
58
|
+
return self
|
70
59
|
|
71
|
-
def
|
72
|
-
|
60
|
+
def set_autoresize_w(self, value: bool) -> Self:
|
61
|
+
self.autoresize_w = value
|
62
|
+
self.dirty_shape = True
|
63
|
+
return self
|
64
|
+
|
65
|
+
def set_autoresize_h(self, value: bool) -> Self:
|
66
|
+
self.autoresize_h = value
|
67
|
+
self.dirty_shape = True
|
68
|
+
return self
|
69
|
+
|
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
|
73
75
|
|
74
|
-
def
|
76
|
+
def inflate_rect_by_padding(
|
77
|
+
self, rect: pygame.Rect | pygame.FRect
|
78
|
+
) -> pygame.Rect | pygame.FRect:
|
75
79
|
return pygame.FRect(
|
76
|
-
|
77
|
-
|
78
|
-
self.
|
79
|
-
self.
|
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],
|
80
84
|
)
|
81
85
|
|
82
|
-
def
|
83
|
-
|
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:
|
92
|
+
return self
|
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]
|
96
|
+
return 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
|
+
]
|
111
|
+
return self
|
84
112
|
|
85
|
-
def
|
86
|
-
|
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)
|
87
117
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
else:
|
92
|
-
self.gui_depth = self.parent.get_depth() + 1
|
93
|
-
return self.gui_depth
|
118
|
+
for c in self.children:
|
119
|
+
c.set_parent_scene(parent_scene)
|
120
|
+
return self
|
94
121
|
|
95
|
-
def
|
96
|
-
if self.
|
97
|
-
for child in reversed(self.children):
|
98
|
-
r = child.top_at(x,y)
|
99
|
-
if r is not None:
|
100
|
-
return r
|
101
|
-
if self.rect.collidepoint(x,y) and self.visible:
|
122
|
+
def set_parent(self, parent: "Widget") -> Self:
|
123
|
+
if parent == self.parent:
|
102
124
|
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()
|
125
|
+
if self.parent is not None:
|
126
|
+
self.parent.remove(self)
|
127
|
+
self.parent = parent
|
112
128
|
return self
|
113
|
-
|
114
|
-
def
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
129
|
+
|
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
|
142
|
+
|
143
|
+
self.dirty_shape = True
|
120
144
|
return self
|
121
145
|
|
122
|
-
def
|
123
|
-
|
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
|
124
152
|
|
125
|
-
def
|
126
|
-
|
127
|
-
self.apply_constraints()
|
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)
|
153
|
+
def get_min_required_size(self) -> tuple[float, float]:
|
154
|
+
return self.rect.size
|
138
155
|
|
139
|
-
|
140
|
-
|
156
|
+
def get_padded_width(self) -> float:
|
157
|
+
return self.rect.w - self.padding[0] - self.padding[2]
|
141
158
|
|
142
|
-
|
143
|
-
|
144
|
-
unsatisfied.append(constraint)
|
145
|
-
constraint.apply(self.parent, self)
|
146
|
-
if not unsatisfied:
|
147
|
-
# data = ''.join(f"\n\t->{c.to_string()}" for c in self.constraints)
|
148
|
-
# print(self.get_depth()*'\t'+f"Following constraints of {self.to_string()} were all satisfied :{data}")
|
149
|
-
break
|
150
|
-
# print(f"pass {iteration}/{max_iterations} : unsatisfied = {';'.join(c.to_string() for c in unsatisfied)}")
|
151
|
-
if iteration == max_iterations - 1:
|
152
|
-
raise ValueError(f"[WARNING] Following constraints for {self.to_string()} were not satisfied : \n\t{';'.join([c.to_string() for c in unsatisfied])}")
|
159
|
+
def get_padded_height(self) -> float:
|
160
|
+
return self.rect.h - self.padding[1] - self.padding[3]
|
153
161
|
|
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()
|
162
|
+
def get_padded_left(self) -> float:
|
163
|
+
return self.rect.left + self.padding[0]
|
159
164
|
|
160
|
-
def
|
161
|
-
return
|
165
|
+
def get_padded_right(self) -> float:
|
166
|
+
return self.rect.right + self.padding[2]
|
162
167
|
|
168
|
+
def get_padded_center(self) -> tuple[float, float]:
|
169
|
+
return self.get_padded_rect().center
|
163
170
|
|
164
|
-
def
|
165
|
-
return self.rect.
|
171
|
+
def get_padded_top(self) -> float:
|
172
|
+
return self.rect.y + self.padding[1]
|
166
173
|
|
174
|
+
def get_padded_bottom(self) -> float:
|
175
|
+
return self.rect.bottom - self.padding[3]
|
167
176
|
|
168
|
-
def
|
169
|
-
|
170
|
-
|
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)
|
171
183
|
for child in self.children:
|
172
|
-
yield from child.
|
173
|
-
|
174
|
-
def
|
175
|
-
self.
|
176
|
-
|
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 not any(c == o for o 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
|
177
197
|
return self
|
178
198
|
|
179
|
-
def
|
180
|
-
if self.parent:
|
181
|
-
self.
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
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]
|
188
231
|
return self
|
189
232
|
|
190
|
-
def
|
191
|
-
|
192
|
-
for child in self.children :
|
193
|
-
child.set_parent_scene(scene)
|
233
|
+
def has_constraint(self, name: str) -> bool:
|
234
|
+
return any(c.name == name for c in self.constraints)
|
194
235
|
|
195
|
-
def
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
236
|
+
def get_root(self) -> "Root":
|
237
|
+
if self.is_root:
|
238
|
+
return self
|
239
|
+
return self.parent.get_root()
|
240
|
+
|
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
|
201
260
|
return self
|
202
261
|
|
203
|
-
def
|
204
|
-
delta = y - self.rect.y
|
205
|
-
self.rect.y = y
|
262
|
+
def remove(self, *children: "Widget") -> Self:
|
206
263
|
for child in self.children:
|
207
|
-
child
|
208
|
-
|
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
|
209
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
|
274
|
+
self.set_size(size)
|
210
275
|
return self
|
211
276
|
|
212
|
-
def
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
self.
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
delta_x = x - self.rect.centerx
|
223
|
-
delta_y = y - self.rect.centery
|
224
|
-
self.rect.center = x,y
|
225
|
-
for child in self.children:
|
226
|
-
child.set_position(child.rect.x + delta_x,child.rect.y+delta_y)
|
227
|
-
self.apply_constraints()
|
277
|
+
def set_size(self, size: tuple) -> Self:
|
278
|
+
size = list(size)
|
279
|
+
if size[0] is None:
|
280
|
+
size[0] = self.rect.w
|
281
|
+
if size[1] is None:
|
282
|
+
size[1] = self.rect.h
|
283
|
+
if size == self.rect.size:
|
284
|
+
return self
|
285
|
+
self.rect.size = size
|
286
|
+
self.dirty_shape = True
|
228
287
|
return self
|
229
288
|
|
230
|
-
|
231
|
-
|
232
|
-
self.
|
233
|
-
|
289
|
+
def process_event(self, event: pygame.Event) -> bool:
|
290
|
+
# First propagate to children
|
291
|
+
for child in self.children:
|
292
|
+
child.process_event(event)
|
293
|
+
# return True if the method is blocking (no propagation to next children of the scene)
|
294
|
+
super().process_event(event)
|
295
|
+
|
296
|
+
def update(self, dt) -> None:
|
297
|
+
if self.do_sort_children:
|
298
|
+
self.children.sort(key=lambda c: c.render_order)
|
299
|
+
self.do_sort_children = False
|
300
|
+
_ = [c.update(dt) for c in self.children]
|
301
|
+
super().update(dt)
|
302
|
+
|
303
|
+
def build(self) -> None:
|
304
|
+
new_size = tuple(map(int, self.rect.size))
|
305
|
+
if self.surface.get_size() != new_size:
|
306
|
+
old_alpha = self.surface.get_alpha()
|
307
|
+
new_size = [max(0, i) for i in new_size]
|
308
|
+
self.surface = pygame.Surface(new_size, self.surface_flags)
|
309
|
+
if self.convert_alpha:
|
310
|
+
self.surface = self.surface.convert_alpha()
|
311
|
+
self.surface.set_alpha(old_alpha)
|
312
|
+
|
313
|
+
def paint(self) -> None:
|
314
|
+
self.surface.fill((0, 0, 0, 0))
|
234
315
|
return self
|
235
|
-
|
236
|
-
|
237
|
-
# Other Methods
|
238
|
-
|
239
|
-
def print_tree(self,ident:int=0)->None:
|
240
|
-
print('\t'*ident+self.to_string()+(':' if self.children else ''))
|
241
|
-
for child in self.children :
|
242
|
-
child.print_tree(ident+1)
|
243
|
-
|
244
|
-
def to_string(self)->str:
|
245
|
-
|
246
|
-
return f"{self.to_string_id()}@{*self.rect.topleft,* self.rect.size}"
|
247
|
-
|
248
|
-
|
249
|
-
def to_string_id(self)->str:
|
250
|
-
return "Widget"
|
251
|
-
|
252
|
-
|
253
|
-
def do_when_removed(self)->None:
|
254
|
-
if self.parent_scene and self.parent == self.parent_scene.root:
|
255
|
-
self.set_parent(None)
|
256
316
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
for
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
c.apply_constraints()
|
265
|
-
self.children_modified()
|
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)
|