diff --git a/CHANGELOG.md b/CHANGELOG.md index bb6d168..3490b3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ToDo: - add new button attributes to wiki - cursor configuring - overwrite winfo methods + - renew input dialog ## Unreleased - 2022-10-2 ### Added diff --git a/Readme.md b/Readme.md index 24af68c..419b096 100644 --- a/Readme.md +++ b/Readme.md @@ -1,5 +1,6 @@ ![PyPI](https://img.shields.io/pypi/v/customtkinter) -![PyPI - Downloads](https://img.shields.io/pypi/dm/customtkinter?color=green&label=pip%20downloads) +![PyPI - Downloads](https://img.shields.io/pypi/dm/customtkinter?color=green&label=downloads) +![Downloads](https://static.pepy.tech/personalized-badge/customtkinter?period=total&units=international_system&left_color=grey&right_color=green&left_text=downloads) ![PyPI - License](https://img.shields.io/pypi/l/customtkinter) ![Total lines](https://img.shields.io/tokei/lines/github.com/tomschimansky/customtkinter?color=green&label=total%20lines) diff --git a/customtkinter/assets/themes/blue.json b/customtkinter/assets/themes/blue.json index 1eb6db9..b97fb2c 100644 --- a/customtkinter/assets/themes/blue.json +++ b/customtkinter/assets/themes/blue.json @@ -12,7 +12,7 @@ "frame_border": ["#979DA2", "#565B5E"], "frame_low": ["#D1D5D8", "#2A2D2E"], "frame_high": ["#C0C2C5", "#343638"], - "label": [null, null], + "label": "transparent", "text": ["gray10", "#DCE4EE"], "text_disabled": ["gray60", "gray45"], "text_button": ["#DCE4EE", "#DCE4EE"], @@ -78,7 +78,6 @@ "slider_button_corner_radius": 1000, "switch_border_width": 3, "switch_corner_radius": 1000, - "switch_button_corner_radius": 1000, "switch_button_length": 0, "scrollbar_corner_radius": 1000, "scrollbar_border_spacing": 4 diff --git a/customtkinter/windows/ctk_input_dialog.py b/customtkinter/windows/ctk_input_dialog.py index 6da4d96..e594716 100644 --- a/customtkinter/windows/ctk_input_dialog.py +++ b/customtkinter/windows/ctk_input_dialog.py @@ -15,20 +15,20 @@ class CTkInputDialog(CTkToplevel): def __init__(self, master: any = None, - fg_color: Union[str, Tuple[str, str]] = "default_theme", - button_fg_color: Union[str, Tuple[str, str]] = "default_theme", - button_hover_color: Union[str, Tuple[str, str]] = "default_theme", - text_color: Union[str, Tuple[str, str]] = "default_theme", + fg_color: Union[str, Tuple[str, str]] = "default", + button_fg_color: Union[str, Tuple[str, str]] = "default", + button_hover_color: Union[str, Tuple[str, str]] = "default", + text_color: Union[str, Tuple[str, str]] = "default", title: str = "CTkDialog", text: str = "CTkDialog"): super().__init__(master=master, fg_color=fg_color) - self._fg_color = ThemeManager.theme["color"]["window"] if fg_color == "default_theme" else fg_color - self._button_fg_color = ThemeManager.theme["color"]["button"] if button_fg_color == "default_theme" else button_fg_color - self._button_hover_color = ThemeManager.theme["color"]["button_hover"] if button_hover_color == "default_theme" else button_hover_color - self._text_color = ThemeManager.theme["color"]["text"] if button_hover_color == "default_theme" else button_hover_color + self._fg_color = ThemeManager.theme["color"]["window"] if fg_color == "default" else fg_color + self._button_fg_color = ThemeManager.theme["color"]["button"] if button_fg_color == "default" else button_fg_color + self._button_hover_color = ThemeManager.theme["color"]["button_hover"] if button_hover_color == "default" else button_hover_color + self._text_color = ThemeManager.theme["color"]["text"] if button_hover_color == "default" else button_hover_color self._user_input: Union[str, None] = None self._running: bool = False self._height: int = len(text.split("\n")) * 20 + 150 diff --git a/customtkinter/windows/ctk_tk.py b/customtkinter/windows/ctk_tk.py index e74730b..53b8467 100644 --- a/customtkinter/windows/ctk_tk.py +++ b/customtkinter/windows/ctk_tk.py @@ -4,7 +4,7 @@ import sys import os import platform import ctypes -from typing import Union, Tuple +from typing import Union, Tuple, Optional from .widgets.theme.theme_manager import ThemeManager from .widgets.scaling.scaling_base_class import CTkScalingBaseClass @@ -19,17 +19,17 @@ class CTk(tkinter.Tk, CTkAppearanceModeBaseClass, CTkScalingBaseClass): For detailed information check out the documentation. """ - _valid_tk_constructor_arguments = {"screenName", "baseName", "className", "useTk", "sync", "use"} + _valid_tk_constructor_arguments: set = {"screenName", "baseName", "className", "useTk", "sync", "use"} - _valid_tk_configure_arguments = {'bd', 'borderwidth', 'class', 'menu', 'relief', 'screen', - 'use', 'container', 'cursor', 'height', - 'highlightthickness', 'padx', 'pady', 'takefocus', 'visual', 'width'} + _valid_tk_configure_arguments: set = {'bd', 'borderwidth', 'class', 'menu', 'relief', 'screen', + 'use', 'container', 'cursor', 'height', + 'highlightthickness', 'padx', 'pady', 'takefocus', 'visual', 'width'} - _deactivate_macos_window_header_manipulation = False - _deactivate_windows_window_header_manipulation = False + _deactivate_macos_window_header_manipulation: bool = False + _deactivate_windows_window_header_manipulation: bool = False def __init__(self, - fg_color: Union[str, Tuple[str, str]] = "default_theme", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, **kwargs): self._enable_macos_dark_title_bar() @@ -48,7 +48,7 @@ class CTk(tkinter.Tk, CTkAppearanceModeBaseClass, CTkScalingBaseClass): self._max_height: int = 1_000_000 self._last_resizable_args: Union[Tuple[list, dict], None] = None # (args, kwargs) - self._fg_color = ThemeManager.theme["color"]["window"] if fg_color == "default_theme" else fg_color + self._fg_color = ThemeManager.theme["color"]["window"] if fg_color is None else self._check_color_type(fg_color) # set bg of tkinter.Tk super().configure(bg=self._apply_appearance_mode(self._fg_color)) @@ -195,7 +195,7 @@ class CTk(tkinter.Tk, CTkAppearanceModeBaseClass, CTkScalingBaseClass): def configure(self, **kwargs): if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color")) super().configure(bg=self._apply_appearance_mode(self._fg_color)) for child in self.winfo_children(): diff --git a/customtkinter/windows/ctk_toplevel.py b/customtkinter/windows/ctk_toplevel.py index d26a6ac..2075618 100644 --- a/customtkinter/windows/ctk_toplevel.py +++ b/customtkinter/windows/ctk_toplevel.py @@ -4,7 +4,7 @@ import sys import os import platform import ctypes -from typing import Union, Tuple +from typing import Union, Tuple, Optional from .widgets.theme.theme_manager import ThemeManager from .widgets.scaling.scaling_base_class import CTkScalingBaseClass @@ -19,15 +19,15 @@ class CTkToplevel(tkinter.Toplevel, CTkAppearanceModeBaseClass, CTkScalingBaseCl For detailed information check out the documentation. """ - _valid_tk_toplevel_arguments = {"bd", "borderwidth", "class", "container", "cursor", "height", + _valid_tk_toplevel_arguments: set = {"bd", "borderwidth", "class", "container", "cursor", "height", "highlightbackground", "highlightthickness", "menu", "relief", "screen", "takefocus", "use", "visual", "width"} - _deactivate_macos_window_header_manipulation = False - _deactivate_windows_window_header_manipulation = False + _deactivate_macos_window_header_manipulation: bool = False + _deactivate_windows_window_header_manipulation: bool = False def __init__(self, *args, - fg_color: Union[str, Tuple[str, str]] = "default_theme", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, **kwargs): self._enable_macos_dark_title_bar() @@ -46,7 +46,7 @@ class CTkToplevel(tkinter.Toplevel, CTkAppearanceModeBaseClass, CTkScalingBaseCl self._max_height: int = 1_000_000 self._last_resizable_args: Union[Tuple[list, dict], None] = None # (args, kwargs) - self._fg_color = ThemeManager.theme["color"]["window"] if fg_color == "default_theme" else fg_color + self._fg_color = ThemeManager.theme["color"]["window"] if fg_color is None else self._check_color_type(fg_color) # set bg color of tkinter.Toplevel super().configure(bg=self._apply_appearance_mode(self._fg_color)) @@ -153,7 +153,7 @@ class CTkToplevel(tkinter.Toplevel, CTkAppearanceModeBaseClass, CTkScalingBaseCl def configure(self, **kwargs): if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color")) super().configure(bg=self._apply_appearance_mode(self._fg_color)) for child in self.winfo_children(): diff --git a/customtkinter/windows/widgets/appearance_mode/appearance_mode_base_class.py b/customtkinter/windows/widgets/appearance_mode/appearance_mode_base_class.py index 910d2bf..0d19147 100644 --- a/customtkinter/windows/widgets/appearance_mode/appearance_mode_base_class.py +++ b/customtkinter/windows/widgets/appearance_mode/appearance_mode_base_class.py @@ -44,3 +44,18 @@ class CTkAppearanceModeBaseClass: return color[self.__appearance_mode] else: return color + + @staticmethod + def _check_color_type(color: any, transparency: bool = False): + if color is None: + raise ValueError(f"color is None, for transparency set color='transparent'") + elif isinstance(color, (tuple, list)) and (color[0] == "transparent" or color[1] == "transparent"): + raise ValueError(f"transparency is not allowed in tuple color {color}, use 'transparent'") + elif color == "transparent" and transparency is False: + raise ValueError(f"transparency is not allowed for this attribute") + elif isinstance(color, str): + return color + elif isinstance(color, (tuple, list)) and len(color) == 2 and isinstance(color[0], str) and isinstance(color[1], str): + return color + else: + raise ValueError(f"color {color} must be string ('transparent' or 'color-name' or 'hex-color') or tuple of two strings, not {type(color)}") diff --git a/customtkinter/windows/widgets/core_widget_classes/dropdown_menu.py b/customtkinter/windows/widgets/core_widget_classes/dropdown_menu.py index 846400e..e93b81f 100644 --- a/customtkinter/windows/widgets/core_widget_classes/dropdown_menu.py +++ b/customtkinter/windows/widgets/core_widget_classes/dropdown_menu.py @@ -1,44 +1,38 @@ import tkinter import sys -from typing import Union, Tuple, Callable, List +from typing import Union, Tuple, Callable, List, Optional from ..theme.theme_manager import ThemeManager -from ..scaling.scaling_tracker import ScalingTracker from ..font.ctk_font import CTkFont -from ..appearance_mode.appearance_mode_tracker import AppearanceModeTracker from ..appearance_mode.appearance_mode_base_class import CTkAppearanceModeBaseClass +from ..scaling.scaling_base_class import CTkScalingBaseClass -class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass): +class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass, CTkScalingBaseClass): def __init__(self, *args, min_character_width: int = 18, - fg_color: Union[str, Tuple[str, str]] = "default_theme", - hover_color: Union[str, Tuple[str, str]] = "default_theme", - text_color: Union[str, Tuple[str, str]] = "default_theme", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + hover_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color: Optional[Union[str, Tuple[str, str]]] = None, - font: Union[tuple, CTkFont] = "default_theme", - command: Callable = None, - values: List[str] = None, + font: Optional[Union[tuple, CTkFont]] = None, + command: Union[Callable, None] = None, + values: Optional[List[str]] = None, **kwargs): # call init methods of super classes tkinter.Menu.__init__(self, *args, **kwargs) CTkAppearanceModeBaseClass.__init__(self) - - ScalingTracker.add_widget(self._set_scaling, self) - self._widget_scaling = ScalingTracker.get_widget_scaling(self) - - AppearanceModeTracker.add(self._set_appearance_mode, self) - self._appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark" + CTkScalingBaseClass.__init__(self, scaling_type="widget") self._min_character_width = min_character_width - self._fg_color = ThemeManager.theme["color"]["dropdown_color"] if fg_color == "default_theme" else fg_color - self._hover_color = ThemeManager.theme["color"]["dropdown_hover"] if hover_color == "default_theme" else hover_color - self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color + self._fg_color = ThemeManager.theme["color"]["dropdown_color"] if fg_color is None else self._check_color_type(fg_color) + self._hover_color = ThemeManager.theme["color"]["dropdown_hover"] if hover_color is None else self._check_color_type(hover_color) + self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color) # font - self._font = CTkFont() if font == "default_theme" else self._check_font_type(font) + self._font = CTkFont() if font is None else self._check_font_type(font) if isinstance(self._font, CTkFont): self._font.add_size_configure_callback(self._update_font) @@ -125,16 +119,16 @@ class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass): def configure(self, **kwargs): if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") - super().configure(bg=ThemeManager._apply_appearance_mode(self._fg_color, self._appearance_mode)) + self._fg_color = self._check_color_type(kwargs.pop("fg_color")) + super().configure(bg=self._apply_appearance_mode(self._fg_color)) if "hover_color" in kwargs: - self._hover_color = kwargs.pop("hover_color") - super().configure(activebackground=ThemeManager._apply_appearance_mode(self._hover_color, self._appearance_mode)) + self._hover_color = self._check_color_type(kwargs.pop("hover_color")) + super().configure(activebackground=self._apply_appearance_mode(self._hover_color)) if "text_color" in kwargs: - self._text_color = kwargs.pop("text_color") - super().configure(fg=ThemeManager._apply_appearance_mode(self._text_color, self._appearance_mode)) + self._text_color = self._check_color_type(kwargs.pop("text_color")) + super().configure(fg=self._apply_appearance_mode(self._text_color)) if "font" in kwargs: if isinstance(self._font, CTkFont): @@ -175,29 +169,6 @@ class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass): else: return super().cget(attribute_name) - def _apply_widget_scaling(self, value: Union[int, float, str]) -> Union[float, str]: - if isinstance(value, (int, float)): - return value * self._widget_scaling - else: - return value - - def _apply_font_scaling(self, font: Union[Tuple, CTkFont]) -> tuple: - """ Takes CTkFont object and returns tuple font with scaled size, has to be called again for every change of font object """ - if type(font) == tuple: - if len(font) == 1: - return font - elif len(font) == 2: - return font[0], -abs(round(font[1] * self._widget_scaling)) - elif len(font) == 3: - return font[0], -abs(round(font[1] * self._widget_scaling)), font[2] - else: - raise ValueError(f"Can not scale font {font}. font needs to be tuple of len 1, 2 or 3") - - elif isinstance(font, CTkFont): - return font.create_scaled_tuple(self._widget_scaling) - else: - raise ValueError(f"Can not scale font '{font}' of type {type(font)}. font needs to be tuple or instance of CTkFont") - @staticmethod def _check_font_type(font: any): if isinstance(font, CTkFont): @@ -211,23 +182,17 @@ class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass): return font else: - raise ValueError(f"Wrong font type {type(font)}\n" + + raise ValueError(f"Wrong font type {type(font)} for font '{font}'\n" + f"For consistency, Customtkinter requires the font argument to be a tuple of len 2 or 3 or an instance of CTkFont.\n" + f"\nUsage example:\n" + f"font=customtkinter.CTkFont(family='', size=)\n" + f"font=('', )\n") def _set_scaling(self, new_widget_scaling, new_window_scaling): - self._widget_scaling = new_widget_scaling - + super()._set_scaling(new_widget_scaling, new_window_scaling) self._configure_menu_for_platforms() def _set_appearance_mode(self, mode_string): """ colors won't update on appearance mode change when dropdown is open, because it's not necessary """ - - if mode_string.lower() == "dark": - self._appearance_mode = 1 - elif mode_string.lower() == "light": - self._appearance_mode = 0 - + super()._set_appearance_mode(mode_string) self._configure_menu_for_platforms() diff --git a/customtkinter/windows/widgets/core_widget_classes/widget_base_class.py b/customtkinter/windows/widgets/core_widget_classes/widget_base_class.py index 728e3b5..3cb39d7 100644 --- a/customtkinter/windows/widgets/core_widget_classes/widget_base_class.py +++ b/customtkinter/windows/widgets/core_widget_classes/widget_base_class.py @@ -1,7 +1,7 @@ import sys import tkinter import tkinter.ttk as ttk -from typing import Union, Callable, Tuple +from typing import Union, Callable, Tuple, Optional try: from typing import TypedDict @@ -20,7 +20,7 @@ from ....utility.utility_functions import pop_from_dict_by_set, check_kwargs_emp class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClass): - """ Base class of every CTk widget, handles the dimensions, _bg_color, + """ Base class of every CTk widget, handles the dimensions, bg_color, appearance_mode changes, scaling, bg changes of master if master is not a CTk widget """ # attributes that are passed to and managed by the tkinter frame only: @@ -29,11 +29,11 @@ class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClas _cursor_manipulation_enabled: bool = True def __init__(self, - master: any = None, + master: any, width: int = 0, height: int = 0, - bg_color: Union[str, Tuple[str, str], None] = None, + bg_color: Union[str, Tuple[str, str]] = "transparent", **kwargs): # call init methods of super classes @@ -61,7 +61,7 @@ class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClas self._last_geometry_manager_call: Union[GeometryCallDict, None] = None # background color - self._bg_color: Union[str, Tuple[str, str]] = self._detect_color_of_master() if bg_color is None else bg_color + self._bg_color: Union[str, Tuple[str, str]] = self._detect_color_of_master() if bg_color == "transparent" else self._check_color_type(bg_color, transparency=True) # set bg color of tkinter.Frame super().configure(bg=self._apply_appearance_mode(self._bg_color)) @@ -116,11 +116,11 @@ class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClas self._set_dimensions(height=kwargs.pop("height")) if "bg_color" in kwargs: - new_bg_color = kwargs.pop("bg_color") - if new_bg_color is None: + new_bg_color = self._check_color_type(kwargs.pop("bg_color"), transparency=True) + if new_bg_color == "transparent": self._bg_color = self._detect_color_of_master() else: - self._bg_color = new_bg_color + self._bg_color = self._check_color_type(new_bg_color) require_redraw = True super().configure(**pop_from_dict_by_set(kwargs, self._valid_tk_frame_attributes)) # configure tkinter.Frame @@ -185,13 +185,13 @@ class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClas self._draw(no_color_updates=True) # faster drawing without color changes def _detect_color_of_master(self, master_widget=None) -> Union[str, Tuple[str, str]]: - """ detect color of self.master widget to set correct _bg_color """ + """ detect foreground color of master widget for bg_color and transparent color """ if master_widget is None: master_widget = self.master - if isinstance(master_widget, (CTkBaseClass, CTk, CTkToplevel)) and hasattr(master_widget, "_fg_color"): - if master_widget.cget("fg_color") is not None: + if isinstance(master_widget, (CTkBaseClass, CTk, CTkToplevel)): + if master_widget.cget("fg_color") is not None and master_widget.cget("fg_color") != "transparent": return master_widget.cget("fg_color") # if fg_color of master is None, try to retrieve fg_color from master of master diff --git a/customtkinter/windows/widgets/ctk_button.py b/customtkinter/windows/widgets/ctk_button.py index 9b41c19..e9c6abc 100644 --- a/customtkinter/windows/widgets/ctk_button.py +++ b/customtkinter/windows/widgets/ctk_button.py @@ -1,6 +1,6 @@ import tkinter import sys -from typing import Union, Tuple, Callable +from typing import Union, Tuple, Callable, Optional from .core_rendering.ctk_canvas import CTkCanvas from .theme.theme_manager import ThemeManager @@ -16,80 +16,82 @@ class CTkButton(CTkBaseClass): For detailed information check out the documentation. """ - _image_label_spacing = 6 + _image_label_spacing: int = 6 def __init__(self, - master: any = None, + master: any, width: int = 140, height: int = 28, - corner_radius: Union[int, str] = "default_theme", - border_width: Union[int, str] = "default_theme", + corner_radius: Optional[int] = None, + border_width: Optional[int] = None, border_spacing: int = 2, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str], None] = "default_theme", - hover_color: Union[str, Tuple[str, str]] = "default_theme", - border_color: Union[str, Tuple[str, str]] = "default_theme", - text_color: Union[str, Tuple[str, str]] = "default_theme", - text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + hover_color: Optional[Union[str, Tuple[str, str]]] = None, + border_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None, - background_corner_colors: Tuple[Union[str, Tuple[str, str]]] = None, + background_corner_colors: Union[Tuple[Union[str, Tuple[str, str]]], None] = None, round_width_to_even_numbers: bool = True, round_height_to_even_numbers: bool = True, text: str = "CTkButton", - font: Union[tuple, CTkFont] = "default_theme", - textvariable: tkinter.Variable = None, - image: Union[tkinter.PhotoImage, CTkImage] = None, + font: Optional[Union[tuple, CTkFont]] = None, + textvariable: Union[tkinter.Variable, None] = None, + image: Union[tkinter.PhotoImage, CTkImage, None] = None, state: str = "normal", hover: bool = True, - command: Callable = None, + command: Union[Callable[[], None], None] = None, compound: str = "left", anchor: str = "center", **kwargs): - # transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass + # transfer basic functionality (bg_color, size, appearance_mode, scaling) to CTkBaseClass super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) - # color - self._fg_color = ThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_color - self._hover_color = ThemeManager.theme["color"]["button_hover"] if hover_color == "default_theme" else hover_color - self._border_color = ThemeManager.theme["color"]["button_border"] if border_color == "default_theme" else border_color - self._text_color = ThemeManager.theme["color"]["text_button"] if text_color == "default_theme" else text_color - self._text_color_disabled = ThemeManager.theme["color"]["text_button_disabled"] if text_color_disabled == "default_theme" else text_color_disabled - self._background_corner_colors = background_corner_colors # rendering options for DrawEngine - # shape - self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius - self._border_width = ThemeManager.theme["shape"]["button_border_width"] if border_width == "default_theme" else border_width - self._round_width_to_even_numbers = round_width_to_even_numbers # rendering options for DrawEngine - self._round_height_to_even_numbers = round_height_to_even_numbers # rendering options for DrawEngine - self._corner_radius = min(self._corner_radius, round(self._current_height/2)) - self._compound = compound - self._anchor = anchor - self._border_spacing = border_spacing + self._corner_radius: int = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius is None else corner_radius + self._corner_radius = min(self._corner_radius, round(self._current_height / 2)) + self._border_width: int = ThemeManager.theme["shape"]["button_border_width"] if border_width is None else border_width + self._border_spacing: int = border_spacing - # text, image - self._image = self._check_image_type(image) - self._image_label: Union[tkinter.Label, None] = None + # color + self._fg_color: Union[str, Tuple[str, str]] = ThemeManager.theme["color"]["button"] if fg_color is None else self._check_color_type(fg_color, transparency=True) + self._hover_color: Union[str, Tuple[str, str]] = ThemeManager.theme["color"]["button_hover"] if hover_color is None else self._check_color_type(hover_color) + self._border_color: Union[str, Tuple[str, str]] = ThemeManager.theme["color"]["button_border"] if border_color is None else self._check_color_type(border_color) + self._text_color: Union[str, Tuple[str, str]] = ThemeManager.theme["color"]["text_button"] if text_color is None else self._check_color_type(text_color) + self._text_color_disabled: Union[str, Tuple[str, str]] = ThemeManager.theme["color"]["text_button_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled) + + # rendering options + self._background_corner_colors: Union[Tuple[Union[str, Tuple[str, str]]], None] = background_corner_colors # rendering options for DrawEngine + self._round_width_to_even_numbers: bool = round_width_to_even_numbers # rendering options for DrawEngine + self._round_height_to_even_numbers: bool = round_height_to_even_numbers # rendering options for DrawEngine + + # text, font self._text = text self._text_label: Union[tkinter.Label, None] = None - if isinstance(self._image, CTkImage): - self._image.add_configure_callback(self._update_image) - - # font - self._font = CTkFont() if font == "default_theme" else self._check_font_type(font) + self._textvariable: tkinter.Variable = textvariable + self._font: Union[tuple, CTkFont] = CTkFont() if font is None else self._check_font_type(font) if isinstance(self._font, CTkFont): self._font.add_size_configure_callback(self._update_font) - # callback and hover functionality - self._command = command - self._textvariable = textvariable - self._state = state - self._hover = hover + # image + self._image = self._check_image_type(image) + self._image_label: Union[tkinter.Label, None] = None + if isinstance(self._image, CTkImage): + self._image.add_configure_callback(self._update_image) + + # other + self._state: str = state + self._hover: bool = hover + self._command: Callable = command + self._compound: str = compound + self._anchor: str = anchor self._click_animation_running: bool = False - # canvas + # canvas and draw engine self._canvas = CTkCanvas(master=self, highlightthickness=0, width=self._apply_widget_scaling(self._desired_width), @@ -116,6 +118,9 @@ class CTkButton(CTkBaseClass): if self._text_label is not None: self._text_label.configure(font=self._apply_font_scaling(self._font)) + if self._image_label is not None: + self._update_image() + self._canvas.configure(width=self._apply_widget_scaling(self._desired_width), height=self._apply_widget_scaling(self._desired_height)) self._draw(no_color_updates=True) @@ -175,7 +180,7 @@ class CTkButton(CTkBaseClass): fill=self._apply_appearance_mode(self._border_color)) # set color for inner button parts - if self._fg_color is None: + if self._fg_color == "transparent": self._canvas.itemconfig("inner_parts", outline=self._apply_appearance_mode(self._bg_color), fill=self._apply_appearance_mode(self._bg_color)) @@ -211,7 +216,7 @@ class CTkButton(CTkBaseClass): else: self._text_label.configure(fg=self._apply_appearance_mode(self._text_color)) - if self._fg_color is None: + if self._apply_appearance_mode(self._fg_color) == "transparent": self._text_label.configure(bg=self._apply_appearance_mode(self._bg_color)) else: self._text_label.configure(bg=self._apply_appearance_mode(self._fg_color)) @@ -228,6 +233,7 @@ class CTkButton(CTkBaseClass): if self._image_label is None: self._image_label = tkinter.Label(master=self) + self._update_image() # set image self._create_grid() self._image_label.bind("", self._on_enter) @@ -237,13 +243,11 @@ class CTkButton(CTkBaseClass): if no_color_updates is False: # set image_label bg color (background color of label) - if self._fg_color is None: + if self._apply_appearance_mode(self._fg_color) == "transparent": self._image_label.configure(bg=self._apply_appearance_mode(self._bg_color)) else: self._image_label.configure(bg=self._apply_appearance_mode(self._fg_color)) - self._update_image() # set image - else: # delete text_label if no text given if self._image_label is not None: @@ -334,23 +338,23 @@ class CTkButton(CTkBaseClass): require_redraw = True if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True) require_redraw = True if "hover_color" in kwargs: - self._hover_color = kwargs.pop("hover_color") + self._hover_color = self._check_color_type(kwargs.pop("hover_color")) require_redraw = True if "border_color" in kwargs: - self._border_color = kwargs.pop("border_color") + self._border_color = self._check_color_type(kwargs.pop("border_color")) require_redraw = True if "text_color" in kwargs: - self._text_color = kwargs.pop("text_color") + self._text_color = self._check_color_type(kwargs.pop("text_color")) require_redraw = True if "text_color_disabled" in kwargs: - self._text_color_disabled = kwargs.pop("text_color_disabled") + self._text_color_disabled = self._check_color_type(kwargs.pop("text_color_disabled")) require_redraw = True if "background_corner_colors" in kwargs: @@ -486,7 +490,7 @@ class CTkButton(CTkBaseClass): def _on_leave(self, event=None): self._click_animation_running = False - if self._fg_color is None: + if self._fg_color == "transparent": inner_parts_color = self._bg_color else: inner_parts_color = self._fg_color diff --git a/customtkinter/windows/widgets/ctk_checkbox.py b/customtkinter/windows/widgets/ctk_checkbox.py index 560e39a..717977f 100644 --- a/customtkinter/windows/widgets/ctk_checkbox.py +++ b/customtkinter/windows/widgets/ctk_checkbox.py @@ -1,6 +1,6 @@ import tkinter import sys -from typing import Union, Tuple, Callable +from typing import Union, Tuple, Callable, Optional from .core_rendering.ctk_canvas import CTkCanvas from .theme.theme_manager import ThemeManager @@ -16,31 +16,31 @@ class CTkCheckBox(CTkBaseClass): """ def __init__(self, - master: any = None, + master: any, width: int = 100, height: int = 24, checkbox_width: int = 24, checkbox_height: int = 24, - corner_radius: Union[int, str] = "default_theme", - border_width: Union[int, str] = "default_theme", + corner_radius: Optional[int] = None, + border_width: Optional[int] = None, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str]] = "default_theme", - hover_color: Union[str, Tuple[str, str]] = "default_theme", - border_color: Union[str, Tuple[str, str]] = "default_theme", - checkmark_color: Union[str, Tuple[str, str]] = "default_theme", - text_color: Union[str, Tuple[str, str]] = "default_theme", - text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + hover_color: Optional[Union[str, Tuple[str, str]]] = None, + border_color: Optional[Union[str, Tuple[str, str]]] = None, + checkmark_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None, text: str = "CTkCheckBox", - font: Union[tuple, CTkFont] = "default_theme", - textvariable: tkinter.Variable = None, + font: Optional[Union[tuple, CTkFont]] = None, + textvariable: Union[tkinter.Variable, None] = None, state: str = tkinter.NORMAL, hover: bool = True, - command: Callable = None, + command: Union[Callable[[], None], None] = None, onvalue: Union[int, str] = 1, offvalue: Union[int, str] = 0, - variable: tkinter.Variable = None, + variable: Union[tkinter.Variable, None] = None, **kwargs): # transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass @@ -51,23 +51,23 @@ class CTkCheckBox(CTkBaseClass): self._checkbox_height = checkbox_height # color - self._fg_color = ThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_color - self._hover_color = ThemeManager.theme["color"]["button_hover"] if hover_color == "default_theme" else hover_color - self._border_color = ThemeManager.theme["color"]["checkbox_border"] if border_color == "default_theme" else border_color - self._checkmark_color = ThemeManager.theme["color"]["checkmark"] if checkmark_color == "default_theme" else checkmark_color + self._fg_color = ThemeManager.theme["color"]["button"] if fg_color is None else self._check_color_type(fg_color) + self._hover_color = ThemeManager.theme["color"]["button_hover"] if hover_color is None else self._check_color_type(hover_color) + self._border_color = ThemeManager.theme["color"]["checkbox_border"] if border_color is None else self._check_color_type(border_color) + self._checkmark_color = ThemeManager.theme["color"]["checkmark"] if checkmark_color is None else self._check_color_type(checkmark_color) # shape - self._corner_radius = ThemeManager.theme["shape"]["checkbox_corner_radius"] if corner_radius == "default_theme" else corner_radius - self._border_width = ThemeManager.theme["shape"]["checkbox_border_width"] if border_width == "default_theme" else border_width + self._corner_radius = ThemeManager.theme["shape"]["checkbox_corner_radius"] if corner_radius is None else corner_radius + self._border_width = ThemeManager.theme["shape"]["checkbox_border_width"] if border_width is None else border_width # text self._text = text self._text_label: Union[tkinter.Label, None] = None - self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color - self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled == "default_theme" else text_color_disabled + self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color) + self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled) # font - self._font = CTkFont() if font == "default_theme" else self._check_font_type(font) + self._font = CTkFont() if font is None else self._check_font_type(font) if isinstance(self._font, CTkFont): self._font.add_size_configure_callback(self._update_font) @@ -253,19 +253,19 @@ class CTkCheckBox(CTkBaseClass): require_redraw = True if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color")) require_redraw = True if "hover_color" in kwargs: - self._hover_color = kwargs.pop("hover_color") + self._hover_color = self._check_color_type(kwargs.pop("hover_color")) require_redraw = True if "text_color" in kwargs: - self._text_color = kwargs.pop("text_color") + self._text_color = self._check_color_type(kwargs.pop("text_color")) require_redraw = True if "border_color" in kwargs: - self._border_color = kwargs.pop("border_color") + self._border_color = self._check_color_type(kwargs.pop("border_color")) require_redraw = True if "hover" in kwargs: diff --git a/customtkinter/windows/widgets/ctk_combobox.py b/customtkinter/windows/widgets/ctk_combobox.py index 86526b9..34e460c 100644 --- a/customtkinter/windows/widgets/ctk_combobox.py +++ b/customtkinter/windows/widgets/ctk_combobox.py @@ -1,6 +1,6 @@ import tkinter import sys -from typing import Union, Tuple, Callable, List +from typing import Union, Tuple, Callable, List, Optional from .core_widget_classes.dropdown_menu import DropdownMenu from .core_rendering.ctk_canvas import CTkCanvas @@ -17,52 +17,50 @@ class CTkComboBox(CTkBaseClass): """ def __init__(self, - master: any = None, + master: any, width: int = 140, height: int = 28, - corner_radius: Union[int, str] = "default_theme", - border_width: Union[int, str] = "default_theme", + corner_radius: Optional[int] = None, + border_width: Optional[int] = None, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str]] = "default_theme", - border_color: Union[str, Tuple[str, str]] = "default_theme", - button_color: Union[str, Tuple[str, str]] = "default_theme", - button_hover_color: Union[str, Tuple[str, str]] = "default_theme", - dropdown_fg_color: Union[str, Tuple[str, str]] = "default_theme", - dropdown_hover_color: Union[str, Tuple[str, str]] = "default_theme", - dropdown_text_color: Union[str, Tuple[str, str]] = "default_theme", - text_color: Union[str, Tuple[str, str]] = "default_theme", - text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + border_color: Optional[Union[str, Tuple[str, str]]] = None, + button_color: Optional[Union[str, Tuple[str, str]]] = None, + button_hover_color: Optional[Union[str, Tuple[str, str]]] = None, + dropdown_fg_color: Optional[Union[str, Tuple[str, str]]] = None, + dropdown_hover_color: Optional[Union[str, Tuple[str, str]]] = None, + dropdown_text_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None, - font: Union[tuple, CTkFont] = "default_theme", - dropdown_font: Union[tuple, CTkFont] = "default_theme", - values: List[str] = None, + font: Optional[Union[tuple, CTkFont]] = None, + dropdown_font: Optional[Union[tuple, CTkFont]] = None, + values: Optional[List[str]] = None, state: str = tkinter.NORMAL, hover: bool = True, - variable: tkinter.Variable = None, - command: Callable = None, + variable: Union[tkinter.Variable, None] = None, + command: Union[Callable[[str], None], None] = None, justify: str = "left", **kwargs): # transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) - # color variables - self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color == "default_theme" else fg_color - self._border_color = ThemeManager.theme["color"]["combobox_border"] if border_color == "default_theme" else border_color - self._button_color = ThemeManager.theme["color"]["combobox_border"] if button_color == "default_theme" else button_color - self._button_hover_color = ThemeManager.theme["color"]["combobox_button_hover"] if button_hover_color == "default_theme" else button_hover_color - # shape - self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius - self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width == "default_theme" else border_width + self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius is None else corner_radius + self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width is None else border_width - # text and font - self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color - self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled == "default_theme" else text_color_disabled + # color + self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color is None else self._check_color_type(fg_color) + self._border_color = ThemeManager.theme["color"]["combobox_border"] if border_color is None else self._check_color_type(border_color) + self._button_color = ThemeManager.theme["color"]["combobox_border"] if button_color is None else self._check_color_type(button_color) + self._button_hover_color = ThemeManager.theme["color"]["combobox_button_hover"] if button_hover_color is None else self._check_color_type(button_hover_color) + self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color) + self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled) # font - self._font = CTkFont() if font == "default_theme" else self._check_font_type(font) + self._font = CTkFont() if font is None else self._check_font_type(font) if isinstance(self._font, CTkFont): self._font.add_size_configure_callback(self._update_font) @@ -226,19 +224,19 @@ class CTkComboBox(CTkBaseClass): require_redraw = True if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color")) require_redraw = True if "border_color" in kwargs: - self._border_color = kwargs.pop("border_color") + self._border_color = self._check_color_type(kwargs.pop("border_color")) require_redraw = True if "button_color" in kwargs: - self._button_color = kwargs.pop("button_color") + self._button_color = self._check_color_type(kwargs.pop("button_color")) require_redraw = True if "button_hover_color" in kwargs: - self._button_hover_color = kwargs.pop("button_hover_color") + self._button_hover_color = self._check_color_type(kwargs.pop("button_hover_color")) require_redraw = True if "dropdown_fg_color" in kwargs: @@ -251,11 +249,11 @@ class CTkComboBox(CTkBaseClass): self._dropdown_menu.configure(text_color=kwargs.pop("dropdown_text_color")) if "text_color" in kwargs: - self._text_color = kwargs.pop("text_color") + self._text_color = self._check_color_type(kwargs.pop("text_color")) require_redraw = True if "text_color_disabled" in kwargs: - self._text_color_disabled = kwargs.pop("text_color_disabled") + self._text_color_disabled = self._check_color_type(kwargs.pop("text_color_disabled")) require_redraw = True if "font" in kwargs: diff --git a/customtkinter/windows/widgets/ctk_entry.py b/customtkinter/windows/widgets/ctk_entry.py index a04340c..ded3daa 100644 --- a/customtkinter/windows/widgets/ctk_entry.py +++ b/customtkinter/windows/widgets/ctk_entry.py @@ -1,5 +1,5 @@ import tkinter -from typing import Union, Tuple +from typing import Union, Tuple, Optional from .core_rendering.ctk_canvas import CTkCanvas from .theme.theme_manager import ThemeManager @@ -24,21 +24,21 @@ class CTkEntry(CTkBaseClass): "show", "takefocus", "validate", "validatecommand", "xscrollcommand"} def __init__(self, - master: any = None, + master: any, width: int = 140, height: int = 28, - corner_radius: int = "default_theme", - border_width: int = "default_theme", + corner_radius: Optional[int] = None, + border_width: Optional[int] = None, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str], None] = "default_theme", - border_color: Union[str, Tuple[str, str]] = "default_theme", - text_color: Union[str, Tuple[str, str]] = "default_theme", - placeholder_text_color: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + border_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color: Optional[Union[str, Tuple[str, str]]] = None, + placeholder_text_color: Optional[Union[str, Tuple[str, str]]] = None, - textvariable: tkinter.Variable = None, - placeholder_text: str = None, - font: Union[tuple, CTkFont] = "default_theme", + textvariable: Union[tkinter.Variable, None] = None, + placeholder_text: Union[str, None] = None, + font: Optional[Union[tuple, CTkFont]] = None, state: str = tkinter.NORMAL, **kwargs): @@ -50,14 +50,14 @@ class CTkEntry(CTkBaseClass): self.grid_columnconfigure(0, weight=1) # color - self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color == "default_theme" else fg_color - self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color - self._placeholder_text_color = ThemeManager.theme["color"]["entry_placeholder_text"] if placeholder_text_color == "default_theme" else placeholder_text_color - self._border_color = ThemeManager.theme["color"]["entry_border"] if border_color == "default_theme" else border_color + self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color is None else self._check_color_type(fg_color, transparency=True) + self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color) + self._placeholder_text_color = ThemeManager.theme["color"]["entry_placeholder_text"] if placeholder_text_color is None else self._check_color_type(placeholder_text_color) + self._border_color = ThemeManager.theme["color"]["entry_border"] if border_color is None else self._check_color_type(border_color) # shape - self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius - self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width == "default_theme" else border_width + self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius is None else corner_radius + self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width is None else border_width # text and state self._is_focused: bool = True @@ -69,7 +69,7 @@ class CTkEntry(CTkBaseClass): self._textvariable_callback_name: str = "" # font - self._font = CTkFont() if font == "default_theme" else self._check_font_type(font) + self._font = CTkFont() if font is None else self._check_font_type(font) if isinstance(self._font, CTkFont): self._font.add_size_configure_callback(self._update_font) @@ -158,17 +158,7 @@ class CTkEntry(CTkBaseClass): self._apply_widget_scaling(self._border_width)) if requires_recoloring or no_color_updates is False: - if self._apply_appearance_mode(self._fg_color) is not None: - self._canvas.itemconfig("inner_parts", - fill=self._apply_appearance_mode(self._fg_color), - outline=self._apply_appearance_mode(self._fg_color)) - self._entry.configure(bg=self._apply_appearance_mode(self._fg_color), - fg=self._apply_appearance_mode(self._text_color), - disabledbackground=self._apply_appearance_mode(self._fg_color), - disabledforeground=self._apply_appearance_mode(self._text_color), - highlightcolor=self._apply_appearance_mode(self._fg_color), - insertbackground=self._apply_appearance_mode(self._text_color)) - else: + if self._apply_appearance_mode(self._fg_color) == "transparent": self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._bg_color), outline=self._apply_appearance_mode(self._bg_color)) @@ -178,6 +168,16 @@ class CTkEntry(CTkBaseClass): disabledforeground=self._apply_appearance_mode(self._text_color), highlightcolor=self._apply_appearance_mode(self._bg_color), insertbackground=self._apply_appearance_mode(self._text_color)) + else: + self._canvas.itemconfig("inner_parts", + fill=self._apply_appearance_mode(self._fg_color), + outline=self._apply_appearance_mode(self._fg_color)) + self._entry.configure(bg=self._apply_appearance_mode(self._fg_color), + fg=self._apply_appearance_mode(self._text_color), + disabledbackground=self._apply_appearance_mode(self._fg_color), + disabledforeground=self._apply_appearance_mode(self._text_color), + highlightcolor=self._apply_appearance_mode(self._fg_color), + insertbackground=self._apply_appearance_mode(self._text_color)) self._canvas.itemconfig("border_parts", fill=self._apply_appearance_mode(self._border_color), @@ -192,15 +192,19 @@ class CTkEntry(CTkBaseClass): self._entry.configure(state=self._state) if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color")) require_redraw = True if "text_color" in kwargs: - self._text_color = kwargs.pop("text_color") + self._text_color = self._check_color_type(kwargs.pop("text_color")) + require_redraw = True + + if "placeholder_text_color" in kwargs: + self._placeholder_text_color = self._check_color_type(kwargs.pop("placeholder_text_color")) require_redraw = True if "border_color" in kwargs: - self._border_color = kwargs.pop("border_color") + self._border_color = self._check_color_type(kwargs.pop("border_color")) require_redraw = True if "border_width" in kwargs: @@ -221,10 +225,6 @@ class CTkEntry(CTkBaseClass): else: self._activate_placeholder() - if "placeholder_text_color" in kwargs: - self._placeholder_text_color = kwargs.pop("placeholder_text_color") - require_redraw = True - if "textvariable" in kwargs: self._textvariable = kwargs.pop("textvariable") self._entry.configure(textvariable=self._textvariable) diff --git a/customtkinter/windows/widgets/ctk_frame.py b/customtkinter/windows/widgets/ctk_frame.py index 18793eb..2d20108 100644 --- a/customtkinter/windows/widgets/ctk_frame.py +++ b/customtkinter/windows/widgets/ctk_frame.py @@ -1,4 +1,4 @@ -from typing import Union, Tuple, List +from typing import Union, Tuple, List, Optional from .core_rendering.ctk_canvas import CTkCanvas from .theme.theme_manager import ThemeManager @@ -15,28 +15,28 @@ class CTkFrame(CTkBaseClass): """ def __init__(self, - master: any = None, + master: any, width: int = 200, height: int = 200, - corner_radius: Union[int, str] = "default_theme", - border_width: Union[int, str] = "default_theme", + corner_radius: Optional[Union[int, str]] = None, + border_width: Optional[Union[int, str]] = None, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str], None] = "default_theme", - border_color: Union[str, Tuple[str, str]] = "default_theme", - background_corner_colors: Tuple[Union[str, Tuple[str, str]]] = None, + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + border_color: Optional[Union[str, Tuple[str, str]]] = None, + background_corner_colors: Union[Tuple[Union[str, Tuple[str, str]]], None] = None, - overwrite_preferred_drawing_method: str = None, + overwrite_preferred_drawing_method: Union[str, None] = None, **kwargs): # transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) # color - self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color == "default_theme" else border_color + self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color is None else self._check_color_type(border_color) # determine fg_color of frame - if fg_color == "default_theme": + if fg_color is None: if isinstance(self.master, CTkFrame): if self.master._fg_color == ThemeManager.theme["color"]["frame_low"]: self._fg_color = ThemeManager.theme["color"]["frame_high"] @@ -45,13 +45,13 @@ class CTkFrame(CTkBaseClass): else: self._fg_color = ThemeManager.theme["color"]["frame_low"] else: - self._fg_color = fg_color + self._fg_color = self._check_color_type(fg_color, transparency=True) self._background_corner_colors = background_corner_colors # rendering options for DrawEngine # shape - self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius - self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width == "default_theme" else border_width + self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius is None else corner_radius + self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width is None else border_width self._canvas = CTkCanvas(master=self, highlightthickness=0, @@ -80,7 +80,8 @@ class CTkFrame(CTkBaseClass): 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._canvas.configure(width=self._apply_widget_scaling(self._desired_width), + height=self._apply_widget_scaling(self._desired_height)) self._draw() def _set_dimensions(self, width=None, height=None): @@ -113,7 +114,7 @@ class CTkFrame(CTkBaseClass): overwrite_preferred_drawing_method=self._overwrite_preferred_drawing_method) if no_color_updates is False or requires_recoloring: - if self._fg_color is None: + if self._fg_color == "transparent": self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._bg_color), outline=self._apply_appearance_mode(self._bg_color)) @@ -132,7 +133,7 @@ class CTkFrame(CTkBaseClass): def configure(self, require_redraw=False, **kwargs): if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True) require_redraw = True # check if CTk widgets are children of the frame and change their bg_color to new frame fg_color @@ -141,14 +142,14 @@ class CTkFrame(CTkBaseClass): child.configure(bg_color=self._fg_color) if "bg_color" in kwargs: - # pass bg_color change to children if fg_color is None - if self._fg_color is None: + # pass bg_color change to children if fg_color is "transparent" + if self._fg_color == "transparent": for child in self.winfo_children(): if isinstance(child, CTkBaseClass): child.configure(bg_color=self._fg_color) if "border_color" in kwargs: - self._border_color = kwargs.pop("border_color") + self._border_color = self._check_color_type(kwargs.pop("border_color")) require_redraw = True if "background_corner_colors" in kwargs: diff --git a/customtkinter/windows/widgets/ctk_label.py b/customtkinter/windows/widgets/ctk_label.py index 49297d1..a9d5161 100644 --- a/customtkinter/windows/widgets/ctk_label.py +++ b/customtkinter/windows/widgets/ctk_label.py @@ -1,5 +1,5 @@ import tkinter -from typing import Union, Tuple, Callable +from typing import Union, Tuple, Callable, Optional from .core_rendering.ctk_canvas import CTkCanvas from .theme.theme_manager import ThemeManager @@ -22,18 +22,18 @@ class CTkLabel(CTkBaseClass): "textvariable", "state", "takefocus", "underline", "wraplength"} def __init__(self, - master: any = None, + master: any, width: int = 0, height: int = 28, - corner_radius: Union[int, str] = "default_theme", + corner_radius: Optional[int] = None, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str], None] = "default_theme", - text_color: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color: Optional[Union[str, Tuple[str, str]]] = None, text: str = "CTkLabel", - font: Union[tuple, CTkFont] = "default_theme", - image: Union[tkinter.PhotoImage, CTkImage] = None, + font: Optional[Union[tuple, CTkFont]] = None, + image: Union[tkinter.PhotoImage, CTkImage, None] = None, compound: str = "center", anchor: str = "center", # label anchor: center, n, e, s, w **kwargs): @@ -42,11 +42,11 @@ class CTkLabel(CTkBaseClass): super().__init__(master=master, bg_color=bg_color, width=width, height=height) # color - self._fg_color = ThemeManager.theme["color"]["label"] if fg_color == "default_theme" else fg_color - self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color + self._fg_color = ThemeManager.theme["color"]["label"] if fg_color is None else self._check_color_type(fg_color, transparency=True) + self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color) # shape - self._corner_radius = ThemeManager.theme["shape"]["label_corner_radius"] if corner_radius == "default_theme" else corner_radius + self._corner_radius = ThemeManager.theme["shape"]["label_corner_radius"] if corner_radius is None else corner_radius # text self._anchor = anchor @@ -59,7 +59,7 @@ class CTkLabel(CTkBaseClass): self._image.add_configure_callback(self._update_image) # font - self._font = CTkFont() if font == "default_theme" else self._check_font_type(font) + self._font = CTkFont() if font is None else self._check_font_type(font) if isinstance(self._font, CTkFont): self._font.add_size_configure_callback(self._update_font) @@ -145,20 +145,20 @@ class CTkLabel(CTkBaseClass): 0) if no_color_updates is False or requires_recoloring: - if self._apply_appearance_mode(self._fg_color) is not None: - self._canvas.itemconfig("inner_parts", - fill=self._apply_appearance_mode(self._fg_color), - outline=self._apply_appearance_mode(self._fg_color)) - - self._label.configure(fg=self._apply_appearance_mode(self._text_color), - bg=self._apply_appearance_mode(self._fg_color)) - else: + if self._apply_appearance_mode(self._fg_color) == "transparent": self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._bg_color), outline=self._apply_appearance_mode(self._bg_color)) self._label.configure(fg=self._apply_appearance_mode(self._text_color), bg=self._apply_appearance_mode(self._bg_color)) + else: + self._canvas.itemconfig("inner_parts", + fill=self._apply_appearance_mode(self._fg_color), + outline=self._apply_appearance_mode(self._fg_color)) + + self._label.configure(fg=self._apply_appearance_mode(self._text_color), + bg=self._apply_appearance_mode(self._fg_color)) self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color)) @@ -172,11 +172,11 @@ class CTkLabel(CTkBaseClass): require_redraw = True if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True) require_redraw = True if "text_color" in kwargs: - self._text_color = kwargs.pop("text_color") + self._text_color = self._check_color_type(kwargs.pop("text_color")) require_redraw = True if "text" in kwargs: diff --git a/customtkinter/windows/widgets/ctk_optionmenu.py b/customtkinter/windows/widgets/ctk_optionmenu.py index 8002ca5..8edc59f 100644 --- a/customtkinter/windows/widgets/ctk_optionmenu.py +++ b/customtkinter/windows/widgets/ctk_optionmenu.py @@ -1,6 +1,6 @@ import tkinter import sys -from typing import Union, Tuple, Callable +from typing import Union, Tuple, Callable, Optional from .core_rendering.ctk_canvas import CTkCanvas from .theme.theme_manager import ThemeManager @@ -17,28 +17,28 @@ class CTkOptionMenu(CTkBaseClass): """ def __init__(self, - master: any = None, + master: any, width: int = 140, height: int = 28, - corner_radius: Union[int, str] = "default_theme", + corner_radius: Optional[Union[int]] = None, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str]] = "default_theme", - button_color: Union[str, Tuple[str, str]] = "default_theme", - button_hover_color: Union[str, Tuple[str, str]] = "default_theme", - text_color: Union[str, Tuple[str, str]] = "default_theme", - text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", - dropdown_fg_color: Union[str, Tuple[str, str]] = "default_theme", - dropdown_hover_color: Union[str, Tuple[str, str]] = "default_theme", - dropdown_text_color: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + button_color: Optional[Union[str, Tuple[str, str]]] = None, + button_hover_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None, + dropdown_fg_color: Optional[Union[str, Tuple[str, str]]] = None, + dropdown_hover_color: Optional[Union[str, Tuple[str, str]]] = None, + dropdown_text_color: Optional[Union[str, Tuple[str, str]]] = None, - font: Union[tuple, CTkFont] = "default_theme", - dropdown_font: Union[tuple, CTkFont] = "default_theme", - values: list = None, - variable: tkinter.Variable = None, + font: Optional[Union[tuple, CTkFont]] = None, + dropdown_font: Optional[Union[tuple, CTkFont]] = None, + values: Optional[list] = None, + variable: Union[tkinter.Variable, None] = None, state: str = tkinter.NORMAL, hover: bool = True, - command: Callable[[str], None] = None, + command: Union[Callable[[str], None], None] = None, dynamic_resizing: bool = True, anchor: str = "w", **kwargs): @@ -47,19 +47,19 @@ class CTkOptionMenu(CTkBaseClass): super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) # color variables - self._fg_color = ThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_color - self._button_color = ThemeManager.theme["color"]["optionmenu_button"] if button_color == "default_theme" else button_color - self._button_hover_color = ThemeManager.theme["color"]["optionmenu_button_hover"] if button_hover_color == "default_theme" else button_hover_color + self._fg_color = ThemeManager.theme["color"]["button"] if fg_color is None else self._check_color_type(fg_color) + self._button_color = ThemeManager.theme["color"]["optionmenu_button"] if button_color is None else self._check_color_type(button_color) + self._button_hover_color = ThemeManager.theme["color"]["optionmenu_button_hover"] if button_hover_color is None else self._check_color_type(button_hover_color) # shape - self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius + self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius is None else corner_radius # text and font - self._text_color = ThemeManager.theme["color"]["text_button"] if text_color == "default_theme" else text_color - self._text_color_disabled = ThemeManager.theme["color"]["text_button_disabled"] if text_color_disabled == "default_theme" else text_color_disabled + self._text_color = ThemeManager.theme["color"]["text_button"] if text_color is None else self._check_color_type(text_color) + self._text_color_disabled = ThemeManager.theme["color"]["text_button_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled) # font - self._font = CTkFont() if font == "default_theme" else self._check_font_type(font) + self._font = CTkFont() if font is None else self._check_font_type(font) if isinstance(self._font, CTkFont): self._font.add_size_configure_callback(self._update_font) @@ -194,7 +194,6 @@ class CTkOptionMenu(CTkBaseClass): self._apply_widget_scaling(self._current_height / 3)) if no_color_updates is False or requires_recoloring or requires_recoloring_2: - self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color)) self._canvas.itemconfig("inner_parts_left", @@ -226,19 +225,19 @@ class CTkOptionMenu(CTkBaseClass): require_redraw = True if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color")) require_redraw = True if "button_color" in kwargs: - self._button_color = kwargs.pop("button_color") + self._button_color = self._check_color_type(kwargs.pop("button_color")) require_redraw = True if "button_hover_color" in kwargs: - self._button_hover_color = kwargs.pop("button_hover_color") + self._button_hover_color = self._check_color_type(kwargs.pop("button_hover_color")) require_redraw = True if "text_color" in kwargs: - self._text_color = kwargs.pop("text_color") + self._text_color = self._check_color_type(kwargs.pop("text_color")) require_redraw = True if "dropdown_color" in kwargs: diff --git a/customtkinter/windows/widgets/ctk_progressbar.py b/customtkinter/windows/widgets/ctk_progressbar.py index cec4fdd..9b02f23 100644 --- a/customtkinter/windows/widgets/ctk_progressbar.py +++ b/customtkinter/windows/widgets/ctk_progressbar.py @@ -1,6 +1,6 @@ import tkinter import math -from typing import Union, Tuple +from typing import Union, Tuple, Optional from .core_rendering.ctk_canvas import CTkCanvas from .theme.theme_manager import ThemeManager @@ -16,18 +16,18 @@ class CTkProgressBar(CTkBaseClass): """ def __init__(self, - master: any = None, - width: Union[int, str] = "default_init", - height: Union[int, str] = "default_init", - corner_radius: Union[str, Tuple[str, str]] = "default_theme", - border_width: Union[int, str] = "default_theme", + master: any, + width: Optional[int] = None, + height: Optional[int] = None, + corner_radius: Optional[int] = None, + border_width: Optional[int] = None, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str]] = "default_theme", - border_color: Union[str, Tuple[str, str]] = "default_theme", - progress_color: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + border_color: Optional[Union[str, Tuple[str, str]]] = None, + progress_color: Optional[Union[str, Tuple[str, str]]] = None, - variable: tkinter.Variable = None, + variable: Union[tkinter.Variable, None] = None, orientation: str = "horizontal", mode: str = "determinate", determinate_speed: float = 1, @@ -35,12 +35,12 @@ class CTkProgressBar(CTkBaseClass): **kwargs): # set default dimensions according to orientation - if width == "default_init": + if width is None: if orientation.lower() == "vertical": width = 8 else: width = 200 - if height == "default_init": + if height is None: if orientation.lower() == "vertical": height = 200 else: @@ -50,9 +50,9 @@ class CTkProgressBar(CTkBaseClass): super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) # color - self._border_color = ThemeManager.theme["color"]["progressbar_border"] if border_color == "default_theme" else border_color - self._fg_color = ThemeManager.theme["color"]["progressbar"] if fg_color == "default_theme" else fg_color - self._progress_color = ThemeManager.theme["color"]["progressbar_progress"] if progress_color == "default_theme" else progress_color + self._border_color = ThemeManager.theme["color"]["progressbar_border"] if border_color is None else self._check_color_type(border_color) + self._fg_color = ThemeManager.theme["color"]["progressbar"] if fg_color is None else self._check_color_type(fg_color) + self._progress_color = ThemeManager.theme["color"]["progressbar_progress"] if progress_color is None else self._check_color_type(progress_color) # control variable self._variable = variable @@ -60,8 +60,8 @@ class CTkProgressBar(CTkBaseClass): self._variable_callback_name = None # shape - self._corner_radius = ThemeManager.theme["shape"]["progressbar_corner_radius"] if corner_radius == "default_theme" else corner_radius - self._border_width = ThemeManager.theme["shape"]["progressbar_border_width"] if border_width == "default_theme" else border_width + self._corner_radius = ThemeManager.theme["shape"]["progressbar_corner_radius"] if corner_radius is None else corner_radius + self._border_width = ThemeManager.theme["shape"]["progressbar_border_width"] if border_width is None else border_width self._determinate_value: float = 0.5 # range 0-1 self._determinate_speed = determinate_speed # range 0-1 self._indeterminate_value: float = 0 # range 0-inf @@ -162,15 +162,15 @@ class CTkProgressBar(CTkBaseClass): require_redraw = True if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color")) require_redraw = True if "border_color" in kwargs: - self._border_color = kwargs.pop("border_color") + self._border_color = self._check_color_type(kwargs.pop("border_color")) require_redraw = True if "progress_color" in kwargs: - self._progress_color = kwargs.pop("progress_color") + self._progress_color = self._check_color_type(kwargs.pop("progress_color")) require_redraw = True if "variable" in kwargs: diff --git a/customtkinter/windows/widgets/ctk_radiobutton.py b/customtkinter/windows/widgets/ctk_radiobutton.py index f03cc23..775151e 100644 --- a/customtkinter/windows/widgets/ctk_radiobutton.py +++ b/customtkinter/windows/widgets/ctk_radiobutton.py @@ -1,6 +1,6 @@ import tkinter import sys -from typing import Union, Tuple, Callable +from typing import Union, Tuple, Callable, Optional from .core_rendering.ctk_canvas import CTkCanvas from .theme.theme_manager import ThemeManager @@ -16,30 +16,30 @@ class CTkRadioButton(CTkBaseClass): """ def __init__(self, - master: any = None, + master: any, width: int = 100, height: int = 22, radiobutton_width: int = 22, radiobutton_height: int = 22, - corner_radius: Union[int, str] = "default_theme", - border_width_unchecked: Union[int, str] = "default_theme", - border_width_checked: Union[int, str] = "default_theme", + corner_radius: Optional[int] = None, + border_width_unchecked: Optional[int] = None, + border_width_checked: Optional[int] = None, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str]] = "default_theme", - hover_color: Union[str, Tuple[str, str]] = "default_theme", - border_color: Union[str, Tuple[str, str]] = "default_theme", - text_color: Union[str, Tuple[str, str]] = "default_theme", - text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + hover_color: Optional[Union[str, Tuple[str, str]]] = None, + border_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None, text: str = "CTkRadioButton", - font: Union[tuple, CTkFont] = "default_theme", - textvariable: tkinter.Variable = None, - variable: tkinter.Variable = None, + font: Optional[Union[tuple, CTkFont]] = None, + textvariable: Union[tkinter.Variable, None] = None, + variable: Union[tkinter.Variable, None] = None, value: Union[int, str] = 0, state: str = tkinter.NORMAL, hover: bool = True, - command: Callable = None, + command: Union[Callable, None] = None, **kwargs): # transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass @@ -50,23 +50,23 @@ class CTkRadioButton(CTkBaseClass): self._radiobutton_height = radiobutton_height # color - self._fg_color = ThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_color - self._hover_color = ThemeManager.theme["color"]["button_hover"] if hover_color == "default_theme" else hover_color - self._border_color = ThemeManager.theme["color"]["checkbox_border"] if border_color == "default_theme" else border_color + self._fg_color = ThemeManager.theme["color"]["button"] if fg_color is None else self._check_color_type(fg_color) + self._hover_color = ThemeManager.theme["color"]["button_hover"] if hover_color is None else self._check_color_type(hover_color) + self._border_color = ThemeManager.theme["color"]["checkbox_border"] if border_color is None else self._check_color_type(border_color) # shape - self._corner_radius = ThemeManager.theme["shape"]["radiobutton_corner_radius"] if corner_radius == "default_theme" else corner_radius - self._border_width_unchecked = ThemeManager.theme["shape"]["radiobutton_border_width_unchecked"] if border_width_unchecked == "default_theme" else border_width_unchecked - self._border_width_checked = ThemeManager.theme["shape"]["radiobutton_border_width_checked"] if border_width_checked == "default_theme" else border_width_checked + self._corner_radius = ThemeManager.theme["shape"]["radiobutton_corner_radius"] if corner_radius is None else corner_radius + self._border_width_unchecked = ThemeManager.theme["shape"]["radiobutton_border_width_unchecked"] if border_width_unchecked is None else border_width_unchecked + self._border_width_checked = ThemeManager.theme["shape"]["radiobutton_border_width_checked"] if border_width_checked is None else border_width_checked # text self._text = text self._text_label: Union[tkinter.Label, None] = None - self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color - self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled == "default_theme" else text_color_disabled + self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color) + self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled) # font - self._font = CTkFont() if font == "default_theme" else self._check_font_type(font) + self._font = CTkFont() if font is None else self._check_font_type(font) if isinstance(self._font, CTkFont): self._font.add_size_configure_callback(self._update_font) @@ -241,19 +241,23 @@ class CTkRadioButton(CTkBaseClass): require_redraw = True if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color")) require_redraw = True if "hover_color" in kwargs: - self._hover_color = kwargs.pop("hover_color") + self._hover_color = self._check_color_type(kwargs.pop("hover_color")) require_redraw = True if "text_color" in kwargs: - self._text_color = kwargs.pop("text_color") + self._text_color = self._check_color_type(kwargs.pop("text_color")) + require_redraw = True + + if "text_color_disabled" in kwargs: + self._text_color_disabled = self._check_color_type(kwargs.pop("text_color_disabled")) require_redraw = True if "border_color" in kwargs: - self._border_color = kwargs.pop("border_color") + self._border_color = self._check_color_type(kwargs.pop("border_color")) require_redraw = True if "hover" in kwargs: diff --git a/customtkinter/windows/widgets/ctk_scrollbar.py b/customtkinter/windows/widgets/ctk_scrollbar.py index 745b36d..17014dc 100644 --- a/customtkinter/windows/widgets/ctk_scrollbar.py +++ b/customtkinter/windows/widgets/ctk_scrollbar.py @@ -1,5 +1,5 @@ import sys -from typing import Union, Tuple, Callable +from typing import Union, Tuple, Callable, Optional from .core_rendering.ctk_canvas import CTkCanvas from .theme.theme_manager import ThemeManager @@ -15,30 +15,30 @@ class CTkScrollbar(CTkBaseClass): """ def __init__(self, - master: any = None, - width: Union[int, str] = "default_init", - height: Union[int, str] = "default_init", - corner_radius: Union[int, str] = "default_theme", - border_spacing: Union[int, str] = "default_theme", + master: any, + width: Optional[Union[int, str]] = None, + height: Optional[Union[int, str]] = None, + corner_radius: Optional[int] = None, + border_spacing: Optional[int] = None, minimum_pixel_length: int = 20, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str], None] = "default_theme", - scrollbar_color: Union[str, Tuple[str, str]] = "default_theme", - scrollbar_hover_color: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + scrollbar_color: Optional[Union[str, Tuple[str, str]]] = None, + scrollbar_hover_color: Optional[Union[str, Tuple[str, str]]] = None, hover: bool = True, - command: Callable = None, + command: Union[Callable, None] = None, orientation: str = "vertical", **kwargs): # set default dimensions according to orientation - if width == "default_init": + if width is None: if orientation.lower() == "vertical": width = 16 else: width = 200 - if height == "default_init": + if height is None: if orientation.lower() == "horizontal": height = 16 else: @@ -48,13 +48,13 @@ class CTkScrollbar(CTkBaseClass): super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) # color - self._fg_color = ThemeManager.theme["color"]["frame_high"] if fg_color == "default_theme" else fg_color - self._scrollbar_color = ThemeManager.theme["color"]["scrollbar_button"] if scrollbar_color == "default_theme" else scrollbar_color - self._scrollbar_hover_color = ThemeManager.theme["color"]["scrollbar_button_hover"] if scrollbar_hover_color == "default_theme" else scrollbar_hover_color + self._fg_color = ThemeManager.theme["color"]["frame_high"] if fg_color is None else self._check_color_type(fg_color, transparency=True) + self._scrollbar_color = ThemeManager.theme["color"]["scrollbar_button"] if scrollbar_color is None else self._check_color_type(scrollbar_color) + self._scrollbar_hover_color = ThemeManager.theme["color"]["scrollbar_button_hover"] if scrollbar_hover_color is None else self._check_color_type(scrollbar_hover_color) # shape - self._corner_radius = ThemeManager.theme["shape"]["scrollbar_corner_radius"] if corner_radius == "default_theme" else corner_radius - self._border_spacing = ThemeManager.theme["shape"]["scrollbar_border_spacing"] if border_spacing == "default_theme" else border_spacing + self._corner_radius = ThemeManager.theme["shape"]["scrollbar_corner_radius"] if corner_radius is None else corner_radius + self._border_spacing = ThemeManager.theme["shape"]["scrollbar_border_spacing"] if border_spacing is None else border_spacing self._hover = hover self._hover_state: bool = False @@ -139,7 +139,7 @@ class CTkScrollbar(CTkBaseClass): fill=self._apply_appearance_mode(self._scrollbar_color), outline=self._apply_appearance_mode(self._scrollbar_color)) - if self._fg_color is None: + if self._fg_color == "transparent": self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color)) self._canvas.itemconfig("border_parts", fill=self._apply_appearance_mode(self._bg_color), @@ -154,15 +154,15 @@ class CTkScrollbar(CTkBaseClass): def configure(self, require_redraw=False, **kwargs): if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True) require_redraw = True if "scrollbar_color" in kwargs: - self._scrollbar_color = kwargs.pop("scrollbar_color") + self._scrollbar_color = self._check_color_type(kwargs.pop("scrollbar_color")) require_redraw = True if "scrollbar_hover_color" in kwargs: - self._scrollbar_hover_color = kwargs.pop("scrollbar_hover_color") + self._scrollbar_hover_color = self._check_color_type(kwargs.pop("scrollbar_hover_color")) require_redraw = True if "hover" in kwargs: diff --git a/customtkinter/windows/widgets/ctk_segmented_button.py b/customtkinter/windows/widgets/ctk_segmented_button.py index a39b063..da12d76 100644 --- a/customtkinter/windows/widgets/ctk_segmented_button.py +++ b/customtkinter/windows/widgets/ctk_segmented_button.py @@ -1,5 +1,5 @@ import tkinter -from typing import Union, Tuple, List, Dict, Callable +from typing import Union, Tuple, List, Dict, Callable, Optional, Literal from .theme.theme_manager import ThemeManager from .ctk_button import CTkButton @@ -14,50 +14,50 @@ class CTkSegmentedButton(CTkFrame): """ def __init__(self, - master: any = None, + master: any, width: int = 140, height: int = 28, - corner_radius: Union[int, str] = "default_theme", - border_width: Union[int, str] = 3, + corner_radius: Optional[int] = None, + border_width: int = 3, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str], None] = "default_theme", - selected_color: Union[str, Tuple[str, str]] = "default_theme", - selected_hover_color: Union[str, Tuple[str, str]] = "default_theme", - unselected_color: Union[str, Tuple[str, str]] = "default_theme", - unselected_hover_color: Union[str, Tuple[str, str]] = "default_theme", - text_color: Union[str, Tuple[str, str]] = "default_theme", - text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", - background_corner_colors: Tuple[Union[str, Tuple[str, str]]] = None, + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + selected_color: Optional[Union[str, Tuple[str, str]]] = None, + selected_hover_color: Optional[Union[str, Tuple[str, str]]] = None, + unselected_color: Optional[Union[str, Tuple[str, str]]] = None, + unselected_hover_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None, + background_corner_colors: Union[Tuple[Union[str, Tuple[str, str]]], None] = None, - font: Union[tuple, CTkFont] = "default_theme", - values: list = None, - variable: tkinter.Variable = None, + font: Optional[Union[tuple, CTkFont]] = None, + values: Optional[list] = None, + variable: Union[tkinter.Variable, None] = None, dynamic_resizing: bool = True, - command: Callable[[str], None] = None, + command: Union[Callable[[str], None], None] = None, state: str = "normal", **kwargs): super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) - self._sb_fg_color = ThemeManager.theme["color"]["segmented_button"] if fg_color == "default_theme" else fg_color + self._sb_fg_color = ThemeManager.theme["color"]["segmented_button"] if fg_color is None else self._check_color_type(fg_color) - self._sb_selected_color = ThemeManager.theme["color"]["button"] if selected_color == "default_theme" else selected_color - self._sb_selected_hover_color = ThemeManager.theme["color"]["button_hover"] if selected_hover_color == "default_theme" else selected_hover_color + self._sb_selected_color = ThemeManager.theme["color"]["button"] if selected_color is None else self._check_color_type(selected_color) + self._sb_selected_hover_color = ThemeManager.theme["color"]["button_hover"] if selected_hover_color is None else self._check_color_type(selected_hover_color) - self._sb_unselected_color = ThemeManager.theme["color"]["segmented_button_unselected"] if unselected_color == "default_theme" else unselected_color - self._sb_unselected_hover_color = ThemeManager.theme["color"]["segmented_button_unselected_hover"] if unselected_hover_color == "default_theme" else unselected_hover_color + self._sb_unselected_color = ThemeManager.theme["color"]["segmented_button_unselected"] if unselected_color is None else self._check_color_type(unselected_color) + self._sb_unselected_hover_color = ThemeManager.theme["color"]["segmented_button_unselected_hover"] if unselected_hover_color is None else self._check_color_type(unselected_hover_color) - self._sb_text_color = ThemeManager.theme["color"]["text_button"] if text_color == "default_theme" else text_color - self._sb_text_color_disabled = ThemeManager.theme["color"]["text_button_disabled"] if text_color_disabled == "default_theme" else text_color_disabled + self._sb_text_color = ThemeManager.theme["color"]["text_button"] if text_color is None else self._check_color_type(text_color) + self._sb_text_color_disabled = ThemeManager.theme["color"]["text_button_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled) - self._sb_corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius - self._sb_border_width = ThemeManager.theme["shape"]["button_border_width"] if border_width == "default_theme" else border_width + self._sb_corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius is None else corner_radius + self._sb_border_width = ThemeManager.theme["shape"]["button_border_width"] if border_width is None else border_width self._background_corner_colors = background_corner_colors # rendering options for DrawEngine self._command: Callable[[str], None] = command - self._font = (ThemeManager.theme["text"]["font"], ThemeManager.theme["text"]["size"]) if font == "default_theme" else font + self._font = (ThemeManager.theme["text"]["font"], ThemeManager.theme["text"]["size"]) if font is None else font self._state = state self._buttons_dict: Dict[str, CTkButton] = {} # mapped from value to button object @@ -84,7 +84,7 @@ class CTkSegmentedButton(CTkFrame): self._variable_callback_name = self._variable.trace_add("write", self._variable_callback) self.set(self._variable.get(), from_variable_callback=True) - super().configure(corner_radius=self._sb_corner_radius, fg_color=None) + super().configure(corner_radius=self._sb_corner_radius, fg_color="red") def destroy(self): if self._variable is not None: # remove old callback @@ -147,21 +147,22 @@ class CTkSegmentedButton(CTkFrame): def _create_button(self, index: int, value: str) -> CTkButton: new_button = CTkButton(self, - height=self._current_height, width=0, + height=self._current_height, corner_radius=self._sb_corner_radius, - text=value, border_width=self._sb_border_width, - border_color=self._sb_fg_color, fg_color=self._sb_unselected_color, + border_color=self._sb_fg_color, hover_color=self._sb_unselected_hover_color, text_color=self._sb_text_color, text_color_disabled=self._sb_text_color_disabled, + text=value, font=self._font, state=self._state, command=lambda v=value: self.set(v, from_button_callback=True), background_corner_colors=None, - round_width_to_even_numbers=False) # DrawEngine rendering option (so that theres no gap between buttons) + round_width_to_even_numbers=False, + round_height_to_even_numbers=False) # DrawEngine rendering option (so that theres no gap between buttons) return new_button @@ -201,40 +202,40 @@ class CTkSegmentedButton(CTkFrame): self._configure_button_corners_for_index(max_index) if "fg_color" in kwargs: - self._sb_fg_color = kwargs.pop("fg_color") + self._sb_fg_color = self._check_color_type(kwargs.pop("fg_color")) for index, button in enumerate(self._buttons_dict.values()): button.configure(border_color=self._sb_fg_color) self._configure_button_corners_for_index(index) if "selected_color" in kwargs: - self._sb_selected_color = kwargs.pop("selected_color") + self._sb_selected_color = self._check_color_type(kwargs.pop("selected_color")) if self._current_value in self._buttons_dict: self._buttons_dict[self._current_value].configure(fg_color=self._sb_selected_color) if "selected_hover_color" in kwargs: - self._sb_selected_hover_color = kwargs.pop("selected_hover_color") + self._sb_selected_hover_color = self._check_color_type(kwargs.pop("selected_hover_color")) if self._current_value in self._buttons_dict: self._buttons_dict[self._current_value].configure(hover_color=self._sb_selected_hover_color) if "unselected_color" in kwargs: - self._sb_unselected_color = kwargs.pop("unselected_color") + self._sb_unselected_color = self._check_color_type(kwargs.pop("unselected_color")) for value, button in self._buttons_dict.items(): if value != self._current_value: button.configure(fg_color=self._sb_unselected_color) if "unselected_hover_color" in kwargs: - self._sb_unselected_hover_color = kwargs.pop("unselected_hover_color") + self._sb_unselected_hover_color = self._check_color_type(kwargs.pop("unselected_hover_color")) for value, button in self._buttons_dict.items(): if value != self._current_value: button.configure(hover_color=self._sb_unselected_hover_color) if "text_color" in kwargs: - self._sb_text_color = kwargs.pop("text_color") + self._sb_text_color = self._check_color_type(kwargs.pop("text_color")) for button in self._buttons_dict.values(): button.configure(text_color=self._sb_text_color) if "text_color_disabled" in kwargs: - self._sb_text_color_disabled = kwargs.pop("text_color_disabled") + self._sb_text_color_disabled = self._check_color_type(kwargs.pop("text_color_disabled")) for button in self._buttons_dict.values(): button.configure(text_color_disabled=self._sb_text_color_disabled) diff --git a/customtkinter/windows/widgets/ctk_slider.py b/customtkinter/windows/widgets/ctk_slider.py index cf6ceeb..dce6aa4 100644 --- a/customtkinter/windows/widgets/ctk_slider.py +++ b/customtkinter/windows/widgets/ctk_slider.py @@ -1,6 +1,6 @@ import tkinter import sys -from typing import Union, Tuple, Callable +from typing import Union, Tuple, Callable, Optional from .core_rendering.ctk_canvas import CTkCanvas from .theme.theme_manager import ThemeManager @@ -15,38 +15,38 @@ class CTkSlider(CTkBaseClass): """ def __init__(self, - master: any = None, - width: Union[int, str] = "default_init", - height: Union[int, str] = "default_init", - corner_radius: Union[int, str] = "default_theme", - button_corner_radius: Union[int, str] = "default_theme", - border_width: Union[int, str] = "default_theme", - button_length: Union[int, str] = "default_theme", + master: any, + width: Optional[int] = None, + height: Optional[int] = None, + corner_radius: Optional[int] = None, + button_corner_radius: Optional[int] = None, + border_width: Optional[int] = None, + button_length: Optional[int] = None, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str]] = "default_theme", - border_color: Union[str, Tuple[str, str], None] = None, - progress_color: Union[str, Tuple[str, str], None] = "default_theme", - button_color: Union[str, Tuple[str, str]] = "default_theme", - button_hover_color: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + border_color: Union[str, Tuple[str, str]] = "transparent", + progress_color: Optional[Union[str, Tuple[str, str]]] = None, + button_color: Optional[Union[str, Tuple[str, str]]] = None, + button_hover_color: Optional[Union[str, Tuple[str, str]]] = None, from_: int = 0, to: int = 1, state: str = "normal", number_of_steps: Union[int, None] = None, hover: bool = True, - command: Callable[[float], None] = None, - variable: tkinter.Variable = None, + command: Union[Callable[[float], None], None] = None, + variable: Union[tkinter.Variable, None] = None, orientation: str = "horizontal", **kwargs): # set default dimensions according to orientation - if width == "default_init": + if width is None: if orientation.lower() == "vertical": width = 16 else: width = 200 - if height == "default_init": + if height is None: if orientation.lower() == "vertical": height = 200 else: @@ -56,17 +56,17 @@ class CTkSlider(CTkBaseClass): super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) # color - self._border_color = border_color - self._fg_color = ThemeManager.theme["color"]["slider"] if fg_color == "default_theme" else fg_color - self._progress_color = ThemeManager.theme["color"]["slider_progress"] if progress_color == "default_theme" else progress_color - self._button_color = ThemeManager.theme["color"]["slider_button"] if button_color == "default_theme" else button_color - self._button_hover_color = ThemeManager.theme["color"]["slider_button_hover"] if button_hover_color == "default_theme" else button_hover_color + self._border_color = self._check_color_type(border_color, transparency=True) + self._fg_color = ThemeManager.theme["color"]["slider"] if fg_color is None else self._check_color_type(fg_color) + self._progress_color = ThemeManager.theme["color"]["slider_progress"] if progress_color is None else self._check_color_type(progress_color, transparency=True) + self._button_color = ThemeManager.theme["color"]["slider_button"] if button_color is None else self._check_color_type(button_color) + self._button_hover_color = ThemeManager.theme["color"]["slider_button_hover"] if button_hover_color is None else self._check_color_type(button_hover_color) # shape - self._corner_radius = ThemeManager.theme["shape"]["slider_corner_radius"] if corner_radius == "default_theme" else corner_radius - self._button_corner_radius = ThemeManager.theme["shape"]["slider_button_corner_radius"] if button_corner_radius == "default_theme" else button_corner_radius - self._border_width = ThemeManager.theme["shape"]["slider_border_width"] if border_width == "default_theme" else border_width - self._button_length = ThemeManager.theme["shape"]["slider_button_length"] if button_length == "default_theme" else button_length + self._corner_radius = ThemeManager.theme["shape"]["slider_corner_radius"] if corner_radius is None else corner_radius + self._button_corner_radius = ThemeManager.theme["shape"]["slider_button_corner_radius"] if button_corner_radius is None else button_corner_radius + self._border_width = ThemeManager.theme["shape"]["slider_border_width"] if border_width is None else border_width + self._button_length = ThemeManager.theme["shape"]["slider_button_length"] if button_length is None else button_length self._value: float = 0.5 # initial value of slider in percent self._orientation = orientation self._hover_state: bool = False @@ -165,7 +165,7 @@ class CTkSlider(CTkBaseClass): if no_color_updates is False or requires_recoloring: self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color)) - if self._border_color is None: + if self._border_color == "transparent": self._canvas.itemconfig("border_parts", fill=self._apply_appearance_mode(self._bg_color), outline=self._apply_appearance_mode(self._bg_color)) else: @@ -175,7 +175,7 @@ class CTkSlider(CTkBaseClass): self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._fg_color), outline=self._apply_appearance_mode(self._fg_color)) - if self._progress_color is None: + if self._progress_color == "transparent": self._canvas.itemconfig("progress_parts", fill=self._apply_appearance_mode(self._fg_color), outline=self._apply_appearance_mode(self._fg_color)) else: @@ -198,23 +198,23 @@ class CTkSlider(CTkBaseClass): require_redraw = True if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color")) require_redraw = True if "progress_color" in kwargs: - self._progress_color = kwargs.pop("progress_color") + self._progress_color = self._check_color_type(kwargs.pop("progress_color"), transparency=True) require_redraw = True if "button_color" in kwargs: - self._button_color = kwargs.pop("button_color") + self._button_color = self._check_color_type(kwargs.pop("button_color")) require_redraw = True if "button_hover_color" in kwargs: - self._button_hover_color = kwargs.pop("button_hover_color") + self._button_hover_color = self._check_color_type(kwargs.pop("button_hover_color")) require_redraw = True if "border_color" in kwargs: - self._border_color = kwargs.pop("border_color") + self._border_color = self._check_color_type(kwargs.pop("border_color"), transparency=True) require_redraw = True if "border_width" in kwargs: @@ -294,9 +294,9 @@ class CTkSlider(CTkBaseClass): def _clicked(self, event=None): if self._state == "normal": if self._orientation.lower() == "horizontal": - self._value = (event.x / self._current_width) / self._widget_scaling + self._value = self._reverse_widget_scaling(event.x / self._current_width) else: - self._value = 1 - (event.y / self._current_height) / self._widget_scaling + self._value = 1 - self._reverse_widget_scaling(event.y / self._current_height) if self._value > 1: self._value = 1 diff --git a/customtkinter/windows/widgets/ctk_switch.py b/customtkinter/windows/widgets/ctk_switch.py index cc6f113..d9b3fc6 100644 --- a/customtkinter/windows/widgets/ctk_switch.py +++ b/customtkinter/windows/widgets/ctk_switch.py @@ -1,6 +1,6 @@ import tkinter import sys -from typing import Union, Tuple, Callable +from typing import Union, Tuple, Callable, Optional from .core_rendering.ctk_canvas import CTkCanvas from .theme.theme_manager import ThemeManager @@ -16,32 +16,32 @@ class CTkSwitch(CTkBaseClass): """ def __init__(self, - master: any = None, + master: any, width: int = 100, height: int = 24, switch_width: int = 36, switch_height: int = 18, - corner_radius: Union[int, str] = "default_theme", - border_width: Union[int, str] = "default_theme", - button_length: Union[int, str] = "default_theme", + corner_radius: Optional[int] = None, + border_width: Optional[int] = None, + button_length: Optional[int] = None, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str]] = "default_theme", - border_color: Union[str, Tuple[str, str], None] = None, - progress_color: Union[str, Tuple[str, str]] = "default_theme", - button_color: Union[str, Tuple[str, str]] = "default_theme", - button_hover_color: Union[str, Tuple[str, str]] = "default_theme", - text_color: Union[str, Tuple[str, str]] = "default_theme", - text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + border_color: Union[str, Tuple[str, str]] = "transparent", + progress_color: Optional[Union[str, Tuple[str, str]]] = None, + button_color: Optional[Union[str, Tuple[str, str]]] = None, + button_hover_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None, text: str = "CTkSwitch", - font: Union[tuple, CTkFont] = "default_theme", - textvariable: tkinter.Variable = None, + font: Optional[Union[tuple, CTkFont]] = None, + textvariable: Union[tkinter.Variable, None] = None, onvalue: Union[int, str] = 1, offvalue: Union[int, str] = 0, - variable: tkinter.Variable = None, + variable: Union[tkinter.Variable, None] = None, hover: bool = True, - command: Callable = None, + command: Union[Callable, None] = None, state: str = tkinter.NORMAL, **kwargs): @@ -53,28 +53,27 @@ class CTkSwitch(CTkBaseClass): self._switch_height = switch_height # color - self._border_color = border_color - self._fg_color = ThemeManager.theme["color"]["switch"] if fg_color == "default_theme" else fg_color - self._progress_color = ThemeManager.theme["color"]["switch_progress"] if progress_color == "default_theme" else progress_color - self._button_color = ThemeManager.theme["color"]["switch_button"] if button_color == "default_theme" else button_color - self._button_hover_color = ThemeManager.theme["color"]["switch_button_hover"] if button_hover_color == "default_theme" else button_hover_color - self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color - self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled == "default_theme" else text_color_disabled + self._border_color = self._check_color_type(border_color, transparency=True) + self._fg_color = ThemeManager.theme["color"]["switch"] if fg_color is None else self._check_color_type(fg_color) + self._progress_color = ThemeManager.theme["color"]["switch_progress"] if progress_color is None else self._check_color_type(progress_color, transparency=True) + self._button_color = ThemeManager.theme["color"]["switch_button"] if button_color is None else self._check_color_type(button_color) + self._button_hover_color = ThemeManager.theme["color"]["switch_button_hover"] if button_hover_color is None else self._check_color_type(button_hover_color) + self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color) + self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled) # text self._text = text self._text_label = None # font - self._font = CTkFont() if font == "default_theme" else self._check_font_type(font) + self._font = CTkFont() if font is None else self._check_font_type(font) if isinstance(self._font, CTkFont): self._font.add_size_configure_callback(self._update_font) # shape - self._corner_radius = ThemeManager.theme["shape"]["switch_corner_radius"] if corner_radius == "default_theme" else corner_radius - # self.button_corner_radius = ThemeManager.theme["shape"]["switch_button_corner_radius"] if button_corner_radius == "default_theme" else button_corner_radius - self._border_width = ThemeManager.theme["shape"]["switch_border_width"] if border_width == "default_theme" else border_width - self._button_length = ThemeManager.theme["shape"]["switch_button_length"] if button_length == "default_theme" else button_length + self._corner_radius = ThemeManager.theme["shape"]["switch_corner_radius"] if corner_radius is None else corner_radius + self._border_width = ThemeManager.theme["shape"]["switch_border_width"] if border_width is None else border_width + self._button_length = ThemeManager.theme["shape"]["switch_button_length"] if button_length is None else button_length self._hover_state: bool = False self._check_state: bool = False # True if switch is activated self._hover = hover @@ -84,7 +83,7 @@ class CTkSwitch(CTkBaseClass): # callback and control variables self._command = command - self._variable: tkinter.Variable = variable + self._variable = variable self._variable_callback_blocked = False self._variable_callback_name = None self._textvariable = textvariable @@ -216,7 +215,7 @@ class CTkSwitch(CTkBaseClass): self._bg_canvas.configure(bg=self._apply_appearance_mode(self._bg_color)) self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color)) - if self._border_color is None: + if self._border_color == "transparent": self._canvas.itemconfig("border_parts", fill=self._apply_appearance_mode(self._bg_color), outline=self._apply_appearance_mode(self._bg_color)) else: @@ -226,7 +225,7 @@ class CTkSwitch(CTkBaseClass): self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._fg_color), outline=self._apply_appearance_mode(self._fg_color)) - if self._progress_color is None: + if self._progress_color == "transparent": self._canvas.itemconfig("progress_parts", fill=self._apply_appearance_mode(self._fg_color), outline=self._apply_appearance_mode(self._fg_color)) else: @@ -285,27 +284,23 @@ class CTkSwitch(CTkBaseClass): require_redraw = True if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color")) require_redraw = True if "progress_color" in kwargs: - new_progress_color = kwargs.pop("progress_color") - if new_progress_color is None: - self._progress_color = self._fg_color - else: - self._progress_color = new_progress_color + self._progress_color = self._check_color_type(kwargs.pop("progress_color"), transparency=True) require_redraw = True if "button_color" in kwargs: - self._button_color = kwargs.pop("button_color") + self._button_color = self._check_color_type(kwargs.pop("button_color")) require_redraw = True if "button_hover_color" in kwargs: - self._button_hover_color = kwargs.pop("button_hover_color") + self._button_hover_color = self._check_color_type(kwargs.pop("button_hover_color")) require_redraw = True if "border_color" in kwargs: - self._border_color = kwargs.pop("border_color") + self._border_color = self._check_color_type(kwargs.pop("border_color"), transparency=True) require_redraw = True if "hover" in kwargs: diff --git a/customtkinter/windows/widgets/ctk_tabview.py b/customtkinter/windows/widgets/ctk_tabview.py index 51c058d..20be810 100644 --- a/customtkinter/windows/widgets/ctk_tabview.py +++ b/customtkinter/windows/widgets/ctk_tabview.py @@ -1,4 +1,4 @@ -from typing import Union, Tuple, Dict, List, Callable +from typing import Union, Tuple, Dict, List, Callable, Optional from .theme.theme_manager import ThemeManager from .ctk_frame import CTkFrame @@ -14,32 +14,32 @@ class CTkTabview(CTkBaseClass): For detailed information check out the documentation. """ - _top_spacing = 10 # px on top of the buttons - _top_button_overhang = 8 # px - _button_height = 26 - _segmented_button_border_width = 3 + _top_spacing: int = 10 # px on top of the buttons + _top_button_overhang: int = 8 # px + _button_height: int = 26 + _segmented_button_border_width: int = 3 def __init__(self, - master: any = None, + master: any, width: int = 300, height: int = 250, - corner_radius: Union[int, str] = "default_theme", - border_width: Union[int, str] = "default_theme", + corner_radius: Optional[int] = None, + border_width: Optional[int] = None, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str], None] = "default_theme", - border_color: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + border_color: Optional[Union[str, Tuple[str, str]]] = None, - segmented_button_fg_color: Union[str, Tuple[str, str], None] = "default_theme", - segmented_button_selected_color: Union[str, Tuple[str, str]] = "default_theme", - segmented_button_selected_hover_color: Union[str, Tuple[str, str]] = "default_theme", - segmented_button_unselected_color: Union[str, Tuple[str, str]] = "default_theme", - segmented_button_unselected_hover_color: Union[str, Tuple[str, str]] = "default_theme", + segmented_button_fg_color: Optional[Union[str, Tuple[str, str]]] = None, + segmented_button_selected_color: Optional[Union[str, Tuple[str, str]]] = None, + segmented_button_selected_hover_color: Optional[Union[str, Tuple[str, str]]] = None, + segmented_button_unselected_color: Optional[Union[str, Tuple[str, str]]] = None, + segmented_button_unselected_hover_color: Optional[Union[str, Tuple[str, str]]] = None, - text_color: Union[str, Tuple[str, str]] = "default_theme", - text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", + text_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None, - command: Callable = None, + command: Union[Callable, None] = None, state: str = "normal", **kwargs): @@ -47,10 +47,10 @@ class CTkTabview(CTkBaseClass): super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) # color - self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color == "default_theme" else border_color + self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color is None else self._check_color_type(border_color) # determine fg_color of frame - if fg_color == "default_theme": + if fg_color is None: if isinstance(self.master, (CTkFrame, CTkTabview)): if self.master.cget("fg_color") == ThemeManager.theme["color"]["frame_low"]: self._fg_color = ThemeManager.theme["color"]["frame_high"] @@ -59,11 +59,11 @@ class CTkTabview(CTkBaseClass): else: self._fg_color = ThemeManager.theme["color"]["frame_low"] else: - self._fg_color = fg_color + self._fg_color = self._check_color_type(fg_color, transparency=True) # shape - self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius - self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width == "default_theme" else border_width + self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius is None else corner_radius + self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width is None else border_width self._canvas = CTkCanvas(master=self, bg=self._apply_appearance_mode(self._bg_color), @@ -83,7 +83,7 @@ class CTkTabview(CTkBaseClass): text_color=text_color, text_color_disabled=text_color_disabled, corner_radius=corner_radius, - border_width=self._apply_widget_scaling(self._segmented_button_border_width), + border_width=self._segmented_button_border_width, command=self._segmented_button_callback, state=state) self._configure_segmented_button_background_corners() @@ -124,6 +124,7 @@ class CTkTabview(CTkBaseClass): self._canvas.configure(width=self._apply_widget_scaling(self._desired_width), height=self._apply_widget_scaling(self._desired_height - self._top_spacing - self._top_button_overhang)) + self._configure_grid() self._draw(no_color_updates=True) def _set_dimensions(self, width=None, height=None): @@ -194,7 +195,7 @@ class CTkTabview(CTkBaseClass): self._apply_widget_scaling(self._border_width)) if no_color_updates is False or requires_recoloring: - if self._fg_color is None: + if self._fg_color == "transparent": self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._bg_color), outline=self._apply_appearance_mode(self._bg_color)) @@ -217,10 +218,10 @@ class CTkTabview(CTkBaseClass): require_redraw = True if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True) require_redraw = True if "border_color" in kwargs: - self._border_color = kwargs.pop("border_color") + self._border_color = self._check_color_type(kwargs.pop("border_color")) require_redraw = True if "segmented_button_fg_color" in kwargs: self._segmented_button.configure(fg_color=kwargs.pop("segmented_button_fg_color")) diff --git a/customtkinter/windows/widgets/ctk_textbox.py b/customtkinter/windows/widgets/ctk_textbox.py index 558d292..9dcab45 100644 --- a/customtkinter/windows/widgets/ctk_textbox.py +++ b/customtkinter/windows/widgets/ctk_textbox.py @@ -1,5 +1,5 @@ import tkinter -from typing import Union, Tuple +from typing import Union, Tuple, Optional from .core_rendering.ctk_canvas import CTkCanvas from .ctk_scrollbar import CTkScrollbar @@ -33,21 +33,21 @@ class CTkTextbox(CTkBaseClass): "xscrollcommand", "yscrollcommand"} def __init__(self, - master: any = None, + master: any, width: int = 200, height: int = 200, - corner_radius: Union[int, str] = "default_theme", - border_width: Union[int, str] = "default_theme", + corner_radius: Optional[int] = None, + border_width: Optional[int] = None, border_spacing: int = 3, - bg_color: Union[str, Tuple[str, str], None] = None, - fg_color: Union[str, Tuple[str, str], None] = "default_theme", - border_color: Union[str, Tuple[str, str]] = "default_theme", - text_color: Union[str, str] = "default_theme", - scrollbar_color: Union[str, Tuple[str, str]] = "default_theme", - scrollbar_hover_color: Union[str, Tuple[str, str]] = "default_theme", + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + border_color: Optional[Union[str, Tuple[str, str]]] = None, + text_color: Optional[Union[str, str]] = None, + scrollbar_color: Optional[Union[str, Tuple[str, str]]] = None, + scrollbar_hover_color: Optional[Union[str, Tuple[str, str]]] = None, - font: Union[tuple, CTkFont] = "default_theme", + font: Optional[Union[tuple, CTkFont]] = None, activate_scrollbars: bool = True, **kwargs): @@ -55,19 +55,19 @@ class CTkTextbox(CTkBaseClass): super().__init__(master=master, bg_color=bg_color, width=width, height=height) # color - self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color == "default_theme" else fg_color - self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color == "default_theme" else border_color - self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color - self._scrollbar_color = ThemeManager.theme["color"]["scrollbar_button"] if scrollbar_color == "default_theme" else scrollbar_color - self._scrollbar_hover_color = ThemeManager.theme["color"]["scrollbar_button_hover"] if scrollbar_hover_color == "default_theme" else scrollbar_hover_color + self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color is None else self._check_color_type(fg_color, transparency=True) + self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color is None else self._check_color_type(border_color) + self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color) + self._scrollbar_color = ThemeManager.theme["color"]["scrollbar_button"] if scrollbar_color is None else self._check_color_type(scrollbar_color) + self._scrollbar_hover_color = ThemeManager.theme["color"]["scrollbar_button_hover"] if scrollbar_hover_color is None else self._check_color_type(scrollbar_hover_color) # shape - self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius - self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width == "default_theme" else border_width + self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius is None else corner_radius + self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width is None else border_width self._border_spacing = border_spacing # font - self._font = CTkFont() if font == "default_theme" else self._check_font_type(font) + self._font = CTkFont() if font is None else self._check_font_type(font) if isinstance(self._font, CTkFont): self._font.add_size_configure_callback(self._update_font) @@ -221,7 +221,7 @@ class CTkTextbox(CTkBaseClass): self._apply_widget_scaling(self._border_width)) if no_color_updates is False or requires_recoloring: - if self._fg_color is None: + if self._fg_color == "transparent": self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._bg_color), outline=self._apply_appearance_mode(self._bg_color)) @@ -254,7 +254,7 @@ class CTkTextbox(CTkBaseClass): def configure(self, require_redraw=False, **kwargs): if "fg_color" in kwargs: - self._fg_color = kwargs.pop("fg_color") + self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True) require_redraw = True # check if CTk widgets are children of the frame and change their _bg_color to new frame fg_color @@ -263,13 +263,23 @@ class CTkTextbox(CTkBaseClass): child.configure(bg_color=self._fg_color) if "border_color" in kwargs: - self._border_color = kwargs.pop("border_color") + self._border_color = self._check_color_type(kwargs.pop("border_color")) require_redraw = True if "text_color" in kwargs: - self._text_color = kwargs.pop("text_color") + self._text_color = self._check_color_type(kwargs.pop("text_color")) require_redraw = True + if "scrollbar_color" in kwargs: + self._scrollbar_color = self._check_color_type(kwargs.pop("scrollbar_color")) + self._x_scrollbar.configure(scrollbar_color=self._scrollbar_color) + self._y_scrollbar.configure(scrollbar_color=self._scrollbar_color) + + if "scrollbar_hover_color" in kwargs: + self._scrollbar_hover_color = self._check_color_type(kwargs.pop("scrollbar_hover_color")) + self._x_scrollbar.configure(scrollbar_hover_color=self._scrollbar_hover_color) + self._y_scrollbar.configure(scrollbar_hover_color=self._scrollbar_hover_color) + if "corner_radius" in kwargs: self._corner_radius = kwargs.pop("corner_radius") self._create_grid_for_text_and_scrollbars(re_grid_textbox=True, re_grid_x_scrollbar=True, re_grid_y_scrollbar=True) diff --git a/customtkinter/windows/widgets/font/ctk_font.py b/customtkinter/windows/widgets/font/ctk_font.py index 16775f7..f27ca87 100644 --- a/customtkinter/windows/widgets/font/ctk_font.py +++ b/customtkinter/windows/widgets/font/ctk_font.py @@ -21,8 +21,8 @@ class CTkFont(Font): """ def __init__(self, - family: str = "default_theme", - size: int = "default_theme", + family: str = "default", + size: int = "default", weight: str = "normal", slant: str = "roman", underline: bool = False, @@ -31,10 +31,10 @@ class CTkFont(Font): self._size_configure_callback_list: List[Callable] = [] self._family = family - self._size = ThemeManager.theme["text"]["size"] if size == "default_theme" else size + self._size = ThemeManager.theme["text"]["size"] if size == "default" else size self._tuple_style_string = f"{weight} {slant} {'underline' if underline else ''} {'overstrike' if overstrike else ''}" - super().__init__(family=ThemeManager.theme["text"]["font"] if family == "default_theme" else family, + super().__init__(family=ThemeManager.theme["text"]["font"] if family == "default" else family, size=-abs(self._size), weight=weight, slant=slant, diff --git a/customtkinter/windows/widgets/scaling/scaling_base_class.py b/customtkinter/windows/widgets/scaling/scaling_base_class.py index 009ec99..3c7862f 100644 --- a/customtkinter/windows/widgets/scaling/scaling_base_class.py +++ b/customtkinter/windows/widgets/scaling/scaling_base_class.py @@ -1,4 +1,3 @@ -import tkinter from typing import Union, Tuple import copy import re @@ -9,7 +8,6 @@ except ImportError: from .scaling_tracker import ScalingTracker from ..font.ctk_font import CTkFont -from ..image.ctk_image import CTkImage class CTkScalingBaseClass(): diff --git a/examples/complex_example.py b/examples/complex_example.py index 9eeef82..ab091ee 100644 --- a/examples/complex_example.py +++ b/examples/complex_example.py @@ -47,7 +47,7 @@ class App(customtkinter.CTk): self.entry = customtkinter.CTkEntry(self, placeholder_text="CTkEntry") self.entry.grid(row=3, column=1, columnspan=2, padx=(20, 0), pady=(20, 20), sticky="nsew") - self.main_button_1 = customtkinter.CTkButton(master=self, fg_color=None, border_width=2) + self.main_button_1 = customtkinter.CTkButton(master=self, fg_color="transparent", border_width=2) self.main_button_1.grid(row=3, column=3, padx=(20, 20), pady=(20, 20), sticky="nsew") # create textbox @@ -101,7 +101,7 @@ class App(customtkinter.CTk): self.switch_2.grid(row=4, column=0, pady=(10, 20), padx=20, sticky="n") # create slider and progressbar frame - self.slider_progressbar_frame = customtkinter.CTkFrame(self, fg_color=None) + self.slider_progressbar_frame = customtkinter.CTkFrame(self, fg_color="transparent") self.slider_progressbar_frame.grid(row=1, column=1, columnspan=2, padx=(20, 0), pady=(20, 0), sticky="nsew") self.slider_progressbar_frame.grid_columnconfigure(0, weight=1) self.slider_progressbar_frame.grid_rowconfigure(4, weight=1)