############################################################################ # # File: drag.icn # # Subject: Procedures for dragging rectangles # # Author: Gregg M. Townsend # # Date: August 21, 1998 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # These procedures drag rectangular objects in a window. # # Drag(x, y, w, h) provides an opaque move. # # DragOutline(x, y, w, h) drags only the outline. # ############################################################################ # # Drag(x, y, w, h) lets the user move a rectangular area using the # mouse. Called when a mouse button is pressed, Drag() handles all # subsequent events until a mouse button is released. As the mouse # moves, the rectangular area originally at (x,y,w,h) follows it # across the screen; vacated pixels at the original location are # filled with the background color. The rectangle cannot be dragged # off-screen or outside the clipping region. When the mouse button # is released, Drag() sets &x and &y to the upper-left corner of the # new location and returns. # # DragOutline(x, y, w, h) lets the user move a reverse-mode rectangle # using the mouse. Called when a mouse button is pressed, DragOutline # draws a reverse-mode rectangle inside the limits of the rectangle # (x,y,w,h) and handles all subsequent events until a mouse button is # released. As the mouse moves, the rectangle follows it. When the # mouse button is released, the rectangle disappears, and DragOutline # sets &x and &y to the upper-left corner of the new location. It is # up to the calling program to update the display as necessary. # ############################################################################ # # Requires: Version 9 graphics # ############################################################################ link graphics # Drag(x, y, w, h) -- opaque drag procedure Drag(win, x, y, w, h) #: opaque rectangle drag local dx, dy, x0, y0, x1, y1 local behind, xoff, yoff, xnew, ynew, xshift, yshift if type(win) ~== "window" then return Drag((\&window | runerr(140)), win, x, y, w) if w < 0 then x -:= (w := -w) if h < 0 then y -:= (h := -h) dx := WAttrib(win, "dx") dy := WAttrib(win, "dy") x0 := -dx # set limits due to window size y0 := -dy x1 := WAttrib(win, "width") - dx - w y1 := WAttrib(win, "height") - dy - h x0 <:= \WAttrib(win, "clipx") # adjust limits for clipping y0 <:= \WAttrib(win, "clipy") x1 >:= \WAttrib(win, "clipx") + \WAttrib(win, "clipw") - w y1 >:= \WAttrib(win, "clipy") + \WAttrib(win, "cliph") - h behind := ScratchCanvas(win, , , "__Drag__") | stop("can't get ScratchCanvas in Drag()") CopyArea(win, behind, -dx, -dy) Bg(behind, Bg(win)) EraseArea(behind, x + dx, y + dy, w, h) xoff := x - &x yoff := y - &y until Event(win) === (&lrelease | &mrelease | &rrelease) do { # move the rectangle xnew := &x + xoff ynew := &y + yoff xnew <:= x0 ynew <:= y0 xnew >:= x1 ynew >:= y1 CopyArea(win, x, y, w, h, xnew, ynew) # repaint the area exposed by its movement xshift := xnew - x yshift := ynew - y if abs(xshift) >= w | abs(yshift) >= h then { # completely disjoint from new location CopyArea(behind, win, x + dx, y + dy, w, h, x, y) } else { # new area overlaps old if xshift > 0 then CopyArea(behind, win, x + dx, y + dy, xshift, h, x, y) else if xshift < 0 then CopyArea(behind, win, x + dx + w + xshift, y + dy, -xshift, h, x + w + xshift, y) if yshift > 0 then CopyArea(behind, win, x + dx, y + dy, w, yshift, x, y) else if yshift < 0 then CopyArea(behind, win, x + dx, y + dy + h + yshift, w, -yshift, x, y + h + yshift) } x := xnew y := ynew } EraseArea(behind) &x := x &y := y return win end # DragOutline(x, y, w, h) -- outlined drag procedure DragOutline(win, x, y, w, h) #: outlined rectangle drag local wrev, xoff, yoff if type(win) ~== "window" then return DragOutline((\&window | runerr(140)), win, x, y, w) if w < 0 then x -:= (w := -w) if h < 0 then y -:= (h := -h) wrev := Clone(win, "drawop=reverse") xoff := x - &x yoff := y - &y w -:= 1 # adjust Draw/Fill inconsistency h -:= 1 DrawRectangle(wrev, x, y, w, h) # draw initial rectangle until Event(wrev) === (&lrelease | &mrelease | &rrelease) do { DrawRectangle(wrev, x, y, w, h) # erase old rectangle x := &x + xoff y := &y + yoff DrawRectangle(wrev, x, y, w, h) # draw new rectangle } DrawRectangle(wrev, x, y, w, h) # erase final rectangle Uncouple(wrev) &x := x &y := y return win end