feat: Enhance preset saving functionality with themed modal dialog for name input

This commit is contained in:
William Valentin
2025-08-08 12:30:26 -07:00
parent f5c9b79a33
commit d85027152e

View File

@@ -2,7 +2,7 @@
import tkinter as tk
from collections.abc import Callable
from tkinter import messagebox, simpledialog, ttk
from tkinter import messagebox, ttk
from init import logger
from preferences import get_pref, save_preferences, set_pref
@@ -521,11 +521,8 @@ class SearchFilterWidget:
self._apply_filter_summary(summary)
def _save_preset(self) -> None:
# Ask for a name
name = simpledialog.askstring("Save Preset", "Preset name:", parent=self.parent)
if not name:
return
name = name.strip()
# Ask for a name via themed modal dialog
name = self._ask_preset_name(initial=self.preset_var.get().strip())
if not name:
return
presets = get_pref("filter_presets", {}) or {}
@@ -536,6 +533,65 @@ class SearchFilterWidget:
self.preset_var.set(name)
self._update_status()
def _ask_preset_name(self, initial: str = "") -> str | None:
"""Prompt for a preset name using a themed ttk modal dialog.
Returns the entered name (stripped) or None if cancelled.
"""
result: dict[str, str | None] = {"value": None}
top = tk.Toplevel(self.parent)
top.title("Save Preset")
top.transient(self.parent)
top.grab_set()
frame = ttk.Frame(top, padding="10")
frame.pack(fill="both", expand=True)
ttk.Label(frame, text="Preset name:").pack(anchor="w")
name_var = tk.StringVar(value=initial)
entry = ttk.Entry(frame, textvariable=name_var, width=32)
entry.pack(fill="x", pady=(4, 10))
buttons = ttk.Frame(frame)
buttons.pack(anchor="e")
def on_ok() -> None:
value = (name_var.get() or "").strip()
if not value:
messagebox.showwarning(
"Save Preset", "Please enter a name.", parent=top
)
return
result["value"] = value
top.destroy()
def on_cancel() -> None:
result["value"] = None
top.destroy()
cancel_btn = ttk.Button(buttons, text="Cancel", command=on_cancel)
cancel_btn.pack(side="right")
ok_btn = ttk.Button(buttons, text="Save", command=on_ok)
ok_btn.pack(side="right", padx=(6, 0))
# Key bindings
entry.bind("<Return>", lambda e: on_ok())
entry.bind("<Escape>", lambda e: on_cancel())
# Center the dialog relative to parent
top.update_idletasks()
px, py = self.parent.winfo_rootx(), self.parent.winfo_rooty()
pw, ph = self.parent.winfo_width(), self.parent.winfo_height()
ww, wh = top.winfo_width(), top.winfo_height()
x = px + (pw // 2) - (ww // 2)
y = py + (ph // 2) - (wh // 2)
top.geometry(f"+{x}+{y}")
entry.focus_set()
top.wait_window()
return result["value"]
def _delete_preset(self) -> None:
name = self.preset_var.get().strip()
if not name: