batframework 1.0.8a4__py3-none-any.whl → 1.0.8a7__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 (38) hide show
  1. batFramework/__init__.py +15 -1
  2. batFramework/animatedSprite.py +65 -50
  3. batFramework/character.py +27 -0
  4. batFramework/dynamicEntity.py +1 -0
  5. batFramework/enums.py +2 -2
  6. batFramework/fontManager.py +2 -2
  7. batFramework/gui/clickableWidget.py +6 -7
  8. batFramework/gui/constraints/constraints.py +125 -40
  9. batFramework/gui/image.py +14 -14
  10. batFramework/gui/interactiveWidget.py +15 -0
  11. batFramework/gui/label.py +44 -27
  12. batFramework/gui/layout.py +23 -14
  13. batFramework/gui/meter.py +10 -7
  14. batFramework/gui/radioButton.py +1 -1
  15. batFramework/gui/shape.py +3 -25
  16. batFramework/gui/slider.py +40 -30
  17. batFramework/gui/textInput.py +160 -50
  18. batFramework/gui/toggle.py +20 -22
  19. batFramework/gui/widget.py +65 -32
  20. batFramework/manager.py +17 -5
  21. batFramework/object.py +17 -8
  22. batFramework/particle.py +18 -4
  23. batFramework/scene.py +1 -1
  24. batFramework/sceneManager.py +42 -13
  25. batFramework/stateMachine.py +9 -6
  26. batFramework/templates/__init__.py +2 -0
  27. batFramework/templates/character.py +44 -0
  28. batFramework/templates/states.py +166 -0
  29. batFramework/time.py +31 -9
  30. batFramework/transition.py +2 -2
  31. batFramework/triggerZone.py +1 -1
  32. batFramework/utils.py +35 -6
  33. {batframework-1.0.8a4.dist-info → batframework-1.0.8a7.dist-info}/METADATA +3 -15
  34. batframework-1.0.8a7.dist-info/RECORD +62 -0
  35. {batframework-1.0.8a4.dist-info → batframework-1.0.8a7.dist-info}/WHEEL +1 -1
  36. batframework-1.0.8a4.dist-info/RECORD +0 -58
  37. {batframework-1.0.8a4.dist-info → batframework-1.0.8a7.dist-info}/LICENCE +0 -0
  38. {batframework-1.0.8a4.dist-info → batframework-1.0.8a7.dist-info}/top_level.txt +0 -0
@@ -4,9 +4,12 @@ import pygame
4
4
 
5
5
 
6
6
  class Constraint:
7
- def __init__(self, name="Constraint", priority=0):
7
+ def __init__(self, name:str|None=None, priority=0):
8
8
  self.priority = priority
9
- self.name = name
9
+ self.name = name if name is not None else self.__class__.__name__
10
+
11
+ def on_removal(self,child_widget: Widget)->None:
12
+ pass
10
13
 
11
14
  def set_priority(self, priority) -> "Constraint":
12
15
  self.priority = priority
@@ -34,13 +37,20 @@ class Constraint:
34
37
 
35
38
  class MinWidth(Constraint):
36
39
  def __init__(self, width: float):
37
- super().__init__(name="min_width")
40
+ super().__init__()
38
41
  self.min_width = width
39
42
 
43
+ def on_removal(self, child_widget: Widget) -> None:
44
+ child_widget.set_autoresize_w(False)
45
+
40
46
  def evaluate(self, parent_widget, child_widget):
41
- return child_widget.rect.width >= self.min_width
47
+ res = child_widget.rect.width >= self.min_width
48
+ if not res:
49
+ child_widget.set_autoresize_w(False)
50
+ return res
42
51
 
43
52
  def apply_constraint(self, parent_widget, child_widget):
53
+ child_widget.set_autoresize_w(True)
44
54
  child_widget.set_size((self.min_width, None))
45
55
 
46
56
  def __eq__(self,other:"Constraint")->bool:
@@ -53,11 +63,17 @@ class MinWidth(Constraint):
53
63
 
54
64
  class MinHeight(Constraint):
55
65
  def __init__(self, height: float):
56
- super().__init__(name="min_height")
66
+ super().__init__()
57
67
  self.min_height = height
58
68
 
69
+ def on_removal(self, child_widget: Widget) -> None:
70
+ child_widget.set_autoresize_h(False)
71
+
59
72
  def evaluate(self, parent_widget, child_widget):
60
- return child_widget.rect.h >= self.min_height
73
+ res = child_widget.rect.h >= self.min_height
74
+ if not res:
75
+ child_widget.set_autoresize_w(False)
76
+ return res
61
77
 
62
78
  def apply_constraint(self, parent_widget, child_widget):
63
79
  child_widget.set_size((None, self.min_height))
@@ -70,9 +86,60 @@ class MinHeight(Constraint):
70
86
  other.min_height == self.min_height
71
87
  )
72
88
 
89
+ class MaxWidth(Constraint):
90
+ def __init__(self, width: float):
91
+ super().__init__()
92
+ self.max_width = width
93
+
94
+ def on_removal(self, child_widget: Widget) -> None:
95
+ child_widget.set_autoresize_w(False)
96
+
97
+ def evaluate(self, parent_widget, child_widget):
98
+ res = child_widget.rect.width <= self.max_width
99
+ if not res:
100
+ child_widget.set_autoresize_w(False)
101
+ return res
102
+
103
+ def apply_constraint(self, parent_widget, child_widget):
104
+ child_widget.set_autoresize_w(True)
105
+ current_height = child_widget.rect.height
106
+ child_widget.set_size((self.max_width, current_height))
107
+
108
+ def __eq__(self, other: "Constraint") -> bool:
109
+ if not isinstance(other, self.__class__):
110
+ return False
111
+ return other.max_width == self.max_width
112
+
113
+
114
+ class MaxHeight(Constraint):
115
+ def __init__(self, height: float):
116
+ super().__init__()
117
+ self.max_height = height
118
+
119
+ def on_removal(self, child_widget: Widget) -> None:
120
+ child_widget.set_autoresize_h(False)
121
+
122
+ def evaluate(self, parent_widget, child_widget):
123
+ res = child_widget.rect.height <= self.max_height
124
+ if not res:
125
+ child_widget.set_autoresize_h(False)
126
+ return res
127
+
128
+ def apply_constraint(self, parent_widget, child_widget):
129
+ child_widget.set_autoresize_h(True)
130
+ current_width = child_widget.rect.width
131
+ child_widget.set_size((current_width, self.max_height))
132
+
133
+ def __eq__(self, other: "Constraint") -> bool:
134
+ if not isinstance(other, self.__class__):
135
+ return False
136
+ return other.max_height == self.max_height
137
+
138
+
139
+
73
140
  class CenterX(Constraint):
74
141
  def __init__(self):
75
- super().__init__(name="centerx")
142
+ super().__init__()
76
143
 
77
144
  def evaluate(self, parent_widget, child_widget):
78
145
  return (
@@ -87,7 +154,7 @@ class CenterX(Constraint):
87
154
 
88
155
  class CenterY(Constraint):
89
156
  def __init__(self):
90
- super().__init__(name="centery")
157
+ super().__init__()
91
158
 
92
159
  def evaluate(self, parent_widget, child_widget):
93
160
  return (
@@ -102,7 +169,7 @@ class CenterY(Constraint):
102
169
 
103
170
  class Center(Constraint):
104
171
  def __init__(self):
105
- super().__init__(name="center")
172
+ super().__init__()
106
173
 
107
174
  def evaluate(self, parent_widget, child_widget):
108
175
  return (
@@ -117,10 +184,13 @@ class Center(Constraint):
117
184
 
118
185
  class PercentageWidth(Constraint):
119
186
  def __init__(self, percentage: float, keep_autoresize: bool = False):
120
- super().__init__(name="percentage_width")
187
+ super().__init__()
121
188
  self.percentage: float = percentage
122
189
  self.keep_autoresize: bool = keep_autoresize
123
190
 
191
+ def on_removal(self, child_widget: Widget) -> None:
192
+ child_widget.set_autoresize_w(True)
193
+
124
194
  def __str__(self) -> str:
125
195
  return f"{super().__str__()}.[{self.percentage*100}%,keep_autoresize={self.keep_autoresize}]"
126
196
 
@@ -153,10 +223,13 @@ class PercentageWidth(Constraint):
153
223
 
154
224
  class PercentageHeight(Constraint):
155
225
  def __init__(self, percentage: float, keep_autoresize: bool = False):
156
- super().__init__(name="percentage_height")
226
+ super().__init__()
157
227
  self.percentage: float = percentage
158
228
  self.keep_autoresize: bool = keep_autoresize
159
229
 
230
+ def on_removal(self, child_widget: Widget) -> None:
231
+ child_widget.set_autoresize_h(True)
232
+
160
233
  def evaluate(self, parent_widget, child_widget):
161
234
  return child_widget.rect.height == round(
162
235
  parent_widget.get_padded_height() * self.percentage
@@ -188,7 +261,7 @@ class PercentageHeight(Constraint):
188
261
  class FillX(PercentageWidth):
189
262
  def __init__(self, keep_autoresize: bool = False):
190
263
  super().__init__(1, keep_autoresize)
191
- self.name = "fill_x"
264
+ self.name = "FillX"
192
265
 
193
266
  def __eq__(self, other: Constraint) -> bool:
194
267
  return Constraint.__eq__(self,other)
@@ -196,7 +269,7 @@ class FillX(PercentageWidth):
196
269
  class FillY(PercentageHeight):
197
270
  def __init__(self, keep_autoresize: bool = False):
198
271
  super().__init__(1, keep_autoresize)
199
- self.name = "fill_y"
272
+ self.name = "FillY"
200
273
 
201
274
  def __eq__(self, other: Constraint) -> bool:
202
275
  return Constraint.__eq__(self,other)
@@ -204,10 +277,13 @@ class FillY(PercentageHeight):
204
277
 
205
278
  class PercentageRectHeight(Constraint):
206
279
  def __init__(self, percentage: float, keep_autoresize: bool = False):
207
- super().__init__(name="percentage_rect_height")
280
+ super().__init__()
208
281
  self.percentage: float = percentage
209
282
  self.keep_autoresize: bool = keep_autoresize
210
283
 
284
+ def on_removal(self, child_widget: Widget) -> None:
285
+ child_widget.set_autoresize_h(True)
286
+
211
287
  def evaluate(self, parent_widget, child_widget):
212
288
  return child_widget.rect.height == round(
213
289
  parent_widget.rect.height * self.percentage
@@ -238,10 +314,13 @@ class PercentageRectHeight(Constraint):
238
314
 
239
315
  class PercentageRectWidth(Constraint):
240
316
  def __init__(self, percentage: float, keep_autoresize: bool = False):
241
- super().__init__(name="percentage_rect_width")
317
+ super().__init__()
242
318
  self.percentage: float = percentage
243
319
  self.keep_autoresize: bool = keep_autoresize
244
320
 
321
+ def on_removal(self, child_widget: Widget) -> None:
322
+ child_widget.set_autoresize_w(True)
323
+
245
324
  def evaluate(self, parent_widget, child_widget):
246
325
  return child_widget.rect.width == round(
247
326
  parent_widget.rect.width * self.percentage
@@ -287,7 +366,7 @@ class AspectRatio(Constraint):
287
366
  reference_axis: bf.axis = bf.axis.HORIZONTAL,
288
367
  keep_autoresize=False,
289
368
  ):
290
- super().__init__(name="aspect_ratio")
369
+ super().__init__()
291
370
  self.ref_axis: bf.axis = reference_axis
292
371
  self.keep_autoresize: bool = keep_autoresize
293
372
 
@@ -302,6 +381,10 @@ class AspectRatio(Constraint):
302
381
  else:
303
382
  raise TypeError(f"Ratio must be float or FRect")
304
383
 
384
+ def on_removal(self, child_widget: Widget) -> None:
385
+ child_widget.set_autoresize(True)
386
+
387
+
305
388
  def evaluate(self, parent_widget, child_widget):
306
389
  if self.ref_axis == bf.axis.HORIZONTAL:
307
390
  return self.ratio == child_widget.rect.h / child_widget.rect.w
@@ -343,7 +426,7 @@ class AspectRatio(Constraint):
343
426
 
344
427
  class AnchorBottom(Constraint):
345
428
  def __init__(self):
346
- super().__init__(name="anchor_bottom")
429
+ super().__init__()
347
430
 
348
431
  def evaluate(self, parent_widget, child_widget):
349
432
  return (
@@ -358,7 +441,7 @@ class AnchorBottom(Constraint):
358
441
 
359
442
  class AnchorTop(Constraint):
360
443
  def __init__(self):
361
- super().__init__(name="anchor_top")
444
+ super().__init__()
362
445
 
363
446
  def evaluate(self, parent_widget, child_widget):
364
447
  return (child_widget.rect.top == parent_widget.get_padded_top())
@@ -369,21 +452,21 @@ class AnchorTop(Constraint):
369
452
 
370
453
  class AnchorTopRight(Constraint):
371
454
  def __init__(self):
372
- super().__init__(name="anchor_topright")
455
+ super().__init__()
373
456
 
374
457
  def evaluate(self, parent_widget, child_widget):
375
458
  return child_widget.rect.topright == parent_widget.get_padded_rect().topright
376
459
 
377
460
  def apply_constraint(self, parent_widget, child_widget):
378
- child_widget.set_position(
379
- parent_widget.get_padded_right() - child_widget.rect.w,
380
- parent_widget.get_padded_top(),
381
- )
461
+ # print("before",child_widget.rect.topright, parent_widget.get_padded_rect().topright)
462
+ topright = parent_widget.get_padded_rect().topright
463
+ child_widget.set_position(topright[0] - child_widget.rect.w,topright[1])
464
+ # print("after",child_widget.rect.topright, parent_widget.get_padded_rect().topright)
382
465
 
383
466
 
384
467
  class AnchorBottomRight(Constraint):
385
468
  def __init__(self):
386
- super().__init__(name="anchor_bottomright")
469
+ super().__init__()
387
470
 
388
471
  def evaluate(self, parent_widget, child_widget):
389
472
  return (
@@ -391,15 +474,17 @@ class AnchorBottomRight(Constraint):
391
474
  )
392
475
 
393
476
  def apply_constraint(self, parent_widget, child_widget):
477
+ bottomright = parent_widget.get_padded_rect().bottomright
478
+
394
479
  child_widget.set_position(
395
- parent_widget.get_padded_right() - child_widget.rect.w,
396
- parent_widget.get_padded_bottom() - child_widget.rect.h,
480
+ bottomright[0] - child_widget.rect.w,
481
+ bottomright[1] - child_widget.rect.h,
397
482
  )
398
483
 
399
484
 
400
485
  class AnchorRight(Constraint):
401
486
  def __init__(self):
402
- super().__init__(name="anchor_right")
487
+ super().__init__()
403
488
 
404
489
  def evaluate(self, parent_widget, child_widget):
405
490
  return child_widget.rect.right == parent_widget.get_padded_right()
@@ -413,7 +498,7 @@ class AnchorRight(Constraint):
413
498
 
414
499
  class AnchorLeft(Constraint):
415
500
  def __init__(self):
416
- super().__init__(name="anchor_left")
501
+ super().__init__()
417
502
 
418
503
  def evaluate(self, parent_widget, child_widget):
419
504
  return child_widget.rect.left == parent_widget.get_padded_left()
@@ -426,7 +511,7 @@ class AnchorLeft(Constraint):
426
511
 
427
512
  class MarginBottom(Constraint):
428
513
  def __init__(self, margin: float):
429
- super().__init__(name="margin_bottom")
514
+ super().__init__()
430
515
  self.margin = margin
431
516
 
432
517
  def evaluate(self, parent_widget, child_widget):
@@ -450,7 +535,7 @@ class MarginBottom(Constraint):
450
535
 
451
536
  class MarginTop(Constraint):
452
537
  def __init__(self, margin: float):
453
- super().__init__(name="margin_top")
538
+ super().__init__()
454
539
  self.margin = margin
455
540
 
456
541
  def evaluate(self, parent_widget, child_widget):
@@ -471,7 +556,7 @@ class MarginTop(Constraint):
471
556
 
472
557
  class MarginLeft(Constraint):
473
558
  def __init__(self, margin: float):
474
- super().__init__(name="margin_left")
559
+ super().__init__()
475
560
  self.margin = margin
476
561
 
477
562
  def evaluate(self, parent_widget, child_widget):
@@ -493,7 +578,7 @@ class MarginLeft(Constraint):
493
578
 
494
579
  class MarginRight(Constraint):
495
580
  def __init__(self, margin: float):
496
- super().__init__(name="margin_right")
581
+ super().__init__()
497
582
  self.margin = margin
498
583
 
499
584
  def evaluate(self, parent_widget, child_widget):
@@ -515,7 +600,7 @@ class MarginRight(Constraint):
515
600
 
516
601
  class PercentageMarginBottom(Constraint):
517
602
  def __init__(self, margin: float):
518
- super().__init__(name="percentage_margin_bottom")
603
+ super().__init__()
519
604
  self.margin = margin
520
605
 
521
606
  def evaluate(self, parent_widget, child_widget):
@@ -543,7 +628,7 @@ class PercentageMarginBottom(Constraint):
543
628
 
544
629
  class PercentageMarginTop(Constraint):
545
630
  def __init__(self, margin: float):
546
- super().__init__(name="percentage_margin_top")
631
+ super().__init__()
547
632
  self.margin = margin
548
633
 
549
634
  def evaluate(self, parent_widget, child_widget):
@@ -570,7 +655,7 @@ class PercentageMarginTop(Constraint):
570
655
 
571
656
  class PercentageMarginLeft(Constraint):
572
657
  def __init__(self, margin: float):
573
- super().__init__(name="percentage_margin_left")
658
+ super().__init__()
574
659
  self.margin = margin
575
660
 
576
661
  def evaluate(self, parent_widget, child_widget):
@@ -598,7 +683,7 @@ class PercentageMarginLeft(Constraint):
598
683
 
599
684
  class PercentageMarginRight(Constraint):
600
685
  def __init__(self, margin: float):
601
- super().__init__(name="percentage_margin_right")
686
+ super().__init__()
602
687
  self.margin = margin
603
688
 
604
689
  def evaluate(self, parent_widget, child_widget):
@@ -626,7 +711,7 @@ class PercentageMarginRight(Constraint):
626
711
 
627
712
  class PercentageRectMarginBottom(Constraint):
628
713
  def __init__(self, margin: float):
629
- super().__init__(name="percentage_rect_margin_bottom")
714
+ super().__init__()
630
715
  self.margin = margin
631
716
 
632
717
  def evaluate(self, parent_widget, child_widget):
@@ -653,7 +738,7 @@ class PercentageRectMarginBottom(Constraint):
653
738
 
654
739
  class PercentageRectMarginTop(Constraint):
655
740
  def __init__(self, margin: float):
656
- super().__init__(name="percentage_rect_margin_top")
741
+ super().__init__()
657
742
  self.margin = margin
658
743
 
659
744
  def evaluate(self, parent_widget, child_widget):
@@ -678,7 +763,7 @@ class PercentageRectMarginTop(Constraint):
678
763
 
679
764
  class PercentageRectMarginLeft(Constraint):
680
765
  def __init__(self, margin: float):
681
- super().__init__(name="percentage_rect_margin_left")
766
+ super().__init__()
682
767
  self.margin = margin
683
768
 
684
769
  def evaluate(self, parent_widget, child_widget):
@@ -704,7 +789,7 @@ class PercentageRectMarginLeft(Constraint):
704
789
 
705
790
  class PercentageRectMarginRight(Constraint):
706
791
  def __init__(self, margin: float):
707
- super().__init__(name="percentage_rect_margin_right")
792
+ super().__init__()
708
793
  self.margin = margin
709
794
 
710
795
  def evaluate(self, parent_widget, child_widget):
batFramework/gui/image.py CHANGED
@@ -21,15 +21,22 @@ class Image(Shape):
21
21
 
22
22
  def paint(self) -> None:
23
23
  super().paint()
24
- # self.surface.fill((0,0,0,0 if self.convert_alpha else 255))
25
24
  if self.original_surface is None:
26
25
  return
27
- if self.rect.size != self.original_surface.get_size():
28
- self.surface.blit(
29
- pygame.transform.scale(self.original_surface, self.rect.size), (0, 0)
30
- )
26
+ padded = self.get_padded_rect().move(-self.rect.x,-self.rect.y)
27
+ target_size = padded.size
28
+ if self.original_surface.get_size() != target_size:
29
+ self.surface.blit(pygame.transform.scale(self.original_surface, target_size), padded.topleft)
31
30
  else:
32
- self.surface.blit(self.original_surface, (0, 0))
31
+ self.surface.blit(self.original_surface, padded.topleft)
32
+
33
+ def build(self) -> None:
34
+ if self.original_surface is not None:
35
+ self.set_size_if_autoresize(
36
+ self.inflate_rect_by_padding((0,0,*self.original_surface.get_size())).size
37
+ )
38
+ super().build()
39
+
33
40
 
34
41
  def from_path(self, path: str) -> Self:
35
42
  tmp = bf.ResourceManager().get_image(path, self.convert_alpha)
@@ -37,10 +44,6 @@ class Image(Shape):
37
44
  return self
38
45
  self.original_surface = tmp
39
46
  size = self.original_surface.get_size()
40
- if not self.autoresize_h:
41
- size[0] = None
42
- if not self.autoresize_h:
43
- size[1] = None
44
47
  self.set_size(size)
45
48
  self.dirty_surface = True
46
49
  return self
@@ -50,10 +53,7 @@ class Image(Shape):
50
53
  return self
51
54
  self.original_surface = surface
52
55
  size = self.original_surface.get_size()
53
- if not self.autoresize_h:
54
- size[0] = None
55
- if not self.autoresize_h:
56
- size[1] = None
57
56
  self.set_size(size)
57
+
58
58
  self.dirty_surface = True
59
59
  return self
@@ -8,6 +8,14 @@ if TYPE_CHECKING:
8
8
  from .container import Container
9
9
  import batFramework as bf
10
10
 
11
+ def children_has_focus(widget):
12
+ if isinstance(widget,InteractiveWidget) and widget.is_focused:
13
+ return True
14
+ for child in widget.children:
15
+ if children_has_focus(child):
16
+ return True
17
+ return False
18
+
11
19
 
12
20
  class InteractiveWidget(Widget):
13
21
  def __init__(self, *args, **kwargs) -> None:
@@ -39,6 +47,13 @@ class InteractiveWidget(Widget):
39
47
  return True
40
48
  return False
41
49
 
50
+ def set_parent(self, parent: Widget) -> Self:
51
+ if parent is None and children_has_focus(self):
52
+ self.get_root().clear_focused()
53
+ # pass focus on
54
+
55
+ return super().set_parent(parent)
56
+
42
57
  def on_get_focus(self) -> None:
43
58
  self.is_focused = True
44
59
  self.do_on_get_focus()
batFramework/gui/label.py CHANGED
@@ -2,7 +2,7 @@ import batFramework as bf
2
2
  import pygame
3
3
  from .shape import Shape
4
4
  from typing import Self
5
-
5
+ from math import ceil
6
6
 
7
7
  class Label(Shape):
8
8
  _text_cache = {}
@@ -59,7 +59,7 @@ class Label(Shape):
59
59
  Label._text_cache = {}
60
60
 
61
61
  def __str__(self) -> str:
62
- return f"Label({self.text})"
62
+ return f"Label({repr(self.text)})"
63
63
 
64
64
  def enable_caching(self) -> Self:
65
65
  self.do_caching = True
@@ -106,6 +106,7 @@ class Label(Shape):
106
106
  m = [[self._text_outline_mask.get_at((x,y)) for x in range(min(old_size[0],size[0]))] for y in range(min(old_size[1],size[1]))]
107
107
  self._text_outline_mask = pygame.Mask(size, fill=True)
108
108
  self.set_text_outline_matrix(m)
109
+ return self
109
110
 
110
111
  def set_text_outline_matrix(self, matrix: list[list[0 | 1]]) -> Self:
111
112
  if matrix is None:
@@ -113,7 +114,7 @@ class Label(Shape):
113
114
  for y in range(3):
114
115
  for x in range(3):
115
116
  self._text_outline_mask.set_at((x, y), matrix[2 - y][2 - x])
116
- self.dirty_surface = True
117
+ self.dirty_shape = True
117
118
  return self
118
119
 
119
120
  def set_text_outline_color(self, color) -> Self:
@@ -123,12 +124,12 @@ class Label(Shape):
123
124
 
124
125
  def enable_text_outline(self) -> Self:
125
126
  self.show_text_outline = True
126
- self.dirty_surface = True
127
+ self.dirty_shape = True
127
128
  return self
128
129
 
129
130
  def disable_text_outline(self) -> Self:
130
131
  self.show_text_outline = False
131
- self.dirty_surface = True
132
+ self.dirty_shape = True
132
133
  return self
133
134
 
134
135
  def set_alignment(self, alignment: bf.alignment) -> Self:
@@ -146,7 +147,8 @@ class Label(Shape):
146
147
 
147
148
  def get_debug_outlines(self):
148
149
  if self.visible:
149
- yield (self.text_rect.move(*self.rect.topleft), "purple")
150
+ offset = self._get_outline_offset() if self.show_text_outline else (0,0)
151
+ yield (self.text_rect.move(self.rect.x - offset[0],self.rect.y - offset[1]), "purple")
150
152
  yield from super().get_debug_outlines()
151
153
 
152
154
  def set_font(self, font_name: str = None, force: bool = False) -> Self:
@@ -194,7 +196,8 @@ class Label(Shape):
194
196
  if not self.text_rect:
195
197
  self.text_rect.size = self._get_text_rect_required_size()
196
198
  res = self.inflate_rect_by_padding((0, 0, *self.text_rect.size)).size
197
- # return res
199
+
200
+ return res
198
201
  return res[0] if self.autoresize_w else self.rect.w, (
199
202
  res[1] if self.autoresize_h else self.rect.h
200
203
  )
@@ -238,22 +241,34 @@ class Label(Shape):
238
241
 
239
242
  return surf
240
243
  def _get_text_rect_required_size(self):
241
- params = {
242
- "font_name": self.font_object.name,
243
- "text": self.text,
244
- "antialias": False,
245
- "color": "white",
246
- "bgcolor": "black", # if (self.has_alpha_color() or self.draw_mode == bf.drawMode.TEXTURED) else self.color,
247
- "wraplength": int(self.get_padded_width()) if self.auto_wraplength else 0,
248
- }
244
+ font_height = self.font_object.get_linesize()
245
+ if not self.text:
246
+ # font_height = self.font_object.get_ascent() - self.font_object.get_ascent()
247
+ size = (0,font_height)
248
+ else:
249
+ tmp_text = self.text
250
+ if self.text.endswith('\n'):
251
+ tmp_text+=" "
252
+ params = {
253
+ "font_name": self.font_object.name,
254
+ "text": tmp_text,
255
+ "antialias": self.antialias,
256
+ "color": self.text_color,
257
+ "bgcolor": None, # if (self.has_alpha_color() or self.draw_mode == bf.drawMode.TEXTURED) else self.color,
258
+ "wraplength": int(self.get_padded_width()) if self.auto_wraplength and not self.autoresize_w else 0,
259
+ }
260
+
261
+ size = self._render_font(params).get_size()
262
+ size = size[0],max(font_height,size[1])
263
+ s = self._get_outline_offset() if self.show_text_outline else (0,0)
264
+ return size[0] + s[0]*2, size[1] + s[1]*2
249
265
 
250
- size = self._render_font(params).get_size()
251
- s = self._text_outline_mask.get_size()
252
- return size[0] + s[0]//2, size[1] + s[1]//2
253
266
  def _build_layout(self) -> None:
254
267
 
255
268
  self.text_rect.size = self._get_text_rect_required_size()
256
-
269
+ # self.text_rect.w = ceil(self.text_rect.w)
270
+ # self.text_rect.h = ceil(self.text_rect.h)
271
+
257
272
  if self.autoresize_h or self.autoresize_w:
258
273
  target_rect = self.inflate_rect_by_padding((0, 0, *self.text_rect.size))
259
274
  if not self.autoresize_w:
@@ -264,7 +279,8 @@ class Label(Shape):
264
279
  self.set_size(target_rect.size)
265
280
  self.build()
266
281
  return
267
- padded = self.get_padded_rect().move(-self.rect.x, -self.rect.y)
282
+ offset = self._get_outline_offset() if self.show_text_outline else (0,0)
283
+ padded = self.get_padded_rect().move(-self.rect.x + offset[0], -self.rect.y + offset[1])
268
284
  self.align_text(self.text_rect, padded, self.alignment)
269
285
 
270
286
  def _get_outline_offset(self)->tuple[int,int]:
@@ -282,8 +298,9 @@ class Label(Shape):
282
298
  "antialias": self.antialias,
283
299
  "color": self.text_color,
284
300
  "bgcolor": None, # if (self.has_alpha_color() or self.draw_mode == bf.drawMode.TEXTURED) else self.color,
285
- "wraplength": int(self.get_padded_width()) if self.auto_wraplength else 0,
301
+ "wraplength": int(self.get_padded_width()) if self.auto_wraplength and not self.autoresize_w else 0,
286
302
  }
303
+
287
304
  self.text_surface = self._render_font(params)
288
305
 
289
306
  if self.show_text_outline:
@@ -294,16 +311,15 @@ class Label(Shape):
294
311
  )
295
312
 
296
313
  l = []
297
- outline_offset = self._get_outline_offset()
314
+ outline_offset = self._get_outline_offset() if self.show_text_outline else (0,0)
315
+
298
316
  if self.show_text_outline:
299
317
  l.append(
300
- (
301
- self.text_outline_surface,
302
- self.text_rect.move(0, self.relief - self.get_relief()),
303
- )
318
+ (self.text_outline_surface,
319
+ (self.text_rect.x - outline_offset[0],self.text_rect.y - outline_offset[1]))
304
320
  )
305
321
  l.append(
306
- (self.text_surface, self.text_rect.move(outline_offset[0], self.relief - self.get_relief() + outline_offset[1]))
322
+ (self.text_surface, self.text_rect)
307
323
  )
308
324
  self.surface.fblits(l)
309
325
 
@@ -317,6 +333,7 @@ class Label(Shape):
317
333
 
318
334
  pos = area.__getattribute__(alignment.value)
319
335
  text_rect.__setattr__(alignment.value, pos)
336
+ text_rect.y = ceil(text_rect.y)
320
337
 
321
338
  def build(self) -> None:
322
339
  super().build()