(in-package :cl-tui.box) ;; ── Component Protocol ──────────────────────────────────────── (defgeneric component-layout-node (component) (:documentation "Return the layout-node for COMPONENT.") (:method ((bx box)) (box-layout-node bx)) (:method ((tx text)) (text-layout-node tx))) (defgeneric component-children (component) (:documentation "Return the children of COMPONENT, or nil.") (:method ((c t)) nil)) (defgeneric component-parent (component) (:documentation "Return the parent of COMPONENT, or nil.") (:method ((c t)) nil)) ;; ── Rendering Pipeline ──────────────────────────────────────── (defgeneric render (component backend) (:documentation "Render COMPONENT at its computed position using BACKEND.") (:method ((c t) backend) (declare (ignore backend)) (values))) (defmethod render ((bx box) backend) (render-box bx backend)) (defmethod render ((tx text) backend) (render-text tx backend)) (defun render-screen (root backend) "Render the component tree ROOT using BACKEND. Computes layout for dirty branches, calls render on each component, and wraps output in synchronized updates." (let ((w (available-width root)) (h (available-height root))) (begin-sync backend) (render-node root backend w h) (end-sync backend))) (defun render-node (node backend w h) "Render a component NODE and its children." (compute-layout (component-layout-node node) w h) (render node backend) (dolist (child (component-children node)) (render-node child backend w h))) (defun available-width (component) "Return the available width for COMPONENT (or 80 as default)." (let ((ln (component-layout-node component))) (if ln (layout-node-width ln) 80))) (defun available-height (component) "Return the available height for COMPONENT (or 24 as default)." (let ((ln (component-layout-node component))) (if ln (layout-node-height ln) 24))) ;; ── Dirty Propagation ───────────────────────────────────────── (defun propagate-dirty (component) "Mark COMPONENT and all ancestors dirty." (mark-dirty component) (let ((parent (component-parent component))) (when parent (propagate-dirty parent))))