completed scaling

This commit is contained in:
Tom Schimansky
2022-05-01 23:29:14 +02:00
parent c3c7d1a5de
commit cb12711b5c
22 changed files with 485 additions and 217 deletions

View File

@ -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: