From f49d8874c1d0996b5d2c63b336eba335fc06e145 Mon Sep 17 00:00:00 2001 From: Yadciel Date: Sun, 22 Dec 2024 20:24:23 +0100 Subject: [PATCH] Add Cython setup and enhance installer functionality Introduced a Cython-based setup to compile Python files for performance improvements. Updated installer scripts with customtkinter modifications for better UI, added support for additional content loading, and enhanced project structure. Adjusted build commands, streamlined file paths, and integrated new UI elements in the HTML resources. --- inc/toolboxWindow.h | 1 + installer/coder.py | 4 +- installer/command | 4 +- installer/main-loader.py | 15 ++ installer/main.py | 290 +++++++++++++++++++++--------------- installer/requirements.txt | 3 + installer/setup.py | 11 ++ res/html/einstellungen.html | 60 ++++---- res/html/index.html | 43 +++++- src/toolboxWindow.cpp | 10 ++ 10 files changed, 280 insertions(+), 161 deletions(-) create mode 100644 installer/main-loader.py create mode 100644 installer/requirements.txt create mode 100644 installer/setup.py diff --git a/inc/toolboxWindow.h b/inc/toolboxWindow.h index 9017cf7..f1f4a52 100644 --- a/inc/toolboxWindow.h +++ b/inc/toolboxWindow.h @@ -82,4 +82,5 @@ private: void openEinst(); void openIndex(); + void getNewContent(); }; diff --git a/installer/coder.py b/installer/coder.py index 870ee9a..cec40c7 100644 --- a/installer/coder.py +++ b/installer/coder.py @@ -7,8 +7,8 @@ def encode_file_to_base64(file_path): # Base64-kodierte Strings generieren -exe_base64 = encode_file_to_base64("D:/Repos/toolbox/cmake-build-minsizerel-visual-studio/Toolbox.exe") -icon_base64 = encode_file_to_base64("D:/Repos/toolbox/cmake-build-MinSizeRel-visual-studio/toolbox.ico") +exe_base64 = encode_file_to_base64("../cmake-build-minsizerel-visual-studio/Toolbox.exe") +icon_base64 = encode_file_to_base64("../res/ico/Toolbox.ico") # Base64-Strings in eine Python-Datei schreiben with open("base64_strings.py", 'w') as py_file: diff --git a/installer/command b/installer/command index dcd27bd..643513e 100644 --- a/installer/command +++ b/installer/command @@ -1,4 +1,6 @@ saucer embed res out_embed - pyinstaller --onefile --icon=..\res\ico\toolbox.ico --name=toolbox_installer --uac-admin main.py + pyinstaller --onefile -key "secretkey" --icon=..\res\ico\toolbox.ico --name=toolbox_installer --add-data "../res/ico/toolbox.ico:." --noconsole --uac-admin main-loader.py + python setup.py build_ext --inplace + upx --force --best --lzma dist/toolbox_installer.exe \ No newline at end of file diff --git a/installer/main-loader.py b/installer/main-loader.py new file mode 100644 index 0000000..eacd7a8 --- /dev/null +++ b/installer/main-loader.py @@ -0,0 +1,15 @@ +import sys +import os + +# Pfad zu deinem `cython`-Ordner +cython_dir = os.path.abspath("./cython") + +# Ordner zum Python-Suchpfad hinzufügen +if cython_dir not in sys.path: + sys.path.insert(0, cython_dir) + +# Importiere die `main.pyd`-Datei +import main + +if __name__ == "__main__": + main.run() # Beispiel: Funktion `run()` aufrufen diff --git a/installer/main.py b/installer/main.py index f85c09c..b5bd2b7 100644 --- a/installer/main.py +++ b/installer/main.py @@ -1,14 +1,30 @@ -import base64 +import sys + +import customtkinter as ctk +from tkinter import filedialog, StringVar, DoubleVar, messagebox import os -from tkinter import Tk, Button, Label, Entry, filedialog, messagebox, StringVar, DoubleVar, Frame, Text -from tkinter.ttk import Progressbar, Style +import base64 import base64_strings # Base64-Strings für die Dateien exe_base64 = base64_strings.exe_base64 icon_base64 = base64_strings.icon_base64 +# Setup für Stil und Farben +def apply_custom_styles(): + ctk.set_appearance_mode("dark") # Dark Mode + ctk.set_default_color_theme("blue") + global style_options + style_options = { + "bg_color": "#1e1e2e", + "text_color": "#ff79c6", + "button_hover_color": "#ff47b4", + "inactive_button_color": "#777", + "progress_color": "#ff79c6", + } + +# Funktionen für die Installation def decode_base64_to_file(base64_str, output_path, progress_callback=None): """Decodes a Base64 string and writes it to a file.""" data = base64.b64decode(base64_str) @@ -20,168 +36,196 @@ def decode_base64_to_file(base64_str, output_path, progress_callback=None): if progress_callback: progress_callback(min((i + chunk_size) / total_bytes * 100, 100)) - def update_progress(value): """Updates the progress bar.""" progress_var.set(value) root.update_idletasks() - def select_directory(): """Opens a directory selection dialog.""" directory = filedialog.askdirectory( - title="Select Output Directory", - initialdir=output_dir_var.get() or os.path.expandvars('%PROGRAMFILES(X86)%') + title="Installationsordner auswählen" ) if directory: - os.makedirs(directory, exist_ok=True) # Create the folder if it doesn't exist output_dir_var.set(directory) - -def create_shortcut(target, shortcut_name, icon_path): - """Creates shortcuts on Desktop and Startup folder.""" - desktop = os.path.join(os.environ['USERPROFILE'], 'Desktop') - path = os.path.join(desktop, shortcut_name + ".lnk") - - startup = os.path.join(os.getenv('APPDATA'), r'Microsoft\Windows\Start Menu\Programs\Startup') - startup_shortcut = os.path.join(startup, shortcut_name + ".lnk") - - vbs_script = f''' - Set oWS = WScript.CreateObject("WScript.Shell") - sLinkFile = "{path}" - Set oLink = oWS.CreateShortcut(sLinkFile) - oLink.TargetPath = "{target}" - oLink.IconLocation = "{icon_path}" - oLink.Save - ''' - startup_vbs_script = f''' - Set oWS = WScript.CreateObject("WScript.Shell") - sLinkFile = "{startup_shortcut}" - Set oLink = oWS.CreateShortcut(sLinkFile) - oLink.TargetPath = "{target}" - oLink.IconLocation = "{icon_path}" - oLink.Save - ''' - - for script, output in [(vbs_script, "create_shortcut.vbs"), (startup_vbs_script, "create_startup_shortcut.vbs")]: - with open(output, "w") as file: - file.write(script) - os.system(f"wscript {output}") - os.remove(output) - - def extract_files(): """Extracts the files to the selected directory and creates shortcuts.""" output_directory = output_dir_var.get() if not output_directory: - messagebox.showerror("Error", "Please select a valid output directory.") + messagebox.showerror("Fehler", "Bitte wählen Sie einen gültigen Installationsordner.") return exe_path = os.path.join(output_directory, "application.exe") icon_path = os.path.join(output_directory, "toolbox.ico") try: - # Ensure the output directory exists + # Sicherstellen, dass der Ordner existiert os.makedirs(output_directory, exist_ok=True) - # Decode and save files + # Dateien decodieren und speichern decode_base64_to_file(exe_base64, exe_path, update_progress) decode_base64_to_file(icon_base64, icon_path, update_progress) - # Create shortcuts - create_shortcut(exe_path, "Toolbox", icon_path) - - messagebox.showinfo("Success", "Installation abgeschlossen!") + messagebox.showinfo("Erfolg", "Installation abgeschlossen!") except Exception as e: - messagebox.showerror("Error", f"Failed to extract files: {e}") - - -def show_readme(): - """Displays the final README page.""" - readme_window = Frame(root, bg='#2e2e2e') - readme_window.pack(fill='both', expand=True) - Label(readme_window, text="Installation abgeschlossen!", bg="#2e2e2e", fg="white", font=("Helvetica", 16)).pack( - pady=20) - readme_text = Text(readme_window, bg="#444", fg="white", wrap='word', height=10, width=50) - readme_text.insert('1.0', - "Vielen Dank, dass Sie 'Toolbox' installiert haben!\n\nWeitere Informationen finden Sie auf unserer Website.") - readme_text.configure(state='disabled') - readme_text.pack(pady=10) - button = Button(readme_window, text="Beenden", command=root.quit) - button.place(relx=0.9, rely=0.9, anchor='se') - - -def next_page(): - """Handles the navigation between pages.""" - global current_page - if current_page == 1: - setup_page_2() - elif current_page == 2: - extract_files() - setup_page_3() - + messagebox.showerror("Fehler", f"Fehler beim Extrahieren der Dateien: {e}") +# Seiten-Setup def setup_page_1(): - """Sets up the welcome page.""" - global current_page - current_page = 1 - welcome_page = Frame(root, bg='#2e2e2e') - welcome_page.pack(fill='both', expand=True) + for widget in root.winfo_children(): + widget.destroy() - Label(welcome_page, text="Willkommen beim Installer!", bg="#2e2e2e", fg="white", font=("Helvetica", 16)).pack( - pady=20) - Label(welcome_page, text="Klicken Sie auf 'Weiter', um fortzufahren.", bg="#2e2e2e", fg="white").pack(pady=10) + welcome_label = ctk.CTkLabel( + root, + text="Willkommen bei der Installation!", + font=("Arial", 16), + text_color=style_options["text_color"], + ) + welcome_label.pack(pady=20) - # Button unten rechts positionieren - button = Button(welcome_page, text="Weiter", command=lambda: (welcome_page.pack_forget(), next_page())) - button.place(relx=0.9, rely=0.9, anchor='se') # Position relativ, unten rechts ankern + description_label = ctk.CTkLabel( + root, text="Klicken Sie auf 'Weiter', um fortzufahren.", text_color="#bbb" + ) + description_label.pack(pady=10) + next_button = ctk.CTkButton( + root, + text="Weiter", + fg_color=style_options["text_color"], + hover_color=style_options["button_hover_color"], + text_color="white", + command=setup_page_2, + ) + next_button.place(relx=1.0, rely=1.0, anchor="se", x=-20, y=-20) def setup_page_2(): - """Sets up the installation folder selection page.""" - global current_page - current_page = 2 - folder_page = Frame(root, bg='#2e2e2e') - folder_page.pack(fill='both', expand=True) + for widget in root.winfo_children(): + widget.destroy() - Label(folder_page, text="Installationsordner wählen:", bg="#2e2e2e", fg="white").pack(pady=5) - Entry(folder_page, textvariable=output_dir_var, width=50).pack(pady=5) - Button(folder_page, text="Durchsuchen...", command=select_directory).pack(pady=5) - button = Button(folder_page, text="Weiter", command=lambda: (folder_page.pack_forget(), next_page())) - button.place(relx=0.9, rely=0.9, anchor='se') + folder_label = ctk.CTkLabel( + root, + text="Installationsordner wählen:", + font=("Arial", 14), + text_color=style_options["text_color"], + ) + folder_label.pack(pady=10) + folder_entry = ctk.CTkEntry( + root, + textvariable=output_dir_var, + placeholder_text="Pfad auswählen", + fg_color=style_options["bg_color"], + text_color="white", + ) + folder_entry.pack(pady=10) + + browse_button = ctk.CTkButton( + root, + text="Durchsuchen", + fg_color=style_options["text_color"], + hover_color=style_options["button_hover_color"], + text_color="white", + command=select_directory, + ) + browse_button.pack(pady=10) + + next_button = ctk.CTkButton( + root, + text="Weiter", + fg_color=style_options["progress_color"], + hover_color=style_options["button_hover_color"], + text_color="white", + command=setup_page_3, + ) + next_button.place(relx=1.0, rely=1.0, anchor="se", x=-20, y=-20) def setup_page_3(): - """Sets up the installation progress page.""" - global current_page - current_page = 3 - progress_page = Frame(root, bg='#2e2e2e') - progress_page.pack(fill='both', expand=True) + for widget in root.winfo_children(): + widget.destroy() - Label(progress_page, text="Installation läuft...", bg="#2e2e2e", fg="white").pack(pady=20) - progress_bar = Progressbar(progress_page, orient='horizontal', length=400, variable=progress_var, - style='Horizontal.TProgressbar') - progress_bar.pack(pady=10) - button = Button(progress_page, text="Weiter", command=lambda: (progress_page.pack_forget(), show_readme())) - button.place(relx=0.9, rely=0.9, anchor='se') + progress_label = ctk.CTkLabel( + root, + text="Installation läuft...", + font=("Arial", 14), + text_color=style_options["text_color"], + ) + progress_label.pack(pady=20) + + progressbar = ctk.CTkProgressBar( + root, + variable=progress_var, + fg_color=style_options["progress_color"], + progress_color=style_options["text_color"], + ) + progressbar.set(0) # Anfang des Fortschritts + progressbar.pack(pady=20) + + finish_button = ctk.CTkButton( + root, + text="Installieren", + fg_color=style_options["text_color"], + hover_color=style_options["button_hover_color"], + text_color="white", + command=lambda: [extract_files(), setup_page_4()], + ) + finish_button.place(relx=1.0, rely=1.0, anchor="se", x=-20, y=-20) + +def setup_page_4(): + for widget in root.winfo_children(): + widget.destroy() + + complete_label = ctk.CTkLabel( + root, + text="Installation abgeschlossen!", + font=("Arial", 16), + text_color=style_options["text_color"], + ) + complete_label.pack(pady=20) + + finish_button = ctk.CTkButton( + root, + text="Beenden", + fg_color=style_options["progress_color"], + hover_color=style_options["button_hover_color"], + text_color="white", + command=root.quit, + ) + finish_button.place(relx=1.0, rely=1.0, anchor="se", x=-20, y=-20) + +def resource_path(relative_path): + """Ermittelt den absoluten Pfad, um Ressourcen im PyInstaller-Build zu finden.""" + base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))) + return os.path.join(base_path, relative_path) -# Tkinter Setup -root = Tk() -root.title("Installer") -root.geometry("500x350") +def run(): + # Hauptprogramm -# Darkmode Style -style = Style(root) -style.theme_use('clam') -style.configure('TLabel', background='#2e2e2e', foreground='white', font=('Helvetica', 12)) -style.configure('TButton', background='#444', foreground='white', font=('Helvetica', 10)) -style.configure('Horizontal.TProgressbar', troughcolor='#444', background='#5a9') -root.configure(background='#2e2e2e') + root.title("Toolbox Installer") -output_dir_var = StringVar(value=os.path.join(os.environ['PROGRAMFILES(X86)'], "Toolbox")) -progress_var = DoubleVar() -current_page = 0 + # Icon setzen + icon_path = resource_path("toolbox.ico") # Stelle sicher, dass toolbox.ico vorhanden ist + root.iconbitmap(icon_path) + root.geometry("500x350") -setup_page_1() -root.mainloop() \ No newline at end of file + # Globale Variablen + global output_dir_var, progress_var + output_dir_var = StringVar() + progress_var = DoubleVar() + + # Stile anwenden und Startseite laden + apply_custom_styles() + setup_page_1() + + # Haupt-Loop + root.mainloop() + + + + + +root = ctk.CTk() + +if __name__ == "__main__": + run() # Führt die Methode 'run()' aus, wenn die Datei direkt ausgeführt wird \ No newline at end of file diff --git a/installer/requirements.txt b/installer/requirements.txt new file mode 100644 index 0000000..058bca2 --- /dev/null +++ b/installer/requirements.txt @@ -0,0 +1,3 @@ +customtkinter~=5.2.2 +setuptools~=75.6.0 +Cython~=3.0.11 \ No newline at end of file diff --git a/installer/setup.py b/installer/setup.py new file mode 100644 index 0000000..2c5a84b --- /dev/null +++ b/installer/setup.py @@ -0,0 +1,11 @@ +from setuptools import setup +from Cython.Build import cythonize +import os + +# Zielordner für kompilierten Code +build_dir = os.path.join(os.getcwd(), "cython") + +setup( + ext_modules=cythonize("main.py", compiler_directives={'language_level': "3"}), + script_args=["build_ext", "--build-lib", build_dir] +) diff --git a/res/html/einstellungen.html b/res/html/einstellungen.html index 0ac47a7..a1bc8fb 100644 --- a/res/html/einstellungen.html +++ b/res/html/einstellungen.html @@ -4,7 +4,7 @@ Toolbox - +