batframework 0.1.13__py3-none-any.whl → 1.0.1__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 (47) hide show
  1. batFramework/__init__.py +41 -46
  2. batFramework/action.py +42 -20
  3. batFramework/actionContainer.py +43 -4
  4. batFramework/animatedSprite.py +26 -20
  5. batFramework/camera.py +177 -47
  6. batFramework/constants.py +26 -51
  7. batFramework/cutscene.py +15 -15
  8. batFramework/cutsceneBlocks.py +11 -9
  9. batFramework/dynamicEntity.py +7 -6
  10. batFramework/easing.py +28 -23
  11. batFramework/entity.py +87 -49
  12. batFramework/enums.py +14 -0
  13. batFramework/fontManager.py +57 -0
  14. batFramework/gui/__init__.py +2 -2
  15. batFramework/gui/button.py +82 -31
  16. batFramework/gui/constraints.py +137 -104
  17. batFramework/gui/container.py +27 -28
  18. batFramework/gui/debugger.py +92 -42
  19. batFramework/gui/frame.py +15 -15
  20. batFramework/gui/image.py +37 -17
  21. batFramework/gui/indicator.py +18 -14
  22. batFramework/gui/interactiveWidget.py +11 -10
  23. batFramework/gui/label.py +60 -56
  24. batFramework/gui/layout.py +50 -47
  25. batFramework/gui/root.py +43 -30
  26. batFramework/gui/shape.py +34 -41
  27. batFramework/gui/slider.py +5 -0
  28. batFramework/gui/toggle.py +31 -27
  29. batFramework/gui/widget.py +148 -128
  30. batFramework/manager.py +18 -13
  31. batFramework/particles.py +16 -13
  32. batFramework/resourceManager.py +55 -0
  33. batFramework/scene.py +141 -83
  34. batFramework/sceneManager.py +21 -16
  35. batFramework/sprite.py +31 -0
  36. batFramework/stateMachine.py +1 -0
  37. batFramework/tileset.py +7 -9
  38. batFramework/time.py +61 -50
  39. batFramework/transition.py +20 -12
  40. batFramework/utils.py +2 -65
  41. batframework-1.0.1.dist-info/LICENCE +21 -0
  42. {batframework-0.1.13.dist-info → batframework-1.0.1.dist-info}/METADATA +3 -2
  43. batframework-1.0.1.dist-info/RECORD +48 -0
  44. {batframework-0.1.13.dist-info → batframework-1.0.1.dist-info}/WHEEL +1 -1
  45. batFramework/debugger.py +0 -48
  46. batframework-0.1.13.dist-info/RECORD +0 -43
  47. {batframework-0.1.13.dist-info → batframework-1.0.1.dist-info}/top_level.txt +0 -0
batFramework/gui/image.py CHANGED
@@ -1,23 +1,43 @@
1
1
  import batFramework as bf
2
2
  from .widget import Widget
3
3
  import pygame
4
+
5
+
4
6
  class Image(Widget):
5
- def __init__(self,data:pygame.Surface|str,size:None|tuple[int,int]=None,convert_alpha=True):
6
- super().__init__(False)
7
- self.surface = None
8
- if isinstance(data,str):
9
- path = bf.utils.get_path(data)
10
- self.original_surface=pygame.image.load(path)
11
- elif isinstance(data,pygame.Surface):
12
- self.original_surface = data
13
-
14
- if convert_alpha: self.original_surface = self.original_surface.convert_alpha()
15
- if not size : size = self.original_surface.get_size()
16
- self.set_size(*size)
7
+ def __init__(
8
+ self,
9
+ data: pygame.Surface | str | None = None,
10
+ size: None | tuple[int, int] = None,
11
+ convert_alpha=True,
12
+ ):
13
+ self.dirty : bool = False
14
+ self.original_surface = None
15
+ self.surface = None
16
+ super().__init__(convert_alpha)
17
+ if data:
18
+ self.set_image(data,size)
17
19
 
20
+ def build(self) -> None:
21
+ if self.original_surface and (
22
+ (not self.surface or self.surface.get_size() != self.get_size_int())
23
+ or self.dirty
24
+ ) :
25
+ self.surface = pygame.transform.scale(
26
+ self.original_surface, self.get_size_int()
27
+ )
18
28
 
19
- def build(self)->None:
20
- if not self.surface or self.surface.get_size() != self.get_size_int():
21
- self.surface = pygame.transform.scale(self.original_surface,self.get_size_int())
22
-
23
-
29
+ def set_image(
30
+ self, data: pygame.Surface | str, size: None | tuple[int, int] = None
31
+ ):
32
+ if isinstance(data, str):
33
+ path = bf.utils.get_path(data)
34
+ tmp = pygame.image.load(path)
35
+ elif isinstance(data, pygame.Surface):
36
+ tmp= data
37
+ if self.convert_alpha:
38
+ tmp = tmp.convert_alpha()
39
+ if tmp != self.original_surface: self.dirty = True
40
+ self.original_surface = tmp
41
+ if not size:
42
+ size = self.original_surface.get_size()
43
+ self.set_size(*size)
@@ -1,42 +1,46 @@
1
1
  from .shape import Shape
2
2
  from typing import Any
3
3
  import pygame
4
+
4
5
  # from .constraints import ConstraintAspectRatio
5
6
 
7
+
6
8
  class Indicator(Shape):
7
- def __init__(self,width:int|float= 10,height:int|float=10)->None:
8
- super().__init__(width,height)
9
+ def __init__(self, width: int | float = 10, height: int | float = 10) -> None:
10
+ super().__init__(width, height)
9
11
 
10
- def to_string_id(self)->str:
12
+ def to_string_id(self) -> str:
11
13
  return "Indicator"
12
14
 
13
- def set_value(self,value:Any)->None:
15
+ def set_value(self, value: Any) -> None:
14
16
  pass
15
17
 
16
- def get_value(self)->Any:
18
+ def get_value(self) -> Any:
17
19
  pass
18
20
 
19
- def _build_indicator(self)->None:
21
+ def _build_indicator(self) -> None:
20
22
  pass
21
-
22
- def build(self)->None:
23
+
24
+ def build(self) -> None:
23
25
  super().build()
24
26
  self._build_indicator()
25
27
 
26
28
 
27
29
  class ToggleIndicator(Indicator):
28
- def __init__(self,default_value:bool)->None:
29
- self.value:bool = default_value
30
- super().__init__(20,20)
30
+ def __init__(self, default_value: bool) -> None:
31
+ self.value: bool = default_value
32
+ super().__init__(20, 20)
33
+
34
+ #TODO aspect ratio would be good right about here
31
35
  # self.add_constraint(ConstraintAspectRatio(1))
32
36
 
33
- def set_value(self,value)->None:
37
+ def set_value(self, value) -> None:
34
38
  self.value = value
35
39
  self.set_color("green" if value else "red")
36
40
  self.build()
37
41
 
38
- def get_value(self)->bool:
39
- return self.value
42
+ def get_value(self) -> bool:
43
+ return self.value
40
44
 
41
45
  def top_at(self, x: float, y: float) -> "None|Widget":
42
46
  return None
@@ -1,22 +1,23 @@
1
1
  from .widget import Widget
2
2
 
3
+
3
4
  class InteractiveWidget(Widget):
4
- def __init__(self,*args,**kwargs):
5
- super().__init__(convert_alpha = True)
5
+ def __init__(self, *args, **kwargs):
6
+ super().__init__(convert_alpha=True)
6
7
  self.focusable = True
7
- self.is_focused : bool = False
8
+ self.is_focused: bool = False
8
9
 
9
- def get_focus(self)->bool:
10
- if self.parent is None or not self.focusable: return False
10
+ def get_focus(self) -> bool:
11
+ if self.parent is None or not self.focusable:
12
+ return False
11
13
  self.get_root().focus_on(self)
12
14
 
13
- def on_get_focus(self)->None:
15
+ def on_get_focus(self) -> None:
14
16
  self.is_focused = True
15
17
 
16
- def on_lose_focus(self)->None:
18
+ def on_lose_focus(self) -> None:
17
19
  self.is_focused = False
18
-
19
- def lose_focus(self)->bool:
20
+
21
+ def lose_focus(self) -> bool:
20
22
  if self.is_focused and self.parent is not None:
21
23
  self.get_root().focus_on(None)
22
-
batFramework/gui/label.py CHANGED
@@ -10,21 +10,21 @@ class Align(Enum):
10
10
  CENTER = 3
11
11
 
12
12
  class Label(Shape):
13
- def __init__(self,text:str) -> None:
13
+ def __init__(self, text: str) -> None:
14
14
  self._text = ""
15
15
 
16
- self._resized_flag : bool = False
16
+ self._resized_flag: bool = False
17
17
 
18
18
  # Enable/Disable antialiasing
19
- self._antialias : bool = True
20
-
21
- self._text_size = bf.const.DEFAULT_TEXT_SIZE
19
+ self._antialias: bool = True
22
20
 
23
- self.auto_wraplength:bool = False
21
+ self._text_size = bf.FontManager().DEFAULT_TEXT_SIZE
24
22
 
25
- self._alignment : Align = Align.CENTER
26
-
27
- self._text_color : tuple[int,int,int]|str = "black"
23
+ self.auto_wraplength: bool = False
24
+
25
+ self._alignment: Align = Align.CENTER
26
+
27
+ self._text_color: tuple[int, int, int] | str = "black"
28
28
  # font name (given when loaded by utils) to use for the text
29
29
  self._font_name = None
30
30
  # reference to the font object
@@ -32,96 +32,102 @@ class Label(Shape):
32
32
  # Rect containing the text of the label
33
33
  self._text_rect = None
34
34
  # text surface (result of font.render)
35
- self._text_surface : pygame.Surface | None= None
36
- super().__init__(width=0,height=0)
37
- self.set_padding((10,4))
35
+ self._text_surface: pygame.Surface | None = None
36
+ super().__init__(width=0, height=0)
37
+ self.set_padding((10, 4))
38
38
  self.set_debug_color("blue")
39
39
  self.set_color(bf.color.CLOUD_WHITE)
40
40
  self.set_autoresize(True)
41
41
  self.set_font(force=True)
42
42
  self.set_text(text)
43
43
 
44
- def set_text_color(self,color)->Self:
44
+ def set_text_color(self, color) -> Self:
45
45
  self._text_color = color
46
46
  self.build()
47
47
  return self
48
48
 
49
- def to_string_id(self)->str:
49
+ def to_string_id(self) -> str:
50
50
  return f"Label({self._text})"
51
51
 
52
- def set_align(self,alignment:Align)->"Label":
52
+ def set_align(self, alignment: Align) -> "Label":
53
53
  self._alignment = alignment
54
- self.build()
54
+ self.build()
55
55
  return self
56
56
 
57
- def set_auto_wraplength(self,val:bool)->"Label":
57
+ def set_auto_wraplength(self, val: bool) -> "Label":
58
58
  self.auto_wraplength = val
59
59
  self.build()
60
60
  return self
61
61
 
62
62
  def get_bounding_box(self):
63
63
  yield from super().get_bounding_box()
64
- if self._text_rect : yield self._text_rect.move(*self.rect.topleft)
64
+ if self._text_rect:
65
+ yield self._text_rect.move(*self.rect.topleft)
65
66
 
66
- def set_font(self,font_name:str=None,force:bool = False)-> "Label":
67
- if font_name == self._font_name and not force: return self
67
+ def set_font(self, font_name: str = None, force: bool = False) -> "Label":
68
+ if font_name == self._font_name and not force:
69
+ return self
68
70
  self._font_name = font_name
69
- self._font_object = bf.utils.get_font(self._font_name,self._text_size)
71
+ self._font_object = bf.FontManager().get_font(self._font_name, self._text_size)
70
72
  self.build()
71
73
  return self
72
74
 
73
- def set_text_size(self,text_size:int) -> "Label":
74
- text_size = round(text_size/2) * 2
75
- if text_size == self._text_size : return self
75
+ def set_text_size(self, text_size: int) -> "Label":
76
+ text_size = round(text_size / 2) * 2
77
+ if text_size == self._text_size:
78
+ return self
76
79
  self._text_size = text_size
77
- self._font_object = bf.utils.get_font(self._font_name,self._text_size)
80
+ self._font_object = bf.FontManager().get_font(self._font_name, self._text_size)
78
81
  self.build()
79
82
  return self
80
83
 
81
- def get_text_size(self)-> int:
84
+ def get_text_size(self) -> int:
82
85
  return self._text_size
83
86
 
84
- def is_antialias(self)->bool:
87
+ def is_antialias(self) -> bool:
85
88
  return self._antialias
86
89
 
87
- def set_antialias(self,value:bool)->"Label":
90
+ def set_antialias(self, value: bool) -> "Label":
88
91
  self._antialias = value
89
92
  self.build()
90
93
  return self
91
94
 
92
- def set_text(self,text:str) -> "Label":
93
- if text == self._text : return self
95
+ def set_text(self, text: str) -> "Label":
96
+ if text == self._text:
97
+ return self
94
98
  self._text = text
95
99
  self.build()
96
100
  return self
97
-
98
- def get_text(self)->str:
101
+
102
+ def get_text(self) -> str:
99
103
  return self._text
100
104
 
101
105
 
102
- def _build_text(self)-> None:
106
+ def get_min_required_size(self)->tuple[float,float]:
107
+ return (0,0) if not self._font_object else self.inflate_rect_by_padding(pygame.FRect(0,0,*self._font_object.size(self._text))).size
108
+
109
+ def _build_text(self) -> None:
103
110
  if self._font_object is None:
104
111
  print(f"No font for '{self.to_string_id()}' :(")
105
112
  return
106
113
  # render(text, antialias, color, bgcolor=None, wraplength=0) -> Surface
107
114
  self._text_surface = self._font_object.render(
108
- text = self._text,
109
- antialias = self._antialias,
110
- color = self._text_color,
111
- bgcolor = self._color,
112
- wraplength = int(self.get_content_width()) if self.auto_wraplength else 0
115
+ text=self._text,
116
+ antialias=self._antialias,
117
+ color=self._text_color,
118
+ bgcolor=self._color,
119
+ wraplength=int(self.get_content_width()) if self.auto_wraplength else 0,
113
120
  )
114
-
121
+
115
122
  self._text_rect = self._text_surface.get_frect()
116
123
 
117
- def _build_layout(self)->None:
124
+ def _build_layout(self) -> None:
125
+ if not self._text_rect : return
118
126
  if self.autoresize:
119
- if self.rect.size != self.inflate_rect_by_padding(self._text_rect).size :
120
- self.set_size(
121
- self._text_rect.w + self.padding[0]+self.padding[2],
122
- self._text_rect.h + self.padding[1]+self.padding[3]
123
- )
124
- self._resized_flag = True
127
+ target_rect = self.inflate_rect_by_padding(self._text_rect)
128
+ if self.rect.size != target_rect.size:
129
+ self._resized_flag = True
130
+ self.set_size(* target_rect.size)
125
131
  return
126
132
  if self._alignment == Align.CENTER:
127
133
  self._text_rect.center = self.get_content_rect_rel().center
@@ -129,20 +135,18 @@ class Label(Shape):
129
135
  self._text_rect.topleft = self.get_content_rect_rel().topleft
130
136
  elif self._alignment == Align.RIGHT:
131
137
  self._text_rect.topright = self.get_content_rect_rel().topright
132
- if self._resized_flag :
138
+ if self._resized_flag:
133
139
  self._resized_flag = False
134
- if self.parent : self.parent.children_modified()
140
+ if self.parent:
141
+ # print("Children modified call")
142
+ self.parent.children_modified()
135
143
 
144
+ self.surface.fblits([(self._text_surface, self._text_rect)])
136
145
 
137
-
138
-
139
- self.surface.blit(self._text_surface,self._text_rect)
140
-
141
- def build(self)->None:
146
+ def build(self) -> None:
142
147
  super().build()
143
- if not self._font_object:return
148
+ if not self._font_object:
149
+ return
144
150
  self._build_text()
145
151
  self._build_layout()
146
152
  self.apply_constraints()
147
-
148
-
@@ -4,90 +4,93 @@ from .constraints import *
4
4
  from typing import Self
5
5
  import pygame
6
6
 
7
+
7
8
  class Layout:
8
- def __init__(self, parent: Widget=None):
9
+ def __init__(self, parent: Widget = None):
9
10
  self.parent = parent
10
- self.child_constraints : list[Constraint] = []
11
-
12
- def set_child_constraints(self,*constraints)->Self:
13
- self.child_constraints = constraints
11
+ self.child_constraints: list[Constraint] = []
12
+ self.children_rect = pygame.FRect(0, 0, 0, 0)
13
+
14
+ def set_child_constraints(self, *constraints) -> Self:
15
+ self.child_constraints = list(constraints)
14
16
  self.arrange()
15
17
  return self
16
-
17
- def set_parent(self,parent:Widget):
18
+
19
+ def set_parent(self, parent: Widget):
18
20
  self.parent = parent
19
21
  self.arrange()
20
22
 
21
- def arrange(self)->None:
23
+ def arrange(self) -> None:
22
24
  raise NotImplementedError("Subclasses must implement arrange method")
23
25
 
26
+
24
27
  class Column(Layout):
25
- def __init__(self,gap:int=0,shrink:bool=False,center:bool = False):
28
+ def __init__(self, gap: int = 0, fit_children: bool = True, center: bool = True):
26
29
  super().__init__()
27
30
  self.gap = gap
28
- self.shrink :bool = shrink
31
+ self.fit_children: bool = fit_children
29
32
  self.center = center
30
- self.children_rect = pygame.FRect(0,0,0,0)
31
-
32
-
33
- def arrange(self)->None:
34
- if not self.parent or not self.parent.children : return
35
33
 
34
+ def arrange(self) -> None:
35
+ if not self.parent or not self.parent.children:
36
+ return
36
37
  len_children = len(self.parent.children)
37
- parent_height = sum(c.rect.h for c in self.parent.children)
38
- parent_width = max(c.rect.w for c in self.parent.children)
39
- if self.gap : parent_height += (len_children-1) * self.gap
40
- self.children_rect.update(self.parent.get_content_left(),self.parent.get_content_top(), parent_width, parent_height)
41
- if self.center : self.children_rect.center = self.parent.rect.center
42
- if self.shrink:
43
- c = self.parent.get_constraint("height")
44
- if not c or c.height != parent_height :
45
- self.parent.add_constraints(ConstraintHeight(parent_height))
46
- c = self.parent.get_constraint("width")
47
- if not c or c.width != parent_width :
48
- self.parent.add_constraints(ConstraintWidth(parent_width))
38
+ parent_height = sum(c.get_min_required_size()[1] for c in self.parent.children)
39
+ parent_width = max(c.get_min_required_size()[0] for c in self.parent.children)
40
+ if self.gap:
41
+ parent_height += (len_children - 1) * self.gap
42
+ self.children_rect.update(
43
+ self.parent.get_content_left(),
44
+ self.parent.get_content_top(),
45
+ parent_width,
46
+ parent_height,
47
+ )
48
+ if self.fit_children:
49
+ self.parent.set_size(parent_width,parent_height)
50
+ if self.center:
51
+ self.children_rect.center = self.parent.rect.center
52
+
49
53
  current_y = self.children_rect.top
50
54
 
51
55
  for child in self.parent.children:
52
- child.set_position(self.parent.rect.x,current_y)
56
+ child.set_position(self.parent.rect.x, current_y)
53
57
  current_y += child.rect.h + self.gap
54
58
  for c in self.child_constraints:
55
- if not child.has_constraint(c.name):
56
- child.add_constraints(c)
57
-
59
+ child.add_constraints(c)
60
+
61
+
58
62
  class Row(Layout):
59
- def __init__(self, gap: int = 0, shrink: bool = False, center: bool = False):
63
+ def __init__(self, gap: int = 0, fit_children: bool = True, center: bool = True):
60
64
  super().__init__()
61
65
  self.gap = gap
62
- self.shrink: bool = shrink
66
+ self.fit_children: bool = fit_children
63
67
  self.center = center
64
- self.children_rect = pygame.FRect(0, 0, 0, 0)
65
68
 
66
69
  def arrange(self) -> None:
67
70
  if not self.parent or not self.parent.children:
68
71
  return
69
72
 
70
73
  len_children = len(self.parent.children)
71
- parent_width = sum(c.rect.w for c in self.parent.children)
72
- parent_height = max(c.rect.h for c in self.parent.children)
74
+ parent_width = sum(c.get_min_required_size()[0] for c in self.parent.children)
75
+ parent_height = max(c.get_min_required_size()[1] for c in self.parent.children)
76
+
73
77
  if self.gap:
74
78
  parent_width += (len_children - 1) * self.gap
75
- self.children_rect.update(self.parent.get_content_left(),self.parent.get_content_top(), parent_width, parent_height)
79
+ self.children_rect.update(
80
+ self.parent.get_content_left(),
81
+ self.parent.get_content_top(),
82
+ parent_width,
83
+ parent_height,
84
+ )
76
85
  if self.center:
77
86
  self.children_rect.center = self.parent.get_content_center()
78
- if self.shrink:
79
- c = self.parent.get_constraint("width")
80
- if not c or c.width != parent_width:
81
- self.parent.add_constraints(ConstraintWidth(parent_width))
82
- c = self.parent.get_constraint("height")
83
- if not c or c.height != parent_height:
84
- self.parent.add_constraints(ConstraintHeight(parent_height))
87
+ if self.fit_children:
88
+ self.parent.set_size(parent_width,parent_height)
89
+
85
90
  current_x = self.children_rect.left
86
91
 
87
92
  for child in self.parent.children:
88
93
  child.set_position(current_x, self.parent.rect.y)
89
94
  current_x += child.rect.w + self.gap
90
95
  for c in self.child_constraints:
91
- if not child.has_constraint(c.name):
92
- child.add_constraints(c)
93
-
96
+ child.add_constraints(c)
batFramework/gui/root.py CHANGED
@@ -3,63 +3,76 @@ from .interactiveWidget import InteractiveWidget
3
3
  from .widget import Widget
4
4
  import pygame
5
5
 
6
+
6
7
  class Root(InteractiveWidget):
7
8
  def __init__(self):
8
9
  super().__init__()
9
10
  self.surface = None
10
11
  self.set_root()
11
12
  self.rect.size = pygame.display.get_surface().get_size()
12
- self.focused : InteractiveWidget = self
13
- self.hovered : Widget|None = self
13
+ self.focused: InteractiveWidget |None= self
14
+ self.hovered: Widget | None = self
14
15
  self.set_debug_color("purple")
15
16
 
16
- def to_string(self)->str:
17
- return "ROOT"
17
+ def to_string(self) -> str:
18
+ return "ROOT"
18
19
 
19
- def get_focused(self)->Widget|None:
20
+ def get_focused(self) -> Widget | None:
20
21
  return self.focused
21
22
 
22
- def get_hovered(self)->Widget|None:
23
+ def get_hovered(self) -> Widget | None:
23
24
  return self.hovered
24
-
25
- def to_string_id(self)->str:
25
+
26
+ def reset(self)->None:
27
+ self.focus_on(None)
28
+ self.hovered = None
29
+
30
+ def to_string_id(self) -> str:
26
31
  return "ROOT"
27
32
 
28
- def focus_on(self,widget:InteractiveWidget)->None:
29
- if self.focused is not None:
33
+ def focus_on(self, widget: InteractiveWidget|None) -> None:
34
+ if self.focused is not None:
30
35
  self.focused.on_lose_focus()
31
- if widget is None :
36
+ if widget is None:
32
37
  self.focused = self
33
38
  return
34
- self.focused= widget
39
+ self.focused = widget
35
40
  self.focused.on_get_focus()
36
41
 
37
- def set_size(self,width:float,height:float,force:bool=False)->"Root":
38
- if not force : return self
39
- self.rect.size = width,height
42
+ def set_size(self, width: float, height: float, force: bool = False) -> "Root":
43
+ if not force:
44
+ return self
45
+ self.rect.size = width, height
40
46
  self.build(apply_constraints=True)
41
47
  return self
42
-
43
- def build(self,apply_constraints:bool=False)->None:
44
- if apply_constraints : self.apply_all_constraints()
45
- for child in self.children :
48
+
49
+ def build(self, apply_constraints: bool = False) -> None:
50
+ if apply_constraints:
51
+ self.apply_all_constraints()
52
+ for child in self.children:
46
53
  child.build()
47
-
48
- def do_handle_event(self,event):
54
+
55
+ def do_handle_event(self, event):
49
56
  if event.type == pygame.VIDEORESIZE:
50
- self.set_size(event.w,event.h,force=True)
57
+ self.set_size(event.w, event.h, force=True)
51
58
  return True
52
59
  return False
53
60
 
54
- def update(self,dt:float)->None:
61
+ def get_root(self) -> "Root" :
62
+ return self
63
+
64
+
65
+ def update(self, dt: float) -> None:
55
66
  super().update(dt)
56
67
  old = self.hovered
57
- self.hovered = self.top_at(*pygame.mouse.get_pos()) if self.top_at(*pygame.mouse.get_pos()) else None
58
- if old == self.hovered:return
59
- if isinstance(self.hovered,bf.Button):
68
+ self.hovered = (
69
+ self.top_at(*pygame.mouse.get_pos())
70
+ if self.top_at(*pygame.mouse.get_pos())
71
+ else None
72
+ )
73
+ if old == self.hovered:
74
+ return
75
+ if isinstance(self.hovered, bf.Button):
60
76
  pygame.mouse.set_cursor(*pygame.cursors.tri_left)
61
77
  else:
62
- pygame.mouse.set_cursor()
63
-
64
-
65
-
78
+ pygame.mouse.set_cursor(pygame.cursors.arrow)