anchor.diff:  ;;; ------------------------------------------------------------------------------------------
   ;;;  30.4.4 The concrete scroll-bar Gadget
   
  -(defclass scroll-bar-pane (sheet-multiple-child-mixin
  -                           3D-border-mixin
  -                           scroll-bar
  -                           )
  +(defclass scroll-bar-pane (3D-border-mixin
  +                           scroll-bar)
     ((event-state :initform nil)
      (drag-dy :initform nil)
  -   (inhibit-redraw-p
  -    :initform nil
  -    :documentation "Hack, when set to non-NIL changing something does not trigger redrawing.")
  -   (thumb :initform nil)
  -   )
  +   ;;; poor man's incremental redisplay
  +   ;; drawn state
  +   (up-state :initform nil)
  +   (dn-state :initform nil)
  +   (tb-state :initform nil)
  +   (tb-y1    :initform nil)
  +   (tb-y2    :initform nil)
  +   ;; old drawn state
  +   (old-up-state :initform nil)
  +   (old-dn-state :initform nil)
  +   (old-tb-state :initform nil)
  +   (old-tb-y1    :initform nil)
  +   (old-tb-y2    :initform nil)
  +   ;;
  +   (all-new-p    :initform t) )
     (:default-initargs :value 0
                        :min-value 0
                        :max-value 1
  
positive.code:       (cond ((region-contains-position-p (scroll-bar-up-region sb) x y)
               (scroll-up-line-callback sb (gadget-client sb) (gadget-id sb))
               (setf event-state :up-armed)
               (dispatch-repaint sb +everywhere+))
              ((region-contains-position-p (scroll-bar-down-region sb) x y)
               (scroll-down-line-callback sb (gadget-client sb) (gadget-id sb))
               (setf event-state :dn-armed)
               (dispatch-repaint sb +everywhere+))
              ((region-contains-position-p (scroll-bar-thumb-region sb) x y)
               (setf event-state :dragging
                     drag-dy (- y (bounding-rectangle-min-y (scroll-bar-thumb-region sb)))))
              ((region-contains-position-p (scroll-bar-thumb-bed-region sb) x y)
               (if (< y (bounding-rectangle-min-y (scroll-bar-thumb-region sb)))
                   (scroll-up-page-callback sb (gadget-client sb) (gadget-id sb))
                   (scroll-down-page-callback sb (gadget-client sb) (gadget-id sb))))
              (t
               nil)))))
  
  (defmethod handle-event ((sb scroll-bar-pane) (event pointer-button-release-event))
    (with-slots (event-state) sb
  
negative.code:     (make-rectangle* minx (- maxy (- maxx minx))
                       maxx maxy)))
  
  (defun scroll-bar/thumb-bed* (sb)
    ;; -> y1 y2 y3
    (with-bounding-rectangle* (minx miny maxx maxy) (transform-region (scroll-bar-transformation sb)
                                                                      (pane-inner-region sb))
      (let ((y1 (+ miny (- maxx minx) 1))
            (y3 (- maxy (- maxx minx) 1)))
        (let ((ts (scroll-bar-thumb-size sb)))
          ;; This is the right spot to handle ts = :none or perhaps NIL
          (multiple-value-bind (range) (gadget-range sb)
            (let ((ts-in-pixels (round (* (- y3 y1) (/ ts (+ range ts)))))) ;### range + ts = 0?
              (setf ts-in-pixels (min (- y3 y1) ;thumb can't be larger than the thumb bed
                                      (max +minimum-thumb-size-in-pixels+ ;but shouldn't be smaller than this.
                                           ts-in-pixels)))
              (values
               y1
               (- y3 ts-in-pixels)
               y3)))))))
  
  (defmethod scroll-bar-thumb-bed-region ((sb scroll-bar-pane))
    (with-bounding-rectangle* (minx miny maxx maxy) (transform-region (scroll-bar-transformation sb)
                                                                      (pane-inner-region sb))
      (declare (ignore miny maxy))
      (multiple-value-bind (y1 y2 y3) (scroll-bar/thumb-bed* sb)
        (declare (ignore y2))
        (make-rectangle* minx y1
                         maxx y3))))
  
  (defun scroll-bar/map-coordinate-to-value (sb y)
    (multiple-value-bind (y1 y2 y3) (scroll-bar/thumb-bed* sb)
      (declare (ignore y3))
      (multiple-value-bind (minv maxv) (gadget-range* sb)
        (if (= y1 y2)             ;### fix this in translate-range-value
            minv
            (translate-range-value y y1 y2 minv maxv)))))
  
  (defun scroll-bar/map-value-to-coordinate (sb v)
    (multiple-value-bind (y1 y2 y3) (scroll-bar/thumb-bed* sb)
      (declare (ignore y3))
      (multiple-value-bind (minv maxv) (gadget-range* sb)
        ;; oops, if the range is empty we lose!
        (if (= minv maxv)         ;### fix this in translate-range-value
            y1
            (round (translate-range-value v minv maxv y1 y2))))))
  
  (defmethod scroll-bar-thumb-region ((sb scroll-bar-pane))
    (with-bounding-rectangle* (x1 y1 x2 y2) (scroll-bar-thumb-bed-region sb)
      (multiple-value-bind (y1 y2 y3) (scroll-bar/thumb-bed* sb)
        (let ((y4 (scroll-bar/map-value-to-coordinate sb (gadget-value sb))))
          (make-rectangle* x1 y4 x2 (+ y4 (- y3 y2)))))))
  
  ;;;; event handler
  
  (defmethod handle-event ((sb scroll-bar-pane) (event pointer-button-press-event))
    (multiple-value-bind (x y) (transform-position (scroll-bar-transformation sb)
  