batframework 1.0.8a8__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.8a8.dist-info/METADATA +0 -53
  68. batframework-1.0.8a8.dist-info/RECORD +0 -42
  69. {batframework-1.0.8a8.dist-info → batframework-1.0.8a10.dist-info}/WHEEL +0 -0
  70. {batframework-1.0.8a8.dist-info → batframework-1.0.8a10.dist-info}/top_level.txt +0 -0
batFramework/gui/shape.py CHANGED
@@ -1,86 +1,266 @@
1
1
  import batFramework as bf
2
2
  from .widget import Widget
3
3
  import pygame
4
+ from typing import Self, Iterable
5
+ from math import ceil
4
6
 
5
7
 
6
8
  class Shape(Widget):
7
- def __init__(self,width:float,height:float):
8
- self._color = (0,0,0,0)
9
- self._border_radius:list[int] = [0]
10
- self._outline : int = 0
11
- self._outline_color : tuple[int,int,int] | str = (0,0,0,0)
12
- super().__init__(convert_alpha = True)
13
- self.set_size(width,height)
9
+ def __init__(self, size: tuple[float, float] = None, *args, **kwargs):
10
+ super().__init__(size=size, convert_alpha=True)
11
+ self.color = (0, 0, 0, 0)
12
+ self.border_radius: list[int] = [0]
13
+ self.outline_width: int = 0
14
+ self.outline_color: tuple[int, int, int] | str = (0, 0, 0, 255)
15
+ self.texture_surface = None
16
+ self.texture_subsize = (0, 0)
17
+ self.relief = 0
18
+ self.shadow_color: tuple[int, int, int] | str = (0, 0, 0, 255)
19
+ self.draw_mode = bf.drawMode.SOLID
14
20
 
21
+ def get_padded_bottom(self) -> float:
22
+ return self.rect.bottom - self.padding[3] - self.relief
15
23
 
16
- def to_string_id(self)->str:
24
+ def get_padded_height(self) -> float:
25
+ return self.rect.h - self.padding[1] - self.padding[3] - self.relief
26
+
27
+ def get_padded_top(self) -> float:
28
+ return self.rect.y + self.relief
29
+
30
+ def get_padded_rect(self) -> pygame.FRect:
31
+ return pygame.FRect(
32
+ self.rect.x + self.padding[0],
33
+ self.rect.y + self.padding[1],
34
+ self.rect.w - self.padding[2] - self.padding[0],
35
+ self.rect.h - self.padding[1] - self.padding[3] - self.relief,
36
+ )
37
+
38
+ def set_shadow_color(self, color: tuple[int, int, int] | str) -> Self:
39
+ self.shadow_color = color
40
+ self.dirty_surface = True
41
+ return self
42
+
43
+ def set_relief(self, relief: int) -> Self:
44
+ if relief < 0:
45
+ return self
46
+ self.dirty_shape = self.relief != relief
47
+ self.relief = relief
48
+ return self
49
+
50
+ def set_texture(
51
+ self, surface: pygame.SurfaceType, subsize: tuple[int, int] | None = None
52
+ ) -> Self:
53
+ self.texture_surface = surface
54
+ if subsize is None:
55
+ subsize = (ceil(surface.get_width() / 3), ceil(surface.get_height() / 3))
56
+ self.texture_subsize = subsize
57
+ self.dirty_surface = True
58
+ return self
59
+
60
+ def set_draw_mode(self, mode: bf.drawMode) -> Self:
61
+ self.draw_mode = mode
62
+ self.dirty_surface = True
63
+ return self
64
+
65
+ def get_draw_mode(self) -> bf.drawMode:
66
+ return self.draw_mode
67
+
68
+ def has_alpha_color(self) -> bool:
69
+ return (pygame.Color(self.color).a != 255) or (
70
+ pygame.Color(self.outline_color).a != 255
71
+ )
72
+
73
+ def __str__(self) -> str:
17
74
  return "Shape"
18
75
 
19
- def set_color(self,color:tuple[int,int,int]|str) -> "Frame":
20
- self._color = color
21
- self.build()
76
+ def set_color(self, color: tuple[int, int, int] | str) -> Self:
77
+ self.color = color
78
+ self.dirty_surface = True
22
79
  return self
23
80
 
24
- def set_outline_color(self,color:tuple[int,int,int]|str) -> "Frame":
25
- self._outline_color = color
26
- self.build()
81
+ def set_outline_color(self, color: tuple[int, int, int] | str) -> Self:
82
+ self.outline_color = color
83
+ self.dirty_surface = True
27
84
  return self
28
85
 
29
- def set_border_radius(self,value:int|list[int]) -> "Frame":
30
- if isinstance(value,int):
31
- self._border_radius = [value]
86
+ def set_border_radius(self, value: int | list[int]) -> Self:
87
+ if isinstance(value, int):
88
+ self.border_radius = [value]
32
89
  else:
33
- self._border_radius = value
34
- self.build()
90
+ self.border_radius = value
91
+ self.dirty_surface = True
35
92
  return self
36
-
37
- def set_outline_width(self,value:int) -> "Frame":
38
- self._outline = value
39
- self.build()
93
+
94
+ def set_outline_width(self, value: int) -> Self:
95
+ self.outline_width = value
96
+ self.dirty_surface = True
40
97
  return self
41
-
42
- def build(self)->None:
43
- if self.surface.get_size() != self.get_size_int():
44
- self.surface = pygame.Surface(self.get_size_int())
45
- if self.convert_alpha :
46
- self.surface = self.surface.convert_alpha()
47
- self.surface.fill((0,0,0,0))
48
- if self.parent :
49
- self.parent.children_modified()
50
- if self._border_radius == [0]:
51
- self._build_shape()
52
- if self._outline : self._build_outline()
98
+
99
+ def paint(self) -> None:
100
+ if self.draw_mode == bf.drawMode.TEXTURED:
101
+ self._paint_textured()
102
+ return
103
+ if self.border_radius == [0]:
104
+ self._paint_shape()
105
+ if self.outline_width:
106
+ self._paint_outline()
53
107
  else:
54
- self._build_rounded_shape()
55
- if self._outline : self._build_rounded_outline()
108
+ self._paint_rounded_shape()
109
+ if self.outline_width:
110
+ self._paint_rounded_outline()
56
111
 
112
+ def _paint_textured(self) -> None:
113
+ self.surface.fill((0, 0, 0, 0))
114
+ if self.texture_surface is None:
115
+ return
116
+ w, h = self.surface.get_size()
117
+ sw, sh = self.texture_surface.get_size()
118
+ sub = self.texture_subsize
57
119
 
58
- def _build_shape(self)->None:
59
- self.surface.fill(self._color)
120
+ # center
121
+ center_surface = self.texture_surface.subsurface((sub[0], sub[1], *sub))
122
+ top_surface = self.texture_surface.subsurface((sub[0], 0, *sub))
123
+ bottom_surface = self.texture_surface.subsurface((sub[0], sh - sub[1], *sub))
124
+ left_surface = self.texture_surface.subsurface((0, sub[1], *sub))
125
+ right_surface = self.texture_surface.subsurface((sw - sub[0], sub[1], *sub))
60
126
 
61
- def _build_rounded_shape(self)->None:
62
- self.surface.fill((0,0,0,0))
63
- pygame.draw.rect(
64
- self.surface,
65
- self._color,
66
- (0,0,*self.rect.size),
67
- 0,
68
- *self._border_radius
127
+ lst = []
128
+ for y in range(sub[1], h + 1 - sub[1] * 2, sub[1]):
129
+ for x in range(sub[0], w + 1 - sub[0] * 2, sub[0]):
130
+ lst.append((center_surface, (x, y)))
131
+
132
+ w_remainder = w % sub[0]
133
+ h_remainder = h % sub[1]
134
+ fix_x = ((w // sub[0]) - 1) * sub[0]
135
+ fix_y = ((h // sub[1]) - 1) * sub[1]
136
+
137
+ if (w > sub[0]) and (w_remainder > 0):
138
+ # Center : Fix gaps on the x axis
139
+ h_portion = center_surface.subsurface(0, 0, w_remainder, sub[1])
140
+ for y in range(sub[1], h - sub[1] * 2, sub[1]):
141
+ lst.append((h_portion, (fix_x, y)))
142
+
143
+ # Fix partial gaps on the top
144
+
145
+ t_portion = top_surface.subsurface(0, 0, w_remainder, sub[1])
146
+ lst.append((t_portion, (fix_x, 0)))
147
+
148
+ # Fix partial gaps on the bottom
149
+ b_portion = bottom_surface.subsurface(0, 0, w_remainder, sub[1])
150
+ lst.append((b_portion, (fix_x, h - sub[1] - 1)))
151
+
152
+ if (h > sub[1]) and (h_remainder > 0):
153
+ # Center : Fix gaps on the y axis
154
+ v_portion = center_surface.subsurface(0, 0, sub[0], h_remainder)
155
+ for x in range(sub[0], w - sub[0] * 2, sub[0]):
156
+ lst.append((v_portion, (x, fix_y)))
157
+
158
+ # Fix partial gaps on the left
159
+ l_portion = left_surface.subsurface(0, 0, sub[0], h_remainder)
160
+ lst.append((l_portion, (0, fix_y)))
161
+
162
+ # Fix partial gaps on the right
163
+ r_portion = right_surface.subsurface(0, 0, sub[0], h_remainder)
164
+ lst.append((r_portion, (w - sub[0] - 1, fix_y)))
165
+
166
+ # fix corner gap
167
+ if h > sub[1] or w > sub[0]:
168
+ corner_portion = center_surface.subsurface(
169
+ 0,
170
+ 0,
171
+ w_remainder if w_remainder else sub[0],
172
+ h_remainder if h_remainder else sub[1],
173
+ )
174
+ if w_remainder == 0:
175
+ fix_x -= sub[0]
176
+ if h_remainder == 0:
177
+ fix_y -= sub[1]
178
+ lst.append((corner_portion, (fix_x - 1, fix_y - 1)))
179
+
180
+ # borders
181
+ lst.extend(
182
+ [(top_surface, (x, 0)) for x in range(sub[0], w + 1 - sub[0] * 2, sub[0])]
183
+ + [
184
+ (bottom_surface, (x, h - sub[1] - 1))
185
+ for x in range(sub[0], w + 1 - sub[0] * 2, sub[0])
186
+ ]
187
+ + [
188
+ (left_surface, (0, y))
189
+ for y in range(sub[1], h + 1 - sub[1] * 2, sub[1])
190
+ ]
191
+ + [
192
+ (right_surface, (w - sub[0] - 1, y))
193
+ for y in range(sub[1], h + 1 - sub[1] * 2, sub[1])
194
+ ]
195
+ + [
196
+ (self.texture_surface.subsurface((0, 0, *sub)), (0, 0)),
197
+ (
198
+ self.texture_surface.subsurface((sw - sub[0], 0, *sub)),
199
+ (w - sub[0] - 1, 0),
200
+ ),
201
+ (
202
+ self.texture_surface.subsurface((0, sh - sub[1], *sub)),
203
+ (0, h - sub[1] - 1),
204
+ ),
205
+ (
206
+ self.texture_surface.subsurface((sw - sub[0], sh - sub[1], *sub)),
207
+ (w - sub[0] - 1, h - sub[1] - 1),
208
+ ),
209
+ ]
69
210
  )
70
211
 
71
- def _build_outline(self)->None:
212
+ self.surface.fblits(lst)
213
+
214
+ def _get_elevated_rect(self) -> pygame.FRect:
215
+ return pygame.FRect(0, 0, self.rect.w, self.rect.h - self.relief)
216
+
217
+ def _get_base_rect(self) -> pygame.FRect:
218
+ return pygame.FRect(0, self.rect.h - self.relief, self.rect.w, self.relief)
219
+
220
+ def _paint_shape(self) -> None:
221
+ self.surface.fill((0, 0, 0, 0))
222
+ if self.relief!=0:
223
+ self.surface.fill(self.shadow_color, self._get_base_rect())
224
+ self.surface.fill(self.color, self._get_elevated_rect())
225
+ else:
226
+ self.surface.fill(self.color, self._get_elevated_rect())
227
+
228
+ def _paint_rounded_shape(self) -> None:
229
+ self.surface.fill((0, 0, 0, 0))
230
+ e = self._get_elevated_rect()
231
+ if self.relief != 0:
232
+ b = e.copy()
233
+ b.bottom = self.rect.h
234
+ pygame.draw.rect(self.surface, self.shadow_color, b, 0, *self.border_radius)
235
+ pygame.draw.rect(self.surface, self.color, e, 0, *self.border_radius)
236
+ else:
237
+ pygame.draw.rect(self.surface, self.color, e, 0, *self.border_radius)
238
+
239
+ def _paint_outline(self) -> None:
72
240
  pygame.draw.rect(
73
241
  self.surface,
74
- self._outline_color,
75
- (0,0,*self.rect.size),
76
- self._outline
242
+ self.outline_color,
243
+ self._get_elevated_rect(),
244
+ self.outline_width,
77
245
  )
78
-
79
- def _build_rounded_outline(self)->None:
246
+
247
+ def _paint_rounded_outline(self) -> None:
248
+ e = self._get_elevated_rect()
249
+ b = e.copy()
250
+ b.h += e.bottom - b.bottom
251
+
80
252
  pygame.draw.rect(
81
253
  self.surface,
82
- self._outline_color,
83
- (0,0,*self.rect.size),
84
- self._outline,
85
- *self._border_radius
254
+ self.outline_color,
255
+ e,
256
+ self.outline_width,
257
+ *self.border_radius,
86
258
  )
259
+ if self.relief:
260
+ pygame.draw.rect(
261
+ self.surface,
262
+ self.outline_color,
263
+ b,
264
+ self.outline_width,
265
+ *self.border_radius,
266
+ )
@@ -0,0 +1,240 @@
1
+ import batFramework as bf
2
+ from .meter import Meter
3
+ from .button import Button
4
+ from .indicator import *
5
+ from .meter import Meter
6
+ from .shape import Shape
7
+ from .interactiveWidget import InteractiveWidget
8
+
9
+
10
+ class SliderHandle(Indicator, DraggableWidget):
11
+ def __init__(self):
12
+ super().__init__()
13
+ self.set_color(bf.color.CLOUD_SHADE)
14
+ self.old_key_repeat: tuple = (0, 0)
15
+ self.parent : bf.ClickableWidget = self.parent
16
+ def __str__(self) -> str:
17
+ return "SliderHandle"
18
+
19
+ def on_click_down(self, button: int) -> None:
20
+ if not self.parent.is_enabled():
21
+ return
22
+ super().on_click_down(button)
23
+ if button == 1:
24
+ self.parent.get_focus()
25
+
26
+ def on_exit(self) -> None:
27
+ self.is_hovered = False
28
+ self.do_on_exit()
29
+
30
+ def do_on_drag(
31
+ self, drag_start: tuple[float, float], drag_end: tuple[float, float]
32
+ ) -> None:
33
+ if not self.parent.is_enabled():
34
+ return
35
+ super().do_on_drag(drag_start, drag_end)
36
+ m: Meter = self.parent.meter
37
+ r = m.get_padded_rect()
38
+ position = self.rect.centerx
39
+ self.rect.clamp_ip(r)
40
+ # Adjust handle position to value
41
+ new_value = self.parent.position_to_value(position)
42
+ self.parent.set_value(new_value)
43
+ self.rect.centerx = self.parent.value_to_position(new_value)
44
+
45
+ def top_at(self, x, y):
46
+ return Widget.top_at(self, x, y)
47
+
48
+
49
+ class SliderMeter(Meter, InteractiveWidget):
50
+ def __str__(self) -> str:
51
+ return "SliderMeter"
52
+
53
+ def on_click_down(self, button: int) -> None:
54
+ if not self.parent.is_enabled():
55
+ return
56
+ if button == 1:
57
+ self.parent.get_focus()
58
+ r = self.get_root()
59
+ if r:
60
+ pos = r.drawing_camera.screen_to_world(pygame.mouse.get_pos())[0]
61
+ self.parent.set_value(self.parent.position_to_value(pos))
62
+ self.do_on_click_down(button)
63
+
64
+ class Slider(Button):
65
+ def __init__(self, text: str, default_value: float = 1.0) -> None:
66
+ super().__init__(text, None)
67
+ self.gap: float | int = 0
68
+ self.spacing: bf.spacing = bf.spacing.MANUAL
69
+ self.modified_callback = None
70
+ self.meter: SliderMeter = SliderMeter()
71
+ self.handle = SliderHandle()
72
+ self.add(self.meter, self.handle)
73
+ self.meter.set_debug_color(bf.color.RED)
74
+ self.set_value(default_value, True)
75
+
76
+ def set_visible(self, value: bool) -> Self:
77
+ self.handle.set_visible(value)
78
+ self.meter.set_visible(value)
79
+ return super().set_visible(value)
80
+
81
+ def __str__(self) -> str:
82
+ return "Slider"
83
+
84
+ def set_gap(self, value: int | float) -> Self:
85
+ value = max(0, value)
86
+ self.gap = value
87
+ return self
88
+
89
+ def do_on_get_focus(self) -> None:
90
+ super().do_on_get_focus()
91
+ self.old_key_repeat = pygame.key.get_repeat()
92
+ pygame.key.set_repeat(200, 50)
93
+
94
+ def do_on_lose_focus(self) -> None:
95
+ super().do_on_lose_focus()
96
+ pygame.key.set_repeat(*self.old_key_repeat)
97
+
98
+ def set_spacing(self, spacing: bf.spacing) -> Self:
99
+ if spacing == self.spacing:
100
+ return self
101
+ self.spacing = spacing
102
+ self.dirty_shape = True
103
+ return self
104
+
105
+ def set_modify_callback(self, callback) -> Self:
106
+ self.modified_callback = callback
107
+ return self
108
+
109
+ def set_range(self, range_min: float, range_max: float) -> Self:
110
+ self.meter.set_range(range_min, range_max)
111
+ self.dirty_shape = True
112
+ return self
113
+
114
+ def set_step(self, step: float) -> Self:
115
+ self.meter.set_step(step)
116
+ self.dirty_shape = True
117
+ return self
118
+
119
+ def set_value(self, value, no_callback: bool = False) -> Self:
120
+ if self.meter.value != value:
121
+ self.meter.set_value(value)
122
+ self.dirty_shape = True
123
+ if self.modified_callback and (not no_callback):
124
+ self.modified_callback(self.meter.value)
125
+ return self
126
+
127
+ def get_value(self) -> float:
128
+ return self.meter.get_value()
129
+
130
+ def do_on_key_down(self, key):
131
+ if not self.is_enabled():
132
+ return
133
+ if key == pygame.K_RIGHT:
134
+ self.set_value(self.meter.get_value() + self.meter.step)
135
+ elif key == pygame.K_LEFT:
136
+ self.set_value(self.meter.get_value() - self.meter.step)
137
+
138
+ def do_on_click_down(self, button) -> None:
139
+ if not self.is_enabled():
140
+ return
141
+ if button == 1:
142
+ self.get_focus()
143
+
144
+ def value_to_position(self, value: float) -> float:
145
+ """
146
+ Converts a value to a position on the meter, considering the step size.
147
+ """
148
+ rect = self.meter.get_padded_rect()
149
+ value_range = self.meter.get_range()
150
+ value = round(value / self.meter.step) * self.meter.step
151
+ position_ratio = (value - self.meter.min_value) / value_range
152
+ return (
153
+ rect.left
154
+ + (self.handle.rect.w / 2)
155
+ + position_ratio * (rect.width - self.handle.rect.w)
156
+ )
157
+
158
+ def position_to_value(self, position: float) -> float:
159
+ """
160
+ Converts a position on the meter to a value, considering the step size.
161
+ """
162
+ handle_half = self.handle.rect.w / 2
163
+ rect = self.meter.get_padded_rect()
164
+ position = max(rect.left + handle_half, min(position, rect.right - handle_half))
165
+
166
+ position_ratio = (position - rect.left - handle_half) / (
167
+ rect.width - self.handle.rect.w
168
+ )
169
+ value_range = self.meter.get_range()
170
+ value = self.meter.min_value + position_ratio * value_range
171
+ return round(value / self.meter.step) * self.meter.step
172
+
173
+ def get_min_required_size(self) -> tuple[float, float]:
174
+ gap = self.gap if self.text else 0
175
+ if not self.text_rect:
176
+ self.text_rect.size = self._get_text_rect_required_size()
177
+ w, h = self.text_rect.size
178
+ return self.inflate_rect_by_padding((0, 0, w + gap + self.meter.get_min_required_size()[1], h)).size
179
+
180
+ def _build_layout(self) -> None:
181
+
182
+ gap = self.gap if self.text else 0
183
+ self.text_rect.size = self._get_text_rect_required_size()
184
+
185
+ #right part size
186
+ meter_width = self.text_rect.h * 10
187
+ if not self.autoresize_w:
188
+ meter_width = self.get_padded_width() - self.text_rect.w - gap
189
+ right_part_height = min(self.text_rect.h, self.font_object.point_size)
190
+ self.meter.set_size_if_autoresize((meter_width,right_part_height))
191
+ self.handle.set_size_if_autoresize((None,right_part_height))
192
+
193
+
194
+ #join left and right
195
+ joined_rect = pygame.FRect(
196
+ 0, 0, self.text_rect.w + gap + meter_width, self.text_rect.h
197
+ )
198
+
199
+ if self.autoresize_h or self.autoresize_w:
200
+ target_rect = self.inflate_rect_by_padding(joined_rect)
201
+ if not self.autoresize_w:
202
+ target_rect.w = self.rect.w
203
+ if not self.autoresize_h:
204
+ target_rect.h = self.rect.h
205
+ if self.rect.size != target_rect.size:
206
+ self.set_size(target_rect.size)
207
+ self.build()
208
+ return
209
+
210
+ # ------------------------------------ size is ok
211
+
212
+
213
+ offset = self._get_outline_offset() if self.show_text_outline else (0,0)
214
+ padded_rect = self.get_padded_rect()
215
+ padded_relative = padded_rect.move(-self.rect.x, -self.rect.y)
216
+
217
+ self.align_text(joined_rect, padded_relative.move( offset), self.alignment)
218
+ self.text_rect.midleft = joined_rect.midleft
219
+
220
+ if self.text:
221
+ match self.spacing:
222
+ case bf.spacing.MAX:
223
+ gap = padded_relative.right - self.text_rect.right - self.meter.rect.w
224
+ case bf.spacing.MIN:
225
+ gap = 0
226
+
227
+ # place meter
228
+
229
+ pos = self.text_rect.move(
230
+ self.rect.x + gap -offset[0],
231
+ self.rect.y + (self.text_rect.h / 2) - (right_part_height / 2) -offset[1],
232
+ ).topright
233
+ self.meter.rect.topleft = pos
234
+ # place handle
235
+
236
+ x = self.value_to_position(self.meter.value)
237
+ r = self.meter.get_padded_rect()
238
+ self.handle.set_center(x, r.centery)
239
+
240
+ # self.handle.set_center(x,self.rect.top)
@@ -0,0 +1,10 @@
1
+ from .widget import Widget
2
+
3
+
4
+ class Style:
5
+
6
+ def __init__(self):
7
+ pass
8
+
9
+ def apply(self, widget: Widget):
10
+ pass
@@ -0,0 +1,48 @@
1
+ from ..utils import Singleton
2
+ from .widget import Widget
3
+
4
+
5
+ class Style:
6
+ def __init__(self):
7
+ pass
8
+
9
+ def apply(self, widget: Widget):
10
+ pass
11
+
12
+
13
+ class StyleManager(metaclass=Singleton):
14
+ def __init__(self):
15
+ self.styles: list[Style] = []
16
+ self.widgets: set[Widget] = set()
17
+ self.lookup: dict[Widget, bool] = {}
18
+
19
+ def register_widget(self, widget: Widget):
20
+ if widget in self.widgets:
21
+ return
22
+ self.widgets.add(widget)
23
+ self.lookup[widget] = False
24
+ self.update()
25
+
26
+ def refresh_widget(self, widget: Widget):
27
+ if widget in self.widgets:
28
+ self.lookup[widget] = True
29
+ self.update()
30
+
31
+ def remove_widget(self, widget: Widget):
32
+ if widget not in self.widgets:
33
+ return
34
+ self.widgets.remove(widget)
35
+ self.lookup.pop(widget)
36
+
37
+ def add(self, style: Style):
38
+ self.styles.append(style)
39
+ self.lookup = {key: False for key in self.lookup}
40
+ self.update()
41
+
42
+ def update(self):
43
+ for widget in self.widgets:
44
+ if self.lookup[widget]:
45
+ continue
46
+ for style in self.styles:
47
+ style.apply(widget)
48
+ self.lookup[widget] = True