diff --git a/.github/workflows/release_pipeline.yml b/.github/workflows/release_pipeline.yml index 0e1c171..9ec7c95 100644 --- a/.github/workflows/release_pipeline.yml +++ b/.github/workflows/release_pipeline.yml @@ -9,34 +9,6 @@ on: - master jobs: - build-macos: - runs-on: macos-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.x' - - - name: Install PyInstaller - run: pip install pyinstaller pyserial - - - name: Build with PyInstaller - run: pyinstaller arduino_logique.spec - - - name: Compress the build - run: | - cd dist - tar -czvf arduino_logique_macos.tar.gz arduino_logique - - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: macos-build - path: dist/arduino_logique_macos.tar.gz - build-ubuntu: runs-on: ubuntu-latest steps: @@ -92,7 +64,7 @@ jobs: path: arduino_logique_windows.zip release: - needs: [build-macos, build-ubuntu, build-windows] + needs: [build-ubuntu, build-windows] runs-on: ubuntu-latest permissions: contents: write @@ -102,12 +74,6 @@ jobs: with: fetch-depth: 0 - - name: Download macOS build - uses: actions/download-artifact@v3 - with: - name: macos-build - path: ./dist/ - - name: Download Ubuntu build uses: actions/download-artifact@v3 with: @@ -132,7 +98,7 @@ jobs: - name: Create release uses: ncipollo/release-action@v1 with: - artifacts: "./dist/arduino_logique_macos.tar.gz,./dist/arduino_logique_ubuntu.tar.gz,./dist/arduino_logique_windows.zip" + artifacts: "./dist/arduino_logique_ubuntu.tar.gz,./dist/arduino_logique_windows.zip" token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ steps.bump.outputs.new_tag }} makeLatest: ${{ !contains(steps.bump.outputs.new_tag, 'beta') }} diff --git a/Assets/Icons/clock.png b/Assets/Icons/clock.png new file mode 100644 index 0000000..3c01ef4 Binary files /dev/null and b/Assets/Icons/clock.png differ diff --git a/menus.py b/menus.py index 9211d76..fdded35 100644 --- a/menus.py +++ b/menus.py @@ -8,16 +8,20 @@ from dataclasses import dataclass import os import tkinter as tk -from tkinter import messagebox, filedialog, ttk import json import subprocess import platform -from typing import Callable import serial.tools.list_ports # type: ignore from breadboard import Breadboard -from dataCDLT import INPUT, OUTPUT, USED, CLOCK +from dataCDLT import INPUT, OUTPUT, CLOCK + +if os.name == "darwin": + from tkinter import messagebox, filedialog, ttk + from tkmacosx import Button # type: ignore +else: + from tkinter import Button, messagebox, filedialog, ttk MICROCONTROLLER_PINS = { "Arduino Mega": { @@ -169,6 +173,7 @@ def select_microcontroller(self): available_microcontrollers = list(MICROCONTROLLER_PINS.keys()) # Create a combobox with the options combobox = ttk.Combobox(dialog, values=available_microcontrollers) + combobox.set(self.selected_microcontroller if self.selected_microcontroller else "Choisir un microcontrôleur") combobox.pack(pady=10) # Create a button to confirm the selection @@ -181,13 +186,15 @@ def confirm_selection(): self.microcontroller_label.config(text=self.selected_microcontroller) dialog.destroy() - confirm_button = tk.Button(dialog, text="Confirmer", command=confirm_selection) + confirm_button = Button(dialog, text="Confirmer", command=confirm_selection) confirm_button.pack(pady=10) def show_correspondence_table(self): """Displays the correspondence table between pin_io objects and microcontroller pins in a table format.""" if self.selected_microcontroller is None: - messagebox.showwarning("Aucun microcontrôleur sélectionné", "Veuillez d'abord sélectionner un microcontrôleur.") + messagebox.showwarning( + "Aucun microcontrôleur sélectionné", "Veuillez d'abord sélectionner un microcontrôleur." + ) return pin_mappings = MICROCONTROLLER_PINS.get(self.selected_microcontroller) @@ -279,7 +286,7 @@ def create_menu(self, menu_name, options, menu_commands): - options (list): List of options under the menu. """ # Create the menu button - btn = tk.Button( + btn = Button( self.menu_bar, text=menu_name, bg="#333333", @@ -312,7 +319,7 @@ def select_menu_item(option): # Populate the dropdown with menu options for option in options: - option_btn = tk.Button( + option_btn = Button( dropdown, text=option, bg="#333333", @@ -343,7 +350,7 @@ def toggle_dropdown(self, menu_name): - menu_name (str): The name of the menu to toggle. """ for child in self.menu_bar.winfo_children(): - if isinstance(child, tk.Button) and hasattr(child, "dropdown"): + if isinstance(child, Button) and hasattr(child, "dropdown"): if child["text"] == menu_name: if child.dropdown.winfo_ismapped(): child.dropdown.place_forget() @@ -387,11 +394,11 @@ def close_dropdown(self, event): and not any( self.is_descendant(event.widget, child.dropdown) for child in self.menu_bar.winfo_children() - if isinstance(child, tk.Button) and hasattr(child, "dropdown") + if isinstance(child, Button) and hasattr(child, "dropdown") ) ): for child in self.menu_bar.winfo_children(): - if isinstance(child, tk.Button) and hasattr(child, "dropdown"): + if isinstance(child, Button) and hasattr(child, "dropdown"): child.dropdown.place_forget() # Menu Handler Functions @@ -424,9 +431,9 @@ def open_file(self): for key, val in circuit_data.items(): if key == "_battery_pos_wire": - battery_pos_wire_end = val['end'] + battery_pos_wire_end = val["end"] elif key == "_battery_neg_wire": - battery_neg_wire_end = val['end'] + battery_neg_wire_end = val["end"] self.board.draw_blank_board_model( x_o, @@ -451,7 +458,9 @@ def open_file(self): messagebox.showinfo("Ouvrir un fichier", f"Circuit chargé depuis {file_path}") except Exception as e: print(f"Error loading file: {e}") - messagebox.showerror("Erreur d'ouverture", f"Une erreur s'est produite lors de l'ouverture du fichier:\n{e}") + messagebox.showerror( + "Erreur d'ouverture", f"Une erreur s'est produite lors de l'ouverture du fichier:\n{e}" + ) raise e else: print("Open file cancelled.") @@ -529,7 +538,7 @@ def save_file(self): if "label" in comp_data: comp_data["label"] = comp_data["type"] if "wire" in key: - comp_data.pop("XY", None) # Remove XY, will be recalculated anyway + 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 @@ -539,7 +548,9 @@ def save_file(self): messagebox.showinfo("Sauvegarde réussie", f"Circuit sauvegardé dans {file_path}") except (TypeError, KeyError) as e: print(f"Error saving file: {e}") - messagebox.showerror("Erreur de sauvegarde", f"Une erreur s'est produite lors de la sauvegarde du fichier:\n{e}") + messagebox.showerror( + "Erreur de sauvegarde", f"Une erreur s'est produite lors de la sauvegarde du fichier:\n{e}" + ) else: print("Save file cancelled.") @@ -568,7 +579,7 @@ def confirm_selection(): self.serial_port.com_port = selected_option dialog.destroy() - confirm_button = tk.Button(dialog, text="Confirm", command=confirm_selection) + confirm_button = Button(dialog, text="Confirm", command=confirm_selection) confirm_button.pack(pady=10) def open_documentation(self): diff --git a/readme.md b/readme.md index e1a322c..e795a7d 100644 --- a/readme.md +++ b/readme.md @@ -13,16 +13,47 @@ ## Contents - [Installation Instructions (English)](#installation-instructions) + - [MacOS installation](#macos-installation) - [Windows installation](#windows-installation) - [Microcontroller](#microcontroller) - [Instructions d'installation (Français)](#instructions-dinstallation) - - [Microcontrôleur](#microcontrôleur) + - [Installation sur MacOS](#installation-sur-macos) - [Installation sur Windows](#installation-sur-windows) + - [Microcontrôleur](#microcontrôleur) ## Installation Instructions Please go to the [release page](https://github.com/Team-Arduino-Logique/Arduino-Logique/releases) and download the latest release for your operating system. +### MacOS installation + +#### Prerequisites for macOS + +1. Install Python 3. +2. Install the required Python packages: + - pyserial + - tkmacosx + +You can install the packages using pip: + +```sh +pip install pyserial tkmacosx +``` + +To download the source code, click on the green `<> Code` button at the top of this page and select "Download Zip". + +You can also clone the repository using git. Open a terminal and run the following command: + +```sh +git clone https://github.com/Team-Arduino-Logique/Arduino-Logique.git +``` + +This will create a local copy of the repository on your machine. + +#### Running `arduino_logique.py` on MacOS + +After installing the prerequisites, you can run the `arduino_logique.py` script. + ### Windows installation Windows Defender will warn you about an unverified program. You can still execute it by clicking "More information", then "Continue". @@ -35,12 +66,41 @@ Windows Defender will warn you about an unverified program. You can still execut Veuillez vous rendre sur la [page des versions](https://github.com/Team-Arduino-Logique/Arduino-Logique/releases) et télécharger la dernière version pour votre système d'exploitation. -### Microcontrôleur +### Installation sur MacOS -#### TODO instructions pour microcontrôleur +#### Prérequis pour macOS + +1. Installez Python 3. +2. Installez les packages Python requis : + - pyserial + - tkmacosx + +Vous pouvez installer les packages en utilisant pip : + +```sh +pip install pyserial tkmacosx +``` + +Pour télécharger le code source, cliquez sur le bouton vert `<> Code` en haut de cette page et choisir "Download Zip". + +Vous pouvez aussi cloner le dépôt en utilisant git. Ouvrez un terminal et exécutez la commande suivante : + +```sh +git clone https://github.com/Team-Arduino-Logique/Arduino-Logique.git +``` + +Cela créera une copie locale du dépôt sur votre machine. + +#### Exécution de `arduino_logique.py` sur MacOS + +Après avoir installé les prérequis, vous pouvez exécuter le script `arduino_logique.py`. ### Installation sur Windows Lors de l'installation sur Windows, un avertissement de sécurité peut apparaître. Pour continuer, cliquez sur "Informations complémentaires", puis sélectionnez "Exécuter quand même". -![Avertissement de sécurité Windows](docs/images/defender-warning-french.png) \ No newline at end of file +![Avertissement de sécurité Windows](docs/images/defender-warning-french.png) + +### Microcontrôleur + +#### TODO instructions pour microcontrôleur diff --git a/sidebar.py b/sidebar.py index 13f3459..37498f3 100644 --- a/sidebar.py +++ b/sidebar.py @@ -7,7 +7,6 @@ from dataclasses import dataclass from pathlib import Path import tkinter as tk -from tkinter import messagebox, font import os from typing import Callable, Tuple import subprocess @@ -18,6 +17,12 @@ from dataCDLT import FREE, USED from object_model.circuit_object_model import Chip, get_all_available_chips, get_chip_modification_times +if os.name == "darwin": + from tkinter import messagebox, font + from tkmacosx import Button # type: ignore +else: + from tkinter import Button, messagebox, font + @dataclass class SidebarGrid: @@ -217,7 +222,7 @@ def display_chips(self, chips: list[Tuple[Chip, tk.PhotoImage]]): for index, (chip, chip_image) in enumerate(display_chips): row = index // self.sidebar_grid.columns col = index % self.sidebar_grid.columns - btn = tk.Button( + btn = Button( self.chips_inner_frame, image=chip_image, text=chip.chip_type, @@ -257,7 +262,7 @@ def create_manage_button(self, sidebar_frame): """ Creates the 'Manage Components' button at the bottom of the sidebar without an icon. """ - manage_button = tk.Button( + manage_button = Button( sidebar_frame, text="Gérer les composants", bg="#333333", # Matching the sidebar's background to simulate transparency diff --git a/toolbar.py b/toolbar.py index 29c4287..450ad45 100644 --- a/toolbar.py +++ b/toolbar.py @@ -5,16 +5,20 @@ for selecting connection colors. The Toolbar class manages the state and behavior of these buttons and handles user interactions for placing wires and pin_ios on a canvas. """ - +import os from dataclasses import dataclass from pathlib import Path import tkinter as tk -from tkinter import messagebox, colorchooser -import os + from component_sketch import ComponentSketcher from dataCDLT import INPUT, OUTPUT, FREE, CLOCK from utils import resource_path +if os.name == "darwin": + from tkinter import messagebox, colorchooser + from tkmacosx import Button # type: ignore +else: + from tkinter import Button, messagebox, colorchooser @dataclass class WirePlacementInfo: @@ -45,7 +49,7 @@ def __init__(self, parent: tk.Tk, canvas: tk.Canvas, sketcher: ComponentSketcher self.sketcher = sketcher self.current_dict_circuit = current_dict_circuit self.selected_color = "#479dff" - self.buttons: dict[str, tk.Button] = {} + self.buttons: dict[str, Button] = {} self.tool_mode = None self.wire_info: WirePlacementInfo = WirePlacementInfo(0, None, None) self.cursor_indicator_id = None @@ -79,7 +83,7 @@ def create_topbar(self, parent: tk.Tk): self.create_button("Clock", left_frame, images) # Create the color chooser and Delete button in the right frame - self.color_button = tk.Button( + self.color_button = Button( right_frame, bg=self.selected_color, width=2, @@ -129,7 +133,7 @@ def create_button(self, action: str, parent_frame: tk.Frame, images: dict[str, t """ image = images.get(action.lower()) if image: - btn = tk.Button( + btn = Button( parent_frame, image=image, bg="#505050", # Inactive background @@ -145,7 +149,7 @@ def create_button(self, action: str, parent_frame: tk.Frame, images: dict[str, t btn.image = image # type: ignore else: # Fallback button with text if image is not available - btn = tk.Button( + btn = Button( parent_frame, text=action, bg="#505050", # Inactive background