|
|
# -*- coding: utf-8 -*-
|
|
|
"""
|
|
|
Диалози за съобщения, центрирани спрямо прозореца на приложението (parent),
|
|
|
а не спрямо физическия екран.
|
|
|
"""
|
|
|
|
|
|
import tkinter as tk
|
|
|
from tkinter import ttk
|
|
|
|
|
|
|
|
|
def _center_on_parent(dialog, parent):
|
|
|
"""Поставя диалога в центъра на parent (размер и позиция на приложението)."""
|
|
|
if parent is None:
|
|
|
return
|
|
|
dialog.update_idletasks()
|
|
|
parent.update_idletasks()
|
|
|
w = dialog.winfo_reqwidth()
|
|
|
h = dialog.winfo_reqheight()
|
|
|
rw = parent.winfo_width()
|
|
|
rh = parent.winfo_height()
|
|
|
rx = parent.winfo_rootx()
|
|
|
ry = parent.winfo_rooty()
|
|
|
x = rx + max(0, (rw - w) // 2)
|
|
|
y = ry + max(0, (rh - h) // 2)
|
|
|
dialog.geometry(f"+{x}+{y}")
|
|
|
|
|
|
|
|
|
def _dialog(parent, title, message, dialog_type="info", ask_yes_no=False):
|
|
|
"""
|
|
|
Показва модален диалог (Toplevel), центриран спрямо parent.
|
|
|
dialog_type: "info" | "warning" | "error"
|
|
|
ask_yes_no: ако True, бутони Да/Не и връща True/False.
|
|
|
"""
|
|
|
root = parent.winfo_toplevel() if parent else tk._default_root
|
|
|
d = tk.Toplevel(root)
|
|
|
d.title(title)
|
|
|
d.transient(parent or root)
|
|
|
d.resizable(False, False)
|
|
|
|
|
|
# рамка с отстъп
|
|
|
f = ttk.Frame(d, padding=16)
|
|
|
f.pack(fill=tk.BOTH, expand=True)
|
|
|
|
|
|
# иконка + текст (опционално различни цветове за error/warning)
|
|
|
msg_label = ttk.Label(f, text=message, wraplength=400, justify=tk.LEFT)
|
|
|
msg_label.pack(anchor=tk.W, fill=tk.X, pady=(0, 12))
|
|
|
|
|
|
result = [None]
|
|
|
|
|
|
def ok():
|
|
|
result[0] = True
|
|
|
d.destroy()
|
|
|
|
|
|
def no():
|
|
|
result[0] = False
|
|
|
d.destroy()
|
|
|
|
|
|
btn_frame = ttk.Frame(f)
|
|
|
btn_frame.pack(anchor=tk.E)
|
|
|
if ask_yes_no:
|
|
|
ttk.Button(btn_frame, text="Да", command=ok).pack(side=tk.LEFT, padx=4)
|
|
|
ttk.Button(btn_frame, text="Не", command=no).pack(side=tk.LEFT, padx=4)
|
|
|
else:
|
|
|
ttk.Button(btn_frame, text="OK", command=ok).pack(side=tk.LEFT, padx=4)
|
|
|
|
|
|
d.protocol("WM_DELETE_WINDOW", no if ask_yes_no else ok)
|
|
|
if parent:
|
|
|
d.after_idle(lambda: _center_on_parent(d, parent))
|
|
|
d.grab_set()
|
|
|
d.focus_set()
|
|
|
d.wait_window()
|
|
|
return result[0] if ask_yes_no else None
|
|
|
|
|
|
|
|
|
def showinfo(title, message, parent=None):
|
|
|
_dialog(parent, title, message, "info", ask_yes_no=False)
|
|
|
|
|
|
|
|
|
def showwarning(title, message, parent=None):
|
|
|
_dialog(parent, title, message, "warning", ask_yes_no=False)
|
|
|
|
|
|
|
|
|
def showerror(title, message, parent=None):
|
|
|
_dialog(parent, title, message, "error", ask_yes_no=False)
|
|
|
|
|
|
|
|
|
def askyesno(title, message, parent=None):
|
|
|
return _dialog(parent, title, message, "info", ask_yes_no=True) is True
|