; $Id: xviewer.pro,v 1.7 2005/02/09 13:44:56 dimeo Exp $
;###############################################################################
;
; NAME:
;  XVIEWER
;
; PURPOSE:
;  Mimics funcationality of the NCNR XPEAK program.
;
; CATEGORY:
;  DAVE, data visualization
;
; AUTHOR:
;   Robert M. Dimeo, Ph.D.
;   NIST Center for Neutron Research
;   100 Bureau Drive
;   Gaithersburg, MD 20899
;   Phone: (301) 975-8135
;   E-mail: robert.dimeo@nist.gov
;   http://www.ncnr.nist.gov/staff/dimeo
;
; LICENSE:
;  The software in this file is written by an employee of
;  National Institute of Standards and Technology
;  as part of the DAVE software project.
;
;  The DAVE software package is not subject to copyright protection
;  and is in the public domain. It should be considered as an
;  experimental neutron scattering data reduction, visualization, and
;  analysis system. As such, the authors assume no responsibility
;  whatsoever for its use, and make no guarantees, expressed or
;  implied, about its quality, reliability, or any other
;  characteristic. The use of certain trade names or commercial
;  products does not imply any endorsement of a particular product,
;  nor does it imply that the named product is necessarily the best
;  product for the stated purpose. We would appreciate acknowledgment
;  if the DAVE software is used of if the code in this file is
;  included in another product.
;
;###############################################################################
;+
;  NAME:
;        XVIEWER.PRO
;
;  PURPOSE:
;
;     This simple widget application mimics the functionality of the NCNR
;     program called XPEEK, a "real-time" data display for scan-type data
;     from instruments.
;
; AUTHOR:
;
;     Robert M. Dimeo, Ph.D.
;     NIST Center for Neutron Research
;     100 Bureau Drive
;     Gaithersburg, MD 20899
;     Phone: (301) 975-8135
;     E-mail: robert.dimeo@nist.gov
;     http://www.ncnr.nist.gov/staff/dimeo
;
;  CATEGORY:
;
;     Widgets
;
;  CALLING SEQUENCE:
;
;     IDL>  xviewer
;
;  INPUT PARAMETERS:
;
;     NONE
;
;  INPUT KEYWORDS:
;
;     NOTIFY_IDS: two-elements long integer array composed of the calling program's
;                 [event.id,event.top].
;     GROUP_LEADER:  group leader of the program, typically the calling programs's
;                 event.top
;
;  REQUIRED PROGRAMS:
;
;     Multiple programs from the DAVE suite including (but not limited to...
;        OPAN__DEFINE.PRO
;
;  COMMON BLOCKS:
;
;     NONE
;
;  RESTRICTIONS
;
;     This program will only work from within the NIST NCNR firewall.
;
;  MODIFICATION HISTORY:
;
;     Written by Rob Dimeo, October 21, 2003
;     10-22-03:   Added ability to modify the existing (persistent) DAVE
;                 pointer (RMD)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function xgaussian,x,area,center,width,bg
sig = width/2.354
return,(area/sqrt(2.0*!pi*sig^2))*exp(-0.5*((x-center)/sig)^2)+bg
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer_cleanup,tlb
widget_control,tlb,get_uvalue = pstate
wdelete,(*pstate).winpix
heap_free,(*pstate).davePtr
ptr_free,(*pstate).darray_ptr
ptr_free,(*pstate).dataptr
ptr_free,pstate
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function get_npts,s
; This function extracts the number of points that are supposed to be in the
; data file being read in.  This information is contained in the first line
; of the broadcast.
segs = strsplit(s,/extract)
npts_string = segs[2]
next_seg = strsplit(npts_string,/extract,'=')
if n_elements(next_seg) eq 2 then begin
   npts = fix((strsplit(npts_string,/extract,'='))[1])
endif else begin
   npts = fix(npts_string)
endelse
return,npts
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer_update_daveptr,event
widget_control,event.top,get_uvalue = pstate
if n_elements(*(*pstate).dataptr) eq 0 then return
; Fill up the dave pointer
widget_control,(*pstate).group_leader,get_uvalue = daveptr
dave_ptr = (*daveptr).daveptr

x = (*(*pstate).dataptr).x
xsort = sort(x)
x = x[xsort]
qty_size = size((*(*pstate).dataptr).y)
qty = transpose((*(*pstate).dataptr).y)
err = transpose((*(*pstate).dataptr).dy)
qty = qty[xsort,*]
err = err[xsort,*]
if qty_size[0] eq 1 then y = 0.0 else $
   y = findgen(qty_size[1])
; What are the currently selected menu items?
ind_drop_menu = widget_info(event.top,find_by_uname = 'IVAR_MENU')
dep_drop_menu = widget_info(event.top,find_by_uname = 'DVAR_MENU')
ind_list = show_sel_drop_menu_item(ind_drop_menu,UNAME = ind_uname)
dep_list = show_sel_drop_menu_item(dep_drop_menu,UNAME = dep_uname)

retval = create_dave_pointer(dave_ptr,$
      instrument = (*pstate).instrument,  $
      QTY = qty,                          $
      ERR = err,                          $
      XLABEL = ind_uname,                 $
      QTLABEL = dep_uname,                $
      YVALS = y,                          $
      XVALS = x,                          $
      XTYPE = 'POINTS',                   $
      YTYPE = 'POINTS',                   $
      TREATMENT = ['Data collected from instrument'])

end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer_process_bt1,event
widget_control,event.top,get_uvalue = pstate
x = (*(*pstate).dataptr).x
y = (*(*pstate).dataptr).y
dy = (*(*pstate).dataptr).dy
; Define the processing variables
scl = [  2.7,2.479,2.827,2.483,2.260,2.347,2.011,1.749,  $
         1.63,1.36,1.339,1.218,1.058,1.,1.054,0.953,     $
         0.941,0.985,1.031,1.021,0.982,1.011,0.9,1.118,  $
         0.955,1.056,0.973,0.974,0.943,0.877,0.872,0.82  ]

z_c = [  0.0,1.0,1.29,-0.48,1.53,-0.98,2.03,0.89,        $
         1.54,1.28,0.4,0.35,1.53,-1.57,0.63,1.43,        $
         -0.08,-0.01,-0.78,0.16,-1.08,-2.08,-1.23,-0.47, $
         0.43,-0.27,-2.6,0.88,-1.34,2.24,3.,4.           ]

ysize = size(y)
;ndet = ysize[1]
npts = ysize[1]
ndet = n_elements(scl)

udet = 1+bytarr(ndet) & upts = 1+bytarr(npts)

v = (scl#upts)*y
dv = (scl#upts)*dy

xmat = udet#x
angle = xmat+(5.0*((findgen(ndet))#upts))-(0.01*(z_c#upts))

asort = sort(angle)
n = n_elements(asort)
*(*pstate).dataptr = {  x:reform(angle,1,n),  $
                        y:reform(v,1,n),       $
                        dy:reform(dv,1,n)}
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function get_var_struct,   txt,  $
                           VALUES = values,  $
                           NAMES = names,    $
                           IVARNAMES = ivarnames,  $
                           IVARVALS = ivarvals

; See if the DATA field is made up of comma-delimited numbers
comma_position = strpos(txt,',')
if (comma_position)[0] ne (-1) then begin
   ; Ok we have a comma-delimited list for the DATA field.  Read in and parse
   ; the comma-delimited list.
   data_position = strpos(txt,'DATA=')
   timestamp_position = strpos(txt,'TIMESTAMP=')
   data_seg = fix(strsplit(strmid(txt,data_position+6, $
      -data_position-6+timestamp_position),',',/extract))
   timestamp = long(strmid(txt,timestamp_position+10))
   ; Now split up the input string into its individual elements and parse
   ; the variables
   first_segmentation = strsplit(txt,':',/extract)
   second_segmentation = strsplit(first_segmentation[1:*],'=',/extract)
   for i = 0,n_elements(second_segmentation)-1 do begin
    if i eq 0 then begin
         segs = strsplit(second_segmentation[i],/extract)
      endif else begin
         segs = [segs,strsplit(second_segmentation[i],/extract)]
      endelse
   endfor
   data_index = where(segs eq 'DATA')
   segs = segs[0:data_index-1]
endif else begin
   ; No comma-delimited list here....just read them in one-at-a-time
   first_segmentation = strsplit(txt,':',/extract)
   second_segmentation = strsplit(first_segmentation[1:*],'=',/extract)
   for i = 0,n_elements(second_segmentation)-1 do begin
    if i eq 0 then begin
         segs = strsplit(second_segmentation[i],/extract)
      endif else begin
         segs = [segs,strsplit(second_segmentation[i],/extract)]
      endelse
   endfor
endelse

names = segs[0:*:2]
values = float(segs[1:*:2])
; Get the independent variable information out
nvars = n_elements(names)
if (comma_position)[0] ne (-1) then begin
   ivarnames = names[0:nvars-1]
   ivarvals = values[0:nvars-1]
endif else begin
   ivarnames = names[0:nvars-3]
   ivarvals = values[0:nvars-3]
endelse
; Create an output data structure
p = create_struct(names[0],values[0])
for i = 1,n_elements(names)-1 do begin
   p = create_struct(p,names[i],values[i])
endfor
; If the DATA field was comma-delimited then we need to put in the
; DATA and TIMESTAMP by brute force.
if (comma_position)[0] ne (-1) then begin
   p = create_struct(p,'DATA',data_seg,'TIMESTAMP',timestamp)
   names = [names,'DATA','TIMESTAMP']
   values = [values,data_seg,timestamp]
endif
return,p
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer_get_data,event
widget_control,event.top,get_uvalue = pstate
(*pstate).counter = (*pstate).counter + 1L
time_out = 0.25
socket, unit, (*pstate).host, (*pstate).port, $
   /get_lun,read_timeout = time_out,error = err
printf,unit,'SubScribe '+(*pstate).instrument

ind_drop_menu = widget_info(event.top,find_by_uname = 'IVAR_MENU')
dep_drop_menu = widget_info(event.top,find_by_uname = 'DVAR_MENU')
s=""
catch,theError
if (theError ne 0) then begin
    catch,/cancel
    if n_elements(darray) ne 0 then begin
      *(*pstate).darray_ptr = darray[0:count]
      darray = darray[0:count]
      ivar_vals = ivar_vals[*,0:count]
      if (*pstate).counter eq 1L then begin
         ; Destroy the current list widget
         ret = destroy_drop_menu_items(ind_drop_menu)
         ret = destroy_drop_menu_items(dep_drop_menu)
         list = tag_names(darray[0])
         ; ...and create the new list widget
         ret = create_drop_menu_items(ind_drop_menu,list)
         ret = create_drop_menu_items(dep_drop_menu,list)
         ; Now check off some defaults
         if (*pstate).instrument eq 'BT1' then begin
            ret = set_menu_check_item(dep_drop_menu,sel = n_elements(list)-2) ; DATA
            ret = set_menu_check_item(ind_drop_menu,sel = 1)                  ; A04
         endif else begin
            ret = set_menu_check_item(dep_drop_menu,sel = n_elements(list)-2) ; DATA
            ret = set_menu_check_item(ind_drop_menu,sel = 0)                  ; PT
         endelse
      endif
    ; Which items are checked?
      ind_drop_select = show_sel_drop_menu_item(ind_drop_menu,uname = ind_uname)
      if ind_drop_select[0] eq '' then begin
         ;print,'Closing socket prematurely'
         close,unit
         free_lun,unit,/force
         return
      endif
      dep_drop_select = show_sel_drop_menu_item(dep_drop_menu,uname = dep_uname)
    ; Now fill up the native data structure based on the checked menu items
    ; and the contents of DARRAY
      tags = tag_names(darray[0])
      ind_index = where(tags eq ind_uname)
      dep_index = where(tags eq dep_uname)
      npts = n_elements(darray[*])
      if npts gt 1 then begin
         if (*pstate).instrument eq 'BT0' then dy = 0.1+fltarr(npts)
         if (*pstate).instrument eq 'BT1' then begin

            x = darray[*].(1)
            y = darray[*].(5)
            dy = sqrt(y)
            *(*pstate).dataptr = {x:x,y:y,dy:dy}
            xviewer_process_bt1,event
            data = (*(*pstate).dataptr).y
            dy = (*(*pstate).dataptr).dy
            x = (*(*pstate).dataptr).x
            npts = n_elements(x)
            *(*pstate).dataptr = {  x:reform(x,1,npts),  $
                                    y:reform(data,1,npts), $
                                    dy:reform(dy,1,npts)}
            (*pstate).xlabel = 'A04'
            (*pstate).ylabel = 'DATA'
         endif else begin
            *(*pstate).dataptr = {  x:reform(darray[*].(ind_index[0]),1,npts),  $
                                    y:reform(darray[*].(dep_index[0]),1,npts), $
                                    dy:reform(sqrt(darray[*].(dep_index[0])),1,npts)}
            (*pstate).xlabel = ind_uname[0]
            (*pstate).ylabel = dep_uname[0]
         endelse
      endif
    endif
    close,unit
    free_lun,unit,/force
    xviewer_update_daveptr,event
    return
endif

;READ IN FIRST LINE
readf,unit,s
segs = strsplit(s,/extract)
; Is there a start line?
if (strpos(s,'START'))[0] ne -1 then begin   ; There is a START line
   npts = get_npts(s)
   ; Get the filename out
   filetext = sep[3]
   (*pstate).file_name = (strsplit(filetext,'=',/extract))[1]
   readf,unit,s
endif else begin  ; There is no START line
   npts = 250

endelse
i = 0
count = 0
d = get_var_struct(s,IVARNAMES = ivarnames,IVARVALS = ivarvals)
num_ivars = n_elements(ivarnames)
ivar_vals = fltarr(num_ivars,npts)
ivar_vals[*,0] = ivarvals
darray = replicate(d,npts)
darray[0] = d
i = i+1
while (i le npts-1) do begin
   readf,unit,s
   d = get_var_struct(s,IVARVALS = ivarvals)
   ivar_vals[*,i] = ivarvals[*]
   darray[i] = d
   count = i
   i = i + 1
endwhile
darray = darray[0:count]


      darray = darray[0:count]
      *(*pstate).darray_ptr = darray
      ivar_vals = ivar_vals[*,0:count]
      if (*pstate).counter eq 1L then begin
         ; Destroy the current list widget
         ret = destroy_drop_menu_items(ind_drop_menu)
         ret = destroy_drop_menu_items(dep_drop_menu)
         list = tag_names(darray[0])
         ; ...and create the new list widget
         ret = create_drop_menu_items(ind_drop_menu,list)
         ret = create_drop_menu_items(dep_drop_menu,list)
         ; Now check off some defaults
         if (*pstate).instrument eq 'BT1' then begin
            ret = set_menu_check_item(dep_drop_menu,sel = n_elements(list)-2) ; DATA
            ret = set_menu_check_item(ind_drop_menu,sel = 1)                  ; PT
         endif else begin
            ret = set_menu_check_item(dep_drop_menu,sel = n_elements(list)-2) ; DATA
            ret = set_menu_check_item(ind_drop_menu,sel = 0)                  ; PT
         endelse
      endif
    ; Which items are checked?
      ind_drop_select = show_sel_drop_menu_item(ind_drop_menu,uname = ind_uname)
      dep_drop_select = show_sel_drop_menu_item(dep_drop_menu,uname = dep_uname)
    ; Now fill up the native data structure based on the checked menu items
    ; and the contents of DARRAY
      tags = tag_names(darray[0])
      ind_index = where(tags eq ind_uname)
      dep_index = where(tags eq dep_uname)
      npts = n_elements(darray[*])

         if (*pstate).instrument eq 'BT1' then begin
            x = darray[*].(1)
            y = darray[*].(5)
            dy = sqrt(y)
            *(*pstate).dataptr = {x:x,y:y,dy:dy}
            xviewer_process_bt1,event
            data = (*(*pstate).dataptr).y
            dy = (*(*pstate).dataptr).dy
            x = (*(*pstate).dataptr).x
            npts = n_elements(x)
            *(*pstate).dataptr = {  x:reform(x,1,npts),  $
                                    y:reform(data,1,npts), $
                                    dy:reform(dy,1,npts)}
            (*pstate).xlabel = 'A04'
            (*pstate).ylabel = 'DATA'
         endif else begin
            *(*pstate).dataptr = {  x:reform(darray[*].(ind_index[0]),1,npts),  $
                                    y:reform(darray[*].(dep_index[0]),1,npts), $
                                    dy:reform(sqrt(darray[*].(dep_index[0])),1,npts)}
            (*pstate).xlabel = ind_uname[0]
            (*pstate).ylabel = dep_uname[0]
         endelse

close,unit
free_lun,unit,/force
xviewer_update_daveptr,event
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer_get_data_old,event
widget_control,event.top,get_uvalue = pstate
catch,the_error
if the_error ne 0 then begin
   catch,/cancel
   if unit ne 0 then begin
      close,unit
      free_lun,unit,/force
   endif else begin
      strout = 'Host computer not available'
      void = dialog_message(dialog_parent = event.top,strout)
      return
   endelse
   if n_elements(i) eq 0 then begin
      print,'error with the data'
      return
   endif
   dy = sqrt(data)
   where_zero = where(data eq 0.0,count)
   if count gt 0 then dy[where_zero] = 1.0
   *(*pstate).dataptr = {x:x[0:i-1],y:data[*,0:i-1],dy:dy[*,0:i-1]}
;   *(*pstate).dataptr = {x:x,y:data,dy:dy}
   case (*pstate).instrument of
   'BT1':   $
      begin
         xviewer_process_bt1,event
         data = (*(*pstate).dataptr).y
         dy = (*(*pstate).dataptr).dy
         x = (*(*pstate).dataptr).x
      end
   else:
   endcase
   xviewer_update_daveptr,event
   slider_id = widget_info(event.top,find_by_uname = 'ANGLE')
   data_size = size(data,/dimension)
   if data_size[0] eq 1 then begin
      widget_control,slider_id,sensitive = 0
   endif else begin
      widget_control,slider_id,sensitive = 1
      widget_control,slider_id,set_slider_max = data_size[0]
   endelse
   xviewer_update,event
   return
endif
txt = ''
time_out = 0.25
socket, unit, (*pstate).host, (*pstate).port, $
   /get_lun,read_timeout = time_out,error = err
printf,unit,'SubScribe '+(*pstate).instrument
; Read the first line
readf,unit,txt
sep = strsplit(txt,/extract)
start = strpos(txt,'START')
if start[0] eq (-1) then begin
; The broadcast "dropped" the START line
   (*pstate).xlabel = 'INDEX'
   npts = 500
   filetext = 'Current run'
   (*pstate).file_name = filetext
   ; What are the field names?
   segs = strsplit(txt,'=',/extract)
   for i = 0,n_elements(segs)-1 do begin
      if i eq 0 then $
         these_segs = strsplit(segs[i],/extract) else $
         these_segs = [these_segs,strsplit(segs[i],/extract)]
   endfor
   start_pos = where(these_segs eq 'PT')+2
   end_pos = where(these_segs eq 'DATA')-1
   n = end_pos - start_pos + 1
   titles = these_segs[start_pos:end_pos:2]
   values = these_segs[start_pos-1:end_pos-1:2]
   (*pstate).xlabel = titles[0]
   sep_txt = sep

endif else begin
; There is a START line in the broadcast content
   (*pstate).xlabel = strmid(sep[4],5)
   if ((*pstate).xlabel eq 'ignore') or ((*pstate).xlabel eq '') then $
      (*pstate).xlabel = 'INDEX'
   npts = sep[2]
   filetext = sep[3]
   (*pstate).file_name = (strsplit(filetext,'=',/extract))[1]
; Read the second line to find out how long the line is
   readf,unit,txt
   sep_txt = strsplit(txt,/extract)
; New code here!
   segs = strsplit(txt,'=',/extract)
   for i = 0,n_elements(segs)-1 do begin
      if i eq 0 then $
         these_segs = strsplit(segs[i],/extract) else $
         these_segs = [these_segs,strsplit(segs[i],/extract)]
   endfor
   start_pos = where(these_segs eq 'PT')+2
   end_pos = where(these_segs eq 'DATA')-1
   n = end_pos - start_pos + 1
   titles = these_segs[start_pos:end_pos:2]
   var_id = widget_info(event.top,find_by_uname = 'VAR_MENU')
   for i = 0,n_elements(titles)-1 do begin
      void = widget_button(var_id,value = titles[i],uname = 'VAR_SELECT')
   endfor

   values = these_segs[start_pos-1:end_pos-1:2]
   (*pstate).xlabel = titles[0]
   sep_txt = sep

endelse

pos = strpos(txt,'DATA=')
endpos = strpos(txt,'TIMESTAMP')
line = strsplit(strmid(txt,pos+5,endpos-pos-5),',',/extract)
ndets = n_elements(line)
data = fltarr(ndets,npts)
x = fltarr(npts)
if (*pstate).xlabel ne 'INDEX' then begin
   ivar_index = (where(sep_txt eq (*pstate).xlabel+'=',count))[0] + 1
   x[0] = float(sep_txt[ivar_index])
endif else begin
   x[0] = 0
endelse
data[*,0] = float(line)
i = 1
while i lt npts-1 do begin
   readf,unit,txt
   pos = strpos(txt,'DATA=')
   endpos = strpos(txt,'TIMESTAMP')
   sep_txt = strsplit(txt,/extract)
   if (*pstate).xlabel ne 'INDEX' then begin
      ivar_index = (where(sep_txt eq (*pstate).xlabel+'=',count))[0] + 1
      x[i] = float(sep_txt[ivar_index])
   endif else begin
      x[i] = i
   endelse
   line = strsplit(strmid(txt,pos+5,endpos-pos-5),',',/extract)
   data[0:ndets-1,i] = float(line[0:ndets-1])
   i = i + 1
endwhile
where_zero = where(data eq 0.0,count)
dy = sqrt(data)
if count gt 0 then dy[where_zero] = 1.0
*(*pstate).dataptr = {x:x[0:i-1],y:data[*,0:i-1],dy:dy[*,0:i-1]}
case (*pstate).instrument of
   'BT1':   $
      begin
         xviewer_process_bt1,event
         data = (*(*pstate).dataptr).y
         dy = (*(*pstate).dataptr).dy
         x = (*(*pstate).dataptr).x
      end
   else:
endcase
xviewer_update_daveptr,event
slider_id = widget_info(event.top,find_by_uname = 'ANGLE')
data_size = size(data,/dimension)
if data_size[0] eq 1 then begin
      widget_control,slider_id,sensitive = 0
endif else begin
      widget_control,slider_id,sensitive = 1
      widget_control,slider_id,set_slider_max = data_size[0]
endelse
close,unit
free_lun,unit,/force
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer_start,event
widget_control,event.top,get_uvalue = pstate
ptr_free,(*pstate).dataptr
(*pstate).counter = 0L
(*pstate).dataptr = ptr_new(/allocate_heap)
(*pstate).loop = 1
; If there are any menu items then destroy them
ind_drop_menu = widget_info(event.top,find_by_uname = 'IVAR_MENU')
dep_drop_menu = widget_info(event.top,find_by_uname = 'DVAR_MENU')
ret = destroy_drop_menu_items(ind_drop_menu)
ret = destroy_drop_menu_items(dep_drop_menu)
widget_control,(*pstate).timer_id,timer = 0.01
pause_button = widget_info(event.top,find_by_uname = 'PAUSE')
widget_control,pause_button,set_value = 'Pause'
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer_pause,event
widget_control,event.top,get_uvalue = pstate
if n_elements(*(*pstate).dataptr) eq 0 then return
widget_control,event.id,get_value = val
if strupcase(val[0]) eq 'PAUSE' then begin
   (*pstate).loop = 0
   widget_control,event.top,/clear_events
   widget_control,event.id,set_value = 'Resume'
endif else begin
   (*pstate).loop = 1
   widget_control,event.id,set_value = 'Pause'
   widget_control,(*pstate).timer_id,timer = 0.1;(*pstate).duration
endelse
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer_update,event
widget_control,event.top,get_uvalue = pstate
catch,the_error
if the_error ne 0 then begin
   catch,/cancel
   print,'error plotting'
   return
endif
; Update the window with the new data...use pixmap for smooth updates (no flashing)
slider_id = widget_info(event.top,find_by_uname = 'ANGLE')
widget_control,slider_id,get_value = val & index = val[0] - 1
;index = 0
if n_elements(*(*pstate).dataptr) eq 0 then return
if n_elements((*(*pstate).dataptr).x) eq 0 then return

x = (*(*pstate).dataptr).x
y = (*(*pstate).dataptr).y[index,*]
dy = (*(*pstate).dataptr).dy[index,*]
if (*pstate).autoscale eq 1 then begin
   if n_elements(x) gt 1 then begin
      xmin = min(x,max = xmax)
      dx = (xmax-xmin)
      (*pstate).xrange = [xmin-0.2*dx,xmax+0.2*dx]
   endif else begin
      (*pstate).xrange = [min(x),max(x)]
   endelse
   (*pstate).yrange = [0.0,1.2*(max(y)+max(dy))]
endif
title = (*pstate).instrument+': '+(*pstate).file_name
wset,(*pstate).winpix
plot,[x],[y],psym = 4,xtitle = (*pstate).xlabel,ytitle = (*pstate).ylabel, $
      title = title,xrange = (*pstate).xrange,yrange = (*pstate).yrange,$
      /xsty,/ysty

errplot,[x],[y]-[dy],[y]+[dy],width = 0.0
wset,(*pstate).winvis
device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*pstate).winpix]
empty

end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer_resize,event
widget_control,event.top,get_uvalue = pstate
row_base = widget_info(event.top,find_by_uname = 'ROW_BASE')
row_geom = widget_info(row_base,/geometry)
new_xsize = event.x > 300
new_ysize = (event.y - row_geom.ysize) > 300
widget_control,(*pstate).win,draw_xsize = new_xsize,draw_ysize = new_ysize
wdelete,(*pstate).winpix
window,/free,/pixmap,xsize = new_xsize,ysize = new_ysize
(*pstate).winpix = !d.window
xviewer_update,event
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer_zoom_events,event
widget_control,event.top,get_uvalue = pstate
if n_elements(*(*pstate).dataptr) eq 0 then return
case event.type of
0: begin    ; button press
      (*pstate).mouse = event.press
      if (*pstate).mouse eq 4 then begin
         (*pstate).autoscale = 1
         xviewer_update,event
      endif
      if (*pstate).mouse eq 1 then begin
         (*pstate).xbox[0] = event.x
         (*pstate).ybox[0] = event.y
         xviewer_update,event
         empty
         (*pstate).autoscale = 0
         widget_control,(*pstate).win,/draw_motion_events
      endif
   end
1: begin ; button release
   if (*pstate).mouse eq 1 then begin
      xll = (*pstate).xbox[0] < (*pstate).xbox[1]
      yll = (*pstate).ybox[0] < (*pstate).ybox[1]
      w = abs((*pstate).xbox[1] - (*pstate).xbox[0])
      h = abs((*pstate).ybox[1] - (*pstate).ybox[0])
      xur = xll + w
      yur = yll + h
      ll = convert_coord(xll,yll,/device,/to_data)
      ur = convert_coord(xur,yur,/device,/to_data)
      (*pstate).xrange = [ll[0],ur[0]]
      (*pstate).yrange = [ll[1],ur[1]]
      xviewer_update,event
      (*pstate).mouse = 0B
      widget_control,(*pstate).win,draw_motion_events = 0
   endif
   if (*pstate).mouse eq 4 then begin
      xviewer_update,event
      (*pstate).mouse = 0B
      widget_control,(*pstate).win,draw_motion_events = 0
   endif
   end
2: begin ; mouse motion
      if (*pstate).mouse eq 1 then begin
         (*pstate).xbox[1] = event.x
         (*pstate).ybox[1] = event.y
         xc = [(*pstate).xbox[0],event.x,event.x, $
               (*pstate).xbox[0], $
               (*pstate).xbox[0]]
         yc = [(*pstate).ybox[0],(*pstate).ybox[0],$
               event.y,event.y,$
               (*pstate).ybox[0]]
         wset,(*pstate).winvis
         device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*pstate).winpix]
         plots,xc,yc,/device
         empty
      endif
   end
else:
endcase
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer_send_to_pan,event
widget_control,event.top,get_uvalue = pstate
if n_elements(*(*pstate).dataptr) eq 0 then return

thisEvent = tag_names(event,/structure_name)
case thisEvent of
'WIDGET_BUTTON': $
   begin
      pause_id = widget_info(event.top,find_by_uname = 'PAUSE')
      pseudo_event = {event,id:event.id,top:event.top,handler:0L,select:1}
      widget_control,pause_id,send_event = pseudo_event
   ; Get the DAVE pointer
      file_path = (*!dave_defaults).workDir
   ; Create a DAVE pointer
      x = (*(*pstate).dataptr).x
      xsort = sort(x)
      x = x[xsort]
      qty_size = size((*(*pstate).dataptr).y)
      qty = transpose((*(*pstate).dataptr).y)
      err = transpose((*(*pstate).dataptr).dy)
      qty = qty[xsort,*]
      err = err[xsort,*]
      if qty_size[0] eq 1 then y = 0.0 else $
         y = findgen(qty_size[1])
      ; What are the currently selected menu items?
      ind_drop_menu = widget_info(event.top,find_by_uname = 'IVAR_MENU')
      dep_drop_menu = widget_info(event.top,find_by_uname = 'DVAR_MENU')
      ind_list = show_sel_drop_menu_item(ind_drop_menu,UNAME = ind_uname)
      dep_list = show_sel_drop_menu_item(dep_drop_menu,UNAME = dep_uname)
   RET_VAL = CREATE_DAVE_POINTER(   thisPTR,          $
                  INSTRUMENT = (*pstate).instrument,  $
                  QTY = qty,                          $
                  ERR = err,                          $
                  XLABEL = ind_uname,                 $
                  QTLABEL = dep_uname,                $
                  YVALS = y,                          $
                  XVALS = x,                          $
                  XTYPE = 'POINTS',                   $
                  YTYPE = 'POINTS',                   $
                  TREATMENT = ['Data collected from instrument'])
      (*pstate).davePtr = thisPtr
      o = obj_new('opan',notifyId = [event.id,event.top], $
                         group_leader = event.top, $
                        davePtr = thisPtr, $
                        workDir = file_path, $
                        dataDir = file_path)
    ;(*(*pState).extraPtr).panInfo.panContainer->add,o
   end
'OPANEVENT': $
  begin
    obj = event.object  ; This is the object that just quit
;    (*(*pState).extraPtr).panInfo.panContainer->remove,obj
   obj_destroy,obj
   heap_free,(*pstate).davePtr
   (*pstate).davePtr = ptr_new(/allocate_heap)
  end
else:
endcase

end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer_event,event
; Main event handler/dispatcher for application.
widget_control,event.top,get_uvalue = pstate

if (tag_names(event,/structure_name) eq 'WIDGET_TIMER') and $
   (*pstate).loop then begin
   widget_control,(*pstate).timer_id,timer = (*pstate).duration
   xviewer_get_data,event
   xviewer_update,event
   return
endif
if (tag_names(event,/structure_name) eq 'WIDGET_BASE') then $
   xviewer_resize,event
uname = widget_info(event.id,/uname)
case uname of
'INSTRUMENT':  $
   begin
      widget_control,event.id,get_value = val
      (*pstate).instrument = val[0]
      xviewer_start,event
   end
'PLOT_WINDOW': xviewer_zoom_events,event
'ANGLE':       xviewer_update,event
'START':       xviewer_start,event
'PAUSE':       xviewer_pause,event
'PAN':         xviewer_send_to_pan,event
'EXIT':        widget_control,event.top,/destroy
else: $
   begin
      if not widget_info(event.id,/valid_id) then return
      if not widget_info(widget_info(event.id,/parent),/valid_id) then return
      parent_uname = widget_info(widget_info(event.id,/parent),/uname)
      case parent_uname of
      'IVAR_MENU':   $
         begin
            if (*pstate).instrument eq 'BT1' then return
            ind_drop_menu = widget_info(event.top,find_by_uname = 'IVAR_MENU')
            list_items = get_list_items(ind_drop_menu,IDS = ids,UNAMES = ind_unames)
            which_ind_menu_item = where(ind_unames eq uname,count_ind)
            if count_ind eq 1 then begin
               ret = set_menu_check_item(ind_drop_menu,sel = which_ind_menu_item[0])
            endif
            ind_drop_select = show_sel_drop_menu_item(ind_drop_menu,uname = ind_uname)
            darray = *(*pstate).darray_ptr
            tags = tag_names(darray[0])
            ind_index = where(tags eq ind_uname)
            npts = n_elements(darray[*])
            (*(*pstate).dataptr).x = reform(darray[*].(ind_index[0]),1,npts)
            (*pstate).xlabel = ind_uname[0]
         end
      'DVAR_MENU':   $
         begin
            if (*pstate).instrument eq 'BT1' then return
            dep_drop_menu = widget_info(event.top,find_by_uname = 'DVAR_MENU')
            list_items = get_list_items(dep_drop_menu,IDS = ids,UNAMES = dep_unames)
            which_menu_item = where(dep_unames eq uname,count_dep)
            if count_dep eq 1 then begin
               ret = set_menu_check_item(dep_drop_menu,sel = which_menu_item[0])
            endif
            dep_drop_select = show_sel_drop_menu_item(dep_drop_menu,uname = dep_uname)
            darray = *(*pstate).darray_ptr
            tags = tag_names(darray[0])
            dep_index = where(tags eq dep_uname)
            npts = n_elements(darray[*])
            (*(*pstate).dataptr).y = reform(darray[*].(dep_index[0]),1,npts)
            (*(*pstate).dataptr).dy = reform(0.0*findgen(npts),1,npts)
            (*pstate).ylabel = dep_uname[0]
         end
      else:
      endcase
      xviewer_update,event
   end
endcase
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro xviewer,notify_ids = notify_ids,group_leader = group_leader
if n_elements(notify_ids) eq 0 then notify_ids = 0L
if n_elements(group_leader) eq 0 then group_leader = 0L
; Widget definition module
tlb = widget_base(title = 'DAVE PEEK',/tlb_size_events,/col, $
   uname = 'RESIZE',mbar = bar,group_leader = group_leader)
c100 = widget_button(bar,value = 'C-100',/menu)
if lmgr(/runtime) then sens = 0 else sens = 1
bt1 = widget_button(c100,value = 'BT0',uname = 'INSTRUMENT',sensitive = sens)
bt1 = widget_button(c100,value = 'BT1',uname = 'INSTRUMENT');,sensitive = 0)
bt2 = widget_button(c100,value = 'BT2',uname = 'INSTRUMENT')
bt4 = widget_button(c100,value = 'BT4',uname = 'INSTRUMENT')
bt7 = widget_button(c100,value = 'BT7',uname = 'INSTRUMENT', $
   sensitive = 0)
bt9 = widget_button(c100,value = 'BT9',uname = 'INSTRUMENT')
g100 = widget_button(bar,value = 'Guide Hall',/menu)
ng1 = widget_button(g100,value = 'NG1',uname = 'INSTRUMENT')
ng5 = widget_button(g100,value = 'NG5',uname = 'INSTRUMENT')
ng7 = widget_button(g100,value = 'NG7',uname = 'INSTRUMENT',sensitive = 0)
ivar_select = widget_button(bar,value = 'Independent Variable',/menu,uname = 'IVAR_MENU')
dvar_select = widget_button(bar,value = 'Dependent Variable',/menu,uname = 'DVAR_MENU')
xsize = 500 & ysize = 400
host ='www-i.ncnr.nist.gov'
port = 1010
win = widget_draw(tlb,xsize = xsize,ysize = ysize,uname = 'PLOT_WINDOW',/button_events)
row_base = widget_base(tlb,/row,uname = 'ROW_BASE')
col_base = widget_base(row_base,/row)
void = widget_button(col_base,value = 'Pause',uname = 'PAUSE',/dynamic_resize)
void = widget_button(col_base,value = 'DATA->PAN',uname = 'PAN',/dynamic_resize)
;nonex_base = widget_base(col_base,/nonexclusive,/frame)
;dave_data = widget_button(nonex_base,value = 'DATA->DAVE',uname = 'SEND_TO_DAVE')
void = widget_button(col_base,value = 'Exit',uname = 'EXIT')
slider_id = widget_slider(row_base,title = 'Group (detector)',value = 1,min = 1,   $
   max = 2,uname = 'ANGLE')
centertlb,tlb
widget_control,tlb,/realize
widget_control,bt1,/set_button
;widget_control,dave_data,/set_button
widget_control,win,get_value = winvis
window,/free,/pixmap,xsize = xsize,ysize = ysize
winpix = !d.window

state =  {  winvis:winvis,                      $
            winpix:winpix,                      $
            win:win,                            $
            notify_ids:notify_ids,              $
            davePtr:ptr_new(/allocate_heap),    $
            group_leader:group_leader,          $
            autoscale:1,                        $
            xbox:fltarr(2),                     $
            ybox:fltarr(2),                     $
            mouse:0B,                           $
            xrange:fltarr(2),                   $
            yrange:fltarr(2),                   $
            timer_id:col_base,                  $
            port:port,                          $
            host:host,                          $
            duration:5.0,                      $
            counter:0L,                         $
            xlabel:'',                          $
            ylabel:'',                          $
            file_name:'',                       $
            instrument:'BT1',                   $
            dataptr:ptr_new(/allocate_heap),    $
            darray_ptr:ptr_new(/allocate_heap), $
            loop:0                              }

pstate = ptr_new(state,/no_copy)
widget_control,tlb,set_uvalue = pstate
xmanager,'xviewer',tlb,/no_block,event_handler = 'xviewer_event', $
   cleanup = 'xviewer_cleanup'
end
