CLIM mail archive


Re: double-clicking

    #+ACL 4.2
    has anyone got a good version of a double-click method? I have one
    that's weak, doesn't always behave properly.
    I need to be able to dbl-click on a presentation to bring up its
    editor-frame (much like the mac does stuff).
    I need one with the next month.
    thanks for any help!
     -- clint

Well, thats what I wrote to hack this. Double clicks are
mapped to gestures with have the :hyper modifier key set, 
as this was the best way I could think of to map this 
into clim's gesture stuff.

This implementation defines a click to be a double-click if 
 a) it follows the last click within a short period of time
    (i.e., within *Double-Click-Interval*)
 b) the click is near the last click
    (i.e., nearer than *Double-Click-Radius*)
 c) the mouse button and modifiers are the same as with the
    last click.
If all these conditions hold, the "hyper-modifer-state" is set.

Note that with this implementation the "two clicks" of a double-click lead to
two pointer-gestures. I.e., if you define a normal single-click gesture
as :select and a double-click gesture as :open, then
when you double-click on a presentation clim will see two gestures:
first a :select gesture and then the :open gesture.

I once had a lengthy discussion on this on the net (with some
misunderstandings), and I dont know how to circumvent this problem.
Moreover, it might not always be a problem e.g., when an object
must be selected before it can be opened (as it is on the mac).

Regards - Stefan B.

;;; Double Clicks

(defvar *last-button-press-event-time* 0)
(defvar *last-button-press-event-x* 0)
(defvar *last-button-press-event-y* 0)
(defvar *last-button-press-event-button* nil)
(defvar *last-button-press-event-modifier-state* nil)
(defvar *last-button-press-was-double-click* nil)

(defparameter *Double-Click-Interval* (* 1 internal-time-units-per-second))
(defparameter *Double-Click-Radius* 2)

(defun mouse-still-down (stream &optional (start-time
				(wait-time *Double-Click-Interval*))
  (let* ((pointer (stream-primary-pointer stream)))
    (loop with wait-until = (+ start-time wait-time)
	  while (and (<= (get-internal-real-time) wait-until)
		     (/= (pointer-button-state pointer) 0))
	  finally (return (/= (pointer-button-state pointer) 0)))))

(defmethod clim:queue-event :before ((pane clim:clim-stream-pane)
				     (event clim:pointer-button-press-event))
  (let ((x (pointer-event-x event))
	(y (pointer-event-y event))
	(button (pointer-event-button event))
	(modifier-state (event-modifier-state event))
	(radius *Double-Click-Radius*)
	(-radius (- *Double-Click-Radius*))
	(current-time (get-internal-real-time)))
       (setf *last-button-press-was-double-click*
	     (and (not *last-button-press-was-double-click*)
		  (eql button *last-button-press-event-button*)
		  (eql modifier-state *last-button-press-event-modifier-state*)
		  (<= (- current-time *last-button-press-event-time*) *Double-Click-Interval*)
		  (<= -radius (- x *last-button-press-event-x*) radius)
		  (<= -radius (- y *last-button-press-event-y*) radius)
       (with-slots ((modifier-state clim-silica::modifier-state)) event
          (setf modifier-state (logior modifier-state +hyper-key+))))
    (setf *last-button-press-event-time* current-time
	  *last-button-press-event-x* x
	  *last-button-press-event-y* y
	  *last-button-press-event-button* button
	  *last-button-press-event-modifier-state* modifier-state)))

(defun double-click-p ()

;;; example: the :open-gesture maps to a double-left-click
(define-gesture-name :open
  (:left :hyper))

;;; - Stefan Bernemann   (

Main Index | Thread Index