changed transparent color value from None to "transparent", fixed type hints, added color type and value checking

This commit is contained in:
Tom Schimansky 2022-11-10 23:27:55 +01:00
parent 1387e834b5
commit cbbc9efda3
27 changed files with 566 additions and 574 deletions

View File

@ -10,6 +10,7 @@ ToDo:
- add new button attributes to wiki - add new button attributes to wiki
- cursor configuring - cursor configuring
- overwrite winfo methods - overwrite winfo methods
- renew input dialog
## Unreleased - 2022-10-2 ## Unreleased - 2022-10-2
### Added ### Added

View File

@ -1,5 +1,6 @@
![PyPI](https://img.shields.io/pypi/v/customtkinter) ![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) ![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) ![Total lines](https://img.shields.io/tokei/lines/github.com/tomschimansky/customtkinter?color=green&label=total%20lines)

View File

@ -12,7 +12,7 @@
"frame_border": ["#979DA2", "#565B5E"], "frame_border": ["#979DA2", "#565B5E"],
"frame_low": ["#D1D5D8", "#2A2D2E"], "frame_low": ["#D1D5D8", "#2A2D2E"],
"frame_high": ["#C0C2C5", "#343638"], "frame_high": ["#C0C2C5", "#343638"],
"label": [null, null], "label": "transparent",
"text": ["gray10", "#DCE4EE"], "text": ["gray10", "#DCE4EE"],
"text_disabled": ["gray60", "gray45"], "text_disabled": ["gray60", "gray45"],
"text_button": ["#DCE4EE", "#DCE4EE"], "text_button": ["#DCE4EE", "#DCE4EE"],
@ -78,7 +78,6 @@
"slider_button_corner_radius": 1000, "slider_button_corner_radius": 1000,
"switch_border_width": 3, "switch_border_width": 3,
"switch_corner_radius": 1000, "switch_corner_radius": 1000,
"switch_button_corner_radius": 1000,
"switch_button_length": 0, "switch_button_length": 0,
"scrollbar_corner_radius": 1000, "scrollbar_corner_radius": 1000,
"scrollbar_border_spacing": 4 "scrollbar_border_spacing": 4

View File

@ -15,20 +15,20 @@ class CTkInputDialog(CTkToplevel):
def __init__(self, def __init__(self,
master: any = None, master: any = None,
fg_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_theme", button_fg_color: Union[str, Tuple[str, str]] = "default",
button_hover_color: Union[str, Tuple[str, str]] = "default_theme", button_hover_color: Union[str, Tuple[str, str]] = "default",
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Union[str, Tuple[str, str]] = "default",
title: str = "CTkDialog", title: str = "CTkDialog",
text: str = "CTkDialog"): text: str = "CTkDialog"):
super().__init__(master=master, fg_color=fg_color) super().__init__(master=master, fg_color=fg_color)
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 == "default" else fg_color
self._button_fg_color = ThemeManager.theme["color"]["button"] if button_fg_color == "default_theme" else button_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_theme" else button_hover_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_theme" 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._user_input: Union[str, None] = None
self._running: bool = False self._running: bool = False
self._height: int = len(text.split("\n")) * 20 + 150 self._height: int = len(text.split("\n")) * 20 + 150

View File

@ -4,7 +4,7 @@ import sys
import os import os
import platform import platform
import ctypes import ctypes
from typing import Union, Tuple from typing import Union, Tuple, Optional
from .widgets.theme.theme_manager import ThemeManager from .widgets.theme.theme_manager import ThemeManager
from .widgets.scaling.scaling_base_class import CTkScalingBaseClass 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. 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', _valid_tk_configure_arguments: set = {'bd', 'borderwidth', 'class', 'menu', 'relief', 'screen',
'use', 'container', 'cursor', 'height', 'use', 'container', 'cursor', 'height',
'highlightthickness', 'padx', 'pady', 'takefocus', 'visual', 'width'} 'highlightthickness', 'padx', 'pady', 'takefocus', 'visual', 'width'}
_deactivate_macos_window_header_manipulation = False _deactivate_macos_window_header_manipulation: bool = False
_deactivate_windows_window_header_manipulation = False _deactivate_windows_window_header_manipulation: bool = False
def __init__(self, def __init__(self,
fg_color: Union[str, Tuple[str, str]] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
**kwargs): **kwargs):
self._enable_macos_dark_title_bar() self._enable_macos_dark_title_bar()
@ -48,7 +48,7 @@ class CTk(tkinter.Tk, CTkAppearanceModeBaseClass, CTkScalingBaseClass):
self._max_height: int = 1_000_000 self._max_height: int = 1_000_000
self._last_resizable_args: Union[Tuple[list, dict], None] = None # (args, kwargs) 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 # set bg of tkinter.Tk
super().configure(bg=self._apply_appearance_mode(self._fg_color)) super().configure(bg=self._apply_appearance_mode(self._fg_color))
@ -195,7 +195,7 @@ class CTk(tkinter.Tk, CTkAppearanceModeBaseClass, CTkScalingBaseClass):
def configure(self, **kwargs): def configure(self, **kwargs):
if "fg_color" in 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)) super().configure(bg=self._apply_appearance_mode(self._fg_color))
for child in self.winfo_children(): for child in self.winfo_children():

View File

@ -4,7 +4,7 @@ import sys
import os import os
import platform import platform
import ctypes import ctypes
from typing import Union, Tuple from typing import Union, Tuple, Optional
from .widgets.theme.theme_manager import ThemeManager from .widgets.theme.theme_manager import ThemeManager
from .widgets.scaling.scaling_base_class import CTkScalingBaseClass 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. 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", "highlightbackground", "highlightthickness", "menu", "relief",
"screen", "takefocus", "use", "visual", "width"} "screen", "takefocus", "use", "visual", "width"}
_deactivate_macos_window_header_manipulation = False _deactivate_macos_window_header_manipulation: bool = False
_deactivate_windows_window_header_manipulation = False _deactivate_windows_window_header_manipulation: bool = False
def __init__(self, *args, def __init__(self, *args,
fg_color: Union[str, Tuple[str, str]] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
**kwargs): **kwargs):
self._enable_macos_dark_title_bar() self._enable_macos_dark_title_bar()
@ -46,7 +46,7 @@ class CTkToplevel(tkinter.Toplevel, CTkAppearanceModeBaseClass, CTkScalingBaseCl
self._max_height: int = 1_000_000 self._max_height: int = 1_000_000
self._last_resizable_args: Union[Tuple[list, dict], None] = None # (args, kwargs) 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 # set bg color of tkinter.Toplevel
super().configure(bg=self._apply_appearance_mode(self._fg_color)) super().configure(bg=self._apply_appearance_mode(self._fg_color))
@ -153,7 +153,7 @@ class CTkToplevel(tkinter.Toplevel, CTkAppearanceModeBaseClass, CTkScalingBaseCl
def configure(self, **kwargs): def configure(self, **kwargs):
if "fg_color" in 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)) super().configure(bg=self._apply_appearance_mode(self._fg_color))
for child in self.winfo_children(): for child in self.winfo_children():

View File

@ -44,3 +44,18 @@ class CTkAppearanceModeBaseClass:
return color[self.__appearance_mode] return color[self.__appearance_mode]
else: else:
return color 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)}")

View File

@ -1,44 +1,38 @@
import tkinter import tkinter
import sys import sys
from typing import Union, Tuple, Callable, List from typing import Union, Tuple, Callable, List, Optional
from ..theme.theme_manager import ThemeManager from ..theme.theme_manager import ThemeManager
from ..scaling.scaling_tracker import ScalingTracker
from ..font.ctk_font import CTkFont from ..font.ctk_font import CTkFont
from ..appearance_mode.appearance_mode_tracker import AppearanceModeTracker
from ..appearance_mode.appearance_mode_base_class import CTkAppearanceModeBaseClass 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, def __init__(self, *args,
min_character_width: int = 18, min_character_width: int = 18,
fg_color: Union[str, Tuple[str, str]] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
hover_color: Union[str, Tuple[str, str]] = "default_theme", hover_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Optional[Union[str, Tuple[str, str]]] = None,
font: Union[tuple, CTkFont] = "default_theme", font: Optional[Union[tuple, CTkFont]] = None,
command: Callable = None, command: Union[Callable, None] = None,
values: List[str] = None, values: Optional[List[str]] = None,
**kwargs): **kwargs):
# call init methods of super classes # call init methods of super classes
tkinter.Menu.__init__(self, *args, **kwargs) tkinter.Menu.__init__(self, *args, **kwargs)
CTkAppearanceModeBaseClass.__init__(self) CTkAppearanceModeBaseClass.__init__(self)
CTkScalingBaseClass.__init__(self, scaling_type="widget")
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"
self._min_character_width = min_character_width self._min_character_width = min_character_width
self._fg_color = ThemeManager.theme["color"]["dropdown_color"] if fg_color == "default_theme" else fg_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 == "default_theme" else hover_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 == "default_theme" else text_color self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color)
# font # 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): if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font) self._font.add_size_configure_callback(self._update_font)
@ -125,16 +119,16 @@ class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass):
def configure(self, **kwargs): def configure(self, **kwargs):
if "fg_color" in 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=ThemeManager._apply_appearance_mode(self._fg_color, self._appearance_mode)) super().configure(bg=self._apply_appearance_mode(self._fg_color))
if "hover_color" in kwargs: if "hover_color" in kwargs:
self._hover_color = kwargs.pop("hover_color") self._hover_color = self._check_color_type(kwargs.pop("hover_color"))
super().configure(activebackground=ThemeManager._apply_appearance_mode(self._hover_color, self._appearance_mode)) super().configure(activebackground=self._apply_appearance_mode(self._hover_color))
if "text_color" in kwargs: if "text_color" in kwargs:
self._text_color = kwargs.pop("text_color") self._text_color = self._check_color_type(kwargs.pop("text_color"))
super().configure(fg=ThemeManager._apply_appearance_mode(self._text_color, self._appearance_mode)) super().configure(fg=self._apply_appearance_mode(self._text_color))
if "font" in kwargs: if "font" in kwargs:
if isinstance(self._font, CTkFont): if isinstance(self._font, CTkFont):
@ -175,29 +169,6 @@ class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass):
else: else:
return super().cget(attribute_name) 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 @staticmethod
def _check_font_type(font: any): def _check_font_type(font: any):
if isinstance(font, CTkFont): if isinstance(font, CTkFont):
@ -211,23 +182,17 @@ class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass):
return font return font
else: 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"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"\nUsage example:\n" +
f"font=customtkinter.CTkFont(family='<name>', size=<size in px>)\n" + f"font=customtkinter.CTkFont(family='<name>', size=<size in px>)\n" +
f"font=('<name>', <size in px>)\n") f"font=('<name>', <size in px>)\n")
def _set_scaling(self, new_widget_scaling, new_window_scaling): 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() self._configure_menu_for_platforms()
def _set_appearance_mode(self, mode_string): def _set_appearance_mode(self, mode_string):
""" colors won't update on appearance mode change when dropdown is open, because it's not necessary """ """ colors won't update on appearance mode change when dropdown is open, because it's not necessary """
super()._set_appearance_mode(mode_string)
if mode_string.lower() == "dark":
self._appearance_mode = 1
elif mode_string.lower() == "light":
self._appearance_mode = 0
self._configure_menu_for_platforms() self._configure_menu_for_platforms()

View File

@ -1,7 +1,7 @@
import sys import sys
import tkinter import tkinter
import tkinter.ttk as ttk import tkinter.ttk as ttk
from typing import Union, Callable, Tuple from typing import Union, Callable, Tuple, Optional
try: try:
from typing import TypedDict 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): 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 """ 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: # 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 _cursor_manipulation_enabled: bool = True
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 0, width: int = 0,
height: int = 0, height: int = 0,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
**kwargs): **kwargs):
# call init methods of super classes # 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 self._last_geometry_manager_call: Union[GeometryCallDict, None] = None
# background color # 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 # set bg color of tkinter.Frame
super().configure(bg=self._apply_appearance_mode(self._bg_color)) 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")) self._set_dimensions(height=kwargs.pop("height"))
if "bg_color" in kwargs: if "bg_color" in kwargs:
new_bg_color = kwargs.pop("bg_color") new_bg_color = self._check_color_type(kwargs.pop("bg_color"), transparency=True)
if new_bg_color is None: if new_bg_color == "transparent":
self._bg_color = self._detect_color_of_master() self._bg_color = self._detect_color_of_master()
else: else:
self._bg_color = new_bg_color self._bg_color = self._check_color_type(new_bg_color)
require_redraw = True require_redraw = True
super().configure(**pop_from_dict_by_set(kwargs, self._valid_tk_frame_attributes)) # configure tkinter.Frame 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 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]]: 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: if master_widget is None:
master_widget = self.master master_widget = self.master
if isinstance(master_widget, (CTkBaseClass, CTk, CTkToplevel)) and hasattr(master_widget, "_fg_color"): if isinstance(master_widget, (CTkBaseClass, CTk, CTkToplevel)):
if master_widget.cget("fg_color") is not None: if master_widget.cget("fg_color") is not None and master_widget.cget("fg_color") != "transparent":
return master_widget.cget("fg_color") return master_widget.cget("fg_color")
# if fg_color of master is None, try to retrieve fg_color from master of master # if fg_color of master is None, try to retrieve fg_color from master of master

View File

@ -1,6 +1,6 @@
import tkinter import tkinter
import sys import sys
from typing import Union, Tuple, Callable from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager from .theme.theme_manager import ThemeManager
@ -16,80 +16,82 @@ class CTkButton(CTkBaseClass):
For detailed information check out the documentation. For detailed information check out the documentation.
""" """
_image_label_spacing = 6 _image_label_spacing: int = 6
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 140, width: int = 140,
height: int = 28, height: int = 28,
corner_radius: Union[int, str] = "default_theme", corner_radius: Optional[int] = None,
border_width: Union[int, str] = "default_theme", border_width: Optional[int] = None,
border_spacing: int = 2, border_spacing: int = 2,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str], None] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
hover_color: Union[str, Tuple[str, str]] = "default_theme", hover_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str]] = "default_theme", border_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", 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_width_to_even_numbers: bool = True,
round_height_to_even_numbers: bool = True, round_height_to_even_numbers: bool = True,
text: str = "CTkButton", text: str = "CTkButton",
font: Union[tuple, CTkFont] = "default_theme", font: Optional[Union[tuple, CTkFont]] = None,
textvariable: tkinter.Variable = None, textvariable: Union[tkinter.Variable, None] = None,
image: Union[tkinter.PhotoImage, CTkImage] = None, image: Union[tkinter.PhotoImage, CTkImage, None] = None,
state: str = "normal", state: str = "normal",
hover: bool = True, hover: bool = True,
command: Callable = None, command: Union[Callable[[], None], None] = None,
compound: str = "left", compound: str = "left",
anchor: str = "center", anchor: str = "center",
**kwargs): **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) 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 # shape
self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius self._corner_radius: int = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius is None else corner_radius
self._border_width = ThemeManager.theme["shape"]["button_border_width"] if border_width == "default_theme" else border_width self._corner_radius = min(self._corner_radius, round(self._current_height / 2))
self._round_width_to_even_numbers = round_width_to_even_numbers # rendering options for DrawEngine self._border_width: int = ThemeManager.theme["shape"]["button_border_width"] if border_width is None else border_width
self._round_height_to_even_numbers = round_height_to_even_numbers # rendering options for DrawEngine self._border_spacing: int = border_spacing
self._corner_radius = min(self._corner_radius, round(self._current_height/2))
self._compound = compound
self._anchor = anchor
self._border_spacing = border_spacing
# text, image # color
self._image = self._check_image_type(image) 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._image_label: Union[tkinter.Label, None] = None 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 = text
self._text_label: Union[tkinter.Label, None] = None self._text_label: Union[tkinter.Label, None] = None
if isinstance(self._image, CTkImage): self._textvariable: tkinter.Variable = textvariable
self._image.add_configure_callback(self._update_image) self._font: Union[tuple, CTkFont] = CTkFont() if font is None else self._check_font_type(font)
# font
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
if isinstance(self._font, CTkFont): if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font) self._font.add_size_configure_callback(self._update_font)
# callback and hover functionality # image
self._command = command self._image = self._check_image_type(image)
self._textvariable = textvariable self._image_label: Union[tkinter.Label, None] = None
self._state = state if isinstance(self._image, CTkImage):
self._hover = hover 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 self._click_animation_running: bool = False
# canvas # canvas and draw engine
self._canvas = CTkCanvas(master=self, self._canvas = CTkCanvas(master=self,
highlightthickness=0, highlightthickness=0,
width=self._apply_widget_scaling(self._desired_width), width=self._apply_widget_scaling(self._desired_width),
@ -116,6 +118,9 @@ class CTkButton(CTkBaseClass):
if self._text_label is not None: if self._text_label is not None:
self._text_label.configure(font=self._apply_font_scaling(self._font)) 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), self._canvas.configure(width=self._apply_widget_scaling(self._desired_width),
height=self._apply_widget_scaling(self._desired_height)) height=self._apply_widget_scaling(self._desired_height))
self._draw(no_color_updates=True) self._draw(no_color_updates=True)
@ -175,7 +180,7 @@ class CTkButton(CTkBaseClass):
fill=self._apply_appearance_mode(self._border_color)) fill=self._apply_appearance_mode(self._border_color))
# set color for inner button parts # set color for inner button parts
if self._fg_color is None: if self._fg_color == "transparent":
self._canvas.itemconfig("inner_parts", self._canvas.itemconfig("inner_parts",
outline=self._apply_appearance_mode(self._bg_color), outline=self._apply_appearance_mode(self._bg_color),
fill=self._apply_appearance_mode(self._bg_color)) fill=self._apply_appearance_mode(self._bg_color))
@ -211,7 +216,7 @@ class CTkButton(CTkBaseClass):
else: else:
self._text_label.configure(fg=self._apply_appearance_mode(self._text_color)) 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)) self._text_label.configure(bg=self._apply_appearance_mode(self._bg_color))
else: else:
self._text_label.configure(bg=self._apply_appearance_mode(self._fg_color)) 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: if self._image_label is None:
self._image_label = tkinter.Label(master=self) self._image_label = tkinter.Label(master=self)
self._update_image() # set image
self._create_grid() self._create_grid()
self._image_label.bind("<Enter>", self._on_enter) self._image_label.bind("<Enter>", self._on_enter)
@ -237,13 +243,11 @@ class CTkButton(CTkBaseClass):
if no_color_updates is False: if no_color_updates is False:
# set image_label bg color (background color of label) # 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)) self._image_label.configure(bg=self._apply_appearance_mode(self._bg_color))
else: else:
self._image_label.configure(bg=self._apply_appearance_mode(self._fg_color)) self._image_label.configure(bg=self._apply_appearance_mode(self._fg_color))
self._update_image() # set image
else: else:
# delete text_label if no text given # delete text_label if no text given
if self._image_label is not None: if self._image_label is not None:
@ -334,23 +338,23 @@ class CTkButton(CTkBaseClass):
require_redraw = True require_redraw = True
if "fg_color" in 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 require_redraw = True
if "hover_color" in kwargs: 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 require_redraw = True
if "border_color" in kwargs: 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 require_redraw = True
if "text_color" in kwargs: 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 require_redraw = True
if "text_color_disabled" in kwargs: 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 require_redraw = True
if "background_corner_colors" in kwargs: if "background_corner_colors" in kwargs:
@ -486,7 +490,7 @@ class CTkButton(CTkBaseClass):
def _on_leave(self, event=None): def _on_leave(self, event=None):
self._click_animation_running = False self._click_animation_running = False
if self._fg_color is None: if self._fg_color == "transparent":
inner_parts_color = self._bg_color inner_parts_color = self._bg_color
else: else:
inner_parts_color = self._fg_color inner_parts_color = self._fg_color

View File

@ -1,6 +1,6 @@
import tkinter import tkinter
import sys import sys
from typing import Union, Tuple, Callable from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager from .theme.theme_manager import ThemeManager
@ -16,31 +16,31 @@ class CTkCheckBox(CTkBaseClass):
""" """
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 100, width: int = 100,
height: int = 24, height: int = 24,
checkbox_width: int = 24, checkbox_width: int = 24,
checkbox_height: int = 24, checkbox_height: int = 24,
corner_radius: Union[int, str] = "default_theme", corner_radius: Optional[int] = None,
border_width: Union[int, str] = "default_theme", border_width: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str]] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
hover_color: Union[str, Tuple[str, str]] = "default_theme", hover_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str]] = "default_theme", border_color: Optional[Union[str, Tuple[str, str]]] = None,
checkmark_color: Union[str, Tuple[str, str]] = "default_theme", checkmark_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
text: str = "CTkCheckBox", text: str = "CTkCheckBox",
font: Union[tuple, CTkFont] = "default_theme", font: Optional[Union[tuple, CTkFont]] = None,
textvariable: tkinter.Variable = None, textvariable: Union[tkinter.Variable, None] = None,
state: str = tkinter.NORMAL, state: str = tkinter.NORMAL,
hover: bool = True, hover: bool = True,
command: Callable = None, command: Union[Callable[[], None], None] = None,
onvalue: Union[int, str] = 1, onvalue: Union[int, str] = 1,
offvalue: Union[int, str] = 0, offvalue: Union[int, str] = 0,
variable: tkinter.Variable = None, variable: Union[tkinter.Variable, None] = None,
**kwargs): **kwargs):
# transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass # transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass
@ -51,23 +51,23 @@ class CTkCheckBox(CTkBaseClass):
self._checkbox_height = checkbox_height self._checkbox_height = checkbox_height
# color # color
self._fg_color = ThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_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 == "default_theme" else hover_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 == "default_theme" else border_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 == "default_theme" else checkmark_color self._checkmark_color = ThemeManager.theme["color"]["checkmark"] if checkmark_color is None else self._check_color_type(checkmark_color)
# shape # shape
self._corner_radius = ThemeManager.theme["shape"]["checkbox_corner_radius"] if corner_radius == "default_theme" else corner_radius 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 == "default_theme" else border_width self._border_width = ThemeManager.theme["shape"]["checkbox_border_width"] if border_width is None else border_width
# text # text
self._text = text self._text = text
self._text_label: Union[tkinter.Label, None] = None 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 = 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 == "default_theme" else text_color_disabled self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled)
# font # 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): if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font) self._font.add_size_configure_callback(self._update_font)
@ -253,19 +253,19 @@ class CTkCheckBox(CTkBaseClass):
require_redraw = True require_redraw = True
if "fg_color" in kwargs: 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 require_redraw = True
if "hover_color" in kwargs: 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 require_redraw = True
if "text_color" in kwargs: 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 require_redraw = True
if "border_color" in kwargs: 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 require_redraw = True
if "hover" in kwargs: if "hover" in kwargs:

View File

@ -1,6 +1,6 @@
import tkinter import tkinter
import sys 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_widget_classes.dropdown_menu import DropdownMenu
from .core_rendering.ctk_canvas import CTkCanvas from .core_rendering.ctk_canvas import CTkCanvas
@ -17,52 +17,50 @@ class CTkComboBox(CTkBaseClass):
""" """
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 140, width: int = 140,
height: int = 28, height: int = 28,
corner_radius: Union[int, str] = "default_theme", corner_radius: Optional[int] = None,
border_width: Union[int, str] = "default_theme", border_width: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str]] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str]] = "default_theme", border_color: Optional[Union[str, Tuple[str, str]]] = None,
button_color: Union[str, Tuple[str, str]] = "default_theme", button_color: Optional[Union[str, Tuple[str, str]]] = None,
button_hover_color: Union[str, Tuple[str, str]] = "default_theme", button_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
dropdown_fg_color: Union[str, Tuple[str, str]] = "default_theme", dropdown_fg_color: Optional[Union[str, Tuple[str, str]]] = None,
dropdown_hover_color: Union[str, Tuple[str, str]] = "default_theme", dropdown_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
dropdown_text_color: Union[str, Tuple[str, str]] = "default_theme", dropdown_text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
font: Union[tuple, CTkFont] = "default_theme", font: Optional[Union[tuple, CTkFont]] = None,
dropdown_font: Union[tuple, CTkFont] = "default_theme", dropdown_font: Optional[Union[tuple, CTkFont]] = None,
values: List[str] = None, values: Optional[List[str]] = None,
state: str = tkinter.NORMAL, state: str = tkinter.NORMAL,
hover: bool = True, hover: bool = True,
variable: tkinter.Variable = None, variable: Union[tkinter.Variable, None] = None,
command: Callable = None, command: Union[Callable[[str], None], None] = None,
justify: str = "left", justify: str = "left",
**kwargs): **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) 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 # 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
self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width == "default_theme" else border_width self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width is None else border_width
# text and font # color
self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color is None else self._check_color_type(fg_color)
self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled == "default_theme" else text_color_disabled 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 # 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): if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font) self._font.add_size_configure_callback(self._update_font)
@ -226,19 +224,19 @@ class CTkComboBox(CTkBaseClass):
require_redraw = True require_redraw = True
if "fg_color" in kwargs: 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 require_redraw = True
if "border_color" in kwargs: 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 require_redraw = True
if "button_color" in kwargs: 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 require_redraw = True
if "button_hover_color" in kwargs: 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 require_redraw = True
if "dropdown_fg_color" in kwargs: if "dropdown_fg_color" in kwargs:
@ -251,11 +249,11 @@ class CTkComboBox(CTkBaseClass):
self._dropdown_menu.configure(text_color=kwargs.pop("dropdown_text_color")) self._dropdown_menu.configure(text_color=kwargs.pop("dropdown_text_color"))
if "text_color" in kwargs: 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 require_redraw = True
if "text_color_disabled" in kwargs: 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 require_redraw = True
if "font" in kwargs: if "font" in kwargs:

View File

@ -1,5 +1,5 @@
import tkinter import tkinter
from typing import Union, Tuple from typing import Union, Tuple, Optional
from .core_rendering.ctk_canvas import CTkCanvas from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager from .theme.theme_manager import ThemeManager
@ -24,21 +24,21 @@ class CTkEntry(CTkBaseClass):
"show", "takefocus", "validate", "validatecommand", "xscrollcommand"} "show", "takefocus", "validate", "validatecommand", "xscrollcommand"}
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 140, width: int = 140,
height: int = 28, height: int = 28,
corner_radius: int = "default_theme", corner_radius: Optional[int] = None,
border_width: int = "default_theme", border_width: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str], None] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str]] = "default_theme", border_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Optional[Union[str, Tuple[str, str]]] = None,
placeholder_text_color: Union[str, Tuple[str, str]] = "default_theme", placeholder_text_color: Optional[Union[str, Tuple[str, str]]] = None,
textvariable: tkinter.Variable = None, textvariable: Union[tkinter.Variable, None] = None,
placeholder_text: str = None, placeholder_text: Union[str, None] = None,
font: Union[tuple, CTkFont] = "default_theme", font: Optional[Union[tuple, CTkFont]] = None,
state: str = tkinter.NORMAL, state: str = tkinter.NORMAL,
**kwargs): **kwargs):
@ -50,14 +50,14 @@ class CTkEntry(CTkBaseClass):
self.grid_columnconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1)
# color # color
self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color == "default_theme" else fg_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 == "default_theme" else text_color 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 == "default_theme" else placeholder_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 == "default_theme" else border_color self._border_color = ThemeManager.theme["color"]["entry_border"] if border_color is None else self._check_color_type(border_color)
# shape # 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
self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width == "default_theme" else border_width self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width is None else border_width
# text and state # text and state
self._is_focused: bool = True self._is_focused: bool = True
@ -69,7 +69,7 @@ class CTkEntry(CTkBaseClass):
self._textvariable_callback_name: str = "" self._textvariable_callback_name: str = ""
# font # 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): if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font) self._font.add_size_configure_callback(self._update_font)
@ -158,17 +158,7 @@ class CTkEntry(CTkBaseClass):
self._apply_widget_scaling(self._border_width)) self._apply_widget_scaling(self._border_width))
if requires_recoloring or no_color_updates is False: if requires_recoloring or no_color_updates is False:
if self._apply_appearance_mode(self._fg_color) is not None: if self._apply_appearance_mode(self._fg_color) == "transparent":
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:
self._canvas.itemconfig("inner_parts", self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._bg_color), fill=self._apply_appearance_mode(self._bg_color),
outline=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), disabledforeground=self._apply_appearance_mode(self._text_color),
highlightcolor=self._apply_appearance_mode(self._bg_color), highlightcolor=self._apply_appearance_mode(self._bg_color),
insertbackground=self._apply_appearance_mode(self._text_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", self._canvas.itemconfig("border_parts",
fill=self._apply_appearance_mode(self._border_color), fill=self._apply_appearance_mode(self._border_color),
@ -192,15 +192,19 @@ class CTkEntry(CTkBaseClass):
self._entry.configure(state=self._state) self._entry.configure(state=self._state)
if "fg_color" in kwargs: 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 require_redraw = True
if "text_color" in kwargs: 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 require_redraw = True
if "border_color" in kwargs: 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 require_redraw = True
if "border_width" in kwargs: if "border_width" in kwargs:
@ -221,10 +225,6 @@ class CTkEntry(CTkBaseClass):
else: else:
self._activate_placeholder() 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: if "textvariable" in kwargs:
self._textvariable = kwargs.pop("textvariable") self._textvariable = kwargs.pop("textvariable")
self._entry.configure(textvariable=self._textvariable) self._entry.configure(textvariable=self._textvariable)

View File

@ -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 .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager from .theme.theme_manager import ThemeManager
@ -15,28 +15,28 @@ class CTkFrame(CTkBaseClass):
""" """
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 200, width: int = 200,
height: int = 200, height: int = 200,
corner_radius: Union[int, str] = "default_theme", corner_radius: Optional[Union[int, str]] = None,
border_width: Union[int, str] = "default_theme", border_width: Optional[Union[int, str]] = None,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str], None] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str]] = "default_theme", border_color: 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,
overwrite_preferred_drawing_method: str = None, overwrite_preferred_drawing_method: Union[str, None] = None,
**kwargs): **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) super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color # 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 # determine fg_color of frame
if fg_color == "default_theme": if fg_color is None:
if isinstance(self.master, CTkFrame): if isinstance(self.master, CTkFrame):
if self.master._fg_color == ThemeManager.theme["color"]["frame_low"]: if self.master._fg_color == ThemeManager.theme["color"]["frame_low"]:
self._fg_color = ThemeManager.theme["color"]["frame_high"] self._fg_color = ThemeManager.theme["color"]["frame_high"]
@ -45,13 +45,13 @@ class CTkFrame(CTkBaseClass):
else: else:
self._fg_color = ThemeManager.theme["color"]["frame_low"] self._fg_color = ThemeManager.theme["color"]["frame_low"]
else: 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 self._background_corner_colors = background_corner_colors # rendering options for DrawEngine
# shape # shape
self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius 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 == "default_theme" else border_width self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width is None else border_width
self._canvas = CTkCanvas(master=self, self._canvas = CTkCanvas(master=self,
highlightthickness=0, highlightthickness=0,
@ -80,7 +80,8 @@ class CTkFrame(CTkBaseClass):
def _set_scaling(self, *args, **kwargs): def _set_scaling(self, *args, **kwargs):
super()._set_scaling(*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() self._draw()
def _set_dimensions(self, width=None, height=None): def _set_dimensions(self, width=None, height=None):
@ -113,7 +114,7 @@ class CTkFrame(CTkBaseClass):
overwrite_preferred_drawing_method=self._overwrite_preferred_drawing_method) overwrite_preferred_drawing_method=self._overwrite_preferred_drawing_method)
if no_color_updates is False or requires_recoloring: 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", self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._bg_color), fill=self._apply_appearance_mode(self._bg_color),
outline=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): def configure(self, require_redraw=False, **kwargs):
if "fg_color" in 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 require_redraw = True
# check if CTk widgets are children of the frame and change their bg_color to new frame fg_color # 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) child.configure(bg_color=self._fg_color)
if "bg_color" in kwargs: if "bg_color" in kwargs:
# pass bg_color change to children if fg_color is None # pass bg_color change to children if fg_color is "transparent"
if self._fg_color is None: if self._fg_color == "transparent":
for child in self.winfo_children(): for child in self.winfo_children():
if isinstance(child, CTkBaseClass): if isinstance(child, CTkBaseClass):
child.configure(bg_color=self._fg_color) child.configure(bg_color=self._fg_color)
if "border_color" in kwargs: 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 require_redraw = True
if "background_corner_colors" in kwargs: if "background_corner_colors" in kwargs:

View File

@ -1,5 +1,5 @@
import tkinter import tkinter
from typing import Union, Tuple, Callable from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager from .theme.theme_manager import ThemeManager
@ -22,18 +22,18 @@ class CTkLabel(CTkBaseClass):
"textvariable", "state", "takefocus", "underline", "wraplength"} "textvariable", "state", "takefocus", "underline", "wraplength"}
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 0, width: int = 0,
height: int = 28, height: int = 28,
corner_radius: Union[int, str] = "default_theme", corner_radius: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str], None] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Optional[Union[str, Tuple[str, str]]] = None,
text: str = "CTkLabel", text: str = "CTkLabel",
font: Union[tuple, CTkFont] = "default_theme", font: Optional[Union[tuple, CTkFont]] = None,
image: Union[tkinter.PhotoImage, CTkImage] = None, image: Union[tkinter.PhotoImage, CTkImage, None] = None,
compound: str = "center", compound: str = "center",
anchor: str = "center", # label anchor: center, n, e, s, w anchor: str = "center", # label anchor: center, n, e, s, w
**kwargs): **kwargs):
@ -42,11 +42,11 @@ class CTkLabel(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height) super().__init__(master=master, bg_color=bg_color, width=width, height=height)
# color # color
self._fg_color = ThemeManager.theme["color"]["label"] if fg_color == "default_theme" else fg_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 == "default_theme" else text_color self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color)
# shape # 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 # text
self._anchor = anchor self._anchor = anchor
@ -59,7 +59,7 @@ class CTkLabel(CTkBaseClass):
self._image.add_configure_callback(self._update_image) self._image.add_configure_callback(self._update_image)
# font # 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): if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font) self._font.add_size_configure_callback(self._update_font)
@ -145,20 +145,20 @@ class CTkLabel(CTkBaseClass):
0) 0)
if no_color_updates is False or requires_recoloring: if no_color_updates is False or requires_recoloring:
if self._apply_appearance_mode(self._fg_color) is not None: if self._apply_appearance_mode(self._fg_color) == "transparent":
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:
self._canvas.itemconfig("inner_parts", self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._bg_color), fill=self._apply_appearance_mode(self._bg_color),
outline=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), self._label.configure(fg=self._apply_appearance_mode(self._text_color),
bg=self._apply_appearance_mode(self._bg_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)) self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color))
@ -172,11 +172,11 @@ class CTkLabel(CTkBaseClass):
require_redraw = True require_redraw = True
if "fg_color" in 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 require_redraw = True
if "text_color" in kwargs: 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 require_redraw = True
if "text" in kwargs: if "text" in kwargs:

View File

@ -1,6 +1,6 @@
import tkinter import tkinter
import sys import sys
from typing import Union, Tuple, Callable from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager from .theme.theme_manager import ThemeManager
@ -17,28 +17,28 @@ class CTkOptionMenu(CTkBaseClass):
""" """
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 140, width: int = 140,
height: int = 28, 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, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str]] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
button_color: Union[str, Tuple[str, str]] = "default_theme", button_color: Optional[Union[str, Tuple[str, str]]] = None,
button_hover_color: Union[str, Tuple[str, str]] = "default_theme", button_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
dropdown_fg_color: Union[str, Tuple[str, str]] = "default_theme", dropdown_fg_color: Optional[Union[str, Tuple[str, str]]] = None,
dropdown_hover_color: Union[str, Tuple[str, str]] = "default_theme", dropdown_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
dropdown_text_color: Union[str, Tuple[str, str]] = "default_theme", dropdown_text_color: Optional[Union[str, Tuple[str, str]]] = None,
font: Union[tuple, CTkFont] = "default_theme", font: Optional[Union[tuple, CTkFont]] = None,
dropdown_font: Union[tuple, CTkFont] = "default_theme", dropdown_font: Optional[Union[tuple, CTkFont]] = None,
values: list = None, values: Optional[list] = None,
variable: tkinter.Variable = None, variable: Union[tkinter.Variable, None] = None,
state: str = tkinter.NORMAL, state: str = tkinter.NORMAL,
hover: bool = True, hover: bool = True,
command: Callable[[str], None] = None, command: Union[Callable[[str], None], None] = None,
dynamic_resizing: bool = True, dynamic_resizing: bool = True,
anchor: str = "w", anchor: str = "w",
**kwargs): **kwargs):
@ -47,19 +47,19 @@ class CTkOptionMenu(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color variables # color variables
self._fg_color = ThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_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 == "default_theme" else button_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 == "default_theme" else button_hover_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 # 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 # text and font
self._text_color = ThemeManager.theme["color"]["text_button"] if text_color == "default_theme" else text_color 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 == "default_theme" else text_color_disabled 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 # 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): if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font) self._font.add_size_configure_callback(self._update_font)
@ -194,7 +194,6 @@ class CTkOptionMenu(CTkBaseClass):
self._apply_widget_scaling(self._current_height / 3)) self._apply_widget_scaling(self._current_height / 3))
if no_color_updates is False or requires_recoloring or requires_recoloring_2: 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.configure(bg=self._apply_appearance_mode(self._bg_color))
self._canvas.itemconfig("inner_parts_left", self._canvas.itemconfig("inner_parts_left",
@ -226,19 +225,19 @@ class CTkOptionMenu(CTkBaseClass):
require_redraw = True require_redraw = True
if "fg_color" in kwargs: 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 require_redraw = True
if "button_color" in kwargs: 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 require_redraw = True
if "button_hover_color" in kwargs: 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 require_redraw = True
if "text_color" in kwargs: 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 require_redraw = True
if "dropdown_color" in kwargs: if "dropdown_color" in kwargs:

View File

@ -1,6 +1,6 @@
import tkinter import tkinter
import math import math
from typing import Union, Tuple from typing import Union, Tuple, Optional
from .core_rendering.ctk_canvas import CTkCanvas from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager from .theme.theme_manager import ThemeManager
@ -16,18 +16,18 @@ class CTkProgressBar(CTkBaseClass):
""" """
def __init__(self, def __init__(self,
master: any = None, master: any,
width: Union[int, str] = "default_init", width: Optional[int] = None,
height: Union[int, str] = "default_init", height: Optional[int] = None,
corner_radius: Union[str, Tuple[str, str]] = "default_theme", corner_radius: Optional[int] = None,
border_width: Union[int, str] = "default_theme", border_width: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str]] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str]] = "default_theme", border_color: Optional[Union[str, Tuple[str, str]]] = None,
progress_color: Union[str, Tuple[str, str]] = "default_theme", progress_color: Optional[Union[str, Tuple[str, str]]] = None,
variable: tkinter.Variable = None, variable: Union[tkinter.Variable, None] = None,
orientation: str = "horizontal", orientation: str = "horizontal",
mode: str = "determinate", mode: str = "determinate",
determinate_speed: float = 1, determinate_speed: float = 1,
@ -35,12 +35,12 @@ class CTkProgressBar(CTkBaseClass):
**kwargs): **kwargs):
# set default dimensions according to orientation # set default dimensions according to orientation
if width == "default_init": if width is None:
if orientation.lower() == "vertical": if orientation.lower() == "vertical":
width = 8 width = 8
else: else:
width = 200 width = 200
if height == "default_init": if height is None:
if orientation.lower() == "vertical": if orientation.lower() == "vertical":
height = 200 height = 200
else: else:
@ -50,9 +50,9 @@ class CTkProgressBar(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color # color
self._border_color = ThemeManager.theme["color"]["progressbar_border"] if border_color == "default_theme" else border_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 == "default_theme" else fg_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 == "default_theme" else progress_color self._progress_color = ThemeManager.theme["color"]["progressbar_progress"] if progress_color is None else self._check_color_type(progress_color)
# control variable # control variable
self._variable = variable self._variable = variable
@ -60,8 +60,8 @@ class CTkProgressBar(CTkBaseClass):
self._variable_callback_name = None self._variable_callback_name = None
# shape # shape
self._corner_radius = ThemeManager.theme["shape"]["progressbar_corner_radius"] if corner_radius == "default_theme" else corner_radius 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 == "default_theme" else border_width 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_value: float = 0.5 # range 0-1
self._determinate_speed = determinate_speed # range 0-1 self._determinate_speed = determinate_speed # range 0-1
self._indeterminate_value: float = 0 # range 0-inf self._indeterminate_value: float = 0 # range 0-inf
@ -162,15 +162,15 @@ class CTkProgressBar(CTkBaseClass):
require_redraw = True require_redraw = True
if "fg_color" in kwargs: 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 require_redraw = True
if "border_color" in kwargs: 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 require_redraw = True
if "progress_color" in kwargs: 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 require_redraw = True
if "variable" in kwargs: if "variable" in kwargs:

View File

@ -1,6 +1,6 @@
import tkinter import tkinter
import sys import sys
from typing import Union, Tuple, Callable from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager from .theme.theme_manager import ThemeManager
@ -16,30 +16,30 @@ class CTkRadioButton(CTkBaseClass):
""" """
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 100, width: int = 100,
height: int = 22, height: int = 22,
radiobutton_width: int = 22, radiobutton_width: int = 22,
radiobutton_height: int = 22, radiobutton_height: int = 22,
corner_radius: Union[int, str] = "default_theme", corner_radius: Optional[int] = None,
border_width_unchecked: Union[int, str] = "default_theme", border_width_unchecked: Optional[int] = None,
border_width_checked: Union[int, str] = "default_theme", border_width_checked: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str]] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
hover_color: Union[str, Tuple[str, str]] = "default_theme", hover_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str]] = "default_theme", border_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
text: str = "CTkRadioButton", text: str = "CTkRadioButton",
font: Union[tuple, CTkFont] = "default_theme", font: Optional[Union[tuple, CTkFont]] = None,
textvariable: tkinter.Variable = None, textvariable: Union[tkinter.Variable, None] = None,
variable: tkinter.Variable = None, variable: Union[tkinter.Variable, None] = None,
value: Union[int, str] = 0, value: Union[int, str] = 0,
state: str = tkinter.NORMAL, state: str = tkinter.NORMAL,
hover: bool = True, hover: bool = True,
command: Callable = None, command: Union[Callable, None] = None,
**kwargs): **kwargs):
# transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass # transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass
@ -50,23 +50,23 @@ class CTkRadioButton(CTkBaseClass):
self._radiobutton_height = radiobutton_height self._radiobutton_height = radiobutton_height
# color # color
self._fg_color = ThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_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 == "default_theme" else hover_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 == "default_theme" else border_color self._border_color = ThemeManager.theme["color"]["checkbox_border"] if border_color is None else self._check_color_type(border_color)
# shape # shape
self._corner_radius = ThemeManager.theme["shape"]["radiobutton_corner_radius"] if corner_radius == "default_theme" else corner_radius 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 == "default_theme" else border_width_unchecked 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 == "default_theme" else border_width_checked self._border_width_checked = ThemeManager.theme["shape"]["radiobutton_border_width_checked"] if border_width_checked is None else border_width_checked
# text # text
self._text = text self._text = text
self._text_label: Union[tkinter.Label, None] = None 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 = 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 == "default_theme" else text_color_disabled self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled)
# font # 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): if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font) self._font.add_size_configure_callback(self._update_font)
@ -241,19 +241,23 @@ class CTkRadioButton(CTkBaseClass):
require_redraw = True require_redraw = True
if "fg_color" in kwargs: 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 require_redraw = True
if "hover_color" in kwargs: 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 require_redraw = True
if "text_color" in kwargs: 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 require_redraw = True
if "border_color" in kwargs: 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 require_redraw = True
if "hover" in kwargs: if "hover" in kwargs:

View File

@ -1,5 +1,5 @@
import sys import sys
from typing import Union, Tuple, Callable from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager from .theme.theme_manager import ThemeManager
@ -15,30 +15,30 @@ class CTkScrollbar(CTkBaseClass):
""" """
def __init__(self, def __init__(self,
master: any = None, master: any,
width: Union[int, str] = "default_init", width: Optional[Union[int, str]] = None,
height: Union[int, str] = "default_init", height: Optional[Union[int, str]] = None,
corner_radius: Union[int, str] = "default_theme", corner_radius: Optional[int] = None,
border_spacing: Union[int, str] = "default_theme", border_spacing: Optional[int] = None,
minimum_pixel_length: int = 20, minimum_pixel_length: int = 20,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str], None] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
scrollbar_color: Union[str, Tuple[str, str]] = "default_theme", scrollbar_color: Optional[Union[str, Tuple[str, str]]] = None,
scrollbar_hover_color: Union[str, Tuple[str, str]] = "default_theme", scrollbar_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
hover: bool = True, hover: bool = True,
command: Callable = None, command: Union[Callable, None] = None,
orientation: str = "vertical", orientation: str = "vertical",
**kwargs): **kwargs):
# set default dimensions according to orientation # set default dimensions according to orientation
if width == "default_init": if width is None:
if orientation.lower() == "vertical": if orientation.lower() == "vertical":
width = 16 width = 16
else: else:
width = 200 width = 200
if height == "default_init": if height is None:
if orientation.lower() == "horizontal": if orientation.lower() == "horizontal":
height = 16 height = 16
else: else:
@ -48,13 +48,13 @@ class CTkScrollbar(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color # color
self._fg_color = ThemeManager.theme["color"]["frame_high"] if fg_color == "default_theme" else fg_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 == "default_theme" else scrollbar_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 == "default_theme" else scrollbar_hover_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 # shape
self._corner_radius = ThemeManager.theme["shape"]["scrollbar_corner_radius"] if corner_radius == "default_theme" else corner_radius 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 == "default_theme" else border_spacing self._border_spacing = ThemeManager.theme["shape"]["scrollbar_border_spacing"] if border_spacing is None else border_spacing
self._hover = hover self._hover = hover
self._hover_state: bool = False self._hover_state: bool = False
@ -139,7 +139,7 @@ class CTkScrollbar(CTkBaseClass):
fill=self._apply_appearance_mode(self._scrollbar_color), fill=self._apply_appearance_mode(self._scrollbar_color),
outline=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.configure(bg=self._apply_appearance_mode(self._bg_color))
self._canvas.itemconfig("border_parts", self._canvas.itemconfig("border_parts",
fill=self._apply_appearance_mode(self._bg_color), fill=self._apply_appearance_mode(self._bg_color),
@ -154,15 +154,15 @@ class CTkScrollbar(CTkBaseClass):
def configure(self, require_redraw=False, **kwargs): def configure(self, require_redraw=False, **kwargs):
if "fg_color" in 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 require_redraw = True
if "scrollbar_color" in kwargs: 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 require_redraw = True
if "scrollbar_hover_color" in kwargs: 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 require_redraw = True
if "hover" in kwargs: if "hover" in kwargs:

View File

@ -1,5 +1,5 @@
import tkinter 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 .theme.theme_manager import ThemeManager
from .ctk_button import CTkButton from .ctk_button import CTkButton
@ -14,50 +14,50 @@ class CTkSegmentedButton(CTkFrame):
""" """
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 140, width: int = 140,
height: int = 28, height: int = 28,
corner_radius: Union[int, str] = "default_theme", corner_radius: Optional[int] = None,
border_width: Union[int, str] = 3, border_width: int = 3,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str], None] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
selected_color: Union[str, Tuple[str, str]] = "default_theme", selected_color: Optional[Union[str, Tuple[str, str]]] = None,
selected_hover_color: Union[str, Tuple[str, str]] = "default_theme", selected_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
unselected_color: Union[str, Tuple[str, str]] = "default_theme", unselected_color: Optional[Union[str, Tuple[str, str]]] = None,
unselected_hover_color: Union[str, Tuple[str, str]] = "default_theme", unselected_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", 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,
font: Union[tuple, CTkFont] = "default_theme", font: Optional[Union[tuple, CTkFont]] = None,
values: list = None, values: Optional[list] = None,
variable: tkinter.Variable = None, variable: Union[tkinter.Variable, None] = None,
dynamic_resizing: bool = True, dynamic_resizing: bool = True,
command: Callable[[str], None] = None, command: Union[Callable[[str], None], None] = None,
state: str = "normal", state: str = "normal",
**kwargs): **kwargs):
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **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_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 == "default_theme" else selected_hover_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_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 == "default_theme" else unselected_hover_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 = 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 == "default_theme" else text_color_disabled 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_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 == "default_theme" else border_width 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._background_corner_colors = background_corner_colors # rendering options for DrawEngine
self._command: Callable[[str], None] = command 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._state = state
self._buttons_dict: Dict[str, CTkButton] = {} # mapped from value to button object 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._variable_callback_name = self._variable.trace_add("write", self._variable_callback)
self.set(self._variable.get(), from_variable_callback=True) 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): def destroy(self):
if self._variable is not None: # remove old callback 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: def _create_button(self, index: int, value: str) -> CTkButton:
new_button = CTkButton(self, new_button = CTkButton(self,
height=self._current_height,
width=0, width=0,
height=self._current_height,
corner_radius=self._sb_corner_radius, corner_radius=self._sb_corner_radius,
text=value,
border_width=self._sb_border_width, border_width=self._sb_border_width,
border_color=self._sb_fg_color,
fg_color=self._sb_unselected_color, fg_color=self._sb_unselected_color,
border_color=self._sb_fg_color,
hover_color=self._sb_unselected_hover_color, hover_color=self._sb_unselected_hover_color,
text_color=self._sb_text_color, text_color=self._sb_text_color,
text_color_disabled=self._sb_text_color_disabled, text_color_disabled=self._sb_text_color_disabled,
text=value,
font=self._font, font=self._font,
state=self._state, state=self._state,
command=lambda v=value: self.set(v, from_button_callback=True), command=lambda v=value: self.set(v, from_button_callback=True),
background_corner_colors=None, 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 return new_button
@ -201,40 +202,40 @@ class CTkSegmentedButton(CTkFrame):
self._configure_button_corners_for_index(max_index) self._configure_button_corners_for_index(max_index)
if "fg_color" in kwargs: 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()): for index, button in enumerate(self._buttons_dict.values()):
button.configure(border_color=self._sb_fg_color) button.configure(border_color=self._sb_fg_color)
self._configure_button_corners_for_index(index) self._configure_button_corners_for_index(index)
if "selected_color" in kwargs: 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: if self._current_value in self._buttons_dict:
self._buttons_dict[self._current_value].configure(fg_color=self._sb_selected_color) self._buttons_dict[self._current_value].configure(fg_color=self._sb_selected_color)
if "selected_hover_color" in kwargs: 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: if self._current_value in self._buttons_dict:
self._buttons_dict[self._current_value].configure(hover_color=self._sb_selected_hover_color) self._buttons_dict[self._current_value].configure(hover_color=self._sb_selected_hover_color)
if "unselected_color" in kwargs: 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(): for value, button in self._buttons_dict.items():
if value != self._current_value: if value != self._current_value:
button.configure(fg_color=self._sb_unselected_color) button.configure(fg_color=self._sb_unselected_color)
if "unselected_hover_color" in kwargs: 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(): for value, button in self._buttons_dict.items():
if value != self._current_value: if value != self._current_value:
button.configure(hover_color=self._sb_unselected_hover_color) button.configure(hover_color=self._sb_unselected_hover_color)
if "text_color" in kwargs: 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(): for button in self._buttons_dict.values():
button.configure(text_color=self._sb_text_color) button.configure(text_color=self._sb_text_color)
if "text_color_disabled" in kwargs: 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(): for button in self._buttons_dict.values():
button.configure(text_color_disabled=self._sb_text_color_disabled) button.configure(text_color_disabled=self._sb_text_color_disabled)

View File

@ -1,6 +1,6 @@
import tkinter import tkinter
import sys import sys
from typing import Union, Tuple, Callable from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager from .theme.theme_manager import ThemeManager
@ -15,38 +15,38 @@ class CTkSlider(CTkBaseClass):
""" """
def __init__(self, def __init__(self,
master: any = None, master: any,
width: Union[int, str] = "default_init", width: Optional[int] = None,
height: Union[int, str] = "default_init", height: Optional[int] = None,
corner_radius: Union[int, str] = "default_theme", corner_radius: Optional[int] = None,
button_corner_radius: Union[int, str] = "default_theme", button_corner_radius: Optional[int] = None,
border_width: Union[int, str] = "default_theme", border_width: Optional[int] = None,
button_length: Union[int, str] = "default_theme", button_length: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str]] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str], None] = None, border_color: Union[str, Tuple[str, str]] = "transparent",
progress_color: Union[str, Tuple[str, str], None] = "default_theme", progress_color: Optional[Union[str, Tuple[str, str]]] = None,
button_color: Union[str, Tuple[str, str]] = "default_theme", button_color: Optional[Union[str, Tuple[str, str]]] = None,
button_hover_color: Union[str, Tuple[str, str]] = "default_theme", button_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
from_: int = 0, from_: int = 0,
to: int = 1, to: int = 1,
state: str = "normal", state: str = "normal",
number_of_steps: Union[int, None] = None, number_of_steps: Union[int, None] = None,
hover: bool = True, hover: bool = True,
command: Callable[[float], None] = None, command: Union[Callable[[float], None], None] = None,
variable: tkinter.Variable = None, variable: Union[tkinter.Variable, None] = None,
orientation: str = "horizontal", orientation: str = "horizontal",
**kwargs): **kwargs):
# set default dimensions according to orientation # set default dimensions according to orientation
if width == "default_init": if width is None:
if orientation.lower() == "vertical": if orientation.lower() == "vertical":
width = 16 width = 16
else: else:
width = 200 width = 200
if height == "default_init": if height is None:
if orientation.lower() == "vertical": if orientation.lower() == "vertical":
height = 200 height = 200
else: else:
@ -56,17 +56,17 @@ class CTkSlider(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color # color
self._border_color = border_color self._border_color = self._check_color_type(border_color, transparency=True)
self._fg_color = ThemeManager.theme["color"]["slider"] if fg_color == "default_theme" else fg_color 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 == "default_theme" else progress_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 == "default_theme" else button_color 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 == "default_theme" else button_hover_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 # shape
self._corner_radius = ThemeManager.theme["shape"]["slider_corner_radius"] if corner_radius == "default_theme" else corner_radius 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 == "default_theme" else button_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 == "default_theme" else border_width 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 == "default_theme" else button_length 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._value: float = 0.5 # initial value of slider in percent
self._orientation = orientation self._orientation = orientation
self._hover_state: bool = False self._hover_state: bool = False
@ -165,7 +165,7 @@ class CTkSlider(CTkBaseClass):
if no_color_updates is False or requires_recoloring: if no_color_updates is False or requires_recoloring:
self._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), self._canvas.itemconfig("border_parts", fill=self._apply_appearance_mode(self._bg_color),
outline=self._apply_appearance_mode(self._bg_color)) outline=self._apply_appearance_mode(self._bg_color))
else: else:
@ -175,7 +175,7 @@ class CTkSlider(CTkBaseClass):
self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._fg_color), self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._fg_color),
outline=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), self._canvas.itemconfig("progress_parts", fill=self._apply_appearance_mode(self._fg_color),
outline=self._apply_appearance_mode(self._fg_color)) outline=self._apply_appearance_mode(self._fg_color))
else: else:
@ -198,23 +198,23 @@ class CTkSlider(CTkBaseClass):
require_redraw = True require_redraw = True
if "fg_color" in kwargs: 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 require_redraw = True
if "progress_color" in kwargs: 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 require_redraw = True
if "button_color" in kwargs: 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 require_redraw = True
if "button_hover_color" in kwargs: 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 require_redraw = True
if "border_color" in kwargs: 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 require_redraw = True
if "border_width" in kwargs: if "border_width" in kwargs:
@ -294,9 +294,9 @@ class CTkSlider(CTkBaseClass):
def _clicked(self, event=None): def _clicked(self, event=None):
if self._state == "normal": if self._state == "normal":
if self._orientation.lower() == "horizontal": 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: 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: if self._value > 1:
self._value = 1 self._value = 1

View File

@ -1,6 +1,6 @@
import tkinter import tkinter
import sys import sys
from typing import Union, Tuple, Callable from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager from .theme.theme_manager import ThemeManager
@ -16,32 +16,32 @@ class CTkSwitch(CTkBaseClass):
""" """
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 100, width: int = 100,
height: int = 24, height: int = 24,
switch_width: int = 36, switch_width: int = 36,
switch_height: int = 18, switch_height: int = 18,
corner_radius: Union[int, str] = "default_theme", corner_radius: Optional[int] = None,
border_width: Union[int, str] = "default_theme", border_width: Optional[int] = None,
button_length: Union[int, str] = "default_theme", button_length: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str]] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str], None] = None, border_color: Union[str, Tuple[str, str]] = "transparent",
progress_color: Union[str, Tuple[str, str]] = "default_theme", progress_color: Optional[Union[str, Tuple[str, str]]] = None,
button_color: Union[str, Tuple[str, str]] = "default_theme", button_color: Optional[Union[str, Tuple[str, str]]] = None,
button_hover_color: Union[str, Tuple[str, str]] = "default_theme", button_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
text: str = "CTkSwitch", text: str = "CTkSwitch",
font: Union[tuple, CTkFont] = "default_theme", font: Optional[Union[tuple, CTkFont]] = None,
textvariable: tkinter.Variable = None, textvariable: Union[tkinter.Variable, None] = None,
onvalue: Union[int, str] = 1, onvalue: Union[int, str] = 1,
offvalue: Union[int, str] = 0, offvalue: Union[int, str] = 0,
variable: tkinter.Variable = None, variable: Union[tkinter.Variable, None] = None,
hover: bool = True, hover: bool = True,
command: Callable = None, command: Union[Callable, None] = None,
state: str = tkinter.NORMAL, state: str = tkinter.NORMAL,
**kwargs): **kwargs):
@ -53,28 +53,27 @@ class CTkSwitch(CTkBaseClass):
self._switch_height = switch_height self._switch_height = switch_height
# color # color
self._border_color = border_color self._border_color = self._check_color_type(border_color, transparency=True)
self._fg_color = ThemeManager.theme["color"]["switch"] if fg_color == "default_theme" else fg_color 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 == "default_theme" else progress_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 == "default_theme" else button_color 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 == "default_theme" else button_hover_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 == "default_theme" else text_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 == "default_theme" else text_color_disabled self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled)
# text # text
self._text = text self._text = text
self._text_label = None self._text_label = None
# font # 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): if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font) self._font.add_size_configure_callback(self._update_font)
# shape # shape
self._corner_radius = ThemeManager.theme["shape"]["switch_corner_radius"] if corner_radius == "default_theme" else corner_radius self._corner_radius = ThemeManager.theme["shape"]["switch_corner_radius"] if corner_radius is None 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 is None else border_width
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 is None else button_length
self._button_length = ThemeManager.theme["shape"]["switch_button_length"] if button_length == "default_theme" else button_length
self._hover_state: bool = False self._hover_state: bool = False
self._check_state: bool = False # True if switch is activated self._check_state: bool = False # True if switch is activated
self._hover = hover self._hover = hover
@ -84,7 +83,7 @@ class CTkSwitch(CTkBaseClass):
# callback and control variables # callback and control variables
self._command = command self._command = command
self._variable: tkinter.Variable = variable self._variable = variable
self._variable_callback_blocked = False self._variable_callback_blocked = False
self._variable_callback_name = None self._variable_callback_name = None
self._textvariable = textvariable self._textvariable = textvariable
@ -216,7 +215,7 @@ class CTkSwitch(CTkBaseClass):
self._bg_canvas.configure(bg=self._apply_appearance_mode(self._bg_color)) self._bg_canvas.configure(bg=self._apply_appearance_mode(self._bg_color))
self._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), self._canvas.itemconfig("border_parts", fill=self._apply_appearance_mode(self._bg_color),
outline=self._apply_appearance_mode(self._bg_color)) outline=self._apply_appearance_mode(self._bg_color))
else: else:
@ -226,7 +225,7 @@ class CTkSwitch(CTkBaseClass):
self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._fg_color), self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._fg_color),
outline=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), self._canvas.itemconfig("progress_parts", fill=self._apply_appearance_mode(self._fg_color),
outline=self._apply_appearance_mode(self._fg_color)) outline=self._apply_appearance_mode(self._fg_color))
else: else:
@ -285,27 +284,23 @@ class CTkSwitch(CTkBaseClass):
require_redraw = True require_redraw = True
if "fg_color" in kwargs: 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 require_redraw = True
if "progress_color" in kwargs: if "progress_color" in kwargs:
new_progress_color = kwargs.pop("progress_color") self._progress_color = self._check_color_type(kwargs.pop("progress_color"), transparency=True)
if new_progress_color is None:
self._progress_color = self._fg_color
else:
self._progress_color = new_progress_color
require_redraw = True require_redraw = True
if "button_color" in kwargs: 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 require_redraw = True
if "button_hover_color" in kwargs: 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 require_redraw = True
if "border_color" in kwargs: 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 require_redraw = True
if "hover" in kwargs: if "hover" in kwargs:

View File

@ -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 .theme.theme_manager import ThemeManager
from .ctk_frame import CTkFrame from .ctk_frame import CTkFrame
@ -14,32 +14,32 @@ class CTkTabview(CTkBaseClass):
For detailed information check out the documentation. For detailed information check out the documentation.
""" """
_top_spacing = 10 # px on top of the buttons _top_spacing: int = 10 # px on top of the buttons
_top_button_overhang = 8 # px _top_button_overhang: int = 8 # px
_button_height = 26 _button_height: int = 26
_segmented_button_border_width = 3 _segmented_button_border_width: int = 3
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 300, width: int = 300,
height: int = 250, height: int = 250,
corner_radius: Union[int, str] = "default_theme", corner_radius: Optional[int] = None,
border_width: Union[int, str] = "default_theme", border_width: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str], None] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str]] = "default_theme", border_color: Optional[Union[str, Tuple[str, str]]] = None,
segmented_button_fg_color: Union[str, Tuple[str, str], None] = "default_theme", segmented_button_fg_color: Optional[Union[str, Tuple[str, str]]] = None,
segmented_button_selected_color: Union[str, Tuple[str, str]] = "default_theme", segmented_button_selected_color: Optional[Union[str, Tuple[str, str]]] = None,
segmented_button_selected_hover_color: Union[str, Tuple[str, str]] = "default_theme", segmented_button_selected_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
segmented_button_unselected_color: Union[str, Tuple[str, str]] = "default_theme", segmented_button_unselected_color: Optional[Union[str, Tuple[str, str]]] = None,
segmented_button_unselected_hover_color: Union[str, Tuple[str, str]] = "default_theme", segmented_button_unselected_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
command: Callable = None, command: Union[Callable, None] = None,
state: str = "normal", state: str = "normal",
**kwargs): **kwargs):
@ -47,10 +47,10 @@ class CTkTabview(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs) super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color # 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 # determine fg_color of frame
if fg_color == "default_theme": if fg_color is None:
if isinstance(self.master, (CTkFrame, CTkTabview)): if isinstance(self.master, (CTkFrame, CTkTabview)):
if self.master.cget("fg_color") == ThemeManager.theme["color"]["frame_low"]: if self.master.cget("fg_color") == ThemeManager.theme["color"]["frame_low"]:
self._fg_color = ThemeManager.theme["color"]["frame_high"] self._fg_color = ThemeManager.theme["color"]["frame_high"]
@ -59,11 +59,11 @@ class CTkTabview(CTkBaseClass):
else: else:
self._fg_color = ThemeManager.theme["color"]["frame_low"] self._fg_color = ThemeManager.theme["color"]["frame_low"]
else: else:
self._fg_color = fg_color self._fg_color = self._check_color_type(fg_color, transparency=True)
# shape # shape
self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius 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 == "default_theme" else border_width self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width is None else border_width
self._canvas = CTkCanvas(master=self, self._canvas = CTkCanvas(master=self,
bg=self._apply_appearance_mode(self._bg_color), bg=self._apply_appearance_mode(self._bg_color),
@ -83,7 +83,7 @@ class CTkTabview(CTkBaseClass):
text_color=text_color, text_color=text_color,
text_color_disabled=text_color_disabled, text_color_disabled=text_color_disabled,
corner_radius=corner_radius, 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, command=self._segmented_button_callback,
state=state) state=state)
self._configure_segmented_button_background_corners() self._configure_segmented_button_background_corners()
@ -124,6 +124,7 @@ class CTkTabview(CTkBaseClass):
self._canvas.configure(width=self._apply_widget_scaling(self._desired_width), 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)) height=self._apply_widget_scaling(self._desired_height - self._top_spacing - self._top_button_overhang))
self._configure_grid()
self._draw(no_color_updates=True) self._draw(no_color_updates=True)
def _set_dimensions(self, width=None, height=None): def _set_dimensions(self, width=None, height=None):
@ -194,7 +195,7 @@ class CTkTabview(CTkBaseClass):
self._apply_widget_scaling(self._border_width)) self._apply_widget_scaling(self._border_width))
if no_color_updates is False or requires_recoloring: 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", self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._bg_color), fill=self._apply_appearance_mode(self._bg_color),
outline=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 require_redraw = True
if "fg_color" in 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 require_redraw = True
if "border_color" in kwargs: 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 require_redraw = True
if "segmented_button_fg_color" in kwargs: if "segmented_button_fg_color" in kwargs:
self._segmented_button.configure(fg_color=kwargs.pop("segmented_button_fg_color")) self._segmented_button.configure(fg_color=kwargs.pop("segmented_button_fg_color"))

View File

@ -1,5 +1,5 @@
import tkinter import tkinter
from typing import Union, Tuple from typing import Union, Tuple, Optional
from .core_rendering.ctk_canvas import CTkCanvas from .core_rendering.ctk_canvas import CTkCanvas
from .ctk_scrollbar import CTkScrollbar from .ctk_scrollbar import CTkScrollbar
@ -33,21 +33,21 @@ class CTkTextbox(CTkBaseClass):
"xscrollcommand", "yscrollcommand"} "xscrollcommand", "yscrollcommand"}
def __init__(self, def __init__(self,
master: any = None, master: any,
width: int = 200, width: int = 200,
height: int = 200, height: int = 200,
corner_radius: Union[int, str] = "default_theme", corner_radius: Optional[int] = None,
border_width: Union[int, str] = "default_theme", border_width: Optional[int] = None,
border_spacing: int = 3, border_spacing: int = 3,
bg_color: Union[str, Tuple[str, str], None] = None, bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Union[str, Tuple[str, str], None] = "default_theme", fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str]] = "default_theme", border_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, str] = "default_theme", text_color: Optional[Union[str, str]] = None,
scrollbar_color: Union[str, Tuple[str, str]] = "default_theme", scrollbar_color: Optional[Union[str, Tuple[str, str]]] = None,
scrollbar_hover_color: Union[str, Tuple[str, str]] = "default_theme", 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, activate_scrollbars: bool = True,
**kwargs): **kwargs):
@ -55,19 +55,19 @@ class CTkTextbox(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height) super().__init__(master=master, bg_color=bg_color, width=width, height=height)
# color # color
self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color == "default_theme" else fg_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 == "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)
self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_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 == "default_theme" else scrollbar_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 == "default_theme" else scrollbar_hover_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 # shape
self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius 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 == "default_theme" else border_width self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width is None else border_width
self._border_spacing = border_spacing self._border_spacing = border_spacing
# font # 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): if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font) self._font.add_size_configure_callback(self._update_font)
@ -221,7 +221,7 @@ class CTkTextbox(CTkBaseClass):
self._apply_widget_scaling(self._border_width)) self._apply_widget_scaling(self._border_width))
if no_color_updates is False or requires_recoloring: 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", self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._bg_color), fill=self._apply_appearance_mode(self._bg_color),
outline=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): def configure(self, require_redraw=False, **kwargs):
if "fg_color" in 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 require_redraw = True
# check if CTk widgets are children of the frame and change their _bg_color to new frame fg_color # 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) child.configure(bg_color=self._fg_color)
if "border_color" in kwargs: 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 require_redraw = True
if "text_color" in kwargs: 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 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: if "corner_radius" in kwargs:
self._corner_radius = kwargs.pop("corner_radius") 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) self._create_grid_for_text_and_scrollbars(re_grid_textbox=True, re_grid_x_scrollbar=True, re_grid_y_scrollbar=True)

View File

@ -21,8 +21,8 @@ class CTkFont(Font):
""" """
def __init__(self, def __init__(self,
family: str = "default_theme", family: str = "default",
size: int = "default_theme", size: int = "default",
weight: str = "normal", weight: str = "normal",
slant: str = "roman", slant: str = "roman",
underline: bool = False, underline: bool = False,
@ -31,10 +31,10 @@ class CTkFont(Font):
self._size_configure_callback_list: List[Callable] = [] self._size_configure_callback_list: List[Callable] = []
self._family = family 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 ''}" 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), size=-abs(self._size),
weight=weight, weight=weight,
slant=slant, slant=slant,

View File

@ -1,4 +1,3 @@
import tkinter
from typing import Union, Tuple from typing import Union, Tuple
import copy import copy
import re import re
@ -9,7 +8,6 @@ except ImportError:
from .scaling_tracker import ScalingTracker from .scaling_tracker import ScalingTracker
from ..font.ctk_font import CTkFont from ..font.ctk_font import CTkFont
from ..image.ctk_image import CTkImage
class CTkScalingBaseClass(): class CTkScalingBaseClass():

View File

@ -47,7 +47,7 @@ class App(customtkinter.CTk):
self.entry = customtkinter.CTkEntry(self, placeholder_text="CTkEntry") 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.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") self.main_button_1.grid(row=3, column=3, padx=(20, 20), pady=(20, 20), sticky="nsew")
# create textbox # 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") self.switch_2.grid(row=4, column=0, pady=(10, 20), padx=20, sticky="n")
# create slider and progressbar frame # 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(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_columnconfigure(0, weight=1)
self.slider_progressbar_frame.grid_rowconfigure(4, weight=1) self.slider_progressbar_frame.grid_rowconfigure(4, weight=1)