batframework 1.1.0__py3-none-any.whl → 2.0.0__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 (81) hide show
  1. batFramework/__init__.py +84 -51
  2. batFramework/action.py +280 -252
  3. batFramework/actionContainer.py +105 -38
  4. batFramework/animatedSprite.py +81 -117
  5. batFramework/animation.py +91 -0
  6. batFramework/audioManager.py +156 -85
  7. batFramework/baseScene.py +249 -0
  8. batFramework/camera.py +245 -123
  9. batFramework/constants.py +57 -75
  10. batFramework/cutscene.py +239 -119
  11. batFramework/cutsceneManager.py +34 -0
  12. batFramework/drawable.py +107 -0
  13. batFramework/dynamicEntity.py +30 -23
  14. batFramework/easingController.py +58 -0
  15. batFramework/entity.py +130 -123
  16. batFramework/enums.py +171 -0
  17. batFramework/fontManager.py +65 -0
  18. batFramework/gui/__init__.py +28 -14
  19. batFramework/gui/animatedLabel.py +90 -0
  20. batFramework/gui/button.py +18 -84
  21. batFramework/gui/clickableWidget.py +244 -0
  22. batFramework/gui/collapseContainer.py +98 -0
  23. batFramework/gui/constraints/__init__.py +1 -0
  24. batFramework/gui/constraints/constraints.py +1066 -0
  25. batFramework/gui/container.py +220 -49
  26. batFramework/gui/debugger.py +140 -47
  27. batFramework/gui/draggableWidget.py +63 -0
  28. batFramework/gui/image.py +61 -23
  29. batFramework/gui/indicator.py +116 -40
  30. batFramework/gui/interactiveWidget.py +243 -22
  31. batFramework/gui/label.py +147 -110
  32. batFramework/gui/layout.py +442 -81
  33. batFramework/gui/meter.py +155 -0
  34. batFramework/gui/radioButton.py +43 -0
  35. batFramework/gui/root.py +228 -60
  36. batFramework/gui/scrollingContainer.py +282 -0
  37. batFramework/gui/selector.py +232 -0
  38. batFramework/gui/shape.py +286 -86
  39. batFramework/gui/slider.py +353 -0
  40. batFramework/gui/style.py +10 -0
  41. batFramework/gui/styleManager.py +49 -0
  42. batFramework/gui/syncedVar.py +43 -0
  43. batFramework/gui/textInput.py +331 -0
  44. batFramework/gui/textWidget.py +308 -0
  45. batFramework/gui/toggle.py +140 -62
  46. batFramework/gui/tooltip.py +35 -0
  47. batFramework/gui/widget.py +546 -307
  48. batFramework/manager.py +131 -50
  49. batFramework/particle.py +118 -0
  50. batFramework/propertyEaser.py +79 -0
  51. batFramework/renderGroup.py +34 -0
  52. batFramework/resourceManager.py +130 -0
  53. batFramework/scene.py +31 -226
  54. batFramework/sceneLayer.py +134 -0
  55. batFramework/sceneManager.py +200 -165
  56. batFramework/scrollingSprite.py +115 -0
  57. batFramework/sprite.py +46 -0
  58. batFramework/stateMachine.py +49 -51
  59. batFramework/templates/__init__.py +2 -0
  60. batFramework/templates/character.py +15 -0
  61. batFramework/templates/controller.py +158 -0
  62. batFramework/templates/stateMachine.py +39 -0
  63. batFramework/tileset.py +46 -0
  64. batFramework/timeManager.py +213 -0
  65. batFramework/transition.py +162 -157
  66. batFramework/triggerZone.py +22 -22
  67. batFramework/utils.py +306 -184
  68. {batframework-1.1.0.dist-info → batframework-2.0.0.dist-info}/LICENSE +1 -1
  69. {batframework-1.1.0.dist-info → batframework-2.0.0.dist-info}/METADATA +8 -4
  70. batframework-2.0.0.dist-info/RECORD +72 -0
  71. batFramework/cutsceneBlocks.py +0 -176
  72. batFramework/debugger.py +0 -48
  73. batFramework/easing.py +0 -71
  74. batFramework/gui/constraints.py +0 -204
  75. batFramework/gui/frame.py +0 -19
  76. batFramework/particles.py +0 -77
  77. batFramework/time.py +0 -75
  78. batFramework/transitionManager.py +0 -0
  79. batframework-1.1.0.dist-info/RECORD +0 -43
  80. {batframework-1.1.0.dist-info → batframework-2.0.0.dist-info}/WHEEL +0 -0
  81. {batframework-1.1.0.dist-info → batframework-2.0.0.dist-info}/top_level.txt +0 -0
@@ -1,40 +1,116 @@
1
- from .shape import Shape
2
- from typing import Any
3
- import pygame
4
- # from .constraints import ConstraintAspectRatio
5
-
6
- class Indicator(Shape):
7
- def __init__(self,width:int|float= 10,height:int|float=10)->None:
8
- super().__init__(width,height)
9
-
10
- def to_string_id(self)->str:
11
- return "Indicator"
12
-
13
- def set_value(self,value:Any)->None:
14
- pass
15
-
16
- def get_value(self)->Any:
17
- pass
18
-
19
- def _build_indicator(self)->None:
20
- pass
21
-
22
- def build(self)->None:
23
- super().build()
24
- self._build_indicator()
25
-
26
-
27
- class ToggleIndicator(Indicator):
28
- def __init__(self,default_value:bool)->None:
29
- self.value:bool = default_value
30
- super().__init__(20,20)
31
- # self.add_constraint(ConstraintAspectRatio(1))
32
-
33
- def set_value(self,value)->None:
34
- self.value = value
35
- self.set_color("green" if value else "red")
36
- self.build()
37
-
38
- def get_value(self)->bool:
39
- return self.value
40
- #
1
+ from .shape import Shape
2
+ from typing import Any, Self, Callable
3
+ import pygame
4
+ from .widget import Widget
5
+ from .interactiveWidget import InteractiveWidget
6
+ from .draggableWidget import DraggableWidget
7
+ import batFramework as bf
8
+
9
+
10
+ class Indicator(Shape):
11
+ """
12
+ Shape intended to be used as icons/indicators
13
+ due to its nature, it overrides the top_at function (it can not be 'seen' by the mouse)
14
+
15
+ """
16
+
17
+ def __init__(self, size: tuple[int | float] = (10, 10)) -> None:
18
+ super().__init__(size)
19
+ self.debug_color = "magenta"
20
+ self.set_outline_width(1)
21
+ self.set_outline_color("black")
22
+
23
+ def to_string_id(self) -> str:
24
+ return "Indicator"
25
+
26
+ def set_value(self, value: Any) -> None:
27
+ pass
28
+
29
+ def get_value(self) -> Any:
30
+ pass
31
+
32
+ def top_at(self, x, y):
33
+ return None
34
+
35
+
36
+ class ToggleIndicator(Indicator):
37
+ def __init__(self, default_value: bool) -> None:
38
+ super().__init__((20, 20))
39
+ self.value: bool = default_value
40
+ self.callback = lambda val: self.set_color("green" if val else "red")
41
+ self.set_value(default_value)
42
+ self.callback(default_value)
43
+ # TODO aspect ratio would be good right about here
44
+ self.add_constraints(bf.gui.AspectRatio(1,reference_axis=bf.axis.VERTICAL))
45
+
46
+ def __str__(self):
47
+ return "ToggleIndicator"
48
+
49
+ def set_callback(self, callback : Callable[[bool],Any]) -> Self:
50
+ self.callback = callback
51
+ return self
52
+
53
+ def set_value(self, value: bool) -> None:
54
+ self.value = value
55
+ if self.callback:
56
+ self.callback(value)
57
+ self.dirty_surface = True
58
+
59
+ def get_value(self) -> bool:
60
+ return self.value
61
+
62
+ def top_at(self, x: float, y: float) -> "None|Widget":
63
+ r = super().top_at(x, y)
64
+ if r is self:
65
+ return None
66
+ return r
67
+
68
+ class ArrowIndicator(Indicator):
69
+ def __init__(self,direction:bf.direction):
70
+ super().__init__()
71
+ self.direction : bf.direction = direction
72
+ self.arrow_color = bf.color.WHITE
73
+ self.line_width : int = 1
74
+
75
+ def set_arrow_color(self,color)-> Self:
76
+ self.arrow_color = color
77
+ self.dirty_surface = True
78
+ return self
79
+
80
+ def set_arrow_direction(self,direction:bf.direction)->Self:
81
+ self.direction = direction
82
+ self.dirty_surface = True
83
+ return self
84
+
85
+ def set_arrow_line_width(self,value:int)->Self:
86
+ self.line_width = value
87
+ self.dirty_surface = True
88
+ return self
89
+
90
+ def paint(self):
91
+ super().paint()
92
+ r = self.get_local_inner_rect()
93
+ size = min(r.width, r.height)
94
+ if size %2 == 0:
95
+ size -= 1
96
+ r.width = size
97
+ r.height = size
98
+
99
+ #pixel alignment
100
+ if (self.padding[1]+self.padding[3] )%2 ==0:
101
+ r.height-=1
102
+ if (self.padding[0]+self.padding[2] )%2 ==0:
103
+ r.width-=1
104
+ r.center = self.get_local_inner_rect().center
105
+
106
+ bf.utils.draw_triangle(
107
+ surface = self.surface,
108
+ color = self.arrow_color,
109
+ rect =r,
110
+ direction = self.direction,
111
+ width = self.line_width
112
+
113
+ )
114
+
115
+
116
+
@@ -1,22 +1,243 @@
1
- from .widget import Widget
2
-
3
- class InteractiveWidget(Widget):
4
- def __init__(self,*args,**kwargs):
5
- super().__init__(convert_alpha = True)
6
- self.focusable = True
7
- self.is_focused : bool = False
8
-
9
- def get_focus(self)->bool:
10
- if self.parent is None or not self.focusable: return False
11
- self.get_root().focus_on(self)
12
-
13
- def on_get_focus(self)->None:
14
- self.is_focused = True
15
-
16
- def on_lose_focus(self)->None:
17
- self.is_focused = False
18
-
19
- def lose_focus(self)->bool:
20
- if self.is_focused and self.parent is not None:
21
- self.get_root().focus_on(None)
22
-
1
+ from .widget import Widget
2
+ from typing import Self
3
+ import pygame
4
+ from math import cos
5
+ import batFramework as bf
6
+
7
+ def children_has_focus(widget)->bool:
8
+ if isinstance(widget,InteractiveWidget) and widget.is_focused:
9
+ return True
10
+ for child in widget.children:
11
+ if children_has_focus(child):
12
+ return True
13
+ return False
14
+
15
+
16
+ class InteractiveWidget(Widget):
17
+ __focus_effect_cache = {}
18
+ def __init__(self, *args, **kwargs) -> None:
19
+ self.is_focused: bool = False
20
+ self.is_hovered: bool = False
21
+ self.is_clicked_down: list[bool] = [False]*5
22
+ self.focused_index = 0
23
+ self.click_pass_through : bool = False
24
+ super().__init__(*args, **kwargs)
25
+
26
+
27
+ def handle_event(self, event):
28
+ if self.is_hovered:
29
+ if event.type == pygame.MOUSEBUTTONDOWN:
30
+ self.is_clicked_down[event.button-1] = True
31
+ self.on_click_down(event.button,event)
32
+ elif event.type == pygame.MOUSEBUTTONUP:
33
+ self.is_clicked_down[event.button-1] = False
34
+ self.on_click_up(event.button,event)
35
+
36
+ if self.is_focused:
37
+ if event.type == pygame.KEYDOWN:
38
+ self.on_key_down(event.key,event)
39
+ elif event.type == pygame.KEYUP:
40
+ self.on_key_up(event.key,event)
41
+
42
+ def set_click_pass_through(self,pass_through:bool)->Self:
43
+ """
44
+ # Allows mouse click events to pass through this widget to underlying widgets if True.
45
+ """
46
+ self.click_pass_through = pass_through
47
+ return self
48
+
49
+
50
+ def allow_focus_to_self(self) -> bool:
51
+ return self.visible
52
+
53
+ def get_focus(self) -> bool:
54
+ if self.allow_focus_to_self() and ((r := self.get_root()) is not None):
55
+ r.focus_on(self)
56
+ return True
57
+ return False
58
+
59
+ def lose_focus(self) -> bool:
60
+ if self.is_focused and ((r := self.get_root()) is not None):
61
+ r.focus_on(None)
62
+ return True
63
+ return False
64
+
65
+ def set_parent(self, parent: Widget) -> Self:
66
+ if parent is None and children_has_focus(self):
67
+ self.get_root().clear_focused()
68
+ # pass focus on
69
+
70
+ return super().set_parent(parent)
71
+
72
+ def get_interactive_widgets(self):
73
+ """Retrieve all interactive widgets in the tree, in depth-first order."""
74
+ widgets = []
75
+ stack = [self]
76
+ while stack:
77
+ widget = stack.pop()
78
+ if isinstance(widget, InteractiveWidget) and widget.allow_focus_to_self():
79
+ widgets.append(widget)
80
+ stack.extend(reversed(widget.children)) # Add children in reverse for left-to-right traversal
81
+ return widgets
82
+
83
+ def find_next_widget(self, current):
84
+ """Find the next interactive widget, considering parent and sibling relationships."""
85
+ if current.is_root:
86
+ return None # Root has no parent
87
+
88
+ if hasattr(current.parent, "layout"):
89
+ siblings = current.parent.get_interactive_children()
90
+ else:
91
+ siblings = current.parent.children
92
+
93
+ start_index = siblings.index(current)
94
+ good_index = -1
95
+ for i in range(start_index + 1, len(siblings)):
96
+ sibling = siblings[i]
97
+ if isinstance(sibling,InteractiveWidget) and not(sibling is current) :
98
+ if sibling.allow_focus_to_self():
99
+ good_index = i
100
+ break
101
+ if good_index >= 0:
102
+ # Not the last child, return the next sibling
103
+ return siblings[good_index]
104
+ else:
105
+ # Current is the last child, move to parent's next sibling
106
+ return self.find_next_widget(current.parent)
107
+
108
+ def find_prev_widget(self, current : "Widget"):
109
+ """Find the previous interactive widget, considering parent and sibling relationships."""
110
+ if current.is_root:
111
+ return None # Root has no parent
112
+
113
+ # siblings = [c for c in current.parent.children if isinstance(c,InteractiveWidget) and c.allow_focus_to_self()]
114
+ if hasattr(current.parent, "layout"):
115
+ siblings = current.parent.get_interactive_children()
116
+ else:
117
+ siblings = current.parent.children
118
+ start_index = siblings.index(current)
119
+ good_index = -1
120
+ for i in range(start_index-1,-1,-1):
121
+ sibling = siblings[i]
122
+ if isinstance(sibling,InteractiveWidget) and not(sibling is current) :
123
+ if sibling.allow_focus_to_self():
124
+ good_index = i
125
+ break
126
+ if good_index >= 0:
127
+ # Not the first child, return the previous sibling
128
+ return siblings[good_index]
129
+ else:
130
+ # Current is the first child, move to parent's previous sibling
131
+ return self.find_prev_widget(current.parent)
132
+
133
+ def focus_next_tab(self, previous_widget):
134
+ """Focus the next interactive widget."""
135
+ if previous_widget:
136
+ next_widget = self.find_next_widget(previous_widget)
137
+ if next_widget:
138
+ next_widget.get_focus()
139
+
140
+ def focus_prev_tab(self, previous_widget):
141
+ """Focus the previous interactive widget."""
142
+ if previous_widget:
143
+ prev_widget = self.find_prev_widget(previous_widget)
144
+ if prev_widget:
145
+ prev_widget.get_focus()
146
+
147
+
148
+
149
+ def on_key_down(self, key,event) -> None:
150
+ self.do_on_key_down(key,event)
151
+
152
+ def on_key_up(self, key,event) -> None:
153
+ self.do_on_key_up(key,event)
154
+
155
+ def on_click_down(self, button: int,event=None) -> None:
156
+ if not self.click_pass_through:
157
+ event.consumed = True
158
+ self.do_on_click_down(button,event)
159
+
160
+ def on_click_up(self, button: int,event=None) -> None:
161
+ if not self.click_pass_through:
162
+ event.consumed = True
163
+ self.do_on_click_up(button,event)
164
+
165
+ def on_get_focus(self) -> None:
166
+ self.is_focused = True
167
+ if isinstance(self.parent,bf.gui.InteractiveWidget):
168
+ self.parent.set_focused_child(self)
169
+ self.do_on_get_focus()
170
+
171
+ def on_lose_focus(self) -> None:
172
+ self.is_focused = False
173
+ self.do_on_lose_focus()
174
+
175
+ def do_on_get_focus(self) -> None:
176
+ pass
177
+
178
+ def do_on_lose_focus(self) -> None:
179
+ pass
180
+
181
+ def do_on_key_down(self, key,event) -> None:
182
+ return
183
+
184
+ def do_on_key_up(self, key,event) -> None:
185
+ return
186
+
187
+ def do_on_click_down(self, button: int,event=None) -> None:
188
+ return
189
+
190
+ def do_on_click_up(self, button: int,event=None) -> None:
191
+ return
192
+
193
+ def on_enter(self) -> None:
194
+ self.is_hovered = True
195
+ self.do_on_enter()
196
+
197
+ def on_exit(self) -> None:
198
+ self.is_hovered = False
199
+ self.is_clicked_down = [False]*5
200
+ self.do_on_exit()
201
+
202
+ def do_on_enter(self) -> None:
203
+ pass
204
+
205
+ def do_on_exit(self) -> None:
206
+ pass
207
+
208
+ def on_mouse_motion(self, x, y) -> None:
209
+ self.do_on_mouse_motion(x, y)
210
+
211
+ def do_on_mouse_motion(self, x, y) -> None:
212
+ pass
213
+
214
+ def set_focused_child(self, child: "InteractiveWidget"):
215
+ pass
216
+
217
+ def draw_focused(self, camera: bf.Camera) -> None:
218
+ if isinstance(self,bf.gui.Shape):
219
+ prop = 8
220
+ pulse = int(prop * 0.75 - (prop * cos(pygame.time.get_ticks() / 100) / 4))
221
+ delta = (pulse // 2) * 2 # ensure even
222
+
223
+ # Get rect in screen space, inflated for visual effect
224
+ screen_rect = camera.world_to_screen(self.rect.inflate(prop+self.outline_width, prop+self.outline_width))
225
+
226
+ # Shrink for inner pulsing border
227
+ inner = screen_rect.inflate(-delta, -delta)
228
+ inner.topleft = 0,0
229
+ inner.w = round(inner.w)
230
+ inner.h = round(inner.h)
231
+
232
+ surface = InteractiveWidget.__focus_effect_cache.get(inner.size)
233
+ if surface is None:
234
+ surface = pygame.Surface(inner.size)
235
+ InteractiveWidget.__focus_effect_cache[inner.size] = surface
236
+
237
+ surface.set_colorkey((0,0,0))
238
+ pygame.draw.rect(surface, "white", inner, 2, *self.border_radius)
239
+ pygame.draw.rect(surface, "black", inner.inflate(-1 * min(16,inner.w*0.75),0), 2)
240
+ pygame.draw.rect(surface, "black", inner.inflate(0,-1 * min(16,inner.h*0.75)), 2)
241
+ inner.center = screen_rect.center
242
+ camera.surface.blit(surface,inner)
243
+
batFramework/gui/label.py CHANGED
@@ -1,110 +1,147 @@
1
- import batFramework as bf
2
- import pygame
3
- from .shape import Shape
4
- from typing import Self
5
-
6
- class Label(Shape):
7
- def __init__(self,text:str) -> None:
8
- self._text = ""
9
- # Enable/Disable antialiasing
10
- self._antialias : bool = True
11
-
12
- self._text_size = bf.const.DEFAULT_TEXT_SIZE
13
-
14
- self._text_color : tuple[int,int,int]|str = "black"
15
- # font name (given when loaded by utils) to use for the text
16
- self._font_name = None
17
- # reference to the font object
18
- self._font_object = None
19
- # Rect containing the text of the label
20
- self._text_rect = None
21
- # text surface (result of font.render)
22
- self._text_surface : pygame.Surface | None= None
23
- super().__init__(width=0,height=0)
24
- self.set_padding((10,4))
25
- self.set_debug_color("blue")
26
- self.set_color("white")
27
- self.set_autoresize(True)
28
- self.set_font(force=True)
29
- self.set_text(text)
30
-
31
- def set_text_color(self,color)->Self:
32
- self._text_color = color
33
- self.build()
34
- return self
35
-
36
- def to_string_id(self)->str:
37
- return f"Label({self._text})"
38
-
39
-
40
- def get_bounding_box(self):
41
- yield from super().get_bounding_box()
42
- if self._text_rect : yield self._text_rect.move(*self.rect.topleft)
43
-
44
- def set_font(self,font_name:str=None,force:bool = False)-> "Label":
45
- if font_name == self._font_name and not force: return self
46
- self._font_name = font_name
47
- self._font_object = bf.utils.get_font(self._font_name,self._text_size)
48
- self.build()
49
- return self
50
-
51
- def set_text_size(self,text_size:int) -> "Label":
52
- text_size = round(text_size/2) * 2
53
- if text_size == self._text_size : return self
54
- self._text_size = text_size
55
- self._font_object = bf.utils.get_font(self._font_name,self._text_size)
56
- self.build()
57
- return self
58
-
59
- def get_text_size(self)-> int:
60
- return self._text_size
61
-
62
- def is_antialias(self)->bool:
63
- return self._antialias
64
-
65
- def set_antialias(self,value:bool)->"Label":
66
- self._antialias = value
67
- self.build()
68
- return self
69
-
70
- def set_text(self,text:str) -> "Label":
71
- if text == self._text : return self
72
- self._text = text
73
- self.build()
74
- return self
75
-
76
- def get_text(self)->str:
77
- return self._text
78
-
79
-
80
- def _build_text(self)-> None:
81
- if self._font_object is None:
82
- print("No font :(")
83
- return
84
- # render(text, antialias, color, bgcolor=None, wraplength=0) -> Surface
85
- self._text_surface = self._font_object.render(
86
- text = self._text,
87
- antialias = self._antialias,
88
- color = self._text_color,
89
- bgcolor = self._color,
90
- wraplength = 0
91
- )
92
- self._text_rect = self._text_surface.get_frect()
93
-
94
- def _build_layout(self)->None:
95
- if self.autoresize:
96
- if self.rect.size != self.inflate_rect_by_padding(self._text_rect).size :
97
- self.set_size(
98
- self._text_rect.w + self.padding[0]+self.padding[2],
99
- self._text_rect.h + self.padding[1]+self.padding[3]
100
- )
101
- return
102
- self._text_rect.center = self.get_content_rect_rel().center
103
- self.surface.blit(self._text_surface,self._text_rect)
104
-
105
- def build(self)->None:
106
- super().build()
107
- if not self._font_object:return
108
- self._build_text()
109
- self._build_layout()
110
-
1
+ import batFramework as bf
2
+ import pygame
3
+ from .shape import Shape
4
+ from .textWidget import TextWidget
5
+ from typing import Literal, Self,Union
6
+ from math import ceil
7
+
8
+ class Label(Shape):
9
+
10
+ def __init__(self, text: str = "") -> None:
11
+ super().__init__((0, 0))
12
+ self.alignment: bf.alignment = bf.alignment.CENTER
13
+ self.text_widget = TextWidget(text)
14
+ self.set_padding((10, 4))
15
+ self.set_debug_color("blue")
16
+ self.set_color("gray50")
17
+ self.set_autoresize(True)
18
+ self.set_font(force=True)
19
+ self.add(self.text_widget)
20
+
21
+ def __str__(self) -> str:
22
+ return f"Label({repr(self.text_widget.text)})"
23
+
24
+ def set_visible(self, value):
25
+ self.text_widget.set_visible(value)
26
+ return super().set_visible(value)
27
+
28
+ def set_allow_scroll(self, value:bool)->Self:
29
+ self.text_widget.set_allow_scroll(value)
30
+ return self
31
+
32
+ def set_text_color(self, color) -> Self:
33
+ self.text_widget.set_text_color(color)
34
+ return self
35
+
36
+ def set_line_alignment(self, alignment: int) -> Self:
37
+ """
38
+ alignment: One of pygame.FONT_CENTER, pygame.FONT_LEFT, pygame.FONT_RIGHT
39
+ """
40
+ self.text_widget.set_line_alignment(alignment)
41
+ return self
42
+
43
+ def set_italic(self, value: bool) -> Self:
44
+ self.text_widget.set_italic(value)
45
+ return self
46
+
47
+ def set_bold(self, value: bool) -> Self:
48
+ self.text_widget.set_bold(value)
49
+ return self
50
+
51
+ def set_underlined(self, value: bool) -> Self:
52
+ self.text_widget.set_underlined(value)
53
+ return self
54
+
55
+ def set_text_outline_mask_size(self,size:tuple[int,int])->Self:
56
+ self.text_widget.set_text_outline_mask_size(size)
57
+ return self
58
+
59
+ def set_text_outline_matrix(self, matrix: list[list[0 | 1]]) -> Self:
60
+ self.text_widget.set_text_outline_matrix(matrix)
61
+ return self
62
+
63
+ def set_text_outline_color(self, color) -> Self:
64
+ self.text_widget.set_text_outline_color(color)
65
+ return self
66
+
67
+ def set_text_bg_color(self, color) -> Self:
68
+ self.text_widget.set_text_bg_color(color)
69
+ return self
70
+
71
+ def set_show_text_outline(self,value:bool) -> Self:
72
+ self.text_widget.set_show_text_outline(value)
73
+ return self
74
+
75
+ def set_alignment(self, alignment: bf.alignment) -> Self:
76
+ self.alignment = alignment
77
+ self.dirty_shape = True
78
+ return self
79
+
80
+ def set_auto_wraplength(self, val: bool) -> Self:
81
+ self.text_widget.set_auto_wraplength(val)
82
+ return self
83
+
84
+ def get_debug_outlines(self):
85
+ if self.visible:
86
+ yield from super().get_debug_outlines()
87
+ yield from self.text_widget.get_debug_outlines()
88
+
89
+ def set_font(self, font_name: str = None, force: bool = False) -> Self:
90
+ self.text_widget.set_font(font_name,force)
91
+ return self
92
+
93
+ def set_text_size(self, text_size: int) -> Self:
94
+ self.text_widget.set_text_size(text_size)
95
+ return self
96
+
97
+ def get_text_size(self) -> int:
98
+ return self.text_widget.text_size
99
+
100
+ def is_antialias(self) -> bool:
101
+ return self.text_widget.antialias
102
+
103
+ def set_antialias(self, value: bool) -> Self:
104
+ self.text_widget.set_antialias(value)
105
+ return self
106
+
107
+ def set_text(self, text: str) -> Self:
108
+ self.text_widget.set_text(text)
109
+ return self
110
+
111
+ def get_min_required_size(self) -> tuple[float, float]:
112
+ return self.expand_rect_with_padding(
113
+ (0, 0, *self.text_widget.get_min_required_size())
114
+ ).size
115
+
116
+ def get_text(self) -> str:
117
+ return self.text_widget.text
118
+
119
+ def align_text(
120
+ self, text_rect: pygame.FRect, area: pygame.FRect, alignment: bf.alignment
121
+ ):
122
+ if alignment == bf.alignment.LEFT:
123
+ alignment = bf.alignment.MIDLEFT
124
+ elif alignment == bf.alignment.MIDRIGHT:
125
+ alignment = bf.alignment.MIDRIGHT
126
+
127
+ pos = area.__getattribute__(alignment.value)
128
+ text_rect.__setattr__(alignment.value, pos)
129
+ text_rect.y = ceil(text_rect.y)
130
+
131
+ def build(self):
132
+ ret = False
133
+ target_size = self.resolve_size(self.get_min_required_size())
134
+ if self.rect.size != target_size :
135
+ self.set_size(target_size)
136
+ self.text_widget.set_size(self.get_inner_rect().size)
137
+ ret = True
138
+
139
+ padded = self.get_inner_rect()
140
+ self.align_text(self.text_widget.rect, padded, self.alignment)
141
+ return ret
142
+
143
+ def apply_pre_updates(self):
144
+ if self.text_widget.dirty_shape:
145
+ self.dirty_shape =True
146
+ return super().apply_pre_updates()
147
+