Skip to content

Commit 70d8fa1

Browse files
authored
Merge pull request #106 from Team-Arduino-Logique/gui_upgrades
Gui upgrades
2 parents bdf3629 + b28ccfc commit 70d8fa1

File tree

7 files changed

+81
-37
lines changed

7 files changed

+81
-37
lines changed

Assets/Icons/clock.png

2.42 KB
Loading

arduino_logique.py

Lines changed: 24 additions & 4 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,7 +28,7 @@ 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
31+
win.geometry("1500x800") # Initial window size
2832
win.resizable(False, False) # Disabling window resizing
2933
win.configure(bg="#333333") # Setting consistent background color
3034

@@ -50,7 +54,7 @@ def main():
5054
# Creating the toolbar instance
5155
toolbar = Toolbar(parent=win, canvas=canvas, sketcher=sketcher, current_dict_circuit=sketcher.current_dict_circuit)
5256
# 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))
57+
toolbar.topbar_frame.grid(row=1, column=1, sticky="ew", padx=(0, 0), pady=(0, 0))
5458

5559
# Set initial scale factor
5660
initial_scale = 1.0 # Equivalent to 10.0 / 10.0
@@ -69,6 +73,22 @@ def main():
6973
toolbar=toolbar,
7074
)
7175

76+
def toggle_sidebar():
77+
sidebar.toggle_sidebar()
78+
if sidebar.is_sidebar_visible:
79+
toggle_sidebar_btn.config(text="<<")
80+
else:
81+
toggle_sidebar_btn.config(text=">>")
82+
83+
toggle_sidebar_btn = Button(
84+
win,
85+
text="<<",
86+
command=toggle_sidebar,
87+
bg="#333333",
88+
fg="#FFFFFF",
89+
)
90+
toggle_sidebar_btn.grid(row=1, column=0, sticky="w")
91+
7292
def refresh_sidebar():
7393
sidebar.refresh()
7494
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
@@ -2764,8 +2764,8 @@ def draw_battery(
27642764
original_width = battery_photo.width()
27652765
original_height = battery_photo.height()
27662766

2767-
new_width = int(original_width * scale * 0.7)
2768-
new_height = int(original_height * scale * 0.7)
2767+
new_width = int(original_width * scale * 0.4)
2768+
new_height = int(original_height * scale * 0.4)
27692769

27702770
scale_x = new_width / original_width
27712771
scale_y = new_height / original_height
@@ -2817,8 +2817,8 @@ def draw_battery(
28172817
if neg_wire_end:
28182818
neg_wire_end_x, neg_wire_end_y = neg_wire_end
28192819
else:
2820-
neg_wire_end_x = neg_wire_start_x - 100 * scale # Wires go to the left
2821-
neg_wire_end_y = neg_wire_start_y
2820+
neg_wire_end_x = neg_wire_start_x - 50 * scale # Wires go to the left
2821+
neg_wire_end_y = neg_wire_start_y - 50 * scale # Wires go up
28222822

28232823
self.draw_battery_wire(
28242824
wire_id=neg_wire_id,
@@ -2834,8 +2834,8 @@ def draw_battery(
28342834
if pos_wire_end:
28352835
pos_wire_end_x, pos_wire_end_y = pos_wire_end
28362836
else:
2837-
pos_wire_end_x = pos_wire_start_x - 100 * scale
2838-
pos_wire_end_y = pos_wire_start_y
2837+
pos_wire_end_x = pos_wire_start_x - 50 * scale
2838+
pos_wire_end_y = pos_wire_start_y + 50 * scale # Wires go down
28392839

28402840
self.draw_battery_wire(
28412841
wire_id=pos_wire_id,

menus.py

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

124+
self.open_file_path: str | None = None
125+
"""The file path for the current open file."""
126+
124127
# Define menu items and their corresponding dropdown options
125128
menus = {
126-
"Fichier": ["Nouveau", "Ouvrir", "Enregistrer", "Quitter"],
129+
"Fichier": ["Nouveau", "Ouvrir", "Enregistrer", "Enregistrer sous", "Quitter"],
127130
"Microcontrôleur": ["Choisir un microcontrôleur", "Table de correspondance", "Configurer le port série"],
128131
"Exporter": ["Vérifier", "Téléverser"],
129132
"Aide": ["Documentation", "À propos"],
@@ -132,7 +135,8 @@ def __init__(
132135
menu_commands = {
133136
"Nouveau": self.new_file,
134137
"Ouvrir": self.open_file,
135-
"Enregistrer": self.save_file,
138+
"Enregistrer": lambda: self.save_file(False),
139+
"Enregistrer sous": self.save_file,
136140
"Quitter": self.parent.quit,
137141
"Configurer le port série": self.configure_ports,
138142
"Table de correspondance": self.show_correspondence_table,
@@ -152,12 +156,14 @@ def __init__(
152156
fg="white",
153157
font=("FiraCode-Bold", 12),
154158
)
155-
self.microcontroller_label.pack(side="right", padx=10)
159+
self.microcontroller_label.pack(side="right", fill="y", padx=175)
156160

157161
# Bind to parent to close dropdowns when clicking outside
158162
self.parent.bind("<Button-1>", self.close_dropdown, add="+")
159163
self.canvas.bind("<Button-1>", self.close_dropdown, add="+")
160164

165+
self.parent.bind("<Control-s>", lambda _: self.save_file(False), add="+")
166+
161167
def select_microcontroller(self):
162168
"""Handler for microcontroller selection."""
163169
# Create a new top-level window for the dialog
@@ -405,6 +411,7 @@ def close_dropdown(self, event):
405411
def new_file(self):
406412
"""Handler for the 'New' menu item."""
407413
# Clear the canvas and reset the circuit
414+
self.open_file_path = None
408415
self.board.sketcher.clear_board()
409416
self.board.fill_matrix_1260_pts()
410417
self.board.draw_blank_board_model()
@@ -456,6 +463,7 @@ def open_file(self):
456463

457464
print(f"Unspecified component: {key}")
458465
messagebox.showinfo("Ouvrir un fichier", f"Circuit chargé depuis {file_path}")
466+
self.open_file_path = file_path
459467
except Exception as e:
460468
print(f"Error loading file: {e}")
461469
messagebox.showerror(
@@ -521,12 +529,15 @@ def load_io(self, io_data):
521529
]
522530
self.board.sketcher.circuit(x_o, y_o, model=model_io)
523531

524-
def save_file(self):
532+
def save_file(self, prompt_for_path: bool = True):
525533
"""Handler for the 'Save' menu item."""
526534
print("Save File")
527-
file_path = filedialog.asksaveasfilename(
528-
defaultextension=".json", filetypes=[("JSON files", "*.json"), ("All files", "*.*")]
529-
)
535+
if prompt_for_path or not self.open_file_path:
536+
file_path = filedialog.asksaveasfilename(
537+
defaultextension=".json", filetypes=[("JSON files", "*.json"), ("All files", "*.*")]
538+
)
539+
else:
540+
file_path = self.open_file_path
530541
if file_path:
531542
try:
532543
circuit_data = deepcopy(self.current_dict_circuit)
@@ -546,6 +557,7 @@ def save_file(self):
546557
json.dump(circuit_data, file, indent=4)
547558
print(f"Circuit saved to {file_path}")
548559
messagebox.showinfo("Sauvegarde réussie", f"Circuit sauvegardé dans {file_path}")
560+
self.open_file_path = file_path
549561
except (TypeError, KeyError) as e:
550562
print(f"Error saving file: {e}")
551563
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)