diff --git a/customtkinter/assets/themes/blue.json b/customtkinter/assets/themes/blue.json index 8ca41b9..3d7f72f 100644 --- a/customtkinter/assets/themes/blue.json +++ b/customtkinter/assets/themes/blue.json @@ -43,21 +43,21 @@ } }, "shape": { - "button_corner_radius": 8, + "button_corner_radius": 6, "button_border_width": 0, - "checkbox_corner_radius": 7, + "checkbox_corner_radius": 6, "checkbox_border_width": 3, "radiobutton_corner_radius": 1000, "radiobutton_border_width_unchecked": 3, "radiobutton_border_width_checked": 6, "entry_border_width": 2, - "frame_corner_radius": 8, + "frame_corner_radius": 6, "frame_border_width": 0, "label_corner_radius": 8, "progressbar_border_width": 0, "progressbar_corner_radius": 1000, "slider_border_width": 6, - "slider_corner_radius": 8, + "slider_corner_radius": 1000, "slider_button_length": 0, "slider_button_corner_radius": 1000, "switch_border_width": 3, diff --git a/customtkinter/draw_engine.py b/customtkinter/draw_engine.py index bcbc1ae..15c0d51 100644 --- a/customtkinter/draw_engine.py +++ b/customtkinter/draw_engine.py @@ -17,6 +17,7 @@ class DrawEngine: Functions: - draw_rounded_rect_with_border() + - draw_rounded_rect_with_border_vertical_split() - draw_rounded_progress_bar_with_border() - draw_rounded_slider_with_border_and_button() - draw_checkmark() @@ -27,9 +28,8 @@ class DrawEngine: def __init__(self, canvas: CTkCanvas): self._canvas = canvas - self._existing_tags = set() - def _calc_optimal_corner_radius(self, user_corner_radius: Union[float, int]) -> Union[float, int]: + def __calc_optimal_corner_radius(self, user_corner_radius: Union[float, int]) -> Union[float, int]: # optimize for drawing with polygon shapes if self.preferred_drawing_method == "polygon_shapes": if sys.platform == "darwin": @@ -67,7 +67,7 @@ class DrawEngine: corner_radius = min(width / 2, height / 2) border_width = round(border_width) - corner_radius = self._calc_optimal_corner_radius(corner_radius) # optimize corner_radius for different drawing methods (different rounding) + corner_radius = self.__calc_optimal_corner_radius(corner_radius) # optimize corner_radius for different drawing methods (different rounding) if corner_radius >= border_width: inner_corner_radius = corner_radius - border_width @@ -75,13 +75,13 @@ class DrawEngine: inner_corner_radius = 0 if self.preferred_drawing_method == "polygon_shapes": - return self._draw_rounded_rect_with_border_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius) + return self.__draw_rounded_rect_with_border_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius) elif self.preferred_drawing_method == "font_shapes": - return self._draw_rounded_rect_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, ()) + return self.__draw_rounded_rect_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, ()) elif self.preferred_drawing_method == "circle_shapes": - return self._draw_rounded_rect_with_border_circle_shapes(width, height, corner_radius, border_width, inner_corner_radius) + return self.__draw_rounded_rect_with_border_circle_shapes(width, height, corner_radius, border_width, inner_corner_radius) - def _draw_rounded_rect_with_border_polygon_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int) -> bool: + def __draw_rounded_rect_with_border_polygon_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int) -> bool: requires_recoloring = False # create border button parts (only if border exists) @@ -134,8 +134,8 @@ class DrawEngine: return requires_recoloring - def _draw_rounded_rect_with_border_font_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int, - exclude_parts: tuple) -> bool: + def __draw_rounded_rect_with_border_font_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int, + exclude_parts: tuple) -> bool: requires_recoloring = False # create border button parts @@ -272,7 +272,7 @@ class DrawEngine: return requires_recoloring - def _draw_rounded_rect_with_border_circle_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int) -> bool: + def __draw_rounded_rect_with_border_circle_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int) -> bool: requires_recoloring = False # border button parts @@ -346,6 +346,285 @@ class DrawEngine: return requires_recoloring + def draw_rounded_rect_with_border_vertical_split(self, width: int, height: int, corner_radius: Union[float, int], border_width: Union[float, int], + left_section_width: int) -> bool: + """ Draws a rounded rectangle with a corner_radius and border_width on the canvas which is split at left_section_width. + The border elements have the tags 'border_parts_left', 'border_parts_lright', + the main foreground elements have an 'inner_parts_left' and inner_parts_right' tag, + to color the elements accordingly. + + returns bool if recoloring is necessary """ + + width = math.floor(width / 2) * 2 # round (floor) current_width and current_height and restrict them to even values only + height = math.floor(height / 2) * 2 + corner_radius = round(corner_radius) + + if corner_radius > width / 2 or corner_radius > height / 2: # restrict corner_radius if it's too larger + corner_radius = min(width / 2, height / 2) + + border_width = round(border_width) + corner_radius = self.__calc_optimal_corner_radius(corner_radius) # optimize corner_radius for different drawing methods (different rounding) + + if corner_radius >= border_width: + inner_corner_radius = corner_radius - border_width + else: + inner_corner_radius = 0 + + if left_section_width > width - corner_radius * 2: + left_section_width = width - corner_radius * 2 + elif left_section_width < corner_radius * 2: + left_section_width = corner_radius * 2 + + if self.preferred_drawing_method == "polygon_shapes" or self.preferred_drawing_method == "circle_shapes": + return self.__draw_rounded_rect_with_border_vertical_split_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius, left_section_width) + elif self.preferred_drawing_method == "font_shapes": + return self.__draw_rounded_rect_with_border_vertical_split_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, left_section_width, ()) + + def __draw_rounded_rect_with_border_vertical_split_polygon_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int, + left_section_width: int) -> bool: + requires_recoloring = False + + # create border button parts (only if border exists) + if border_width > 0: + if not self._canvas.find_withtag("border_parts"): + self._canvas.create_polygon((0, 0, 0, 0), tags=("border_line_left_1", "border_parts_left", "border_parts")) + self._canvas.create_polygon((0, 0, 0, 0), tags=("border_line_right_1", "border_parts_right", "border_parts")) + self._canvas.create_rectangle((0, 0, 0, 0), tags=("border_rect_left_1", "border_parts_left", "border_parts")) + self._canvas.create_rectangle((0, 0, 0, 0), tags=("border_rect_right_1", "border_parts_right", "border_parts")) + requires_recoloring = True + + self._canvas.coords("border_line_left_1", + (corner_radius, + corner_radius, + left_section_width - corner_radius, + corner_radius, + left_section_width - corner_radius, + height - corner_radius, + corner_radius, + height - corner_radius)) + self._canvas.coords("border_line_right_1", + (left_section_width + corner_radius, + corner_radius, + width - corner_radius, + corner_radius, + width - corner_radius, + height - corner_radius, + left_section_width + corner_radius, + height - corner_radius)) + self._canvas.coords("border_rect_left_1", + (left_section_width - corner_radius, + 0, + left_section_width, + height)) + self._canvas.coords("border_rect_right_1", + (left_section_width, + 0, + left_section_width + corner_radius, + height)) + self._canvas.itemconfig("border_line_left_1", joinstyle=tkinter.ROUND, width=corner_radius * 2) + self._canvas.itemconfig("border_line_right_1", joinstyle=tkinter.ROUND, width=corner_radius * 2) + + else: + self._canvas.delete("border_parts") + + # create inner button parts + if not self._canvas.find_withtag("inner_parts"): + self._canvas.create_polygon((0, 0, 0, 0), tags=("inner_line_left_1", "inner_parts"), joinstyle=tkinter.ROUND) + self._canvas.create_polygon((0, 0, 0, 0), tags=("inner_line_right_1", "inner_parts"), joinstyle=tkinter.ROUND) + self._canvas.create_rectangle((0, 0, 0, 0), tags=("inner_rect_left_1", "border_parts_right", "border_parts")) + self._canvas.create_rectangle((0, 0, 0, 0), tags=("inner_rect_right_1", "border_parts_right", "border_parts")) + requires_recoloring = True + + self._canvas.coords("inner_line_left_1", + corner_radius, + corner_radius, + left_section_width - corner_radius, + corner_radius, + left_section_width - corner_radius, + height - corner_radius, + corner_radius, + height - corner_radius) + self._canvas.coords("inner_line_right_1", + left_section_width + corner_radius, + corner_radius, + width - corner_radius, + corner_radius, + width - corner_radius, + height - corner_radius, + left_section_width + corner_radius, + height - corner_radius) + self._canvas.coords("inner_rect_left_1", + (left_section_width - inner_corner_radius, + border_width, + left_section_width, + height - border_width)) + self._canvas.coords("inner_rect_right_1", + (left_section_width, + border_width, + left_section_width + inner_corner_radius, + height - border_width)) + self._canvas.itemconfig("inner_line_left_1", width=inner_corner_radius * 2) + self._canvas.itemconfig("inner_line_right_1", width=inner_corner_radius * 2) + + if requires_recoloring: # new parts were added -> manage z-order + self._canvas.tag_lower("inner_parts") + self._canvas.tag_lower("border_parts") + + return requires_recoloring + + def __draw_rounded_rect_with_border_vertical_split_font_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int, + left_section_width: int, exclude_parts: tuple) -> bool: + requires_recoloring = False + + # create border button parts + if border_width > 0: + if corner_radius > 0: + # create canvas border corner parts if not already created, but only if needed, and delete if not needed + if not self._canvas.find_withtag("border_oval_1_a") and "border_oval_1" not in exclude_parts: + self._canvas.create_aa_circle(0, 0, 0, tags=("border_oval_1_a", "border_corner_part", "border_parts_left" "border_parts"), anchor=tkinter.CENTER) + self._canvas.create_aa_circle(0, 0, 0, tags=("border_oval_1_b", "border_corner_part", "border_parts_left", "border_parts"), anchor=tkinter.CENTER, angle=180) + requires_recoloring = True + elif self._canvas.find_withtag("border_oval_1_a") and "border_oval_1" in exclude_parts: + self._canvas.delete("border_oval_1_a", "border_oval_1_b") + + if not self._canvas.find_withtag("border_oval_2_a") and width > 2 * corner_radius and "border_oval_2" not in exclude_parts: + self._canvas.create_aa_circle(0, 0, 0, tags=("border_oval_2_a", "border_corner_part", "border_parts_right", "border_parts"), anchor=tkinter.CENTER) + self._canvas.create_aa_circle(0, 0, 0, tags=("border_oval_2_b", "border_corner_part", "border_parts_right", "border_parts"), anchor=tkinter.CENTER, angle=180) + requires_recoloring = True + elif self._canvas.find_withtag("border_oval_2_a") and (not width > 2 * corner_radius or "border_oval_2" in exclude_parts): + self._canvas.delete("border_oval_2_a", "border_oval_2_b") + + if not self._canvas.find_withtag("border_oval_3_a") and height > 2 * corner_radius \ + and width > 2 * corner_radius and "border_oval_3" not in exclude_parts: + self._canvas.create_aa_circle(0, 0, 0, tags=("border_oval_3_a", "border_corner_part", "border_parts_right", "border_parts"), anchor=tkinter.CENTER) + self._canvas.create_aa_circle(0, 0, 0, tags=("border_oval_3_b", "border_corner_part", "border_parts_right", "border_parts"), anchor=tkinter.CENTER, angle=180) + requires_recoloring = True + elif self._canvas.find_withtag("border_oval_3_a") and (not (height > 2 * corner_radius + and width > 2 * corner_radius) or "border_oval_3" in exclude_parts): + self._canvas.delete("border_oval_3_a", "border_oval_3_b") + + if not self._canvas.find_withtag("border_oval_4_a") and height > 2 * corner_radius and "border_oval_4" not in exclude_parts: + self._canvas.create_aa_circle(0, 0, 0, tags=("border_oval_4_a", "border_corner_part", "border_parts_left", "border_parts"), anchor=tkinter.CENTER) + self._canvas.create_aa_circle(0, 0, 0, tags=("border_oval_4_b", "border_corner_part", "border_parts_left", "border_parts"), anchor=tkinter.CENTER, angle=180) + requires_recoloring = True + elif self._canvas.find_withtag("border_oval_4_a") and (not height > 2 * corner_radius or "border_oval_4" in exclude_parts): + self._canvas.delete("border_oval_4_a", "border_oval_4_b") + + # change position of border corner parts + self._canvas.coords("border_oval_1_a", corner_radius, corner_radius, corner_radius) + self._canvas.coords("border_oval_1_b", corner_radius, corner_radius, corner_radius) + self._canvas.coords("border_oval_2_a", width - corner_radius, corner_radius, corner_radius) + self._canvas.coords("border_oval_2_b", width - corner_radius, corner_radius, corner_radius) + self._canvas.coords("border_oval_3_a", width - corner_radius, height - corner_radius, corner_radius) + self._canvas.coords("border_oval_3_b", width - corner_radius, height - corner_radius, corner_radius) + self._canvas.coords("border_oval_4_a", corner_radius, height - corner_radius, corner_radius) + self._canvas.coords("border_oval_4_b", corner_radius, height - corner_radius, corner_radius) + + else: + self._canvas.delete("border_corner_part") # delete border corner parts if not needed + + # create canvas border rectangle parts if not already created + if not self._canvas.find_withtag("border_rectangle_1"): + self._canvas.create_rectangle(0, 0, 0, 0, tags=("border_rectangle_left_1", "border_rectangle_part", "border_parts_left", "border_parts"), width=0) + self._canvas.create_rectangle(0, 0, 0, 0, tags=("border_rectangle_left_2", "border_rectangle_part", "border_parts_left", "border_parts"), width=0) + self._canvas.create_rectangle(0, 0, 0, 0, tags=("border_rectangle_right_1", "border_rectangle_part", "border_parts_right", "border_parts"), width=0) + self._canvas.create_rectangle(0, 0, 0, 0, tags=("border_rectangle_right_2", "border_rectangle_part", "border_parts_right", "border_parts"), width=0) + requires_recoloring = True + + # change position of border rectangle parts + self._canvas.coords("border_rectangle_left_1", (0, corner_radius, left_section_width, height - corner_radius)) + self._canvas.coords("border_rectangle_left_2", (corner_radius, 0, left_section_width, height)) + self._canvas.coords("border_rectangle_right_1", (left_section_width, corner_radius, width, height - corner_radius)) + self._canvas.coords("border_rectangle_right_2", (corner_radius, left_section_width, width - corner_radius, height)) + + else: + self._canvas.delete("border_parts") + + # create inner button parts + if inner_corner_radius > 0: + + # create canvas border corner parts if not already created, but only if they're needed and delete if not needed + if not self._canvas.find_withtag("inner_oval_1_a") and "inner_oval_1" not in exclude_parts: + self._canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_1_a", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER) + self._canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_1_b", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER, angle=180) + requires_recoloring = True + elif self._canvas.find_withtag("inner_oval_1_a") and "inner_oval_1" in exclude_parts: + self._canvas.delete("inner_oval_1_a", "inner_oval_1_b") + + if not self._canvas.find_withtag("inner_oval_2_a") and width - (2 * border_width) > 2 * inner_corner_radius and "inner_oval_2" not in exclude_parts: + self._canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_2_a", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER) + self._canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_2_b", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER, angle=180) + requires_recoloring = True + elif self._canvas.find_withtag("inner_oval_2_a") and (not width - (2 * border_width) > 2 * inner_corner_radius or "inner_oval_2" in exclude_parts): + self._canvas.delete("inner_oval_2_a", "inner_oval_2_b") + + if not self._canvas.find_withtag("inner_oval_3_a") and height - (2 * border_width) > 2 * inner_corner_radius \ + and width - (2 * border_width) > 2 * inner_corner_radius and "inner_oval_3" not in exclude_parts: + self._canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_3_a", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER) + self._canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_3_b", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER, angle=180) + requires_recoloring = True + elif self._canvas.find_withtag("inner_oval_3_a") and (not (height - (2 * border_width) > 2 * inner_corner_radius + and width - (2 * border_width) > 2 * inner_corner_radius) or "inner_oval_3" in exclude_parts): + self._canvas.delete("inner_oval_3_a", "inner_oval_3_b") + + if not self._canvas.find_withtag("inner_oval_4_a") and height - (2 * border_width) > 2 * inner_corner_radius and "inner_oval_4" not in exclude_parts: + self._canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_4_a", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER) + self._canvas.create_aa_circle(0, 0, 0, tags=("inner_oval_4_b", "inner_corner_part", "inner_parts"), anchor=tkinter.CENTER, angle=180) + requires_recoloring = True + elif self._canvas.find_withtag("inner_oval_4_a") and (not height - (2 * border_width) > 2 * inner_corner_radius or "inner_oval_4" in exclude_parts): + self._canvas.delete("inner_oval_4_a", "inner_oval_4_b") + + # change position of border corner parts + self._canvas.coords("inner_oval_1_a", border_width + inner_corner_radius, border_width + inner_corner_radius, inner_corner_radius) + self._canvas.coords("inner_oval_1_b", border_width + inner_corner_radius, border_width + inner_corner_radius, inner_corner_radius) + self._canvas.coords("inner_oval_2_a", width - border_width - inner_corner_radius, border_width + inner_corner_radius, inner_corner_radius) + self._canvas.coords("inner_oval_2_b", width - border_width - inner_corner_radius, border_width + inner_corner_radius, inner_corner_radius) + self._canvas.coords("inner_oval_3_a", width - border_width - inner_corner_radius, height - border_width - inner_corner_radius, inner_corner_radius) + self._canvas.coords("inner_oval_3_b", width - border_width - inner_corner_radius, height - border_width - inner_corner_radius, inner_corner_radius) + self._canvas.coords("inner_oval_4_a", border_width + inner_corner_radius, height - border_width - inner_corner_radius, inner_corner_radius) + self._canvas.coords("inner_oval_4_b", border_width + inner_corner_radius, height - border_width - inner_corner_radius, inner_corner_radius) + else: + self._canvas.delete("inner_corner_part") # delete inner corner parts if not needed + + # create canvas inner rectangle parts if not already created + if not self._canvas.find_withtag("inner_rectangle_1"): + self._canvas.create_rectangle(0, 0, 0, 0, tags=("inner_rectangle_left_1", "inner_rectangle_part", "inner_parts_left", "inner_parts"), width=0) + self._canvas.create_rectangle(0, 0, 0, 0, tags=("inner_rectangle_right_1", "inner_rectangle_part", "inner_parts_right", "inner_parts"), width=0) + requires_recoloring = True + + if not self._canvas.find_withtag("inner_rectangle_2") and inner_corner_radius * 2 < height - (border_width * 2): + self._canvas.create_rectangle(0, 0, 0, 0, tags=("inner_rectangle_left_2", "inner_rectangle_part", "inner_parts_left", "inner_parts"), width=0) + self._canvas.create_rectangle(0, 0, 0, 0, tags=("inner_rectangle_right_2", "inner_rectangle_part", "inner_parts_right", "inner_parts"), width=0) + requires_recoloring = True + + elif self._canvas.find_withtag("inner_rectangle_2") and not inner_corner_radius * 2 < height - (border_width * 2): + self._canvas.delete("inner_rectangle_left_2") + self._canvas.delete("inner_rectangle_right_2") + + # change position of inner rectangle parts + self._canvas.coords("inner_rectangle_left_1", (border_width + inner_corner_radius, + border_width, + left_section_width, + height - border_width)) + self._canvas.coords("inner_rectangle_left_2", (border_width, + border_width + inner_corner_radius, + left_section_width, + height - inner_corner_radius - border_width)) + self._canvas.coords("inner_rectangle_right_1", (left_section_width, + border_width, + width - border_width, + height - border_width)) + self._canvas.coords("inner_rectangle_right_2", (left_section_width, + border_width + inner_corner_radius, + width - border_width - inner_corner_radius, + height - inner_corner_radius - border_width)) + + if requires_recoloring: # new parts were added -> manage z-order + self._canvas.tag_lower("inner_parts") + self._canvas.tag_lower("border_parts") + + return requires_recoloring + def draw_rounded_progress_bar_with_border(self, width: int, height: int, corner_radius: Union[float, int], border_width: Union[float, int], progress_value: float, orientation: str) -> bool: """ Draws a rounded bar on the canvas, which is split in half according to the argument 'progress_value' (0 - 1). @@ -361,7 +640,7 @@ class DrawEngine: corner_radius = min(width / 2, height / 2) border_width = round(border_width) - corner_radius = self._calc_optimal_corner_radius(corner_radius) # optimize corner_radius for different drawing methods (different rounding) + corner_radius = self.__calc_optimal_corner_radius(corner_radius) # optimize corner_radius for different drawing methods (different rounding) if corner_radius >= border_width: inner_corner_radius = corner_radius - border_width @@ -369,16 +648,16 @@ class DrawEngine: inner_corner_radius = 0 if self.preferred_drawing_method == "polygon_shapes" or self.preferred_drawing_method == "circle_shapes": - return self._draw_rounded_progress_bar_with_border_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius, - progress_value, orientation) + return self.__draw_rounded_progress_bar_with_border_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius, + progress_value, orientation) elif self.preferred_drawing_method == "font_shapes": - return self._draw_rounded_progress_bar_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, - progress_value, orientation) + return self.__draw_rounded_progress_bar_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, + progress_value, orientation) - def _draw_rounded_progress_bar_with_border_polygon_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int, - progress_value: float, orientation: str) -> bool: + def __draw_rounded_progress_bar_with_border_polygon_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int, + progress_value: float, orientation: str) -> bool: - requires_recoloring = self._draw_rounded_rect_with_border_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius) + requires_recoloring = self.__draw_rounded_rect_with_border_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius) if corner_radius <= border_width: bottom_right_shift = 0 # weird canvas rendering inaccuracy that has to be corrected in some cases @@ -417,8 +696,8 @@ class DrawEngine: return requires_recoloring - def _draw_rounded_progress_bar_with_border_font_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int, - progress_value: float, orientation: str) -> bool: + def __draw_rounded_progress_bar_with_border_font_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int, + progress_value: float, orientation: str) -> bool: requires_recoloring, requires_recoloring_2 = False, False @@ -452,8 +731,8 @@ class DrawEngine: # horizontal orientation from the bottom if orientation == "w": - requires_recoloring_2 = self._draw_rounded_rect_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, - ("inner_oval_1", "inner_oval_4")) + requires_recoloring_2 = self.__draw_rounded_rect_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, + ("inner_oval_1", "inner_oval_4")) # set positions of progress corner parts self._canvas.coords("progress_oval_1_a", border_width + inner_corner_radius, border_width + inner_corner_radius, inner_corner_radius) @@ -483,8 +762,8 @@ class DrawEngine: # vertical orientation from the bottom if orientation == "s": - requires_recoloring_2 = self._draw_rounded_rect_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, - ("inner_oval_3", "inner_oval_4")) + requires_recoloring_2 = self.__draw_rounded_rect_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, + ("inner_oval_3", "inner_oval_4")) # set positions of progress corner parts self._canvas.coords("progress_oval_1_a", border_width + inner_corner_radius, @@ -530,7 +809,7 @@ class DrawEngine: button_length = round(button_length) border_width = round(border_width) button_corner_radius = round(button_corner_radius) - corner_radius = self._calc_optimal_corner_radius(corner_radius) # optimize corner_radius for different drawing methods (different rounding) + corner_radius = self.__calc_optimal_corner_radius(corner_radius) # optimize corner_radius for different drawing methods (different rounding) if corner_radius >= border_width: inner_corner_radius = corner_radius - border_width @@ -538,18 +817,18 @@ class DrawEngine: inner_corner_radius = 0 if self.preferred_drawing_method == "polygon_shapes" or self.preferred_drawing_method == "circle_shapes": - return self._draw_rounded_slider_with_border_and_button_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius, - button_length, button_corner_radius, slider_value, orientation) + return self.__draw_rounded_slider_with_border_and_button_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius, + button_length, button_corner_radius, slider_value, orientation) elif self.preferred_drawing_method == "font_shapes": - return self._draw_rounded_slider_with_border_and_button_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, - button_length, button_corner_radius, slider_value, orientation) + return self.__draw_rounded_slider_with_border_and_button_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, + button_length, button_corner_radius, slider_value, orientation) - def _draw_rounded_slider_with_border_and_button_polygon_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int, - button_length: int, button_corner_radius: int, slider_value: float, orientation: str) -> bool: + def __draw_rounded_slider_with_border_and_button_polygon_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int, + button_length: int, button_corner_radius: int, slider_value: float, orientation: str) -> bool: # draw normal progressbar - requires_recoloring = self._draw_rounded_progress_bar_with_border_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius, - slider_value, orientation) + requires_recoloring = self.__draw_rounded_progress_bar_with_border_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius, + slider_value, orientation) # create slider button part if not self._canvas.find_withtag("slider_parts"): @@ -583,12 +862,12 @@ class DrawEngine: return requires_recoloring - def _draw_rounded_slider_with_border_and_button_font_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int, - button_length: int, button_corner_radius: int, slider_value: float, orientation: str) -> bool: + def __draw_rounded_slider_with_border_and_button_font_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int, + button_length: int, button_corner_radius: int, slider_value: float, orientation: str) -> bool: # draw normal progressbar - requires_recoloring = self._draw_rounded_progress_bar_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, - slider_value, orientation) + requires_recoloring = self.__draw_rounded_progress_bar_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, + slider_value, orientation) # create 4 circles (if not needed, then less) if not self._canvas.find_withtag("slider_oval_1_a"): diff --git a/test/manual_integration_tests/test_combobox.py b/test/manual_integration_tests/test_combobox.py new file mode 100644 index 0000000..760e5d1 --- /dev/null +++ b/test/manual_integration_tests/test_combobox.py @@ -0,0 +1,30 @@ +from tkinter import * + +ws = Tk() +ws.title('PythonGuides') +ws.geometry('400x300') +ws.config(bg='#F2B90C') + +def display_selected(choice): + choice = variable.get() + print(choice) + +countries = ['Bahamas','Canada', 'Cuba','United States'] + +# setting variable for Integers +variable = StringVar() +variable.set(countries[3]) + +# creating widget +dropdown = OptionMenu( + ws, + variable, + *countries, + command=display_selected +) + +# positioning widget +dropdown.pack(expand=True) + +# infinite loop +ws.mainloop() diff --git a/test/manual_integration_tests/test_new_menu_design.py b/test/manual_integration_tests/test_new_menu_design.py index c331fef..f52f782 100644 --- a/test/manual_integration_tests/test_new_menu_design.py +++ b/test/manual_integration_tests/test_new_menu_design.py @@ -12,6 +12,7 @@ class CTkMenu(tkinter.Toplevel): self.config(bg='systemTransparent') # transparent bg self.geometry(f"120x{len(options) * (25 + 3) + 3}+{x}+{y}") self.bind("", self.focus_loss_event) + self.focus_force() self.frame = customtkinter.CTkFrame(self, border_width=0, width=120, corner_radius=6, border_color="gray4", fg_color="#333740") self.frame.grid(row=0, column=0, sticky="nsew", rowspan=len(options) + 1, columnspan=1, ipadx=0, ipady=0) @@ -44,7 +45,7 @@ app.geometry("600x500") def open_menu(): menu = CTkMenu(app, button.winfo_rootx(), button.winfo_rooty() + button.winfo_height() + 4, ["Option 1", "Option 2", "Point 3"]) - print(menu) + button = customtkinter.CTkButton(command=open_menu, height=30, corner_radius=6) button.pack(pady=20)