; $Id: demo_record.pro,v 1.15 2001/01/15 22:26:40 scottm Exp $ ; ; Copyright (c) 1992-2001, Research Systems, Inc. All rights reserved. ; Unauthorized reproduction prohibited. ;+ ; NAME: ; DEMO_RECORD ; ; PURPOSE: ; Append IDL commands to an ASCII file ; of IDL commands in the current directory. If the ; file does not exist, it will get created. ; ; Edited output from DEMO_RECORD is played by DEMO_TOUR. ; ; CATEGORY: ; Demos ; ; CALLING SEQUENCE: ; demo_record, arg ; ; INPUTS: ; Arg: The event being recorded. Typically this is a ; widget event structure. (e.g. {WIDGET_BUTTON, ID:...}) ; ; Handler_Name (optional): A procedure that takes ARG. The name ; of the procedure will appear in the recorded ; command string. By default this name is ; the name of the procedure in which DEMO_RECORD ; was invoked. ; ; KEYWORD PARAMETERS: ; Filename: (Input). Set this keyword to the name of the file ; to which DEMO_RECORD will write. The default name is ; "recording.txt". If filename is explicitly set to '', ; then no recording is performed. ; ; CW: (Input). An array of widget IDs. Events recorded ; for widgets on this list are recorded with a ; WIDGET_CONTROL, SET_VALUE command or ; WIDGET_CONTROL, SET_BUTTON command preceding them. ; This is useful for compund widgets such as CW_BGROUP ; radio buttons, and for buttons in exclusive or ; non-exclusive bases. ; ; OUTPUTS: none ; ; SIDE EFFECTS: ; A file in the current directory can be created or appended. ; ; RESTRICTIONS: ; Please note: demo_record is not a "complete solution" ; for end-user use. This is because: ; ; 1. The file that results from using DEMO_RECORD ; is not necessarily "ready-to-run", and may require ; hand editing. In particular, applications which use ; unusual widgets (e.g. applications which use compound ; widgets that do not send events with a "value:" ; field that contains a value that can be sensibly ; passed to WIDGET_CONTROL, SET_VALUE=...) may be ; difficult (or impossible?) to record successfully. ; ; 2. Within an application, invokations of DEMO_RECORD ; must be used/placed carefully (typically one call to ; DEMO_RECORD in each event handler) to ensure that the ; resulting series of recorded commands is not missing ; needed events, or does not have unwanted events. ; ; 3. Only events for widgets that have a suitable UNAME ; can be successfully recorded. The commands output by ; DEMO_RECORD include calls to DEMO_FIND_WID(), which ; only works for widgets that have a UNAME ; suitable for use with DEMO_FIND_WID(). ; ; 4. DEMO_RECORD makes its recording with the ; assumption that HANDLER_NAME is a procedure ; (not a function). ; ; 5. DEMO_RECORD relies on the convention that ; pseudo events (generated by explicit calls to an ; event handler routine in IDL .pro program code) ; contain 0 in the ARG.handler field. (Such events are ; skipped by DEMP_RECORD; they are not recorded.) ; ; 6. DEMO_RECORD assumes that ARG is an event structure with ; id, top and handler fields. ; ; PROCEDURE: ; Typically, one line of text is appended to an ; ASCII file with each invocation of DEMO_RECORD. ; The line is of the form... ; ; , ; ; ...where is a HANDLER_NAME, and ; is an ASCII string like ; {WIDGET_BUTTON: ID: ...etc...} ; ; If CW is supplied, and ARG.ID is in CW, then two lines ; of text are recorded. The first is of the form... ; ; widget_control, ..., set_value= ; or ; widget_control, ..., set_button= ; ; ...and the second is of the form... ; ; , ; ; ...as discussed above. ;- pro demo_record, arg, handler_name, filename=filename, cw=cw on_error, 2 ; Return to caller on error. if n_elements(filename) eq 0 then $ filename = 'recording.txt' if filename eq '' then $ return if lmgr(/demo) then $ message, 'cannot DEMO_RECORD in IDL timed demo mode.' if n_elements(handler_name) eq 0 then begin help, calls=calls handler_name = (strtok(calls[1], ' ', /extract))[0] end ; ;If the event was not generated by user, then don't ;record it. When explicit calls to an event ;handler are made in code, it is conventional to supply 0L ;for the handler field of the event. Here we are relying ;on that convention. ; if arg.handler le 0L then begin return end ; ;If event is exiting the entire demo system, don't record it. ;DEMO_TOUR uses one invokation of 'demo' and then assumes all ;recordings leave you in the demo system. The DEMO_TOUR assumes ;it will not have to invoke 'demo' again. ; tagn = tag_names(arg, /structure_name) if (tagn eq 'WIDGET_KILL_REQUEST' and $ arg.id eq demo_find_wid("demo:mainWinBase")) $ or (arg.id eq demo_find_wid("demo:quit")) then $ return if arg.id eq demo_find_wid("demo:main_pulldown") then begin if arg.value eq 1 then $ return end ; ;Open file for output. ;We are opening and closing the file each time DEMO_RECORD ;is invoked (typically), which is probably slow, but it seems ;fast enough. ; get_lun, lun openw, lun, filename, /append ; ;If we are recording an event that happens to be for one of the ;supplied "CW" compund widgets. Record a command to set the ;compund widget's value. ; if n_elements(cw) ge 1 then begin if max(cw eq arg.id) eq 1 then begin if tag_names(arg, /structure_name) eq 'WIDGET_BUTTON' then begin printf, lun, 'widget_control, demo_find_wid("' $ + widget_info(arg.id, /uname) $ + '"), set_button=' $ + strtrim(arg.select, 2) end $ else begin printf, lun, 'widget_control, demo_find_wid("' $ + widget_info(arg.id, /uname) $ + '"), set_value=' $ + strtrim(arg.value, 2) end end end ; ;Try some tests to make sure that the Widget has a good UNAME. ; uname = widget_info(arg.id, /uname) if uname eq '' then $ message, 'Widget does not have a UNAME' if strpos(uname, ':') le 0 then $ message, 'UNAME does not have a colon-delimited prefix.' xreg_name = strmid(uname, 0, strpos(uname, ':')) if xregistered(xreg_name) eq 0 then $ message, 'Not xregistered: ' + xreg_name ; ev = arg ; Make a local copy. ; id = 'demo_find_wid("' + widget_info(arg.id, /uname) + '")' top = 'demo_find_wid("' + widget_info(arg.top, /uname) + '")' handler = 'demo_find_wid("' + widget_info(arg.handler, /uname) + '")' ; ;The DEMO_TOUR playback routine assumes that recordings are made on ;a 2048 x 2048 pixel draw widget. ; if tagn eq 'WIDGET_DRAW' then begin geometry = widget_info( $ demo_find_wid(widget_info(arg.id, /uname)), $ /geometry $ ) ev.x = round(arg.x / (geometry.draw_xsize - 1.) * 2047) ev.y = round(arg.y / (geometry.draw_ysize - 1.) * 2047) end printf, lun, handler_name + ', {' + tagn + ([', ',''])[tagn eq ''], format='($,a)' printf, lun, 'ID: ' + id + ', ', format='($,a)' printf, lun, 'TOP: ' + top + ', ', format='($,a)' printf, lun, 'HANDLER: ' + handler + ([' ', ', '])[n_tags(arg) gt 3], format='($,a)' for i=3,n_tags(arg)-2 do begin printf, lun, (tag_names(arg))[i], ':', ev.(i), format='($,3a)' case size(arg.(i), /tname) of 'LONG': printf, lun, 'L', format='($,a)' 'BYTE': printf, lun, 'B', format='($,a)' 'DOUBLE': printf, lun, 'D', format='($,a)' else: endcase printf, lun, ', ', format='($,4a)' end i = n_tags(arg) - 1 if i gt 2 then begin printf, lun, (tag_names(arg))[i], ': ', ev.(i), format='($,3a)' case size(arg.(i), /tname) of 'LONG': printf, lun, 'L', format='($,a)' 'BYTE': printf, lun, 'B', format='($,a)' 'DOUBLE': printf, lun, 'D', format='($,a)' else: endcase end printf, lun, '}' free_lun, lun end