crystalwindow 5.9__tar.gz → 6.0.1__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.
- {crystalwindow-5.9/crystalwindow.egg-info → crystalwindow-6.0.1}/PKG-INFO +2 -2
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/__init__.py +8 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/assets.py +95 -17
- crystalwindow-6.0.1/crystalwindow/spritesheets.py +26 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1/crystalwindow.egg-info}/PKG-INFO +2 -2
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow.egg-info/SOURCES.txt +1 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/setup.py +2 -2
- {crystalwindow-5.9 → crystalwindow-6.0.1}/LICENSE +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/MANIFEST.in +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/README.md +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/FileHelper.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/Fonts.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/Icons/default_icon.png +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/Icons/file_icons.png +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/System.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/ai.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/animation.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/apphelper.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/camera.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/chatvpn.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/clock.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/collision.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/color_handler.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/crystal3d.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/draw_helpers.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/draw_rects.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/draw_text_helper.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/draw_tool.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/fun_helpers.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/3dsquare.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/__init__.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/__main__.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/gravitytest.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/guitesting.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/sandbox.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/squaremove.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/testtttagain.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/windowtesting.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gravity.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gui.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gui_ext.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/math.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/messagebus.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/objects.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/scores.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/sprites.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/tilemap.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/ver_warner.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/websearch.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/window.py +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow.egg-info/dependency_links.txt +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow.egg-info/requires.txt +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow.egg-info/top_level.txt +0 -0
- {crystalwindow-5.9 → crystalwindow-6.0.1}/setup.cfg +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crystalwindow
|
|
3
|
-
Version:
|
|
3
|
+
Version: 6.0.1
|
|
4
4
|
Summary: A Tkinter powered window + GUI toolkit made by Crystal (ME)! Easier apps, smoother UI and all-in-one helpers!, Gui, Buttons, FileHelper, Sprites, Animations, Colors, Math, Gravity, Camera, 3D and more!
|
|
5
5
|
Home-page: https://pypi.org/project/crystalwindow/
|
|
6
6
|
Author: CrystalBallyHereXD
|
|
7
7
|
Author-email: mavilla.519@gmail.com
|
|
8
|
-
Project-URL: Homepage, https://github.com/
|
|
8
|
+
Project-URL: Homepage, https://github.com/CrystalBallyHereXD/crystalwindow
|
|
9
9
|
Project-URL: YouTube, https://www.Youtube.com/@CrystalBallyHereXD
|
|
10
10
|
Project-URL: PiWheels, https://www.piwheels.org/project/crystalwindow/
|
|
11
11
|
Keywords: tkinter gui window toolkit easy crystalwindow crystal cw player moveable easygui python py file math gravity hex color
|
|
@@ -22,6 +22,7 @@ from .assets import (
|
|
|
22
22
|
flip_vertical,
|
|
23
23
|
LoopAnim,
|
|
24
24
|
loop_images,
|
|
25
|
+
loop_imgs,
|
|
25
26
|
load_file,
|
|
26
27
|
Sound,
|
|
27
28
|
)
|
|
@@ -70,6 +71,9 @@ from .System import System, Watchdog
|
|
|
70
71
|
# === Score System ===
|
|
71
72
|
from .scores import Score
|
|
72
73
|
|
|
74
|
+
# === Spritesheets ===
|
|
75
|
+
from .spritesheets import SpriteSheet
|
|
76
|
+
|
|
73
77
|
__all__ = [
|
|
74
78
|
# --- Core ---
|
|
75
79
|
"Window", "Sprite", "TileMap", "Player", "Block", "Enemy", "Gravity", "FileHelper", "Mathematics",
|
|
@@ -85,6 +89,7 @@ __all__ = [
|
|
|
85
89
|
"Animation",
|
|
86
90
|
"LoopAnim",
|
|
87
91
|
"loop_images",
|
|
92
|
+
"loop_imgs",
|
|
88
93
|
"load_file",
|
|
89
94
|
"Sound",
|
|
90
95
|
|
|
@@ -127,4 +132,7 @@ __all__ = [
|
|
|
127
132
|
|
|
128
133
|
# --- Scores ---
|
|
129
134
|
"Score",
|
|
135
|
+
|
|
136
|
+
# --- Spritesheets ---
|
|
137
|
+
"SpriteSheet",
|
|
130
138
|
]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import random, json, pickle
|
|
3
3
|
from tkinter import PhotoImage
|
|
4
|
+
import time
|
|
4
5
|
|
|
5
6
|
try:
|
|
6
7
|
from PIL import Image, ImageTk
|
|
@@ -159,34 +160,86 @@ def flip_vertical(img):
|
|
|
159
160
|
# LOOPING ANIMATIONS / IMAGES
|
|
160
161
|
# --------------------------------------------------------
|
|
161
162
|
class LoopAnim:
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
"""
|
|
164
|
+
Flexible looping animation.
|
|
165
|
+
|
|
166
|
+
Usage patterns:
|
|
167
|
+
- time-based using FPS:
|
|
168
|
+
anim = LoopAnim(frames, fps=12)
|
|
169
|
+
frame = anim.next() # auto uses time delta internally
|
|
170
|
+
- manual dt-based (e.g., game loop provides dt):
|
|
171
|
+
anim = LoopAnim(frames, fps=24)
|
|
172
|
+
frame = anim.next(dt) # dt in seconds
|
|
173
|
+
- legacy speed-based (per-call increment):
|
|
174
|
+
anim = LoopAnim(frames, speed=0.2)
|
|
175
|
+
frame = anim.next() # increments by 'speed' each call
|
|
176
|
+
|
|
177
|
+
Notes:
|
|
178
|
+
- `frames` may be any iterable (list/tuple/set); it will be converted to a list.
|
|
179
|
+
- If frames is empty, returns None from `next()`.
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
def __init__(self, frames, fps=None, speed=None):
|
|
183
|
+
self.frames = [f for f in frames if f is not None]
|
|
184
|
+
self.length = len(self.frames)
|
|
185
|
+
self._index = 0
|
|
186
|
+
|
|
187
|
+
# time-based mode
|
|
188
|
+
self.fps = float(fps) if fps else None
|
|
189
|
+
self.frame_duration = (1.0 / self.fps) if self.fps and self.fps > 0 else None
|
|
190
|
+
self._acc = 0.0
|
|
191
|
+
self._last_time = time.time()
|
|
192
|
+
|
|
193
|
+
# legacy speed (per-call fractional index)
|
|
194
|
+
self.speed = float(speed) if speed else None
|
|
195
|
+
self._float_index = 0.0
|
|
166
196
|
|
|
167
|
-
def next(self):
|
|
168
|
-
"""Return next frame
|
|
197
|
+
def next(self, dt=None):
|
|
198
|
+
"""Return next frame. If dt (seconds) provided, uses it; otherwise uses internal clock."""
|
|
169
199
|
if not self.frames:
|
|
170
200
|
return None
|
|
171
201
|
|
|
172
|
-
|
|
173
|
-
if self.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
202
|
+
# Time-based FPS mode (preferred)
|
|
203
|
+
if self.frame_duration:
|
|
204
|
+
if dt is None:
|
|
205
|
+
now = time.time()
|
|
206
|
+
dt = now - self._last_time
|
|
207
|
+
self._last_time = now
|
|
208
|
+
self._acc += dt
|
|
209
|
+
advance = int(self._acc / self.frame_duration)
|
|
210
|
+
if advance > 0:
|
|
211
|
+
self._acc -= advance * self.frame_duration
|
|
212
|
+
self._index = (self._index + advance) % self.length
|
|
213
|
+
return self.frames[self._index]
|
|
214
|
+
|
|
215
|
+
# Legacy speed-per-call mode
|
|
216
|
+
if self.speed:
|
|
217
|
+
self._float_index += self.speed
|
|
218
|
+
if self._float_index >= self.length:
|
|
219
|
+
self._float_index = self._float_index % self.length
|
|
220
|
+
return self.frames[int(self._float_index)]
|
|
221
|
+
|
|
222
|
+
# Default: simple step each call
|
|
223
|
+
self._index = (self._index + 1) % self.length
|
|
224
|
+
return self.frames[self._index]
|
|
177
225
|
|
|
178
226
|
|
|
179
227
|
def loop_images(*imgs, speed=0.2):
|
|
180
228
|
"""
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
229
|
+
Backwards-compatible wrapper.
|
|
230
|
+
Accepts varargs like loop_images(img1, img2, ...) or a single iterable:
|
|
231
|
+
loop_images([img1, img2], speed=0.2)
|
|
232
|
+
|
|
233
|
+
This returns a LoopAnim that uses legacy per-call `speed`.
|
|
184
234
|
"""
|
|
185
|
-
frames = [
|
|
235
|
+
frames = []
|
|
236
|
+
if len(imgs) == 1 and hasattr(imgs[0], "__iter__") and not isinstance(imgs[0], (str, bytes)):
|
|
237
|
+
frames = [x for x in imgs[0] if x is not None]
|
|
238
|
+
else:
|
|
239
|
+
frames = [x for x in imgs if x is not None]
|
|
186
240
|
|
|
187
|
-
# If nothing was passed → fallback
|
|
188
241
|
if not frames:
|
|
189
|
-
print("⚠️
|
|
242
|
+
print("⚠️ loop_images() got no frames.")
|
|
190
243
|
fb = load_image("fallback.png") if os.path.exists("fallback.png") else None
|
|
191
244
|
if fb is None:
|
|
192
245
|
return LoopAnim([None], speed=speed)
|
|
@@ -195,6 +248,31 @@ def loop_images(*imgs, speed=0.2):
|
|
|
195
248
|
return LoopAnim(frames, speed=speed)
|
|
196
249
|
|
|
197
250
|
|
|
251
|
+
def loop_imgs(*imgs, framerate=None, speed=None):
|
|
252
|
+
"""
|
|
253
|
+
New helper supporting a single iterable or varargs and an explicit framerate (FPS).
|
|
254
|
+
Usage:
|
|
255
|
+
idle = [idle1, idle2, idle3]
|
|
256
|
+
idles = loop_imgs(idle, framerate=24) # time-based, 24 FPS
|
|
257
|
+
idles = loop_imgs(idle1, idle2, framerate=12)
|
|
258
|
+
idles = loop_imgs(idle, speed=0.2) # fallback to legacy speed-per-call
|
|
259
|
+
"""
|
|
260
|
+
frames = []
|
|
261
|
+
if len(imgs) == 1 and hasattr(imgs[0], "__iter__") and not isinstance(imgs[0], (str, bytes)):
|
|
262
|
+
frames = [x for x in imgs[0] if x is not None]
|
|
263
|
+
else:
|
|
264
|
+
frames = [x for x in imgs if x is not None]
|
|
265
|
+
|
|
266
|
+
if not frames:
|
|
267
|
+
print("⚠️ loop_imgs() got no frames.")
|
|
268
|
+
fb = load_image("fallback.png") if os.path.exists("fallback.png") else None
|
|
269
|
+
if fb is None:
|
|
270
|
+
return LoopAnim([None], fps=framerate, speed=speed)
|
|
271
|
+
return LoopAnim([fb], fps=framerate, speed=speed)
|
|
272
|
+
|
|
273
|
+
return LoopAnim(frames, fps=framerate, speed=speed)
|
|
274
|
+
|
|
275
|
+
|
|
198
276
|
# --------------------------------------------------------
|
|
199
277
|
# FOLDER LOADING
|
|
200
278
|
# --------------------------------------------------------
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from PIL import Image, ImageTk
|
|
2
|
+
import xml.etree.ElementTree as ET
|
|
3
|
+
|
|
4
|
+
class SpriteSheet:
|
|
5
|
+
def __init__(self, image_path, xml_path):
|
|
6
|
+
self.pil_image = Image.open(image_path).convert("RGBA")
|
|
7
|
+
self.frames = {}
|
|
8
|
+
|
|
9
|
+
tree = ET.parse(xml_path)
|
|
10
|
+
root = tree.getroot()
|
|
11
|
+
|
|
12
|
+
for sub in root.iter("SubTexture"):
|
|
13
|
+
name = sub.attrib["name"]
|
|
14
|
+
x = int(sub.attrib["x"])
|
|
15
|
+
y = int(sub.attrib["y"])
|
|
16
|
+
w = int(sub.attrib["width"])
|
|
17
|
+
h = int(sub.attrib["height"])
|
|
18
|
+
|
|
19
|
+
self.frames[name] = (x, y, w, h)
|
|
20
|
+
|
|
21
|
+
def get_pil(self, name):
|
|
22
|
+
x, y, w, h = self.frames[name]
|
|
23
|
+
return self.pil_image.crop((x, y, x + w, y + h))
|
|
24
|
+
|
|
25
|
+
def get_tk(self, name):
|
|
26
|
+
return ImageTk.PhotoImage(self.get_pil(name))
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crystalwindow
|
|
3
|
-
Version:
|
|
3
|
+
Version: 6.0.1
|
|
4
4
|
Summary: A Tkinter powered window + GUI toolkit made by Crystal (ME)! Easier apps, smoother UI and all-in-one helpers!, Gui, Buttons, FileHelper, Sprites, Animations, Colors, Math, Gravity, Camera, 3D and more!
|
|
5
5
|
Home-page: https://pypi.org/project/crystalwindow/
|
|
6
6
|
Author: CrystalBallyHereXD
|
|
7
7
|
Author-email: mavilla.519@gmail.com
|
|
8
|
-
Project-URL: Homepage, https://github.com/
|
|
8
|
+
Project-URL: Homepage, https://github.com/CrystalBallyHereXD/crystalwindow
|
|
9
9
|
Project-URL: YouTube, https://www.Youtube.com/@CrystalBallyHereXD
|
|
10
10
|
Project-URL: PiWheels, https://www.piwheels.org/project/crystalwindow/
|
|
11
11
|
Keywords: tkinter gui window toolkit easy crystalwindow crystal cw player moveable easygui python py file math gravity hex color
|
|
@@ -7,7 +7,7 @@ with open("README.md", encoding="utf-8") as f:
|
|
|
7
7
|
|
|
8
8
|
setup(
|
|
9
9
|
name="crystalwindow",
|
|
10
|
-
version="
|
|
10
|
+
version="6.0.1", # Force metadata refresh
|
|
11
11
|
packages=find_packages(include=["crystalwindow", "crystalwindow.*"]),
|
|
12
12
|
|
|
13
13
|
include_package_data=True, # include package_data files
|
|
@@ -29,7 +29,7 @@ setup(
|
|
|
29
29
|
url="https://pypi.org/project/crystalwindow/",
|
|
30
30
|
|
|
31
31
|
project_urls={
|
|
32
|
-
"Homepage": "https://github.com/
|
|
32
|
+
"Homepage": "https://github.com/CrystalBallyHereXD/crystalwindow",
|
|
33
33
|
"YouTube": "https://www.Youtube.com/@CrystalBallyHereXD",
|
|
34
34
|
"PiWheels": "https://www.piwheels.org/project/crystalwindow/",
|
|
35
35
|
},
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|