From 5d2150beee2e5f63fd9e2b1cac48f00e3e152d36 Mon Sep 17 00:00:00 2001 From: abbou169 Date: Fri, 15 Nov 2024 20:40:04 -0500 Subject: [PATCH 1/9] first implementation --- breadboard.py | 4 + component_sketch.py | 351 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 355 insertions(+) diff --git a/breadboard.py b/breadboard.py index 6aba360..c78cb15 100644 --- a/breadboard.py +++ b/breadboard.py @@ -250,3 +250,7 @@ def draw_blank_board_model(self, x_origin: int = 50, y_origin: int = 10): (self.sketcher.go_xy, 1, {"line": 0, "column": 0, "id_origin": "circTest"}), ] self.sketcher.circuit(x_origin, y_origin, scale=self.sketcher.scale_factor, model=blank_board_model) + + battery_x = x_origin + 1100 # Adjust as needed for proper positioning + battery_y = y_origin + 400 # Adjust as needed for proper positioning + self.sketcher.draw_battery(battery_x, battery_y) diff --git a/component_sketch.py b/component_sketch.py index 1f7f2ef..54c65a9 100644 --- a/component_sketch.py +++ b/component_sketch.py @@ -11,6 +11,7 @@ from typing import Any, Callable + from dataCDLT import ( HORIZONTAL, RIGHT, @@ -60,6 +61,8 @@ def __init__(self, canvas) -> None: self.current_dict_circuit: dict[str, Any] = {} self.matrix: dict[str, Any] = {} self.id_origins = {"xyOrigin": (0, 0)} + self.battery_wire_drag_data: dict[str, Any] = {} + def circuit(self, x_distance=0, y_distance=0, scale=1, width=-1, direction=VERTICAL, **kwargs): """ @@ -2654,6 +2657,8 @@ def draw_pin_io(self, x_distance, y_distance, scale=1, width=-1, direction=HORIZ matrix[f"{coord[0][0]},{coord[0][1]}"]["state"] = USED return x_distance, y_distance + + def clear_board(self): """Clear the board of all drawn components.""" @@ -2666,3 +2671,349 @@ def clear_board(self): self.id_type[key] = 0 self.current_dict_circuit.clear() # TODO Khalid update the Circuit instance + + + def draw_battery(self, x_distance, y_distance, scale=1, width=-1, direction=HORIZONTAL, **kwargs): + """ + Draws a battery at the given coordinates with two hanging wires. + """ + if width != -1: + scale = width / 9.0 + + inter_space = 15 * scale + thickness = 2 * scale + + battery_id = '_battery' + + # Check if battery already exists + if battery_id in self.current_dict_circuit: + print("Battery already exists in the circuit.") + return x_distance, y_distance + + # Draw the battery as a rectangle with '+' and '-' signs + battery_width = 40 * scale + battery_height = 60 * scale + battery_x = x_distance + battery_y = y_distance + + # Draw the battery rectangle + self.canvas.create_rectangle( + battery_x, + battery_y, + battery_x + battery_width, + battery_y + battery_height, + fill='gray', + outline='black', + width=2, + tags=(battery_id,) + ) + + # Draw '+' sign at the top + self.canvas.create_text( + battery_x + battery_width / 2, + battery_y + 15 * scale, + text='+', + font=("Arial", int(20 * scale), 'bold'), + fill='black', + tags=(battery_id,) + ) + + # Draw '-' sign at the bottom + self.canvas.create_text( + battery_x + battery_width / 2, + battery_y + battery_height - 15 * scale, + text='-', + font=("Arial", int(20 * scale), 'bold'), + fill='black', + tags=(battery_id,) + ) + + # Store the battery in current_dict_circuit + self.current_dict_circuit[battery_id] = { + 'id': battery_id, + 'tags': [battery_id], + 'battery_rect': (battery_x, battery_y, battery_x + battery_width, battery_y + battery_height), + } + + # Draw wires from the left side of the battery + # Positive wire (from the '+' sign) + pos_wire_id = '_battery_pos_wire' + pos_wire_start_x = battery_x + pos_wire_start_y = battery_y + 15 * scale + pos_wire_end_x = battery_x - 100 * scale # Wires go to the left + pos_wire_end_y = pos_wire_start_y + + # Negative wire (from the '-' sign) + neg_wire_id = '_battery_neg_wire' + neg_wire_start_x = battery_x + neg_wire_start_y = battery_y + battery_height - 15 * scale + neg_wire_end_x = battery_x - 100 * scale # Wires go to the left + neg_wire_end_y = neg_wire_start_y + + # Use draw_battery_wire to draw the wires with similar appearance to draw_wire + # Positive wire + self.draw_battery_wire( + wire_id=pos_wire_id, + start_x=pos_wire_start_x, + start_y=pos_wire_start_y, + end_x=pos_wire_end_x, + end_y=pos_wire_end_y, + color=(255, 0, 0), # Red for positive + terminal_type='pos' + ) + + # Negative wire + self.draw_battery_wire( + wire_id=neg_wire_id, + start_x=neg_wire_start_x, + start_y=neg_wire_start_y, + end_x=neg_wire_end_x, + end_y=neg_wire_end_y, + color=(0, 0, 0), # Black for negative + terminal_type='neg' + ) + + # Update the battery's tags + self.current_dict_circuit[battery_id]['tags'].extend( + self.current_dict_circuit[pos_wire_id]['tags'] + self.current_dict_circuit[neg_wire_id]['tags'] + ) + + return x_distance, y_distance + + + def draw_battery_wire(self, wire_id, start_x, start_y, end_x, end_y, color, terminal_type): + """ + Draws a battery wire with appearance similar to draw_wire, but with separate event handling. + """ + # Create the wire line with shadow for 3D effect + thickness = 2 * self.scale_factor + encre = f"#{color[0]:02x}{color[1]:02x}{color[2]:02x}" + contour = f"#{max(color[0] - 100, 0):02x}{max(color[1] - 100, 0):02x}{max(color[2] - 100, 0):02x}" + + wire_body_tag = f"{wire_id}_body" + wire_body_shadow_tag = f"{wire_id}_body_shadow" + endpoint_tag = f"{wire_id}_endpoint" + + # Draw the shadow line + self.canvas.create_line( + start_x, + start_y, + end_x, + end_y, + fill=contour, + width=8 * thickness, + tags=(wire_id, wire_body_shadow_tag) + ) + # Draw the main line + self.canvas.create_line( + start_x, + start_y, + end_x, + end_y, + fill=encre, + width=4 * thickness, + tags=(wire_id, wire_body_tag) + ) + + # Create the endpoint + radius = 5 * self.scale_factor + endpoint = self.canvas.create_oval( + end_x - radius, + end_y - radius, + end_x + radius, + end_y + radius, + fill='green' if terminal_type == 'pos' else 'black', + outline='', + tags=(endpoint_tag,) + ) + + # Store wire data + self.current_dict_circuit[wire_id] = { + 'id': wire_id, + 'tags': [wire_id, wire_body_tag, wire_body_shadow_tag, endpoint_tag], + 'start': (start_x, start_y), + 'end': (end_x, end_y), + 'color': color, + 'terminal_type': terminal_type, + 'endpoint_tag': endpoint_tag, + } + + # Bind event handlers to the endpoint + self.canvas.tag_bind( + endpoint_tag, + "", + lambda event, wire_id=wire_id: self.on_battery_wire_endpoint_click(event, wire_id) + ) + self.canvas.tag_bind( + endpoint_tag, + "", + lambda event, wire_id=wire_id: self.on_battery_wire_endpoint_drag(event, wire_id) + ) + self.canvas.tag_bind( + endpoint_tag, + "", + lambda event, wire_id=wire_id: self.on_battery_wire_endpoint_release(event, wire_id) + ) + + def create_battery_wire_endpoint(self, x, y, wire_id, terminal_type): + """ + Creates an interactive endpoint for a battery wire. + """ + endpoint_tag = f"{wire_id}_endpoint" + + # Draw a small circle at the end of the wire + radius = 5 + endpoint = self.canvas.create_oval( + x - radius, + y - radius, + x + radius, + y + radius, + fill='green' if terminal_type == 'pos' else 'black', + outline='', + tags=(endpoint_tag,) + ) + + # Bind event handlers + self.canvas.tag_bind( + endpoint_tag, + "", + lambda event, wire_id=wire_id: self.on_battery_wire_endpoint_click(event, wire_id) + ) + self.canvas.tag_bind( + endpoint_tag, + "", + lambda event, wire_id=wire_id: self.on_battery_wire_endpoint_drag(event, wire_id) + ) + self.canvas.tag_bind( + endpoint_tag, + "", + lambda event, wire_id=wire_id: self.on_battery_wire_endpoint_release(event, wire_id) + ) + + # Store the endpoint in current_dict_circuit + self.current_dict_circuit[wire_id]['endpoint_tag'] = endpoint_tag + + def on_battery_wire_endpoint_click(self, event, wire_id): + """ + Handler for when a battery wire endpoint is clicked. + Initializes the drag data. + """ + self.battery_wire_drag_data = { + 'wire_id': wire_id, + } + + def on_battery_wire_endpoint_drag(self, event, wire_id): + """ + Handler for dragging a battery wire endpoint. + Updates the wire's end position as it's being dragged. + """ + if self.battery_wire_drag_data['wire_id'] != wire_id: + return + + wire_data = self.current_dict_circuit[wire_id] + start_x, start_y = wire_data['start'] + + # Update wire lines to current mouse position + wire_body_tag = f"{wire_id}_body" + wire_body_shadow_tag = f"{wire_id}_body_shadow" + + self.canvas.coords(wire_body_shadow_tag, start_x, start_y, event.x, event.y) + self.canvas.coords(wire_body_tag, start_x, start_y, event.x, event.y) + + # Move the endpoint to the current mouse position + endpoint_tag = wire_data['endpoint_tag'] + radius = 5 * self.scale_factor + self.canvas.coords( + endpoint_tag, + event.x - radius, + event.y - radius, + event.x + radius, + event.y + radius + ) + + # Update the wire data + wire_data['end'] = (event.x, event.y) + + def on_battery_wire_endpoint_release(self, event, wire_id): + """ + Handler for when a battery wire endpoint is released. + Snaps the wire end to the nearest allowed power line pin. + """ + # Snap to allowed positions + allowed_positions = self.get_power_line_last_pins() + x, y = event.x, event.y + nearest_point, nearest_point_coord = self.find_nearest_allowed_grid_point(x, y, allowed_positions) + + # Update wire end position to the snapped point + wire_data = self.current_dict_circuit[wire_id] + start_x, start_y = wire_data['start'] + new_end_x, new_end_y = nearest_point + + # Update wire lines + wire_body_tag = f"{wire_id}_body" + wire_body_shadow_tag = f"{wire_id}_body_shadow" + + self.canvas.coords(wire_body_shadow_tag, start_x, start_y, new_end_x, new_end_y) + self.canvas.coords(wire_body_tag, start_x, start_y, new_end_x, new_end_y) + + # Move the endpoint to the snapped position + endpoint_tag = wire_data['endpoint_tag'] + radius = 5 * self.scale_factor + self.canvas.coords( + endpoint_tag, + new_end_x - radius, + new_end_y - radius, + new_end_x + radius, + new_end_y + radius + ) + + # Update wire data + wire_data['end'] = (new_end_x, new_end_y) + + # Clear drag data + self.battery_wire_drag_data = {} + + def get_power_line_last_pins(self): + """ + Returns a list of allowed positions (coordinates) for the battery wires. + """ + allowed_positions = [] + last_col = 61 + power_lines = [1, 2, 13, 14, 15, 16, 27, 28] + + for line in power_lines: + x, y = self.get_xy(last_col, line, scale=self.scale_factor) + x += self.id_origins["xyOrigin"][0] + y += self.id_origins["xyOrigin"][1] + allowed_positions.append((x, y)) + + return allowed_positions + + def find_nearest_allowed_grid_point(self, x, y, allowed_positions): + """ + Find the nearest grid point among the allowed positions to the given x, y coordinates. + + Parameters: + - x (float): The x-coordinate of the point. + - y (float): The y-coordinate of the point. + - allowed_positions (list of tuples): List of allowed (x, y) positions. + + Returns: + - tuple: (nearest_point (x, y), nearest_point_coord (col, line)) + """ + min_distance = float('inf') + nearest_point = (x, y) + nearest_point_coord = (0, 0) + + for grid_x, grid_y in allowed_positions: + distance = math.hypot(x - grid_x, y - grid_y) + if distance < min_distance: + min_distance = distance + nearest_point = (grid_x, grid_y) + # Retrieve (col, line) from the matrix based on (x, y) + for key, value in self.matrix.items(): + if value['xy'] == (grid_x, grid_y): + nearest_point_coord = value['coord'] + break + + return nearest_point, nearest_point_coord \ No newline at end of file From 2a0eadc5014be294e4bf67ef8cc32133d118af75 Mon Sep 17 00:00:00 2001 From: abbou169 Date: Fri, 15 Nov 2024 20:56:20 -0500 Subject: [PATCH 2/9] some enhancements --- breadboard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/breadboard.py b/breadboard.py index c78cb15..0536414 100644 --- a/breadboard.py +++ b/breadboard.py @@ -251,6 +251,6 @@ def draw_blank_board_model(self, x_origin: int = 50, y_origin: int = 10): ] self.sketcher.circuit(x_origin, y_origin, scale=self.sketcher.scale_factor, model=blank_board_model) - battery_x = x_origin + 1100 # Adjust as needed for proper positioning - battery_y = y_origin + 400 # Adjust as needed for proper positioning + battery_x = x_origin + 1200 # Adjust as needed for proper positioning + battery_y = y_origin + 300 # Adjust as needed for proper positioning self.sketcher.draw_battery(battery_x, battery_y) From 5db4c47ce0988df3512201e70364a4f8e47e5195 Mon Sep 17 00:00:00 2001 From: abbou169 Date: Fri, 15 Nov 2024 20:56:32 -0500 Subject: [PATCH 3/9] other enhancements --- component_sketch.py | 131 +++++++++++++++++++++++++++++--------------- 1 file changed, 87 insertions(+), 44 deletions(-) diff --git a/component_sketch.py b/component_sketch.py index 54c65a9..ff775e8 100644 --- a/component_sketch.py +++ b/component_sketch.py @@ -2681,7 +2681,7 @@ def draw_battery(self, x_distance, y_distance, scale=1, width=-1, direction=HORI scale = width / 9.0 inter_space = 15 * scale - thickness = 2 * scale + thickness = 1 * self.scale_factor # Adjusted thickness battery_id = '_battery' @@ -2696,11 +2696,23 @@ def draw_battery(self, x_distance, y_distance, scale=1, width=-1, direction=HORI battery_x = x_distance battery_y = y_distance - # Draw the battery rectangle - self.canvas.create_rectangle( + # Draw the battery rectangle as a rounded rectangle + battery_body = self.canvas.create_rectangle( battery_x, - battery_y, + battery_y + 5 * scale, battery_x + battery_width, + battery_y + battery_height - 5 * scale, + fill='silver', + outline='black', + width=2, + tags=(battery_id,) + ) + + # Draw the positive terminal (a small rectangle at the bottom) + self.canvas.create_rectangle( + battery_x + battery_width / 3, + battery_y + battery_height - 5 * scale, + battery_x + 2 * battery_width / 3, battery_y + battery_height, fill='gray', outline='black', @@ -2708,21 +2720,45 @@ def draw_battery(self, x_distance, y_distance, scale=1, width=-1, direction=HORI tags=(battery_id,) ) - # Draw '+' sign at the top + # Draw the negative terminal (a small rectangle at the top) + self.canvas.create_rectangle( + battery_x + battery_width / 3, + battery_y, + battery_x + 2 * battery_width / 3, + battery_y + 5 * scale, + fill='gray', + outline='black', + width=2, + tags=(battery_id,) + ) + + # Optionally add text or lines to enhance the look + # For example, adding a label "5V" + self.canvas.create_text( + battery_x + battery_width / 2, + battery_y + battery_height / 2, + text='5V', + font=("Arial", int(12 * scale), 'bold'), + fill='black', + tags=(battery_id,) + ) + + # Swap positions of '+' and '-' signs + # Draw '-' sign at the top self.canvas.create_text( battery_x + battery_width / 2, battery_y + 15 * scale, - text='+', + text='-', font=("Arial", int(20 * scale), 'bold'), fill='black', tags=(battery_id,) ) - # Draw '-' sign at the bottom + # Draw '+' sign at the bottom self.canvas.create_text( battery_x + battery_width / 2, battery_y + battery_height - 15 * scale, - text='-', + text='+', font=("Arial", int(20 * scale), 'bold'), fill='black', tags=(battery_id,) @@ -2736,17 +2772,18 @@ def draw_battery(self, x_distance, y_distance, scale=1, width=-1, direction=HORI } # Draw wires from the left side of the battery - # Positive wire (from the '+' sign) + # Swap positions of wires + # Positive wire (from the '+' sign at the bottom) pos_wire_id = '_battery_pos_wire' pos_wire_start_x = battery_x - pos_wire_start_y = battery_y + 15 * scale + pos_wire_start_y = battery_y + battery_height - 15 * scale pos_wire_end_x = battery_x - 100 * scale # Wires go to the left pos_wire_end_y = pos_wire_start_y - # Negative wire (from the '-' sign) + # Negative wire (from the '-' sign at the top) neg_wire_id = '_battery_neg_wire' neg_wire_start_x = battery_x - neg_wire_start_y = battery_y + battery_height - 15 * scale + neg_wire_start_y = battery_y + 15 * scale neg_wire_end_x = battery_x - 100 * scale # Wires go to the left neg_wire_end_y = neg_wire_start_y @@ -2785,8 +2822,8 @@ def draw_battery_wire(self, wire_id, start_x, start_y, end_x, end_y, color, term """ Draws a battery wire with appearance similar to draw_wire, but with separate event handling. """ - # Create the wire line with shadow for 3D effect - thickness = 2 * self.scale_factor + # Adjusted thickness to match regular wires + thickness = 1 * self.scale_factor encre = f"#{color[0]:02x}{color[1]:02x}{color[2]:02x}" contour = f"#{max(color[0] - 100, 0):02x}{max(color[1] - 100, 0):02x}{max(color[2] - 100, 0):02x}" @@ -2815,8 +2852,8 @@ def draw_battery_wire(self, wire_id, start_x, start_y, end_x, end_y, color, term tags=(wire_id, wire_body_tag) ) - # Create the endpoint - radius = 5 * self.scale_factor + # Adjusted radius to match regular wire endpoints + radius = 2 * self.scale_factor endpoint = self.canvas.create_oval( end_x - radius, end_y - radius, @@ -2896,8 +2933,12 @@ def create_battery_wire_endpoint(self, x, y, wire_id, terminal_type): def on_battery_wire_endpoint_click(self, event, wire_id): """ Handler for when a battery wire endpoint is clicked. - Initializes the drag data. """ + wire_data = self.current_dict_circuit[wire_id] + if 'connected_hole' in wire_data: + old_col, old_line = wire_data['connected_hole'] + self.matrix[f'{old_col},{old_line}']['state'] = FREE + del wire_data['connected_hole'] self.battery_wire_drag_data = { 'wire_id': wire_id, } @@ -2937,13 +2978,17 @@ def on_battery_wire_endpoint_drag(self, event, wire_id): def on_battery_wire_endpoint_release(self, event, wire_id): """ Handler for when a battery wire endpoint is released. - Snaps the wire end to the nearest allowed power line pin. """ # Snap to allowed positions allowed_positions = self.get_power_line_last_pins() x, y = event.x, event.y nearest_point, nearest_point_coord = self.find_nearest_allowed_grid_point(x, y, allowed_positions) + if nearest_point_coord is None: + # No free hole found; do not update the wire's position + print("No free hole available.") + return + # Update wire end position to the snapped point wire_data = self.current_dict_circuit[wire_id] start_x, start_y = wire_data['start'] @@ -2958,7 +3003,7 @@ def on_battery_wire_endpoint_release(self, event, wire_id): # Move the endpoint to the snapped position endpoint_tag = wire_data['endpoint_tag'] - radius = 5 * self.scale_factor + radius = 2 * self.scale_factor self.canvas.coords( endpoint_tag, new_end_x - radius, @@ -2969,51 +3014,49 @@ def on_battery_wire_endpoint_release(self, event, wire_id): # Update wire data wire_data['end'] = (new_end_x, new_end_y) + wire_data['connected_hole'] = nearest_point_coord + + # Mark the hole as USED + col, line = nearest_point_coord + self.matrix[f'{col},{line}']['state'] = USED # Clear drag data self.battery_wire_drag_data = {} def get_power_line_last_pins(self): """ - Returns a list of allowed positions (coordinates) for the battery wires. + Returns a list of allowed positions (x, y, col, line) for the battery wires. """ allowed_positions = [] - last_col = 61 - power_lines = [1, 2, 13, 14, 15, 16, 27, 28] + last_col = 61 # Adjusted based on your breadboard configuration + power_lines = [1, 2, 13, 14, 15, 16, 27, 28] # Your updated power lines for line in power_lines: - x, y = self.get_xy(last_col, line, scale=self.scale_factor) - x += self.id_origins["xyOrigin"][0] - y += self.id_origins["xyOrigin"][1] - allowed_positions.append((x, y)) - + col = last_col + key = f"{col},{line}" + if key in self.matrix: + x, y = self.matrix[key]['xy'] + x += self.id_origins["xyOrigin"][0] + y += self.id_origins["xyOrigin"][1] + allowed_positions.append((x, y, col, line)) return allowed_positions def find_nearest_allowed_grid_point(self, x, y, allowed_positions): """ Find the nearest grid point among the allowed positions to the given x, y coordinates. - - Parameters: - - x (float): The x-coordinate of the point. - - y (float): The y-coordinate of the point. - - allowed_positions (list of tuples): List of allowed (x, y) positions. - - Returns: - - tuple: (nearest_point (x, y), nearest_point_coord (col, line)) + Skips positions that are already USED. """ min_distance = float('inf') nearest_point = (x, y) - nearest_point_coord = (0, 0) - - for grid_x, grid_y in allowed_positions: + nearest_point_coord = None + for grid_x, grid_y, col, line in allowed_positions: + # Check if the hole is FREE + hole_state = self.matrix.get(f'{col},{line}', {}).get('state', None) + if hole_state != FREE: + continue # Skip used holes distance = math.hypot(x - grid_x, y - grid_y) if distance < min_distance: min_distance = distance nearest_point = (grid_x, grid_y) - # Retrieve (col, line) from the matrix based on (x, y) - for key, value in self.matrix.items(): - if value['xy'] == (grid_x, grid_y): - nearest_point_coord = value['coord'] - break - + nearest_point_coord = (col, line) return nearest_point, nearest_point_coord \ No newline at end of file From 06ac5b20fbf0b817b391429cdfa77effac4995e3 Mon Sep 17 00:00:00 2001 From: abbou169 Date: Fri, 15 Nov 2024 21:32:05 -0500 Subject: [PATCH 4/9] save and open inclusion --- breadboard.py | 9 +++++++-- component_sketch.py | 18 ++++++++++++------ menus.py | 27 ++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/breadboard.py b/breadboard.py index 0536414..5cfa572 100644 --- a/breadboard.py +++ b/breadboard.py @@ -183,7 +183,7 @@ def draw_matrix_points(self, scale=1): # used to debug the matrix radius = 2 * scale # Adjust size as needed self.canvas.create_oval(x - radius, y - radius, x + radius, y + radius, fill=color, outline="") - def draw_blank_board_model(self, x_origin: int = 50, y_origin: int = 10): + def draw_blank_board_model(self, x_origin: int = 50, y_origin: int = 10, battery_pos_wire_end=None, battery_neg_wire_end=None): """ Draws a blank breadboard model on the canvas. """ @@ -253,4 +253,9 @@ def draw_blank_board_model(self, x_origin: int = 50, y_origin: int = 10): battery_x = x_origin + 1200 # Adjust as needed for proper positioning battery_y = y_origin + 300 # Adjust as needed for proper positioning - self.sketcher.draw_battery(battery_x, battery_y) + self.sketcher.draw_battery( + battery_x, + battery_y, + pos_wire_end=battery_pos_wire_end, + neg_wire_end=battery_neg_wire_end, + ) diff --git a/component_sketch.py b/component_sketch.py index ff775e8..ad2e185 100644 --- a/component_sketch.py +++ b/component_sketch.py @@ -2673,7 +2673,7 @@ def clear_board(self): # TODO Khalid update the Circuit instance - def draw_battery(self, x_distance, y_distance, scale=1, width=-1, direction=HORIZONTAL, **kwargs): + def draw_battery(self, x_distance, y_distance, scale=1, width=-1, direction=HORIZONTAL, pos_wire_end=None, neg_wire_end=None, **kwargs): """ Draws a battery at the given coordinates with two hanging wires. """ @@ -2681,7 +2681,7 @@ def draw_battery(self, x_distance, y_distance, scale=1, width=-1, direction=HORI scale = width / 9.0 inter_space = 15 * scale - thickness = 1 * self.scale_factor # Adjusted thickness + thickness = 1 * self.scale_factor battery_id = '_battery' @@ -2777,15 +2777,21 @@ def draw_battery(self, x_distance, y_distance, scale=1, width=-1, direction=HORI pos_wire_id = '_battery_pos_wire' pos_wire_start_x = battery_x pos_wire_start_y = battery_y + battery_height - 15 * scale - pos_wire_end_x = battery_x - 100 * scale # Wires go to the left - pos_wire_end_y = pos_wire_start_y + if pos_wire_end: + pos_wire_end_x, pos_wire_end_y = pos_wire_end + else: + pos_wire_end_x = battery_x - 100 * scale # Wires go to the left + pos_wire_end_y = pos_wire_start_y # Negative wire (from the '-' sign at the top) neg_wire_id = '_battery_neg_wire' neg_wire_start_x = battery_x neg_wire_start_y = battery_y + 15 * scale - neg_wire_end_x = battery_x - 100 * scale # Wires go to the left - neg_wire_end_y = neg_wire_start_y + if neg_wire_end: + neg_wire_end_x, neg_wire_end_y = neg_wire_end + else: + neg_wire_end_x = battery_x - 100 * scale # Wires go to the left + neg_wire_end_y = neg_wire_start_y # Use draw_battery_wire to draw the wires with similar appearance to draw_wire # Positive wire diff --git a/menus.py b/menus.py index 1e4213a..967eaa5 100644 --- a/menus.py +++ b/menus.py @@ -13,7 +13,7 @@ from breadboard import Breadboard -from dataCDLT import INPUT, OUTPUT +from dataCDLT import INPUT, OUTPUT, USED MICROCONTROLLER_PINS = { "Arduino Mega": { @@ -117,7 +117,7 @@ def __init__( "NodeMCU ESP32" ], "Ports": ["Configure Ports"], - "Export": ["Show Correspondence Table"], + "Export": ["Correspondence Table"], "Help": ["Documentation", "About"], } @@ -344,6 +344,8 @@ def new_file(self): # Clear the canvas and reset the circuit self.board.sketcher.clear_board() self.board.fill_matrix_1260_pts() + self.board.draw_blank_board_model() + print("New file created.") messagebox.showinfo("New File", "A new circuit has been created.") @@ -363,6 +365,23 @@ def open_file(self): x_o, y_o = self.board.sketcher.id_origins["xyOrigin"] self.board.sketcher.circuit(x_o, y_o, model=[]) + battery_pos_wire_end = None + battery_neg_wire_end = None + + for key, val in circuit_data.items(): + if key == "_battery_pos_wire": + battery_pos_wire_end = val['end'] + elif key == "_battery_neg_wire": + battery_neg_wire_end = val['end'] + + # Redraw the blank board model, including the battery with wire positions + self.board.draw_blank_board_model( + x_o, + y_o, + battery_pos_wire_end=battery_pos_wire_end, + battery_neg_wire_end=battery_neg_wire_end, + ) + for key, val in circuit_data.items(): if "chip" in key: x, y = val["XY"] @@ -378,7 +397,7 @@ def open_file(self): ] self.board.sketcher.circuit(x, y, model=model_chip) - elif "wire" in key: + elif "wire" in key and not key.startswith("_battery"): model_wire = [ ( self.board.sketcher.draw_wire, @@ -433,6 +452,8 @@ def save_file(self): comp_data["label"] = comp_data["type"] if "wire" in key: comp_data.pop("XY", None) # Remove XY, will be recalculated anyway + if key == "_battery": + comp_data.pop("battery_rect", None) # Save the data to a JSON file with open(file_path, "w", encoding="utf-8") as file: json.dump(circuit_data, file, indent=4) From 5e685d98d3dfa8b6a8d77e575f888477a6618345 Mon Sep 17 00:00:00 2001 From: abbou169 Date: Tue, 19 Nov 2024 21:03:45 -0500 Subject: [PATCH 5/9] battery enhancement and bug fixes --- breadboard.py | 13 +++ component_sketch.py | 251 ++++++++++++++++++-------------------------- menus.py | 15 +-- 3 files changed, 114 insertions(+), 165 deletions(-) diff --git a/breadboard.py b/breadboard.py index 5cfa572..b35e8a3 100644 --- a/breadboard.py +++ b/breadboard.py @@ -14,6 +14,7 @@ HORIZONTAL, PERSO, VERTICAL, + USED, ) @@ -253,9 +254,21 @@ def draw_blank_board_model(self, x_origin: int = 50, y_origin: int = 10, battery battery_x = x_origin + 1200 # Adjust as needed for proper positioning battery_y = y_origin + 300 # Adjust as needed for proper positioning + + # Reset all matrix elements' states to FREE + for key in self.sketcher.matrix: + self.sketcher.matrix[key]['state'] = FREE + self.sketcher.draw_battery( battery_x, battery_y, pos_wire_end=battery_pos_wire_end, neg_wire_end=battery_neg_wire_end, ) + if battery_pos_wire_end: + allowed_positions = self.sketcher.get_power_line_last_pins() + nearest_point, nearest_point_coord = self.sketcher.find_nearest_allowed_grid_point(battery_pos_wire_end[0], battery_pos_wire_end[1], allowed_positions) + col, line = nearest_point_coord + self.sketcher.matrix[f'{col},{line}']['state'] = USED + + \ No newline at end of file diff --git a/component_sketch.py b/component_sketch.py index ad2e185..6390c21 100644 --- a/component_sketch.py +++ b/component_sketch.py @@ -9,6 +9,8 @@ from tkinter import font import math from typing import Any, Callable +from PIL import Image, ImageTk +import os @@ -2673,16 +2675,25 @@ def clear_board(self): # TODO Khalid update the Circuit instance - def draw_battery(self, x_distance, y_distance, scale=1, width=-1, direction=HORIZONTAL, pos_wire_end=None, neg_wire_end=None, **kwargs): + + + def draw_battery(self, x_distance, y_distance, scale=1, width=-1, direction='HORIZONTAL', pos_wire_end=None, neg_wire_end=None, **kwargs): """ - Draws a battery at the given coordinates with two hanging wires. + Draws a battery image at the given coordinates with two hanging wires on the left side. + + Parameters: + - x_distance (int): The x-coordinate where the battery will be drawn. + - y_distance (int): The y-coordinate where the battery will be drawn. + - scale (float): Scaling factor for the battery size. + - width (int): Specific width if needed, otherwise calculated from scale. + - direction (str): Orientation of the battery, currently only 'HORIZONTAL' is handled. + - pos_wire_end (tuple): Coordinates where the positive wire should end. + - neg_wire_end (tuple): Coordinates where the negative wire should end. + - kwargs: Additional keyword arguments. + + Returns: + - Tuple of (x_distance, y_distance) """ - if width != -1: - scale = width / 9.0 - - inter_space = 15 * scale - thickness = 1 * self.scale_factor - battery_id = '_battery' # Check if battery already exists @@ -2690,145 +2701,101 @@ def draw_battery(self, x_distance, y_distance, scale=1, width=-1, direction=HORI print("Battery already exists in the circuit.") return x_distance, y_distance - # Draw the battery as a rectangle with '+' and '-' signs - battery_width = 40 * scale - battery_height = 60 * scale - battery_x = x_distance - battery_y = y_distance - - # Draw the battery rectangle as a rounded rectangle - battery_body = self.canvas.create_rectangle( - battery_x, - battery_y + 5 * scale, - battery_x + battery_width, - battery_y + battery_height - 5 * scale, - fill='silver', - outline='black', - width=2, - tags=(battery_id,) - ) - - # Draw the positive terminal (a small rectangle at the bottom) - self.canvas.create_rectangle( - battery_x + battery_width / 3, - battery_y + battery_height - 5 * scale, - battery_x + 2 * battery_width / 3, - battery_y + battery_height, - fill='gray', - outline='black', - width=2, - tags=(battery_id,) + image_path = os.path.join('Assets', 'Icons', 'battery.png') + + if not os.path.isfile(image_path): + print(f"Battery image not found at {image_path}.") + return x_distance, y_distance + + try: + battery_image = Image.open(image_path) + + original_width, original_height = battery_image.size + new_width = int(original_width * scale * 0.7) + new_height = int(original_height * scale * 0.7) + battery_image = battery_image.resize((new_width, new_height), Image.LANCZOS) + + battery_photo = ImageTk.PhotoImage(battery_image) + + except Exception as e: + print(f"Error loading battery image: {e}") + return x_distance, y_distance + + battery_obj = self.canvas.create_image( + x_distance - 10, + y_distance, + anchor='nw', + image=battery_photo, + tags=() ) - # Draw the negative terminal (a small rectangle at the top) - self.canvas.create_rectangle( - battery_x + battery_width / 3, - battery_y, - battery_x + 2 * battery_width / 3, - battery_y + 5 * scale, - fill='gray', - outline='black', - width=2, - tags=(battery_id,) - ) - - # Optionally add text or lines to enhance the look - # For example, adding a label "5V" - self.canvas.create_text( - battery_x + battery_width / 2, - battery_y + battery_height / 2, - text='5V', - font=("Arial", int(12 * scale), 'bold'), - fill='black', - tags=(battery_id,) - ) - - # Swap positions of '+' and '-' signs - # Draw '-' sign at the top - self.canvas.create_text( - battery_x + battery_width / 2, - battery_y + 15 * scale, - text='-', - font=("Arial", int(20 * scale), 'bold'), - fill='black', - tags=(battery_id,) - ) - - # Draw '+' sign at the bottom - self.canvas.create_text( - battery_x + battery_width / 2, - battery_y + battery_height - 15 * scale, - text='+', - font=("Arial", int(20 * scale), 'bold'), - fill='black', - tags=(battery_id,) - ) - - # Store the battery in current_dict_circuit + if not hasattr(self, 'image_references'): + self.image_references = [] + self.image_references.append(battery_photo) + neg_wire_offset_x = 0 # Left edge + neg_wire_offset_y = new_height * 0.2 # 20% from the top + + pos_wire_offset_x = 0 # Left edge + pos_wire_offset_y = new_height * 0.8 + + neg_wire_start_x = x_distance + neg_wire_offset_x + neg_wire_start_y = y_distance + neg_wire_offset_y + + pos_wire_start_x = x_distance + pos_wire_offset_x + pos_wire_start_y = y_distance + pos_wire_offset_y + self.current_dict_circuit[battery_id] = { 'id': battery_id, - 'tags': [battery_id], - 'battery_rect': (battery_x, battery_y, battery_x + battery_width, battery_y + battery_height), + 'tags': [battery_id] } - # Draw wires from the left side of the battery - # Swap positions of wires - # Positive wire (from the '+' sign at the bottom) - pos_wire_id = '_battery_pos_wire' - pos_wire_start_x = battery_x - pos_wire_start_y = battery_y + battery_height - 15 * scale - if pos_wire_end: - pos_wire_end_x, pos_wire_end_y = pos_wire_end - else: - pos_wire_end_x = battery_x - 100 * scale # Wires go to the left - pos_wire_end_y = pos_wire_start_y - - # Negative wire (from the '-' sign at the top) neg_wire_id = '_battery_neg_wire' - neg_wire_start_x = battery_x - neg_wire_start_y = battery_y + 15 * scale if neg_wire_end: neg_wire_end_x, neg_wire_end_y = neg_wire_end else: - neg_wire_end_x = battery_x - 100 * scale # Wires go to the left + neg_wire_end_x = neg_wire_start_x - 100 * scale # Wires go to the left neg_wire_end_y = neg_wire_start_y - # Use draw_battery_wire to draw the wires with similar appearance to draw_wire - # Positive wire + self.draw_battery_wire( + wire_id=neg_wire_id, + start_x=neg_wire_start_x, + start_y=neg_wire_start_y, + end_x=neg_wire_end_x + 3, + end_y=neg_wire_end_y + 3, + color=(0, 0, 0), + terminal_type='neg' + ) + + pos_wire_id = '_battery_pos_wire' + if pos_wire_end: + pos_wire_end_x, pos_wire_end_y = pos_wire_end + else: + pos_wire_end_x = pos_wire_start_x - 100 * scale + pos_wire_end_y = pos_wire_start_y + self.draw_battery_wire( wire_id=pos_wire_id, start_x=pos_wire_start_x, start_y=pos_wire_start_y, - end_x=pos_wire_end_x, - end_y=pos_wire_end_y, - color=(255, 0, 0), # Red for positive + end_x=pos_wire_end_x + 3, + end_y=pos_wire_end_y + 3, + color=(255, 0, 0), terminal_type='pos' ) - # Negative wire - self.draw_battery_wire( - wire_id=neg_wire_id, - start_x=neg_wire_start_x, - start_y=neg_wire_start_y, - end_x=neg_wire_end_x, - end_y=neg_wire_end_y, - color=(0, 0, 0), # Black for negative - terminal_type='neg' - ) + self.canvas.tag_raise(battery_id) - # Update the battery's tags self.current_dict_circuit[battery_id]['tags'].extend( self.current_dict_circuit[pos_wire_id]['tags'] + self.current_dict_circuit[neg_wire_id]['tags'] ) return x_distance, y_distance - def draw_battery_wire(self, wire_id, start_x, start_y, end_x, end_y, color, terminal_type): """ Draws a battery wire with appearance similar to draw_wire, but with separate event handling. """ - # Adjusted thickness to match regular wires + thickness = 1 * self.scale_factor encre = f"#{color[0]:02x}{color[1]:02x}{color[2]:02x}" contour = f"#{max(color[0] - 100, 0):02x}{max(color[1] - 100, 0):02x}{max(color[2] - 100, 0):02x}" @@ -2837,7 +2804,7 @@ def draw_battery_wire(self, wire_id, start_x, start_y, end_x, end_y, color, term wire_body_shadow_tag = f"{wire_id}_body_shadow" endpoint_tag = f"{wire_id}_endpoint" - # Draw the shadow line + # shadow line self.canvas.create_line( start_x, start_y, @@ -2847,7 +2814,7 @@ def draw_battery_wire(self, wire_id, start_x, start_y, end_x, end_y, color, term width=8 * thickness, tags=(wire_id, wire_body_shadow_tag) ) - # Draw the main line + # main line self.canvas.create_line( start_x, start_y, @@ -2858,7 +2825,6 @@ def draw_battery_wire(self, wire_id, start_x, start_y, end_x, end_y, color, term tags=(wire_id, wire_body_tag) ) - # Adjusted radius to match regular wire endpoints radius = 2 * self.scale_factor endpoint = self.canvas.create_oval( end_x - radius, @@ -2870,7 +2836,6 @@ def draw_battery_wire(self, wire_id, start_x, start_y, end_x, end_y, color, term tags=(endpoint_tag,) ) - # Store wire data self.current_dict_circuit[wire_id] = { 'id': wire_id, 'tags': [wire_id, wire_body_tag, wire_body_shadow_tag, endpoint_tag], @@ -2881,7 +2846,6 @@ def draw_battery_wire(self, wire_id, start_x, start_y, end_x, end_y, color, term 'endpoint_tag': endpoint_tag, } - # Bind event handlers to the endpoint self.canvas.tag_bind( endpoint_tag, "", @@ -2904,7 +2868,6 @@ def create_battery_wire_endpoint(self, x, y, wire_id, terminal_type): """ endpoint_tag = f"{wire_id}_endpoint" - # Draw a small circle at the end of the wire radius = 5 endpoint = self.canvas.create_oval( x - radius, @@ -2916,7 +2879,6 @@ def create_battery_wire_endpoint(self, x, y, wire_id, terminal_type): tags=(endpoint_tag,) ) - # Bind event handlers self.canvas.tag_bind( endpoint_tag, "", @@ -2933,18 +2895,17 @@ def create_battery_wire_endpoint(self, x, y, wire_id, terminal_type): lambda event, wire_id=wire_id: self.on_battery_wire_endpoint_release(event, wire_id) ) - # Store the endpoint in current_dict_circuit self.current_dict_circuit[wire_id]['endpoint_tag'] = endpoint_tag def on_battery_wire_endpoint_click(self, event, wire_id): """ Handler for when a battery wire endpoint is clicked. """ - wire_data = self.current_dict_circuit[wire_id] - if 'connected_hole' in wire_data: - old_col, old_line = wire_data['connected_hole'] - self.matrix[f'{old_col},{old_line}']['state'] = FREE - del wire_data['connected_hole'] + allowed_positions = self.get_power_line_last_pins() + x, y = event.x, event.y + _, nearest_point_coord = self.find_nearest_grid_point(x, y) + old_col, old_line = nearest_point_coord + self.matrix[f'{old_col},{old_line}']['state'] = FREE self.battery_wire_drag_data = { 'wire_id': wire_id, } @@ -2960,14 +2921,12 @@ def on_battery_wire_endpoint_drag(self, event, wire_id): wire_data = self.current_dict_circuit[wire_id] start_x, start_y = wire_data['start'] - # Update wire lines to current mouse position wire_body_tag = f"{wire_id}_body" wire_body_shadow_tag = f"{wire_id}_body_shadow" self.canvas.coords(wire_body_shadow_tag, start_x, start_y, event.x, event.y) self.canvas.coords(wire_body_tag, start_x, start_y, event.x, event.y) - # Move the endpoint to the current mouse position endpoint_tag = wire_data['endpoint_tag'] radius = 5 * self.scale_factor self.canvas.coords( @@ -2978,55 +2937,45 @@ def on_battery_wire_endpoint_drag(self, event, wire_id): event.y + radius ) - # Update the wire data wire_data['end'] = (event.x, event.y) def on_battery_wire_endpoint_release(self, event, wire_id): """ Handler for when a battery wire endpoint is released. """ - # Snap to allowed positions allowed_positions = self.get_power_line_last_pins() x, y = event.x, event.y nearest_point, nearest_point_coord = self.find_nearest_allowed_grid_point(x, y, allowed_positions) if nearest_point_coord is None: - # No free hole found; do not update the wire's position print("No free hole available.") return - # Update wire end position to the snapped point wire_data = self.current_dict_circuit[wire_id] start_x, start_y = wire_data['start'] new_end_x, new_end_y = nearest_point - # Update wire lines wire_body_tag = f"{wire_id}_body" wire_body_shadow_tag = f"{wire_id}_body_shadow" - self.canvas.coords(wire_body_shadow_tag, start_x, start_y, new_end_x, new_end_y) - self.canvas.coords(wire_body_tag, start_x, start_y, new_end_x, new_end_y) + self.canvas.coords(wire_body_shadow_tag, start_x, start_y, new_end_x + 3, new_end_y + 3) + self.canvas.coords(wire_body_tag, start_x, start_y, new_end_x + 3, new_end_y + 3) - # Move the endpoint to the snapped position endpoint_tag = wire_data['endpoint_tag'] radius = 2 * self.scale_factor self.canvas.coords( endpoint_tag, - new_end_x - radius, - new_end_y - radius, - new_end_x + radius, - new_end_y + radius + new_end_x - radius + 3, + new_end_y - radius + 3, + new_end_x + radius + 3, + new_end_y + radius + 3 ) - # Update wire data wire_data['end'] = (new_end_x, new_end_y) - wire_data['connected_hole'] = nearest_point_coord - # Mark the hole as USED col, line = nearest_point_coord self.matrix[f'{col},{line}']['state'] = USED - # Clear drag data self.battery_wire_drag_data = {} def get_power_line_last_pins(self): @@ -3034,8 +2983,8 @@ def get_power_line_last_pins(self): Returns a list of allowed positions (x, y, col, line) for the battery wires. """ allowed_positions = [] - last_col = 61 # Adjusted based on your breadboard configuration - power_lines = [1, 2, 13, 14, 15, 16, 27, 28] # Your updated power lines + last_col = 61 + power_lines = [1, 2, 13, 14, 15, 16, 27, 28] for line in power_lines: col = last_col @@ -3059,7 +3008,7 @@ def find_nearest_allowed_grid_point(self, x, y, allowed_positions): # Check if the hole is FREE hole_state = self.matrix.get(f'{col},{line}', {}).get('state', None) if hole_state != FREE: - continue # Skip used holes + continue distance = math.hypot(x - grid_x, y - grid_y) if distance < min_distance: min_distance = distance diff --git a/menus.py b/menus.py index 967eaa5..d5655b3 100644 --- a/menus.py +++ b/menus.py @@ -100,11 +100,9 @@ def __init__( self.selected_microcontroller = None """The selected microcontroller.""" - # Create the menu bar frame (do not pack here) self.menu_bar = tk.Frame(parent, bg="#333333") """The frame containing the menu bar buttons.""" - # Define menu items and their corresponding dropdown options menus = { "File": ["New", "Open", "Save", "Exit"], "Controllers": [ @@ -121,7 +119,6 @@ def __init__( "Help": ["Documentation", "About"], } - # Mapping menu labels to their handler functions menu_commands = { "New": self.new_file, "Open": self.open_file, @@ -140,7 +137,6 @@ def __init__( "About": self.about, } - # Create each menu button and its dropdown for menu_name, options in menus.items(): self.create_menu(menu_name, options, menu_commands) @@ -358,7 +354,6 @@ def open_file(self): with open(file_path, "r", encoding="utf-8") as file: circuit_data = json.load(file) print(f"Circuit loaded from {file_path}") - # Update current_dict_circuit and redraw the circuit self.board.sketcher.clear_board() # self.zoom(self.canvas, 10.0, self.board, 50, 10, []) @@ -374,7 +369,6 @@ def open_file(self): elif key == "_battery_neg_wire": battery_neg_wire_end = val['end'] - # Redraw the blank board model, including the battery with wire positions self.board.draw_blank_board_model( x_o, y_o, @@ -440,12 +434,10 @@ def save_file(self): ) if file_path: try: - # Extract the circuit data from current_dict_circuit circuit_data = deepcopy(self.current_dict_circuit) - circuit_data.pop("last_id", None) # Remove the "last_id" key + circuit_data.pop("last_id", None) for key, comp_data in circuit_data.items(): - # Remove the "id" and "tags" keys before saving comp_data.pop("id", None) comp_data.pop("tags", None) if "label" in comp_data: @@ -485,21 +477,16 @@ def configure_ports(self): print(message) messagebox.showwarning("No COM Ports", message) else: - # Create a new top-level window for the dialog dialog = tk.Toplevel(self.parent) dialog.title("Configure Ports") - # Set the size and position of the dialog dialog.geometry("300x150") - # Create a label for the combobox label = tk.Label(dialog, text="Select an option:") label.pack(pady=10) - # Create a combobox with the options combobox = ttk.Combobox(dialog, values=options) combobox.pack(pady=10) - # Create a button to confirm the selection def confirm_selection(): selected_option = combobox.get() print(f"Selected option: {selected_option}") From 0bac7d30b02c975748abf1cc09fac958d7c62ef2 Mon Sep 17 00:00:00 2001 From: abbou169 Date: Tue, 19 Nov 2024 21:18:01 -0500 Subject: [PATCH 6/9] ajout de batterie --- Assets/Icons/battery.png | Bin 0 -> 6780 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Assets/Icons/battery.png diff --git a/Assets/Icons/battery.png b/Assets/Icons/battery.png new file mode 100644 index 0000000000000000000000000000000000000000..7cc81011c8f1e4306e349c9980ce561d2ae5e214 GIT binary patch literal 6780 zcmX|`XH*kUxW+|A0-=`>TIfw$K#&$eddG;0lqiHQy@?b72?+#(G-*l?MS4+MsFKh- zh=71}5LBv26XfQ9?>TqR*_|^Vc4lYhEx+g87`Uk(9StYVl`B{14D_|l$n6yQ#shAU zpLgK5PRR|0pP8QKm8uc$Epq3&vxbSrl`FLgz;h%exliq_Z|QgC3Vr8)H$_vD+xC?! zoJ`XZf8GpM@&EO-F08{?s_Do6Pv6rmF6%QEA$|Zr`vj>r#7)TYMV1kN)?pH zxf!inY5(c@7^}x>o{Ji*MpCioxQO>pd<>1K$&VRNyXm`b)-CmB0^$!?Ul^`=i#q29 zeg56?G96+z$(8(0@m;yH`toL5&>XGu?&!zX7Nz9=LR+xNN2Ot55|jgt>4x6^M6?5Q zHL>|hp8GVB5W4-$4)k&f1o^%dhaXhkVc-V)%-MMR&e!LflYb@^Hmr%0A**-x3133q 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 RlK&W8G0-v9uF|wc{SSp~!PEc% literal 0 HcmV?d00001 From 1bffff0a00eb9c2a854ed26bc961016e0853d7f6 Mon Sep 17 00:00:00 2001 From: Charles-Olivier Trudel Date: Tue, 19 Nov 2024 21:22:38 -0500 Subject: [PATCH 7/9] Resize main window --- arduino_logique.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arduino_logique.py b/arduino_logique.py index ba425c9..1932b75 100644 --- a/arduino_logique.py +++ b/arduino_logique.py @@ -22,7 +22,7 @@ def main(): # Creating main window win = tk.Tk() win.title("Laboratoire virtuel de circuit logique - GIF-1002") - win.geometry("1400x800") # Initial window size + win.geometry("1700x800") # Initial window size win.resizable(False, False) # Disabling window resizing win.configure(bg="#333333") # Setting consistent background color From 4b7e3d1eb76c4aa30701654515ce0d88afaaa7ca Mon Sep 17 00:00:00 2001 From: Charles-Olivier Trudel Date: Tue, 19 Nov 2024 21:25:04 -0500 Subject: [PATCH 8/9] Install pillow in lint pipeline --- .github/workflows/pylint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index 7385174..c457f8a 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -29,7 +29,7 @@ jobs: if: steps.changed-files.outputs.any_changed == 'true' run: | sudo apt-get update - sudo apt-get install -y python3-tk + sudo apt-get install -y python3-tk pillow python -m pip install --upgrade pip pip install pylint python -m pip install mypy From bb22b387dd16f7717bd0d1b79c4b586247a8dfd8 Mon Sep 17 00:00:00 2001 From: Charles-Olivier Trudel Date: Tue, 19 Nov 2024 21:26:11 -0500 Subject: [PATCH 9/9] correctly install pillow --- .github/workflows/pylint.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index c457f8a..317f41a 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -29,9 +29,9 @@ jobs: if: steps.changed-files.outputs.any_changed == 'true' run: | sudo apt-get update - sudo apt-get install -y python3-tk pillow + sudo apt-get install -y python3-tk python -m pip install --upgrade pip - pip install pylint + pip install pylint pillow python -m pip install mypy - name: Analysing the code with pylint