;;; -*- Mode: LISP; Syntax: Common-Lisp; Package: OPAL; 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. ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Changes:
;;; 16-Jul-93 amickish Moved Set-Draw-Functions to defs.lisp
;;; 22-Jul-92 bvz Rewrote gv-right, etc. functions to use broken-link-throw
;;; 16-Mar-92 dzg,amickish  Removed copy-down of :update-slots and
;;;               :fast-redraw-p in :intialize method of opal:view-object
;;; 10-Mar-92 ecp Rewrote halftone, halftone-darker, halftone-lighter
;;;		  so that if you call halftone twice with the same argument
;;;		  you'll get the same answer.
;;;  6-Aug-91 dzg Added error checking in bottom, right, etc.
;;; 20-May-90 ecp New :percent slot in opal:bitmap tells what percent it is.
;;; 19-Jun-90 ecp New functions gv-center-x-is-center-of, gv-center-y-is-center-of,
;;;		  gv-right-is-left-of, gv-bottom-is-top-of.
;;;  5-Jun-90 dzg Changed update-info structure to reduce storage allocation.
;;; 16-Apr-90 ecp Moved center-x, center-y from basics.lisp to objects.lisp
;;; 19-Mar-90 ecp Changed :tile to :stipple
;;; 13-Feb-90 dzg Changed certain macros to defuns.
;;;               Added new arguments to halftone (for color).

(in-package "OPAL" :use '("LISP" "KR"))

;;; The following allow access and setting to the gobs center
;;; position.

(defun center (gob)
  (values (center-x gob) (center-y gob)))

;;; The accessors for the bottom and right of the gob, make it easier to
;;; adjust the far side of the gob's bounding box.
;;; Used to be macros, but were changed to defuns for efficiency.

(defun bottom (gob)
  (when gob (1- (+ (g-value gob :top) (g-value gob :height)))))

(defun right (gob)
  (when gob (1- (+ (g-value gob :left) (g-value gob :width)))))

(defun gv-bottom (gob)
  (if gob (1- (+ (gv gob :top) (gv gob :height)))
          (kr::broken-link-throw nil :top)))

(defun gv-right (gob)
  (if gob (1- (+ (gv gob :left) (gv gob :width)))
          (kr::broken-link-throw nil :left)))

(defun gv-center-x (gob)
  (if gob (+ (gv gob :left) (truncate (gv gob :width) 2))
          (kr::broken-link-throw nil :left)))

(defun gv-center-y (gob)
  (if gob (+ (gv gob :top) (truncate (gv gob :height) 2))
          (kr::broken-link-throw nil :top)))

;;; For formulas that want to set an object's center, right or bottom.

; Gives the value for :left such that (gv-right :self) equals (gv gob :left)
(defun gv-right-is-left-of (gob)
  (if gob (- (gv gob :left) (gvl :width))
          (kr::broken-link-throw nil :left)))

; Gives the value for :top such that (gv-bottom :self) equals (gv gob :top)
(defun gv-bottom-is-top-of (gob)
  (if gob (- (gv gob :top) (gvl :height))
          (kr::broken-link-throw nil :top)))

; Gives the value for :left such that (gv-center-x :self) equals (gv-center-x 
; gob)
(defun gv-center-x-is-center-of (gob)
  (if gob (- (gv-center-x gob) (truncate (gvl :width) 2))
          (kr::broken-link-throw nil :left)))

; Gives the value for :top such that (gv-center-y :self) equals (gv-center-y
; gob)
(defun gv-center-y-is-center-of (gob)
  (if gob (- (gv-center-y gob) (truncate (gvl :height) 2))
          (kr::broken-link-throw nil :top)))

;;; bounding-box just returns the current cached value of the bounding box
;;; as four values (top left width height)
(defun bounding-box (gob)
  (values (g-value gob :left) (g-value gob :top)
	  (g-value gob :width) (g-value gob :height)))

;;; Unified setting methods
;;;
;;; These set more than one property of a gob, and may be much faster than
;;; calling numerous methods.

;;;
;;; Currently they aren't.

(defun set-center (gob x y)
  (setf (center-x gob) x)
  (setf (center-y gob) y))


(defun set-position (gob left top)
  (setf (g-value gob :left) left)
  (setf (g-value gob :top) top))

(defun set-size (gob width height)
  (setf (g-value gob :width) width)
  (setf (g-value gob :height) height))

(defun set-bounding-box (gob left top width height)
  (set-size gob width height)
  (set-position gob left top))


;;; Methods on view objects
;;; This sets up the update-info slot (allocates memory for it), and then
;;; copies down the :update-slots value to make it local.
;;; -- dzg,amickish -- removed copy-down of :update-slots and :fast-redraw-p
(define-method :initialize opal:view-object (gob)
  (let ((temp-info (make-update-info)))
    (setf (update-info-bits temp-info) 0)
    (setf (update-info-old-bbox temp-info) (make-bbox))
    (s-value gob :update-info temp-info)))


;;; Methods on graphical objects

;;; Initialize sets up the default values of objects
(define-method :initialize opal:graphical-object (gob)
  (call-prototype-method gob)
  ;; This is not an aggregate!  Used by update algorithm for efficiency
  (setf (update-info-aggregate-p (g-local-value gob :update-info)) NIL))

(define-method :point-in-gob opal:view-object (gob x y)
 (and (g-value gob :visible)
  (let ((top (g-value gob :top))
	(left (g-value gob :left))
	(width (g-value gob :width))
	(height (g-value gob :height))
	(hit (g-value gob :hit-threshold)))
    (and (>= x (- left hit))
	 (< x (+ left width hit))
	 (>= y (- top hit))
	 (< y (+ top height hit))))))

(defun assign-draw-function (f n)
  (let ((pair (assoc f *function-alist*)))
    (when pair
	(setf (get f :x-draw-function) n)
	(rplacd pair n))))


;;; Halftone creation functions
(defun halftone (percent &key (foreground-color opal:black)
			      (background-color opal:white))
  (let* ((halftone (aref *halftone-table* (find-halftone percent)))
	 (fstyle (halftone-filling-style halftone)))
    (unless fstyle
      (setf (halftone-filling-style halftone)
        (setq fstyle
          (create-instance NIL opal:filling-style
            (:fill-style :opaque-stippled)
            (:stipple
	      (create-instance NIL opal:bitmap
	        (:percent (halftone-percent halftone))
	        (:image (halftone-x-image halftone))))))))
    (values
      ;; the filling-style
      (if (and (eq foreground-color opal:black)
	       (eq background-color opal:white))
	fstyle
        (create-instance NIL fstyle
	   (:foreground-color foreground-color)
	   (:background-color background-color)))
      ;; the real percentage
      (halftone-percent halftone))))



(defun halftone-darker (percent &key (foreground-color opal:black)
                                     (background-color opal:white))
  (halftone (halftone-percent
               (aref *halftone-table*
		     (min (1- *halftone-table-size*)
			  (1+ (find-halftone percent)))))
            :foreground-color foreground-color
            :background-color background-color))


(defun halftone-lighter (percent &key (foreground-color opal:black)
                                      (background-color opal:white))
  (halftone (halftone-percent
               (aref *halftone-table*
		     (max 0 (1- (find-halftone percent)))))
            :foreground-color foreground-color
            :background-color background-color))
