crystalwindow 3.7.1b0__tar.gz → 3.8.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 (45) hide show
  1. {crystalwindow-3.7.1b0/crystalwindow.egg-info → crystalwindow-3.8.1}/PKG-INFO +1 -1
  2. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/__init__.py +21 -5
  3. crystalwindow-3.8.1/crystalwindow/assets.py +150 -0
  4. crystalwindow-3.8.1/crystalwindow/sprites.py +115 -0
  5. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/window.py +1 -1
  6. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1/crystalwindow.egg-info}/PKG-INFO +1 -1
  7. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/setup.py +1 -1
  8. crystalwindow-3.7.1b0/crystalwindow/assets.py +0 -72
  9. crystalwindow-3.7.1b0/crystalwindow/sprites.py +0 -78
  10. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/LICENSE +0 -0
  11. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/MANIFEST.in +0 -0
  12. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/README.md +0 -0
  13. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/FileHelper.py +0 -0
  14. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/Icons/default_icon.png +0 -0
  15. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/animation.py +0 -0
  16. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/camera.py +0 -0
  17. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/clock.py +0 -0
  18. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/collision.py +0 -0
  19. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/crystal3d.py +0 -0
  20. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/docs/getting_started.md +0 -0
  21. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/docs/index.md +0 -0
  22. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/draw_helpers.py +0 -0
  23. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/draw_rects.py +0 -0
  24. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/draw_text_helper.py +0 -0
  25. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/draw_tool.py +0 -0
  26. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/fun_helpers.py +0 -0
  27. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/gametests/3dsquare.py +0 -0
  28. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/gametests/__init__.py +0 -0
  29. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/gametests/__main__.py +0 -0
  30. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/gametests/gravitytest.py +0 -0
  31. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/gametests/guitesting.py +0 -0
  32. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/gametests/sandbox.py +0 -0
  33. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/gametests/squaremove.py +0 -0
  34. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/gametests/windowtesting.py +0 -0
  35. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/gravity.py +0 -0
  36. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/gui.py +0 -0
  37. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/gui_ext.py +0 -0
  38. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/math.py +0 -0
  39. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/player.py +0 -0
  40. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/tilemap.py +0 -0
  41. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow/ver_warner.py +0 -0
  42. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow.egg-info/SOURCES.txt +0 -0
  43. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow.egg-info/dependency_links.txt +0 -0
  44. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/crystalwindow.egg-info/top_level.txt +0 -0
  45. {crystalwindow-3.7.1b0 → crystalwindow-3.8.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crystalwindow
3
- Version: 3.7.1b0
3
+ Version: 3.8.1
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
@@ -12,7 +12,15 @@ from .FileHelper import FileHelper
12
12
  from .math import Mathematics
13
13
 
14
14
  # === Assets & Animation ===
15
- from .assets import load_image, load_folder_images, load_music, play_music
15
+ from .assets import (
16
+ load_image,
17
+ load_folder_images,
18
+ load_music,
19
+ play_music,
20
+ flip_image,
21
+ flip_horizontal,
22
+ flip_vertical,
23
+ )
16
24
  from .animation import Animation
17
25
 
18
26
  # === Collision ===
@@ -23,7 +31,7 @@ from .gui import Button, Label, GUIManager, random_color, hex_to_rgb, Fade
23
31
  from .gui_ext import Toggle, Slider
24
32
 
25
33
  # === Time ===
26
- from .clock import Clock # ⏰ for frame timing / tick control
34
+ from .clock import Clock
27
35
 
28
36
  # === Drawing Helpers ===
29
37
  from .draw_helpers import gradient_rect, CameraShake
@@ -36,14 +44,22 @@ from .fun_helpers import random_name, DebugOverlay
36
44
  from .camera import Camera
37
45
 
38
46
  # === 3D Engine ===
39
- from .crystal3d import CW3D # 🧊 brand new 3D handler!
47
+ from .crystal3d import CW3D
48
+
40
49
 
41
50
  __all__ = [
42
51
  # --- Core ---
43
52
  "Window", "Sprite", "TileMap", "Player", "Gravity", "FileHelper", "Mathematics",
44
53
 
45
54
  # --- Assets & Animation ---
46
- "load_image", "load_folder_images", "load_music", "play_music", "Animation",
55
+ "load_image",
56
+ "load_folder_images",
57
+ "load_music",
58
+ "play_music",
59
+ "flip_image",
60
+ "flip_horizontal",
61
+ "flip_vertical",
62
+ "Animation",
47
63
 
48
64
  # --- Collision ---
49
65
  "check_collision", "resolve_collision",
@@ -64,5 +80,5 @@ __all__ = [
64
80
  "random_name", "DebugOverlay", "Camera",
65
81
 
66
82
  # --- 3D ---
67
- "CW3D"
83
+ "CW3D",
68
84
  ]
@@ -0,0 +1,150 @@
1
+ # assets.py
2
+ import os
3
+ import random
4
+ from tkinter import PhotoImage
5
+
6
+ try:
7
+ from PIL import Image, ImageTk
8
+ except ImportError:
9
+ Image = None
10
+ ImageTk = None
11
+
12
+ ASSETS = {} # cache for all loaded images
13
+
14
+
15
+ # --------------------------------------------------------
16
+ # MAIN IMAGE LOADER
17
+ # --------------------------------------------------------
18
+ def load_image(path, flip_h=False, flip_v=False):
19
+ """
20
+ Loads an image and returns a Tk PhotoImage.
21
+ Supports flipping using Pillow.
22
+ """
23
+
24
+ key = f"{path}|h={flip_h}|v={flip_v}"
25
+ if key in ASSETS:
26
+ return ASSETS[key]
27
+
28
+ if not os.path.exists(path):
29
+ print(f"⚠️ Missing file: {path}")
30
+ img = generate_fallback(path)
31
+ ASSETS[key] = img
32
+ return img
33
+
34
+ # If Pillow is missing → load normal image
35
+ if Image is None or ImageTk is None:
36
+ try:
37
+ img = PhotoImage(file=path)
38
+ ASSETS[key] = img
39
+ return img
40
+ except:
41
+ fb = generate_fallback(path)
42
+ ASSETS[key] = fb
43
+ return fb
44
+
45
+ # Load with PIL to allow flipping
46
+ try:
47
+ pil_img = Image.open(path)
48
+
49
+ if flip_h:
50
+ pil_img = pil_img.transpose(Image.FLIP_LEFT_RIGHT)
51
+ if flip_v:
52
+ pil_img = pil_img.transpose(Image.FLIP_TOP_BOTTOM)
53
+
54
+ tk_img = ImageTk.PhotoImage(pil_img)
55
+ ASSETS[key] = tk_img
56
+ return tk_img
57
+
58
+ except Exception as e:
59
+ print(f"⚠️ Error loading {path}: {e}")
60
+ fb = generate_fallback(path)
61
+ ASSETS[key] = fb
62
+ return fb
63
+
64
+
65
+ # --------------------------------------------------------
66
+ # FALLBACK NODE
67
+ # --------------------------------------------------------
68
+ def generate_fallback(path):
69
+ """Fallback colored block used when an image is missing."""
70
+ rand_color = (
71
+ random.randint(50, 255),
72
+ random.randint(50, 255),
73
+ random.randint(50, 255),
74
+ )
75
+
76
+ if Image:
77
+ try:
78
+ pil_img = Image.open(path)
79
+ w, h = pil_img.size
80
+ except:
81
+ w, h = 64, 64
82
+ else:
83
+ w, h = 64, 64
84
+
85
+ return {
86
+ "fallback": True,
87
+ "size": (w, h),
88
+ "color": rand_color
89
+ }
90
+
91
+
92
+ # --------------------------------------------------------
93
+ # PYGAME-STYLE FLIP HELPERS
94
+ # --------------------------------------------------------
95
+ def flip_image(img, flip_h=False, flip_v=False):
96
+ """
97
+ Returns a NEW flipped PhotoImage.
98
+ Like pygame.transform.flip().
99
+ """
100
+ if Image is None or ImageTk is None:
101
+ print("⚠️ Pillow not installed; cannot flip images.")
102
+ return img
103
+
104
+ pil_img = ImageTk.getimage(img)
105
+
106
+ if flip_h:
107
+ pil_img = pil_img.transpose(Image.FLIP_LEFT_RIGHT)
108
+ if flip_v:
109
+ pil_img = pil_img.transpose(Image.FLIP_TOP_BOTTOM)
110
+
111
+ return ImageTk.PhotoImage(pil_img)
112
+
113
+
114
+ def flip_horizontal(img):
115
+ return flip_image(img, flip_h=True)
116
+
117
+
118
+ def flip_vertical(img):
119
+ return flip_image(img, flip_v=True)
120
+
121
+
122
+ # --------------------------------------------------------
123
+ # FOLDER LOADING
124
+ # --------------------------------------------------------
125
+ def load_folder_images(folder, nested=True):
126
+ if not os.path.exists(folder):
127
+ print(f"⚠️ Folder not found: {folder}")
128
+ return {}
129
+
130
+ result = {}
131
+ for item in os.listdir(folder):
132
+ full = os.path.join(folder, item)
133
+
134
+ if os.path.isdir(full) and nested:
135
+ result[item] = load_folder_images(full)
136
+
137
+ elif item.lower().endswith((".png", ".gif")):
138
+ result[item] = load_image(full)
139
+
140
+ return result
141
+
142
+
143
+ # --------------------------------------------------------
144
+ # MUSIC PLACEHOLDER
145
+ # --------------------------------------------------------
146
+ def load_music(path):
147
+ print(f"[assets] Music load not supported: {path}")
148
+
149
+ def play_music(loop=-1):
150
+ print("[assets] Music playback not supported.")
@@ -0,0 +1,115 @@
1
+ # sprites.py
2
+ from tkinter import PhotoImage
3
+ from PIL import Image, ImageTk
4
+
5
+
6
+ class Sprite:
7
+ def __init__(self, pos, size=None, image=None, color=(255, 0, 0)):
8
+ self.x, self.y = pos
9
+ self.pos = pos
10
+
11
+ self.image = None
12
+ self.color = color
13
+
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
+ elif size is not None:
25
+ self.width, self.height = size
26
+
27
+ else:
28
+ raise ValueError("Sprite needs 'size' or 'image'")
29
+
30
+ # Movement physics
31
+ self.vel_x = 0
32
+ self.vel_y = 0
33
+
34
+ # Optional direction flag
35
+ self.facing_left = False
36
+
37
+ # --------------------------------------
38
+ # Constructors
39
+ # --------------------------------------
40
+ @classmethod
41
+ def image(cls, img, pos):
42
+ if isinstance(img, dict) and img.get("fallback"):
43
+ w, h = img["size"]
44
+ color = img["color"]
45
+ return cls(pos, size=(w, h), color=color)
46
+ return cls(pos, image=img)
47
+
48
+ @classmethod
49
+ def rect(cls, pos, w, h, color=(255, 0, 0)):
50
+ return cls(pos, size=(w, h), color=color)
51
+
52
+ # --------------------------------------
53
+ # Draw
54
+ # --------------------------------------
55
+ def draw(self, win, cam=None):
56
+ if cam:
57
+ draw_x, draw_y = cam.apply(self)
58
+ else:
59
+ draw_x, draw_y = self.x, self.y
60
+
61
+ if self.image:
62
+ win.canvas.create_image(draw_x, draw_y, anchor="nw", image=self.image)
63
+ else:
64
+ win.draw_rect(self.color, (draw_x, draw_y, self.width, self.height))
65
+
66
+ # --------------------------------------
67
+ # Movement
68
+ # --------------------------------------
69
+ def move(self, dx, dy):
70
+ self.x += dx
71
+ self.y += dy
72
+ self.pos = (self.x, self.y)
73
+
74
+ def apply_velocity(self, dt=1):
75
+ self.x += self.vel_x * dt
76
+ self.y += self.vel_y * dt
77
+ self.pos = (self.x, self.y)
78
+
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
+ def colliderect(self, other):
110
+ 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
+ )
@@ -115,7 +115,7 @@ class Window:
115
115
  self._bg_color = (20, 20, 50)
116
116
  self.draw_calls = []
117
117
  self._key_last = {} # new dict to store last press time per key
118
- self._key_cooldown = 0.02 # seconds, tweak for faster/slower input
118
+ self._key_cooldown = 0.00001 # seconds, tweak for faster/slower input
119
119
 
120
120
  # === Event bindings ===
121
121
  self.root.bind("<KeyPress>", self._on_keydown)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crystalwindow
3
- Version: 3.7.1b0
3
+ Version: 3.8.1
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
@@ -7,7 +7,7 @@ with open("README.md", encoding="utf-8") as f:
7
7
 
8
8
  setup(
9
9
  name="crystalwindow",
10
- version="3.7.1.b0", # Force metadata refresh
10
+ version="3.8.1", # Force metadata refresh
11
11
  packages=find_packages(include=["crystalwindow", "crystalwindow.*"]),
12
12
 
13
13
  include_package_data=True, # include package_data files
@@ -1,72 +0,0 @@
1
- import os
2
- import random
3
- from tkinter import PhotoImage
4
-
5
- try:
6
- from PIL import Image
7
- except:
8
- Image = None
9
-
10
- ASSETS = {}
11
-
12
- def load_image(path):
13
- # try normal load
14
- if os.path.exists(path):
15
- try:
16
- img = PhotoImage(file=path)
17
- ASSETS[path] = img
18
- return img
19
- except:
20
- print(f"⚠️ Ops!, could not load img: {path}")
21
- else:
22
- print(f"⚠️ Ops!, file not found: {path}")
23
-
24
- # fallback: get natural size using PIL if possible
25
- if Image is not None:
26
- try:
27
- pil_img = Image.open(path)
28
- w, h = pil_img.size
29
- except:
30
- w, h = 64, 64
31
- else:
32
- w, h = 64, 64
33
-
34
- # RANDOM COLOR FALLBACK (chaos energy)
35
- rand_color = (
36
- random.randint(0, 255),
37
- random.randint(0, 255),
38
- random.randint(0, 255)
39
- )
40
-
41
- return {
42
- "fallback": True,
43
- "size": (w, h),
44
- "color": rand_color
45
- }
46
-
47
-
48
- def load_folder_images(folder, nested=True):
49
- if not os.path.exists(folder):
50
- print(f"⚠️ Ops!, folder not found: {folder}")
51
- return {}
52
-
53
- result = {}
54
- for item in os.listdir(folder):
55
- full_path = os.path.join(folder, item)
56
-
57
- if os.path.isdir(full_path) and nested:
58
- result[item] = load_folder_images(full_path, nested=True)
59
-
60
- elif item.lower().endswith((".png", ".gif")):
61
- result[item] = load_image(full_path)
62
-
63
- return result
64
-
65
-
66
- def load_music(path):
67
- print(f"[assets] Music loading not supported in this crystalwindow ver, sorry! ~Crystal: {path}")
68
- return None
69
-
70
-
71
- def play_music(loop=-1):
72
- print("[assets] Music playback not supported in this ver sorry! ~Crystal")
@@ -1,78 +0,0 @@
1
- import random
2
- from tkinter import PhotoImage
3
-
4
- class Sprite:
5
- def __init__(self, pos, size=None, image=None, color=(255, 0, 0)):
6
- """
7
- pos: (x, y)
8
- size: (w, h) optional
9
- image: PhotoImage (Tkinter)
10
- color: fill color if no image
11
- """
12
- self.pos = pos
13
- self.x, self.y = pos
14
- self.image = image
15
- self.color = color
16
-
17
- if image is not None:
18
- self.width = image.width()
19
- self.height = image.height()
20
- elif size is not None:
21
- self.width, self.height = size
22
- else:
23
- raise ValueError("Sprite needs either 'size' or 'image'")
24
-
25
- # optional velocity fields for physics
26
- self.vel_x = 0
27
- self.vel_y = 0
28
-
29
- # === CLASS METHODS ===
30
- @classmethod
31
- def image(cls, img, pos):
32
- # fallback if img is missing
33
- if isinstance(img, dict) and img.get("fallback"):
34
- print("⚠️ Missing image, making RANDOM rect fallback.")
35
- w, h = img["size"]
36
- color = img["color"]
37
- return cls.rect(pos, w, h, color=color)
38
- return cls(pos, image=img)
39
-
40
- @classmethod
41
- def rect(cls, pos, w, h, color=(255, 0, 0)):
42
- """Create sprite using a plain colored rectangle"""
43
- return cls(pos, size=(w, h), color=color)
44
-
45
- # === METHODS ===
46
- def draw(self, win, cam=None):
47
- """Draw sprite on a CrystalWindow or Tkinter canvas"""
48
- if cam:
49
- draw_x, draw_y = cam.apply(self)
50
- else:
51
- draw_x, draw_y = self.x, self.y
52
-
53
- if self.image:
54
- win.canvas.create_image(draw_x, draw_y, anchor="nw", image=self.image)
55
- else:
56
- win.draw_rect(self.color, (draw_x, draw_y, self.width, self.height))
57
-
58
- def move(self, dx, dy):
59
- """Move sprite manually by dx/dy"""
60
- self.x += dx
61
- self.y += dy
62
- self.pos = (self.x, self.y)
63
-
64
- def apply_velocity(self, dt=1):
65
- """Apply vel_x/vel_y to x/y for physics"""
66
- self.x += self.vel_x * dt
67
- self.y += self.vel_y * dt
68
- self.pos = (self.x, self.y)
69
-
70
- # === COLLISION ===
71
- def colliderect(self, other):
72
- """Check if self collides with another sprite"""
73
- return (
74
- self.x < other.x + getattr(other, "width", 0) and
75
- self.x + getattr(self, "width", 0) > other.x and
76
- self.y < other.y + getattr(other, "height", 0) and
77
- self.y + getattr(self, "height", 0) > other.y
78
- )
File without changes
File without changes
File without changes