; $Id: binary_template.pro,v 1.33 2001/04/12 21:24:37 chris Exp $ ; ; Copyright (c) 1999-2001, 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 ne '' then begin on_ioerror, set_str_to_null if 1 then begin str = strcompress( $ abs(long64(current_str)), $ /remove_all $ ) end $ else begin set_str_to_null: str = '' message, /reset end on_ioerror, NULL if tag_names(event, /structure_name) ne '' then begin if str ne current_str then begin beep 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 end end $ else begin widget_control, event.id, set_value=str end widget_control, event.id, get_value=current_str widget_control, event.id, set_uvalue=current_str end 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 $ on_error, 0 $ else begin catch, bt_error_status if bt_error_status ne 0 then begin catch, /cancel if n_elements(bt_lun) gt 0 then begin free_lun, bt_lun end bt_msg = [ $ 'Could not validate entry.', $ 'Internal error message was:', $ ' ' + !error_state.msg_prefix + !error_state.msg $ ] return, 0 end end 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] end widget_control, bt_state.wOffset, get_value=bt_offset_str widget_control, bt_state.wFieldName, get_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 end if strpos(strupcase(bt_field_name_str), 'RB_') ne -1 $ or 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 end ; ;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 end $ else begin if bt_indx[0] ne bt_state.current_field_indx then begin bt_msg = 'Another field has the same name.' return, 0 end end end end ; ;Attempt to assign to the user-given field name to see if ;the name is valid. ; if not execute(bt_field_name_str + ' = 0', 1) then begin bt_msg = 'Field name is invalid.' return, 0 end ; ;Undefine the named variable to which we just assigned. ;We do this in the event that the named variable is used ;in an expression to be tested below in this routine. ;We want to get a 'Variable undefined' message in that case. ; if not execute( $ 'ptr_free, ptr_new(' + bt_field_name_str + ', /no_copy)', $ 1 $ ) $ then begin print, 'Error executing string: ' + bt_str message, !error_state.msg end bt_dims_str = rb_dim_str(bt_arr_str, bt_num_dims) widget_control, bt_state.wFormulaCheckbox, get_value=bt_offset_is_formula widget_control, bt_state.wAbsoluteRadio, get_value=bt_offset_is_relative widget_control, bt_state.wDimFormulaCheckbox, get_value=bt_size_is_formula widget_control, bt_state.wVerifyCheckbox, get_value=bt_do_verify if bt_offset_is_relative then begin if strmid(bt_offset_str, 0, 1) ne '<' $ and strmid(bt_offset_str, 0, 1) ne '>' then begin bt_msg = 'Relative offset should start with ">" or "<". return, 0 end if strlen(bt_offset_str) eq 1 then begin bt_msg = 'No offset given.' return, 0 end end $ else begin if bt_offset_str eq '' then begin bt_msg = 'No offset given.' return, 0 end end if bt_state.filename eq '' then begin if bt_offset_is_formula then begin ; ; Check user's offset syntax. ; if strpos(strupcase(bt_offset_str), 'RB_') ne -1 $ or strpos(strupcase(bt_offset_str), 'BT_') ne -1 then begin bt_msg = [ $ 'Offset is invalid.', $ '(Expressions containing "rb_" or "bt_" are not allowed.)' $ ] return, 0 end message, /reset ; clear !error_state bt_void = execute( $ 'bt_void = ' $ + strmid(bt_offset_str, bt_offset_is_relative ? 1 : 0), $ 1 $ ) if !error_state.name eq 'IDL_M_BADSYNTAX' $ or !error_state.name eq 'IDL_M_ILLOP' $ or !error_state.name eq 'IDL_M_ILLCHAR' then begin bt_msg = ['Offset is invalid.', '(' + !error_state.msg + ')'] return, 0 end end if keyword_set(bt_size_is_formula) then begin ; ; Check user's dimensions syntax. ; if strpos(strupcase(bt_dims_str), 'RB_') ne -1 $ or strpos(strupcase(bt_dims_str), 'BT_') ne -1 then begin bt_msg = [ $ 'Dimension is invalid.', $ '(Expressions containing "rb_" or "bt_" are not allowed.)' $ ] return, 0 end message, /reset ; clear !error_state bt_void = execute('bt_void = ' + bt_dims_str, 1) if !error_state.name eq 'IDL_M_BADSYNTAX' $ or !error_state.name eq 'IDL_M_ILLOP' $ or !error_state.name eq 'IDL_M_ILLCHAR' then begin bt_msg = ['Invalid size.', '(' + !error_state.msg + ')'] return, 0 end end if keyword_set(bt_do_verify) then begin ; ; Check user's verify value syntax. ; if bt_verify_str eq '' then begin bt_msg = 'Verify value is blank.' return, 0 end if strpos(strupcase(bt_verify_str), 'RB_') ne -1 $ or strpos(strupcase(bt_verify_str), 'BT_') ne -1 then begin bt_msg = [ $ 'Verify value is invalid.', $ '(Expressions containing "rb_" or "bt_" are not allowed.)' $ ] return, 0 end message, /reset ; clear !error_state bt_void = execute('bt_void = ' + bt_verify_str, 1) if !error_state.name eq 'IDL_M_BADSYNTAX' $ or !error_state.name eq 'IDL_M_ILLOP' $ or !error_state.name eq 'IDL_M_ILLCHAR' then begin bt_msg = ['Invalid verify value.', '(' + !error_state.msg + ')'] return, 0 end end end $ else begin get_lun, bt_lun openr, bt_lun, bt_state.filename if bt_state.fieldcount gt 0 then begin bt_varnames = strcompress(*bt_state.pNames, /remove_all) for bt_i=0, $ bt_state.current_field_indx-(bt_state.we_are_inserting eq 0) $ do begin bt_str = bt_varnames[bt_i] if (*bt_state.pNumDims)[bt_i] eq 0 then begin ; Scalar. bt_str = bt_str $ + ' = fix(0, type=(*bt_state.pTypecodes)[bt_i])' end $ else begin ; Array bt_str = bt_str $ + ' = make_array(' $ + 'dimension=' $ + rb_dim_str( $ (*bt_state.pDimensions)[bt_i, *], $ (*bt_state.pNumDims)[bt_i] $ ) $ + ', ' $ + 'type=(*bt_state.pTypecodes)[bt_i]' $ + ')' end if not execute(bt_str, 1) then begin print, 'Error executing string: ' + bt_str message, !error_state.msg end if (*bt_state.pAbsoluteflags)[bt_i] eq 1 then begin bt_str = 'point_lun, bt_lun, long64(' $ + (*bt_state.pOffsets)[bt_i] $ + ')' end $ else begin point_lun, -bt_lun, bt_pos ; Get the current position. if strpos((*bt_state.pOffsets)[bt_i], '>') eq 0 then begin bt_str = 'point_lun, bt_lun, bt_pos + long64(' $ + strmid((*bt_state.pOffsets)[bt_i], 1) $ + ')' end $ else begin bt_str = 'point_lun, bt_lun, (bt_pos - long64(' $ + strmid((*bt_state.pOffsets)[bt_i], 1) $ + ')) > 0' end end if not execute(bt_str, 1) then begin print, 'Error executing string: ' + bt_str message, !error_state.msg ; e.g. 'Unable to allocate memory...' end bt_str = 'readu, bt_lun, ' + bt_varnames[bt_i] if not execute(bt_str, 1) then begin print, 'Error executing string: ' + bt_str message, !error_state.msg ; e.g. 'Unable to allocate memory...' end end end bt_str = 'bt_offset_int = long64(' $ + strmid(bt_offset_str, bt_offset_is_relative ? 1 : 0) $ + ')' if not execute(bt_str, 1) then begin bt_strip_str = 'LONG64: ' if strpos(!error_state.msg, bt_strip_str) eq 0 then begin bt_msg = strmid(!error_state.msg, strlen(bt_strip_str)) end $ else begin bt_msg = !error_state.msg end bt_msg = ['Invalid offset.', '(' + bt_msg + ')'] free_lun, bt_lun return, 0 end if bt_num_dims gt 0 then begin bt_str = 'bt_field = make_array(' $ + 'dimension=' $ + bt_dims_str $ + ', ' $ + 'type=bt_typecode(bt_state.wType)' $ + ')' if not execute(bt_str, 1) then begin bt_msg = ['Invalid dimension.', '(' +!error_state.msg + ')'] free_lun, bt_lun return, 0 end end $ else begin bt_field = fix(0, type=bt_typecode(bt_state.wType)) end if size(bt_field, /n_dimensions) ne bt_num_dims $ and 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.' $ ] free_lun, bt_lun return, 0 end if bt_offset_is_relative then begin point_lun, -bt_lun, bt_pos ; Get the current position. if strpos(bt_offset_str, '>') eq 0 then begin bt_str = 'point_lun, bt_lun, bt_pos + bt_offset_int' end $ else begin bt_str = 'point_lun, bt_lun, (bt_pos - bt_offset_int) > 0' end end $ else begin bt_str = 'point_lun, bt_lun, bt_offset_int' end if not execute(bt_str, 1) then begin bt_msg = ['Invalid offset.', '(', + !error_state.msg + ')'] free_lun, bt_lun return, 0 end bt_str = 'readu, bt_lun, bt_field' if not execute(bt_str, 1) then begin bt_msg = [ $ 'Specified field cannot be read.', $ '(' + !error_state.msg + ')' $ ] free_lun, bt_lun return, 0 end free_lun, bt_lun ; ; Swap endian-ness. ; if size(bt_field, /type) gt 1 then begin if strupcase(bt_state.endian) eq 'LITTLE' then begin byteorder, bt_field, /swap_if_big_endian end if strupcase(bt_state.endian) eq 'BIG' then begin byteorder, bt_field, /swap_if_little_endian end end ; ; Verify the value we read. ; if bt_do_verify then begin if bt_verify_str eq '' then begin bt_msg = 'Verify value is empty.' return, 0 end if not execute('bt_verify_value = ' + bt_verify_str, 1) then begin bt_msg = ['Invalid verify value.', '(' + !error_state.msg + ')'] return, 0 end if size(bt_verify_value, /n_dimensions) ne 0 then begin bt_msg = 'Verify value must be a scalar.' return, 0 end bt_tname = size(bt_verify_value, /tname) if bt_tname eq 'STRING' $ or bt_tname eq 'POINTER' $ or bt_tname eq 'OBJREF' then begin bt_msg = 'Verify value cannot be a ' + bt_tname + '.' return, 0 end bt_str = 'bt_test = bt_field eq ' + bt_verify_str if not execute(bt_str, 1) then begin print, 'Error executing string: ' + bt_str message, !error_state.msg end if bt_test eq 0 then begin bt_msg =[ $ 'Field does not equal verify value.', $ 'Field = ' + strcompress(string(bt_field, /print)) $ ] return, 0 end end end bt_msg = 'Entry is valid.' return, 1 ; We made it. 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 end 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 end if indx lt 0 then $ message, 'Negative array index.' siz = size(array) if siz[0] eq 0 then begin array = [array] siz = size(array) end 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 end $ else begin array[indx, 0] = val end 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 end if indx lt 0 then $ message, 'Negative array index.' siz = size(array) if siz[0] eq 0 then begin message, 'Array is undefined.' end 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) ; Undefine array. return end ; ;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 end 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 end 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] $ ) end 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' if !version.os_family eq 'MacOS' then begin widget_control, $ state.wTable, $ set_value=value end $ else begin widget_control, $ state.wTable, $ set_value=value, $ ysize=state.fieldcount, $ column_labels=state.column_labels end 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) $ ] end 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: begin widget_control, (*pState).wAbsoluteRadio, set_value=0 end endcase widget_control, (*pState).wFormulaCheckbox, get_value=formula_chkbx if formula_chkbx eq 1 $ or value eq '>' $ or value eq '<' $ or value eq '' then begin (*pState).offset_str = value return endif widget_control, (*pState).wAbsoluteRadio, get_value=radio on_ioerror, cast_failed if radio eq 1 then $ str = strcompress( $ long64(strmid(value, 1)), $ /remove_all $ ) $ else $ str = strcompress( $ long64(value), $ /remove_all $ ) on_ioerror, NULL ; ; Allow a leading zero, just to be nice. ; if str ne 0 then begin if strpos(value, '>0') eq 0 $ or strpos(value, '<0') eq 0 $ or strpos(value, '0' ) eq 0 then begin str = '0' + str end end ; if radio eq 1 then begin if strpos(value, '>') eq 0 then $ str = '>' + str if strpos(value, '<') eq 0 then $ str = '<' + str end if value ne str or strpos(value, '-') ne -1 then begin beep ; Illegal character in VALUE. case event.type of 0: offset = event.offset - 1 1: offset = event.offset $ - strlen(event.str) $ - 1 ; correct? 2: offset = 1 endcase end $ else begin offset = event.offset (*pState).offset_str = value end widget_control, event.id, set_value=(*pState).offset_str widget_control, event.id, set_text_select=offset end end (*pState).wAbsoluteRadio: begin if event.value eq 0 then begin (*pState).offset_str = strmid( $ (*pState).offset_str, $ stregex((*pState).offset_str, '^[<>]') + 1 $ ) end $ else $ if stregex((*pState).offset_str, '^[<>]') eq -1 $ then $ (*pState).offset_str = $ (*pState).offset_sign + (*pState).offset_str 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 end end widget_control, $ (*pState).wDimFormulaCheckbox, $ sensitive=event.index gt 0 if event.index eq 0 then $ widget_control, (*pState).wDimFormulaCheckbox, set_value=0 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).wType: begin end (*pState).wModifyOK: begin widget_control, /hourglass if not bt_entry_is_valid(*pState, msg=msg) then begin void = dialog_message(msg, /error) return end 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] end 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 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 widget_control, $ (*pState).wFormulaCheckbox, $ get_value=offset_is_formula bt_put_val_into_array, $ *(*pState).pAllowFormulas, $ ; The array. offset_is_formula, $ ; The value. (*pState).current_field_indx, $ insert=(*pState).we_are_inserting, $ debug=(*pState).debug widget_control, $ (*pState).wDimFormulaCheckbox, $ get_value=dims_are_formulas bt_put_val_into_array, $ *(*pState).pDimAllowFormulas, $ ; The array. dims_are_formulas, $ ; 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) end bt_update_field_display, *pState, /highlight_current_row widget_control, event.top, /destroy end (*pState).wDimFormulaCheckbox: begin ; ; Purge non-digit characters. ; if (event.select)[0] eq 0 then begin; for i=0,(*pState).max_idl_dims-1 do begin bt_purge_non_digits, {id:(*pState).wDimText[i]} end end end (*pState).wModifyCancel: begin widget_control, event.top, /destroy end (*pState).wFormulaCheckbox: begin ; ; Purge illegal characters. ; if event.select[0] eq 0 then begin widget_control, (*pState).wAbsoluteRadio, get_value=radio widget_control, (*pState).wOffset, get_value=offset_str offset_str = offset_str[0] if radio[0] eq 1 then begin on_ioerror, set_str_to_zero if 1 then begin str = strcompress( $ abs(long64(strmid(offset_str, 1))), $ /remove_all $ ) if str ne 0 then begin ; Allow a leading zero. if strpos(offset_str, '>0') eq 0 $ or strpos(offset_str, '<0') eq 0 then begin str = '0' + str end end end $ else begin set_str_to_zero: str = '0' message, /reset end on_ioerror, NULL widget_control, $ (*pState).wOffset, $ set_value=(*pState).offset_sign + str (*pState).offset_str = (*pState).offset_sign + str end $ else begin on_ioerror, set_str_to_zero2 if 1 then begin str = strcompress( $ abs(long64(offset_str)), $ /remove_all $ ) if str ne 0 then begin ; Allow a leading zero. if strpos(offset_str, '0') eq 0 then begin str = '0' + str end end end $ else begin set_str_to_zero2: str = '0' message, /reset end on_ioerror, NULL widget_control, (*pState).wOffset, set_value=str (*pState).offset_str = str end end end (*pState).wVerifyCheckbox: begin if event.select eq 0 then $ widget_control, (*pState).wVerifyText, set_value='' widget_control, (*pState).wVerifyText, sensitive=event.select end else: endcase for i = 0,(*pState).max_idl_dims-1 do begin if event.id eq (*pState).wDimText[i] then begin widget_control, (*pState).wDimFormulaCheckbox, get_value=dim_is_expr if not dim_is_expr[0] then begin bt_purge_non_digits, event end end end return cast_failed: ; Leading character is illegal. beep 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, $ title=((*pState).we_are_inserting ? 'New' : 'Modify') + ' Field' $ ) (*pState).wFieldName = cw_field(tlb, Title='Field name: ', xsize=45) wRowBase = widget_base(tlb, /row, xpad=0, ypad=0) wOffsetBase = widget_base(wRowBase, /col, /frame) 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 $ ) (*pState).wFormulaCheckbox = cw_bgroup( $ wOffsetBase, $ /nonexclusive, $ 'Allow an expression for the offset' $ ) wRightBase = widget_base(wRowBase, /column, /align_center) void = widget_label(wRightBase, value='When a file is read with') (*pState).wMessageLabel = widget_label( $ wRightBase, $ value='this template, this field shall be:', $ /dynamic_resize $ ) wReturnBase = widget_base(wRightBase, /row, ypad=0) ; Parallels wVerifyBase. (*pState).wReturn = cw_bgroup( $ wReturnBase, $ /nonexclusive, $ ; 'Returned in the resulting structure' $ 'Returned in the result' $ ) widget_control, (*pState).wReturn, set_value=[1] (*pState).wVerifyBase = widget_base(wRightBase, /row, frame=0, ypad=0) (*pState).wVerifyCheckbox = cw_bgroup( $ (*pState).wVerifyBase, $ /nonexclusive, $ 'Verified equal to:' $ ) (*pState).wVerifyText = widget_text( $ widget_base((*pState).wVerifyBase, /row, xpad=0), $ scr_xsize=70, $ sensitive=0, $ /editable $ ) (*pState).wType = widget_droplist( $ tlb, $ 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-imaginary pair of floats)', $ 'Double-Precision Complex (pair of doubles)' $ ], $ uvalue=[ $ ; IDL typecodes corresponding to each droplist entry. 1, $ 2, $ 3, $ 14, $ 4, $ 5, $ 12, $ 13, $ 15, $ 6, $ 9 $ ] $ ) wDimensionsBase = widget_base(tlb, /frame, /column) wRowBase = widget_base(wDimensionsBase, row=1) void = widget_label(wRowBase, val='Dimensions: ') (*pState).wNumDims = widget_droplist( $ wRowBase, $ value=[ $ '0 (scalar)', $ strcompress(indgen((*pState).max_idl_dims) + 1, /remove_all) $ ], $ title=' Number of dimensions:' $ ) (*pState).wDimFormulaCheckbox = cw_bgroup( $ wDimensionsBase, $ /nonexclusive, $ 'Allow expressions for dimension sizes' $ ) w2x4Base = widget_base(wDimensionsBase, col=2, xpad=0, ypad=0) for i=0,2 do begin (*pState).wIndividualDimBase[i] = widget_base( $ w2x4Base, column=2, $ /base_align_lef, $ /frame $ ) void = widget_label( $ (*pState).wIndividualDimBase[i], $ value=(['1st', '2nd', '3rd'])[i] + ' dimension:' $ ) wSubBase = widget_base((*pState).wIndividualDimBase[i], /row) void = widget_label(wSubBase, value='Size: ') (*pState).wDimText[i] = widget_text( $ wSubBase, $ /editable, $ /all_events $ ) (*pState).wReverseCheckbox[i] = cw_bgroup( $ (*pState).wIndividualDimBase[i], $ 'Reverse', $ /nonexcl, $ ypad=0 $ ) end for i=3,(*pState).max_idl_dims-1 do begin (*pState).wIndividualDimBase[i] = widget_base( $ w2x4Base, $ column=1, $ /base_align_left, $ /frame $ ) void = widget_label( $ (*pState).wIndividualDimBase[i], $ value=strcompress(i+1, /remove_all) + 'th dimension:' $ ) wSubBase = widget_base((*pState).wIndividualDimBase[i], /row) void = widget_label(wSubBase, value='Size: ') (*pState).wDimText[i] = widget_text( $ wSubBase, $ /editable, $ /all_events $ ) end wRowBase = widget_base(tlb, /row) (*pState).wModifyOK = widget_button(wRowBase, value=' OK ') (*pState).wModifyCancel = widget_button(wRowBase, Value='Cancel') widget_control, tlb, /realize if not (*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).wFormulaCheckbox, $ set_value=(*(*pState).pAllowFormulas)[(*pState).current_field_indx] widget_control, $ (*pState).wDimFormulaCheckbox, $ set_value=(*(*pState).pDimAllowFormulas)[ $ (*pState).current_field_indx $ ] 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 $ ] end 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 $ ] end 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] end num_dims = widget_info((*pState).wNumDims, /droplist_select) widget_control, $ (*pState).wDimFormulaCheckbox, $ sensitive=num_dims gt 0 for i=0,(*pState).max_idl_dims-1 do $ widget_control, $ (*pState).wIndividualDimBase[i], $ sensitive=i lt num_dims 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 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 end end 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: begin (*pState).endian = (['native', 'little', 'big'])[event.index] end (*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 and 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 $ and event.sel_right eq 5 $ and (*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 $ ] end ; ; 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)) $ ] end end 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 end if keyword_set(group_leader_is_fabricated) then $ 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) end ; ; Re-throw the error. ; message, !error_state.msg + ' ' + !error_state.sys_msg end ; if keyword_set(debug) then begin catch, /cancel on_error, 0 end if !version.os_family eq 'vms' then $ message, 'Binary_Template is not supported on VMS.', /noname ; ;Test TEMPLATE argument. ; ; Use ARG_PRESENT so undefined variables get passed into rb_template_is_valid ; which will then throw appropriate error message if n_elements(template) gt 0 or arg_present(template) then begin if not 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 end end size(filename, /n_dimensions) gt 1: begin message, 'First argument must be scalar.', /noname end 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 (findfile(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 end ; ;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 end $ else begin if not widget_info(group_leader, /valid_id) then $ message, 'Specified GROUP_LEADER is invalid.', /noname group_leader_is_fabricated = 0b end ; tlb = widget_base( $ ; Top-level base. /column, $ title='Binary Template', $ group_leader=group_leader, $ /modal $ ) 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, 40, 50, 90, 70, 50, 50] ; good? endcase column_labels = [ $ 'Name', $ 'Offset', $ '# Dims', $ 'Size', $ 'Type', $ 'Return', $ 'Verify' $ ] if not keyword_set(n_rows) then begin if n_elements(template) gt 0 then begin n_rows = 6 > template.fieldcount < 12 end $ else begin n_rows = 6 end end if n_rows le 0 then begin message, 'N_ROWS must be positive.' end wTable = widget_table( $ wFrameBase, $ column_labels=column_labels, $ xsize=n_elements(column_labels), $ scr_xsize=total(column_widths) $ + (!version.os_family ne 'Windows' ? 60 : 0), $ 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), $ wFormulaCheckbox: 0L, $ wType: 0L, $ wMessageLabel: 0L, $ wDimFormulaCheckbox: 0L, $ wModifyOK: 0L, $ wModifyCancel: 0L, $ column_labels: column_labels, $ n_rows: n_rows, $ n_scroll_rows: n_rows, $ we_are_inserting: 0L, $ cancel: 1b, $ 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] switch !D.NAME of 'MAC': 'X': 'WIN': DEVICE, GET_SCREEN_SIZE=screen_size endswitch 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 end ; ;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 or (*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. end $ 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. end ; ;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) end ; return, result end