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

(defobclass window ()
  (mouse-char nil)
  mouse-font
  mouse-hot-x
  mouse-hot-y)

(defobclass object-managing-window (window)
  (objects nil)
  (mouseable-objects nil)
  (old-mouse-x 0)
  (old-mouse-y 0)
  (mouse-highlighted-object nil)
  )

;+++!
(defobfun (draw object-managing-window) ()
  (mapc-ask objects (draw)))

(defobfun (refresh object-managing-window) ()
  (draw))

(defobfun (obj-under-point object-managing-window) (x y &optional class non-mouseable-objects)
  (dolist (obj (if non-mouseable-objects objects mouseable-objects))
    (and (or (not class)
	     (obj-classp class obj))
	 (ask-funcall obj 'point-in-region x y)
	 (return obj))))

(defobfun (obj-under-mouse object-managing-window) (&optional class non-mouseable-objects)
  (obj-under-point (- tv:mouse-x (send tv-window :x-offset) (tv:sheet-left-margin-size tv-window))
		   (- tv:mouse-y (send tv-window :y-offset) (tv:sheet-top-margin-size tv-window))
		   class non-mouseable-objects))

(defobfun (mouse-moves object-managing-window) (x y)
  (dolist (obj mouseable-objects)
    (when (ask-funcall obj 'point-in-region old-mouse-x old-mouse-y)
      (unless (ask-funcall obj 'point-in-region x y)
	(ask-funcall obj 'mouse-out)
	(setq mouse-highlighted-object nil)
	(return))))
  (dolist (obj mouseable-objects)
    (when (ask-funcall obj 'point-in-region x y)
      (unless (ask-funcall obj 'point-in-region old-mouse-x old-mouse-y)
	(ask-funcall obj 'mouse-in)
	(setq mouse-highlighted-object obj)
	(return))))
  (setq old-mouse-x x
	old-mouse-y y))

(defobfun (mouse-click object-managing-window) (char x y)
  (dolist (obj mouseable-objects)
    (when (ask-funcall obj 'point-in-region x y)
      (ask obj (mouse-click char x y))
      (return))))

(defobfun (add-object object-managing-window) (new-object)
  (push new-object objects)
  (if (ask new-object mouseable-p)
      (push new-object mouseable-objects)))

(defobfun (remove-object object-managing-window) (obj)
  (pull obj objects)
  (pull obj mouseable-objects))


;;; Window system interface

(defflavor obie-window
	   ((oblisp-window nil))				       ;An oblisp object that does the work
	   (tv:window)
  (:init-keywords :oblisp-window-class)
  :gettable-instance-variables
  (:default-handler obie-window-handler))

(declare-flavor-instance-variables (obie-window)
(defobfun obie-window-handler (operation &rest args)
  (when oblisp-window
    (ask oblisp-window (apply (intern (symbol-name operation) 'obie) args)))))

(defmethod (obie-window :after :init) (plist)
  (setq oblisp-window (oneof (or (cadr (memq :oblisp-window-class plist)) ghost-window) 'tv-window self)))

;;; This is pointed to by a TV window and does the work for it
(defobclass ghost-window (object-managing-window)
  (tv-window nil))

(defmethod (obie-window :mouse-moves) (x y)
  (obie-window-handler :mouse-moves x y))

(defmethod (obie-window :mouse-click) (char x y)
  (obie-window-handler :mouse-click char x y))

(defmethod (obie-window :after :refresh) (&optional ignore)
  (obie-window-handler :refresh))

(defmethod (obie-window :mouse-standard-blinker) ()
  (obie-window-handler :mouse-standard-blinker))

(defobfun (mouse-standard-blinker window) ()
  (if mouse-char
      (tv:mouse-set-blinker-definition ':character mouse-hot-x mouse-hot-y ':on
				       ':set-character mouse-char mouse-font)
    (tv:mouse-set-blinker-definition ':character 0 0 ':on
				     ':set-character 6 'fonts:mouse)))
