Viewing contents of file '../idllib/contrib/windt/cw_vector.pro'
;+
; NAME:
; 
;       CW_VECTOR
;
; PURPOSE:
; 
;       A compound widget used to get input necessary to create a
;       "vector", in the spirit of the VECTOR function in this
;       directory, i.e, get input for the MIN, MAX, and PTS values.
;       The widget also lets the user specify the increment between
;       points, and whether the point spacing is linear or
;       logarithmic.
;      
; CATEGORY:
; 
;	compound widgets.
;
; CALLING SEQUENCE:
; 
;	Result = CW_VECTOR(PARENT)
;
; INPUTS:
; 
;       PARENT - the id of the parent widget.  
;
; OPTIONAL KEYWORD PARAMETERS:
; 
;	UVALUE - Supplies the user value for the widget.
; 
;       FRAME - Set to draw a frame around the widget.
;
;       FONT - Font keyword for labels etc.
;
;       TITLE - A string used to label the widget
;
;       XSIZE - An explicit horizontal size (in characters) for the
;               min, max and increment input areas.  The default is to
;               let the window manager size the widget.  
;
;       NXSIZE - An explicit horizontal size (in characters) for the
;                pts field area.  The default is to let the window
;                manager size the widget.  
;
;       YSIZE - An explicit vertical size (in lines) for the text input
;               areas.  The default is 1.
;
;       VALUE - A structure used to set the initial value of the
;               widget, containing the following tags:
;
;               min, max, n and log - the parameters used to specify a
;                                     vector (see vector.pro)
;
;               format - a valid format command string used to format
;                        the min, max, and increment values. a null
;                        string will result in default floating-point
;                        formatting.
;
;               nformat - a valid format command string to format the
;                         pts field.  a null string will result in
;                         default integer formatting.
; 
;               units - a string used to label the vector units. for
;                       example, if the CW_VECTOR widget is being used
;                       to get input to create a vector of lengths in
;                       feet, then set value.units='feet'
;
;               uunits - a flag to indicate whether or not to actually
;                        update the units label.
;             
;               The same value structure is used with WIDGET_CONTROL
;               to set the value of a CW_VECTOR, as in
;               WIDGET_CONTROL,WIDGET,SET_VALUE=VALUE
;
;               When using the GET_VALUE keyword with WIDGET_CONTROL,
;               however, the returned value is a structure with only
;               four tags: {min,max,pts,log}
;
;      MINRANGE, MAXRANGE - These keywords define the range of
;                           acceptable values for the min and max
;                           fields.  If not set, any values for min
;                           and max are allowed; otherwise, (min >
;                           MINRANGE) < MAXRANGE, and (max > MINRANGE)
;                           < MAXRANGE.  None, one or both of these
;                           keywords can be specified.
;
;      MINN - The minimum allowable value for n. default is 1.
;
;      NO_RETURN - The default behavior is that the user must press
;                  <return> after entering new values.  Set this
;                  keyword so that an event is returned even if the
;                  user just changes a value and then moves the
;                  cursor outside of the text entry area.
;
; OUTPUTS:
; 
;       The id of the created widget is returned.
;
; PROCEDURE:
; 
;      Entering a value in the pts, min or max fields will set the
;      increment field.  Entering a value in the increment field will
;      set the points field, and possibly the max field if the
;      increment doesn't divide evenly into the range specified by min
;      and max.
;
; EXAMPLE:
; 
;     Create a CW_VECTOR to get input to create a vector of lengths in
;     [feet]:
;     
;      
;        base=WIDGET_BASE()
;        length_widget=CW_VECTOR(BASE,VALUE={MIN:0.,MAX:10.,N:11,LOG:0, $
;                                            UNITS:'feet', $
;                                            FORMAT:'(F10.2)',
;                                            NFORMAT:'(I4)',
;                                            UUNITS:1}
;                                TITLE='LENGTHS')
;
;     Later, get the widget values and create the length vector:
; 
;        WIDGET_CONTROL,length_widget,GET_VALUE=value
;        lengths=VECTOR(value.min,value.max,value.n,log=value.log)
;
; MODIFICATION HISTORY:
; 
;       David L. Windt, Bell Labs, March 1997
;       windt@bell-labs.com
;
;       DLW, June 1997, Added NO_RETURN keyword.
;
;       DLW, November 1997, Removed TRACKING keyword; corrected bug
;       that caused improper updates when NO_RETURN was set and the
;       user toggled between linear and logarithmic step sizes.
;
;-
;-procedure to set widget value--------------------------------------------
;
pro cw_vector_set_value,id,value

on_error,2

;; get stash id:
stash=widget_info(id,/child)

;; get state:
widget_control,stash,get_uvalue=state,/no_copy

;; make sure values are in range, and of correct type:
n=fix(value.n) > state.minn
v1=(value.min > state.minrange) < state.maxrange
v2=(value.max > state.minrange) < state.maxrange
log=( (value.log > 0) < 1)

;; for log spacing, can't have non-positive values:
if log then begin
    if v1 le 0. then v1=1.
    if v2 le 0. then v2=1.
endif

;; save formats and units in state:
state.units=value.units
state.nformat=value.nformat
state.format=value.format

;; set increment:
inc=0.
if n gt 1 then inc=(v2-v1)/(n-1)

;; set n:
widget_control,state.n,set_value=strtrim(string(n,format=value.nformat),2)
widget_control,state.n,set_uvalue=n

;; set min1:
widget_control,state.min1,set_value=strtrim(string(v1,format=value.format),2)
widget_control,state.min1,set_uvalue=v1

;; set unit label:
if value.uunits then widget_control,state.unit,set_value=value.units

;; set min:
widget_control,state.min,set_value=strtrim(string(v1,format=value.format),2)
widget_control,state.min,set_uvalue=v1

;; set max:
widget_control,state.max,set_value=strtrim(string(v2,format=value.format),2)
widget_control,state.max,set_uvalue=v2

;; set inc:
widget_control,state.inc,set_value=strtrim(string(inc,format=value.format),2)

;; set units label:
if value.uunits then widget_control,state.unitp,set_value=value.units

;; set increment droplist label:
if value.uunits then begin
    if value.units eq '' then $
      widget_control,state.log, $
      set_value=['step size:','logarithmic steps']  $
    else $
      widget_control,state.log, $
      set_value=['step size ['+value.units+']:','logarithmic steps']
    widget_control,state.log,set_droplist_select=log
endif

;; map/unmap unit or max, inc, and units:
widget_control,state.row3,map=(n eq 1)
widget_control,state.row4,map=(n gt 1)
widget_control,state.inc,map=(log eq 0)

;; restore state:
widget_control,stash,set_uvalue=state,/no_copy

return
end

;-function to get widget value---------------------------------------------
;
function cw_vector_get_value,id

on_error,2

;; get stash id:
stash=widget_info(id,/child)

;; get state:
widget_control,stash,get_uvalue=state,/no_copy

;; get n:
widget_control,state.n,get_uvalue=val
n=fix(val(0))

;; get min1:
widget_control,state.min,get_uvalue=val
if n eq 1 then v1=double(val(0))

;; get min:
widget_control,state.min,get_uvalue=val
if n gt 1 then v1=double(val(0))

;; get max:
widget_control,state.max,get_uvalue=val
v2=double(val(0))

;; get log:
log=widget_info(state.log,/droplist_select)

;; restore the state.
widget_control,stash,set_uvalue=state,/no_copy

value={min:v1,max:v2,n:n,log:log}

return,value
end

;-function to handle cw_vector widget events---------------------------------

function cw_vector_event,event

;; get parent id:
parent=event.handler

;; get stash id:
stash=widget_info(parent,/child)

;; get state:
widget_control,stash,get_uvalue=state,/no_copy

;; deal with no_return stuff:
update=1
if keyword_set(state.no_return) then begin
    ;; set new_text flag if it's a tracking event or a carriage
    ;; return:
    new_text=(tag_names(event,/str) eq 'WIDGET_TRACKING')
    if new_text eq 0 then $
      if (strmid(tag_names(event,/str),0,11) eq 'WIDGET_TEXT') then $
      if (event.type eq 0) then new_text=event.ch eq 10B 
    ;; or a droplist event:
    if new_text eq 0 then $
      if (strmid(tag_names(event,/str),0,15) eq 'WIDGET_DROPLIST') then $
      new_text=1

    ;; if there's new text, then get it and (a) turn off tracking
    ;; events and (b) turn on all text events. otherwise, turn on
    ;; tracking and turn off all text events:
    if new_text then begin
        if (strmid(tag_names(event,/str),0,11) ne 'WIDGET_DROPLIST') then begin
            widget_control,event.id,tracking_events=0
            widget_control,event.id,all_text_events=1
        endif
    endif else begin
        if (strmid(tag_names(event,/str),0,11) eq 'WIDGET_TEXT') then begin
            widget_control,event.id,tracking_events=1
            widget_control,event.id,all_text_events=0
        endif
        ;; no new text, so just exit:
        update=0
        goto,finish
    endelse
endif 

;; get n:
widget_control,state.n,get_value=n
n=fix(n(0))

;; get min and mix values:
if n eq 1 then widget_control,state.min1,get_value=v1 else $
  widget_control,state.min,get_value=v1
widget_control,state.max,get_value=v2
v1=double(v1(0))
v2=double(v2(0))

;; get log:
log=widget_info(state.log,/droplist_select)

widget_control,event.id,get_uvalue=uvalue

;; specifying increment?
if string(uvalue) eq 'inc' then begin
    ;; get increment:
    widget_control,state.inc,get_value=inc
    inc=double(inc(0)) 
    ;; set n, based on valid increment:
    if inc ne 0 then n1=1+fix((v2-v1)/inc) else n1=0
    ;; if n1 is negative, ignore the specified increment:
    if n1 lt 1 then inc=double((v2-v1)/(n-1)) else n=n1
    ;; set v2, based on valid n, v1 and inc:
    v2=double(v1+inc*(n-1))
endif

units=state.units
nformat=state.nformat
format=state.format

finish:;;
;; restore the state structure
widget_control,stash,set_uvalue=state,/no_copy

;; update the values:
if update then $
  cw_vector_set_value,parent,{min:v1,max:v2,n:n,log:log,units:units, $
                              nformat:nformat,format:format,uunits:0}

if update eq 0 then return,0 else $
  return,{CW_VECTOR_EVENT, id:parent,top:event.top,handler:0l}
end

;-cw_vector-------------------------------------------------------------------

function cw_vector,parent,uvalue=uval,font=font, $
           frame=frame,title=title,  $
           xsize=xsize,nxsize=nxsize,ysize=ysize, $
           value=value,minn=minn, $
           minrange=minrange,maxrange=maxrange, $
           no_return=no_return

if n_elements(value) ne 1 then $
  value={min:0.,max:0.,n:1,log:0,units:'',nformat:'',format:'',uunits:0}

if (n_params() ne 1) then message,'usage - widget_id=cw_vector(parent)'

on_error, 2

if n_elements(uval) ne 1 then uval=0
if n_elements(font) ne 1 then font=''
if n_elements(xsize) ne 1 then xsize=0
if n_elements(nxsize) ne 1 then nxsize=0
if n_elements(ysize) ne 1 then ysize=1
;; get xmin and xmax values using machar:
cm=check_math(0,1)
ma=machar()
if n_elements(minn) ne 1 then minn=1
if n_elements(minrange) ne 1 then minrange=-ma.xmax
if n_elements(maxrange) ne 1 then maxrange=ma.xmax

state={units:value.units, $
       format:value.format, $
       nformat:value.nformat, $
       minn:minn, $
       minrange:minrange, $
       maxrange:maxrange, $
       title:0l,  $
       row1:0l, $
       row2:0l, $
       n:0l, $
       base:0l, $
       row3:0l, $
       value:0l, $
       min1:0l, $
       unit:0l, $
       row4:0l, $
       from:0l, $
       min:0l, $
       to:0l, $
       max:0l, $
       unitp:0l, $
       log:0l, $
       inc_base:0l, $
       inc:0l, $
       no_return:keyword_set(no_return)}

mainbase=widget_base(parent,uvalue=uval,frame=keyword_set(frame),/column, $
                     event_func="cw_vector_event", $
                     func_get_value="cw_vector_get_value", $
                     pro_set_value="cw_vector_set_value")

if n_elements(title) eq 1 then $
  state.title=widget_label(mainbase,value=title,font=font,/align_left)

state.row1=widget_base(mainbase,/row)

state.row2=widget_base(state.row1,/row)
state.n=widget_text(state.row2,uvalue='n',font=font,/editable, $
                    xsize=nxsize,ysize=ysize, $
                    all_event=keyword_set(no_return))

state.base=widget_base(state.row1)

state.row3=widget_base(state.base,/row)
state.value=widget_label(state.row3,font=font,value='value:')
state.min1=widget_text(state.row3,uvalue='min1',font=font,/editable, $
                       xsize=xsize,ysize=ysize, $
                       all_event=keyword_set(no_return))
state.unit=widget_label(state.row3,font=font)

state.row4=widget_base(state.base,/row)
state.from=widget_label(state.row4,font=font,value='values, from')
state.min=widget_text(state.row4,uvalue='min',font=font,/editable, $
                      xsize=xsize,ysize=ysize, $
                      all_event=keyword_set(no_return))
state.to=widget_label(state.row4,font=font,value='to ')
state.max=widget_text(state.row4,uvalue='max',font=font,/editable, $
                      xsize=xsize,ysize=ysize, $
                      all_event=keyword_set(no_return))
state.unitp=widget_label(state.row4,font=font)
state.log=widget_droplist(state.row4,uvalue='log',font=font)
state.inc_base=widget_base(state.row4,/row)
state.inc=widget_text(state.inc_base,uvalue='inc',font=font,/editable, $
                      xsize=xsize,ysize=ysize, $
                      all_event=keyword_set(no_return))

;; stash state into first child widget:
widget_control,widget_info(mainbase,/child),set_uvalue=state,/no_copy

cw_vector_set_value,mainbase,value

return,mainbase
end