remove old colorPicker
This commit is contained in:
parent
b79bcef58a
commit
323ca4def6
|
@ -1,275 +0,0 @@
|
||||||
"""Fabelous CTK Color Picker for customtkinter
|
|
||||||
----------------------------------------
|
|
||||||
Based on the original work by Akash Bora (Akascape)
|
|
||||||
Contributions from Victor Vimbert-Guerlais (helloHackYnow)
|
|
||||||
Original: https://github.com/Akascape/CTkColorPicker/tree/main
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
import customtkinter as Ctk
|
|
||||||
from PIL import Image, ImageTk
|
|
||||||
import os
|
|
||||||
import math
|
|
||||||
|
|
||||||
|
|
||||||
class AskColor(Ctk.CTkToplevel):
|
|
||||||
|
|
||||||
def __init__(self,
|
|
||||||
master,
|
|
||||||
font = None,
|
|
||||||
width: int = 250,
|
|
||||||
title: str = "Choose Color",
|
|
||||||
initial_color: str = None,
|
|
||||||
text: str = "apply",
|
|
||||||
corner_radius: int = 16,
|
|
||||||
slider_border: int = 1,
|
|
||||||
**button_kwargs):
|
|
||||||
super().__init__(master, **button_kwargs)
|
|
||||||
self.selected_color = None
|
|
||||||
self.title(title)
|
|
||||||
WIDTH = width if width >= 250 else 250
|
|
||||||
HEIGHT = WIDTH + 110
|
|
||||||
self.font = font if font is not None else Ctk.CTkFont(family="kDefaultFont", size=16)
|
|
||||||
self.image_dimension = self._apply_window_scaling(WIDTH - 100)
|
|
||||||
self.target_dimension = self._apply_window_scaling(20)
|
|
||||||
self.initial_color = initial_color
|
|
||||||
self.maxsize(WIDTH, HEIGHT)
|
|
||||||
self.minsize(WIDTH, HEIGHT)
|
|
||||||
self.resizable(width=False, height=False)
|
|
||||||
self.transient(self.master)
|
|
||||||
self.lift()
|
|
||||||
self.after(10)
|
|
||||||
self.protocol("WM_DELETE_WINDOW", self._on_closing)
|
|
||||||
|
|
||||||
self.default_hex_color = "#ffffff"
|
|
||||||
self.default_rgb = [255, 255, 255]
|
|
||||||
self.rgb_color = self.default_rgb[:]
|
|
||||||
self.button_text = text
|
|
||||||
self.corner_radius = corner_radius
|
|
||||||
self.slider_border = 10 if slider_border >= 10 else slider_border
|
|
||||||
|
|
||||||
self.frame = Ctk.CTkFrame(master=self)
|
|
||||||
self.frame.grid(sticky="nswe", padx=5, pady=5)
|
|
||||||
self.fg_color = self.fg_color = self._apply_appearance_mode(Ctk.ThemeManager.theme["CTkFrame"]["fg_color"])
|
|
||||||
self.canvas = Ctk.CTkCanvas(self.frame, height=self.image_dimension, width=self.image_dimension, highlightthickness=0, bg=self.fg_color)
|
|
||||||
self.canvas.grid(row=0, column=0, columnspan=2, pady=20)
|
|
||||||
|
|
||||||
|
|
||||||
self.canvas.bind("<B1-Motion>", self.on_mouse_drag)
|
|
||||||
|
|
||||||
self.img1 = Image.open('icons/color_wheel.png').resize((self.image_dimension, self.image_dimension), Image.Resampling.LANCZOS)
|
|
||||||
self.img2 = Image.open('icons/target.png').resize((self.target_dimension, self.target_dimension), Image.Resampling.LANCZOS)
|
|
||||||
self.wheel = ImageTk.PhotoImage(self.img1)
|
|
||||||
self.target = ImageTk.PhotoImage(self.img2)
|
|
||||||
|
|
||||||
self.canvas.create_image(self.image_dimension/2, self.image_dimension/2, image=self.wheel)
|
|
||||||
self.set_initial_color(initial_color)
|
|
||||||
|
|
||||||
self.brightness_slider_value = Ctk.IntVar()
|
|
||||||
self.brightness_slider_value.set(255)
|
|
||||||
|
|
||||||
self.slider = Ctk.CTkSlider(master=self.frame, height=20, border_width=self.slider_border,
|
|
||||||
button_length=15, progress_color=self.default_hex_color, from_=0, to=255,
|
|
||||||
variable=self.brightness_slider_value, number_of_steps=256,
|
|
||||||
button_corner_radius=self.corner_radius, corner_radius=self.corner_radius,
|
|
||||||
command=lambda x:self.update_colors())
|
|
||||||
|
|
||||||
self.slider.grid(row=1, column=0, columnspan=2, pady=(0, 15), padx=20-self.slider_border)
|
|
||||||
|
|
||||||
self.label = Ctk.CTkLabel(master=self.frame, text_color="#000000", height=50, width=75, fg_color=self.default_hex_color,
|
|
||||||
corner_radius=self.corner_radius, text="")
|
|
||||||
|
|
||||||
self.color_entry = Ctk.CTkEntry(master=self.frame, height=50, corner_radius=self.corner_radius, font=self.font, width=100)
|
|
||||||
self.color_entry.configure(placeholder_text=self.default_hex_color) # Insert the new text
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.button = Ctk.CTkButton(master=self.frame, text=self.button_text, height=50, corner_radius=self.corner_radius,width = 200,
|
|
||||||
command=self._ok_event, **button_kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
self.label.grid(row=2, column=0, padx=(5, 20), pady=10, sticky="e")
|
|
||||||
self.color_entry.grid(row=2, column=1, padx=(5, 5), pady=10, sticky="w")
|
|
||||||
self.button.grid(row=3, column=0, columnspan=3, padx=5, pady=10)
|
|
||||||
self.after(150, lambda: self.label.focus())
|
|
||||||
|
|
||||||
self.grab_set()
|
|
||||||
|
|
||||||
|
|
||||||
def get(self):
|
|
||||||
# Use the stored selected_color instead of accessing the widget
|
|
||||||
return self.selected_color
|
|
||||||
|
|
||||||
def _ok_event(self, event=None):
|
|
||||||
input_string = self.color_entry.get()
|
|
||||||
self.selected_color = self.check_rgb_hex_color(input_string) # Store the selected color
|
|
||||||
self.grab_release()
|
|
||||||
self.destroy()
|
|
||||||
del self.img1
|
|
||||||
del self.img2
|
|
||||||
del self.wheel
|
|
||||||
del self.target
|
|
||||||
|
|
||||||
def check_rgb_hex_color(self, input_string):
|
|
||||||
if not input_string:
|
|
||||||
return self.default_hex_color
|
|
||||||
if not input_string.startswith("#"):
|
|
||||||
input_string = "#" + input_string
|
|
||||||
hex_color = input_string.lstrip("#")
|
|
||||||
if len(hex_color) != 6:
|
|
||||||
return None
|
|
||||||
try:
|
|
||||||
int(hex_color, 16)
|
|
||||||
return input_string
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _on_closing(self):
|
|
||||||
self._color = None
|
|
||||||
self.grab_release()
|
|
||||||
self.destroy()
|
|
||||||
del self.img1
|
|
||||||
del self.img2
|
|
||||||
del self.wheel
|
|
||||||
del self.target
|
|
||||||
|
|
||||||
def on_mouse_drag(self, event):
|
|
||||||
x = event.x
|
|
||||||
y = event.y
|
|
||||||
self.canvas.delete("all")
|
|
||||||
self.canvas.create_image(self.image_dimension/2, self.image_dimension/2, image=self.wheel)
|
|
||||||
|
|
||||||
d_from_center = math.sqrt(((self.image_dimension/2)-x)**2 + ((self.image_dimension/2)-y)**2)
|
|
||||||
|
|
||||||
if d_from_center < self.image_dimension/2:
|
|
||||||
self.target_x, self.target_y = x, y
|
|
||||||
else:
|
|
||||||
self.target_x, self.target_y = self.projection_on_circle(x, y, self.image_dimension/2, self.image_dimension/2, self.image_dimension/2 -1)
|
|
||||||
|
|
||||||
self.canvas.create_image(self.target_x, self.target_y, image=self.target)
|
|
||||||
|
|
||||||
self.get_target_color()
|
|
||||||
self.update_colors()
|
|
||||||
|
|
||||||
def get_target_color(self):
|
|
||||||
try:
|
|
||||||
self.rgb_color = self.img1.getpixel((self.target_x, self.target_y))
|
|
||||||
|
|
||||||
r = self.rgb_color[0]
|
|
||||||
g = self.rgb_color[1]
|
|
||||||
b = self.rgb_color[2]
|
|
||||||
self.rgb_color = [r, g, b]
|
|
||||||
|
|
||||||
except AttributeError:
|
|
||||||
self.rgb_color = self.default_rgb
|
|
||||||
|
|
||||||
def update_colors(self):
|
|
||||||
brightness = self.brightness_slider_value.get()
|
|
||||||
|
|
||||||
self.get_target_color()
|
|
||||||
|
|
||||||
r = int(self.rgb_color[0] * (brightness/255))
|
|
||||||
g = int(self.rgb_color[1] * (brightness/255))
|
|
||||||
b = int(self.rgb_color[2] * (brightness/255))
|
|
||||||
|
|
||||||
self.rgb_color = [r, g, b]
|
|
||||||
|
|
||||||
self.default_hex_color = "#{:02x}{:02x}{:02x}".format(*self.rgb_color)
|
|
||||||
|
|
||||||
self.slider.configure(progress_color=self.default_hex_color)
|
|
||||||
self.label.configure(fg_color=self.default_hex_color)
|
|
||||||
|
|
||||||
self.color_entry.delete(0, Ctk.END) # Delete any existing text in the color_entry widget
|
|
||||||
self.color_entry.configure(placeholder_text=self.default_hex_color) # Insert the new text
|
|
||||||
|
|
||||||
|
|
||||||
def projection_on_circle(self, point_x, point_y, circle_x, circle_y, radius):
|
|
||||||
angle = math.atan2(point_y - circle_y, point_x - circle_x)
|
|
||||||
projection_x = circle_x + radius * math.cos(angle)
|
|
||||||
projection_y = circle_y + radius * math.sin(angle)
|
|
||||||
|
|
||||||
return projection_x, projection_y
|
|
||||||
|
|
||||||
def set_initial_color(self, initial_color):
|
|
||||||
"""
|
|
||||||
Sets the initial color of the target if it matches the specified `initial_color`.
|
|
||||||
Falls back to the center of the image if no matching color is found or `initial_color` is invalid.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- initial_color (str): The hexadecimal color value (e.g., '#RRGGBB') to match in the image.
|
|
||||||
|
|
||||||
Note: This method is in beta stage and may not accurately handle all colors.
|
|
||||||
"""
|
|
||||||
if not initial_color or not initial_color.startswith("#"):
|
|
||||||
self._place_image_at_center()
|
|
||||||
return
|
|
||||||
|
|
||||||
r, g, b = self._hex_to_rgb(initial_color)
|
|
||||||
|
|
||||||
for i in range(self.image_dimension):
|
|
||||||
for j in range(self.image_dimension):
|
|
||||||
if self._pixel_matches_color(i, j, (r, g, b)):
|
|
||||||
self._place_image_at(i, j)
|
|
||||||
return
|
|
||||||
|
|
||||||
self._place_image_at_center()
|
|
||||||
|
|
||||||
def _hex_to_rgb(self, hex_color):
|
|
||||||
"""
|
|
||||||
Converts a hexadecimal color to an RGB tuple.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- hex_color (str): The hexadecimal color string (e.g., '#RRGGBB').
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(tuple): A tuple containing the RGB values (r, g, b).
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return tuple(int(hex_color.lstrip('#')[i:i+2], 16) for i in (0, 2, 4))
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _pixel_matches_color(self, x, y, color):
|
|
||||||
"""
|
|
||||||
Checks if the pixel at (x, y) matches the specified `color`.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- x (int): The x-coordinate of the pixel.
|
|
||||||
- y (int): The y-coordinate of the pixel.
|
|
||||||
- color (tuple): The RGB tuple to match.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(bool): True if the pixel matches the `color`; False otherwise.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return self.img1.getpixel((x, y))[:3] == color
|
|
||||||
except IndexError:
|
|
||||||
# Outside the image bounds
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _place_image_at(self, x, y):
|
|
||||||
"""
|
|
||||||
Places the image at the specified (x, y) coordinates.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- x (int): The x-coordinate where the image should be placed.
|
|
||||||
- y (int): The y-coordinate where the image should be placed.
|
|
||||||
"""
|
|
||||||
self.default_hex_color = self.initial_color
|
|
||||||
self.canvas.create_image(x, y, image=self.target)
|
|
||||||
self.target_x = x
|
|
||||||
self.target_y = y
|
|
||||||
|
|
||||||
def _place_image_at_center(self):
|
|
||||||
"""
|
|
||||||
Places the image at the center of the canvas.
|
|
||||||
"""
|
|
||||||
center = self.image_dimension // 2
|
|
||||||
self.canvas.create_image(center, center, image=self.target)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
app = AskColor(master=None, font=None)
|
|
||||||
app.wait_window(app) # This waits until the window is closed
|
|
||||||
color = app.get() # Access the color stored before the window was destroyed
|
|
||||||
print("Selected color:", color)
|
|
Loading…
Reference in New Issue