Fixes from subagent review: - Word-wrap now hard-breaks words exceeding max-width (was returning un-truncated overflow strings) - Box zero-size guard now catches any zero/single dimension (was only catching both zero together) - Title-align now respected (:left/:center/:right) with proper positioning - render-text declares (ignore spans) to suppress unused warning - ASDF test-op fixed: run! → run-tests (symbol didn't exist) - New test: box-single-column (width=1 renders nothing) - Tightened word-wrap test: verifies hard-break produces both chunks - Simplified word-wrap with cond instead of nested if/progn (avoided recurring paren-balance issue)
55 lines
2.0 KiB
Common Lisp
55 lines
2.0 KiB
Common Lisp
(in-package :cl-tui.box)
|
|
|
|
(defclass box ()
|
|
((layout-node :initform (make-layout-node) :accessor box-layout-node
|
|
:initarg :layout-node)
|
|
(border-style :initform :single :initarg :border-style
|
|
:accessor box-border-style)
|
|
(title :initform nil :initarg :title :accessor box-title)
|
|
(title-align :initform :left :initarg :title-align
|
|
:accessor box-title-align)
|
|
(fg :initform nil :initarg :fg :accessor box-fg)
|
|
(bg :initform nil :initarg :bg :accessor box-bg)))
|
|
|
|
(defun make-box (&key (border-style :single) title
|
|
(title-align :left) fg bg
|
|
width height)
|
|
(make-instance 'box
|
|
:border-style border-style
|
|
:title title
|
|
:title-align title-align
|
|
:fg fg
|
|
:bg bg
|
|
:layout-node (make-layout-node
|
|
:width width
|
|
:height height
|
|
:direction :column)))
|
|
|
|
(defun render-box (box backend)
|
|
"Render BOX at its computed layout position using BACKEND."
|
|
(let ((ln (box-layout-node box))
|
|
(bs (box-border-style box))
|
|
(title (box-title box))
|
|
(fg (box-fg box))
|
|
(bg (box-bg box)))
|
|
(let ((x (layout-node-x ln))
|
|
(y (layout-node-y ln))
|
|
(w (layout-node-width ln))
|
|
(h (layout-node-height ln)))
|
|
(when (or (zerop w) (zerop h) (< w 2) (< h 2))
|
|
(return-from render-box (values)))
|
|
(when bg
|
|
(draw-rect backend x y w h :bg bg))
|
|
(when bs
|
|
(draw-border backend x y w h :style bs :fg fg :bg bg))
|
|
(when title
|
|
(let* ((content-w (- w 4))
|
|
(tx (+ x 2))
|
|
(ty (+ y (if bs 1 0)))
|
|
(ta (box-title-align box))
|
|
(display (subseq title 0 (min (length title) content-w))))
|
|
(case ta
|
|
(:center (draw-text backend (+ x (ceiling (- w (length display)) 2)) ty display fg bg))
|
|
(:right (draw-text backend (+ x (- w (length display) 2)) ty display fg bg))
|
|
(t (draw-text backend tx ty display fg bg))))))))
|