Skip to content

Commit a4b746c

Browse files
committed
Merge branch 'master' of github.com:Team-Arduino-Logique/Arduino-Logique into generate_script
2 parents d08169e + c3436a4 commit a4b746c

File tree

7 files changed

+83
-38
lines changed

7 files changed

+83
-38
lines changed

Assets/Icons/clock.png

2.42 KB
Loading

arduino_logique.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,21 @@
44
simulating logic circuits using Tkinter. It includes functionality to initialize a canvas,
55
draw a breadboard, etc.
66
"""
7-
7+
import os
88
from pathlib import Path
99
import tkinter as tk
10-
from tkinter import font
1110
from breadboard import Breadboard
1211
from component_sketch import ComponentSketcher
1312
from menus import Menus
1413
from sidebar import Sidebar
1514
from toolbar import Toolbar
1615
from utils import resource_path
1716

17+
if os.name == "darwin" or os.name == "posix":
18+
from tkinter import font
19+
from tkmacosx import Button # type: ignore
20+
else:
21+
from tkinter import Button, font
1822

1923
def main():
2024
"""
@@ -24,8 +28,9 @@ def main():
2428
# Creating main window
2529
win = tk.Tk()
2630
win.title("Laboratoire virtuel de circuit logique - GIF-1002")
27-
win.geometry("1700x800") # Initial window size
28-
win.resizable(False, False) # Disabling window resizing
31+
win.geometry("1500x800") # Initial window size
32+
win.minsize(1500, 800) # Set minimal window size
33+
win.resizable(True, True) # Disabling window resizing
2934
win.configure(bg="#333333") # Setting consistent background color
3035

3136
# Configuring grid layout for the main window
@@ -50,7 +55,7 @@ def main():
5055
# Creating the toolbar instance
5156
toolbar = Toolbar(parent=win, canvas=canvas, sketcher=sketcher, current_dict_circuit=sketcher.current_dict_circuit)
5257
# Placing the secondary top bar in row=1, column=1 (spanning only the canvas area)
53-
toolbar.topbar_frame.grid(row=1, column=1, sticky="ew", padx=(0, 10), pady=(0, 0))
58+
toolbar.topbar_frame.grid(row=1, column=1, sticky="ew", padx=(0, 0), pady=(0, 0))
5459

5560
# Set initial scale factor
5661
initial_scale = 1.0 # Equivalent to 10.0 / 10.0
@@ -69,6 +74,22 @@ def main():
6974
toolbar=toolbar,
7075
)
7176

77+
def toggle_sidebar():
78+
sidebar.toggle_sidebar()
79+
if sidebar.is_sidebar_visible:
80+
toggle_sidebar_btn.config(text="<<")
81+
else:
82+
toggle_sidebar_btn.config(text=">>")
83+
84+
toggle_sidebar_btn = Button(
85+
win,
86+
text="<<",
87+
command=toggle_sidebar,
88+
bg="#333333",
89+
fg="#FFFFFF",
90+
)
91+
toggle_sidebar_btn.grid(row=1, column=0, sticky="w")
92+
7293
def refresh_sidebar():
7394
sidebar.refresh()
7495
win.after(5000, refresh_sidebar)

breadboard.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ def draw_blank_board_model(self, x_origin: int = 50, y_origin: int = 10, battery
225225
]
226226
self.sketcher.circuit(x_origin, y_origin, scale=self.sketcher.scale_factor, model=blank_board_model)
227227

228-
battery_x = x_origin + 1200 # Adjust as needed for proper positioning
228+
battery_x = x_origin + 1050 # Adjust as needed for proper positioning
229229
battery_y = y_origin + 300 # Adjust as needed for proper positioning
230230

231231
# Reset all matrix elements' states to FREE

component_sketch.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2795,8 +2795,8 @@ def draw_battery(
27952795
original_width = battery_photo.width()
27962796
original_height = battery_photo.height()
27972797

2798-
new_width = int(original_width * scale * 0.7)
2799-
new_height = int(original_height * scale * 0.7)
2798+
new_width = int(original_width * scale * 0.4)
2799+
new_height = int(original_height * scale * 0.4)
28002800

28012801
scale_x = new_width / original_width
28022802
scale_y = new_height / original_height
@@ -2848,8 +2848,8 @@ def draw_battery(
28482848
if neg_wire_end:
28492849
neg_wire_end_x, neg_wire_end_y = neg_wire_end
28502850
else:
2851-
neg_wire_end_x = neg_wire_start_x - 100 * scale # Wires go to the left
2852-
neg_wire_end_y = neg_wire_start_y
2851+
neg_wire_end_x = neg_wire_start_x - 50 * scale # Wires go to the left
2852+
neg_wire_end_y = neg_wire_start_y - 50 * scale # Wires go up
28532853

28542854
self.draw_battery_wire(
28552855
wire_id=neg_wire_id,
@@ -2865,8 +2865,8 @@ def draw_battery(
28652865
if pos_wire_end:
28662866
pos_wire_end_x, pos_wire_end_y = pos_wire_end
28672867
else:
2868-
pos_wire_end_x = pos_wire_start_x - 100 * scale
2869-
pos_wire_end_y = pos_wire_start_y
2868+
pos_wire_end_x = pos_wire_start_x - 50 * scale
2869+
pos_wire_end_y = pos_wire_start_y + 50 * scale # Wires go down
28702870

28712871
self.draw_battery_wire(
28722872
wire_id=pos_wire_id,

menus.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,12 @@ def __init__(
147147
self.serial_port = SerialPort(None, 115200, 1, None)
148148
"""The serial port configuration."""
149149

150+
self.open_file_path: str | None = None
151+
"""The file path for the current open file."""
152+
150153
# Define menu items and their corresponding dropdown options
151154
menus = {
152-
"Fichier": ["Nouveau", "Ouvrir", "Enregistrer", "Quitter"],
155+
"Fichier": ["Nouveau", "Ouvrir", "Enregistrer", "Enregistrer sous", "Quitter"],
153156
"Microcontrôleur": ["Choisir un microcontrôleur", "Table de correspondance", "Configurer le port série"],
154157
"Circuit": [
155158
"Vérifier",
@@ -161,7 +164,8 @@ def __init__(
161164
menu_commands = {
162165
"Nouveau": self.new_file,
163166
"Ouvrir": self.open_file,
164-
"Enregistrer": self.save_file,
167+
"Enregistrer": lambda: self.save_file(False),
168+
"Enregistrer sous": self.save_file,
165169
"Quitter": self.parent.quit,
166170
"Configurer le port série": self.configure_ports,
167171
"Table de correspondance": self.show_correspondence_table,
@@ -183,12 +187,14 @@ def __init__(
183187
fg="white",
184188
font=("FiraCode-Bold", 12),
185189
)
186-
self.microcontroller_label.pack(side="right", padx=10)
190+
self.microcontroller_label.pack(side="right", fill="y", padx=175)
187191

188192
# Bind to parent to close dropdowns when clicking outside
189193
self.parent.bind("<Button-1>", self.close_dropdown, add="+")
190194
self.canvas.bind("<Button-1>", self.close_dropdown, add="+")
191195

196+
self.parent.bind("<Control-s>", lambda _: self.save_file(False), add="+")
197+
192198
def select_microcontroller(self):
193199
"""Handler for microcontroller selection."""
194200
# Create a new top-level window for the dialog
@@ -472,6 +478,7 @@ def close_dropdown(self, event):
472478
def new_file(self):
473479
"""Handler for the 'New' menu item."""
474480
# Clear the canvas and reset the circuit
481+
self.open_file_path = None
475482
self.board.sketcher.clear_board()
476483
self.board.fill_matrix_1260_pts()
477484
self.board.draw_blank_board_model()
@@ -523,6 +530,7 @@ def open_file(self):
523530

524531
print(f"Unspecified component: {key}")
525532
messagebox.showinfo("Ouvrir un fichier", f"Circuit chargé depuis {file_path}")
533+
self.open_file_path = file_path
526534
except Exception as e:
527535
print(f"Error loading file: {e}")
528536
messagebox.showerror(
@@ -588,12 +596,15 @@ def load_io(self, io_data):
588596
]
589597
self.board.sketcher.circuit(x_o, y_o, model=model_io)
590598

591-
def save_file(self):
599+
def save_file(self, prompt_for_path: bool = True):
592600
"""Handler for the 'Save' menu item."""
593601
print("Save File")
594-
file_path = filedialog.asksaveasfilename(
595-
defaultextension=".json", filetypes=[("JSON files", "*.json"), ("All files", "*.*")]
596-
)
602+
if prompt_for_path or not self.open_file_path:
603+
file_path = filedialog.asksaveasfilename(
604+
defaultextension=".json", filetypes=[("JSON files", "*.json"), ("All files", "*.*")]
605+
)
606+
else:
607+
file_path = self.open_file_path
597608
if file_path:
598609
try:
599610
circuit_data = deepcopy(self.current_dict_circuit)
@@ -613,6 +624,7 @@ def save_file(self):
613624
json.dump(circuit_data, file, indent=4)
614625
print(f"Circuit saved to {file_path}")
615626
messagebox.showinfo("Sauvegarde réussie", f"Circuit sauvegardé dans {file_path}")
627+
self.open_file_path = file_path
616628
except (TypeError, KeyError) as e:
617629
print(f"Error saving file: {e}")
618630
messagebox.showerror(

sidebar.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,26 +78,35 @@ def __init__(
7878
self.saved_bindings: dict[str, Callable] = {}
7979

8080
# Creating the sidebar frame
81-
sidebar_frame = tk.Frame(parent, bg="#333333", width=275, bd=0, highlightthickness=0)
82-
sidebar_frame.grid(row=2, column=0, sticky="nsew", padx=0, pady=0)
83-
sidebar_frame.grid_propagate(False) # Preventing frame from resizing
81+
self.sidebar_frame = tk.Frame(parent, bg="#333333", width=275, bd=0, highlightthickness=0)
82+
self.sidebar_frame.grid(row=2, column=0, sticky="nsew", padx=0, pady=0)
83+
self.sidebar_frame.grid_propagate(False) # Preventing frame from resizing
84+
85+
self.is_sidebar_visible = True
8486

8587
# Configuring grid weights for the sidebar
86-
sidebar_frame.grid_rowconfigure(0, weight=0) # Search bar
87-
sidebar_frame.grid_rowconfigure(1, weight=0) # Chips label
88-
sidebar_frame.grid_rowconfigure(2, weight=8) # Chips area (80%)
89-
sidebar_frame.grid_rowconfigure(3, weight=0) # Manage button
90-
sidebar_frame.grid_columnconfigure(0, weight=1)
88+
self.sidebar_frame.grid_rowconfigure(0, weight=0) # Search bar
89+
self.sidebar_frame.grid_rowconfigure(1, weight=0) # Chips label
90+
self.sidebar_frame.grid_rowconfigure(2, weight=8) # Chips area (80%)
91+
self.sidebar_frame.grid_rowconfigure(3, weight=0) # Manage button
92+
self.sidebar_frame.grid_columnconfigure(0, weight=1)
9193

9294
self.sidebar_grid = SidebarGrid(columns=2, visible_rows=12, grid_capacity=24)
9395

9496
# Creating sidebar components
95-
self.create_search_bar(sidebar_frame)
96-
self.create_chips_area(sidebar_frame)
97-
self.create_manage_button(sidebar_frame)
97+
self.create_search_bar(self.sidebar_frame)
98+
self.create_chips_area(self.sidebar_frame)
99+
self.create_manage_button(self.sidebar_frame)
98100

99101
self.chip_files_mtimes = get_chip_modification_times()
100102

103+
def toggle_sidebar(self):
104+
if self.is_sidebar_visible:
105+
self.sidebar_frame.grid_remove()
106+
else:
107+
self.sidebar_frame.grid()
108+
self.is_sidebar_visible = not self.is_sidebar_visible
109+
101110
def initialize_chip_data(self, current_dict_circuit, chip_images_path) -> None:
102111
"""
103112
Initializes the chip data for the sidebar.

toolbar.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from dataclasses import dataclass
1010
from pathlib import Path
1111
import tkinter as tk
12+
from idlelib.tooltip import Hovertip # type: ignore
1213

1314
from component_sketch import ComponentSketcher
1415
from dataCDLT import INPUT, OUTPUT, FREE, CLOCK
@@ -67,20 +68,20 @@ def create_topbar(self, parent: tk.Tk):
6768

6869
# Create left and right subframes
6970
left_frame = tk.Frame(self.topbar_frame, bg="#505050")
70-
left_frame.pack(side=tk.LEFT, padx=5, pady=5)
71+
left_frame.pack(side=tk.LEFT, padx=50, pady=5)
7172

7273
right_frame = tk.Frame(self.topbar_frame, bg="#505050")
73-
right_frame.pack(side=tk.RIGHT, padx=5, pady=5)
74+
right_frame.pack(after=left_frame, side=tk.LEFT, padx=100, pady=5)
7475

7576
# Load images
7677
images = self.load_images()
7778

7879
# Create buttons in the left frame
79-
self.create_button("Connection", left_frame, images)
80+
self.create_button("Connection", left_frame, images, "Ajouter une connexion")
8081
# self.create_button("Power", left_frame, images) # à ajouter après si besoin
81-
self.create_button("Input", left_frame, images)
82-
self.create_button("Output", left_frame, images)
83-
self.create_button("Clock", left_frame, images)
82+
self.create_button("Input", left_frame, images, "Ajouter une entrée")
83+
self.create_button("Output", left_frame, images, "Ajouter une sortie")
84+
self.create_button("Clock", left_frame, images, "Ajouter une horloge")
8485

8586
# Create the color chooser and Delete button in the right frame
8687
self.color_button = Button(
@@ -94,8 +95,9 @@ def create_topbar(self, parent: tk.Tk):
9495
borderwidth=0,
9596
highlightthickness=0,
9697
)
98+
Hovertip(self.color_button, "Choisir une couleur pour les composantes", 500)
9799
self.color_button.pack(side=tk.LEFT, padx=2, pady=2)
98-
self.create_button("Delete", right_frame, images)
100+
self.create_button("Delete", right_frame, images, "Supprimer un composant")
99101

100102
def load_images(self) -> dict[str, tk.PhotoImage | None]:
101103
"""
@@ -123,7 +125,7 @@ def load_images(self) -> dict[str, tk.PhotoImage | None]:
123125

124126
return images
125127

126-
def create_button(self, action: str, parent_frame: tk.Frame, images: dict[str, tk.PhotoImage | None]) -> None:
128+
def create_button(self, action: str, parent_frame: tk.Frame, images: dict[str, tk.PhotoImage | None], hovertext: str) -> None:
127129
"""
128130
Helper method to create a button in the specified frame with an icon.
129131
@@ -164,6 +166,7 @@ def create_button(self, action: str, parent_frame: tk.Frame, images: dict[str, t
164166
borderwidth=0,
165167
highlightthickness=0,
166168
)
169+
Hovertip(btn, hovertext, 500)
167170
btn.pack(side=tk.LEFT, padx=10, pady=2) # Minimal spacing between buttons
168171
self.buttons[action] = btn # Store button reference
169172

0 commit comments

Comments
 (0)