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 import tkinter as tk
from collections.abc import Callable from collections.abc import Callable
from tkinter import messagebox, simpledialog, ttk from tkinter import messagebox, ttk
from init import logger from init import logger
from preferences import get_pref, save_preferences, set_pref from preferences import get_pref, save_preferences, set_pref
@@ -521,11 +521,8 @@ class SearchFilterWidget:
self._apply_filter_summary(summary) self._apply_filter_summary(summary)
def _save_preset(self) -> None: def _save_preset(self) -> None:
# Ask for a name # Ask for a name via themed modal dialog
name = simpledialog.askstring("Save Preset", "Preset name:", parent=self.parent) name = self._ask_preset_name(initial=self.preset_var.get().strip())
if not name:
return
name = name.strip()
if not name: if not name:
return return
presets = get_pref("filter_presets", {}) or {} presets = get_pref("filter_presets", {}) or {}
@@ -536,6 +533,65 @@ class SearchFilterWidget:
self.preset_var.set(name) self.preset_var.set(name)
self._update_status() 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: def _delete_preset(self) -> None:
name = self.preset_var.get().strip() name = self.preset_var.get().strip()
if not name: if not name: