crystalwindow 3.8.1__py3-none-any.whl → 3.8.4__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.
crystalwindow/__init__.py CHANGED
@@ -20,6 +20,8 @@ from .assets import (
20
20
  flip_image,
21
21
  flip_horizontal,
22
22
  flip_vertical,
23
+ LoopAnim,
24
+ loop_image,
23
25
  )
24
26
  from .animation import Animation
25
27
 
@@ -60,6 +62,8 @@ __all__ = [
60
62
  "flip_horizontal",
61
63
  "flip_vertical",
62
64
  "Animation",
65
+ "LoopAnim",
66
+ "loop_image",
63
67
 
64
68
  # --- Collision ---
65
69
  "check_collision", "resolve_collision",
crystalwindow/assets.py CHANGED
@@ -118,6 +118,47 @@ def flip_horizontal(img):
118
118
  def flip_vertical(img):
119
119
  return flip_image(img, flip_v=True)
120
120
 
121
+ # --------------------------------------------------------
122
+ # LOOPING ANIMAITONS/IMAGES
123
+ # --------------------------------------------------------
124
+ class LoopAnim:
125
+ def __init__(self, frames, speed=0.2):
126
+ self.frames = frames
127
+ self.i = 0
128
+ self.speed = speed
129
+
130
+ def next(self):
131
+ """Return next frame automatically looping."""
132
+ if not self.frames:
133
+ return None
134
+
135
+ self.i += self.speed
136
+ if self.i >= len(self.frames):
137
+ self.i = 0
138
+
139
+ return self.frames[int(self.i)]
140
+
141
+
142
+ def loop_image(*imgs, speed=0.2):
143
+ """
144
+ Usage:
145
+ anim = loop_image(img1, img2, img3)
146
+ anim = loop_image(load_image("p1.png"), load_image("p2.png"))
147
+
148
+ Returns a LoopAnim object.
149
+ """
150
+ frames = [x for x in imgs if x is not None]
151
+
152
+ # If nothing was passed → fallback
153
+ if not frames:
154
+ print("⚠️ loop_image() got no frames.")
155
+ fb = load_image("fallback.png") if os.path.exists("fallback.png") else None
156
+ if fb is None:
157
+ return LoopAnim([None], speed=speed)
158
+ return LoopAnim([fb], speed=speed)
159
+
160
+ return LoopAnim(frames, speed=speed)
161
+
121
162
 
122
163
  # --------------------------------------------------------
123
164
  # FOLDER LOADING
crystalwindow/sprites.py CHANGED
@@ -1,44 +1,55 @@
1
1
  # sprites.py
2
+ import random
2
3
  from tkinter import PhotoImage
3
- from PIL import Image, ImageTk
4
4
 
5
+ try:
6
+ from PIL import Image, ImageTk
7
+ except ImportError:
8
+ Image = None
9
+ ImageTk = None
5
10
 
6
11
  class Sprite:
7
12
  def __init__(self, pos, size=None, image=None, color=(255, 0, 0)):
8
- self.x, self.y = pos
13
+ """
14
+ pos: (x, y)
15
+ size: (w, h) optional
16
+ image: PhotoImage or PIL ImageTk.PhotoImage
17
+ color: fallback rectangle color
18
+ """
9
19
  self.pos = pos
10
-
11
- self.image = None
20
+ self.x, self.y = pos
21
+ self.image = image
12
22
  self.color = color
13
23
 
14
- # If fallback dict provided from assets
15
- if isinstance(image, dict) and image.get("fallback"):
16
- self.width, self.height = image["size"]
17
- self.color = image["color"]
18
-
19
- # Normal image
20
- elif isinstance(image, PhotoImage):
21
- self.set_image(image)
22
-
23
- # Rectangle sprite
24
+ # Determine width/height
25
+ if image is not None:
26
+ try:
27
+ # Tkinter PhotoImage
28
+ self.width = image.width()
29
+ self.height = image.height()
30
+ except Exception:
31
+ try:
32
+ # PIL ImageTk.PhotoImage
33
+ self.width = image.width
34
+ self.height = image.height
35
+ except Exception:
36
+ raise ValueError("Sprite image has no size info")
24
37
  elif size is not None:
25
38
  self.width, self.height = size
26
-
27
39
  else:
28
40
  raise ValueError("Sprite needs 'size' or 'image'")
29
41
 
30
- # Movement physics
42
+ # Optional velocity
31
43
  self.vel_x = 0
32
44
  self.vel_y = 0
33
45
 
34
- # Optional direction flag
35
- self.facing_left = False
36
-
37
- # --------------------------------------
38
- # Constructors
39
- # --------------------------------------
46
+ # === CLASS METHODS ===
40
47
  @classmethod
41
48
  def image(cls, img, pos):
49
+ """
50
+ Create a sprite from an image.
51
+ Accepts fallback dict or actual PhotoImage.
52
+ """
42
53
  if isinstance(img, dict) and img.get("fallback"):
43
54
  w, h = img["size"]
44
55
  color = img["color"]
@@ -47,12 +58,12 @@ class Sprite:
47
58
 
48
59
  @classmethod
49
60
  def rect(cls, pos, w, h, color=(255, 0, 0)):
61
+ """Create sprite using a plain colored rectangle"""
50
62
  return cls(pos, size=(w, h), color=color)
51
63
 
52
- # --------------------------------------
53
- # Draw
54
- # --------------------------------------
64
+ # === METHODS ===
55
65
  def draw(self, win, cam=None):
66
+ """Draw sprite on CrystalWindow / Tk canvas"""
56
67
  if cam:
57
68
  draw_x, draw_y = cam.apply(self)
58
69
  else:
@@ -63,9 +74,6 @@ class Sprite:
63
74
  else:
64
75
  win.draw_rect(self.color, (draw_x, draw_y, self.width, self.height))
65
76
 
66
- # --------------------------------------
67
- # Movement
68
- # --------------------------------------
69
77
  def move(self, dx, dy):
70
78
  self.x += dx
71
79
  self.y += dy
@@ -76,40 +84,25 @@ class Sprite:
76
84
  self.y += self.vel_y * dt
77
85
  self.pos = (self.x, self.y)
78
86
 
79
- # --------------------------------------
80
- # Image setter
81
- # --------------------------------------
82
- def set_image(self, new_image):
83
- """Set sprite image and update size."""
84
- self.image = new_image
85
- self.width = new_image.width()
86
- self.height = new_image.height()
87
-
88
- # --------------------------------------
89
- # In-place flipping (optional)
90
- # --------------------------------------
91
- def flip_horizontal(self):
92
- if not self.image:
93
- return
94
- pil = ImageTk.getimage(self.image)
95
- flipped = pil.transpose(Image.FLIP_LEFT_RIGHT)
96
- self.set_image(ImageTk.PhotoImage(flipped))
97
- self.facing_left = not self.facing_left
98
-
99
- def flip_vertical(self):
100
- if not self.image:
101
- return
102
- pil = ImageTk.getimage(self.image)
103
- flipped = pil.transpose(Image.FLIP_TOP_BOTTOM)
104
- self.set_image(ImageTk.PhotoImage(flipped))
105
-
106
- # --------------------------------------
107
- # Collision
108
- # --------------------------------------
109
87
  def colliderect(self, other):
110
88
  return (
111
- self.x < other.x + other.width and
112
- self.x + self.width > other.x and
113
- self.y < other.y + other.height and
114
- self.y + self.height > other.y
115
- )
89
+ self.x < other.x + getattr(other, "width", 0) and
90
+ self.x + getattr(self, "width", 0) > other.x and
91
+ self.y < other.y + getattr(other, "height", 0) and
92
+ self.y + getattr(self, "height", 0) > other.y
93
+ ) # returns tuple for consistency
94
+
95
+ def set_image(self, img):
96
+ """Update sprite's image at runtime (like flipping)"""
97
+ self.image = img
98
+ # update width/height
99
+ if img is not None:
100
+ try:
101
+ self.width = img.width()
102
+ self.height = img.height()
103
+ except Exception:
104
+ try:
105
+ self.width = img.width
106
+ self.height = img.height
107
+ except:
108
+ pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crystalwindow
3
- Version: 3.8.1
3
+ Version: 3.8.4
4
4
  Summary: A Tkinter powered window + GUI toolkit made by Crystal (MEEEEEE)! Easier apps, smoother UI and all-in-one helpers!
5
5
  Home-page: https://pypi.org/project/crystalwindow/
6
6
  Author: CrystalBallyHereXD
@@ -1,7 +1,7 @@
1
1
  crystalwindow/FileHelper.py,sha256=aUnnRG7UwvzJt-idjWjmpwy3RM6nqLlC3-7Bae6Yb94,5471
2
- crystalwindow/__init__.py,sha256=1O0qUvD6dGRZEwCXZU5byqWQUdRNYhyUZ54SN_NM2Dk,2015
2
+ crystalwindow/__init__.py,sha256=c8-c4hLW3AhIN9J8uNVGSTz6Navsfs7FGexV55lkP6g,2083
3
3
  crystalwindow/animation.py,sha256=zHjrdBXQeyNaLAuaGPldJueX05OZ5j31YR8NizmR0uQ,427
4
- crystalwindow/assets.py,sha256=3FubtFHcemIFBiV5h79QyvKkHiLSUNBEPbGP4UyGRyI,3999
4
+ crystalwindow/assets.py,sha256=2Cj0zdhMWo3mWjdr9KU5n-9_8iKj_fJ9uShMFA-27HU,5193
5
5
  crystalwindow/camera.py,sha256=tbn4X-jxMIszAUg3Iu-89gJN5nij0mjPMEzGotcLbJI,712
6
6
  crystalwindow/clock.py,sha256=iryeURnfXx6TIDyJhpxe0KkeSaHCdxrMckN6Tby00i0,461
7
7
  crystalwindow/collision.py,sha256=hpkHTp_KparghVK-itp_rxuYdd2GbQMxICHlUBv0rSw,472
@@ -16,7 +16,7 @@ crystalwindow/gui.py,sha256=D-El18XUaZQR-XZoOr28hnhO7EEoGuypCHxPbPR_yng,3680
16
16
  crystalwindow/gui_ext.py,sha256=ZhNgc5eK6Vzj-jUNeFzimuEbLnTmM7Bx594Z34_N0oM,2856
17
17
  crystalwindow/math.py,sha256=slOY3KQZ99VDMUMxsSJabMyRtJcwVzEyxR2RoXspHho,963
18
18
  crystalwindow/player.py,sha256=4wpIdUZLTlRXV8fDRQ11yVJRbx_cv8Ekpn2y7pQGgAQ,3442
19
- crystalwindow/sprites.py,sha256=b_ErcbqoWduk4otxcETJhNsSNfpSUMmcjV4qL5gMf5g,3590
19
+ crystalwindow/sprites.py,sha256=2kYW4QfSnyUwRLedZCkb99wUSxn2a0JdWOHcfkxcG0U,3411
20
20
  crystalwindow/tilemap.py,sha256=PHoKL1eWuNeHIf0w-Jh5MGdQGEgklVsxqqJOS-GNMKI,322
21
21
  crystalwindow/ver_warner.py,sha256=qEN3ulc1NixBy15FFx2R3Zu0DhyJTVJwiESGAPwpynM,3373
22
22
  crystalwindow/window.py,sha256=e6C8yIdVdjOduIeU0ZmlrNn8GmyvHuzKs473pRggkz0,18180
@@ -31,8 +31,8 @@ crystalwindow/gametests/guitesting.py,sha256=SrOssY5peCQEV6TQ1AiOWtjb9phVGdRzW-Q
31
31
  crystalwindow/gametests/sandbox.py,sha256=Oo2tU2N0y3BPVa6T5vs_h9N6islhQrjSrr_78XLut5I,1007
32
32
  crystalwindow/gametests/squaremove.py,sha256=poP2Zjl2oc2HVvIAgIK34H2jVj6otL4jEdvAOR6L9sI,572
33
33
  crystalwindow/gametests/windowtesting.py,sha256=_9X6wnV1-_X_PtNS-0zu-k209NtFIwAc4vpxLPp7V2o,97
34
- crystalwindow-3.8.1.dist-info/licenses/LICENSE,sha256=7pvUgvRXL3ED5VVAZPH5oGn1CaIXcyoDC9gqox6sB0g,1079
35
- crystalwindow-3.8.1.dist-info/METADATA,sha256=L7kncNlmZMHmJl0AeneiHfGYxt7UkJiYtBKeRXbVkhA,7340
36
- crystalwindow-3.8.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
- crystalwindow-3.8.1.dist-info/top_level.txt,sha256=PeQSld4b19XWT-zvbYkvE2Xg8sakIMbDzSzSdOSRN8o,14
38
- crystalwindow-3.8.1.dist-info/RECORD,,
34
+ crystalwindow-3.8.4.dist-info/licenses/LICENSE,sha256=Gt5cJRchdNt0guxyQMHKsATN5PM5mjuDhdO6Gzs9qQc,1096
35
+ crystalwindow-3.8.4.dist-info/METADATA,sha256=sNkJRxTwkTfPeCtzmhkyLMV0FA8NDjLKxgZ5GTVmxv4,7340
36
+ crystalwindow-3.8.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
+ crystalwindow-3.8.4.dist-info/top_level.txt,sha256=PeQSld4b19XWT-zvbYkvE2Xg8sakIMbDzSzSdOSRN8o,14
38
+ crystalwindow-3.8.4.dist-info/RECORD,,
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 C
3
+ Copyright (c) 2025 CrystalBallyHereXD
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal