batframework 1.0.8a9__py3-none-any.whl → 1.0.8a10__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 (70) hide show
  1. batFramework/__init__.py +68 -51
  2. batFramework/action.py +126 -99
  3. batFramework/actionContainer.py +53 -9
  4. batFramework/animatedSprite.py +141 -82
  5. batFramework/audioManager.py +69 -26
  6. batFramework/camera.py +259 -69
  7. batFramework/character.py +27 -0
  8. batFramework/constants.py +16 -54
  9. batFramework/cutscene.py +39 -29
  10. batFramework/cutsceneBlocks.py +36 -43
  11. batFramework/dynamicEntity.py +18 -9
  12. batFramework/easingController.py +58 -0
  13. batFramework/entity.py +48 -97
  14. batFramework/enums.py +113 -0
  15. batFramework/fontManager.py +65 -0
  16. batFramework/gui/__init__.py +10 -2
  17. batFramework/gui/button.py +9 -78
  18. batFramework/gui/clickableWidget.py +220 -0
  19. batFramework/gui/constraints/__init__.py +1 -0
  20. batFramework/gui/constraints/constraints.py +815 -0
  21. batFramework/gui/container.py +174 -32
  22. batFramework/gui/debugger.py +131 -43
  23. batFramework/gui/dialogueBox.py +99 -0
  24. batFramework/gui/draggableWidget.py +40 -0
  25. batFramework/gui/image.py +56 -20
  26. batFramework/gui/indicator.py +38 -21
  27. batFramework/gui/interactiveWidget.py +192 -13
  28. batFramework/gui/label.py +309 -74
  29. batFramework/gui/layout.py +231 -63
  30. batFramework/gui/meter.py +74 -0
  31. batFramework/gui/radioButton.py +84 -0
  32. batFramework/gui/root.py +134 -38
  33. batFramework/gui/shape.py +237 -57
  34. batFramework/gui/slider.py +240 -0
  35. batFramework/gui/style.py +10 -0
  36. batFramework/gui/styleManager.py +48 -0
  37. batFramework/gui/textInput.py +247 -0
  38. batFramework/gui/toggle.py +101 -51
  39. batFramework/gui/widget.py +358 -250
  40. batFramework/manager.py +52 -19
  41. batFramework/object.py +123 -0
  42. batFramework/particle.py +115 -0
  43. batFramework/renderGroup.py +67 -0
  44. batFramework/resourceManager.py +100 -0
  45. batFramework/scene.py +281 -123
  46. batFramework/sceneManager.py +178 -116
  47. batFramework/scrollingSprite.py +114 -0
  48. batFramework/sprite.py +51 -0
  49. batFramework/stateMachine.py +11 -8
  50. batFramework/templates/__init__.py +2 -0
  51. batFramework/templates/character.py +44 -0
  52. batFramework/templates/states.py +166 -0
  53. batFramework/tileset.py +46 -0
  54. batFramework/time.py +145 -58
  55. batFramework/transition.py +195 -124
  56. batFramework/triggerZone.py +1 -1
  57. batFramework/utils.py +112 -147
  58. batframework-1.0.8a10.dist-info/LICENCE +21 -0
  59. batframework-1.0.8a10.dist-info/METADATA +43 -0
  60. batframework-1.0.8a10.dist-info/RECORD +62 -0
  61. batFramework/debugger.py +0 -48
  62. batFramework/easing.py +0 -71
  63. batFramework/gui/constraints.py +0 -204
  64. batFramework/gui/frame.py +0 -19
  65. batFramework/particles.py +0 -77
  66. batFramework/transitionManager.py +0 -0
  67. batframework-1.0.8a9.dist-info/METADATA +0 -53
  68. batframework-1.0.8a9.dist-info/RECORD +0 -42
  69. {batframework-1.0.8a9.dist-info → batframework-1.0.8a10.dist-info}/WHEEL +0 -0
  70. {batframework-1.0.8a9.dist-info → batframework-1.0.8a10.dist-info}/top_level.txt +0 -0
batFramework/gui/label.py CHANGED
@@ -2,109 +2,344 @@ import batFramework as bf
2
2
  import pygame
3
3
  from .shape import Shape
4
4
  from typing import Self
5
+ from math import ceil
5
6
 
6
7
  class Label(Shape):
7
- def __init__(self,text:str) -> None:
8
- self._text = ""
8
+ _text_cache = {}
9
+
10
+ def __init__(self, text: str = "") -> None:
11
+ self.text = text
12
+
13
+ self.resized_flag: bool = False
14
+
9
15
  # 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"
16
+ self.antialias: bool = bf.FontManager().DEFAULT_ANTIALIAS
17
+
18
+ self.text_size = bf.FontManager().DEFAULT_TEXT_SIZE
19
+
20
+ self.auto_wraplength: bool = False
21
+
22
+ self.alignment: bf.alignment = bf.alignment.CENTER
23
+
24
+ self.text_color: tuple[int, int, int] | str = "black"
25
+
26
+ self.text_outline_color: tuple[int, int, int] | str = "gray50"
27
+
28
+ self.text_outline_surface: pygame.Surface = None
29
+
30
+ self._text_outline_mask = pygame.Mask((3, 3), fill=True)
31
+
15
32
  # font name (given when loaded by utils) to use for the text
16
- self._font_name = None
33
+ self.font_name = None
17
34
  # reference to the font object
18
- self._font_object = None
35
+ self.font_object = None
19
36
  # Rect containing the text of the label
20
- self._text_rect = None
37
+ self.text_rect = pygame.FRect(0, 0, 0, 0)
21
38
  # 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))
39
+ self.text_surface: pygame.Surface = pygame.Surface((0, 0))
40
+ self.do_caching: bool = False
41
+
42
+ self.show_text_outline: bool = False
43
+
44
+ self.is_italic: bool = False
45
+
46
+ self.is_bold: bool = False
47
+
48
+ self.is_underlined: bool = False
49
+
50
+ super().__init__((0, 0))
51
+ self.set_padding((10, 4))
25
52
  self.set_debug_color("blue")
26
- self.set_color("white")
53
+ self.set_color("gray50")
27
54
  self.set_autoresize(True)
28
55
  self.set_font(force=True)
29
- self.set_text(text)
30
56
 
31
- def set_text_color(self,color)->Self:
32
- self._text_color = color
33
- self.build()
57
+ @staticmethod
58
+ def clear_cache():
59
+ Label._text_cache = {}
60
+
61
+ def __str__(self) -> str:
62
+ return f"Label({repr(self.text)})"
63
+
64
+ def enable_caching(self) -> Self:
65
+ self.do_caching = True
34
66
  return self
35
67
 
36
- def to_string_id(self)->str:
37
- return f"Label({self._text})"
68
+ def disable_caching(self) -> Self:
69
+ self.do_caching = False
70
+ return self
38
71
 
72
+ def set_text_color(self, color) -> Self:
73
+ self.text_color = color
74
+ self.dirty_surface = True
75
+ return self
39
76
 
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)
77
+ def set_italic(self, value: bool) -> Self:
78
+ if value == self.is_italic:
79
+ return self
80
+ self.is_italic = value
81
+ if self.autoresize_h or self.autoresize_w:
82
+ self.dirty_shape = True
83
+ else:
84
+ self.dirty_surface = True
85
+ return self
43
86
 
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()
87
+ def set_bold(self, value: bool) -> Self:
88
+ if value == self.is_bold:
89
+ return self
90
+ self.is_bold = value
91
+ if self.autoresize_h or self.autoresize_w:
92
+ self.dirty_shape = True
93
+ else:
94
+ self.dirty_surface = True
49
95
  return self
50
96
 
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()
97
+ def set_underlined(self, value: bool) -> Self:
98
+ if value == self.is_underlined:
99
+ return self
100
+ self.is_underlined = value
101
+ self.dirty_surface = True
57
102
  return self
58
103
 
59
- def get_text_size(self)-> int:
60
- return self._text_size
104
+ def set_text_outline_mask_size(self,size:tuple[int,int])->Self:
105
+ old_size = self._text_outline_mask.get_size()
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
+ self._text_outline_mask = pygame.Mask(size, fill=True)
108
+ self.set_text_outline_matrix(m)
109
+ return self
61
110
 
62
- def is_antialias(self)->bool:
63
- return self._antialias
111
+ def set_text_outline_matrix(self, matrix: list[list[0 | 1]]) -> Self:
112
+ if matrix is None:
113
+ matrix = [[0 for _ in range(3)] for _ in range(3)]
114
+ for y in range(3):
115
+ for x in range(3):
116
+ self._text_outline_mask.set_at((x, y), matrix[2 - y][2 - x])
117
+ self.dirty_shape = True
118
+ return self
64
119
 
65
- def set_antialias(self,value:bool)->"Label":
66
- self._antialias = value
67
- self.build()
120
+ def set_text_outline_color(self, color) -> Self:
121
+ self.text_outline_color = color
122
+ self.dirty_surface = True
68
123
  return self
69
124
 
70
- def set_text(self,text:str) -> "Label":
71
- if text == self._text : return self
72
- self._text = text
73
- self.build()
125
+ def enable_text_outline(self) -> Self:
126
+ self.show_text_outline = True
127
+ self.dirty_shape = True
74
128
  return self
75
-
76
- def get_text(self)->str:
77
- return self._text
78
129
 
130
+ def disable_text_outline(self) -> Self:
131
+ self.show_text_outline = False
132
+ self.dirty_shape = True
133
+ return self
79
134
 
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
135
+ def set_alignment(self, alignment: bf.alignment) -> Self:
136
+ self.alignment = alignment
137
+ self.dirty_surface = True
138
+ return self
139
+
140
+ def set_auto_wraplength(self, val: bool) -> Self:
141
+ self.auto_wraplength = val
142
+ if self.autoresize_h or self.autoresize_w:
143
+ self.dirty_shape = True
144
+ else:
145
+ self.dirty_surface = True
146
+ return self
147
+
148
+ def get_debug_outlines(self):
149
+ if self.visible:
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")
152
+ yield from super().get_debug_outlines()
153
+
154
+ def set_font(self, font_name: str = None, force: bool = False) -> Self:
155
+ if font_name == self.font_name and not force:
156
+ return self
157
+ self.font_name = font_name
158
+ self.font_object = bf.FontManager().get_font(self.font_name, self.text_size)
159
+ if self.autoresize_h or self.autoresize_w:
160
+ self.dirty_shape = True
161
+ else:
162
+ self.dirty_surface = True
163
+ return self
164
+
165
+ def set_text_size(self, text_size: int) -> Self:
166
+ text_size = round(text_size / 2) * 2
167
+ if text_size == self.text_size:
168
+ return self
169
+ self.text_size = text_size
170
+ self.font_object = bf.FontManager().get_font(self.font_name, self.text_size)
171
+ if self.autoresize_h or self.autoresize_w:
172
+ self.dirty_shape = True
173
+ return self
174
+
175
+ def get_text_size(self) -> int:
176
+ return self.text_size
177
+
178
+ def is_antialias(self) -> bool:
179
+ return self.antialias
180
+
181
+ def set_antialias(self, value: bool) -> Self:
182
+ self.antialias = value
183
+ self.dirty_surface = True
184
+ return self
185
+
186
+ def set_text(self, text: str) -> Self:
187
+ if text == self.text:
188
+ return self
189
+ self.text = text
190
+ self.dirty_shape = True
191
+ return self
192
+
193
+ def get_min_required_size(self) -> tuple[float, float]:
194
+ if not (self.autoresize_w or self.autoresize_h):
195
+ return self.rect.size
196
+ if not self.text_rect:
197
+ self.text_rect.size = self._get_text_rect_required_size()
198
+ res = self.inflate_rect_by_padding((0, 0, *self.text_rect.size)).size
199
+
200
+ return res
201
+ return res[0] if self.autoresize_w else self.rect.w, (
202
+ res[1] if self.autoresize_h else self.rect.h
91
203
  )
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
- )
204
+
205
+ def get_text(self) -> str:
206
+ return self.text
207
+
208
+ def _render_font(self, params: dict) -> pygame.Surface:
209
+ key = tuple(params.values())
210
+
211
+ cached_value = Label._text_cache.get(key, None)
212
+
213
+ if self.draw_mode == bf.drawMode.SOLID:
214
+ if cached_value is None:
215
+ params.pop("font_name")
216
+
217
+ # save old settings
218
+ old_italic = self.font_object.get_italic()
219
+ old_bold = self.font_object.get_bold()
220
+ old_underline = self.font_object.get_underline()
221
+
222
+ # setup font
223
+ self.font_object.set_italic(self.is_italic)
224
+ self.font_object.set_bold(self.is_bold)
225
+ self.font_object.set_underline(self.is_underlined)
226
+
227
+ surf = self.font_object.render(**params)
228
+
229
+ # reset font
230
+ self.font_object.set_italic(old_italic)
231
+ self.font_object.set_bold(old_bold)
232
+ self.font_object.set_underline(old_underline)
233
+
234
+ if self.do_caching:
235
+ Label._text_cache[key] = surf
236
+ else:
237
+ surf = cached_value
238
+ else:
239
+ params.pop("font_name")
240
+ surf = self.font_object.render(**params)
241
+
242
+ return surf
243
+ def _get_text_rect_required_size(self):
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
265
+
266
+ def _build_layout(self) -> None:
267
+
268
+ self.text_rect.size = self._get_text_rect_required_size()
269
+ # self.text_rect.w = ceil(self.text_rect.w)
270
+ # self.text_rect.h = ceil(self.text_rect.h)
271
+
272
+ if self.autoresize_h or self.autoresize_w:
273
+ target_rect = self.inflate_rect_by_padding((0, 0, *self.text_rect.size))
274
+ if not self.autoresize_w:
275
+ target_rect.w = self.rect.w
276
+ if not self.autoresize_h:
277
+ target_rect.h = self.rect.h
278
+ if self.rect.size != target_rect.size:
279
+ self.set_size(target_rect.size)
280
+ self.build()
101
281
  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:
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])
284
+ self.align_text(self.text_rect, padded, self.alignment)
285
+
286
+ def _get_outline_offset(self)->tuple[int,int]:
287
+ mask_size = self._text_outline_mask.get_size()
288
+ return mask_size[0]//2,mask_size[1]//2
289
+
290
+ def _paint_text(self) -> None:
291
+ if self.font_object is None:
292
+ print(f"No font for widget with text : '{self}' :(")
293
+ return
294
+
295
+ params = {
296
+ "font_name": self.font_object.name,
297
+ "text": self.text,
298
+ "antialias": self.antialias,
299
+ "color": self.text_color,
300
+ "bgcolor": None, # if (self.has_alpha_color() or self.draw_mode == bf.drawMode.TEXTURED) else self.color,
301
+ "wraplength": int(self.get_padded_width()) if self.auto_wraplength and not self.autoresize_w else 0,
302
+ }
303
+
304
+ self.text_surface = self._render_font(params)
305
+
306
+ if self.show_text_outline:
307
+ self.text_outline_surface = (
308
+ pygame.mask.from_surface(self.text_surface)
309
+ .convolve(self._text_outline_mask)
310
+ .to_surface(setcolor=self.text_outline_color, unsetcolor=(0, 0, 0, 0))
311
+ )
312
+
313
+ l = []
314
+ outline_offset = self._get_outline_offset() if self.show_text_outline else (0,0)
315
+
316
+ if self.show_text_outline:
317
+ l.append(
318
+ (self.text_outline_surface,
319
+ (self.text_rect.x - outline_offset[0],self.text_rect.y - outline_offset[1]))
320
+ )
321
+ l.append(
322
+ (self.text_surface, self.text_rect)
323
+ )
324
+ self.surface.fblits(l)
325
+
326
+ def align_text(
327
+ self, text_rect: pygame.FRect, area: pygame.FRect, alignment: bf.alignment
328
+ ):
329
+ if alignment == bf.alignment.LEFT:
330
+ alignment = bf.alignment.MIDLEFT
331
+ elif alignment == bf.alignment.MIDRIGHT:
332
+ alignment = bf.alignment.MIDRIGHT
333
+
334
+ pos = area.__getattribute__(alignment.value)
335
+ text_rect.__setattr__(alignment.value, pos)
336
+ text_rect.y = ceil(text_rect.y)
337
+
338
+ def build(self) -> None:
106
339
  super().build()
107
- if not self._font_object:return
108
- self._build_text()
109
340
  self._build_layout()
110
341
 
342
+ def paint(self) -> None:
343
+ super().paint()
344
+ if self.font_object:
345
+ self._paint_text()