feat: Enhance create_edit_window method with dynamic fields and improved layout

This commit is contained in:
William Valentin
2025-08-09 13:10:58 -07:00
parent d0c9f55a10
commit 1613fb2625

View File

@@ -602,52 +602,199 @@ class UIManager:
pass
def create_edit_window(self, values, callbacks):
"""Minimal edit window allowing date and note changes.
"""Create the full edit window with dynamic fields.
This simplified version passes missing pathology/medicine values as zeros
and an empty dose mapping to the caller's save callback for compatibility.
Expected `values` format (as provided by main._create_edit_window):
(date,
[pathology values...],
[for each medicine: taken, doses_string],
note)
On save, call the provided callback with:
(window, date, pathology_values..., medicine_values..., note, dose_data_dict)
"""
win = tk.Toplevel(master=self.root)
win.title("Edit Entry")
win.transient(self.root)
win.minsize(400, 240)
win.minsize(520, 420)
container = ttk.Frame(win, padding=12)
container.pack(fill=tk.BOTH, expand=True)
# Scrollable content area
outer = ttk.Frame(win, padding=12)
outer.pack(fill=tk.BOTH, expand=True)
ttk.Label(container, text="Date (mm/dd/yyyy):").grid(
row=0, column=0, sticky="w"
)
date_var = tk.StringVar(value=values[0] if values else "")
canvas = tk.Canvas(outer, highlightthickness=0)
vscroll = ttk.Scrollbar(outer, orient="vertical", command=canvas.yview)
content = ttk.Frame(canvas)
content.grid_columnconfigure(1, weight=1)
canvas_window_id = canvas.create_window((0, 0), window=content, anchor="nw")
canvas.configure(yscrollcommand=vscroll.set)
canvas.grid(row=0, column=0, sticky="nsew")
vscroll.grid(row=0, column=1, sticky="ns")
outer.grid_rowconfigure(0, weight=1)
outer.grid_columnconfigure(0, weight=1)
def _on_configure(_evt=None):
canvas.configure(scrollregion=canvas.bbox("all"))
def _on_canvas_width(_evt=None):
# Keep inner frame width in sync so widgets expand
bbox = canvas.bbox("all")
if bbox:
canvas.itemconfigure(canvas_window_id, width=canvas.winfo_width())
content.bind("<Configure>", _on_configure)
canvas.bind("<Configure>", _on_canvas_width)
# Unpack incoming values using managers' key orders
pathology_keys = list(self.pathology_manager.get_pathology_keys())
medicine_keys = list(self.medicine_manager.get_medicine_keys())
idx = 0
date_str = values[idx] if values else ""
idx += 1
# Pathology values
pathology_values: dict[str, int] = {}
for key in pathology_keys:
try:
pathology_values[key] = int(values[idx])
except Exception:
pathology_values[key] = 0
idx += 1
# Medicine taken and stored dose strings
medicine_taken: dict[str, int] = {}
medicine_doses_str: dict[str, str] = {}
for key in medicine_keys:
try:
medicine_taken[key] = int(values[idx])
except Exception:
medicine_taken[key] = 0
idx += 1
try:
medicine_doses_str[key] = str(values[idx])
except Exception:
medicine_doses_str[key] = ""
idx += 1
note_val = values[idx] if idx < len(values) else ""
# --- Build UI ---
# Date
ttk.Label(content, text="Date (mm/dd/yyyy):").grid(row=0, column=0, sticky="w")
date_var = tk.StringVar(value=str(date_str))
ttk.Entry(
container, textvariable=date_var, justify="center", style="Modern.TEntry"
content,
textvariable=date_var,
justify="center",
style="Modern.TEntry",
).grid(row=0, column=1, sticky="ew", padx=8, pady=4)
ttk.Label(container, text="Note:").grid(row=1, column=0, sticky="w")
note_val = values[-1] if values else ""
# Pathologies section
row = 1
ttk.Label(content, text="Pathologies:").grid(row=row, column=0, sticky="w")
path_frame = ttk.Frame(content)
path_frame.grid(row=row, column=1, sticky="ew", padx=8, pady=4)
path_frame.grid_columnconfigure(1, weight=1)
row += 1
pathology_vars: dict[str, tk.IntVar] = {}
for i, key in enumerate(pathology_keys):
pathology_vars[key] = tk.IntVar(value=pathology_values.get(key, 0))
pathology = self.pathology_manager.get_pathology(key)
label = (
pathology.display_name
if getattr(pathology, "display_name", None)
else key.capitalize()
)
ttk.Label(path_frame, text=f"{label}:").grid(
row=i, column=0, sticky="w", padx=2
)
scale = ttk.Scale(path_frame, from_=0, to=10, orient=tk.HORIZONTAL)
scale.grid(row=i, column=1, sticky="ew", padx=4)
with suppress(Exception):
scale.set(pathology_vars[key].get())
# Keep IntVar in sync when dragging
def _mk_scale_cmd(k: str, s: ttk.Scale):
def _cmd(_evt=None):
with suppress(Exception):
pathology_vars[k].set(int(float(s.get())))
return _cmd
scale.bind("<ButtonRelease-1>", _mk_scale_cmd(key, scale))
# Medicines section
ttk.Label(content, text="Medicines:").grid(row=row, column=0, sticky="w")
meds_frame = ttk.Frame(content)
meds_frame.grid(row=row, column=1, sticky="ew", padx=8, pady=4)
meds_frame.grid_columnconfigure(0, weight=1)
row += 1
medicine_vars: dict[str, tk.IntVar] = {}
for i, key in enumerate(medicine_keys):
medicine_vars[key] = tk.IntVar(value=medicine_taken.get(key, 0))
med = self.medicine_manager.get_medicine(key)
text = (
med.display_name
if getattr(med, "display_name", None)
else key.capitalize()
)
chk = ttk.Checkbutton(
meds_frame,
text=text,
variable=medicine_vars[key],
style="Modern.TCheckbutton",
)
chk.grid(row=i, column=0, sticky="w", padx=2, pady=2)
# Note field
ttk.Label(content, text="Note:").grid(row=row, column=0, sticky="nw")
note_var = tk.StringVar(value=str(note_val))
ttk.Entry(container, textvariable=note_var, style="Modern.TEntry").grid(
row=1, column=1, sticky="ew", padx=8, pady=4
ttk.Entry(content, textvariable=note_var, style="Modern.TEntry").grid(
row=row, column=1, sticky="ew", padx=8, pady=4
)
row += 1
container.grid_columnconfigure(1, weight=1)
buttons = ttk.Frame(container)
buttons.grid(row=2, column=0, columnspan=2, pady=10)
# Buttons
buttons = ttk.Frame(content)
buttons.grid(row=row, column=0, columnspan=2, pady=10)
def _on_save():
# Only provide date and note; caller will default others.
# Build args matching main._save_edit expectation
args: list[object] = [date_var.get()]
# Pathology values in key order
for key in pathology_keys:
args.append(int(pathology_vars[key].get()))
# Medicine 'taken' values in key order
for key in medicine_keys:
args.append(int(medicine_vars[key].get()))
# Note
args.append(note_var.get())
# Preserve existing dose strings unless caller offers an editor elsewhere
dose_map = {k: medicine_doses_str.get(k, "") for k in medicine_keys}
args.append(dose_map)
with suppress(Exception):
callbacks.get("save")(win, date_var.get(), note_var.get(), {})
callbacks.get("save")(win, *args)
def _on_delete():
with suppress(Exception):
callbacks.get("delete")(win)
def _on_cancel():
with suppress(Exception):
win.destroy()
ttk.Button(buttons, text="Save", command=_on_save, style="Action.TButton").pack(
side="left", padx=5
)
ttk.Button(buttons, text="Delete", command=_on_delete).pack(side="left", padx=5)
ttk.Button(buttons, text="Cancel", command=_on_cancel).pack(side="left", padx=5)
# Finalize scroll region
content.update_idletasks()
canvas.configure(scrollregion=canvas.bbox("all"))
return win