batframework 1.0.9a10__py3-none-any.whl → 1.0.9a12__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 (73) hide show
  1. batFramework/__init__.py +2 -0
  2. batFramework/action.py +280 -279
  3. batFramework/actionContainer.py +105 -82
  4. batFramework/animatedSprite.py +80 -58
  5. batFramework/animation.py +91 -77
  6. batFramework/audioManager.py +156 -131
  7. batFramework/baseScene.py +249 -240
  8. batFramework/camera.py +245 -317
  9. batFramework/constants.py +57 -51
  10. batFramework/cutscene.py +239 -253
  11. batFramework/cutsceneManager.py +34 -34
  12. batFramework/drawable.py +107 -77
  13. batFramework/dynamicEntity.py +30 -30
  14. batFramework/easingController.py +58 -58
  15. batFramework/entity.py +130 -130
  16. batFramework/enums.py +171 -135
  17. batFramework/fontManager.py +65 -65
  18. batFramework/gui/__init__.py +28 -25
  19. batFramework/gui/animatedLabel.py +90 -89
  20. batFramework/gui/button.py +17 -17
  21. batFramework/gui/clickableWidget.py +244 -245
  22. batFramework/gui/collapseContainer.py +98 -0
  23. batFramework/gui/constraints/__init__.py +1 -1
  24. batFramework/gui/constraints/constraints.py +1066 -980
  25. batFramework/gui/container.py +220 -201
  26. batFramework/gui/debugger.py +140 -130
  27. batFramework/gui/draggableWidget.py +63 -44
  28. batFramework/gui/image.py +61 -58
  29. batFramework/gui/indicator.py +116 -113
  30. batFramework/gui/interactiveWidget.py +243 -239
  31. batFramework/gui/label.py +147 -344
  32. batFramework/gui/layout.py +442 -426
  33. batFramework/gui/meter.py +155 -96
  34. batFramework/gui/radioButton.py +43 -35
  35. batFramework/gui/root.py +228 -228
  36. batFramework/gui/scrollingContainer.py +282 -0
  37. batFramework/gui/selector.py +232 -250
  38. batFramework/gui/shape.py +286 -276
  39. batFramework/gui/slider.py +353 -397
  40. batFramework/gui/style.py +10 -10
  41. batFramework/gui/styleManager.py +49 -54
  42. batFramework/gui/syncedVar.py +43 -49
  43. batFramework/gui/textInput.py +331 -306
  44. batFramework/gui/textWidget.py +308 -0
  45. batFramework/gui/toggle.py +140 -128
  46. batFramework/gui/tooltip.py +35 -30
  47. batFramework/gui/widget.py +546 -521
  48. batFramework/manager.py +131 -134
  49. batFramework/particle.py +118 -118
  50. batFramework/propertyEaser.py +79 -79
  51. batFramework/renderGroup.py +34 -34
  52. batFramework/resourceManager.py +130 -130
  53. batFramework/scene.py +31 -31
  54. batFramework/sceneLayer.py +134 -138
  55. batFramework/sceneManager.py +200 -197
  56. batFramework/scrollingSprite.py +115 -115
  57. batFramework/sprite.py +46 -51
  58. batFramework/stateMachine.py +49 -54
  59. batFramework/templates/__init__.py +2 -1
  60. batFramework/templates/character.py +15 -0
  61. batFramework/templates/controller.py +158 -97
  62. batFramework/templates/stateMachine.py +39 -0
  63. batFramework/tileset.py +46 -46
  64. batFramework/timeManager.py +213 -213
  65. batFramework/transition.py +162 -162
  66. batFramework/triggerZone.py +22 -22
  67. batFramework/utils.py +306 -306
  68. {batframework-1.0.9a10.dist-info → batframework-1.0.9a12.dist-info}/LICENSE +20 -20
  69. {batframework-1.0.9a10.dist-info → batframework-1.0.9a12.dist-info}/METADATA +24 -17
  70. batframework-1.0.9a12.dist-info/RECORD +72 -0
  71. batframework-1.0.9a10.dist-info/RECORD +0 -67
  72. {batframework-1.0.9a10.dist-info → batframework-1.0.9a12.dist-info}/WHEEL +0 -0
  73. {batframework-1.0.9a10.dist-info → batframework-1.0.9a12.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,308 @@
1
+ from math import ceil
2
+ import pygame
3
+ from .widget import Widget
4
+ import batFramework as bf
5
+ from typing import Literal, Self,Union
6
+
7
+ class TextWidget(Widget):
8
+ def __init__(self, text:str):
9
+ super().__init__()
10
+ self.text = text
11
+
12
+ # Allows scrolling the text
13
+ self.allow_scroll : bool = True
14
+
15
+ # Scroll variable
16
+ # TODO make scroll work
17
+ self.scroll :pygame.Vector2 = pygame.Vector2(0,0)
18
+
19
+ # Enable/Disable antialiasing
20
+ self.antialias: bool = bf.FontManager().DEFAULT_ANTIALIAS
21
+
22
+ self.text_size = bf.FontManager().DEFAULT_FONT_SIZE
23
+
24
+ self.auto_wraplength: bool = False
25
+
26
+ self.text_color: tuple[int, int, int] | str = "black"
27
+
28
+ self.text_bg_color : tuple[int,int,int]| str | None = None
29
+
30
+
31
+ self.text_outline_color: tuple[int, int, int] | str = "gray50"
32
+
33
+ self._text_outline_mask = pygame.Mask((3, 3), fill=True)
34
+
35
+ self.line_alignment = pygame.FONT_LEFT
36
+ # font name (given when loaded by utils) to use for the text
37
+
38
+ self.font_name = None
39
+ # reference to the font object
40
+ self.font_object = None
41
+ # Rect containing the text of the label
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__()
51
+ self.set_debug_color("purple")
52
+ self.set_autoresize(True)
53
+ self.set_font(force=True)
54
+ self.set_convert_alpha(True)
55
+
56
+
57
+ def set_padding(self, value): # can't set padding
58
+ return self
59
+
60
+ def __str__(self) -> str:
61
+ return f"TextWidget({repr(self.text)})"
62
+
63
+ def set_allow_scroll(self, value:bool)->Self:
64
+ if self.allow_scroll == value: return self
65
+ self.allow_scroll = value
66
+ self.dirty_surface = True
67
+ return self
68
+
69
+ def set_scroll(self,x=None,y=None)->Self:
70
+ x = x if x is not None else self.scroll.x
71
+ y = y if y is not None else self.scroll.y
72
+
73
+ self.scroll.update(x,y)
74
+ self.dirty_surface = True
75
+ return self
76
+
77
+ def scroll_by(self,x=0,y=0)->Self:
78
+ self.scroll += x,y
79
+ self.dirty_surface = True
80
+ return self
81
+
82
+ def set_text_color(self, color) -> Self:
83
+ self.text_color = color
84
+ self.dirty_surface = True
85
+ return self
86
+
87
+ def set_text_bg_color(self, color) -> Self:
88
+ self.text_bg_color = color
89
+ self.set_convert_alpha(color is None)
90
+ self.dirty_surface = True
91
+ return self
92
+
93
+
94
+ def top_at(self, x, y):
95
+ return None
96
+
97
+ def set_line_alignment(self, alignment: Union[Literal["left"], Literal["right"], Literal["center"]]) -> Self:
98
+ self.line_alignment = alignment
99
+ self.dirty_surface = True
100
+ return self
101
+
102
+ def set_italic(self, value: bool) -> Self:
103
+ if value == self.is_italic:
104
+ return self
105
+ self.is_italic = value
106
+ if self.autoresize_h or self.autoresize_w:
107
+ self.dirty_shape = True
108
+ else:
109
+ self.dirty_surface = True
110
+ return self
111
+
112
+ def set_bold(self, value: bool) -> Self:
113
+ if value == self.is_bold:
114
+ return self
115
+ self.is_bold = value
116
+ if self.autoresize_h or self.autoresize_w:
117
+ self.dirty_shape = True
118
+ else:
119
+ self.dirty_surface = True
120
+ return self
121
+
122
+ def set_underlined(self, value: bool) -> Self:
123
+ if value == self.is_underlined:
124
+ return self
125
+ self.is_underlined = value
126
+ self.dirty_surface = True
127
+ return self
128
+
129
+ def set_text_outline_mask_size(self,size:tuple[int,int])->Self:
130
+ old_size = self._text_outline_mask.get_size()
131
+ min_w, min_h = min(old_size[0], size[0]), min(old_size[1], size[1])
132
+ m = [
133
+ [self._text_outline_mask.get_at((x, y)) for x in range(min_w)]
134
+ for y in range(min_h)
135
+ ]
136
+ self._text_outline_mask = pygame.Mask(size, fill=True)
137
+ self.set_text_outline_matrix(m)
138
+ return self
139
+
140
+ def set_text_outline_matrix(self, matrix: list[list[0 | 1]]) -> Self:
141
+ if matrix is None:
142
+ matrix = [[0 for _ in range(3)] for _ in range(3)]
143
+ for y in range(3):
144
+ for x in range(3):
145
+ self._text_outline_mask.set_at((x, y), matrix[2 - y][2 - x])
146
+ self.dirty_shape = True
147
+ return self
148
+
149
+ def set_text_outline_color(self, color) -> Self:
150
+ self.text_outline_color = color
151
+ self.dirty_surface = True
152
+ return self
153
+
154
+ def set_show_text_outline(self,value:bool) -> Self:
155
+ self.show_text_outline = value
156
+ self.dirty_shape = True
157
+ return self
158
+
159
+ def set_auto_wraplength(self, val: bool) -> Self:
160
+ self.auto_wraplength = val
161
+ if self.autoresize_h or self.autoresize_w:
162
+ self.dirty_shape = True
163
+ else:
164
+ self.dirty_surface = True
165
+ return self
166
+
167
+ def get_debug_outlines(self):
168
+ if self.visible:
169
+ yield from super().get_debug_outlines()
170
+
171
+ def set_font(self, font_name: str = None, force: bool = False) -> Self:
172
+ if font_name == self.font_name and not force:
173
+ return self
174
+ self.font_name = font_name
175
+ self.font_object = bf.FontManager().get_font(self.font_name, self.text_size)
176
+ if self.autoresize_h or self.autoresize_w:
177
+ self.dirty_shape = True
178
+ else:
179
+ self.dirty_surface = True
180
+ return self
181
+
182
+ def set_text_size(self, text_size: int) -> Self:
183
+ text_size = (text_size // 2) * 2
184
+ if text_size == self.text_size:
185
+ return self
186
+ self.text_size = text_size
187
+ self.font_object = bf.FontManager().get_font(self.font_name, self.text_size)
188
+ self.dirty_shape = True
189
+ return self
190
+
191
+ def get_text_size(self) -> int:
192
+ return self.text_size
193
+
194
+
195
+ def is_antialias(self) -> bool:
196
+ return self.antialias
197
+
198
+ def set_antialias(self, value: bool) -> Self:
199
+ self.antialias = value
200
+ self.dirty_surface = True
201
+ return self
202
+
203
+ def set_text(self, text: str) -> Self:
204
+ if text == self.text:
205
+ return self
206
+ self.text = text
207
+ self.dirty_shape = True
208
+ return self
209
+
210
+ def get_min_required_size(self) -> tuple[float, float]:
211
+ if not self.font_object : return 0,0
212
+
213
+ tmp_text = self.text
214
+ if self.text.endswith('\n'):
215
+ tmp_text+=" " # hack to have correct size if ends with newline
216
+ params = {
217
+ "font_name": self.font_object.name,
218
+ "text": tmp_text,
219
+ "antialias": self.antialias,
220
+ "color": self.text_color,
221
+ "bgcolor": self.text_bg_color,
222
+ "wraplength": int(self.get_inner_width()) if self.auto_wraplength and not self.autoresize_w else 0,
223
+ }
224
+
225
+ size = list(self._render_font(params).get_size())
226
+ size[1]= max(size[1],self.font_object.get_ascent() - self.font_object.get_descent())
227
+ if not self.show_text_outline:
228
+ return size
229
+ s = self._get_outline_offset()
230
+ return size[0] + s[0]*2, size[1] + s[1]*2
231
+
232
+
233
+ def get_text(self) -> str:
234
+ return self.text
235
+
236
+ def _render_font(self, params: dict) -> pygame.Surface:
237
+ params.pop("font_name")
238
+ # save old settings
239
+ old_italic = self.font_object.get_italic()
240
+ old_bold = self.font_object.get_bold()
241
+ old_underline = self.font_object.get_underline()
242
+ old_align = self.font_object.align
243
+ # setup font
244
+ self.font_object.set_italic(self.is_italic)
245
+ self.font_object.set_bold(self.is_bold)
246
+ self.font_object.set_underline(self.is_underlined)
247
+ self.font_object.align = self.line_alignment
248
+ surf = self.font_object.render(**params)
249
+ # reset font
250
+ self.font_object.set_italic(old_italic)
251
+ self.font_object.set_bold(old_bold)
252
+ self.font_object.set_underline(old_underline)
253
+ self.font_object.align = old_align
254
+ return surf
255
+
256
+ def _get_outline_offset(self)->tuple[int,int]:
257
+ mask_size = self._text_outline_mask.get_size()
258
+ return mask_size[0]//2,mask_size[1]//2
259
+
260
+
261
+ def build(self) -> bool:
262
+ """
263
+ return True if size changed
264
+ """
265
+ target_size = self.resolve_size(self.get_min_required_size())
266
+ if self.rect.size != target_size:
267
+ self.set_size(target_size)
268
+ return True
269
+ return False
270
+
271
+
272
+
273
+ def paint(self) -> None:
274
+ self._resize_surface()
275
+ if self.font_object is None:
276
+ print(f"No font for widget with text : '{self}' :(")
277
+ return
278
+
279
+
280
+ wrap = int(self.get_inner_width()) if self.auto_wraplength and not self.autoresize_w else 0
281
+ params = {
282
+ "font_name": self.font_object.name,
283
+ "text": self.text,
284
+ "antialias": self.antialias,
285
+ "color": self.text_color,
286
+ "bgcolor": self.text_bg_color if not self.show_text_outline else None,
287
+ "wraplength": wrap,
288
+ }
289
+
290
+ if self.text_bg_color is None :
291
+ self.surface = self.surface.convert_alpha()
292
+
293
+ bg_fill_color = (0, 0, 0, 0) if self.text_bg_color is None else self.text_bg_color
294
+ self.surface.fill(bg_fill_color)
295
+
296
+ text_surf = self._render_font(params)
297
+
298
+ if self.show_text_outline:
299
+ mask = pygame.mask.from_surface(text_surf).convolve(self._text_outline_mask)
300
+ outline_surf = mask.to_surface(
301
+ setcolor=self.text_outline_color,
302
+ unsetcolor=bg_fill_color
303
+ )
304
+
305
+ outline_surf.blit(text_surf,self._get_outline_offset())
306
+ text_surf = outline_surf
307
+
308
+ self.surface.blit(text_surf, -self.scroll)
@@ -1,128 +1,140 @@
1
- from .button import Button
2
- from .indicator import Indicator, ToggleIndicator
3
- from .shape import Shape
4
- import batFramework as bf
5
- from typing import Self,Callable,Any
6
-
7
- class Toggle(Button):
8
- def __init__(self, text: str = "", callback : Callable[[bool],Any]=None, default_value: bool = False) -> None:
9
- self.value: bool = default_value
10
- self.indicator: ToggleIndicator = ToggleIndicator(default_value)
11
- self.gap: float | int = 0
12
- self.spacing: bf.spacing = bf.spacing.MANUAL
13
- super().__init__(text, callback)
14
- self.add(self.indicator)
15
- self.set_clip_children(False)
16
-
17
- def set_visible(self, value: bool) -> Self:
18
- self.indicator.set_visible(value)
19
- return super().set_visible(value)
20
-
21
- def set_value(self, value: bool, do_callback=False) -> Self:
22
- self.value = value
23
- self.indicator.set_value(value)
24
- self.dirty_surface = True
25
- if do_callback and self.callback:
26
- self.callback(self.value)
27
- return self
28
-
29
- def set_spacing(self, spacing: bf.spacing) -> Self:
30
- if spacing == self.spacing:
31
- return self
32
- self.spacing = spacing
33
- self.dirty_shape = True
34
- return self
35
-
36
- def click(self) -> None:
37
- self.set_value(not self.value, True)
38
-
39
- def set_gap(self, value: int | float) -> Self:
40
- value = max(0, value)
41
- if value == self.gap:
42
- return self
43
- self.gap = value
44
- self.dirty_shape = True
45
- return self
46
-
47
- def __str__(self) -> str:
48
- return f"Toggle({self.value})"
49
-
50
- def toggle(self) -> None:
51
- self.set_value(not self.value, do_callback=True)
52
-
53
- def get_min_required_size(self) -> tuple[float, float]:
54
- if not self.text_rect:
55
- self.text_rect.size = self._get_text_rect_required_size()
56
-
57
- text_width, text_height = self.text_rect.size
58
- indicator_size = self.indicator.get_min_required_size()[1]
59
- gap = self.gap if self.text else 0
60
-
61
- total_width = text_width + gap + indicator_size
62
- total_height = text_height + self.unpressed_relief
63
-
64
- return self.expand_rect_with_padding((0, 0, total_width, total_height)).size
65
-
66
- def _build_composed_layout(self,other:Shape):
67
- size_changed = False
68
- self.text_rect.size = self._get_text_rect_required_size()
69
-
70
- gap = self.gap if self.text else 0
71
- full_rect = self.text_rect.copy()
72
-
73
- other_height = min(self.text_rect.h, self.font_object.get_height()+1)
74
- other.set_size(other.resolve_size((other_height,other_height)))
75
-
76
- full_rect.w += other.rect.w + gap
77
- full_rect.h += self.unpressed_relief
78
-
79
-
80
- # take into account the relief when calculating target size
81
- inflated = self.expand_rect_with_padding((0, 0, *full_rect.size)).size
82
- target_size = self.resolve_size(inflated)
83
- if self.rect.size != target_size:
84
- self.set_size(target_size)
85
- size_changed = True
86
-
87
- self._align_composed(other)
88
- return size_changed
89
-
90
- def _align_composed(self,other:Shape):
91
-
92
- full_rect = self.get_local_inner_rect()
93
- left_rect = self.text_rect
94
- right_rect = other.rect
95
- gap = {
96
- bf.spacing.MIN: 0,
97
- bf.spacing.HALF: (full_rect.width - left_rect.width - right_rect.width) // 2,
98
- bf.spacing.MAX: full_rect.width - left_rect.width - right_rect.width,
99
- bf.spacing.MANUAL: self.gap
100
- }.get(self.spacing, 0)
101
-
102
- gap = max(0, gap)
103
- combined_width = left_rect.width + right_rect.width + gap
104
-
105
- group_x = {
106
- bf.alignment.LEFT: full_rect.left,
107
- bf.alignment.MIDLEFT: full_rect.left,
108
- bf.alignment.RIGHT: full_rect.right - combined_width,
109
- bf.alignment.MIDRIGHT: full_rect.right - combined_width,
110
- bf.alignment.CENTER: full_rect.centerx - combined_width // 2
111
- }.get(self.alignment, full_rect.left)
112
-
113
- left_rect.x, right_rect.x = group_x, group_x + left_rect.width + gap
114
-
115
- if self.alignment in {bf.alignment.TOP, bf.alignment.TOPLEFT, bf.alignment.TOPRIGHT}:
116
- left_rect.top = right_rect.top = full_rect.top
117
- elif self.alignment in {bf.alignment.BOTTOM, bf.alignment.BOTTOMLEFT, bf.alignment.BOTTOMRIGHT}:
118
- left_rect.bottom = right_rect.bottom = full_rect.bottom
119
- else:
120
- left_rect.centery = right_rect.centery = full_rect.centery
121
-
122
- right_rect.move_ip(*self.rect.topleft)
123
-
124
- def _build_layout(self) -> None:
125
- return self._build_composed_layout(self.indicator)
126
-
127
-
128
-
1
+ from .widget import Widget
2
+ from .button import Button
3
+ from .indicator import Indicator, ToggleIndicator
4
+ from .shape import Shape
5
+ import batFramework as bf
6
+ from typing import Self, Callable, Any
7
+ import pygame
8
+ from .syncedVar import SyncedVar # Adjust import path
9
+
10
+ class Toggle(Button):
11
+ def __init__(
12
+ self,
13
+ text: str = "",
14
+ callback: Callable[[bool], Any] = None,
15
+ default_value: bool = False,
16
+ synced_var: SyncedVar[bool] = None,
17
+ ) -> None:
18
+ # Use passed SyncedVar or create a new one
19
+ self.synced_var: SyncedVar[bool] = synced_var or SyncedVar(default_value)
20
+
21
+ # Local value synced to SyncedVar.value
22
+ self.value: bool = self.synced_var.value
23
+
24
+ self.indicator: ToggleIndicator = ToggleIndicator(self.value)
25
+ self.gap: float | int = 0
26
+ self.spacing: bf.spacing = bf.spacing.MANUAL
27
+
28
+ super().__init__(text, callback)
29
+
30
+ # Add indicator to widget
31
+ self.add(self.indicator)
32
+ self.set_clip_children(False)
33
+
34
+ # Bind this toggle’s _on_synced_var_update to synced_var updates
35
+ self.synced_var.bind(self, self._on_synced_var_update)
36
+
37
+ def _on_synced_var_update(self, new_value: bool) -> None:
38
+ # Called when SyncedVar changes externally
39
+ if self.value != new_value:
40
+ self.set_value(new_value, do_callback=False)
41
+
42
+
43
+ def set_indicator(self,indicator:Indicator):
44
+ self.remove(self.indicator)
45
+ self.synced_var.unbind(self.indicator)
46
+ self.indicator = indicator
47
+ self.add(self.indicator)
48
+ def set_visible(self, value: bool) -> Self:
49
+ self.indicator.set_visible(value)
50
+ return super().set_visible(value)
51
+
52
+ def set_value(self, value: bool, do_callback=False) -> Self:
53
+ if self.value == value:
54
+ return self # No change
55
+
56
+ self.value = value
57
+ self.indicator.set_value(value)
58
+ self.dirty_surface = True
59
+
60
+ # Update SyncedVar only if different (avoid recursion)
61
+ if self.synced_var.value != value:
62
+ self.synced_var.value = value
63
+
64
+ if do_callback and self.callback:
65
+ self.callback(self.value)
66
+ return self
67
+
68
+ def set_spacing(self, spacing: bf.spacing) -> Self:
69
+ if spacing == self.spacing:
70
+ return self
71
+ self.spacing = spacing
72
+ self.dirty_shape = True
73
+ return self
74
+
75
+ def click(self) -> None:
76
+ self.set_value(not self.value, do_callback=True)
77
+
78
+ def set_gap(self, value: int | float) -> Self:
79
+ value = max(0, value)
80
+ if value == self.gap:
81
+ return self
82
+ self.gap = value
83
+ self.dirty_shape = True
84
+ return self
85
+
86
+ def __str__(self) -> str:
87
+ return f"Toggle({self.value})"
88
+
89
+ def toggle(self) -> None:
90
+ self.set_value(not self.value, do_callback=True)
91
+
92
+ def get_min_required_size(self) -> tuple[float, float]:
93
+ left = self.text_widget.get_min_required_size()
94
+ gap = self.gap if self.text_widget.text else 0
95
+ full_rect = pygame.FRect(0, 0, left[0] + left[1] + gap, left[1])
96
+ full_rect.h += self.unpressed_relief
97
+ return self.expand_rect_with_padding((0, 0, *full_rect.size)).size
98
+
99
+ def _align_composed(self, left: Shape, right: Shape):
100
+ full_rect = self.get_inner_rect()
101
+ left_rect = left.rect
102
+ right_rect = right.rect
103
+ gap = {
104
+ bf.spacing.MIN: 0,
105
+ bf.spacing.HALF: (full_rect.width - left_rect.width - right_rect.width) // 2,
106
+ bf.spacing.MAX: full_rect.width - left_rect.width - right_rect.width,
107
+ bf.spacing.MANUAL: self.gap,
108
+ }.get(self.spacing, 0)
109
+
110
+ gap = max(0, gap)
111
+ combined_width = left_rect.width + right_rect.width + gap
112
+
113
+ group_x = {
114
+ bf.alignment.LEFT: full_rect.left,
115
+ bf.alignment.MIDLEFT: full_rect.left,
116
+ bf.alignment.RIGHT: full_rect.right - combined_width,
117
+ bf.alignment.MIDRIGHT: full_rect.right - combined_width,
118
+ bf.alignment.CENTER: full_rect.centerx - combined_width // 2,
119
+ }.get(self.alignment, full_rect.left)
120
+
121
+ # Set horizontal positions
122
+ left.set_position(x=group_x)
123
+ right.set_position(x=group_x + left_rect.width + gap)
124
+
125
+ # Set vertical positions
126
+ if self.alignment in {bf.alignment.TOP, bf.alignment.TOPLEFT, bf.alignment.TOPRIGHT}:
127
+ left.set_position(y=full_rect.top)
128
+ right.set_position(y=full_rect.top)
129
+ elif self.alignment in {bf.alignment.BOTTOM, bf.alignment.BOTTOMLEFT, bf.alignment.BOTTOMRIGHT}:
130
+ left.set_position(y=full_rect.bottom - left_rect.height)
131
+ right.set_position(y=full_rect.bottom - right_rect.height)
132
+ else:
133
+ left.set_center(y=full_rect.centery)
134
+ right.set_center(y=full_rect.centery)
135
+
136
+ def build(self) -> None:
137
+ res = super().build()
138
+ self.indicator.set_size(self.indicator.resolve_size((self.text_widget.rect.h, self.text_widget.rect.h)))
139
+ self._align_composed(self.text_widget, self.indicator)
140
+ return res
@@ -1,30 +1,35 @@
1
- from .label import Label
2
- import batFramework as bf
3
- import sys
4
-
5
- class ToolTip(Label):
6
- def __init__(self, text = ""):
7
- super().__init__(text)
8
- self.fade_in_duration : float = 0.1
9
- self.fade_out_duration : float = 0.1
10
- self.set_render_order(sys.maxsize)
11
-
12
- def __str__(self):
13
- return f"ToolTip('{self.text}')"
14
-
15
- def top_at(self, x, y):
16
- return None
17
-
18
- def fade_in(self):
19
- self.set_visible(True)
20
- bf.PropertyEaser(
21
- self.fade_in_duration,bf.easing.EASE_OUT,
22
- 0,self.parent_scene.name
23
- ).add_custom(self.get_alpha,self.set_alpha,255).start()
24
-
25
- def fade_out(self):
26
- bf.PropertyEaser(
27
- self.fade_out_duration,bf.easing.EASE_IN,
28
- 0,self.parent_scene.name,
29
- lambda : self.set_visible(False)
30
- ).add_custom(self.get_alpha,self.set_alpha,0).start()
1
+ from .label import Label
2
+ import batFramework as bf
3
+ import sys
4
+
5
+ class ToolTip(Label):
6
+ def __init__(self, text = ""):
7
+ super().__init__(text)
8
+ self.fade_in_duration : float = 0.1
9
+ self.fade_out_duration : float = 0.1
10
+ self.set_render_order(sys.maxsize)
11
+ self.set_padding(2)
12
+
13
+ def __str__(self):
14
+ return f"ToolTip('{self.text_widget.text}')"
15
+
16
+ def top_at(self, x, y):
17
+ return None
18
+
19
+ def set_all_alpha(self,value:int):
20
+ self.text_widget.set_alpha(value)
21
+ return self.set_alpha(value)
22
+
23
+ def fade_in(self):
24
+ self.set_visible(True)
25
+ bf.PropertyEaser(
26
+ self.fade_in_duration,bf.easing.EASE_OUT,
27
+ 0,self.parent_scene.name
28
+ ).add_custom(self.get_alpha,self.set_all_alpha,255).start()
29
+
30
+ def fade_out(self):
31
+ bf.PropertyEaser(
32
+ self.fade_out_duration,bf.easing.EASE_IN,
33
+ 0,self.parent_scene.name,
34
+ lambda : self.set_visible(False)
35
+ ).add_custom(self.get_alpha,self.set_all_alpha,0).start()