;+ ; NAME: ; PS_FORM ; ; PURPOSE: ; This function puts up a form the user can manipulate to configure a ; PostScript device driver. The function result (ONLY if the user ; selects the ACCEPT button) can be sent directly to the DEVICE procedure ; by means of its _Extra keyword. ; ; MAJOR TOPICS: ; Device Drivers, Hardcopy Output, PostScript Output ; ; PROCEDURE: ; This is a pop-up form widget. It is a modal or blocking widget. ; Keywords appropriate for the PostScript DEVICE command are returned. ; ; Use your LEFT mouse button to move the "Plot Window" around the page. ; Use your RIGHT mouse button to draw your own "Plot Window" on the page. ; ; HELP: ; formInfo = PS_FORM(/Help) ; ; CALLING SEQUENCE: ; formInfo = PS_FORM(xoffset, yoffset, Cancel=cancelButton) ; ; OPTIONAL INPUTS: ; ; XOFFSET -- Optional xoffset of the top-level base of PS_Form. Default is ; to try to center the form on the display. ; ; YOFFSET -- Optional yoffset of the top-level base of PS_Form. Default is ; to try to center the form on the display. ; ; KEYWORD PARAMETERS: ; ; BITS_PER_PIXEL -- The initial configuration of the bits per pixel button. ; ; CANCEL -- This is an OUTPUT keyword. It is used to check if the user ; selected the "Cancel" button on the form. Check this variable rather ; than the return value of the function, since the return value is designed ; to be sent directly to the DEVICE procedure. The varible is set to 1 if ; the user selected the "Cancel" button. Otherwise, it is set to 0. ; ; COLOR -- The initial configuration of the color switch. ; ; DEFAULTS -- A stucture variable of the same type and structure as the ; RETURN VALUE of PS_FORM. It will set initial conditions. This makes ; it possible to start PS_FORM up again with the same values it had the ; last time it was called. For example: ; ; mysetup = PS_FORM() ; newsetup = PS_FORM(Defaults=mysetup) ; ; NOTE: Using the DEFAULTS keyword will nullify any of the other ; DEVICE-type keywords listed above (e.g., XSIZE, ENCAPSULATED, etc.) ; ; ENCAPSULATED -- The initial configuration of the encapsulated switch. ; ; FILENAME -- The initial filename to be used on the form. ; ; HELP -- Prints a helpful message in the output log. ; ; INCHES -- The initial configuration of the inches/cm switch. ; ; INITIALIZE -- If this keyword is set, the program immediately returns the ; "localdefaults" structure. This gives you the means to configue the ; PostScript device without interrupting the user. ; ; LANDSCAPE -- The initial configuration of the landscape/portrait switch. ; ; LOCALDEFAULTS -- A structure like the DEFAULTS structure. Used if the ; "Local Defaults" button is pressed in the form. This gives you the ; opportunity to have a "local" as well as "system" default setup. ; If this keyword is not used, the procedure Set_Personal_Local_Defaults ; is called. Use this procedure (see below) to define your own local ; defaults. ; ; XOFFSET -- The initial XOffSet of the PostScript page. ; ; YOFFSET -- The initial YOffSet of the PostScript page. ; ; XSIZE -- The initial XSize of the PostScript page. ; ; YSIZE -- The initial YSize of the PostScript page. ; ; RETURN VALUE: ; ; formInfo = { PS_FORM_INFO, $ ; xsize:0.0, $ ; The x size of the plot ; xoff:0.0, $ ; The x offset of the plot ; ysize:0.0, $ ; The y size of the plot ; yoff:0.0 $ ; The y offset of the plot ; filename:'', $ ; The name of the output file ; inches:0 $ ; Inches or centimeters? ; color:0, $ ; Color on or off? ; bits_per_pixel:0, $ ; How many bits per image pixel? ; encapsulated:0,$ ; Encapsulated or regular PostScript? ; landscape:0 } ; Landscape or portrait mode? ; ; USAGE: ; ; The calling procedure for this function will look something like this: ; ; formInfo = PS_FORM(Cancel=cancelButton) ; ; IF NOT cancelButton THEN BEGIN ; ; oldDevice = !D.Name ; Set_Plot, "PS" ; Device, _Extra=formInfo ; ; Enter Your Graphics Commands Here! ; ; Device, /Close ; Set_Plot, oldDevice ; ; ENDIF ; ; MAJOR FUNCTIONS and PROCEDURES: ; ; None. Designed to work originally in conjunction with GWindow, ; a resizable graphics window. ; ; MODIFICATION HISTORY: ; ; Written by: David Fanning, RSI, March 1995. ; Given to attendees of IDL training courses. ; ; Modified to work when grapics device set to PostScript: 6 May 95. ; Modified to configure initial conditions via keywords: 13 October 95. ; Modified to load personal local defaults if LocalDefaults keyword not ; used: 3 Nov 95. ; Found and fixed bits_per_pixel error in Local Defaults setting ; procedure: 3 Nov 95. ; Modified to produce initial plot box with the same aspect ratio as ; the current graphics window. (XSIZE or YSIZE keywords overrule this ; behavior.) 22 Apr 96. ; Fixed annoying behavior of going to default-sized plot box when selecting ; the Landscape or Portrait option. Now keeps current plot box size. ; 22 Apr 96. ; Made the size and offset text widgets a little bigger and changed the ; size and offset formatting from F4.2 to F5.2 to accomodate larger plot ; box sizes. 29 Apr 96. ; Fixed a bug in the filename text widget that caused a crash when a CR ; was hit. 3 Sept 96. ; Added the Initialize keyword to immediately return the "localdefaults" ; structure. 27 Oct 96. ; Fixed another problem with the BITS_PER_PIXEL keyword. 27 Oct 96. ; Made the return value a named structure of the name PS_FORM_INFO. ; 3 Nov 96. ; Discovered and fixed a problem whereby YOFFSET was set incorrectly if ; LOCALDEFAULTS was used instead of DEFAULTS keyword. 3 Nov 96. ; Fixed bug in how Portrait mode was set using YSIZE and XSIZE keywords. ; 25 Nov 96. ; Fixed a bug in how YOFFSET was calculated when in Landscape mode. 27 ;Nov 96. ; ;- Pro Set_Personal_Local_Defaults, ptr ; If you don't use the LocalDefaults keyword, you can use ; this procedure to define local defaults for yourself. ; This procedure will be called if the keyword is not used. ; If you don't want to set local defaults, don't put anything ; in this procedure. personalDefaults = { PS_FORM_INFO, $ xsize:7.0, $ ; The x size of the plot xoff:1.0, $ ; The x offset of the plot ysize:5.0, $ ; The y size of the plot yoff:3.0, $ ; The y offset of the plot filename:'davidf.ps', $ ; The name of the output file inches:1, $ ; Inches on. color:0, $ ; Color off. bits_per_pixel:8, $ ; 8 bits per image pixel. encapsulated:0,$ ; Encapsulated file off. landscape:0 } ; Portrait mode on. Handle_Value, ptr, personalDefaults, /Set, /No_Copy END ;******************************************************************* Function PlotBox_Coords, xsize, ysize, xoff, yoff, inches ; This function converts sizes and offsets to appropriate ; Device coordinates for drawing the PLOT BOX on the PostScript ; page. The return value is a [2,5] array. returnValue = IntArr(2,5) IF inches EQ 0 THEN BEGIN xs = xsize * 10.0 / 2.54 ys = ysize * 10.0 / 2.54 xof = xoff * 10.0 / 2.54 yof = yoff * 10.0 / 2.54 ENDIF ELSE BEGIN xs = xsize * 10.0 ys = ysize * 10.0 xof = xoff * 10.0 yof = yoff * 10.0 ENDELSE xcoords = Round([xof, xof+xs, xof+xs, xof, xof]) ycoords = Round([yof, yof, yof+ys, yof+ys, yof]) returnValue(0,*) = xcoords returnValue(1,*) = ycoords RETURN, returnValue END ;******************************************************************* Pro Set_Local_Defaults, event ; Define local variables xsize = 0 ysize = 0 xoff = 0 yoff = 0 landscape = 0 encapsulated = 0 color = 0 filename = '' bits_per_pixel = 0 inches = 0 ; Get the info structure out of the TLB. Widget_Control, event.top, Get_UValue=info, /No_Copy ; Are there local defaults loaded in the program? check = Handle_Info(info.localDefaultPtr) IF check EQ 0 THEN BEGIN ok = Widget_Message('No local defaults loaded in program.') Widget_Control, event.top, Set_UValue=info, /No_Copy RETURN ENDIF ; Get the local defaults structure and process it. ; Special processing for YOffset. Handle_Value, info.localDefaultPtr, defaults yoff_flag = 0 names = Tag_Names(defaults) yoff_test = Where(names EQ 'YOFF') IF yoff_test(0) GT 0 THEN yoff_flag = 1 ELSE yoff_flag = 0 FOR j=0,N_Elements(names)-1 DO BEGIN IF names(j) NE 'YOFF' THEN BEGIN str = names(j) + '= defaults.' + names(j) dummy = Execute(str) ENDIF ENDFOR ; Process YOffset if yoff_flag is set. (ASSUMING xoff is DEFINED ; and passed in with the DEFAULTS!!) IF yoff_flag THEN BEGIN yof = Where(names EQ 'YOFF') IF landscape EQ 1 AND inches EQ 0 THEN BEGIN yoff = xoff str = 'xoff = 27.94 - defaults.' + names(yof) ENDIF IF landscape EQ 1 AND inches EQ 1 THEN BEGIN yoff = xoff str = 'xoff = 11.0 - defaults.' + names(yof) ENDIF IF landscape EQ 0 AND inches EQ 0 THEN $ str = 'yoff = defaults.' + names(yof) IF landscape EQ 0 AND inches EQ 1 THEN $ str = 'yoff = defaults.' + names(yof) dummy = Execute(str(0)) ENDIF IF landscape EQ 1 THEN BEGIN ; Make the draw widget the current graphics window WSet, info.wid ; Erase the old window and draw the Landscape page outline ; and the default Landscape box outline Erase ; Make the draw widget have a charcoal background color. TV, Replicate(info.charcoal,114,114) PlotS, info.landbox_x, info.landbox_y, /Device, Color=info.pagecolor coords = PlotBox_Coords(xsize, ysize, xoff, yoff, inches) PlotS, coords(0,*), coords(1,*), Color=info.boxcolor, /Device ; Draw the Landscape page outline in the pixmap WSet, info.pixwid Erase ; Make the draw widget have a charcoal background color. TV, Replicate(info.charcoal,114,114) PlotS, info.landbox_x, info.landbox_y, /Device, Color=info.pagecolor ; Make the draw widget the current graphics window WSet, info.wid ; Change the labels to their default values xsizeStr = String(xsize, Format='(F5.2)') ysizeStr = String(ysize, Format='(F5.2)') xoffStr = String(xoff, Format='(F5.2)') yoffStr = String(yoff, Format='(F5.2)') ; Put the new default values into the appropriate boxes on the form Widget_Control, info.xsize, Set_Value=xsizeStr Widget_Control, info.ysize, Set_Value=ysizeStr Widget_Control, info.xoff, Set_Value=xoffStr Widget_Control, info.yoff, Set_Value=yoffStr ; Set up the landscape x and y default maximums and minimums info.lbox_xmax = Max(coords(0,*)) info.lbox_ymax = Max(coords(1,*)) info.lbox_xmin = Min(coords(0,*)) info.lbox_ymin = Min(coords(1,*)) ENDIF ELSE BEGIN ; Make the draw widget the current graphics window WSet, info.wid ; Erase the old window and draw the Portrait page outline ; and the default Portrait box outline Erase ; Make the draw widget have a charcoal background color. TV, Replicate(info.charcoal,114,114) PlotS, info.portraitbox_x, info.portraitbox_y, /Device, Color=info.pagecolor coords = PlotBox_Coords(xsize, ysize, xoff, yoff, inches) PlotS, coords(0,*), coords(1,*), Color=info.boxcolor, /Device ; Draw the Portrait page outline on the pixmap and then reset the ; current graphics window WSet, info.pixwid Erase ; Make the draw widget have a charcoal background color. TV, Replicate(info.charcoal,114,114) PlotS, info.portraitbox_x, info.portraitbox_y, /Device, $ Color=info.pagecolor WSet, info.wid ; Change the labels to their default values xsizeStr = String(xsize, Format='(F5.2)') ysizeStr = String(ysize, Format='(F5.2)') xoffStr = String(xoff, Format='(F5.2)') yoffStr = String(yoff, Format='(F5.2)') ; Put the new default values into the appropriate boxes on the form Widget_Control, info.xsize, Set_Value=xsizeStr Widget_Control, info.ysize, Set_Value=ysizeStr Widget_Control, info.xoff, Set_Value=xoffStr Widget_Control, info.yoff, Set_Value=yoffStr ; Set up the portrait x and y maximums and minimums info.pbox_xmax = Max(coords(0,*)) info.pbox_ymax = Max(coords(1,*)) info.pbox_xmin = Min(coords(0,*)) info.pbox_ymin = Min(coords(1,*)) ENDELSE ; Set encapsulation buttons. IF encapsulated EQ 0 THEN BEGIN Widget_Control, info.encap_on, Set_Button=0 Widget_Control, info.encap_off, Set_Button=1 info.encapsulated = encapsulated ENDIF ELSE BEGIN Widget_Control, info.encap_on, Set_Button=1 Widget_Control, info.encap_off, Set_Button=0 info.encapsulated = encapsulated ENDELSE ; Set color buttons. IF color EQ 0 THEN BEGIN Widget_Control, info.col_on, Set_Button=0 Widget_Control, info.col_off, Set_Button=1 info.color = color ENDIF ELSE BEGIN Widget_Control, info.col_on, Set_Button=1 Widget_Control, info.col_off, Set_Button=0 info.color = color ENDELSE ; Set inch/cm buttons. IF inches EQ 0 THEN BEGIN Widget_Control, info.inch, Set_Button=0 Widget_Control, info.cm, Set_Button=1 info.inches = inches ENDIF ELSE BEGIN Widget_Control, info.inch, Set_Button=1 Widget_Control, info.cm, Set_Button=0 info.inches = inches ENDELSE ; Set bits_per_pixel buttons. CASE bits_per_pixel OF 2: BEGIN Widget_Control, info.bit2, Set_Button=1 Widget_Control, info.bit8, Set_Button=0 Widget_Control, info.bit4, Set_Button=0 info.bits_per_pixel = 2 END 4: BEGIN Widget_Control, info.bit2, Set_Button=0 Widget_Control, info.bit4, Set_Button=1 Widget_Control, info.bit8, Set_Button=0 info.bits_per_pixel = 4 END 8: BEGIN Widget_Control, info.bit2, Set_Button=0 Widget_Control, info.bit8, Set_Button=1 Widget_Control, info.bit4, Set_Button=0 info.bits_per_pixel = 8 END ENDCASE ; Set default filename. Widget_Control, info.filename, Set_Value=filename ; Set protrait/landscape button. IF landscape EQ 0 THEN BEGIN Widget_Control, info.land, Set_Button=0 Widget_Control, info.port, Set_Button=1 info.landscape = landscape ENDIF ELSE BEGIN Widget_Control, info.land, Set_Button=1 Widget_Control, info.port, Set_Button=0 info.landscape = landscape ENDELSE Widget_Control, event.top, Set_UValue=info, /No_Copy END ;******************************************************************* Pro Set_System_Defaults, event ; This event handler sets up the system default values. There will ; be different defaults based on whether the form is in landscape ; or portrait mode when the button is selected. ; Get the info stucture. Widget_Control, event.top, Get_UValue=info, /No_Copy IF info.landscape EQ 1 THEN BEGIN ; Make the draw widget the current graphics window WSet, info.wid ; Erase the old window and draw the Landscape page outline ; and the default Landscape box outline Erase ; Make the draw widget have a charcoal background color. TV, Replicate(info.charcoal,114,114) PlotS, info.landbox_x, info.landbox_y, /Device, Color=info.pagecolor PlotS, info.lplotbox_x, info.lplotbox_y, Color=info.boxcolor, /Device ; Draw the Landscape page outline in the pixmap WSet, info.pixwid Erase ; Make the draw widget have a charcoal background color. TV, Replicate(info.charcoal,114,114) PlotS, info.landbox_x, info.landbox_y, /Device, Color=info.pagecolor ; Make the draw widget the current graphics window WSet, info.wid ; Change the labels to their default values xsize = '24.13' ysize = '17.78' xoff = '1.91' yoff = '1.91' ; Put the new default values into the appropriate boxes on the form Widget_Control, info.xsize, Set_Value=xsize Widget_Control, info.ysize, Set_Value=ysize Widget_Control, info.xoff, Set_Value=xoff Widget_Control, info.yoff, Set_Value=yoff ; Set up the landscape x and y default maximums and minimums info.lbox_xmax = 106 info.lbox_ymax = 82 info.lbox_xmin = 8 info.lbox_ymin = 8 ENDIF ELSE BEGIN ; Make the draw widget the current graphics window WSet, info.wid ; Erase the old window and draw the Portrait page outline ; and the default Portrait box outline Erase ; Make the draw widget have a charcoal background color. TV, Replicate(info.charcoal,114,114) PlotS, info.portraitbox_x, info.portraitbox_y, /Device, $ Color=info.pagecolor PlotS, info.pplotbox_x, info.pplotbox_y, Color=info.boxcolor, /Device ; Draw the Portrait page outline on the pixmap and then reset the ; current graphics window WSet, info.pixwid Erase ; Make the draw widget have a charcoal background color. TV, Replicate(info.charcoal,114,114) PlotS, info.portraitbox_x, info.portraitbox_y, /Device, $ Color=info.pagecolor WSet, info.wid ; Change the labels to their default values xsize = '17.78' ysize = '12.70' xoff = '1.91' yoff = '12.70' ; Put the new default values into the appropriate boxes on the form Widget_Control, info.xsize, Set_Value=xsize Widget_Control, info.ysize, Set_Value=ysize Widget_Control, info.xoff, Set_Value=xoff Widget_Control, info.yoff, Set_Value=yoff ; Set up the portrait x and y maximums and minimums info.pbox_xmax = 82 info.pbox_ymax = 106 info.pbox_xmin = 8 info.pbox_ymin = 60 ENDELSE ; Set encapsulation buttons. Widget_Control, info.encap_on, Set_Button=0 Widget_Control, info.encap_off, Set_Button=1 info.encapsulated = 0 ; Set color buttons. Widget_Control, info.col_on, Set_Button=0 Widget_Control, info.col_off, Set_Button=1 info.color = 0 ; Set inch/cm buttons. Widget_Control, info.inch, Set_Button=0 Widget_Control, info.cm, Set_Button=1 info.inches = 0 ; Set bits_per_pixel buttons. Widget_Control, info.bit2, Set_Button=0 Widget_Control, info.bit8, Set_Button=0 Widget_Control, info.bit4, Set_Button=1 info.bits_per_pixel = 4 ; Set default filename. filename = 'idl.ps' Widget_Control, info.filename, Set_Value=filename Widget_Control, event.top, Set_UValue=info, /No_Copy END ;******************************************************************* Pro Ignore_Event, event END ;******************************************************************* Function What_Button_Type, event ; Checks event.type to find out what kind of button ; was clicked in a draw widget. This is NOT an event handler. type = ['DOWN', 'UP', 'MOTION', 'SCROLL'] Return, type(event.type) END ;******************************************************************* Function What_Button_Pressed, event ; Checks event.press to find out what kind of button ; was pressed in a draw widget. This is NOT an event handler. button = ['NONE', 'LEFT', 'MIDDLE', 'NONE', 'RIGHT'] Return, button(event.press) END ;******************************************************************* Function What_Button_Released, event ; Checks event.release to find out what kind of button ; was released in a draw widget. This is NOT an event handler. button = ['NONE', 'LEFT', 'MIDDLE', 'NONE', 'RIGHT'] Return, button(event.release) END ;******************************************************************* Pro PSFormNumEvents, event ; If an event comes here, read the offsets and sizes from the ; form and draw the appropriately sized box in the draw widget. Widget_Control, event.top, Get_UValue= info, /No_Copy ; Get current values for offset and sizes Widget_Control, info.xsize, Get_Value=xsize Widget_Control, info.ysize, Get_Value=ysize Widget_Control, info.xoff, Get_Value=xoff Widget_Control, info.yoff, Get_Value=yoff xsize = xsize(0) ysize = ysize(0) xoff = xoff(0) yoff = yoff(0) ; Don't let the user pick sizes that don't make sense ; Sizes must fit on page along with minimum offsets IF info.inches EQ 1 THEN Begin ; Calculation in inches IF info.landscape EQ 0 THEN Begin ; Portrait Mode xsize = 0.25 > xsize < 8.25 ysize = 0.25 > ysize < 10.75 IF xsize + xoff GT 8.25 THEN xoff = 8.5 - xsize IF ysize + yoff GT 10.75 THEN yoff = 11.0 - ysize ENDIF ELSE Begin ; Landscape Mode ysize = 0.25 > ysize < 8.25 xsize = 0.25 > xsize < 10.75 IF xsize + xoff GT 10.75 THEN xoff = 11.0 - xsize IF ysize + yoff GT 8.25 THEN yoff = 8.5 - ysize ENDELSE ENDIF ELSE Begin ; Calculation in centimeters IF info.landscape EQ 0 THEN Begin ; Portrait Mode xsize = 1 > xsize < 20.95 ysize = 1 > ysize < 27.30 IF xsize + xoff GT 20.95 THEN xoff = 20.95 - xsize IF ysize + yoff GT 27.30 THEN yoff = 27.30 - ysize ENDIF ELSE Begin ; Landscape Mode ysize = 1 > ysize < 20.95 xsize = 1 > xsize < 27.30 IF xsize + xoff GT 27.30 THEN xoff = 27.30 - xsize IF ysize + yoff GT 20.95 THEN yoff = 20.95 - ysize ENDELSE ENDELSE ; Put correct sizes back into the text fields Widget_Control, info.xsize, $ Set_Value=StrTrim(String(xsize, Format='(F5.2)'), 2) Widget_Control, info.ysize, $ Set_Value=StrTrim(String(ysize, Format='(F5.2)'), 2) Widget_Control, info.xoff, Set_Value=StrTrim(String(xoff, Format='(F5.2)'), 2) Widget_Control, info.yoff, Set_Value=StrTrim(String(yoff, Format='(F5.2)'), 2) ; Convert sizes to Device coordinates IF info.inches EQ 1 THEN Begin ; 1 inch equals 10 pixels xsize = xsize * 10.0 xoff = xoff * 10.0 ysize = ysize * 10.0 yoff = yoff * 10.0 ENDIF ELSE Begin ; 2.54 cm equals 1 inch equals 10 pixels xsize = xsize * 10.0 / 2.54 xoff = xoff * 10.0 / 2.54 ysize = ysize * 10.0 / 2.54 yoff = yoff * 10.0 / 2.54 ENDELSE ; Make the draw widget the current graphics window WSet, info.wid ; Copy the page outline from the pixmap Device, Copy=[0, 0, 114, 114, 0, 0, info.pixwid] ; Draw the appropriately sized box PlotS, [xoff, xoff+xsize, xoff+xsize, xoff, xoff], Color=info.boxcolor, $ [yoff, yoff, yoff+ysize, yoff+ysize, yoff], /Device ; Update the box parameters IF info.landscape EQ 0 THEN Begin ; Portrait mode info.pbox_xmax = (xoff + xsize) info.pbox_xmin = xoff info.pbox_ymax = (yoff + ysize) info.pbox_ymin = yoff ENDIF ELSE Begin ; Landscape mode info.lbox_xmax = (xoff + xsize) info.lbox_xmin = xoff info.lbox_ymax = (yoff + ysize) info.lbox_ymin = yoff ENDELSE ; Put the info structure back into the top-level base Widget_Control, event.top, Set_UValue=info, /No_Copy END ;******************************************************************* Pro PSFormMoveBox, event ; This is the event handler that allows the user to "move" ; the plot box around in the page window. It will set the ; event handler back to "PSFormDrawEvents" when it senses an ; "UP" draw button event and it will also turn Draw_Motion_Events ; OFF. ; Get the info structure out of the top-level base. Widget_Control, event.top, Get_UValue=info, /No_Copy whatButtonType = What_Button_Type(event) IF whatButtonType EQ 'UP' THEN Begin Widget_Control, info.draw, Draw_Motion_Events=0, $ ; Motion events off Event_Pro='PSFormDrawEvents' ; Change to normal processing ; Copy page outline from the pixmap Device, Copy=[0, 0, 114, 114, 0, 0, info.pixwid] ; Draw the final box shape Plots, [info.xmin, info.xmin, info.xmax, info.xmax, info.xmin], $ Color=info.boxcolor, [info.ymin, info.ymax, info.ymax, info.ymin, $ info.ymin], /Device ; Update new offsets IF info.inches EQ 0 THEN Begin ; Offset in Centimeters xoff = (info.xmin/10.0) * 2.54 yoff = (info.ymin/10.0) * 2.54 ENDIF ELSE Begin ; Offset in Inches xoff = (info.xmin/10.0) yoff = (info.ymin/10.0) ENDELSE ; Update new offsets in the offset boxes on the form. Widget_Control, info.xoff, $ Set_Value=StrTrim(String(xoff, Format='(F5.2)'), 2) Widget_Control, info.yoff, $ Set_Value=StrTrim(String(yoff, Format='(F5.2)'), 2) ; Update the new box parameters in the info structure IF info.landscape EQ 0 THEN Begin ; Portrait mode info.pbox_xmax = info.xmax info.pbox_xmin = info.xmin info.pbox_ymax = info.ymax info.pbox_ymin = info.ymin ENDIF ELSE Begin ; Landscape mode info.lbox_xmax = info.xmax info.lbox_xmin = info.xmin info.lbox_ymax = info.ymax info.lbox_ymin = info.ymin ENDELSE ; Put the info structure back in the top-level base and RETURN Widget_Control, event.top, Set_UValue=info, /No_Copy Return ENDIF ; You come to this section of the code for all events except ; an UP button event. Most of the action in this event handler ; occurs here. ; Make the draw widget the current graphics window WSet, info.wid ; Copy the page outline from the pixmap into the window, thus ; erasing the last box you drew. Device, Copy=[0, 0, 114, 114, 0, 0, info.pixwid] ; Calculate the length of of the current box xlength = info.xmax - info.xmin ylength = info.ymax - info.ymin ; Calculate location of lower-left corner of box. ; Constrain the box to lie inside the page outline. IF info.landscape EQ 0 THEN Begin ; Portrait Mode test = info.xmin + event.x - info.mouse_x info.xmin = 2.5 > test info.xmin = info.xmin < (86 - xlength) test = info.ymin + event.y - info.mouse_y info.ymin = 2.5 > test info.ymin = info.ymin < (111 - ylength) ENDIF ELSE Begin ; Landscape Mode test = info.xmin + event.x - info.mouse_x info.xmin = 2.5 > test info.xmin = info.xmin < (111 - xlength) test = info.ymin + event.y - info.mouse_y info.ymin = 2.5 > test info.ymin = info.ymin < (86 - ylength) ENDELSE ; Calculate upper-right corners of the box info.xmax = info.xmin + xlength info.ymax = info.ymin + ylength ; Draw the new box on the display Plots, [info.xmin, info.xmin, info.xmax, info.xmax, info.xmin], $ Color=info.boxcolor, [info.ymin, info.ymax, info.ymax, info.ymin, $ info.ymin], /Device ; Update the mouse pointer info.mouse_x = event.x info.mouse_y = event.y ; Put the info structure back into the top-level base. Widget_Control, event.top, Set_UValue=info, /No_Copy END ;******************************************************************* Pro PsFormDrawBox, event ; This event handler is summoned when a RIGHT button is clicked ; in the draw widget. It allows the user to draw the outline of a ; box with the mouse. It will continue drawing the new box shape ; until an UP event is detected. Then it will set the event handler ; back to PSFormDrawEvents and turn Draw_Motion_Events to OFF. ; Get the info structure out of the top-level base. Widget_Control, event.top, Get_UValue=info, /No_Copy whatButtonType = What_Button_Type(event) IF whatButtonType EQ 'UP' THEN Begin Widget_Control, info.draw, Draw_Motion_Events=0, $ ; Motion events off Event_Pro='PSFormDrawEvents' ; Change to normal processing ; Make the draw widget the current graphics window WSet, info.wid ; Copy the page outline from the pixmap Device, Copy=[0, 0, 114, 114, 0, 0, info.pixwid] ; Draw the final box shape PlotS, [info.xs, info.xs, info.xcur, info.xcur, info.xs], $ Color=info.boxcolor, [info.ys, info.ycur, info.ycur, info.ys, info.ys],$ /Device ; Update new box sizes and offsets xmax = (info.xs > info.xcur) xmin = (info.xs < info.xcur) ymax = (info.ys > info.ycur) ymin = (info.ys < info.ycur) IF info.inches EQ 0 THEN Begin ; Values in Centimeters (10 pixels/inch) xoff = (xmin/10.0 * 2.54) yoff = ymin/10.0 * 2.54 xsize = (xmax - xmin)/10.0 * 2.54 ysize = (ymax - ymin)/10.0 * 2.54 ENDIF ELSE Begin ; Values in Inches (10 pixels/inch) xoff = (xmin/10.0) yoff = (ymin/10.0) xsize = (xmax - xmin)/10.0 ysize = (ymax - ymin)/10.0 ENDELSE ; Update the new sizes in the size and offset boxes Widget_Control, info.xsize, $ Set_Value=StrTrim(String(xsize, Format='(F5.2)'), 2) Widget_Control, info.ysize, $ Set_Value=StrTrim(String(ysize, Format='(F5.2)'), 2) Widget_Control, info.xoff, $ Set_Value=StrTrim(String(xoff, Format='(F5.2)'), 2) Widget_Control, info.yoff, $ Set_Value=StrTrim(String(yoff, Format='(F5.2)'), 2) ; Update the box location IF info.landscape EQ 0 THEN Begin ; Portrait mode info.pbox_xmax = info.xcur > info.xs info.pbox_xmin = info.xcur < info.xs info.pbox_ymax = info.ycur > info.ys info.pbox_ymin = info.ycur < info.ys ENDIF ELSE Begin ; Landscape mode info.lbox_xmax = info.xcur > info.xs info.lbox_xmin = info.xcur < info.xs info.lbox_ymax = info.ycur > info.ys info.lbox_ymin = info.ycur < info.ys ENDELSE ; Put the info structure back into the top-level base and RETURN Widget_Control, event.top, Set_UValue=info, /No_Copy Return ENDIF ; This is the potion of the code that handles all events except for ; UP button events. The bulk of the work is done here. Basically, ; you need to erase the old box and draw a new box at the new ; location. Just keep doing this until you get an UP event. ; Make the draw widget be the current graphics window WSet, info.wid ; Copy the page outline from the pixmap Device, Copy=[0, 0, 114, 114, 0, 0, info.pixwid] ; Locate the current position of the cursor. Make sure it is ; located inside the page outline. IF info.landscape EQ 0 THEN Begin ; Portrait mode info.xcur = 2.5 > event.x < 84.5 info.ycur = 2.5 > event.y < 109.5 ENDIF ELSE Begin ; Landscape mode info.xcur = 2.5 > event.x < 109.5 info.ycur = 2.5 > event.y < 84.5 ENDELSE ; Draw the new box on the display Plots, [info.xs, info.xs, info.xcur, info.xcur, info.xs], $ Color=info.boxcolor, [info.ys, info.ycur, info.ycur, info.ys, info.ys], $ /Device ; Put the info structure back in the top-level base. Widget_Control, event.top, Set_UValue=info, /No_Copy END ;******************************************************************* Pro PSFormDrawEvents, event whatButtonType = What_Button_Type(event) IF whatButtonType NE 'DOWN' THEN Return ; Get info structure out of TLB Widget_Control, event.top, Get_UValue=info, /No_Copy whatButtonPressed = What_Button_Pressed(event) CASE whatButtonPressed OF 'RIGHT': Begin ; Resize the plot box interactively. Change the event handler ; to PSFormDrawBox. All subsequent events will be handled by ; PSFormDrawBox until an UP event is detected. Then you will ; return to this event handler. Also, turn motion events ON. Widget_Control, event.id, Event_Pro='PSFormDrawBox', $ Draw_Motion_Events=1 ; Portrait mode or landscape mode? Set constraints accordingly IF info.landscape EQ 0 THEN Begin ; Portrait mode info.xs = 2.5 > event.x < 85.0 info.ys = 2.5 > event.y < 110.0 info.xcur = 2.5 > event.x < 85.0 info.ycur = 2.5 > event.y < 110.0 ENDIF ELSE Begin ; Landscape mode info.xs = 2.5 > event.x < 110.0 info.ys = 2.5 > event.y < 85.0 info.xcur = 2.5 > event.x < 110.0 info.ycur = 2.5 > event.y < 85.0 ENDELSE Plots, [info.xs, info.xs, info.xcur, info.xcur, info.xs], $ Color=info.boxcolor, $ [info.ys, info.ycur, info.ycur, info.ys, info.ys], /Device End 'LEFT': Begin ; Resize the plot box interactively. Change the event handler ; to PSFormMoveBox. All subsequent events will be handled by ; PSFormMoveBox until an UP event is detected. Then you will ; return to this event handler. Also, turn motion events ON. ; Copy max and min values into the info structure from the ; current box size IF info.landscape EQ 0 THEN Begin ; Portrait mode info.xmax = info.pbox_xmax info.xmin = info.pbox_xmin info.ymax = info.pbox_ymax info.ymin = info.pbox_ymin ENDIF ELSE Begin ; Landscape mode info.xmax = info.lbox_xmax info.xmin = info.lbox_xmin info.ymax = info.lbox_ymax info.ymin = info.lbox_ymin ENDELSE ; Only move the box if the cursor is inside the box. ;If it is NOT, then RETURN. IF event.x LT info.xmin OR event.x GT info.xmax OR event.y $ LT info.ymin OR event.y GT info.ymax THEN Begin Widget_Control, event.top, Set_UValue=info, /No_Copy Return ENDIF ; Relocate the event handler and turn motion events ON. Widget_Control, event.id, Event_Pro='PSFormMoveBox', $ Draw_Motion_Events=1 ; Locate the cursor point inside the box that will be moved info.mouse_x = event.x info.mouse_y = event.y End ELSE: ; Middle button ignored in this program ENDCASE ; Put the info structure back into the top-level base Widget_Control, event.top, Set_UValue=info, /No_Copy END ;******************************************************************* Pro PS_Form_Event, event ; This is the main event handler for PS_FORM. It handles ; the exclusive buttons on the form. Other events on the form ; will have their own event handlers. ; Get the name of the event structure name = Tag_Names(event, /Structure_Name) ; If name is NOT "WIDGET_BUTTON" or this is not a button ; selection event, RETURN. IF name NE 'WIDGET_BUTTON' OR event.select NE 1 THEN Return ; Get the info structure out of the top-level base Widget_Control, event.top, Get_UValue=info, /No_Copy ; Get the User Value of the Button Widget_Control, event.id, Get_UValue=thisButton ; Respond appropriately to whatever button was selected CASE thisButton OF 'INCHES': Begin ; Get current centimeter values Widget_Control, info.xsize, Get_Value=xsize Widget_Control, info.ysize, Get_Value=ysize Widget_Control, info.xoff, Get_Value=xoff Widget_Control, info.yoff, Get_Value=yoff ; Set values to inches and make a string xsize = StrTrim(String(Float(xsize) / 2.54, Format='(F5.2)'), 2) ysize = StrTrim(String(Float(ysize) / 2.54, Format='(F5.2)'), 2) xoff = StrTrim(String(Float(xoff) / 2.54, Format='(F5.2)'), 2) yoff = StrTrim(String(Float(yoff) / 2.54, Format='(F5.2)'), 2) ; Put inch values on the labels Widget_Control, info.xsize, Set_Value=xsize Widget_Control, info.ysize, Set_Value=ysize Widget_Control, info.xoff, Set_Value=xoff Widget_Control, info.yoff, Set_Value=yoff ; Update the info structure to indicate that current status is inches info.inches = 1 End 'CENTIMETERS': Begin ; Get current inch values Widget_Control, info.xsize, Get_Value=xsize Widget_Control, info.ysize, Get_Value=ysize Widget_Control, info.xoff, Get_Value=xoff Widget_Control, info.yoff, Get_Value=yoff ; Set values to centimeters and make a string xsize = StrTrim(String(Float(xsize) * 2.54, Format='(F5.2)'), 2) ysize = StrTrim(String(Float(ysize) * 2.54, Format='(F5.2)'), 2) xoff = StrTrim(String(Float(xoff) * 2.54, Format='(F5.2)'), 2) yoff = StrTrim(String(Float(yoff) * 2.54, Format='(F5.2)'), 2) ; Put inch values on the labels Widget_Control, info.xsize, Set_Value=xsize Widget_Control, info.ysize, Set_Value=ysize Widget_Control, info.xoff, Set_Value=xoff Widget_Control, info.yoff, Set_Value=yoff ; Update the info structure to indicate that current ; status is centimeters info.inches = 0 End 'COLOR_ON': Begin ; Update the info structure to indicate that current status ; is COLOR ON info.color = 1 End 'COLOR_OFF': Begin ; Update the info structure to indicate that current status ; is COLOR OFF info.color = 0 End 'BITS2': Begin ; Update the info structure to indicate that current status is BITS=2 info.bits_per_pixel = 2 End 'BITS4': Begin ; Update the info structure to indicate that current status is BITS=4 info.bits_per_pixel = 4 End 'BITS8': Begin ; Update the info structure to indicate that current status is BITS=8 info.bits_per_pixel = 8 End 'LANDSCAPE': Begin ; Going to landscape mode. Have to change the draw widget window. ; Make the draw widget the current graphics window WSet, info.wid ; Erase the old window and draw the Landscape page outline ; and the default Landscape box outline Erase ; Make the draw widget have a charcoal background color. TV, Replicate(info.charcoal,114,114) ; Get the curent sizes of the box. Widget_Control, info.xsize, Get_Value=xsize Widget_Control, info.ysize, Get_Value=ysize xsize = Float(xsize(0)) ysize = Float(ysize(0)) ; Calculate new offsets. IF info.inches EQ 1 THEN xoff = (11.0 - xsize) / 2.0 IF info.inches EQ 0 THEN xoff = (27.95 - xsize) / 2.0 IF info.inches EQ 1 THEN yoff = (8.5 - ysize) / 2.0 IF info.inches EQ 0 THEN yoff = (21.60 - ysize) / 2.0 ; Constrain user sizes and offsets to fit on the page. IF info.inches EQ 0 THEN BEGIN xsize = 0.64 > xsize < 27.3 ysize = 0.64 > ysize < 20.95 xoff = 0.64 > xoff < 27.3 yoff = 0.64 > yoff < 20.95 ENDIF IF info.inches EQ 1 THEN BEGIN xsize = 0.25 > xsize < 10.75 ysize = 0.25 > ysize < 8.25 xoff = 0.25 > xoff < 10.75 yoff = 0.25 > yoff < 8.25 ENDIF ; Get the box coordinates. box = PlotBox_Coords(xsize, ysize, xoff, yoff, info.inches) PlotS, info.landbox_x, info.landbox_y, /Device, Color=info.pagecolor PlotS, box, Color=info.boxcolor, /Device ; Draw the Landscape page outline in the pixmap WSet, info.pixwid Erase ; Make the draw widget have a charcoal background color. TV, Replicate(info.charcoal,114,114) PlotS, info.landbox_x, info.landbox_y, /Device, Color=info.pagecolor ; Make the draw widget the current graphics window WSet, info.wid ; Change the labels to their default values xsize = String(xsize, Format='(F5.2)') ysize = String(ysize, Format='(F5.2)') xoff = String(xoff, Format='(F5.2)') yoff = String(yoff, Format='(F5.2)') ; Put the new default values into the appropriate boxes on the form Widget_Control, info.xsize, Set_Value=xsize Widget_Control, info.ysize, Set_Value=ysize Widget_Control, info.xoff, Set_Value=xoff Widget_Control, info.yoff, Set_Value=yoff ; Set up the landscape x and y default maximums and minimums info.lbox_xmax = Max(box(0,*)) info.lbox_ymax = Max(box(1,*)) info.lbox_xmin = Min(box(0,*)) info.lbox_ymin = Min(box(1,*)) ; Set landscape mode info.landscape = 1 End 'PORTRAIT': Begin ; Going to landscape mode. Have to change the draw widget window. ; Make the draw widget the current graphics window WSet, info.wid ; Erase the old window and draw the Portrait page outline ; and the default Portrait box outline Erase ; Get the curent sizes of the box. Widget_Control, info.xsize, Get_Value=xsize Widget_Control, info.ysize, Get_Value=ysize xsize = Float(xsize(0)) ysize = Float(ysize(0)) ; Calculate new offsets. IF info.inches EQ 1 THEN xoff = (8.5 - xsize) / 2.0 IF info.inches EQ 0 THEN xoff = (21.6 - xsize) / 2.0 IF info.inches EQ 1 THEN yoff = (11.0 - ysize) / 2.0 IF info.inches EQ 0 THEN yoff = (27.95 - ysize) / 2.0 ; Constrain user sizes and offsets to fit on the page. IF info.inches EQ 0 THEN BEGIN xsize = 0.64 > xsize < 27.3 ysize = 0.64 > ysize < 20.95 xoff = 0.64 > xoff < 27.3 yoff = 0.64 > yoff < 20.95 ENDIF IF info.inches EQ 1 THEN BEGIN xsize = 0.25 > xsize < 10.75 ysize = 0.25 > ysize < 8.25 xoff = 0.25 > xoff < 10.75 yoff = 0.25 > yoff < 8.25 ENDIF ; Get the box coordinates. box = PlotBox_Coords(xsize, ysize, xoff, yoff, info.inches) ; Make the draw widget have a charcoal background color. TV, Replicate(info.charcoal,114,114) PlotS, info.portraitbox_x, info.portraitbox_y, /Device, $ Color=info.pagecolor PlotS, box, Color=info.boxcolor, /Device ; Draw the Portrait page outline on the pixmap and then reset the ; current graphics window WSet, info.pixwid Erase ; Make the draw widget have a charcoal background color. TV, Replicate(info.charcoal,114,114) PlotS, info.portraitbox_x, info.portraitbox_y, /Device, $ Color=info.pagecolor WSet, info.wid ; Change the labels to their default values xsize = String(xsize, Format='(F5.2)') ysize = String(ysize, Format='(F5.2)') xoff = String(xoff, Format='(F5.2)') yoff = String(yoff, Format='(F5.2)') ; Put the new default values into the appropriate boxes on the form Widget_Control, info.xsize, Set_Value=xsize Widget_Control, info.ysize, Set_Value=ysize Widget_Control, info.xoff, Set_Value=xoff Widget_Control, info.yoff, Set_Value=yoff ; Set up the portrait x and y maximums and minimums info.pbox_xmax = Max(box(0,*)) info.pbox_ymax = Max(box(1,*)) info.pbox_xmin = Min(box(0,*)) info.pbox_ymin = Min(box(1,*)) ; Set portrait mode info.landscape = 0 End 'ENCAPSULATED_ON': Begin ; Update the info structure to indicate that current status ; is ENCAPSULATED ON info.encapsulated = 1 End 'ENCAPSULATED_OFF': Begin ; Update the info structure to indicate that current status ; is ENCAPSULATED OFF info.encapsulated = 0 End 'ACCEPT': Begin ; The user wants to accept the information in the form. ; The procedure is to gather all the information from the ; form and then fill out a formInfo structure variable ; with the information. The formInfo structure is stored ; in a pointer. The reason for this is that we want the ; information to exist even after the form is destroyed. ; Gather the information from the form Widget_Control, info.filename, Get_Value=filename Widget_Control, info.xsize, Get_Value=xsize Widget_Control, info.ysize, Get_Value=ysize Widget_Control, info.xoff, Get_Value=xoff Widget_Control, info.yoff, Get_Value=yoff ; I am shielding the user from the strangeness of PostScript ; Landscape mode, in which the X and Y offsets are rotated ; 180 degrees. Thus, in the form, the offsets are calculated from ; the lower-left corner in both Landscape and Portrait mode. ; This means I have to monkey around to get the proper offsets ; if the form is in Landscape mode. IF info.landscape EQ 1 THEN Begin IF info.inches EQ 1 THEN pagesize = 11.0 ELSE pagesize = 11.0 * 2.54 temp = yoff ; Switch x and y offsets yoff = pagesize - xoff ; Offset really calculated from right ;of page xoff = temp ENDIF ; Fill out the formInfo structure with the information formInfo = { cancel:0, $ ; The CANCEL flag xsize:Float(xsize(0)), $ ; The x size of the plot xoff:Float(xoff(0)), $ ; The x offset of the plot ysize:Float(ysize(0)), $ ; The y size of the plot yoff:Float(yoff(0)), $ ; The y offset of the plot filename:filename(0), $ ; The name of the file inches:info.inches, $ ; Inches or centimeters? color:info.color, $ ; Color on or off? bits_per_pixel:info.bits_per_pixel, $ ; How many bits per pixel? encapsulated:info.encapsulated,$ ; Encapsulated file? landscape:info.landscape } ; Landscape or portrait mode? ; Put the formInfo structure into the location pointer ; to by the pointer Handle_Value, info.ptr, formInfo, /Set, /No_Copy ; Delete the pixmap window WDelete, info.pixwid ; Restore the user's color table TVLct, info.red, info.green, info.blue ; Destroy the PS_FORM widget program Widget_Control, event.top, /Destroy End 'CANCEL': Begin ; The user wants to cancel out of this form. We need a way to ; do that gracefully. Our method here is to set a "cancel" ; field in the formInfo structure. formInfo = {cancel:1} ; Put the formInfo structure into the location pointer to ; by the pointer Handle_Value, info.ptr, formInfo, /Set, /No_Copy ; Delete the pixmap window WDelete, info.pixwid ; Restore the user's color table TVLct, info.red, info.green, info.blue ; Destroy the PS_FORM widget program Widget_Control, event.top, /Destroy End ENDCASE ; Put the info structure back into the top-level base if the ; base is still in existence. If Widget_Info(event.top, /Valid) THEN $ Widget_Control, event.top, Set_UValue=info, /No_Copy END ;******************************************************************* Function PS_Form, xoffset, yoffset, Cancel=cancelButton, Help=help, $ XSize=xsize, YSize=ysize, XOffset=xoff, YOffset=yoff, $ Inches=inches, Color=color, Bits_Per_Pixel=bits_per_pixel, $ Encapsulated=encapsulated, Landscape=landscape, Filename=filename, $ Defaults=defaults, LocalDefaults=localDefaults, Initialize=initialize ; If the Help keyword is set, print some help information and return IF Keyword_Set(help) THEN BEGIN Doc_Library, 'PS_FORM' RETURN, 0 ENDIF ; Check other keyword parameters. IF N_Elements(localDefaults) EQ 0 THEN BEGIN localDefaultPtr = Handle_Create() Set_Personal_Local_Defaults, localDefaultPtr ENDIF ELSE localDefaultPtr = Handle_Create(Value=localDefaults) IF Keyword_Set(initialize) THEN BEGIN ; Get the local defaults and return them without asking the user ; for input. Handle_Value, localDefaultPtr, localdefaults, /No_Copy Handle_Free, localDefaultPtr RETURN, localdefaults ENDIF ; Special processing for YOffset. yoff_flag = 0 IF N_Elements(localdefaults) NE 0 THEN BEGIN names = Tag_Names(localdefaults) yoff_test = Where(names EQ 'YOFF') IF yoff_test(0) GT 0 THEN yoff_flag = 1 ELSE yoff_flag = 0 FOR j=0,N_Elements(names)-1 DO BEGIN IF names(j) NE 'YOFF' THEN BEGIN str = names(j) + '= localdefaults.' + names(j) dummy = Execute(str) ENDIF ENDFOR ENDIF IF N_Elements(defaults) NE 0 THEN BEGIN names = Tag_Names(defaults) yoff_test = Where(names EQ 'YOFF') IF yoff_test(0) GT 0 THEN yoff_flag = 1 ELSE yoff_flag = 0 FOR j=0,N_Elements(names)-1 DO BEGIN IF names(j) NE 'YOFF' THEN BEGIN str = names(j) + '= defaults.' + names(j) dummy = Execute(str) ENDIF ENDFOR ENDIF landscape = Keyword_Set(landscape) color = Keyword_Set(color) encapsulated = Keyword_Set(encapsulated) inches = Keyword_Set(inches) IF N_Elements(bits_per_pixel) EQ 0 THEN bits_per_pixel = 8 IF NOT (bits_per_pixel NE 2 OR bits_per_pixel NE 4 $ OR bits_per_pixel NE 8) THEN BEGIN ok = Widget_Message(['Bits_Per_Pixel keyword set with incorrect ' , $ 'value of ' + StrTrim(bits_per_pixel,2) + '.', '', $ 'Setting Bits_Per_Pixel = 8.']) bits_per_pixel = 8 ENDIF IF N_ELements(filename) EQ 0 THEN filename ='idl.ps' ; Process YOffset if yoff_flag is set. (ASSUMING xoff is DEFINED ; and passed in with the DEFAULTS or LOCALDEFAULTS!!) IF yoff_flag THEN BEGIN IF N_ELEMENTS(defaults) EQ 0 THEN defaults = localdefaults yof = Where(names EQ 'YOFF') IF landscape EQ 1 AND inches EQ 0 THEN BEGIN yoff = xoff str = 'xoff = 27.94 - defaults.' + names(yof) ENDIF IF landscape EQ 1 AND inches EQ 1 THEN BEGIN yoff = xoff str = 'xoff = 11.0 - defaults.' + names(yof) ENDIF IF landscape EQ 0 AND inches EQ 0 THEN $ str = 'yoff = defaults.' + names(yof) IF landscape EQ 0 AND inches EQ 1 THEN $ str = 'yoff = defaults.' + names(yof) dummy = Execute(str(0)) ENDIF ; Portrait mode IF landscape EQ 0 THEN BEGIN ; Check for undefined sizes and offsets. Use current window ; aspect ratio if no XSIZE or YSIZE keywords are used. IF N_Elements(xsize) EQ 0 AND N_Elements(ysize) EQ 0 THEN BEGIN IF !D.Window NE -1 THEN $ aspect = Float(!D.X_VSize) / !D.Y_VSize ELSE aspect = 1.0 IF aspect GE 1 THEN BEGIN xsize = 7.0 ysize = xsize / aspect ENDIF ELSE BEGIN ysize = 7.0 xsize = ysize * aspect ENDELSE IF inches EQ 0 THEN BEGIN xsize = xsize * 2.54 ysize = ysize * 2.54 ENDIF ENDIF IF N_Elements(xsize) EQ 0 THEN BEGIN IF inches EQ 0 THEN xsize = 17.75 IF inches EQ 1 THEN xsize = 17.75 / 2.54 ENDIF IF N_Elements(ysize) EQ 0 THEN BEGIN IF inches EQ 0 THEN ysize = 12.70 IF inches EQ 1 THEN ysize = 12.70 / 2.54 ENDIF IF N_Elements(xoff) EQ 0 THEN BEGIN IF inches EQ 1 THEN xoff = (8.5 - xsize) / 2.0 IF inches EQ 0 THEN xoff = (21.6 - xsize) / 2.0 ENDIF IF N_Elements(yoff) EQ 0 THEN BEGIN IF inches EQ 1 THEN yoff = (11.0 - ysize) / 2.0 IF inches EQ 0 THEN yoff = (27.95 - ysize) / 2.0 ENDIF ; Constrain user sizes and offsets to fit on the page. IF inches EQ 0 THEN BEGIN xsize = 0.64 > xsize < 20.95 ysize = 0.64 > ysize < 27.3 xoff = 0.64 > xoff < 20.95 yoff = 0.64 > yoff < 27.3 ENDIF IF inches EQ 1 THEN BEGIN xsize = 0.25 > xsize < 8.25 ysize = 0.25 > ysize < 10.75 xoff = 0.25 > xoff < 8.25 yoff = 0.25 > yoff < 10.75 ENDIF ENDIF ; Landscape mode IF landscape EQ 1 THEN BEGIN ; Check for undefined sizes and offsets. Use current window ; aspect ratio if no XSIZE or YSIZE keywords are used. IF N_Elements(xsize) EQ 0 AND N_Elements(ysize) EQ 0 THEN BEGIN IF !D.Window NE -1 THEN $ aspect = Float(!D.X_VSize) / !D.Y_VSize ELSE aspect = 1.0 IF aspect GE 1 THEN BEGIN xsize = 7.0 ysize = xsize / aspect ENDIF ELSE BEGIN ysize = 7.0 xsize = ysize * aspect ENDELSE IF inches EQ 0 THEN BEGIN xsize = xsize * 2.54 ysize = ysize * 2.54 ENDIF ENDIF ; Check for undefined sizes and offsets IF N_Elements(xsize) EQ 0 THEN BEGIN IF inches EQ 1 THEN xsize = 9.5 IF inches EQ 0 THEN xsize = 24.13 ENDIF IF N_Elements(ysize) EQ 0 THEN BEGIN IF inches EQ 1 THEN ysize = 7.0 IF inches EQ 0 THEN ysize = 17.78 ENDIF IF N_Elements(xoff) EQ 0 THEN BEGIN IF inches EQ 1 THEN xoff = (11.0 - xsize) / 2.0 IF inches EQ 0 THEN xoff = (27.94 - xsize) / 2.0 ENDIF IF N_Elements(yoff) EQ 0 THEN BEGIN IF inches EQ 1 THEN yoff = (8.5 - ysize) / 2.0 IF inches EQ 0 THEN yoff = (21.60 - ysize) / 2.0 ENDIF ; Constrain user sizes and offsets to fit on the page. IF inches EQ 0 THEN BEGIN xsize = 0.64 > xsize < 27.3 ysize = 0.64 > ysize < 20.95 xoff = 0.64 > xoff < 27.3 yoff = 0.64 > yoff < 20.95 ENDIF IF inches EQ 1 THEN BEGIN xsize = 0.25 > xsize < 10.75 ysize = 0.25 > ysize < 8.25 xoff = 0.25 > xoff < 10.75 yoff = 0.25 > yoff < 8.25 ENDIF ENDIF ; Put sizes and offsets into strings that can be placed in ; the text widgets. sizeFormat = '(F5.2)' xsize_str = String(xsize, Format=sizeFormat) ysize_str = String(ysize, Format=sizeFormat) xoff_str = String(xoff, Format=sizeFormat) yoff_str = String(yoff, Format=sizeFormat) ; This program cannot work if the graphics device is already set ; to PostScript. So if it is, set it to the native OS graphics device. ; Remember to set it back later. IF !D.Name EQ 'PS' THEN BEGIN oldName = 'PS' thisDevice = Byte(!Version.OS) thisDevice = StrUpCase( thisDevice(0:2) ) IF thisDevice EQ 'MAC' OR thisDevice EQ 'WIN' THEN Set_Plot, thisDevice $ ELSE Set_Plot, 'X' ENDIF ELSE oldName = !D.Name ; Check for optional offset parameters and give defaults if not passed Device, Get_Screen_Size=screenSize IF N_Elements(xoffset) EQ 0 THEN xoffset = (screenSize(0) - 600) / 2. IF N_Elements(yoffset) EQ 0 THEN yoffset = (screenSize(1) - 400) / 2. tlb = Widget_Base(Title='Configure PostScript Parameters', Column=1, $ XOffset=xoffset, YOffset=yoffset, TLB_Frame_Attr=9) ; Sub-bases for layout sizebase = Widget_Base(tlb, Row=1, Frame=1) numbase = Widget_Base(sizebase, Column=1) numsub1 = Widget_Base(numbase, Row=1) junk = Widget_Label(numsub1, Value=' Units: ') junksub = Widget_Base(numsub1, Row=1, /Exclusive) inch = Widget_Button(junksub, Value='Inches', UValue='INCHES') cm = Widget_Button(junksub, Value='Centimeters', $ UValue='CENTIMETERS') IF inches EQ 1 THEN Widget_Control, inch, Set_Button=1 ELSE $ Widget_Control, cm, Set_Button=1 numsub2 = Widget_Base(numbase, Row=1, Event_Pro='PSFormNumEvents') lab1base = Widget_Base(numsub2, Column=1, Base_Align_Center=1) junk = Widget_Label(lab1base, Value='XSize: ') junk = Widget_Label(lab1base, Value='XOffset: ') lab2base = Widget_Base(numsub2, Column=1, Base_Align_Center=1) xsizew = Widget_Text(lab2base, Scr_XSize=60, /Editable, $ Value=xsize_str, UValue=xsize) xoffw = Widget_Text(lab2base, Scr_XSize=60, /Editable, $ Value=xoff_str, UValue=xoff) lab3base = Widget_Base(numsub2, Column=1, Base_Align_Center=1) junk = Widget_Label(lab3base, Value='YSize: ') junk = Widget_Label(lab3base, Value='YOffset: ') lab2base = Widget_Base(numsub2, Column=1, Base_Align_Center=1) ysizew = Widget_Text(lab2base, Scr_XSize=60, /Editable, $ Value=ysize_str, UValue=ysize) yoffw = Widget_Text(lab2base, Scr_XSize=60, /Editable, $ Value=yoff_str, UValue=yoff) drawbase = Widget_Base(sizebase, Row=1) draw = Widget_Draw(drawbase, XSize=114, YSize=114, $ Event_Pro='PSFormDrawEvents', Button_Events=1) colorbase = Widget_Base(tlb, Row=1, Frame=1) colorlabel = Widget_Label(colorbase, Value='Color:') coloron = Widget_Base(colorbase, Row=1, /Exclusive, Frame=1) col_on = Widget_Button(coloron, Value='On', UValue='COLOR_ON') col_off = Widget_Button(coloron, Value='Off', UValue='COLOR_OFF') IF color EQ 0 THEN Widget_Control, col_off, Set_Button=1 ELSE $ Widget_Control, col_on, Set_Button=1 bitslabel = Widget_Label(colorbase, Value='Bits') bitsw = Widget_Base(colorbase, Row=1, /Exclusive, Frame=1) bit2 = Widget_Button(bitsw, Value='2', UValue='BITS2') bit4 = Widget_Button(bitsw, Value='4', UValue='BITS4') bit8 = Widget_Button(bitsw, Value='8', UValue='BITS8') CASE bits_per_pixel OF 2: Widget_Control, bit2, Set_Button=1 4: Widget_Control, bit4, Set_Button=1 8: Widget_Control, bit8, Set_Button=1 ENDCASE orientbase = Widget_Base(tlb, Row=1, Frame=1) junk = Widget_Label(orientbase, Value='Orientation: ') junkbase = Widget_Base(orientbase, Column=1, /Frame, /Exclusive) land = Widget_Button(junkbase, Value='Landscape', UValue='LANDSCAPE') port = Widget_Button(junkbase, Value='Portrait', UValue='PORTRAIT') IF landscape EQ 0 THEN Widget_Control, port, Set_Button=1 ELSE $ Widget_Control, land, Set_Button=1 junk = Widget_Label(orientbase, Value='Encapsulated: ') junkbase = Widget_Base(orientbase, Column=1, /Frame, /Exclusive) encap_on = Widget_Button(junkbase, Value='On', $ UValue='ENCAPSULATED_ON') encap_off = Widget_Button(junkbase, Value='Off', $ UValue='ENCAPSULATED_OFF') IF encapsulated EQ 0 THEN Widget_Control, encap_off, $ Set_Button=1 ELSE Widget_Control, encap_on, Set_Button=1 filenamebase = Widget_Base(tlb, Row=1, Frame=1) textlabel = Widget_Label(filenamebase, Value='Filename: ') ; Set up text widget with an event handler that ignores any event. filenamew = Widget_Text(filenamebase, /Editable, Scr_XSize=250, $ Value=filename, Event_Pro='Ignore_Event') buttonbase = Widget_Base(tlb, Row=1, Frame=1) cancel = Widget_Button(buttonbase, Value='Cancel', UValue='CANCEL') sysdefaults = Widget_Button(buttonbase, Value='System Defaults', $ Event_Pro='Set_System_Defaults', UValue='SYSTEM') localdefs = Widget_Button(buttonbase, Value='Local Defaults', $ Event_Pro='Set_Local_Defaults', UValue='LOCAL') accept = Widget_Button(buttonbase, Value='Accept', UValue='ACCEPT') Widget_Control, tlb, /Realize Widget_Control, draw, Get_Value=wid WSet, wid ; How big is the top-level base? Want to size the filename text widget ; the appropriate size. baseSize = Widget_Info(filenamebase, /Geometry) textlabelSize = Widget_Info(textlabel, /Geometry) Widget_Control, filenamew, $ Scr_XSize=(baseSize.XSize - textlabelSize.XSize - baseSize.XPad - $ textlabelSize.XPad) ; Ready to set up parameters to draw the boxes on the display. portraitbox_x = [1,1,88,88,1] portraitbox_y = [1, 112, 112, 1, 1] landbox_x = [1, 112, 112, 1, 1] landbox_y = [1, 1, 88, 88, 1] ; Convert sizes and offsets to Device coordinates. boxInfo = PlotBox_Coords(xsize, ysize, xoff, yoff, inches) IF landscape EQ 0 THEN BEGIN pbox_xmax = Max(boxInfo(0,*)) pbox_xmin = Min(boxInfo(0,*)) pbox_ymax = Max(boxInfo(1,*)) pbox_ymin = Min(boxInfo(1,*)) lbox_xmax = 0 lbox_xmin = 0 lbox_ymax = 0 lbox_ymin = 0 ENDIF ELSE BEGIN pbox_xmax = 0 pbox_xmin = 0 pbox_ymax = 0 pbox_ymin = 0 lbox_xmax = Max(boxInfo(0,*)) lbox_xmin = Min(boxInfo(0,*)) lbox_ymax = Max(boxInfo(1,*)) lbox_ymin = Min(boxInfo(1,*)) ENDELSE ; Get the colors in the current color table TVLct, r, g, b, /Get ; Modify color indices N_Colors-2, N_Colors-3 and N_Colors-4 for ; drawing colors ; The number of colors in the session can be less then the ; number of colors in the color vectors on PCs (and maybe other ; computers), so take the smaller value. (Bug fix?) ncol = !D.N_Colors < N_Elements(r) red = r green = g blue=b red(ncol-4:ncol-2) = [70B, 0B, 255B] green(ncol-4:ncol-2) = [70B, 255B, 255B] blue(ncol-4:ncol-2) = [70B, 0B, 0B] ; Load the newly modified colortable TVLct, red, green, blue ; Make the draw widget have a charcoal background color. TV, Replicate(ncol-4,114,114) ; Draw a page box in the draw widget IF landscape EQ 0 THEN PlotS, portraitbox_x, portraitbox_y, /Device,$ Color=ncol-2 ELSE $ PlotS, landbox_x, landbox_y, /Device, Color=ncol-2 ; Draw a plot box in the draw widget PlotS, boxInfo(0,*), boxInfo(1,*), /Device, Color=ncol-3 ; Create a pixmap and draw the page box on it Window, /Free, XSize=114, YSize=114, /Pixmap pixwid = !D.Window WSet, pixwid TV, Replicate(ncol-4,114,114) IF landscape EQ 0 THEN PlotS, portraitbox_x, portraitbox_y, /Device,$ Color=ncol-2 ELSE $ PlotS, landbox_x, landbox_y, /Device, Color=ncol-2 WSet, wid ; Create a pointer to store the formInfo structure from the form ptr = Handle_Create() ; Create an info structure to store information required by the program info = {draw:draw, $ ; The draw widget id pixwid:pixwid, $ ; The pixmap window id wid:wid, $ ; The draw widget window id xsize:xsizew, $ ; The widget id to get XSIZE ysize:ysizew, $ ; The widget id to get YSIZE xoff:xoffw, $ ; The widget id to get XOFFSET yoff:yoffw, $ ; The widget id to get YOFFSET filename:filenamew, $ ; The widget id to get FILENAME inch:inch, $ ; The widget id of inch button. cm:cm, $ ; The widget id of cm button. col_on:col_on, $ ; The widget id of color on button. col_off:col_off, $ ; The widget id of color off button. bit2:bit2, $ ; The widget id of bit=2 button. bit4:bit4, $ ; The widget id of bit=4 button. bit8:bit8, $ ; The widget id of bit=8 button. encap_on:encap_on, $ ; The widget id of encapsulate on button. encap_off:encap_off, $ ; The widget id of encapsulate off button. land:land, $ ; The widget id of the landscape button. port:port, $ ; The widget id of the portrait button. portraitbox_x:portraitbox_x, $ ; Portrait page outline x (default) portraitbox_y:portraitbox_y, $ ; Portrait page outline y (default) pplotbox_x:[8, 8, 82, 82, 8], $ ; Portrait box outline x ;(default) pplotbox_y:[60, 106, 106, 60, 60], $ ; Portrait box outline y ;(default) landbox_x:landbox_x, $ ; Landscape page outline x (default) landbox_y:landbox_y, $ ; Landscape page outline y (default) lplotbox_x:[8, 8, 106, 106, 8], $ ; Landscape box outline x (default) lplotbox_y:[8, 82, 82, 8, 8], $ ; Landscape box outline y (default) pbox_xmax:pbox_xmax, $ ; Current portrait box x maximum pbox_xmin:pbox_xmin, $ ; Current portrait box x minimum pbox_ymax:pbox_ymax, $ ; Current portrait box y maximum pbox_ymin:pbox_ymin, $ ; Current portrait box Y minimum lbox_xmax:lbox_xmax, $ ; Current landscape box x maximum lbox_xmin:lbox_xmin, $ ; Current landscape box x minimum lbox_ymax:lbox_ymax, $ ; Current landscape box y maximum lbox_ymin:lbox_ymin, $ ; Current landscape box y minimum inches:inches, $ ; Inches = 1, Centimeters = 0 color:color, $ ; Color = 1, B&W = 0 bits_per_pixel:bits_per_pixel, $ ; Number of bits per pixel landscape:landscape, $ ; Landscape mode = 1, Portrait mode = 0 encapsulated:encapsulated, $ ; Encapsulated = 1, Non-encapsulated = 0 pagecolor:ncol-2, $ ; Color to draw page outline (yellow) boxcolor:ncol-3, $ ; Color to draw plot box (green) charcoal:ncol-4, $ ; Color to put as background in the draw widget red:r, $ ; Old red color vector green:g, $ ; Old green color vector blue:b, $ ; Old blue color vector ptr:ptr, $ ; Pointer to store data from the form. localDefaultPtr:localDefaultPtr, $ ; Pointer to local default structure. xs:0.0, $ ; X value of static corner of box ys:0.0, $ ; Y value of static corner of box xcur:0.0, $ ; X value of moving corner of box ycur:0.0, $ ; Y value of moving corner of box mouse_x:0.0, $ ; X value of mouse in moving box mouse_y:0.0, $ ; Y value of mouse in moving box xmax:0.0, $ ; Temporary X max value of moving box ymax:0.0, $ ; Temporary Y max value of moving box xmin:0.0, $ ; Temporary X min value of moving box ymin:0.0 } ; Temporary Y min value of moving box ; Store the info structure in the top-level base Widget_Control, tlb, Set_UValue=info, /No_Copy ; Set this widget program up as a modal or blocking widget. What this means ; is that you will return to the line after this XManager call when the ; widget is destroyed. XManager, 'ps_form', tlb, /Modal ; Get the formInfo structure from the pointer location. Handle_Value, ptr, formInfo, /No_Copy ; Strip the CANCEL field out of the formInfo structure so the ; cancelButton flag can be returned via the CANCEL keyword and the ; formInfo structure is suitable for passing directly to the DEVICE ; procedure through its _Extra keyword. cancelButton = formInfo.cancel IF NOT cancelButton THEN BEGIN formInfo = { PS_FORM_INFO, $ xsize:formInfo.xsize, $ xoff:formInfo.xoff, $ ysize:formInfo.ysize, $ yoff:formInfo.yoff, $ filename:formInfo.filename, $ inches:formInfo.inches, $ color:formInfo.color, $ bits_per_pixel:formInfo.bits_per_pixel, $ encapsulated:formInfo.encapsulated, $ landscape:formInfo.landscape } ENDIF ELSE formInfo = 0 ; Return a throw-away value ; Free up the space allocated to the pointer and the data Handle_Free, ptr ; Restore graphics device. Set_Plot, oldname RETURN, formInfo END ;*******************************************************************