pygkit 1.0.1__tar.gz → 1.0.3__tar.gz
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.
- {pygkit-1.0.1 → pygkit-1.0.3}/PKG-INFO +5 -2
- {pygkit-1.0.1 → pygkit-1.0.3}/README.md +4 -1
- {pygkit-1.0.1 → pygkit-1.0.3}/pyproject.toml +1 -1
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/__init__.py +5 -0
- pygkit-1.0.3/src/pygkit/inventory/__init__.py +86 -0
- pygkit-1.0.3/src/pygkit/inventory/assets.py +307 -0
- pygkit-1.0.3/src/pygkit/inventory/core.py +599 -0
- pygkit-1.0.3/src/pygkit/inventory/data.py +273 -0
- pygkit-1.0.3/src/pygkit/inventory/ui.py +694 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/ui/__init__.py +6 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/ui/base.py +1 -0
- pygkit-1.0.3/src/pygkit/ui/dialog.py +487 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit.egg-info/PKG-INFO +5 -2
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit.egg-info/SOURCES.txt +8 -0
- pygkit-1.0.3/tests/test_dialog.py +313 -0
- pygkit-1.0.3/tests/test_inventory.py +730 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/LICENSE +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/setup.cfg +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/audio/__init__.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/audio/soundmanager.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/protocols.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/transitions/__init__.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/transitions/base.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/transitions/effects.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/transitions/fades.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/transitions/wipes.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/ui/container.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/ui/cooldown.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/ui/progressbar.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/utils/__init__.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/utils/interpolation.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/utils/text.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit/utils/timer.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit.egg-info/dependency_links.txt +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit.egg-info/requires.txt +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/src/pygkit.egg-info/top_level.txt +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/tests/test_box_model.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/tests/test_interpolation.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/tests/test_text.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/tests/test_timer.py +0 -0
- {pygkit-1.0.1 → pygkit-1.0.3}/tests/test_transitions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pygkit
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: General-purpose Pygame CE runtime kit: UI widgets, audio, timers, interpolation, and more.
|
|
5
5
|
Author: pygkit contributors
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -708,8 +708,11 @@ import pygkit
|
|
|
708
708
|
|
|
709
709
|
## Features
|
|
710
710
|
|
|
711
|
-
- **UI**: Box-model widgets with plugin compositing — progress bars, cooldown overlays, containers
|
|
711
|
+
- **UI**: Box-model widgets with plugin compositing — progress bars, cooldown overlays, containers, dialog system
|
|
712
|
+
- **Dialog**: Typewriter effect with customizable speeds, speaker names, and progress indicators
|
|
713
|
+
- **Inventory**: Grid-based item management with stacking, weight tracking, events, and serialization
|
|
712
714
|
- **Audio**: SoundManager with channel pools and explicit targeting
|
|
715
|
+
- **Transitions**: Screen transitions with fade, wipe, and custom effects
|
|
713
716
|
- **Utils**: Timer, interpolation/easing functions
|
|
714
717
|
|
|
715
718
|
## Installation
|
|
@@ -10,8 +10,11 @@ import pygkit
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
- **UI**: Box-model widgets with plugin compositing — progress bars, cooldown overlays, containers
|
|
13
|
+
- **UI**: Box-model widgets with plugin compositing — progress bars, cooldown overlays, containers, dialog system
|
|
14
|
+
- **Dialog**: Typewriter effect with customizable speeds, speaker names, and progress indicators
|
|
15
|
+
- **Inventory**: Grid-based item management with stacking, weight tracking, events, and serialization
|
|
14
16
|
- **Audio**: SoundManager with channel pools and explicit targeting
|
|
17
|
+
- **Transitions**: Screen transitions with fade, wipe, and custom effects
|
|
15
18
|
- **Utils**: Timer, interpolation/easing functions
|
|
16
19
|
|
|
17
20
|
## Installation
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pygkit"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.3"
|
|
8
8
|
description = "General-purpose Pygame CE runtime kit: UI widgets, audio, timers, interpolation, and more."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pygkit Inventory System - Production-grade inventory management for Pygame.
|
|
3
|
+
|
|
4
|
+
A complete, generic, and optimized inventory system with:
|
|
5
|
+
- Data-driven item definitions
|
|
6
|
+
- Grid-based slot management
|
|
7
|
+
- Drag-and-drop interactions
|
|
8
|
+
- Tooltips and visual feedback
|
|
9
|
+
- Asset caching for performance
|
|
10
|
+
- Event-driven architecture
|
|
11
|
+
- Save/load serialization support
|
|
12
|
+
|
|
13
|
+
Modules:
|
|
14
|
+
data: Type definitions and data structures
|
|
15
|
+
core: Inventory logic and state management
|
|
16
|
+
assets: Asset caching and procedural generation
|
|
17
|
+
ui: UI rendering and user interaction
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
from pygkit.inventory import Inventory, InventoryWidget, ItemData
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
config = {"rows": 4, "cols": 6, "slot_size": 48}
|
|
24
|
+
inventory = Inventory("player_backpack", config)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
item: ItemData = {
|
|
28
|
+
"id": "health_potion",
|
|
29
|
+
"name": "Health Potion",
|
|
30
|
+
"description": "Restores 50 HP",
|
|
31
|
+
"stack_size": 99,
|
|
32
|
+
"icon_color": (200, 50, 50, 255),
|
|
33
|
+
"icon_shape": "circle",
|
|
34
|
+
"value": 25,
|
|
35
|
+
"weight": 0.5,
|
|
36
|
+
}
|
|
37
|
+
inventory.add_item(item, quantity=5)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
widget = InventoryWidget(inventory, position=(100, 100))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
widget.handle_events(pygame.event.get())
|
|
44
|
+
widget.update(dt)
|
|
45
|
+
widget.render(screen)
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
from .assets import (
|
|
49
|
+
AssetCache,
|
|
50
|
+
generate_procedural_icon,
|
|
51
|
+
get_cache,
|
|
52
|
+
render_quantity_text,
|
|
53
|
+
)
|
|
54
|
+
from .core import Inventory
|
|
55
|
+
from .data import (
|
|
56
|
+
DEFAULT_INVENTORY_CONFIG,
|
|
57
|
+
RARITY_COLORS,
|
|
58
|
+
InventoryConfig,
|
|
59
|
+
InventoryEvent,
|
|
60
|
+
ItemData,
|
|
61
|
+
ItemStack,
|
|
62
|
+
)
|
|
63
|
+
from .ui import (
|
|
64
|
+
DragDropState,
|
|
65
|
+
InventoryManager,
|
|
66
|
+
InventoryWidget,
|
|
67
|
+
Tooltip,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
__all__ = [
|
|
71
|
+
"ItemData",
|
|
72
|
+
"InventoryConfig",
|
|
73
|
+
"ItemStack",
|
|
74
|
+
"InventoryEvent",
|
|
75
|
+
"RARITY_COLORS",
|
|
76
|
+
"DEFAULT_INVENTORY_CONFIG",
|
|
77
|
+
"Inventory",
|
|
78
|
+
"AssetCache",
|
|
79
|
+
"get_cache",
|
|
80
|
+
"generate_procedural_icon",
|
|
81
|
+
"render_quantity_text",
|
|
82
|
+
"Tooltip",
|
|
83
|
+
"DragDropState",
|
|
84
|
+
"InventoryWidget",
|
|
85
|
+
"InventoryManager",
|
|
86
|
+
]
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Asset caching and procedural generation for the Inventory System.
|
|
3
|
+
|
|
4
|
+
Provides optimized caching of static UI elements and procedural
|
|
5
|
+
generation of item icons to avoid runtime overhead.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
import pygame
|
|
13
|
+
from pygame import SRCALPHA, Surface
|
|
14
|
+
from pygame.typing import ColorLike
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AssetCache:
|
|
18
|
+
"""
|
|
19
|
+
Singleton-style cache for static UI assets.
|
|
20
|
+
|
|
21
|
+
Caches procedurally generated surfaces to avoid redundant creation.
|
|
22
|
+
Automatically handles different sizes and colors.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
_instance: Optional[AssetCache] = None
|
|
26
|
+
|
|
27
|
+
def __new__(cls) -> AssetCache:
|
|
28
|
+
if cls._instance is None:
|
|
29
|
+
cls._instance = super().__new__(cls)
|
|
30
|
+
cls._instance._initialized = False
|
|
31
|
+
return cls._instance
|
|
32
|
+
|
|
33
|
+
def __init__(self) -> None:
|
|
34
|
+
if self._initialized:
|
|
35
|
+
return
|
|
36
|
+
self._initialized = True
|
|
37
|
+
|
|
38
|
+
self._slot_surfaces: dict[tuple[int, int, str], Surface] = {}
|
|
39
|
+
self._icon_surfaces: dict[tuple[str, tuple[int, int], ColorLike], Surface] = {}
|
|
40
|
+
self._background_surfaces: dict[tuple[int, int, int, ColorLike], Surface] = {}
|
|
41
|
+
|
|
42
|
+
def clear(self) -> None:
|
|
43
|
+
"""Clear all cached surfaces."""
|
|
44
|
+
self._slot_surfaces.clear()
|
|
45
|
+
self._icon_surfaces.clear()
|
|
46
|
+
self._background_surfaces.clear()
|
|
47
|
+
|
|
48
|
+
def get_slot_surface(
|
|
49
|
+
self,
|
|
50
|
+
size: int | tuple[int, int],
|
|
51
|
+
border_radius: int = 4,
|
|
52
|
+
style: str = "default",
|
|
53
|
+
) -> Surface:
|
|
54
|
+
"""
|
|
55
|
+
Get or create a cached slot background surface.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
size: Slot size (width, height) or single int for square
|
|
59
|
+
border_radius: Corner radius for rounded slots
|
|
60
|
+
style: Style variant ("default", "highlighted", "invalid")
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Cached surface for the slot
|
|
64
|
+
"""
|
|
65
|
+
if isinstance(size, int):
|
|
66
|
+
size = (size, size)
|
|
67
|
+
|
|
68
|
+
key = (*size, style)
|
|
69
|
+
|
|
70
|
+
if key not in self._slot_surfaces:
|
|
71
|
+
self._slot_surfaces[key] = self._create_slot_surface(size, border_radius, style)
|
|
72
|
+
|
|
73
|
+
return self._slot_surfaces[key].copy()
|
|
74
|
+
|
|
75
|
+
def _create_slot_surface(
|
|
76
|
+
self,
|
|
77
|
+
size: tuple[int, int],
|
|
78
|
+
border_radius: int,
|
|
79
|
+
style: str,
|
|
80
|
+
) -> Surface:
|
|
81
|
+
"""Create a new slot surface (internal use)."""
|
|
82
|
+
surf = Surface(size, SRCALPHA)
|
|
83
|
+
surf.fill((0, 0, 0, 0))
|
|
84
|
+
|
|
85
|
+
if style == "default":
|
|
86
|
+
color = (60, 60, 70, 200)
|
|
87
|
+
elif style == "highlighted":
|
|
88
|
+
color = (100, 150, 200, 180)
|
|
89
|
+
elif style == "invalid":
|
|
90
|
+
color = (200, 80, 80, 180)
|
|
91
|
+
else:
|
|
92
|
+
color = (60, 60, 70, 200)
|
|
93
|
+
|
|
94
|
+
w, h = int(size[0]), int(size[1])
|
|
95
|
+
pygame.draw.rect(surf, color, (0, 0, w, h), border_radius=border_radius)
|
|
96
|
+
|
|
97
|
+
inner_rect = pygame.Rect(2, 2, size[0] - 4, size[1] - 4)
|
|
98
|
+
pygame.draw.rect(surf, (80, 80, 90, 150), inner_rect, width=1, border_radius=max(0, border_radius - 1))
|
|
99
|
+
|
|
100
|
+
return surf
|
|
101
|
+
|
|
102
|
+
def get_icon_surface(
|
|
103
|
+
self,
|
|
104
|
+
shape: str,
|
|
105
|
+
size: int | tuple[int, int],
|
|
106
|
+
color: ColorLike,
|
|
107
|
+
) -> Surface:
|
|
108
|
+
"""
|
|
109
|
+
Get or create a cached item icon surface.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
shape: Icon shape ("circle", "square", "diamond", "cross", "star")
|
|
113
|
+
size: Icon size (width, height) or single int for square
|
|
114
|
+
color: RGBA color for the icon
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Cached surface with the icon rendered
|
|
118
|
+
"""
|
|
119
|
+
if isinstance(size, int):
|
|
120
|
+
size = (size, size)
|
|
121
|
+
|
|
122
|
+
color_tuple = tuple(color) if not isinstance(color, tuple) else color
|
|
123
|
+
|
|
124
|
+
key = (shape, size, color_tuple)
|
|
125
|
+
|
|
126
|
+
if key not in self._icon_surfaces:
|
|
127
|
+
self._icon_surfaces[key] = self._create_icon_surface(shape, size, color)
|
|
128
|
+
|
|
129
|
+
return self._icon_surfaces[key].copy()
|
|
130
|
+
|
|
131
|
+
def _create_icon_surface(
|
|
132
|
+
self,
|
|
133
|
+
shape: str,
|
|
134
|
+
size: tuple[int, int],
|
|
135
|
+
color: ColorLike,
|
|
136
|
+
) -> Surface:
|
|
137
|
+
"""Create a new icon surface (internal use)."""
|
|
138
|
+
surf = Surface(size, SRCALPHA)
|
|
139
|
+
surf.fill((0, 0, 0, 0))
|
|
140
|
+
|
|
141
|
+
center_x = size[0] // 2
|
|
142
|
+
center_y = size[1] // 2
|
|
143
|
+
radius = min(size[0], size[1]) // 2 - 4
|
|
144
|
+
|
|
145
|
+
if shape == "circle":
|
|
146
|
+
pygame.draw.circle(surf, color, (center_x, center_y), radius)
|
|
147
|
+
|
|
148
|
+
elif shape == "square":
|
|
149
|
+
rect = pygame.Rect(
|
|
150
|
+
center_x - radius,
|
|
151
|
+
center_y - radius,
|
|
152
|
+
radius * 2,
|
|
153
|
+
radius * 2,
|
|
154
|
+
)
|
|
155
|
+
pygame.draw.rect(surf, color, rect, border_radius=4)
|
|
156
|
+
|
|
157
|
+
elif shape == "diamond":
|
|
158
|
+
points = [
|
|
159
|
+
(center_x, center_y - radius),
|
|
160
|
+
(center_x + radius, center_y),
|
|
161
|
+
(center_x, center_y + radius),
|
|
162
|
+
(center_x - radius, center_y),
|
|
163
|
+
]
|
|
164
|
+
pygame.draw.polygon(surf, color, points)
|
|
165
|
+
|
|
166
|
+
elif shape == "cross":
|
|
167
|
+
arm_width = radius // 3
|
|
168
|
+
|
|
169
|
+
pygame.draw.rect(surf, color, (center_x - arm_width, center_y - radius, arm_width * 2, radius * 2))
|
|
170
|
+
|
|
171
|
+
pygame.draw.rect(surf, color, (center_x - radius, center_y - arm_width, radius * 2, arm_width * 2))
|
|
172
|
+
|
|
173
|
+
elif shape == "star":
|
|
174
|
+
outer_r = radius
|
|
175
|
+
inner_r = radius // 2
|
|
176
|
+
points = []
|
|
177
|
+
import math
|
|
178
|
+
|
|
179
|
+
for i in range(8):
|
|
180
|
+
r = outer_r if i % 2 == 0 else inner_r
|
|
181
|
+
rad = math.radians(i * 45)
|
|
182
|
+
x = center_x + r * math.cos(rad)
|
|
183
|
+
y = center_y + r * math.sin(rad)
|
|
184
|
+
points.append((x, y))
|
|
185
|
+
pygame.draw.polygon(surf, color, points)
|
|
186
|
+
|
|
187
|
+
else:
|
|
188
|
+
pygame.draw.circle(surf, color, (center_x, center_y), radius)
|
|
189
|
+
|
|
190
|
+
return surf
|
|
191
|
+
|
|
192
|
+
def get_background_surface(
|
|
193
|
+
self,
|
|
194
|
+
width: int,
|
|
195
|
+
height: int,
|
|
196
|
+
border_radius: int,
|
|
197
|
+
color: ColorLike,
|
|
198
|
+
) -> Surface:
|
|
199
|
+
"""
|
|
200
|
+
Get or create a cached background panel surface.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
width: Panel width
|
|
204
|
+
height: Panel height
|
|
205
|
+
border_radius: Corner radius
|
|
206
|
+
color: Background color (RGBA)
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
Cached background surface
|
|
210
|
+
"""
|
|
211
|
+
color_tuple = tuple(color) if not isinstance(color, tuple) else color
|
|
212
|
+
key = (width, height, border_radius, color_tuple)
|
|
213
|
+
|
|
214
|
+
if key not in self._background_surfaces:
|
|
215
|
+
self._background_surfaces[key] = self._create_background_surface(width, height, border_radius, color)
|
|
216
|
+
|
|
217
|
+
return self._background_surfaces[key].copy()
|
|
218
|
+
|
|
219
|
+
def _create_background_surface(
|
|
220
|
+
self,
|
|
221
|
+
width: int,
|
|
222
|
+
height: int,
|
|
223
|
+
border_radius: int,
|
|
224
|
+
color: ColorLike,
|
|
225
|
+
) -> Surface:
|
|
226
|
+
"""Create a new background surface (internal use)."""
|
|
227
|
+
surf = Surface((width, height), SRCALPHA)
|
|
228
|
+
surf.fill((0, 0, 0, 0))
|
|
229
|
+
|
|
230
|
+
pygame.draw.rect(surf, color, (0, 0, width, height), border_radius=border_radius)
|
|
231
|
+
|
|
232
|
+
return surf
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
_cache: Optional[AssetCache] = None
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def get_cache() -> AssetCache:
|
|
239
|
+
"""Get the global asset cache instance."""
|
|
240
|
+
global _cache
|
|
241
|
+
if _cache is None:
|
|
242
|
+
_cache = AssetCache()
|
|
243
|
+
return _cache
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def generate_procedural_icon(
|
|
247
|
+
shape: str,
|
|
248
|
+
size: int = 32,
|
|
249
|
+
color: ColorLike = (200, 200, 200, 255),
|
|
250
|
+
) -> Surface:
|
|
251
|
+
"""
|
|
252
|
+
Generate a procedural item icon.
|
|
253
|
+
|
|
254
|
+
Convenience function that uses the global cache.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
shape: Icon shape ("circle", "square", "diamond", "cross", "star")
|
|
258
|
+
size: Icon size in pixels
|
|
259
|
+
color: RGBA color
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
Surface with the rendered icon
|
|
263
|
+
"""
|
|
264
|
+
return get_cache().get_icon_surface(shape, size, color)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def render_quantity_text(
|
|
268
|
+
quantity: int,
|
|
269
|
+
font: pygame.font.Font,
|
|
270
|
+
color: ColorLike = (255, 255, 255, 255),
|
|
271
|
+
outline_color: ColorLike = (0, 0, 0, 255),
|
|
272
|
+
) -> Surface:
|
|
273
|
+
"""
|
|
274
|
+
Render quantity text with outline for readability.
|
|
275
|
+
|
|
276
|
+
Args:
|
|
277
|
+
quantity: Number to display
|
|
278
|
+
font: Font to use
|
|
279
|
+
color: Text color
|
|
280
|
+
outline_color: Outline color
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
Surface with rendered text
|
|
284
|
+
"""
|
|
285
|
+
if quantity <= 1:
|
|
286
|
+
return Surface((1, 1), SRCALPHA)
|
|
287
|
+
|
|
288
|
+
text = str(quantity)
|
|
289
|
+
|
|
290
|
+
base_surf = font.render(text, True, color)
|
|
291
|
+
|
|
292
|
+
thickness = 1
|
|
293
|
+
w = base_surf.get_width() + thickness * 2
|
|
294
|
+
h = base_surf.get_height() + thickness * 2
|
|
295
|
+
result = Surface((w, h), SRCALPHA)
|
|
296
|
+
result.fill((0, 0, 0, 0))
|
|
297
|
+
|
|
298
|
+
for dx in range(-thickness, thickness + 1):
|
|
299
|
+
for dy in range(-thickness, thickness + 1):
|
|
300
|
+
if dx == 0 and dy == 0:
|
|
301
|
+
continue
|
|
302
|
+
outline = font.render(text, True, outline_color)
|
|
303
|
+
result.blit(outline, (thickness + dx, thickness + dy))
|
|
304
|
+
|
|
305
|
+
result.blit(base_surf, (thickness, thickness))
|
|
306
|
+
|
|
307
|
+
return result
|