Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified Assets/Icons/clock.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 24 additions & 4 deletions arduino_logique.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@
simulating logic circuits using Tkinter. It includes functionality to initialize a canvas,
draw a breadboard, etc.
"""

import os
from pathlib import Path
import tkinter as tk
from tkinter import font
from breadboard import Breadboard
from component_sketch import ComponentSketcher
from menus import Menus
from sidebar import Sidebar
from toolbar import Toolbar
from utils import resource_path

if os.name == "darwin" or os.name == "posix":
from tkinter import font
from tkmacosx import Button # type: ignore
else:
from tkinter import Button, font

def main():
"""
Expand All @@ -24,7 +28,7 @@ def main():
# Creating main window
win = tk.Tk()
win.title("Laboratoire virtuel de circuit logique - GIF-1002")
win.geometry("1700x800") # Initial window size
win.geometry("1500x800") # Initial window size
win.resizable(False, False) # Disabling window resizing
win.configure(bg="#333333") # Setting consistent background color

Expand All @@ -50,7 +54,7 @@ def main():
# Creating the toolbar instance
toolbar = Toolbar(parent=win, canvas=canvas, sketcher=sketcher, current_dict_circuit=sketcher.current_dict_circuit)
# Placing the secondary top bar in row=1, column=1 (spanning only the canvas area)
toolbar.topbar_frame.grid(row=1, column=1, sticky="ew", padx=(0, 10), pady=(0, 0))
toolbar.topbar_frame.grid(row=1, column=1, sticky="ew", padx=(0, 0), pady=(0, 0))

# Set initial scale factor
initial_scale = 1.0 # Equivalent to 10.0 / 10.0
Expand All @@ -69,6 +73,22 @@ def main():
toolbar=toolbar,
)

def toggle_sidebar():
sidebar.toggle_sidebar()
if sidebar.is_sidebar_visible:
toggle_sidebar_btn.config(text="<<")
else:
toggle_sidebar_btn.config(text=">>")

toggle_sidebar_btn = Button(
win,
text="<<",
command=toggle_sidebar,
bg="#333333",
fg="#FFFFFF",
)
toggle_sidebar_btn.grid(row=1, column=0, sticky="w")

def refresh_sidebar():
sidebar.refresh()
win.after(5000, refresh_sidebar)
Expand Down
2 changes: 1 addition & 1 deletion breadboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def draw_blank_board_model(self, x_origin: int = 50, y_origin: int = 10, battery
]
self.sketcher.circuit(x_origin, y_origin, scale=self.sketcher.scale_factor, model=blank_board_model)

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

# Reset all matrix elements' states to FREE
Expand Down
12 changes: 6 additions & 6 deletions component_sketch.py
Original file line number Diff line number Diff line change
Expand Up @@ -2764,8 +2764,8 @@ def draw_battery(
original_width = battery_photo.width()
original_height = battery_photo.height()

new_width = int(original_width * scale * 0.7)
new_height = int(original_height * scale * 0.7)
new_width = int(original_width * scale * 0.4)
new_height = int(original_height * scale * 0.4)

scale_x = new_width / original_width
scale_y = new_height / original_height
Expand Down Expand Up @@ -2817,8 +2817,8 @@ def draw_battery(
if neg_wire_end:
neg_wire_end_x, neg_wire_end_y = neg_wire_end
else:
neg_wire_end_x = neg_wire_start_x - 100 * scale # Wires go to the left
neg_wire_end_y = neg_wire_start_y
neg_wire_end_x = neg_wire_start_x - 50 * scale # Wires go to the left
neg_wire_end_y = neg_wire_start_y - 50 * scale # Wires go up

self.draw_battery_wire(
wire_id=neg_wire_id,
Expand All @@ -2834,8 +2834,8 @@ def draw_battery(
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
pos_wire_end_x = pos_wire_start_x - 50 * scale
pos_wire_end_y = pos_wire_start_y + 50 * scale # Wires go down

self.draw_battery_wire(
wire_id=pos_wire_id,
Expand Down
26 changes: 19 additions & 7 deletions menus.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,12 @@ def __init__(
self.serial_port = SerialPort(None, 115200, 1, None)
"""The serial port configuration."""

self.open_file_path: str | None = None
"""The file path for the current open file."""

# Define menu items and their corresponding dropdown options
menus = {
"Fichier": ["Nouveau", "Ouvrir", "Enregistrer", "Quitter"],
"Fichier": ["Nouveau", "Ouvrir", "Enregistrer", "Enregistrer sous", "Quitter"],
"Microcontrôleur": ["Choisir un microcontrôleur", "Table de correspondance", "Configurer le port série"],
"Exporter": ["Vérifier", "Téléverser"],
"Aide": ["Documentation", "À propos"],
Expand All @@ -132,7 +135,8 @@ def __init__(
menu_commands = {
"Nouveau": self.new_file,
"Ouvrir": self.open_file,
"Enregistrer": self.save_file,
"Enregistrer": lambda: self.save_file(False),
"Enregistrer sous": self.save_file,
"Quitter": self.parent.quit,
"Configurer le port série": self.configure_ports,
"Table de correspondance": self.show_correspondence_table,
Expand All @@ -152,12 +156,14 @@ def __init__(
fg="white",
font=("FiraCode-Bold", 12),
)
self.microcontroller_label.pack(side="right", padx=10)
self.microcontroller_label.pack(side="right", fill="y", padx=175)

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

self.parent.bind("<Control-s>", lambda _: self.save_file(False), add="+")

def select_microcontroller(self):
"""Handler for microcontroller selection."""
# Create a new top-level window for the dialog
Expand Down Expand Up @@ -405,6 +411,7 @@ def close_dropdown(self, event):
def new_file(self):
"""Handler for the 'New' menu item."""
# Clear the canvas and reset the circuit
self.open_file_path = None
self.board.sketcher.clear_board()
self.board.fill_matrix_1260_pts()
self.board.draw_blank_board_model()
Expand Down Expand Up @@ -456,6 +463,7 @@ def open_file(self):

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

def save_file(self):
def save_file(self, prompt_for_path: bool = True):
"""Handler for the 'Save' menu item."""
print("Save File")
file_path = filedialog.asksaveasfilename(
defaultextension=".json", filetypes=[("JSON files", "*.json"), ("All files", "*.*")]
)
if prompt_for_path or not self.open_file_path:
file_path = filedialog.asksaveasfilename(
defaultextension=".json", filetypes=[("JSON files", "*.json"), ("All files", "*.*")]
)
else:
file_path = self.open_file_path
if file_path:
try:
circuit_data = deepcopy(self.current_dict_circuit)
Expand All @@ -546,6 +557,7 @@ def save_file(self):
json.dump(circuit_data, file, indent=4)
print(f"Circuit saved to {file_path}")
messagebox.showinfo("Sauvegarde réussie", f"Circuit sauvegardé dans {file_path}")
self.open_file_path = file_path
except (TypeError, KeyError) as e:
print(f"Error saving file: {e}")
messagebox.showerror(
Expand Down
31 changes: 20 additions & 11 deletions sidebar.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,26 +78,35 @@ def __init__(
self.saved_bindings: dict[str, Callable] = {}

# Creating the sidebar frame
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
self.sidebar_frame = tk.Frame(parent, bg="#333333", width=275, bd=0, highlightthickness=0)
self.sidebar_frame.grid(row=2, column=0, sticky="nsew", padx=0, pady=0)
self.sidebar_frame.grid_propagate(False) # Preventing frame from resizing

self.is_sidebar_visible = True

# Configuring grid weights for the sidebar
sidebar_frame.grid_rowconfigure(0, weight=0) # Search bar
sidebar_frame.grid_rowconfigure(1, weight=0) # Chips label
sidebar_frame.grid_rowconfigure(2, weight=8) # Chips area (80%)
sidebar_frame.grid_rowconfigure(3, weight=0) # Manage button
sidebar_frame.grid_columnconfigure(0, weight=1)
self.sidebar_frame.grid_rowconfigure(0, weight=0) # Search bar
self.sidebar_frame.grid_rowconfigure(1, weight=0) # Chips label
self.sidebar_frame.grid_rowconfigure(2, weight=8) # Chips area (80%)
self.sidebar_frame.grid_rowconfigure(3, weight=0) # Manage button
self.sidebar_frame.grid_columnconfigure(0, weight=1)

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

# Creating sidebar components
self.create_search_bar(sidebar_frame)
self.create_chips_area(sidebar_frame)
self.create_manage_button(sidebar_frame)
self.create_search_bar(self.sidebar_frame)
self.create_chips_area(self.sidebar_frame)
self.create_manage_button(self.sidebar_frame)

self.chip_files_mtimes = get_chip_modification_times()

def toggle_sidebar(self):
if self.is_sidebar_visible:
self.sidebar_frame.grid_remove()
else:
self.sidebar_frame.grid()
self.is_sidebar_visible = not self.is_sidebar_visible

def initialize_chip_data(self, current_dict_circuit, chip_images_path) -> None:
"""
Initializes the chip data for the sidebar.
Expand Down
19 changes: 11 additions & 8 deletions toolbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from dataclasses import dataclass
from pathlib import Path
import tkinter as tk
from idlelib.tooltip import Hovertip # type: ignore

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

# Create left and right subframes
left_frame = tk.Frame(self.topbar_frame, bg="#505050")
left_frame.pack(side=tk.LEFT, padx=5, pady=5)
left_frame.pack(side=tk.LEFT, padx=50, pady=5)

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

# Load images
images = self.load_images()

# Create buttons in the left frame
self.create_button("Connection", left_frame, images)
self.create_button("Connection", left_frame, images, "Ajouter une connexion")
# self.create_button("Power", left_frame, images) # à ajouter après si besoin
self.create_button("Input", left_frame, images)
self.create_button("Output", left_frame, images)
self.create_button("Clock", left_frame, images)
self.create_button("Input", left_frame, images, "Ajouter une entrée")
self.create_button("Output", left_frame, images, "Ajouter une sortie")
self.create_button("Clock", left_frame, images, "Ajouter une horloge")

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

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

return images

def create_button(self, action: str, parent_frame: tk.Frame, images: dict[str, tk.PhotoImage | None]) -> None:
def create_button(self, action: str, parent_frame: tk.Frame, images: dict[str, tk.PhotoImage | None], hovertext: str) -> None:
"""
Helper method to create a button in the specified frame with an icon.

Expand Down Expand Up @@ -164,6 +166,7 @@ def create_button(self, action: str, parent_frame: tk.Frame, images: dict[str, t
borderwidth=0,
highlightthickness=0,
)
Hovertip(btn, hovertext, 500)
btn.pack(side=tk.LEFT, padx=10, pady=2) # Minimal spacing between buttons
self.buttons[action] = btn # Store button reference

Expand Down
Loading