diff --git a/__pycache__/custom_file_dialog.cpython-312.pyc b/__pycache__/custom_file_dialog.cpython-312.pyc index bfe6bd6..e8312d5 100644 Binary files a/__pycache__/custom_file_dialog.cpython-312.pyc and b/__pycache__/custom_file_dialog.cpython-312.pyc differ diff --git a/custom_file_dialog.py b/custom_file_dialog.py index 321cf38..6ee5782 100644 --- a/custom_file_dialog.py +++ b/custom_file_dialog.py @@ -128,13 +128,20 @@ class CustomFileDialog(tk.Toplevel): 'file_small': '/usr/share/icons/lx-icons/32/document-32.png', 'python_small': '/usr/share/icons/lx-icons/32/file-python-32.png', 'pdf_small': '/usr/share/icons/lx-icons/32/pdf-32.png', 'archive_small': '/usr/share/icons/lx-icons/32/tar-32.png', 'audio_small': '/usr/share/icons/lx-icons/32/audio-32.png', 'video_small_file': '/usr/share/icons/lx-icons/32/video-32.png', - 'picture_small': '/usr/share/icons/lx-icons/32/picture-32.png', 'iso_small': '/usr/share/icons/lx-icons/32/media-optical-32.png' + 'picture_small': '/usr/share/icons/lx-icons/32/picture-32.png', 'iso_small': '/usr/share/icons/lx-icons/32/media-optical-32.png', + 'list_view': '/usr/share/icons/lx-icons/32/list-32.png', + 'icon_view': '/usr/share/icons/lx-icons/32/carrel-32.png', + 'hide': '/usr/share/icons/lx-icons/32/hide-32.png', + 'unhide': '/usr/share/icons/lx-icons/32/unhide-32.png', + 'back': '/usr/share/icons/lx-icons/32/arrow-left-32.png', + 'forward': '/usr/share/icons/lx-icons/32/arrow-right-32.png', + 'home': '/usr/share/icons/lx-icons/32/home-32.png' } for key, filename in icon_files.items(): try: self.icons[key] = tk.PhotoImage(file=get_icon_path(filename)) except tk.TclError: - size = 32 if 'small' in key else 64 + size = 32 if 'small' in key or 'view' in key or 'hide' in key or 'unhide' in key or 'back' in key or 'forward' in key or 'home' in key else 64 self.icons[key] = tk.PhotoImage(width=size, height=size) def get_file_icon(self, filename, size='large'): @@ -178,6 +185,8 @@ class CustomFileDialog(tk.Toplevel): style.map("Sidebar.TButton", background=[ ('active', self.selection_color)]) + style.configure("Sidebar.TLabel", background=self.sidebar_color, + foreground="black" if not is_dark else "white") style.configure("Content.TFrame", background=self.icon_bg_color) style.configure("Item.TFrame", background=self.icon_bg_color) style.map('Item.TFrame', background=[ @@ -189,34 +198,56 @@ class CustomFileDialog(tk.Toplevel): style.map('Icon.TLabel', background=[ ('selected', self.selection_color)]) - style.configure("Treeview.Heading", relief="raised", - borderwidth=1, font=('TkDefaultFont', 10, 'bold')) + style.configure("Treeview.Heading", relief="flat", + borderwidth=0, font=('TkDefaultFont', 10, 'bold')) style.configure("Treeview", rowheight=28, background=self.icon_bg_color, fieldbackground=self.icon_bg_color) style.map("Treeview", background=[('selected', self.selection_color)], foreground=[ ('selected', "black" if not is_dark else "white")]) + style.configure("Toolbutton.TCheckbutton", padding=5, + relief="flat", background=self.icon_bg_color) + style.map("Toolbutton.TCheckbutton", + background=[('active', self.selection_color)], + ) + + style.configure("Toolbutton.TRadiobutton", padding=5, + relief="flat", background=self.icon_bg_color) + style.map("Toolbutton.TRadiobutton", + background=[('active', self.selection_color)], + ) + + style.configure("Toolbutton.TButton", padding=0, + relief="flat", background=self.sidebar_color) + style.map("Toolbutton.TButton", + background=[('active', self.selection_color)], + ) + def create_widgets(self): main_frame = ttk.Frame(self, padding=(0, 0, 10, 0)) main_frame.pack(fill="both", expand=True) + paned_window = ttk.PanedWindow(main_frame, orient=tk.HORIZONTAL) paned_window.pack(fill="both", expand=True) sidebar_frame = ttk.Frame(paned_window, padding=( - 15, 5, 15, 0), style="Sidebar.TFrame") + 15, 10, 15, 15), style="Sidebar.TFrame") paned_window.add(sidebar_frame, weight=0) + paned_window.pane(0, weight=0) sidebar_frame.grid_rowconfigure(1, weight=1) sidebar_nav_frame = ttk.Frame(sidebar_frame, style="Sidebar.TFrame") sidebar_nav_frame.grid(row=0, column=0, sticky="ew", pady=(0, 10)) self.back_button = ttk.Button( - sidebar_nav_frame, text="◀", command=self.go_back, state=tk.DISABLED, width=3) + sidebar_nav_frame, image=self.icons['back'], command=self.go_back, state=tk.DISABLED, style="Toolbutton.TButton") self.back_button.pack(side="left", fill="x", expand=True) - self.home_button = ttk.Button(sidebar_nav_frame, text="🏠", command=lambda: self.navigate_to( - os.path.expanduser("~")), width=3) + Tooltip(self.back_button, "Zurück") + self.home_button = ttk.Button(sidebar_nav_frame, image=self.icons['home'], command=lambda: self.navigate_to( + os.path.expanduser("~")), style="Toolbutton.TButton") self.home_button.pack(side="left", fill="x", expand=True, padx=2) + Tooltip(self.home_button, "Home") self.forward_button = ttk.Button( - sidebar_nav_frame, text="▶", command=self.go_forward, state=tk.DISABLED, width=3) + sidebar_nav_frame, image=self.icons['forward'], command=self.go_forward, state=tk.DISABLED, style="Toolbutton.TButton") self.forward_button.pack(side="left", fill="x", expand=True) sidebar_buttons_frame = ttk.Frame( @@ -241,33 +272,43 @@ class CustomFileDialog(tk.Toplevel): compound="top", command=lambda p=config['path']: self.navigate_to(p), style="Sidebar.TButton") btn.pack(fill="x", pady=1) + storage_frame = ttk.Frame(sidebar_frame, style="Sidebar.TFrame") + storage_frame.grid(row=2, column=0, sticky="ew", pady=(10, 0), padx=10) + self.storage_label = ttk.Label( + storage_frame, text="Freier Speicher:", style="Sidebar.TLabel") + self.storage_label.pack(fill="x") + self.storage_bar = ttk.Progressbar( + storage_frame, orient="horizontal", length=100, mode="determinate") + self.storage_bar.pack(fill="x", pady=(2, 10)) + content_frame = ttk.Frame(paned_window, padding=(5, 0, 0, 0)) paned_window.add(content_frame, weight=1) content_frame.grid_rowconfigure(2, weight=1) content_frame.grid_columnconfigure(0, weight=1) top_bar = ttk.Frame(content_frame) - top_bar.grid(row=0, column=0, sticky="ew", pady=(5, 0)) + top_bar.grid(row=0, column=0, sticky="ew", pady=(10, 0)) top_bar.grid_columnconfigure(0, weight=1) self.path_entry = ttk.Entry(top_bar) self.path_entry.grid(row=0, column=0, sticky="ew") self.path_entry.bind( "", lambda e: self.navigate_to(self.path_entry.get())) - self.hidden_files_button = ttk.Checkbutton( - top_bar, text="Versteckte Dateien", variable=self.show_hidden_files, command=self.populate_files) - self.hidden_files_button.grid(row=0, column=1, padx=5) + view_switch = ttk.Frame(top_bar, padding=(5, 0)) - view_switch.grid(row=0, column=2) - ttk.Radiobutton(view_switch, text="Kacheln", variable=self.view_mode, - value="icons", command=self.populate_files).pack(side="left") - ttk.Radiobutton(view_switch, text="Liste", variable=self.view_mode, - value="list", command=self.populate_files).pack(side="left") - self.filter_combobox = ttk.Combobox( - top_bar, values=[ft[0] for ft in self.filetypes], state="readonly", width=20) - self.filter_combobox.grid(row=0, column=3, padx=5) - self.filter_combobox.bind( - "<>", self.on_filter_change) - self.filter_combobox.set(self.filetypes[0][0]) + view_switch.grid(row=0, column=1) + self.icon_view_button = ttk.Button(view_switch, image=self.icons['icon_view'], command=lambda: ( + self.view_mode.set("icons"), self.populate_files()), style="Toolbutton.TButton") + self.icon_view_button.pack(side="left") + Tooltip(self.icon_view_button, "Kachelansicht") + self.list_view_button = ttk.Button(view_switch, image=self.icons['list_view'], command=lambda: ( + self.view_mode.set("list"), self.populate_files()), style="Toolbutton.TButton") + self.list_view_button.pack(side="left") + Tooltip(self.list_view_button, "Listenansicht") + + self.hidden_files_button = ttk.Button( + top_bar, image=self.icons['hide'], command=self.toggle_hidden_files, style="Toolbutton.TButton") + self.hidden_files_button.grid(row=0, column=2, padx=5) + Tooltip(self.hidden_files_button, "Versteckte Dateien anzeigen") ttk.Separator(content_frame, orient='horizontal').grid( row=1, column=0, sticky="ew", pady=5) @@ -276,17 +317,40 @@ class CustomFileDialog(tk.Toplevel): self.file_list_frame.grid(row=2, column=0, sticky="nsew") self.bind("", self.on_window_resize) - bottom_frame = ttk.Frame(content_frame) - bottom_frame.grid(row=3, column=0, sticky="ew", pady=(5, 0)) - bottom_frame.grid_columnconfigure(0, weight=1) - self.status_bar = ttk.Label(bottom_frame, text="", anchor="w") + bottom_controls_frame = ttk.Frame(content_frame) + bottom_controls_frame.grid(row=3, column=0, sticky="ew", pady=(5, 0)) + bottom_controls_frame.grid_columnconfigure(0, weight=1) + + self.status_bar = ttk.Label(bottom_controls_frame, text="", anchor="w") self.status_bar.grid(row=0, column=0, sticky="ew") - action_buttons_frame = ttk.Frame(bottom_frame) - action_buttons_frame.grid(row=0, column=1) + + right_side_buttons_frame = ttk.Frame(bottom_controls_frame) + right_side_buttons_frame.grid(row=0, column=1, sticky="e") + + self.filter_combobox = ttk.Combobox( + right_side_buttons_frame, values=[ft[0] for ft in self.filetypes], state="readonly", width=20) + self.filter_combobox.pack(anchor="e", pady=(0, 5)) + self.filter_combobox.bind( + "<>", self.on_filter_change) + self.filter_combobox.set(self.filetypes[0][0]) + + action_buttons_frame = ttk.Frame(right_side_buttons_frame) + action_buttons_frame.pack(anchor="e", pady=(0, 10)) + ttk.Button(action_buttons_frame, text="Öffnen", command=self.on_open).pack(side="right") ttk.Button(action_buttons_frame, text="Abbrechen", - command=self.on_cancel).pack(side="right", padx=5, pady=15) + command=self.on_cancel).pack(side="right", padx=5) + + def toggle_hidden_files(self): + self.show_hidden_files.set(not self.show_hidden_files.get()) + if self.show_hidden_files.get(): + self.hidden_files_button.config(image=self.icons['unhide']) + Tooltip(self.hidden_files_button, "Versteckte Dateien ausblenden") + else: + self.hidden_files_button.config(image=self.icons['hide']) + Tooltip(self.hidden_files_button, "Versteckte Dateien anzeigen") + self.populate_files() def on_window_resize(self, event): new_width = self.file_list_frame.winfo_width() @@ -311,9 +375,7 @@ class CustomFileDialog(tk.Toplevel): self.path_entry.delete(0, tk.END) self.path_entry.insert(0, self.current_dir) self.selected_file = None - current_status = self.status_bar.cget("text") - if not current_status.startswith("Zeige"): - self.update_status_bar() + self.update_status_bar() if self.view_mode.get() == "list": self.populate_list_view() else: @@ -400,25 +462,36 @@ class CustomFileDialog(tk.Toplevel): def populate_list_view(self): tree_frame = ttk.Frame(self.file_list_frame) tree_frame.pack(fill='both', expand=True) - columns = ("name", "size", "type", "modified") - self.tree = ttk.Treeview(tree_frame, columns=columns, show="headings") - self.tree.heading("name", text="Name", anchor="w") - self.tree.column("name", anchor="w", width=300, stretch=True) + tree_frame.grid_rowconfigure(0, weight=1) + tree_frame.grid_columnconfigure(0, weight=1) + + columns = ("size", "type", "modified") + self.tree = ttk.Treeview( + tree_frame, columns=columns, show="tree headings") + + # Tree Column (#0) + self.tree.heading("#0", text="Name", anchor="w") + self.tree.column("#0", anchor="w", width=250, stretch=True) + + # Other Columns self.tree.heading("size", text="Größe", anchor="e") self.tree.column("size", anchor="e", width=120, stretch=False) self.tree.heading("type", text="Typ", anchor="w") self.tree.column("type", anchor="w", width=120, stretch=False) self.tree.heading("modified", text="Geändert am", anchor="w") self.tree.column("modified", anchor="w", width=160, stretch=False) + v_scrollbar = ttk.Scrollbar( tree_frame, orient="vertical", command=self.tree.yview) h_scrollbar = ttk.Scrollbar( tree_frame, orient="horizontal", command=self.tree.xview) self.tree.configure(yscrollcommand=v_scrollbar.set, xscrollcommand=h_scrollbar.set) - self.tree.pack(side="left", fill="both", expand=True) - v_scrollbar.pack(side="right", fill="y") - h_scrollbar.pack(side="bottom", fill="x") + + self.tree.grid(row=0, column=0, sticky='nsew') + v_scrollbar.grid(row=0, column=1, sticky='ns') + h_scrollbar.grid(row=1, column=0, sticky='ew') + self.tree.bind("", self.on_list_double_click) self.tree.bind("<>", self.on_list_select) @@ -426,7 +499,7 @@ class CustomFileDialog(tk.Toplevel): if warning: self.status_bar.config(text=warning) if error: - self.tree.insert("", "end", values=(error,)) + self.tree.insert("", "end", text=error, values=()) return for name in items: @@ -446,7 +519,7 @@ class CustomFileDialog(tk.Toplevel): icon, file_type, size = self.get_file_icon( name, 'small'), "Datei", self._format_size(stat.st_size) self.tree.insert("", "end", text=name, image=icon, values=( - name, size, file_type, modified_time)) + size, file_type, modified_time)) except (FileNotFoundError, PermissionError): continue @@ -468,7 +541,7 @@ class CustomFileDialog(tk.Toplevel): if not self.tree.selection(): return item_id = self.tree.selection()[0] - item_text = self.tree.item(item_id, 'values')[0] + item_text = self.tree.item(item_id, 'text') self.selected_file = os.path.join(self.current_dir, item_text) self.update_status_bar() @@ -492,7 +565,7 @@ class CustomFileDialog(tk.Toplevel): if not self.tree.selection(): return item_id = self.tree.selection()[0] - item_text = self.tree.item(item_id, 'values')[0] + item_text = self.tree.item(item_id, 'text') path = os.path.join(self.current_dir, item_text) if self._handle_unsupported_file(path): return @@ -530,6 +603,7 @@ class CustomFileDialog(tk.Toplevel): self.history_pos = len(self.history) - 1 self.populate_files() self.update_nav_buttons() + self.update_status_bar() except Exception as e: self.status_bar.config(text=f"Fehler: {e}") @@ -539,6 +613,7 @@ class CustomFileDialog(tk.Toplevel): self.current_dir = self.history[self.history_pos] self.populate_files() self.update_nav_buttons() + self.update_status_bar() def go_forward(self): if self.history_pos < len(self.history) - 1: @@ -546,6 +621,7 @@ class CustomFileDialog(tk.Toplevel): self.current_dir = self.history[self.history_pos] self.populate_files() self.update_nav_buttons() + self.update_status_bar() def update_nav_buttons(self): self.back_button.config( @@ -555,16 +631,21 @@ class CustomFileDialog(tk.Toplevel): def update_status_bar(self): try: - _, _, free = shutil.disk_usage(self.current_dir) + total, used, free = shutil.disk_usage(self.current_dir) free_str = self._format_size(free) - status_text = f"Freier Speicher: {free_str}" + self.storage_label.config(text=f"Freier Speicher: {free_str}") + self.storage_bar['value'] = (used / total) * 100 + + status_text = "" if self.selected_file and os.path.exists(self.selected_file) and not os.path.isdir(self.selected_file): size = os.path.getsize(self.selected_file) size_str = self._format_size(size) - status_text += f" | '{os.path.basename(self.selected_file)}' Größe: {size_str}" + status_text = f"'{os.path.basename(self.selected_file)}' Größe: {size_str}" self.status_bar.config(text=status_text) except FileNotFoundError: self.status_bar.config(text="Verzeichnis nicht gefunden") + self.storage_label.config(text="Freier Speicher: Unbekannt") + self.storage_bar['value'] = 0 def on_open(self): if self.selected_file and os.path.isfile(self.selected_file): diff --git a/mainwindow.py b/mainwindow.py index 00ce153..0610908 100644 --- a/mainwindow.py +++ b/mainwindow.py @@ -13,7 +13,7 @@ class GlotzMol(tk.Tk): self.title("Custom File Dialog Test") container = ttk.Frame(self, padding=10) - container.pack(fill="both", expand=True) + container.pack(fill="x", anchor="n") ttk.Label(container, text="Ausgewählte Datei:").grid( row=0, column=0, sticky="w") @@ -58,7 +58,7 @@ if __name__ == "__main__": style = ttk.Style(root) root.tk.call('source', f"{theme_path}/water.tcl") try: - root.tk.call('set_theme', 'dark') + root.tk.call('set_theme', 'light') except tk.TclError: pass root.mainloop()