v0.3.0: Rendering pipeline — render dispatch, tree walk, dirty propagation
- render generic function dispatches per component type - render-screen entry point with sync wrapper - render-node walks tree, computes layout, calls render - component-layout-node generic (box/text methods) - component-children/component-parent generics - propagate-dirty marks component + ancestors dirty - box and text now inherit from dirty-mixin - 6 new tests: render dispatch, layout-node accessor, children, dirty propagation, available-width defaults - 42 component tests, 100% GREEN
This commit is contained in:
67
src/components/render.lisp
Normal file
67
src/components/render.lisp
Normal file
@@ -0,0 +1,67 @@
|
||||
(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 ((bx box)) nil)
|
||||
(:method ((tx text)) 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))))
|
||||
Reference in New Issue
Block a user