diff --git a/Assets/Icons/input.png b/Assets/Icons/input.png index 469dc53..103d7cc 100644 Binary files a/Assets/Icons/input.png and b/Assets/Icons/input.png differ diff --git a/Assets/Icons/output.png b/Assets/Icons/output.png index 4efed40..b7bb551 100644 Binary files a/Assets/Icons/output.png and b/Assets/Icons/output.png differ diff --git a/breadboard.py b/breadboard.py index 6aba360..13de819 100644 --- a/breadboard.py +++ b/breadboard.py @@ -31,34 +31,7 @@ class Breadboard: def __init__(self, canvas: Canvas, sketcher: ComponentSketcher): self.canvas = canvas self.sketcher = sketcher - self.selector() self.canvas.config(cursor="") - canvas.bind("", self.follow_mouse) - - def follow_mouse(self, event): - """ - Updates the mouse coordinates based on the given event. - Args: - event: An event object that contains the current mouse position. - """ - # FIXME fixing the coords crashes the app - self.canvas.coords("selector_cable", [event.x - 10, event.y - 10, event.x + 0, event.y + 0]) - - def selector(self): - """ - Create the round selector cable movement - """ - self.canvas.create_oval( - 100, - 100, - 110, - 110, - fill="#dfdfdf", - outline="#404040", - width=1, - tags=("selector_cable"), - ) - self.canvas.itemconfig("selector_cable", state="hidden") def fill_matrix_830_pts(self, col_distance=1, line_distance=1): """ diff --git a/component_sketch.py b/component_sketch.py index 1f7f2ef..89aea81 100644 --- a/component_sketch.py +++ b/component_sketch.py @@ -52,7 +52,13 @@ def __init__(self, canvas) -> None: self.drag_selector = False self.nearest_multipoint = -1 self.drag_chip_data = {"chip_id": None, "x": 0, "y": 0} - self.wire_drag_data: dict[str, str | int | None] = {"wire_id": None, "endpoint": None, "x": 0, "y": 0} + self.wire_drag_data: dict[str, str | int | None] = { + "wire_id": None, + "endpoint": None, + "x": 0, + "y": 0, + "creating_wire": False, + } self.pin_io_drag_data = {"pin_id": None, "x": 0, "y": 0} self.delete_mode_active = False self.drag_mouse = [0, 0] @@ -323,19 +329,18 @@ def on_wire_body_enter(self, _, wire_id): """ Event handler for when the mouse enters the wire body. """ - if not self.drag_selector and not self.delete_mode_active: + if not self.drag_selector and not self.delete_mode_active and not self.wire_drag_data["creating_wire"]: color = self.current_dict_circuit[wire_id]["color"] encre = f"#{color[0]:02x}{color[1]:02x}{color[2]:02x}" contour = f"#{color[0]//2:02x}{color[1]//2:02x}{color[2]//2:02x}" - self.canvas.itemconfig("selector_cable", fill=contour, outline=encre) - self.canvas.itemconfig("selector_cable", state="normal") + self.canvas.config(cursor=f"dot {encre} {contour}") def on_wire_body_leave(self, *_): """ Event handler for when the mouse leaves the wire body. """ - if not self.drag_selector: - self.canvas.itemconfig("selector_cable", state="hidden") + if not self.drag_selector and not self.wire_drag_data["creating_wire"]: + self.canvas.config(cursor="arrow") def on_wire_body_click(self, event, wire_id) -> None: """ @@ -349,6 +354,7 @@ def on_wire_body_click(self, event, wire_id) -> None: self.delete_wire(wire_id) else: + self.wire_drag_data["creating_wire"] = True self.wire_drag_data["wire_id"] = wire_id self.wire_drag_data["endpoint"] = "selector_cable" endpoint_tag = "selector_cable" @@ -450,10 +456,7 @@ def on_wire_body_release(self, *_): """ Event handler for when the wire body is released. """ - self.wire_drag_data["wire_id"] = None - self.wire_drag_data["endpoint"] = None - self.nearest_multipoint = -1 - self.canvas.itemconfig("selector_cable", state="hidden") + self.wire_drag_data["creating_wire"] = False def start_chip_drag(self, event, chip_id): """ @@ -2410,7 +2413,6 @@ def draw_wire(self, x_distance, y_distance, scale=1, width=-1, direction=HORIZON } self.canvas.tag_raise(select_start_tag) self.canvas.tag_raise(select_end_tag) - self.canvas.tag_raise("selector_cable") # Bind events to the endpoints for drag-and-drop self.canvas.tag_bind( @@ -2429,6 +2431,12 @@ def draw_wire(self, x_distance, y_distance, scale=1, width=-1, direction=HORIZON wire_body_tag, "", lambda event, wire_id=wire_id: self.on_wire_body_drag(event, wire_id) ) + self.canvas.tag_bind( + wire_body_tag, + "", + lambda event, wire_id=wire_id: self.on_wire_body_release(event, wire_id), + ) + self.canvas.tag_bind( select_start_tag, "", @@ -2564,10 +2572,10 @@ def draw_pin_io(self, x_distance, y_distance, scale=1, width=-1, direction=HORIZ self.canvas.tag_raise(element_id) # take the last number of the element_id as the pin number as an integer - pin_number = element_id.rsplit('_', maxsplit=1)[-1] + pin_number = element_id.rsplit("_", maxsplit=1)[-1] - label_x = x_distance + x_origin + 5 * scale, - label_y = y_distance + y_origin - 17 * scale, + label_x = (x_distance + x_origin + 5 * scale,) + label_y = (y_distance + y_origin - 17 * scale,) label_tag = f"{element_id}_label" text_id = self.canvas.create_text( @@ -2633,8 +2641,6 @@ def draw_pin_io(self, x_distance, y_distance, scale=1, width=-1, direction=HORIZ ) params["tags"].append(arrow_head_id) - - self.current_dict_circuit[element_id] = params print("coord : " + str(coord[0][0]) + "," + str(coord[0][1])) diff --git a/menus.py b/menus.py index f213e92..9495a7a 100644 --- a/menus.py +++ b/menus.py @@ -272,6 +272,8 @@ def create_menu(self, menu_name, options, menu_commands): pady=5, font=("FiraCode-Bold", 12), command=lambda m=menu_name: self.toggle_dropdown(m), + borderwidth=0, + highlightthickness=0, ) btn.pack(side="left") @@ -305,6 +307,8 @@ def select_menu_item(option): pady=5, font=("FiraCode-Bold", 12), command=lambda o=option: select_menu_item(o), + borderwidth=0, + highlightthickness=0, ) option_btn.pack(fill="both") diff --git a/sidebar.py b/sidebar.py index 8af9978..03b3286 100644 --- a/sidebar.py +++ b/sidebar.py @@ -73,7 +73,7 @@ def __init__( self.saved_bindings: dict[str, Callable] = {} # Creating the sidebar frame - sidebar_frame = tk.Frame(parent, bg="#333333", width=250, bd=0, highlightthickness=0) + sidebar_frame = tk.Frame(parent, bg="#333333", width=275, bd=0, highlightthickness=0) sidebar_frame.grid(row=2, column=0, sticky="nsew", padx=0, pady=0) sidebar_frame.grid_propagate(False) # Preventing frame from resizing @@ -230,8 +230,11 @@ def display_chips(self, chips: list[Tuple[Chip, tk.PhotoImage]]): command=self.create_select_chip_command(chip.chip_type), width=100, # Fixed width to match image size height=60, # Fixed height to match image size + borderwidth=0, + highlightthickness=0, + padx=10 ) - btn.grid(row=row, column=col, padx=1, pady=1) + btn.grid(row=row, column=col, padx=0, pady=0) Hovertip(btn, chip.description, 500) # Adding tooltip with chip name def enter_effect(_, b=btn): @@ -265,8 +268,9 @@ def create_manage_button(self, sidebar_frame): relief="flat", borderwidth=0, command=self.manage_components, + highlightthickness=0, ) - manage_button.grid(row=3, column=0, padx=10, pady=5, sticky="we") + manage_button.grid(row=3, column=0, padx=0, pady=0, sticky="we") def select_chip(self, chip_name): """ @@ -479,9 +483,13 @@ def manage_components(self): """ path = Path("Components").resolve() if os.name == "nt": # For Windows - os.startfile(path) - elif os.name == "posix": # For macOS and Linux - subprocess.Popen(["open", path] if sys.platform == "darwin" else ["xdg-open", path]) + try: + os.startfile(path) + except AttributeError: + pass + elif os.name == "posix": # For macOS and Linux # type: ignore + with subprocess.Popen(["open", path] if sys.platform == "darwin" else ["xdg-open", path]): + pass else: messagebox.showerror("Error", "Unsupported operating system.") diff --git a/toolbar.py b/toolbar.py index 2d1dac3..1baadab 100644 --- a/toolbar.py +++ b/toolbar.py @@ -85,6 +85,8 @@ def create_topbar(self, parent: tk.Tk): relief="raised", bd=1, command=self.choose_color, + borderwidth=0, + highlightthickness=0, ) self.color_button.pack(side=tk.LEFT, padx=2, pady=2) self.create_button("Delete", right_frame, images) @@ -134,6 +136,8 @@ def create_button(self, action: str, parent_frame: tk.Frame, images: dict[str, t command=lambda: self.button_action(action), padx=2, pady=2, + borderwidth=0, + highlightthickness=0, ) # Keep a reference to prevent garbage collection btn.image = image # type: ignore @@ -151,6 +155,8 @@ def create_button(self, action: str, parent_frame: tk.Frame, images: dict[str, t command=lambda: self.button_action(action), padx=2, pady=2, + borderwidth=0, + highlightthickness=0, ) btn.pack(side=tk.LEFT, padx=10, pady=2) # Minimal spacing between buttons self.buttons[action] = btn # Store button reference @@ -318,6 +324,7 @@ def canvas_click(self, event): }, ) ] + self.sketcher.wire_drag_data["creating_wire"] = True self.sketcher.circuit(x_origin, y_origin, model=model_wire) self.wire_info.wire_id = self.current_dict_circuit["last_id"] self.wire_info.start_point = (adjusted_x, adjusted_y) @@ -326,6 +333,7 @@ def canvas_click(self, event): # Finalize the wire self.wire_info.start_point = None self.wire_info.start_col_line = None + self.sketcher.wire_drag_data["creating_wire"] = False print("Wire placement completed.") elif self.tool_mode in ("Input", "Output") and self.sketcher.matrix[f"{col},{line}"]["state"] == FREE: