commit 39
This commit is contained in:
BIN
__pycache__/cfd_app_config.cpython-312.pyc
Normal file
BIN
__pycache__/cfd_app_config.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/cfd_ui_setup.cpython-312.pyc
Normal file
BIN
__pycache__/cfd_ui_setup.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1,128 @@
|
||||
#!/usr/bin/python3
|
||||
"""App configuration for Wire-Py"""
|
||||
import logging
|
||||
from pathlib import Path
|
||||
import os
|
||||
from subprocess import CompletedProcess, run
|
||||
from typing import Dict, Any
|
||||
from shared_libs.common_tools import Translate
|
||||
|
||||
|
||||
class AppConfig:
|
||||
"""Central configuration and system setup manager for the Wire-Py application.
|
||||
|
||||
This class serves as a singleton-like container for all global configuration data,
|
||||
including paths, UI settings, localization, versioning, and system-specific resources.
|
||||
It ensures that required directories, files, and services are created and configured
|
||||
before the application starts. Additionally, it provides tools for managing translations,
|
||||
default settings, and autostart functionality to maintain a consistent user experience.
|
||||
|
||||
Key Responsibilities:
|
||||
- Centralizes all configuration values (paths, UI preferences, localization).
|
||||
- Ensures required directories and files exist on startup.
|
||||
- Handles translation setup via `gettext` for multilingual support.
|
||||
- Manages default settings file generation.
|
||||
- Configures autostart services using systemd for user-specific launch behavior.
|
||||
|
||||
This class is used globally across the application to access configuration data
|
||||
consistently and perform system-level setup tasks.
|
||||
"""
|
||||
|
||||
# Helper to make icon paths robust, so the script can be run from anywhere
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
MAX_ITEMS_TO_DISPLAY = 1000
|
||||
|
||||
# Logging
|
||||
LOG_DIR = Path.home() / ".local/share/lxlogs"
|
||||
Path(LOG_DIR).mkdir(parents=True, exist_ok=True)
|
||||
LOG_FILE_PATH = LOG_DIR / "cfiledialog.log"
|
||||
|
||||
# Base paths
|
||||
BASE_DIR: Path = Path.home()
|
||||
CONFIG_DIR: Path = BASE_DIR / ".config/cfiledialog"
|
||||
|
||||
# Configuration files
|
||||
SETTINGS_FILE: Path = CONFIG_DIR / "settings"
|
||||
DEFAULT_SETTINGS: Dict[str, str] = {
|
||||
"# Configuration": "on",
|
||||
"# Theme": "dark",
|
||||
"# Tooltips": True,
|
||||
"# Autostart": "off",
|
||||
"# Logfile": LOG_FILE_PATH,
|
||||
}
|
||||
|
||||
# Updates
|
||||
# 1 = 1. Year, 09 = Month of the Year, 2924 = Day and Year of the Year
|
||||
VERSION: str = "v. 1.07.2725"
|
||||
UPDATE_URL: str = "https://git.ilunix.de/api/v1/repos/punix/example/releases"
|
||||
DOWNLOAD_URL: str = "https://git.ilunix.de/punix/example/archive"
|
||||
|
||||
# UI configuration
|
||||
UI_CONFIG: Dict[str, Any] = {
|
||||
"window_title": "File Dialog",
|
||||
"window_size": (1100, 850),
|
||||
"font_family": "Ubuntu",
|
||||
"font_size": 11,
|
||||
"resizable_window": (True, True),
|
||||
}
|
||||
|
||||
# System-dependent paths
|
||||
SYSTEM_PATHS: Dict[str, Path] = {
|
||||
"tcl_path": "/usr/share/TK-Themes",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def ensure_directories(cls) -> None:
|
||||
"""Ensures that all required directories exist"""
|
||||
if not cls.CONFIG_DIR.exists():
|
||||
cls.CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@classmethod
|
||||
def create_default_settings(cls) -> None:
|
||||
"""Creates default settings if they don't exist"""
|
||||
if not cls.SETTINGS_FILE.exists():
|
||||
content = "\n".join(
|
||||
f"[{k.upper()}]\n{v}" for k, v in cls.DEFAULT_SETTINGS.items()
|
||||
)
|
||||
cls.SETTINGS_FILE.write_text(content)
|
||||
|
||||
@classmethod
|
||||
def ensure_log(cls) -> None:
|
||||
"""Ensures that the log file exists"""
|
||||
if not cls.LOG_FILE_PATH.exists():
|
||||
cls.LOG_FILE_PATH.touch()
|
||||
|
||||
|
||||
# here is initializing the class for translation strings
|
||||
_ = Translate.setup_translations("custom_file_fialog")
|
||||
|
||||
|
||||
class Msg:
|
||||
"""
|
||||
A utility class that provides centralized access to translated message strings.
|
||||
|
||||
This class contains a dictionary of message strings used throughout the custom file dialog application.
|
||||
All strings are prepared for translation using gettext. The short key names make the code
|
||||
more concise while maintaining readability.
|
||||
|
||||
Attributes:
|
||||
STR (dict): A dictionary mapping short keys to translated message strings.
|
||||
Keys are abbreviated for brevity but remain descriptive.
|
||||
|
||||
Usage:
|
||||
Import this class and access messages using the dictionary:
|
||||
`Msg.STR["sel_tl"]` returns the translated "Select tunnel" message.
|
||||
|
||||
Note:
|
||||
Ensure that gettext translation is properly initialized before
|
||||
accessing these strings to ensure correct localization.
|
||||
"""
|
||||
|
||||
STR: Dict[str, str] = {
|
||||
# Strings for messages
|
||||
|
||||
}
|
||||
TTIP: Dict[str, str] = {
|
||||
# Strings for Tooltips
|
||||
|
||||
}
|
||||
|
456
cfd_ui_setup.py
Normal file
456
cfd_ui_setup.py
Normal file
@@ -0,0 +1,456 @@
|
||||
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
|
||||
|
||||
|
||||
def get_xdg_user_dir(dir_key, fallback_name):
|
||||
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:
|
||||
def __init__(self, dialog):
|
||||
self.dialog = dialog
|
||||
self.setup_styles()
|
||||
|
||||
def setup_styles(self):
|
||||
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)
|
||||
|
||||
|
||||
class WidgetManager:
|
||||
def __init__(self, dialog):
|
||||
self.dialog = dialog
|
||||
self.style_manager = dialog.style_manager
|
||||
self.setup_widgets()
|
||||
|
||||
def setup_widgets(self):
|
||||
# Main container
|
||||
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)
|
||||
|
||||
# Top bar for navigation and path
|
||||
top_bar = ttk.Frame(
|
||||
main_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)
|
||||
|
||||
# Navigation buttons
|
||||
nav_buttons_container = ttk.Frame(top_bar, style='Accent.TFrame')
|
||||
nav_buttons_container.grid(row=0, column=0, sticky="w")
|
||||
|
||||
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)
|
||||
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")
|
||||
Tooltip(self.forward_button, "Vorwärts")
|
||||
|
||||
self.home_button = ttk.Button(nav_buttons_container, image=self.dialog.icon_manager.get_icon(
|
||||
'home'), command=lambda: self.dialog.navigate_to(os.path.expanduser("~")), style="Header.TButton.Borderless.Round")
|
||||
self.home_button.pack(side="left", padx=10)
|
||||
Tooltip(self.home_button, "Home")
|
||||
|
||||
# Path entry
|
||||
self.path_entry = ttk.Entry(top_bar)
|
||||
self.path_entry.grid(row=0, column=1, sticky="ew")
|
||||
self.path_entry.bind(
|
||||
"<Return>", lambda e: self.dialog.navigate_to(self.path_entry.get()))
|
||||
|
||||
# Search, view switch and hidden files button
|
||||
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')
|
||||
search_container.pack(side="left", padx=(0, 10))
|
||||
|
||||
self.search_button = ttk.Button(search_container, image=self.dialog.icon_manager.get_icon(
|
||||
'search_small'), command=self.dialog.toggle_search_mode, style="Header.TButton.Borderless.Round")
|
||||
self.search_button.pack(side="left")
|
||||
Tooltip(self.search_button, "Suchen")
|
||||
|
||||
# Search options frame (initially hidden, next to search button)
|
||||
self.search_options_frame = ttk.Frame(
|
||||
search_container, style='Accent.TFrame')
|
||||
|
||||
# Recursive search toggle button
|
||||
self.recursive_search = tk.BooleanVar(value=True)
|
||||
self.recursive_button = ttk.Button(self.search_options_frame, image=self.dialog.icon_manager.get_icon(
|
||||
'recursive_small'), command=self.dialog.toggle_recursive_search, style="Header.TButton.Active.Round")
|
||||
self.recursive_button.pack(side="left", padx=2)
|
||||
Tooltip(self.recursive_button, "Rekursive Suche ein/ausschalten")
|
||||
|
||||
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))
|
||||
Tooltip(self.icon_view_button, "Kachelansicht")
|
||||
|
||||
self.list_view_button = ttk.Button(view_switch, image=self.dialog.icon_manager.get_icon(
|
||||
'list_view'), command=self.dialog.set_list_view, style="Header.TButton.Borderless.Round")
|
||||
self.list_view_button.pack(side="left")
|
||||
Tooltip(self.list_view_button, "Listenansicht")
|
||||
|
||||
self.hidden_files_button = ttk.Button(right_top_bar_frame, image=self.dialog.icon_manager.get_icon(
|
||||
'hide'), command=self.dialog.toggle_hidden_files, style="Header.TButton.Borderless.Round")
|
||||
self.hidden_files_button.pack(side="left", padx=10)
|
||||
Tooltip(self.hidden_files_button, "Versteckte Dateien anzeigen")
|
||||
|
||||
# Horizontal separator
|
||||
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")
|
||||
|
||||
# PanedWindow for resizable sidebar and content
|
||||
paned_window = ttk.PanedWindow(main_frame, orient=tk.HORIZONTAL)
|
||||
paned_window.grid(row=2, column=0, columnspan=2, sticky="nsew")
|
||||
|
||||
# Sidebar
|
||||
sidebar_frame = ttk.Frame(
|
||||
paned_window, style="Sidebar.TFrame", padding=(0, 0, 0, 0), width=200)
|
||||
sidebar_frame.grid_propagate(False)
|
||||
sidebar_frame.bind("<Configure>", self.dialog.on_sidebar_resize)
|
||||
paned_window.add(sidebar_frame, weight=0)
|
||||
sidebar_frame.grid_rowconfigure(2, weight=1)
|
||||
|
||||
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': 'Computer', 'icon': self.dialog.icon_manager.get_icon(
|
||||
'computer_small'), 'path': '/'},
|
||||
{'name': 'Downloads', 'icon': self.dialog.icon_manager.get_icon(
|
||||
'downloads_small'), 'path': get_xdg_user_dir("XDG_DOWNLOAD_DIR", "Downloads")},
|
||||
{'name': 'Dokumente', 'icon': self.dialog.icon_manager.get_icon(
|
||||
'documents_small'), 'path': get_xdg_user_dir("XDG_DOCUMENTS_DIR", "Documents")},
|
||||
{'name': 'Bilder', 'icon': self.dialog.icon_manager.get_icon(
|
||||
'pictures_small'), 'path': get_xdg_user_dir("XDG_PICTURES_DIR", "Pictures")},
|
||||
{'name': 'Musik', 'icon': self.dialog.icon_manager.get_icon(
|
||||
'music_small'), 'path': get_xdg_user_dir("XDG_MUSIC_DIR", "Music")},
|
||||
{'name': '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:
|
||||
btn = ttk.Button(sidebar_buttons_frame, text=f" {config['name']}", image=config['icon'], compound="left",
|
||||
command=lambda p=config['path']: self.dialog.navigate_to(p), style="Dark.TButton.Borderless")
|
||||
btn.pack(fill="x", pady=1)
|
||||
self.sidebar_buttons.append((btn, f" {config['name']}"))
|
||||
|
||||
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)
|
||||
|
||||
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="Geräte:", 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")
|
||||
|
||||
self.devices_canvas.bind("<Enter>", self.dialog._on_devices_enter)
|
||||
self.devices_canvas.bind("<Leave>", self.dialog._on_devices_leave)
|
||||
self.devices_scrollable_frame.bind(
|
||||
"<Enter>", self.dialog._on_devices_enter)
|
||||
self.devices_scrollable_frame.bind(
|
||||
"<Leave>", self.dialog._on_devices_leave)
|
||||
|
||||
def _configure_devices_canvas(event):
|
||||
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("<Configure>", lambda e: self.devices_canvas.configure(
|
||||
scrollregion=self.devices_canvas.bbox("all")))
|
||||
self.devices_canvas.bind("<Configure>", _configure_devices_canvas)
|
||||
|
||||
def _on_devices_mouse_wheel(event):
|
||||
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("<MouseWheel>", _on_devices_mouse_wheel)
|
||||
widget.bind("<Button-4>", _on_devices_mouse_wheel)
|
||||
widget.bind("<Button-5>", _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.navigate_to(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("<MouseWheel>", _on_devices_mouse_wheel)
|
||||
w.bind("<Button-4>", _on_devices_mouse_wheel)
|
||||
w.bind("<Button-5>", _on_devices_mouse_wheel)
|
||||
w.bind("<Enter>", self.dialog._on_devices_enter)
|
||||
w.bind("<Leave>", self.dialog._on_devices_leave)
|
||||
|
||||
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("<MouseWheel>", _on_devices_mouse_wheel)
|
||||
w.bind("<Button-4>", _on_devices_mouse_wheel)
|
||||
w.bind("<Button-5>", _on_devices_mouse_wheel)
|
||||
w.bind("<Enter>", self.dialog._on_devices_enter)
|
||||
w.bind("<Leave>", self.dialog._on_devices_leave)
|
||||
except (FileNotFoundError, PermissionError):
|
||||
pass
|
||||
|
||||
tk.Frame(sidebar_frame, height=1, bg=separator_color).grid(
|
||||
row=3, column=0, sticky="ew", padx=20, pady=15)
|
||||
|
||||
storage_frame = ttk.Frame(sidebar_frame, style="Sidebar.TFrame")
|
||||
storage_frame.grid(row=5, column=0, sticky="sew", padx=10, pady=10)
|
||||
self.storage_label = ttk.Label(
|
||||
storage_frame, text="Freier Speicher:", 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)
|
||||
|
||||
content_frame = ttk.Frame(paned_window, padding=(
|
||||
0, 0, 0, 0), style="AccentBottom.TFrame")
|
||||
paned_window.add(content_frame, weight=1)
|
||||
content_frame.grid_rowconfigure(0, weight=1)
|
||||
content_frame.grid_columnconfigure(0, weight=1)
|
||||
|
||||
self.file_list_frame = ttk.Frame(
|
||||
content_frame, style="AccentBottom.TFrame")
|
||||
self.file_list_frame.grid(row=0, column=0, sticky="nsew")
|
||||
self.dialog.bind("<Configure>", self.dialog.on_window_resize)
|
||||
|
||||
bottom_controls_frame = ttk.Frame(
|
||||
content_frame, style="AccentBottom.TFrame")
|
||||
bottom_controls_frame.grid(row=1, column=0, sticky="ew", pady=(5, 0))
|
||||
bottom_controls_frame.grid_columnconfigure(1, weight=1)
|
||||
|
||||
# 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,
|
||||
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))
|
||||
|
||||
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")
|
||||
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)
|
||||
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)
|
||||
|
||||
|
||||
# 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.set(self.dialog.filetypes[0][0])
|
File diff suppressed because it is too large
Load Diff
@@ -30,24 +30,23 @@ class GlotzMol(tk.Tk):
|
||||
|
||||
def open_custom_dialog(self):
|
||||
|
||||
dialog = CustomFileDialog(self,
|
||||
initial_dir=os.path.expanduser("~"),
|
||||
filetypes=[("Wireguard Files (.conf)", "*.conf"),
|
||||
("All Files", "*.*")
|
||||
])
|
||||
CustomFileDialog(self,
|
||||
initial_dir=os.path.expanduser("~"),
|
||||
filetypes=[("All Files", "*.*")
|
||||
])
|
||||
|
||||
# This is the crucial part: wait for the dialog to be closed
|
||||
self.wait_window(dialog)
|
||||
# self.wait_window(dialog)
|
||||
|
||||
# Now, get the result
|
||||
selected_path = dialog.get_selected_file()
|
||||
# selected_path = dialog.get_selected_file()
|
||||
|
||||
if selected_path:
|
||||
self.iso_path_entry.delete(0, tk.END)
|
||||
self.iso_path_entry.insert(0, selected_path)
|
||||
print(f"Die ausgewählte Datei ist: {selected_path}")
|
||||
else:
|
||||
print("Keine Datei ausgewählt.")
|
||||
# if selected_path:
|
||||
# self.iso_path_entry.delete(0, tk.END)
|
||||
# self.iso_path_entry.insert(0, selected_path)
|
||||
# print(f"Die ausgewählte Datei ist: {selected_path}")
|
||||
# else:
|
||||
# print("Keine Datei ausgewählt.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
Reference in New Issue
Block a user