Viewing contents of file '../idllib/contrib/esrg_ucsb/curbox.pro'
PRO curbox, x1,x2,y1,y2,xwin,ywin,xrng,yrng,init=init,message=message,inc=inc,$
            index=index,label=label,color=color,charsize=charsize,fill=fill
;+
; NAME:
;        CURBOX
;
; PURPOSE:
;        Emulate the operation of a variable-sized box cursor (also known as
;        a "marquee" selector).  CURBOX can be used to select a sub-region
;        from a TVIM image (see example).   
;
; CATEGORY:
;        Interactive graphics.
;
; CALLING SEQUENCE:
;        CURBOX, x1,x2,y1,y2
;
;        curbox,x1,x2,y1,y2,xwin,ywin,xrng,yrng,init=init,$
;                message=message,inc=inc, index=index,label=label, $
;                color=color,charsize=charsize
;+
;
; INPUTS:
;   x1,x2,y1,y2
;     coordinates of box edges. If XWIN,YWIN,XRNG,YRNG are set, then
;     input is in data coordinates, otherwise in normalized coordinates.
;
; KEYWORD PARAMETERS:
;
;   init
;     If this keyword is set, the initial position of the cursor
;     is given by X1,X2,Y1,Y2
;
;   message
;     If this keyword is set, print a short message describing
;     operation of the cursor.
;
;   xwin,ywin
;     two element vectors giving normalized x and y coordinates of window
;     subregion, for example that given by !x.window or !y.window
;   
;   xrng,yrng
;     two elements vectors giving data range of window subregion, for 
;     example, as given by !x.crange or !y.crange.  When CURBOX is used
;     with TVIM (and XRANGE and YRANGE are not used with TVIM), XRNG
;     and YRNG represent the total index range of the displayed
;     image. X1,X2,Y1,Y2 will then be the array subrange of the
;     selected region.
;
;   index
;     if set, the XRNG,YRNG,XWIN,YWIN parameters are set to the values of
;     the last data window, i.e., !x.crange,!y.crange, !x.window, and
;     !y.window respectively.  Setting INDEX causes X1,X2,Y1,Y2 to be
;     interpreted as index range coordinates.
;     
;   inc
;     increment by which to change cursor box size when right or left
;     mouse button is pressed.  Specified in data index coordinates (i.e.,
;     array index coordinate) when XWIN,YWIN,XRNG,YRNG are set, otherwise
;     in normalized coordinates.  The x and y increments may be specified
;     separately by providing INC as a two element array.
;
;   label
;     a string which is used to label the selected region.  The string is
;     centered within the region and is sized to ensure that it fits within
;     the box.  If LABEL is set the box is not erased after CURBOX returns
;     
;   color
;     color used to label regions
;
;   charsize
;     character size used for region labels
;
;   fill
;     color used to fill box region, only effective when LABEL is set
;
; OUTPUTS:
;   x1,x2,y1,y2
;     normalized coordinates coordinates of box edges.  Howvever, if
;     xwin, ywin, xrng, and yrng are set, output is in data index
;     coordinates, i.e., x1,x2,y1,y2 provide the index range of the
;     boxed region of the image.
;
;     If xwin,ywin,xrng,yrng are set, the output range is clipped to be
;     within the limits of xrng and yrng.  
;
; 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:   reduce box size
;        Middle mouse button: increase box size
;        Right mouse button:  Exit this procedure, returning the 
;                             current box parameters.
;
;        NOTE: CURBOX is designed for applications in which the aspect
;              ratio of the cursor box is fixed. However, if the
;              aspect ratio must be adjusted do the following: jam the
;              box against one of the window borders.  If you force
;              the box against the left or right borders (while
;              keeping the cursor pointer within the window) box size
;              is constrained to change only in the height. Similarly
;              the box can be made fatter or thiner by pushing the box
;              against the top or bottom. As usual the LMB decreases
;              size and the MMB increases size.
;
;
;
;; EXAMPLE
;;
;;    use curbox to interactively select subregions from a TVIM image
;
;       w8x11
;       !p.multi=[0,1,2]
;       f=randata(128,128,s=3)
;       tvim,f,/interp
;       xw=!x.window & xr=!x.crange
;       yw=!y.window & yr=!y.crange
;        
;       x1=60 & x2=80 & y1=60 & y2=80
;       !p.charsize=2
;       !p.multi=[4,2,4]
;       curbox,x1,x2,y1,y2,xw,yw,xr,yr,/init,inc=4,/mess,label='region 1'
;       confill,f(x1:x2,y1:y2),title='region 1'
;       curbox,x1,x2,y1,y2,xw,yw,xr,yr,/init,inc=4,/mess,label='region 2'
;       confill,f(x1:x2,y1:y2),title='region 2'
;       curbox,x1,x2,y1,y2,xw,yw,xr,yr,/init,inc=4,/mess,label='region 3'
;       confill,f(x1:x2,y1:y2),title='region 3'
;       curbox,x1,x2,y1,y2,xw,yw,xr,yr,/init,inc=4,/mess,label='region 4'
;       confill,f(x1:x2,y1:y2),title='region 4'
;
;;    use CURBOX to find the normalized coordinates of a window region
;;    of given aspect ratio
;
;        x1=.4 & x2=x1+.3 & y1=.4 & y2=y1+.1
;        curbox,x1,x2,y1,y2,/init,/mess
;        print,x1,x2,y1,y2
;
; author   Paul Ricchiazzi      April, 1993
;-


device, get_graphics = old, set_graphics = 6   ;Set xor
xdvsz=!d.x_vsize-1
ydvsz=!d.y_vsize-1
if keyword_set(index) then begin
  xwin=!x.window
  ywin=!y.window
  xrng=!x.crange
  yrng=!y.crange
endif
if keyword_set(xwin) then begin
  cx=poly_fit(xwin,xrng,1)
  cy=poly_fit(ywin,yrng,1)
  centx=.5*(xwin(0)+xwin(1))
  centy=.5*(ywin(0)+ywin(1))
  indexed=1
endif else begin
  cx=[0.,1.]
  cy=[0.,1.]
  centx=.5
  centy=.5
  indexed=0
endelse

if keyword_set(init) then begin  ;Supply default values for box:
  x0=xdvsz*(.5*(x1+x2)-cx(0))/cx(1)
  y0=ydvsz*(.5*(y1+y2)-cy(0))/cy(1)
  mx=x2-x1+indexed
  my=y2-y1+indexed
  fixit=size(x1)
  if fixit(1) eq 2 or fixit(1) eq 3 then fixit=1 else fixit=0
endif else begin
  x0 = !d.x_size*centx
  y0 = !d.y_size*centy
  if indexed then begin
    mx=.5*(xrng(1)-xrng(0)+1)
    my=.5*(yrng(1)-yrng(0)+1)
    fixit=1
  endif else begin
    mx=.2
    my=mx*xdvsz/ydvsz
    fixit=0
  endelse
endelse
   
tvcrs,x0,y0

if keyword_set(inc) then begin
  if n_elements(inc) eq 1 then begin
    dx=inc 
    dy=inc
  endif else begin
    dx=inc(0)
    dy=inc(1)
  endelse
  mx=dx*fix(mx/dx)
  my=dy*fix(my/dy)
endif else begin
  dx=mx/10.
  dy=my/10.
endelse  

aspin=float(mx)/my

mxin=float(mx)
nx=xdvsz*mx/cx(1)
ny=ydvsz*my/cy(1)

px=[x0,x0+nx,x0+nx,x0,x0]-nx/2
py=[y0,y0,y0+ny,y0+ny,y0]-ny/2

plots,px,py,/device

chgx=1
chgy=1

if keyword_set(message) then begin
  szlabel=strcompress(string(f='(a,f10.4)',"SIZE = ",mx/mxin))
  if indexed then szlabel=szlabel+"    "+strcompress(string(mx," x ",my))
  strings=["Hit the left mouse button to reduce the box size",$
           "Hit the middle mouse button to increase the box size",$
           "Hit the right mouse button to quit",szlabel]
  xmessage,strings,wbase=wbase,wlabels=wlabels,title="CURBOX info:"
  lastlabel=wlabels(n_elements(strings)-1)
endif

xinit=x0
yinit=y0

while 1 do begin
  nxo=nx
  nyo=ny
  x00=x0
  y00=y0
  cursor, x0, y0, /nowait, /dev

  butn = !err

  if (x0 ne x00 and y0 ne y00) or $
     (nx ne nxo) or (ny ne nyo) or (butn ne 0) then begin

    if butn eq 1 then begin
      if chgx then mx=(mx-dx) > dx
      if chgy then my=(my-dy) > dy
      nx=xdvsz*mx/cx(1)
      ny=ydvsz*my/cy(1)
      if keyword_set(lastlabel) ne 0 then begin
        szlabel=strcompress(string(f='(a,f10.4)',"SIZE = ",mx/mxin))
        if indexed then szlabel=szlabel+"    "+strcompress(string(mx," x ",my))
        xmessage,szlabel,relabel=lastlabel
      endif

    endif
    if butn eq 2 then begin
      if chgx then mx=(mx+dx)
      if chgy then my=(my+dy)
      nx=xdvsz*(mx/cx(1) < 1.)
      ny=ydvsz*(my/cy(1) < 1.)
      if keyword_set(lastlabel) ne 0 then begin
        szlabel=strcompress(string(f='(a,f10.4)',"SIZE = ",mx/mxin))
        if indexed then szlabel=szlabel+"    "+strcompress(string(mx," x ",my))
        xmessage,szlabel,relabel=lastlabel
      endif
    endif

    plots, px, py,/device                       ; erase old box
    empty
  
    xnew = x0 > (nx/2) < (!d.x_size-nx/2)
    ynew = y0 > (ny/2) < (!d.y_size-ny/2) 
  
    chgx=xnew eq x0
    chgy=ynew eq y0

    x0=xnew
    y0=ynew

    px=[x0,x0+nx,x0+nx,x0,x0]-nx/2
    py=[y0,y0,y0+ny,y0+ny,y0]-ny/2
  
    plots, px, py,/device                       ; draw new box
    empty
  
    if !err eq 4 then begin  ;Quitting?
      plots, px, py,/device
      empty
      device,set_graphics = old, cursor_standard=30
      if keyword_set(message) then xmessage,kill=wbase

      x1=poly((x0-.5*nx)/xdvsz,cx)
      x2=x1+mx-indexed
      y1=poly((y0-.5*ny)/ydvsz,cy)
      y2=y1+my-indexed
      
      if indexed then begin
        x1=x1 >xrng(0) <xrng(1)
        x2=x2 >xrng(0) <xrng(1)
        y1=y1 >yrng(0) <yrng(1)
        y2=y2 >yrng(0) <yrng(1)
      endif
      
      if fixit then begin
        x1=fix(.51+x1)
        x2=fix(.51+x2)
        y1=fix(.51+y1)
        y2=fix(.51+y2)
      endif
      
      if keyword_set(label) then begin
        if n_elements(fill) ne 0 then polyfill,px,py,/device,color=fill
        if not keyword_set(color) then color=!p.color
        plots,px,py,color=color,/device
        xlen=!d.x_vsize*lenstr(label)
        if keyword_set(charsize) then begin
          chsz=charsize
        endif else begin
          if !p.charsize ne 0 then chsz=!p.charsize else chsz=1.
        endelse
        chsz=chsz < (.8*nx/xlen)
        y0lab=y0-.25*chsz*!d.y_ch_size
        xyouts,x0,y0lab,label,charsize=chsz,align=.5,/device
      endif
      return

    endif
  endif
  wait,.05
endwhile

end