PRO ZOOMER_CLEANUP, tlb ; The purpose of this program is to delete the pixmap window ; when the program ZOOMER is destroyed. Get the info structure, ; which holds the pixmap window index number and delete the window. ; Make sure info is defined before you use it. Widget_Control, tlb, Get_UValue=info IF N_Elements(info) NE 0 THEN WDelete, info.pixIndex END ; of ZOOMER_CLEANUP ********************************************************** PRO ZOOMER_PROCESS_EVENTS, event ; This event handler ONLY responds to button down events from the ; draw widget. If it gets a DOWN event, it does three things: (1) sets ; the static and dynamic corners of the zoom box, (2) changes the ; event handler for the draw widget to ZOOMER_DRAWBOX and turns on MOTION ; events, and (3) takes over color index 1 of the color table for the ; zoom box drawing color. possibleEventTypes = [ 'DOWN', 'UP', 'MOTION', 'SCROLL' ] thisEvent = possibleEventTypes(event.type) IF thisEvent NE 'DOWN' THEN RETURN ; Must be DOWN event to get here, so get info structure. Widget_Control, event.top, Get_UValue=info, /No_Copy ; Set the static corners of the box to current ; cursor location. info.xs = event.x info.ys = event.y ; Change the event handler for the draw widget and turn MOTION ; events ON. Widget_Control, event.id, Event_Pro='ZOOMER_DRAWBOX', $ Draw_Motion_Events=1 ; Take over color index 1 for the zoom box drawing color. Store the ; current (r,g,b) values for color index 1 so you can restore the ; current colors after the zoom box is drawn. TVLct, r, g, b, /Get info.r_old = r(1) info.g_old = g(1) info.b_old = b(1) ; Put the info structure back into its storage location. Widget_Control, event.top, Set_UValue=info, /No_Copy END ; of ZOOMER_PROCESS_EVENTS ***************************************************** PRO ZOOMER_DRAWBOX, event ; This event handler continuously draws and erases the zoom box until it ; receives an UP event from the draw widget. Then it turns draw widget motion ; events OFF and changes the event handler for the draw widget back to ; ZOOMER_PROCESS_EVENTS. ; Get the info structure out of the top-level base. Widget_Control, event.top, Get_UValue=info, /No_Copy ; What type of an event is this? possibleEventTypes = [ 'DOWN', 'UP', 'MOTION', 'SCROLL' ] thisEvent = possibleEventTypes(event.type) IF thisEvent EQ 'UP' THEN BEGIN ; If this is an UP event, you need to erase the zoombox, restore ; the user's color table, turn motion events OFF, set the ; draw widget's event handler back to ZOOMER_PROCESS_EVENTS, and ; draw the "zoomed" plot in both the draw widget and the pixmap. ; Erase the zoombox one final time by copying the plot from the pixmap. WSet, info.drawIndex Device, Copy = [0, 0, info.zxsize, info.zysize, 0, 0, info.pixIndex] ; Restore the user's color table. TVLct, info.r_old, info.g_old, info.b_old, 1 ; Turn motion events off and redirect the events to ZOOMER_PROCESS_EVENTS. Widget_Control, event.id, Draw_Motion_Events=0, $ Event_Pro='ZOOMER_PROCESS_EVENTS' ; Draw the "zoomed" plot. Start by getting the new limits to the plot ; (i.e., the LAST zoom box outline). x = [info.xs, event.x] y = [info.ys, event.y] ; Make sure the x values are ordered as [min, max]. IF info.xs GT event.x THEN x = [event.x, info.xs] ; Convert the x device coordinates to data coordinates. coords = Convert_Coord(x, y, /Device, /To_Data) ; Make sure the x coordinates are within the data boundaries of the plot. x1 = !X.CRange(0) > coords(0,0) < !X.CRange(1) x2 = !X.CRange(0) > coords(0,1) < !X.CRange(1) ; Draw the "zoomed" plot in both the draw widget and the pixmap. yDataRange = [Min(info.data),Max(info.data)] Plot, info.data, XRange=[x1,x2], XStyle=1, YRange=yDataRange WSet, info.pixIndex Plot, info.data, XRange=[x1,x2], XStyle=1, YRange=yDataRange ; Put the info structure back into its storage location and then, out of here! Widget_Control, event.top, Set_UValue=info, /No_Copy RETURN ENDIF ; thisEvent = UP ; Most of the action in this event handler occurs here while we are waiting ; for an UP event to occur. As long as we don't get it, keep erasing the ; old zoom box and drawing a new one. ; Erase the old zoom box. WSet, info.drawIndex Device, Copy = [0, 0, info.zxsize, info.zysize, 0, 0, info.pixIndex] ; Update the dynamic corner of the zoom box to the current cursor location. info.xd = event.x info.yd = event.y ; Load a green color in color index 1 to draw the zoom box with. TVLct, 0B, 255B, 0B, 1 ; Draw the zoom box. PlotS, [info.xs, info.xs, info.xd, info.xd, info.xs], $ [info.ys, info.yd, info.yd, info.ys, info.ys], $ /Device, Color=1 ; Put the info structure back into its storage location. Widget_Control, event.top, Set_UValue=info, /No_Copy END ; of ZOOMER_DRAWBOX ****************************************************************** PRO ZOOMER, data, Zoom_XSize=zxsize, Zoom_YSize=zysize, $ Group=group ; This procedure allows the user to "zoom" into the data plot ; by drawing a box around the part of the data to zoom into. ; The zoom box will be drawn and erased by using a pixmap and ; the "Device Copy" technique. ; On an error condition, return to the main level of IDL. On_Error, 1 ; Was data passed into the procedure? If not, exit with error message. IF N_Params() EQ 0 THEN $ Message, 'Must pass ZOOMER one positional parameter' ; Check for keywords. Set defaults if necessary. IF N_Elements(zxsize) EQ 0 THEN zxsize = 300 IF N_Elements(zysize) EQ 0 THEN zysize = 300 ; Create a top-level base for this program. No resizing of this base. tlb = Widget_Base(Title='Zoomer Window', TLB_Frame_Attr=1) ; The only thing in the top-level base is a draw widget. ; The draw widget will have its own event handler. draw = Widget_Draw(tlb, XSize=zxsize, YSize=zysize, $ Button_Events=1, Event_Pro='ZOOMER_PROCESS_EVENTS') ; Realize the program. Widget_Control, tlb, /Realize ; Get the window index number of the draw widget. ; Make the draw widget the current graphics window ; and draw the plot of the data in it. Make the ; X data range exactly fit the data. Widget_Control, draw, Get_Value=drawIndex WSet, drawIndex Plot, data, XRange=[0, N_Elements(data)], XStyle=1, $ YRange=[Min(data),Max(data)] ; Create a pixmap window the same size as the draw widget window. ; Store its window index number in a local variable. Draw the same ; plot you just put in the draw widget in the pixmap window. Window, /Free, XSize=zxsize, YSize=zysize, /Pixmap pixIndex = !D.Window Plot, data, XRange=[0, N_Elements(data)], XStyle=1, $ YRange=[Min(data),Max(data)] ; Create an info structure to hold information required by the program. info = { $ data:data, $ ; The data to be plotted. zxsize:zxsize, $ ; The X size of the draw widget. zysize:zysize, $ ; The Y size of the draw widget. drawIndex:drawIndex, $ ; The draw window index number. pixIndex:pixIndex, $ ; The pixmap window index number. xs:0, $ ; X static corner of the zoom box. ys:0, $ ; Y static corner of the zoom box. xd:0, $ ; X dynamic corner of the zoom box. yd:0, $ ; Y dynamic corner of the zoom box. r_old:0, $ ; The user's red color value. g_old:0, $ ; The user's green color value. b_old:0 } ; The user's blue color value. ; Store the info structure in the user value of the top-level base. Widget_Control, tlb, Set_UValue=info, /No_Copy ; Register this program and set up the event loop. XManager, 'Zoomer', tlb, Cleanup='Zoomer_Cleanup', Group_Leader=group END ; of ZOOMER ****************************************************************************