;;; -*- Mode:LISP; Package:OBIE; Base:10 -*-

(defobclass mouseable-rect (window-rect))

(defobclass inverting-rect (window-rect)
  inverted-p)

(defobfun (invert inverting-rect) ()
  (send window :draw-rectangle width height x y tv:alu-xor)
  (setq inverted-p (not inverted-p)))

(defobfun (erase inverting-rect) ()
  (if inverted-p (invert))
  (shadowed-erase))

(defobfun (remove-frippery inverting-rect) ()
  (if inverted-p (invert))
  (shadowed-remove-frippery))

; Special hack for images
(defobfun (invert image-icon) ()
  (send window :bitblt tv:alu-xor width height mask 0 0 x y)
  (setq inverted-p (not inverted-p)))

(defobfun (invert char-icon) ()
  (send window :draw-char font shape-char x y tv:alu-xor))

(defobfun (draw inverting-rect) ()
  (shadowed-draw)
  (setq inverted-p (not inverted-p))		       ;sort of a hack
  (invert)) 

(defobclass mouse-highlighting-rect (inverting-rect mouseable-rect))

(defobfun (mouse-in mouse-highlighting-rect) ()
  (unless inverted-p (invert)))

(defobfun (mouse-out mouse-highlighting-rect) ()
  (when inverted-p (invert)))

; Temp, for demo
(defobfun (mouse-click mouse-highlighting-rect) (char x y)
  char
  (and (point-in-region (- x (tv:sheet-left-margin-size window)) (- y (tv:sheet-top-margin-size window)))
       (progn
	 (drag))))


(defobclass dynamic-mouseable-text-icon (dynamic-text-icon mouse-highlighting-rect))
(defobclass dynamic-mouseable-image-icon (dynamic-image-icon mouse-highlighting-rect))
(defobclass dynamic-mouseable-char-icon (dynamic-char-icon mouse-highlighting-rect))

(defobfun test (&aux ike)
  (setq window (make-instance 'obie-window :edges-from :mouse :expose-p t :borders 10))
  (dolist (i '("foo" "bar" "blather" "ugh" "fnord"))
    (setq ike (oneof dynamic-mouseable-text-icon 'window window 'opaque-p t 'bordered-p nil 'x 0  'y 0 'font fonts:hl12b 'text i))
    (send window :add-object ike t)
;    (ask ike (draw))
    (ask ike (drag))))

(defobfun icon-madness (&aux ike window)
  (unless (boundp '*file-image*)
    (load "lad:efh;icons")
    (setq *file-image* (load-image "efh.icons;file")
	  *file-group-image* (load-image "efh.icons;double-file")
	  *dir-image* (load-image "efh.icons;file-folder")
	  *host-image* (load-image "efh.icons;lambda")))
  (setq window (make-instance 'obie-window :edges-from :mouse :expose-p t :borders 10))
  (dotimes (i 5)
    (setq ike
	  (caseq i
	    (0 (oneof dynamic-mouseable-text-icon 'window window 'opaque-p t 'bordered-p nil 'x 0  'y 0 'font fonts:hl12b 'text "frobozz"))
	    (1 (oneof dynamic-mouseable-image-icon 'window window 'x 0 'y 0 'image *host-image*))
	    (2 (oneof dynamic-mouseable-char-icon 'window window 'x 0 'y 0 'font fonts:mouse 'shape-char #\ 'image-char #\0))   
	    (3 (oneof dynamic-mouseable-image-icon 'window window 'x 0 'y 0 'image *file-group-image*))
	    (4 (oneof dynamic-mouseable-text-icon 'window window 'opaque-p t 'bordered-p nil 'x 0  'y 0 'font fonts:25fr3 'text "Icon Madness!"))	       ;
		    
))
    (send window :add-object ike t)
    (ask ike (drag))))

tv:
(defmacro obie:with-mouse-grabbed (&rest body)
  `(let ((.old.value. window-owning-mouse))
     (let-globally ((who-line-mouse-grabbed-documentation nil))
       (unwind-protect
	 (progn
	   (with-mouse-grabbed-internal t)
	   . ,body)
	 (setq window-owning-mouse .old.value.)
	 (setq mouse-reconsider t)))))


;;; Tell the mouse process to switch "modes" and wait for it to do so
; this version can be called from mouse process (no-op)
tv:
(DEFUN WITH-MOUSE-GRABBED-INTERNAL (WOM &AUX (INHIBIT-SCHEDULING-FLAG T))
  (unless (eq si:current-process mouse-process)
    (SETQ WINDOW-OWNING-MOUSE WOM)
    (WHEN (NEQ WOM MOUSE-WINDOW)
      (SETQ MOUSE-RECONSIDER T
	    INHIBIT-SCHEDULING-FLAG NIL )
      (PROCESS-WAIT "Grab Mouse" #'(LAMBDA (WOM) (AND (NULL MOUSE-RECONSIDER)
						      (EQ MOUSE-WINDOW WOM)))
		    WOM))))
  

(defobfun (drag window-point) (&aux starting-mouse-buttons)
  (setq starting-mouse-buttons (tv:mouse-buttons))
  (tv:with-mouse-grabbed
    (do-forever
      (tv:mouse-wait)
      (if (eql (tv:mouse-buttons) starting-mouse-buttons)
	  (move (- tv:mouse-x (send window :x-offset) (tv:sheet-left-margin-size window))
		(- tv:mouse-y (send window :y-offset) (tv:sheet-top-margin-size window)))
	(return)))))


; system version is broken
tv:
(DEFUN MOUSE-WAIT (&OPTIONAL (OLD-X MOUSE-X) (OLD-Y MOUSE-Y) (OLD-BUTTONS MOUSE-LAST-BUTTONS)
		   (WHOSTATE "MOUSE"))
  "Wait for the mouse to move or a button transition.  For processes other than MOUSE-PROCESS.
If the arguments are supplied, we wait for the mouse state to be
different from them.  To avoid lossage, save the values of
MOUSE-X and MOUSE-Y and MOUSE-LAST-BUTTONS, use the saved values,
then pass the saved values to this function.
WHOSTATE is displayed in the who line while we wait."
  (PROCESS-WAIT WHOSTATE
    #'(LAMBDA (OLD-X OLD-Y OLD-BUTTONS)
	(OR ( MOUSE-X OLD-X)
	    ( MOUSE-Y OLD-Y)
	    ( (tv:%lambda-mouse-buttons) OLD-BUTTONS)))
    OLD-X OLD-Y OLD-BUTTONS))
