mirror of
https://github.com/TomSchimansky/CustomTkinter.git
synced 2023-08-10 21:13:13 +03:00
completed scaling
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
import tkinter
|
||||
import sys
|
||||
import math
|
||||
|
||||
from .ctk_canvas import CTkCanvas
|
||||
from ..theme_manager import CTkThemeManager
|
||||
@ -65,8 +66,8 @@ class CTkButton(CTkBaseClass):
|
||||
|
||||
self.canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width * self.scaling,
|
||||
height=self.height * self.scaling)
|
||||
width=self.apply_widget_scaling(self.desired_width),
|
||||
height=self.apply_widget_scaling(self.desired_height))
|
||||
self.canvas.grid(row=0, column=0, rowspan=2, columnspan=2, sticky="nsew")
|
||||
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
|
||||
|
||||
@ -87,11 +88,24 @@ class CTkButton(CTkBaseClass):
|
||||
self.grid_rowconfigure(1, weight=1)
|
||||
self.grid_columnconfigure(1, weight=1)
|
||||
|
||||
def set_scaling(self, *args, **kwargs):
|
||||
super().set_scaling( *args, **kwargs)
|
||||
|
||||
if self.text_label is not None:
|
||||
self.text_label.destroy()
|
||||
self.text_label = None
|
||||
if self.image_label is not None:
|
||||
self.image_label.destroy()
|
||||
self.image_label = None
|
||||
|
||||
self.canvas.configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
self.draw()
|
||||
|
||||
def draw(self, no_color_updates=False):
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width * self.scaling,
|
||||
self.height * self.scaling,
|
||||
self.corner_radius * self.scaling,
|
||||
self.border_width * self.scaling)
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.apply_widget_scaling(self.current_width),
|
||||
self.apply_widget_scaling(self.current_height),
|
||||
self.apply_widget_scaling(self.corner_radius),
|
||||
self.apply_widget_scaling(self.border_width))
|
||||
|
||||
if no_color_updates is False or requires_recoloring:
|
||||
|
||||
@ -175,35 +189,35 @@ class CTkButton(CTkBaseClass):
|
||||
|
||||
# create grid layout with just an image given
|
||||
if self.image_label is not None and self.text_label is None:
|
||||
self.image_label.grid(row=0, column=0, rowspan=2, columnspan=2, sticky="", pady=self.border_width * self.scaling)
|
||||
self.image_label.grid(row=0, column=0, rowspan=2, columnspan=2, sticky="", pady=self.apply_widget_scaling(self.border_width))
|
||||
|
||||
# create grid layout with just text given
|
||||
if self.image_label is None and self.text_label is not None:
|
||||
self.text_label.grid(row=0, column=0, rowspan=2, columnspan=2, sticky="",
|
||||
padx=self.corner_radius * self.scaling, pady=self.border_width * self.scaling)
|
||||
padx=self.apply_widget_scaling(self.corner_radius), pady=self.apply_widget_scaling(self.border_width) + 1)
|
||||
|
||||
# create grid layout of image and text label in 2x2 grid system with given compound
|
||||
if self.image_label is not None and self.text_label is not None:
|
||||
if self.compound == tkinter.LEFT or self.compound == "left":
|
||||
self.image_label.grid(row=0, column=0, sticky="e", rowspan=2, columnspan=1,
|
||||
padx=(max(self.corner_radius * self.scaling, self.border_width * self.scaling), 2), pady=self.border_width * self.scaling)
|
||||
padx=(max(self.apply_widget_scaling(self.corner_radius), self.apply_widget_scaling(self.border_width)), 2), pady=self.apply_widget_scaling(self.border_width))
|
||||
self.text_label.grid(row=0, column=1, sticky="w", rowspan=2, columnspan=1,
|
||||
padx=(2, max(self.corner_radius * self.scaling, self.border_width * self.scaling)), pady=self.border_width * self.scaling)
|
||||
padx=(2, max(self.apply_widget_scaling(self.corner_radius), self.apply_widget_scaling(self.border_width))), pady=self.apply_widget_scaling(self.border_width))
|
||||
elif self.compound == tkinter.TOP or self.compound == "top":
|
||||
self.image_label.grid(row=0, column=0, sticky="s", columnspan=2, rowspan=1,
|
||||
padx=max(self.corner_radius * self.scaling, self.border_width * self.scaling), pady=(self.border_width * self.scaling, 2))
|
||||
padx=max(self.apply_widget_scaling(self.corner_radius), self.apply_widget_scaling(self.border_width)), pady=(self.apply_widget_scaling(self.border_width), 2))
|
||||
self.text_label.grid(row=1, column=0, sticky="n", columnspan=2, rowspan=1,
|
||||
padx=max(self.corner_radius * self.scaling, self.border_width * self.scaling), pady=(2, self.border_width * self.scaling))
|
||||
padx=max(self.apply_widget_scaling(self.corner_radius), self.apply_widget_scaling(self.border_width)), pady=(2, self.apply_widget_scaling(self.border_width)))
|
||||
elif self.compound == tkinter.RIGHT or self.compound == "right":
|
||||
self.image_label.grid(row=0, column=1, sticky="w", rowspan=2, columnspan=1,
|
||||
padx=(2, max(self.corner_radius * self.scaling, self.border_width * self.scaling)), pady=self.border_width * self.scaling)
|
||||
padx=(2, max(self.apply_widget_scaling(self.corner_radius), self.apply_widget_scaling(self.border_width))), pady=self.apply_widget_scaling(self.border_width))
|
||||
self.text_label.grid(row=0, column=0, sticky="e", rowspan=2, columnspan=1,
|
||||
padx=(max(self.corner_radius * self.scaling, self.border_width * self.scaling), 2), pady=self.border_width * self.scaling)
|
||||
padx=(max(self.apply_widget_scaling(self.corner_radius), self.apply_widget_scaling(self.border_width)), 2), pady=self.apply_widget_scaling(self.border_width))
|
||||
elif self.compound == tkinter.BOTTOM or self.compound == "bottom":
|
||||
self.image_label.grid(row=1, column=0, sticky="n", columnspan=2, rowspan=1,
|
||||
padx=max(self.corner_radius * self.scaling, self.border_width * self.scaling), pady=(2, self.border_width * self.scaling))
|
||||
padx=max(self.apply_widget_scaling(self.corner_radius), self.apply_widget_scaling(self.border_width)), pady=(2, self.apply_widget_scaling(self.border_width)))
|
||||
self.text_label.grid(row=0, column=0, sticky="s", columnspan=2, rowspan=1,
|
||||
padx=max(self.corner_radius * self.scaling, self.border_width * self.scaling), pady=(self.border_width * self.scaling, 2))
|
||||
padx=max(self.apply_widget_scaling(self.corner_radius), self.apply_widget_scaling(self.border_width)), pady=(self.apply_widget_scaling(self.border_width), 2))
|
||||
|
||||
def configure(self, *args, **kwargs):
|
||||
require_redraw = False # some attribute changes require a call of self.draw() at the end
|
||||
@ -271,17 +285,18 @@ class CTkButton(CTkBaseClass):
|
||||
self.draw()
|
||||
|
||||
def set_cursor(self):
|
||||
if self.state == tkinter.DISABLED:
|
||||
if sys.platform == "darwin" and self.function is not None and CTkSettings.hand_cursor_enabled:
|
||||
self.configure(cursor="arrow")
|
||||
elif sys.platform.startswith("win") and self.function is not None and CTkSettings.hand_cursor_enabled:
|
||||
self.configure(cursor="arrow")
|
||||
if CTkSettings.cursor_manipulation_enabled:
|
||||
if self.state == tkinter.DISABLED:
|
||||
if sys.platform == "darwin" and self.function is not None and CTkSettings.cursor_manipulation_enabled:
|
||||
self.configure(cursor="arrow")
|
||||
elif sys.platform.startswith("win") and self.function is not None and CTkSettings.cursor_manipulation_enabled:
|
||||
self.configure(cursor="arrow")
|
||||
|
||||
elif self.state == tkinter.NORMAL:
|
||||
if sys.platform == "darwin" and self.function is not None and CTkSettings.hand_cursor_enabled:
|
||||
self.configure(cursor="pointinghand")
|
||||
elif sys.platform.startswith("win") and self.function is not None and CTkSettings.hand_cursor_enabled:
|
||||
self.configure(cursor="hand2")
|
||||
elif self.state == tkinter.NORMAL:
|
||||
if sys.platform == "darwin" and self.function is not None and CTkSettings.cursor_manipulation_enabled:
|
||||
self.configure(cursor="pointinghand")
|
||||
elif sys.platform.startswith("win") and self.function is not None and CTkSettings.cursor_manipulation_enabled:
|
||||
self.configure(cursor="hand2")
|
||||
|
||||
def set_text(self, text):
|
||||
self.text = text
|
||||
|
@ -68,20 +68,20 @@ class CTkCheckBox(CTkBaseClass):
|
||||
|
||||
# configure grid system (1x3)
|
||||
self.grid_columnconfigure(0, weight=0)
|
||||
self.grid_columnconfigure(1, weight=0, minsize=6 * self.scaling)
|
||||
self.grid_columnconfigure(1, weight=0, minsize=self.apply_widget_scaling(6))
|
||||
self.grid_columnconfigure(2, weight=1)
|
||||
self.grid_rowconfigure(0, weight=1)
|
||||
|
||||
self.bg_canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width * self.scaling,
|
||||
height=self.height * self.scaling)
|
||||
width=self.apply_widget_scaling(self.desired_width),
|
||||
height=self.apply_widget_scaling(self.desired_height))
|
||||
self.bg_canvas.grid(row=0, column=0, padx=0, pady=0, columnspan=3, rowspan=1, sticky="nswe")
|
||||
|
||||
self.canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width * self.scaling,
|
||||
height=self.height * self.scaling)
|
||||
width=self.apply_widget_scaling(self.desired_width),
|
||||
height=self.apply_widget_scaling(self.desired_height))
|
||||
self.canvas.grid(row=0, column=0, padx=0, pady=0, columnspan=1, rowspan=1)
|
||||
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
|
||||
|
||||
@ -103,6 +103,16 @@ class CTkCheckBox(CTkBaseClass):
|
||||
self.set_cursor()
|
||||
self.draw() # initial draw
|
||||
|
||||
def set_scaling(self, *args, **kwargs):
|
||||
super().set_scaling(*args, **kwargs)
|
||||
|
||||
self.grid_columnconfigure(1, weight=0, minsize=self.apply_widget_scaling(6))
|
||||
self.text_label.configure(font=self.apply_font_scaling(self.text_font))
|
||||
|
||||
self.bg_canvas.configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
self.canvas.configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
self.draw()
|
||||
|
||||
def destroy(self):
|
||||
if self.variable is not None:
|
||||
self.variable.trace_remove("write", self.variable_callback_name)
|
||||
@ -110,15 +120,15 @@ class CTkCheckBox(CTkBaseClass):
|
||||
super().destroy()
|
||||
|
||||
def draw(self, no_color_updates=False):
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width * self.scaling,
|
||||
self.height * self.scaling,
|
||||
self.corner_radius * self.scaling,
|
||||
self.border_width * self.scaling)
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.apply_widget_scaling(self.current_width),
|
||||
self.apply_widget_scaling(self.current_height),
|
||||
self.apply_widget_scaling(self.corner_radius),
|
||||
self.apply_widget_scaling(self.border_width))
|
||||
|
||||
if self.check_state is True:
|
||||
self.draw_engine.draw_checkmark(self.width * self.scaling,
|
||||
self.height * self.scaling,
|
||||
self.height * 0.58 * self.scaling)
|
||||
self.draw_engine.draw_checkmark(self.apply_widget_scaling(self.current_width),
|
||||
self.apply_widget_scaling(self.current_height),
|
||||
self.apply_widget_scaling(self.current_height * 0.58))
|
||||
else:
|
||||
self.canvas.delete("checkmark")
|
||||
|
||||
@ -146,7 +156,6 @@ class CTkCheckBox(CTkBaseClass):
|
||||
fill=CTkThemeManager.single_color(self.border_color, self.appearance_mode))
|
||||
|
||||
if self.text_label is None:
|
||||
print("create label")
|
||||
self.text_label = tkinter.Label(master=self,
|
||||
bd=0,
|
||||
text=self.text,
|
||||
@ -231,17 +240,18 @@ class CTkCheckBox(CTkBaseClass):
|
||||
self.draw()
|
||||
|
||||
def set_cursor(self):
|
||||
if self.state == tkinter.DISABLED:
|
||||
if sys.platform == "darwin" and CTkSettings.hand_cursor_enabled:
|
||||
self.canvas.configure(cursor="arrow")
|
||||
elif sys.platform.startswith("win") and CTkSettings.hand_cursor_enabled:
|
||||
self.canvas.configure(cursor="arrow")
|
||||
if CTkSettings.cursor_manipulation_enabled:
|
||||
if self.state == tkinter.DISABLED:
|
||||
if sys.platform == "darwin" and CTkSettings.cursor_manipulation_enabled:
|
||||
self.canvas.configure(cursor="arrow")
|
||||
elif sys.platform.startswith("win") and CTkSettings.cursor_manipulation_enabled:
|
||||
self.canvas.configure(cursor="arrow")
|
||||
|
||||
elif self.state == tkinter.NORMAL:
|
||||
if sys.platform == "darwin" and CTkSettings.hand_cursor_enabled:
|
||||
self.canvas.configure(cursor="pointinghand")
|
||||
elif sys.platform.startswith("win") and CTkSettings.hand_cursor_enabled:
|
||||
self.canvas.configure(cursor="hand2")
|
||||
elif self.state == tkinter.NORMAL:
|
||||
if sys.platform == "darwin" and CTkSettings.cursor_manipulation_enabled:
|
||||
self.canvas.configure(cursor="pointinghand")
|
||||
elif sys.platform.startswith("win") and CTkSettings.cursor_manipulation_enabled:
|
||||
self.canvas.configure(cursor="hand2")
|
||||
|
||||
def set_text(self, text):
|
||||
self.text = text
|
||||
|
@ -46,8 +46,8 @@ class CTkEntry(CTkBaseClass):
|
||||
|
||||
self.canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width * self.scaling,
|
||||
height=self.height * self.scaling)
|
||||
width=self.apply_widget_scaling(self.current_width),
|
||||
height=self.apply_widget_scaling(self.current_height))
|
||||
self.canvas.grid(column=0, row=0, sticky="we")
|
||||
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
|
||||
|
||||
@ -58,7 +58,7 @@ class CTkEntry(CTkBaseClass):
|
||||
font=self.apply_font_scaling(self.text_font),
|
||||
**kwargs)
|
||||
self.entry.grid(column=0, row=0, sticky="we",
|
||||
padx=self.corner_radius * self.scaling if self.corner_radius >= 6 * self.scaling else 6 * self.scaling)
|
||||
padx=self.apply_widget_scaling(self.corner_radius) if self.corner_radius >= 6 else self.apply_widget_scaling(6))
|
||||
|
||||
super().bind('<Configure>', self.update_dimensions_event)
|
||||
self.entry.bind('<FocusOut>', self.set_placeholder)
|
||||
@ -67,6 +67,16 @@ class CTkEntry(CTkBaseClass):
|
||||
self.draw()
|
||||
self.set_placeholder()
|
||||
|
||||
def set_scaling(self, *args, **kwargs):
|
||||
super().set_scaling( *args, **kwargs)
|
||||
|
||||
self.entry.configure(font=self.apply_font_scaling(self.text_font))
|
||||
self.entry.grid(column=0, row=0, sticky="we",
|
||||
padx=self.apply_widget_scaling(self.corner_radius) if self.corner_radius >= 6 else self.apply_widget_scaling(6))
|
||||
|
||||
self.canvas.configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
self.draw()
|
||||
|
||||
def configure_basic_grid(self):
|
||||
self.grid_rowconfigure(0, weight=1)
|
||||
self.grid_columnconfigure(0, weight=1)
|
||||
@ -91,10 +101,10 @@ class CTkEntry(CTkBaseClass):
|
||||
def draw(self, no_color_updates=False):
|
||||
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
|
||||
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width * self.scaling,
|
||||
self.height * self.scaling,
|
||||
self.corner_radius * self.scaling,
|
||||
self.border_width * self.scaling)
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.apply_widget_scaling(self.current_width),
|
||||
self.apply_widget_scaling(self.current_height),
|
||||
self.apply_widget_scaling(self.corner_radius),
|
||||
self.apply_widget_scaling(self.border_width))
|
||||
|
||||
if CTkThemeManager.single_color(self.fg_color, self.appearance_mode) is not None:
|
||||
self.canvas.itemconfig("inner_parts",
|
||||
@ -147,12 +157,12 @@ class CTkEntry(CTkBaseClass):
|
||||
if "corner_radius" in kwargs:
|
||||
self.corner_radius = kwargs["corner_radius"]
|
||||
|
||||
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
|
||||
if self.corner_radius * 2 > self.current_height:
|
||||
self.corner_radius = self.current_height / 2
|
||||
elif self.corner_radius * 2 > self.current_width:
|
||||
self.corner_radius = self.current_width / 2
|
||||
|
||||
self.entry.grid(column=0, row=0, sticky="we", padx=self.corner_radius if self.corner_radius >= 6 else 6)
|
||||
self.entry.grid(column=0, row=0, sticky="we", padx=self.apply_widget_scaling(self.corner_radius) if self.corner_radius >= 6 else self.apply_widget_scaling(6))
|
||||
del kwargs["corner_radius"]
|
||||
require_redraw = True
|
||||
|
||||
|
@ -41,8 +41,8 @@ class CTkFrame(CTkBaseClass):
|
||||
|
||||
self.canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width * self.scaling,
|
||||
height=self.height * self.scaling)
|
||||
width=self.apply_widget_scaling(self.current_width),
|
||||
height=self.apply_widget_scaling(self.current_height))
|
||||
self.canvas.place(x=0, y=0, relwidth=1, relheight=1)
|
||||
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
|
||||
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
|
||||
@ -62,12 +62,18 @@ class CTkFrame(CTkBaseClass):
|
||||
except ValueError:
|
||||
return child_widgets
|
||||
|
||||
def set_scaling(self, *args, **kwargs):
|
||||
super().set_scaling(*args, **kwargs)
|
||||
|
||||
self.canvas.configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
self.draw()
|
||||
|
||||
def draw(self, no_color_updates=False):
|
||||
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width * self.scaling,
|
||||
self.height * self.scaling,
|
||||
self.corner_radius * self.scaling,
|
||||
self.border_width * self.scaling)
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.apply_widget_scaling(self.current_width),
|
||||
self.apply_widget_scaling(self.current_height),
|
||||
self.apply_widget_scaling(self.corner_radius),
|
||||
self.apply_widget_scaling(self.border_width))
|
||||
|
||||
if no_color_updates is False or requires_recoloring:
|
||||
self.canvas.itemconfig("inner_parts",
|
||||
|
@ -1,105 +0,0 @@
|
||||
import tkinter
|
||||
import time
|
||||
|
||||
from .ctk_label import CTkLabel
|
||||
from .ctk_entry import CTkEntry
|
||||
from .ctk_frame import CTkFrame
|
||||
from .ctk_toplevel import CTkToplevel
|
||||
from .ctk_button import CTkButton
|
||||
from ..appearance_mode_tracker import AppearanceModeTracker
|
||||
from ..theme_manager import CTkThemeManager
|
||||
|
||||
|
||||
class CTkInputDialog:
|
||||
def __init__(self,
|
||||
master=None,
|
||||
title="CTkDialog",
|
||||
text="CTkDialog",
|
||||
fg_color="default_theme",
|
||||
hover_color="default_theme",
|
||||
border_color="default_theme"):
|
||||
|
||||
self.appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark"
|
||||
self.master = master
|
||||
|
||||
self.user_input = None
|
||||
self.running = False
|
||||
|
||||
self.height = len(text.split("\n"))*20 + 150
|
||||
|
||||
self.window_bg_color = CTkThemeManager.theme["color"]["window_bg_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 = CTkToplevel()
|
||||
self.top.geometry(f"280x{self.height}")
|
||||
self.top.resizable(False, False)
|
||||
self.top.title(title)
|
||||
self.top.lift()
|
||||
self.top.focus_force()
|
||||
self.top.grab_set()
|
||||
|
||||
self.label_frame = CTkFrame(master=self.top,
|
||||
corner_radius=0,
|
||||
fg_color=self.window_bg_color,
|
||||
width=300,
|
||||
height=self.height-100)
|
||||
self.label_frame.place(relx=0.5, rely=0, anchor=tkinter.N)
|
||||
|
||||
self.button_and_entry_frame = CTkFrame(master=self.top,
|
||||
corner_radius=0,
|
||||
fg_color=self.window_bg_color,
|
||||
width=300,
|
||||
height=100)
|
||||
self.button_and_entry_frame.place(relx=0.5, rely=1, anchor=tkinter.S)
|
||||
|
||||
self.myLabel = CTkLabel(master=self.label_frame,
|
||||
text=text,
|
||||
width=300,
|
||||
fg_color=None,
|
||||
height=self.height-100)
|
||||
self.myLabel.place(relx=0.5, rely=0.5, anchor=tkinter.CENTER)
|
||||
|
||||
self.entry = CTkEntry(master=self.button_and_entry_frame,
|
||||
width=230)
|
||||
self.entry.place(relx=0.5, rely=0.15, anchor=tkinter.CENTER)
|
||||
|
||||
self.ok_button = CTkButton(master=self.button_and_entry_frame,
|
||||
text='Ok',
|
||||
width=100,
|
||||
command=self.ok_event,
|
||||
fg_color=self.fg_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,
|
||||
text='Cancel',
|
||||
width=100,
|
||||
command=self.cancel_event,
|
||||
fg_color=self.fg_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()
|
||||
self.entry.bind("<Return>", self.ok_event)
|
||||
|
||||
def ok_event(self, event=None):
|
||||
self.user_input = self.entry.get()
|
||||
self.running = False
|
||||
|
||||
def cancel_event(self):
|
||||
self.running = False
|
||||
|
||||
def get_input(self):
|
||||
self.running = True
|
||||
|
||||
while self.running:
|
||||
self.top.update()
|
||||
time.sleep(0.01)
|
||||
|
||||
time.sleep(0.05)
|
||||
self.top.destroy()
|
||||
return self.user_input
|
@ -45,8 +45,8 @@ class CTkLabel(CTkBaseClass):
|
||||
|
||||
self.canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width * self.scaling,
|
||||
height=self.height * self.scaling)
|
||||
width=self.apply_widget_scaling(self.desired_width),
|
||||
height=self.apply_widget_scaling(self.desired_height))
|
||||
self.canvas.grid(row=0, column=0, sticky="nswe")
|
||||
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
|
||||
|
||||
@ -56,15 +56,22 @@ class CTkLabel(CTkBaseClass):
|
||||
text=self.text,
|
||||
font=self.apply_font_scaling(self.text_font),
|
||||
**kwargs)
|
||||
self.text_label.grid(row=0, column=0, padx=self.corner_radius)
|
||||
self.text_label.grid(row=0, column=0, padx=self.apply_widget_scaling(self.corner_radius))
|
||||
|
||||
self.bind('<Configure>', self.update_dimensions_event)
|
||||
self.draw()
|
||||
|
||||
def set_scaling(self, *args, **kwargs):
|
||||
super().set_scaling(*args, **kwargs)
|
||||
|
||||
self.canvas.configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
self.text_label.configure(font=self.apply_font_scaling(self.text_font))
|
||||
self.text_label.grid(row=0, column=0, padx=self.apply_widget_scaling(self.corner_radius))
|
||||
|
||||
def draw(self, no_color_updates=False):
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width * self.scaling,
|
||||
self.height * self.scaling,
|
||||
self.corner_radius * self.scaling,
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.apply_widget_scaling(self.current_width),
|
||||
self.apply_widget_scaling(self.current_height),
|
||||
self.apply_widget_scaling(self.corner_radius),
|
||||
0)
|
||||
|
||||
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
|
||||
|
@ -40,14 +40,14 @@ class CTkProgressBar(CTkBaseClass):
|
||||
self.border_width = CTkThemeManager.theme["shape"]["progressbar_border_width"] if border_width == "default_theme" else border_width
|
||||
self.value = 0.5
|
||||
|
||||
self.grid_rowconfigure(1, weight=1)
|
||||
self.grid_columnconfigure(1, weight=1)
|
||||
self.grid_rowconfigure(0, weight=1)
|
||||
self.grid_columnconfigure(0, weight=1)
|
||||
|
||||
self.canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width * self.scaling,
|
||||
height=self.height * self.scaling)
|
||||
self.canvas.grid(row=0, column=0, rowspan=1, columnspan=1)
|
||||
width=self.apply_widget_scaling(self.desired_width),
|
||||
height=self.apply_widget_scaling(self.desired_height))
|
||||
self.canvas.grid(row=0, column=0, rowspan=1, columnspan=1, sticky="nswe")
|
||||
self.draw_engine = CTkDrawEngine(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
|
||||
@ -61,6 +61,12 @@ class CTkProgressBar(CTkBaseClass):
|
||||
self.set(self.variable.get(), from_variable_callback=True)
|
||||
self.variable_callback_blocked = False
|
||||
|
||||
def set_scaling(self, *args, **kwargs):
|
||||
super().set_scaling(*args, **kwargs)
|
||||
|
||||
self.canvas.configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
self.draw()
|
||||
|
||||
def destroy(self):
|
||||
if self.variable is not None:
|
||||
self.variable.trace_remove("write", self.variable_callback_name)
|
||||
@ -68,12 +74,10 @@ class CTkProgressBar(CTkBaseClass):
|
||||
super().destroy()
|
||||
|
||||
def draw(self, no_color_updates=False):
|
||||
print("progress", self.scaling)
|
||||
|
||||
requires_recoloring = self.draw_engine.draw_rounded_progress_bar_with_border(self.width * self.scaling,
|
||||
self.height * self.scaling,
|
||||
self.corner_radius * self.scaling,
|
||||
self.border_width * self.scaling,
|
||||
requires_recoloring = self.draw_engine.draw_rounded_progress_bar_with_border(self.apply_widget_scaling(self.current_width),
|
||||
self.apply_widget_scaling(self.current_height),
|
||||
self.apply_widget_scaling(self.corner_radius),
|
||||
self.apply_widget_scaling(self.border_width),
|
||||
self.value, "w")
|
||||
|
||||
if no_color_updates is False or requires_recoloring:
|
||||
|
@ -65,19 +65,19 @@ class CTkRadioButton(CTkBaseClass):
|
||||
|
||||
# configure grid system (3x1)
|
||||
self.grid_columnconfigure(0, weight=0)
|
||||
self.grid_columnconfigure(1, weight=0, minsize=6 * self.scaling)
|
||||
self.grid_columnconfigure(1, weight=0, minsize=self.apply_widget_scaling(6))
|
||||
self.grid_columnconfigure(2, weight=1)
|
||||
|
||||
self.bg_canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width * self.scaling,
|
||||
height=self.height * self.scaling)
|
||||
width=self.apply_widget_scaling(self.current_width),
|
||||
height=self.apply_widget_scaling(self.current_height))
|
||||
self.bg_canvas.grid(row=0, column=0, padx=0, pady=0, columnspan=3, rowspan=1, sticky="nswe")
|
||||
|
||||
self.canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width * self.scaling,
|
||||
height=self.height * self.scaling)
|
||||
width=self.apply_widget_scaling(self.current_width),
|
||||
height=self.apply_widget_scaling(self.current_height))
|
||||
self.canvas.grid(row=0, column=0, padx=0, pady=0, columnspan=1)
|
||||
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
|
||||
|
||||
@ -96,6 +96,16 @@ class CTkRadioButton(CTkBaseClass):
|
||||
else:
|
||||
self.deselect(from_variable_callback=True)
|
||||
|
||||
def set_scaling(self, *args, **kwargs):
|
||||
super().set_scaling(*args, **kwargs)
|
||||
|
||||
self.grid_columnconfigure(1, weight=0, minsize=self.apply_widget_scaling(6))
|
||||
self.text_label.configure(font=self.apply_font_scaling(self.text_font))
|
||||
|
||||
self.bg_canvas.configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
self.canvas.configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
self.draw()
|
||||
|
||||
def destroy(self):
|
||||
if self.variable is not None:
|
||||
self.variable.trace_remove("write", self.variable_callback_name)
|
||||
@ -103,10 +113,10 @@ class CTkRadioButton(CTkBaseClass):
|
||||
super().destroy()
|
||||
|
||||
def draw(self, no_color_updates=False):
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width * self.scaling,
|
||||
self.height * self.scaling,
|
||||
self.corner_radius * self.scaling,
|
||||
self.border_width * self.scaling)
|
||||
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.apply_widget_scaling(self.current_width),
|
||||
self.apply_widget_scaling(self.current_height),
|
||||
self.apply_widget_scaling(self.corner_radius),
|
||||
self.apply_widget_scaling(self.border_width))
|
||||
|
||||
self.bg_canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
|
||||
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
|
||||
@ -215,17 +225,18 @@ class CTkRadioButton(CTkBaseClass):
|
||||
self.draw()
|
||||
|
||||
def set_cursor(self):
|
||||
if self.state == tkinter.DISABLED:
|
||||
if sys.platform == "darwin" and CTkSettings.hand_cursor_enabled:
|
||||
self.canvas.configure(cursor="arrow")
|
||||
elif sys.platform.startswith("win") and CTkSettings.hand_cursor_enabled:
|
||||
self.canvas.configure(cursor="arrow")
|
||||
if CTkSettings.cursor_manipulation_enabled:
|
||||
if self.state == tkinter.DISABLED:
|
||||
if sys.platform == "darwin" and CTkSettings.cursor_manipulation_enabled:
|
||||
self.canvas.configure(cursor="arrow")
|
||||
elif sys.platform.startswith("win") and CTkSettings.cursor_manipulation_enabled:
|
||||
self.canvas.configure(cursor="arrow")
|
||||
|
||||
elif self.state == tkinter.NORMAL:
|
||||
if sys.platform == "darwin" and CTkSettings.hand_cursor_enabled:
|
||||
self.canvas.configure(cursor="pointinghand")
|
||||
elif sys.platform.startswith("win") and CTkSettings.hand_cursor_enabled:
|
||||
self.canvas.configure(cursor="hand2")
|
||||
elif self.state == tkinter.NORMAL:
|
||||
if sys.platform == "darwin" and CTkSettings.cursor_manipulation_enabled:
|
||||
self.canvas.configure(cursor="pointinghand")
|
||||
elif sys.platform.startswith("win") and CTkSettings.cursor_manipulation_enabled:
|
||||
self.canvas.configure(cursor="hand2")
|
||||
|
||||
def set_text(self, text):
|
||||
self.text = text
|
||||
|
@ -62,11 +62,14 @@ class CTkSlider(CTkBaseClass):
|
||||
self.variable_callback_blocked = False
|
||||
self.variable_callback_name = None
|
||||
|
||||
self.grid_rowconfigure(0, weight=1)
|
||||
self.grid_columnconfigure(0, weight=1)
|
||||
|
||||
self.canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width * self.scaling,
|
||||
height=self.height * self.scaling)
|
||||
self.canvas.grid(column=0, row=0, sticky="nswe")
|
||||
width=self.apply_widget_scaling(self.desired_width),
|
||||
height=self.apply_widget_scaling(self.desired_height))
|
||||
self.canvas.grid(column=0, row=0, rowspan=1, columnspan=1, sticky="nswe")
|
||||
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
|
||||
|
||||
self.canvas.bind("<Enter>", self.on_enter)
|
||||
@ -86,6 +89,12 @@ class CTkSlider(CTkBaseClass):
|
||||
self.set(self.variable.get(), from_variable_callback=True)
|
||||
self.variable_callback_blocked = False
|
||||
|
||||
def set_scaling(self, *args, **kwargs):
|
||||
super().set_scaling(*args, **kwargs)
|
||||
|
||||
self.canvas.configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
self.draw()
|
||||
|
||||
def destroy(self):
|
||||
# remove variable_callback from variable callbacks if variable exists
|
||||
if self.variable is not None:
|
||||
@ -93,23 +102,20 @@ class CTkSlider(CTkBaseClass):
|
||||
|
||||
super().destroy()
|
||||
|
||||
def configure_basic_grid(self):
|
||||
self.grid_rowconfigure(0, weight=1)
|
||||
self.grid_columnconfigure(0, weight=1)
|
||||
|
||||
def set_cursor(self):
|
||||
if sys.platform == "darwin":
|
||||
self.configure(cursor="pointinghand")
|
||||
elif sys.platform.startswith("win"):
|
||||
self.configure(cursor="hand2")
|
||||
if CTkSettings.cursor_manipulation_enabled:
|
||||
if sys.platform == "darwin":
|
||||
self.configure(cursor="pointinghand")
|
||||
elif sys.platform.startswith("win"):
|
||||
self.configure(cursor="hand2")
|
||||
|
||||
def draw(self, no_color_updates=False):
|
||||
requires_recoloring = self.draw_engine.draw_rounded_slider_with_border_and_button(self.width * self.scaling,
|
||||
self.height * self.scaling,
|
||||
self.corner_radius * self.scaling,
|
||||
self.border_width * self.scaling,
|
||||
self.button_length * self.scaling,
|
||||
self.button_corner_radius * self.scaling,
|
||||
requires_recoloring = self.draw_engine.draw_rounded_slider_with_border_and_button(self.apply_widget_scaling(self.current_width),
|
||||
self.apply_widget_scaling(self.current_height),
|
||||
self.apply_widget_scaling(self.corner_radius),
|
||||
self.apply_widget_scaling(self.border_width),
|
||||
self.apply_widget_scaling(self.button_length),
|
||||
self.apply_widget_scaling(self.button_corner_radius),
|
||||
self.value, "w")
|
||||
|
||||
if no_color_updates is False or requires_recoloring:
|
||||
@ -136,7 +142,7 @@ class CTkSlider(CTkBaseClass):
|
||||
outline=CTkThemeManager.single_color(self.button_color, self.appearance_mode))
|
||||
|
||||
def clicked(self, event=None):
|
||||
self.value = (event.x / self.width) / self.scaling
|
||||
self.value = (event.x / self.current_width) / self.widget_scaling
|
||||
|
||||
if self.value > 1:
|
||||
self.value = 1
|
||||
@ -159,12 +165,12 @@ class CTkSlider(CTkBaseClass):
|
||||
def on_enter(self, event=0):
|
||||
self.hover_state = True
|
||||
self.canvas.itemconfig("slider_parts", fill=CTkThemeManager.single_color(self.button_hover_color, self.appearance_mode),
|
||||
outline=CTkThemeManager.single_color(self.button_hover_color, self.appearance_mode))
|
||||
outline=CTkThemeManager.single_color(self.button_hover_color, self.appearance_mode))
|
||||
|
||||
def on_leave(self, event=0):
|
||||
self.hover_state = False
|
||||
self.canvas.itemconfig("slider_parts", fill=CTkThemeManager.single_color(self.button_color, self.appearance_mode),
|
||||
outline=CTkThemeManager.single_color(self.button_color, self.appearance_mode))
|
||||
outline=CTkThemeManager.single_color(self.button_color, self.appearance_mode))
|
||||
|
||||
def round_to_step_size(self, value):
|
||||
if self.number_of_steps is not None:
|
||||
|
@ -70,19 +70,19 @@ class CTkSwitch(CTkBaseClass):
|
||||
|
||||
# configure grid system (3x1)
|
||||
self.grid_columnconfigure(0, weight=1)
|
||||
self.grid_columnconfigure(1, weight=0, minsize=6 * self.scaling)
|
||||
self.grid_columnconfigure(1, weight=0, minsize=self.apply_widget_scaling(6))
|
||||
self.grid_columnconfigure(2, weight=0)
|
||||
|
||||
self.bg_canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width * self.scaling,
|
||||
height=self.height * self.scaling)
|
||||
width=self.apply_widget_scaling(self.current_width),
|
||||
height=self.apply_widget_scaling(self.current_height))
|
||||
self.bg_canvas.grid(row=0, column=0, padx=0, pady=0, columnspan=3, rowspan=1, sticky="nswe")
|
||||
|
||||
self.canvas = CTkCanvas(master=self,
|
||||
highlightthickness=0,
|
||||
width=self.width * self.scaling,
|
||||
height=self.height * self.scaling)
|
||||
width=self.apply_widget_scaling(self.current_width),
|
||||
height=self.apply_widget_scaling(self.current_height))
|
||||
self.canvas.grid(row=0, column=0, padx=0, pady=0, columnspan=1, sticky="nswe")
|
||||
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
|
||||
|
||||
@ -100,6 +100,16 @@ class CTkSwitch(CTkBaseClass):
|
||||
elif self.variable.get() == self.offvalue:
|
||||
self.deselect(from_variable_callback=True)
|
||||
|
||||
def set_scaling(self, *args, **kwargs):
|
||||
super().set_scaling(*args, **kwargs)
|
||||
|
||||
self.grid_columnconfigure(1, weight=0, minsize=self.apply_widget_scaling(6))
|
||||
self.text_label.configure(font=self.apply_font_scaling(self.text_font))
|
||||
|
||||
self.bg_canvas.configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
self.canvas.configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
self.draw()
|
||||
|
||||
def destroy(self):
|
||||
# remove variable_callback from variable callbacks if variable exists
|
||||
if self.variable is not None:
|
||||
@ -108,28 +118,29 @@ class CTkSwitch(CTkBaseClass):
|
||||
super().destroy()
|
||||
|
||||
def set_cursor(self):
|
||||
if sys.platform == "darwin" and CTkSettings.hand_cursor_enabled:
|
||||
self.canvas.configure(cursor="pointinghand")
|
||||
elif sys.platform.startswith("win") and CTkSettings.hand_cursor_enabled:
|
||||
self.canvas.configure(cursor="hand2")
|
||||
if CTkSettings.cursor_manipulation_enabled:
|
||||
if sys.platform == "darwin" and CTkSettings.cursor_manipulation_enabled:
|
||||
self.canvas.configure(cursor="pointinghand")
|
||||
elif sys.platform.startswith("win") and CTkSettings.cursor_manipulation_enabled:
|
||||
self.canvas.configure(cursor="hand2")
|
||||
|
||||
def draw(self, no_color_updates=False):
|
||||
|
||||
if self.check_state is True:
|
||||
requires_recoloring = self.draw_engine.draw_rounded_slider_with_border_and_button(self.width * self.scaling,
|
||||
self.height * self.scaling,
|
||||
self.corner_radius * self.scaling,
|
||||
self.border_width * self.scaling,
|
||||
self.button_length * self.scaling,
|
||||
self.corner_radius * self.scaling
|
||||
, 1, "w")
|
||||
requires_recoloring = self.draw_engine.draw_rounded_slider_with_border_and_button(self.apply_widget_scaling(self.current_width),
|
||||
self.apply_widget_scaling(self.current_height),
|
||||
self.apply_widget_scaling(self.corner_radius),
|
||||
self.apply_widget_scaling(self.border_width),
|
||||
self.apply_widget_scaling(self.button_length),
|
||||
self.apply_widget_scaling(self.corner_radius),
|
||||
1, "w")
|
||||
else:
|
||||
requires_recoloring = self.draw_engine.draw_rounded_slider_with_border_and_button(self.width * self.scaling,
|
||||
self.height * self.scaling,
|
||||
self.corner_radius * self.scaling,
|
||||
self.border_width * self.scaling,
|
||||
self.button_length * self.scaling,
|
||||
self.corner_radius * self.scaling,
|
||||
requires_recoloring = self.draw_engine.draw_rounded_slider_with_border_and_button(self.apply_widget_scaling(self.current_width),
|
||||
self.apply_widget_scaling(self.current_height),
|
||||
self.apply_widget_scaling(self.corner_radius),
|
||||
self.apply_widget_scaling(self.border_width),
|
||||
self.apply_widget_scaling(self.button_length),
|
||||
self.apply_widget_scaling(self.corner_radius),
|
||||
0, "w")
|
||||
|
||||
if no_color_updates is False or requires_recoloring:
|
||||
|
@ -1,186 +0,0 @@
|
||||
import tkinter
|
||||
from distutils.version import StrictVersion as Version
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
import ctypes
|
||||
|
||||
from ..appearance_mode_tracker import AppearanceModeTracker
|
||||
from ..theme_manager import CTkThemeManager
|
||||
|
||||
|
||||
class CTk(tkinter.Tk):
|
||||
def __init__(self, *args,
|
||||
fg_color="default_theme",
|
||||
**kwargs):
|
||||
|
||||
self.enable_macos_dark_title_bar()
|
||||
super().__init__(*args, **kwargs)
|
||||
self.appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark"
|
||||
|
||||
self.fg_color = CTkThemeManager.theme["color"]["window_bg_color"] if fg_color == "default_theme" else fg_color
|
||||
|
||||
if "bg" in kwargs:
|
||||
self.fg_color = kwargs["bg"]
|
||||
del kwargs["bg"]
|
||||
elif "background" in kwargs:
|
||||
self.fg_color = kwargs["background"]
|
||||
del kwargs["background"]
|
||||
|
||||
# add set_appearance_mode method to callback list of AppearanceModeTracker for appearance mode changes
|
||||
AppearanceModeTracker.add(self.set_appearance_mode, self)
|
||||
super().configure(bg=CTkThemeManager.single_color(self.fg_color, self.appearance_mode))
|
||||
super().title("CTk")
|
||||
|
||||
self.window_exists = False # indicates if the window is already shown through .update or .mainloop
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
if self.appearance_mode == 1:
|
||||
self.windows_set_titlebar_color("dark")
|
||||
else:
|
||||
self.windows_set_titlebar_color("light")
|
||||
|
||||
def destroy(self):
|
||||
AppearanceModeTracker.remove(self.set_appearance_mode)
|
||||
self.disable_macos_dark_title_bar()
|
||||
super().destroy()
|
||||
|
||||
def update(self):
|
||||
if self.window_exists is False:
|
||||
self.deiconify()
|
||||
self.window_exists = True
|
||||
super().update()
|
||||
|
||||
def mainloop(self, *args, **kwargs):
|
||||
if self.window_exists is False:
|
||||
self.deiconify()
|
||||
self.window_exists = True
|
||||
super().mainloop(*args, **kwargs)
|
||||
|
||||
def resizable(self, *args, **kwargs):
|
||||
super().resizable(*args, **kwargs)
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
if self.appearance_mode == 1:
|
||||
self.windows_set_titlebar_color("dark")
|
||||
else:
|
||||
self.windows_set_titlebar_color("light")
|
||||
|
||||
def config(self, *args, **kwargs):
|
||||
self.configure(*args, **kwargs)
|
||||
|
||||
def configure(self, *args, **kwargs):
|
||||
bg_changed = False
|
||||
|
||||
if "bg" in kwargs:
|
||||
self.fg_color = kwargs["bg"]
|
||||
bg_changed = True
|
||||
kwargs["bg"] = CTkThemeManager.single_color(self.fg_color, self.appearance_mode)
|
||||
elif "background" in kwargs:
|
||||
self.fg_color = kwargs["background"]
|
||||
bg_changed = True
|
||||
kwargs["background"] = CTkThemeManager.single_color(self.fg_color, self.appearance_mode)
|
||||
elif "fg_color" in kwargs:
|
||||
self.fg_color = kwargs["fg_color"]
|
||||
kwargs["bg"] = CTkThemeManager.single_color(self.fg_color, self.appearance_mode)
|
||||
del kwargs["fg_color"]
|
||||
bg_changed = True
|
||||
|
||||
elif len(args) > 0 and type(args[0]) == dict:
|
||||
if "bg" in args[0]:
|
||||
self.fg_color=args[0]["bg"]
|
||||
bg_changed = True
|
||||
args[0]["bg"] = CTkThemeManager.single_color(self.fg_color, self.appearance_mode)
|
||||
elif "background" in args[0]:
|
||||
self.fg_color=args[0]["background"]
|
||||
bg_changed = True
|
||||
args[0]["background"] = CTkThemeManager.single_color(self.fg_color, self.appearance_mode)
|
||||
|
||||
if bg_changed:
|
||||
from .ctk_slider import CTkSlider
|
||||
from .ctk_progressbar import CTkProgressBar
|
||||
from .ctk_label import CTkLabel
|
||||
from .ctk_frame import CTkFrame
|
||||
from .ctk_entry import CTkEntry
|
||||
from customtkinter.widgets.ctk_checkbox import CTkCheckBox
|
||||
from customtkinter.widgets.ctk_button import CTkButton
|
||||
|
||||
for child in self.winfo_children():
|
||||
if isinstance(child, (CTkFrame, CTkButton, CTkLabel, CTkSlider, CTkCheckBox, CTkEntry, CTkProgressBar)):
|
||||
child.configure(bg_color=self.fg_color)
|
||||
|
||||
super().configure(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def enable_macos_dark_title_bar():
|
||||
if sys.platform == "darwin": # macOS
|
||||
if Version(platform.python_version()) < Version("3.10"):
|
||||
if Version(tkinter.Tcl().call("info", "patchlevel")) >= Version("8.6.9"): # Tcl/Tk >= 8.6.9
|
||||
os.system("defaults write -g NSRequiresAquaSystemAppearance -bool No")
|
||||
|
||||
@staticmethod
|
||||
def disable_macos_dark_title_bar():
|
||||
if sys.platform == "darwin": # macOS
|
||||
if Version(platform.python_version()) < Version("3.10"):
|
||||
if Version(tkinter.Tcl().call("info", "patchlevel")) >= Version("8.6.9"): # Tcl/Tk >= 8.6.9
|
||||
os.system("defaults delete -g NSRequiresAquaSystemAppearance")
|
||||
# This command reverts the dark-mode setting for all programs.
|
||||
|
||||
def windows_set_titlebar_color(self, color_mode: str):
|
||||
"""
|
||||
Set the titlebar color of the window to light or dark theme on Microsoft Windows.
|
||||
|
||||
Credits for this function:
|
||||
https://stackoverflow.com/questions/23836000/can-i-change-the-title-bar-in-tkinter/70724666#70724666
|
||||
|
||||
MORE INFO:
|
||||
https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
|
||||
"""
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
|
||||
super().withdraw() # hide window so that it can be redrawn after the titlebar change so that the color change is visible
|
||||
if not self.window_exists:
|
||||
super().update()
|
||||
|
||||
if color_mode.lower() == "dark":
|
||||
value = 1
|
||||
elif color_mode.lower() == "light":
|
||||
value = 0
|
||||
else:
|
||||
return
|
||||
|
||||
try:
|
||||
hwnd = ctypes.windll.user32.GetParent(self.winfo_id())
|
||||
DWMWA_USE_IMMERSIVE_DARK_MODE = 20
|
||||
DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19
|
||||
|
||||
# try with DWMWA_USE_IMMERSIVE_DARK_MODE
|
||||
if ctypes.windll.dwmapi.DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE,
|
||||
ctypes.byref(ctypes.c_int(value)),
|
||||
ctypes.sizeof(ctypes.c_int(value))) != 0:
|
||||
|
||||
# try with DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20h1
|
||||
ctypes.windll.dwmapi.DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1,
|
||||
ctypes.byref(ctypes.c_int(value)),
|
||||
ctypes.sizeof(ctypes.c_int(value)))
|
||||
|
||||
except Exception as err:
|
||||
print(err)
|
||||
|
||||
if self.window_exists:
|
||||
self.deiconify()
|
||||
|
||||
def set_appearance_mode(self, mode_string):
|
||||
if mode_string.lower() == "dark":
|
||||
self.appearance_mode = 1
|
||||
elif mode_string.lower() == "light":
|
||||
self.appearance_mode = 0
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
if self.appearance_mode == 1:
|
||||
self.windows_set_titlebar_color("dark")
|
||||
else:
|
||||
self.windows_set_titlebar_color("light")
|
||||
|
||||
super().configure(bg=CTkThemeManager.single_color(self.fg_color, self.appearance_mode))
|
@ -1,169 +0,0 @@
|
||||
import tkinter
|
||||
from distutils.version import StrictVersion as Version
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
import ctypes
|
||||
|
||||
from ..appearance_mode_tracker import AppearanceModeTracker
|
||||
from ..theme_manager import CTkThemeManager
|
||||
|
||||
|
||||
class CTkToplevel(tkinter.Toplevel):
|
||||
def __init__(self, *args,
|
||||
fg_color="default_theme",
|
||||
**kwargs):
|
||||
|
||||
self.enable_macos_dark_title_bar()
|
||||
super().__init__(*args, **kwargs)
|
||||
self.appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark"
|
||||
|
||||
self.fg_color = CTkThemeManager.theme["color"]["window_bg_color"] if fg_color == "default_theme" else fg_color
|
||||
|
||||
if "bg" in kwargs:
|
||||
self.fg_color = kwargs["bg"]
|
||||
del kwargs["bg"]
|
||||
elif "background" in kwargs:
|
||||
self.fg_color = kwargs["background"]
|
||||
del kwargs["background"]
|
||||
|
||||
# add set_appearance_mode method to callback list of AppearanceModeTracker for appearance mode changes
|
||||
AppearanceModeTracker.add(self.set_appearance_mode, self)
|
||||
super().configure(bg=CTkThemeManager.single_color(self.fg_color, self.appearance_mode))
|
||||
super().title("CTkToplevel")
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
if self.appearance_mode == 1:
|
||||
self.windows_set_titlebar_color("dark")
|
||||
else:
|
||||
self.windows_set_titlebar_color("light")
|
||||
|
||||
def destroy(self):
|
||||
AppearanceModeTracker.remove(self.set_appearance_mode)
|
||||
self.disable_macos_dark_title_bar()
|
||||
super().destroy()
|
||||
|
||||
def resizable(self, *args, **kwargs):
|
||||
super().resizable(*args, **kwargs)
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
if self.appearance_mode == 1:
|
||||
self.windows_set_titlebar_color("dark")
|
||||
else:
|
||||
self.windows_set_titlebar_color("light")
|
||||
|
||||
def config(self, *args, **kwargs):
|
||||
self.configure(*args, **kwargs)
|
||||
|
||||
def configure(self, *args, **kwargs):
|
||||
bg_changed = False
|
||||
|
||||
if "bg" in kwargs:
|
||||
self.fg_color = kwargs["bg"]
|
||||
bg_changed = True
|
||||
kwargs["bg"] = CTkThemeManager.single_color(self.fg_color, self.appearance_mode)
|
||||
elif "background" in kwargs:
|
||||
self.fg_color = kwargs["background"]
|
||||
bg_changed = True
|
||||
kwargs["background"] = CTkThemeManager.single_color(self.fg_color, self.appearance_mode)
|
||||
elif "fg_color" in kwargs:
|
||||
self.fg_color = kwargs["fg_color"]
|
||||
kwargs["bg"] = CTkThemeManager.single_color(self.fg_color, self.appearance_mode)
|
||||
del kwargs["fg_color"]
|
||||
bg_changed = True
|
||||
|
||||
elif len(args) > 0 and type(args[0]) == dict:
|
||||
if "bg" in args[0]:
|
||||
self.fg_color=args[0]["bg"]
|
||||
bg_changed = True
|
||||
args[0]["bg"] = CTkThemeManager.single_color(self.fg_color, self.appearance_mode)
|
||||
elif "background" in args[0]:
|
||||
self.fg_color=args[0]["background"]
|
||||
bg_changed = True
|
||||
args[0]["background"] = CTkThemeManager.single_color(self.fg_color, self.appearance_mode)
|
||||
|
||||
if bg_changed:
|
||||
from .ctk_slider import CTkSlider
|
||||
from .ctk_progressbar import CTkProgressBar
|
||||
from .ctk_label import CTkLabel
|
||||
from .ctk_frame import CTkFrame
|
||||
from .ctk_entry import CTkEntry
|
||||
from customtkinter.widgets.ctk_checkbox import CTkCheckBox
|
||||
from customtkinter.widgets.ctk_button import CTkButton
|
||||
|
||||
for child in self.winfo_children():
|
||||
if isinstance(child, (CTkFrame, CTkButton, CTkLabel, CTkSlider, CTkCheckBox, CTkEntry, CTkProgressBar)):
|
||||
child.configure(bg_color=self.fg_color)
|
||||
|
||||
super().configure(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def enable_macos_dark_title_bar():
|
||||
if sys.platform == "darwin": # macOS
|
||||
if Version(platform.python_version()) < Version("3.10"):
|
||||
if Version(tkinter.Tcl().call("info", "patchlevel")) >= Version("8.6.9"): # Tcl/Tk >= 8.6.9
|
||||
os.system("defaults write -g NSRequiresAquaSystemAppearance -bool No")
|
||||
|
||||
@staticmethod
|
||||
def disable_macos_dark_title_bar():
|
||||
if sys.platform == "darwin": # macOS
|
||||
if Version(platform.python_version()) < Version("3.10"):
|
||||
if Version(tkinter.Tcl().call("info", "patchlevel")) >= Version("8.6.9"): # Tcl/Tk >= 8.6.9
|
||||
os.system("defaults delete -g NSRequiresAquaSystemAppearance")
|
||||
# This command reverts the dark-mode setting for all programs.
|
||||
|
||||
def windows_set_titlebar_color(self, color_mode: str):
|
||||
"""
|
||||
Set the titlebar color of the window to light or dark theme on Microsoft Windows.
|
||||
|
||||
Credits for this function:
|
||||
https://stackoverflow.com/questions/23836000/can-i-change-the-title-bar-in-tkinter/70724666#70724666
|
||||
|
||||
MORE INFO:
|
||||
https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
|
||||
"""
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
|
||||
super().withdraw() # hide window so that it can be redrawn after the titlebar change so that the color change is visible
|
||||
super().update()
|
||||
|
||||
if color_mode.lower() == "dark":
|
||||
value = 1
|
||||
elif color_mode.lower() == "light":
|
||||
value = 0
|
||||
else:
|
||||
return
|
||||
|
||||
try:
|
||||
hwnd = ctypes.windll.user32.GetParent(self.winfo_id())
|
||||
DWMWA_USE_IMMERSIVE_DARK_MODE = 20
|
||||
DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19
|
||||
|
||||
# try with DWMWA_USE_IMMERSIVE_DARK_MODE
|
||||
if ctypes.windll.dwmapi.DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE,
|
||||
ctypes.byref(ctypes.c_int(value)),
|
||||
ctypes.sizeof(ctypes.c_int(value))) != 0:
|
||||
# try with DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20h1
|
||||
ctypes.windll.dwmapi.DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1,
|
||||
ctypes.byref(ctypes.c_int(value)),
|
||||
ctypes.sizeof(ctypes.c_int(value)))
|
||||
|
||||
except Exception as err:
|
||||
print(err)
|
||||
|
||||
self.deiconify()
|
||||
|
||||
def set_appearance_mode(self, mode_string):
|
||||
if mode_string.lower() == "dark":
|
||||
self.appearance_mode = 1
|
||||
elif mode_string.lower() == "light":
|
||||
self.appearance_mode = 0
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
if self.appearance_mode == 1:
|
||||
self.windows_set_titlebar_color("dark")
|
||||
else:
|
||||
self.windows_set_titlebar_color("light")
|
||||
|
||||
super().configure(bg=CTkThemeManager.single_color(self.fg_color, self.appearance_mode))
|
@ -2,10 +2,10 @@ import tkinter
|
||||
import tkinter.ttk as ttk
|
||||
import copy
|
||||
import re
|
||||
import math
|
||||
from typing import Callable, Union, TypedDict
|
||||
|
||||
from .ctk_tk import CTk
|
||||
from .ctk_toplevel import CTkToplevel
|
||||
from ..windows.ctk_tk import CTk
|
||||
from ..windows.ctk_toplevel import CTkToplevel
|
||||
from ..appearance_mode_tracker import AppearanceModeTracker
|
||||
from ..scaling_tracker import ScalingTracker
|
||||
from ..theme_manager import CTkThemeManager
|
||||
@ -16,12 +16,23 @@ class CTkBaseClass(tkinter.Frame):
|
||||
super().__init__(*args, width=width, height=height, **kwargs) # set desired size of underlying tkinter.Frame
|
||||
|
||||
self.bg_color = self.detect_color_of_master() if bg_color is None else bg_color
|
||||
self.width = width # width and height in pixel, represent current size of the widget (not the desired size by init)
|
||||
self.height = height # width and height are independent of the scale
|
||||
|
||||
self.current_width = width # current_width and current_height in pixel, represent current size of the widget (not the desired size by init)
|
||||
self.current_height = height # current_width and current_height are independent of the scale
|
||||
self.desired_width = width
|
||||
self.desired_height = height
|
||||
|
||||
# add set_scaling method to callback list of ScalingTracker for automatic scaling changes
|
||||
ScalingTracker.add_widget(self.set_scaling, self)
|
||||
self.scaling = ScalingTracker.get_widget_scaling(self)
|
||||
self.widget_scaling = ScalingTracker.get_widget_scaling(self)
|
||||
self.spacing_scaling = ScalingTracker.get_spacing_scaling(self)
|
||||
|
||||
# save latest geometry function and kwargs
|
||||
class GeometryCallDict(TypedDict):
|
||||
function: Callable
|
||||
kwargs: dict
|
||||
|
||||
self.last_geometry_manager_call: Union[GeometryCallDict, None] = None
|
||||
|
||||
# add set_appearance_mode method to callback list of AppearanceModeTracker for appearance mode changes
|
||||
AppearanceModeTracker.add(self.set_appearance_mode, self)
|
||||
@ -54,6 +65,39 @@ class CTkBaseClass(tkinter.Frame):
|
||||
AppearanceModeTracker.remove(self.set_appearance_mode)
|
||||
super().destroy()
|
||||
|
||||
def place(self, **kwargs):
|
||||
self.last_geometry_manager_call = {"function": super().place, "kwargs": kwargs}
|
||||
super().place(**self.apply_argument_scaling(kwargs))
|
||||
|
||||
def pack(self, **kwargs):
|
||||
self.last_geometry_manager_call = {"function": super().pack, "kwargs": kwargs}
|
||||
super().pack(**self.apply_argument_scaling(kwargs))
|
||||
|
||||
def grid(self, **kwargs):
|
||||
self.last_geometry_manager_call = {"function": super().grid, "kwargs": kwargs}
|
||||
super().grid(**self.apply_argument_scaling(kwargs))
|
||||
|
||||
def apply_argument_scaling(self, kwargs: dict) -> dict:
|
||||
scaled_kwargs = copy.copy(kwargs)
|
||||
|
||||
if "pady" in scaled_kwargs:
|
||||
if isinstance(scaled_kwargs["pady"], (int, float, str)):
|
||||
scaled_kwargs["pady"] = self.apply_spacing_scaling(scaled_kwargs["pady"])
|
||||
elif isinstance(scaled_kwargs["pady"], tuple):
|
||||
scaled_kwargs["pady"] = tuple([self.apply_spacing_scaling(v) for v in scaled_kwargs["pady"]])
|
||||
if "padx" in kwargs:
|
||||
if isinstance(scaled_kwargs["padx"], (int, float, str)):
|
||||
scaled_kwargs["padx"] = self.apply_spacing_scaling(scaled_kwargs["padx"])
|
||||
elif isinstance(scaled_kwargs["padx"], tuple):
|
||||
scaled_kwargs["padx"] = tuple([self.apply_spacing_scaling(v) for v in scaled_kwargs["padx"]])
|
||||
|
||||
if "x" in scaled_kwargs:
|
||||
scaled_kwargs["x"] = self.apply_spacing_scaling(scaled_kwargs["x"])
|
||||
if "y" in scaled_kwargs:
|
||||
scaled_kwargs["y"] = self.apply_spacing_scaling(scaled_kwargs["y"])
|
||||
|
||||
return scaled_kwargs
|
||||
|
||||
def config(self, *args, **kwargs):
|
||||
self.configure(*args, **kwargs)
|
||||
|
||||
@ -77,9 +121,9 @@ class CTkBaseClass(tkinter.Frame):
|
||||
|
||||
def update_dimensions_event(self, event):
|
||||
# only redraw if dimensions changed (for performance)
|
||||
if self.width != math.floor(event.width * self.scaling) or self.height != math.floor(event.height * self.scaling):
|
||||
self.width = event.width / self.scaling # adjust current size according to new size given by event
|
||||
self.height = event.height / self.scaling # width and height are independent of the scale
|
||||
if self.current_width != round(event.width / self.widget_scaling) or self.current_height != round(event.height / self.widget_scaling):
|
||||
self.current_width = round(event.width / self.widget_scaling) # adjust current size according to new size given by event
|
||||
self.current_height = round(event.height / self.widget_scaling) # current_width and current_height are independent of the scale
|
||||
|
||||
self.draw(no_color_updates=True) # faster drawing without color changes
|
||||
|
||||
@ -115,28 +159,44 @@ class CTkBaseClass(tkinter.Frame):
|
||||
|
||||
self.draw()
|
||||
|
||||
def set_scaling(self, new_scaling):
|
||||
self.scaling = new_scaling
|
||||
def set_scaling(self, new_widget_scaling, new_spacing_scaling, new_window_scaling):
|
||||
self.widget_scaling = new_widget_scaling
|
||||
self.spacing_scaling = new_spacing_scaling
|
||||
|
||||
super().configure(width=self.width * self.scaling, height=self.height * self.scaling)
|
||||
super().configure(width=self.apply_widget_scaling(self.desired_width), height=self.apply_widget_scaling(self.desired_height))
|
||||
|
||||
if self.last_geometry_manager_call is not None:
|
||||
self.last_geometry_manager_call["function"](**self.apply_argument_scaling(self.last_geometry_manager_call["kwargs"]))
|
||||
|
||||
def apply_widget_scaling(self, value):
|
||||
if isinstance(value, (int, float)):
|
||||
return value * self.widget_scaling
|
||||
else:
|
||||
return value
|
||||
|
||||
def apply_spacing_scaling(self, value):
|
||||
if isinstance(value, (int, float)):
|
||||
return value * self.spacing_scaling
|
||||
else:
|
||||
return value
|
||||
|
||||
def apply_font_scaling(self, font):
|
||||
if type(font) == tuple or type(font) == list:
|
||||
font_list = list(font)
|
||||
for i in range(len(font_list)):
|
||||
if (type(font_list[i]) == int or type(font_list[i]) == float) and font_list[i] < 0:
|
||||
font_list[i] = int(font_list[i] * self.scaling)
|
||||
font_list[i] = int(font_list[i] * self.widget_scaling)
|
||||
return tuple(font_list)
|
||||
|
||||
elif type(font) == str:
|
||||
for negative_number in re.findall(r" -\d* ", font):
|
||||
font = font.replace(negative_number, f" {int(int(negative_number) * self.scaling)} ")
|
||||
font = font.replace(negative_number, f" {int(int(negative_number) * self.widget_scaling)} ")
|
||||
return font
|
||||
|
||||
elif isinstance(font, tkinter.font.Font):
|
||||
new_font_object = copy.copy(font)
|
||||
if font.cget("size") < 0:
|
||||
new_font_object.config(size=int(font.cget("size") * self.scaling))
|
||||
new_font_object.config(size=int(font.cget("size") * self.widget_scaling))
|
||||
return new_font_object
|
||||
|
||||
else:
|
||||
|
Reference in New Issue
Block a user