batframework 1.0.6__py3-none-any.whl → 1.0.8a1__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.
- batFramework/__init__.py +23 -14
- batFramework/action.py +95 -106
- batFramework/actionContainer.py +11 -8
- batFramework/animatedSprite.py +60 -43
- batFramework/audioManager.py +52 -22
- batFramework/camera.py +87 -72
- batFramework/constants.py +19 -41
- batFramework/cutscene.py +12 -11
- batFramework/cutsceneBlocks.py +12 -14
- batFramework/dynamicEntity.py +5 -4
- batFramework/easingController.py +58 -0
- batFramework/entity.py +37 -130
- batFramework/enums.py +93 -3
- batFramework/fontManager.py +15 -7
- batFramework/gui/__init__.py +5 -1
- batFramework/gui/button.py +6 -144
- batFramework/gui/clickableWidget.py +206 -0
- batFramework/gui/constraints/__init__.py +1 -0
- batFramework/gui/constraints/constraints.py +378 -0
- batFramework/gui/container.py +147 -34
- batFramework/gui/debugger.py +39 -22
- batFramework/gui/dialogueBox.py +69 -43
- batFramework/gui/draggableWidget.py +38 -0
- batFramework/gui/image.py +33 -28
- batFramework/gui/indicator.py +30 -16
- batFramework/gui/interactiveWidget.py +72 -20
- batFramework/gui/label.py +240 -98
- batFramework/gui/layout.py +125 -53
- batFramework/gui/meter.py +76 -0
- batFramework/gui/radioButton.py +62 -0
- batFramework/gui/root.py +72 -48
- batFramework/gui/shape.py +257 -49
- batFramework/gui/slider.py +217 -2
- batFramework/gui/textInput.py +106 -60
- batFramework/gui/toggle.py +85 -42
- batFramework/gui/widget.py +259 -288
- batFramework/manager.py +30 -16
- batFramework/object.py +115 -0
- batFramework/{particles.py → particle.py} +37 -34
- batFramework/renderGroup.py +62 -0
- batFramework/resourceManager.py +36 -24
- batFramework/scene.py +94 -88
- batFramework/sceneManager.py +140 -57
- batFramework/scrollingSprite.py +113 -0
- batFramework/sprite.py +35 -23
- batFramework/tileset.py +34 -52
- batFramework/time.py +105 -56
- batFramework/transition.py +213 -1
- batFramework/utils.py +38 -18
- {batframework-1.0.6.dist-info → batframework-1.0.8a1.dist-info}/METADATA +1 -1
- batframework-1.0.8a1.dist-info/RECORD +56 -0
- {batframework-1.0.6.dist-info → batframework-1.0.8a1.dist-info}/WHEEL +1 -1
- batFramework/easing.py +0 -76
- batFramework/gui/constraints.py +0 -277
- batFramework/gui/frame.py +0 -25
- batFramework/transitionManager.py +0 -0
- batframework-1.0.6.dist-info/RECORD +0 -50
- {batframework-1.0.6.dist-info → batframework-1.0.8a1.dist-info}/LICENCE +0 -0
- {batframework-1.0.6.dist-info → batframework-1.0.8a1.dist-info}/top_level.txt +0 -0
batFramework/dynamicEntity.py
CHANGED
@@ -7,11 +7,10 @@ class DynamicEntity(bf.Entity):
|
|
7
7
|
def __init__(
|
8
8
|
self,
|
9
9
|
size: None | tuple[int, int] = None,
|
10
|
-
no_surface: bool = False,
|
11
10
|
surface_flags: int = 0,
|
12
11
|
convert_alpha: bool = False,
|
13
12
|
) -> None:
|
14
|
-
super().__init__(size,
|
13
|
+
super().__init__(size, surface_flags, convert_alpha)
|
15
14
|
self.velocity = pygame.math.Vector2(0, 0)
|
16
15
|
|
17
16
|
def on_collideX(self, collider: Self):
|
@@ -20,5 +19,7 @@ class DynamicEntity(bf.Entity):
|
|
20
19
|
def on_collideY(self, collider: Self):
|
21
20
|
return False
|
22
21
|
|
23
|
-
def move_by_velocity(self,dt) -> None:
|
24
|
-
self.set_position(
|
22
|
+
def move_by_velocity(self, dt) -> None:
|
23
|
+
self.set_position(
|
24
|
+
self.rect.x + self.velocity.x * dt, self.rect.y + self.velocity.y * dt
|
25
|
+
)
|
@@ -0,0 +1,58 @@
|
|
1
|
+
import pygame
|
2
|
+
import batFramework as bf
|
3
|
+
from functools import lru_cache
|
4
|
+
from .enums import easing
|
5
|
+
|
6
|
+
|
7
|
+
@lru_cache(maxsize=None)
|
8
|
+
def process_value(progress: float, p0: float, p1: float, p2: float, p3: float) -> float:
|
9
|
+
if p0 == 0 and p1 == 0 and p2 == 1 and p3 == 1: # Linear easing control points
|
10
|
+
return progress
|
11
|
+
t = progress
|
12
|
+
t_inv = 1.0 - t
|
13
|
+
t2 = t * t
|
14
|
+
t3 = t * t2
|
15
|
+
t_inv2 = t_inv * t_inv
|
16
|
+
return 3 * t_inv2 * t * p1 + 3 * t_inv * t2 * p3 + t3
|
17
|
+
|
18
|
+
|
19
|
+
class EasingController(bf.Timer):
|
20
|
+
def __init__(
|
21
|
+
self,
|
22
|
+
easing_function: easing = easing.LINEAR,
|
23
|
+
duration: float = 1,
|
24
|
+
update_callback=None,
|
25
|
+
end_callback=None,
|
26
|
+
loop: bool = False,
|
27
|
+
) -> None:
|
28
|
+
self.easing_function = easing_function
|
29
|
+
self.update_callback = update_callback
|
30
|
+
self.value: float = 0.0
|
31
|
+
super().__init__(duration, end_callback, loop)
|
32
|
+
|
33
|
+
def get_value(self) -> float:
|
34
|
+
return self.value
|
35
|
+
|
36
|
+
def start(self, force: bool = False):
|
37
|
+
super().start(force)
|
38
|
+
self.value = 0
|
39
|
+
|
40
|
+
def update(self, dt: float) -> None:
|
41
|
+
if self.get_progression() == 1:
|
42
|
+
return
|
43
|
+
super().update(dt)
|
44
|
+
if self.get_progression() == 0:
|
45
|
+
return
|
46
|
+
if self.easing_function == easing.LINEAR:
|
47
|
+
self.value = self.get_progression()
|
48
|
+
else:
|
49
|
+
self.value = process_value(
|
50
|
+
self.get_progression(), *self.easing_function.control_points
|
51
|
+
)
|
52
|
+
if self.update_callback:
|
53
|
+
self.update_callback(self.value)
|
54
|
+
|
55
|
+
def end(self):
|
56
|
+
if self.update_callback:
|
57
|
+
self.update_callback(1)
|
58
|
+
super().end()
|
batFramework/entity.py
CHANGED
@@ -1,160 +1,67 @@
|
|
1
1
|
from typing import Any, Self
|
2
2
|
import pygame
|
3
3
|
import batFramework as bf
|
4
|
+
from .object import Object
|
4
5
|
|
5
|
-
class Entity:
|
6
|
+
class Entity(Object):
|
6
7
|
"""
|
7
|
-
|
8
|
+
Basic entity class
|
8
9
|
"""
|
9
|
-
__instance_count = 0
|
10
|
-
|
11
10
|
def __init__(
|
12
11
|
self,
|
13
12
|
size: None | tuple[int, int] = None,
|
14
|
-
no_surface: bool = False,
|
15
13
|
surface_flags: int = 0,
|
16
14
|
convert_alpha: bool = False,
|
15
|
+
*args,
|
16
|
+
**kwargs,
|
17
17
|
) -> None:
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
if convert_alpha and self.surface is not None:
|
18
|
+
super().__init__()
|
19
|
+
self.visible: bool = True
|
20
|
+
self.rect.size = (10, 10) if size is None else size
|
21
|
+
self.convert_alpha: bool = convert_alpha
|
22
|
+
self.surface_flags: int = surface_flags
|
23
|
+
self.blit_flags: int = 0
|
24
|
+
self.surface: pygame.Surface = pygame.Surface(self.rect.size, surface_flags)
|
25
|
+
if convert_alpha:
|
27
26
|
self.surface = self.surface.convert_alpha()
|
28
27
|
self.surface.fill((0, 0, 0, 0))
|
29
28
|
|
30
|
-
|
31
|
-
self.
|
32
|
-
self.parent_scene: bf.Scene | None = None
|
33
|
-
self.visible: bool = True
|
34
|
-
self.debug_color: tuple = bf.color.DARK_RED
|
35
|
-
self.render_order: int = 0
|
36
|
-
self.uid: Any = Entity.__instance_count
|
37
|
-
Entity.__instance_count += 1
|
38
|
-
|
39
|
-
def set_render_order(self, render_order: int) -> Self:
|
40
|
-
self.render_order = render_order
|
41
|
-
return self
|
42
|
-
|
43
|
-
def get_bounding_box(self):
|
44
|
-
yield (self.rect, self.debug_color)
|
45
|
-
|
46
|
-
def set_debug_color(self, color) -> Self:
|
47
|
-
self.debug_color = color
|
48
|
-
return self
|
49
|
-
|
50
|
-
def set_visible(self, value: bool) -> Self:
|
51
|
-
self.visible = value
|
52
|
-
return self
|
53
|
-
|
54
|
-
def set_parent_scene(self, scene) -> Self:
|
55
|
-
self.parent_scene = scene
|
29
|
+
def set_alpha(self, alpha: int) -> Self:
|
30
|
+
self.surface.set_alpha(min(max(0, alpha), 255))
|
56
31
|
return self
|
57
32
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
61
|
-
def do_when_removed(self):
|
62
|
-
pass
|
63
|
-
|
64
|
-
def set_position(self, x, y) -> Self:
|
65
|
-
self.rect.topleft = (x, y)
|
66
|
-
return self
|
67
|
-
|
68
|
-
def get_position(self) -> tuple:
|
69
|
-
return self.rect.topleft
|
70
|
-
|
71
|
-
def get_center(self) -> tuple:
|
72
|
-
return self.rect.center
|
33
|
+
def get_alpha(self)->int:
|
34
|
+
return self.surface.get_alpha()
|
73
35
|
|
74
|
-
def
|
75
|
-
self.
|
36
|
+
def set_surface_flags(self, surface_flags: int) -> Self:
|
37
|
+
self.surface_flags = surface_flags
|
76
38
|
return self
|
77
39
|
|
78
|
-
def
|
79
|
-
self.
|
40
|
+
def set_convert_alpha(self, value: bool) -> Self:
|
41
|
+
self.convert_alpha = value
|
80
42
|
return self
|
81
43
|
|
82
|
-
def
|
83
|
-
self.
|
44
|
+
def set_blit_flags(self, blit_flags: int) -> Self:
|
45
|
+
self.blit_flags = blit_flags
|
84
46
|
return self
|
85
47
|
|
86
|
-
def
|
87
|
-
self.
|
48
|
+
def set_render_order(self, render_order: int) -> Self:
|
49
|
+
self.render_order = render_order
|
50
|
+
if self.parent_scene:
|
51
|
+
self.parent_scene.sort_entities()
|
88
52
|
return self
|
89
53
|
|
90
|
-
def
|
91
|
-
|
92
|
-
if tag not in self.tags:
|
93
|
-
self.tags.append(tag)
|
94
|
-
self.tags.sort()
|
54
|
+
def set_visible(self, value: bool) -> Self:
|
55
|
+
self.visible = value
|
95
56
|
return self
|
96
57
|
|
97
|
-
def
|
98
|
-
self.tags = [tag for tag in self.tags if tag not in tags]
|
99
|
-
|
100
|
-
def has_tags(self, *tags) -> bool:
|
101
|
-
return all(tag in self.tags for tag in tags)
|
102
|
-
|
103
|
-
def get_tags(self) -> list[str]:
|
104
|
-
return self.tags
|
105
|
-
|
106
|
-
def process_event(self, event: pygame.Event) -> bool:
|
107
|
-
"""
|
108
|
-
Returns bool : True if the method is blocking (no propagation to next children of the scene)
|
109
|
-
"""
|
110
|
-
self.do_process_actions(event)
|
111
|
-
res = self.do_handle_actions()
|
112
|
-
res = res or self.do_handle_event(event)
|
113
|
-
self.do_reset_actions()
|
114
|
-
return res
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
def do_process_actions(self, event: pygame.Event) -> None:
|
119
|
-
"""
|
120
|
-
Process entity actions you may have set
|
121
|
-
"""
|
122
|
-
|
123
|
-
def do_reset_actions(self) -> None:
|
124
|
-
"""
|
125
|
-
Reset entity actions you may have set
|
126
|
-
"""
|
127
|
-
|
128
|
-
def do_handle_actions(self) ->None:
|
129
|
-
"""
|
130
|
-
Handle entity actions
|
58
|
+
def draw(self, camera: bf.Camera) -> None:
|
131
59
|
"""
|
132
|
-
|
133
|
-
def do_handle_event(self, event: pygame.Event) -> bool:
|
134
|
-
"""
|
135
|
-
Handle specific
|
60
|
+
Draw the entity onto the camera surface
|
136
61
|
"""
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
"""
|
144
|
-
self.do_update(dt)
|
145
|
-
|
146
|
-
def do_update(self, dt: float):
|
147
|
-
"""
|
148
|
-
Update method to be overriden for specific behavior by the end user
|
149
|
-
"""
|
150
|
-
|
151
|
-
def draw(self, camera: bf.Camera) -> int:
|
152
|
-
"""
|
153
|
-
Draw the entity onto the camera with coordinate transposing
|
154
|
-
"""
|
155
|
-
should_not_draw = not self.visible or not self.surface or not camera.intersects(self.rect)
|
156
|
-
if should_not_draw:
|
157
|
-
return 0
|
158
|
-
camera.surface.blit(self.surface, camera.transpose(self.rect))
|
159
|
-
|
160
|
-
return 1
|
62
|
+
if not self.visible or not camera.rect.colliderect(self.rect): return
|
63
|
+
camera.surface.blit(
|
64
|
+
self.surface,
|
65
|
+
camera.world_to_screen(self.rect),
|
66
|
+
special_flags=self.blit_flags,
|
67
|
+
)
|
batFramework/enums.py
CHANGED
@@ -1,14 +1,104 @@
|
|
1
1
|
from enum import Enum
|
2
2
|
|
3
|
-
|
3
|
+
|
4
|
+
class color:
|
5
|
+
WHITE = (255, 255, 255)
|
6
|
+
LIGHTER_GRAY = (236, 240, 241)
|
7
|
+
LIGHT_GRAY = (189, 195, 199)
|
8
|
+
DARK_GRAY = (66, 66, 66)
|
9
|
+
DARKER_GRAY = (23, 23, 23)
|
10
|
+
BLACK = (0, 0, 0)
|
11
|
+
|
12
|
+
TURQUOISE = (26, 188, 156)
|
13
|
+
TURQUOISE_SHADE = (22, 160, 133)
|
14
|
+
|
15
|
+
GREEN = (46, 204, 113)
|
16
|
+
GREEN_SHADE = (39, 174, 96)
|
17
|
+
|
18
|
+
BLUE = (52, 152, 219)
|
19
|
+
BLUE_SHADE = (41, 128, 185)
|
20
|
+
|
21
|
+
PURPLE = (155, 89, 182)
|
22
|
+
PURPLE_SHADE = (142, 68, 173)
|
23
|
+
|
24
|
+
CHARCOAL = (52, 73, 94)
|
25
|
+
CHARCOAL_SHADE = (44, 62, 80)
|
26
|
+
|
27
|
+
GOLD = (241, 196, 15)
|
28
|
+
GOLD_SHADE = (243, 156, 18)
|
29
|
+
|
30
|
+
ORANGE = (230, 126, 34)
|
31
|
+
ORANGE_SHADE = (211, 84, 0)
|
32
|
+
|
33
|
+
RED = (231, 76, 60)
|
34
|
+
RED_SHADE = (192, 57, 43)
|
35
|
+
|
36
|
+
CLOUD = (236, 240, 241)
|
37
|
+
CLOUD_SHADE = (189, 195, 199)
|
38
|
+
|
39
|
+
CONCRETE = (149, 165, 166)
|
40
|
+
CONCRETE_SHADE = (127, 140, 141)
|
41
|
+
|
42
|
+
# GB
|
43
|
+
DARKER_GB = (27, 42, 9)
|
44
|
+
DARK_GB = (14, 69, 11)
|
45
|
+
LIGHT_GB = (73, 107, 34)
|
46
|
+
LIGHTER_GB = (154, 158, 63)
|
47
|
+
|
48
|
+
class easing(Enum):
|
49
|
+
LINEAR = (0, 0, 1, 1)
|
50
|
+
EASE_IN = (0.95, 0, 1, 0.55)
|
51
|
+
EASE_OUT = (0.5, 1, 0.5, 1)
|
52
|
+
EASE_IN_OUT = (0.55, 0, 0.45, 1)
|
53
|
+
EASE_IN_OUT_ELASTIC = (0.39, -0.55, 0.3, 1.3)
|
54
|
+
|
55
|
+
def __init__(self, *control_points):
|
56
|
+
self.control_points = control_points
|
57
|
+
|
58
|
+
class axis(Enum):
|
4
59
|
HORIZONTAL = "horizontal"
|
5
60
|
VERTICAL = "vertical"
|
6
61
|
|
7
|
-
|
8
|
-
|
62
|
+
class spacing(Enum):
|
63
|
+
MIN = "min"
|
64
|
+
HALF = "half"
|
65
|
+
MAX = "max"
|
66
|
+
MANUAL = "manual"
|
67
|
+
class alignment(Enum):
|
9
68
|
LEFT = "left"
|
10
69
|
RIGHT = "right"
|
11
70
|
CENTER = "center"
|
12
71
|
TOP = "top"
|
13
72
|
BOTTOM = "bottom"
|
73
|
+
TOPLEFT = "topleft"
|
74
|
+
TOPRIGHT = "topright"
|
75
|
+
MIDLEFT = "midleft"
|
76
|
+
MIDRIGHT = "midright"
|
77
|
+
BOTTOMLEFT = "bottomleft"
|
78
|
+
BOTTOMRIGHT = "bottomright"
|
79
|
+
|
80
|
+
class direction(Enum):
|
81
|
+
LEFT = 0
|
82
|
+
UP = 1
|
83
|
+
RIGHT = 2
|
84
|
+
DOWN = 3
|
85
|
+
|
86
|
+
class drawMode(Enum):
|
87
|
+
SOLID = 0
|
88
|
+
TEXTURED = 1
|
89
|
+
|
90
|
+
class debugMode(Enum):
|
91
|
+
HIDDEN = 0
|
92
|
+
DEBUGGER = 1
|
93
|
+
OUTLINES = 2
|
94
|
+
|
95
|
+
class actionType(Enum):
|
96
|
+
INSTANTANEOUS = 0
|
97
|
+
CONTINUOUS = 1
|
98
|
+
HOLDING = 2
|
99
|
+
|
14
100
|
|
101
|
+
class textMode(Enum):
|
102
|
+
ALPHABETICAL = 0
|
103
|
+
NUMERICAL = 1
|
104
|
+
ALPHANUMERIC = 3
|
batFramework/fontManager.py
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
from .utils import Singleton
|
2
|
+
|
2
3
|
# put font stuff here later
|
3
4
|
import pygame
|
4
5
|
import os
|
5
6
|
import batFramework as bf
|
7
|
+
|
8
|
+
|
6
9
|
class FontManager(metaclass=Singleton):
|
7
10
|
def __init__(self):
|
8
11
|
pygame.font.init()
|
@@ -12,10 +15,13 @@ class FontManager(metaclass=Singleton):
|
|
12
15
|
self.DEFAULT_ANTIALIAS = False
|
13
16
|
self.FONTS = {}
|
14
17
|
|
15
|
-
def
|
18
|
+
def set_antialias(self,value:bool):
|
19
|
+
self.DEFAULT_ANTIALIAS = value
|
20
|
+
|
21
|
+
def set_default_text_size(self, size: int):
|
16
22
|
self.DEFAULT_TEXT_SIZE = size
|
17
23
|
|
18
|
-
def init_font(self,raw_path: str|None):
|
24
|
+
def init_font(self, raw_path: str | None):
|
19
25
|
try:
|
20
26
|
if raw_path is not None:
|
21
27
|
self.load_font(raw_path if raw_path else None, None)
|
@@ -24,14 +30,14 @@ class FontManager(metaclass=Singleton):
|
|
24
30
|
self.load_sysfont(raw_path)
|
25
31
|
self.load_sysfont(raw_path, None)
|
26
32
|
|
27
|
-
def load_font(self,path: str|None, name: str|None = ""):
|
33
|
+
def load_font(self, path: str | None, name: str | None = ""):
|
28
34
|
if path is not None:
|
29
35
|
path = bf.ResourceManager().get_path(path) # convert path if given
|
30
36
|
filename = None
|
31
37
|
if path is not None:
|
32
38
|
filename = os.path.basename(path).split(".")[0]
|
33
|
-
|
34
|
-
|
39
|
+
|
40
|
+
# get filename if path is given, else None
|
35
41
|
if name != "":
|
36
42
|
filename = name # if name is not given, name is the filename
|
37
43
|
self.FONTS[filename] = {}
|
@@ -39,7 +45,7 @@ class FontManager(metaclass=Singleton):
|
|
39
45
|
for size in range(self.MIN_FONT_SIZE, self.MAX_FONT_SIZE, 2):
|
40
46
|
self.FONTS[filename][size] = pygame.font.Font(path, size=size)
|
41
47
|
|
42
|
-
def load_sysfont(self,font_name: str|None, key: str |None= ""):
|
48
|
+
def load_sysfont(self, font_name: str | None, key: str | None = ""):
|
43
49
|
if key == "":
|
44
50
|
key = font_name
|
45
51
|
if font_name is None or pygame.font.match_font(font_name) is None:
|
@@ -49,7 +55,9 @@ class FontManager(metaclass=Singleton):
|
|
49
55
|
for size in range(self.MIN_FONT_SIZE, self.MAX_FONT_SIZE, 2):
|
50
56
|
self.FONTS[key][size] = pygame.font.SysFont(font_name, size=size)
|
51
57
|
|
52
|
-
def get_font(
|
58
|
+
def get_font(
|
59
|
+
self, name: str | None = None, text_size: int = 12
|
60
|
+
) -> pygame.Font | None:
|
53
61
|
if not name in self.FONTS:
|
54
62
|
return None
|
55
63
|
if not text_size in self.FONTS[name]:
|
batFramework/gui/__init__.py
CHANGED
@@ -2,9 +2,11 @@ from .constraints import *
|
|
2
2
|
from .widget import Widget
|
3
3
|
from .image import Image
|
4
4
|
from .interactiveWidget import InteractiveWidget
|
5
|
+
from .draggableWidget import DraggableWidget
|
6
|
+
from .clickableWidget import ClickableWidget
|
5
7
|
from .root import Root
|
6
8
|
from .shape import Shape
|
7
|
-
from .
|
9
|
+
from .meter import Meter
|
8
10
|
from .label import Label
|
9
11
|
from .dialogueBox import DialogueBox
|
10
12
|
from .textInput import TextInput
|
@@ -14,3 +16,5 @@ from .layout import *
|
|
14
16
|
from .container import Container
|
15
17
|
from .indicator import *
|
16
18
|
from .toggle import Toggle
|
19
|
+
from .radioButton import RadioButton,RadioVariable
|
20
|
+
from .slider import Slider
|
batFramework/gui/button.py
CHANGED
@@ -1,150 +1,12 @@
|
|
1
1
|
from .label import Label
|
2
2
|
import batFramework as bf
|
3
|
-
from typing import Self,Callable
|
4
|
-
from .
|
3
|
+
from typing import Self, Callable
|
4
|
+
from .clickableWidget import ClickableWidget
|
5
5
|
import pygame
|
6
|
+
from math import ceil
|
6
7
|
|
7
8
|
|
8
|
-
class Button(Label,
|
9
|
-
|
10
|
-
|
11
|
-
def __init__(self, text: str, callback: None| Callable = None) -> None:
|
12
|
-
# Label.__init__(self,text)
|
13
|
-
self.callback = callback
|
14
|
-
self.is_hovered: bool = False
|
15
|
-
self.effect_max :float= 20
|
16
|
-
self.effect_speed :float= 1.8
|
17
|
-
self.is_clicking : bool = False
|
18
|
-
self.effect :float = 0
|
19
|
-
self.enabled :bool = True
|
9
|
+
class Button(Label, ClickableWidget):
|
10
|
+
def __init__(self, text: str, callback: None | Callable = None) -> None:
|
20
11
|
super().__init__(text=text)
|
21
|
-
self.
|
22
|
-
self.focusable = True
|
23
|
-
|
24
|
-
def get_surface_filter(self) -> pygame.Surface | None:
|
25
|
-
if not self.surface:
|
26
|
-
return None
|
27
|
-
|
28
|
-
size = self.surface.get_size()
|
29
|
-
surface_filter = Button._cache.get(size, None)
|
30
|
-
|
31
|
-
if surface_filter is None:
|
32
|
-
# Create a mask from the original surface
|
33
|
-
mask = pygame.mask.from_surface(self.surface,threshold=0)
|
34
|
-
|
35
|
-
# Get the bounding box of the mask
|
36
|
-
silhouette_surface = mask.to_surface(
|
37
|
-
setcolor = (30,30,30),unsetcolor= (255,255,255)
|
38
|
-
).convert_alpha()
|
39
|
-
|
40
|
-
|
41
|
-
Button._cache[size] = silhouette_surface
|
42
|
-
surface_filter = silhouette_surface
|
43
|
-
|
44
|
-
return surface_filter
|
45
|
-
def enable(self)->Self:
|
46
|
-
self.enabled = True
|
47
|
-
self.build()
|
48
|
-
return self
|
49
|
-
|
50
|
-
def disable(self)->Self:
|
51
|
-
self.enabled = False
|
52
|
-
self.build()
|
53
|
-
return self
|
54
|
-
|
55
|
-
def is_enabled(self)->bool:
|
56
|
-
return self.enabled
|
57
|
-
|
58
|
-
def set_callback(self, callback: Callable) -> Self:
|
59
|
-
self.callback = callback
|
60
|
-
return self
|
61
|
-
|
62
|
-
def on_get_focus(self):
|
63
|
-
super().on_get_focus()
|
64
|
-
self.build()
|
65
|
-
|
66
|
-
def on_lose_focus(self):
|
67
|
-
super().on_lose_focus()
|
68
|
-
self.build()
|
69
|
-
|
70
|
-
def to_string_id(self) -> str:
|
71
|
-
return f"Button({self._text}){'' if self.enabled else '[disabled]'}"
|
72
|
-
|
73
|
-
def click(self) -> None:
|
74
|
-
if self.callback is not None:
|
75
|
-
self.callback()
|
76
|
-
bf.Timer(duration=0.3,end_callback=self._safety_effect_end).start()
|
77
|
-
|
78
|
-
def _safety_effect_end(self)->None:
|
79
|
-
if self.effect > 0:
|
80
|
-
self.effect = 0
|
81
|
-
self.build()
|
82
|
-
|
83
|
-
def start_effect(self):
|
84
|
-
if self.effect <= 0 : self.effect = self.effect_max
|
85
|
-
|
86
|
-
|
87
|
-
def do_on_click_down(self,button)->None:
|
88
|
-
if self.enabled and button == 1 and self.effect == 0:
|
89
|
-
if not self.get_focus():return
|
90
|
-
self.is_clicking = True
|
91
|
-
self.start_effect()
|
92
|
-
|
93
|
-
def do_on_click_up(self,button)->None:
|
94
|
-
if self.enabled and button == 1 and self.is_clicking:
|
95
|
-
# self.effect = 0
|
96
|
-
self.is_clicking = False
|
97
|
-
self.build()
|
98
|
-
self.click()
|
99
|
-
|
100
|
-
def on_enter(self)->None:
|
101
|
-
if not self.enabled : return
|
102
|
-
super().on_enter()
|
103
|
-
self.effect = 0
|
104
|
-
self.build()
|
105
|
-
pygame.mouse.set_cursor(*pygame.cursors.tri_left)
|
106
|
-
|
107
|
-
def on_exit(self)->None:
|
108
|
-
super().on_exit()
|
109
|
-
# self.effect = 0
|
110
|
-
self.is_clicking = False
|
111
|
-
self.build()
|
112
|
-
pygame.mouse.set_cursor(pygame.cursors.arrow)
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
def update(self,dt):
|
117
|
-
super().update(dt)
|
118
|
-
if self.effect <= 0: return
|
119
|
-
self.effect -= dt*60*self.effect_speed
|
120
|
-
if self.is_clicking:
|
121
|
-
if self.effect < 1 : self.effect = 1
|
122
|
-
else:
|
123
|
-
if self.effect < 0 : self.effect = 0
|
124
|
-
self.build()
|
125
|
-
|
126
|
-
def _build_effect(self)->None:
|
127
|
-
if self.effect < 1 : return
|
128
|
-
e = int(min(self.rect.w //3, self.rect.h//3,self.effect))
|
129
|
-
pygame.draw.rect(
|
130
|
-
self.surface,
|
131
|
-
bf.color.CLOUD_WHITE,
|
132
|
-
(0,0,*self.surface.get_size()),
|
133
|
-
#int(self.effect),
|
134
|
-
e,
|
135
|
-
*self._border_radius
|
136
|
-
)
|
137
|
-
def _build_disabled(self)->None:
|
138
|
-
self.surface.blit(self.get_surface_filter(), (0, 0), special_flags=pygame.BLEND_SUB)
|
139
|
-
|
140
|
-
def _build_hovered(self)->None:
|
141
|
-
self.surface.blit(self.get_surface_filter(), (0, 0), special_flags=pygame.BLEND_ADD)
|
142
|
-
|
143
|
-
def build(self) -> None:
|
144
|
-
super().build()
|
145
|
-
if not self.enabled:
|
146
|
-
self._build_disabled()
|
147
|
-
elif self.is_hovered:
|
148
|
-
self._build_hovered()
|
149
|
-
if self.effect:
|
150
|
-
self._build_effect()
|
12
|
+
self.set_callback(callback)
|