mirror of
https://github.com/TomSchimansky/CustomTkinter.git
synced 2023-08-10 21:13:13 +03:00
changed CTkThemeManager to json file loading system
This commit is contained in:
parent
4a0b0a9c71
commit
bb1fe25625
@ -6,8 +6,8 @@ from .customtkinter_frame import CTkFrame
|
||||
from .customtkinter_progressbar import CTkProgressBar
|
||||
from .customtkinter_label import CTkLabel
|
||||
from .customtkinter_entry import CTkEntry
|
||||
from .customtkinter_dialog import CTkDialog
|
||||
from .customtkinter_checkbox import CTkCheckBox
|
||||
from .customtkinter_dialog import CTkDialog
|
||||
from .customtkinter_tk import CTk
|
||||
from .customtkinter_canvas import CTkCanvas
|
||||
from .customtkinter_toplevel import CTkToplevel
|
||||
@ -62,24 +62,24 @@ def set_default_color_theme(color_string):
|
||||
CTkThemeManager.initialize_color_theme(color_string)
|
||||
|
||||
|
||||
import warnings
|
||||
warnings.simplefilter("ignore", category=UserWarning)
|
||||
if not sys.platform == "darwin":
|
||||
import warnings
|
||||
warnings.simplefilter("ignore", category=UserWarning)
|
||||
|
||||
import pyglet.font
|
||||
import pyglet.font
|
||||
|
||||
# load text fonts and custom font with circle shapes for round corner rendering
|
||||
script_directory = os.path.dirname(os.path.abspath(__file__))
|
||||
pyglet.font.add_file(os.path.join(script_directory, "assets", "CustomTkinter_shapes_font-Regular.otf"))
|
||||
pyglet.font.add_file(os.path.join(script_directory, "assets", "Roboto", "Roboto-Regular.ttf"))
|
||||
pyglet.font.add_file(os.path.join(script_directory, "assets", "Roboto", "Roboto-Medium.ttf"))
|
||||
CTkSettings.circle_font_is_ready = pyglet.font.have_font("CustomTkinter_shapes_font")
|
||||
|
||||
# load text fonts and custom font with circle shapes for round corner rendering
|
||||
script_directory = os.path.dirname(os.path.abspath(__file__))
|
||||
pyglet.font.add_file(os.path.join(script_directory, "assets", "CustomTkinter_shapes_font-Regular.otf"))
|
||||
pyglet.font.add_file(os.path.join(script_directory, "assets", "Roboto", "Roboto-Regular.ttf"))
|
||||
pyglet.font.add_file(os.path.join(script_directory, "assets", "Roboto", "Roboto-Medium.ttf"))
|
||||
CTkSettings.circle_font_is_ready = pyglet.font.have_font("CustomTkinter_shapes_font")
|
||||
warnings.simplefilter("default")
|
||||
|
||||
warnings.simplefilter("default")
|
||||
|
||||
# correct drawing method if font could not be loaded
|
||||
if not CTkSettings.circle_font_is_ready:
|
||||
if CTkSettings.preferred_drawing_method == "font_shapes":
|
||||
sys.stderr.write("WARNING (customtkinter.CTkSettings): " +
|
||||
"Preferred drawing method 'font_shapes' can not be used because the font file could not be loaded. Using 'circle_shapes' instead.")
|
||||
CTkSettings.preferred_drawing_method = "circle_shapes"
|
||||
# correct drawing method if font could not be loaded
|
||||
if not CTkSettings.circle_font_is_ready:
|
||||
if CTkSettings.preferred_drawing_method == "font_shapes":
|
||||
sys.stderr.write("WARNING (customtkinter.CTkSettings): " +
|
||||
"Preferred drawing method 'font_shapes' can not be used because the font file could not be loaded. Using 'circle_shapes' instead.")
|
||||
CTkSettings.preferred_drawing_method = "circle_shapes"
|
||||
|
55
customtkinter/assets/themes/blue.json
Normal file
55
customtkinter/assets/themes/blue.json
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
"color": {
|
||||
"window_bg_color": ["#ECECEC", "#323232"],
|
||||
"button": ["#64A1D2", "#1C94CF"],
|
||||
"button_hover": ["#A7C2E0", "#5FB4DD"],
|
||||
"button_border": ["#A7C2E0", "#5FB4DD"],
|
||||
"checkbox_border": ["black", "#ededed"],
|
||||
"entry": ["gray95", "#222222"],
|
||||
"entry_border": ["gray65", "gray40"],
|
||||
"entry_placeholder_text": ["gray52", "gray62"],
|
||||
"frame_border": ["#A7C2E0", "#5FB4DD"],
|
||||
"frame_low": ["#D4D5D6", "#3F3F3F"],
|
||||
"frame_high": ["#BFBEC1", "#505050"],
|
||||
"label": ["white", "#626061"],
|
||||
"text": ["gray18", "gray90"],
|
||||
"progressbar": ["#6B6B6B", "#222222"],
|
||||
"progressbar_progress": ["red", "red"],
|
||||
"progressbar_border": ["gray", "gray"],
|
||||
"slider": ["#6B6B6B", "#222222"],
|
||||
"slider_progress": ["#A5A6A5", "#555555"],
|
||||
"slider_button": ["#64A1D2", "#1C94CF"],
|
||||
"slider_button_hover": ["#A7C2E0", "#5FB4DD"],
|
||||
"darken_factor": 0.8
|
||||
},
|
||||
|
||||
"text": {
|
||||
"macOS": {
|
||||
"font": "SF Display",
|
||||
"size": -14
|
||||
},
|
||||
"Windows": {
|
||||
"font": "Roboto",
|
||||
"size": -14
|
||||
},
|
||||
"Linux": {
|
||||
"font": "Roboto",
|
||||
"size": -14
|
||||
}
|
||||
|
||||
},
|
||||
"shape": {
|
||||
"button_corner_radius": 8,
|
||||
"button_border_width": 2,
|
||||
"checkbox_corner_radius": 6,
|
||||
"checkbox_border_width": 3,
|
||||
"entry_border_width": 2,
|
||||
"frame_corner_radius": 10,
|
||||
"frame_border_width": 0,
|
||||
"label_corner_radius": 8,
|
||||
"progressbar_border_width": 2,
|
||||
"progressbar_corner_radius": 1000,
|
||||
"slider_border_width": 4,
|
||||
"slider_corner_radius": 3
|
||||
}
|
||||
}
|
@ -18,12 +18,12 @@ class CTkButton(tkinter.Frame):
|
||||
fg_color="default_theme",
|
||||
hover_color="default_theme",
|
||||
border_color="default_theme",
|
||||
border_width=0,
|
||||
border_width="default_theme",
|
||||
command=None,
|
||||
textvariable=None,
|
||||
width=120,
|
||||
height=30,
|
||||
corner_radius=8,
|
||||
corner_radius="default_theme",
|
||||
text_font="default_theme",
|
||||
text_color="default_theme",
|
||||
text="CTkButton",
|
||||
@ -62,16 +62,16 @@ class CTkButton(tkinter.Frame):
|
||||
|
||||
# color variables
|
||||
self.bg_color = self.detect_color_of_master() if bg_color is None else bg_color
|
||||
self.fg_color = CTkThemeManager.MAIN_COLOR if fg_color == "default_theme" else fg_color
|
||||
self.hover_color = CTkThemeManager.MAIN_HOVER_COLOR if hover_color == "default_theme" else hover_color
|
||||
self.border_color = CTkThemeManager.CHECKBOX_LINES_COLOR if border_color == "default_theme" else border_color
|
||||
self.fg_color = CTkThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_color
|
||||
self.hover_color = CTkThemeManager.theme["color"]["button_hover"] if hover_color == "default_theme" else hover_color
|
||||
self.border_color = CTkThemeManager.theme["color"]["button_hover"] if border_color == "default_theme" else border_color
|
||||
|
||||
# shape and size
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.configure(width=self.width, height=self.height)
|
||||
self.corner_radius = corner_radius
|
||||
self.border_width = border_width
|
||||
self.corner_radius = CTkThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius
|
||||
self.border_width = CTkThemeManager.theme["shape"]["button_border_width"] if border_width == "default_theme" else border_width
|
||||
|
||||
if self.corner_radius * 2 > self.height:
|
||||
self.corner_radius = self.height / 2
|
||||
@ -88,8 +88,8 @@ class CTkButton(tkinter.Frame):
|
||||
self.image_label = None
|
||||
self.text = text
|
||||
self.text_label = None
|
||||
self.text_color = CTkThemeManager.TEXT_COLOR if text_color == "default_theme" else text_color
|
||||
self.text_font = (CTkThemeManager.TEXT_FONT_NAME, CTkThemeManager.TEXT_FONT_SIZE) if text_font == "default_theme" else text_font
|
||||
self.text_color = CTkThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
|
||||
self.text_font = (CTkThemeManager.theme["text"]["font"], CTkThemeManager.theme["text"]["size"]) if text_font == "default_theme" else text_font
|
||||
|
||||
# callback and hover functionality
|
||||
self.function = command
|
||||
|
@ -1,13 +1,13 @@
|
||||
import tkinter
|
||||
import sys
|
||||
|
||||
from .customtkinter_tk import CTk
|
||||
from .customtkinter_frame import CTkFrame
|
||||
from .appearance_mode_tracker import AppearanceModeTracker
|
||||
from .customtkinter_theme_manager import CTkThemeManager
|
||||
from .customtkinter_canvas import CTkCanvas
|
||||
from .customtkinter_settings import CTkSettings
|
||||
from .customtkinter_draw_engine import DrawEngine
|
||||
from customtkinter.customtkinter_tk import CTk
|
||||
from customtkinter.customtkinter_frame import CTkFrame
|
||||
from customtkinter.appearance_mode_tracker import AppearanceModeTracker
|
||||
from customtkinter.customtkinter_theme_manager import CTkThemeManager
|
||||
from customtkinter.customtkinter_canvas import CTkCanvas
|
||||
from customtkinter.customtkinter_settings import CTkSettings
|
||||
from customtkinter.customtkinter_draw_engine import DrawEngine
|
||||
|
||||
|
||||
class CTkCheckBox(tkinter.Frame):
|
||||
@ -18,10 +18,10 @@ class CTkCheckBox(tkinter.Frame):
|
||||
fg_color="default_theme",
|
||||
hover_color="default_theme",
|
||||
border_color="default_theme",
|
||||
border_width=3,
|
||||
width=25,
|
||||
height=25,
|
||||
corner_radius=6,
|
||||
border_width="default_theme",
|
||||
width=24,
|
||||
height=24,
|
||||
corner_radius="default_theme",
|
||||
text_font="default_theme",
|
||||
text_color="default_theme",
|
||||
text="CTkCheckBox",
|
||||
@ -60,29 +60,28 @@ class CTkCheckBox(tkinter.Frame):
|
||||
self.appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark"
|
||||
|
||||
self.bg_color = self.detect_color_of_master() if bg_color is None else bg_color
|
||||
self.fg_color = CTkThemeManager.MAIN_COLOR if fg_color == "default_theme" else fg_color
|
||||
self.hover_color = CTkThemeManager.MAIN_HOVER_COLOR if hover_color == "default_theme" else hover_color
|
||||
self.border_color = CTkThemeManager.CHECKBOX_LINES_COLOR if border_color == "default_theme" else border_color
|
||||
self.fg_color = CTkThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_color
|
||||
self.hover_color = CTkThemeManager.theme["color"]["button"] if hover_color == "default_theme" else hover_color
|
||||
self.border_color = CTkThemeManager.theme["color"]["checkbox_border"] if border_color == "default_theme" else border_color
|
||||
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.corner_radius = corner_radius
|
||||
self.corner_radius = CTkThemeManager.theme["shape"]["checkbox_corner_radius"] if corner_radius == "default_theme" else corner_radius
|
||||
self.border_width = CTkThemeManager.theme["shape"]["checkbox_border_width"] if border_width == "default_theme" else border_width
|
||||
|
||||
if self.corner_radius*2 > self.height:
|
||||
self.corner_radius = self.height/2
|
||||
elif self.corner_radius*2 > self.width:
|
||||
self.corner_radius = self.width/2
|
||||
|
||||
self.border_width = border_width
|
||||
|
||||
if self.corner_radius >= self.border_width:
|
||||
self.inner_corner_radius = self.corner_radius - self.border_width
|
||||
else:
|
||||
self.inner_corner_radius = 0
|
||||
|
||||
self.text = text
|
||||
self.text_color = CTkThemeManager.TEXT_COLOR if text_color == "default_theme" else text_color
|
||||
self.text_font = (CTkThemeManager.TEXT_FONT_NAME, CTkThemeManager.TEXT_FONT_SIZE) if text_font == "default_theme" else text_font
|
||||
self.text_color = CTkThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
|
||||
self.text_font = (CTkThemeManager.theme["text"]["font"], CTkThemeManager.theme["text"]["size"]) if text_font == "default_theme" else text_font
|
||||
|
||||
self.function = command
|
||||
self.state = state
|
||||
|
@ -13,7 +13,8 @@ class CTkDialog:
|
||||
title="CTkDialog",
|
||||
text="CTkDialog",
|
||||
fg_color="default_theme",
|
||||
hover_color="default_theme"):
|
||||
hover_color="default_theme",
|
||||
border_color="default_theme"):
|
||||
self.master = master
|
||||
|
||||
self.user_input = None
|
||||
@ -21,8 +22,9 @@ class CTkDialog:
|
||||
|
||||
self.height = len(text.split("\n"))*20 + 150
|
||||
|
||||
self.fg_color = CTkThemeManager.MAIN_COLOR if fg_color == "default_theme" else fg_color
|
||||
self.hover_color = CTkThemeManager.MAIN_HOVER_COLOR if hover_color == "default_theme" else hover_color
|
||||
self.fg_color = CTkThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_color
|
||||
self.hover_color = CTkThemeManager.theme["color"]["button_hover"] if hover_color == "default_theme" else hover_color
|
||||
self.border_color = CTkThemeManager.theme["color"]["button_hover"] if border_color == "default_theme" else border_color
|
||||
|
||||
self.top = customtkinter.CTkToplevel()
|
||||
self.top.geometry(f"280x{self.height}")
|
||||
@ -60,7 +62,8 @@ class CTkDialog:
|
||||
width=100,
|
||||
command=self.ok_event,
|
||||
fg_color=self.fg_color,
|
||||
hover_color=self.hover_color)
|
||||
hover_color=self.hover_color,
|
||||
border_color=self.border_color)
|
||||
self.ok_button.place(relx=0.28, rely=0.65, anchor=tkinter.CENTER)
|
||||
|
||||
self.cancel_button = CTkButton(master=self.button_and_entry_frame,
|
||||
@ -68,7 +71,8 @@ class CTkDialog:
|
||||
width=100,
|
||||
command=self.cancel_event,
|
||||
fg_color=self.fg_color,
|
||||
hover_color=self.hover_color)
|
||||
hover_color=self.hover_color,
|
||||
border_color=self.border_color)
|
||||
self.cancel_button.place(relx=0.72, rely=0.65, anchor=tkinter.CENTER)
|
||||
|
||||
self.entry.entry.focus_force()
|
||||
|
@ -1,3 +1,4 @@
|
||||
import sys
|
||||
import tkinter
|
||||
from typing import Union
|
||||
from .customtkinter_canvas import CTkCanvas
|
||||
@ -6,12 +7,15 @@ from .customtkinter_canvas import CTkCanvas
|
||||
class DrawEngine:
|
||||
def __init__(self, canvas: CTkCanvas, rendering_method: str):
|
||||
self.canvas = canvas
|
||||
self.rendering_method = rendering_method
|
||||
self.rendering_method = rendering_method # "polygon_shapes" (macOS), "font_shapes" (Windows, Linux), "circle_shapes" (backup)
|
||||
|
||||
def calc_optimal_corner_radius(self, user_corner_radius: Union[float, int]) -> Union[float, int]:
|
||||
# optimize for drawing with polygon shapes
|
||||
if self.rendering_method == "polygon_shapes":
|
||||
return user_corner_radius
|
||||
if sys.platform == "darwin":
|
||||
return user_corner_radius
|
||||
else:
|
||||
return round(user_corner_radius)
|
||||
|
||||
# optimize forx drawing with antialiased font shapes
|
||||
elif self.rendering_method == "font_shapes":
|
||||
@ -30,7 +34,13 @@ class DrawEngine:
|
||||
return user_corner_radius
|
||||
|
||||
def draw_rounded_rect_with_border(self, width: int, height: int, corner_radius: Union[float, int], border_width: Union[float, int]) -> bool:
|
||||
""" returns bool if recoloring is necessary """
|
||||
""" Draws a rounded rectangle with a corner_radius and border_width on the canvas. The border elements have a 'border_parts' tag,
|
||||
the main foreground elements have an 'inner_parts' tag to color the elements accordingly.
|
||||
|
||||
returns bool if recoloring is necessary """
|
||||
|
||||
if corner_radius > width / 2 or corner_radius > height / 2: # restrict corner_radius if it's too larger
|
||||
corner_radius = min(width / 2, height / 2)
|
||||
|
||||
border_width = round(border_width)
|
||||
corner_radius = self.calc_optimal_corner_radius(corner_radius) # optimize corner_radius for different drawing methods (different rounding)
|
||||
@ -287,8 +297,302 @@ class DrawEngine:
|
||||
|
||||
return requires_recoloring
|
||||
|
||||
def draw_rounded_bar_with_border(self, width: int, height: int, corner_radius: Union[float, int], border_width: Union[float, int]) -> bool:
|
||||
pass
|
||||
def draw_rounded_progress_bar_with_border(self, width: int, height: int, corner_radius: Union[float, int], border_width: Union[float, int],
|
||||
progress_value: float, orientation: str) -> bool:
|
||||
""" Draws a rounded bar on the canvas, which is splitted in half according to the argument 'progress_value' (0 - 1).
|
||||
The border elements get the 'border_parts' tag", the main elements get the 'inner_parts' tag and
|
||||
the progress elements get the 'progress_parts' tag. The 'orientation' argument defines from which direction the progress starts (n, w, s, e).
|
||||
|
||||
returns bool if recoloring is necessary """
|
||||
|
||||
if corner_radius > width / 2 or corner_radius > height / 2: # restrict corner_radius if it's too larger
|
||||
corner_radius = min(width / 2, height / 2)
|
||||
|
||||
border_width = round(border_width)
|
||||
corner_radius = self.calc_optimal_corner_radius(corner_radius) # optimize corner_radius for different drawing methods (different rounding)
|
||||
|
||||
if corner_radius >= border_width:
|
||||
inner_corner_radius = corner_radius - border_width
|
||||
else:
|
||||
inner_corner_radius = 0
|
||||
|
||||
if self.rendering_method == "polygon_shapes":
|
||||
return self._draw_rounded_progress_bar_with_border_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius,
|
||||
progress_value, orientation)
|
||||
elif self.rendering_method == "font_shapes":
|
||||
return self._draw_rounded_progress_bar_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius,
|
||||
progress_value, orientation)
|
||||
elif self.rendering_method == "circle_shapes":
|
||||
return self._draw_rounded_progress_bar_with_border_circle_shapes(width, height, corner_radius, border_width, inner_corner_radius)
|
||||
|
||||
def _draw_rounded_progress_bar_with_border_polygon_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int,
|
||||
progress_value: float, orientation: str) -> bool:
|
||||
requires_recoloring = False
|
||||
print(border_width, corner_radius, inner_corner_radius)
|
||||
|
||||
# create border button parts (only if border exists)
|
||||
if border_width > 0:
|
||||
if not self.canvas.find_withtag("border_parts"):
|
||||
self.canvas.create_polygon((0, 0, 0, 0), tags=("border_line_1", "border_parts"), joinstyle=tkinter.ROUND)
|
||||
print("create border")
|
||||
self.canvas.tag_lower("border_parts")
|
||||
requires_recoloring = True
|
||||
|
||||
self.canvas.coords("border_line_1",
|
||||
(corner_radius, corner_radius,
|
||||
width - corner_radius, corner_radius,
|
||||
width - corner_radius, height - corner_radius,
|
||||
corner_radius, height - corner_radius))
|
||||
self.canvas.itemconfig("border_line_1", width=corner_radius * 2)
|
||||
else:
|
||||
self.canvas.delete("border_parts")
|
||||
|
||||
# create inner button parts
|
||||
if not self.canvas.find_withtag("inner_parts"):
|
||||
self.canvas.create_polygon((0, 0, 0, 0), tags=("inner_line_1", "inner_parts"), joinstyle=tkinter.ROUND)
|
||||
print("create inner")
|
||||
if self.canvas.find_withtag("border_parts"):
|
||||
self.canvas.tag_raise("inner_parts", "border_parts")
|
||||
requires_recoloring = True
|
||||
|
||||
if corner_radius <= border_width:
|
||||
bottom_right_shift = -1 # weird canvas rendering inaccuracy that has to be corrected in some cases
|
||||
else:
|
||||
bottom_right_shift = 0
|
||||
|
||||
self.canvas.coords("inner_line_1",
|
||||
border_width + inner_corner_radius,
|
||||
border_width + inner_corner_radius,
|
||||
width - (border_width + inner_corner_radius) + bottom_right_shift,
|
||||
border_width + inner_corner_radius,
|
||||
width - (border_width + inner_corner_radius) + bottom_right_shift,
|
||||
height - (border_width + inner_corner_radius) + bottom_right_shift,
|
||||
border_width + inner_corner_radius,
|
||||
height - (border_width + inner_corner_radius) + bottom_right_shift)
|
||||
self.canvas.itemconfig("inner_line_1", width=inner_corner_radius * 2)
|
||||
|
||||
# create progress parts
|
||||
if not self.canvas.find_withtag("progress_parts"):
|
||||
self.canvas.create_polygon((0, 0, 0, 0), tags=("progress_line_1", "progress_parts"), joinstyle=tkinter.ROUND)
|
||||
self.canvas.tag_raise("progress_parts", "inner_parts")
|
||||
requires_recoloring = True
|
||||
|
||||
if orientation == "w":
|
||||
self.canvas.coords("progress_line_1",
|
||||
border_width + inner_corner_radius,
|
||||
border_width + inner_corner_radius,
|
||||
border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value,
|
||||
border_width + inner_corner_radius,
|
||||
border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value,
|
||||
height - (border_width + inner_corner_radius) + bottom_right_shift,
|
||||
border_width + inner_corner_radius,
|
||||
height - (border_width + inner_corner_radius) + bottom_right_shift)
|
||||
|
||||
elif orientation == "s":
|
||||
self.canvas.coords("progress_line_1",
|
||||
border_width + inner_corner_radius,
|
||||
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value),
|
||||
width - (border_width + inner_corner_radius),
|
||||
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value),
|
||||
width - (border_width + inner_corner_radius),
|
||||
height - (border_width + inner_corner_radius) + bottom_right_shift,
|
||||
border_width + inner_corner_radius,
|
||||
height - (border_width + inner_corner_radius) + bottom_right_shift)
|
||||
|
||||
self.canvas.itemconfig("progress_line_1", width=inner_corner_radius * 2)
|
||||
|
||||
return requires_recoloring
|
||||
|
||||
def _draw_rounded_progress_bar_with_border_font_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int,
|
||||
progress_value: float, orientation: str) -> bool:
|
||||
|
||||
print(width, height, border_width, corner_radius, inner_corner_radius)
|
||||
requires_recoloring = False
|
||||
|
||||
# create border button parts
|
||||
if border_width > 0:
|
||||
if corner_radius > 0:
|
||||
# create canvas border corner parts if not already created
|
||||
if not self.canvas.find_withtag("border_oval_1_a"):
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("border_oval_1_a", "border_corner_part", "border_parts"), anchor=tkinter.CENTER)
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("border_oval_1_b", "border_corner_part", "border_parts"), anchor=tkinter.CENTER, angle=180)
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("border_oval_2_a", "border_corner_part", "border_parts"), anchor=tkinter.CENTER)
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("border_oval_2_b", "border_corner_part", "border_parts"), anchor=tkinter.CENTER, angle=180)
|
||||
self.canvas.tag_lower("border_corner_part")
|
||||
requires_recoloring = True
|
||||
|
||||
if not self.canvas.find_withtag("border_oval_3_a") and round(corner_radius) * 2 < height:
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("border_oval_3_a", "border_corner_part", "border_parts"), anchor=tkinter.CENTER)
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("border_oval_3_b", "border_corner_part", "border_parts"), anchor=tkinter.CENTER, angle=180)
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("border_oval_4_a", "border_corner_part", "border_parts"), anchor=tkinter.CENTER)
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("border_oval_4_b", "border_corner_part", "border_parts"), anchor=tkinter.CENTER, angle=180)
|
||||
self.canvas.tag_lower("border_corner_part")
|
||||
requires_recoloring = True
|
||||
|
||||
elif self.canvas.find_withtag("border_oval_3_a") and not round(corner_radius) * 2 < height:
|
||||
self.canvas.delete(["border_oval_3_a", "border_oval_3_b", "border_oval_4_a", "border_oval_4_b"])
|
||||
|
||||
# change position of border corner parts
|
||||
self.canvas.coords("border_oval_1_a", corner_radius, corner_radius, corner_radius)
|
||||
self.canvas.coords("border_oval_1_b", corner_radius, corner_radius, corner_radius)
|
||||
self.canvas.coords("border_oval_2_a", width - corner_radius, corner_radius, corner_radius)
|
||||
self.canvas.coords("border_oval_2_b", width - corner_radius, corner_radius, corner_radius)
|
||||
self.canvas.coords("border_oval_3_a", width - corner_radius, height - corner_radius, corner_radius)
|
||||
self.canvas.coords("border_oval_3_b", width - corner_radius, height - corner_radius, corner_radius)
|
||||
self.canvas.coords("border_oval_4_a", corner_radius, height - corner_radius, corner_radius)
|
||||
self.canvas.coords("border_oval_4_b", corner_radius, height - corner_radius, corner_radius)
|
||||
|
||||
else:
|
||||
self.canvas.delete("border_corner_part") # delete border corner parts if not needed
|
||||
|
||||
# create canvas border rectangle parts if not already created
|
||||
if not self.canvas.find_withtag("border_rectangle_1"):
|
||||
self.canvas.create_rectangle(0, 0, 0, 0, tags=("border_rectangle_1", "border_rectangle_part", "border_parts"), width=0)
|
||||
self.canvas.create_rectangle(0, 0, 0, 0, tags=("border_rectangle_2", "border_rectangle_part", "border_parts"), width=0)
|
||||
self.canvas.tag_lower("border_rectangle_part")
|
||||
requires_recoloring = True
|
||||
|
||||
# change position of border rectangle parts
|
||||
self.canvas.coords("border_rectangle_1", (0, corner_radius, width, height - corner_radius))
|
||||
self.canvas.coords("border_rectangle_2", (corner_radius, 0, width - corner_radius, height))
|
||||
|
||||
else:
|
||||
self.canvas.delete("border_parts")
|
||||
|
||||
# create inner button parts
|
||||
if inner_corner_radius > 0:
|
||||
|
||||
# create canvas border corner parts if not already created
|
||||
if not self.canvas.find_withtag("inner_oval_1_a"):
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_1_a", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER)
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_1_b", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER, angle=180)
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_2_a", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER)
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_2_b", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER, angle=180)
|
||||
self.canvas.tag_raise("inner_corner_part")
|
||||
requires_recoloring = True
|
||||
|
||||
if not self.canvas.find_withtag("inner_oval_3_a") and round(inner_corner_radius) * 2 < height - (2 * border_width):
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_3_a", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER)
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_3_b", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER, angle=180)
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_4_a", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER)
|
||||
self.canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_4_b", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER, angle=180)
|
||||
self.canvas.tag_raise("inner_corner_part")
|
||||
requires_recoloring = True
|
||||
|
||||
elif self.canvas.find_withtag("inner_oval_3_a") and not round(inner_corner_radius) * 2 < height - (2 * border_width):
|
||||
self.canvas.delete(["inner_oval_3_a", "inner_oval_3_b", "inner_oval_4_a", "inner_oval_4_b"])
|
||||
|
||||
# change position of border corner parts
|
||||
self.canvas.coords("inner_oval_1_a", border_width + inner_corner_radius, border_width + inner_corner_radius, inner_corner_radius)
|
||||
self.canvas.coords("inner_oval_1_b", border_width + inner_corner_radius, border_width + inner_corner_radius, inner_corner_radius)
|
||||
self.canvas.coords("inner_oval_2_a", width - border_width - inner_corner_radius, border_width + inner_corner_radius, inner_corner_radius)
|
||||
self.canvas.coords("inner_oval_2_b", width - border_width - inner_corner_radius, border_width + inner_corner_radius, inner_corner_radius)
|
||||
self.canvas.coords("inner_oval_3_a", width - border_width - inner_corner_radius, height - border_width - inner_corner_radius, inner_corner_radius)
|
||||
self.canvas.coords("inner_oval_3_b", width - border_width - inner_corner_radius, height - border_width - inner_corner_radius, inner_corner_radius)
|
||||
self.canvas.coords("inner_oval_4_a", border_width + inner_corner_radius, height - border_width - inner_corner_radius, inner_corner_radius)
|
||||
self.canvas.coords("inner_oval_4_b", border_width + inner_corner_radius, height - border_width - inner_corner_radius, inner_corner_radius)
|
||||
else:
|
||||
self.canvas.delete("inner_corner_part") # delete inner corner parts if not needed
|
||||
|
||||
# create canvas inner rectangle parts if not already created
|
||||
if not self.canvas.find_withtag("inner_rectangle_1"):
|
||||
self.canvas.create_rectangle(0, 0, 0, 0, tags=("inner_rectangle_1", "inner_rectangle_part", "inner_parts"), width=0)
|
||||
self.canvas.tag_raise("inner_rectangle_part")
|
||||
requires_recoloring = True
|
||||
|
||||
if not self.canvas.find_withtag("inner_rectangle_2") and inner_corner_radius * 2 < height - (border_width * 2):
|
||||
self.canvas.create_rectangle(0, 0, 0, 0, tags=("inner_rectangle_2", "inner_rectangle_part", "inner_parts"), width=0)
|
||||
self.canvas.tag_raise("inner_rectangle_part")
|
||||
requires_recoloring = True
|
||||
|
||||
elif self.canvas.find_withtag("inner_rectangle_2") and not inner_corner_radius * 2 < height - (border_width * 2):
|
||||
self.canvas.delete("inner_rectangle_2")
|
||||
|
||||
# change position of inner rectangle parts
|
||||
self.canvas.coords("inner_rectangle_1", (border_width + inner_corner_radius,
|
||||
border_width,
|
||||
width - border_width - inner_corner_radius,
|
||||
height - border_width))
|
||||
self.canvas.coords("inner_rectangle_2", (border_width,
|
||||
border_width + inner_corner_radius,
|
||||
width - border_width,
|
||||
height - inner_corner_radius - border_width))
|
||||
|
||||
return requires_recoloring
|
||||
|
||||
def _draw_rounded_rect_with_border_circle_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int) -> bool:
|
||||
requires_recoloring = False
|
||||
|
||||
# border button parts
|
||||
if border_width > 0:
|
||||
if corner_radius > 0:
|
||||
|
||||
if not self.canvas.find_withtag("border_oval_1"):
|
||||
self.canvas.create_oval(0, 0, 0, 0, tags=("border_oval_1", "border_corner_part", "border_parts"), width=0)
|
||||
self.canvas.create_oval(0, 0, 0, 0, tags=("border_oval_2", "border_corner_part", "border_parts"), width=0)
|
||||
self.canvas.create_oval(0, 0, 0, 0, tags=("border_oval_3", "border_corner_part", "border_parts"), width=0)
|
||||
self.canvas.create_oval(0, 0, 0, 0, tags=("border_oval_4", "border_corner_part", "border_parts"), width=0)
|
||||
self.canvas.tag_lower("border_parts")
|
||||
requires_recoloring = True
|
||||
|
||||
self.canvas.coords("border_oval_1", 0, 0, corner_radius * 2 - 1, corner_radius * 2 - 1)
|
||||
self.canvas.coords("border_oval_2", width - corner_radius * 2, 0, width - 1, corner_radius * 2 - 1)
|
||||
self.canvas.coords("border_oval_3", 0, height - corner_radius * 2, corner_radius * 2 - 1, height - 1)
|
||||
self.canvas.coords("border_oval_4", width - corner_radius * 2, height - corner_radius * 2, width - 1, height - 1)
|
||||
|
||||
else:
|
||||
self.canvas.delete("border_corner_part")
|
||||
|
||||
if not self.canvas.find_withtag("border_rectangle_1"):
|
||||
self.canvas.create_rectangle(0, 0, 0, 0, tags=("border_rectangle_1", "border_rectangle_part", "border_parts"), width=0)
|
||||
self.canvas.create_rectangle(0, 0, 0, 0, tags=("border_rectangle_2", "border_rectangle_part", "border_parts"), width=0)
|
||||
self.canvas.tag_lower("border_parts")
|
||||
requires_recoloring = True
|
||||
|
||||
self.canvas.coords("border_rectangle_1", (0, corner_radius, width, height - corner_radius))
|
||||
self.canvas.coords("border_rectangle_2", (corner_radius, 0, width - corner_radius, height))
|
||||
|
||||
else:
|
||||
self.canvas.delete("border_parts")
|
||||
|
||||
# inner button parts
|
||||
if inner_corner_radius > 0:
|
||||
|
||||
if not self.canvas.find_withtag("inner_oval_1"):
|
||||
self.canvas.create_oval(0, 0, 0, 0, tags=("inner_oval_1", "inner_corner_part", "inner_parts"), width=0)
|
||||
self.canvas.create_oval(0, 0, 0, 0, tags=("inner_oval_2", "inner_corner_part", "inner_parts"), width=0)
|
||||
self.canvas.create_oval(0, 0, 0, 0, tags=("inner_oval_3", "inner_corner_part", "inner_parts"), width=0)
|
||||
self.canvas.create_oval(0, 0, 0, 0, tags=("inner_oval_4", "inner_corner_part", "inner_parts"), width=0)
|
||||
self.canvas.tag_raise("inner_parts")
|
||||
requires_recoloring = True
|
||||
|
||||
self.canvas.coords("inner_oval_1", (border_width, border_width,
|
||||
border_width + inner_corner_radius * 2 - 1, border_width + inner_corner_radius * 2 - 1))
|
||||
self.canvas.coords("inner_oval_2", (width - border_width - inner_corner_radius * 2, border_width,
|
||||
width - border_width - 1, border_width + inner_corner_radius * 2 - 1))
|
||||
self.canvas.coords("inner_oval_3", (border_width, height - border_width - inner_corner_radius * 2,
|
||||
border_width + inner_corner_radius * 2 - 1, height - border_width - 1))
|
||||
self.canvas.coords("inner_oval_4", (width - border_width - inner_corner_radius * 2, height - border_width - inner_corner_radius * 2,
|
||||
width - border_width - 1, height - border_width - 1))
|
||||
else:
|
||||
self.canvas.delete("inner_corner_part") # delete inner corner parts if not needed
|
||||
|
||||
if not self.canvas.find_withtag("inner_rectangle_1"):
|
||||
self.canvas.create_rectangle(0, 0, 0, 0, tags=("inner_rectangle_1", "inner_rectangle_part", "inner_parts"), width=0)
|
||||
self.canvas.create_rectangle(0, 0, 0, 0, tags=("inner_rectangle_2", "inner_rectangle_part", "inner_parts"), width=0)
|
||||
self.canvas.tag_raise("inner_parts")
|
||||
requires_recoloring = True
|
||||
|
||||
self.canvas.coords("inner_rectangle_1", (border_width + inner_corner_radius,
|
||||
border_width,
|
||||
width - border_width - inner_corner_radius,
|
||||
height - border_width))
|
||||
self.canvas.coords("inner_rectangle_2", (border_width,
|
||||
border_width + inner_corner_radius,
|
||||
width - border_width,
|
||||
height - inner_corner_radius - border_width))
|
||||
|
||||
return requires_recoloring
|
||||
|
||||
def draw_rounded_button(self, canvas, width, height):
|
||||
pass
|
||||
|
@ -20,6 +20,8 @@ class CTkEntry(tkinter.Frame):
|
||||
text_font="default_theme",
|
||||
placeholder_text=None,
|
||||
corner_radius=8,
|
||||
border_width=0,
|
||||
border_color="default_theme",
|
||||
width=120,
|
||||
height=30,
|
||||
**kwargs):
|
||||
@ -55,10 +57,11 @@ class CTkEntry(tkinter.Frame):
|
||||
self.configure_basic_grid()
|
||||
|
||||
self.bg_color = self.detect_color_of_master() if bg_color is None else bg_color
|
||||
self.fg_color = CTkThemeManager.ENTRY_COLOR if fg_color == "default_theme" else fg_color
|
||||
self.text_color = CTkThemeManager.TEXT_COLOR if text_color == "default_theme" else text_color
|
||||
self.placeholder_text_color = CTkThemeManager.PLACEHOLDER_TEXT_COLOR if placeholder_text_color == "default_theme" else placeholder_text_color
|
||||
self.text_font = (CTkThemeManager.TEXT_FONT_NAME, CTkThemeManager.TEXT_FONT_SIZE) if text_font == "default_theme" else text_font
|
||||
self.fg_color = CTkThemeManager.theme["color"]["entry"] if fg_color == "default_theme" else fg_color
|
||||
self.text_color = CTkThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
|
||||
self.placeholder_text_color = CTkThemeManager.theme["color"]["entry_placeholder_text"] if placeholder_text_color == "default_theme" else placeholder_text_color
|
||||
self.text_font = (CTkThemeManager.theme["text"]["font"], CTkThemeManager.theme["text"]["size"]) if text_font == "default_theme" else text_font
|
||||
self.border_color = CTkThemeManager.theme["color"]["entry_border"] if border_color == "default_theme" else border_color
|
||||
|
||||
self.placeholder_text = placeholder_text
|
||||
self.placeholder_text_active = False
|
||||
@ -66,7 +69,8 @@ class CTkEntry(tkinter.Frame):
|
||||
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.corner_radius = corner_radius
|
||||
self.corner_radius = CTkThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius
|
||||
self.border_width = CTkThemeManager.theme["shape"]["entry_border_width"] if border_width == "default_theme" else border_width
|
||||
|
||||
if self.corner_radius*2 > self.height:
|
||||
self.corner_radius = self.height/2
|
||||
@ -150,12 +154,16 @@ class CTkEntry(tkinter.Frame):
|
||||
fg=CTkThemeManager.single_color(self.text_color, self.appearance_mode),
|
||||
insertbackground=CTkThemeManager.single_color(self.text_color, self.appearance_mode))
|
||||
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width, self.height, self.corner_radius, 0)
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width, self.height, self.corner_radius, self.border_width)
|
||||
|
||||
self.canvas.itemconfig("inner_parts",
|
||||
fill=CTkThemeManager.single_color(self.fg_color, self.appearance_mode),
|
||||
outline=CTkThemeManager.single_color(self.fg_color, self.appearance_mode))
|
||||
|
||||
self.canvas.itemconfig("border_parts",
|
||||
fill=CTkThemeManager.single_color(self.border_color, self.appearance_mode),
|
||||
outline=CTkThemeManager.single_color(self.border_color, self.appearance_mode))
|
||||
|
||||
def bind(self, *args, **kwargs):
|
||||
self.entry.bind(*args, **kwargs)
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import tkinter
|
||||
import sys
|
||||
|
||||
from .customtkinter_tk import CTk
|
||||
from .appearance_mode_tracker import AppearanceModeTracker
|
||||
@ -14,8 +13,8 @@ class CTkFrame(tkinter.Frame):
|
||||
bg_color=None,
|
||||
fg_color="default_theme",
|
||||
border_color="default_theme",
|
||||
border_width=0,
|
||||
corner_radius=10,
|
||||
border_width="default_theme",
|
||||
corner_radius="default_theme",
|
||||
width=200,
|
||||
height=200,
|
||||
**kwargs):
|
||||
@ -46,16 +45,16 @@ class CTkFrame(tkinter.Frame):
|
||||
self.appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark"
|
||||
|
||||
self.bg_color = self.detect_color_of_master() if bg_color is None else bg_color
|
||||
self.border_color = CTkThemeManager.CHECKBOX_LINES_COLOR if border_color == "default_theme" else border_color
|
||||
self.border_color = CTkThemeManager.theme["color"]["frame_border"] if border_color == "default_theme" else border_color
|
||||
|
||||
if fg_color == "default_theme":
|
||||
if isinstance(self.master, CTkFrame):
|
||||
if self.master.fg_color == CTkThemeManager.FRAME_COLOR:
|
||||
self.fg_color = CTkThemeManager.FRAME_2_COLOR
|
||||
if self.master.fg_color == CTkThemeManager.theme["color"]["frame_low"]:
|
||||
self.fg_color = CTkThemeManager.theme["color"]["frame_high"]
|
||||
else:
|
||||
self.fg_color = CTkThemeManager.FRAME_COLOR
|
||||
self.fg_color = CTkThemeManager.theme["color"]["frame_low"]
|
||||
else:
|
||||
self.fg_color = CTkThemeManager.FRAME_COLOR
|
||||
self.fg_color = CTkThemeManager.theme["color"]["frame_low"]
|
||||
else:
|
||||
self.fg_color = fg_color
|
||||
|
||||
@ -63,8 +62,8 @@ class CTkFrame(tkinter.Frame):
|
||||
self.height = height
|
||||
self.configure(width=self.width, height=self.height)
|
||||
|
||||
self.corner_radius = corner_radius
|
||||
self.border_width = border_width
|
||||
self.corner_radius = CTkThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius
|
||||
self.border_width = CTkThemeManager.theme["shape"]["frame_border_width"] if border_width == "default_theme" else border_width
|
||||
|
||||
if self.corner_radius * 2 > self.height:
|
||||
self.corner_radius = self.height / 2
|
||||
@ -138,7 +137,7 @@ class CTkFrame(tkinter.Frame):
|
||||
from .customtkinter_progressbar import CTkProgressBar
|
||||
from .customtkinter_label import CTkLabel
|
||||
from .customtkinter_entry import CTkEntry
|
||||
from .customtkinter_checkbox import CTkCheckBox
|
||||
from customtkinter.customtkinter_checkbox import CTkCheckBox
|
||||
from .customtkinter_button import CTkButton
|
||||
|
||||
for child in self.winfo_children():
|
||||
|
@ -16,7 +16,7 @@ class CTkLabel(tkinter.Frame):
|
||||
bg_color=None,
|
||||
fg_color="default_theme",
|
||||
text_color="default_theme",
|
||||
corner_radius=8,
|
||||
corner_radius="default_theme",
|
||||
width=120,
|
||||
height=25,
|
||||
text="CTkLabel",
|
||||
@ -52,14 +52,14 @@ class CTkLabel(tkinter.Frame):
|
||||
self.appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark"
|
||||
|
||||
self.bg_color = self.detect_color_of_master() if bg_color is None else bg_color
|
||||
self.fg_color = CTkThemeManager.LABEL_BG_COLOR if fg_color == "default_theme" else fg_color
|
||||
self.fg_color = CTkThemeManager.theme["color"]["label"] if fg_color == "default_theme" else fg_color
|
||||
if self.fg_color is None:
|
||||
self.fg_color = self.bg_color
|
||||
self.text_color = CTkThemeManager.TEXT_COLOR if text_color == "default_theme" else text_color
|
||||
self.text_color = CTkThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
|
||||
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.corner_radius = corner_radius
|
||||
self.corner_radius = CTkThemeManager.theme["shape"]["label_corner_radius"] if corner_radius == "default_theme" else corner_radius
|
||||
|
||||
if self.corner_radius * 2 > self.height:
|
||||
self.corner_radius = self.height / 2
|
||||
@ -67,7 +67,7 @@ class CTkLabel(tkinter.Frame):
|
||||
self.corner_radius = self.width / 2
|
||||
|
||||
self.text = text
|
||||
self.text_font = (CTkThemeManager.TEXT_FONT_NAME, CTkThemeManager.TEXT_FONT_SIZE) if text_font == "default_theme" else text_font
|
||||
self.text_font = (CTkThemeManager.theme["text"]["font"], CTkThemeManager.theme["text"]["size"]) if text_font == "default_theme" else text_font
|
||||
|
||||
self.canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
|
@ -5,6 +5,9 @@ from .customtkinter_tk import CTk
|
||||
from .customtkinter_frame import CTkFrame
|
||||
from .appearance_mode_tracker import AppearanceModeTracker
|
||||
from .customtkinter_theme_manager import CTkThemeManager
|
||||
from .customtkinter_canvas import CTkCanvas
|
||||
from .customtkinter_draw_engine import DrawEngine
|
||||
from .customtkinter_settings import CTkSettings
|
||||
|
||||
|
||||
class CTkProgressBar(tkinter.Frame):
|
||||
@ -16,9 +19,10 @@ class CTkProgressBar(tkinter.Frame):
|
||||
border_color="default_theme",
|
||||
fg_color="default_theme",
|
||||
progress_color="default_theme",
|
||||
width=160,
|
||||
height=10,
|
||||
border_width=0,
|
||||
corner_radius="default_theme",
|
||||
width=200,
|
||||
height=16,
|
||||
border_width="default_theme",
|
||||
**kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@ -47,26 +51,29 @@ class CTkProgressBar(tkinter.Frame):
|
||||
self.appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark"
|
||||
|
||||
self.bg_color = self.detect_color_of_master() if bg_color is None else bg_color
|
||||
self.border_color = CTkThemeManager.PROGRESS_BG_COLOR if border_color == "default_theme" else border_color
|
||||
self.fg_color = CTkThemeManager.PROGRESS_BG_COLOR if fg_color == "default_theme" else fg_color
|
||||
self.progress_color = CTkThemeManager.MAIN_COLOR if progress_color == "default_theme" else progress_color
|
||||
self.border_color = CTkThemeManager.theme["color"]["progressbar_border"] if border_color == "default_theme" else border_color
|
||||
self.fg_color = CTkThemeManager.theme["color"]["progressbar"] if fg_color == "default_theme" else fg_color
|
||||
self.progress_color = CTkThemeManager.theme["color"]["progressbar_progress"] if progress_color == "default_theme" else progress_color
|
||||
|
||||
self.variable = variable
|
||||
self.variable_callback_blocked = False
|
||||
self.variabel_callback_name = None
|
||||
self.variable_callback_name = None
|
||||
|
||||
self.width = width
|
||||
self.height = self.calc_optimal_height(height)
|
||||
self.border_width = round(border_width)
|
||||
self.height = height
|
||||
self.corner_radius = CTkThemeManager.theme["shape"]["progressbar_corner_radius"] if corner_radius == "default_theme" else corner_radius
|
||||
self.border_width = CTkThemeManager.theme["shape"]["progressbar_border_width"] if border_width == "default_theme" else border_width
|
||||
self.value = 0.5
|
||||
|
||||
self.configure(width=self.width, height=self.height)
|
||||
|
||||
self.canvas = tkinter.Canvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width,
|
||||
height=self.height)
|
||||
self.canvas.place(x=0, y=0)
|
||||
self.canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width,
|
||||
height=self.height)
|
||||
self.canvas.place(x=0, y=0, relwidth=1, relheight=1)
|
||||
|
||||
self.draw_engine = DrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
|
||||
|
||||
# Each time an item is resized due to pack position mode, the binding Configure is called on the widget
|
||||
self.bind('<Configure>', self.update_dimensions)
|
||||
@ -74,7 +81,7 @@ class CTkProgressBar(tkinter.Frame):
|
||||
self.draw() # initial draw
|
||||
|
||||
if self.variable is not None:
|
||||
self.variabel_callback_name = self.variable.trace_add("write", self.variable_callback)
|
||||
self.variable_callback_name = self.variable.trace_add("write", self.variable_callback)
|
||||
self.variable_callback_blocked = True
|
||||
self.set(self.variable.get(), from_variable_callback=True)
|
||||
self.variable_callback_blocked = False
|
||||
@ -83,7 +90,7 @@ class CTkProgressBar(tkinter.Frame):
|
||||
AppearanceModeTracker.remove(self.change_appearance_mode)
|
||||
|
||||
if self.variable is not None:
|
||||
self.variable.trace_remove("write", self.variabel_callback_name)
|
||||
self.variable.trace_remove("write", self.variable_callback_name)
|
||||
|
||||
super().destroy()
|
||||
|
||||
@ -117,18 +124,26 @@ class CTkProgressBar(tkinter.Frame):
|
||||
def draw(self, no_color_updates=False):
|
||||
|
||||
# decide the drawing method
|
||||
if sys.platform == "darwin":
|
||||
# on macOS draw button with polygons (positions are more accurate, macOS has Antialiasing)
|
||||
self.draw_with_polygon_shapes()
|
||||
else:
|
||||
# on Windows and other draw with ovals (corner_radius can be optimised to look better than with polygons)
|
||||
self.draw_with_ovals_and_rects()
|
||||
#if sys.platform == "darwin":
|
||||
# # on macOS draw button with polygons (positions are more accurate, macOS has Antialiasing)
|
||||
# self.draw_with_polygon_shapes()
|
||||
#else:
|
||||
# # on Windows and other draw with ovals (corner_radius can be optimised to look better than with polygons)
|
||||
#self.draw_with_ovals_and_rects()
|
||||
|
||||
if no_color_updates is False:
|
||||
requires_recoloring = self.draw_engine.draw_rounded_progress_bar_with_border(self.width, self.height, self.corner_radius, self.border_width, self.value, "w")
|
||||
|
||||
if no_color_updates is False or requires_recoloring:
|
||||
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
|
||||
self.canvas.itemconfig("border_parts", fill=CTkThemeManager.single_color(self.border_color, self.appearance_mode))
|
||||
self.canvas.itemconfig("inner_parts", fill=CTkThemeManager.single_color(self.fg_color, self.appearance_mode))
|
||||
self.canvas.itemconfig("progress_parts", fill=CTkThemeManager.single_color(self.progress_color, self.appearance_mode))
|
||||
self.canvas.itemconfig("border_parts",
|
||||
fill=CTkThemeManager.single_color(self.border_color, self.appearance_mode),
|
||||
outline=CTkThemeManager.single_color(self.border_color, self.appearance_mode))
|
||||
self.canvas.itemconfig("inner_parts",
|
||||
fill=CTkThemeManager.single_color(self.fg_color, self.appearance_mode),
|
||||
outline=CTkThemeManager.single_color(self.fg_color, self.appearance_mode))
|
||||
self.canvas.itemconfig("progress_parts",
|
||||
fill=CTkThemeManager.single_color(self.progress_color, self.appearance_mode),
|
||||
outline=CTkThemeManager.single_color(self.progress_color, self.appearance_mode))
|
||||
|
||||
def draw_with_polygon_shapes(self):
|
||||
""" draw the progress bar parts with just three polygons that have a rounded border """
|
||||
@ -277,12 +292,12 @@ class CTkProgressBar(tkinter.Frame):
|
||||
|
||||
if "variable" in kwargs:
|
||||
if self.variable is not None:
|
||||
self.variable.trace_remove("write", self.variabel_callback_name)
|
||||
self.variable.trace_remove("write", self.variable_callback_name)
|
||||
|
||||
self.variable = kwargs["variable"]
|
||||
|
||||
if self.variable is not None and self.variable != "":
|
||||
self.variabel_callback_name = self.variable.trace_add("write", self.variable_callback)
|
||||
self.variable_callback_name = self.variable.trace_add("write", self.variable_callback)
|
||||
self.set(self.variable.get(), from_variable_callback=True)
|
||||
else:
|
||||
self.variable = None
|
||||
|
@ -22,7 +22,8 @@ class CTkSlider(tkinter.Frame):
|
||||
number_of_steps=None,
|
||||
width=160,
|
||||
height=16,
|
||||
border_width=5,
|
||||
corner_radius="default_theme",
|
||||
border_width="default_theme",
|
||||
command=None,
|
||||
variable=None,
|
||||
**kwargs):
|
||||
@ -56,14 +57,15 @@ class CTkSlider(tkinter.Frame):
|
||||
|
||||
self.bg_color = self.detect_color_of_master() if bg_color is None else bg_color
|
||||
self.border_color = border_color
|
||||
self.fg_color = CTkThemeManager.SLIDER_BG_COLOR if fg_color == "default_theme" else fg_color
|
||||
self.progress_color = CTkThemeManager.SLIDER_PROGRESS_COLOR if progress_color == "default_theme" else progress_color
|
||||
self.button_color = CTkThemeManager.MAIN_COLOR if button_color == "default_theme" else button_color
|
||||
self.button_hover_color = CTkThemeManager.MAIN_HOVER_COLOR if button_hover_color == "default_theme" else button_hover_color
|
||||
self.fg_color = CTkThemeManager.theme["color"]["slider"] if fg_color == "default_theme" else fg_color
|
||||
self.progress_color = CTkThemeManager.theme["color"]["slider_progress"] if progress_color == "default_theme" else progress_color
|
||||
self.button_color = CTkThemeManager.theme["color"]["slider_button"] if button_color == "default_theme" else button_color
|
||||
self.button_hover_color = CTkThemeManager.theme["color"]["slider_button_hover"] if button_hover_color == "default_theme" else button_hover_color
|
||||
|
||||
self.width = width
|
||||
self.height = self.calc_optimal_height(height)
|
||||
self.border_width = round(border_width)
|
||||
self.corner_radius = CTkThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius
|
||||
self.border_width = CTkThemeManager.theme["shape"]["slider_border_width"] if border_width == "default_theme" else border_width
|
||||
self.value = 0.5 # initial value of slider in percent
|
||||
self.hover_state = False
|
||||
self.from_ = from_
|
||||
@ -74,7 +76,7 @@ class CTkSlider(tkinter.Frame):
|
||||
self.callback_function = command
|
||||
self.variable: tkinter.Variable = variable
|
||||
self.variable_callback_blocked = False
|
||||
self.variabel_callback_name = None
|
||||
self.variable_callback_name = None
|
||||
|
||||
self.configure(width=self.width, height=self.height)
|
||||
if sys.platform == "darwin":
|
||||
@ -97,7 +99,7 @@ class CTkSlider(tkinter.Frame):
|
||||
self.draw() # initial draw
|
||||
|
||||
if self.variable is not None:
|
||||
self.variabel_callback_name = self.variable.trace_add("write", self.variable_callback)
|
||||
self.variable_callback_name = self.variable.trace_add("write", self.variable_callback)
|
||||
self.variable_callback_blocked = True
|
||||
self.set(self.variable.get(), from_variable_callback=True)
|
||||
self.variable_callback_blocked = False
|
||||
@ -106,9 +108,9 @@ class CTkSlider(tkinter.Frame):
|
||||
# remove change_appearance_mode function from callback list of AppearanceModeTracker
|
||||
AppearanceModeTracker.remove(self.change_appearance_mode)
|
||||
|
||||
# remove variabel_callback from variable callbacks if variable exists
|
||||
# remove variable_callback from variable callbacks if variable exists
|
||||
if self.variable is not None:
|
||||
self.variable.trace_remove("write", self.variabel_callback_name)
|
||||
self.variable.trace_remove("write", self.variable_callback_name)
|
||||
|
||||
super().destroy()
|
||||
|
||||
@ -444,12 +446,12 @@ class CTkSlider(tkinter.Frame):
|
||||
|
||||
if "variable" in kwargs:
|
||||
if self.variable is not None:
|
||||
self.variable.trace_remove("write", self.variabel_callback_name)
|
||||
self.variable.trace_remove("write", self.variable_callback_name)
|
||||
|
||||
self.variable = kwargs["variable"]
|
||||
|
||||
if self.variable is not None and self.variable != "":
|
||||
self.variabel_callback_name = self.variable.trace_add("write", self.variable_callback)
|
||||
self.variable_callback_name = self.variable.trace_add("write", self.variable_callback)
|
||||
self.set(self.variable.get(), from_variable_callback=True)
|
||||
else:
|
||||
self.variable = None
|
||||
|
@ -1,25 +1,30 @@
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
|
||||
|
||||
class CTkThemeManager:
|
||||
|
||||
TEXT_FONT_NAME = None
|
||||
TEXT_FONT_SIZE = None
|
||||
theme = {} # contains all the theme data
|
||||
built_in_themes = ["blue", "green", "dark_blue"]
|
||||
|
||||
WINDOW_BG_COLOR = None
|
||||
MAIN_COLOR = None
|
||||
MAIN_HOVER_COLOR = None
|
||||
ENTRY_COLOR = None
|
||||
TEXT_COLOR = None
|
||||
PLACEHOLDER_TEXT_COLOR = None
|
||||
LABEL_BG_COLOR = None
|
||||
SLIDER_BG_COLOR = None
|
||||
SLIDER_PROGRESS_COLOR = None
|
||||
PROGRESS_BG_COLOR = None
|
||||
FRAME_COLOR = None
|
||||
FRAME_2_COLOR = None
|
||||
CHECKBOX_LINES_COLOR = None
|
||||
DARKEN_COLOR_FACTOR = None
|
||||
@classmethod
|
||||
def load_theme(cls, theme_name_or_path: str):
|
||||
script_directory = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
if theme_name_or_path in cls.built_in_themes:
|
||||
with open(os.path.join(script_directory, "assets", "themes", f"{theme_name_or_path}.json"), "r") as f:
|
||||
cls.theme = json.load(f)
|
||||
else:
|
||||
with open(theme_name_or_path, "r") as f:
|
||||
cls.theme = json.load(f)
|
||||
|
||||
if sys.platform == "darwin":
|
||||
cls.theme["text"] = cls.theme["text"]["macOS"]
|
||||
elif sys.platform.startswith("win"):
|
||||
cls.theme["text"] = cls.theme["text"]["Windows"]
|
||||
else:
|
||||
cls.theme["text"] = cls.theme["text"]["Linux"]
|
||||
|
||||
@classmethod
|
||||
def initialize_color_theme(cls, theme_name):
|
||||
@ -37,7 +42,8 @@ class CTkThemeManager:
|
||||
cls.WINDOW_BG_COLOR = ("#ECECEC", "#323232") # macOS standard light and dark window bg colors
|
||||
cls.MAIN_COLOR = ("#64A1D2", "#1C94CF")
|
||||
cls.MAIN_HOVER_COLOR = ("#A7C2E0", "#5FB4DD")
|
||||
cls.ENTRY_COLOR = ("white", "#222222")
|
||||
cls.ENTRY_COLOR = ("gray95", "#222222")
|
||||
cls.ENTRY_BORDER_COLOR = ("gray65", "gray40")
|
||||
cls.TEXT_COLOR = ("black", "white")
|
||||
cls.PLACEHOLDER_TEXT_COLOR = ("gray52", "gray62")
|
||||
cls.LABEL_BG_COLOR = ("white", "#626061")
|
||||
@ -87,7 +93,7 @@ class CTkThemeManager:
|
||||
tuple color with (light_color, dark_color). The functions then returns
|
||||
always a single color string """
|
||||
|
||||
if type(color) == tuple:
|
||||
if type(color) == tuple or type(color) == list:
|
||||
return color[appearance_mode]
|
||||
else:
|
||||
return color
|
||||
@ -138,4 +144,4 @@ class CTkThemeManager:
|
||||
cls.MAIN_HOVER_COLOR = main_color_hover
|
||||
|
||||
|
||||
CTkThemeManager.initialize_color_theme("blue")
|
||||
CTkThemeManager.load_theme("blue")
|
||||
|
@ -101,7 +101,7 @@ class CTk(tkinter.Tk):
|
||||
from .customtkinter_label import CTkLabel
|
||||
from .customtkinter_frame import CTkFrame
|
||||
from .customtkinter_entry import CTkEntry
|
||||
from .customtkinter_checkbox import CTkCheckBox
|
||||
from customtkinter.customtkinter_checkbox import CTkCheckBox
|
||||
from .customtkinter_button import CTkButton
|
||||
|
||||
for child in self.winfo_children():
|
||||
|
@ -87,7 +87,7 @@ class CTkToplevel(tkinter.Toplevel):
|
||||
from .customtkinter_label import CTkLabel
|
||||
from .customtkinter_frame import CTkFrame
|
||||
from .customtkinter_entry import CTkEntry
|
||||
from .customtkinter_checkbox import CTkCheckBox
|
||||
from customtkinter.customtkinter_checkbox import CTkCheckBox
|
||||
from .customtkinter_button import CTkButton
|
||||
|
||||
for child in self.winfo_children():
|
||||
|
@ -4,7 +4,7 @@ import customtkinter
|
||||
import sys
|
||||
|
||||
customtkinter.set_appearance_mode("Light") # Modes: "System" (standard), "Dark", "Light"
|
||||
customtkinter.set_default_color_theme("dark-blue") # Themes: "blue" (standard), "green", "dark-blue"
|
||||
customtkinter.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue"
|
||||
|
||||
customtkinter.CTkSettings.preferred_drawing_method = "font_shapes"
|
||||
|
||||
@ -38,8 +38,6 @@ class App(customtkinter.CTk):
|
||||
self.frame_right = customtkinter.CTkFrame(master=self,
|
||||
width=420,
|
||||
height=App.HEIGHT-40,
|
||||
border_width=0,
|
||||
border_color=customtkinter.CTkThemeManager.MAIN_COLOR,
|
||||
corner_radius=12)
|
||||
self.frame_right.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)
|
||||
|
||||
@ -95,8 +93,7 @@ class App(customtkinter.CTk):
|
||||
|
||||
self.frame_info = customtkinter.CTkFrame(master=self.frame_right,
|
||||
width=380,
|
||||
height=200,
|
||||
corner_radius=10)
|
||||
height=200)
|
||||
self.frame_info.grid(row=0, column=0, columnspan=3, pady=20, padx=20, sticky="wens")
|
||||
|
||||
# ============ frame_right -> frame_info ============
|
||||
@ -108,22 +105,18 @@ class App(customtkinter.CTk):
|
||||
"invidunt ut labore",
|
||||
width=250,
|
||||
height=100,
|
||||
corner_radius=8,
|
||||
fg_color=("white", "gray38"), # <- custom tuple-color
|
||||
justify=tkinter.LEFT)
|
||||
self.label_info_1.place(relx=0.5, rely=0.15, anchor=tkinter.N)
|
||||
|
||||
self.progressbar = customtkinter.CTkProgressBar(master=self.frame_info,
|
||||
width=250,
|
||||
height=12)
|
||||
self.progressbar = customtkinter.CTkProgressBar(master=self.frame_info)
|
||||
self.progressbar.place(relx=0.5, rely=0.85, anchor=tkinter.S)
|
||||
self.progressbar.set(0.65)
|
||||
|
||||
# ============ frame_right <- ============
|
||||
|
||||
self.slider_1 = customtkinter.CTkSlider(master=self.frame_right,
|
||||
height=16,
|
||||
border_width=5,
|
||||
border_width=0,
|
||||
from_=1,
|
||||
to=0,
|
||||
number_of_steps=3,
|
||||
@ -134,7 +127,6 @@ class App(customtkinter.CTk):
|
||||
self.slider_2 = customtkinter.CTkSlider(master=self.frame_right,
|
||||
width=160,
|
||||
height=16,
|
||||
border_width=5,
|
||||
command=self.progressbar.set)
|
||||
self.slider_2.grid(row=2, column=0, columnspan=2, pady=10, padx=20, sticky="we")
|
||||
self.slider_2.set(0.7)
|
||||
@ -157,8 +149,9 @@ class App(customtkinter.CTk):
|
||||
|
||||
self.entry = customtkinter.CTkEntry(master=self.frame_right,
|
||||
width=120,
|
||||
height=25,
|
||||
corner_radius=8,
|
||||
height=30,
|
||||
corner_radius=10,
|
||||
border_width=2,
|
||||
placeholder_text="CTkEntry")
|
||||
self.entry.grid(row=4, column=0, columnspan=2, pady=20, padx=20, sticky="we")
|
||||
|
||||
@ -172,6 +165,8 @@ class App(customtkinter.CTk):
|
||||
corner_radius=13)
|
||||
self.button_5.grid(row=4, column=2, columnspan=1, pady=20, padx=20, sticky="we")
|
||||
|
||||
self.progressbar.set(0.2)
|
||||
|
||||
def button_event(self):
|
||||
print("Button pressed")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user