Subagent review fixes: textarea ignore-w, hit-test recursion, select/tabbar position, X10 release, CSI param < digit, text-input truncation
CRITICAL: Remove (declare (ignore w)) from textarea render (textarea.lisp:251) w is used for horizontal truncation on the next line. Declaring it ignored while using it is undefined behavior in CL (SBCL warns). HIGH: hit-test recurses into children (mouse.lisp:18-34) Was returning the root component for any click within its bounds, ignoring nested widgets entirely. Now checks component-children first, returning the deepest match. MEDIUM: Select/TabBar position hardcoded to (0,0) Both rendered at terminal origin regardless of layout position. Now read layout-node-x/y for absolute positioning. MEDIUM: Text-input truncation missing Render drew full value string even when exceeding widget width. Now truncates to (min (length display) w). MEDIUM: X10 mouse release detection added (input.lisp:219-226) X10 encoding uses button=3 for release. Was detecting all events as press/drag. Now checks button=3 → :release. MEDIUM: parse-csi-params handles private markers (input.lisp:128-131) < = > ? characters (0x3c-0x3f) treated as parameter start markers instead of accumulating bogus digit values. Latent trap removed. Deferred (pre-existing design): - Scrollbox visibility cy vs orig-y: match for column layout (common case) - Nested scrollbox coordinates: assumes sequential layout positions - text-input cursor drawing: feature, not bugfix 392 tests pass.
This commit is contained in:
@@ -124,7 +124,10 @@
|
|||||||
((and (>= b #x30) (<= b #x3f))
|
((and (>= b #x30) (<= b #x3f))
|
||||||
(if (char= (code-char b) #\;)
|
(if (char= (code-char b) #\;)
|
||||||
(progn (push current params) (setf current 0))
|
(progn (push current params) (setf current 0))
|
||||||
(setf current (+ (* current 10) (- b #x30)))))
|
;; Non-digit parameter characters (< = > ?) start a new param at zero
|
||||||
|
(if (member b '(#x3c #x3d #x3e #x3f) :test #'=)
|
||||||
|
(setf current 0)
|
||||||
|
(setf current (+ (* current 10) (- b #x30))))))
|
||||||
((and (>= b #x20) (<= b #x2f))
|
((and (>= b #x20) (<= b #x2f))
|
||||||
nil)
|
nil)
|
||||||
((and (>= b #x40) (<= b #x7e))
|
((and (>= b #x40) (<= b #x7e))
|
||||||
@@ -219,15 +222,12 @@
|
|||||||
(y (third params))
|
(y (third params))
|
||||||
(button (logand p0 #x03))
|
(button (logand p0 #x03))
|
||||||
(motion (logand p0 #x20))
|
(motion (logand p0 #x20))
|
||||||
(wheel (logand p0 #x40)))
|
(release (= button 3)))
|
||||||
(make-mouse-event
|
(make-mouse-event
|
||||||
:type (if motion :drag :press)
|
:type (cond (release :release)
|
||||||
:button (cond (wheel (if (zerop (logand p0 #x01))
|
(motion :drag)
|
||||||
:wheel-up :wheel-down))
|
(t :press))
|
||||||
((= button 0) :left)
|
:button (let ((b button)) (cond ((= b 0) :left) ((= b 1) :middle) ((= b 2) :right) (t :none)))
|
||||||
((= button 1) :middle)
|
|
||||||
((= button 2) :right)
|
|
||||||
(t :none))
|
|
||||||
:x x :y y :raw (format nil "~C[<~d;~d;~d~C" #\Esc p0 x y (code-char final-byte))))
|
:x x :y y :raw (format nil "~C[<~d;~d;~d~C" #\Esc p0 x y (code-char final-byte))))
|
||||||
(let* ((tilde-p (char= (code-char final-byte) #\~))
|
(let* ((tilde-p (char= (code-char final-byte) #\~))
|
||||||
(param (or p0 0))
|
(param (or p0 0))
|
||||||
|
|||||||
@@ -17,17 +17,26 @@
|
|||||||
|
|
||||||
(defun hit-test (root x y)
|
(defun hit-test (root x y)
|
||||||
"Find the deepest component at (X, Y) by testing layout-node bounds.
|
"Find the deepest component at (X, Y) by testing layout-node bounds.
|
||||||
|
Recurses into component-children to find the innermost match.
|
||||||
Components without a layout-node or position return nil."
|
Components without a layout-node or position return nil."
|
||||||
(labels ((recurse (node)
|
(labels ((recurse (node)
|
||||||
(let ((ln (ignore-errors (component-layout-node node))))
|
(let ((ln (ignore-errors (component-layout-node node)))
|
||||||
|
(best nil))
|
||||||
(when ln
|
(when ln
|
||||||
(let ((nx (layout-node-x ln))
|
(let ((nx (layout-node-x ln))
|
||||||
(ny (layout-node-y ln))
|
(ny (layout-node-y ln))
|
||||||
(nw (layout-node-width ln))
|
(nw (layout-node-width ln))
|
||||||
(nh (layout-node-height ln)))
|
(nh (layout-node-height ln)))
|
||||||
(when (and (>= x nx) (< x (+ nx nw))
|
;; Check children first for deeper match
|
||||||
(>= y ny) (< y (+ ny nh)))
|
(dolist (child (ignore-errors (component-children node)))
|
||||||
node))))))
|
(let ((child-hit (recurse child)))
|
||||||
|
(when child-hit
|
||||||
|
(setf best child-hit))))
|
||||||
|
;; If no child matched, check self
|
||||||
|
(or best
|
||||||
|
(when (and (>= x nx) (< x (+ nx nw))
|
||||||
|
(>= y ny) (< y (+ ny nh)))
|
||||||
|
node)))))))
|
||||||
(recurse root)))
|
(recurse root)))
|
||||||
|
|
||||||
;; Selection
|
;; Selection
|
||||||
|
|||||||
@@ -76,7 +76,9 @@
|
|||||||
(subseq filtered start end)))
|
(subseq filtered start end)))
|
||||||
|
|
||||||
(defmethod render ((sel select) backend)
|
(defmethod render ((sel select) backend)
|
||||||
(let* ((ln (select-layout-node sel)) (x 0) (y 0)
|
(let* ((ln (select-layout-node sel))
|
||||||
|
(x (if ln (layout-node-x ln) 0))
|
||||||
|
(y (if ln (layout-node-y ln) 0))
|
||||||
(w (if ln (layout-node-width ln) 80))
|
(w (if ln (layout-node-width ln) 80))
|
||||||
(visible (select-visible-options sel)) (sel-idx (select-selected-index sel)))
|
(visible (select-visible-options sel)) (sel-idx (select-selected-index sel)))
|
||||||
(dolist (item visible)
|
(dolist (item visible)
|
||||||
|
|||||||
@@ -35,9 +35,11 @@
|
|||||||
(case (key-event-key event) (:left (tab-bar-prev tb) t) (:right (tab-bar-next tb) t) (t nil)))
|
(case (key-event-key event) (:left (tab-bar-prev tb) t) (:right (tab-bar-next tb) t) (t nil)))
|
||||||
|
|
||||||
(defmethod render ((tb tab-bar) backend)
|
(defmethod render ((tb tab-bar) backend)
|
||||||
(let* ((ln (tab-bar-layout-node tb)) (y 0)
|
(let* ((ln (tab-bar-layout-node tb))
|
||||||
|
(x (if ln (layout-node-x ln) 0))
|
||||||
|
(y (if ln (layout-node-y ln) 0))
|
||||||
(w (if ln (layout-node-width ln) 80))
|
(w (if ln (layout-node-width ln) 80))
|
||||||
(active-id (tab-bar-active tb)) (tabs (tab-bar-tabs tb)) (x-pos 0))
|
(active-id (tab-bar-active tb)) (tabs (tab-bar-tabs tb)) (x-pos x))
|
||||||
(dolist (tab tabs)
|
(dolist (tab tabs)
|
||||||
(let* ((id (getf tab :id)) (title (getf tab :title))
|
(let* ((id (getf tab :id)) (title (getf tab :title))
|
||||||
(label (format nil " ~A " title)) (label-len (length label))
|
(label (format nil " ~A " title)) (label-len (length label))
|
||||||
|
|||||||
@@ -165,6 +165,7 @@
|
|||||||
(cursor (text-input-cursor in))
|
(cursor (text-input-cursor in))
|
||||||
(display (if (plusp (length value))
|
(display (if (plusp (length value))
|
||||||
value
|
value
|
||||||
(or (text-input-placeholder in) ""))))
|
(or (text-input-placeholder in) "")))
|
||||||
|
(truncated (subseq display 0 (min (length display) w))))
|
||||||
(declare (ignore w cursor))
|
(declare (ignore w cursor))
|
||||||
(draw-text backend x y display nil nil)))
|
(draw-text backend x y truncated nil nil)))
|
||||||
|
|||||||
BIN
src/components/textarea.fasl
Normal file
BIN
src/components/textarea.fasl
Normal file
Binary file not shown.
@@ -248,7 +248,6 @@
|
|||||||
(h (if ln (layout-node-height ln) 24))
|
(h (if ln (layout-node-height ln) 24))
|
||||||
(lines (textarea-lines ta))
|
(lines (textarea-lines ta))
|
||||||
(max-lines (min (length lines) h)))
|
(max-lines (min (length lines) h)))
|
||||||
(declare (ignore w))
|
|
||||||
(loop for i from 0 below max-lines
|
(loop for i from 0 below max-lines
|
||||||
for line in lines
|
for line in lines
|
||||||
do (draw-text backend x (+ y i)
|
do (draw-text backend x (+ y i)
|
||||||
|
|||||||
Reference in New Issue
Block a user