; $Id: dm_dialog_listinput.pro,v 1.4 2005/02/07 20:03:58 qiuym Exp $
;#######################################################################
;
; NAME:
;  dm_dialog_listinput
;
; PURPOSE:
;  a dialog input for data lists
;
; CATEGORY:
;  general
;
; AUTHOR:
;  Yiming Qiu
;  NIST Center for Neutron Research
;  100 Bureau Drive, Gaithersburg, MD 20899-8562
;  United States
;  yiming.qiu@nist.gov
;  Feb, 2005
;
; 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 or if the code in this file is
;  included in another product.
;
;#######################################################################

pro dm_dialog_listinput_Exit,tlb,tmp=tmp
    ;do nothing, leave the job to obj_destroy
end

;widget event handler
pro dm_dialog_listinput_event,event
    widget_control,event.handler,get_uvalue=self
    if obj_valid(self) then self->event,event
end

;object event handler
pro dm_dialog_listinput::event, event
    compile_opt IDL2    ;,strictarrsubs
                        ;idl2=defint32,strictarr
                        ;strictarr:   [] to index array
                        ;strictarrsubs: error when out-of-range indices,IDL5.6 or after
    widget_control,/hourglass
    ;error handling
    catch, anyerror
    if anyerror ne 0 then begin
       catch,/cancel
       ok = dialog_message(!error_state.msg,/error)
       return
    end
    ;make the dialog window always on top of the screen
    if tag_names(event, /STRUCTURE_NAME) eq 'WIDGET_KBRD_FOCUS' then begin
        if event.id eq self.tlb then self->totop
    endif
    eventname = widget_info(event.id,/uname)
    eventname = strlowcase(eventname[0])
    case eventname of
       'input':begin
            widget_control,event.id,get_value=tmp
            if self.type eq 0 then begin
                if finite(dm_to_number(tmp[event.y])) then $
                    (*self.value)[event.y]=tmp[event.y] $
                else begin
                    ok = dialog_message('The value entered is not a valid number.',/error,dialog_parent=self.tlb)
                    widget_control,event.id,/use_table_select,set_value=(*self.value)[event.y]
                    event.y = event.y-1
                endelse
            endif else $
                (*self.value)[event.y]=tmp[event.y]
            widget_control,event.id,edit_cell=[(event.y+1) mod self.n_item,event.x]
            end
       'ok':begin
            widget_control,self.tlb,/destroy
            return
            end
       'reset':begin
            if strlen(self.reset) ne 0 then $
                (*self.value)[*] = self.reset $
            else $
                (*self.value) = (*self.default)
            input = widget_info(self.tlb,find_by_uname='input')
            widget_control,input,set_value=reform(*self.value,1,self.n_item)
            end
       'read':begin
            file = dm_choose_file('txt',/read,dialog_parent=self.tlb)
            openr,unit,file,/get_lun,error=openerr
            if openerr ne 0 then begin
                ok=dialog_message("Can't read "+detfile+'.',/error)
                break
            endif
            tmp = ''
            sep = string('A4'xb)
            if self.type eq 0 then sep=sep+' ,'+ string(9b)
            while not eof(unit) do begin
                readf,unit,tmp
                tmp1 = strsplit(tmp,sep,/extract)
                if n_elements(tmp1) ge 2 then tmp1=tmp1[0:1]
                if n_elements(in) eq 0 then in=tmp1 else in=[[in],[tmp1]]
            endwhile
            free_lun,unit
            if n_elements(in) ne 0 then begin
                in  = reform(in)
                in_size = size(in,/dimension)
                n_dim   = n_elements(in_size)
                if (n_dim ge 2) and (ptr_valid(self.xvalue)) and (n_elements(in) gt 2) then begin
                    in  = float(in)
                    ind = sort(in[0,*])
                    in  = in[*,ind]
                    (*self.value)[*] = dm_to_string(interpol(in[1,*],in[0,*],(*self.xvalue)))
                endif else begin
                    if n_dim ge 2 then begin
                      for i=0,(self.n_item-1)<(in_size[1]-1) do $
                        (*self.value)[i] = in[1,i]
                    endif else begin
                      for i=0,(self.n_item-1)<(in_size[0]-1) do $
                        (*self.value)[i] = in[i]
                    endelse
                endelse
            endif
            input = widget_info(self.tlb,find_by_uname='input')
            widget_control,input,set_value=reform(*self.value,1,self.n_item)
            end
       'save':begin
            file = dm_choose_file('txt',/write,dialog_parent=self.tlb)
            openw,unit,file,/get_lun,error=openerr
            if openerr ne 0 then begin
                ok=dialog_message("Can't write in "+detfile+'.',/error)
                break
            endif
            if ptr_valid(self.xvalue) then begin
                if self.type eq 0 then sep=string(9b) else sep=string('A4'xb)
                for i=0,self.n_item-1 do $
                    printf,unit,(*self.xvalue)[i]+sep+(*self.value)[i]
            endif else begin
                for i=0,self.n_item-1 do $
                    printf,unit,(*self.value)[i]
            endelse
            free_lun,unit
            end
       else:
    endcase
end

;get properties
pro dm_dialog_listinput::getproperty,value=value
    if arg_present(value) then begin
        value = *self.value
        if self.type eq 0 then value=dm_to_number(value)
        if self.n_item eq 1 then value=value[0]
    endif
end

pro dm_dialog_listinput::totop
    widget_control,self.tlb,kbrd_focus_event=0
    widget_control,self.tlb,/show,iconify=0
    wid = widget_info(self.tlb,find_by_uname='ok')
    if wid gt 0 then widget_control,wid,/input_focus
    widget_control,self.tlb,/kbrd_focus_event
end

;destroy the object,life cycle method
pro dm_dialog_listinput::Cleanup
    if widget_info(self.extbase,/valid_id) then widget_control,self.extbase,/destroy
    if widget_info(self.tlb,/valid_id) then widget_control,self.tlb,/destroy
    ptr_free,self.default,self.value,self.xvalue
end

;constructor,lifecycle method
;syntax:
;   obj=obj_new('dm_dialog_listinput','color',default=1,droplist_content=['red','blue','green'],is_droplist=[1],/return_number)
;parameter:
;   name:               a string array of names
;keyword:
;   default:            default value, or rather starting value
;   dialog_parent:      dialog parent, tlb will be centered on dialog parent
;   info:               informations to be shown at the bottom of tlb
;   label:              column label
;   reset:              reset value, scalor
;   title:              title of tlb
;   xsize:              xsize of the table column width
;   xvalue:             a number array assigned to name, when save, this value will also be saved
;                       when read, if present, this value will be used to locate the name(interpolation)
;                       if not present, read  will be done according to order
function dm_dialog_listinput::Init,name,label=label,default=default,dialog_parent=dialog_parent,info=info,$
    reset=reset,title=title,xsize=xsize,xvalue=xvalue

    self.type = 1     ;default type is string
    if n_elements(name)  eq 0 then name=''
    if n_elements(label) eq 0 then label=['Value'] else label=[label]
    self.n_item = n_elements(name)
    if n_elements(title) eq 0 then title='Input:'
    if n_elements(xsize) eq 0 then xsize=80
    if n_elements(reset) eq 1 then self.reset=dm_to_string(reset)
    if n_elements(default) ne 0 then begin
        type=size(default,/type)
        if type ne 7 then self.type=0
        mydefault = dm_to_string(default)
    endif else mydefault=''
    n_default  = n_elements(mydefault)
    self.value = ptr_new(strarr(self.n_item))
    if (n_elements(xvalue) eq self.n_item) and (size(xvalue,/type) ne 7) then $
        self.xvalue = ptr_new(dm_to_string(xvalue))
    for i=0,self.n_item-1 do (*self.value)[i]=mydefault[i mod n_default]
    self.default = ptr_new(*self.value)
    self.extbase = widget_base(group_leader=dialog_parent,map=0)
    tlb  = widget_base(title=title,/col,group_leader=self.extbase,/modal,/align_center)
    mesg = 'Press Return or Enter to insert a value.'
    void = widget_label(tlb,value=mesg,/align_center)
    row  = widget_base(tlb,/row,/align_center)
    if n_elements(name) eq 1 then name = [name]
    void = widget_table(row,row_labels=name,column_labels=label,/editable,uname='input',$
            value=reform(*self.value,1,self.n_item),y_scroll_size=(15<(self.n_item)),$
            x_scroll_size=1,column_widths=[xsize])
    n_info = n_elements(info)
    if n_info gt 0 then  begin
        col = widget_base(tlb,/col,/align_center)
        for i=0,n_info-1 do $
            label = widget_label(col,value=info[i],/align_left)
    endif
    row  = widget_base(tlb,/row,/align_center)
    void = widget_button(row,value='Save',uname='save')
    void = widget_label(row,value='',xsize=15)
    void = widget_button(row,value='Read',uname='read')
    void = widget_label(row,value='',xsize=15)
    void = widget_button(row,value='Reset',uname='reset')
    void = widget_label(row,value='',xsize=15)
    void = widget_button(row,value='OK',uname='ok')
    dm_center_kid,tlb,dialog_parent   ;centering over the dialog_parent widget
    widget_control,tlb,/realize
    self.tlb=tlb
    widget_control,tlb,set_uvalue=self,/kbrd_focus_event
    xmanager,'dm_dialog_listinput',tlb,cleanup='dm_dialog_listinput_Exit'
    return,1
end

;class definition
pro dm_dialog_listinput__define
    void={dm_dialog_listinput    , $    ;thie object class name
        extbase:               0L, $    ;group leader of the modal tlb
        tlb:                   0L, $    ;top level base
        n_item:                0s, $    ;number of items
        type:                  0s, $    ;data type 0:float 1:string
        reset:                 '', $    ;reset value
        default:        ptr_new(), $    ;default values for reset button
        value:          ptr_new(), $    ;save the results
        xvalue:         ptr_new()  $    ;save the identifying xvalue
    }
end

;example
;   result = dm_dialog_listinput(['item 0','item 1'],default=1,label='Factor',$
;               info=['The factor must be greater than 0','and less than 1'])
;   result = dm_dialog_listinput(['item 0','item 1'],default=['red','blue'],label='Color')
function dm_dialog_listinput,name,_ref_extra=extra
    tmp=obj_new('dm_dialog_listinput',name,_extra=extra)
    if obj_valid(tmp) then begin
        tmp->getproperty,value=value,_extra=extra
        obj_destroy,tmp
    endif
    if n_elements(value) ne 0 then return,value
end