home *** CD-ROM | disk | FTP | other *** search
- (in-package :oou)
- (oou-provide :draggable-svm)
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; draggable-svm.lisp
- ;;
- ;; Copyright ⌐ 1992 Northwestern University Institute for the Learning Sciences
- ;; All Rights Reserved
- ;;
- ;; author: Michael S. Engber
- ;; based on an idea originally implemented for MACL 1.32 by Rich Lynch
- ;;
- ;; mixin for dragging views
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (oou-dependencies
- :simple-view-ce
- :WMgr-view
- :QuickDraw-u
- :kinesis-u)
-
- (export '(draggable-svm pre-drag-hilite draggable-p point-in-drag-region-p set-drag-outline-rgn))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (defclass draggable-svm ()
- ((drag-bounds :initarg :drag-bounds
- :accessor drag-bounds)
- (h-drag-slop :initarg :h-drag-slop
- :accessor h-drag-slop)
- (v-drag-slop :initarg :v-drag-slop
- :accessor v-drag-slop)
- (drag-axis :initarg :drag-axis
- :accessor drag-axis)
- (drag-outline-p :initarg :drag-outline-p
- :accessor drag-outline-p)
- (drag-pre-hilite-p :initarg :drag-pre-hilite-p
- :accessor drag-pre-hilite-p)
- (drag-pre-erase-p :initarg :drag-pre-erase-p
- :accessor drag-pre-erase-p)
- (drag-post-erase-p :initarg :drag-post-erase-p
- :accessor drag-post-erase-p)
- (drag-start-tol :initarg :drag-start-tol
- :accessor drag-start-tol)
- (drag-action-fn :initarg :drag-action-fn
- :accessor drag-action-fn)
- (drag-end-action-fn :initarg :drag-end-action-fn
- :accessor drag-end-action-fn))
- (:default-initargs
- :drag-bounds :none
- :h-drag-slop 20
- :v-drag-slop 20
- :drag-axis :both
- :drag-start-tol #@(2 2)
- :drag-outline-p t
- :drag-pre-hilite-p t
- :drag-pre-erase-p nil
- :drag-post-erase-p t
- ))
-
- (defmethod view-click-event-handler ((sv draggable-svm) where)
- (unless (view-drag-handler sv where)
- (call-next-method)))
-
- (defmethod view-drag-handler ((sv draggable-svm) where)
- (when (and (draggable-p sv) (point-in-drag-region-p sv where))
- (when (drag-pre-hilite-p sv) (pre-drag-hilite sv t))
- (multiple-value-bind (drag-offset end-action-p) (when (drag-start-p sv where)
- (drag-item sv where))
- (when (drag-pre-hilite-p sv) (pre-drag-hilite sv nil))
- (when end-action-p
- (call-drag-end-action sv drag-offset (add-points where drag-offset)))
- drag-offset)))
-
- (defmethod draggable-p ((sv draggable-svm))
- (declare (ignore sv))
- ;;specialize to control when an item can be dragged
- t)
-
- (defmethod point-in-drag-region-p ((sv draggable-svm) pt)
- ;;specialize to control from where an item can be dragged
- ;;defaults to any area not also contained by a subview
- (eq sv (find-clicked-subview sv pt)))
-
- (defmethod call-drag-action ((sv draggable-svm))
- ;;exists primarily to be specialized by selectable-svm
- (drag-action sv))
-
- (defmethod drag-action ((sv draggable-svm))
- (when (slot-boundp sv 'drag-action-fn)
- (funcall (drag-action-fn sv) sv)))
-
- (defmethod call-drag-end-action ((sv draggable-svm) drag-offset dest-point)
- ;;exists primarily to be specialized by selectable-svm
- (drag-end-action sv drag-offset dest-point))
-
- (defmethod drag-end-action ((sv draggable-svm) drag-offset dest-point)
- (when (slot-boundp sv 'drag-end-action-fn)
- (funcall (drag-end-action-fn sv) sv drag-offset dest-point)))
-
- (defmethod pre-drag-hilite ((sv draggable-svm) hilite-flag)
- (with-focused-view (focusing-view sv)
- (hilite-view sv hilite-flag)))
-
- (defmethod drag-start-p ((sv draggable-svm) where)
- ;;tracks the mouse to see if the user breaks the item loose
- (rlet ((r :Rect
- :topLeft (subtract-points where (drag-start-tol sv))
- :botRight (add-points where (drag-start-tol sv))))
- (loop (unless (#_WaitMouseUp) (return nil))
- (unless (#_PtInRect (view-mouse-position (focusing-view sv)) r)
- (return t)))))
-
- (defpascal drag-action-proc ()
- ;;pascal style fn passed to DragGrayRgn, the call-drag-action method does the
- ;;real work. *current-draggable-di* is bound for the duration of the drag, to
- ;;communicate the item being dragged to drag-action-proc.
- (declare (special *current-draggable-di*))
- (call-drag-action *current-draggable-di*))
-
-
- (defmethod drag-proc ((sv draggable-svm) drag-rgn start-pt bounds-rect slop-rect)
- (if (drag-outline-p sv)
- (let ((axis-const (ecase (drag-axis sv)
- (:both #.#$noConstraint)
- (:horizontal #.#$hAxisOnly)
- (:vertical #.#$vAxisOnly))))
- (#_DragGrayRgn drag-rgn start-pt bounds-rect slop-rect axis-const drag-action-proc))
- (flet ((action-fn () (call-drag-action sv)))
- (drag-region drag-rgn start-pt
- :bounds-rect bounds-rect
- :slop-rect slop-rect
- :drag-axis (drag-axis sv)
- :action-fn #'action-fn
- :erase-at-start-p (drag-pre-erase-p sv)
- :erase-at-end-p (drag-post-erase-p sv)))))
-
- (defmethod drag-item ((sv draggable-svm) where)
- ;;returns 2 values: the drag-offset and whether to call the drag-end-action
- (setf where (view-to-global (focusing-view sv) where))
- (rlet ((limitRect :Rect)
- (slopRect :Rect))
- (with-macptrs ((dragRgn (#_NewRgn)))
- (unwind-protect
- (let ((*current-draggable-di* sv))
- (declare (special *current-draggable-di*))
- (set-DragGrayRgn-areas sv where dragRgn limitRect slopRect)
- (shrink-wrap-limitRect where dragRgn limitRect)
- (with-focused-view *WMgr-view*
- (setf where (drag-proc sv dragRgn where limitRect slopRect)))
- (if (eql #@(-32768 -32768) where)
- (values nil nil)
- (values where t)))
- (#_DisposeRgn dragRgn)))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; these routines use GLOBAL coordinates
-
- (defmethod set-DragGrayRgn-areas ((sv draggable-svm) where drag-rgn limitRect slopRect)
- (declare (ignore where))
- (set-drag-limit-rect sv limitRect)
- (set-drag-slop-rect sv slopRect)
- (set-drag-outline-rgn sv drag-rgn))
-
- (defmethod set-drag-outline-rgn ((sv draggable-svm) drag-rgn)
- (multiple-value-bind (topLeft botRight) (view-global-corners sv)
- (rlet ((r :Rect :topLeft topLeft :botRight botRight))
- (#_RectRgn drag-rgn r))))
-
- (defmethod set-drag-limit-rect ((sv draggable-svm) r)
- (ecase (drag-bounds sv)
- (:container (multiple-value-bind (c-topLeft c-botRight) (view-global-corners (view-container sv))
- (pset r :Rect.topLeft c-topLeft)
- (pset r :Rect.botRight c-botRight))
- (multiple-value-bind (w-topLeft w-botRight) (view-global-corners (view-window sv))
- (rlet ((wRect :Rect :topLeft w-topLeft :botRight w-botRight))
- (#_SectRect r wRect r))))
- (:window (multiple-value-bind (w-topLeft w-botRight) (view-global-corners (view-window sv))
- (pset r :Rect.topLeft w-topLeft)
- (pset r :Rect.botRight w-botRight)))
- (:none (pset r :Rect.topLeft #@(-16384 -16384))
- (pset r :Rect.botRight #@(16384 16384)))))
-
- (defmethod set-drag-slop-rect ((sv draggable-svm) r)
- (set-drag-limit-rect sv r)
- (#_InsetRect r (- (h-drag-slop sv)) (- (v-drag-slop sv))))
-
- (defun shrink-wrap-limitRect (where dragRgn limitRect)
- (let ((h (point-h where))
- (v (point-v where)))
- (pset limitRect :Rect.top (- v (max 0 (- (href dragRgn :Region.rgnBBox.top)
- (pref limitRect :Rect.top)))))
- (pset limitRect :Rect.left (- h (max 0 (- (href dragRgn :Region.rgnBBox.left)
- (pref limitRect :Rect.left)))))
- (pset limitRect :Rect.bottom (+ v (max 0 (- (pref limitRect :Rect.bottom)
- (href dragRgn :Region.rgnBBox.bottom)))))
- (pset limitRect :Rect.right (+ h (max 0 (- (pref limitRect :Rect.right)
- (href dragRgn :Region.rgnBBox.right)))))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- #|
- ;;; a modest example - adding drag behavior to static text dialog items
-
- (defclass stdrg (draggable-svm static-text-dialog-item) ())
-
-
- (setf *test-w*
- (make-instance 'dialog
- :window-type :document
- :view-position :centered
- :view-size #@(200 100)
- :window-title "draggable-svm demo"
- :close-box-p t
- :color-p t
- :view-subviews
- (list (make-instance 'stdrg
- :view-position #@(10 20)
- :dialog-item-text "change my position"
- :view-nick-name :i1
- :drag-end-action-fn #'(lambda (sv delta pt)
- (declare (ignore pt))
- (offset-view-position sv delta))
- :drag-bounds :window
- )
- (make-instance 'stdrg
- :view-position #@(10 50)
- :dialog-item-text "drag me anywhere"
- :view-nick-name :i2
- :dialog-item-action #'(lambda (di) (declare (ignore di)) (ed-beep))
- :drag-action-fn #'(lambda (di) (declare (ignore di)) (ed-beep))
- :drag-bounds :none
- ))))
-
- |#