;;;-*- 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 '( family-name make-font-family find-font-family find-font find-family-members default-family-name ) 'pictures) ;font families utilites (DEFPARAMETER default-family-name "-adobe-helvetica-medium-r-normal-*") (DEFCONSTANT minimum-font-attributes-in-a-name 1) (DEFMACRO font-size (font) `(+ (font-ascent ,font)(font-descent ,font))) (DEFMACRO x11-font-string-p (font-name) `(AND (STRINGP ,font-name) (> (COUNT #\- ,font-name) minimum-font-attributes-in-a-name)) ) (defclass font-family () ( (family-name :type string :accessor family-name :initarg :family-name :documentation "The name for a family of fonts ") (family-members :type list :initarg :family-members :documentation "An assoc list of the member fonts and their sizes for a font-family") ) ) (DEFMETHOD print-object ((font font) stream ) (FORMAT stream "~a" (font-name font))) (DEFMACRO x11-font-sizes (font-string display) `(MAPCAR #'(lambda (font-name) (READ-FROM-STRING (font-name-attribute font-name :size :size))) (list-font-names ,display (CONCATENATE 'string ,font-string "*" ))) ) (DEFUN add-size (name size) (IF (x11-font-string-p name) (CONCATENATE 'string "-" (font-name-attribute name :company :blank) (FORMAT nil "-~A" size) "-" (OR (font-name-attribute :resolution :rest) "*")) (CONCATENATE 'string name size))) (defmacro font-objects (members display) "determine if members is nil, a string or a list of (font-name size) and return nil or a list of (font-name size)" `(COND ((AND ,members (LISTP (FIRST ,members))) (MAPCAR #'(lambda (font-list) (LIST (open-font ,display (CONCATENATE 'string (FIRST font-list) "*")) (SECOND font-list))) ,members)) ((AND (STRINGP (FIRST ,members)) (x11-font-string-p (FIRST ,members))(EQL (LENGTH ,members) 1)) (mapcar #'(lambda (size) (LIST (open-font display (add-size (FIRST ,members) size)) size)) (SORT (x11-font-sizes (first ,members) ,display) '<))) ((STRINGP (FIRST ,members)) (get-size-font-pairs (mapcar #'(lambda (string) (open-font display string)) (list-ft-names ,members ,display))))) ) (DEFUN list-ft-names (names display &optional font-names) (DOLIST (name names) (IF (x11-font-string-p name) (SETF font-names (APPEND font-names (list-font-names display (CONCATENATE 'string name "*")))) (SETF font-names (APPEND font-names (LIST name))))) font-names) (DEFUN get-size-font-pairs (font-list) "given a font-list sort it according to font size and return a list of '(fonts size)" (LET* ((font-size-pairs (MAPCAR #'(lambda (font) (LIST (IF (x11-font-string-p (font-name font)) (READ-FROM-STRING (font-name-attribute (font-name font) :size :size)) (font-size font)) font)) font-list)) (sorted-sizes (REMOVE-DUPLICATES (SORT (MAPCAR #'(lambda (pairs) (FIRST pairs)) font-size-pairs) #'<)))) (MAPCAR #'(lambda (size) (NREVERSE (ASSOC size font-size-pairs))) sorted-sizes))) (DEFUN make-font-family (family-name display &rest members) (DECLARE (VALUES (type font-family))) (DECLARE (LIST members)) (funcall #'make-instance 'font-family :display display :family-name family-name :family-members (OR (font-objects members display) (IF (x11-font-string-p family-name) (mapcar #'(lambda (x) (LIST (open-font display (add-size family-name x)) x)) (SORT (x11-font-sizes family-name display) '<)) (mapcar #'(lambda (x) (LIST (open-font display (add-size default-family-name x)) x)) (SORT (x11-font-sizes default-family-name display) '<)))))) (DEFMETHOD initialize-instance :around ((font-family font-family) &key family-name display) (DECLARE (IGNORE members)) (LET ((font-families (GETF (display-plist display) 'font-families))) (SETF font-families (REMOVE (ASSOC family-name font-families :test #'STRING-EQUAL) font-families :test #'EQUAL)) (SETF (GETF (display-plist display) 'font-families) (APPEND font-families (LIST (LIST family-name (call-next-method))))))) (DEFUN find-font-family (family-name display) "Returns the font-family of the FAMILY-NAME for the DISPLAY" (DECLARE (VALUES (type font-family or nil))) (SECOND (ASSOC family-name (GETF (display-plist display) 'font-families) :test #'STRING-EQUAL )) ) (DEFSETF find-font-family (family-name display) (font-family) `(LET ((font-families (GETF (display-plist ,display) 'font-families))) (SETF font-families (REMOVE (ASSOC ,family-name font-families :test #'STRING-EQUAL) font-families :test #'EQUAL)) (SETF (GETF (display-plist ,display) 'font-families) (APPEND font-families (LIST (LIST ,family-name ,font-family)))) ,font-family)) (DEFMACRO the-font-size (MEMBER) `(SECOND ,member)) (DEFMACRO the-font (MEMBER) `(FIRST ,member)) (DEFMETHOD find-font ((family font-family) size) (with-slots (family-members) family (WHEN family-members (IF (< size (the-font-size (FIRST family-members))) (the-font (FIRST family-members)) (DO* ((font-pair (FIRST family-members) next-pair) (font-size (the-font-size font-pair) next-font-size) (next-font-pairs (REST family-members) (REST next-font-pairs)) (next-pair (FIRST next-font-pairs) (FIRST next-font-pairs)) (next-font-size (the-font-size next-pair) (the-font-size next-pair)) ) ((not next-pair ) (the-font font-pair)) (WHEN (= font-size size) (RETURN (the-font font-pair))) (WHEN (< font-size size next-font-size) (RETURN (the-font font-pair) ))))))) (DEFMETHOD (SETF find-font ) ( font (family font-family) size ) (with-slots (family-members) family (WHEN (< size (SECOND (FIRST family-members))) (FIRST (FIRST family-members))) (DO* ((pairs 1 (1+ pairs)) (font-pair (FIRST family-members) next-pair) (font-size (SECOND font-pair) next-font-size) (next-font-pairs (CDR family-members) (CDR next-font-pairs)) (next-pair (FIRST next-font-pairs) (FIRST next-font-pairs)) (next-font-size (SECOND next-pair) (SECOND next-pair)) ) ((NOT next-pair ) (IF (= font-size size) (SETF (FIRST font-pair) font) (SETF family-members (APPEND family-members (LIST (LIST font size))))) (RETURN font)) (WHEN (= font-size size) (SETF (FIRST font-pair) font) (RETURN font)) (WHEN (< font-size size next-font-size) (SETF family-members (APPEND (BUTLAST family-members (- (LENGTH family-members) pairs)) (LIST (LIST font size)) (NTHCDR pairs family-members))) (RETURN font))))) (DEFMETHOD font-family-members ((family font-family) display) (DECLARE (IGNORE display)) (slot-value family 'family-members) ) (DEFMETHOD (SETF font-family-members) ( members (family font-family) display) (IF members (SETF (slot-value family 'family-members) (font-objects members display)) (ERROR "~%the value for members is ~a ~%" members))) ;get the attributes from the X11 font name (DEFCONSTANT large-number 1000) (DEFUN dash-positions (STRING &optional position-list) (IF (> (OR (FIRST (LAST position-list)) 0) (LENGTH string)) (BUTLAST position-list) (dash-positions string (APPEND position-list (LIST (OR (POSITION #\- string :start (1+ (OR (FIRST (LAST position-list)) -1))) large-number)))))) (DEFUN font-name-attribute (name attribute &optional (name-range nil)) "Parse the X11 font NAME string and for a ATTRIBUTE and return the string representing the ATTRIBUTE. ATTRIBUTE is (member :size :company :weight :blank :name :resolution :end)" (WHEN (x11-font-string-p name) (flet ((elt-safe (sequence index) (when (< index (length sequence)) (elt sequence index)))) (LET* ((dash-positions (dash-positions name)) (attribute-position (CASE attribute (:size (ELT-SAFE dash-positions 6)) (:company (ELT-SAFE dash-positions 0)) (:weight (ELT-SAFE dash-positions 2)) (:blank (ELT-SAFE dash-positions 5)) (:name (ELT-SAFE dash-positions 1)) (:resolution (ELT-SAFE dash-positions 7)) )) (name-range-position (CASE name-range (:size (ELT-SAFE dash-positions 7)) (:company (ELT-SAFE dash-positions 1)) (:weight (ELT-SAFE dash-positions 3)) (:blank (ELT-SAFE dash-positions 6)) (:name (ELT-SAFE dash-positions 2)) (:resolution (ELT-SAFE dash-positions 8)) (:end (ELT-SAFE dash-positions 14)) (:rest (LENGTH name)) ))) (SUBSEQ name (1+ (OR attribute-position 0)) name-range-position ) ))))