mirror of
https://github.com/TomSchimansky/CustomTkinter.git
synced 2023-08-10 21:13:13 +03:00
restructured settings, small scaling fixes in CTk
This commit is contained in:
@@ -9,32 +9,30 @@ from .appearance_mode_tracker import AppearanceModeTracker
|
||||
from .theme_manager import ThemeManager
|
||||
from .scaling_tracker import ScalingTracker
|
||||
from .font_manager import FontManager
|
||||
|
||||
Settings.init_font_character_mapping()
|
||||
Settings.init_drawing_method()
|
||||
from .draw_engine import DrawEngine
|
||||
|
||||
AppearanceModeTracker.init_appearance_mode()
|
||||
|
||||
ThemeManager.load_theme("blue")
|
||||
|
||||
FontManager.init_font_manager()
|
||||
|
||||
# determine draw method based on current platform
|
||||
if sys.platform == "darwin":
|
||||
DrawEngine.preferred_drawing_method = "polygon_shapes"
|
||||
else:
|
||||
DrawEngine.preferred_drawing_method = "font_shapes"
|
||||
|
||||
# load Roboto fonts
|
||||
script_directory = os.path.dirname(os.path.abspath(__file__))
|
||||
FontManager.load_font(os.path.join(script_directory, "assets", "fonts", "Roboto", "Roboto-Regular.ttf"))
|
||||
FontManager.load_font(os.path.join(script_directory, "assets", "fonts", "Roboto", "Roboto-Medium.ttf"))
|
||||
|
||||
# load font necessary for rendering the widgets on Windows, Linux
|
||||
if FontManager.load_font(os.path.join(script_directory, "assets", "fonts", "CustomTkinter_shapes_font-fine.otf")) is True:
|
||||
Settings.circle_font_is_ready = True
|
||||
else:
|
||||
Settings.circle_font_is_ready = False
|
||||
|
||||
if Settings.preferred_drawing_method == "font_shapes":
|
||||
if FontManager.load_font(os.path.join(script_directory, "assets", "fonts", "CustomTkinter_shapes_font-fine.otf")) is False:
|
||||
if DrawEngine.preferred_drawing_method == "font_shapes":
|
||||
sys.stderr.write("customtkinter.__init__ warning: " +
|
||||
"Preferred drawing method 'font_shapes' can not be used because the font file could not be loaded.\n" +
|
||||
"Using 'circle_shapes' instead. The rendering quality will be bad!")
|
||||
Settings.preferred_drawing_method = "circle_shapes"
|
||||
DrawEngine.preferred_drawing_method = "circle_shapes"
|
||||
|
||||
# import widgets
|
||||
from .widgets.ctk_button import CTkButton
|
||||
@@ -69,10 +67,10 @@ def set_default_color_theme(color_string):
|
||||
ThemeManager.load_theme(color_string)
|
||||
|
||||
|
||||
def deactivate_dpi_awareness(deactivate_awareness: bool):
|
||||
Settings.deactivate_automatic_dpi_awareness = deactivate_awareness
|
||||
|
||||
|
||||
def set_user_scaling(scaling_value: float):
|
||||
ScalingTracker.set_spacing_scaling(scaling_value)
|
||||
ScalingTracker.set_widget_scaling(scaling_value)
|
||||
|
||||
|
||||
def deactivate_automatic_dpi_awareness():
|
||||
ScalingTracker.deactivate_automatic_dpi_awareness = False
|
||||
|
||||
@@ -98,7 +98,7 @@ class AppearanceModeTracker:
|
||||
# find an existing tkinter.Tk object for the next call of .after()
|
||||
for root_tk in cls.root_tk_list:
|
||||
try:
|
||||
root_tk.after(200, cls.update)
|
||||
root_tk.after(500, cls.update)
|
||||
return
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
"radiobutton_border_width_unchecked": 3,
|
||||
"radiobutton_border_width_checked": 6,
|
||||
"entry_border_width": 2,
|
||||
"frame_corner_radius": 10,
|
||||
"frame_corner_radius": 8,
|
||||
"frame_border_width": 0,
|
||||
"label_corner_radius": 8,
|
||||
"progressbar_border_width": 0,
|
||||
@@ -65,4 +65,4 @@
|
||||
"switch_button_corner_radius": 1000,
|
||||
"switch_button_length": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
from __future__ import annotations
|
||||
import sys
|
||||
import math
|
||||
import tkinter
|
||||
from typing import Union
|
||||
from typing import Union, TYPE_CHECKING
|
||||
|
||||
from .widgets.ctk_canvas import CTkCanvas
|
||||
if TYPE_CHECKING:
|
||||
from .widgets.ctk_canvas import CTkCanvas
|
||||
|
||||
|
||||
class DrawEngine:
|
||||
@@ -21,25 +23,26 @@ class DrawEngine:
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, canvas: CTkCanvas, rendering_method: str):
|
||||
preferred_drawing_method: str = None # 'polygon_shapes', 'font_shapes', 'circle_shapes'
|
||||
|
||||
def __init__(self, canvas: CTkCanvas):
|
||||
self._canvas = canvas
|
||||
self._rendering_method = rendering_method # "polygon_shapes" (macOS), "font_shapes" (Windows, Linux), "circle_shapes" (backup without fonts)
|
||||
self._existing_tags = set()
|
||||
|
||||
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":
|
||||
if self.preferred_drawing_method == "polygon_shapes":
|
||||
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":
|
||||
elif self.preferred_drawing_method == "font_shapes":
|
||||
return round(user_corner_radius)
|
||||
|
||||
# optimize for drawing with circles and rects
|
||||
elif self._rendering_method == "circle_shapes":
|
||||
elif self.preferred_drawing_method == "circle_shapes":
|
||||
user_corner_radius = 0.5 * round(user_corner_radius / 0.5) # round to 0.5 steps
|
||||
|
||||
# make sure the value is always with .5 at the end for smoother corners
|
||||
@@ -71,11 +74,11 @@ class DrawEngine:
|
||||
else:
|
||||
inner_corner_radius = 0
|
||||
|
||||
if self._rendering_method == "polygon_shapes":
|
||||
if self.preferred_drawing_method == "polygon_shapes":
|
||||
return self._draw_rounded_rect_with_border_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius)
|
||||
elif self._rendering_method == "font_shapes":
|
||||
elif self.preferred_drawing_method == "font_shapes":
|
||||
return self._draw_rounded_rect_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, ())
|
||||
elif self._rendering_method == "circle_shapes":
|
||||
elif self.preferred_drawing_method == "circle_shapes":
|
||||
return self._draw_rounded_rect_with_border_circle_shapes(width, height, corner_radius, border_width, inner_corner_radius)
|
||||
|
||||
def _draw_rounded_rect_with_border_polygon_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int) -> bool:
|
||||
@@ -365,10 +368,10 @@ class DrawEngine:
|
||||
else:
|
||||
inner_corner_radius = 0
|
||||
|
||||
if self._rendering_method == "polygon_shapes" or self._rendering_method == "circle_shapes":
|
||||
if self.preferred_drawing_method == "polygon_shapes" or self.preferred_drawing_method == "circle_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":
|
||||
elif self.preferred_drawing_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)
|
||||
|
||||
@@ -534,10 +537,10 @@ class DrawEngine:
|
||||
else:
|
||||
inner_corner_radius = 0
|
||||
|
||||
if self._rendering_method == "polygon_shapes" or self._rendering_method == "circle_shapes":
|
||||
if self.preferred_drawing_method == "polygon_shapes" or self.preferred_drawing_method == "circle_shapes":
|
||||
return self._draw_rounded_slider_with_border_and_button_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius,
|
||||
button_length, button_corner_radius, slider_value, orientation)
|
||||
elif self._rendering_method == "font_shapes":
|
||||
elif self.preferred_drawing_method == "font_shapes":
|
||||
return self._draw_rounded_slider_with_border_and_button_font_shapes(width, height, corner_radius, border_width, inner_corner_radius,
|
||||
button_length, button_corner_radius, slider_value, orientation)
|
||||
|
||||
@@ -659,7 +662,7 @@ class DrawEngine:
|
||||
size = round(size)
|
||||
requires_recoloring = False
|
||||
|
||||
if self._rendering_method == "polygon_shapes" or self._rendering_method == "circle_shapes":
|
||||
if self.preferred_drawing_method == "polygon_shapes" or self.preferred_drawing_method == "circle_shapes":
|
||||
x, y, radius = width / 2, height / 2, size / 2.8
|
||||
if not self._canvas.find_withtag("checkmark"):
|
||||
self._canvas.create_line(0, 0, 0, 0, tags=("checkmark", "create_line"), width=round(height / 8), joinstyle=tkinter.MITER, capstyle=tkinter.ROUND)
|
||||
@@ -670,7 +673,7 @@ class DrawEngine:
|
||||
x + radius, y - radius,
|
||||
x - radius / 4, y + radius * 0.8,
|
||||
x - radius, y + radius / 6)
|
||||
elif self._rendering_method == "font_shapes":
|
||||
elif self.preferred_drawing_method == "font_shapes":
|
||||
if not self._canvas.find_withtag("checkmark"):
|
||||
self._canvas.create_text(0, 0, text="Z", font=("CustomTkinter_shapes_font", -size), tags=("checkmark", "create_text"), anchor=tkinter.CENTER)
|
||||
self._canvas.tag_raise("checkmark")
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import tkinter
|
||||
import sys
|
||||
from typing import Callable, Type
|
||||
|
||||
from .settings import Settings
|
||||
from typing import Callable
|
||||
|
||||
|
||||
class ScalingTracker:
|
||||
deactivate_automatic_dpi_awareness = False
|
||||
|
||||
window_widgets_dict = {} # contains window objects as keys with list of widget callbacks as elements
|
||||
window_dpi_scaling_dict = {} # contains window objects as keys and corresponding scaling factors
|
||||
@@ -34,17 +33,17 @@ class ScalingTracker:
|
||||
@classmethod
|
||||
def set_widget_scaling(cls, widget_scaling_factor: float):
|
||||
cls.widget_scaling = max(widget_scaling_factor, 0.4)
|
||||
cls.update_scaling_callbacks()
|
||||
cls.update_scaling_callbacks_all()
|
||||
|
||||
@classmethod
|
||||
def set_spacing_scaling(cls, spacing_scaling_factor: float):
|
||||
cls.spacing_scaling = max(spacing_scaling_factor, 0.4)
|
||||
cls.update_scaling_callbacks()
|
||||
cls.update_scaling_callbacks_all()
|
||||
|
||||
@classmethod
|
||||
def set_window_scaling(cls, window_scaling_factor: float):
|
||||
cls.window_scaling = max(window_scaling_factor, 0.4)
|
||||
cls.update_scaling_callbacks()
|
||||
cls.update_scaling_callbacks_all()
|
||||
|
||||
@classmethod
|
||||
def get_window_root_of_widget(cls, widget):
|
||||
@@ -57,17 +56,29 @@ class ScalingTracker:
|
||||
return current_widget
|
||||
|
||||
@classmethod
|
||||
def update_scaling_callbacks(cls):
|
||||
def update_scaling_callbacks_all(cls):
|
||||
for window, callback_list in cls.window_widgets_dict.items():
|
||||
for callback in callback_list:
|
||||
if not Settings.deactivate_automatic_dpi_awareness:
|
||||
callback(cls.window_dpi_scaling_dict[window] * cls.widget_scaling,
|
||||
cls.window_dpi_scaling_dict[window] * cls.spacing_scaling,
|
||||
cls.window_dpi_scaling_dict[window] * cls.window_scaling)
|
||||
for set_scaling_callback in callback_list:
|
||||
if not cls.deactivate_automatic_dpi_awareness:
|
||||
set_scaling_callback(cls.window_dpi_scaling_dict[window] * cls.widget_scaling,
|
||||
cls.window_dpi_scaling_dict[window] * cls.spacing_scaling,
|
||||
cls.window_dpi_scaling_dict[window] * cls.window_scaling)
|
||||
else:
|
||||
callback(cls.widget_scaling,
|
||||
cls.spacing_scaling,
|
||||
cls.window_scaling)
|
||||
set_scaling_callback(cls.widget_scaling,
|
||||
cls.spacing_scaling,
|
||||
cls.window_scaling)
|
||||
|
||||
@classmethod
|
||||
def update_scaling_callbacks_for_window(cls, window):
|
||||
for set_scaling_callback in cls.window_widgets_dict[window]:
|
||||
if not cls.deactivate_automatic_dpi_awareness:
|
||||
set_scaling_callback(cls.window_dpi_scaling_dict[window] * cls.widget_scaling,
|
||||
cls.window_dpi_scaling_dict[window] * cls.spacing_scaling,
|
||||
cls.window_dpi_scaling_dict[window] * cls.window_scaling)
|
||||
else:
|
||||
set_scaling_callback(cls.widget_scaling,
|
||||
cls.spacing_scaling,
|
||||
cls.window_scaling)
|
||||
|
||||
@classmethod
|
||||
def add_widget(cls, widget_callback: Callable, widget):
|
||||
@@ -81,9 +92,9 @@ class ScalingTracker:
|
||||
if window_root not in cls.window_dpi_scaling_dict:
|
||||
cls.window_dpi_scaling_dict[window_root] = cls.get_window_dpi_scaling(window_root)
|
||||
|
||||
#if not cls.update_loop_running:
|
||||
# window_root.after(100, cls.check_dpi_scaling)
|
||||
# cls.update_loop_running = True
|
||||
if not cls.update_loop_running:
|
||||
window_root.after(100, cls.check_dpi_scaling)
|
||||
cls.update_loop_running = True
|
||||
|
||||
@classmethod
|
||||
def remove_widget(cls, widget_callback, widget):
|
||||
@@ -115,7 +126,7 @@ class ScalingTracker:
|
||||
""" make process DPI aware, customtkinter elemets will get scaled automatically,
|
||||
only gets activated when CTk object is created """
|
||||
|
||||
if not Settings.deactivate_automatic_dpi_awareness:
|
||||
if not cls.deactivate_automatic_dpi_awareness:
|
||||
if sys.platform == "darwin":
|
||||
pass # high DPI scaling works automatically on macOS
|
||||
|
||||
@@ -151,10 +162,16 @@ class ScalingTracker:
|
||||
# check for every window if scaling value changed
|
||||
# (not implemented yet)
|
||||
|
||||
for window in cls.window_widgets_dict:
|
||||
current_dpi_scaling_value = cls.get_window_dpi_scaling(window)
|
||||
if current_dpi_scaling_value != cls.window_dpi_scaling_dict[window]:
|
||||
cls.window_dpi_scaling_dict[window] = current_dpi_scaling_value
|
||||
cls.update_scaling_callbacks_for_window(window)
|
||||
|
||||
# find an existing tkinter object for the next call of .after()
|
||||
for root_tk in cls.window_widgets_dict.keys():
|
||||
try:
|
||||
root_tk.after(500, cls.check_dpi_scaling)
|
||||
root_tk.after(200, cls.check_dpi_scaling)
|
||||
return
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
@@ -1,42 +1,5 @@
|
||||
import sys
|
||||
|
||||
|
||||
class Settings:
|
||||
|
||||
circle_font_is_ready = False
|
||||
preferred_drawing_method: str = None # 'polygon_shapes', 'font_shapes', 'circle_shapes'
|
||||
radius_to_char_fine: dict = None # set in self.init_font_character_mapping()
|
||||
cursor_manipulation_enabled = True
|
||||
deactivate_macos_window_header_manipulation = False
|
||||
deactivate_windows_window_header_manipulation = False
|
||||
deactivate_automatic_dpi_awareness = False
|
||||
|
||||
@classmethod
|
||||
def init_font_character_mapping(cls):
|
||||
""" optimizations made for Windows 10, 11 only """
|
||||
|
||||
radius_to_char_warped = {19: 'B', 18: 'B', 17: 'B', 16: 'B', 15: 'B', 14: 'B', 13: 'B', 12: 'B', 11: 'B', 10: 'B',
|
||||
9: 'C', 8: 'D', 7: 'C', 6: 'E', 5: 'F', 4: 'G', 3: 'H', 2: 'H', 1: 'H', 0: 'A'}
|
||||
|
||||
radius_to_char_fine_windows_10 = {19: 'A', 18: 'A', 17: 'B', 16: 'B', 15: 'B', 14: 'B', 13: 'C', 12: 'C', 11: 'C', 10: 'C',
|
||||
9: 'D', 8: 'D', 7: 'D', 6: 'F', 5: 'D', 4: 'G', 3: 'G', 2: 'H', 1: 'H', 0: 'A'}
|
||||
|
||||
radius_to_char_fine_windows_11 = {19: 'A', 18: 'A', 17: 'B', 16: 'B', 15: 'B', 14: 'B', 13: 'C', 12: 'C', 11: 'D', 10: 'D',
|
||||
9: 'E', 8: 'F', 7: 'C', 6: 'I', 5: 'E', 4: 'G', 3: 'P', 2: 'R', 1: 'R', 0: 'A'}
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
if sys.getwindowsversion().build > 20000: # Windows 11
|
||||
cls.radius_to_char_fine = radius_to_char_fine_windows_11
|
||||
else: # < Windows 11
|
||||
cls.radius_to_char_fine = radius_to_char_fine_windows_10
|
||||
else: # macOS and Linux
|
||||
cls.radius_to_char_fine = radius_to_char_fine_windows_10
|
||||
|
||||
@classmethod
|
||||
def init_drawing_method(cls):
|
||||
""" possible: 'polygon_shapes', 'font_shapes', 'circle_shapes' """
|
||||
|
||||
if sys.platform == "darwin":
|
||||
cls.preferred_drawing_method = "polygon_shapes"
|
||||
else:
|
||||
cls.preferred_drawing_method = "font_shapes"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
from .ctk_canvas import CTkCanvas
|
||||
|
||||
CTkCanvas.init_font_character_mapping()
|
||||
|
||||
@@ -69,7 +69,7 @@ class CTkButton(CTkBaseClass):
|
||||
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 = DrawEngine(self.canvas, Settings.preferred_drawing_method)
|
||||
self.draw_engine = DrawEngine(self.canvas)
|
||||
|
||||
# event bindings
|
||||
self.canvas.bind("<Enter>", self.on_enter)
|
||||
|
||||
@@ -1,23 +1,50 @@
|
||||
import tkinter
|
||||
from ..settings import Settings
|
||||
import sys
|
||||
from typing import Union
|
||||
|
||||
|
||||
class CTkCanvas(tkinter.Canvas):
|
||||
|
||||
radius_to_char_fine = Settings.radius_to_char_fine # dict to map radius to font circle character
|
||||
radius_to_char_fine: dict = None # dict to map radius to font circle character
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.aa_circle_canvas_ids = set()
|
||||
|
||||
def get_char_from_radius(self, radius):
|
||||
@classmethod
|
||||
def init_font_character_mapping(cls):
|
||||
""" optimizations made for Windows 10, 11 only """
|
||||
|
||||
radius_to_char_warped = {19: 'B', 18: 'B', 17: 'B', 16: 'B', 15: 'B', 14: 'B', 13: 'B', 12: 'B', 11: 'B',
|
||||
10: 'B',
|
||||
9: 'C', 8: 'D', 7: 'C', 6: 'E', 5: 'F', 4: 'G', 3: 'H', 2: 'H', 1: 'H', 0: 'A'}
|
||||
|
||||
radius_to_char_fine_windows_10 = {19: 'A', 18: 'A', 17: 'B', 16: 'B', 15: 'B', 14: 'B', 13: 'C', 12: 'C',
|
||||
11: 'C', 10: 'C',
|
||||
9: 'D', 8: 'D', 7: 'D', 6: 'F', 5: 'D', 4: 'G', 3: 'G', 2: 'H', 1: 'H',
|
||||
0: 'A'}
|
||||
|
||||
radius_to_char_fine_windows_11 = {19: 'A', 18: 'A', 17: 'B', 16: 'B', 15: 'B', 14: 'B', 13: 'C', 12: 'C',
|
||||
11: 'D', 10: 'D',
|
||||
9: 'E', 8: 'F', 7: 'C', 6: 'I', 5: 'E', 4: 'G', 3: 'P', 2: 'R', 1: 'R',
|
||||
0: 'A'}
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
if sys.getwindowsversion().build > 20000: # Windows 11
|
||||
cls.radius_to_char_fine = radius_to_char_fine_windows_11
|
||||
else: # < Windows 11
|
||||
cls.radius_to_char_fine = radius_to_char_fine_windows_10
|
||||
else: # macOS and Linux
|
||||
cls.radius_to_char_fine = radius_to_char_fine_windows_10
|
||||
|
||||
def get_char_from_radius(self, radius: int) -> str:
|
||||
if radius >= 20:
|
||||
return "A"
|
||||
else:
|
||||
return self.radius_to_char_fine[radius]
|
||||
|
||||
def create_aa_circle(self, x_pos, y_pos, radius, angle=0, fill="white", tags="", anchor=tkinter.CENTER) -> str:
|
||||
def create_aa_circle(self, x_pos: int, y_pos: int, radius: int, angle: int = 0, fill: str = "white",
|
||||
tags: Union[str, tuple[str, ...]] = "", anchor: str = tkinter.CENTER) -> int:
|
||||
# create a circle with a font element
|
||||
circle_1 = self.create_text(x_pos, y_pos, text=self.get_char_from_radius(radius), anchor=anchor, fill=fill,
|
||||
font=("CustomTkinter_shapes_font", -radius * 2), tags=tags, angle=angle)
|
||||
@@ -61,5 +88,3 @@ class CTkCanvas(tkinter.Canvas):
|
||||
super().itemconfigure(configure_id, *args, **kwargs_except_outline)
|
||||
else:
|
||||
super().itemconfigure(configure_id, *args, **kwargs)
|
||||
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ class CTkCheckBox(CTkBaseClass):
|
||||
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 = DrawEngine(self.canvas, Settings.preferred_drawing_method)
|
||||
self.draw_engine = DrawEngine(self.canvas)
|
||||
|
||||
if self.hover is True:
|
||||
self.canvas.bind("<Enter>", self.on_enter)
|
||||
|
||||
@@ -50,7 +50,7 @@ class CTkEntry(CTkBaseClass):
|
||||
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 = DrawEngine(self.canvas, Settings.preferred_drawing_method)
|
||||
self.draw_engine = DrawEngine(self.canvas)
|
||||
|
||||
self.entry = tkinter.Entry(master=self,
|
||||
bd=0,
|
||||
|
||||
@@ -45,7 +45,7 @@ class CTkFrame(CTkBaseClass):
|
||||
height=self.apply_widget_scaling(self.current_height))
|
||||
self.canvas.place(x=0, y=0, relwidth=1, relheight=1)
|
||||
self.canvas.configure(bg=ThemeManager.single_color(self.bg_color, self.appearance_mode))
|
||||
self.draw_engine = DrawEngine(self.canvas, Settings.preferred_drawing_method)
|
||||
self.draw_engine = DrawEngine(self.canvas)
|
||||
|
||||
self.bind('<Configure>', self.update_dimensions_event)
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class CTkLabel(CTkBaseClass):
|
||||
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 = DrawEngine(self.canvas, Settings.preferred_drawing_method)
|
||||
self.draw_engine = DrawEngine(self.canvas)
|
||||
|
||||
self.text_label = tkinter.Label(master=self,
|
||||
highlightthickness=0,
|
||||
|
||||
@@ -62,7 +62,7 @@ class CTkProgressBar(CTkBaseClass):
|
||||
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 = DrawEngine(self.canvas, Settings.preferred_drawing_method)
|
||||
self.draw_engine = DrawEngine(self.canvas)
|
||||
|
||||
# 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_event)
|
||||
|
||||
@@ -79,7 +79,7 @@ class CTkRadioButton(CTkBaseClass):
|
||||
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 = DrawEngine(self.canvas, Settings.preferred_drawing_method)
|
||||
self.draw_engine = DrawEngine(self.canvas)
|
||||
|
||||
self.canvas.bind("<Enter>", self.on_enter)
|
||||
self.canvas.bind("<Leave>", self.on_leave)
|
||||
|
||||
@@ -84,7 +84,7 @@ class CTkSlider(CTkBaseClass):
|
||||
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 = DrawEngine(self.canvas, Settings.preferred_drawing_method)
|
||||
self.draw_engine = DrawEngine(self.canvas)
|
||||
|
||||
self.canvas.bind("<Enter>", self.on_enter)
|
||||
self.canvas.bind("<Leave>", self.on_leave)
|
||||
|
||||
@@ -84,7 +84,7 @@ class CTkSwitch(CTkBaseClass):
|
||||
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 = DrawEngine(self.canvas, Settings.preferred_drawing_method)
|
||||
self.draw_engine = DrawEngine(self.canvas)
|
||||
|
||||
self.canvas.bind("<Enter>", self.on_enter)
|
||||
self.canvas.bind("<Leave>", self.on_leave)
|
||||
|
||||
@@ -69,24 +69,21 @@ class CTk(tkinter.Tk):
|
||||
if self.current_width != round(detected_width / self.window_scaling) or self.current_height != round(detected_height / self.window_scaling):
|
||||
self.current_width = round(detected_width / self.window_scaling) # adjust current size according to new size given by event
|
||||
self.current_height = round(detected_height / self.window_scaling) # current_width and current_height are independent of the scale
|
||||
print("update_dimensions_event:", self.current_width)
|
||||
|
||||
def set_scaling(self, new_widget_scaling, new_spacing_scaling, new_window_scaling):
|
||||
self.window_scaling = new_window_scaling
|
||||
|
||||
# reset min, max and resizable constraints for applying scaling
|
||||
if self.last_resizable_args is not None:
|
||||
super().resizable(True, True)
|
||||
if self.min_width is not None or self.min_height is not None:
|
||||
super().minsize(0, 0)
|
||||
if self.max_width is not None or self.max_height is not None:
|
||||
super().maxsize(1_000_000, 1_000_000)
|
||||
# force new dimensions on window by using min, max, and geometry
|
||||
super().minsize(self.apply_window_scaling(self.current_width), self.apply_window_scaling(self.current_height))
|
||||
super().maxsize(self.apply_window_scaling(self.current_width), self.apply_window_scaling(self.current_height))
|
||||
super().geometry(f"{self.apply_window_scaling(self.current_width)}x"+f"{self.apply_window_scaling(self.current_height)}")
|
||||
print("set_scaling:", self.apply_window_scaling(self.current_width), self.max_width, self.min_width)
|
||||
|
||||
# set new window size by applying scaling to the current window size
|
||||
self.geometry(f"{self.current_width}x{self.current_height}")
|
||||
# set new scaled min and max with 400ms delay (otherwise it won't work for some reason)
|
||||
self.after(400, self.set_scaled_min_max)
|
||||
|
||||
# set scaled min, max sizes and reapply resizable
|
||||
if self.last_resizable_args is not None:
|
||||
super().resizable(*self.last_resizable_args[0], **self.last_resizable_args[1]) # args, kwargs
|
||||
def set_scaled_min_max(self):
|
||||
if self.min_width is not None or self.min_height is not None:
|
||||
super().minsize(self.apply_window_scaling(self.min_width), self.apply_window_scaling(self.min_height))
|
||||
if self.max_width is not None or self.max_height is not None:
|
||||
@@ -106,6 +103,7 @@ class CTk(tkinter.Tk):
|
||||
|
||||
def mainloop(self, *args, **kwargs):
|
||||
if not self.window_exists:
|
||||
print("deiconify")
|
||||
self.deiconify()
|
||||
self.window_exists = True
|
||||
super().mainloop(*args, **kwargs)
|
||||
@@ -135,6 +133,7 @@ class CTk(tkinter.Tk):
|
||||
super().maxsize(self.apply_window_scaling(self.max_width), self.apply_window_scaling(self.max_height))
|
||||
|
||||
def geometry(self, geometry_string):
|
||||
print("geometry:", geometry_string)
|
||||
super().geometry(self.apply_geometry_scaling(geometry_string))
|
||||
|
||||
# update width and height attributes
|
||||
|
||||
Reference in New Issue
Block a user