Refine member and asset detail layouts

This commit is contained in:
Marcel Peterkau
2026-06-27 10:36:03 +02:00
parent 87e972bb43
commit 04c23fbdf9
5 changed files with 452 additions and 52 deletions
+80
View File
@@ -0,0 +1,80 @@
from __future__ import annotations
import tkinter as tk
from collections.abc import Callable, Iterable
from dataclasses import dataclass
from tkinter import ttk
MessageType = str
@dataclass(frozen=True)
class MessageAction:
label: str
callback: Callable[[], None]
@dataclass(frozen=True)
class TabMessage:
message_type: MessageType
text: str
action: MessageAction | None = None
_TYPE_STYLES = {
"error": "Error",
"notification": "Notification",
"warning": "Warning",
"info": "Info",
}
class MessageBannerList(ttk.Frame):
def __init__(self, master: tk.Misc):
super().__init__(master)
self.columnconfigure(0, weight=1)
self._messages: list[TabMessage] = []
def set_messages(self, messages: Iterable[TabMessage]) -> None:
self._messages = [message for message in messages if message.text.strip()]
self._render()
if self._messages:
self.grid()
else:
self.grid_remove()
def _render(self) -> None:
for child in self.winfo_children():
child.destroy()
for row_index, message in enumerate(self._messages):
style_name = _message_style_name(message.message_type)
banner = ttk.Frame(self, style=f"Message{style_name}Border.TFrame", padding=1)
banner.grid(row=row_index, column=0, sticky="ew", pady=(0, 6))
banner.columnconfigure(0, weight=1)
body = ttk.Frame(banner, style=f"Message{style_name}.TFrame", padding=(10, 8))
body.grid(row=0, column=0, sticky="ew")
body.columnconfigure(0, weight=1)
label = ttk.Label(
body,
text=message.text,
style=f"Message{style_name}.TLabel",
wraplength=900,
justify="left",
)
label.grid(row=0, column=0, sticky="ew")
body.bind(
"<Configure>",
lambda event, target=label: target.configure(wraplength=max(240, event.width - 180)),
add="+",
)
if message.action is not None:
ttk.Button(
body,
text=message.action.label,
command=message.action.callback,
).grid(row=0, column=1, sticky="e", padx=(12, 0))
def _message_style_name(message_type: MessageType) -> str:
return _TYPE_STYLES.get(message_type.casefold(), "Info")