CLIM mail archive



   Reply-To: jmorrill@BBN.COM
   Date: Thu, 17 Dec 92 10:25:13 -0500
   From: Jeff Morrill <jmorrill@BBN.COM>

     Date: Thu, 17 Dec 1992 11:57:17 +0100
     From: Dietmar Pree <>
     To: clim@BBN.COM

     I am searching for a (very) efficient way to code a function like

	clim:dragging-output-record stream output-record & key (:repaint t)

	which enters an interaction mode in which the user moves the
	pointer, and output-record is RESIZED (and not dragged !!!) on stream
	when the pointer is moved.

   In general, all dragging or "rubberbanding" should be done this way:

   Use tracking-pointer to get reports on mouse motion.  Each time
   the mouse moves, you:

     1.  erase (that is, draw with the flip ink) at the old position
     2.  display (that is, draw with the flip ink) at the new position

   Obviously you need a display function that takes INK as one
   of its arguments.

   In your case, the display function should also take some sort of
   size arguments that are a function of the mouse position.  Then you:

     1.  erase (that is, draw with the flip ink) at the old size
     2.  display (that is, draw with the flip ink) at the new size

   Display should be done with output recording disabled because there is
   no point recording what you are going to erase the next time the mouse
   moves.  With output recording disabled, the display function probably
   won't take longer than a fraction of a second, and the animation
   effect will seem real enough.  Dragging with output recording
   enabled is almost always wrong.  When you are done dragging, you can
   draw it once with output recording enabled to make it persist.

More concretely, here is a simple example of a "rubber band" box.

(in-package :clim-user)

(defun rubber-band-box (win)
  (let ((start-x nil) (start-y nil)
	(prev-x nil) (prev-y nil))
    ;; Draw a box from the start point to (x, y), erasing
    ;; the previous box (if any)
    (flet ((draw-box (x y)
	     (when start-x
	       ;; erase old box
	       (when prev-x
		 (draw-rectangle* win start-x start-y prev-x prev-y
				  :filled nil
				  :ink +flipping-ink+))
	       ;; draw new
	       (draw-rectangle* win start-x start-y x y
				:filled nil
				:ink +flipping-ink+)
	       ;; remember newly old box
	       (setq prev-x x prev-y y))))
      ;; Doesn't do anything until a button is pressed, then
      ;; rubber bands until the button is released.
      (with-output-recording-options (win :record-p nil)
	(tracking-pointer (win)
	  (:pointer-motion (x y)
	    (draw-box x y))
	  (:presentation (x y)
	    (draw-box x y))
	  (:pointer-button-press (x y)
	    (setq start-x x start-y y))
	  (:pointer-button-release ()
	    (setq start-x nil)
	    (return-from rubber-band-box)))))))


Follow-Ups: References:

Main Index | Thread Index