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.
Files changed (54) hide show
  1. {crystalwindow-5.9/crystalwindow.egg-info → crystalwindow-6.0.1}/PKG-INFO +2 -2
  2. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/__init__.py +8 -0
  3. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/assets.py +95 -17
  4. crystalwindow-6.0.1/crystalwindow/spritesheets.py +26 -0
  5. {crystalwindow-5.9 → crystalwindow-6.0.1/crystalwindow.egg-info}/PKG-INFO +2 -2
  6. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow.egg-info/SOURCES.txt +1 -0
  7. {crystalwindow-5.9 → crystalwindow-6.0.1}/setup.py +2 -2
  8. {crystalwindow-5.9 → crystalwindow-6.0.1}/LICENSE +0 -0
  9. {crystalwindow-5.9 → crystalwindow-6.0.1}/MANIFEST.in +0 -0
  10. {crystalwindow-5.9 → crystalwindow-6.0.1}/README.md +0 -0
  11. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/FileHelper.py +0 -0
  12. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/Fonts.py +0 -0
  13. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/Icons/default_icon.png +0 -0
  14. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/Icons/file_icons.png +0 -0
  15. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/System.py +0 -0
  16. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/ai.py +0 -0
  17. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/animation.py +0 -0
  18. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/apphelper.py +0 -0
  19. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/camera.py +0 -0
  20. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/chatvpn.py +0 -0
  21. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/clock.py +0 -0
  22. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/collision.py +0 -0
  23. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/color_handler.py +0 -0
  24. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/crystal3d.py +0 -0
  25. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/draw_helpers.py +0 -0
  26. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/draw_rects.py +0 -0
  27. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/draw_text_helper.py +0 -0
  28. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/draw_tool.py +0 -0
  29. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/fun_helpers.py +0 -0
  30. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/3dsquare.py +0 -0
  31. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/__init__.py +0 -0
  32. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/__main__.py +0 -0
  33. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/gravitytest.py +0 -0
  34. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/guitesting.py +0 -0
  35. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/sandbox.py +0 -0
  36. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/squaremove.py +0 -0
  37. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/testtttagain.py +0 -0
  38. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gametests/windowtesting.py +0 -0
  39. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gravity.py +0 -0
  40. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gui.py +0 -0
  41. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/gui_ext.py +0 -0
  42. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/math.py +0 -0
  43. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/messagebus.py +0 -0
  44. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/objects.py +0 -0
  45. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/scores.py +0 -0
  46. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/sprites.py +0 -0
  47. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/tilemap.py +0 -0
  48. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/ver_warner.py +0 -0
  49. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/websearch.py +0 -0
  50. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow/window.py +0 -0
  51. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow.egg-info/dependency_links.txt +0 -0
  52. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow.egg-info/requires.txt +0 -0
  53. {crystalwindow-5.9 → crystalwindow-6.0.1}/crystalwindow.egg-info/top_level.txt +0 -0
  54. {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: 5.9
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/yourusername/crystalwindow
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
- def __init__(self, frames, speed=0.2):
163
- self.frames = frames
164
- self.i = 0
165
- self.speed = speed
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 automatically looping."""
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
- self.i += self.speed
173
- if self.i >= len(self.frames):
174
- self.i = 0
175
-
176
- return self.frames[int(self.i)]
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
- Usage:
182
- anim = loop_image(img1, img2, img3)
183
- anim = loop_image(load_image("p1.png"), load_image("p2.png"))
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 = [x for x in imgs if x is not None]
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("⚠️ loop_image() got no frames.")
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: 5.9
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/yourusername/crystalwindow
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
@@ -29,6 +29,7 @@ crystalwindow/messagebus.py
29
29
  crystalwindow/objects.py
30
30
  crystalwindow/scores.py
31
31
  crystalwindow/sprites.py
32
+ crystalwindow/spritesheets.py
32
33
  crystalwindow/tilemap.py
33
34
  crystalwindow/ver_warner.py
34
35
  crystalwindow/websearch.py
@@ -7,7 +7,7 @@ with open("README.md", encoding="utf-8") as f:
7
7
 
8
8
  setup(
9
9
  name="crystalwindow",
10
- version="5.9", # Force metadata refresh
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/yourusername/crystalwindow",
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