batframework 1.0.10__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.
- batFramework/__init__.py +84 -52
- batFramework/action.py +280 -252
- batFramework/actionContainer.py +105 -38
- batFramework/animatedSprite.py +81 -117
- batFramework/animation.py +91 -0
- batFramework/audioManager.py +156 -85
- batFramework/baseScene.py +249 -0
- batFramework/camera.py +245 -123
- batFramework/constants.py +57 -75
- batFramework/cutscene.py +239 -119
- batFramework/cutsceneManager.py +34 -0
- batFramework/drawable.py +107 -0
- batFramework/dynamicEntity.py +30 -23
- batFramework/easingController.py +58 -0
- batFramework/entity.py +130 -123
- batFramework/enums.py +171 -0
- batFramework/fontManager.py +65 -0
- batFramework/gui/__init__.py +28 -14
- batFramework/gui/animatedLabel.py +90 -0
- batFramework/gui/button.py +18 -84
- batFramework/gui/clickableWidget.py +244 -0
- batFramework/gui/collapseContainer.py +98 -0
- batFramework/gui/constraints/__init__.py +1 -0
- batFramework/gui/constraints/constraints.py +1066 -0
- batFramework/gui/container.py +220 -49
- batFramework/gui/debugger.py +140 -47
- batFramework/gui/draggableWidget.py +63 -0
- batFramework/gui/image.py +61 -23
- batFramework/gui/indicator.py +116 -40
- batFramework/gui/interactiveWidget.py +243 -22
- batFramework/gui/label.py +147 -110
- batFramework/gui/layout.py +442 -81
- batFramework/gui/meter.py +155 -0
- batFramework/gui/radioButton.py +43 -0
- batFramework/gui/root.py +228 -60
- batFramework/gui/scrollingContainer.py +282 -0
- batFramework/gui/selector.py +232 -0
- batFramework/gui/shape.py +286 -86
- batFramework/gui/slider.py +353 -0
- batFramework/gui/style.py +10 -0
- batFramework/gui/styleManager.py +49 -0
- batFramework/gui/syncedVar.py +43 -0
- batFramework/gui/textInput.py +331 -0
- batFramework/gui/textWidget.py +308 -0
- batFramework/gui/toggle.py +140 -62
- batFramework/gui/tooltip.py +35 -0
- batFramework/gui/widget.py +546 -307
- batFramework/manager.py +131 -50
- batFramework/particle.py +118 -0
- batFramework/propertyEaser.py +79 -0
- batFramework/renderGroup.py +34 -0
- batFramework/resourceManager.py +130 -0
- batFramework/scene.py +31 -226
- batFramework/sceneLayer.py +134 -0
- batFramework/sceneManager.py +200 -165
- batFramework/scrollingSprite.py +115 -0
- batFramework/sprite.py +46 -0
- batFramework/stateMachine.py +49 -51
- batFramework/templates/__init__.py +2 -0
- batFramework/templates/character.py +15 -0
- batFramework/templates/controller.py +158 -0
- batFramework/templates/stateMachine.py +39 -0
- batFramework/tileset.py +46 -0
- batFramework/timeManager.py +213 -0
- batFramework/transition.py +162 -157
- batFramework/triggerZone.py +22 -22
- batFramework/utils.py +306 -184
- {batframework-1.0.10.dist-info → batframework-2.0.0.dist-info}/LICENSE +1 -1
- {batframework-1.0.10.dist-info → batframework-2.0.0.dist-info}/METADATA +3 -4
- batframework-2.0.0.dist-info/RECORD +72 -0
- batFramework/cutsceneBlocks.py +0 -176
- batFramework/debugger.py +0 -48
- batFramework/easing.py +0 -71
- batFramework/gui/constraints.py +0 -204
- batFramework/gui/frame.py +0 -19
- batFramework/particles.py +0 -77
- batFramework/time.py +0 -75
- batFramework/transitionManager.py +0 -0
- batframework-1.0.10.dist-info/RECORD +0 -43
- {batframework-1.0.10.dist-info → batframework-2.0.0.dist-info}/WHEEL +0 -0
- {batframework-1.0.10.dist-info → batframework-2.0.0.dist-info}/top_level.txt +0 -0
batFramework/gui/indicator.py
CHANGED
@@ -1,40 +1,116 @@
|
|
1
|
-
from .shape import Shape
|
2
|
-
from typing import Any
|
3
|
-
import pygame
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
self.
|
13
|
-
|
14
|
-
self.
|
15
|
-
|
16
|
-
self.
|
17
|
-
|
18
|
-
self.
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
self.
|
23
|
-
|
24
|
-
|
25
|
-
self.
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
self.
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
self.
|
34
|
-
return self
|
35
|
-
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
self.
|
49
|
-
return self
|
50
|
-
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
self.
|
57
|
-
return self
|
58
|
-
|
59
|
-
def
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
self.
|
73
|
-
self
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
def
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
self.
|
109
|
-
self
|
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
|
+
|