;;;-*- 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 '(
	  add-event delete-event 
	  )
	'pictures)
#-clx-mit-r4
(defmethod add-event ((graphic graphic) event-spec &rest actions)
  "Add EVENT-SPEC and ACTIONS to the plist for GRAPHIC."
  (let ((event-binding  (graphic-parse-event-spec (list* event-spec (copy-list actions))))
	)
    (with-slots ( plist) (the graphic graphic)
      (LET* ((event-translations (GETF plist :event-translations))
	    (previous (assoc (car event-binding) event-translations :test #'equal))
	    )
	(if previous
	    ;; Yes, modify it with the new actions.
	    (setf (rest previous) (rest event-translations))
	    
	    ;; No, add new translation.
	    (progn
	      (push event-binding event-translations)
	      (SETF (GETF plist :event-translations) event-translations))
	    )
	)
      (DOLIST (view (graphic-views graphic) )
	
	(when (realized-p view)
	  (LET* ((view-event-mask (slot-value view 'event-mask)) ;update the view mask
		 (view-new-mask (cluei::update-event-mask event-binding view-event-mask)))
	    (unless (= view-new-mask view-event-mask) ;; When modified
	      (setf (window-event-mask view) view-new-mask)
	      ))))))
  (values))

#+clx-mit-r4
(defmethod add-event ((graphic graphic) event-spec &rest actions)
  "Add EVENT-SPEC and ACTIONS to the plist for GRAPHIC."
  (let ((event-binding  (graphic-parse-event-spec (list* event-spec (copy-list actions))))
	)
    (with-slots ( plist) (the graphic graphic)
      (LET* ((event-translations (GETF plist :event-translations))
	    (previous (assoc (car event-binding) event-translations :test #'equal))
	    )
	(if previous
	    ;; Yes, modify it with the new actions.
	    (setf (rest previous) (rest event-translations))
	    
	    ;; No, add new translation.
	    (progn
	      (push event-binding event-translations)
	      (SETF (GETF plist :event-translations) event-translations))
	    )
	
      (DOLIST (view (graphic-views graphic) )
	
	(when (realized-p view)
	  (when (realized-p view)
	    (LET* ((view-event-mask (slot-value view 'event-mask))
		  (view-new-mask (cluei::event-translation-mask view-event-mask event-translations) ))
	      (unless (= view-new-mask view-event-mask) 
		(setf (window-event-mask view) view-new-mask))))
	  
	  )))))
  (values))

(defmethod delete-event ((graphic graphic) event-spec)
  "Remove EVENT-SPEC from the event-translations for GRAPHIC."
  (let ((event-binding (graphic-parse-event-spec (list event-spec))))
    (with-slots (plist) (the graphic graphic) 
      ;; Compute event mask without current event translations	
      (LET* ((event-translations (GETF plist :event-translations)))	
	(SETF (GETF plist :event-translations) (delete (car event-binding) event-translations 
		      :key #'car :count 1
		      :test #'equal)))
	;; Update the graphic event mask
	))
  (values))


(defun class-name-of (instance)
  (class-name (class-of instance)))

(defun translate-graphic-event (graphic event)
  "Returns the actions for the first event-translation matching EVENT"
  (declare (type graphic graphic)
	   (type event         event))
  (labels ((find-translation (event event-key translations)
	     (dolist (event-binding translations)
	       (let ((event-spec (car event-binding)))
		 (when (if (atom event-spec)
			   ;; Simple EQ test when event spec is an atom
			   (eq event-key event-spec)
			 ;; When event spec is a list, and
			 ;; the car of the list is EQ to the event, and
			 ;; the matcher function returns T
			 (and (eq event-key (car event-spec))
			      (apply (cadr event-spec) event (cddr event-spec))))
		   (return event-binding))))))

    (let ((key (slot-value (the event event) 'key)))
      (cdr
	(or
	  ;; Instance translations
	  (find-translation event key (GETF (slot-value (the graphic graphic) 'plist) :event-translations))

	  ;; Class translations 
	    (find-translation event key (GET (class-name-of graphic) 'event-translations))))
	      )))


(defun graphic-parse-event-spec (event-translation)
  "Return a canonical form of the EVENT-TRANSLATION."
  (declare (values canonical-event-translation))
  
  (cons
    (let ((event-spec (first event-translation)))
      (typecase event-spec
	(list
	 (let* ((key     (first event-spec))
		(checker (check-function key)))
	   (assert checker nil "No check function defined for ~s." key)
	   (multiple-value-bind (args real-key) (apply checker event-spec)
	     (cons (or real-key key) args))))
	
	(character
	 (cons :key-press (key-check :key-press event-spec)))
	
	(otherwise
	 (unless (assoc event-spec cluei::*event-mask-alist* :test #'eq)
	   (error "~s is not a known event keyword." event-spec))
	 event-spec)))
    
    (cdr event-translation)))


(defun key-check (event-key &optional char state select)
  ;; Returns the canonical form of the key (i.e. one that may speed up
  ;; the matching operation)
  (declare (ignore event-key))
  (unless (typep char '(or card16 character (member :any)))
    (error "~a is not a CHARACTER, CARD16 or :ANY." char))
  
  (let*
    ((modifiers
       (cond ((or (null state) (eq state :none))   0)
	     ((numberp state)                      state)
	     ((eq state :any)                      (setf select 0))		 		 
	     (t                                    (encode-clue-modifier-mask state))))
     (mask 
       (cond ((null select)                        (if (characterp char) 0 modifiers))
	     ((numberp select)                     select)
	     ((eq select :same)                    modifiers)
	     ((eq select :all)                     #xffff)	     	     
	     (t                                    (encode-clue-modifier-mask select)))))
    
    (list 'key-match char modifiers mask)))



(defun encode-clue-modifier-mask (modifiers)
  ;; Make a state-mask from modifiers
  (declare (type (or mask16 state-mask-key (member :meta :super :hyper) list) modifiers)
	   (values mask16))
  (typecase modifiers
    (fixnum (ldb (byte cluei::meta-shift 0) modifiers))
    (cons (let ((mask 0))
	    (dolist (modifier modifiers)
	      (setf mask (logior mask (encode-clue-modifier-mask modifier))))
	    mask))
    (otherwise
     (let ((temp (position modifiers (the list cluei::*meta-modifier-alist*) :key #'car :test #'eq)))
       (if temp
	   (ash 1 (+ temp cluei::meta-shift))
	 (make-state-mask modifiers))))))

;;;------------------------------  added for Lispworks and any derivites there of ---------------------------

(DEFMETHOD clue::class-event-translations  ((class t))
  (get (class-name  class) 'event-translations))

(DEFMETHOD (SETF clue::class-event-translations) (translations (class t))
  (setf (GET (class-name class)  'event-translations) translations))





