Index: main/widget/checkbox.lisp
===================================================================
--- main/widget/checkbox.lisp	(revision main,84)
+++ main/widget/checkbox.lisp	(revision main,84)
@@ -0,0 +1,87 @@
+(defpackage #:tui-widget-checkbox
+  (:use #:cl #:tui-widget-generic)
+  (:import-from #:dso-util #:nothing)
+  (:import-from #:tui-cursor #:cursor-position #:set-cursor-visible)
+  (:import-from #:tui-input #:read-key)
+  (:import-from #:tui-output #:add-clipped-string #:background)
+  (:import-from #:tui-window #:create-subwindow #:destroy-subwindow #:erase
+                #:refresh #:window-pointer)
+  (:export
+
+   ;; inherited
+   #:text #:widget #:parent-window #:column #:row #:inactive-background
+   #:active-background #:scroll #:insertion-point #:create-widget #:destroy
+   #:draw #:activate
+
+   ;; local
+   #:checkbox #:checked #:listener))
+
+(in-package #:tui-widget-checkbox)
+
+
+
+(defclass checkbox (widget)
+  ((checked :type boolean :initform nil :accessor checked)
+   (listener :type (or null function) :initform nil :accessor listener)
+   (cue-window :initarg :cue-window)
+   (data-window :initarg :data-window)
+   (active :type boolean :initform nil)))
+
+
+
+(defmethod draw ((cb checkbox))
+  (with-slots (checked cue-window data-window inactive-background
+                       active-background active) cb
+    (erase cue-window)
+    (add-clipped-string cue-window 0 0 "[ ]")
+    (setf (background data-window)
+          (if active active-background inactive-background))
+    (add-clipped-string data-window 0 0 (if (checked cb) "X" " "))
+    (setf (cursor-position data-window) '(0 0))
+    (refresh cue-window)))
+
+(defmethod (setf checked) :after (flag (cb checkbox))
+  (draw cb)
+  (with-slots (listener) cb
+    (when listener
+      (funcall listener))))
+
+
+
+(defmethod create-widget ((type (eql 'checkbox)) parent y x &rest args &key
+                          inactive-background active-background)
+  (declare (ignore type inactive-background active-background))
+  (let* ((cue-window (create-subwindow parent 1 3 y x))
+         (data-window (create-subwindow cue-window 1 1 0 1))
+         (inst (apply 'make-instance 'checkbox :cue-window cue-window
+                                               :data-window data-window args)))
+    (draw inst)
+    inst))
+
+(defmethod destroy ((cb checkbox))
+  (with-slots (cue-window data-window) cb
+    (destroy-subwindow data-window)
+    (destroy-subwindow cue-window)))
+
+
+
+(defmethod activate ((cb checkbox) &key (key-callback 'nothing)
+                     &allow-other-keys)
+  (with-slots (data-window active) cb
+    (with-accessors ((checked checked)) cb
+      (set-cursor-visible t)
+      (setf active t)
+      (unwind-protect
+           (progn
+             (cdk::c-keypad (window-pointer data-window) t)
+             (loop
+                (let ((key (read-key data-window)))
+                  (case key
+                    (#\Space
+                     (setf checked (not checked)))
+                    (t
+                     (let ((r (funcall key-callback key)))
+                       (when r
+                         (return r))))))))
+        (setf active nil)
+        (set-cursor-visible nil)))))
