diff --git a/customtkinter/settings.py b/customtkinter/settings.py index cf1c681..a93f800 100644 --- a/customtkinter/settings.py +++ b/customtkinter/settings.py @@ -3,3 +3,4 @@ class Settings: cursor_manipulation_enabled = True deactivate_macos_window_header_manipulation = False deactivate_windows_window_header_manipulation = False + use_dropdown_fallback = True diff --git a/customtkinter/widgets/ctk_entry.py b/customtkinter/widgets/ctk_entry.py index 3c6c9a6..00ed619 100644 --- a/customtkinter/widgets/ctk_entry.py +++ b/customtkinter/widgets/ctk_entry.py @@ -51,7 +51,7 @@ class CTkEntry(CTkBaseClass): highlightthickness=0, width=self.apply_widget_scaling(self._current_width), height=self.apply_widget_scaling(self._current_height)) - self.canvas.grid(column=0, row=0, sticky="we") + self.canvas.grid(column=0, row=0, sticky="nswe") self.draw_engine = DrawEngine(self.canvas) self.entry = tkinter.Entry(master=self, @@ -61,8 +61,9 @@ class CTkEntry(CTkBaseClass): font=self.apply_font_scaling(self.text_font), state=self.state, **kwargs) - self.entry.grid(column=0, row=0, sticky="we", - padx=self.apply_widget_scaling(self.corner_radius) if self.corner_radius >= 6 else self.apply_widget_scaling(6)) + self.entry.grid(column=0, row=0, sticky="nswe", + padx=self.apply_widget_scaling(self.corner_radius) if self.corner_radius >= 6 else self.apply_widget_scaling(6), + pady=(self.apply_widget_scaling(self.border_width), self.apply_widget_scaling(self.border_width + 1))) super().bind('', self.update_dimensions_event) self.entry.bind('', self.set_placeholder) diff --git a/customtkinter/widgets/ctk_optionmenu.py b/customtkinter/widgets/ctk_optionmenu.py index 6b0253f..3532f29 100644 --- a/customtkinter/widgets/ctk_optionmenu.py +++ b/customtkinter/widgets/ctk_optionmenu.py @@ -3,6 +3,7 @@ import sys from typing import Union from .dropdown_menu import DropdownMenu +from .dropdown_menu_fallback import DropdownMenuFallback from .ctk_canvas import CTkCanvas from ..theme_manager import ThemeManager @@ -168,15 +169,22 @@ class CTkOptionMenu(CTkBaseClass): self.text_label.configure(bg=ThemeManager.single_color(self.fg_color, self._appearance_mode)) def open_dropdown_menu(self): - self.dropdown_menu = DropdownMenu(x_position=self.winfo_rootx(), - y_position=self.winfo_rooty() + self.apply_widget_scaling(self._current_height + 4), - width=self._current_width, - values=self.values, - command=self.set, - fg_color=self.dropdown_color, - button_hover_color=self.dropdown_hover_color, - button_color=self.dropdown_color, - text_color=self.dropdown_text_color) + if not Settings.use_dropdown_fallback: + self.dropdown_menu = DropdownMenu(x_position=self.winfo_rootx(), + y_position=self.winfo_rooty() + self.apply_widget_scaling(self._current_height + 4), + width=self._current_width, + values=self.values, + command=self.set, + fg_color=self.dropdown_color, + button_hover_color=self.dropdown_hover_color, + button_color=self.dropdown_color, + text_color=self.dropdown_text_color) + else: + self.dropdown_menu = DropdownMenuFallback(master=self, + values=self.values, + command=self.set) + self.dropdown_menu.open(x=self.winfo_rootx(), + y=self.winfo_rooty() + self.apply_widget_scaling(self._current_height + 0)) def configure(self, *args, **kwargs): require_redraw = False # some attribute changes require a call of self.draw() at the end diff --git a/customtkinter/widgets/dropdown_menu.py b/customtkinter/widgets/dropdown_menu.py index 9a1dd40..d7057de 100644 --- a/customtkinter/widgets/dropdown_menu.py +++ b/customtkinter/widgets/dropdown_menu.py @@ -1,6 +1,8 @@ import customtkinter import tkinter import sys +from distutils.version import StrictVersion as Version +import platform from typing import Union from ..theme_manager import ThemeManager @@ -55,8 +57,15 @@ class DropdownMenu(tkinter.Toplevel): self.grid_rowconfigure(0, weight=1) if sys.platform.startswith("darwin"): - self.overrideredirect(True) # remove title-bar - self.overrideredirect(False) + if Version(platform.python_version()) < Version("3.10"): + self.focus() + self.overrideredirect(True) # remove title-bar + self.overrideredirect(False) + else: + self.overrideredirect(True) + self.geometry(f"+{round(x_position)}+{round(y_position)}") + self.focus_set() + self.wm_attributes("-transparent", True) # turn off window shadow self.config(bg='systemTransparent') # transparent bg self.frame = customtkinter.CTkFrame(self, @@ -74,16 +83,17 @@ class DropdownMenu(tkinter.Toplevel): border_width=0, width=self.width, corner_radius=self.corner_radius, - fg_color=self.fg_color, overwrite_preferred_drawing_method="circle_shapes") - else: + fg_color=self.fg_color, + overwrite_preferred_drawing_method="circle_shapes") + else: # Linux self.overrideredirect(True) # remove title-bar - self.configure(bg="#010302") - self.wm_attributes("-transparentcolor", "#010302") + # self.configure(bg="#010302") + # self.wm_attributes("-transparentcolor", "#010302") self.frame = customtkinter.CTkFrame(self, border_width=0, width=self.width, - corner_radius=self.corner_radius, - fg_color=self.fg_color, overwrite_preferred_drawing_method="circle_shapes") + corner_radius=0, + fg_color=self.fg_color) self.frame.grid(row=0, column=0, sticky="nsew", rowspan=1) self.frame.grid_rowconfigure(len(self.values) + 1, minsize=self.apply_spacing_scaling(y_spacing)) # add spacing at the bottom @@ -108,7 +118,6 @@ class DropdownMenu(tkinter.Toplevel): self.button_list.append(button) self.bind("", self.focus_loss_event) - self.frame.canvas.bind("", self.focus_loss_event) def apply_widget_scaling(self, value: Union[int, float, str]) -> Union[float, str]: if isinstance(value, (int, float)): diff --git a/customtkinter/widgets/dropdown_menu_fallback.py b/customtkinter/widgets/dropdown_menu_fallback.py new file mode 100644 index 0000000..476f634 --- /dev/null +++ b/customtkinter/widgets/dropdown_menu_fallback.py @@ -0,0 +1,55 @@ +import tkinter +import sys +from distutils.version import StrictVersion as Version +import platform +from typing import Union + +from ..theme_manager import ThemeManager +from ..appearance_mode_tracker import AppearanceModeTracker +from ..scaling_tracker import ScalingTracker + + +class DropdownMenuFallback(tkinter.Menu): + def __init__(self, *args, + fg_color="#555555", + button_hover_color="gray35", + text_color="default_theme", + text_font="default_theme", + command=None, + values=None, + **kwargs): + super().__init__(*args, **kwargs) + + ScalingTracker.add_widget(self.set_scaling, self) + self._widget_scaling = ScalingTracker.get_widget_scaling(self) + self._spacing_scaling = ScalingTracker.get_spacing_scaling(self) + + self.fg_color = fg_color + self.button_hover_color = button_hover_color + self.text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color + self.text_font = (ThemeManager.theme["text"]["font"], ThemeManager.theme["text"]["size"]) if text_font == "default_theme" else text_font + + self.menu = tkinter.Menu(master=self) + + if sys.platform.startswith("win"): + self.menu.configure() + + self.values = values + self.command = command + + for value in self.values: + self.menu.add_command(label=value.ljust(16), command=lambda v=value: self.button_callback(v)) + + def open(self, x, y): + if sys.platform == "darwin": + y = y + 8 + + self.menu.post(x, y) + + def button_callback(self, value): + if self.command is not None: + self.command(value) + + def set_scaling(self, new_widget_scaling, new_spacing_scaling, new_window_scaling): + self._widget_scaling = new_widget_scaling + self._spacing_scaling = new_spacing_scaling diff --git a/setup.cfg b/setup.cfg index 3fa8688..55ddd3e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,7 +2,7 @@ name = customtkinter version = 4.3.0 description = Create modern looking GUIs with Python -long_description = '# CustomTkinter UI-Library\nhttps://github.com/TomSchimansky/CustomTkinter/blob/master/documentation_images/Windows_dark.png\n\nMore Information: https://github.com/TomSchimansky/CustomTkinter' +long_description = CustomTkinter UI-Library\n\n[](https://github.com/TomSchimansky/CustomTkinter/blob/master/documentation_images/Windows_dark.png)\n\nMore Information: https://github.com/TomSchimansky/CustomTkinter long_description_content_type = text/markdown url = https://github.com/TomSchimansky/CustomTkinter author = Tom Schimansky diff --git a/test/manual_integration_tests/test_optionmenu_combobox.py b/test/manual_integration_tests/test_optionmenu_combobox.py index 7543105..32b29e8 100644 --- a/test/manual_integration_tests/test_optionmenu_combobox.py +++ b/test/manual_integration_tests/test_optionmenu_combobox.py @@ -1,4 +1,5 @@ import tkinter +import tkinter.ttk as ttk import customtkinter app = customtkinter.CTk() @@ -16,14 +17,14 @@ countries = ['Bahamas', 'Canada', 'Cuba', 'United States'] variable = tkinter.StringVar() variable.set("test") -# optionmenu_tk = tkinter.OptionMenu(app, variable, *countries, command=select_callback) -# optionmenu_tk.pack(pady=10, padx=10) +optionmenu_tk = tkinter.OptionMenu(app, variable, *countries, command=select_callback) +optionmenu_tk.pack(pady=10, padx=10) optionmenu_1 = customtkinter.CTkOptionMenu(app, variable=variable, values=countries, command=select_callback) optionmenu_1.pack(pady=20, padx=10) -# combobox_tk = ttk.Combobox(app, values=countries) -# combobox_tk.pack(pady=10, padx=10) +combobox_tk = ttk.Combobox(app, values=countries) +combobox_tk.pack(pady=10, padx=10) combobox_1 = customtkinter.CTkComboBox(app, variable=variable, values=countries, command=select_callback) combobox_1.pack(pady=20, padx=10)