crystalwindow 3.7.1b1__tar.gz → 3.8.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.
Files changed (44) hide show
  1. {crystalwindow-3.7.1b1/crystalwindow.egg-info → crystalwindow-3.8.3}/PKG-INFO +1 -1
  2. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/__init__.py +21 -5
  3. crystalwindow-3.8.3/crystalwindow/assets.py +150 -0
  4. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/sprites.py +45 -15
  5. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3/crystalwindow.egg-info}/PKG-INFO +1 -1
  6. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/setup.py +1 -1
  7. crystalwindow-3.7.1b1/crystalwindow/assets.py +0 -72
  8. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/LICENSE +0 -0
  9. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/MANIFEST.in +0 -0
  10. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/README.md +0 -0
  11. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/FileHelper.py +0 -0
  12. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/Icons/default_icon.png +0 -0
  13. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/animation.py +0 -0
  14. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/camera.py +0 -0
  15. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/clock.py +0 -0
  16. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/collision.py +0 -0
  17. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/crystal3d.py +0 -0
  18. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/docs/getting_started.md +0 -0
  19. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/docs/index.md +0 -0
  20. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/draw_helpers.py +0 -0
  21. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/draw_rects.py +0 -0
  22. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/draw_text_helper.py +0 -0
  23. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/draw_tool.py +0 -0
  24. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/fun_helpers.py +0 -0
  25. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/gametests/3dsquare.py +0 -0
  26. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/gametests/__init__.py +0 -0
  27. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/gametests/__main__.py +0 -0
  28. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/gametests/gravitytest.py +0 -0
  29. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/gametests/guitesting.py +0 -0
  30. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/gametests/sandbox.py +0 -0
  31. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/gametests/squaremove.py +0 -0
  32. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/gametests/windowtesting.py +0 -0
  33. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/gravity.py +0 -0
  34. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/gui.py +0 -0
  35. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/gui_ext.py +0 -0
  36. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/math.py +0 -0
  37. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/player.py +0 -0
  38. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/tilemap.py +0 -0
  39. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/ver_warner.py +0 -0
  40. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow/window.py +0 -0
  41. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow.egg-info/SOURCES.txt +0 -0
  42. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow.egg-info/dependency_links.txt +0 -0
  43. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/crystalwindow.egg-info/top_level.txt +0 -0
  44. {crystalwindow-3.7.1b1 → crystalwindow-3.8.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crystalwindow
3
- Version: 3.7.1b1
3
+ Version: 3.8.3
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.")
@@ -1,40 +1,59 @@
1
+ # sprites.py
1
2
  import random
2
3
  from tkinter import PhotoImage
3
4
 
5
+ try:
6
+ from PIL import Image, ImageTk
7
+ except ImportError:
8
+ Image = None
9
+ ImageTk = None
10
+
4
11
  class Sprite:
5
12
  def __init__(self, pos, size=None, image=None, color=(255, 0, 0)):
6
13
  """
7
14
  pos: (x, y)
8
15
  size: (w, h) optional
9
- image: PhotoImage (Tkinter)
10
- color: fill color if no image
16
+ image: PhotoImage or PIL ImageTk.PhotoImage
17
+ color: fallback rectangle color
11
18
  """
12
19
  self.pos = pos
13
20
  self.x, self.y = pos
14
21
  self.image = image
15
22
  self.color = color
16
23
 
24
+ # Determine width/height
17
25
  if image is not None:
18
- self.width = image.width()
19
- self.height = image.height()
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")
20
37
  elif size is not None:
21
38
  self.width, self.height = size
22
39
  else:
23
- raise ValueError("Sprite needs either 'size' or 'image'")
40
+ raise ValueError("Sprite needs 'size' or 'image'")
24
41
 
25
- # optional velocity fields for physics
42
+ # Optional velocity
26
43
  self.vel_x = 0
27
44
  self.vel_y = 0
28
45
 
29
46
  # === CLASS METHODS ===
30
47
  @classmethod
31
48
  def image(cls, img, pos):
32
- # fallback if img is missing
49
+ """
50
+ Create a sprite from an image.
51
+ Accepts fallback dict or actual PhotoImage.
52
+ """
33
53
  if isinstance(img, dict) and img.get("fallback"):
34
- print("⚠️ Missing image, making RANDOM rect fallback.")
35
54
  w, h = img["size"]
36
55
  color = img["color"]
37
- return cls.rect(pos, w, h, color=color)
56
+ return cls(pos, size=(w, h), color=color)
38
57
  return cls(pos, image=img)
39
58
 
40
59
  @classmethod
@@ -44,7 +63,7 @@ class Sprite:
44
63
 
45
64
  # === METHODS ===
46
65
  def draw(self, win, cam=None):
47
- """Draw sprite on a CrystalWindow or Tkinter canvas"""
66
+ """Draw sprite on CrystalWindow / Tk canvas"""
48
67
  if cam:
49
68
  draw_x, draw_y = cam.apply(self)
50
69
  else:
@@ -56,23 +75,34 @@ class Sprite:
56
75
  win.draw_rect(self.color, (draw_x, draw_y, self.width, self.height))
57
76
 
58
77
  def move(self, dx, dy):
59
- """Move sprite manually by dx/dy"""
60
78
  self.x += dx
61
79
  self.y += dy
62
80
  self.pos = (self.x, self.y)
63
81
 
64
82
  def apply_velocity(self, dt=1):
65
- """Apply vel_x/vel_y to x/y for physics"""
66
83
  self.x += self.vel_x * dt
67
84
  self.y += self.vel_y * dt
68
85
  self.pos = (self.x, self.y)
69
86
 
70
- # === COLLISION ===
71
87
  def colliderect(self, other):
72
- """Check if self collides with another sprite"""
73
88
  return (
74
89
  self.x < other.x + getattr(other, "width", 0) and
75
90
  self.x + getattr(self, "width", 0) > other.x and
76
91
  self.y < other.y + getattr(other, "height", 0) and
77
92
  self.y + getattr(self, "height", 0) > other.y
78
- )
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.7.1b1
3
+ Version: 3.8.3
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.b1", # Force metadata refresh
10
+ version="3.8.3", # 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")
File without changes
File without changes
File without changes