commit ff970973e20207742a6cb439090122311e3968c8 Author: Désiré Werner Menrath Date: Fri Jul 25 23:42:43 2025 +0200 first commit diff --git a/__pycache__/custom_file_dialog.cpython-312.pyc b/__pycache__/custom_file_dialog.cpython-312.pyc new file mode 100644 index 0000000..fd2297e Binary files /dev/null and b/__pycache__/custom_file_dialog.cpython-312.pyc differ diff --git a/custom_file_dialog.py b/custom_file_dialog.py new file mode 100644 index 0000000..a6ca54e --- /dev/null +++ b/custom_file_dialog.py @@ -0,0 +1,257 @@ +import tkinter as tk +from tkinter import ttk +import os +from functools import partial + + +class CustomFileDialog(tk.Toplevel): + def __init__(self, parent, initial_dir=None, filetypes=None): + super().__init__(parent) + self.parent = parent + self.title("Datei auswählen") + self.geometry("800x600") # Standardgröße, kann angepasst werden + # Macht das Dialogfenster modal zum Hauptfenster + self.transient(parent) + self.grab_set() # Fängt alle Ereignisse ab, bis der Dialog geschlossen wird + + self.selected_file = None + self.current_dir = os.path.abspath( + initial_dir) if initial_dir else os.getcwd() + self.filetypes = filetypes if filetypes else [("All files", "*.*")] + self.current_filter_pattern = "*.*" # Standardfilter + + # Icons (Platzhalter, müssten geladen werden) + # Sie müssen hier Ihre eigenen Icons laden oder generieren + # Beispiel: self.folder_icon = tk.PhotoImage(file="path/to/your/folder_icon.png") + # Für den Anfang verwenden wir leere PhotoImages + self.folder_icon = tk.PhotoImage( + file="./water-folder.png") + self.file_icon = tk.PhotoImage( + file="./text-x-generic.png") + self.iso_icon = tk.PhotoImage( + file="./media-optical.png") + + self._create_widgets() + + # Filter-Combobox initialisieren + filter_descriptions = [desc for desc, pattern in self.filetypes] + self.filter_combobox["values"] = filter_descriptions + # Ersten Filter als Standard setzen + self.filter_combobox.set(filter_descriptions[0]) + # Den initialen Filter explizit setzen, da <> nicht immer ausgelöst wird + self.current_filter_pattern = self.filetypes[0][1] + + self._populate_files() + + # Behandelt das Schließen des Fensters + self.protocol("WM_DELETE_WINDOW", self._on_closing) + self.wait_window(self) # Wartet, bis das Fenster geschlossen wird + + def _create_widgets(self): + # Hauptframe + main_frame = ttk.Frame(self, padding="10") + main_frame.pack(fill="both", expand=True) + # Canvas-Bereich soll sich ausdehnen + main_frame.grid_rowconfigure(1, weight=1) + main_frame.grid_columnconfigure(0, weight=1) + + # Pfad-Navigation + path_frame = ttk.Frame(main_frame) + path_frame.grid(row=0, column=0, sticky="ew", pady=(0, 5)) + path_frame.grid_columnconfigure(1, weight=1) + + ttk.Button(path_frame, text="Up", command=self._go_up_dir).grid( + row=0, column=0, padx=(0, 5)) + self.path_entry = ttk.Entry(path_frame, state="readonly") + self.path_entry.grid(row=0, column=1, sticky="ew") + + ttk.Label(path_frame, text="Dateityp:").grid( + row=0, column=2, padx=(10, 5)) + self.filter_combobox = ttk.Combobox(path_frame, state="readonly") + self.filter_combobox.grid(row=0, column=3, sticky="ew") + self.filter_combobox.bind( + "<>", self._on_filter_select) + # Optional: Pfad im System-Explorer öffnen + # Canvas für Dateianzeige (Kachelansicht) + self.canvas_frame = ttk.Frame(main_frame) + self.canvas_frame.grid(row=1, column=0, sticky="nsew") + self.canvas_frame.grid_rowconfigure(0, weight=1) + self.canvas_frame.grid_columnconfigure(0, weight=1) + + self.canvas = tk.Canvas( + self.canvas_frame, bg="white", highlightthickness=0) + self.canvas.grid(row=0, column=0, sticky="nsew") + + self.v_scrollbar = ttk.Scrollbar( + self.canvas_frame, orient="vertical", command=self.canvas.yview) + self.v_scrollbar.grid(row=0, column=1, sticky="ns") + self.canvas.configure(yscrollcommand=self.v_scrollbar.set) + + self.h_scrollbar = ttk.Scrollbar( + self.canvas_frame, orient="horizontal", command=self.canvas.xview) + self.h_scrollbar.grid(row=1, column=0, sticky="ew") + self.canvas.configure(xscrollcommand=self.h_scrollbar.set) + + # Frame zum Halten der Kacheln + self.inner_frame = ttk.Frame(self.canvas) + self.canvas.create_window((0, 0), window=self.inner_frame, anchor="nw") + + self.inner_frame.bind("", lambda e: self.canvas.configure( + scrollregion=self.canvas.bbox("all"))) + # Für Klicks auf leeren Bereich + self.canvas.bind("", self._on_canvas_click) + + # Buttons + button_frame = ttk.Frame(main_frame) + button_frame.grid(row=2, column=0, sticky="ew", pady=(5, 0)) + button_frame.grid_columnconfigure(0, weight=1) # Leerraum links + ttk.Button(button_frame, text="Öffnen", command=self._on_open).grid( + row=0, column=1, padx=(0, 5)) + ttk.Button(button_frame, text="Abbrechen", + command=self._on_cancel).grid(row=0, column=2) + + def _populate_files(self): + # Lösche alle vorhandenen Kacheln + for widget in self.inner_frame.winfo_children(): + widget.destroy() + + self.path_entry.config(state="normal") + self.path_entry.delete(0, tk.END) + self.path_entry.insert(0, self.current_dir) + self.path_entry.config(state="readonly") + + files_and_dirs = [] + try: + for item in os.listdir(self.current_dir): + full_path = os.path.join(self.current_dir, item) + if os.path.isdir(full_path): + files_and_dirs.append((item, "dir")) + elif os.path.isfile(full_path): + # Dateien nur hinzufügen, wenn sie dem aktuellen Filter entsprechen + if self._matches_filetype(item): + files_and_dirs.append((item, "file")) + except PermissionError: + # Fehlerbehandlung für nicht zugängliche Verzeichnisse + ttk.Label(self.inner_frame, + text="Zugriff verweigert.").pack(pady=20) + return + except Exception as e: + ttk.Label(self.inner_frame, text=f"Fehler: {e}").pack(pady=20) + return + + # Sortieren: Ordner zuerst, dann Dateien, alphabetisch + files_and_dirs.sort(key=lambda x: (x[1] == "file", x[0].lower())) + + # Kachel-Layout (Beispiel: 4 Spalten) + col_count = 4 + for i, (name, item_type) in enumerate(files_and_dirs): + row = i // col_count + col = i % col_count + + icon = self.folder_icon if item_type == "dir" else ( + self.iso_icon if name.lower().endswith(".iso") else self.file_icon) + + # Kachel-Frame + item_frame = ttk.Frame( + self.inner_frame, relief="solid", borderwidth=1, padding=5) + item_frame.grid(row=row, column=col, padx=5, pady=5, sticky="nsew") + # Text soll sich ausdehnen + item_frame.grid_rowconfigure(1, weight=1) + item_frame.grid_columnconfigure( + 0, weight=1) # Icon/Text zentrieren + + # Daten an den Frame anhängen + item_frame.file_path = full_path + item_frame.item_type = item_type + + # Icon + icon_label = ttk.Label(item_frame, image=icon) + icon_label.grid(row=0, column=0, pady=(0, 5)) + # Daten an das Icon-Label anhängen + icon_label.file_path = full_path + icon_label.item_type = item_type + + # Dateiname + # wraplength für Zeilenumbruch + name_label = ttk.Label(item_frame, text=name, + wraplength=100, anchor="n") + name_label.grid(row=1, column=0, sticky="ew") + # Daten an das Name-Label anhängen + name_label.file_path = full_path + name_label.item_type = item_type + + # Bindungen für Klicks (mit functools.partial) + item_frame.bind( + "", partial(self._on_item_click, full_path, item_type)) + icon_label.bind( + "", partial(self._on_item_click, full_path, item_type)) + name_label.bind( + "", partial(self._on_item_click, full_path, item_type)) + + item_frame.bind( + "", partial(self._on_item_double_click, full_path, item_type)) + icon_label.bind( + "", partial(self._on_item_double_click, full_path, item_type)) + name_label.bind( + "", partial(self._on_item_double_click, full_path, item_type)) + + def _go_up_dir(self): + parent_dir = os.path.dirname(self.current_dir) + if parent_dir != self.current_dir: # Verhindert, dass man über das Root-Verzeichnis hinausgeht + self.current_dir = parent_dir + self._populate_files() + + def _on_item_click(self, path, item_type, event): + print(f"DEBUG: _on_item_click - Path: {path}, Type: {item_type}") + # Hier können Sie eine visuelle Auswahl hervorheben + self.selected_file = path # Temporär speichern + + def _on_item_double_click(self, path, item_type, event): + print( + f"DEBUG: _on_item_double_click - Path: {path}, Type: {item_type}") + if item_type == "dir": + self.current_dir = path + self._populate_files() + else: + self.selected_file = path + self.destroy() # Dialog schließen und ausgewählte Datei zurückgeben + + def _on_open(self): + if self.selected_file and os.path.isfile(self.selected_file): + self.destroy() + else: + # Optional: Fehlermeldung, wenn keine Datei ausgewählt oder Ordner doppelt geklickt wurde + print("Bitte eine Datei auswählen oder einen Ordner doppelt klicken.") + + def _on_cancel(self): + self.selected_file = None # Nichts ausgewählt + self.destroy() + + def _on_closing(self): + self.selected_file = None # Nichts ausgewählt, wenn Fenster geschlossen wird + self.destroy() + + def _matches_filetype(self, filename): + # Wenn der aktuelle Filter "*.*" ist, passen alle Dateien + if self.current_filter_pattern == "*.*": + return True + + # Ansonsten prüfen, ob die Datei zum aktuellen spezifischen Filter passt + ext = self.current_filter_pattern[2:].lower() + return filename.lower().endswith("." + ext) + + def _on_filter_select(self, event): + selected_desc = self.filter_combobox.get() + for desc, pattern in self.filetypes: + if desc == selected_desc: + self.current_filter_pattern = pattern + break + self._populate_files() # Dateiliste neu laden mit neuem Filter + + def _on_canvas_click(self, event): + # Wenn auf den leeren Bereich des Canvas geklickt wird, Auswahl aufheben + self.selected_file = None + # Optional: Visuelle Hervorhebung entfernen + + def get_selected_file(self): + return self.selected_file diff --git a/mainwindow.py b/mainwindow.py new file mode 100644 index 0000000..b60280e --- /dev/null +++ b/mainwindow.py @@ -0,0 +1,39 @@ +#!/usr/bin/python3 +import tkinter as tk +from tkinter import ttk +from custom_file_dialog import CustomFileDialog + + +class GlotzMol(tk.Tk): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.geometry('800x400') + ttk.Label(text="Custodialog-teschdfeschda").grid(row=0, column=0) + self.columnconfigure(1, weight=1) + self.iso_path_entry = ttk.Entry(self) + self.iso_path_entry.grid( + row=1, column=0, columnspan=2, padx=15, pady=5, sticky="ew") + ttk.Button(self, text="Öffnen", command=self.customtest).grid( + row=2, column=0, padx=5, pady=5) + + def customtest(self): + dialog = CustomFileDialog(self, initial_dir="/home/punix/Downloads", + filetypes=[("ISO files", "*.iso")]) + path = dialog.get_selected_file() + + if path: + self.iso_path_entry.delete(0, tk.END) + self.iso_path_entry.insert(0, path) + + +if __name__ == "__main__": + root = GlotzMol() + theme_path = '/usr/share/TK-Themes' + style = ttk.Style(root) + root.tk.call('source', f"{theme_path}/water.tcl") + try: + root.tk.call('set_theme', 'dark') + except tk.TclError: + pass + root.mainloop() diff --git a/media-optical.png b/media-optical.png new file mode 100644 index 0000000..80d3d2f Binary files /dev/null and b/media-optical.png differ diff --git a/text-x-generic.png b/text-x-generic.png new file mode 100644 index 0000000..f6cb0c8 Binary files /dev/null and b/text-x-generic.png differ diff --git a/water-folder.png b/water-folder.png new file mode 100644 index 0000000..4aeccf6 Binary files /dev/null and b/water-folder.png differ