;;; -*- Mode: LISP; Syntax: Common-Lisp; Package: DEMO-SCROLLBAR; Base: 10 -*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;         The Garnet User Interface Development Environment.      ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; This code was written as part of the Garnet project at          ;;;
;;; Carnegie Mellon University, and has been placed in the public   ;;;
;;; domain.  If you are using this code or any part of Garnet,      ;;;
;;; please contact garnet@cs.cmu.edu to be put on the mailing list. ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;  This file contains a top level function that creates a window and four
;;;  scroll bars -- Mac, Openlook, NeXT, and Motif.  Each module is included
;;;  in this single file, but a demo for each scroll bar may be run
;;;  independently.
;;;
;;;  ** (demo-scrollbar:do-go) to begin, **
;;;  ** (demo-scrollbar:do-stop) to stop **
;;;
;;;  Features:
;;;    1)  Leftdown in a trill box moves the indicator
;;;    2)  Leftdown in the background moves the indicator
;;;    3)  Leftdown + Drag in the indicator moves the indicator
;;;
;;;  Each scroll bar has a demo function included in this file --
;;;  MAC-GO, OPEN-GO, NEXT-GO, and MOTIF-GO, to display macintosh, openlook,
;;;  Next, and Motif scroll bars independently.
;;;
;;; -------------------------------------------------------------------------
;;; Designed and implemented by Brad Vander Zanden
;;;
;;; 2/25/92 Pervin  Added :constant slots
;;; 2/13/92 Pervin: merged demo-scrollbar and color-demo-scrollbar
;;; 3/14/90 Andrew Mickish:  Removed local motif-scrollbar and put in
;;;           garnet-gadgtets version
;;; 7/25/90 Roger Dannenberg - Changed :window slot of interactors to
;;;           (gv-local :self ...)
;;; 4/30/90  Edward Pervin : Added color
;;; 4/30/90  Andrew Mickish:  Updated appearance of Openlook and Next scrollbars
;;; 4/30/90  Andrew Mickish:  Added Motif scroll bar
;;; 4/9/90   R. Cook    Indent calls to opal:update.
;;; 11/20/89 Ed Pervin  Removed definition of Clip-and-Map,
;;;                     which is now exported from Interactor.
;;; 11/15/89 Ed Pervin: Had to rewrite BACKGROUND-TRILL because :y slot
;;;          was replaced by :y-off.
;;; 8/25/89  Andrew Mickish:  Added background trill interactor and integrated
;;;          into demo-scrollbar
;;; -------------------------------------------------------------------------


(in-package "DEMO-SCROLLBAR" :use '("LISP" "KR"))

(export '(Do-Go Do-Stop))
(export '(MAC-obj MAC-Go MAC-Stop))
(export '(Open-obj Open-Go Open-Stop))
(export '(NEXT-obj NEXT-Go NEXT-Stop))
(export '(Motif-obj Motif-Go Motif-Stop))

(defvar DEMO-SCROLLBAR-INIT
  (dolist (file '("motif-v-scroll-loader"))
    (load (merge-pathnames file
			   #+cmu "gadgets:"
			   #+(not cmu) user::Garnet-Gadgets-PathName))))

(defvar *color-p* (g-value opal:color :color-p))

;;; ********************************
;;; *  MACINTOSH SCROLL BAR MODULE *
;;; ********************************
;;;
;;; This module contains demo code for showing a macintosh-like scroll bar.
;;; When loaded, it creates a window that contains a scroll-bar that can be
;;; operated with the left mouse button
;;;
;;; This module is intended for use with the demo-scrollbar demo, which
;;; dispays mac, next, openlook, and motif scroll bars.
;;;
;;; There is also a demo function at the end of this file to display just the
;;; macintosh scroll bar:  (demo-scrollbar:mac-go) to begin.
;;;
;;; Features:
;;;   1)  Leftdown in a trill box moves the indicator
;;;   2)  Leftdown in the background moves the indicator
;;;   3)  Leftdown + Drag in the indicator moves the indicator
;;;

;;; function to create lines for the arrows. 

(defun MAC-create-arrow-line (obj init-x1 init-y1 init-x2 init-y2 x-offset y-offset)
    (create-instance NIL opal:line
	(:constant T)
	(:obj obj)
	(:x-offset x-offset)
	(:y-offset y-offset)
	(:x1 (o-formula (gvl :obj :x2) init-x1))
	(:y1 (o-formula (gvl :obj :y2) init-y1))
	(:x2 (o-formula (+ (gvl :x1) (gvl :x-offset)) init-x2))
	(:y2 (o-formula (+ (gvl :y1) (gvl :y-offset)) init-y2))))

;;;---------------------------------
;;; function to create a scroll bar
;;;---------------------------------

(defun MAC-make-scroll-bar (viewport top-agg scroll-bar-name left top width height)

  (let (slider trill-box-incr trill-box-decr slider-shell indicator)

;;; create the scroll bar and add it to top-agg

    (opal:add-component top-agg
	     (setf scroll-bar-name (create-instance NIL opal:aggregate)))
				

;;; create all the objects I need for a slider
    
    (setf slider (create-instance NIL opal:aggregate))
    (setf slider-shell (create-instance NIL opal:rectangle))
    (setf indicator (create-instance NIL opal:rectangle))

;;; create the slot definitions for the scroll box

    (s-value scroll-bar-name :left left)
    (s-value scroll-bar-name :top top)
    (s-value scroll-bar-name :width width)
    (s-value scroll-bar-name :height height)

;;; create the slot definitions for the slider

    (s-value slider :indicator indicator)

;;; create the slot definitions for the slider shell

    (s-value slider-shell :scroll-bar-name scroll-bar-name)
    (s-value slider-shell :left (o-formula (gvl :scroll-bar-name :left)))
    (s-value slider-shell :top (o-formula (gvl :scroll-bar-name :top)))
    (s-value slider-shell :width (o-formula (gvl :scroll-bar-name :width)))
    (s-value slider-shell :height (o-formula (gvl :scroll-bar-name :height)))
    (s-value slider-shell :bottom (o-formula (+ (gvl :top) (gvl :height))))
    (s-value slider-shell :filling-style 
			  (opal:halftone 50 :foreground-color
				(if *color-p* opal:red opal:black)))

;;; create the slot definitions for the indicator

    (s-value indicator :box '(0 80 10 10)) ; set by mouse interactor
    (s-value indicator :slider-shell slider-shell)
    (s-value indicator :percent (o-formula (inter:Clip-and-Map (second (gvl :box))
						    (gvl :slider-shell :top)
						    (- (gvl :slider-shell :bottom)
						       (gvl :height) 2)
						    0 100)))
    (s-value indicator :left (o-formula (+ 1 (gvl :slider-shell :left))))
    (s-value indicator :top (o-formula (1+ (inter:Clip-and-Map (gvl :percent)
						   0 100
						   (gvl :slider-shell :top)
						   (- (gvl :slider-shell :bottom)
						      (gvl :height) 2)))))
    (s-value indicator :filling-style (opal:halftone 0))
    (s-value indicator :width (o-formula (- (gvl :slider-shell :width) 2)))
    (s-value indicator :height (o-formula (gvl :width)))

;;; add the components to the slider

    (opal:add-component slider slider-shell)
    (opal:add-component slider indicator)

;;; create the increment and decrement trill boxes

    (setf trill-box-incr (MAC-make-incr-box viewport 'trill-box-incr1 indicator
			   (formula `(gv ',scroll-bar-name :left))
			   (formula `(- (gv ',scroll-bar-name :top)
					    (gvl :height)))
			   (formula `(gv ',scroll-bar-name :width))
			   20))

    (setf trill-box-decr (MAC-make-decr-box viewport 'trill-box-decr1 indicator
			   (formula `(gv ',scroll-bar-name :left))
			   (formula `(+ (gv ',scroll-bar-name :top)
					    (gv ',scroll-bar-name :height)))
			   (formula `(gv ',scroll-bar-name :width))
			   20))

;;; add the slider and the trill boxes to the scroll bar

    (opal:add-components scroll-bar-name slider trill-box-incr trill-box-decr)
    (s-value scroll-bar-name :slider slider)

;;; create the scroll bar interactor

    (create-instance NIL inter:Move-Grow-Interactor
		       (:window viewport)
		       (:continuous t)
		       (:start-event :leftdown)
		       (:start-where (list :in-box indicator))
		       (:running-where (list :in-box slider-shell))
		       (:outside :last)
		       (:obj-to-be-moved indicator)
		       (:feedback-obj NIL)
		       (:attach-point :center)
		       (:grow-p NIL)
		       (:waiting-priority inter:high-priority-level))

    (create-instance NIL inter:Move-Grow-Interactor
       (:window viewport)
       (:continuous T)
       (:start-event :leftdown)
       (:start-where (list :in-box slider-shell))
       ; The function checks whether the mouse event (leftdown) occured above
       ; or below the indicator box, and moves the indicator up or down
       ; by 5 appropriately.
       (:start-action
	#'(lambda (interactor final-obj-over point-list)
	    (declare (ignore final-obj-over point-list))
	    (let ((obj-to-be-moved (g-value interactor :obj-to-be-moved)))
	      (if (< (* (g-value interactor :y-off) 100)
		     (* (g-value obj-to-be-moved :percent)
			(g-value interactor :obj-being-changed :height)))
		  (if (>= (g-value obj-to-be-moved :percent) 5)
		      (decf (g-value obj-to-be-moved :percent) 5))
		  (if (<= (g-value obj-to-be-moved :percent) 95)
		      (incf (g-value obj-to-be-moved :percent) 5))))))
       (:running-where (list :in-box slider-shell))
       (:outside NIL)
       (:obj-to-be-moved indicator)
       (:grow-p NIL)))

  scroll-bar-name)


;;;---------------------------------------------
;;; function to create the increment trill box
;;;---------------------------------------------

(defun MAC-make-incr-box (viewport trill-box-incr indicator left top width height)
  (let (incr-box up-arrow up-arrow-line1 up-arrow-line2 up-arrow-line3
		   up-arrow-line4 up-arrow-line5 up-arrow-line6 up-arrow-line7)
 
;;; create the objects I need to make an increment trill box

    (setf trill-box-incr (create-instance NIL opal:aggregate))
    (setf incr-box (create-instance NIL opal:rectangle))
    (setf up-arrow (create-instance NIL opal:aggregate))
    (setf up-arrow-line1 (create-instance NIL opal:line))

;;; create the slot definitions for the trill box

    (s-value trill-box-incr :left left)
    (s-value trill-box-incr :top top)
    (s-value trill-box-incr :width width)
    (s-value trill-box-incr :height height)

;;; create the slot definitions for the increment box

    (s-value incr-box :trill-box-incr trill-box-incr)
    (s-value incr-box :left (o-formula (gvl :trill-box-incr :left)))
    (s-value incr-box :top (o-formula (gvl :trill-box-incr :top)))
    (s-value incr-box :width (o-formula (gvl :trill-box-incr :width)))
    (s-value incr-box :height (o-formula (gvl :trill-box-incr :height)))

;;; create the slot definitions for the arrow lines

    (s-value up-arrow-line1 :incr-box incr-box)
    (s-value up-arrow-line1 :x1 (o-formula (+ (gvl :incr-box :left) 6)))
    (s-value up-arrow-line1 :y1 (o-formula (+ (gvl :incr-box :top) 17)))
    (s-value up-arrow-line1 :x2 (o-formula (+ (gvl :x1) 8)))
    (s-value up-arrow-line1 :y2 (o-formula (gvl :y1)))

;;; create the other six lines used in the up arrow

    (setf up-arrow-line2 (MAC-create-arrow-line up-arrow-line1 114 165 114 159 0 -6))
    (setf up-arrow-line3 (MAC-create-arrow-line up-arrow-line2 114 159 119 159 5 0))
    (setf up-arrow-line4 (MAC-create-arrow-line up-arrow-line3 119 159 110 150 -9 -9))
    (setf up-arrow-line5 (MAC-create-arrow-line up-arrow-line4 110 150 101 159 -9 9))
    (setf up-arrow-line6 (MAC-create-arrow-line up-arrow-line5 101 159 106 159 5 0))
    (setf up-arrow-line7 (MAC-create-arrow-line up-arrow-line6 106 159 106 165 0 6))

;;; add the arrow lines to the up arrow aggregate

    (opal:add-component up-arrow up-arrow-line1)
    (opal:add-component up-arrow up-arrow-line2)
    (opal:add-component up-arrow up-arrow-line3)
    (opal:add-component up-arrow up-arrow-line4)
    (opal:add-component up-arrow up-arrow-line5)
    (opal:add-component up-arrow up-arrow-line6)
    (opal:add-component up-arrow up-arrow-line7)

;;; add the increment box and up arrow aggregate to the trill box aggregate

    (opal:add-component trill-box-incr incr-box)
    (opal:add-component trill-box-incr up-arrow)

;;; create the interactor for the increment trill box

    (create-instance NIL inter:Button-Interactor
		       (:window viewport)
		       (:continuous t)
		       (:feedback-obj NIL)
		       (:start-where (list :element-of trill-box-incr))
		       (:exception NIL)  ; no exceptions
		       (:start-event :leftdown)
		       (:stop-event :leftup)
		       (:stop-action #'(lambda (interactor final-obj-over)
					 (declare (ignore interactor final-obj-over))
					 (if (>= (g-value indicator :percent) 1)
					     (decf (g-value indicator :percent)))))))

  trill-box-incr)


;;;---------------------------------------------
;;; function to create the decrement trill box
;;;---------------------------------------------

(defun MAC-make-decr-box (viewport trill-box-decr indicator left top width height)
  (let (decr-box down-arrow down-arrow-line1 down-arrow-line2 down-arrow-line3
		   down-arrow-line4 down-arrow-line5 down-arrow-line6 
		   down-arrow-line7)
 
;;; create the objects I need to make a decrement trill box

    (setf trill-box-decr (create-instance NIL opal:aggregate))
    (setf decr-box (create-instance NIL opal:rectangle))
    (setf down-arrow (create-instance NIL opal:aggregate))
    (setf down-arrow-line1 (create-instance NIL opal:line))

;;; create the slot definitions for the trill box

    (s-value trill-box-decr :left left)
    (s-value trill-box-decr :top top)
    (s-value trill-box-decr :width width)
    (s-value trill-box-decr :height height)

;;; create the slot definitions for the decrement box

    (s-value decr-box :trill-box-decr trill-box-decr)
    (s-value decr-box :left (o-formula (gvl :trill-box-decr :left)))
    (s-value decr-box :top (o-formula (gvl :trill-box-decr :top)))
    (s-value decr-box :width (o-formula (gvl :trill-box-decr :width)))
    (s-value decr-box :height (o-formula (gvl :trill-box-decr :height)))

;;; create the slot definitions for the first down arrow line

    (s-value down-arrow-line1 :decr-box decr-box)
    (s-value down-arrow-line1 :x1 (o-formula (+ (gvl :decr-box :left) 6) 142))
    (s-value down-arrow-line1 :y1 (o-formula (+ (gvl :decr-box :top) 2) 150))
    (s-value down-arrow-line1 :x2 (o-formula (+ (gvl :x1) 8) 150))
    (s-value down-arrow-line1 :y2 (o-formula (gvl :y1) 150))

;;; create the other six lines used in the down arrow

    (setf down-arrow-line2 (MAC-create-arrow-line down-arrow-line1 150 150 150 156 0 6))
    (setf down-arrow-line3 (MAC-create-arrow-line down-arrow-line2 150 156 155 156 5 0))
    (setf down-arrow-line4 (MAC-create-arrow-line down-arrow-line3 155 156 146 165 -9 9))
    (setf down-arrow-line5 (MAC-create-arrow-line down-arrow-line4 146 165 137 156 -9 -9))
    (setf down-arrow-line6 (MAC-create-arrow-line down-arrow-line5 137 156 142 156 5 0))
    (setf down-arrow-line7 (MAC-create-arrow-line down-arrow-line6 142 156 142 150 0 -6))

;;; add the arrow lines to the down arrow aggregate

    (opal:add-component down-arrow down-arrow-line1)
    (opal:add-component down-arrow down-arrow-line2)
    (opal:add-component down-arrow down-arrow-line3)
    (opal:add-component down-arrow down-arrow-line4)
    (opal:add-component down-arrow down-arrow-line5)
    (opal:add-component down-arrow down-arrow-line6)
    (opal:add-component down-arrow down-arrow-line7)

;;; add the decrement box and down arrow aggregate to the trill box aggregate

    (opal:add-component trill-box-decr decr-box)
    (opal:add-component trill-box-decr down-arrow)

;;; create the interactor decrement trill box

    (create-instance NIL inter:button-interactor
		       (:window viewport)
		       (:feedback-obj NIL)
		       (:continuous t)
		       (:start-where (list :element-of trill-box-decr))
		       (:exception NIL)  ; no exceptions
		       (:start-event :leftdown)
		       (:stop-event :leftup)
		       (:stop-action #'(lambda (interactor final-obj-over)
					 (declare (ignore interactor final-obj-over))
					 (if (<= (g-value indicator :percent) 99)
					     (incf (g-value indicator :percent)))))))

  trill-box-decr)

;;;--------------------------------------
;;; function to create text that displays
;;; current value of the scroll bar
;;;--------------------------------------

(defun MAC-make-meter-text (top-agg meter-name scroll-bar-name left top)

;;; create the meter and add it to top-agg

    (opal:add-component top-agg
	     (setf meter-name (create-instance NIL opal:text)))

;;; create the slot definitions for the meter

  (s-value meter-name :left left)
  (s-value meter-name :top top)
  (s-value meter-name :scroll-bar-name scroll-bar-name)
  (s-value meter-name :string (o-formula (prin1-to-string (gvl :scroll-bar-name :slider :indicator :percent)) "4"))
  (s-value meter-name :font (create-instance NIL opal:font
					     (:size :small)))
  meter-name)



;;;
;;;  DEMO FUNCTION:  MAC-GO
;;;

(defparameter MAC-obj NIL)
(defparameter MAC-meter NIL)
(defparameter MAC-VP NIL)
(defparameter MAC-top-agg NIL)

(defun MAC-Go ()

;;; create a viewport

  (setq MAC-VP (create-instance NIL inter:interactor-window
				  (:left 100) (:top 10) (:width 200) (:height 300)
				  (:title "GARNET Mac")
				  (:icon-title "Mac")
				  (:aggregate
				   (setq MAC-top-agg
					 (create-instance NIL opal:aggregate)))))

;;; create the scroll bar and meter text and display them

  (setq MAC-obj (MAC-make-scroll-bar MAC-VP MAC-top-agg 'MAC-obj 64 48 21 200))
  (setq MAC-meter (MAC-make-meter-text MAC-top-agg 'MAC-meter MAC-obj
		 (formula `(- (+ (gv ',MAC-obj :slider :indicator :left)
				     (floor (gv ',MAC-obj :slider :indicator :width) 2))
				  (floor (gvl :width) 2)))

		 (formula `(- (+ (gv ',MAC-obj :slider :indicator :top)
				     (floor (gv ',MAC-obj :slider :indicator :height) 2))
				  (floor (gvl :height) 2)))))



  (opal:update MAC-VP))



(defun MAC-Stop ()
  (opal:destroy MAC-VP))


;;; ******************************
;;; * OPENLOOK SCROLL BAR MODULE *
;;; ******************************

;;; This module contains demo code for showing a openlook-like scroll bar.
;;; When the demo is executed, it creates a window that contains a scroll-bar
;;; that can be operated with the left mouse button
;;;
;;; This module is intended for use with the demo-scrollbar demo, which
;;; dispays mac, next, openlook, and motif scroll bars.
;;;
;;; There is also a demo function at the end of this file to display just the
;;; openlook scroll bar:  (demo-scrollbar:open-go) to begin.
;;;
;;; Features:
;;;   1)  Leftdown in a trill box moves the indicator
;;;   2)  Leftdown in the background moves the indicator
;;;   3)  Leftdown + Drag in the indicator moves the indicator
;;;

(create-instance 'OPEN-INTER inter:button-interactor
   (:window (o-formula (gv-local :self :operates-on :window)))
   (:start-where (o-formula (list :in-box (gvl :operates-on) :box)))
   (:waiting-priority inter:high-priority-level))


(create-instance 'OPEN-END-RECT opal:aggregadget
   (:parts
    `((:box ,opal:rectangle
	    (:left ,(o-formula (gvl :parent :parent :left)))
	    (:top ,(o-formula (gvl :parent :top)))
	    (:width ,(o-formula (gvl :parent :parent :bound-width)))
	    (:height ,(o-formula (gvl :parent :parent :end-rect-height))))))
   (:interactors
    `((:jump ,OPEN-INTER
	     (:final-function ,(o-formula (gvl :operates-on :final-fn)))))))


(create-instance 'OPEN-UP-ARROW opal:polyline
   (:left (o-formula (+ 2 (gvl :parent :box :left))))
   (:right (o-formula (- (+ (gvl :parent :box :left) (gvl :parent :box :width))
			 4)))
   (:center-x (o-formula (+ (gvl :left)
			    (floor (- (gvl :right) (gvl :left)) 2))))
   (:top (o-formula (+ 4 (gvl :parent :box :top))))
   (:bottom (o-formula (- (+ (gvl :parent :box :top) (gvl :parent :box :height))
			     8)))
   (:point-list (o-formula (list (gvl :center-x) (gvl :top)
				 (gvl :right) (gvl :bottom)
				 (gvl :left) (gvl :bottom)
				 (gvl :center-x) (gvl :top))))
   (:filling-style opal:green-fill))


(create-instance 'OPEN-DOWN-ARROW OPEN-UP-ARROW
   (:point-list (o-formula (list (gvl :center-x) (gvl :bottom)
				 (gvl :left) (gvl :top)
				 (gvl :right) (gvl :top)
				 (gvl :center-x) (gvl :bottom)))))


(create-instance 'OPEN-TRILL-BOX opal:rectangle
   (:left (o-formula (gvl :parent :parent :parent :left)))
   (:top (o-formula (gvl :parent :top)))
   (:width (o-formula (gvl :parent :parent :parent :bound-width)))
   (:height (o-formula (gvl :width)))
   (:filling-style opal:white-fill))


(create-instance 'OPEN-SCROLLBAR opal:aggregadget
   (:left 50)
   (:top 50)
   (:width 21)
   (:height 200)
   (:end-rect-height 5)
   (:shadow-offset 3)

   (:value (o-formula (inter:Clip-and-Map (second (gvl :indicator :box))
					  (gvl :bound-top)
					  (- (gvl :bound-bottom)
					     (gvl :indicator :height) 2)
					  0 100)))
   (:bound-top (o-formula (+ 1 (gvl :top) (gvl :end-rect-height))))
   (:bound-width (o-formula (- (gvl :width) (gvl :shadow-offset))))
   (:bound-height (o-formula (- (gvl :height)
				(* 2 (gvl :end-rect-height)) 2)))
   (:bound-bottom (o-formula (+ (gvl :bound-top) (gvl :bound-height))))

   (:parts
    `((:bound-box ,opal:rectangle
		  (:left ,(o-formula (gvl :parent :left)))
		  (:top ,(o-formula (gvl :parent :bound-top)))
		  (:width ,(o-formula (gvl :parent :bound-width)))
		  (:height ,(o-formula (gvl :parent :bound-height)))
		  (:line-style NIL))
      (:line ,opal:line
	     (:x1 ,(o-formula (+ (gvl :parent :left)
				 (floor (gvl :parent :width) 2))))
	     (:y1 ,(o-formula (gvl :parent :bound-top)))
	     (:x2 ,(o-formula (gvl :x1)))
	     (:y2 ,(o-formula (gvl :parent :bound-bottom)))
	     (:line-style ,(create-instance NIL opal:line-style
			      (:foreground-color
				 (if *color-p* opal:green opal:black))
			      (:line-thickness 4)
			      (:stipple opal::gray-fill-bitmap))))
      (:top-end-rect ,OPEN-END-RECT
		     (:top ,(o-formula (gvl :parent :top)))
		     (:final-fn ,#'(lambda (interactor obj)
				  (declare (ignore obj))
				  (let ((slider (g-value interactor :operates-on
							 :parent)))
				    (s-value slider :value 0)))))
      (:bot-end-rect ,OPEN-END-RECT
		     (:top ,(o-formula (+ (gvl :parent :bound-bottom) 1)))
		     (:final-fn ,#'(lambda (interactor obj)
				  (declare (ignore obj))
				  (let ((slider (g-value interactor :operates-on
							 :parent)))
				    (s-value slider :value 100)))))
      (:indicator ,opal:aggregadget
	  (:box (0 75 0 0))   ;; Set by interactor
	  (:top ,(o-formula
		  ;; Use LET since :parent is used several times
		  (let ((parent (gvl :parent)))
		    (inter:Clip-and-Map (gv parent :value) 0 100
					(gv parent :bound-top)
					(- (gv parent :bound-bottom)
					   (gvl :height))))))
	  (:height ,(o-formula (+ (* 3 (gvl :parent :bound-width))
				  (gvl :parent :shadow-offset))))
	  (:parts
	   ((:shadow ,opal:rectangle
		 (:left ,(o-formula (+ (gvl :parent :parent :left)
				       (gvl :parent :parent :shadow-offset))))
		 (:top ,(o-formula (+ (gvl :parent :top)
				      (gvl :parent :parent :shadow-offset))))
		 (:width ,(o-formula (gvl :parent :parent :bound-width)))
		 (:height ,(o-formula (* 3 (gvl :width))))
		 (:filling-style ,opal:green-fill))
	     (:top-trill ,opal:aggregadget
		 (:top ,(o-formula (gvl :parent :top)))
		 (:parts
		  ((:box ,OPEN-TRILL-BOX)
		   (:arrow ,OPEN-UP-ARROW)))
		 (:interactors
		  ((:trill ,OPEN-INTER
			   (:final-function
			    ,#'(lambda (interactor obj)
			      (declare (ignore interactor))
			      (let* ((slider (g-value obj :parent :parent))
				     (value (g-value slider :value)))
				(when (> value 1)
				  (s-value slider :value (- value 1))))))))))
	     (:middle ,opal:rectangle
		      (:left ,(o-formula (gvl :parent :parent :left)))
		      (:top ,(o-formula (+ (gvl :parent :parent :bound-width)
					   (gvl :parent :top))))
		      (:width ,(o-formula (gvl :parent :parent :bound-width)))
		      (:height ,(o-formula (gvl :width)))
		      (:filling-style ,opal:white-fill))
	     (:bot-trill ,opal:aggregadget
		 (:top ,(o-formula (+ (gvl :parent :top)
				      (* (gvl :parent :parent :bound-width)
					 2))))
		 (:parts
		  ((:box ,OPEN-TRILL-BOX)
		   (:arrow ,OPEN-DOWN-ARROW)))
		 (:interactors
		  ((:trill ,OPEN-INTER
			   (:final-function
			    ,#'(lambda (interactor obj)
			      (declare (ignore interactor))
			      (let* ((slider (g-value obj :parent :parent))
				     (value (g-value slider :value)))
				(when (< value 100)
				  (s-value slider :value (+ value 1)))))))))))))))
   (:interactors
    `((:slide ,inter:move-grow-interactor
	      (:window ,(o-formula (gv-local :self :operates-on :window)))
	      (:continuous T)
	      (:start-where
	       ,(o-formula (list :in-box
				 (gvl :operates-on :indicator :middle))))
	      (:running-where ,(o-formula (list :in-box
						(gvl :operates-on :bound-box))))
	      (:outside NIL)
	      (:obj-to-change ,(o-formula (gvl :operates-on :indicator)))
	      (:obj-to-be-moved ,(o-formula (gvl :operates-on :indicator)))
	      (:feedback-obj ,(o-formula (gvl :operates-on :indicator)))
	      (:grow-p NIL)
	      (:attach-point :where-hit)
	      (:waiting-priority ,inter:high-priority-level))
      (:jump ,inter:Move-Grow-Interactor
	     (:window ,(o-formula (gv-local :self :operates-on :window)))
	     (:continuous T)
	     (:start-where ,(o-formula (list :in-box
					     (gvl :operates-on :bound-box))))
	     (:running-where ,(o-formula (list :in-box
					       (gvl :operates-on :bound-box))))
	     (:outside NIL)
	     (:obj-to-be-moved ,(o-formula (gvl :operates-on :indicator)))
	     (:grow-p NIL)
	     (:start-action
	      ,#'(lambda (interactor obj-over points-list)
		(declare (ignore obj-over points-list))
		(let* ((indicator (g-value interactor :obj-to-be-moved))
		       (slider (g-value indicator :parent))
		       (value (g-value slider :value)))
		  (if (> (g-value interactor :y-off) (g-value indicator :top))
		      (when (<= value 95) (s-value slider :value (+ value 5)))
		      (when (>= value 5) (s-value slider :value (- value 5)))
		      ))))))))

;;;
;;;  DEMO FUNCTION:  OPEN-GO
;;;

(defun OPEN-Go ()

  ;;; Create a window
  (create-instance 'OPEN-vp inter:interactor-window
     (:left 300) (:top 10) (:width 200) (:height 300)
     (:title "GARNET OpenLook") (:icon-title "OpenLook")
     (:aggregate
      (create-instance 'OPEN-top-agg opal:aggregate)))

  ;;; Add the scroll bar to the window and display it
  (opal:add-component OPEN-top-agg OPEN-SCROLLBAR)
  (opal:update OPEN-vp)

  ;;; Create a text object to display the scrollbar's value
  (create-instance 'OPEN-TEXT opal:text
     (:constant T :except :string)
     (:left 150) (:top 140)
     (:string (o-formula (prin1-to-string (gv OPEN-SCROLLBAR :value))))
     (:font opal:default-font))
  (opal:add-component OPEN-top-agg OPEN-TEXT)
  (opal:update OPEN-vp))


(defun OPEN-Stop ()
  ;; Remove scrollbar first so it won't be destroyed with the window
  (opal:remove-component OPEN-top-agg OPEN-SCROLLBAR)
  (opal:destroy OPEN-vp))




;;; **************************
;;; * NeXT SCROLL BAR MODULE *
;;; **************************


;;;
;;; This file contains demo code for showing a NeXT-like scroll bar.
;;; When loaded, it creates a window that contains a scroll-bar that can be
;;; operated with the left mouse button
;;;
;;; This module is intended for use with the demo-scrollbar demo, which
;;; dispays mac, next, openlook, and motif scroll bars.
;;;
;;; There is also a demo function at the end of this file to display just the
;;; NeXT scroll bar:  (demo-scrollbar:next-go) to begin.
;;;
;;; Features:
;;;   1)  Leftdown in a trill box moves the indicator
;;;   2)  Leftdown in the background moves the indicator
;;;   3)  Leftdown + Drag in the indicator moves the indicator

(create-instance 'NEXT-INTER inter:button-interactor
   (:window (o-formula (gv-local :self :operates-on :window)))
   (:start-where (o-formula (list :in-box (gvl :operates-on) :box)))
   (:waiting-priority inter:high-priority-level))


(create-instance 'NEXT-UP-ARROW opal:polyline
   (:left (o-formula (+ 4 (gvl :parent :box :box :left))))
   (:right (o-formula (- (+ (gvl :parent :box :box :left)
			    (gvl :parent :box :box :width))
			 4)))
   (:center-x (o-formula (+ (gvl :left)
			    (floor (- (gvl :right) (gvl :left)) 2))))
   (:top (o-formula (+ 3 (gvl :parent :box :box :top))))
   (:bottom (o-formula (- (+ (gvl :parent :box :box :top)
			     (gvl :parent :box :box :height))
			     3)))
   (:point-list (o-formula (list (gvl :center-x) (gvl :top)
				 (gvl :right) (gvl :bottom)
				 (gvl :left) (gvl :bottom)
				 (gvl :center-x) (gvl :top)))))

(create-instance 'NEXT-DOWN-ARROW NEXT-UP-ARROW
   (:point-list (o-formula (list (gvl :center-x) (gvl :bottom)
				 (gvl :left) (gvl :top)
				 (gvl :right) (gvl :top)
				 (gvl :center-x) (gvl :bottom)))))


(create-instance 'light-blue-gray-fill opal:light-gray-fill
		 (:foreground-color (if *color-p* opal:blue opal:black)))
(create-instance 'blue-gray-fill opal:gray-fill
		 (:foreground-color (if *color-p* opal:blue opal:black)))

(create-instance 'NEXT-SHADOW-BOX opal:aggregadget
   (:left (o-formula (gvl :parent :parent :trill-left)))
   (:top (o-formula (gvl :parent :top)))
   (:width (o-formula (gvl :parent :parent :trill-width)))
   (:height (o-formula (gvl :parent :height)))
   (:shadow-width (o-formula (- (gvl :width) 2)))
   (:shadow-height (o-formula (- (gvl :height) 2)))
   (:parts
    `((:white-shadow ,opal:rectangle
	  (:left ,(o-formula (gvl :parent :left)))
	  (:top ,(o-formula (gvl :parent :top)))
	  (:width ,(o-formula (gvl :parent :width)))
	  (:height ,(o-formula (gvl :parent :height)))
	  (:filling-style ,opal:white-fill)
	  (:line-style NIL))
      (:black-shadow ,opal:rectangle
	  (:left ,(o-formula (+ 2 (gvl :parent :left))))
	  (:top ,(o-formula (+ 2 (gvl :parent :top))))
	  (:width ,(o-formula (gvl :parent :shadow-width)))
	  (:height ,(o-formula (gvl :parent :shadow-height)))
	  (:filling-style ,opal:blue-fill)
	  (:line-style NIL))
      (:box ,opal:rectangle
	  (:left ,(o-formula (+ 1 (gvl :parent :left))))
	  (:top ,(o-formula (+ 1 (gvl :parent :top))))
	  (:width ,(o-formula (- (gvl :parent :width) 3)))
	  (:height ,(o-formula (- (gvl :parent :height) 3)))
	  (:filling-style ,light-blue-gray-fill)
	  (:line-style NIL)))))

(create-instance 'NEXT-SCROLLBAR opal:aggregadget
   (:left 50)
   (:top 20)
   (:width 23)
   (:height 250)

   (:value (o-formula (inter:Clip-and-Map (second (gvl :indicator :box))
					  (gvl :bound-top)
					  (- (gvl :bound-bottom)
					     (gvl :indicator :height) 2)
					  0 100)))
   (:trill-left (o-formula (+ (gvl :left) 2)))
   (:trill-width (o-formula (- (gvl :width) 4)))
   (:bound-top (o-formula (+ 2 (gvl :top))))
   (:bound-height (o-formula (- (gvl :height) (* 2 (gvl :trill-width)) 8)))
   (:bound-bottom (o-formula (+ (gvl :bound-top) (gvl :bound-height))))

   (:parts
      ;; An invisible bounding box that the :slide interactor works in
    `((:bound-box ,opal:rectangle
		  (:left ,(o-formula (gvl :parent :left)))
		  (:top ,(o-formula (gvl :parent :bound-top)))
		  (:width ,(o-formula (gvl :parent :width)))
		  (:height ,(o-formula (gvl :parent :bound-height)))
		  (:line-style NIL))
      ;; The thin rectangle around the outside of the scroll bar
      (:outline ,opal:rectangle
		(:left ,(o-formula (gvl :parent :left)))
		(:top ,(o-formula (gvl :parent :top)))
		(:width ,(o-formula (gvl :parent :width)))
		(:height ,(o-formula (gvl :parent :height)))
		(:filling-style ,opal:white-fill))
      ;; The gray background
      (:background ,opal:rectangle
		   (:left ,(o-formula (+ 2 (gvl :parent :left))))
		   (:top ,(o-formula (+ 2 (gvl :parent :top))))
		   (:width ,(o-formula (- (gvl :parent :width) 3)))
		   (:height ,(o-formula (- (gvl :parent :height) 3)))
		   (:line-style NIL)
		   (:filling-style ,blue-gray-fill))
      (:top-trill ,opal:aggregadget
		  (:top ,(o-formula (+ (gvl :parent :bound-bottom) 2)))
		  (:height ,(o-formula (gvl :parent :trill-width)))
		  (:parts
		   ((:box ,NEXT-SHADOW-BOX)
		    (:arrow ,NEXT-UP-ARROW)))
		  (:interactors
		   ((:trill ,NEXT-INTER
			    (:final-function
			     ,#'(lambda (interactor obj)
			       (declare (ignore interactor))
			       (let* ((slider (g-value obj :parent))
				      (value (g-value slider :value)))
				 (when (> value 1)
				   (s-value slider :value (- value 1))))))))))
      (:bot-trill ,opal:aggregadget
		  (:top ,(o-formula (+ (gvl :parent :bound-bottom)
				       (gvl :parent :trill-width) 4)))
		  (:height ,(o-formula (gvl :parent :trill-width)))
		  (:parts
		   ((:box ,NEXT-SHADOW-BOX)
		    (:arrow ,NEXT-DOWN-ARROW)))
		  (:interactors
		   ((:trill ,NEXT-INTER
			    (:final-function
			     ,#'(lambda (interactor obj)
			       (declare (ignore interactor))
			       (let* ((slider (g-value obj :parent))
				      (value (g-value slider :value)))
				 (when (< value 100)
				   (s-value slider :value (+ value 1))))))))))
      (:indicator ,opal:aggregadget
	  (:box (0 50 0 0))   ;; Set by interactor
	  (:left ,(o-formula (gvl :parent :trill-left)))
	  (:top ,(o-formula
		  ;; Use LET since :parent is used several times
		  (let ((parent (gvl :parent)))
		    (inter:Clip-and-Map (gv parent :value) 0 100
					(gv parent :bound-top)
					(- (gv parent :bound-bottom)
					   (gvl :height))))))
	  (:width ,(o-formula (gvl :parent :trill-width)))
	  (:height ,(o-formula (floor (gvl :parent :bound-height) 2)))
	  (:circle-left ,(o-formula (- (+ (gvl :left) (floor (gvl :width) 2))
				       5)))
	  (:circle-top ,(o-formula (- (+ (gvl :top) (floor (gvl :height) 2))
				      5)))
	  (:parts
	   ((:rect ,NEXT-SHADOW-BOX)
	    (:circ ,opal:circle
		   (:left ,(o-formula (gvl :parent :circle-left)))
		   (:top ,(o-formula (gvl :parent :circle-top)))
		   (:width 10) (:height 10)
		   (:filling-style ,opal:white-fill))
	    (:semi ,opal:arc
		   (:left ,(o-formula (+ 2 (gvl :parent :circle-left))))
		   (:top ,(o-formula (+ 2 (gvl :parent :circle-top))))
		   (:width 8) (:height 8)
		   (:angle1 ,(/ pi 4)) (:angle2 ,pi)))))))
   (:interactors
    `((:slide ,inter:move-grow-interactor
	      (:window ,(o-formula (gv-local :self :operates-on :window)))
	      (:continuous T)
	      (:start-where ,(o-formula (list :in-box
					      (gvl :operates-on :indicator))))
	      (:running-where ,(o-formula (list :in-box
						(gvl :operates-on :bound-box))))
	      (:outside NIL)
	      (:obj-to-be-moved ,(o-formula (gvl :operates-on :indicator)))
	      (:feedback-obj ,(o-formula (gvl :operates-on :indicator)))
	      (:grow-p NIL)
	      (:attach-point :where-hit)
	      (:waiting-priority ,inter:high-priority-level))
      (:jump ,inter:Move-Grow-Interactor
	     (:window ,(o-formula (gv-local :self :operates-on :window)))
	     (:continuous T)
	     (:start-where ,(o-formula (list :in-box
					     (gvl :operates-on :bound-box))))
	     (:running-where ,(o-formula (list :in-box
					       (gvl :operates-on :bound-box))))
	     (:outside NIL)
	     (:obj-to-be-moved ,(o-formula (gvl :operates-on :indicator)))
	     (:grow-p NIL)
	     (:start-action
	      ,#'(lambda (interactor obj-over points-list)
		(declare (ignore obj-over points-list))
		(let* ((indicator (g-value interactor :obj-to-be-moved))
		       (slider (g-value indicator :parent))
		       (value (g-value slider :value)))
		  (if (> (g-value interactor :y-off) (g-value indicator :top))
		      (when (<= value 95) (s-value slider :value (+ value 5)))
		      (when (>= value 5) (s-value slider :value (- value 5)))
		      ))))))))


;;;
;;;  DEMO FUNCTION: NEXT-GO
;;;

(defun NEXT-Go ()

  ;;; create a viewport
  (create-instance 'NEXT-vp inter:interactor-window
     (:left 500) (:top 10) (:width 200) (:height 300)
     (:title "GARNET NeXT") (:icon-title "NeXT")
     (:aggregate
      (create-instance 'NEXT-top-agg opal:aggregate)))

  ;;; add the scrollbar to the window and display it
  (opal:add-component NEXT-top-agg NEXT-SCROLLBAR)
  (opal:update NEXT-vp)

  ;;; Create a text object to display the scrollbar's value
  (create-instance 'NEXT-TEXT opal:text
     (:constant T :except :string)
     (:left 150) (:top 140)
     (:string (o-formula (prin1-to-string (gv NEXT-SCROLLBAR :value))))
     (:font opal:default-font))
  (opal:add-component NEXT-top-agg NEXT-TEXT)
  (opal:update NEXT-vp))


(defun NEXT-Stop ()
  ;; Remove the scrollbar so that it is not destroyed along with the window
  (opal:remove-component NEXT-top-agg NEXT-SCROLLBAR)
  (opal:destroy NEXT-vp))



;;; **************************
;;; * MOTIF SCROLL BAR MODULE *
;;; **************************

;;;
;;; This file contains demo code for showing a Motif-like scroll bar.
;;; When loaded, it creates a window that contains a scroll-bar that can be
;;; operated with the left mouse button
;;;
;;; This module is intended for use with the demo-scrollbar demo, which
;;; dispays mac, next, openlook, and motif scroll bars.
;;;
;;; There is also a demo function at the end of this file to display just the
;;; Motif scroll bar:  (demo-scrollbar:motif-go) to begin.
;;;
;;; Features:
;;;   1)  Leftdown in a trill box moves the indicator
;;;   2)  Leftdown in the background moves the indicator
;;;   3)  Leftdown + Drag in the indicator moves the indicator


;;;
;;;  DEMO FUNCTION: MOTIF-GO
;;;

(defun MOTIF-Go (&key double-buffered-p)

  ;;; create a viewport
  (create-instance 'MOTIF-vp inter:interactor-window
     (:double-buffered-p double-buffered-p)
     (:left 700) (:top 10) (:width 200) (:height 300)
     (:title "GARNET Motif") (:icon-title "Motif"))
  (s-value MOTIF-vp
	   :aggregate
	   (create-instance 'MOTIF-top-agg opal:aggregate))

  (create-instance 'MOTIF-SCROLLBAR garnet-gadgets:Motif-V-Scroll-Bar
     (:constant T)
     (:left 75) (:top 20) (:height 250)
     (:foreground-color (if *color-p* opal:Motif-Blue opal:black)))

  ;;; Create a text object to display the scrollbar's value
  (create-instance 'MOTIF-TEXT opal:text
     (:constant T :except :string)
     (:left 150) (:top 140)
     (:string (o-formula (prin1-to-string (gv MOTIF-SCROLLBAR :value))))
     (:font opal:default-font))

  (opal:add-components MOTIF-top-agg
                       ;;; The motif scrollbar needs a gray background to be
		       ;;; superimposed over
		       (create-instance NIL garnet-gadgets:Motif-Background
			  (:foreground-color
			    (if *color-p* opal:Motif-Blue opal:Black)))
		       ;;; Now add the scrollbar and the text object
		       MOTIF-SCROLLBAR MOTIF-TEXT)

  (opal:update MOTIF-vp))


(defun MOTIF-Stop ()
  (opal:destroy MOTIF-vp))



;;; ******************************************
;;; * TOP LEVEL DEMO-SCROLLBAR DEMO FUNCTION *
;;; ******************************************


(defparameter SB-VP NIL)
(defparameter SB-TOP-AGG NIL)

(defparameter SB-MAC-obj NIL)
(defparameter SB-MAC-meter NIL)

(defparameter SB-next-vp NIL)
(defparameter SB-next-agg NIL)
(defparameter SB-next-obj NIL)
(defparameter SB-next-incr-button NIL)
(defparameter SB-next-decr-button NIL)
(defparameter SB-next-meter NIL)
(defparameter SB-next-box NIL)
(defparameter SB-next-background NIL)

(defun DO-GO (&key dont-enter-main-event-loop double-buffered-p)

;;; create a viewport

  (setq SB-VP (create-instance NIL inter:interactor-window
		 (:left 100) (:top 10) (:width 600) (:height 300)
		 (:title "GARNET Scroll Bars") (:icon-title "Scroll Bars")
                 (:double-buffered-p double-buffered-p)
		 (:aggregate
		  (setq SB-top-agg
			(create-instance NIL opal:aggregate)))))

;;; create the scroll bar and meter text and display them

  (setq SB-MAC-obj (MAC-make-scroll-bar SB-VP SB-top-agg 'SB-MAC-obj 64 48 21 200))
  (setq SB-MAC-meter (MAC-make-meter-text SB-top-agg 'SB-MAC-meter SB-MAC-obj
		 (formula `(- (+ (gv ',SB-MAC-obj :slider :indicator :left)
				     (floor (gv ',SB-MAC-obj :slider :indicator :width) 2))
				  (floor (gvl :width) 2)))

		 (formula `(- (+ (gv ',SB-MAC-obj :slider :indicator :top)
				     (floor (gv ',SB-MAC-obj :slider :indicator :height) 2))
				  (floor (gvl :height) 2)))))


;;;
;;;  OPEN
;;;

  (opal:add-component SB-top-agg (create-instance 'SB-OPEN-OBJ OPEN-SCROLLBAR
				    (:left 200)))
  (opal:update SB-VP)

  ;;; Create a text object to display the Openlook scrollbar's value
  (create-instance 'SB-OPEN-TEXT opal:text
     (:constant T :except :string)
     (:left 250) (:top 150)
     (:string (o-formula (prin1-to-string (gv SB-OPEN-OBJ :value))))
     (:font opal:default-font))
  (opal:add-component SB-top-agg SB-OPEN-TEXT)
  (opal:update SB-vp)

;;;
;;;  NEXT
;;;

  (opal:add-component SB-top-agg (create-instance 'SB-NEXT-OBJ NEXT-SCROLLBAR
				    (:left 325)))
  (opal:update SB-VP)

  ;;; Create a text object to display the NeXT scrollbar's value
  (create-instance 'SB-NEXT-TEXT opal:text
     (:constant T :except :string)
     (:left 380) (:top 130)
     (:string (o-formula (prin1-to-string (gv SB-NEXT-OBJ :value))))
     (:font opal:default-font))
  (opal:add-component SB-top-agg SB-NEXT-TEXT)
  (opal:update SB-vp)

;;;
;;;  MOTIF
;;;

  ;;; The motif scrollbar needs a gray background to be superimposed over
  (create-instance 'SB-MOTIF-BACKGROUND garnet-gadgets:Motif-Background
     (:left 460)(:top 15)(:width 30)(:height 260)
     (:foreground-color (if *color-p* opal:Motif-Green opal:Black)))
  (opal:add-component SB-top-agg SB-MOTIF-BACKGROUND)
  (opal:update SB-VP)

  ;;; Create an instance of the motif scrollbar and add it to the window
  (create-instance 'SB-MOTIF-OBJ garnet-gadgets:Motif-V-Scroll-Bar
     (:constant T)
     (:left 465) (:top 20) (:height 250)
     (:foreground-color (if *color-p* opal:Motif-Green opal:Black)))
  (opal:add-component SB-top-agg SB-MOTIF-OBJ)
  (opal:update SB-VP)

  ;;; Create a text object to display the Motif scrollbar's value
  (create-instance 'SB-MOTIF-TEXT opal:text
     (:constant T :except :string)
     (:left 520) (:top 110)
     (:string (o-formula (prin1-to-string (gv SB-MOTIF-OBJ :value))))
     (:font opal:default-font))
  (opal:add-component SB-top-agg SB-MOTIF-TEXT)
  (opal:update SB-vp)

  (unless dont-enter-main-event-loop #-cmu (inter:main-event-loop))

  )

(defun DO-STOP ()
  (opal:destroy SB-VP))
