diff --git a/__pycache__/custom_file_dialog.cpython-312.pyc b/__pycache__/custom_file_dialog.cpython-312.pyc index 55022aa..60448b1 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 ac20fda..b609065 100644 --- a/custom_file_dialog.py +++ b/custom_file_dialog.py @@ -71,6 +71,7 @@ class CustomFileDialog(tk.Toplevel): self.history = [self.current_dir] self.history_pos = 0 self.view_mode = tk.StringVar(value="icons") + self.show_hidden_files = tk.BooleanVar(value=False) self.resize_job = None self.last_width = 0 @@ -81,35 +82,120 @@ class CustomFileDialog(tk.Toplevel): self.after(50, self.populate_files) def load_icons(self): + self.icons = {} try: - self.folder_icon_large = tk.PhotoImage( - file="./folder-water-64.png").zoom(1) - self.file_icon_large = tk.PhotoImage( - file="./document-64.png").zoom(1) - self.iso_icon_large = tk.PhotoImage( - file="./media-optical-64.png").zoom(1) - self.folder_icon_small = tk.PhotoImage( + # Sidebar Icons + self.icons['downloads_small'] = tk.PhotoImage( + file="./folder-water-download-32.png") + self.icons['documents_small'] = tk.PhotoImage( + file="./folder-water-documents-32.png") + self.icons['pictures_small'] = tk.PhotoImage( + file="./folder-water-pictures-32.png") + self.icons['music_small'] = tk.PhotoImage( + file="./folder-water-music-32.png") + self.icons['video_small'] = tk.PhotoImage( + file="./folder-water-video-32.png") + + # File Icons (Large) + self.icons['folder_large'] = tk.PhotoImage( file="./folder-water-64.png") - self.file_icon_small = tk.PhotoImage(file="./document-64.png") - self.iso_icon_small = tk.PhotoImage(file="./media-optical-64.png") + self.icons['file_large'] = tk.PhotoImage(file="./document-64.png") + self.icons['python_large'] = tk.PhotoImage( + file="./file-python-64.png") + self.icons['pdf_large'] = tk.PhotoImage(file="./pdf-64.png") + self.icons['archive_large'] = tk.PhotoImage(file="./tar-64.png") + self.icons['audio_large'] = tk.PhotoImage(file="./audio-64.png") + self.icons['video_large'] = tk.PhotoImage(file="./video-64.png") + self.icons['picture_large'] = tk.PhotoImage( + file="./picture-64.png") + self.icons['iso_large'] = tk.PhotoImage( + file="./media-optical-64.png") + + # File Icons (Small) + self.icons['folder_small'] = tk.PhotoImage( + file="./folder-water-32.png") + self.icons['file_small'] = tk.PhotoImage(file="./document-32.png") + self.icons['python_small'] = tk.PhotoImage( + file="./file-python-32.png") + self.icons['pdf_small'] = tk.PhotoImage(file="./pdf-32.png") + self.icons['archive_small'] = tk.PhotoImage(file="./tar-32.png") + self.icons['audio_small'] = tk.PhotoImage(file="./audio-32.png") + self.icons['video_small_file'] = tk.PhotoImage( + file="./video-32.png") + self.icons['picture_small'] = tk.PhotoImage( + file="./picture-32.png") + self.icons['iso_small'] = tk.PhotoImage( + file="./media-optical-32.png") + except tk.TclError: - self.folder_icon_large = tk.PhotoImage(width=48, height=48) - self.file_icon_large = tk.PhotoImage(width=48, height=48) - self.iso_icon_large = tk.PhotoImage(width=48, height=48) - self.folder_icon_small = tk.PhotoImage(width=16, height=16) - self.file_icon_small = tk.PhotoImage(width=16, height=16) - self.iso_icon_small = tk.PhotoImage(width=16, height=16) + # Fallback if icons are missing + for key in ['downloads_small', 'documents_small', 'pictures_small', 'music_small', 'video_small', + 'folder_large', 'file_large', 'python_large', 'pdf_large', 'archive_large', 'audio_large', 'video_large', 'picture_large', 'iso_large', + 'folder_small', 'file_small', 'python_small', 'pdf_small', 'archive_small', 'audio_small', 'video_small_file', 'picture_small', 'iso_small']: + self.icons[key] = tk.PhotoImage( + width=32, height=32) if 'small' in key else tk.PhotoImage(width=64, height=64) + + def get_file_icon(self, filename, size='large'): + ext = os.path.splitext(filename)[1].lower() + if ext == '.py': + return self.icons[f'python_{size}'] + elif ext == '.pdf': + return self.icons[f'pdf_{size}'] + elif ext in ['.tar', '.zip', '.rar', '.7z']: + return self.icons[f'archive_{size}'] + elif ext in ['.mp3', '.wav', '.ogg', '.flac']: + return self.icons[f'audio_{size}'] + elif ext in ['.mp4', '.mkv', '.avi', '.mov']: + return self.icons[f'video_{size}'] if size == 'large' else self.icons['video_small_file'] + elif ext in ['.jpg', '.jpeg', '.png', '.gif', '.bmp']: + return self.icons[f'picture_{size}'] + elif ext == '.iso': + return self.icons[f'iso_{size}'] + else: + return self.icons[f'file_{size}'] def create_styles(self): style = ttk.Style(self) - self.selection_color = "#0078D7" + + # Check for dark theme + try: + theme_bg = style.lookup('TFrame', 'background') + is_dark = sum(self.winfo_rgb(theme_bg)) / 3 < 32768 + except tk.TclError: + is_dark = False + + # --- Theme-Aware Colors --- + if is_dark: + self.selection_color = "#494949" + self.selection_fg_color = "white" + self.icon_bg_color = style.lookup('TFrame', 'background') + else: + self.selection_color = "#D5E5F5" + self.selection_fg_color = "black" + self.icon_bg_color = style.lookup('TFrame', 'background') + + # --- Style Definitions --- + style.configure("Item.TFrame", background=self.icon_bg_color) style.map('Item.TFrame', background=[ ('selected', self.selection_color)]) + + style.configure("Item.TLabel", background=self.icon_bg_color) + style.map('Item.TLabel', + background=[('selected', self.selection_color)], + foreground=[('selected', self.selection_fg_color)]) + + # Style for the icon label itself + style.configure("Icon.TLabel", background=self.icon_bg_color) + style.map('Icon.TLabel', background=[('selected', self.selection_color)]) + style.configure("Treeview.Heading", relief="raised", borderwidth=1, font=('TkDefaultFont', 10, 'bold')) - style.configure("Treeview", rowheight=24) - style.layout("Treeview.Row", - [('Treeview.row', {'children': [('Treeview.padding', {'children': [('Treeview.indicator', {'side': 'left', 'sticky': 'ns'}), ('Treeview.image', {'side': 'left', 'sticky': 'ns'}), ('Treeview.text', {'side': 'left', 'sticky': 'ns'})], 'sticky': 'nsew'})], 'sticky': 'nsew'})]) + style.configure("Treeview", rowheight=28) + style.configure("Content.TFrame", background=self.icon_bg_color) + + style.map("Treeview", + background=[('selected', self.selection_color)], + foreground=[('selected', self.selection_fg_color)]) def create_widgets(self): main_frame = ttk.Frame(self, padding="10") @@ -137,19 +223,19 @@ class CustomFileDialog(tk.Toplevel): sidebar_buttons_frame = ttk.Frame(sidebar_frame) sidebar_buttons_frame.grid(row=1, column=0, sticky="nsew") sidebar_buttons_config = [ - {'name': 'Downloads', 'unicode': '📥', 'path': os.path.join( + {'name': 'Downloads', 'icon': self.icons['downloads_small'], 'path': os.path.join( os.path.expanduser("~"), "Downloads")}, - {'name': 'Dokumente', 'unicode': '📄', 'path': os.path.join( + {'name': 'Dokumente', 'icon': self.icons['documents_small'], 'path': os.path.join( os.path.expanduser("~"), "Documents")}, - {'name': 'Bilder', 'unicode': '🖼️', 'path': os.path.join( + {'name': 'Bilder', 'icon': self.icons['pictures_small'], 'path': os.path.join( os.path.expanduser("~"), "Pictures")}, - {'name': 'Musik', 'unicode': '🎵', 'path': os.path.join( + {'name': 'Musik', 'icon': self.icons['music_small'], 'path': os.path.join( os.path.expanduser("~"), "Music")}, - {'name': 'Videos', 'unicode': '🎬', 'path': os.path.join( + {'name': 'Videos', 'icon': self.icons['video_small'], 'path': os.path.join( os.path.expanduser("~"), "Videos")}, ] for config in sidebar_buttons_config: - btn = ttk.Button(sidebar_buttons_frame, text=f" {config['unicode']} {config['name']}", + btn = ttk.Button(sidebar_buttons_frame, text=f" {config['name']}", image=config['icon'], compound="left", command=lambda p=config['path']: self.navigate_to(p), style="Sidebar.TButton") btn.pack(fill="x", pady=1) ttk.Style().configure("Sidebar.TButton", anchor="w", padding=5) @@ -164,20 +250,25 @@ class CustomFileDialog(tk.Toplevel): 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.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=1) + 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=15) - self.filter_combobox.grid(row=0, column=2, padx=5) + 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]) - self.file_list_frame = ttk.Frame(content_frame) + self.file_list_frame = ttk.Frame(content_frame, style="Content.TFrame") self.file_list_frame.grid(row=1, column=0, sticky="nsew") self.bind("", self.on_window_resize) @@ -214,15 +305,13 @@ class CustomFileDialog(tk.Toplevel): self.populate_icon_view() def populate_icon_view(self): - canvas = tk.Canvas(self.file_list_frame, highlightthickness=0) + canvas = tk.Canvas(self.file_list_frame, + highlightthickness=0, bg=self.icon_bg_color) v_scrollbar = ttk.Scrollbar( self.file_list_frame, orient="vertical", command=canvas.yview) - style = ttk.Style(self) - bg_color = style.lookup("TFrame", "background") - canvas.configure(bg=bg_color) canvas.pack(side="left", fill="both", expand=True) v_scrollbar.pack(side="right", fill="y") - container_frame = ttk.Frame(canvas, style="TFrame") + container_frame = ttk.Frame(canvas, style="Content.TFrame") self.container_frame = container_frame canvas.create_window((0, 0), window=container_frame, anchor="nw") container_frame.bind("", lambda e: canvas.configure( @@ -240,6 +329,8 @@ class CustomFileDialog(tk.Toplevel): col_count = max(1, frame_width // item_width) row, col = 0, 0 for name in sorted(items, key=str.lower): + if not self.show_hidden_files.get() and name.startswith('.'): + continue path = os.path.join(self.current_dir, name) is_dir = os.path.isdir(path) if not is_dir and not self._matches_filetype(name): @@ -250,12 +341,12 @@ class CustomFileDialog(tk.Toplevel): item_frame.grid(row=row, column=col, padx=5, pady=5) item_frame.grid_propagate(False) - icon = self.folder_icon_large if is_dir else ( - self.iso_icon_large if name.lower().endswith(".iso") else self.file_icon_large) - icon_label = ttk.Label(item_frame, image=icon) + icon = self.icons['folder_large'] if is_dir else self.get_file_icon( + name, 'large') + icon_label = ttk.Label(item_frame, image=icon, style="Icon.TLabel") icon_label.pack(pady=(10, 5)) name_label = ttk.Label( - item_frame, text=self.shorten_text(name, 15), anchor="center") + item_frame, text=self.shorten_text(name, 15), anchor="center", style="Item.TLabel") name_label.pack(fill="x", expand=True) Tooltip(item_frame, name) @@ -263,7 +354,7 @@ class CustomFileDialog(tk.Toplevel): widget.bind("", lambda e, p=path: self.on_item_double_click(p)) widget.bind("", lambda e, - p=path: self.on_item_select(p, item_frame)) + p=path, f=item_frame: self.on_item_select(p, f)) col += 1 if col >= col_count: @@ -301,6 +392,8 @@ class CustomFileDialog(tk.Toplevel): return for name in sorted(items, key=str.lower): + if not self.show_hidden_files.get() and name.startswith('.'): + continue path = os.path.join(self.current_dir, name) is_dir = os.path.isdir(path) if not is_dir and not self._matches_filetype(name): @@ -310,12 +403,11 @@ class CustomFileDialog(tk.Toplevel): modified_time = datetime.fromtimestamp( stat.st_mtime).strftime('%d.%m.%Y %H:%M') if is_dir: - icon = self.folder_icon_small + icon = self.icons['folder_small'] file_type = "Ordner" size = "" else: - icon = self.iso_icon_small if name.lower().endswith( - ".iso") else self.file_icon_small + icon = self.get_file_icon(name, 'small') file_type = "Datei" size = self._format_size(stat.st_size) self.tree.insert("", "end", text=name, image=icon, values=( @@ -324,16 +416,28 @@ class CustomFileDialog(tk.Toplevel): continue def on_item_select(self, path, item_frame): - for child in self.container_frame.winfo_children(): - child.state(['!selected']) + if hasattr(self, 'selected_item_frame') and self.selected_item_frame and self.selected_item_frame.winfo_exists(): + self.selected_item_frame.state(['!selected']) + # Also revert the style of the labels inside the old frame + for child in self.selected_item_frame.winfo_children(): + if isinstance(child, ttk.Label): + child.state(['!selected']) + item_frame.state(['selected']) + # Also apply the style to the labels inside the new frame + for child in item_frame.winfo_children(): + if isinstance(child, ttk.Label): + child.state(['selected']) + + self.selected_item_frame = item_frame self.selected_file = path self.update_status_bar() def on_list_select(self, event): if not self.tree.selection(): return - item_text = self.tree.item(self.tree.selection()[0])['text'] + item_id = self.tree.selection()[0] + item_text = self.tree.item(item_id, 'values')[0] self.selected_file = os.path.join(self.current_dir, item_text) self.update_status_bar() @@ -347,7 +451,8 @@ class CustomFileDialog(tk.Toplevel): def on_list_double_click(self, event): if not self.tree.selection(): return - item_text = self.tree.item(self.tree.selection()[0])['text'] + item_id = self.tree.selection()[0] + item_text = self.tree.item(item_id, 'values')[0] path = os.path.join(self.current_dir, item_text) if os.path.isdir(path): self.navigate_to(path) @@ -366,18 +471,18 @@ class CustomFileDialog(tk.Toplevel): def navigate_to(self, path): home_dir = os.path.expanduser("~") abs_path = os.path.abspath(path) - if os.path.isdir(abs_path) and abs_path.startswith(home_dir): + if os.path.isdir(abs_path): # and abs_path.startswith(home_dir): self.current_dir = abs_path if self.history_pos < len(self.history) - 1: self.history = self.history[:self.history_pos + 1] - if self.history[-1] != self.current_dir: + if not self.history or self.history[-1] != self.current_dir: self.history.append(self.current_dir) - self.history_pos += 1 + self.history_pos = len(self.history) - 1 self.populate_files() self.update_nav_buttons() - else: - print( - f"Info: Navigation außerhalb von {home_dir} ist nicht erlaubt.") + # else: + # print( + # f"Info: Navigation außerhalb von {home_dir} ist nicht erlaubt.") def go_back(self): if self.history_pos > 0: diff --git a/mainwindow.py b/mainwindow.py index b60280e..d5a7d1c 100644 --- a/mainwindow.py +++ b/mainwindow.py @@ -19,7 +19,7 @@ class GlotzMol(tk.Tk): def customtest(self): dialog = CustomFileDialog(self, initial_dir="/home/punix/Downloads", - filetypes=[("ISO files", "*.iso")]) + filetypes=[("ISO files", "*.iso"), ("All files", "*.*")]) path = dialog.get_selected_file() if path: