; $Id: binary_template.pro,v 1.45 2004/06/30 21:58:44 chris Exp $ ; ; Copyright (c) 1999-2004, Research Systems, Inc. All rights reserved. ; Unauthorized reproduction prohibited. ;+ ; NAME: ; BINARY_TEMPLATE ; ; PURPOSE: ; Generate a "template" structure that describes a binary file. ; ; CATEGORY: ; Input/Output. ; ; CALLING SEQUENCE: ; template = BINARY_TEMPLATE( [file] ) ; ; INPUTS: ; FILE: A string indicating a sample data file that will be used ; to test the validity of user input "on the fly" as the ; user interacts with Binary_Template's GUI. The file ; should contain the kind of data for which a template ; is being defined. As the user specifies fields via ; Binary_Template's GUI, Binary_Template attempts to ; read this file "behind the scenes" using the user's ; specifications. If errors occur during such a test ; read, Binary_Template displays a Dialog_Message ; indicating where in the user's specifications ; a correction may be required. ; ; Default: if FILE is not supplied, binary_template will ; prompt the user for a file via DIALOG_PICKFILE. ; ; INPUT KEYWORD PARAMETERS: ; TEMPLATE: An initial template structure. ; ; GROUP_LEADER: The widget ID of a widget that calls Binary_Template. ; When this ID is specified, a death of the caller results in a ; death of Binary_Template. ; ; N_ROWS: Specifies the YSIZE of Binary_Template's WIDGET_TABLE. ; ; OUTPUT KEYWORD PARAMETERS: ; CANCEL: Set to 1 if the user clicked cancel, else set to 0. ; ; OUTPUTS: ; Function Binary_Template normally returns an anonymous structure. ; If the user cancels Binary_Template and no initial template was ; supplied the function returns zero. If the user cancels ; Binary_Template and an initial template was supplied (via ; the TEMPLATE keyword), the initial template is returned. ; ; EXAMPLE: ; datafile = filepath('hurric.dat', subdir=['examples', 'data']) ; ; ; ;Use Binary_Template to interactively define a 440x340 field ; ;of type BYTE, named "img". ; ; ; template = binary_template(datafile) ; ; ; ;Use the resulting template to read a file. ; ; ; data = read_binary(datafile, template=template) ; ; ; ;Display results. ; ; ; tvscl, data.img ; ; MODIFICATION HISTORY ; PCS, 6/1999 - Written. ; ;- ; @rb_routines function bt_typecode, wDroplist compile_opt hidden widget_control, wDroplist, get_uvalue=typecodes return, typecodes[ $ widget_info(wDroplist, /droplist_select) $ ] end ;-------------------------------------------------------------------- pro bt_purge_non_digits, event compile_opt hidden ; ;Purge charaters from EVENT.ID text widget that are not one ;of the ten digits 0-9. ; widget_control, event.id, get_value=current_str current_str = current_str[0] if current_str eq '' then $ return on_ioerror, set_str_to_null if 1 then begin str = strcompress( $ abs(long64(current_str)), $ /remove_all $ ) endif else begin set_str_to_null: str = '' message, /reset endelse on_ioerror, NULL if tag_names(event, /structure_name) ne '' then begin if str ne current_str then begin widget_control, event.id, get_uvalue=previous_str if n_elements(previous_str) gt 0 then $ widget_control, event.id, set_value=previous_str $ else $ widget_control, event.id, set_value='' case event.type of 0: offset = event.offset - 1 1: offset = event.offset $ - strlen(event.str) $ - 1 ; correct? 2: offset = 1 endcase widget_control, event.id, set_text_select=offset endif endif else begin widget_control, event.id, set_value=str endelse widget_control, event.id, get_value=current_str widget_control, event.id, set_uvalue=current_str end ;-------------------------------------------------------------------- function bt_entry_is_valid, $ bt_state, $ ; IN: program information structure. msg=bt_msg ; OUT: error message string or 'Entry is valid.' compile_opt hidden ; ;Purpose: Return 1 if the field currently being edited has satisfactory ;values. ; ;Note: variable names in this routine start with "bt_". This is a ;naming convention to help avoid clashing with user specified ;field names. The letters "bt_" stand for "Binary_Template", ; if keyword_set(bt_state.debug) then begin on_error, 0 endif else begin catch, bt_error_status if bt_error_status ne 0 then begin catch, /cancel if n_elements(bt_lun) gt 0 then $ free_lun, bt_lun bt_msg = [ $ 'Could not validate entry.', $ 'Internal error message was:', $ ' ' + !error_state.msg_prefix + !error_state.msg $ ] return, 0 endif endelse ; This will supersede the CATCH above. ON_IOERROR, ioErr ; Assume failure. bt_msg = 'Entry is invalid.' bt_num_dims = widget_info(bt_state.wNumDims, /droplist_select) for bt_i=0,bt_state.max_idl_dims-1 do begin widget_control, bt_state.wDimText[bt_i], get_value=bt_single_str if bt_single_str[0] eq '' and bt_i lt bt_num_dims then begin bt_msg = 'Size of ' + ([ $ '1st', '2nd', '3rd', '4th', '5th', '6th', '7th', '8th' $ ])[bt_i] + ' dimension is unspecified.' return, 0 end if bt_i eq 0 then $ bt_arr_str = bt_single_str $ else $ bt_arr_str = [bt_arr_str, bt_single_str] endfor widget_control, bt_state.wOffset, get_value=bt_offset_str widget_control, bt_state.wFieldName, get_value=bt_field_name_str ; Replace fieldName with a valid version (spaces->underscores, etc.) bt_field_name_str = IDL_VALIDNAME(bt_field_name_str[0], /CONVERT_ALL) widget_control, bt_state.wFieldName, set_value=bt_field_name_str widget_control, bt_state.wVerifyText, get_value=bt_verify_str bt_offset_str = bt_offset_str[0] bt_field_name_str = bt_field_name_str[0] bt_verify_str = bt_verify_str[0] if bt_field_name_str eq ''then begin bt_msg = 'Field name is empty.' return, 0 endif if strpos(strupcase(bt_field_name_str), 'RB_') ne -1 $ || strpos(strupcase(bt_field_name_str), 'BT_') ne -1 then begin bt_msg = [ $ 'Names that contain "bt_" or "rb_" are reserved for', $ 'internal use by BINARY_TEMPLATE and READ_BINARY. Please', $ 'specify a different field name.' $ ] return, 0 endif ; ;See if there is already a field with this name specified. ; if bt_state.fieldcount gt 0 then begin bt_indx = where( $ strupcase(bt_field_name_str) eq strupcase(*bt_state.pNames), $ bt_count $ ) if bt_count gt 0 then begin if bt_state.we_are_inserting then begin bt_msg = 'Another field has the same name.' return, 0 endif else begin if bt_indx[0] ne bt_state.current_field_indx then begin bt_msg = 'Another field has the same name.' return, 0 endif endelse endif endif bt_dims_str = rb_dim_str(bt_arr_str, bt_num_dims) widget_control, bt_state.wAbsoluteRadio, get_value=bt_offset_is_relative widget_control, bt_state.wVerifyCheckbox, get_value=bt_do_verify ;***************************************************************** ; Important note: ; Since this code can create variables with user-defined names, ; you *must* prefix all local variables below this point ; with either rb_ or bt_. These prefixes are reserved for ; use by binary_template and read_binary, and are assumed ; to be "safe". Other variable names should not be used. ; if bt_state.filename eq '' then begin ; ; Check user's offset syntax. ; ; Strip off leading > or < if necessary. rb_offset = bt_offset_str rb_firstChar = STRMID(rb_offset, 0, 1) if (rb_firstChar eq '>' || rb_firstChar eq '<') then $ rb_offset = STRMID(rb_offset, 1) MESSAGE, /RESET ; clear !error_state if (bt_state.useExecute) then $ rb_void = EXECUTE('rb_void = ' + rb_offset, 1) if ~RB_EXPRESSION_IS_VALID('OFFSET', rb_offset, $ bt_field_name_str, RB_MSG=bt_msg) then return, 0 ; ; Check user's dimensions syntax. ; MESSAGE, /RESET ; clear !error_state if (bt_state.useExecute) then $ rb_void = EXECUTE('rb_void = ' + bt_dims_str, 1) if ~RB_EXPRESSION_IS_VALID('DIMENSION', bt_dims_str, $ bt_field_name_str, RB_MSG=bt_msg) then $ return, 0 ; ; Check user's verify value syntax. ; if keyword_set(bt_do_verify) then begin MESSAGE, /RESET ; clear !error_state if (bt_state.useExecute) then $ rb_void = EXECUTE('rb_void = ' + bt_verify_str, 1) if ~RB_EXPRESSION_IS_VALID('VERIFY', bt_verify_str, $ bt_field_name_str, RB_MSG=bt_msg) then $ return, 0 endif endif else begin ; have a filename get_lun, bt_lun openr, bt_lun, bt_state.filename bt_varnames = '' if bt_state.fieldcount gt 0 then begin bt_varnames = strcompress(*bt_state.pNames, /remove_all) bt_nfield = bt_state.current_field_indx + 1 - (bt_state.we_are_inserting eq 0) ; If we can't use execute, we need to cache the data ; for each field within a pointer. if (~bt_state.useExecute) then $ bt_pAlldata = PTRARR(bt_nfield) for bt_i=0, bt_nfield-1 do begin ; Construct result array. if (*bt_state.pNumDims)[bt_i] eq 0 then begin ; Scalar. bt_tempvar = FIX(0, TYPE=(*bt_state.pTypecodes)[bt_i]) endif else begin ; Array if (bt_state.useExecute) then begin bt_str = 'bt_dimension = ULONG64(' + $ rb_dim_str((*bt_state.pDimensions)[bt_i, *], $ (*bt_state.pNumDims)[bt_i]) + ')' if ~execute(bt_str, 1) then begin message, /info, 'Error executing string: ' + bt_str message, !error_state.msg endif endif else begin bt_nd = N_ELEMENTS((*bt_state.pDimensions)[bt_i, *]) bt_dimension = ULON64ARR(bt_nd) ; Loop thru all dimension strings and either do a simple ; cast to an unsigned integer, or see if the dimension ; string matches a variable that has just been read in. for bt_j = 0, bt_nd-1 do begin bt_dim_string = (*bt_state.pDimensions)[bt_i, bt_j] ; See if our string matches a var name. bt_match = (WHERE(STRCMP(bt_varnames, bt_dim_string, $ /FOLD_CASE)))[0] if (bt_match ge 0) then begin if (bt_match ge bt_i) then $ MESSAGE, 'Variable has not been read: ' + $ bt_varnames[bt_match] bt_dimension[bt_j] = ULONG64((*bt_pAlldata[bt_match])[0]) endif else begin ; Just try to cast the string to an integer. bt_dimension[bt_j] = ULONG64(bt_dim_string) endelse endfor bt_dimension >= 1 ; 0 --> 1 endelse bt_tempvar = MAKE_ARRAY(DIMENSION=bt_dimension, $ TYPE=(*bt_state.pTypecodes)[bt_i]) endelse ; Construct offset. bt_offset = (*bt_state.pOffsets)[bt_i] bt_firstChar = STRMID(bt_offset, 0, 1) if ((bt_firstChar eq '>') || (bt_firstChar eq '<')) then $ bt_offset = STRMID(bt_offset, 1) if (bt_state.useExecute) then begin ; Must be a signed int in case offset is negative. bt_str = 'bt_offset = LONG64(' + bt_offset + ')' if ~execute(bt_str, 1) then begin message, /info, 'Error executing string: ' + bt_str message, !error_state.msg endif endif else begin ; See if our string matches a var name. bt_match = (WHERE(STRCMP(bt_varnames, bt_offset, /FOLD_CASE)))[0] if (bt_match ge 0) then begin if (bt_match ge bt_i) then $ MESSAGE, 'Variable has not been read: ' + $ bt_varnames[bt_match] bt_offset = LONG64((*bt_pAlldata[bt_match])[0]) endif else begin ; Just try to cast the string to an integer. bt_offset = LONG64(bt_offset) endelse endelse ; See if relative offset. if (~(*bt_state.pAbsoluteflags)[bt_i]) then begin point_lun, -bt_lun, bt_pos ; Get the current position. bt_offset = (bt_firstChar ne '<') ? $ bt_pos + bt_offset : ((bt_pos - bt_offset) > 0) endif point_lun, bt_lun, bt_offset readu, bt_lun, bt_tempvar case strupcase(bt_state.endian) of 'LITTLE': SWAP_ENDIAN_INPLACE, bt_tempvar, /SWAP_IF_BIG_ENDIAN 'BIG': SWAP_ENDIAN_INPLACE, bt_tempvar, /SWAP_IF_LITTLE_ENDIAN else: endcase ; Change variable name from bt_tempvar to our current varname. if (bt_state.useExecute) then begin (SCOPE_VARFETCH(bt_varnames[bt_i], /ENTER)) = $ TEMPORARY(bt_tempvar) endif else begin bt_pAlldata[bt_i] = PTR_NEW(bt_tempvar, /NO_COPY) endelse endfor ; bt_i endif ; bt_state.fieldcount gt 0 ; We've now read in all previous fields, so go ahead and try ; to read our current field. bt_offset = bt_offset_str bt_firstChar = STRMID(bt_offset, 0, 1) if ((bt_firstChar eq '>') || (bt_firstChar eq '<')) then $ bt_offset = STRMID(bt_offset, 1) if (bt_state.useExecute) then begin ; Must be a signed int in case offset is negative. bt_str = 'bt_offset = LONG64(' + bt_offset + ')' if ~execute(bt_str, 1) then begin bt_msg = ['Invalid offset:', !error_state.msg] goto, ioErr endif endif else begin ; See if our string matches a var name. bt_match = (WHERE(STRCMP(bt_varnames, bt_offset, /FOLD_CASE)))[0] if (bt_match ge 0) then begin if (bt_match ge bt_nfield) then $ MESSAGE, 'Variable has not been read: ' + $ bt_varnames[bt_match] bt_offset = LONG64((*bt_pAlldata[bt_match])[0]) endif else begin ; Just try to cast the string to an integer. bt_offset = LONG64(bt_offset) endelse endelse if bt_offset_is_relative then begin point_lun, -bt_lun, bt_pos ; Get the current position. bt_offset = (bt_firstChar ne '<') ? $ bt_pos + bt_offset : ((bt_pos - bt_offset) > 0) endif if bt_num_dims eq 0 then begin bt_tempvar = fix(0, TYPE=bt_typecode(bt_state.wType)) endif else begin if (bt_state.useExecute) then begin bt_str = 'bt_dimension = ULONG64(' + bt_dims_str + ')' if ~execute(bt_str, 1) then begin message, /info, 'Error executing string: ' + bt_str message, !error_state.msg endif endif else begin bt_nd = N_ELEMENTS(bt_arr_str) bt_dimension = ULON64ARR(bt_nd) ; Loop thru all dimension strings and either do a simple ; cast to an unsigned integer, or see if the dimension ; string matches a variable that has just been read in. for bt_j = 0, bt_nd-1 do begin bt_dim_string = bt_arr_str[bt_j] ; See if our string matches a var name. bt_match = (WHERE(STRCMP(bt_varnames, bt_dim_string, $ /FOLD_CASE)))[0] if (bt_match ge 0) then begin if (bt_match ge bt_nfield) then $ MESSAGE, 'Variable has not been read: ' + $ bt_varnames[bt_match] bt_dimension[bt_j] = ULONG64((*bt_pAlldata[bt_match])[0]) endif else begin ; Just try to cast the string to an integer. bt_dimension[bt_j] = ULONG64(bt_dim_string) endelse endfor bt_dimension >= 1 ; 0 --> 1 endelse bt_tempvar = MAKE_ARRAY(DIMENSION=bt_dimension, $ TYPE=bt_typecode(bt_state.wType)) endelse if size(bt_tempvar, /n_dimensions) ne bt_num_dims $ && bt_num_dims gt 0 then begin bt_msg = [ $ 'Field size yields a number of dimensions that', $ 'does not equal your specified number of dimensions.' $ ] goto, ioErr endif bt_msg = 'Invalid offset.' point_lun, bt_lun, bt_offset bt_msg = 'Specified field cannot be read.' readu, bt_lun, bt_tempvar free_lun, bt_lun ; ; Swap endian-ness. ; case strupcase(bt_state.endian) of 'LITTLE': SWAP_ENDIAN_INPLACE, bt_tempvar, /SWAP_IF_BIG_ENDIAN 'BIG': SWAP_ENDIAN_INPLACE, bt_tempvar, /SWAP_IF_LITTLE_ENDIAN else: endcase ; ; Verify the value we read. ; if bt_do_verify then begin if (bt_state.useExecute) then begin if ~execute('bt_verify = ' + bt_verify_str, 1) then begin bt_msg = ['Invalid verify value.', '(' + !error_state.msg + ')'] goto, ioErr endif endif else begin ; See if our string matches a var name. bt_match = (WHERE(STRCMP(bt_varnames, $ bt_verify_str, /FOLD_CASE)))[0] if (bt_match ge 0) then begin if (bt_match ge bt_nfield) then $ MESSAGE, 'Variable has not been read: ' + $ bt_varnames[bt_match] bt_verify = (*bt_pAlldata[bt_match])[0] endif else begin ; Convert from string to same type as data value. bt_verify = FIX(bt_verify_str, $ TYPE=SIZE(bt_tempvar, /TYPE)) endelse endelse if size(bt_verify, /n_dimensions) ne 0 then begin bt_msg = 'Verify value must be a scalar.' goto, ioErr endif bt_tname = size(bt_verify, /tname) if bt_tname eq 'STRING' $ || bt_tname eq 'POINTER' $ || bt_tname eq 'OBJREF' then begin bt_msg = 'Verify value cannot be a ' + bt_tname + '.' goto, ioErr endif if (bt_tempvar ne bt_verify) then begin bt_msg =[ $ 'Field does not equal verify value.', $ 'Field = ' + strcompress(string(bt_tempvar, /print)) $ ] goto, ioErr endif endif ; bt_do_verify if (N_ELEMENTS(bt_pAlldata) gt 0) then $ PTR_FREE, bt_pAlldata endelse ; have a filename bt_msg = 'Entry is valid.' return, 1 ; We made it. ioErr: if (N_ELEMENTS(bt_pAlldata) gt 0) then $ PTR_FREE, bt_pAlldata bt_msg = [bt_msg, !error_state.msg] free_lun, bt_lun return, 0 end ;-------------------------------------------------------------------- function bt_typestring, typecode compile_opt hidden case typecode of 1: return, 'Byte' 2: return, 'Int (16-bit)' 3: return, 'Long (32-bit)' 14: return, 'Long64 (64-bit)' 4: return, 'Float (32-bit)' 5: return, 'Double (64-bit)' 12: return, 'UInt (16-bit)' 13: return, 'ULong (32-bit)' 15: return, 'ULong64 (64-bit)' 6: return, 'Complex' 9: return, 'DComplex' endcase end ;-------------------------------------------------------------------- pro bt_rake, struc compile_opt hidden ; ;"Rake" heap from a structure as one would rake leaves from ;a lawn. ; on_error, 2 if n_elements(struc) le 0 then $ message, 'Argument is missing.' if size(struc, /TNAME) ne 'STRUCT' then $ message, 'Argument must be a struc.' for i=0,n_tags(struc)-1 do begin case size((struc).(i), /TNAME) of 'POINTER': $ ptr_free, (struc).(i) 'OBJREF': $ obj_destroy, (struc).(i) else: endcase endfor end ;-------------------------------------------------------------------- pro bt_put_val_into_array, array, val, indx, insert=insert, debug=debug compile_opt hidden on_error, keyword_set(debug) ? 0 : 2 if n_elements(array) eq 0 then begin array = val return endif if indx lt 0 then $ message, 'Negative array index.' siz = size(array) if siz[0] eq 0 then begin array = [array] siz = size(array) endif if indx gt siz[1]-1 then $ message, 'Index exceeds array bounds.' if keyword_set(insert) then begin ; ; Insert value after index. ; case indx of siz[1]-1: array = [array, val] else: array = [array[0:indx,*], val, array[indx+1:*, *]] endcase endif else begin array[indx, 0] = val endelse end ;-------------------------------------------------------------------- pro bt_delete_item_from_array, array, indx, debug=debug compile_opt hidden on_error, keyword_set(debug) ? 0 : 2 if n_elements(array) eq 1 then begin ptr_free, ptr_new(array, /no_copy) ; Undefine array. return endif if indx lt 0 then $ message, 'Negative array index.' siz = size(array) if siz[0] eq 0 then $ message, 'Array is undefined.' if indx gt siz[1]-1 then $ message, 'Index exceeds array bounds.' if siz[1] eq 1 then begin ptr_free, ptr_new(array, /no_copy) ; Undefined array. return endif ; ;Remove value at index. ; case indx of siz[1]-1: array = array[0:indx-1, *] 0: array = array[1:*, *] else: begin index = l64indgen(siz[1]-1) index[indx:*] = index[indx:*] + 1LL array = array[index, *] end endcase end ;-------------------------------------------------------------------- pro bt_update_field_display, $ state, $ highlight_current_row=highlight_current_row compile_opt hidden if state.fieldcount eq 0 then begin widget_control, state.wTable, set_value=strarr(7) return endif if state.fieldcount gt state.n_rows then begin widget_control, state.wTable, insert_rows=state.fieldcount-state.n_rows state.n_rows = state.fieldcount endif value = strarr(7, state.fieldcount) value[0, *] = *state.pNames value[1, *] = *state.pOffsets value[2, *] = strcompress(*state.pNumDims, /remove_all) for i=0,state.fieldcount-1 do begin value[3, i] = rb_dim_str( $ (*state.pDimensions)[i, *], $ (*state.pNumDims)[i] $ ) endfor for i=0,state.fieldcount-1 do $ value[4, i] = bt_typestring((*state.pTypeCodes)[i]) value[5, *] = 'No' indx = where(*state.pReturnFlags) if indx[0] ne -1 then $ value[5, indx] = 'Yes' value[6, *] = 'No' indx = where(*state.pVerifyFlags) if indx[0] ne -1 then $ value[6, indx] = 'Yes' widget_control, $ state.wTable, $ set_value=value, $ ysize=state.fieldcount, $ column_labels=state.column_labels if keyword_set(highlight_current_row) then begin ; ; Highlight the entire current row. ; widget_control, state.wTable, $ set_table_select=[ $ 0, $ state.current_field_indx, $ n_elements(state.column_labels) - 1, $ state.current_field_indx $ ] ; ; Center the row that is currently selected. ; widget_control, state.wTable, $ set_table_view=[ $ 0, $ 0 > (state.current_field_indx - (state.n_scroll_rows / 2)) $ < (state.n_rows - state.n_scroll_rows) $ ] endif end ;-------------------------------------------------------------------- pro bt_modify_field_event, event compile_opt hidden widget_control, event.top, get_uvalue=pState case event.id of (*pState).wOffset: begin if event.type lt 3 then begin widget_control, event.id, get_value=value value = value[0] case 1 of strpos(value, '>') eq 0: begin widget_control, (*pState).wAbsoluteRadio, set_value=1 (*pState).offset_sign = '>' end strpos(value, '<') eq 0: begin widget_control, (*pState).wAbsoluteRadio, set_value=1 (*pState).offset_sign = '<' end else: widget_control, (*pState).wAbsoluteRadio, set_value=0 endcase (*pState).offset_str = value endif ; event.type lt 3 end ; (*pState).wOffset (*pState).wAbsoluteRadio: begin if event.value eq 0 then begin (*pState).offset_str = strmid( $ (*pState).offset_str, $ stregex((*pState).offset_str, '^[<>]') + 1 $ ) endif else begin if stregex((*pState).offset_str, '^[<>]') eq -1 then $ (*pState).offset_str = $ (*pState).offset_sign + (*pState).offset_str endelse widget_control, (*pState).wOffset, set_value=(*pState).offset_str end (*pState).wNumDims: begin for i=0,(*pState).max_idl_dims-1 do begin widget_control, $ (*pState).wIndividualDimBase[i], $ sensitive=i lt event.index if i ge event.index then begin widget_control, $ (*pState).wDimText[i], $ set_value='' if i le 2 then $ widget_control, $ (*pState).wReverseCheckbox[i], $ set_value=0 endif endfor widget_control, (*pState).wVerifyCheckbox, set_value=0 bt_modify_field_event, { $ id: (*pState).wVerifyCheckbox, $ top: event.top, $ handler: 0L, $ select: 0 $ } widget_control, $ (*pState).wVerifyBase, $ sensitive=event.index eq 0 end ; (*pState).wNumDims (*pState).wType: ; do nothing (*pState).wModifyOK: begin widget_control, /hourglass if ~bt_entry_is_valid(*pState, msg=msg) then begin void = dialog_message(msg, /error) return endif widget_control, (*pState).wDimText[0], get_value=bt_arr_str for i=1,(*pState).max_idl_dims-1 do begin widget_control, (*pState).wDimText[i], get_value=bt_single_str bt_arr_str = [bt_arr_str, bt_single_str] endfor num_dims = widget_info((*pState).wNumDims, /droplist_select) widget_control, (*pState).wOffset, get_value=field_loc_str field_loc_str = field_loc_str[0] widget_control, (*pState).wFieldName, get_value=field_name_str ; Replace fieldName with a valid version (spaces->underscores, etc.) field_name_str = IDL_VALIDNAME(field_name_str[0], /CONVERT_ALL) widget_control, (*pState).wFieldName, set_value=field_name_str field_name_str = field_name_str[0] widget_control, (*pState).wVerifyText, get_value=verify_text verify_text = verify_text[0] bt_put_val_into_array, $ *(*pState).pNames, $ ; The array. field_name_str, $ ; The value. (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug bt_put_val_into_array, $ *(*pState).pTypecodes, $ ; The array. bt_typecode((*pState).wType), $ (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug bt_put_val_into_array, $ *(*pState).pOffsets, $ ; The array. field_loc_str, $ ; The value. (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug bt_put_val_into_array, $ *(*pState).pAllowFormulas, $ ; The array. 1, $ ; The value. (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug bt_put_val_into_array, $ *(*pState).pDimAllowFormulas, $ ; The array. 1, $ ; The value. (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug widget_control, $ (*pState).wAbsoluteRadio, $ get_value=absolute_radio_sel bt_put_val_into_array, $ *(*pState).pAbsoluteFlags, $ ; The array. absolute_radio_sel eq 0, $ ; The value. (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug bt_put_val_into_array, $ *(*pState).pNumDims, $ ; The array. num_dims, $ ; The value. (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug bt_put_val_into_array, $ *(*pState).pDimensions, $ transpose(bt_arr_str), $ (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug reverseflags = bytarr((*pState).max_idl_dims) for i=0,2 do begin widget_control, (*pState).wReverseCheckbox[i], get_value=checked reverseflags[i] = checked end bt_put_val_into_array, $ *(*pState).pReverseFlags, $ transpose(reverseflags), $ (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug widget_control, (*pState).wReturn, get_value=val bt_put_val_into_array, $ *(*pState).pReturnFlags, $ val, $ (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug widget_control, (*pState).wVerifyCheckbox, get_value=val bt_put_val_into_array, $ *(*pState).pVerifyFlags, $ val, $ (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug bt_put_val_into_array, $ *(*pState).pVerifyVals, $ ; The array. verify_text, $ ; The value. (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug if (*pState).we_are_inserting then begin (*pState).fieldcount = (*pState).fieldcount + 1 (*pState).current_field_indx = $ ((*pState).current_field_indx + 1) $ < ((*pState).fieldcount - 1) endif bt_update_field_display, *pState, /highlight_current_row widget_control, event.top, /destroy end ; (*pState).wModifyOK (*pState).wModifyCancel: widget_control, event.top, /destroy (*pState).wVerifyCheckbox: begin if event.select eq 0 then $ widget_control, (*pState).wVerifyText, set_value='' widget_control, (*pState).wVerifyText, sensitive=event.select end (*pState).wFieldName: begin widget_control, (*pState).wFieldName, get_value=bt_field_name_str ; Replace fieldName with a valid version (spaces->underscores, etc.) bt_field_name_str = IDL_VALIDNAME(bt_field_name_str[0], /CONVERT_ALL) widget_control, (*pState).wFieldName, set_value=bt_field_name_str end else: endcase return cast_failed: ; Leading character is illegal. widget_control, event.id, set_value=(*pState).offset_str widget_control, event.id, set_text_select=radio message, /reset end ;-------------------------------------------------------------------- pro bt_modify_field, pState compile_opt hidden tlb = widget_base( $ /modal, $ group_leader=(*pState).tlb, $ /column, $ space=10, $ title=((*pState).we_are_inserting ? 'New' : 'Modify') + ' Field', $ /TAB_MODE) (*pState).wFieldName = cw_field(tlb, Title='Field name: ', xsize=45, $ /RETURN_EVENTS) wRowBase = widget_base(tlb, /row, xpad=0, ypad=0, space=10) wLeftBase = widget_base(wRowBase, /col, xpad=2, ypad=5) (*pState).wType = widget_droplist( $ wLeftBase, $ title='Type:', $ value=[ $ 'Byte (unsigned 8-bits)', $ 'Integer (16 bits)', $ 'Long (32 bits)', $ 'Long64 (64 bits)', $ 'Float (32 bits)', $ 'Double-Precision (64 bits)', $ 'Unsigned Integer (16 bits)', $ 'Unsigned Long (32 bits)', $ 'Unsigned Long64 (64 bits)', $ 'Complex (real-imag pair of floats)', $ 'Double complex (pair of doubles)' $ ], $ uvalue=[ $ ; IDL typecodes corresponding to each droplist entry. 1, $ 2, $ 3, $ 14, $ 4, $ 5, $ 12, $ 13, $ 15, $ 6, $ 9 $ ] $ ) wOffsetBase = WIDGET_BASE(wLeftBase, /COLUMN, YPAD=5) wFieldBase = widget_base(wOffsetBase, /row) void = widget_label(wFieldBase, value='Offset: ') (*pState).wOffset = widget_text( $ wFieldBase, $ scr_xsize=110, $ /editable, $ /all_events, $ value='>0' $ ) void = widget_label(wFieldBase, value=' bytes') (*pState).wAbsoluteRadio = cw_bgroup(wOffsetBase, $ /exclusive, $ /no_release, $ set_value=1, $ ['From beginning of file', $ (*pState).current_field_indx eq 0 and $ ((*pState).fieldcount eq 0 or (*pState).we_are_inserting eq 0) ? $ 'From initial position in file' : 'From end of previous field' $ ], $ /column, $ space=0) if (*pState).useExecute then begin expString = [ $ ' or an expression', $ 'involving fields defined earlier in the template.'] endif else begin expString = [ $ ' or the name', $ 'of a field defined earlier in the template.'] endelse wDummy = WIDGET_LABEL(wOffsetBase, /ALIGN_LEFT, $ VALUE='Offset can be an integer' + expString[0]) wDummy = WIDGET_LABEL(wOffsetBase, /ALIGN_LEFT, VALUE=expString[1]) void = WIDGET_LABEL(wOffsetBase, VALUE=' ') void = widget_label(wOffsetBase, /ALIGN_LEFT, $ VALUE='When a file is read, this field should be:') (*pState).wReturn = cw_bgroup( $ wOffsetBase, $ /nonexclusive, $ 'Returned in the result' $ ) widget_control, (*pState).wReturn, set_value=[1] (*pState).wVerifyBase = widget_base(wOffsetBase, /row, xpad=0, ypad=3) (*pState).wVerifyCheckbox = cw_bgroup( $ (*pState).wVerifyBase, $ /nonexclusive, $ 'Verified as being equal to:' $ ) (*pState).wVerifyText = widget_text( $ widget_base((*pState).wVerifyBase, /row, xpad=0), $ scr_xsize=70, $ sensitive=0, $ /editable $ ) wDummy = WIDGET_LABEL(wOffsetBase, /ALIGN_LEFT, $ VALUE='The Verify field can contain a number' + expString[0]) wDummy = WIDGET_LABEL(wOffsetBase, /ALIGN_LEFT, VALUE=expString[1]) wRightBase = widget_base(wRowBase, /column, xpad=2, ypad=5) (*pState).wNumDims = widget_droplist( $ wRightBase, $ value=[ $ '0 (scalar)', $ strcompress(indgen((*pState).max_idl_dims) + 1, /remove_all) $ ], $ title='Number of dimensions:' $ ) void = WIDGET_LABEL(wRightBase, VALUE=' ') w2x4Base = widget_base(wRightBase, col=1, xpad=0, ypad=0, space=0) for i=0,2 do begin (*pState).wIndividualDimBase[i] = widget_base( $ w2x4Base, /row, $ /base_align_left) void = widget_label( $ (*pState).wIndividualDimBase[i], $ value=(['1st', '2nd', '3rd'])[i] + ':', SCR_XSIZE=40) void = widget_label((*pState).wIndividualDimBase[i], value=' Size: ') (*pState).wDimText[i] = widget_text( $ (*pState).wIndividualDimBase[i], $ /editable, $ /all_events) (*pState).wReverseCheckbox[i] = cw_bgroup( $ (*pState).wIndividualDimBase[i], $ 'Reverse', $ /nonexcl, $ ypad=0) endfor for i=3,(*pState).max_idl_dims-1 do begin (*pState).wIndividualDimBase[i] = widget_base( $ w2x4Base, $ /row, $ /base_align_left) void = widget_label( $ (*pState).wIndividualDimBase[i], $ value=strcompress(i+1, /remove_all) + 'th:', SCR_XSIZE=40) void = widget_label((*pState).wIndividualDimBase[i], value=' Size: ') (*pState).wDimText[i] = widget_text( $ (*pState).wIndividualDimBase[i], $ /editable, $ /all_events) endfor wDummy = WIDGET_LABEL(wRightBase, /ALIGN_LEFT, $ VALUE='Each dimension can be an integer' + expString[0]) wDummy = WIDGET_LABEL(wRightBase, /ALIGN_LEFT, VALUE=expString[1]) wRowBase = widget_base(tlb, /row) (*pState).wModifyOK = widget_button(wRowBase, value=' OK ') (*pState).wModifyCancel = widget_button(wRowBase, Value='Cancel') widget_control, tlb, /realize if ~(*pState).we_are_inserting then begin widget_control, $ (*pState).wFieldName, $ set_value=(*(*pState).pNames)[(*pState).current_field_indx] widget_control, $ (*pState).wOffset, $ set_value=(*(*pState).pOffsets)[(*pState).current_field_indx] widget_control, $ (*pState).wAbsoluteRadio, $ set_value=(*(*pState).pAbsoluteFlags)[(*pState).current_field_indx] eq 0 widget_control, $ (*pState).wReturn, $ set_value=(*(*pState).pReturnFlags)[(*pState).current_field_indx] widget_control, $ (*pState).wVerifyCheckbox, $ set_value=(*(*pState).pVerifyFlags)[(*pState).current_field_indx] widget_control, $ (*pState).wNumDims, $ set_droplist_select=(*(*pState).pNumDims)[ $ (*pState).current_field_indx $ ] for i=0,(*(*pState).pNumDims)[(*pState).current_field_indx]-1 do begin widget_control, $ (*pState).wDimText[i], $ set_value=(*(*pState).pDimensions)[ $ (*pState).current_field_indx, $ i $ ] endfor for i=0,((*(*pState).pNumDims)[(*pState).current_field_indx]-1)<2 do begin widget_control, $ (*pState).wReverseCheckbox[i], $ set_value=(*(*pState).pReverseFlags)[ $ (*pState).current_field_indx, $ i $ ] endfor widget_control, (*pState).wType, get_uvalue=typecode_table widget_control, $ (*pState).wType, $ set_droplist_select=(where( $ typecode_table eq (*(*pState).pTypecodes)[ $ (*pState).current_field_indx $ ] $ ))[0] widget_control, $ (*pState).wVerifyText, $ sensitive=(*(*pState).pVerifyFlags)[(*pState).current_field_indx] eq 1, $ set_value=(*(*pState).pVerifyVals)[(*pState).current_field_indx] endif ; ~(*pState).we_are_inserting num_dims = widget_info((*pState).wNumDims, /droplist_select) for i=0,(*pState).max_idl_dims-1 do begin widget_control, $ (*pState).wIndividualDimBase[i], $ sensitive=i lt num_dims endfor widget_control, $ (*pState).wVerifyBase, $ sensitive=num_dims eq 0 widget_control, tlb, set_uvalue=pState xmanager, 'bt_modify_field', tlb end ;-------------------------------------------------------------------- pro binary_template_event, event compile_opt hidden ; Need to kill manually to prevent flashing on Windows. ; The Cancel state field is initially set to 1, so we're okay. if (TAG_NAMES(event, /STRUCTURE_NAME) eq 'WIDGET_KILL_REQUEST') then begin WIDGET_CONTROL, event.top, /DESTROY return endif widget_control, event.top, get_uvalue=pState case event.id of (*pState).wOK: begin if (*pState).fieldcount gt 0 then begin if max(*(*pState).pReturnFlags) eq 0 then begin void = dialog_message( $ 'Illegal template: no fields are marked "Yes" ' + $ 'for Return.', $ /error $ ) return endif endif widget_control, (*pState).wNameText, get_value=template_name (*pState).template_name = template_name (*pState).cancel = 0b widget_control, event.top, /destroy return end (*pState).wCancel: begin widget_control, event.top, /destroy return end (*pState).wEndian: $ (*pState).endian = (['native', 'little', 'big'])[event.index] (*pState).wNewFieldButton: begin (*pState).we_are_inserting = 1b bt_modify_field, pState end (*pState).wModifyFieldButton: begin (*pState).we_are_inserting = 0b bt_modify_field, pState end (*pState).wRemoveFieldButton: begin bt_delete_item_from_array, $ *(*pState).pNames, $ (*pState).current_field_indx bt_delete_item_from_array, $ *(*pState).pTypecodes, $ (*pState).current_field_indx bt_delete_item_from_array, $ *(*pState).pOffsets, $ (*pState).current_field_indx bt_delete_item_from_array, $ *(*pState).pAllowFormulas, $ (*pState).current_field_indx bt_delete_item_from_array, $ *(*pState).pDimAllowFormulas, $ (*pState).current_field_indx bt_delete_item_from_array, $ *(*pState).pAbsoluteFlags, $ (*pState).current_field_indx bt_delete_item_from_array, $ *(*pState).pNumDims, $ (*pState).current_field_indx bt_delete_item_from_array, $ *(*pState).pDimensions, $ (*pState).current_field_indx bt_delete_item_from_array, $ *(*pState).pReverseFlags, $ (*pState).current_field_indx bt_delete_item_from_array, $ *(*pState).pReturnFlags, $ (*pState).current_field_indx bt_delete_item_from_array, $ *(*pState).pVerifyFlags, $ (*pState).current_field_indx bt_delete_item_from_array, $ *(*pState).pVerifyVals, $ (*pState).current_field_indx (*pState).fieldcount = (*pState).fieldcount - 1 (*pState).current_field_indx = ((*pState).current_field_indx - 1) > 0 bt_update_field_display, *pState, /highlight_current_row end (*pState).wTable: begin if tag_names(event, /structure_name) eq 'WIDGET_TABLE_CELL_SEL' $ then begin if event.sel_top ne -1 && event.sel_left ne -1 then begin (*pState).current_field_indx = $ 0 > (event.sel_top < ((*pState).fieldcount - 1)) if event.sel_right eq event.sel_left $ && event.sel_right eq 5 $ && (*pState).fieldcount gt 0 then begin bt_put_val_into_array, $ *(*pState).pReturnFlags, $ 1 - (*(*pState).pReturnFlags)[ $ (*pState).current_field_indx $ ], $ (*pState).current_field_indx, $ insert=0, $ debug=(*pState).debug bt_update_field_display, *pState ; ; The cell at Row 0, Column 0 might now be highlighted, in ; addition to the current cell. To undo this ; artifact, highlight only the current cell. ; widget_control, $ event.id, $ set_table_select=[ $ event.sel_left, $ event.sel_top , $ event.sel_right, $ event.sel_bottom $ ] endif ; ; Nicety: If an entire column was selected, allow the ; selection to show on the screen for a moment before ; un-doing the selection. This pause also allows the ; user to see which column is selected if the user is ; pressing the arrow keys to "walk around" in the table. ; Seeing which column is selected when using the arrow ; keys helps the user know when a "Return" will be ; toggled between "No" and "Yes" as a result of ; an arrow keypress. ; wait, .25 ; ; Select a row. ; widget_control, $ event.id, $ set_table_select=[ $ 0, $ 0 > (event.sel_top < ((*pState).fieldcount - 1)), $ n_elements((*pState).column_labels) - 1, $ 0 > (event.sel_top < ((*pState).fieldcount - 1)) $ ] endif endif ; WIDGET_TABLE_CELL_SEL end else: endcase widget_control, $ (*pState).wModifyFieldButton, $ sensitive=(*pState).fieldcount gt 0 widget_control, $ (*pState).wRemoveFieldButton, $ sensitive=(*pState).fieldcount gt 0 widget_control, (*pState).wOK, sensitive=(*pState).fieldcount gt 0 end ;-------------------------------------------------------------------- function binary_template, $ filename, $ ; IN: (opt) test dataset. cancel=cancel, $ ; OUT: (opt) set if user canceled this dialog. template=template, $ ; IN: (opt) initial template. debug=debug, $ ; IN: (opt) n_rows=n_rows, $ ; IN: (opt) number of rows in widget_table. group=group_leader, $ ; IN: (opt) group_leader for base widget no_file=no_file ; IN: (opt) Undocumented. This feature may ; change! If set, do not require ; FILENAME argument. on_error, 2 catch, error_status if error_status ne 0 then begin catch, /cancel ; ; Clean up. ; if n_elements(lun) gt 0 then $ free_lun, lun if n_elements(tlb) gt 0 then $ if widget_info(tlb, /valid_id) then $ widget_control, tlb, /destroy if n_elements(pState) gt 0 then $ if ptr_valid(pState) then begin bt_rake, *pState ptr_free, pState endif if keyword_set(group_leader_is_fabricated) then begin if n_elements(group_leader) gt 0 then begin if widget_info(group_leader, /valid_id) then $ widget_control, group_leader, /destroy ptr_free, ptr_new(group_leader, /no_copy) endif endif ; ; Re-throw the error. ; message, !error_state.msg + ' ' + !error_state.sys_msg endif ; if keyword_set(debug) then begin catch, /cancel on_error, 0 endif ; ;Test TEMPLATE argument. ; if (n_elements(template) gt 0) then begin if ~rb_template_is_valid(template, msg=msg, /edit) then $ message, msg[0], /noname endif ; ;Test the FILENAME input argument. For consistency, the logic here ;is intended to yield results similar to ASCII_TEMPLATE. ; case 1 of keyword_set(no_file): $ filename = '' n_elements(filename) eq 0: begin filename = dialog_pickfile(/must_exist, group=group_leader) if filename eq '' then begin cancel = 1b return, 0 endif end size(filename, /n_dimensions) gt 1: $ message, 'First argument must be scalar.', /noname size(filename, /tname) ne 'STRING': $ message, 'First argument must be a string.', /noname filename eq '': $ message, 'Supplied filename is an empty string.', /noname else: begin if (file_search(filename))[0] eq '' then $ message, $ 'Could not find specified file: ' + filename + '.', $ /noname end endcase ; ;Test that we have read access to the file. ; if filename ne '' then begin get_lun, lun openr, lun, filename close, lun free_lun, lun endif ; ;BINARY_TEMPLATE is a function, thus its GUI will be modal. ;Modal widgets require a group leader. Make sure that ;we have a group leader, fabricating an invisible one ;if necessary. ; if n_elements(group_leader) eq 0 then begin group_leader = widget_base(map=0) group_leader_is_fabricated = 1b endif else begin if ~widget_info(group_leader, /valid_id) then $ message, 'Specified GROUP_LEADER is invalid.', /noname group_leader_is_fabricated = 0b endelse tlb = widget_base( $ ; Top-level base. /column, $ /FLOATING, $ /TLB_KILL_REQUEST_EVENTS, $ title='Binary Template', $ group_leader=group_leader, $ /modal, $ /TAB_MODE) wRowBase = widget_base(tlb, /row) void = widget_label(wRowBase, value='Template name:') wNameText = widget_text(wRowBase, /editable) wEndian = widget_droplist( $ wRowBase, $ title=' File''s byte ordering:', $ value=['Native', 'Little Endian', 'Big Endian'] $ ) wFrameBase = widget_base(tlb, /frame, /col) void = widget_label(wFrameBase, value='Fields:', /align_left) case !version.os_family of 'Windows': column_widths = [100, 50, 50, 100, 70, 50, 50] 'unix': column_widths = [100, 70, 80, 100, 70, 80, 80] else: column_widths = [100, 70, 80, 100, 70, 80, 80] endcase column_labels = [ $ 'Name', $ 'Offset', $ '# Dims', $ 'Size', $ 'Type', $ 'Return', $ 'Verify' $ ] if ~keyword_set(n_rows) then $ n_rows = (n_elements(template) gt 0) ? $ 6 > template.fieldcount < 12 : 6 if n_rows le 0 then $ message, 'N_ROWS must be positive.' wTable = widget_table( $ wFrameBase, $ column_labels=column_labels, $ xsize=n_elements(column_labels), $ scr_xsize=total(column_widths) + 60, $ ysize=n_rows, $ y_scroll_size=n_rows, $ value=strarr(n_elements(column_labels), n_rows), $ /resizeable_columns, $ /all_events, $ /scroll $ ) widget_control, wTable, column_widths=30, use_table_select=[-1, 0, 0, 0] widget_control, $ wTable, $ column_widths=column_widths, $ use_table_select=[0, 0, 6, 0] wRowBase = widget_base(wFrameBase, /row) wNewFieldButton = widget_button(wRowBase, value='New Field...') wModifyFieldButton = widget_button(wRowBase, value='Modify Field...') wRemoveFieldButton = widget_button(wRowBase, value='Remove Field') wRowBase = widget_base(tlb, /row) wOK = widget_button(wRowBase, value=' OK ') wCancel = widget_button(wRowBase, value='Cancel') ; ;Initialize and store the state of this program. ; max_idl_dims = 8 pState = ptr_new({ $ tlb: tlb, $ wNameText: wNameText, $ wEndian: wEndian, $ wOK: wOK, $ wCancel: wCancel, $ wTable: wTable, $ wNewFieldButton: wNewFieldButton, $ wModifyFieldButton: wModifyFieldButton, $ wRemoveFieldButton: wRemoveFieldButton, $ wFieldName: 0L, $ wAbsoluteRadio: 0L, $ wOffset: 0L, $ wReturn: 0L, $ wVerifyCheckbox: 0L, $ wVerifyBase: 0L, $ wVerifyText: 0L, $ wNumDims: 0L, $ max_idl_dims: max_idl_dims, $ wIndividualDimBase: lonarr(max_idl_dims), $ wDimLabel: lonarr(max_idl_dims), $ wDimText: lonarr(max_idl_dims), $ wReverseCheckbox: lonarr(3), $ wType: 0L, $ wModifyOK: 0L, $ wModifyCancel: 0L, $ column_labels: column_labels, $ n_rows: n_rows, $ n_scroll_rows: n_rows, $ we_are_inserting: 0L, $ cancel: 1b, $ useExecute: ~LMGR(/VM), $ ; Cannot use execute in IDL Virtual Machine. fieldcount: 0L, $ current_field_indx: 0L, $ offset_str: '>0', $ offset_sign: '>', $ debug: keyword_set(debug), $ filename: filename, $ ; Valid string, or ''. template_name: '', $ endian: 'native', $ pNames: ptr_new(/allocate_heap), $ ; Array of strings. pOffsets: ptr_new(/allocate_heap), $ pAllowFormulas: ptr_new(/allocate_heap), $ ; Array of "boolean" pDimAllowFormulas: ptr_new(/allocate_heap), $ ; Array of "boolean" pNumDims: ptr_new(/allocate_heap), $ ; Array of ints. pDimensions: ptr_new(/allocate_heap), $ ; Array of array of strings. pReverseFlags: ptr_new(/allocate_heap), $ ; Array of ptrs to array. pTypecodes: ptr_new(/allocate_heap), $ ; Array. pReturnFlags: ptr_new(/allocate_heap), $ pVerifyFlags: ptr_new(/allocate_heap), $ ; Array of "boolean" pVerifyVals: ptr_new(/allocate_heap), $ ; Array of strings. pAbsoluteFlags: ptr_new(/allocate_heap), $ ; Array of "boolean" pInitialTemplate: ptr_new(/allocate_heap) $ }) widget_control, tlb, set_uvalue=pState ; ;Center and realize our top-level base. ; screen_size = [640, 480] DEVICE, GET_SCREEN_SIZE=screen_size geom = widget_info(tlb, /geometry) widget_control, $ tlb, $ xoffset=(screen_size[0]/2 - geom.scr_xsize/2) > 0, $ yoffset=(screen_size[1]/2 - geom.scr_ysize/2) > 0 widget_control, tlb, /realize widget_control, $ wTable, $ set_table_select=[0, 0, n_elements(column_labels) - 1, 0] ; ;Store and display initial template, if any. ; if n_elements(template) gt 0 then begin (*pState).template_name = template.templatename (*pState).endian = template.endian (*pState).fieldcount = template.fieldcount *(*pState).pTypecodes = template.Typecodes *(*pState).pNames = template.Names *(*pState).pOffsets = template.Offsets *(*pState).pNumDims = template.NumDims *(*pState).pDimensions = template.Dimensions *(*pState).pReverseFlags = template.ReverseFlags *(*pState).pAbsoluteFlags = template.AbsoluteFlags *(*pState).pReturnFlags = template.ReturnFlags *(*pState).pVerifyFlags = template.VerifyFlags *(*pState).pVerifyVals = template.VerifyVals *(*pState).pAllowFormulas = template.OffsetAllowFormulas *(*pState).pDimAllowFormulas = template.DimAllowFormulas widget_control, (*pState).wNameText, set_value=template.templatename if strupcase((*pState).endian) eq 'LITTLE' then $ widget_control, (*pState).wEndian, set_droplist_select=1 if strupcase((*pState).endian) eq 'BIG' then $ widget_control, (*pState).wEndian, set_droplist_select=2 bt_update_field_display, *pState, /highlight_current_row *(*pState).pInitialTemplate = template endif ; template ; ;Set initial sensitivity of buttons. ; if (*pState).fieldcount eq 0 then begin widget_control, wModifyFieldButton, sensitive=0 widget_control, wRemoveFieldButton, sensitive=0 widget_control, wOK, sensitive=0 end ; ;Allow the user to interact with this program, affecting the state data. ; xmanager, 'binary_template', tlb if (*pState).cancel || (*pState).fieldcount eq 0 then begin result = 0 if n_elements(*(*pState).pInitialTemplate) gt 0 then begin result = *(*pState).pInitialTemplate end cancel = 1b ; Return parameter. endif else begin ; ; Append a zero ("0") to offset strings that do not have any numeric ; digits in them. This makes the resulting strings more uniform, and ; thus (hopefully) easier to understand should a person be ; examining these values for any reason. ; indx = where(*(*pState).pOffsets eq '') if indx[0] ne -1 then $ (*(*pState).pOffsets)[indx] = '0' indx = where(*(*pState).pOffsets eq '>') if indx[0] ne -1 then $ (*(*pState).pOffsets)[indx] = '>0' indx = where(*(*pState).pOffsets eq '<') if indx[0] ne -1 then $ (*(*pState).pOffsets)[indx] = '<0' ; ; Store a copy of any state information that is to be returned. ; result = { $ version: 1.0, $ templatename: (*pState).template_name, $ endian: (*pState).endian, $ fieldcount: (*pState).fieldcount, $ typecodes: *(*pState).pTypecodes, $ names: *(*pState).pNames, $ offsets: *(*pState).pOffsets, $ numdims: *(*pState).pNumDims, $ dimensions: *(*pState).pDimensions, $ ReverseFlags: *(*pState).pReverseFlags, $ AbsoluteFlags: *(*pState).pAbsoluteFlags, $ ReturnFlags: *(*pState).pReturnFlags, $ VerifyFlags: *(*pState).pVerifyFlags, $ dimAllowFormulas: *(*pState).pDimAllowFormulas, $ offsetAllowFormulas: *(*pState).pAllowFormulas, $ verifyvals: *(*pState).pVerifyVals $ } cancel = 0b ; Return parameter. endelse ; ;Clean up. ; bt_rake, *pState ptr_free, pState if group_leader_is_fabricated then begin widget_control, group_leader, /destroy ; ; Leave GROUP_LEADER parameter like we found it: undefined. ; ptr_free, ptr_new(group_leader, /no_copy) endif return, result end