"""Details pane widget: encapsulates the Details LabelFrame, scrollable canvas, Treeview and editable form container. Assigns key attributes onto the parent MonitorApp so existing code in `monitor.py` can keep referencing `self.detail_tree`, `self.detail_form_container`, etc. """ import tkinter as tk from tkinter import ttk class DetailsPane: def __init__(self, parent, app, width=520, height=540, title='Details'): self.app = app self.parent = parent self.frame = tk.LabelFrame(parent, text=title) self.frame.pack(side=tk.RIGHT, fill=tk.Y, expand=False, padx=6) self.frame.config(width=width, height=height) try: self.frame.pack_propagate(False) except Exception: pass tk.Label(self.frame, text="Message details:").pack(anchor=tk.W) # canvas + scrollbars self._details_canvas = tk.Canvas(self.frame, highlightthickness=0) self._details_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(6,0), pady=6) vsb = ttk.Scrollbar(self.frame, orient=tk.VERTICAL, command=self._details_canvas.yview) hsb = ttk.Scrollbar(self.frame, orient=tk.HORIZONTAL, command=self._details_canvas.xview) self._details_canvas.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) vsb.pack(side=tk.RIGHT, fill=tk.Y) hsb.pack(side=tk.BOTTOM, fill=tk.X) self._details_canvas_frame = tk.Frame(self._details_canvas) self._details_canvas_window = self._details_canvas.create_window((0, 0), window=self._details_canvas_frame, anchor='nw') def _on_frame_configure(event): try: self._details_canvas.configure(scrollregion=self._details_canvas.bbox('all')) except Exception: pass def _on_canvas_configure(event): try: canvas_width = event.width self._details_canvas.itemconfigure(self._details_canvas_window, width=canvas_width) except Exception: pass self._details_canvas_frame.bind('', _on_frame_configure) self._details_canvas.bind('', _on_canvas_configure) # details Treeview (kept for backwards compatibility but not packed) self.detail_tree = ttk.Treeview(self._details_canvas_frame, columns=("param", "value"), show="headings", height=18) self.detail_tree.heading("param", text="Parameter") self.detail_tree.heading("value", text="Value") self.detail_tree.column("param", width=260) self.detail_tree.column("value", width=420) try: self.detail_tree.configure() # placeholder to satisfy possible callers except Exception: pass # form container in the interior frame so it scrolls with canvas self.detail_form_container = tk.Frame(self._details_canvas_frame) # ensure the form container is visible by default (the form builder will # populate it). We do not pack the Treeview to avoid an empty tree # overlaying the form; the form is the primary details UI. try: self.detail_form_container.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=2, pady=2) except Exception: pass # assign attributes onto the app so existing MonitorApp code works setattr(app, 'detail_tree', self.detail_tree) setattr(app, '_details_canvas', self._details_canvas) setattr(app, '_details_canvas_frame', self._details_canvas_frame) setattr(app, '_details_canvas_window', self._details_canvas_window) setattr(app, 'detail_form_container', self.detail_form_container) # default holders setattr(app, 'form_widgets', {}) setattr(app, 'current_form_label', None) setattr(app, 'current_msg_wrapper', None) setattr(app, 'detail_rows', {}) setattr(app, 'detail_selected_label', None) setattr(app, 'detail_accessors', {}) setattr(app, '_flash_items', {}) setattr(app, '_last_detail_update', 0.0) # bind double-click to parent's handler if present try: if hasattr(app, 'on_detail_double_click'): self.detail_tree.bind('', app.on_detail_double_click) except Exception: pass # expose convenience attributes self.vsb = vsb self.hsb = hsb # small helper to pack the form container when needed def show_form_container(self): try: self.detail_form_container.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) except Exception: pass __all__ = ['DetailsPane']