; $Id: box_cursor.pro,v 1.8 1998/05/29 14:08:03 rfrank Exp $
;
; Copyright (c) 1990-1998, Research Systems, Inc.  All rights reserved.
;	Unauthorized reproduction prohibited.
;

pro box_cursor, x0, y0, nx, ny, INIT = init, FIXED_SIZE = fixed_size, $
	MESSAGE = message
;+
; NAME:
;	BOX_CURSOR
;
; PURPOSE:
;	Emulate the operation of a variable-sized box cursor (also known as
;	a "marquee" selector).
;
; CATEGORY:
;	Interactive graphics.
;
; CALLING SEQUENCE:
;	BOX_CURSOR, x0, y0, nx, ny [, INIT = init] [, FIXED_SIZE = fixed_size]
;
; INPUTS:
;	No required input parameters.
;
; OPTIONAL INPUT PARAMETERS:
;	x0, y0, nx, and ny give the initial location (x0, y0) and 
;	size (nx, ny) of the box if the keyword INIT is set.  Otherwise, the 
;	box is initially drawn in the center of the screen.
;
; KEYWORD PARAMETERS:
;	INIT:  If this keyword is set, x0, y0, nx, and ny contain the initial
;	parameters for the box.
;
;	FIXED_SIZE:  If this keyword is set, nx and ny contain the initial
;	size of the box.  This size may not be changed by the user.
;
;	MESSAGE:  If this keyword is set, print a short message describing
;	operation of the cursor.
;
; OUTPUTS:
;	x0:  X value of lower left corner of box.
;	y0:  Y value of lower left corner of box.
;	nx:  width of box in pixels.
;	ny:  height of box in pixels. 
;
;	The box is also constrained to lie entirely within the window.
;
; COMMON BLOCKS:
;	None.
;
; SIDE EFFECTS:
;	A box is drawn in the currently active window.  It is erased
;	on exit.
;
; RESTRICTIONS:
;	Works only with window system drivers.
;
; PROCEDURE:
;	The graphics function is set to 6 for eXclusive OR.  This
;	allows the box to be drawn and erased without disturbing the
;	contents of the window.
;
;	Operation is as follows:
;	Left mouse button:   Move the box by dragging.
;	Middle mouse button: Resize the box by dragging.  The corner
;		nearest the initial mouse position is moved.
;	Right mouse button:  Exit this procedure, returning the 
;			     current box parameters.
;
; MODIFICATION HISTORY:
;	DMS, April, 1990.
;	DMS, April, 1992.  Made dragging more intutitive.
;	June, 1993 - Bill Thompson
;			prevented the box from having a negative size.
;       SJL, Nov, 1997.  Formatted, conform to IDL style guide.
;                       Prevented crash from unitialized corner.
;       RJF, Feb, 1998. Replaced !ERROR_STATE.CODE w/ !MOUSE.BUTTON and
;			fixed some problems w/sizing when a corner might swap.
;-

    DEVICE, GET_GRAPHICS = old, SET_GRAPHICS = 6  ;Set xor
    col = !D.N_COLORS -1
    corner = 0

    if KEYWORD_SET(message) then begin
        print, "Drag Left button to move box."
        print, "Drag Middle button near a corner to resize box."
        print, "Right button when done."
    endif
    
    if KEYWORD_SET(init) eq 0 then begin ;Supply default values for box:
        if KEYWORD_SET(fixed_size) eq 0 then begin
            nx = !D.X_SIZE/8    ;no fixed size.
            ny = !D.X_SIZE/8
        endif
        x0 = !D.X_SIZE/2 - nx/2
        y0 = !D.Y_SIZE/2 - ny/2
    endif
    
    button = 0
    old_button = 1
    goto, middle

    while(1) do begin
        old_button = button
        cursor, x, y, 2, /DEV	;Wait for a button
        button = !MOUSE.BUTTON
     
        if ((old_button eq 0) and (button ne 0)) then begin
            mx0 = x		;For dragging, mouse locn...
            my0 = y		
            x00 = x0            ;Orig start of ll corner
            y00 = y0
        endif

        if (!MOUSE.BUTTON eq 1) then begin ;Drag entire box?
            x0 = x00 + x - mx0
            y0 = y00 + y - my0
        endif

        ;;New size?
        if ((!MOUSE.BUTTON eq 2) and (KEYWORD_SET(fixed_size) eq 0)) $
          then begin
            if (old_button eq 0) then begin ;Find closest corner
                mind = 1e6
                for i=0,3 do begin
                    d = float(px[i]-x)^2 + float(py[i]-y)^2
                    if (d lt mind) then begin
                        mind = d
                        corner = i
                    endif
                endfor
                nx0 = nx	;Save sizes.
                ny0 = ny
            endif
            dx = x - mx0 & dy = y - my0	;Distance dragged...
            case corner of
                0: begin 
                    x0 = x00 + dx & y0 = y00 + dy
                    nx = nx0 -dx & ny = ny0 - dy
                endcase
                1: begin 
                    y0 = y00 + dy
                    nx = nx0 + dx & ny = ny0 - dy
                endcase
                2: begin 
                    nx = nx0 + dx & ny = ny0 + dy
                endcase
                3: begin 
                    x0 = x00 + dx
                    nx = nx0 -  dx & ny = ny0 + dy
                endcase
            endcase
        endif

        if ((old_button ne 0) or (button ne 0)) then begin
            plots, px, py, COL=col, /DEV, THICK=1, LINES=0 ;Erase previous box
            empty                   ;Decwindow bug
	endif

        if (!MOUSE.BUTTON eq 4) then begin ;Quitting?
            DEVICE,SET_GRAPHICS = old
            return
        endif
middle:

        if (nx lt 0) then begin
            x0 = x0 + nx
            nx = -nx
	    case corner of
		0: corner = 1
		1: corner = 0
		2: corner = 3
		3: corner = 2
	    endcase
; reset the starting drag point...
            mx0 = x & my0 = y		
            x00 = x0 & y00 = y0
            nx0 = nx & ny0 = ny
        endif
        if (ny lt 0) then begin
            y0 = y0 + ny
            ny = -ny
	    case corner of
		0: corner = 3
		3: corner = 0
		1: corner = 2
		2: corner = 1
	    endcase
; reset the starting drag point...
            mx0 = x & my0 = y		
            x00 = x0 & y00 = y0
            nx0 = nx & ny0 = ny
        endif
        
        x0 = x0 > 0
        y0 = y0 > 0
        x0 = x0 < (!D.X_SIZE-1 - nx) ;Never outside window
        y0 = y0 < (!D.Y_SIZE-1 - ny)
        
        px = [x0, x0 + nx, x0 + nx, x0, x0] ;X points
        py = [y0, y0, y0 + ny, y0 + ny, y0] ;Y values
        
        if ((old_button ne 0) or (button ne 0)) then begin
            plots,px, py, COL=col, /DEV, THICK=1, LINES=0 ;Draw the box
            empty                   ;Decwindow bug
 	endif

        wait, .1		;Dont hog it all
    endwhile
end
