Viewing contents of file '../idllib/contrib/fanning/xwindow.pro'
;+
; NAME:
; XWINDOW
;
; PURPOSE:
; This routine implements a "smart" resizeable graphics window.
; It is used as a wrapper for built-in IDL graphics procedures
; such as SURFACE, CONTOUR, PLOT, SHADE_SURF, etc. In additon,
; it can be used to display any user-written graphics procedure
; so long as that procedure follows three simple rules: (1) It
; does not open it's own graphics windows, (2) It is defined with
; no more than three positional arguments (an unlimited number
; of keyword arguments are allowed), and (3) It is defined
; with an _EXTRA keyword.
;
; Keyword arguments permit the window to have its own portion
; of a color table and to be able to change the colors loaded in
; that portion of the color table. Colors are updated
; automatically on both 8-bit and 24-bit color displays. In
; addition, the window colors can "protect" themselves. I mean
; by this that the window can re-load its own colors into the
; color table when the cursor is moved over the window (X device)
; or the user clicks in the window (all other devices). This
; prevents other applications from changing the colors used to
; display data in this window. (This is an issue mainly in
; IDL 5 applications where widget applications can run
; concurrently with commands from the IDL command line.)
;
; Keyword arguments also permit the window to create output
; files of its contents. These files can be color and
; gray-scale PostScript, GIF, TIFF, or JPEG files.
;
; AUTHOR:
; FANNING SOFTWARE CONSULTING
; David Fanning, Ph.D.
; 2642 Bradbury Court
; Fort Collins, CO 80521 USA
; Phone: 970-221-0438
; E-mail: davidf@dfanning.com
; Coyote's Guide to IDL Programming: http://www.dfanning.com
;
; CATEGORY:
; Widgets, Graphics.
;
; CALLING SEQUENCE:
; XWINDOW, command, P1, P2, P3
;
; REQUIRED INPUTS:
; COMMAND: The graphics procedure command to be executed. This parameter
; must be a STRING. Examples are 'SURFACE', 'CONTOUR', 'PLOT', etc.
;
; OPTIONAL INPUTS:
; P1: The first positional parameter appropriate for the graphics
; command.
;
; P2: The second positional parameter appropriate for the graphics
; command.
;
; P3: The third positional parameter appropriate for the graphics
; command.
;
; INPUT KEYWORD PARAMETERS:
;
; BACKGROUND: The background color index for the window. Setting this color
; along with the ERASE keyword causes the window to be erased with
; this color.
;
; CPMENU: Setting this keyword adds a "Color Protection" button to the
; "Controls" menu. Color protection can then be turned ON or OFF for the
; window. Otherwise, the color protection scheme used to open the window
; cannot be changed once the window is open. (See the PROTECT keyword.)
; The default is to have this keyword OFF.
;
; ERASE: Setting this keyword "erases" the contents of the current
; graphics window before re-executing the graphics command. For example,
; this keyword might need to be set if the graphics "command" is TVSCL.
; The default is to NOT erase the display before reissuing the graphics
; command.
;
; _EXTRA: This keyword forms an anonymous structure of any unrecognized
; keywords passed to the program. The keywords must be appropriate
; for the graphics command being executed.
;
; GROUP_LEADER: The group leader for this program. When the group leader
; is destroyed, this program will be destroyed.
;
; OUTPUT: Set this keyword if you want a "File Output" menu on
; the menu bar. The default is to have this item turned OFF.
;
; JUST_REGISTER: If this keyword is set, the XWINDOW program is just
; registered with XMANAGER, but XMANAGER doesn't run. This is
; useful, for example, if you want to open an XWINDOW window in
; the widget definition module of another widget program.
;
; NO_CHANGE_CONFIG: Normally as the XWINDOW graphics window is resized
; the size (or aspect ratio, in the case of PostScript) of the
; hardware configuration dialogs change to reflect the new size of
; the graphics window. This results in file output that resembles
; the current graphics window in size and aspect ratio. If you want
; the file output dialogs to remember their current configuration
; even as the window is resized, set this keyword.
;
; NOMENU: Setting this keyword results in a graphics window without
; menu items. The default is to have a "Controls" menu item in the
; window menu bar with a "Quit" button. Setting this keyword
; automatically turns of the COLORS, OUTPUT, and CPMENU menu
; choices. (Note that the values specified by the COLORS keyword
; will still be valid for color protection, but no "Change Colors..."
; menu item will appear.)
;
; PROTECT: If this keyword is set, color protection for the draw
; widget is turned ON. What this means is that the window colors
; (see the XCOLOR keyword) will be restored when the cursor enters
; the draw widget window (on X devices) or when the user clicks in
; the draw widget window (other devices). This prevents someone at
; the IDL command line in IDL 5 from changing the window display
; colors permanently.
;
; WTITLE: This is the window title. It is the string "Resizeable
; COMMAND Window (1)" by default, where COMMAND is the input
; parameter. And the number (1 in this case) is the window
; index number of the draw widget.
;
; WXPOS: This is the initial X offset of the window. Default is to
; position the window in the approximate middle of the display.
;
; WYPOS: This is the initial Y offset of the window. Default is to
; position the window in the approximate middle of the display.
;
; WXSIZE: This is the initial X size of the window. Default is 400
; pixels.
;
; WYSIZE: This is the initial Y size of the window. Default is 400
; pixels.
;
; XCOLORS: Using this keyword adds a "Change Colors..." button to the
; "Controls" menu. Set this keyword to the number of colors available
; in the window and the starting index of the first color. For example,
; to allow the window access to 100 colors, starting at color index 50
; (i.e., color indices 50 to 149), use XColor=[100, 50]. If you use the
; keyword syntax "/XColor", all the colors available will be used, not just
; one color. If the keyword is set to a scalar value greater than 1, the
; starting color index is set to 0. The default value for this keyword
; is [(!D.N_COLORS < 256), 0]. Note that color "protection" may be
; turned on (via the PROTECT keyword) even if this keyword is NOT used.
;
; OUTPUT KEYWORD PARAMETERS:
; DRAWID: This keyword returns the draw widget identifier of the draw
; widget created in XWINDOW.
;
; TOP: This keyword returns the identifier of the top-level base widget
; created by XWINDOW.
;
; WID: This keyword returns the window index number of the draw widget
; created in XWINDOW.
;
; COMMON BLOCKS:
; None.
;
; SIDE EFFECTS:
; If color protection is ON, the window colors are reloaded when the
; cursor enters the XWINDOW graphics windows.
;
; RESTRICTIONS:
; This program requires three additional programs from the Fanning
; Software Consulting library: PSWINDOW, PS_FORM, and XCOLORS. You
; might also want to get the program TVIMAGE if you will be displaying
; images in XWINDOW graphics windows.
;
; If the "command" program requires keywords that are also keywords
; to XWINDOW, then you must use the keyword twice on the command line.
;
; EXAMPLE:
; To display a surface in the window, type:
;
; XWINDOW, 'SURFACE', Dist(20), Charsize=1.5
;
; To enable the Change Colors and File Output menu items, type:
;
; XWINDOW, 'SHADE_SURF', Dist(30), /XColors, /Output
;
; MODIFICATION HISTORY:
; Written by: David Fanning, October 96.
; XSIZE and YSIZE keywords changed to WXSIZE and WYSIZE so as not to
; conflict with these keywords on other programs. 14 April 1997, DWF.
; Updated as non-blocking widget for IDL 5.0. 14 April 1997, DWF.
; Extensively modified to work on either 8-bit or 24-bit displays,
; to enable color protection schemes, to send the contents to a
; number of different output files, and to give the user choices
; about which menu items to enable. 21 April 1997, DWF.
; Renamed COLORS keyword to XCOLORS and fixed a problem cancelling
; out of File Configuration dialogs. 23 April 1997, DWF.
; Updated program to IDL 5 functionality. 20 Oct 1997, DWF.
; Changed color protection scheme to widget tracking for X devices
; and clicking in the draw widget window for all other devices.
; This gets around unreliable tracking events on window machines.
; 20 Oct 1997, DWF.
; Added a BACKGROUND keyword and caused the program to ERASE in the
; background color. 1 May 1998.
; Added a Device, Decomposed=0 call to make this work on 24-bit
; devices. DWF, 29 June 1998.
; Fixed a problem with number of colors that RSI introduced in IDL
; 5.1 for PCs. 15 Aug 1998.
;-
PRO NULL_EVENTS, event
END ; of NULL_EVENTS event handler *****************************************
FUNCTION XWINDOW_ALERT, message, XOffSet=xoff, YOffSet=yoff
; Put up a message box
IF N_PARAMS() EQ 0 THEN message = 'Please wait...'
Device, Get_Screen_Size=screenSize
IF N_ELEMENTS(xoff) EQ 0 THEN xoff = (screenSize(0)/2.0 - 100)
IF N_ELEMENTS(yoff) EQ 0 THEN yoff = (screenSize(1)/2.0 - 75)
tlb = Widget_Base(Title='Writing a File...', XOffSet=xoff, YOffSet=yoff)
label = Widget_Label(tlb, Value=message)
Widget_Control, tlb, /Realize
RETURN, tlb
END ;*******************************************************************
PRO XWINDOW_COLOR_PROTECTION, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
WIDGET_CONTROL, event.id, GET_UVALUE=buttonValue
thisDevice = !D.Name
CASE buttonValue OF
'ON': BEGIN
info.protect = 1
WIDGET_CONTROL, info.cprotectOFF, Sensitive=1
WIDGET_CONTROL, info.cprotectON, Sensitive=0
IF thisDevice EQ 'X' THEN $
WIDGET_CONTROL, info.drawID, Tracking_Events=1 ELSE $
WIDGET_CONTROL, info.drawID, Draw_Button_Events=1
END
'OFF': BEGIN
info.protect = 0
WIDGET_CONTROL, info.cprotectOFF, Sensitive=0
WIDGET_CONTROL, info.cprotectON, Sensitive=1
IF thisDevice EQ 'X' THEN $
WIDGET_CONTROL, info.drawID, Tracking_Events=0 ELSE $
WIDGET_CONTROL, info.drawID, Draw_Button_Events=0
END
ENDCASE
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ;*******************************************************************
PRO XWINDOW_CONFIGURATION_EVENTS, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
WIDGET_CONTROL, event.id, GET_UVALUE=thisEvent
CASE thisEvent OF
'SELECT_FILE': BEGIN
; Start in the current directory.
CD, Current=startDirectory
; Use PICKFILE to pick a filename for writing.
pick = Pickfile(Path=startDirectory, /NoConfirm, $
Get_Path=path, /Write)
; Make sure the user didn't cancel out of PICKFILE.
IF pick NE '' THEN Widget_Control, info.filenameID, Set_Value=pick
END ; of the Select Filename button case
'CANCEL': BEGIN
; Have to exit here gracefully. Set CANCEL field in structure.
formdata = {cancel:1, create:0}
*info.ptr = formdata
; Out of here!
Widget_Control, event.top, /Destroy
RETURN
END ; of the Cancel button case
'ACCEPT': BEGIN ; Gather the form information.
; Get the filename.
Widget_Control, info.filenameID, Get_Value=filename
filename = filename(0)
; Get the size info.
Widget_Control, info.xsizeID, Get_Value=xsize
Widget_Control, info.ysizeID, Get_Value=ysize
; Get the color info from the droplist widget.
listIndex = Widget_Info(info.colordropID, /Droplist_Select)
colortype = FIX(ABS(1-listindex))
; Get the order info from the droplist widget.
order = Widget_Info(info.orderdropID, /Droplist_Select)
order = FIX(order)
; Get the quality fromt he slider widget, if needed
IF info.sliderID NE -1 THEN $
Widget_Control, info.sliderID, Get_Value=quality ELSE quality=-1
; Create the formdata structure from the information you collected.
formdata = {filename:filename, xsize:xsize, ysize:ysize, $
color:colortype, order:order, quality:quality, create:0}
; Store the formdata in the pointer location.
*info.ptr = formdata
; Out of here!
Widget_Control, event.top, /Destroy
RETURN
END ; of the Accept button case
'CREATE': BEGIN ; Gather the form information.
; Get the filename.
Widget_Control, info.filenameID, Get_Value=filename
filename = filename(0)
; Get the size info.
Widget_Control, info.xsizeID, Get_Value=xsize
Widget_Control, info.ysizeID, Get_Value=ysize
; Get the color info from the droplist widget.
listIndex = Widget_Info(info.colordropID, /Droplist_Select)
colortype = FIX(ABS(1-listindex))
; Get the order info from the droplist widget.
order = Widget_Info(info.orderdropID, /Droplist_Select)
order = FIX(order)
; Get the quality fromt he slider widget, if needed
IF info.sliderID NE -1 THEN $
Widget_Control, info.sliderID, Get_Value=quality ELSE quality=-1
; Create the formdata structure from the information you collected.
formdata = {filename:filename, xsize:xsize, ysize:ysize, $
color:colortype, order:order, quality:quality, create:1}
; Store the formdata in the pointer location.
*info.ptr = formdata
; Out of here!
Widget_Control, event.top, /Destroy
RETURN
END ; of the Create button case
ELSE:
ENDCASE
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of XWINDOW_CONFIGURATION_EVENTS event handler ************************
FUNCTION XWINDOW_CONFIGURATION, filetype, config, TITLE=title, $
XOFFSET=xoffset, YOFFSET=yoffset, Cancel=cancel, Create=create, $
PARENT=parent
CATCH, error
IF error NE 0 THEN BEGIN
ok = WIDGET_MESSAGE(!Err_String)
RETURN, -1
ENDIF
IF N_ELEMENTS(filetype) EQ 0 THEN filetype = 'GIF'
IF N_ELEMENTS(config) EQ 0 THEN config = {XSIZE:400, YSIZE:400, $
COLOR:1, FILENAME:'xwindow.gif', NCOLORS:(!D.N_Colors < 256)}
filetype = STRUPCASE(filetype)
IF N_ELEMENTS(title) EQ 0 THEN title = 'Configure ' + $
filetype + ' Output File'
; Check for placement offsets. Define defaults.
IF (N_ELEMENTS(xoffset) EQ 0) THEN BEGIN
DEVICE, GET_SCREEN_SIZE=screenSize
xoffset = (screenSize(0) - 200) / 2.
ENDIF
IF (N_ELEMENTS(yoffset) EQ 0) THEN BEGIN
DEVICE, GET_SCREEN_SIZE=screenSize
yoffset = (screenSize(1) - 100) / 2.
ENDIF
; Create widgets.
tlb = WIDGET_BASE(Column=1, Title=title, XOffset=xoffset, $
YOffset=yoffset, Base_Align_Center=1, /Modal, Group_Leader=parent)
bigbox = WIDGET_BASE(tlb, Column=1, Frame=1, Base_Align_Center=1)
; Create the filename widgets.
filebox = Widget_Base(bigbox, Column=1, Base_Align_Center=1)
filename = config.filename
filenamebase = Widget_Base(filebox, Row=1)
filenamelabel = Widget_Label(filenamebase, Value='Filename:')
filenameID = Widget_Text(filenamebase, Value=filename, /Editable, $
Event_Pro='NULL_EVENTS', SCR_XSIZE=320)
; Create a button to allow user to pick a filename.
pickbutton = Widget_Button(filebox, Value='Select Filename', $
UVALUE='SELECT_FILE')
; Create size widgets
sizebox = Widget_Base(bigbox, Column=1, Base_Align_Left=1)
sizebase = Widget_Base(sizebox, Row=1)
xsizeID = CW_FIELD(sizebase, Value=config.xsize, Title='XSize: ', $
/Integer)
ysizeID = CW_FIELD(sizebase, Value=config.ysize, Title='YSize: ', $
/Integer)
; File type and order.
orderbase = Widget_Base(sizebox, Row=1)
type = ['Color', 'Grayscale']
order = ['0', '1']
colordropID = Widget_Droplist(orderbase, Value=type, $
Title='File Type: ', EVENT_PRO='NULL_EVENTS')
orderdropID = Widget_Droplist(orderbase, Value=order, $
Title='Display Order: ', EVENT_PRO='NULL_EVENTS')
Widget_Control, colordropID, Set_Droplist_Select=FIX(ABS(config.color-1))
Widget_Control, orderdropID, Set_Droplist_Select=config.order
; Quality Slider if needed.
IF filetype EQ 'JPEG' THEN $
sliderID = Widget_Slider(bigbox, Value=config.quality, Max=100, Min=0, $
Title='Compression Quality', EVENT_PRO='NULL_EVENTS', $
SCR_XSize=350) ELSE sliderID = -1
; Cancel and Accept buttons.
buttonbase = Widget_Base(tlb, Row=1)
cancelID = Widget_Button(buttonbase, Value='Cancel', UValue='CANCEL')
createID = Widget_Button(buttonbase, Value='Create File', UValue='CREATE')
ok = Widget_Button(buttonbase, Value='Accept', UValue='ACCEPT')
Widget_Control, tlb, /Realize
ptr = Ptr_New({cancel:1, create:0})
info = { filenameID:filenameID, xsizeID:xsizeID, $
ysizeID:ysizeID, colordropID:colordropID, $
orderdropID:orderdropID, ptr:ptr, sliderID:sliderID}
Widget_Control, tlb, Set_UValue=info, /No_Copy
XManager, 'xwindow_configuration', tlb, $
Event_Handler='XWINDOW_CONFIGURATION_EVENTS'
formdata = *ptr
Ptr_Free, ptr
IF N_ELEMENTS(formdata) EQ 0 THEN BEGIN
cancel = 1
create = 0
RETURN, -1
ENDIF
fields = TAG_NAMES(formdata)
create = formdata.create
cancel = WHERE(fields EQ 'CANCEL')
IF cancel(0) EQ -1 THEN BEGIN
cancel = 0
newConfiguration = Create_Struct('XSIZE', formdata.xsize, $
'YSIZE', formdata.ysize, 'COLOR', formdata.color, $
'FILENAME', formdata.filename, 'ORDER', formdata.order, $
'QUALITY', formdata.quality, NAME='XWINDOW_' + filetype)
RETURN, newConfiguration
ENDIF ELSE BEGIN
cancel = 1
create = 0
RETURN, -1
ENDELSE
END ; of XWINDOW_CONFIGURATION event handler *******************************
FUNCTION XWindow_WhatTypeVariable, variable
; Use SIZE function to get variable info.
varInfo = Size(variable)
; The next to last element in varInfo has the data type.
typeIndex = varInfo(varInfo(0) + 1)
dataTypes = ['UNDEFINED', 'BYTE', 'INTEGER', 'LONG', 'FLOATING', $
'DOUBLE', 'COMPLEX', 'STRING', 'STRUCTURE', 'DCOMPLEX']
thisType = dataTypes(typeIndex)
RETURN, thisType
END ; of XWindow_WhatTypeVariable utility routine **************************
PRO XWINDOW_QUIT, event
WIDGET_CONTROL, event.top, /DESTROY
END ; of XWINDOW_QUIT procedure *********************************************
PRO XWINDOW_CLEANUP, id
WIDGET_CONTROL, id, GET_UVALUE=info, /NO_COPY
IF N_ELEMENTS(info) EQ 0 THEN RETURN
PTR_FREE, info.plotObjPtr
END ; of XWINDOW_CLEANUP cleanup procedure ***********************************
PRO XWINDOW_CONFIGURE_FILES, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
; What kind of file to configure?
WIDGET_CONTROL, event.id, GET_VALUE=whichFile
CASE whichFile OF
'Configure PostScript File...': BEGIN
newkeywords = PS_FORM(DEFAULTS=info.ps, Parent=event.top, $
LocalDefaults=info.pslocal, Cancel=cancel, Create=create)
IF NOT cancel THEN info.ps = newkeywords
IF create THEN WIDGET_CONTROL, info.psID, SEND_EVENT={ID:info.psID, $
TOP:event.top, HANDLER:0L}
END
'Configure GIF File...': BEGIN
config = info.gif
newConfiguration = XWINDOW_CONFIGURATION('GIF', config, $
Cancel=cancel, Create=create, Parent=event.top)
IF NOT cancel THEN info.gif = newConfiguration
IF create THEN WIDGET_CONTROL, info.gifID, SEND_EVENT={ID:info.gifID, $
TOP:event.top, HANDLER:0L}
END
'Configure TIFF File...': BEGIN
config = info.tiff
newConfiguration = XWINDOW_CONFIGURATION('TIFF', config, $
Cancel=cancel, Create=create, Parent=event.top)
IF NOT cancel THEN info.tiff = newConfiguration
IF create THEN WIDGET_CONTROL, info.tiffID, SEND_EVENT={ID:info.tiffID, $
TOP:event.top, HANDLER:0L}
END
'Configure JPEG File...': BEGIN
config = info.jpeg
newConfiguration = XWINDOW_CONFIGURATION('JPEG', config, $
Cancel=cancel, Create=create, Parent=event.top)
IF NOT cancel THEN info.jpeg = newConfiguration
IF create THEN WIDGET_CONTROL, info.jpegID, SEND_EVENT={ID:info.jpegID, $
TOP:event.top, HANDLER:0L}
END
ENDCASE
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of XWINDOW_CONFIGURE_FILES event handler ***********************************
PRO XWINDOW_CREATE_FILES, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
; There can be all kinds of problems writing a file.
; Trap errors here and try to get out of here.
CATCH, error
IF error NE 0 THEN BEGIN
junk=widget_message(!err_string)
ok = WIDGET_MESSAGE(['Problem writing file. The most', $
'common problem is a mis-spelled filename.', 'Returning...'])
IF WIDGET_INFO(id, /Valid_ID) THEN WIDGET_CONTROL, id, /Destroy
IF N_ELEMENTS(thisDevice) GT 0 THEN SET_PLOT, thisDevice
IF N_ELEMENTS(info) NE 0 THEN WIDGET_CONTROL, event.top, $
SET_UVALUE=info, /NO_COPY
RETURN
ENDIF
id = XWINDOW_ALERT('Please be patient while writing a file...')
; Get the Plot Object.
plotObj = *info.plotObjPtr
; What kind of file to create?
WIDGET_CONTROL, event.id, GET_VALUE=whichFile
CASE whichFile OF
'Create PostScript File': BEGIN
keywords = info.ps
thisDevice = !D.NAME
TVLCT, r, g, b, /GET
SET_PLOT, 'PS'
!P.Background = info.background
TVLCT, info.r, info.g, info.b, info.bottom
DEVICE, _EXTRA=keywords
ok = EXECUTE(plotObj.thisCommand)
DEVICE, /CLOSE_FILE
SET_PLOT, thisDevice
TVLCT, r, g, b
!P.Background = info.background
END
'Create GIF File': BEGIN
config = info.gif
; Render graphic in Z-buffer.
thisDevice = !D.NAME
TVLCT, rr, gg, bb, /GET
SET_PLOT, 'Z'
!P.Background = info.background
ERASE, COLOR=info.background
DEVICE, SET_RESOLUTION=[config.xsize, config.ysize], $
SET_COLORS=info.ncolors
ok = EXECUTE(plotObj.thisCommand)
thisImage = TVRD()
IF config.color NE 1 THEN LOADCT, 0, NColors=info.wcolors, $
Bottom=info.bottom ELSE $
TVLCT, info.r, info.g, info.b, info.bottom
TVLCT, r, g, b, /GET
SET_PLOT, thisDevice
!P.Background = info.background
TVLCT, rr, gg, bb
; Write GIF file.
WRITE_GIF, config.filename, thisImage, r, g, b
END ; of GIF file creation.
'Create TIFF File': BEGIN
config = info.tiff
; Render graphic in Z-buffer.
thisDevice = !D.NAME
TVLCT, rr, gg, bb, /GET
SET_PLOT, 'Z'
!P.Background = info.background
TVLCT, info.r, info.g, info.b, info.bottom
ERASE, COLOR=info.background
DEVICE, SET_RESOLUTION=[config.xsize, config.ysize], $
SET_COLORS=info.ncolors
ok = EXECUTE(plotObj.thisCommand)
thisImage = TVRD()
TVLCT, r, g, b, /GET
SET_PLOT, thisDevice
!P.Background = info.background
TVLCT, rr, gg, bb
; Write TIFF file. Use screen resolution.
IF config.color EQ 1 THEN $
TIFF_WRITE, config.filename, thisImage, config.order, $
RED=r, GREEN=g, BLUE=b, XRESOL=ROUND(!D.X_PX_CM * 2.54), $
YRESOL=ROUND(!D.X_PX_CM * 2.54) ELSE $
TIFF_WRITE, config.filename, thisImage, config.order, $
XRESOL=ROUND(!D.X_PX_CM * 2.54), YRESOL=ROUND(!D.X_PX_CM * 2.54)
END
'Create JPEG File': BEGIN
config = info.jpeg
; Render graphic in Z-buffer.
thisDevice = !D.NAME
TVLCT, rr, gg, bb, /GET
SET_PLOT, 'Z'
!P.Background = info.background
ERASE, COLOR=info.background
DEVICE, SET_RESOLUTION=[config.xsize, config.ysize], $
SET_COLORS=info.ncolors
TVLCT, info.r, info.g, info.b, info.bottom
ok = EXECUTE(plotObj.thisCommand)
thisImage = TVRD()
TVLCT, r, g, b, /GET
SET_PLOT, thisDevice
!P.Background = info.background
TVLCT, rr, gg, bb
; Write JPEG file.
IF config.color EQ 1 THEN BEGIN
image24 = BYTARR(3, config.xsize, config.ysize)
image24(0,*,*) = r(thisImage)
image24(1,*,*) = g(thisImage)
image24(2,*,*) = b(thisImage)
WRITE_JPEG, config.filename, image24, TRUE=1, $
QUALITY=config.quality, ORDER=config.order
ENDIF ELSE $
WRITE_JPEG, config.filename, thisimage, $
QUALITY=config.quality, ORDER=config.order
END
ENDCASE
WIDGET_CONTROL, id, /Destroy
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of XWINDOW_CREATE_FILES event handler ***********************************
PRO XWINDOW_COLORS, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
WIDGET_CONTROL, event.id, GET_UVALUE=colors
XCOLORS, Group=event.top, NColors=colors(0), Bottom=colors(1), $
Title='Window ' + STRTRIM(info.wid, 2) + ' Colors', $
NotifyID=[info.drawID, event.top]
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of XWINDOW_COLORS event handler ****************************************
PRO XWINDOW_DRAW_EVENT, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
; Get the Plot Object.
plotObj = *info.plotObjPtr
; Need to respond to WIDGET_TRACKING, WIDGET_DRAW, and
; XCOLORS_LOAD events.
thisEvent = TAG_NAMES(event, /Structure)
IF thisEvent EQ 'WIDGET_TRACKING' THEN BEGIN
IF event.enter EQ 1 THEN $
TVLCT, info.r, info.g, info.b, info.bottom
ENDIF
IF thisEvent EQ 'WIDGET_DRAW' THEN BEGIN
TVLCT, info.r, info.g, info.b, info.bottom
ENDIF
IF thisEvent EQ 'XCOLORS_LOAD' THEN BEGIN
info.r = event.r(info.bottom:info.bottom+info.wcolors-1)
info.g = event.g(info.bottom:info.bottom+info.wcolors-1)
info.b = event.b(info.bottom:info.bottom+info.wcolors-1)
ENDIF
; Redisplay the command in the window if needed.
ncolors = !D.N_Colors
IF ncolors GE 256 THEN BEGIN
WSET, info.wid
IF info.erase THEN ERASE, COLOR=info.background
ok = EXECUTE(plotObj.thisCommand)
ENDIF
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of XWINDOW_DRAW_EVENT event handler **********************************
PRO XWINDOW_RESIZE_EVENTS, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
; Resize the draw widget.
WIDGET_CONTROL, info.drawid, XSIZE=event.x, YSIZE=event.y
; Get the Plot Object.
plotObj = *info.plotObjPtr
; Redisplay the command in the window.
WIDGET_CONTROL, info.drawID, GET_VALUE=wid
WSET, wid
IF info.erase EQ 1 THEN ERASE, COLOR=info.background
ok = EXECUTE(plotObj.thisCommand)
; Update file output configuration structures in necessary.
IF (info.output) AND (NOT info.nochange) THEN BEGIN
info.gif.xsize = event.x
info.gif.ysize = event.y
info.tiff.xsize = event.x
info.tiff.ysize = event.y
info.jpeg.xsize = event.x
info.jpeg.ysize = event.y
IF info.ps.inches EQ 0 THEN newsizes = PSWINDOW(/CM) ELSE $
newsizes = PSWINDOW()
info.ps.xsize = newsizes.xsize
info.ps.ysize = newsizes.ysize
info.ps.xoff = newsizes.xoffset
info.ps.yoff = newsizes.yoffset
ENDIF
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of XWINDOW_RESIZE_EVENTS event handler *********************************
PRO XWINDOW, proName, param1, param2, param3, GROUP_LEADER=group, $
_EXTRA=extra, WXSIZE=xsize, WYSIZE=ysize, WID=wid, XCOLORS=colors, $
DRAWID=drawid, WTITLE=wtitle, JUST_REGISTER=justRegister, $
OUTPUT=output, NO_CHANGE_CONFIG=nochange, ERASE=erase, $
TOP=tlb, PROTECT=protect, NOMENU=nomenu, CPMENU=cpmenu, $
WXPOS=wxpos, WYPOS=wypos, BACKGROUND=background
; Return to main-level on error.
ON_ERROR, 1
; Use undecomposed color for 24-bit systems.
Device, Decomposed=0
thisRelease = StrMid(!Version.Release, 0, 1)
IF thisRelease NE '5' THEN BEGIN
ok = Widget_Message(['XWINDOW requires IDL 5 functionality.', 'Returning...'])
RETURN
ENDIF
; Check keywords.
IF N_ELEMENTS(xsize) EQ 0 THEN xsize = 400
IF N_ELEMENTS(ysize) EQ 0 THEN ysize = 400
IF N_ELEMENTS(background) EQ 0 THEN background = !P.Background
nochange = KEYWORD_SET(nochange)
extraFlag = KEYWORD_SET(extra)
justRegister = KEYWORD_SET(justRegister)
protect = KEYWORD_SET(protect)
needColors = KEYWORD_SET(colors)
needOutput = KEYWORD_SET(output)
cpmenu = KEYWORD_SET(cpmenu)
nomenu = KEYWORD_SET(nomenu)
IF nomenu THEN BEGIN
needOutput = 0
cpmenu = 0
cprotectON = -1L
cprotectOFF = -1L
psID = -1L
gifID = -1L
tiffID = -1L
jpegID = -1L
ENDIF
; Make sure a window has been opened.
thisWindowID = !D.Window
Window, XSize=10, YSize=10, /Free, /Pixmap
WDelete, !D.Window
IF thisWindowID GE 0 THEN WSet, thisWindowID
; Set up color variables. If the user typed "/Colors"
; then use *all* colors!
IF needcolors THEN BEGIN
IF N_ELEMENTS(colors) EQ 1L AND (colors(0) EQ 1) THEN $
colors = FIX([(!D.N_Colors < 256), 0])
IF (N_ELEMENTS(colors) EQ 1L) THEN colors = [colors(0) < 256L, 0]
ENDIF ELSE colors = [(!D.N_Colors < 256L), 0]
colors = FIX([(colors(0) < 256), colors(1)])
wcolors = colors(0)
bottom = colors(1)
TVLCT, r, g, b, /GET
r = r(bottom:bottom+wcolors-1)
g = g(bottom:bottom+wcolors-1)
b = b(bottom:bottom+wcolors-1)
IF nomenu THEN needcolors = 0
; Check for positional parameters. One parameter required.
np = N_PARAMS()
IF np EQ 0 THEN MESSAGE, 'Sorry, at least one argument is required.'
; The first positional argument must be a string.
IF np GT 0 THEN BEGIN
thisType = XWindow_WhatTypeVariable(proName)
IF thisType NE 'STRING' THEN $
MESSAGE, 'First argument must be STRING type. Returning...'
ENDIF
IF N_ELEMENTS(wtitle) EQ 0 THEN $
wtitle = 'Resizeable ' + STRUPCASE(proName) + ' Window'
; Set up the Plot Object based on number of parameters and
; the extraFlag variable.
CASE np OF
0: MESSAGE, 'Must call XWINDOW with at least one argument.'
1: BEGIN
IF extraFlag THEN BEGIN
thisCommand = proName + ", _EXTRA=plotObj.extra"
plotObj = {thisCommand:thisCommand, extra:extra}
ENDIF ELSE BEGIN
thisCommand = proName
plotObj = {thisCommand:thisCommand}
ENDELSE
END ; of np = 1 Case
2: BEGIN
IF extraFlag THEN BEGIN
thisCommand = proName + ", plotObj.param1, _EXTRA=plotObj.extra"
plotObj = {thisCommand:thisCommand, param1:param1, extra:extra}
ENDIF ELSE BEGIN
thisCommand = proName + ", plotObj.param1"
plotObj = {thisCommand:thisCommand, param1:param1}
ENDELSE
END ; of np = 2 Case
3: BEGIN
IF extraFlag THEN BEGIN
thisCommand = proName + ", plotObj.param1, " + $
"plotObj.param2, _EXTRA=plotObj.extra"
plotObj = {thisCommand:thisCommand, param1:param1, $
param2:param2, extra:extra}
ENDIF ELSE BEGIN
thisCommand = proName + ", plotObj.param1, plotObj.param2"
plotObj = {thisCommand:thisCommand, param1:param1, param2:param2}
ENDELSE
END ; of np = 3 Case
4: BEGIN
IF extraFlag THEN BEGIN
thisCommand = proName + ", plotObj.param1, " + $
"plotObj.param2, plotObj.param3, _EXTRA=plotObj.extra"
plotObj = {thisCommand:thisCommand, param1:param1, $
param2:param2, param3:param3, extra:extra}
ENDIF ELSE BEGIN
thisCommand = proName + ", plotObj.param1, plotObj.param2" + $
", plotObj.param3"
plotObj = {thisCommand:thisCommand, param1:param1, $
param2:param2, param3:param3}
ENDELSE
END ; of np = 4 Case
ENDCASE
; Store the Plot Object at a pointer location.
plotObjPtr = Ptr_New(plotObj)
; Create the widgets for this program.
DEVICE, GET_SCREEN_SIZE=screenSize
IF N_ELEMENTS(wxpos) EQ 0 THEN wxpos = (screenSize(0) - xsize) / 2.
IF N_ELEMENTS(wypos) EQ 0 THEN wypos = (screenSize(1) - ysize) / 2.
IF NOT nomenu THEN BEGIN
tlb = WIDGET_BASE(TLB_SIZE_EVENTS=1, $
XOFFSET=wxpos, YOFFSET=wypos, MBar=menubase)
controls = Widget_Button(menubase, Value='Controls', /Menu)
; Need a COLORS button?
IF needColors THEN BEGIN
colorsID = WIDGET_BUTTON(controls, Value='Change Colors...', $
Event_Pro='XWINDOW_COLORS', UValue=colors)
ENDIF
; Need color protection buttons?
IF cpmenu THEN BEGIN
cprotect = Widget_Button(controls, Value='Color Protection', $
/Menu, Event_Pro='XWindow_Color_Protection')
cprotectON = Widget_Button(cprotect, Value='ON', UVALUE='ON')
cprotectOFF = Widget_Button(cprotect, Value='OFF', UVALUE='OFF')
ENDIF ELSE BEGIN
cprotectON = -1L
cprotectOFF = -1L
ENDELSE
; Need FILE OUTPUT button?
IF needOutput THEN BEGIN
outputButton = WIDGET_BUTTON(menubase, Value='File Output', $
/Menu, Event_Pro='XWindow_Create_Files')
psID = WIDGET_BUTTON(outputButton, Value='Create PostScript File')
gifID = WIDGET_BUTTON(outputButton, Value='Create GIF File')
tiffID = WIDGET_BUTTON(outputButton, Value='Create TIFF File')
jpegID = WIDGET_BUTTON(outputButton, Value='Create JPEG File')
configure = WIDGET_BUTTON(outputButton, Value='Configure Output File', $
/Menu, /Separator, Event_Pro='XWindow_Configure_Files')
ps_config = WIDGET_BUTTON(configure, Value='Configure PostScript File...')
gif_config = WIDGET_BUTTON(configure, Value='Configure GIF File...')
tiff_config = WIDGET_BUTTON(configure, Value='Configure TIFF File...')
jpeg_config = WIDGET_BUTTON(configure, Value='Configure JPEG File...')
ENDIF ELSE BEGIN
psID = -1L
gifID = -1L
tiffID = -1L
jpegID = -1L
ENDELSE
quit = Widget_Button(controls, Value='Quit', Event_Pro='XWindow_Quit')
ENDIF ELSE tlb = WIDGET_BASE(TLB_SIZE_EVENTS=1, $
XOFFSET=wxpos, YOFFSET=wypos)
; Color protection is implemented with widget tracking for X devices
; and by clicking inside the draw widget for all others.
thisDevice = !D.NAME
IF thisDevice EQ 'X' THEN $
drawID = WIDGET_DRAW(tlb, XSIZE=xsize, YSIZE=ysize, $
Event_Pro='XWindow_Draw_Event', Tracking_Events=protect) ELSE $
drawID = WIDGET_DRAW(tlb, XSIZE=xsize, YSIZE=ysize, $
Event_Pro='XWindow_Draw_Event', Button_Events=protect)
WIDGET_CONTROL, tlb, /REALIZE
WIDGET_CONTROL, drawID, GET_VALUE=wid
WSET, wid
ERASE, COLOR=background
; Give each window a unique title.
wtitle = wtitle + ' (' + STRTRIM(wid,2) + ')'
Widget_Control, tlb, TLB_SET_TITLE=wtitle
; Set color protection button sensitivity.
IF cpmenu THEN BEGIN
IF protect THEN BEGIN
WIDGET_CONTROL, cprotectON, Sensitive=0
WIDGET_CONTROL, cprotectOFF, Sensitive=1
ENDIF ELSE BEGIN
WIDGET_CONTROL, cprotectON, Sensitive=1
WIDGET_CONTROL, cprotectOFF, Sensitive=0
ENDELSE
ENDIF
; If something goes wrong executing the command, trap it.
CATCH, error
IF error NE 0 THEN BEGIN
ok = WIDGET_MESSAGE(["There is a problem executing the command", $
"string in XWINDOW. Please check keyword", $
"spelling and command syntax. Returning..."])
PTR_FREE, plotObjPtr
WIDGET_CONTROL, tlb, /DESTROY
RETURN
ENDIF
ok = EXECUTE(plotObj.thisCommand)
IF NOT ok THEN BEGIN
ok = WIDGET_MESSAGE(["There is a problem executing the command", $
"string in XWINDOW. Please check keyword", $
"spelling and command syntax. Returning..."])
PTR_FREE, plotObjPtr
WIDGET_CONTROL, tlb, /DESTROY
RETURN
ENDIF
CATCH, /CANCEL
; Create an info structure.
info = { xsize:xsize, $ ; X size of window.
ysize:ysize, $ ; Y size of window.
wid:wid, $ ; Window index number.
drawID:drawID, $ ; Draw widget identifier.
cprotectON:cprotectON, $ ; Color protection ON button.
cprotectOFF:cprotectOFF, $ ; Color protection OFF button.
wtitle:wtitle, $ ; Window title.
r:r, $ ; Red colors in window.
g:g, $ ; Green colors in window.
b:b, $ ; Blue colors in window.
wcolors:wcolors, $ ; Number of window colors.
gifID:gifID, $ ; ID of Create GIF file button.
tiffID:tiffID, $ ; ID of Create TIFF file button.
jpegID:jpegID, $ ; ID of Create JPEG file button.
psID:psID, $ ; ID of Create PS file button.
bottom:bottom, $ ; Starting color index.
protect:protect, $ ; Protect colors flag.
nomenu:nomenu, $ ; No menu flag.
nochange:nochange, $ ; No change flag.
erase:Keyword_Set(erase), $ ; Need erasure flag.
ncolors:(!D.N_Colors < 256), $ ; Size of color table.
plotObjPtr:plotObjPtr, $ ; Pointer to plot object.
background:background, $ ; The background color index.
output:needOutput } ; File Output menu flag.
; File Output configuration structures, if needed.
IF Keyword_Set(output) THEN BEGIN
CD, Current=thisDir
ps = {PS_FORM_INFO, XSIZE:5.0, XOFF:1.75, YSIZE:5.0, $
YOFF:3.0, FILENAME:FilePath(Root_Dir=thisDir,'xwindow.ps'), $
INCHES:1, COLOR:0, BITS_PER_PIXEL:8, $
ENCAPSULATED:0, LANDSCAPE:0}
pslocal = {PS_FORM_INFO, XSIZE:5.0, XOFF:1.75, YSIZE:5.0, $
YOFF:3.0, FILENAME:FilePath(Root_Dir=thisDir,'xwindow.ps'), $
INCHES:1, COLOR:0, BITS_PER_PIXEL:8, $
ENCAPSULATED:0, LANDSCAPE:0}
gif = {XWINDOW_GIF,XSIZE:400, YSIZE:400, COLOR:1, $
FILENAME:FilePath(Root_Dir=thisDir,'xwindow.gif'), $
ORDER:0, QUALITY:-1}
jpeg = {XWINDOW_JPEG,XSIZE:400, YSIZE:400, COLOR:1, $
FILENAME:FilePath(Root_Dir=thisDir,'xwindow.jpg'), $
ORDER:0, QUALITY:75}
tiff = {XWINDOW_TIFF,XSIZE:400, YSIZE:400, COLOR:1, $
FILENAME:FilePath(Root_Dir=thisDir,'xwindow.tif'), $
ORDER:1, QUALITY:-1}
info = CREATE_STRUCT(info, 'PS', ps, 'PSLOCAL', pslocal, 'GIF', gif, $
'JPEG', jpeg, 'TIFF', tiff)
ENDIF
; Store the info structure in the TLB.
WIDGET_CONTROL, tlb, SET_UVALUE=info, /NO_COPY
; Register the program as on-blocking.
XManager, 'xwindow', tlb, EVENT_HANDLER='XWINDOW_RESIZE_EVENTS', $
CLEANUP='XWINDOW_CLEANUP', GROUP_LEADER=group, $
JUST_REG=justRegister, /No_Block
END