diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4f83dda..a98a3b2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,7 +36,7 @@ jobs: --name "threedy" ` --clean ` --add-data "${{ steps.customtkinter.outputs.location }}/customtkinter;customtkinter/" ` - --add-data "src/threedy/components;components/" ` + --add-data "src/threedy/interface;interface/" ` --add-data "src/threedy/modules;modules/" ` "src/threedy/main.py" diff --git a/src/threedy/components/tabview.py b/src/threedy/components/tabview.py deleted file mode 100644 index d0c6348..0000000 --- a/src/threedy/components/tabview.py +++ /dev/null @@ -1,52 +0,0 @@ -import customtkinter as ctk -from modules.settings import * - - -class Tabview(ctk.CTkTabview): - def __init__(self, parent, **kwargs): - super().__init__(master=parent, **kwargs) - # defaults - self.normal_font = ctk.CTkFont(family=FONT, size=FONT_SIZE) - - # setup layout - self.grid( - row=0, - column=1, - columnspan=2, - padx=PADDING["medium"], - pady=PADDING["none"], - sticky="nsew", - ) - self.grid_rowconfigure(3, weight=1) - - # add tabs - self.add("G-Code Tools") - self.add("CSV Tools") - - # setup tabs - self.tab("G-Code Tools").grid_columnconfigure( - (0, 1), - weight=1, - ) - - self.ansys_prep_switch = ctk.CTkSwitch( - self.tab("G-Code Tools"), - text="Tabulate G-Code for Ansys", - onvalue=True, - offvalue=False, - ) - self.ansys_prep_switch.grid( - row=0, - column=0, - padx=PADDING["medium"], - pady=PADDING["none"], - sticky="w", - ) - - def focused_tab(self): - """Returns the currently selected tab - - Returns: - string: current tab name - """ - return self.get() diff --git a/src/threedy/components/__init__.py b/src/threedy/interface/__init__.py similarity index 100% rename from src/threedy/components/__init__.py rename to src/threedy/interface/__init__.py diff --git a/src/threedy/components/commandbar.py b/src/threedy/interface/commandbar.py similarity index 100% rename from src/threedy/components/commandbar.py rename to src/threedy/interface/commandbar.py diff --git a/src/threedy/components/sidebar.py b/src/threedy/interface/sidebar.py similarity index 100% rename from src/threedy/components/sidebar.py rename to src/threedy/interface/sidebar.py diff --git a/src/threedy/interface/tabview.py b/src/threedy/interface/tabview.py new file mode 100644 index 0000000..3f451a6 --- /dev/null +++ b/src/threedy/interface/tabview.py @@ -0,0 +1,116 @@ +import customtkinter as ctk +from modules.settings import * + + +class Tabview(ctk.CTkTabview): + def __init__(self, parent, **kwargs): + super().__init__(master=parent, **kwargs) + # defaults + self.normal_font = ctk.CTkFont(family=FONT, size=FONT_SIZE) + + # setup layout + self.grid( + row=0, + column=1, + columnspan=2, + padx=PADDING["medium"], + pady=PADDING["none"], + sticky="nsew", + ) + self.grid_rowconfigure(3, weight=1) + + # add tabs + self.add("G-Code Tools") + self.add("CSV Tools") + + # setup tabs + self.tab("G-Code Tools").grid_columnconfigure( + (0, 1), + weight=1, + ) + + self.select_all_gcode = ctk.CTkSwitch( + self.tab("G-Code Tools"), + text="Select All", + command=self.toggle_all_switches, + ) + self.select_all_gcode.place(anchor="nw") + + self.gcode_switch_data = [ + { + "text": "Remove Comments", + "variable": "remove_comments_switch", + "row": 0, + "column": 1, + }, + { + "text": "Remove M-Codes", + "variable": "remove_mcodes_switch", + "row": 1, + "column": 1, + }, + { + "text": "Remove F/E-Codes", + "variable": "remove_fecodes_switch", + "row": 2, + "column": 1, + }, + { + "text": "Keep only G0 & G1 moves", + "variable": "remove_nontravel_switch", + "row": 0, + "column": 2, + }, + { + "text": "Remove lines with lonely G0/G1s", + "variable": "remove_lone_gs_switch", + "row": 1, + "column": 2, + }, + { + "text": "Remove coordinate names", + "variable": "remove_coordname_switch", + "row": 2, + "column": 2, + }, + ] + + for data in self.gcode_switch_data: + switch_variable = data["variable"] + switch = ctk.CTkCheckBox( + self.tab("G-Code Tools"), + text=data["text"], + font=self.normal_font, + onvalue=True, + offvalue=False, + ) + setattr(self, switch_variable, switch) + switch.grid( + row=data["row"], + column=data["column"], + padx=PADDING["small"], + pady=PADDING["small"], + sticky="W", + ) + + def toggle_all_switches(self): + """iterates over every switch and toggles it""" + for data in self.gcode_switch_data: + switch_variable = data["variable"] + if isinstance(switch_variable, str): + # Get the actual variable object based on its name + switch_variable = getattr(self, switch_variable) + if self.select_all_gcode.get() == False: + switch_variable.deselect() + self.select_all_gcode.configure(text="Select All") + else: + switch_variable.select() + self.select_all_gcode.configure(text="Deselect All") + + def selected_tab(self): + """Returns the currently selected tab + + Returns: + string: current tab name + """ + return self.get() diff --git a/src/threedy/components/terminal.py b/src/threedy/interface/terminal.py similarity index 100% rename from src/threedy/components/terminal.py rename to src/threedy/interface/terminal.py diff --git a/src/threedy/main.py b/src/threedy/main.py index 559c461..acb889a 100644 --- a/src/threedy/main.py +++ b/src/threedy/main.py @@ -1,8 +1,11 @@ +import os +import sys + import customtkinter as ctk -from components.commandbar import Commandbar -from components.sidebar import Sidebar -from components.tabview import Tabview -from components.terminal import Terminal +from interface.commandbar import Commandbar +from interface.sidebar import Sidebar +from interface.tabview import Tabview +from interface.terminal import Terminal from modules.compute import process_file_contents from modules.dialogs import export_file_dialog, select_file_dialog from modules.settings import * @@ -11,20 +14,10 @@ # PyInstaller helper # https://stackoverflow.com/questions/7674790/bundling-data-files-with-pyinstaller-onefile/13790741#13790741 def resource_path(relative_path): - """Get absolute path to resource, works for dev and for PyInstaller - - Args: - relative_path (string): the relative path of the resource - - Returns: - string: the base pass joined with the relative path - """ - try: - # PyInstaller creates a temp folder and stores path in _MEIPASS + try: # PyInstaller creates a temp folder and stores path in _MEIPASS base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") - return os.path.join(base_path, relative_path) @@ -34,7 +27,7 @@ def __init__(self): # setup window self.geometry(f"{APP_SIZE['width']}x{APP_SIZE['height']}") - # self.iconbitmap("src//threedy//resources//logo.ico") + self.iconbitmap(resource_path("src\\threedy\\resources\\logo.ico")) self.title("threedy") # setup grid @@ -74,12 +67,32 @@ def on_file_select(self): self.terminal.newline("File selected: " + self.file_path + "\n\n") def on_file_export(self): - self.focused_tab = self.tabview.focused_tab() - export_file_dialog(self.focused_tab, self.file_contents) + self.selected_tab = self.tabview.selected_tab() + export_file_dialog(self.selected_tab, self.file_contents) self.terminal.newline("File exported successfully!\n\n") def on_compute(self): - print() + remove_comments = self.tabview.remove_comments_switch.get() + remove_mcodes = self.tabview.remove_mcodes_switch.get() + remove_fecodes = self.tabview.remove_fecodes_switch.get() + remove_nontravel = self.tabview.remove_nontravel_switch.get() + remove_lone_gs = self.tabview.remove_lone_gs_switch.get() + remove_coordname = self.tabview.remove_coordname_switch.get() + + self.terminal.newline("Vars OK. Compute started...\n\n") + + self.file_contents, self.compute_time_taken = process_file_contents( + self.file_contents, + remove_comments, + remove_mcodes, + remove_fecodes, + remove_nontravel, + remove_lone_gs, + remove_coordname, + ) + self.terminal.newline( + "Compute done! Took " + f"{self.compute_time_taken}" + " seconds\n\n" + ) if __name__ == "__main__": diff --git a/src/threedy/modules/dialogs.py b/src/threedy/modules/dialogs.py index fabe090..5c88ba3 100644 --- a/src/threedy/modules/dialogs.py +++ b/src/threedy/modules/dialogs.py @@ -30,10 +30,10 @@ def select_file_dialog(): # --------------------------------------- export file logic -------------------------------------- # -def export_file_dialog(focused_tab, file_contents): - if focused_tab == "G-Code Tools": +def export_file_dialog(selected_tab, file_contents): + if selected_tab == "G-Code Tools": extension = ".gcode" - elif focused_tab == "CSV Tools": + elif selected_tab == "CSV Tools": extension = ".csv" file_path = filedialog.asksaveasfilename( diff --git a/src/threedy/modules/process_gcode.py b/src/threedy/modules/process_gcode.py new file mode 100644 index 0000000..f3232b4 --- /dev/null +++ b/src/threedy/modules/process_gcode.py @@ -0,0 +1,68 @@ +import re +import time + +from interface.tabview import gcode_switch_data +from modules.settings import RE_PATTERNS + + +def process_file_contents( + file_contents, + remove_comments=False, + remove_mcodes=False, + remove_fecodes=False, + remove_nontravel=False, + remove_lone_gs=False, + remove_coordname=False, +): + timer = time.process_time() + + if remove_comments: + file_contents = re.sub( + RE_PATTERNS["remove_comments"], + "", + file_contents, + flags=re.MULTILINE, + ) + + if remove_mcodes: + file_contents = re.sub( + RE_PATTERNS["remove_mcodes"], + "", + file_contents, + flags=re.MULTILINE, + ) + + if remove_fecodes: + file_contents = re.sub( + RE_PATTERNS["remove_fecodes"], + "", + file_contents, + ) + + if remove_nontravel: + file_contents = re.sub( + RE_PATTERNS["remove_nontravel"], + "", + file_contents, + flags=re.MULTILINE, + ) + + if remove_lone_gs: + file_contents = re.sub( + RE_PATTERNS["remove_lone_gs"], + "", + file_contents, + flags=re.MULTILINE, + ) + + if remove_coordname: + file_contents = re.sub( + RE_PATTERNS["remove_coordname"], + r"\2 \3 \4 \1\5", + file_contents, + ) + file_contents = re.sub(r"G", "", file_contents) + + elapsed_time = time.process_time() - timer + + return file_contents, elapsed_time diff --git a/src/threedy/modules/settings.py b/src/threedy/modules/settings.py index dafa123..a653696 100644 --- a/src/threedy/modules/settings.py +++ b/src/threedy/modules/settings.py @@ -1,12 +1,12 @@ # size -APP_SIZE = {"width": 800, "height": 500} +APP_SIZE = {"width": 900, "height": 500} # text FONT = "Calibri" FONT_SIZE = 14 # styling -PADDING = {"none": 0, "medium": 10, "large": 20} +PADDING = {"none": 0, "small": 5, "medium": 10, "large": 20} # terminal TERMINAL_FONT = "Fira Code" diff --git a/src/threedy/resources/test-gcode.gcode b/src/threedy/resources/test-gcode.gcode new file mode 100644 index 0000000..0eea062 --- /dev/null +++ b/src/threedy/resources/test-gcode.gcode @@ -0,0 +1,11 @@ +; test comment + +; + +; +M104 S180 T1 ; non G-Code + +G28 ; non 01 G-Code +G92 E0 ; Reset Extruder + +G1 Z2 F3000 ; no WY \ No newline at end of file diff --git a/tmp/gcode-processor b/tmp/gcode-processor new file mode 100644 index 0000000..e1abfea --- /dev/null +++ b/tmp/gcode-processor @@ -0,0 +1,8 @@ +class GCodeProcessor(file_contents): + + def remove_comments(self, file_contents): + file_contents = re.sub( + RE_PATTERNS["remove_comments"], "", file_contents, flags=re.MULTILINE + ) + + \ No newline at end of file diff --git a/tmp/tabview-switches b/tmp/tabview-switches index 5d398da..e3b2c44 100644 --- a/tmp/tabview-switches +++ b/tmp/tabview-switches @@ -57,4 +57,20 @@ ) def enable_all_switches(self): - self.select_all_event() \ No newline at end of file + self.select_all_event() + + + + self.ansys_prep_switch = ctk.CTkSwitch( + self.tab("G-Code Tools"), + text="Tabulate G-Code for Ansys", + onvalue=True, + offvalue=False, + ) + self.ansys_prep_switch.grid( + row=0, + column=0, + padx=PADDING["medium"], + pady=PADDING["none"], + sticky="w", + ) \ No newline at end of file diff --git a/utils/APtE-config.json b/utils/APtE-config.json index 67c8e3b..6cd1fcf 100644 --- a/utils/APtE-config.json +++ b/utils/APtE-config.json @@ -1,93 +1,93 @@ { - "version": "auto-py-to-exe-configuration_v1", - "pyinstallerOptions": [ - { - "optionDest": "noconfirm", - "value": true - }, - { - "optionDest": "filenames", - "value": "G:/My Drive/Repos/threedy/src/threedy/main.py" - }, - { - "optionDest": "onefile", - "value": true - }, - { - "optionDest": "console", - "value": false - }, - { - "optionDest": "icon_file", - "value": "G:/My Drive/Repos/threedy/src/threedy/resources/logo.ico" - }, - { - "optionDest": "name", - "value": "threedy" - }, - { - "optionDest": "ascii", - "value": false - }, - { - "optionDest": "clean_build", - "value": true - }, - { - "optionDest": "strip", - "value": false - }, - { - "optionDest": "noupx", - "value": false - }, - { - "optionDest": "disable_windowed_traceback", - "value": false - }, - { - "optionDest": "embed_manifest", - "value": true - }, - { - "optionDest": "uac_admin", - "value": false - }, - { - "optionDest": "uac_uiaccess", - "value": false - }, - { - "optionDest": "win_private_assemblies", - "value": false - }, - { - "optionDest": "win_no_prefer_redirects", - "value": false - }, - { - "optionDest": "bootloader_ignore_signals", - "value": false - }, - { - "optionDest": "argv_emulation", - "value": false - }, - { - "optionDest": "datas", - "value": "C:/Users/stu/AppData/Local/Programs/Python/Python311/Lib/site-packages/customtkinter;customtkinter/" - }, - { - "optionDest": "datas", - "value": "G:/My Drive/Repos/threedy/src/threedy/components;components/" - }, - { - "optionDest": "datas", - "value": "G:/My Drive/Repos/threedy/src/threedy/modules;modules/" + "version": "auto-py-to-exe-configuration_v1", + "pyinstallerOptions": [ + { + "optionDest": "noconfirm", + "value": true + }, + { + "optionDest": "filenames", + "value": "G:/My Drive/Repos/threedy/src/threedy/main.py" + }, + { + "optionDest": "onefile", + "value": true + }, + { + "optionDest": "console", + "value": false + }, + { + "optionDest": "icon_file", + "value": "G:/My Drive/Repos/threedy/src/threedy/resources/logo.ico" + }, + { + "optionDest": "name", + "value": "threedy" + }, + { + "optionDest": "ascii", + "value": false + }, + { + "optionDest": "clean_build", + "value": true + }, + { + "optionDest": "strip", + "value": false + }, + { + "optionDest": "noupx", + "value": false + }, + { + "optionDest": "disable_windowed_traceback", + "value": false + }, + { + "optionDest": "embed_manifest", + "value": true + }, + { + "optionDest": "uac_admin", + "value": false + }, + { + "optionDest": "uac_uiaccess", + "value": false + }, + { + "optionDest": "win_private_assemblies", + "value": false + }, + { + "optionDest": "win_no_prefer_redirects", + "value": false + }, + { + "optionDest": "bootloader_ignore_signals", + "value": false + }, + { + "optionDest": "argv_emulation", + "value": false + }, + { + "optionDest": "datas", + "value": "C:/Users/stu/AppData/Local/Programs/Python/Python311/Lib/site-packages/customtkinter;customtkinter/" + }, + { + "optionDest": "datas", + "value": "G:/My Drive/Repos/threedy/src/threedy/interface;interface/" + }, + { + "optionDest": "datas", + "value": "G:/My Drive/Repos/threedy/src/threedy/modules;modules/" + } + ], + "nonPyinstallerOptions": { + "increaseRecursionLimit": true, + "manualArguments": "" } - ], - "nonPyinstallerOptions": { - "increaseRecursionLimit": true, - "manualArguments": "" - } -} \ No newline at end of file +}