;;;-*- Mode:Common-Lisp; Package:PICTURES; Base:10 -*- ;;; ;;; ;;; ;;; TEXAS INSTRUMENTS INCORPORATED ;;; P.O. BOX 149149 ;;; AUSTIN, TEXAS 78714-9149 ;;; ;;; Copyright (C)1987,1988,1989,1990 Texas Instruments Incorporated. ;;; ;;; Permission is granted to any individual or institution to use, copy, modify, ;;; and distribute this software, provided that this complete copyright and ;;; permission notice is maintained, intact, in all copies and supporting ;;; documentation. ;;; ;;; Texas Instruments Incorporated provides this software "as is" without ;;; express or implied warranty. ;;; ;;; Authors: Delmar Hager, James Dutton, Teri Crowe ;;; Contributors: Kerry Kimbrough, Patrick Hogan, Eric Mielke (in-package "PICTURES") (export '( make-label label-base-x label-base-y label-extent-x label-extent-y label-extent-height label-extent-width label-gravity label-font-size label-font-family label-extent-clip-p label-angle label-string label-reverse-p label-filled-background-p label-font label ) 'pictures) (DEFCONSTANT minimum-pixel-size-to-display 4.0) (DEFMACRO change-font-if-scale-values-not-equal ( label label-view-scale view) `(UNLESS (= ,label-view-scale (view-scale ,view)) (SETF (label-font ,label) nil) (extent-changed ,label) (graphic-extent ,label) (SETF ,label-view-scale (view-scale ,view)))) (DEFMACRO compute-base-line-origin-if-not-set (base-x base-y scale-x scale-y) `(UNLESS (AND ,base-x ,base-y) (MULTIPLE-VALUE-BIND (x y) (compute-baseline-origin label ,scale-x ,scale-y) (SETF ,base-x x) (SETF ,base-y y)))) ;Label Class Functional Definition: ;Function: make-label (defclass label (extent-cache graphic) ( (label-string :type string :initarg :label-string :initform (MAKE-STRING 10) :documentation "the string to be displayed ") (label-base-x :type (OR null ocoord) :accessor label-base-x :initarg :base-x :initform nil :documentation "object x-coordinate of lower left corner of the base-line of the label string") (label-base-y :type (OR null ocoord) :accessor label-base-y :initarg :base-y :initform nil :documentation "object y-coordinate of lower left corner of the base-line of the label string") (label-extent-x :type (OR null ocoord) :accessor label-extent-x :initarg :extent-x :initform nil :documentation "object x-coordinate of the lower left corner of the extent of the label") (label-extent-y :type (OR null ocoord) :accessor label-extent-y :initarg :extent-y :initform nil :documentation "object y-coordinate of the lower left corner of the extent of the label") (extent-height :type (or null ocoord) :accessor label-extent-height :initarg :extent-height :initform nil :documentation "the of the height of the extent of the label") (extent-width :type (or null ocoord) :accessor label-extent-width :initarg :extent-width :initform nil :documentation "width of the width of the extent fo the label") (label-gravity :type symbol :accessor label-gravity :initarg :gravity :initform :southwest :documentation "the gravity of the label within a frame") (label-view-scale :type real :accessor label-view-scale :initform 1.0 :documentation "the view scale factor, used to check and see if the view scale has changed") (label-font-size :type (OR null real) :accessor label-font-size :initarg :font-size :initform 10 :documentation "the local coordinate size of a font, one point is on local coordinate unit") (label-font-family :type (OR null string font-family) :accessor label-font-family :initform nil :documentation "The font family to be displayed") (label-font :type (OR null font string) :initform nil :documentation "The font that is to be displayed") (label-extent-clip-p :type boolean :initarg :extent-clip-p :initform nil :accessor label-extent-clip-p :documentation "Set true if the label is not to be displayed outside of the extents") (label-angle :type number :accessor label-angle :initarg :angle :initform 0 :documentation "the angle of the label in radians") ) (:documentation "The graphic class for drawing points in object coordinates")) (defun make-label ( label-string &key base-x base-y extent-x extent-y extent-width extent-height font-family (font-size 10) extent-clip-p filled-background-p reverse-p (gravity :southwest) gstate plist (sensitivity :editable) (angle 0) view ) (FUNCALL #'make-instance 'label :allow-other-keys t :font-family font-family :font-size font-size :base-x base-x :base-y base-y :label-string label-string :extent-x extent-x :extent-y extent-y :extent-clip-p extent-clip-p :extent-width extent-width :extent-height extent-height :gravity gravity :gstate gstate :label-view view :sensitivity sensitivity :plist plist :angle angle :reverse-p reverse-p :filled-background-p filled-background-p )) (DEFMETHOD label-filled-background-p ((label label)) "set or get the amount to pan in along the x axis" (GETF (slot-value label 'plist) :filled-background-p)) (DEFMETHOD (SETF label-filled-background-p) ( filled-background-p (label label) ) "set the relative pan motion along the x axis" (SETF (GETF (slot-value label 'plist) :filled-background-p) filled-background-p)) (DEFMETHOD (SETF gstate-background) :after (background (graphic label)) (if background (SETF (label-filled-background-p graphic) t) (SETF (label-filled-background-p graphic) nil) )) (defmethod (setf gstate-value) :after (attribute (graphic label) keyword) (WHEN (EQL keyword :background) (IF attribute (SETF (label-filled-background-p graphic) t) (SETF (label-filled-background-p graphic) nil) ))) (DEFMETHOD label-reverse-p ((label label)) "set or get the amount to pan in along the x axis" (GETF (slot-value label 'plist) :reverse-p)) (DEFMETHOD (SETF label-reverse-p) ( reverse-p (label label) ) "set the relative pan motion along the x axis" (SETF (GETF (slot-value label 'plist) :reverse-p) reverse-p)) (DEFMETHOD label-angle-extent ((label label)) "set or get the amount to pan in along the x axis" (GETF (slot-value label 'plist) :angle-extent)) (DEFMETHOD (SETF label-angle-extent) ( angle-extent (label label) ) "set the relative pan motion along the x axis" (SETF (GETF (slot-value label 'plist) :angle-extent) angle-extent)) (DEFMETHOD initialize-instance :after ((label label) &key label-view font-family filled-background-p reverse-p) (with-slots (gstate label-base-x label-base-y label-extent-x label-extent-y label-font-family extent-width extent-height views extent extent-valid-p) label (UNLESS gstate (SETF gstate (make-gstate))) ;create an empty gstate (IF (AND label-extent-x label-extent-y) nil (UNLESS (AND label-base-x label-base-y) (SETF label-base-x 0 label-base-y 0))) (WHEN (OR (gstate-background gstate) filled-background-p) (SETF (label-filled-background-p label) t)) (WHEN reverse-p (SETF (label-reverse-p label) t)) (WHEN label-view (SETF views (LIST label-view))) (SETF label-font-family font-family) (COND ((NOT font-family) (SETF label-font-family default-family-name)) ((font-p font-family) (SETF label-font-family font-family))) )) (DEFMETHOD label-font ((label label) &optional change-extent-p) (DECLARE (IGNORE change-extent-p)) (slot-value label 'label-font)) (DEFMETHOD (SETF label-font) (font (label label) &optional change-extent-p) (with-slots (label-font label-extent-x label-extent-y extent-width extent-height) label (SETF label-font font) (WHEN change-extent-p (extent-changed label) (SETF label-extent-x nil label-extent-y nil extent-width nil extent-height nil)))) (DEFMETHOD label-string ((label label) &optional change-extent-p) (DECLARE (IGNORE change-extent-p)) (slot-value label 'label-string)) (DEFMETHOD (SETF label-string) (string (label label) &optional change-extent-p) (with-slots (label-string label-extent-x label-extent-y extent-width extent-height) label (SETF label-string string) (WHEN change-extent-p (extent-changed label) (SETF label-extent-x nil label-extent-y nil extent-width nil extent-height nil))) ) (DEFMETHOD (SETF label-angle) :after (x (label label)) (extent-changed label) (WHEN (EQUAL x 0) (SETF (label-angle-extent label) nil))) (DEFMETHOD (SETF label-base-x) :before (x (label label) ) (with-slots (extent label-extent-x label-base-x) label (WHEN label-extent-x (SETF label-extent-x (+ label-extent-x (- x label-base-x)))) ) (extent-changed label)) (DEFMETHOD (SETF label-base-y) :before ( y (label label)) (with-slots (extent label-extent-y label-base-y) label (WHEN label-extent-y (SETF label-extent-y (+ label-extent-y (- y label-base-y)))) ) (extent-changed label)) (DEFMETHOD (SETF label-extent-x) :before (x (label label)) (DECLARE (IGNORE x)) (extent-changed label) (with-slots (transform label-base-x) label (SETF transform nil) (SETF label-base-x nil))) (DEFMETHOD (SETF label-extent-y) :before (y (label label)) (DECLARE (IGNORE y)) (extent-changed label) (with-slots (transform label-base-y) label (SETF transform nil) (SETF label-base-y nil))) (DEFMETHOD (SETF label-extent-width) :before (width (label label)) (DECLARE (IGNORE width)) (with-slots (extent label-base-x label-gravity) label (WHEN (valid-extent-p extent) (SETF label-base-x nil) ) )) (DEFMETHOD (SETF label-extent-height) :before (height (label label)) (DECLARE (IGNORE height)) (with-slots (extent label-base-y label-gravity) label (WHEN (valid-extent-p extent) (SETF label-base-y nil)) )) (DEFMETHOD (SETF label-gravity) :after (gravity (label label)) (DECLARE (IGNORE gravity)) (extent-changed label) (with-slots (label-base-x label-base-y ) label (SETF label-base-x nil) (SETF label-base-y nil))) (defmethod graphic-contains-p ((label label) x y &optional pixel-size) (declare (type wcoord x y)) (DECLARE (IGNORE pixel-size)) (declare (values boolean)) (IF (label-angle-extent label) (inside-p (label-angle-extent label) (make-point :x x :y y)) (let* ((extent (world-extent label))) (and (>= x (extent-rect-xmin extent)) (>= y (extent-rect-ymin extent)) (<= x (extent-rect-xmax extent)) (<= y (extent-rect-ymax extent))))) ) (DEFMACRO assure-or-make-valid-label-font (font size view) `(PROGN (WHEN (STRINGP label-font-family) ;does not work on the Explorer (SETF label-font-family (OR (find-font-family label-font-family (contact-display ,view)) (make-font-family label-font-family (contact-display ,view))))) (SETF ,font (find-font label-font-family ,size)))) (DEFMETHOD extent-compute ((label label)) (LET* ((view (graphic-view label)) (scale (view-scale view))) (with-slots (extent label-font-size label-view-scale label-font-size label-font label-font-family label-extent-x label-extent-y extent-width extent-height transform label-extent-clip-p transform) label (PROG1 (COND ((label-angle-extent label) (LET ((point-seq (label-angle-extent label))) (make-extent-rect :xmin (point-seq-x-min point-seq) :ymin (point-seq-y-min point-seq) :xmax (point-seq-x-max point-seq) :ymax (point-seq-y-max point-seq)))) ((AND label-extent-clip-p extent-width extent-height label-extent-x label-extent-y) (MULTIPLE-VALUE-BIND (x y) (transform-point transform label-extent-x label-extent-y) (MULTIPLE-VALUE-BIND (width height) (scale-point transform extent-width extent-height ) (extent-transform transform (make-extent-rect :xmin x :ymin y :xmax (+ x width -1) :ymax (+ y height -1)))))) (t (view-label-extents label scale view ))) (UNLESS (= label-view-scale scale) (assure-or-make-valid-label-font label-font (* scale label-font-size) view)) )))) (DEFMETHOD view-label-extents ((label label) scale (view view) ) "changes the extents of the label in a view to match the current size of the label" (with-slots ( label-font-family label-font-size label-base-x label-base-y label-extent-x label-extent-y extent-width extent-height label-font-family-name label-font transform) label (LET* ((font (assure-or-make-valid-label-font label-font(* (scale-point (graphic-world-transform label) 1 1) label-font-size scale) view))) (MULTIPLE-VALUE-BIND (width ascent descent) (text-extents font (label-string label)) (UNLESS (AND label-base-x label-base-y) (MULTIPLE-VALUE-BIND (x y) (compute-baseline-origin label (view-scale-x view) (view-scale-y view)) (SETF label-base-x x label-base-y y))) (MULTIPLE-VALUE-BIND (xmin ymin) (transform-point transform label-base-x label-base-y ) (LET* ( (scale-x (view-scale-x view)) (scale-y (view-scale-y view)) (extent (make-extent-rect :xmin xmin :xmax (+ xmin (/ width scale-x) 1) :ymin (- ymin (/ (+ descent 2) scale-y) ) :ymax (+ ymin (/ (+ ascent 2) scale-y))))) extent)))))) (DEFMACRO set-rotated-extent () `(LET* ((vertices (label-angle-extent label)) (letter (ELT label-string (+ pos (- increment)))) (width (* (max-char-width label-font) scale)) (ascent (* (max-char-ascent label-font) scale)) (descent (* (max-char-descent label-font ) scale)) (height (IF (= 1 (+ (char-width label-font letter)(char-descent label-font letter) )) (* (max-char-ascent label-font) scale) (+ ascent descent ))) (s1 (+ (ABS (* width dy))(ABS (* height dx))))) (SETF s2 (/ (* s1 (1+ dx2)) s) x (+ x (* dy s2)) y (+ y (* (- dx) s2))) (COND ((OR (= quad 0) (= quad 3)) (IF (label-angle-extent label) (SETF (ELT vertices 0) xstart (ELT vertices 1) ystart (ELT vertices 2) x (ELT vertices 3) y (ELT vertices 4) (+ x (* dy s2)) (ELT vertices 5) (- y (* (- dx) s2)) (ELT vertices 6) (+ xstart (* dy s2)) (ELT vertices 7) (- ystart (* (- dx) s2))) (SETF (label-angle-extent label) (MAKE-ARRAY 8 :initial-contents (LIST xstart ystart x y (+ x (* dy s2)) (- y (* (- dx) s2)) (+ xstart (* dy s2)) (- ystart (* (- dx) s2))))))) (t (IF (label-angle-extent label) (SETF (ELT vertices 0) xstart (ELT vertices 1) ystart (ELT vertices 2) x (ELT vertices 3) y (ELT vertices 4) (- x (* dy s2)) (ELT vertices 5) (+ y (* (- dx) s2)) (ELT vertices 6) (- xstart (* dy s2)) (ELT vertices 7) (+ ystart (* (- dx) s2))) (SETF (label-angle-extent label) (MAKE-ARRAY 8 :initial-contents (LIST xstart ystart x y (- x (* dy s2)) (+ y (* (- dx) s2)) (- xstart (* dy s2)) (+ ystart (* (- dx) s2)))))))))) (DEFMACRO draw-rotated-text () `(LET* ((xstart x) (ystart y) (dy (COS label-angle)) (dx (SIN label-angle)) (scale (* (scale-point world-transform 1 1) label-view-scale )) (dx2 (* dx dx) ) (s (* (+ dx2 (* dy dy)) scale)) (quad (mod (floor (/ label-angle pi .5)) 4)) (start (IF (AND (label-reverse-p label) (OR (= quad 1)(= quad 2))) (1- (LENGTH label-string)) 0)) (stop (IF (= start 0) (LENGTH label-string) -1)) (increment (IF (= start 0) 1 -1)) s2) (DO ((pos start (+ increment pos))) ((= pos stop) (set-rotated-extent)) (LET* ((letter (ELT label-string pos)) (width (* (- (char-width label-font letter) 0) scale)) (ascent (* (char-ascent label-font letter) scale)) (descent (* (char-descent label-font letter) scale)) (height (IF (= 1 (+ (char-width label-font letter)(char-descent label-font letter) )) (* (max-char-ascent label-font) scale) (+ ascent descent ))) (s1 (+ (ABS (* width dy))(ABS (* height dx))))) (WHEN (OR (= quad 2) (= quad 1)) (SETF s2 (/ (* s1 (1+ dx2)) s) x (+ x (* dy s2)) y (+ y (* (- dx) s2)))) (IF background (view-draw-image-char view x y (ELT label-string pos) (graphic-gstate label)) (view-draw-char view x y (ELT label-string pos) (graphic-gstate label))) (WHEN (OR (= quad 0) (= quad 3)) (SETF s2 (/ (* s1 (1+ dx2)) s) x (+ x (* dy s2)) y (+ y (* (- dx) s2)))) )) (extent-changed label) (graphic-extent label) )) (DEFMACRO label-visible-p (graphic) `(AND (NOT (AND (and min-x min-y width height) ; Was optional rect given (not (graphic-within-p ,graphic min-x min-y width height)) (not (graphic-intersects-p ,graphic min-x min-y width height)))) (viewable-p ,graphic))) (defmethod draw-graphic ((label label) (view view) &optional min-x min-y width height) (declare (type (or null wcoord) min-x min-y width height)) (WHEN (label-visible-p label) (with-slots (gstate label-extent-clip-p label-base-x label-base-y label-view-scale label-font-family label-angle label-extent-x label-extent-y extent-width extent-height label-font-family-name label-string label-font transform label-font-size extent) label (LET ((world-transform (graphic-world-transform label)) (background (label-filled-background-p label)) (font-family (label-font-family label))) (change-font-if-scale-values-not-equal label label-view-scale view) (WHEN (STRINGP font-family) (SETF (slot-value label 'label-font-family) (OR (find-font-family label-font-family (contact-display view)) (make-font-family label-font-family (contact-display view))))) (SETF label-font (find-font label-font-family (* (scale-point world-transform 1 1) label-font-size label-view-scale ))) (MULTIPLE-VALUE-BIND (x y) (compute-baseline-origin label (view-scale-x view) ( view-scale-y view)) (UNLESS (AND label-base-x label-base-y) (SETF label-base-x x) (SETF label-base-y y))) (UNLESS (extent-valid-p label) (graphic-extent label)) (WHEN ( >= (* label-font-size (* (scale-point world-transform 1 1) label-view-scale )) (* 0.5 (font-size (find-font label-font-family 1)))) (IF label-extent-clip-p (SETF (gstate-value gstate :clip-mask) (label-rectangle-mask label view )) (SETF (gstate-value gstate :clip-mask) :none) ) (SETF (gstate-value gstate :font) label-font) (MULTIPLE-VALUE-BIND (x y) (transform-point world-transform label-base-x label-base-y) (IF (= label-angle 0) (IF background (view-draw-image-text view x y label-string (graphic-gstate label)) (view-draw-text view x y label-string (graphic-gstate label))) (draw-rotated-text)))))))) (DEFUN compute-baseline-origin (label scale-x scale-y) "Return the baseline coordinate of the label" (DECLARE (VALUES (type ocoord x y))) (with-slots (extent label-gravity label-extent-x label-extent-y (label-extent-height extent-height) (label-extent-width extent-width) label-font label-string) label (MULTIPLE-VALUE-BIND (width ascent descent) (text-extents label-font label-string) (LET* ((extent-width (OR label-extent-width (- (extent-rect-xmax extent) (extent-rect-xmin extent)))) (extent-height (OR label-extent-height (- (extent-rect-ymax extent) (extent-rect-ymin extent)))) (extent-x (OR label-extent-x (extent-rect-xmin extent))) (extent-y (OR label-extent-y (extent-rect-ymin extent))) (width (/ width scale-x)) (ascent (/ ascent scale-y)) (descent (/ (1- descent) scale-y)) (height (+ ascent descent ) )) (CASE label-gravity (:southwest (VALUES extent-x (+ extent-y descent) )) (:northwest (VALUES extent-x (+ extent-y (- extent-height height )))) (:south (VALUES (+ (- extent-x (/ width 2.0)) (/ extent-width 2.0) ) (+ extent-y descent))) (:north (VALUES (+ (- extent-x (/ width 2.0)) (/ extent-width 2.0) ) (+ extent-y (- extent-height height )))) (:west (VALUES extent-x (+ extent-y (- (/ extent-height 2.0) (/ height 2.0))))) (:center (VALUES (+ (- extent-x (/ width 2.0)) (/ extent-width 2.0) ) (+ extent-y (- (/ extent-height 2.0) (/ height 2.0))))) (:southeast (VALUES (+ extent-x (- extent-width width)) (+ extent-y descent))) (:northeast (VALUES (+ extent-x (- extent-width width)) (+ extent-y (- extent-height height 1)))) (:east (VALUES (+ extent-x (- extent-width width)) (+ extent-y (- (/ extent-height 2.0) (/ height 2.0))))) (t (VALUES extent-x extent-y)) ) )))) (DEFUN label-rectangle-mask (label view ) (LET ((local-vector (make-array '(4) :adjustable t :fill-pointer 0)) (x 0) (y 1)) (with-slots (transform extent) label (with-vector clip-vector (VECTOR-PUSH-EXTEND (extent-rect-xmin extent) clip-vector) (VECTOR-PUSH-EXTEND (extent-rect-ymin extent) clip-vector) (VECTOR-PUSH-EXTEND (extent-rect-xmax extent) clip-vector) (VECTOR-PUSH-EXTEND (extent-rect-ymax extent) clip-vector) (transform-point-seq (graphic-world-transform label) clip-vector ) (view-transform-vector view clip-vector ) (VECTOR-PUSH-EXTEND (min-value-vector clip-vector x) local-vector) ;get min x value (VECTOR-PUSH-EXTEND (min-value-vector clip-vector y) local-vector) ;get min y value (VECTOR-PUSH-EXTEND (- (max-value-vector clip-vector x)(min-value-vector clip-vector x)) local-vector) ;width (VECTOR-PUSH-EXTEND (- (max-value-vector clip-vector y)(min-value-vector clip-vector y)) local-vector) ;height ) local-vector))) (DEFMETHOD normalize-graphic :before ((label label)) (with-slots (label-base-x label-base-y label-extent-x label-extent-y extent-width extent-height transform) label (MULTIPLE-VALUE-BIND (x y) (transform-point transform label-base-x label-base-y) (SETF (label-base-x label) x (label-base-y label) y)) (WHEN (AND label-extent-x label-extent-y extent-width extent-height) (MULTIPLE-VALUE-BIND (x y) (transform-point transform label-extent-x label-extent-y) (MULTIPLE-VALUE-BIND (x1 y1) (transform-point transform (+ label-extent-x extent-width) (+ label-extent-y extent-height)) (SETF label-extent-x x label-extent-y y extent-width (- x1 x) extent-height (- y1 y)))))))