batframework 1.0.8a1__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.
Files changed (46) hide show
  1. batFramework/action.py +30 -14
  2. batFramework/actionContainer.py +5 -3
  3. batFramework/audioManager.py +0 -1
  4. batFramework/camera.py +29 -24
  5. batFramework/cutscene.py +2 -4
  6. batFramework/entity.py +9 -2
  7. batFramework/enums.py +11 -2
  8. batFramework/fontManager.py +1 -1
  9. batFramework/gui/__init__.py +3 -1
  10. batFramework/gui/button.py +5 -2
  11. batFramework/gui/clickableWidget.py +42 -29
  12. batFramework/gui/constraints/constraints.py +269 -57
  13. batFramework/gui/container.py +39 -21
  14. batFramework/gui/debugger.py +18 -11
  15. batFramework/gui/dialogueBox.py +20 -17
  16. batFramework/gui/draggableWidget.py +7 -5
  17. batFramework/gui/image.py +27 -15
  18. batFramework/gui/indicator.py +1 -4
  19. batFramework/gui/interactiveWidget.py +91 -30
  20. batFramework/gui/label.py +44 -35
  21. batFramework/gui/layout.py +115 -43
  22. batFramework/gui/meter.py +3 -8
  23. batFramework/gui/radioButton.py +47 -25
  24. batFramework/gui/root.py +50 -25
  25. batFramework/gui/shape.py +14 -19
  26. batFramework/gui/slider.py +70 -44
  27. batFramework/gui/style.py +10 -0
  28. batFramework/gui/styleManager.py +48 -0
  29. batFramework/gui/textInput.py +25 -22
  30. batFramework/gui/toggle.py +42 -29
  31. batFramework/gui/widget.py +176 -115
  32. batFramework/object.py +9 -10
  33. batFramework/renderGroup.py +7 -2
  34. batFramework/scene.py +70 -49
  35. batFramework/sceneManager.py +15 -20
  36. batFramework/scrollingSprite.py +5 -3
  37. batFramework/sprite.py +20 -14
  38. batFramework/stateMachine.py +1 -2
  39. batFramework/tileset.py +5 -5
  40. batFramework/utils.py +12 -10
  41. {batframework-1.0.8a1.dist-info → batframework-1.0.8a3.dist-info}/METADATA +1 -1
  42. batframework-1.0.8a3.dist-info/RECORD +58 -0
  43. {batframework-1.0.8a1.dist-info → batframework-1.0.8a3.dist-info}/WHEEL +1 -1
  44. batframework-1.0.8a1.dist-info/RECORD +0 -56
  45. {batframework-1.0.8a1.dist-info → batframework-1.0.8a3.dist-info}/LICENCE +0 -0
  46. {batframework-1.0.8a1.dist-info → batframework-1.0.8a3.dist-info}/top_level.txt +0 -0
@@ -37,7 +37,7 @@ class MinWidth(Constraint):
37
37
  return child_widget.rect.width >= self.min_width
38
38
 
39
39
  def apply_constraint(self, parent_widget, child_widget):
40
- child_widget.set_size((self.min_width,None))
40
+ child_widget.set_size((self.min_width, None))
41
41
 
42
42
 
43
43
  class MinHeight(Constraint):
@@ -57,12 +57,14 @@ class CenterX(Constraint):
57
57
  super().__init__(name="centerx")
58
58
 
59
59
  def evaluate(self, parent_widget, child_widget):
60
- return int(child_widget.rect.centerx - parent_widget.get_padded_center()[0]) == 0
60
+ return (
61
+ int(child_widget.rect.centerx - parent_widget.get_padded_center()[0]) == 0
62
+ )
61
63
 
62
64
  def apply_constraint(self, parent_widget, child_widget):
63
65
  child_widget.set_center(
64
- parent_widget.get_padded_center()[0], child_widget.rect.centery
65
- )
66
+ parent_widget.get_padded_center()[0], child_widget.rect.centery
67
+ )
66
68
 
67
69
 
68
70
  class CenterY(Constraint):
@@ -70,12 +72,14 @@ class CenterY(Constraint):
70
72
  super().__init__(name="centery")
71
73
 
72
74
  def evaluate(self, parent_widget, child_widget):
73
- return int(child_widget.rect.centery - parent_widget.get_padded_center()[1]) == 0
75
+ return (
76
+ int(child_widget.rect.centery - parent_widget.get_padded_center()[1]) == 0
77
+ )
74
78
 
75
79
  def apply_constraint(self, parent_widget, child_widget):
76
80
  child_widget.set_center(
77
- child_widget.rect.centerx, parent_widget.get_padded_center()[1]
78
- )
81
+ child_widget.rect.centerx, parent_widget.get_padded_center()[1]
82
+ )
79
83
 
80
84
 
81
85
  class Center(Constraint):
@@ -83,8 +87,11 @@ class Center(Constraint):
83
87
  super().__init__(name="center")
84
88
 
85
89
  def evaluate(self, parent_widget, child_widget):
86
- return int(child_widget.rect.centerx - parent_widget.get_padded_center()[0]) == 0 and \
87
- int(child_widget.rect.centery - parent_widget.get_padded_center()[1]) == 0
90
+ return (
91
+ int(child_widget.rect.centerx - parent_widget.get_padded_center()[0]) == 0
92
+ and int(child_widget.rect.centery - parent_widget.get_padded_center()[1])
93
+ == 0
94
+ )
88
95
 
89
96
  def apply_constraint(self, parent_widget, child_widget):
90
97
  child_widget.set_center(*parent_widget.get_padded_center())
@@ -114,10 +121,10 @@ class PercentageWidth(Constraint):
114
121
  child_widget.set_autoresize_w(False)
115
122
 
116
123
  child_widget.set_size(
117
- (
118
- round(parent_widget.get_padded_width() * self.percentage),None)
124
+ (round(parent_widget.get_padded_width() * self.percentage), None)
119
125
  )
120
126
 
127
+
121
128
  class PercentageHeight(Constraint):
122
129
  def __init__(self, percentage: float, keep_autoresize: bool = False):
123
130
  super().__init__(name="percentage_height")
@@ -125,7 +132,9 @@ class PercentageHeight(Constraint):
125
132
  self.keep_autoresize: bool = keep_autoresize
126
133
 
127
134
  def evaluate(self, parent_widget, child_widget):
128
- return child_widget.rect.height == round(parent_widget.get_padded_height() * self.percentage)
135
+ return child_widget.rect.height == round(
136
+ parent_widget.get_padded_height() * self.percentage
137
+ )
129
138
 
130
139
  def __str__(self) -> str:
131
140
  return f"{super().__str__()}.[{self.percentage*100}%,keep_autoresize={self.keep_autoresize}]"
@@ -133,68 +142,90 @@ class PercentageHeight(Constraint):
133
142
  def apply_constraint(self, parent_widget, child_widget):
134
143
  if child_widget.autoresize_h:
135
144
  if self.keep_autoresize:
136
- print(f"WARNING: Constraint on {child_widget} can't resize, autoresize set to True")
145
+ print(
146
+ f"WARNING: Constraint on {child_widget} can't resize, autoresize set to True"
147
+ )
137
148
  return
138
149
  child_widget.set_autoresize_h(False)
139
- child_widget.set_size((None,round(parent_widget.get_padded_height() * self.percentage)))
150
+ child_widget.set_size(
151
+ (None, round(parent_widget.get_padded_height() * self.percentage))
152
+ )
153
+
140
154
 
141
155
  class FillX(PercentageWidth):
142
156
  def __init__(self, keep_autoresize: bool = False):
143
- super().__init__(1,keep_autoresize)
157
+ super().__init__(1, keep_autoresize)
144
158
  self.name = "fill_x"
145
159
 
160
+
146
161
  class FillY(PercentageHeight):
147
162
  def __init__(self, keep_autoresize: bool = False):
148
- super().__init__(1,keep_autoresize)
163
+ super().__init__(1, keep_autoresize)
149
164
  self.name = "fill_y"
150
165
 
151
166
 
152
- class Height(Constraint):
153
- def __init__(self, height: float, keep_autoresize: bool = False):
154
- if height < 0:
155
- raise ValueError("height can't be negative")
156
- super().__init__(name="height")
157
- self.height = height
167
+ class PercentageRectHeight(Constraint):
168
+ def __init__(self, percentage: float, keep_autoresize: bool = False):
169
+ super().__init__(name="percentage_rect_height")
170
+ self.percentage: float = percentage
158
171
  self.keep_autoresize: bool = keep_autoresize
159
172
 
160
- def __str__(self) -> str:
161
- return f"{super().__str__()}.(height={self.height})"
162
-
163
173
  def evaluate(self, parent_widget, child_widget):
164
- return child_widget.rect.height == self.height
174
+ return child_widget.rect.height == round(
175
+ parent_widget.rect.height * self.percentage
176
+ )
177
+
178
+ def __str__(self) -> str:
179
+ return f"{super().__str__()}.[{self.percentage*100}%, keep_autoresize={self.keep_autoresize}]"
165
180
 
166
181
  def apply_constraint(self, parent_widget, child_widget):
167
182
  if child_widget.autoresize_h:
168
183
  if self.keep_autoresize:
169
- print(f"WARNING: Constraint on {child_widget.__str__()} can't resize, autoresize set to True")
184
+ print(
185
+ f"WARNING: Constraint on {child_widget} can't resize, autoresize set to True"
186
+ )
170
187
  return
171
188
  child_widget.set_autoresize_h(False)
172
- child_widget.set_size((None, self.height))
189
+ child_widget.set_size(
190
+ (None, round(parent_widget.rect.height * self.percentage))
191
+ )
173
192
 
174
193
 
175
- class Width(Constraint):
176
- def __init__(self, width: float, keep_autoresize: bool = False):
177
- if width < 0:
178
- raise ValueError("width can't be negative")
179
- super().__init__(name="width")
180
- self.width = width
194
+ class PercentageRectWidth(Constraint):
195
+ def __init__(self, percentage: float, keep_autoresize: bool = False):
196
+ super().__init__(name="percentage_rect_width")
197
+ self.percentage: float = percentage
181
198
  self.keep_autoresize: bool = keep_autoresize
182
199
 
183
- def __str__(self) -> str:
184
- return f"{super().__str__()}.(width={self.width})"
185
-
186
200
  def evaluate(self, parent_widget, child_widget):
187
- return child_widget.rect.width == self.width
201
+ return child_widget.rect.width == round(
202
+ parent_widget.rect.width * self.percentage
203
+ )
204
+
205
+ def __str__(self) -> str:
206
+ return f"{super().__str__()}.[{self.percentage*100}%, keep_autoresize={self.keep_autoresize}]"
188
207
 
189
208
  def apply_constraint(self, parent_widget, child_widget):
190
209
  if child_widget.autoresize_w:
191
210
  if self.keep_autoresize:
192
211
  print(
193
- f"WARNING: Constraint on {child_widget.__str__()} can't resize, autoresize set to True"
212
+ f"WARNING: Constraint on {child_widget} can't resize, autoresize set to True"
194
213
  )
195
214
  return
196
215
  child_widget.set_autoresize_w(False)
197
- child_widget.set_size((self.width, None))
216
+ child_widget.set_size((round(parent_widget.rect.width * self.percentage), None))
217
+
218
+
219
+ class FillRectX(PercentageRectWidth):
220
+ def __init__(self, keep_autoresize: bool = False):
221
+ super().__init__(1, keep_autoresize)
222
+ self.name = "fill_rect_x"
223
+
224
+
225
+ class FillRectY(PercentageRectHeight):
226
+ def __init__(self, keep_autoresize: bool = False):
227
+ super().__init__(1, keep_autoresize)
228
+ self.name = "fill_rect_y"
198
229
 
199
230
 
200
231
  class AspectRatio(Constraint):
@@ -205,13 +236,17 @@ class AspectRatio(Constraint):
205
236
  keep_autoresize=False,
206
237
  ):
207
238
  super().__init__(name="aspect_ratio")
208
- self.ref_axis : bf.axis = reference_axis
239
+ self.ref_axis: bf.axis = reference_axis
209
240
  self.keep_autoresize: bool = keep_autoresize
210
241
 
211
242
  if isinstance(ratio, float | int):
212
243
  self.ratio = ratio
213
244
  elif isinstance(ratio, pygame.rect.FRect):
214
- self.ratio = (ratio.w / ratio.h) if reference_axis == bf.axis.HORIZONTAL else (ratio.h / ratio.w)
245
+ self.ratio = (
246
+ (ratio.w / ratio.h)
247
+ if reference_axis == bf.axis.HORIZONTAL
248
+ else (ratio.h / ratio.w)
249
+ )
215
250
  else:
216
251
  raise TypeError(f"Ratio must be float or FRect")
217
252
 
@@ -224,17 +259,17 @@ class AspectRatio(Constraint):
224
259
  def apply_constraint(self, parent_widget, child_widget):
225
260
 
226
261
  if self.ref_axis == bf.axis.VERTICAL:
227
- if child_widget.autoresize_w :
262
+ if child_widget.autoresize_w:
228
263
  if self.keep_autoresize:
229
264
  print(
230
265
  f"WARNING: Constraint on {child_widget.__str__()} can't resize, autoresize set to True"
231
266
  )
232
267
  return
233
268
  child_widget.set_autoresize_w(False)
234
- child_widget.set_size((child_widget.rect.h * self.ratio,None))
235
-
269
+ child_widget.set_size((child_widget.rect.h * self.ratio, None))
270
+
236
271
  if self.ref_axis == bf.axis.HORIZONTAL:
237
- if child_widget.autoresize_h :
272
+ if child_widget.autoresize_h:
238
273
  if self.keep_autoresize:
239
274
  print(
240
275
  f"WARNING: Constraint on {child_widget.__str__()} can't resize, autoresize set to True"
@@ -242,28 +277,39 @@ class AspectRatio(Constraint):
242
277
  return
243
278
  child_widget.set_autoresize_h(False)
244
279
  print("HERE")
245
- child_widget.set_size((None,child_widget.rect.w * self.ratio))
280
+ child_widget.set_size((None, child_widget.rect.w * self.ratio))
281
+
246
282
 
247
283
  class AnchorBottom(Constraint):
248
284
  def __init__(self):
249
285
  super().__init__(name="anchor_bottom")
250
286
 
251
287
  def evaluate(self, parent_widget, child_widget):
252
- return child_widget.rect.top == parent_widget.get_padded_bottom() - child_widget.rect.h
288
+ return (
289
+ child_widget.rect.top
290
+ == parent_widget.get_padded_bottom() - child_widget.rect.h
291
+ )
253
292
 
254
293
  def apply_constraint(self, parent_widget, child_widget):
255
- child_widget.set_position(child_widget.rect.x,parent_widget.get_padded_bottom() - child_widget.rect.h)
294
+ child_widget.set_position(
295
+ child_widget.rect.x, parent_widget.get_padded_bottom() - child_widget.rect.h
296
+ )
297
+
256
298
 
257
299
  class AnchorBottom(Constraint):
258
300
  def __init__(self):
259
301
  super().__init__(name="anchor_bottom")
260
302
 
261
303
  def evaluate(self, parent_widget, child_widget):
262
- return child_widget.rect.top == parent_widget.get_padded_bottom() - child_widget.rect.h
304
+ return (
305
+ child_widget.rect.top
306
+ == parent_widget.get_padded_bottom() - child_widget.rect.h
307
+ )
263
308
 
264
309
  def apply_constraint(self, parent_widget, child_widget):
265
- child_widget.set_position(child_widget.rect.x,parent_widget.get_padded_bottom() - child_widget.rect.h)
266
-
310
+ child_widget.set_position(
311
+ child_widget.rect.x, parent_widget.get_padded_bottom() - child_widget.rect.h
312
+ )
267
313
 
268
314
 
269
315
  class AnchorTopRight(Constraint):
@@ -334,10 +380,12 @@ class MarginBottom(Constraint):
334
380
  )
335
381
 
336
382
  def apply_constraint(self, parent_widget, child_widget):
337
- child_widget.set_position(child_widget.rect.x,
338
- parent_widget.get_padded_bottom() - child_widget.rect.h - self.margin
383
+ child_widget.set_position(
384
+ child_widget.rect.x,
385
+ parent_widget.get_padded_bottom() - child_widget.rect.h - self.margin,
339
386
  )
340
387
 
388
+
341
389
  class MarginTop(Constraint):
342
390
  def __init__(self, margin: float):
343
391
  super().__init__(name="margin_top")
@@ -347,7 +395,9 @@ class MarginTop(Constraint):
347
395
  return child_widget.rect.top == parent_widget.get_padded_top() + self.margin
348
396
 
349
397
  def apply_constraint(self, parent_widget, child_widget):
350
- child_widget.set_position(child_widget.rect.x,parent_widget.get_padded_top() + self.margin)
398
+ child_widget.set_position(
399
+ child_widget.rect.x, parent_widget.get_padded_top() + self.margin
400
+ )
351
401
 
352
402
 
353
403
  class MarginLeft(Constraint):
@@ -360,7 +410,9 @@ class MarginLeft(Constraint):
360
410
 
361
411
  def apply_constraint(self, parent_widget, child_widget):
362
412
  if not self.evaluate(parent_widget, child_widget):
363
- child_widget.set_position(parent_widget.get_padded_left() + self.margin,child_widget.rect.y)
413
+ child_widget.set_position(
414
+ parent_widget.get_padded_left() + self.margin, child_widget.rect.y
415
+ )
364
416
 
365
417
 
366
418
  class MarginRight(Constraint):
@@ -374,5 +426,165 @@ class MarginRight(Constraint):
374
426
  def apply_constraint(self, parent_widget, child_widget):
375
427
  child_widget.set_position(
376
428
  parent_widget.get_padded_right() - child_widget.rect.w - self.margin,
377
- child_widget.rect.y
429
+ child_widget.rect.y,
430
+ )
431
+
432
+
433
+ class PercentageMarginBottom(Constraint):
434
+ def __init__(self, margin: float):
435
+ super().__init__(name="percentage_margin_bottom")
436
+ self.margin = margin
437
+
438
+ def evaluate(self, parent_widget, child_widget):
439
+ return (
440
+ child_widget.rect.bottom
441
+ == parent_widget.get_padded_top()
442
+ + parent_widget.get_padded_height() * self.margin
443
+ )
444
+
445
+ def apply_constraint(self, parent_widget, child_widget):
446
+ child_widget.set_position(
447
+ child_widget.rect.x,
448
+ parent_widget.get_padded_bottom()
449
+ - child_widget.rect.h
450
+ - parent_widget.get_padded_height() * self.margin,
451
+ )
452
+
453
+
454
+ class PercentageMarginTop(Constraint):
455
+ def __init__(self, margin: float):
456
+ super().__init__(name="percentage_margin_top")
457
+ self.margin = margin
458
+
459
+ def evaluate(self, parent_widget, child_widget):
460
+ return (
461
+ child_widget.rect.top
462
+ == parent_widget.get_padded_top()
463
+ + parent_widget.get_padded_height() * self.margin
464
+ )
465
+
466
+ def apply_constraint(self, parent_widget, child_widget):
467
+ child_widget.set_position(
468
+ child_widget.rect.x,
469
+ parent_widget.get_padded_top()
470
+ + parent_widget.get_padded_height() * self.margin,
471
+ )
472
+
473
+
474
+ class PercentageMarginLeft(Constraint):
475
+ def __init__(self, margin: float):
476
+ super().__init__(name="percentage_margin_left")
477
+ self.margin = margin
478
+
479
+ def evaluate(self, parent_widget, child_widget):
480
+ return (
481
+ child_widget.rect.left
482
+ == parent_widget.get_padded_left()
483
+ + parent_widget.get_padded_width() * self.margin
484
+ )
485
+
486
+ def apply_constraint(self, parent_widget, child_widget):
487
+ if not self.evaluate(parent_widget, child_widget):
488
+ child_widget.set_position(
489
+ parent_widget.get_padded_left()
490
+ + parent_widget.get_padded_width() * self.margin,
491
+ child_widget.rect.y,
492
+ )
493
+
494
+
495
+ class PercentageMarginRight(Constraint):
496
+ def __init__(self, margin: float):
497
+ super().__init__(name="percentage_margin_right")
498
+ self.margin = margin
499
+
500
+ def evaluate(self, parent_widget, child_widget):
501
+ return (
502
+ child_widget.rect.right
503
+ == parent_widget.get_padded_right()
504
+ - parent_widget.get_padded_width() * self.margin
505
+ )
506
+
507
+ def apply_constraint(self, parent_widget, child_widget):
508
+ child_widget.set_position(
509
+ parent_widget.get_padded_right()
510
+ - child_widget.rect.w
511
+ - parent_widget.get_padded_width() * self.margin,
512
+ child_widget.rect.y,
513
+ )
514
+
515
+
516
+ class PercentageRectMarginBottom(Constraint):
517
+ def __init__(self, margin: float):
518
+ super().__init__(name="percentage_rect_margin_bottom")
519
+ self.margin = margin
520
+
521
+ def evaluate(self, parent_widget, child_widget):
522
+ return (
523
+ child_widget.rect.bottom
524
+ == parent_widget.rect.top + parent_widget.rect.height * self.margin
525
+ )
526
+
527
+ def apply_constraint(self, parent_widget, child_widget):
528
+ child_widget.set_position(
529
+ child_widget.rect.x,
530
+ parent_widget.rect.bottom
531
+ - child_widget.rect.height
532
+ - parent_widget.rect.height * self.margin,
533
+ )
534
+
535
+
536
+ class PercentageRectMarginTop(Constraint):
537
+ def __init__(self, margin: float):
538
+ super().__init__(name="percentage_rect_margin_top")
539
+ self.margin = margin
540
+
541
+ def evaluate(self, parent_widget, child_widget):
542
+ return (
543
+ child_widget.rect.top
544
+ == parent_widget.rect.top + parent_widget.rect.height * self.margin
545
+ )
546
+
547
+ def apply_constraint(self, parent_widget, child_widget):
548
+ child_widget.set_position(
549
+ child_widget.rect.x,
550
+ parent_widget.rect.top + parent_widget.rect.height * self.margin,
551
+ )
552
+
553
+
554
+ class PercentageRectMarginLeft(Constraint):
555
+ def __init__(self, margin: float):
556
+ super().__init__(name="percentage_rect_margin_left")
557
+ self.margin = margin
558
+
559
+ def evaluate(self, parent_widget, child_widget):
560
+ return (
561
+ child_widget.rect.left
562
+ == parent_widget.rect.left + parent_widget.rect.width * self.margin
563
+ )
564
+
565
+ def apply_constraint(self, parent_widget, child_widget):
566
+ if not self.evaluate(parent_widget, child_widget):
567
+ child_widget.set_position(
568
+ parent_widget.rect.left + parent_widget.rect.width * self.margin,
569
+ child_widget.rect.y,
570
+ )
571
+
572
+
573
+ class PercentageRectMarginRight(Constraint):
574
+ def __init__(self, margin: float):
575
+ super().__init__(name="percentage_rect_margin_right")
576
+ self.margin = margin
577
+
578
+ def evaluate(self, parent_widget, child_widget):
579
+ return (
580
+ child_widget.rect.right
581
+ == parent_widget.rect.right - parent_widget.rect.width * self.margin
582
+ )
583
+
584
+ def apply_constraint(self, parent_widget, child_widget):
585
+ child_widget.set_position(
586
+ parent_widget.rect.right
587
+ - child_widget.rect.width
588
+ - parent_widget.rect.width * self.margin,
589
+ child_widget.rect.y,
378
590
  )
@@ -20,6 +20,9 @@ class Container(Shape, InteractiveWidget):
20
20
  self.layout.set_parent(self)
21
21
  self.add(*children)
22
22
 
23
+ def __str__(self) -> str:
24
+ return f"Container({self.uid},{len(self.children)})"
25
+
23
26
  def get_min_required_size(self):
24
27
  if self.layout:
25
28
  return self.layout.get_auto_size()
@@ -50,6 +53,23 @@ class Container(Shape, InteractiveWidget):
50
53
  self.dirty_children = True
51
54
  return self
52
55
 
56
+ def clamp_scroll(self) -> Self:
57
+ if not self.children:
58
+ return Self
59
+ r = self.get_padded_rect()
60
+ size = self.children[0].rect.unionall(self.children[1:]).size
61
+
62
+ # Calculate the maximum scroll values
63
+ max_scroll_x = max(0, size[0] - r.width)
64
+ max_scroll_y = max(0, size[1] - r.height)
65
+
66
+ # Clamp the scroll values
67
+ self.scroll.x = max(0, min(self.scroll.x, max_scroll_x))
68
+ self.scroll.y = max(0, min(self.scroll.y, max_scroll_y))
69
+
70
+ self.dirty_children = True
71
+ return self
72
+
53
73
  def set_layout(self, layout: Layout) -> Self:
54
74
  tmp = self.layout
55
75
  self.layout = layout
@@ -57,23 +77,16 @@ class Container(Shape, InteractiveWidget):
57
77
  self.dirty_children = True
58
78
  return self
59
79
 
60
-
61
- def get_debug_outlines(self):
62
- yield (self.rect, self.debug_color)
63
- yield (self.get_padded_rect(), self.debug_color)
64
-
65
- for child in self.children:
66
- yield from child.get_debug_outlines()
67
- # for data in child.get_debug_outlines():
68
-
69
80
  def get_interactive_children(self) -> list[InteractiveWidget]:
70
81
  return [
71
- child for child in self.children if isinstance(child, InteractiveWidget) and child.allow_focus_to_self()
82
+ child
83
+ for child in self.children
84
+ if isinstance(child, InteractiveWidget) and child.allow_focus_to_self()
72
85
  ]
73
86
 
74
87
  def focus_next_child(self) -> None:
75
88
  self.layout.focus_next_child()
76
-
89
+
77
90
  def focus_prev_child(self) -> None:
78
91
  self.layout.focus_prev_child()
79
92
 
@@ -94,14 +107,11 @@ class Container(Shape, InteractiveWidget):
94
107
  def resolve_constraints(self) -> None:
95
108
  super().resolve_constraints()
96
109
 
97
- def __str__(self) -> str:
98
- return f"Container({self.uid},{len(self.children)})"
99
-
100
110
  def top_at(self, x: float | int, y: float | int) -> "None|Widget":
101
111
  if self.visible and self.rect.collidepoint(x, y):
102
112
  if self.children:
103
113
  for child in reversed(self.children):
104
- r = child.top_at(x,y)
114
+ r = child.top_at(x, y)
105
115
  if r is not None:
106
116
  return r
107
117
  return self
@@ -117,16 +127,22 @@ class Container(Shape, InteractiveWidget):
117
127
  self.focused_index = min(self.focused_index, len(l))
118
128
  return l[self.focused_index].get_focus()
119
129
 
130
+ def do_handle_event(self, event):
131
+ self.layout.handle_event(event)
132
+
120
133
  def set_focused_child(self, child: InteractiveWidget) -> bool:
121
134
  l = self.get_interactive_children()
122
- i = l.index(child)
135
+ try:
136
+ i = l.index(child)
137
+ except ValueError:
138
+ return False
123
139
  if i >= 0:
124
140
  self.focused_index = i
125
141
  return True
126
142
  return False
127
143
 
128
144
  def allow_focus_to_self(self) -> bool:
129
- return len(self.get_interactive_children()) != 0
145
+ return len(self.get_interactive_children()) != 0 and self.visible
130
146
 
131
147
  def draw(self, camera: bf.Camera) -> None:
132
148
  constraints_down = False
@@ -144,7 +160,8 @@ class Container(Shape, InteractiveWidget):
144
160
  self.parent.visit_up(self.selective_up)
145
161
  else:
146
162
  constraints_down = True
147
-
163
+ if not self.dirty_children:
164
+ self.dirty_children = any(c.dirty_shape for c in self.children)
148
165
  if self.dirty_children:
149
166
  if self.layout:
150
167
  self.layout.arrange()
@@ -157,7 +174,6 @@ class Container(Shape, InteractiveWidget):
157
174
  self.paint()
158
175
  self.dirty_surface = False
159
176
 
160
-
161
177
  bf.Entity.draw(self, camera)
162
178
 
163
179
  if self.clip_children:
@@ -166,8 +182,10 @@ class Container(Shape, InteractiveWidget):
166
182
  new_clip = new_clip.clip(old_clip)
167
183
  camera.surface.set_clip(new_clip)
168
184
  # Draw children with adjusted positions
169
- _ = [child.draw(camera) for child in sorted(self.children, key=lambda c: c.render_order)]
185
+ _ = [
186
+ child.draw(camera)
187
+ for child in sorted(self.children, key=lambda c: c.render_order)
188
+ ]
170
189
 
171
190
  if self.clip_children:
172
191
  camera.surface.set_clip(old_clip)
173
-
@@ -7,6 +7,7 @@ import pygame
7
7
  def convert_to_int(*args):
8
8
  return [int(arg) for arg in args]
9
9
 
10
+
10
11
  class Debugger(Label):
11
12
  def __init__(self) -> None:
12
13
  super().__init__("")
@@ -17,12 +18,6 @@ class Debugger(Label):
17
18
  self.add_tags("debugger")
18
19
  self.set_visible(False)
19
20
 
20
- # def get_debug_outlines(self):
21
- # yield None
22
-
23
- def to_string_id(self) -> str:
24
- return "Debugger"
25
-
26
21
  def set_refresh_rate(self, value: int) -> Self:
27
22
  self.refresh_rate = value
28
23
  return self
@@ -61,14 +56,17 @@ class Debugger(Label):
61
56
  def update_text(self) -> None:
62
57
  if not self.parent_scene:
63
58
  return
59
+
64
60
  d = "\n".join(
65
61
  key + ":" + data if key != "" else data
66
62
  for key, data in self.static_data.items()
67
63
  )
64
+
68
65
  d2 = "\n".join(
69
66
  key + ":" + str(data()) if key != "" else str(data())
70
67
  for key, data in self.dynamic_data.items()
71
68
  )
69
+
72
70
  self.set_text("\n".join((d, d2)).strip())
73
71
 
74
72
  def update(self, dt: float) -> None:
@@ -83,13 +81,17 @@ class Debugger(Label):
83
81
  self.refresh_counter = 0
84
82
  self.update_text()
85
83
 
86
-
87
- def __str__(self)->str:
84
+ def __str__(self) -> str:
88
85
  return "Debugger"
89
- # def top_at(self,x,y):
90
- # return None
86
+
87
+ def top_at(self, x, y):
88
+ return None
89
+
91
90
 
92
91
  class FPSDebugger(Debugger):
92
+ def __init__(self):
93
+ super().__init__()
94
+
93
95
  def do_when_added(self):
94
96
  if not self.parent_scene or not self.parent_scene.manager:
95
97
  print("Debugger could not link to the manager")
@@ -125,4 +127,9 @@ class BasicDebugger(FPSDebugger):
125
127
  self.add_dynamic("W. Ent.", lambda: parent_scene.get_world_entity_count())
126
128
  self.add_dynamic("H. Ent.", lambda: parent_scene.get_hud_entity_count())
127
129
 
128
- self.add_dynamic("Hover",lambda : str(parent_scene.root.hovered) if parent_scene.root.hovered else None)
130
+ self.add_dynamic(
131
+ "Hover",
132
+ lambda: (
133
+ str(parent_scene.root.hovered) if parent_scene.root.hovered else None
134
+ ),
135
+ )