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
@@ -1,201 +1,220 @@
1
- import batFramework as bf
2
- from .widget import Widget
3
- from .shape import Shape
4
- from .interactiveWidget import InteractiveWidget
5
- from .layout import Layout, Column
6
- from typing import Self
7
- from pygame.math import Vector2
8
-
9
-
10
- class Container(Shape, InteractiveWidget):
11
- def __init__(self, layout: Layout = None, *children: Widget) -> None:
12
- super().__init__()
13
- self.dirty_layout: bool = False
14
- self.set_debug_color("green")
15
- self.layout = layout if layout else Column()
16
- self.layout.set_parent(self)
17
- self.scroll = Vector2(0, 0)
18
- self.add(*children)
19
-
20
- def __str__(self) -> str:
21
- return f"Container({self.uid},{len(self.children)})"
22
-
23
- def get_min_required_size(self):
24
- return self.layout.get_auto_size() if self.layout else self.rect.size
25
-
26
- def reset_scroll(self) -> Self:
27
- if self.scroll == (0,0):
28
- return self
29
- self.scroll.update(0, 0)
30
- self.dirty_layout = True
31
- return self
32
-
33
- def set_scroll(self, value: tuple) -> Self:
34
- if (self.scroll.x,self.scroll.y) == value:
35
- return self
36
- self.scroll.update(value)
37
- self.clamp_scroll()
38
- self.dirty_layout = True
39
- return self
40
-
41
- def scrollX_by(self, x: float | int) -> Self:
42
- if x == 0:
43
- return self
44
- self.set_scroll((self.scroll.x + x, self.scroll.y))
45
- return self
46
-
47
- def scrollY_by(self, y: float | int) -> Self:
48
- if y == 0:
49
- return self
50
- self.set_scroll((self.scroll.x, self.scroll.y + y))
51
- return self
52
-
53
- def scroll_by(self, value: tuple[float | int, float | int]) -> Self:
54
- if value[0] == 0 and value[1] == 0:
55
- return self
56
- self.set_scroll((self.scroll.x + value[0], self.scroll.y + value[1]))
57
- return self
58
-
59
- def clamp_scroll(self) -> Self:
60
- if not self.children:
61
- return self
62
- r = self.get_inner_rect()
63
- # Compute the bounding rect of all children in one go
64
- children_rect = self.children[0].rect.copy()
65
- for child in self.children[1:]:
66
- children_rect.union_ip(child.rect)
67
- max_scroll_x = max(0, children_rect.width - r.width)
68
- max_scroll_y = max(0, children_rect.height - r.height)
69
-
70
- # Clamp scroll values only if needed
71
- new_x = min(max(self.scroll.x, 0), max_scroll_x)
72
- new_y = min(max(self.scroll.y, 0), max_scroll_y)
73
-
74
- self.set_scroll((new_x, new_y))
75
- return self
76
-
77
- def set_layout(self, layout: Layout) -> Self:
78
- tmp = self.layout
79
- self.layout = layout
80
- if self.layout != tmp:
81
- tmp.set_parent(None)
82
- self.layout.set_parent(self)
83
- self.reset_scroll()
84
- self.dirty_layout = True
85
- return self
86
-
87
- def get_interactive_children(self) -> list[InteractiveWidget]:
88
- return [child for child in self.get_layout_children() if isinstance(child, InteractiveWidget) and not isinstance(child,Container) and child.allow_focus_to_self()]
89
-
90
- def get_layout_children(self)->list[Widget]:
91
- return self.children
92
-
93
- def clear_children(self) -> None:
94
- self.children.clear()
95
- self.dirty_layout = True
96
-
97
- def add(self, *child: Widget) -> Self:
98
- super().add(*child)
99
- self.dirty_shape = True
100
- self.dirty_layout = True
101
- return self
102
-
103
- def remove(self, *child: Widget) -> Self:
104
- super().remove(*child)
105
- self.dirty_shape = True
106
- self.dirty_layout = True
107
- return self
108
-
109
- def top_at(self, x: float | int, y: float | int) -> "None|Widget":
110
- if self.rect.collidepoint(x, y):
111
- for child in reversed(self.children):
112
- result = child.top_at(x, y)
113
- if result is not None:
114
- return result
115
- return self
116
- return None
117
-
118
- def get_focus(self) -> bool:
119
- if not super().get_focus():
120
- return False
121
- interactive_children = self.get_interactive_children()
122
- if not interactive_children:
123
- return True
124
- self.focused_index = min(self.focused_index, len(interactive_children) - 1)
125
- return interactive_children[self.focused_index].get_focus()
126
-
127
- def children_has_focus(self)->bool:
128
- return any(child.is_focused for child in self.get_interactive_children())
129
-
130
- def do_handle_event(self, event) -> None:
131
- if event.consumed:
132
- return
133
- self.layout.handle_event(event)
134
-
135
- def set_focused_child(self, child: InteractiveWidget) -> bool:
136
- interactive_children = self.get_interactive_children()
137
- try:
138
- index = interactive_children.index(child)
139
- self.focused_index = index
140
- if self.layout :
141
- self.layout.scroll_to_widget(child)
142
- return True
143
- except ValueError:
144
- return False
145
-
146
- def allow_focus_to_self(self) -> bool:
147
- return bool(self.get_interactive_children()) and self.visible
148
-
149
- def build(self) -> None:
150
- if self.layout is not None:
151
- # print("I'm building !",self)
152
- # size = self.expand_rect_with_padding((0,0,*self.layout.get_auto_size())).size
153
- size = self.layout.get_auto_size()
154
- self.set_size(self.resolve_size(size))
155
- super().build()
156
-
157
- def apply_pre_updates(self):
158
- if self.dirty_size_constraints or self.dirty_shape:
159
- self.resolve_constraints(size_only=True)
160
- self.dirty_size_constraints = False
161
- self.dirty_position_constraints = True
162
-
163
- if self.dirty_layout:
164
- self.layout.update_child_constraints()
165
- self.layout.arrange()
166
- self.dirty_layout = False
167
-
168
- def apply_post_updates(self,skip_draw:bool=False):
169
- """
170
- BOTTOM TO TOP
171
- for cases when widget attributes depend on children attributes
172
- """
173
- if self.dirty_shape:
174
- self.layout.update_child_constraints()
175
- self.build()
176
- self.dirty_shape = False
177
- self.dirty_surface = True
178
- self.dirty_layout = True
179
- self.dirty_size_constraints = True
180
- self.dirty_position_constraints = True
181
- from .container import Container
182
- if self.parent and isinstance(self.parent, Container):
183
- self.parent.dirty_layout = True
184
- self.parent.dirty_shape = True
185
-
186
- # trigger layout or constraint updates in parent
187
-
188
-
189
- # force recheck of constraints
190
-
191
-
192
- if self.dirty_position_constraints:
193
- self.resolve_constraints(position_only=True)
194
- self.dirty_position_constraints= False
195
-
196
-
197
- if self.dirty_surface and not skip_draw:
198
- self.paint()
199
- self.dirty_surface = False
200
-
201
-
1
+ import pygame
2
+ import batFramework as bf
3
+ from .widget import Widget
4
+ from .shape import Shape
5
+ from .interactiveWidget import InteractiveWidget
6
+ from .layout import Layout, Column
7
+ from typing import Self
8
+ from pygame.math import Vector2
9
+
10
+
11
+ class Container(Shape, InteractiveWidget):
12
+ def __init__(self, layout: Layout = None, *children: Widget) -> None:
13
+ super().__init__()
14
+ self.dirty_layout: bool = False
15
+ self.layout = layout if layout else Column()
16
+ self.layout.set_parent(self)
17
+ self.scroll = Vector2(0, 0)
18
+ self.dirty_scroll = False
19
+ self.set_debug_color("green")
20
+ self.add(*children)
21
+
22
+
23
+ def __str__(self) -> str:
24
+ return f"Container({self.uid},{len(self.children)})"
25
+
26
+ def get_min_required_size(self):
27
+ return self.layout.get_auto_size() if self.layout else self.rect.size
28
+
29
+ def reset_scroll(self) -> Self:
30
+ if self.scroll == (0,0):
31
+ return self
32
+ self.set_scroll((0, 0))
33
+ return self
34
+
35
+ def set_scroll(self, value: tuple[float]) -> Self:
36
+ # print("Trying to set scroll to ",value)
37
+ # print("Current scroll is : ",self.scroll)
38
+
39
+ if (self.scroll.x,self.scroll.y) == value:
40
+ return self
41
+ self.scroll.update(value)
42
+ # print("Scroll updated to", value)
43
+ self.clamp_scroll()
44
+ self.dirty_scroll = True
45
+ # self.dirty_layout = True
46
+ return self
47
+
48
+ def scrollX_by(self, x: float) -> Self:
49
+ if x == 0:
50
+ return self
51
+ self.set_scroll((self.scroll.x + x, self.scroll.y))
52
+ return self
53
+
54
+ def scrollY_by(self, y: float) -> Self:
55
+ if y == 0:
56
+ return self
57
+ self.set_scroll((self.scroll.x, self.scroll.y + y))
58
+ return self
59
+
60
+ def scroll_by(self, value: tuple[float]) -> Self:
61
+ self.set_scroll((self.scroll.x + value[0], self.scroll.y + value[1]))
62
+ return self
63
+
64
+ def clamp_scroll(self) -> Self:
65
+ if not self.children:
66
+ return self
67
+ r = self.get_inner_rect()
68
+
69
+ if self.layout:
70
+ # self.layout.update_children_rect()
71
+ children_rect = self.layout.children_rect
72
+ else:
73
+ l = self.get_layout_children()
74
+ if l:
75
+ children_rect = l[0].rect.unionall(
76
+ [c.rect for c in l[1:]]
77
+ ) if len(l) > 1 else l
78
+ else:
79
+ children_rect = pygame.Rect(0,0,0,0)
80
+
81
+ max_scroll_x = max(0, children_rect.width - r.width)
82
+ max_scroll_y = max(0, children_rect.height - r.height)
83
+
84
+ sx = min(max(self.scroll.x, 0), max_scroll_x)
85
+ sy = min(max(self.scroll.y, 0), max_scroll_y)
86
+ # print("_"*20)
87
+ # print("Clamping scroll, children rect is :",children_rect)
88
+ # print("scroll to,",(sx,sy), "while current scroll is",self.scroll)
89
+
90
+ self.set_scroll((sx,sy))
91
+
92
+ return self
93
+
94
+ def set_layout(self, layout: Layout) -> Self:
95
+ tmp = self.layout
96
+ self.layout = layout
97
+ if self.layout != tmp:
98
+ tmp.set_parent(None)
99
+ self.layout.set_parent(self)
100
+ self.reset_scroll()
101
+ self.dirty_layout = True
102
+ return self
103
+
104
+ def get_interactive_children(self) -> list[InteractiveWidget]:
105
+ """Return all children that can be cycled through with focus"""
106
+ return [child for child in self.get_layout_children() \
107
+ if isinstance(child, InteractiveWidget) and not\
108
+ isinstance(child,Container) and child.allow_focus_to_self()]
109
+
110
+ def get_layout_children(self)->list[Widget]:
111
+ """Returns all children affected by layout"""
112
+ return self.children
113
+
114
+ def clear_children(self) -> None:
115
+ for child in self.children:
116
+ child.set_parent(None)
117
+ self.children.clear()
118
+ self.dirty_layout = True
119
+
120
+ def add(self, *child: Widget) -> Self:
121
+ super().add(*child)
122
+ self.dirty_shape = True
123
+ self.dirty_layout = True
124
+ return self
125
+
126
+ def remove(self, *child: Widget) -> Self:
127
+ super().remove(*child)
128
+ self.dirty_shape = True
129
+ self.dirty_layout = True
130
+ return self
131
+
132
+ def top_at(self, x: float | int, y: float | int) -> "None|Widget":
133
+ if self.rect.collidepoint(x, y):
134
+ for child in reversed(self.children):
135
+ result = child.top_at(x, y)
136
+ if result is not None:
137
+ return result
138
+ return self
139
+ return None
140
+
141
+ def get_focus(self) -> bool:
142
+ if not super().get_focus():
143
+ return False
144
+ interactive_children = self.get_interactive_children()
145
+ if not interactive_children:
146
+ return True
147
+ self.focused_index = min(self.focused_index, len(interactive_children) - 1)
148
+ return interactive_children[self.focused_index].get_focus()
149
+
150
+ def children_has_focus(self)->bool:
151
+ """Return true if any direct children is focused"""
152
+ return any(child.is_focused for child in self.get_interactive_children())
153
+
154
+ def handle_event(self, event) -> None:
155
+ super().handle_event(event)
156
+ self.layout.handle_event(event)
157
+
158
+ def set_focused_child(self, child: InteractiveWidget) -> bool:
159
+ interactive_children = self.get_interactive_children()
160
+ try:
161
+ index = interactive_children.index(child)
162
+ self.focused_index = index
163
+ if self.layout :
164
+ self.layout.scroll_to_widget(child)
165
+ return True
166
+ except ValueError:
167
+ return False
168
+
169
+ def allow_focus_to_self(self) -> bool:
170
+ """Return whether the container can get focused"""
171
+ return bool(self.get_interactive_children()) and self.visible
172
+
173
+ def build(self) -> None:
174
+ if self.layout is not None:
175
+ size = self.layout.get_auto_size()
176
+ self.set_size(self.resolve_size(size))
177
+ super().build()
178
+
179
+
180
+ def apply_pre_updates(self):
181
+ if self.dirty_size_constraints or self.dirty_shape:
182
+ self.resolve_constraints(size_only=True)
183
+ self.dirty_size_constraints = False
184
+ self.dirty_position_constraints = True
185
+
186
+
187
+
188
+ if self.dirty_layout:
189
+ self.layout.update_child_constraints()
190
+ self.layout.arrange()
191
+ self.dirty_layout = False
192
+
193
+ if self.dirty_scroll:
194
+ self.layout.scroll_children()
195
+ self.dirty_scroll = False
196
+
197
+ def apply_post_updates(self,skip_draw:bool=False):
198
+ if self.dirty_shape:
199
+ self.layout.update_child_constraints()
200
+ self.build()
201
+ self.dirty_size_constraints = True
202
+ self.dirty_position_constraints = True
203
+ self.dirty_layout = True
204
+ from .container import Container
205
+ if self.parent and isinstance(self.parent, Container):
206
+ self.parent.dirty_layout = True
207
+ self.parent.dirty_shape = True
208
+ self.dirty_shape = False
209
+ self.dirty_surface = True
210
+
211
+ if self.dirty_position_constraints:
212
+ self.resolve_constraints(position_only=True)
213
+ self.dirty_position_constraints= False
214
+
215
+
216
+ if self.dirty_surface and not skip_draw:
217
+ self.paint()
218
+ self.dirty_surface = False
219
+
220
+