batframework 1.0.8a14__py3-none-any.whl → 1.0.9a2__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 +9 -13
- batFramework/camera.py +1 -1
- batFramework/constants.py +6 -0
- batFramework/cutscene.py +3 -5
- batFramework/drawable.py +1 -1
- batFramework/dynamicEntity.py +2 -4
- batFramework/entity.py +15 -28
- batFramework/enums.py +1 -0
- batFramework/fontManager.py +3 -3
- batFramework/gui/__init__.py +2 -2
- batFramework/gui/{dialogueBox.py → animatedLabel.py} +18 -36
- batFramework/gui/button.py +30 -0
- batFramework/gui/clickableWidget.py +6 -1
- batFramework/gui/constraints/constraints.py +90 -1
- batFramework/gui/container.py +84 -93
- batFramework/gui/indicator.py +3 -2
- batFramework/gui/interactiveWidget.py +43 -24
- batFramework/gui/label.py +25 -9
- batFramework/gui/layout.py +378 -42
- batFramework/gui/root.py +2 -3
- batFramework/gui/shape.py +2 -0
- batFramework/gui/slider.py +1 -0
- batFramework/gui/textInput.py +115 -78
- batFramework/gui/toggle.py +2 -4
- batFramework/gui/widget.py +49 -37
- batFramework/manager.py +42 -31
- batFramework/sceneManager.py +2 -12
- batFramework/scrollingSprite.py +1 -1
- batFramework/utils.py +0 -1
- {batframework-1.0.8a14.dist-info → batframework-1.0.9a2.dist-info}/METADATA +1 -1
- batframework-1.0.9a2.dist-info/RECORD +63 -0
- {batframework-1.0.8a14.dist-info → batframework-1.0.9a2.dist-info}/WHEEL +1 -1
- batframework-1.0.8a14.dist-info/RECORD +0 -63
- {batframework-1.0.8a14.dist-info → batframework-1.0.9a2.dist-info}/LICENCE +0 -0
- {batframework-1.0.8a14.dist-info → batframework-1.0.9a2.dist-info}/top_level.txt +0 -0
batFramework/gui/textInput.py
CHANGED
@@ -58,7 +58,7 @@ class TextInput(Label, InteractiveWidget):
|
|
58
58
|
def __init__(self) -> None:
|
59
59
|
self.cursor_position = (0, 0)
|
60
60
|
self.old_key_repeat = (0, 0)
|
61
|
-
self.cursor_timer = bf.Timer(0.
|
61
|
+
self.cursor_timer = bf.Timer(0.2, self._cursor_toggle, loop=True).start()
|
62
62
|
self.cursor_timer.pause()
|
63
63
|
self.show_cursor = False
|
64
64
|
self.on_modify: Callable[[str], str] = None
|
@@ -110,6 +110,14 @@ class TextInput(Label, InteractiveWidget):
|
|
110
110
|
return None
|
111
111
|
return lines[line]
|
112
112
|
|
113
|
+
def get_debug_outlines(self):
|
114
|
+
if self.visible:
|
115
|
+
offset = self._get_outline_offset() if self.show_text_outline else (0,0)
|
116
|
+
yield (self.text_rect.move(self.rect.x - offset[0] - self.scroll.x,self.rect.y - offset[1] - self.scroll.y), "purple")
|
117
|
+
yield from super().get_debug_outlines()
|
118
|
+
yield (self.get_cursor_rect().move(-self.scroll+self.rect.topleft),"green")
|
119
|
+
|
120
|
+
|
113
121
|
def set_cursor_position(self, position: tuple[int, int]) -> Self:
|
114
122
|
x, y = position
|
115
123
|
|
@@ -117,12 +125,30 @@ class TextInput(Label, InteractiveWidget):
|
|
117
125
|
y = max(0, min(y, len(lines) - 1))
|
118
126
|
line_length = len(lines[y])
|
119
127
|
x = max(0, min(x, line_length))
|
120
|
-
|
121
|
-
self.cursor_position = (x, y)
|
122
128
|
self.show_cursor = True
|
123
|
-
self.
|
129
|
+
self.cursor_position = (x,y)
|
130
|
+
self.dirty_surface = True
|
131
|
+
offset = self._get_outline_offset() if self.show_text_outline else (0,0)
|
132
|
+
padded = self.get_padded_rect().move(-self.rect.x + offset[0], -self.rect.y + offset[1])
|
133
|
+
self.align_text(self.text_rect,padded,self.alignment)
|
124
134
|
return self
|
125
135
|
|
136
|
+
def get_cursor_rect(self)->pygame.FRect:
|
137
|
+
if not self.font_object:
|
138
|
+
return pygame.FRect(0,0,0,0)
|
139
|
+
|
140
|
+
lines = self.text.split('\n')
|
141
|
+
line_x, line_y = self.cursor_position
|
142
|
+
|
143
|
+
height = self.font_object.get_point_size()
|
144
|
+
|
145
|
+
cursor_y = self.get_padded_rect().__getattribute__(self.alignment.value)[1] - self.rect.top
|
146
|
+
cursor_y += line_y * height
|
147
|
+
cursor_x = self.text_rect.x
|
148
|
+
cursor_x += self.font_object.size(lines[line_y][:line_x])[0] if line_x > 0 else 0
|
149
|
+
cursor_rect = pygame.Rect(cursor_x, cursor_y, 1, height)
|
150
|
+
return cursor_rect
|
151
|
+
|
126
152
|
def cursor_to_absolute(self, position: tuple[int, int]) -> int:
|
127
153
|
x, y = position
|
128
154
|
|
@@ -146,68 +172,72 @@ class TextInput(Label, InteractiveWidget):
|
|
146
172
|
return (len(lines[-1]), len(lines) - 1)
|
147
173
|
|
148
174
|
def do_handle_event(self, event):
|
149
|
-
if not self.is_focused:
|
150
|
-
return
|
151
|
-
|
152
|
-
if event.type not in [pygame.TEXTINPUT, pygame.KEYDOWN]:
|
175
|
+
if not self.is_focused or event.type not in [pygame.TEXTINPUT, pygame.KEYDOWN]:
|
153
176
|
return
|
154
177
|
|
155
178
|
text = self.get_text()
|
156
|
-
|
179
|
+
current_pos = self.cursor_to_absolute(self.cursor_position)
|
180
|
+
pressed = pygame.key.get_pressed()
|
181
|
+
|
157
182
|
if event.type == pygame.TEXTINPUT:
|
158
|
-
|
159
|
-
self.
|
183
|
+
# Insert text at the current cursor position
|
184
|
+
self.set_text(f"{text[:current_pos]}{event.text}{text[current_pos:]}")
|
185
|
+
self.set_cursor_position(self.absolute_to_cursor(current_pos + len(event.text)))
|
186
|
+
|
160
187
|
elif event.type == pygame.KEYDOWN:
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
if
|
166
|
-
|
167
|
-
self.
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
188
|
+
match event.key:
|
189
|
+
case pygame.K_ESCAPE:
|
190
|
+
self.lose_focus()
|
191
|
+
|
192
|
+
case pygame.K_BACKSPACE if current_pos > 0:
|
193
|
+
# Remove the character before the cursor
|
194
|
+
self.set_text(f"{text[:current_pos - 1]}{text[current_pos:]}")
|
195
|
+
self.set_cursor_position(self.absolute_to_cursor(current_pos - 1))
|
196
|
+
|
197
|
+
case pygame.K_DELETE if current_pos < len(text):
|
198
|
+
# Remove the character at the cursor
|
199
|
+
self.set_text(f"{text[:current_pos]}{text[current_pos + 1:]}")
|
200
|
+
|
201
|
+
case pygame.K_RIGHT:
|
202
|
+
if current_pos < len(text):
|
203
|
+
self.handle_cursor_movement(pressed, current_pos, direction="right")
|
204
|
+
|
205
|
+
case pygame.K_LEFT:
|
206
|
+
if current_pos > 0:
|
207
|
+
self.handle_cursor_movement(pressed, current_pos, direction="left")
|
208
|
+
|
209
|
+
case pygame.K_UP:
|
210
|
+
# Move cursor up one line
|
211
|
+
self.set_cursor_position((self.cursor_position[0], self.cursor_position[1] - 1))
|
212
|
+
|
213
|
+
case pygame.K_DOWN:
|
214
|
+
# Move cursor down one line
|
215
|
+
self.set_cursor_position((self.cursor_position[0], self.cursor_position[1] + 1))
|
216
|
+
|
217
|
+
case pygame.K_RETURN:
|
218
|
+
# Insert a newline at the current cursor position
|
219
|
+
self.set_text(f"{text[:current_pos]}\n{text[current_pos:]}")
|
220
|
+
self.set_cursor_position(self.absolute_to_cursor(current_pos + 1))
|
221
|
+
case _ :
|
173
222
|
return
|
174
|
-
if self.cursor_position[0] == len(self.get_line(self.cursor_position[1])):
|
175
|
-
self.set_cursor_position((0, self.cursor_position[1] + 1))
|
176
|
-
else:
|
177
|
-
if pressed[pygame.K_LCTRL] or pressed[pygame.K_RCTRL]:
|
178
|
-
index = find_next_word(self.text,current)
|
179
|
-
if index ==-1 : index = current+1
|
180
|
-
self.set_cursor_position(self.absolute_to_cursor(index))
|
181
|
-
else:
|
182
|
-
self.set_cursor_position(self.absolute_to_cursor(current + 1))
|
183
|
-
elif event.key == pygame.K_LEFT:
|
184
|
-
|
185
|
-
|
186
|
-
if self.cursor_position[0] == 0 and self.cursor_position[1] > 0:
|
187
|
-
self.set_cursor_position((len(self.get_line(self.cursor_position[1] - 1)), self.cursor_position[1] - 1))
|
188
|
-
else:
|
189
|
-
if pressed[pygame.K_LCTRL] or pressed[pygame.K_RCTRL]:
|
190
|
-
index = find_prev_word(self.text,current-1)
|
191
|
-
if index ==-1 : index = current-1
|
192
|
-
self.set_cursor_position(self.absolute_to_cursor(index))
|
193
|
-
else:
|
194
|
-
self.set_cursor_position(self.absolute_to_cursor(current - 1))
|
195
|
-
elif event.key == pygame.K_UP:
|
196
|
-
x, y = self.cursor_position
|
197
|
-
self.set_cursor_position((x, y - 1))
|
198
|
-
elif event.key == pygame.K_DOWN:
|
199
|
-
x, y = self.cursor_position
|
200
|
-
self.set_cursor_position((x, y + 1))
|
201
|
-
elif event.key == pygame.K_RETURN:
|
202
|
-
self.set_text(text[:current] + '\n' + text[current:])
|
203
|
-
self.set_cursor_position(self.absolute_to_cursor(current + 1))
|
204
|
-
else:
|
205
|
-
return
|
206
|
-
else:
|
207
|
-
return
|
208
223
|
|
209
224
|
event.consumed = True
|
210
225
|
|
226
|
+
def handle_cursor_movement(self, pressed, current_pos, direction):
|
227
|
+
if direction == "right":
|
228
|
+
if pressed[pygame.K_LCTRL] or pressed[pygame.K_RCTRL]:
|
229
|
+
next_word_pos = find_next_word(self.text, current_pos)
|
230
|
+
self.set_cursor_position(self.absolute_to_cursor(next_word_pos if next_word_pos != -1 else current_pos + 1))
|
231
|
+
else:
|
232
|
+
self.set_cursor_position(self.absolute_to_cursor(current_pos + 1))
|
233
|
+
elif direction == "left":
|
234
|
+
if pressed[pygame.K_LCTRL] or pressed[pygame.K_RCTRL]:
|
235
|
+
prev_word_pos = find_prev_word(self.text, current_pos - 1)
|
236
|
+
self.set_cursor_position(self.absolute_to_cursor(prev_word_pos if prev_word_pos != -1 else current_pos - 1))
|
237
|
+
else:
|
238
|
+
self.set_cursor_position(self.absolute_to_cursor(current_pos - 1))
|
239
|
+
|
240
|
+
|
211
241
|
def set_text(self, text: str) -> Self:
|
212
242
|
if self.on_modify:
|
213
243
|
text = self.on_modify(text)
|
@@ -216,32 +246,39 @@ class TextInput(Label, InteractiveWidget):
|
|
216
246
|
def _paint_cursor(self) -> None:
|
217
247
|
if not self.font_object or not self.show_cursor:
|
218
248
|
return
|
249
|
+
cursor_rect = self.get_cursor_rect()
|
250
|
+
cursor_rect.move_ip(-self.scroll)
|
219
251
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
cursor_y = self.padding[1]
|
224
|
-
cursor_y += line_y * self.font_object.get_linesize()
|
225
|
-
cursor_x = self.padding[0]
|
226
|
-
cursor_x += self.font_object.size(lines[line_y][:line_x])[0] if line_x > 0 else 0
|
252
|
+
|
253
|
+
pygame.draw.rect(self.surface, bf.color.CLOUD, cursor_rect.inflate(2,2))
|
227
254
|
|
228
|
-
cursor_rect = pygame.Rect(cursor_x, cursor_y, 2, self.font_object.get_height())
|
229
255
|
pygame.draw.rect(self.surface, self.text_color, cursor_rect)
|
230
256
|
|
231
257
|
def paint(self) -> None:
|
232
258
|
super().paint()
|
233
259
|
self._paint_cursor()
|
234
260
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
261
|
+
def align_text(
|
262
|
+
self, text_rect: pygame.FRect, area: pygame.FRect, alignment: bf.alignment
|
263
|
+
):
|
264
|
+
cursor_rect = self.get_cursor_rect()
|
265
|
+
|
266
|
+
if alignment == bf.alignment.LEFT:
|
267
|
+
alignment = bf.alignment.MIDLEFT
|
268
|
+
elif alignment == bf.alignment.MIDRIGHT:
|
269
|
+
alignment = bf.alignment.MIDRIGHT
|
270
|
+
pos = area.__getattribute__(alignment.value)
|
271
|
+
text_rect.__setattr__(alignment.value, pos)
|
272
|
+
|
273
|
+
|
274
|
+
if cursor_rect.right > area.right+self.scroll.x:
|
275
|
+
self.scroll.x=cursor_rect.right - area.right
|
276
|
+
elif cursor_rect.x < self.scroll.x+area.left:
|
277
|
+
self.scroll.x= cursor_rect.left - area.left
|
278
|
+
self.scroll.x = max(self.scroll.x,0)
|
279
|
+
|
280
|
+
if cursor_rect.bottom > area.bottom + self.scroll.y:
|
281
|
+
self.scroll.y = cursor_rect.bottom - area.bottom
|
282
|
+
elif cursor_rect.y < self.scroll.y + area.top:
|
283
|
+
self.scroll.y = cursor_rect.top - area.top
|
284
|
+
self.scroll.y = max(self.scroll.y, 0)
|
batFramework/gui/toggle.py
CHANGED
@@ -14,7 +14,6 @@ class Toggle(Button):
|
|
14
14
|
super().__init__(text, callback)
|
15
15
|
self.add(self.indicator)
|
16
16
|
self.set_clip_children(False)
|
17
|
-
# self.set_gap(int(max(4, self.get_padded_width() / 3)))
|
18
17
|
|
19
18
|
def set_visible(self, value: bool) -> Self:
|
20
19
|
self.indicator.set_visible(value)
|
@@ -77,17 +76,16 @@ class Toggle(Button):
|
|
77
76
|
0, 0, self.text_rect.w + gap + self.indicator.rect.w, self.text_rect.h
|
78
77
|
)
|
79
78
|
|
80
|
-
|
81
79
|
if self.autoresize_h or self.autoresize_w:
|
82
80
|
target_rect = self.inflate_rect_by_padding(joined_rect)
|
81
|
+
target_rect.h += self.unpressed_relief
|
83
82
|
if not self.autoresize_w:
|
84
83
|
target_rect.w = self.rect.w
|
85
84
|
if not self.autoresize_h:
|
86
85
|
target_rect.h = self.rect.h
|
87
86
|
if self.rect.size != target_rect.size:
|
88
87
|
self.set_size(target_rect.size)
|
89
|
-
self.
|
90
|
-
return
|
88
|
+
self.apply_updates()
|
91
89
|
|
92
90
|
# ------------------------------------ size is ok
|
93
91
|
|
batFramework/gui/widget.py
CHANGED
@@ -11,9 +11,7 @@ MAX_CONSTRAINTS = 10
|
|
11
11
|
|
12
12
|
class WidgetMeta(type):
|
13
13
|
def __call__(cls, *args, **kwargs):
|
14
|
-
"""Called when you call MyNewClass()"""
|
15
14
|
obj = type.__call__(cls, *args, **kwargs)
|
16
|
-
# obj.new_init()
|
17
15
|
bf.StyleManager().register_widget(obj)
|
18
16
|
return obj
|
19
17
|
|
@@ -28,10 +26,9 @@ class Widget(bf.Drawable, metaclass=WidgetMeta):
|
|
28
26
|
self.clip_children: bool = True
|
29
27
|
self.padding = (0, 0, 0, 0)
|
30
28
|
self.dirty_surface: bool = True # if true will call paint before drawing
|
31
|
-
self.dirty_shape: bool = (
|
32
|
-
|
33
|
-
|
34
|
-
self.dirty_constraints: bool = False
|
29
|
+
self.dirty_shape: bool = True # if true will call (build+paint) before drawing
|
30
|
+
self.dirty_constraints: bool = False # if true will call resolve_constraints
|
31
|
+
|
35
32
|
self.is_root: bool = False
|
36
33
|
self.autoresize_w, self.autoresize_h = True, True
|
37
34
|
self.__constraint_iteration = 0
|
@@ -221,7 +218,7 @@ class Widget(bf.Drawable, metaclass=WidgetMeta):
|
|
221
218
|
if capture != self.__constraints_capture:
|
222
219
|
self.__constraints_capture = capture
|
223
220
|
self.__constraint_to_ignore = []
|
224
|
-
|
221
|
+
|
225
222
|
constraints = self.constraints.copy()
|
226
223
|
# If all are resolved early exit
|
227
224
|
if all(c.evaluate(self.parent,self) for c in constraints if c not in self.__constraint_to_ignore):
|
@@ -240,6 +237,7 @@ class Widget(bf.Drawable, metaclass=WidgetMeta):
|
|
240
237
|
for c in constraints:
|
241
238
|
if c in self.__constraints_to_ignore:continue
|
242
239
|
if not c.evaluate(self.parent,self) :
|
240
|
+
# print(c," is applied")
|
243
241
|
c.apply(self.parent,self)
|
244
242
|
# second pass where we check conflicts
|
245
243
|
for c in constraints:
|
@@ -256,9 +254,10 @@ class Widget(bf.Drawable, metaclass=WidgetMeta):
|
|
256
254
|
|
257
255
|
if self.__constraints_to_ignore:
|
258
256
|
print("Constraints ignored : ",[str(c) for c in self.__constraints_to_ignore])
|
259
|
-
|
260
|
-
|
257
|
+
|
261
258
|
self.dirty_constraints = False
|
259
|
+
# print(self,self.uid,"resolve constraints : Success")
|
260
|
+
|
262
261
|
|
263
262
|
def has_constraint(self, name: str) -> bool:
|
264
263
|
return any(c.name == name for c in self.constraints)
|
@@ -313,17 +312,16 @@ class Widget(bf.Drawable, metaclass=WidgetMeta):
|
|
313
312
|
size[0] = self.rect.w
|
314
313
|
if size[1] is None:
|
315
314
|
size[1] = self.rect.h
|
316
|
-
if size == self.rect.
|
315
|
+
if (int(size[0]),int(size[1])) == (int(self.rect.w),int(self.rect.h)):
|
317
316
|
return self
|
318
317
|
self.rect.size = size
|
319
318
|
self.dirty_shape = True
|
320
319
|
return self
|
321
320
|
|
322
|
-
def process_event(self, event: pygame.Event) ->
|
321
|
+
def process_event(self, event: pygame.Event) -> None:
|
323
322
|
# First propagate to children
|
324
323
|
for child in self.children:
|
325
324
|
child.process_event(event)
|
326
|
-
# return True if the method is blocking (no propagation to next children of the scene)
|
327
325
|
super().process_event(event)
|
328
326
|
|
329
327
|
def update(self, dt) -> None:
|
@@ -351,7 +349,7 @@ class Widget(bf.Drawable, metaclass=WidgetMeta):
|
|
351
349
|
if top_down:
|
352
350
|
func(self, *args, **kwargs)
|
353
351
|
for child in self.children:
|
354
|
-
child.visit(func, top_down)
|
352
|
+
child.visit(func, top_down,*args,**kwargs)
|
355
353
|
if not top_down:
|
356
354
|
func(self, *args, **kwargs)
|
357
355
|
|
@@ -361,55 +359,69 @@ class Widget(bf.Drawable, metaclass=WidgetMeta):
|
|
361
359
|
if self.parent:
|
362
360
|
self.parent.visit_up(func, *args, **kwargs)
|
363
361
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
return False
|
368
|
-
widget.visit(self.selective_down)
|
369
|
-
return True
|
362
|
+
"""
|
363
|
+
1 :
|
364
|
+
bottom up -> only build children
|
370
365
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
366
|
+
"""
|
367
|
+
def update_children_size(self, widget: "Widget"):
|
368
|
+
# print(widget,widget.uid,"constraints resolve in update size func")
|
369
|
+
|
370
|
+
widget.resolve_constraints()
|
376
371
|
if widget.dirty_shape:
|
372
|
+
# print(widget,widget.uid,"build in update size func")
|
377
373
|
widget.build()
|
378
374
|
widget.dirty_shape = False
|
379
|
-
|
375
|
+
widget.dirty_surface = True
|
376
|
+
|
377
|
+
def find_highest_dirty_constraints_widget(self) -> "Widget":
|
378
|
+
w = self
|
379
|
+
tmp = w
|
380
|
+
while not tmp.is_root:
|
381
|
+
if tmp.dirty_constraints or tmp.dirty_shape:
|
382
|
+
w = tmp
|
383
|
+
if not tmp.parent:
|
384
|
+
break
|
385
|
+
tmp = tmp.parent
|
386
|
+
return w
|
380
387
|
|
381
|
-
|
388
|
+
|
389
|
+
def apply_updates(self) -> None:
|
390
|
+
# Step 1: Build shape if needed
|
382
391
|
if self.dirty_shape:
|
383
|
-
self.
|
384
|
-
self.dirty_surface = True
|
385
|
-
self.build()
|
392
|
+
self.build() # Finalize widget size
|
386
393
|
self.dirty_shape = False
|
394
|
+
self.dirty_surface = True
|
395
|
+
# Propagate dirty_constraints to children in case size affects their position
|
387
396
|
for child in self.children:
|
388
397
|
child.dirty_constraints = True
|
389
398
|
|
399
|
+
# Step 2: Resolve constraints now that size is finalized
|
390
400
|
if self.dirty_constraints:
|
391
|
-
|
392
|
-
|
393
|
-
else:
|
394
|
-
self.visit(lambda c: c.resolve_constraints())
|
401
|
+
self.resolve_constraints() # Finalize positioning based on final size
|
402
|
+
self.dirty_constraints = False
|
395
403
|
|
404
|
+
# Step 3: Paint the surface if flagged as dirty
|
396
405
|
if self.dirty_surface:
|
397
406
|
self.paint()
|
398
407
|
self.dirty_surface = False
|
408
|
+
|
399
409
|
|
410
|
+
|
411
|
+
def draw(self, camera: bf.Camera) -> None:
|
412
|
+
self.apply_updates()
|
413
|
+
# Draw widget and handle clipping if necessary
|
400
414
|
super().draw(camera)
|
401
415
|
|
402
416
|
if self.clip_children:
|
403
|
-
|
404
417
|
new_clip = camera.world_to_screen(self.get_padded_rect())
|
405
418
|
old_clip = camera.surface.get_clip()
|
406
419
|
new_clip = new_clip.clip(old_clip)
|
407
420
|
camera.surface.set_clip(new_clip)
|
408
421
|
|
409
|
-
|
422
|
+
# Draw each child widget, sorted by render order
|
423
|
+
for child in sorted(self.children, key=lambda c: c.render_order):
|
410
424
|
child.draw(camera)
|
411
|
-
for child in sorted(self.children, key=lambda c: c.render_order)
|
412
|
-
]
|
413
425
|
|
414
426
|
if self.clip_children:
|
415
427
|
camera.surface.set_clip(old_clip)
|
batFramework/manager.py
CHANGED
@@ -14,11 +14,12 @@ class Manager(bf.SceneManager):
|
|
14
14
|
self.is_async_running : bool = False
|
15
15
|
self.running = False
|
16
16
|
pygame.mouse.set_cursor(bf.const.DEFAULT_CURSOR)
|
17
|
-
self.do_pre_init()
|
18
|
-
self.init_scenes(*initial_scene_list)
|
19
17
|
bf.ResourceManager().set_sharedVar("clock", self.clock)
|
20
18
|
bf.ResourceManager().set_sharedVar("debug_mode", self.debug_mode)
|
21
|
-
|
19
|
+
|
20
|
+
self.do_pre_init()
|
21
|
+
if initial_scene_list:
|
22
|
+
self.init_scenes(*initial_scene_list)
|
22
23
|
self.do_init()
|
23
24
|
|
24
25
|
@staticmethod
|
@@ -58,65 +59,75 @@ class Manager(bf.SceneManager):
|
|
58
59
|
def stop(self) -> None:
|
59
60
|
self.running = False
|
60
61
|
|
62
|
+
def process_event(self, event: pygame.Event):
|
63
|
+
event.consumed = False
|
64
|
+
keys = pygame.key.get_pressed()
|
65
|
+
if (
|
66
|
+
bf.const.ALLOW_DEBUG and
|
67
|
+
keys[pygame.K_LCTRL]
|
68
|
+
and keys[pygame.K_LSHIFT]
|
69
|
+
and event.type == pygame.KEYDOWN
|
70
|
+
):
|
71
|
+
if event.key == pygame.K_d:
|
72
|
+
self.cycle_debug_mode()
|
73
|
+
return
|
74
|
+
if event.key == pygame.K_p:
|
75
|
+
self.print_status()
|
76
|
+
return
|
77
|
+
super().process_event(event)
|
78
|
+
if not event.consumed:
|
79
|
+
if event.type == pygame.QUIT:
|
80
|
+
self.running = False
|
81
|
+
elif event.type == pygame.VIDEORESIZE and not (
|
82
|
+
bf.const.FLAGS & pygame.SCALED
|
83
|
+
):
|
84
|
+
bf.const.set_resolution((event.w, event.h))
|
85
|
+
|
86
|
+
def update(self, dt: float) -> None:
|
87
|
+
self.timeManager.update(dt)
|
88
|
+
self.cutsceneManager.update(dt)
|
89
|
+
super().update(dt)
|
90
|
+
|
91
|
+
|
61
92
|
async def run_async(self):
|
93
|
+
if len(self.scenes) == 0:
|
94
|
+
raise Exception("Manager can't start without scenes")
|
62
95
|
if self.running:
|
63
|
-
|
96
|
+
raise Exception("Error : Already running")
|
64
97
|
return
|
65
98
|
self.is_async_running = True
|
66
99
|
self.running = True
|
67
100
|
dt: float = 0
|
68
101
|
while self.running:
|
69
102
|
for event in pygame.event.get():
|
70
|
-
event.consumed = False
|
71
103
|
self.process_event(event)
|
72
|
-
if not event.consumed:
|
73
|
-
if event.type == pygame.QUIT:
|
74
|
-
self.running = False
|
75
|
-
break
|
76
|
-
if event.type == pygame.VIDEORESIZE and not (
|
77
|
-
bf.const.FLAGS & pygame.SCALED
|
78
|
-
):
|
79
|
-
bf.const.set_resolution((event.w, event.h))
|
80
104
|
# update
|
81
|
-
self.timeManager.update(dt)
|
82
|
-
self.cutsceneManager.update(dt)
|
83
105
|
self.update(dt)
|
84
106
|
# render
|
85
|
-
self.screen.fill((0, 0, 0))
|
86
107
|
self.draw(self.screen)
|
87
108
|
pygame.display.flip()
|
88
109
|
dt = self.clock.tick(bf.const.FPS) / 1000
|
89
|
-
|
110
|
+
dt = min(dt, 0.02) # dirty fix for dt being too high when window not focused for a long time
|
90
111
|
await asyncio.sleep(0)
|
91
112
|
pygame.quit()
|
92
113
|
|
93
114
|
|
94
115
|
def run(self) -> None:
|
116
|
+
if len(self.scenes) == 0:
|
117
|
+
raise Exception("Manager can't start without scenes")
|
95
118
|
if self.running:
|
96
|
-
|
119
|
+
raise Exception("Error : Already running")
|
97
120
|
return
|
98
121
|
self.running = True
|
99
122
|
dt: float = 0
|
100
123
|
while self.running:
|
101
124
|
for event in pygame.event.get():
|
102
|
-
event.consumed = False
|
103
125
|
self.process_event(event)
|
104
|
-
if not event.consumed:
|
105
|
-
if event.type == pygame.QUIT:
|
106
|
-
self.running = False
|
107
|
-
break
|
108
|
-
if event.type == pygame.VIDEORESIZE and not (
|
109
|
-
bf.const.FLAGS & pygame.SCALED
|
110
|
-
):
|
111
|
-
bf.const.set_resolution((event.w, event.h))
|
112
126
|
# update
|
113
|
-
self.timeManager.update(dt)
|
114
|
-
self.cutsceneManager.update(dt)
|
115
127
|
self.update(dt)
|
116
128
|
# render
|
117
|
-
self.screen.fill((0, 0, 0))
|
118
129
|
self.draw(self.screen)
|
119
130
|
pygame.display.flip()
|
120
131
|
dt = self.clock.tick(bf.const.FPS) / 1000
|
121
|
-
|
132
|
+
dt = min(dt, 0.02) # dirty fix for dt being too high when window not focused for a long time
|
122
133
|
pygame.quit()
|
batFramework/sceneManager.py
CHANGED
@@ -166,21 +166,11 @@ class SceneManager:
|
|
166
166
|
def cycle_debug_mode(self):
|
167
167
|
current_index = bf.ResourceManager().get_sharedVar("debug_mode").value
|
168
168
|
next_index = (current_index + 1) % len(bf.debugMode)
|
169
|
+
bf.ResourceManager().set_sharedVar("debug_mode", bf.debugMode(next_index))
|
169
170
|
return bf.debugMode(next_index)
|
170
171
|
|
171
172
|
def process_event(self, event: pygame.Event):
|
172
|
-
|
173
|
-
if (
|
174
|
-
keys[pygame.K_LCTRL]
|
175
|
-
and keys[pygame.K_LSHIFT]
|
176
|
-
and event.type == pygame.KEYDOWN
|
177
|
-
):
|
178
|
-
if event.key == pygame.K_d:
|
179
|
-
bf.ResourceManager().set_sharedVar("debug_mode", self.cycle_debug_mode())
|
180
|
-
return
|
181
|
-
if event.key == pygame.K_p:
|
182
|
-
self.print_status()
|
183
|
-
return
|
173
|
+
|
184
174
|
if event.type in self.shared_events:
|
185
175
|
[s.process_event(event) for s in self.scenes]
|
186
176
|
else:
|
batFramework/scrollingSprite.py
CHANGED
@@ -16,7 +16,7 @@ class ScrollingSprite(bf.Sprite):
|
|
16
16
|
|
17
17
|
# Use integer values for the starting points, converted from floating point scroll values
|
18
18
|
|
19
|
-
super().__init__(
|
19
|
+
super().__init__(size, data, convert_alpha)
|
20
20
|
self.original_width, self.original_height = self.original_surface.get_size()
|
21
21
|
|
22
22
|
def get_debug_outlines(self):
|
batFramework/utils.py
CHANGED