commit 40

This commit is contained in:
2025-08-02 21:40:06 +02:00
parent 07751e5c9a
commit 2b09721fec
5 changed files with 82 additions and 123 deletions

View File

@@ -2,60 +2,7 @@ import os
import shutil
import tkinter as tk
from tkinter import ttk
import subprocess
import json
from shared_libs.common_tools import Tooltip, LxTools
class InputDialog(tk.Toplevel):
def __init__(self, parent, title, prompt):
super().__init__(parent)
self.title(title)
self.prompt = prompt
self.result = None
self.transient(parent)
self.grab_set()
self.setup_widgets()
LxTools.center_window_cross_platform(self, 300, 120)
self.entry.focus_set()
self.bind("<Return>", self.on_ok)
self.bind("<Escape>", self.on_cancel)
self.protocol("WM_DELETE_WINDOW", self.on_cancel)
self.wait_window(self)
def setup_widgets(self):
main_frame = ttk.Frame(self, padding=10)
main_frame.pack(fill="both", expand=True)
ttk.Label(main_frame, text=self.prompt).pack(pady=5)
self.entry = ttk.Entry(main_frame, width=40)
self.entry.pack(pady=5, padx=5)
button_frame = ttk.Frame(main_frame)
button_frame.pack(pady=10)
ok_button = ttk.Button(button_frame, text="OK", command=self.on_ok)
ok_button.pack(side="left", padx=5)
cancel_button = ttk.Button(
button_frame, text="Abbrechen", command=self.on_cancel)
cancel_button.pack(side="left", padx=5)
def on_ok(self, event=None):
self.result = self.entry.get()
self.destroy()
def on_cancel(self, event=None):
self.result = None
self.destroy()
def get_input(self):
return self.result
from shared_libs.common_tools import Tooltip
def get_xdg_user_dir(dir_key, fallback_name):
@@ -178,12 +125,12 @@ class WidgetManager:
self.back_button = ttk.Button(nav_buttons_container, image=self.dialog.icon_manager.get_icon(
'back'), command=self.dialog.go_back, state=tk.DISABLED, style="Header.TButton.Borderless.Round")
self.back_button.pack(side="left", padx=10)
self.back_button.pack(side="left", padx=20)
Tooltip(self.back_button, "Zurück")
self.forward_button = ttk.Button(nav_buttons_container, image=self.dialog.icon_manager.get_icon(
'forward'), command=self.dialog.go_forward, state=tk.DISABLED, style="Header.TButton.Borderless.Round")
self.forward_button.pack(side="left")
self.forward_button.pack(side="left", padx=(0, 20))
Tooltip(self.forward_button, "Vorwärts")
self.home_button = ttk.Button(nav_buttons_container, image=self.dialog.icon_manager.get_icon(
@@ -201,16 +148,6 @@ class WidgetManager:
right_top_bar_frame = ttk.Frame(top_bar, style='Accent.TFrame')
right_top_bar_frame.grid(row=0, column=2, sticky="e")
self.new_folder_button = ttk.Button(right_top_bar_frame, image=self.dialog.icon_manager.get_icon(
'new_folder_small'), command=self.dialog.create_new_folder, style="Header.TButton.Borderless.Round")
self.new_folder_button.pack(side="left", padx=5)
Tooltip(self.new_folder_button, "Neuen Ordner erstellen")
self.new_file_button = ttk.Button(right_top_bar_frame, image=self.dialog.icon_manager.get_icon(
'new_document_small'), command=self.dialog.create_new_file, style="Header.TButton.Borderless.Round")
self.new_file_button.pack(side="left", padx=(0, 10))
Tooltip(self.new_file_button, "Neues Dokument erstellen")
# Search button and options container
search_container = ttk.Frame(
right_top_bar_frame, style='Accent.TFrame')
@@ -232,13 +169,23 @@ class WidgetManager:
self.recursive_button.pack(side="left", padx=2)
Tooltip(self.recursive_button, "Rekursive Suche ein/ausschalten")
self.new_folder_button = ttk.Button(right_top_bar_frame, image=self.dialog.icon_manager.get_icon(
'new_folder_small'), command=self.dialog.create_new_folder, style="Header.TButton.Borderless.Round")
self.new_folder_button.pack(side="left", padx=5)
Tooltip(self.new_folder_button, "Neuen Ordner erstellen")
self.new_file_button = ttk.Button(right_top_bar_frame, image=self.dialog.icon_manager.get_icon(
'new_document_small'), command=self.dialog.create_new_file, style="Header.TButton.Borderless.Round")
self.new_file_button.pack(side="left", padx=(0, 10))
Tooltip(self.new_file_button, "Neues Dokument erstellen")
view_switch = ttk.Frame(right_top_bar_frame,
padding=(5, 0), style='Accent.TFrame')
view_switch.pack(side="left")
self.icon_view_button = ttk.Button(view_switch, image=self.dialog.icon_manager.get_icon(
'icon_view'), command=self.dialog.set_icon_view, style="Header.TButton.Active.Round")
self.icon_view_button.pack(side="left", padx=(50, 10))
self.icon_view_button.pack(side="left", padx=(5, 10))
Tooltip(self.icon_view_button, "Kachelansicht")
self.list_view_button = ttk.Button(view_switch, image=self.dialog.icon_manager.get_icon(
@@ -257,7 +204,8 @@ class WidgetManager:
row=1, column=0, columnspan=2, sticky="ew")
# PanedWindow for resizable sidebar and content
paned_window = ttk.PanedWindow(main_frame, orient=tk.HORIZONTAL)
paned_window = ttk.PanedWindow(
main_frame, orient=tk.HORIZONTAL, style="Sidebar.TFrame")
paned_window.grid(row=2, column=0, columnspan=2, sticky="nsew")
# Sidebar
@@ -415,42 +363,35 @@ class WidgetManager:
# Status bar (top-left in the bottom area)
self.status_bar = ttk.Label(
bottom_controls_frame, text="", anchor="w", style="AccentBottom.TLabel")
self.status_bar.grid(row=0, column=0, columnspan=2,
self.status_bar.grid(row=0, column=1, columnspan=2,
sticky="w", padx=10, pady=5)
# New folder/file buttons (top-right in the bottom area)
right_top_buttons = ttk.Frame(
bottom_controls_frame, style="AccentBottom.TFrame")
right_top_buttons.grid(row=0, column=2, sticky="e")
self.new_folder_button = ttk.Button(right_top_buttons, image=self.dialog.icon_manager.get_icon(
'new_folder_small'), command=self.dialog.create_new_folder, style="Header.TButton.Borderless.Round")
self.new_folder_button.pack(side="left", padx=5)
Tooltip(self.new_folder_button, "Neuen Ordner erstellen")
self.new_file_button = ttk.Button(right_top_buttons, image=self.dialog.icon_manager.get_icon(
'new_document_small'), command=self.dialog.create_new_file, style="Header.TButton.Borderless.Round")
self.new_file_button.pack(side="left", padx=(0, 10))
Tooltip(self.new_file_button, "Neues Dokument erstellen")
# Main action buttons (bottom-left)
left_bottom_buttons = ttk.Frame(bottom_controls_frame, style="AccentBottom.TFrame")
left_bottom_buttons.grid(row=1, column=0, sticky="w", pady=(5, 10))
left_bottom_buttons = ttk.Frame(
bottom_controls_frame, style="AccentBottom.TFrame")
left_bottom_buttons.grid(row=0, column=0, sticky="w", pady=(5, 10))
if self.dialog.dialog_mode == "save":
self.filename_entry = ttk.Entry(left_bottom_buttons, width=50)
self.filename_entry.grid(row=0, column=0, padx=(10,5), pady=5, sticky="ew")
self.filename_entry.grid(
row=0, column=1, padx=(5, 5), pady=5, sticky="ew")
left_bottom_buttons.grid_columnconfigure(0, weight=1)
ttk.Button(left_bottom_buttons, text="Speichern", command=self.dialog.on_save).grid(row=0, column=1, padx=5)
ttk.Button(left_bottom_buttons, text="Abbrechen", command=self.dialog.on_cancel).grid(row=0, column=2, padx=5)
ttk.Button(left_bottom_buttons, text="Speichern",
command=self.dialog.on_save).grid(row=0, column=0, padx=(10, 5), pady=10)
ttk.Button(left_bottom_buttons, text="Abbrechen",
command=self.dialog.on_cancel).grid(row=1, column=0, padx=(10, 5))
else:
ttk.Button(left_bottom_buttons, text="Öffnen", command=self.dialog.on_open).grid(row=0, column=0, padx=(10, 5))
ttk.Button(left_bottom_buttons, text="Abbrechen", command=self.dialog.on_cancel).grid(row=0, column=1, padx=5)
ttk.Button(left_bottom_buttons, text="Öffnen", command=self.dialog.on_open).grid(
row=0, column=0, padx=(10, 5), pady=10)
ttk.Button(left_bottom_buttons, text="Abbrechen",
command=self.dialog.on_cancel).grid(row=1, column=0, padx=(10, 5))
# Filter combobox (bottom-right)
self.filter_combobox = ttk.Combobox(bottom_controls_frame, values=[ft[0] for ft in self.dialog.filetypes], state="readonly")
self.filter_combobox.grid(row=1, column=2, sticky="e", padx=(0, 10), pady=(5, 10))
self.filter_combobox.bind("<<ComboboxSelected>>", self.dialog.on_filter_change)
self.filter_combobox = ttk.Combobox(left_bottom_buttons, values=[
ft[0] for ft in self.dialog.filetypes], state="readonly")
self.filter_combobox.grid(
row=1, column=1, sticky="w", padx=(5, 10))
self.filter_combobox.bind(
"<<ComboboxSelected>>", self.dialog.on_filter_change)
self.filter_combobox.set(self.dialog.filetypes[0][0])

View File

@@ -8,7 +8,7 @@ import json
from shared_libs.message import MessageDialog
from shared_libs.common_tools import IconManager, Tooltip, ConfigManager, LxTools, ThemeManager
from cfd_app_config import AppConfig
from cfd_ui_setup import StyleManager, WidgetManager, get_xdg_user_dir, InputDialog
from cfd_ui_setup import StyleManager, WidgetManager, get_xdg_user_dir
# Helper to make icon paths robust, so the script can be run from anywhere
@@ -88,11 +88,13 @@ class CustomFileDialog(tk.Toplevel):
if self.show_hidden_files.get():
self.widget_manager.hidden_files_button.config(
image=self.icon_manager.get_icon('unhide'))
Tooltip(self.widget_manager.hidden_files_button, "Versteckte Dateien ausblenden")
Tooltip(self.widget_manager.hidden_files_button,
"Versteckte Dateien ausblenden")
else:
self.widget_manager.hidden_files_button.config(
image=self.icon_manager.get_icon('hide'))
Tooltip(self.widget_manager.hidden_files_button, "Versteckte Dateien anzeigen")
Tooltip(self.widget_manager.hidden_files_button,
"Versteckte Dateien anzeigen")
self.populate_files()
def on_window_resize(self, event):
@@ -123,7 +125,8 @@ class CustomFileDialog(tk.Toplevel):
def _on_devices_enter(self, event):
"""Show scrollbar when mouse enters devices area"""
self.widget_manager.devices_scrollbar.grid(row=1, column=1, sticky="ns")
self.widget_manager.devices_scrollbar.grid(
row=1, column=1, sticky="ns")
def _on_devices_leave(self, event):
"""Hide scrollbar when mouse leaves devices area"""
@@ -148,11 +151,14 @@ class CustomFileDialog(tk.Toplevel):
self.original_path_text = self.widget_manager.path_entry.get()
self.widget_manager.path_entry.delete(0, tk.END)
self.widget_manager.path_entry.insert(0, "Suchbegriff eingeben...")
self.widget_manager.path_entry.bind("<Return>", self.execute_search)
self.widget_manager.path_entry.bind("<FocusIn>", self.clear_search_placeholder)
self.widget_manager.path_entry.bind(
"<Return>", self.execute_search)
self.widget_manager.path_entry.bind(
"<FocusIn>", self.clear_search_placeholder)
# Show search options
self.widget_manager.search_options_frame.pack(side="left", padx=(5, 0))
self.widget_manager.search_options_frame.pack(
side="left", padx=(5, 0))
else:
# Exit search mode
self.search_mode = False
@@ -170,7 +176,8 @@ class CustomFileDialog(tk.Toplevel):
def toggle_recursive_search(self):
"""Toggle recursive search on/off and update button style"""
self.widget_manager.recursive_search.set(not self.widget_manager.recursive_search.get())
self.widget_manager.recursive_search.set(
not self.widget_manager.recursive_search.get())
if self.widget_manager.recursive_search.get():
self.widget_manager.recursive_button.configure(
style="Header.TButton.Active.Round")
@@ -181,7 +188,8 @@ class CustomFileDialog(tk.Toplevel):
def set_icon_view(self):
"""Set icon view and update button styles"""
self.view_mode.set("icons")
self.widget_manager.icon_view_button.configure(style="Header.TButton.Active.Round")
self.widget_manager.icon_view_button.configure(
style="Header.TButton.Active.Round")
self.widget_manager.list_view_button.configure(
style="Header.TButton.Borderless.Round")
self.populate_files()
@@ -189,7 +197,8 @@ class CustomFileDialog(tk.Toplevel):
def set_list_view(self):
"""Set list view and update button styles"""
self.view_mode.set("list")
self.widget_manager.list_view_button.configure(style="Header.TButton.Active.Round")
self.widget_manager.list_view_button.configure(
style="Header.TButton.Active.Round")
self.widget_manager.icon_view_button.configure(
style="Header.TButton.Borderless.Round")
self.populate_files()
@@ -473,7 +482,8 @@ class CustomFileDialog(tk.Toplevel):
else:
icon = self.icon_manager.get_icon('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 = 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, 14), anchor="center", style="Item.TLabel")
@@ -488,7 +498,8 @@ class CustomFileDialog(tk.Toplevel):
widget.bind("<MouseWheel>", _on_mouse_wheel)
widget.bind("<Button-4>", _on_mouse_wheel)
widget.bind("<Button-5>", _on_mouse_wheel)
widget.bind("<F2>", lambda e, p=path, f=item_frame: self.on_rename_request(e, p, f))
widget.bind("<F2>", lambda e, p=path,
f=item_frame: self.on_rename_request(e, p, f))
col = (col + 1) % col_count
if col == 0:
@@ -598,9 +609,10 @@ class CustomFileDialog(tk.Toplevel):
if not self.tree.selection():
return
item_id = self.tree.selection()[0]
item_path = os.path.join(self.current_dir, self.tree.item(item_id, "text").strip())
item_path = os.path.join(
self.current_dir, self.tree.item(item_id, "text").strip())
self.start_rename(item_id, item_path)
else: # icon view
else: # icon view
if item_path and item_frame:
self.start_rename(item_frame, item_path)
@@ -693,7 +705,8 @@ class CustomFileDialog(tk.Toplevel):
try:
total, used, free = shutil.disk_usage(self.current_dir)
free_str = self._format_size(free)
self.widget_manager.storage_label.config(text=f"Freier Speicher: {free_str}")
self.widget_manager.storage_label.config(
text=f"Freier Speicher: {free_str}")
self.widget_manager.storage_bar['value'] = (used / total) * 100
status_text = ""
@@ -703,8 +716,10 @@ class CustomFileDialog(tk.Toplevel):
status_text = f"'{os.path.basename(self.selected_file)}' Größe: {size_str}"
self.widget_manager.status_bar.config(text=status_text)
except FileNotFoundError:
self.widget_manager.status_bar.config(text="Verzeichnis nicht gefunden")
self.widget_manager.storage_label.config(text="Freier Speicher: Unbekannt")
self.widget_manager.status_bar.config(
text="Verzeichnis nicht gefunden")
self.widget_manager.storage_label.config(
text="Freier Speicher: Unbekannt")
self.widget_manager.storage_bar['value'] = 0
def on_open(self):
@@ -744,7 +759,8 @@ class CustomFileDialog(tk.Toplevel):
open(new_path, 'a').close()
self.populate_files(item_to_rename=new_name)
except Exception as e:
self.widget_manager.status_bar.config(text=f"Fehler beim Erstellen: {e}")
self.widget_manager.status_bar.config(
text=f"Fehler beim Erstellen: {e}")
def _get_unique_name(self, base_name):
name, ext = os.path.splitext(base_name)
@@ -758,8 +774,8 @@ class CustomFileDialog(tk.Toplevel):
def start_rename(self, item_widget, item_path):
if self.view_mode.get() == "icons":
self._start_rename_icon_view(item_widget, item_path)
else: # list view
self._start_rename_list_view(item_widget) # item_widget is item_id
else: # list view
self._start_rename_list_view(item_widget) # item_widget is item_id
def _start_rename_icon_view(self, item_frame, item_path):
for child in item_frame.winfo_children():
@@ -776,13 +792,15 @@ class CustomFileDialog(tk.Toplevel):
new_path = os.path.join(self.current_dir, new_name)
if new_name and new_path != item_path:
if os.path.exists(new_path):
self.widget_manager.status_bar.config(text=f"'{new_name}' existiert bereits.")
self.widget_manager.status_bar.config(
text=f"'{new_name}' existiert bereits.")
self.populate_files()
return
try:
os.rename(item_path, new_path)
except Exception as e:
self.widget_manager.status_bar.config(text=f"Fehler beim Umbenennen: {e}")
self.widget_manager.status_bar.config(
text=f"Fehler beim Umbenennen: {e}")
self.populate_files()
def cancel_rename(event):
@@ -809,12 +827,14 @@ class CustomFileDialog(tk.Toplevel):
if new_name and new_path != old_path:
if os.path.exists(new_path):
self.widget_manager.status_bar.config(text=f"'{new_name}' existiert bereits.")
self.widget_manager.status_bar.config(
text=f"'{new_name}' existiert bereits.")
else:
try:
os.rename(old_path, new_path)
except Exception as e:
self.widget_manager.status_bar.config(text=f"Fehler beim Umbenennen: {e}")
self.widget_manager.status_bar.config(
text=f"Fehler beim Umbenennen: {e}")
entry.destroy()
self.populate_files()
@@ -842,8 +862,6 @@ class CustomFileDialog(tk.Toplevel):
return True
return False
def _format_size(self, size_bytes):
if size_bytes is None:
return ""

View File

@@ -55,7 +55,7 @@ if __name__ == "__main__":
style = ttk.Style(root)
root.tk.call('source', f"{theme_path}/water.tcl")
try:
root.tk.call('set_theme', 'light')
root.tk.call('set_theme', 'dark')
except tk.TclError:
pass
root.mainloop()