import os import shutil import tkinter as tk from tkinter import ttk from typing import Dict, Any # To avoid circular import with custom_file_dialog.py from typing import TYPE_CHECKING if TYPE_CHECKING: from custom_file_dialog import CustomFileDialog from shared_libs.common_tools import Tooltip from shared_libs.animated_icon import AnimatedIcon, PIL_AVAILABLE from .cfd_app_config import LocaleStrings from .cfd_sftp_manager import PARAMIKO_AVAILABLE def get_xdg_user_dir(dir_key: str, fallback_name: str) -> str: """ Retrieves a user directory path from the XDG user-dirs.dirs config file. """ home = os.path.expanduser("~") fallback_path = os.path.join(home, fallback_name) config_path = os.path.join(home, ".config", "user-dirs.dirs") if not os.path.exists(config_path): return fallback_path try: with open(config_path, 'r') as f: for line in f: line = line.strip() if line.startswith(f"{dir_key}="): path = line.split('=', 1)[1].strip().strip('"') path = path.replace('$HOME', home) if not os.path.isabs(path): path = os.path.join(home, path) return path except Exception: pass return fallback_path class StyleManager: """Manages the visual styling of the application using ttk styles.""" def __init__(self, dialog: 'CustomFileDialog') -> None: self.dialog = dialog self.setup_styles() def setup_styles(self) -> None: style = ttk.Style(self.dialog) base_bg = self.dialog.cget('background') self.is_dark = sum(self.dialog.winfo_rgb(base_bg)) / 3 < 32768 if self.is_dark: self.selection_color = "#4a6984" self.icon_bg_color = "#3c3c3c" self.accent_color = "#2a2a2a" self.header = "#2b2b2b" self.hover_extrastyle = "#4a4a4a" self.hover_extrastyle2 = "#494949" self.sidebar_color = "#333333" self.bottom_color = self.accent_color self.color_foreground = "#ffffff" self.freespace_background = self.sidebar_color else: self.selection_color = "#cce5ff" self.icon_bg_color = base_bg self.accent_color = "#e0e0e0" self.header = "#d9d9d9" self.hover_extrastyle = "#f5f5f5" self.hover_extrastyle2 = "#494949" self.sidebar_color = "#e7e7e7" self.bottom_color = "#cecece" self.freespace_background = self.sidebar_color self.color_foreground = "#000000" style.configure("Header.TButton.Borderless.Round", background=self.header) style.map("Header.TButton.Borderless.Round", background=[ ('active', self.hover_extrastyle)]) style.configure("Header.TButton.Active.Round", background=self.selection_color) style.layout("Header.TButton.Active.Round", style.layout("Header.TButton.Borderless.Round")) style.map("Header.TButton.Active.Round", background=[ ('active', self.selection_color)]) style.configure("Dark.TButton.Borderless", anchor="w", background=self.sidebar_color, foreground=self.color_foreground, padding=(20, 5, 0, 5)) style.map("Dark.TButton.Borderless", background=[ ('active', self.hover_extrastyle2)]) style.configure("Accent.TFrame", background=self.header) style.configure("Accent.TLabel", background=self.header) style.configure("AccentBottom.TFrame", background=self.bottom_color) style.configure("AccentBottom.TLabel", background=self.bottom_color) style.configure("Sidebar.TFrame", background=self.sidebar_color) style.configure("Content.TFrame", background=self.icon_bg_color) 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', "black" if not self.is_dark else "white")]) style.configure("Icon.TLabel", background=self.icon_bg_color) style.map('Icon.TLabel', background=[ ('selected', self.selection_color)]) style.configure("Treeview.Heading", relief="flat", borderwidth=0, font=('TkDefaultFont', 10, 'bold')) style.configure("Treeview", rowheight=32, pady=2, background=self.icon_bg_color, fieldbackground=self.icon_bg_color, borderwidth=0) style.map("Treeview", background=[('selected', self.selection_color)], foreground=[ ('selected', "black" if not self.is_dark else "white")]) style.configure("TButton.Borderless.Round", anchor="w") style.configure("Small.Horizontal.TProgressbar", thickness=8) style.configure("Bottom.TButton.Borderless.Round", background=self.bottom_color) style.map("Bottom.TButton.Borderless.Round", background=[ ('active', self.hover_extrastyle)]) style.layout("Bottom.TButton.Borderless.Round", style.layout("Header.TButton.Borderless.Round")) class WidgetManager: """Manages the creation, layout, and management of all widgets in the dialog.""" def __init__(self, dialog: 'CustomFileDialog', settings: Dict[str, Any]) -> None: self.dialog = dialog self.style_manager = dialog.style_manager self.settings = settings self.setup_widgets() def _setup_top_bar(self, parent_frame: ttk.Frame) -> None: top_bar = ttk.Frame( parent_frame, style='Accent.TFrame', padding=(0, 5, 0, 5)) top_bar.grid(row=0, column=0, columnspan=2, sticky="ew") top_bar.grid_columnconfigure(1, weight=1) left_nav_container = ttk.Frame(top_bar, style='Accent.TFrame') left_nav_container.grid(row=0, column=0, sticky="w") left_nav_container.grid_propagate(False) self.back_button = ttk.Button(left_nav_container, image=self.dialog.icon_manager.get_icon( 'back'), command=self.dialog.navigation_manager.go_back, state=tk.DISABLED, style="Header.TButton.Borderless.Round") self.back_button.pack(side="left", padx=(10, 5)) Tooltip(self.back_button, LocaleStrings.UI["back"]) self.forward_button = ttk.Button(left_nav_container, image=self.dialog.icon_manager.get_icon( 'forward'), command=self.dialog.navigation_manager.go_forward, state=tk.DISABLED, style="Header.TButton.Borderless.Round") self.forward_button.pack(side="left", padx=5) Tooltip(self.forward_button, LocaleStrings.UI["forward"]) self.up_button = ttk.Button(left_nav_container, image=self.dialog.icon_manager.get_icon( 'up'), command=self.dialog.navigation_manager.go_up_level, style="Header.TButton.Borderless.Round") self.up_button.pack(side="left", padx=5) Tooltip(self.up_button, LocaleStrings.UI["up"]) self.home_button = ttk.Button(left_nav_container, image=self.dialog.icon_manager.get_icon( 'home'), command=lambda: self.dialog.navigation_manager.navigate_to(os.path.expanduser("~")), style="Header.TButton.Borderless.Round") self.home_button.pack(side="left", padx=(5, 10)) Tooltip(self.home_button, LocaleStrings.UI["home"]) path_search_container = ttk.Frame(top_bar, style='Accent.TFrame') path_search_container.grid(row=0, column=1, sticky="ew") path_search_container.grid_columnconfigure(0, weight=1) self.path_entry = ttk.Entry(path_search_container) self.path_entry.grid(row=0, column=0, sticky="ew") self.path_entry.bind( "", lambda e: self.dialog.navigation_manager.navigate_to(self.path_entry.get())) self.update_animation_icon = AnimatedIcon( path_search_container, width=20, height=20, animation_type="blink", use_pillow=PIL_AVAILABLE, bg=self.style_manager.header ) self.update_animation_icon.grid( row=0, column=1, sticky='e', padx=(5, 0)) self.update_animation_icon.grid_remove() # Initially hidden right_controls_container = ttk.Frame( top_bar, style='Accent.TFrame') right_controls_container.grid(row=0, column=2, sticky="e") self.responsive_buttons_container = ttk.Frame( right_controls_container, style='Accent.TFrame') self.responsive_buttons_container.pack(side="left") self.new_folder_button = ttk.Button(self.responsive_buttons_container, image=self.dialog.icon_manager.get_icon( 'new_folder_small'), command=self.dialog.file_op_manager.create_new_folder, style="Header.TButton.Borderless.Round") self.new_folder_button.pack(side="left", padx=5) Tooltip(self.new_folder_button, LocaleStrings.UI["new_folder"]) self.new_file_button = ttk.Button(self.responsive_buttons_container, image=self.dialog.icon_manager.get_icon( 'new_document_small'), command=self.dialog.file_op_manager.create_new_file, style="Header.TButton.Borderless.Round") self.new_file_button.pack(side="left", padx=5) Tooltip(self.new_file_button, LocaleStrings.UI["new_document"]) sftp_icon = self.dialog.icon_manager.get_icon('connect') if sftp_icon: self.sftp_button = ttk.Button(self.responsive_buttons_container, image=sftp_icon, command=self.dialog.open_sftp_dialog, style="Header.TButton.Borderless.Round") else: self.sftp_button = ttk.Button(self.responsive_buttons_container, text="SFTP", command=self.dialog.open_sftp_dialog, style="Header.TButton.Borderless.Round") self.sftp_button.pack(side="left", padx=5) Tooltip(self.sftp_button, LocaleStrings.UI["sftp_connection"]) if not PARAMIKO_AVAILABLE: self.sftp_button.config(state=tk.DISABLED) if self.dialog.dialog_mode == "open": self.new_folder_button.config(state=tk.DISABLED) self.new_file_button.config(state=tk.DISABLED) self.view_switch = ttk.Frame( self.responsive_buttons_container, padding=(5, 0), style='Accent.TFrame') self.view_switch.pack(side="left") self.icon_view_button = ttk.Button(self.view_switch, image=self.dialog.icon_manager.get_icon( 'icon_view'), command=self.dialog.view_manager.set_icon_view, style="Header.TButton.Active.Round") self.icon_view_button.pack(side="left", padx=5) Tooltip(self.icon_view_button, LocaleStrings.VIEW["icon_view"]) self.list_view_button = ttk.Button(self.view_switch, image=self.dialog.icon_manager.get_icon( 'list_view'), command=self.dialog.view_manager.set_list_view, style="Header.TButton.Borderless.Round") self.list_view_button.pack(side="left") Tooltip(self.list_view_button, LocaleStrings.VIEW["list_view"]) self.hidden_files_button = ttk.Button(self.responsive_buttons_container, image=self.dialog.icon_manager.get_icon( 'hide'), command=self.dialog.view_manager.toggle_hidden_files, style="Header.TButton.Borderless.Round") self.hidden_files_button.pack(side="left", padx=10) Tooltip(self.hidden_files_button, LocaleStrings.UI["show_hidden_files"]) self.more_button = ttk.Button(right_controls_container, text="...", command=self.dialog.show_more_menu, style="Header.TButton.Borderless.Round", width=3) def _setup_sidebar(self, parent_paned_window: ttk.PanedWindow) -> None: sidebar_frame = ttk.Frame( parent_paned_window, style="Sidebar.TFrame", padding=(0, 0, 0, 0), width=200) sidebar_frame.grid_propagate(False) sidebar_frame.bind("", self.dialog.on_sidebar_resize) parent_paned_window.add(sidebar_frame, weight=0) sidebar_frame.grid_rowconfigure(4, weight=1) self._setup_sidebar_bookmarks(sidebar_frame) separator_color = "#a9a9a9" if self.style_manager.is_dark else "#7c7c7c" tk.Frame(sidebar_frame, height=1, bg=separator_color).grid( row=1, column=0, sticky="ew", padx=20, pady=15) self._setup_sidebar_devices(sidebar_frame) tk.Frame(sidebar_frame, height=1, bg=separator_color).grid( row=3, column=0, sticky="ew", padx=20, pady=15) self._setup_sidebar_sftp_bookmarks(sidebar_frame) tk.Frame(sidebar_frame, height=1, bg=separator_color).grid( row=5, column=0, sticky="ew", padx=20, pady=15) self._setup_sidebar_storage(sidebar_frame) def _setup_sidebar_bookmarks(self, sidebar_frame: ttk.Frame) -> None: sidebar_buttons_frame = ttk.Frame( sidebar_frame, style="Sidebar.TFrame", padding=(0, 15, 0, 0)) sidebar_buttons_frame.grid(row=0, column=0, sticky="nsew") sidebar_buttons_config = [ {'name': LocaleStrings.NAV["computer"], 'icon': self.dialog.icon_manager.get_icon( 'computer_small'), 'path': '/'}, {'name': LocaleStrings.NAV["downloads"], 'icon': self.dialog.icon_manager.get_icon( 'downloads_small'), 'path': get_xdg_user_dir("XDG_DOWNLOAD_DIR", "Downloads")}, {'name': LocaleStrings.NAV["documents"], 'icon': self.dialog.icon_manager.get_icon( 'documents_small'), 'path': get_xdg_user_dir("XDG_DOCUMENTS_DIR", "Documents")}, {'name': LocaleStrings.NAV["pictures"], 'icon': self.dialog.icon_manager.get_icon( 'pictures_small'), 'path': get_xdg_user_dir("XDG_PICTURES_DIR", "Pictures")}, {'name': LocaleStrings.NAV["music"], 'icon': self.dialog.icon_manager.get_icon( 'music_small'), 'path': get_xdg_user_dir("XDG_MUSIC_DIR", "Music")}, {'name': LocaleStrings.NAV["videos"], 'icon': self.dialog.icon_manager.get_icon( 'video_small'), 'path': get_xdg_user_dir("XDG_VIDEO_DIR", "Videos")}, ] self.sidebar_buttons = [] for config in sidebar_buttons_config: # Special case for "Computer" button to not disconnect SFTP if config['path'] == '/': command = lambda p=config['path']: self.dialog.navigation_manager.navigate_to(p) else: command = lambda p=config['path']: self.dialog.handle_sidebar_bookmark_click(p) btn = ttk.Button(sidebar_buttons_frame, text=f" {config['name']}", image=config['icon'], compound="left", command=command, style="Dark.TButton.Borderless") btn.pack(fill="x", pady=1) self.sidebar_buttons.append((btn, f" {config['name']}")) def _setup_sidebar_sftp_bookmarks(self, sidebar_frame: ttk.Frame) -> None: self.sftp_bookmarks_frame = ttk.Frame( sidebar_frame, style="Sidebar.TFrame") self.sftp_bookmarks_frame.grid(row=4, column=0, sticky="nsew", padx=10) self.sftp_bookmarks_frame.grid_columnconfigure(0, weight=1) bookmarks = self.dialog.config_manager.load_bookmarks() if not bookmarks: return ttk.Label(self.sftp_bookmarks_frame, text=LocaleStrings.UI["sftp_bookmarks"], background=self.style_manager.sidebar_color, foreground=self.style_manager.color_foreground).grid(row=0, column=0, sticky="ew", padx=10, pady=(5, 0)) self.sftp_bookmark_buttons = [] sftp_bookmark_icon = self.dialog.icon_manager.get_icon('star') row_counter = 1 for name, data in bookmarks.items(): if sftp_bookmark_icon: btn = ttk.Button(self.sftp_bookmarks_frame, text=f" {name}", image=sftp_bookmark_icon, compound="left", command=lambda d=data: self.dialog.connect_sftp_bookmark(d), style="Dark.TButton.Borderless") else: btn = ttk.Button(self.sftp_bookmarks_frame, text=f" {name}", compound="left", command=lambda d=data: self.dialog.connect_sftp_bookmark(d), style="Dark.TButton.Borderless") btn.grid(row=row_counter, column=0, sticky="ew") row_counter += 1 btn.bind("", lambda event, n=name, d=data: self._show_sftp_bookmark_context_menu(event, n, d)) self.sftp_bookmark_buttons.append(btn) def _show_sftp_bookmark_context_menu(self, event, name, data): context_menu = tk.Menu(self.dialog, tearoff=0) edit_icon = self.dialog.icon_manager.get_icon('key_small') context_menu.add_command( label="Edit Bookmark", # Replace with LocaleString later image=edit_icon, compound=tk.LEFT, command=lambda: self.dialog.edit_sftp_bookmark(name, data)) trash_icon = self.dialog.icon_manager.get_icon('trash_small2') context_menu.add_command( label=LocaleStrings.UI["remove_bookmark"], image=trash_icon, compound=tk.LEFT, command=lambda: self.dialog.remove_sftp_bookmark(name)) context_menu.tk_popup(event.x_root, event.y_root) def _setup_sidebar_devices(self, sidebar_frame: ttk.Frame) -> None: mounted_devices_frame = ttk.Frame( sidebar_frame, style="Sidebar.TFrame") mounted_devices_frame.grid(row=2, column=0, sticky="nsew", padx=10) mounted_devices_frame.grid_columnconfigure(0, weight=1) ttk.Label(mounted_devices_frame, text=LocaleStrings.UI["devices"], background=self.style_manager.sidebar_color, foreground=self.style_manager.color_foreground).grid(row=0, column=0, sticky="ew", padx=10, pady=(5, 0)) self.devices_canvas = tk.Canvas( mounted_devices_frame, highlightthickness=0, bg=self.style_manager.sidebar_color, height=150, width=180) self.devices_scrollbar = ttk.Scrollbar( mounted_devices_frame, orient="vertical", command=self.devices_canvas.yview) self.devices_canvas.configure( yscrollcommand=self.devices_scrollbar.set) self.devices_canvas.grid(row=1, column=0, sticky="nsew") self.devices_scrollable_frame = ttk.Frame( self.devices_canvas, style="Sidebar.TFrame") self.devices_canvas_window = self.devices_canvas.create_window( (0, 0), window=self.devices_scrollable_frame, anchor="nw") def _configure_devices_canvas(event: tk.Event) -> None: self.devices_canvas.configure( scrollregion=self.devices_canvas.bbox("all")) canvas_width = event.width self.devices_canvas.itemconfig( self.devices_canvas_window, width=canvas_width) self.devices_scrollable_frame.bind("", lambda e: self.devices_canvas.configure( scrollregion=self.devices_canvas.bbox("all"))) self.devices_canvas.bind("", _configure_devices_canvas) def _on_devices_mouse_wheel(event: tk.Event) -> None: if event.num == 4: delta = -1 elif event.num == 5: delta = 1 else: delta = -1 * int(event.delta / 120) self.devices_canvas.yview_scroll(delta, "units") for widget in [self.devices_canvas, self.devices_scrollable_frame]: widget.bind("", _on_devices_mouse_wheel) widget.bind("", _on_devices_mouse_wheel) widget.bind("", _on_devices_mouse_wheel) self.device_buttons = [] for device_name, mount_point, removable in self.dialog._get_mounted_devices(): icon = self.dialog.icon_manager.get_icon( 'usb_small') if removable else self.dialog.icon_manager.get_icon('device_small') button_text = f" {device_name}" if len(device_name) > 15: button_text = f" {device_name[:15]}\n{device_name[15:]}" btn = ttk.Button(self.devices_scrollable_frame, text=button_text, image=icon, compound="left", command=lambda p=mount_point: self.dialog.handle_sidebar_bookmark_click(p), style="Dark.TButton.Borderless") btn.pack(fill="x", pady=1) self.device_buttons.append((btn, button_text)) for w in [btn, self.devices_canvas, self.devices_scrollable_frame]: w.bind("", _on_devices_mouse_wheel) w.bind("", _on_devices_mouse_wheel) w.bind("", _on_devices_mouse_wheel) try: total, used, _ = shutil.disk_usage(mount_point) progress_bar = ttk.Progressbar(self.devices_scrollable_frame, orient="horizontal", length=100, mode="determinate", style='Small.Horizontal.TProgressbar') progress_bar.pack(fill="x", pady=(2, 8), padx=25) progress_bar['value'] = (used / total) * 100 for w in [progress_bar]: w.bind("", _on_devices_mouse_wheel) w.bind("", _on_devices_mouse_wheel) w.bind("", _on_devices_mouse_wheel) except (FileNotFoundError, PermissionError): pass def _setup_sidebar_storage(self, sidebar_frame: ttk.Frame) -> None: storage_frame = ttk.Frame(sidebar_frame, style="Sidebar.TFrame") storage_frame.grid(row=6, column=0, sticky="sew", padx=10, pady=10) self.storage_label = ttk.Label( storage_frame, text=f"{LocaleStrings.CFD['free_space']}", background=self.style_manager.freespace_background) self.storage_label.pack(fill="x", padx=10) self.storage_bar = ttk.Progressbar( storage_frame, orient="horizontal", length=100, mode="determinate") self.storage_bar.pack(fill="x", pady=(2, 5), padx=15) def _setup_bottom_bar(self) -> None: self.action_status_frame = ttk.Frame( self.content_frame, style="AccentBottom.TFrame") self.action_status_frame.grid( row=1, column=0, sticky="ew", pady=(5, 5), padx=10) self.status_container = ttk.Frame( self.action_status_frame, style="AccentBottom.TFrame") self.left_container = ttk.Frame( self.action_status_frame, style="AccentBottom.TFrame") self.center_container = ttk.Frame( self.action_status_frame, style="AccentBottom.TFrame") self.right_container = ttk.Frame( self.action_status_frame, style="AccentBottom.TFrame") self.action_status_frame.grid_columnconfigure(1, weight=1) self.action_status_frame.grid_rowconfigure(0, weight=1) self.left_container.grid(row=0, column=0, sticky='nsw', pady=(5, 0)) self.center_container.grid( row=0, column=1, sticky='nsew', padx=5, pady=(5, 0)) self.right_container.grid(row=0, column=2, sticky='nse', pady=(5, 0)) self.separator_color = "#a9a9a9" if self.style_manager.is_dark else "#7c7c7c" self.separator = tk.Frame( self.action_status_frame, height=1, bg=self.separator_color) self.separator.grid(row=1, column=0, columnspan=3, sticky="ew", pady=(4, 0)) self.status_container.grid(row=2, column=0, columnspan=3, sticky='ew') self.search_status_label = ttk.Label( self.status_container, text="", style="AccentBottom.TLabel") self.filename_entry = ttk.Entry(self.center_container) self.settings_button = ttk.Button(self.action_status_frame, image=self.dialog.icon_manager.get_icon('settings-2_small'), command=self.dialog.open_settings_dialog, style="Bottom.TButton.Borderless.Round") self.search_animation = AnimatedIcon(self.status_container, width=23, height=23, bg=self.style_manager.bottom_color, animation_type=self.settings.get('animation_type', 'counter_arc')) self.search_animation.grid( row=0, column=0, sticky='w', padx=(0, 5), pady=(4, 0)) self.search_animation.bind( "", lambda e: self.dialog.search_manager.activate_search()) self.search_status_label.grid(row=0, column=1, sticky="w") button_box_pos = self.settings.get("button_box_pos", "left") if self.dialog.dialog_mode == "save": self.trash_button = ttk.Button(self.action_status_frame, image=self.dialog.icon_manager.get_icon('trash_small2'), command=self.dialog.file_op_manager.delete_selected_item, style="Bottom.TButton.Borderless.Round") Tooltip(self.trash_button, LocaleStrings.UI["delete_move"]) self.save_button = ttk.Button( self.action_status_frame, text=LocaleStrings.SET["save_button"], command=self.dialog.on_save) self.cancel_button = ttk.Button( self.action_status_frame, text=LocaleStrings.SET["cancel_button"], command=self.dialog.on_cancel) self.filter_combobox = ttk.Combobox(self.center_container, values=[ ft[0] for ft in self.dialog.filetypes], state="readonly") self.filter_combobox.bind( "<>", self.dialog.view_manager.on_filter_change) self.filter_combobox.set(self.dialog.filetypes[0][0]) self.center_container.grid_rowconfigure(0, weight=1) self.filename_entry.grid( row=0, column=0, columnspan=2, sticky="ew") self._layout_bottom_buttons(button_box_pos) else: # Open mode self.open_button = ttk.Button( self.action_status_frame, text=LocaleStrings.CFD["open"], command=self.dialog.on_open) self.cancel_button = ttk.Button( self.action_status_frame, text=LocaleStrings.CFD["cancel"], command=self.dialog.on_cancel) self.filter_combobox = ttk.Combobox(self.center_container, values=[ ft[0] for ft in self.dialog.filetypes], state="readonly") self.filter_combobox.bind( "<>", self.dialog.view_manager.on_filter_change) self.filter_combobox.set(self.dialog.filetypes[0][0]) self.center_container.grid_rowconfigure(0, weight=1) self.filename_entry.grid( row=0, column=0, columnspan=2, sticky="ew") self._layout_bottom_buttons(button_box_pos) def _layout_bottom_buttons(self, button_box_pos: str) -> None: self.left_container.grid_rowconfigure(0, weight=1) self.right_container.grid_rowconfigure(0, weight=1) action_button = self.save_button if self.dialog.dialog_mode == "save" else self.open_button action_container = self.left_container if button_box_pos == 'left' else self.right_container other_container = self.right_container if button_box_pos == 'left' else self.left_container action_button.grid(in_=action_container, row=0, column=0, pady=(0, 5)) self.cancel_button.grid(in_=action_container, row=1, column=0) if button_box_pos == 'left': self.settings_button.grid( in_=other_container, row=0, column=0, sticky="ne") if self.dialog.dialog_mode == "save": self.trash_button.grid( in_=other_container, row=1, column=0, sticky="se", padx=(5, 0)) else: # right self.settings_button.grid( in_=action_container, row=0, column=1, sticky="ne", padx=(5, 0)) if self.dialog.dialog_mode == "save": self.trash_button.grid( in_=other_container, row=0, column=0, sticky="sw") if button_box_pos == 'left': self.center_container.grid_columnconfigure(0, weight=1) self.filter_combobox.grid( in_=self.center_container, row=1, column=0, sticky="w", pady=(5, 0)) else: # right self.center_container.grid_columnconfigure(1, weight=1) self.filter_combobox.grid( in_=self.center_container, row=1, column=1, sticky="e", pady=(5, 0)) def setup_widgets(self) -> None: main_frame = ttk.Frame(self.dialog, style='Accent.TFrame') main_frame.pack(fill="both", expand=True) main_frame.grid_rowconfigure(2, weight=1) main_frame.grid_columnconfigure(0, weight=1) self._setup_top_bar(main_frame) separator_color = "#000000" if self.style_manager.is_dark else "#9c9c9c" tk.Frame(main_frame, height=1, bg=separator_color).grid( row=1, column=0, columnspan=2, sticky="ew") paned_window = ttk.PanedWindow( main_frame, orient=tk.HORIZONTAL, style="Sidebar.TFrame") paned_window.grid(row=2, column=0, columnspan=2, sticky="nsew") self._setup_sidebar(paned_window) self.content_frame = ttk.Frame(paned_window, padding=( 0, 0, 0, 0), style="AccentBottom.TFrame") paned_window.add(self.content_frame, weight=1) self.content_frame.grid_rowconfigure(0, weight=1) self.content_frame.grid_columnconfigure(0, weight=1) self.file_list_frame = ttk.Frame( self.content_frame, style="Content.TFrame") self.file_list_frame.grid(row=0, column=0, sticky="nsew") self.dialog.bind("", self.dialog.on_window_resize) self._setup_bottom_bar()