Viewing contents of file '../idllib/contrib/fanning/slice.pro'
;+
; NAME:
; SLICE
;
; PURPOSE:
;
; This is a routine to display a 3D data set and slice through it
; at arbitrary orthographic angles. The display window (when run
; with the GUI) is resizeable. The output can be sent either to
; the display, to a GUI, or to a PostScript printer (as true
; PostScript output, not a screen dump.) When run with the GUI,
; slices can be animated and displays can be saved and restored
; for later processing. The program works on 8-bit, 16-bit, and
; 24-bit displays.
;
; 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:
;
; 3D Graphics, Widgets.
;
; CALLING SEQUENCE:
;
; For display in a regular IDL graphics window:
;
; SLICE, data
;
; For display with a built-in GUI:
;
; SLICE, data, /GUI
;
; To send display to a PostScript printer:
;
; deviceKeywords = PS_FORM(/INITIALIZE)
; SLICE, data, POSTSCRIPT=deviceKeywords
;
; INPUTS:
;
; data: The 3D data set to be displayed. The data is assumed to be
; scaled into the number of colors (keyword NCOLORS).
;
; KEYWORD PARAMETERS:
;
; AX The rotation of the 3D coordinate system about the X axis.
; Must be between 0 and 90 degrees. Default is 30 degrees.
;
; AZ The rotation of the 3D coordinate system about the Z axis.
; Must be between -30 and 210 degrees. Default is 30 degrees.
;
; BACKGROUND The color index of the plot background. Default is BOTTOM.
;
; BOTTOM The starting index of the color table. Default is 0.
;
; COLOR The color index of the plot axes and annotation. Default is
; (NCOLORS-1) + BOTTOM.
;
; CHARSIZE The size of the plot annotations. Default is 1.0.
;
; _EXTRA This keyword allows other undefined keywords to be passed
; to the SURFACE command. For example: XTITLE, YTITLE, ZTITLE,
; and TITLE keywords.
;
; GROUP The group leader of the GUI. Normally used with GUI.
;
; GUI Set this keyword if you want a graphical user interface to the
; program functionality.
;
; NCOLORS The number of colors used in the color table. The default is
; !D.N_COLORS.
;
; NOAXES Set this keyword to draw the plot without axes.
;
; POSTSCRIPT This will be a strucuture of the type returned by PS_FORM.
; The fields of the structure are used to congfigue the PostScript device.
;
; THISINSTANCE Multiple versions of the GUI program can be running concurrently.
; This keyword is used to make sure they can be managed by XMANAGER
; concurrently. The keyword is NOT normally set by the user.
;
; TRANSPARENT This keyword sets the transparency threshold for the 3D volume.
; allowed values go from 0 to 100 percent. The default is 0.
;
; WID The window index number of the window you wish the display to go into.
; In non-GUI mode, the window does not have to currently be open. This
; keyword is ignored in GUI mode.
;
; WTITLE The window title. Used in conjunction with THISINSTANCE to label
; control and graphics windows. It can be set by the user.
;
; XCOORD The X coordinate of the 3D data set. The data will be sliced at this
; coordinate in the X direction. The default is XSIZE / 2.
;
; XSLICE Set this keyword to draw an slice through the data in the X direction.
;
; YCOORD The Y coordinate of the 3D data set. The data will be sliced at this
; coordinate in the Y direction. The default is YSIZE / 2.
;
; YSLICE Set this keyword to draw an slice through the data in the Y direction.
;
; ZCOORD The Z coordinate of the 3D data set. The data will be sliced at this
; coordinate in the Z direction. The default is ZSIZE / 2.
;
; ZSLICE Set this keyword to draw an slice through the data in the Z direction.
;
;
; OUTPUTS:
;
; None.
;
; COMMON BLOCKS:
;
; None.
;
; RESTRICTIONS:
;
; Requires modified IDL library routines CW_ANIMATE and XINTERANIMATE
; which have been added to this code. Requires the programs PS_FORM,
; XCOLORS, and CHGCOLOR from the Coyote Software Library.
;
; ftp://ftp.frii.com/pub/dfanning/outgoing/idl_examples
;
; EXAMPLE:
;
; To run this program with a GUI, a charcoal background color, axes
; drawn in yellow and with the X and Y axes shown, type:
;
; filename = FILEPATH(SUBDIR=['examples', 'data'], 'abnorm.dat')
; OPENR, lun, filename, /GET_LUN
; heart = BYTARR(64,64,15)
; READU, lun, heart
; FREE_LUN, lun
; LOADCT, 5, NCOLORS=150, BOTTOM=0
; TVLCT, [70, 255], [70, 255], [70, 0], 150
; SLICE, heart, /GUI, BACKGROUND=150, COLOR=151, NCOLORS=150, $
; BOTTOM=0, /XSLICE, /YSLICE
;
; The program code comes with its own example program. Type:
;
; IDL> .Compile SLICE
; IDL> example
;
; MODIFICATION HISTORY:
; Written by: David Fanning, Sept 1996.
; 31 Oct 96: Made slight changes in how PostScript output is handled.
; 23 April 1997. Fixed a bug that prevented PostScript output when
; the size was expressed in centimeters. DWF.
; 23 April 1997. Added support for 24-bit color displays. DWF
;-
FORWARD_FUNCTION SLICE_CW_ANIMATE
PRO SLICE_XINTAnim_kill_pix
; If there are pixmaps currently open, free them.
COMMON SLICE_XINTERAnimate_com, topbase, animatebase, pwin
i = size(pwin)
if (i(0) ne 0) then begin ; Not scalar, so contains valid IDs
i = i(i(0) + 2) ; # of elements in pwin
FOR j=0, i-1 DO IF pwin(j) GE 0 THEN WDELETE, pwin(j) ;Delete the windows
pwin = -1 ;Show nothing there by setting to scalar value
endif
end
PRO SLICE_XINTAnim_event, ev
; The only event that can be seen by this application is the "DONE"
; event from the CW_ANIMATION cluster.
widget_control, /destroy, ev.top
END
PRO SLICE_XINTERAnimate, RATE, SET = SET, IMAGE = IMAGE, FRAME = FRAME, $
ORDER = ORDER, CLOSE = CLOSE, TITLE = TITLE, $
SHOWLOAD = SHOWLOAD, GROUP = GROUP, WINDOW = WINDOW, $
XOFFSET = XOFFSET, YOFFSET = YOFFSET, KEEP_PIXMAPS=KEEP_PIXMAPS, $
CYCLE = cycle, TRACK = track, BOTTOM=bottom, NCOLORS=ncolors
COMMON SLICE_XINTERAnimate_com, topbase, animatebase, pwin
IF N_ELEMENTS(bottom) EQ 0 THEN bottom = 0
IF N_ELEMENTS(ncolors) EQ 0 THEN ncolors = !D.N_COLORS
;--------------------- CLOSE Portion of SLICE_XINTERanimate -------------------------
IF KEYWORD_SET(CLOSE) THEN BEGIN
if (widget_info(topbase, /valid)) THEN $
WIDGET_CONTROL, topbase, /DESTROY
SLICE_XINTAnim_kill_pix
RETURN
ENDIF
;Don't allow two copies of SLICE_XINTERnimate to run at once
IF xregistered("SLICE_XINTERAnimate") THEN begin
XANNOUNCE, 'SLICE_XINTERANIMATE', 'Only one animation at a time is allowed.'
return
endif
;---------------------- SET Portion of SLICE_XINTERanimate ------------------------
IF KEYWORD_SET(SET) THEN BEGIN
;This is the first call to SLICE_XINTERanimate. Here the pixmap is
; created and the widgets are initialized.
SLICE_XINTAnim_kill_pix ;If old pixmap exists, delete
IF NOT(KEYWORD_SET(TITLE)) THEN TITLE = "SLICE_XINTERAnimate"
topbase = WIDGET_BASE(TITLE = TITLE)
animatebase = SLICE_CW_ANIMATE(topbase, set(0), set(1), set(2), $
TRACK = KEYWORD_SET(track), CYCLE=KEYWORD_SET(cycle), $
BOTTOM=bottom, NCOLORS=ncolors)
; If the SHOWLOAD keyword is set, realize things now so the load is seen
IF KEYWORD_SET(SHOWLOAD) THEN $
WIDGET_CONTROL, topbase, /REALIZE, /HOURGLASS
RETURN
ENDIF
;----------------- IMAGE Loading Portion of SLICE_XINTERanimate --------------------
nwindow = N_ELEMENTS(WINDOW)
nimage = N_ELEMENTS(image)
if (nwindow gt 0) or (nimage gt 0) then begin
old_window = !D.WINDOW ;Save old window
; Make sure a widget has been created before trying to load it.
if (not widget_info(topbase, /valid)) then MESSAGE, 'Not initialized'
IF (N_ELEMENTS(YOFFSET) EQ 0) THEN YOFFSET = 0
IF (N_ELEMENTS(XOFFSET) EQ 0) THEN XOFFSET = 0
if (N_ELEMENTS(WINDOW) gt 0) then begin
SLICE_CW_ANIMATE_LOAD, animatebase, frame=frame, window=window, $
XOFFSET = XOFFSET, YOFFSET = YOFFSET
endif else begin
IF (N_ELEMENTS(ORDER) EQ 0) THEN ORDER = 0
SLICE_CW_ANIMATE_LOAD, animatebase, frame=frame, image=image, $
XOFFSET = XOFFSET, YOFFSET = YOFFSET, ORDER = ORDER
endelse
IF (old_window GE 0) THEN WSET, old_window
RETURN
ENDIF
;--------------- Register and Run Portion of SLICE_XINTERanimate -------------------
; If the base is not valid, it means that we have skipped
; calling this routine with the SET keyword. In this case, we can restart
; the last animation if the KEEP_PIXMAP keyword was used to preserve them
; in the previous call.
if (not widget_info(topbase, /valid)) then begin
s = size(pwin)
if (s(0) eq 0) then message, 'No image frames loaded'
; Scan the pixmaps to figure out the image size
n = s(s(0) + 2)
xs = 0
for i = 0, n-1 do begin
if pwin(i) ne -1 then begin
old_window = !D.WINDOW
wset, pwin(i)
xs = !d.x_vsize
ys = !d.y_vsize
IF (old_window GE 0) THEN WSET, old_window
goto, found ; Like a "break" in C
endif
endfor
found:
if (xs ne 0) then begin
IF NOT(KEYWORD_SET(TITLE)) THEN TITLE = 'SLICE_XINTERAnimate'
topbase = WIDGET_BASE(TITLE = TITLE)
animatebase = SLICE_CW_ANIMATE(topbase, xs, ys, 0, PIXMAPS=pwin, $
NCOLORS=ncolors, BOTTOM=bottom)
; The pixmaps are no longer our responsibility. They will get destroyed
; by SLICE_CW_ANIMATE as usual unless this invocation of SLICE_XINTERANIMATE
; specifies the KEEP_PIXMAP keyword.
pwin = 0 ; Indicate that we aren't saving them anymore.
endif else message, 'No image frames loaded'
endif
; At this point, the application must be realized if it isn't already
if (not widget_info(topbase, /realized)) then $
WIDGET_CONTROL, topbase, /REALIZE
; Save the pixmaps for later restart
if keyword_set(keep_pixmaps) then SLICE_CW_ANIMATE_GETP, animatebase, pwin
if N_ELEMENTS(RATE) EQ 0 THEN RATE = 100
SLICE_CW_ANIMATE_run, animatebase, rate
Xmanager, "SLICE_XINTERAnimate", topbase, EVENT_HANDLER = "SLICE_XINTAnim_event", $
GROUP_LEADER = GROUP
END
PRO SLICE_SETBITmapButtons, state
COMMON BitmapButtons, $
reversebutton, blk_reversebutton, $
pausebutton, blk_pausebutton, $
playbutton, blk_playbutton, $
cycleForwardBtn, blk_cycleForwardBtn
WIDGET_CONTROL, state.currentAction, SET_VALUE = state.currentBitmap
IF state.framedelta EQ 0 THEN BEGIN ; paused
WIDGET_CONTROL, state.wPauseButton, SET_VALUE = blk_pausebutton
state.currentAction = state.wPauseButton
state.currentBitmap = pausebutton
ENDIF ELSE BEGIN
IF state.framedelta GT 0 THEN BEGIN ; animating forward
IF state.cycle THEN BEGIN
WIDGET_CONTROL, state.wCyclePlayButton, SET_VALUE = blk_cycleForwardBtn
state.currentAction = state.wCyclePlayButton
state.currentBitmap = cycleForwardBtn
ENDIF ELSE BEGIN
WIDGET_CONTROL, state.wPlayButton, SET_VALUE = blk_playbutton
state.currentAction = state.wPlayButton
state.currentBitmap = playbutton
ENDELSE
ENDIF ELSE BEGIN ; animating backwards
WIDGET_CONTROL, state.wReversePlayButton, SET_VALUE = blk_reversebutton
state.currentAction = state.wReversePlayButton
state.currentBitmap = reversebutton
ENDELSE
ENDELSE
END
PRO SLICE_CW_ANIMATE_CLN, widget
; When the widget dies, clean up here. Widget is the ID of the
; *child* actually holding the state in its UVALUE.
; kills state stored in widget
WIDGET_CONTROL, widget, GET_UVALUE = state, /NO_COPY
IF (N_ELEMENTS(state) GT 0) THEN BEGIN
IF (state.dont_kill_pixmaps EQ 0) THEN BEGIN
HANDLE_VALUE, state.pwinHdl, pwin
FOR i=0, N_ELEMENTS(pwin)-1 DO BEGIN
IF (pwin(i) GE 0) THEN $
WDELETE, pwin(i)
ENDFOR
HANDLE_FREE, state.pwinHdl
ENDIF
; Restore the state
WIDGET_CONTROL, widget, SET_UVALUE = state, /NO_COPY
ENDIF
END
FUNCTION SLICE_CW_ANIMATE_EV, event
; Retrieve the structure from the child that contains the sub ids
wAnimateBase = event.handler
wTopBase = WIDGET_INFO(wAnimateBase, /CHILD)
;This kills the old uvalue
WIDGET_CONTROL, wTopBase, GET_UVALUE = state, /NO_COPY
ret = 0
CASE event.id OF
wAnimateBase: $
IF (state.framedelta NE 0) THEN BEGIN ; Animation
WIDGET_CONTROL, wAnimateBase, TIMER=state.delay
curframe = state.curframe
nframes = state.nframes
curframe = curframe + state.framedelta ; New frame
r = 0.0
IF state.cycle THEN BEGIN
IF curframe LT 0 THEN BEGIN
state.framedelta = 1
curframe = 0
t = systime(1)
r = 2 * nframes / float(t-state.loop_start_t)
ENDIF
IF curframe GE nframes THEN BEGIN
state.framedelta = -1
curframe = nframes-1
ENDIF
ENDIF ELSE BEGIN
WHILE curframe LT 0 DO $
curframe = curframe + nframes ; Into range
WHILE curframe GE nframes DO $
curframe = curframe - nframes
IF curframe EQ 0 THEN BEGIN ; Display rate?
t = systime(1)
r = nframes / FLOAT(t-state.loop_start_t) ; Rate in Frames/Sec
ENDIF
ENDELSE
state.curframe = curframe
IF r NE 0.0 THEN BEGIN ;Update time?
WIDGET_CONTROL, state.wFramesPerSecValue, SET_VALUE = $
STRING(r, FORMAT='(f6.1)')
state.loop_start_t = t
ENDIF
WSET, state.draw_win ;Set to the drawing window
HANDLE_VALUE, state.pwinHdl, pwin, /NO_COPY
IF pwin(curframe) GE 0 THEN $ ;Next frame
DEVICE, COPY =[0, 0, state.sizex, state.sizey, 0, 0, pwin(curframe)]
IF state.track THEN $
WIDGET_CONTROL, state.wFramesIndicatorSlider, SET_VALUE = curframe
HANDLE_VALUE, state.pwinHdl, pwin, /SET, /NO_COPY
EMPTY
ENDIF
state.wFramesSpeedSlider : BEGIN ;New rate
WIDGET_CONTROL, state.wFramesSpeedSlider, GET_VALUE = temp
IF temp EQ 100 THEN $
state.delay=0. $
ELSE $
state.delay= 2./(1.+temp)
END
state.wFramesIndicatorSlider : BEGIN
WIDGET_CONTROL, state.wFramesIndicatorSlider, GET_VALUE = temp
IF (temp NE state.curframe) THEN BEGIN
WSET, state.draw_win
state.curframe = temp
HANDLE_VALUE, state.pwinHdl, pwin, /NO_COPY
IF (pwin(temp) GE 0) THEN $
DEVICE, COPY = [0, 0, state.sizex, state.sizey, 0, 0, pwin(temp)]
HANDLE_VALUE, state.pwinHdl, pwin, /SET, /NO_COPY
EMPTY
ENDIF
END
state.wPauseButton : $
IF (state.framedelta NE 0) THEN BEGIN
WIDGET_CONTROL, state.wFramesIndicatorSlider, SET_VALUE = state.curframe
WIDGET_CONTROL, state.wFramesIndicatorSlider, SENSITIVE = 1
WIDGET_CONTROL, state.wFramesPerSecValue, SET_VALUE = $
STRING(0.0, FORMAT='(f6.1)')
state.framedelta = 0
SLICE_SETBITmapButtons, state
ENDIF
state.wPlayButton : BEGIN
WIDGET_CONTROL, state.wFramesIndicatorSlider, SENSITIVE = 0
WIDGET_CONTROL, state.wFramesSpeedSlider, SENSITIVE = 1
IF (state.framedelta EQ 0) THEN $
WIDGET_CONTROL, wAnimateBase, TIMER=state.delay
state.framedelta = 1
state.cycle = 0
SLICE_SETBITmapButtons, state
END
state.wReversePlayButton : BEGIN
WIDGET_CONTROL, state.wFramesIndicatorSlider, SENSITIVE = 0
WIDGET_CONTROL, state.wFramesSpeedSlider, SENSITIVE = 1
IF (state.framedelta EQ 0) THEN $
WIDGET_CONTROL, wAnimateBase, TIMER=state.delay
state.framedelta = -1
state.cycle = 0
SLICE_SETBITmapButtons, state
END
state.wCyclePlayButton : BEGIN
WIDGET_CONTROL, state.wFramesIndicatorSlider, SENSITIVE = 0
WIDGET_CONTROL, state.wFramesSpeedSlider, SENSITIVE = 1
IF (state.framedelta EQ 0) THEN $
WIDGET_CONTROL, wAnimateBase, TIMER=state.delay
state.framedelta = 1
state.cycle = 1
SLICE_SETBITmapButtons, state
END
state.wActiveSliderCheck: BEGIN
state.track = event.select
END
state.wHelpButton : $
XDISPLAYFILE, "animatedemo.hlp", TITLE = "Animation Help", $
GROUP = event.top, WIDTH = 55, HEIGHT = 16, $
TEXT = [ $
" ", $
" The animation widget is used for displaying", $
"a series of images created with IDL as an animation. The", $
"user can select the speed, direction or specific frames in", $
"the animation.", $
" The top slider is used to control the speed of", $
"the animation. Moving it to the far right is one hundred", $
"percent, as fast as the animation can go. If there are", $
"other IDL widget applications using background tasks,", $
"they can slow down the animation. Closing the other", $
"applications can speed up the animation.", $
" The four bitmap buttons are reverse play, pause, ", $
"forward play and cycle. Use them to select a direction or to", $
"pause the animation and view specific framestate.", $
" The bottom slider is used to view single frames", $
"from the animation. The animation must be paused to ", $
"use the frame selection slider." ]
state.wColorsButton : $
XCOLORS, GROUP = event.top, NCOLORS=state.ncolors, BOTTOM=state.bottom
state.wOpenButton : BEGIN
; get a copy before the structure is killed
open_func = state.open_func
framedelta = state.framedelta
wFramesSpeedSlider = state.wFramesSpeedSlider
; Need to restore state since the following routines use it
WIDGET_CONTROL, wTopBase, SET_UVALUE = state, /NO_COPY
SLICE_CW_ANIMATE_RUN, wAnimateBase, /STOP
; Disable all controls until all frames are loaded
WIDGET_CONTROL, wAnimateBase, SENSITIVE = 0
fileOK = CALL_FUNCTION(open_func, event.top, wAnimateBase)
IF fileOK THEN BEGIN
WIDGET_CONTROL, wFramesSpeedSlider, GET_VALUE = rate
IF framedelta EQ 0 THEN $
framedelta = 1
SLICE_CW_ANIMATE_RUN, wAnimateBase, rate, DELTA=framedelta, /LASTFRAME
ENDIF ELSE $
; Disable all controls until all frames are loaded
WIDGET_CONTROL, wAnimateBase, SENSITIVE = 1
; Need structure back - This kills the old uvalue
WIDGET_CONTROL, wTopBase, GET_UVALUE = state, /NO_COPY
END
state.wEndAnimationButton: $
ret = {ID:wAnimateBase, TOP:event.top, HANDLER:0L, action:"DONE" }
ELSE:
ENDCASE
WIDGET_CONTROL, wTopBase, SET_UVALUE = state, /NO_COPY ; Restore the state
RETURN, ret
END
pro SLICE_CW_ANIMATE_LOAD, widget, IMAGE = image, FRAME = frame, ORDER = order, $
WINDOW = window, XOFFSET = xoffset, YOFFSET = yoffset, $
TRACK = track, CYCLE = cycle
wTopBase = WIDGET_INFO(widget, /CHILD)
WIDGET_CONTROL, wTopBase, GET_UVALUE = state, /NO_COPY
HANDLE_VALUE, state.pwinHdl, pwin, /NO_COPY
old_window = !D.WINDOW
displayload = WIDGET_INFO(widget, /REALIZED)
IF (displayload NE 0) THEN BEGIN
WIDGET_CONTROL, GET_VALUE=temp, state.wImageArea
state.draw_win = temp
WSET, state.draw_win
; In case the draw widget size is different than that requested.
state.sizex = !D.X_VSIZE
state.sizey = !D.Y_VSIZE
ENDIF
; Default values and range checking
IF (N_ELEMENTS(yoffset) EQ 0) THEN $
yoffset = 0
IF (N_ELEMENTS(xoffset) EQ 0) THEN $
xoffset = 0
IF (N_ELEMENTS(frame)) GT 0 THEN BEGIN
IF (frame LT 0) OR (frame GE N_ELEMENTS(pwin)) THEN $
MESSAGE, "Frame number must be from 0 to nframes -1."
ENDIF ELSE $
frame=0
j = N_ELEMENTS(window) ;check to see if WINDOW was set
IF (j GT 0) THEN BEGIN ;Copy image from window?
IF (j LT 5) THEN BEGIN ;If coords not spec, use all
WSET, window(0)
p = [ window(0), 0, 0, !D.X_VSIZE, !D.Y_VSIZE ] ;Get size of window
ENDIF ELSE $
p = window
IF pwin(frame) LT 0 THEN BEGIN ;Create pixwin?
WINDOW, /FREE, XSIZE = state.sizex, YSIZE = state.sizey, /PIXMAP
pwin(frame) = !D.WINDOW
ENDIF
IF (p(3) GT state.sizex) OR (p(4) GT state.sizey) THEN $
MESSAGE, "Window parameter larger than setup"
IF displayload THEN BEGIN ;Load display window
WSET, state.draw_win ;Show it?
IF state.draw_win NE p(0) THEN $ ;Copy to show window?
DEVICE, COPY = [ p(1), p(2), p(3), p(4), xoffset, yoffset, p(0)]
WSET, pwin(frame) ;Pixmap destination
;Copy from display window to pixmap
DEVICE, COPY = [ xoffset, yoffset, p(3), p(4), xoffset, yoffset, $
state.draw_win ]
ENDIF ELSE BEGIN ;load / no show
WSET, pwin(frame)
DEVICE, COPY = [ p(1), p(2), p(3), p(4), xoffset, yoffset, p(0)]
ENDELSE
EMPTY
IF (N_ELEMENTS(state.draw_win) EQ 0) THEN $
state.draw_win = -1
IF (old_window GE 0) THEN $
WSET, old_window
; When displayload is set, the frame slider should update to show frame num
IF displayload THEN $
WIDGET_CONTROL, state.wFramesIndicatorSlider, SET_VALUE = frame
GOTO, Done
ENDIF ;So WINDOW was not set.
IF N_ELEMENTS(image) NE 0 THEN BEGIN ;Make sure image was set.
; When displayload is set, the draw widget should be updated
; to show the new frame being loaded and the frame slider
; should be set correspondingly
IF (displayload NE 0) THEN BEGIN
WIDGET_CONTROL, state.wFramesIndicatorSlider, SET_VALUE = frame
WSET, state.draw_win
TV, image
EMPTY
ENDIF
;Make sure the image is of a valid size and report if not.
sz = SIZE(image)
IF ((sz(0) NE 2) OR (sz(1) GT state.sizex) OR (sz(2) GT state.sizey)) THEN $
MESSAGE, "Image parameter must be 2D of size" + $
STRING(state.sizex)+ STRING(state.sizey)
IF N_ELEMENTS(order) EQ 0 THEN $
ORDER = 0 ;Default order
IF pwin(frame) LT 0 THEN BEGIN
WINDOW, /FREE, xsize = state.sizex, ysize = state.sizey, /pixmap
pwin(frame) = !D.WINDOW
ENDIF ELSE $
WSET, pwin(frame)
TV, image, xoffset, yoffset, ORDER = order
EMPTY
IF (old_window GE 0) THEN $
WSET, old_window
GOTO, Done
ENDIF ;End of "if IMAGE was set".
Done: HANDLE_VALUE, state.pwinHdl, pwin, /SET, /NO_COPY
WIDGET_CONTROL, wTopBase, SET_UVALUE = state, /NO_COPY ;Restore uvalue
END ;SLICE_CW_ANIMATE_LOAD
pro SLICE_CW_ANIMATE_RUN, widget, rate, STOP = stop, NFRAMES = nframes, $
DELTA = delta, LASTFRAME=lastFrame
wTopBase = WIDGET_INFO(widget, /CHILD)
WIDGET_CONTROL, wTopBase, GET_UVALUE = state, /NO_COPY
old_window = !D.WINDOW ;Save old window
; Refuse to run if the cluster isn't realized.
IF (WIDGET_INFO(widget, /REALIZED) EQ 0) THEN $
MESSAGE,'Animation widget must be realized before it can run'
IF KEYWORD_SET(stop) THEN BEGIN ;Stop the animation
state.framedelta = 0 ;This shows we've stopped.
WIDGET_CONTROL, state.wFramesIndicatorSlider, SET_VALUE = state.curframe
WIDGET_CONTROL, state.wFramesIndicatorSlider, SENSITIVE = 1
SLICE_SETBITmapButtons, state
GOTO, done
ENDIF
; It is realized now, so get the draw widget window ID.
WIDGET_CONTROL, GET_VALUE=temp, state.wImageArea
state.draw_win = temp
WSET, temp
EMPTY
WIDGET_CONTROL, widget, /SENSITIVE
WIDGET_CONTROL, state.wFramesIndicatorSlider, SENSITIVE = 0
IF N_ELEMENTS(nframes) GT 0 THEN BEGIN ;Nframes spec?
HANDLE_VALUE, state.pwinHdl, pwin, /NO_COPY
IF nframes GT N_ELEMENTS(pwin) THEN $
MESSAGE, 'Run called with too many frames'
HANDLE_VALUE, state.pwinHdl, pwin, /SET, /NO_COPY
state.nframes = nframes
ENDIF
;Set up the initial values used by the background task
IF N_ELEMENTS(lastFrame) NE 0 THEN $
state.curframe = state.nframes $
ELSE $
state.curframe = 0
IF N_ELEMENTS(delta) NE 0 THEN $
state.framedelta = -1 > delta < 1 $ ; In range?
ELSE $
state.framedelta = 1
IF N_ELEMENTS(rate) NE 0 THEN BEGIN
rate = 0 > rate < 100 ; In range?
WIDGET_CONTROL, state.wFramesSpeedSlider, SET_VALUE = rate
ENDIF ELSE $
rate = 100
IF rate EQ 100 THEN $
state.delay=0.0 $
ELSE $
state.delay = 2./(1.+rate)
SLICE_SETBITmapButtons, state
state.loop_start_t = SYSTIME(1) ;Start of loop time
WIDGET_CONTROL, widget, TIMER=state.delay, EVENT_FUNC = 'SLICE_CW_ANIMATE_EV'
done:
WIDGET_CONTROL, wTopBase, SET_UVALUE = state, /NO_COPY ;Rewrite state
END
pro SLICE_CW_ANIMATE_GETP, widget, PIXMAPS, KILL_ANYWAY = kill_anyway
; Return the vector of pixmap ID's associated with the animation
; widget in named variable PIXMAPSTATE. Frames without a pixmap contain a -1.
; This routine should not be called until all the frames are loaded, or the
; vector will not be complete. It should be called before the call to
; SLICE_CW_ANIMATE_RUN.
;
; Note: Normally, the animation widget destroys its pixmaps when it
; is destroyed. If this routine is called however, the pixmaps
; are not destroyed. Cleanup becomes the responsibility of the
; caller.
wTopBase = WIDGET_INFO(widget, /CHILD)
WIDGET_CONTROL, wTopBase, GET_UVALUE = state, /NO_COPY
HANDLE_VALUE, state.pwinHdl, pwin, /NO_COPY
pixmaps = pwin
HANDLE_VALUE, state.pwinHdl, pwin, /SET, /NO_COPY
IF KEYWORD_SET(kill_anyway) EQ 0 THEN $
state.dont_kill_pixmaps = 1
WIDGET_CONTROL, wTopBase, SET_UVALUE = state, /NO_COPY
END
PRO SLICE_CW_ANIMATE_INIT, wAnimateBase, sizex, sizey, nframes, PIXMAPS=old_pixmaps
ON_ERROR, 2 ;return to caller
wTopBase = WIDGET_INFO(wAnimateBase, /CHILD)
WIDGET_CONTROL, wTopBase, GET_UVALUE = state, /NO_COPY
nparams = N_PARAMS()
IF (nparams LT 3) OR (nparams GT 4) THEN $
MESSAGE, 'Incorrect number of arguments'
IF NOT (KEYWORD_SET(uval)) THEN $
uval = 0
n = N_ELEMENTS(old_pixmaps)
IF (n GT 0) THEN BEGIN
nframes = n
pwin = old_pixmaps
ENDIF ELSE $
pwin = REPLICATE(-1, nframes) ;Array of window indices
IF (nframes LE 1) THEN $
MESSAGE, "Animations must have 2 or more frames"
; save the number of frames to animate in the animation structure
state.nframes = nframes
; save the Pixmap array to animate in the animation structure
IF HANDLE_INFO(state.pwinHdl) THEN BEGIN
; Need to temporarily restore state since the following routine uses it
WIDGET_CONTROL, wTopBase, SET_UVALUE = state, /NO_COPY
SLICE_CW_ANIMATE_CLN, wTopBase
; Need structure back - This kills the widget uvalue
WIDGET_CONTROL, wTopBase, GET_UVALUE = state, /NO_COPY
ENDIF
state.pwinHdl = HANDLE_CREATE()
HANDLE_VALUE, state.pwinHdl, pwin, /SET, /NO_COPY
WIDGET_CONTROL, state.wFramesIndicatorSlider, SET_SLIDER_MAX = nframes - 1
IF state.wImageArea NE 0 THEN BEGIN
; to avoid flash - only set the size if it changes
IF (state.sizex NE sizex OR state.sizey NE sizey) THEN $
WIDGET_CONTROL, state.wImageArea, XSIZE =sizex, YSIZE=sizey
ENDIF ELSE BEGIN
wImageBase = WIDGET_BASE(wTopBase, /COLUMN) ;To prevent stretching
state.wImageArea = WIDGET_DRAW(wImageBase, XSIZE =sizex, YSIZE=sizey, $
XOFFSET = 280, YOFFSET = 20, RETAIN = 2)
ENDELSE
; save the x dimensions of draw widget in the animation structure
state.sizex = sizex
; save the y dimensions of draw widget in the animation structure
state.sizey = sizey
; Disable all controls until all frames are loaded
WIDGET_CONTROL, wAnimateBase, SENSITIVE = 0
WIDGET_CONTROL, wTopBase, SET_UVALUE = state, /NO_COPY
END
; Setup the play reverse, pause, play forward and cycle pushbutton bitmaps. These
; variables reside in the "BitmapButtons" common block.
; Both a depressed (blk_) and a not-depressed version are needed for each button.
PRO SLICE_INITBITmapButtons
COMMON BitmapButtons
reversebutton = [[000B, 000B, 000B], [000B, 032B, 000B], [000B, 048B, 000B],$
[000B, 056B, 000B], [000B, 060B, 000B], [000B, 046B, 000B], $
[000B, 231B, 015B], [144B, 003B, 024B], [016B, 231B, 027B], $
[080B, 238B, 027B], [208B, 060B, 026B], [208B, 056B, 026B], $
[208B, 048B, 026B], [208B, 032B, 026B], [208B, 000B, 026B], $
[208B, 000B, 026B], [208B, 255B, 027B], [016B, 000B, 024B], $
[240B, 255B, 031B], [224B, 255B, 015B], [000B, 000B, 000B], $
[000B, 000B, 000B], [000B, 000B, 000B], [000B, 000B, 000B] ]
blk_reversebutton = [[255B, 255B, 255B], [255B, 223B, 255B],[255B, 207B, 255B],$
[255B, 199B, 255B], [255B, 195B, 255B], [255B, 209B, 255B], $
[255B, 024B, 240B], [111B, 252B, 231B], [239B, 024B, 228B], $
[175B, 017B, 228B], [047B, 195B, 229B], [047B, 199B, 229B], $
[047B, 207B, 229B], [047B, 223B, 229B], [047B, 255B, 229B], $
[047B, 255B, 229B], [047B, 000B, 228B], [239B, 255B, 231B], $
[015B, 000B, 224B], [031B, 000B, 240B], [255B, 255B, 255B], $
[255B, 255B, 255B], [255B, 255B, 255B], [255B, 255B, 255B] ]
pausebutton = [[000B, 000B, 000B], [000B, 000B, 000B], [000B, 000B, 000B], $
[192B, 195B, 003B], [192B, 194B, 002B], [192B, 194B, 002B], $
[192B, 194B, 002B], [192B, 194B, 002B], [192B, 194B, 002B], $
[192B, 194B, 002B], [192B, 194B, 002B], [192B, 194B, 002B], $
[192B, 194B, 002B], [192B, 194B, 002B], [192B, 194B, 002B], $
[192B, 194B, 002B], [192B, 194B, 002B], [192B, 194B, 002B], $
[192B, 194B, 002B], [192B, 195B, 003B], [192B, 195B, 003B], $
[000B, 000B, 000B], [000B, 000B, 000B], [000B, 000B, 000B] ]
blk_pausebutton = [[255B, 255B, 255B], [255B, 255B, 255B], [255B, 255B, 255B],$
[063B, 060B, 252B], [063B, 061B, 253B], [063B, 061B, 253B], $
[063B, 061B, 253B], [063B, 061B, 253B], [063B, 061B, 253B], $
[063B, 061B, 253B], [063B, 061B, 253B], [063B, 061B, 253B], $
[063B, 061B, 253B], [063B, 061B, 253B], [063B, 061B, 253B], $
[063B, 061B, 253B], [063B, 061B, 253B], [063B, 061B, 253B], $
[063B, 061B, 253B], [063B, 060B, 252B], [063B, 060B, 252B], $
[255B, 255B, 255B], [255B, 255B, 255B], [255B, 255B, 255B] ]
playbutton = [[000B, 000B, 000B], [000B, 004B, 000B], [000B, 012B, 000B], $
[000B, 028B, 000B], [000B, 060B, 000B], [000B, 116B, 000B], $
[240B, 231B, 000B], [024B, 192B, 009B], [216B, 231B, 008B], $
[216B, 119B, 010B], [088B, 060B, 011B], [088B, 028B, 011B], $
[088B, 012B, 011B], [088B, 004B, 011B], [088B, 000B, 011B], $
[088B, 000B, 011B], [216B, 255B, 011B], [024B, 000B, 008B], $
[248B, 255B, 015B], [240B, 255B, 007B], [000B, 000B, 000B], $
[000B, 000B, 000B], [000B, 000B, 000B], [000B, 000B, 000B] ]
blk_playbutton = [[255B, 255B, 255B], [255B, 251B, 255B], [255B, 243B, 255B],$
[255B, 227B, 255B], [255B, 195B, 255B], [255B, 139B, 255B], $
[015B, 024B, 255B], [231B, 063B, 246B], [039B, 024B, 247B], $
[039B, 136B, 245B], [167B, 195B, 244B], [167B, 227B, 244B], $
[167B, 243B, 244B], [167B, 251B, 244B], [167B, 255B, 244B], $
[167B, 255B, 244B], [039B, 000B, 244B], [231B, 255B, 247B], $
[007B, 000B, 240B], [015B, 000B, 248B], [255B, 255B, 255B], $
[255B, 255B, 255B], [255B, 255B, 255B], [255B, 255B, 255B] ]
cycleForwardBtn = [[000B, 000B, 000B], [000B, 000B, 000B], [000B, 128B, 000B], $
[000B, 128B, 001B], [000B, 128B, 003B], [248B, 255B, 006B], $
[008B, 000B, 012B], [008B, 000B, 024B], [248B, 255B, 012B], $
[248B, 255B, 006B], [000B, 128B, 003B], [000B, 129B, 001B], $
[128B, 129B, 000B], [192B, 001B, 000B], [096B, 255B, 015B], $
[048B, 000B, 008B], [024B, 000B, 008B], [048B, 255B, 015B], $
[096B, 255B, 015B], [192B, 001B, 000B], [128B, 001B, 000B], $
[000B, 001B, 000B], [000B, 000B, 000B], [000B, 000B, 000B] ]
blk_cycleForwardBtn = [[255B, 255B, 255B], [255B, 255B, 255B], [255B, 127B, 255B], $
[255B, 127B, 254B], [255B, 127B, 252B], [007B, 000B, 249B], $
[247B, 255B, 243B], [247B, 255B, 231B], [007B, 000B, 243B], $
[007B, 000B, 249B], [255B, 127B, 252B], [255B, 126B, 254B], $
[127B, 126B, 255B], [063B, 254B, 255B], [159B, 000B, 240B], $
[207B, 255B, 247B], [231B, 255B, 247B], [207B, 000B, 240B], $
[159B, 000B, 240B], [063B, 254B, 255B], [127B, 254B, 255B], $
[255B, 254B, 255B], [255B, 255B, 255B], [255B, 255B, 255B] ]
END
function SLICE_CW_ANIMATE, parent, sizex, sizey, nframes, UVALUE=uval, $
PIXMAPS=old_pixmaps, TRACK = track, CYCLE=cycle, DRAW = draw, $
NO_KILL = no_kill, OPEN_FUNC=open_func, NCOLORS=ncolors, BOTTOM=bottom
COMMON BitmapButtons
ON_ERROR, 2 ;return to caller
; Set the bitmaps for the bitmap buttons
SLICE_INITBITmapButtons
nparams = N_PARAMS()
IF (nparams LT 3) OR (nparams GT 4) THEN $
MESSAGE, 'Incorrect number of arguments'
IF NOT (KEYWORD_SET(uval)) THEN $
uval = 0
IF NOT (KEYWORD_SET(open_func)) THEN $
open_func = 0
IF N_ELEMENTS(ncolors) EQ 0 THEN ncolors = !D.N_COLORS
IF N_ELEMENTS(bottom) EQ 0 THEN bottom = 0
wAnimateBase = WIDGET_BASE(parent, /COLUMN)
wTopBase = WIDGET_BASE(wAnimateBase, /ROW)
wControlBase = WIDGET_BASE(wTopBase, /COLUMN, /FRAME, XPAD=10, YPAD=10, SPACE=20)
wVCRButtonBase = WIDGET_BASE(wControlBase, /ROW)
wReversePlayButton = WIDGET_BUTTON(wVCRButtonBase, VALUE = reversebutton)
wPauseButton = WIDGET_BUTTON(wVCRButtonBase, VALUE = blk_pausebutton)
wPlayButton = WIDGET_BUTTON(wVCRButtonBase, VALUE = playbutton)
wCyclePlayButton = WIDGET_BUTTON(wVCRButtonBase, VALUE = cycleForwardBtn)
currentAction = wPauseButton
currentBitmap = pausebutton
wSpeedBase = WIDGET_BASE(wControlBase, /COLUMN)
wSpeedBaseLabel = WIDGET_LABEL(wSpeedBase, VALUE = "Animation Speed:", /ALIGN_LEFT)
wFramesSpeedBase = WIDGET_BASE(wSpeedBase, TITLE = "Animation Speed", /COLUMN, /FRAME)
wFramesPerSecBase = WIDGET_BASE(wFramesSpeedBase, /ROW)
wFramesPerSecLabel = WIDGET_LABEL(wFramesPerSecBase, VALUE = "Frames/Sec:")
wFramesPerSecValue = WIDGET_LABEL(wFramesPerSecBase, VALUE = '0.000')
wFramesSpeedSlider = WIDGET_SLIDER(wFramesSpeedBase, /DRAG, VALUE = 100, $
MAXIMUM = 100, MINIMUM = 0, /SUPPRESS_VALUE)
wFrameBase = WIDGET_BASE(wControlBase, /COLUMN)
wFrameBaseLabel = WIDGET_LABEL(wFrameBase, VALUE = "Animation Frame:", /ALIGN_LEFT)
wFrameIndicatorBase = WIDGET_BASE(wFrameBase, TITLE = "Animation Frame", /COLUMN, /FRAME)
wFramesIndicatorSlider = WIDGET_SLIDER(wFrameIndicatorBase, /DRAG, VALUE = 0, $
MAXIMUM = nframes - 1, MINIMUM = 0)
wActiveSliderCheck = CW_BGROUP(wFrameIndicatorBase, ['Active Slider'], $
FRAME = 0, /NONEXCLUSIVE, /RETURN_INDEX, $
SET_VALUE=KEYWORD_SET(track))
wButtonBase = WIDGET_BASE(wAnimateBase, /ROW, /ALIGN_LEFT)
IF KEYWORD_SET(no_kill) THEN $
wEndAnimationButton = 0L $
ELSE $
wEndAnimationButton = WIDGET_BUTTON(wButtonBase, VALUE='End Animation')
; wColorsButton = WIDGET_BUTTON(wButtonBase, VALUE='Colors...')
wcolorsbutton = -1L
IF (KEYWORD_SET(open_func)) THEN $
wOpenButton = WIDGET_BUTTON(wButtonBase, VALUE='Open...') $
ELSE $
wOpenButton = 0
wHelpButton = WIDGET_BUTTON(wButtonBase, VALUE='Help')
IF N_ELEMENTS(draw) EQ 1 THEN $
wImageArea = draw $
ELSE $
wImageArea = 0
; Set the event handler function. This cluster does not get or set a value
; Make sure it lingers so the cleanup routine can get at its state.
WIDGET_CONTROL, wAnimateBase, SET_UVALUE = uval, EVENT_FUNC = 'SLICE_CW_ANIMATE_EV', $
/DELAY_DESTROY
;pwin = REPLICATE(-1, nframes) ;Array of window indices
; This structure gets stuffed into the uval. of the first child
; of wAnimateBase
WIDGET_CONTROL, wTopBase, SET_UVALUE = $
{ wEndAnimationButton: wEndAnimationButton, $ ; End button
wColorsButton: wColorsButton, $ ; Adjust color palette button
wOpenButton: wOpenButton, $ ; Open file button
open_func: open_func, $ ; Open file function
wHelpButton: wHelpButton, $ ; Help button
wActiveSliderCheck: wActiveSliderCheck, $ ; button group widget
wFramesSpeedSlider: wFramesSpeedSlider, $ ; Speed selection slider
wReversePlayButton: wReversePlayButton, $ ; Reverse button
wPauseButton: wPauseButton, $ ; Stop (pause) button
wPlayButton: wPlayButton, $ ; Forward button
wCyclePlayButton: wCyclePlayButton, $ ; Cycle forward button
currentAction : currentAction, $ ; current action button id
currentBitmap : currentBitmap, $ ; current button bitmap
wFramesIndicatorSlider: wFramesIndicatorSlider, $; Frame selection slider
wFramesPerSecValue: wFramesPerSecValue, $ ; Animation rate display
wImageArea: wImageArea, $ ; Draw widget for animation
draw_win: -1, $ ; Window # of draw widget
sizex: 0, sizey: 0, $ ; Dimensions of draw widget
nframes: 0, $ ; # of frames in animation
curframe: 0, $
ncolors:ncolors, $ ; Number of colors to load
bottom:bottom, $ ; Starting index of colors
cycle: KEYWORD_SET(cycle), $ ; Ne 0 to cycle
track: KEYWORD_SET(track), $ ; Ne 0 to track with slider
framedelta: 0, $ ; # frames to step.
delay: 0.0D, $ ; Delay between frames
loop_start_t: 0.0D, $ ; System time at start
dont_kill_pixmaps: 0, $ ; TRUE if pixmaps preserved on kill
pwinHdl: 0L } ; handle to the Pixmap array
; When the child holding the state gets killed, have a cleanup
; procedure called to mop up
WIDGET_CONTROL, wTopBase, KILL_NOTIFY = 'SLICE_CW_ANIMATE_CLN'
SLICE_CW_ANIMATE_INIT, wAnimateBase, sizex, sizey, nframes, PIXMAPS=old_pixmaps
RETURN, wAnimateBase
END
PRO SLICE_CHARSIZE_EVENT, event
WIDGET_CONTROL, event.top, GET_UVALUE=info
CASE event.id OF
info.cancel: BEGIN
HANDLE_VALUE, info.ptr, -1, /SET
WIDGET_CONTROL, event.top, /DESTROY
END
info.accept: BEGIN
WIDGET_CONTROL, info.slider, GET_VALUE=thisValue
val = (thisValue / 100.0) * 5.0
HANDLE_VALUE, info.ptr, val, /SET
WIDGET_CONTROL, event.top, /DESTROY
END
ELSE: BEGIN
WIDGET_CONTROL, info.slider, GET_VALUE=thisValue
val = (thisValue / 100.0) * 5.0
val = STRTRIM(val, 2)
val = STRING(val, FORMAT='(F4.2)')
WIDGET_CONTROL, info.labelID, SET_VALUE=val
END
ENDCASE
END
FUNCTION SLICE_CHARSIZE, initValue, LABEL=label, XOFFSET=xoffset, $
YOFFSET=yoffset
IF N_PARAMS() EQ 0 THEN initValue = 1.0
IF N_ELEMENTS(label) EQ 0 THEN label='Change Character Size'
; Find the center of the display.
DEVICE, GET_SCREEN_SIZE=screenSize
xCenter = FIX(screenSize(0) / 2.0)
yCenter = FIX(screenSize(1) / 2.0)
IF N_ELEMENTS(xoffset) EQ 0 THEN xoffset = xCenter - 75
IF N_ELEMENTS(yoffset) EQ 0 THEN yoffset = yCenter - 50
tlb = WIDGET_BASE(COLUMN=1, TLB_FRAME_ATTR=1, XOFFSET=xoffset, $
YOFFSET=yoffset)
labelID = WIDGET_LABEL(tlb, VALUE=label)
sliderValue = FIX((initValue / 5.0) * 100)
title = STRTRIM(initValue, 2)
title = STRING(title, FORMAT='(F4.2)')
slider = WIDGET_SLIDER(tlb, VALUE=sliderValue, MAX=100, MIN=0, $
/SUPPRESS_VALUE)
labelID = WIDGET_LABEL(tlb, VALUE=title, /DYNAMIC_RESIZE)
buttonBase = WIDGET_BASE(tlb, ROW=1, FRAME=1)
cancel = WIDGET_BUTTON(buttonBase, Value='Cancel')
accept = WIDGET_BUTTON(buttonBase, Value='Accept')
ptr = HANDLE_CREATE()
info = { ptr:ptr, $
slider:slider, $
cancel:cancel, $
accept:accept, $
labelID:labelID}
WIDGET_CONTROL, tlb, /REALIZE, SET_UVALUE=info
XMANAGER, 'SLICE_CHARSIZE', tlb, /MODAL
HANDLE_VALUE, ptr, value
HANDLE_FREE, ptr
IF value LT 0 OR N_ELEMENTS(value) EQ 0 THEN RETURN, -1 ELSE RETURN, value
END
PRO SLICE_Integer_Only, event
; This event handler for text widgets only allows integers to be entered
; in the text widget. A maximum of four digits are allowed.
; Deal with simple one-character insertion events.
IF event.type EQ 0 THEN BEGIN
; Get the current text in the widget and find its length.
Widget_Control, event.id, Get_Value=text
text = text(0)
length = StrLen(text)
; Only react if the insertion character is a number and there
; are less than four characters already in the widget.
IF Byte(event.ch) GE 48B AND Byte(event.ch) LE 57B AND length LT 4 THEN BEGIN
; Get the current text selection.
selection = Widget_Info(event.id, /Text_Select)
; Insert the character at the proper location.
Widget_Control, event.id, /Use_Text_Select, Set_Value=String(event.ch)
; Update the current insertion point in the text widget.
Widget_Control, event.id, Set_Text_Select=event.offset + 1
ENDIF
ENDIF ; of insertion event
; Deal with deletion events.
IF event.type EQ 2 THEN BEGIN
; Get the current text in widget.
Widget_Control, event.id, Get_Value=text
text = text(0)
length = StrLen(text)
; Put it back with the deletion subtracted.
Widget_Control, event.id, Set_Value=StrMid(text, 0, length-event.length)
; Reset the text insertion point in the text widget.
Widget_Control, event.id, Set_Text_Select=event.offset
ENDIF
END ; of SLICE_Integer_Only event handler *************************************************
PRO SLICE_NULL_EVENTS, event
; The purpose of this event handler is to do nothing and ignore all events that
; come to it.
END ; of SLICE_NULL_EVENTS event handler ***************************************************
PRO SLICE_GETIMAGE_EVENT, event
; The only events that can come here are button events.
; Get the info structure out of the user value of the top-level base.
Widget_Control, event.top, Get_UValue=info
; There may be errors we can't anticipate. Catch them here, alert the
; user as to what the error was, and exit the event handler without
; doing any damage.
Catch, error
IF error NE 0 THEN BEGIN
ok = Widget_Message(!Err_String)
RETURN
ENDIF
; Which button caused this event?
Widget_Control, event.id, Get_Value=buttonValue
CASE buttonValue OF
'Pick Filename': BEGIN
; Start in the directory listed in the directory text widget.
; Convert the text value to a scalar.
Widget_Control, info.dirnameID, Get_Value=startDirectory
startDirectory = startDirectory(0)
; If this directory doesn't exist, use the current directory.
test = Findfile(startDirectory, Count=foundfile)
IF foundfile NE 1 THEN CD, Current=startDirectory
; Use PICKFILE to pick a name.
pick = Pickfile(Path=startDirectory, /NoConfirm, Get_Path=path, Filter='*.dat')
; Set the directory text widget with the name of the directory.
; Make sure the user didn't cancel out of PICKFILE.
IF pick NE '' THEN BEGIN
; Find the lengths of the PICK and the PATH.
pathLen = StrLen(path)
picklen = StrLen(pick)
; Shorten the PATH to take off last file separator.
path = StrMid(path,0,pathLen-1)
; Put the PATH in the directory location.
Widget_Control, info.dirnameID, Set_Value=path
; Set the filename text widget with the name of the file.
filename = StrMid(pick, pathlen, picklen-pathlen)
Widget_Control, info.filenameID, Set_Value=filename
ENDIF
END ; of the Pick Filename button case
'Cancel': BEGIN
; Have to exit here gracefully. Null filename means "CANCEL".
formdata = {filename:''}
Handle_Value, info.ptrToFormData, formdata, /Set
; Out of here!
Widget_Control, event.top, /Destroy
END ; of the Cancel button case
'Accept': BEGIN ; Gather the form information.
; Put the directory and filename together to make a path.
Widget_Control, info.dirnameID, Get_Value=directory
Widget_Control, info.filenameID, Get_Value=file
filename = Filepath(Root_Dir=directory(0),file(0))
; Get the size and header info. Remember these are STRINGS!
Widget_Control, info.headerID, Get_Value=header
Widget_Control, info.xsizeID, Get_Value=xsize
Widget_Control, info.ysizeID, Get_Value=ysize
Widget_Control, info.frameID, Get_Value=frames
header = Fix(header(0))
xsize = Fix(xsize(0))
ysize = Fix(ysize(0))
frames = Fix(frames(0))
; Get the data type from the droplist widget.
listIndex = Widget_Info(info.droplistID, /Droplist_Select)
datatype = info.datatypes(listIndex)
; Get the format index from the formatlist widget.
formatIndex = Widget_Info(info.formatlistID, /Droplist_Select)
; Create the formdata structure from the information you collected.
formdata = {header:header, xsize:xsize, ysize:ysize, frames:frames, $
filename:filename, datatype:datatype, formatIndex:formatIndex}
; Store the formdata in the pointer location.
Handle_Value, info.ptrToFormData, formdata, /Set
; Out of here!
Widget_Control, event.top, /Destroy
END ; of the Accept button case
ENDCASE
END ; of SLICE_GETIMAGE_EVENT event handler ************************************************
FUNCTION SLICE_GETIMAGE, filename, Directory=directory, XSize=xsize, YSize=ysize, $
Frames=frames, Header=header, XDR=xdr, XOffSet=xoffset, YOffSet=yoffset
; This is a function to specify the size, data type, and header information
; about an image that you would like to read. It reads the data and returns
; it as the result of the function. If an error occurs, the function returns a 0.
; Check for parameters and keywords.
IF N_Params() EQ 0 THEN filename='ctscan.dat'
; If DIRECTORY keyword is not used, use the "training" directory.
; If that is not found, use the current directory.
IF N_Elements(directory) EQ 0 THEN BEGIN
startDirectory = Filepath('training')
junk = Findfile(startDirectory, Count=foundfile)
IF foundfile EQ 0 THEN CD, Current=startDirectory
ENDIF ELSE startDirectory = directory
; Check for size and header keywords. These probably come in as
; numbers and you need strings to put them into text widgets.
IF N_Elements(xsize) EQ 0 THEN xsize='256' ELSE xsize=StrTrim(xsize,2)
IF N_Elements(ysize) EQ 0 THEN ysize='256' ELSE ysize=StrTrim(ysize,2)
IF N_Elements(frames) EQ 0 THEN frames='0' ELSE frames=StrTrim(frames,2)
IF N_Elements(header) EQ 0 THEN header='0' ELSE header=StrTrim(header,2)
; Find the center of the display.
Device, Get_Screen_Size=screenSize
xCenter = Fix(screenSize(0) / 2.0)
yCenter = Fix(screenSize(1) / 2.0)
IF N_Elements(xoffset) EQ 0 THEN xoffset = xCenter - 275
IF N_Elements(yoffset) EQ 0 THEN yoffset = yCenter - 150
; Create a top-level base.
tlb = Widget_Base(Column=1, Title='Read Image Data', XOffSet=xoffset, $
YOffSet=yoffset)
; Create the directory widgets.
dirnamebase = Widget_Base(tlb, Row=1)
dirnamelabel = Widget_Label(dirnamebase, Value='Directory:')
dirnameID = Widget_Text(dirnamebase, Value=startDirectory, /Editable, $
Event_Pro='SLICE_NULL_EVENTS', XSize=Fix(2.0*StrLen(startDirectory) > 50))
; Create the filename widgets.
filenamebase = Widget_Base(tlb, Row=1)
filenamelabel = Widget_Label(filenamebase, Value='Filename:')
filenameID = Widget_Text(filenamebase, Value=filename, /Editable, $
Event_Pro='SLICE_NULL_EVENTS', XSize=2*StrLen(filename) > 20)
; Create a button to allow user to pick a filename.
pickbutton = Widget_Button(filenamebase, Value='Pick Filename')
; Create a droplist widget to select file data types.
database = Widget_Base(tlb, Row=1)
datatypes = ['Byte', 'Integer', 'Long', 'Float']
droplistID = Widget_Droplist(database, Value=datatypes, $
Title='Data Type: ', Event_Pro='SLICE_NULL_EVENTS')
; Create a droplist widget to select file formats.
formatlistID = Widget_Droplist(database, Value=['None', 'XDR'], $
Title='File Format: ', Event_Pro='SLICE_NULL_EVENTS')
; Create a text widget to accept a header size.
headlabel = Widget_Label(database, Value='Header Size:')
headerID = Widget_Text(database, Value=header, All_Events=1, Editable=0, $
Event_Pro='SLICE_Integer_Only', XSize=8)
; Create widgets to gather the required file sizes.
sizebase = Widget_Base(tlb, Row=1)
xlabel = Widget_Label(sizebase, Value='X Size:')
xsizeID = Widget_Text(sizebase, Value=xsize, All_Events=1, Editable=0, $
Event_Pro='SLICE_Integer_Only', XSize=8)
ylabel = Widget_Label(sizebase, Value='Y Size:')
ysizeID = Widget_Text(sizebase, Value=ysize, All_Events=1, Editable=0, $
Event_Pro='SLICE_Integer_Only', XSize=8)
zlabel = Widget_Label(sizebase, Value='Frames:')
frameID = Widget_Text(sizebase, Value=frames, All_Events=1, Editable=0, $
Event_Pro='SLICE_Integer_Only', XSize=8)
; Create cancel and accept buttons.
cancelbase = Widget_Base(tlb, Column=2, Frame=1)
cancel = Widget_Button(cancelbase, Value='Cancel')
accept = Widget_Button(cancelbase, Value='Accept')
; Realize the program.
Widget_Control, tlb, /Realize
; Create a pointer to store the information collected from the form.
ptrToFormData = Handle_Create()
; Set the correct file format in the format droplist widget.
Widget_Control, formatlistID, Set_Droplist_Select=Keyword_Set(xdr)
; Set the text insertion point at the end of the filename text widget.
tip = [StrLen(filename),0]
Widget_Control, filenameID, Input_Focus=1
Widget_Control, filenameID, Set_Text_Select=tip
; Create an info structure with program information.
info = { filenameID:filenameID, $
dirnameID:dirnameID, $
xsizeID:xsizeID, $
ysizeID:ysizeID, $
frameID:frameID, $
headerID:headerID, $
droplistID:droplistID, $
formatlistID:formatlistID, $
datatypes:datatypes, $
ptrToFormData:ptrToFormData}
; Store the info structure in the user value of the top-level base.
Widget_Control, tlb, Set_UValue=info
; The form will be a MODAL widget. This means we STOP at the
; following XManager call until the widget is destroyed.
XManager, 'SLICE_GETIMAGE', tlb, Event_Handler='SLICE_GETIMAGE_EVENT', /Modal
; Get the form data that was collected by the form.
Handle_Value, ptrToFormData, formdata
; If there is nothing here. Free the pointer and return.
IF N_Elements(formdata) EQ 0 THEN BEGIN
Handle_Free, ptrToFormData
RETURN, 0
ENDIF
; Did the user cancel out of the form? If so, return a 0.
IF formdata.filename EQ '' THEN BEGIN
Handle_Free, ptrToFormData
RETURN, 0
ENDIF
; Make the proper sized image array. Check for success.
image = 0
IF formdata.frames EQ 0 THEN $
command = 'image = Make_Array(formdata.xsize, formdata.ysize, ' + $
formdata.datatype + '=1)' ELSE $
command = 'image = Make_Array(formdata.xsize, ' + $
'formdata.ysize, formdata.frames, ' + formdata.datatype + '=1)'
check = Execute(command)
IF check EQ 0 THEN BEGIN
ok = Widget_Message("Problem making image array. Returning 0.")
RETURN, 0
ENDIF
; We can have all kinds of trouble reading data. Let's catch all
; input and output errors and alert user without crashing the program!
Catch, error
IF error NE 0 THEN BEGIN
; If we can't read the file for some reason, let the user know
; why, free the pointer and its information, check the logical
; unit number back in if it is checked out, and return a 0.
ok = Widget_Message(!Err_String)
Handle_Free, ptrToFormData
IF N_ELements(lun) NE 0 THEN Free_Lun, lun
RETURN, 0
ENDIF
; Read the data file.
IF formdata.header GT 0 THEN header = BytArr(formdata.header)
Get_Lun, lun
OpenR, lun, formdata.filename, XDR=formdata.formatIndex
IF formdata.header EQ 0 THEN ReadU, lun, image $
ELSE ReadU, lun, header, image
Free_Lun, lun
; Free the pointer.
Handle_Free, ptrToFormData
RETURN, image
END ; of SLICE_GETIMAGE program ******************************************************
FUNCTION SLICE_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 SLICE_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 SLICE_DELAY_NOTICE, question
; Default question.
IF N_PARAMS() EQ 0 THEN question = 'There will be a short delay ...'
; Put up in the middle of the display. NOT a modal widget.
DEVICE, GET_SCREEN_SIZE=screenSize
tlb = WIDGET_BASE(XOFFSET=screenSize(0)/2.0 - 75, YOFFSET=screenSize(1)/ 3.0)
label = WIDGET_LABEL(tlb, VALUE=question)
WIDGET_CONTROL, tlb, /REALIZE
RETURN, tlb
END ; of SLICE_DELAY_NOTICE utility routine **********************************
PRO SLICE_DRAW_MOTION_EVENTS, event
; Get info structure.
WIDGET_CONTROL, event.top, GET_UVALUE=tlb
WIDGET_CONTROL, tlb, GET_UVALUE=info, /NO_COPY
; What type of an event is this?
thisButtonType = SLICE_WHAT_BUTTON_TYPE(event)
; Is this a button UP event?
IF thisButtonType EQ 'UP' THEN BEGIN
; If this is an UP event, you need to erase the slice, turn motion
; events OFF, set thedraw widget's event handler back to
; SLICE_DRAW_BUTTON_EVENTS, and redraw the display with the new
; slice.
; Erase the slice one final time by copying from the pixmap.
WSET, info.wid
DEVICE, COPY = [0, 0, info.pixXsize, info.pixYsize, 0, 0, info.pixmapID]
; Delete the pixmap.
WDELETE, info.pixmapID
info.pixmapID = -1
; Turn motion events off.
WIDGET_CONTROL, event.id, DRAW_MOTION_EVENTS=0, $
EVENT_PRO='SLICE_DRAW_BUTTON_EVENTS'
; Set correct transformation matrix.
!P.T = info.pt
; Get the current coodinates in 3D space.
coords = CONVERT_COORD(event.x, event.y, /DEVICE, /TO_DATA, /T3D)
x=coords(0)
y=coords(1)
; Which slice are we talking about. Set the coordinates.
CASE info.interactive OF
'LEFT': BEGIN
x = FIX(x)
info.xcoord = x > 0
info.xcoord = info.xcoord < info.maxx
WIDGET_CONTROL, info.xcoordID, SET_VALUE=STRTRIM(x,2)
END
'RIGHT': BEGIN
y = FIX(y)
info.ycoord = y > 0
info.ycoord = info.ycoord < info.maxy
WIDGET_CONTROL, info.ycoordID, SET_VALUE=STRTRIM(y,2)
END
ELSE:
ENDCASE
; Call drawing procedure.
IF NOT WIDGET_INFO(info.drawID, /VALID_ID) THEN $
SLICE_GUI_MAKE_WINDOW, info, XSIZE=400, YSIZE=400
WSET, info.wid
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
; Put the info structure back into its storage location and then, out of here!
WIDGET_CONTROL, tlb, SET_UVALUE=info, /NO_COPY
RETURN
ENDIF ; thisEvent = UP
; Most of the action in this event handler occurs here while we are waiting
; for an UP event to occur. As long as we don't get it, keep erasing the
; old slice and drawing a new one.
; Erase the old slice.
WSET, info.wid
DEVICE, COPY = [0, 0, info.pixXsize, info.pixYsize, 0, 0, info.pixmapID]
; Set correct transformation matrix.
!P.T = info.pt
; Get the current coodinates in 3D space.
coords = CONVERT_COORD(event.x, event.y, /DEVICE, /TO_DATA, /T3D)
x=coords(0)
y=coords(1)
; Which button was pushed down? Draw the proper slice.
; Left button = X slice, Middle button = Z slice,
; Right button = Y slice.
CASE info.interactive OF
'LEFT': BEGIN
x = FIX(x)
x = x > 0
x = x < info.maxx
PLOTS, [x, x, x, x, x], [0, info.maxy, info.maxy, 0, 0], $
[0, 0, info.maxz, info.maxz, 0], /T3D, COLOR=info.color
XYOUTS, 0.05, 0.05, 'X Coordinate = ' + STRTRIM(x,2), /NORMAL, $
SIZE=info.charscale, COLOR=info.color
END
'RIGHT': BEGIN
y = FIX(y)
y = y > 0
y = y < info.maxy
PLOTS, [0, info.maxx, info.maxx, 0, 0], [y,y,y,y,y], $
[0, 0, info.maxz, info.maxz, 0], /T3D, COLOR=info.color
XYOUTS, 0.05, 0.05, 'Y Coordinate = ' + STRTRIM(y, 2), /NORMAL, $
SIZE=info.charscale, COLOR=info.color
END
ELSE:
ENDCASE
; Put the info structure back into its storage location.
WIDGET_CONTROL, tlb, SET_UVALUE=info, /NO_COPY
END ; of SLICE_DRAW_MOTION_EVENTS event handler **************************************
PRO SLICE_DRAW_BUTTON_EVENTS, event
thisButtonType = SLICE_WHAT_BUTTON_TYPE(event)
; Is this a button down event? If not, return.
IF thisButtonType NE 'DOWN' THEN RETURN
; Don't want to handle middle mouse buttons.
buttonPressed = SLICE_WHAT_BUTTON_PRESSED(event)
IF buttonPressed EQ 'MIDDLE' THEN RETURN
; Get info structure.
WIDGET_CONTROL, event.top, GET_UVALUE=tlb
WIDGET_CONTROL, tlb, GET_UVALUE=info, /NO_COPY
; Create a pixmap for the window.
WIDGET_CONTROL, info.graphics_tlb, TLB_GET_SIZE=gsize
WINDOW, /FREE, XSIZE=gsize(0), YSIZE=gsize(1), /PIXMAP
info.pixmapID = !D.WINDOW
info.pixXsize = gsize(0)
info.pixYsize = gsize(1)
; Draw the plot here with no axes.
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=info.charscale, NOAXES=1, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
; Set correct transformation matrix.
info.pt = !P.T
; Draw 3D box.
oldDevice = !D.NAME
SET_PLOT, 'Z'
PLOTS, [0, 0, info.maxx, info.maxx, 0], [0, info.maxy, info.maxy, 0, 0], $
[0, 0, 0, 0, 0], /T3D, COLOR=info.color
PLOTS, [0, 0, info.maxx, info.maxx, 0], [0, info.maxy, info.maxy, 0, 0], $
[info.maxz, info.maxz, info.maxz, info.maxz, info.maxz], /T3D, COLOR=info.color
PLOTS, [0, 0, 0, 0, 0], [0, info.maxy, info.maxy, 0, 0], $
[0, 0, info.maxz, info.maxz, 0], /T3D, COLOR=info.color
PLOTS, [info.maxx, info.maxx, info.maxx, info.maxx, info.maxx], $
[0, info.maxy, info.maxy, 0, 0], [0, 0, info.maxz, info.maxz, 0], $
/T3D, COLOR=info.color
picture = TVRD()
SET_PLOT, oldDevice
WSET, info.pixmapID
TV, picture
; Do the same thing in the display window.
WSET, info.wid
TV, picture
; Get the current coodinates in 3D space.
coords = CONVERT_COORD(event.x, event.y, /DEVICE, /TO_DATA, /T3D)
x=coords(0)
y=coords(1)
; Which button was pushed down? Draw the proper slice.
; Left button = X slice, Right button = Y slice.
info.interactive = SLICE_WHAT_BUTTON_PRESSED(event)
CASE info.interactive OF
'LEFT': BEGIN
x=info.xcoord
PLOTS, [x, x, x, x, x], [0, info.maxy, info.maxy, 0, 0], $
[0, 0, info.maxz, info.maxz, 0], /T3D, COLOR=info.color
END
'RIGHT': BEGIN
y = info.ycoord
PLOTS, [0, info.maxx, info.maxx, 0, 0], [y,y,y,y,y], $
[0, 0, info.maxz, info.maxz, 0], /T3D, COLOR=info.color
END
ELSE:
ENDCASE
WIDGET_CONTROL, info.drawID, EVENT_PRO='SLICE_DRAW_MOTION_EVENTS', $
DRAW_MOTION_EVENTS=1
WIDGET_CONTROL, tlb, SET_UVALUE=info, /NO_COPY
END ; of SLICE_DRAW_BUTTON_EVENTS event handler ***************************
PRO SLICE_GUI_SAVE_DISPLAY, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
; Get a copy of the data.
HANDLE_VALUE, info.dataptr, data, /NO_COPY
oldData = data
oldInfo = info
HANDLE_VALUE, info.dataptr, data, /NO_COPY, /SET
; Open a file to save the data and the info structure.
filename = 'slice' + STRTRIM(info.thisInstance, 2) + '.slc'
filename = PICKFILE(/WRITE, FILE=filename)
IF filename EQ '' THEN BEGIN
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
RETURN
ENDIF
SAVE, oldData, oldinfo, FILE=filename
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_SAVE_DISPLAY event handler *********************
PRO SLICE_GUI_RESTORE_DISPLAY, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
; Open a file to get the data and the info structure.
filename = PICKFILE(FILTER='*.slc')
IF filename EQ '' THEN BEGIN
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
RETURN
ENDIF
CATCH, error
IF error NE 0 THEN BEGIN
ok = WIDGET_MESSAGE(!ERR_STRING)
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
RETURN
ENDIF
RESTORE, filename
CATCH, /CANCEL
; Free up old pointer and set new pointer to old data.
HANDLE_FREE, info.dataptr
info.dataptr = HANDLE_CREATE(VALUE=oldData, /NO_COPY)
; Set the proper display parameters.
WIDGET_CONTROL, info.xcoordID, SET_VALUE=oldinfo.xcoord
WIDGET_CONTROL, info.ycoordID, SET_VALUE=oldinfo.ycoord
WIDGET_CONTROL, info.zcoordID, SET_VALUE=oldinfo.zcoord
; Set the transparent factor.
transpercent = (oldinfo.transparent - (oldinfo.bottom -1))/(oldinfo.ncolors*0.01)
WIDGET_CONTROL, info.transparentID, SET_VALUE=transpercent
; Find current selection for the droplist.
thisSelection = 0
IF oldinfo.xslice THEN thisSelection = thisSelection + 1
IF oldinfo.yslice THEN thisSelection = thisSelection + 2
IF oldinfo.zslice THEN thisSelection = thisSelection + 4
CASE thisSelection OF
1: WIDGET_CONTROL, info.droplistID, SET_DROPLIST_SELECT=0
2: WIDGET_CONTROL, info.droplistID, SET_DROPLIST_SELECT=1
3: WIDGET_CONTROL, info.droplistID, SET_DROPLIST_SELECT=3
4: WIDGET_CONTROL, info.droplistID, SET_DROPLIST_SELECT=2
5: WIDGET_CONTROL, info.droplistID, SET_DROPLIST_SELECT=4
6: WIDGET_CONTROL, info.droplistID, SET_DROPLIST_SELECT=5
7: WIDGET_CONTROL, info.droplistID, SET_DROPLIST_SELECT=6
ENDCASE
; Set the axes rotations.
WIDGET_CONTROL, info.axsliderID, SET_VALUE=oldinfo.ax
WIDGET_CONTROL, info.azsliderID, SET_VALUE=oldinfo.az
; Call drawing procedure.
IF NOT WIDGET_INFO(info.drawID, /VALID_ID) THEN $
SLICE_GUI_MAKE_WINDOW, info, XSIZE=400, YSIZE=400
WSET, info.wid
oldinfo.wid = info.wid
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=oldinfo.xcoord, YCOORD=oldinfo.ycoord, $
ZCOORD=oldinfo.zcoord, XSLICE=oldinfo.xslice, $
YSLICE=oldinfo.yslice, ZSLICE=oldinfo.zslice, AX=oldinfo.ax, $
AZ=oldinfo.az, WID=oldinfo.wid, NCOLORS=oldinfo.ncolors, $
BOTTOM=oldinfo.bottom, TRANSPARENT=oldinfo.transparent, $
BACKGROUND=oldinfo.background, COLOR=oldinfo.color, $
CHARSIZE=1.0*oldinfo.charscale, NOAXES=oldinfo.noaxes, $
_EXTRA=oldinfo.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
; Set up the info structure.
info = { dataptr:info.dataptr, $
xcoord:oldinfo.xcoord, $
ycoord:oldinfo.ycoord, $
zcoord:oldinfo.zcoord, $
xslice:oldinfo.xslice, $
yslice:oldinfo.yslice, $
zslice:oldinfo.zslice, $
az:oldinfo.az, $
ax:oldinfo.ax, $
wid:oldinfo.wid, $
ncolors:oldinfo.ncolors, $
bottom:oldinfo.bottom, $
transparent:oldinfo.transparent, $
charscale:oldinfo.charscale, $
background:oldinfo.background, $
color:oldinfo.color, $
noaxes:oldinfo.noaxes, $
extra:oldinfo.extra, $
wtitle:oldinfo.wtitle, $
thisInstance:info.thisInstance, $
xcoordID:info.xcoordID, $
ycoordID:info.ycoordID, $
zcoordID:info.zcoordID, $
transparentID:info.transparentID, $
maxx:oldinfo.maxx, $
maxy:oldinfo.maxy, $
maxz:oldinfo.maxz, $
interactive:oldinfo.interactive, $
pt:oldinfo.pt, $
pixmapID:oldinfo.pixmapID, $
pixXsize:oldinfo.pixXsize, $
pixYsize:oldinfo.pixYsize, $
droplistID:info.droplistID, $
axsliderID:info.axsliderID, $
azsliderID:info.azsliderID, $
graphics_tlb:info.graphics_tlb, $
drawID:info.drawID, $
tlb:info.tlb, $
postscript:info.postscript}
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_RESTORE_DISPLAY event handler *********************
PRO SLICE_GUI_ANIMATE, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
WIDGET_CONTROL, event.id, GET_UVALUE=slice
; Get the slice coordinates, just in case someone changed
; them and didn't hit a CR.
WIDGET_CONTROL, info.xcoordID, GET_VALUE=xcoord
info.xcoord = xcoord
WIDGET_CONTROL, info.ycoordID, GET_VALUE=ycoord
info.ycoord = ycoord
WIDGET_CONTROL, info.zcoordID, GET_VALUE=zcoord
info.zcoord = zcoord
CASE slice OF
'X': BEGIN
IF info.xslice EQ 0 THEN BEGIN
info.xslice = 1
setBack = 1
ENDIF ELSE setBack = 0
SLICE_XINTERANIMATE, SET = [300, 300, info.maxx+1], /SHOWLOAD, $
/CYCLE, BOTTOM=info.bottom, NCOLORS=info.ncolors
FOR j=0,info.maxx DO BEGIN
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=j(0), YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=!D.WINDOW, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
SLICE_XINTERANIMATE, FRAME=j, WINDOW=!D.WINDOW
ENDFOR
SLICE_XINTERANIMATE, 20, GROUP=event.top
IF setBack THEN info.xslice = 0
END
'Y': BEGIN
IF info.yslice EQ 0 THEN BEGIN
info.yslice = 1
setBack = 1
ENDIF ELSE setBack = 0
SLICE_XINTERANIMATE, SET = [300, 300, info.maxy+1], /SHOWLOAD, $
/CYCLE, BOTTOM=info.bottom, NCOLORS=info.ncolors
FOR j=0,info.maxy DO BEGIN
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=info.xcoord, YCOORD=j(0), $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=!D.WINDOW, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
SLICE_XINTERANIMATE, FRAME=j, WINDOW=!D.WINDOW
ENDFOR
SLICE_XINTERANIMATE, 20, GROUP=event.top
IF setBack THEN info.yslice = 0
END
'Z': BEGIN
IF info.zslice EQ 0 THEN BEGIN
info.zslice = 1
setBack = 1
ENDIF ELSE setBack = 0
SLICE_XINTERANIMATE, SET = [300, 300, info.maxz+1], /SHOWLOAD, $
/CYCLE, BOTTOM=info.bottom, NCOLORS=info.ncolors
FOR j=0,info.maxz DO BEGIN
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=j(0), XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=!D.WINDOW, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
SLICE_XINTERANIMATE, FRAME=j, WINDOW=!D.WINDOW
ENDFOR
SLICE_XINTERANIMATE, 20, GROUP=event.top
IF setBack THEN info.zslice = 0
END
ENDCASE
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_ANIMATE event handler ***************************
PRO SLICE_GUI_CLEANUP, id
WIDGET_CONTROL, id, GET_VALUE=info
IF N_ELEMENTS(info) NE 0 THEN HANDLE_FREE, info.dataptr
END ; of SLICE_GUI_CLEANUP routine *******************************
PRO SLICE_GUI_AXES_OFF, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
IF info.noaxes EQ 1 THEN BEGIN
WIDGET_CONTROL, event.id, SET_VALUE='Turn Axes Off'
info.noaxes = 0
ENDIF ELSE BEGIN
WIDGET_CONTROL, event.id, SET_VALUE='Turn Axes On'
info.noaxes = 1
ENDELSE
; Get the slice coordinates, just in case someone changed
; them and didn't hit a CR.
WIDGET_CONTROL, info.xcoordID, GET_VALUE=xcoord
info.xcoord = xcoord
WIDGET_CONTROL, info.ycoordID, GET_VALUE=ycoord
info.ycoord = ycoord
WIDGET_CONTROL, info.zcoordID, GET_VALUE=zcoord
info.zcoord = zcoord
; Call drawing procedure.
IF NOT WIDGET_INFO(info.drawID, /VALID_ID) THEN $
SLICE_GUI_MAKE_WINDOW, info, XSIZE=400, YSIZE=400
WSET, info.wid
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_AXES_OFF event handler *************************
PRO SLICE_GUI_CHARSIZE, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
; Get the new character size.
scale = SLICE_CHARSIZE(info.charscale)
; Did user cancel?
IF scale LT 0 THEN BEGIN
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
RETURN
ENDIF
info.charscale = scale
; Get the slice coordinates, just in case someone changed
; them and didn't hit a CR.
WIDGET_CONTROL, info.xcoordID, GET_VALUE=xcoord
info.xcoord = xcoord
WIDGET_CONTROL, info.ycoordID, GET_VALUE=ycoord
info.ycoord = ycoord
WIDGET_CONTROL, info.zcoordID, GET_VALUE=zcoord
info.zcoord = zcoord
; Call drawing procedure.
IF NOT WIDGET_INFO(info.drawID, /VALID_ID) THEN $
SLICE_GUI_MAKE_WINDOW, info, XSIZE=400, YSIZE=400
WSET, info.wid
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_CHARSIZE event handler ******************************
PRO SLICE_GUI_AXES_COLOR, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
drawbase = WIDGET_INFO(info.drawID, /Parent)
CHGCOLOR, info.color, Title='Change Axes Color', $
GROUP=event.top, NOTIFYID=[drawbase, event.top]
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_AXES_COLOR event handl*******************************
PRO SLICE_GUI_BACKGROUND_COLOR, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
drawbase = WIDGET_INFO(info.drawID, /Parent)
CHGCOLOR, info.background, Title='Change Background Color', $
GROUP=event.top, NOTIFYID=[drawbase, event.top]
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_BACKGROUND_COLOR event handl*************************
PRO SLICE_GUI_NEW_DISPLAY, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
; Create another SQRSLIICE_GUI application.
; Get the slice coordinates, just in case someone changed
; them and didn't hit a CR.
WIDGET_CONTROL, info.xcoordID, GET_VALUE=xcoord
info.xcoord = xcoord
WIDGET_CONTROL, info.ycoordID, GET_VALUE=ycoord
info.ycoord = ycoord
WIDGET_CONTROL, info.zcoordID, GET_VALUE=zcoord
info.zcoord = zcoord
HANDLE_VALUE, info.dataptr, data, /NO_COPY
newdata = data
SLICE_GUI, newdata, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=0, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra, WTITLE=info.wtitle, $
THISINSTANCE=info.thisInstance + 1
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_NEW_DISPLAY event handler *********************************
PRO SLICE_GUI_MAKE_WINDOW, info, XSIZE=xsize, YSIZE=ysize, $
XOFFSET=xoffset, YOFFSET=yoffset
ON_ERROR, 1
np = N_PARAMS()
IF np NE 1 THEN MESSAGE, 'Info structure parameter required.'
IF N_ELEMENTS(xsize) EQ 0 THEN xsize = 400
IF N_ELEMENTS(ysize) EQ 0 THEN ysize = 400
DEVICE, GET_SCREEN_SIZE=screenSize
xoff = (screenSize(0) - xsize) / 2.0
yoff = (screenSize(1) - ysize) / 2.0
IF N_ELEMENTS(xoffset) EQ 0 THEN xoffset = xoff
IF N_ELEMENTS(yoffset) EQ 0 THEN yoffset = yoff
thisTitle = 'Slice Resizeable Display: ' + STRTRIM(info.thisInstance, 2)
graphics_tlb = WIDGET_BASE(TLB_SIZE_EVENT=1, $
EVENT_PRO='SLICE_GUI_RESIZE', $
UVALUE=info.tlb, XOFFSET=xoffset, YOFFSET=yoffset, $
TITLE=thisTitle, GROUP=info.tlb)
drawID = WIDGET_DRAW(graphics_tlb, XSIZE=xsize, YSIZE=ysize, $
EVENT_PRO='SLICE_DRAW_BUTTON_EVENTS')
WIDGET_CONTROL, graphics_tlb, /REALIZE
WIDGET_CONTROL, drawID, GET_VALUE=wid
info.wid = wid
info.drawID = drawID
info.graphics_tlb = graphics_tlb
WSET, info.wid
END ; of SLICE_GUI_MAKE_WINDOW utility routine *********************************
PRO SLICE_GUI_TRANSPARENT, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
; Get the new transparent factor.
WIDGET_CONTROL, event.id, GET_VALUE=transpercent
transvalue = ((info.bottom-1)+(transpercent*info.ncolors*0.01)) > 0
info.transparent = transvalue
; Get the slice coordinates, just in case someone changed
; them and didn't hit a CR.
WIDGET_CONTROL, info.xcoordID, GET_VALUE=xcoord
info.xcoord = xcoord
WIDGET_CONTROL, info.ycoordID, GET_VALUE=ycoord
info.ycoord = ycoord
WIDGET_CONTROL, info.zcoordID, GET_VALUE=zcoord
info.zcoord = zcoord
; Call drawing procedure.
IF NOT WIDGET_INFO(info.drawID, /VALID_ID) THEN $
SLICE_GUI_MAKE_WINDOW, info, XSIZE=400, YSIZE=400
WSET, info.wid
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_TRANSPARENT event handler *********************************
PRO SLICE_GUI_ROTATE, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
; Get the new rotation.
WIDGET_CONTROL, event.id, GET_VALUE=thisRotation
; Branch appropriately.
CASE event.id OF
info.axsliderID: info.ax = thisRotation
info.azsliderID: info.az = thisRotation
ENDCASE
; Get the slice coordinates, just in case someone changed
; them and didn't hit a CR.
WIDGET_CONTROL, info.xcoordID, GET_VALUE=xcoord
info.xcoord = xcoord
WIDGET_CONTROL, info.ycoordID, GET_VALUE=ycoord
info.ycoord = ycoord
WIDGET_CONTROL, info.zcoordID, GET_VALUE=zcoord
info.zcoord = zcoord
; Call drawing procedure.
IF NOT WIDGET_INFO(info.drawID, /VALID_ID) THEN $
SLICE_GUI_MAKE_WINDOW, info, XSIZE=400, YSIZE=400
WSET, info.wid
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_ROTATE event handler *********************************
PRO SLICE_GUI_COORDINATE_SELECT, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
; Get the new coordinate.
WIDGET_CONTROL, event.id, GET_VALUE=thisCoordinate
; Branch appropriately.
CASE event.id OF
info.xcoordID: BEGIN
IF thisCoordinate LT 0 OR thisCoordinate GT info.maxx THEN BEGIN
ok = WIDGET_MESSAGE(['The value ' + STRTRIM(thisCoordinate, 2) + $
' is out of range.', 'Range: 0 - ' + STRTRIM(info.maxx,2)])
WIDGET_CONTROL, info.xcoordID, SET_VALUE=info.xcoord
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
RETURN
ENDIF
info.xcoord = thisCoordinate
END
info.ycoordID: BEGIN
IF thisCoordinate LT 0 OR thisCoordinate GT info.maxy THEN BEGIN
ok = WIDGET_MESSAGE(['The value ' + STRTRIM(thisCoordinate, 2) + $
' is out of range.', 'Range: 0 - ' + STRTRIM(info.maxy,2)])
WIDGET_CONTROL, info.ycoordID, SET_VALUE=info.ycoord
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
RETURN
ENDIF
info.ycoord = thisCoordinate
END
info.zcoordID: BEGIN
IF thisCoordinate LT 0 OR thisCoordinate GT info.maxz THEN BEGIN
ok = WIDGET_MESSAGE(['The value ' + STRTRIM(thisCoordinate, 2) + $
' is out of range.', 'Range: 0 - ' + STRTRIM(info.maxz, 2)])
WIDGET_CONTROL, info.zcoordID, SET_VALUE=info.zcoord
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
RETURN
ENDIF
info.zcoord = thisCoordinate
END
ENDCASE
; User could type in bogus value. Check for it.
CATCH, error
IF error NE 0 THEN BEGIN
ok = WIDGET_MESSAGE(['Problem with coordinate you', $
'just typed in. Returning...'])
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
RETURN
ENDIF
; Get the slice coordinates, just in case someone changed
; them and didn't hit a CR.
WIDGET_CONTROL, info.xcoordID, GET_VALUE=xcoord
info.xcoord = xcoord
WIDGET_CONTROL, info.ycoordID, GET_VALUE=ycoord
info.ycoord = ycoord
WIDGET_CONTROL, info.zcoordID, GET_VALUE=zcoord
info.zcoord = zcoord
; Call drawing procedure.
IF NOT WIDGET_INFO(info.drawID, /VALID_ID) THEN $
SLICE_GUI_MAKE_WINDOW, info, XSIZE=400, YSIZE=400
WSET, info.wid
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_COORDINATE_SELECT event handler ***************************
PRO SLICE_GUI_SLICE_SELECT, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
WIDGET_CONTROL, event.id, GET_UVALUE=options
CASE options(event.index) OF
'X Only': BEGIN
info.xslice = 1
info.yslice = 0
info.zslice = 0
WIDGET_CONTROL, info.drawID, DRAW_BUTTON_EVENTS=0
END
'Y Only': BEGIN
info.xslice = 0
info.yslice = 1
info.zslice = 0
WIDGET_CONTROL, info.drawID, DRAW_BUTTON_EVENTS=0
END
'Z Only': BEGIN
info.xslice = 0
info.yslice = 0
info.zslice = 1
WIDGET_CONTROL, info.drawID, DRAW_BUTTON_EVENTS=0
END
'X and Y': BEGIN
info.xslice = 1
info.yslice = 1
info.zslice = 0
WIDGET_CONTROL, info.drawID, DRAW_BUTTON_EVENTS=0
END
'X and Z': BEGIN
info.xslice = 1
info.yslice = 0
info.zslice = 1
WIDGET_CONTROL, info.drawID, DRAW_BUTTON_EVENTS=0
END
'Y and Z': BEGIN
info.xslice = 0
info.yslice = 1
info.zslice = 1
WIDGET_CONTROL, info.drawID, DRAW_BUTTON_EVENTS=0
END
'XYZ': BEGIN
info.xslice = 1
info.yslice = 1
info.zslice = 1
WIDGET_CONTROL, info.drawID, DRAW_BUTTON_EVENTS=0
END
'Interactive XY': BEGIN
WIDGET_CONTROL, info.drawID, DRAW_BUTTON_EVENTS=1
END
ENDCASE
; Get the slice coordinates, just in case someone changed
; them and didn't hit a CR.
WIDGET_CONTROL, info.xcoordID, GET_VALUE=xcoord
info.xcoord = xcoord
WIDGET_CONTROL, info.ycoordID, GET_VALUE=ycoord
info.ycoord = ycoord
WIDGET_CONTROL, info.zcoordID, GET_VALUE=zcoord
info.zcoord = zcoord
; Call the drawing procedure.
IF NOT WIDGET_INFO(info.drawID, /VALID_ID) THEN $
SLICE_GUI_MAKE_WINDOW, info, XSIZE=400, YSIZE=400
WSET, info.wid
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_SLICE_SELECT event handler ************************
PRO SLICE_GUI_LOAD_DATA, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
CATCH, error
IF error NE 0 THEN BEGIN
ok = WIDGET_MESSAGE(['You must download the file SLICE_GETIMAGE.PRO', $
'from the TRAINING directory at RSI. E-mail', $
'davidf@fortnet.org for more information.'])
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
RETURN
ENDIF
data = SLICE_GETIMAGE()
CATCH, /CANCEL
IF N_ELEMENTS(data) LE 1 THEN BEGIN
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
RETURN
ENDIF
s = SIZE(data)
IF s(0) NE 3 THEN BEGIN
ok = WIDGET_MESSAGE('New data set must be 3D.')
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
RETURN
ENDIF
xs = s(1)
ys = s(2)
zs = s(3)
; Use current coodinates if they fit, otherwise
; update them.
IF info.xcoord GE s(1) THEN BEGIN
info.xcoord = s(1) / 2
WIDGET_CONTROL, info.xcoordID, SET_VALUE=info.xcoord
ENDIF
IF info.ycoord GE s(2) THEN BEGIN
info.ycoord = s(2) / 2
WIDGET_CONTROL, info.ycoordID, SET_VALUE=info.ycoord
ENDIF
IF info.zcoord GE s(3) THEN BEGIN
info.zcoord = s(3) / 2
WIDGET_CONTROL, info.zcoordID, SET_VALUE=info.zcoord
ENDIF
; Get the slice coordinates, just in case someone changed
; them and didn't hit a CR.
WIDGET_CONTROL, info.xcoordID, GET_VALUE=xcoord
info.xcoord = xcoord
WIDGET_CONTROL, info.ycoordID, GET_VALUE=ycoord
info.ycoord = ycoord
WIDGET_CONTROL, info.zcoordID, GET_VALUE=zcoord
info.zcoord = zcoord
; Make sure requested slices are inside the data.
info.maxX = xs - 1
info.maxY = ys - 1
info.maxZ = zs - 1
info.xcoord = 0 > info.xcoord
info.xcoord = info.xcoord < info.maxX
info.ycoord = 0 > info.ycoord
info.ycoord = info.ycoord < info.maxY
info.zcoord = 0 > info.zcoord
info.zcoord = info.zcoord < info.maxZ
IF NOT WIDGET_INFO(info.drawID, /VALID_ID) THEN $
SLICE_GUI_MAKE_WINDOW, info, XSIZE=400, YSIZE=400
WSET, info.wid
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, /SET, data, /NO_COPY
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_LOAD_DATA event handler ******************************
PRO SLICE_GUI_CHANGE_COLORS, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
drawbase = WIDGET_INFO(info.drawID, /Parent)
XCOLORS, NCOLORS=info.ncolors, BOTTOM=info.bottom, $
GROUP=event.top, NOTIFYID=[drawbase, event.top]
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_CHANGE_COLORS event handler ***************************
PRO SLICE_GUI_POSTSCRIPT, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
; Get the slice coordinates, just in case someone changed
; them and didn't hit a CR.
WIDGET_CONTROL, info.xcoordID, GET_VALUE=xcoord
info.xcoord = xcoord
WIDGET_CONTROL, info.ycoordID, GET_VALUE=ycoord
info.ycoord = ycoord
WIDGET_CONTROL, info.zcoordID, GET_VALUE=zcoord
info.zcoord = zcoord
; Get the user value of the button.
WIDGET_CONTROL, event.id, GET_UVALUE=thisUValue
CASE thisUVALUE of
'CREATE': BEGIN
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.color, COLOR=info.background, $
POSTSCRIPT=info.postscript, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
END
'CONFIGURE': BEGIN
keywords = PS_FORM(CANCEL=cancelled, CREATE=create, $
DEFAULTS=info.postscript)
IF NOT cancelled THEN info.postscript = keywords
IF create THEN BEGIN
HANDLE_VALUE, info.dataptr, data, /NO_COPY
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.color, COLOR=info.background, $
POSTSCRIPT=info.postscript, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
ENDIF
END
ENDCASE
WIDGET_CONTROL, event.top, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_POSTSCRIPT event handler *******************************
PRO SLICE_GUI_RESIZE, event
WIDGET_CONTROL, event.top, GET_UVALUE=tlb
WIDGET_CONTROL, tlb, GET_UVALUE=info, /NO_COPY
thisEvent = TAG_NAMES(event, /Structure)
IF (thisEvent EQ 'XCOLORS_LOAD') OR $
(thisEvent EQ 'CHGCOLOR_LOAD') THEN BEGIN
skip = 0
TVLCT, event.r, event.g, event.b
ENDIF ELSE skip = 1
IF skip THEN BEGIN
WIDGET_CONTROL, info.drawID, XSIZE=event.x, YSIZE=event.y
; Update file output configuration structures.
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
ENDIF
; Get the slice coordinates, just in case someone changed
; them and didn't hit a CR.
WIDGET_CONTROL, info.xcoordID, GET_VALUE=xcoord
info.xcoord = xcoord
WIDGET_CONTROL, info.ycoordID, GET_VALUE=ycoord
info.ycoord = ycoord
WIDGET_CONTROL, info.zcoordID, GET_VALUE=zcoord
info.zcoord = zcoord
HANDLE_VALUE, info.dataptr, data, /NO_COPY
WSET, info.wid
IF skip THEN ERASE, Color=info.background
SLICE, data, XCOORD=info.xcoord, YCOORD=info.ycoord, $
ZCOORD=info.zcoord, XSLICE=info.xslice, $
YSLICE=info.yslice, ZSLICE=info.zslice, AX=info.ax, $
AZ=info.az, WID=info.wid, NCOLORS=info.ncolors, $
BOTTOM=info.bottom, TRANSPARENT=info.transparent, $
BACKGROUND=info.background, COLOR=info.color, $
CHARSIZE=1.0*info.charscale, NOAXES=info.noaxes, $
_EXTRA=info.extra
HANDLE_VALUE, info.dataptr, data, /SET, /NO_COPY
WIDGET_CONTROL, tlb, SET_UVALUE=info, /NO_COPY
END ; of SLICE_GUI_RESIZE event handler *********************************
PRO SLICE_GUI_QUITTER, event
WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY
HANDLE_FREE, info.dataptr
WIDGET_CONTROL, event.top, /DESTROY
END ; of SLICE_GUI_QUITTER event handler ********************************
PRO SLICE_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}
Handle_Value, info.ptr, formdata, /Set
; 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.
Handle_Value, info.ptr, formdata, /Set
; 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.
Handle_Value, info.ptr, formdata, /Set
; 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 SLICE_CONFIGURATION_EVENTS event handler ************************
FUNCTION SLICE_CONFIGURATION, filetype, config, TITLE=title, $
XOFFSET=xoffset, YOFFSET=yoffset, Cancel=cancel, Create=create
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)
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='SLICE_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='SLICE_NULL_EVENTS')
orderdropID = Widget_Droplist(orderbase, Value=order, $
Title='Display Order: ', EVENT_PRO='SLICE_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='SLICE_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 = HANDLE_CREATE()
info = { filenameID:filenameID, xsizeID:xsizeID, $
ysizeID:ysizeID, colordropID:colordropID, $
orderdropID:orderdropID, ptr:ptr, sliderID:sliderID}
Widget_Control, tlb, Set_UValue=info, /No_Copy
XManager, 'slice_configuration', tlb, /Modal, $
Event_Handler='SLICE_CONFIGURATION_EVENTS'
Handle_Value, ptr, formdata
Handle_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 SLICE_CONFIGURATION event handler *******************************
PRO SLICE_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 GIF File...': BEGIN
config = info.gif
newConfiguration = SLICE_CONFIGURATION('GIF', config, $
Cancel=cancel, Create=create)
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 = SLICE_CONFIGURATION('TIFF', config, $
Cancel=cancel, Create=create)
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 = SLICE_CONFIGURATION('JPEG', config, $
Cancel=cancel, Create=create)
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 SLICE_CONFIGURE_FILES event handler ***********************************
PRO SLICE_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 = SLICE_DELAY_NOTICE('Please be patient while writing the file...')
WIDGET_CONTROL, event.id, GET_VALUE=whichFile
CASE whichFile OF
'Create GIF File': BEGIN
config = info.gif
; Copy the image
IF WIDGET_INFO(info.drawID, /Valid_ID) THEN BEGIN
thisImage = TVRD()
IF config.color EQ 0 THEN BEGIN
TVLCT, rr, gg, bb, /GET
LOADCT, 0, NCOLORS=info.ncolors, BOTTOM=info.bottom
TVLCT, r, g, b, /GET
ENDIF ELSE TVLCT, r, g, b, /GET
END
; Write GIF file.
s = SIZE(thisImage)
IF (s(1) NE config.xsize) OR (s(2) NE config.ysize) THEN $
thisImage = CONGRID(thisImage, config.xsize, config.ysize, /Interp)
WRITE_GIF, config.filename, thisImage, r, g, b
END ; of GIF file creation.
'Create TIFF File': BEGIN
config = info.tiff
; Copy the image
thisImage = TVRD()
TVLCT, r, g, b, /GET
; Write TIFF file. Use screen resolution.
s = SIZE(thisImage)
IF (s(1) NE config.xsize) OR (s(2) NE config.ysize) THEN $
thisImage = CONGRID(thisImage, config.xsize, config.ysize, /Interp)
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
; Get the image.
thisImage = TVRD()
TVLCT, r, g, b, /GET
; Write JPEG file.
s = SIZE(thisImage)
IF (s(1) NE config.xsize) OR (s(2) NE config.ysize) THEN $
thisImage = CONGRID(thisImage, config.xsize, config.ysize, /Interp)
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 SLICE_CREATE_FILES event handler ***********************************
PRO SLICE_GUI, data, XSLICE=xslice, YSLICE=yslice, ZSLICE=zslice, $
WID=wid, NOAXES=noaxes, XCOORD=xcoord, YCOORD=ycoord, ZCOORD=zcoord, $
NCOLORS=ncolors, BOTTOM=bottom, BACKGROUND=background, GROUP=group, $
COLOR=color, AZ=az, AX=ax, TRANSPARENT=transparent, _EXTRA=extra, $
CHARSIZE=charscale, WTITLE=wtitle, THISINSTANCE=thisInstance, $
POSTSCRIPT=postscript
ON_ERROR, 1
; If no data passed in, make some up for demo purposes.
np = N_PARAMS()
IF np EQ 0 THEN BEGIN
MESSAGE, 'No data passed in. Using jet data...', /INFORMATIONAL
filename = FILEPATH(SUBDIR=['examples', 'data'], 'jet.dat')
CATCH, error
IF error NE 0 THEN BEGIN
ok = WIDGET_MESSAGE("Can't find JET.DAT. Returning...")
RETURN
ENDIF
OPENR, lun, filename, /GET_LUN
CATCH, /CANCEL
data = BYTARR(81, 40, 101)
READU, lun, data
FREE_LUN, lun
ENDIF
; Make sure data is 3D. Pick appropriate row and column slices.
s = SIZE(data)
IF s(0) NE 3 THEN MESSAGE, 'Data set must be 3D.'
xs = s(1)
ys = s(2)
zs = s(3)
IF N_ELEMENTS(xcoord) EQ 0 THEN xcoord= xs / 2
IF N_ELEMENTS(ycoord) EQ 0 THEN ycoord= ys / 2
IF N_ELEMENTS(zcoord) EQ 0 THEN zcoord= zs / 2
; Make sure requested slices are inside the data.
maxX = xs - 1
maxY = ys - 1
maxZ = zs - 1
xcoord = 0 > xcoord
xcoord = xcoord < maxX
ycoord = 0 > ycoord
ycoord = ycoord < maxY
zcoord = 0 > zcoord
zcoord = zcoord < maxZ
; What slices do you want. Must have something! X Slice is default.
xslice = KEYWORD_SET(xslice)
yslice = KEYWORD_SET(yslice)
zslice = KEYWORD_SET(zslice)
IF NOT xslice AND NOT yslice AND NOT zslice THEN xslice = 1
; Set colors.
IF N_ELEMENTS(ncolors) EQ 0 THEN ncolors=!D.N_COLORS
IF N_ELEMENTS(bottom) EQ 0 THEN bottom = 0
IF N_ELEMENTS(background) EQ 0 THEN background = bottom
IF N_ELEMENTS(color) EQ 0 THEN color = (ncolors-1) + bottom
; Default axes rotations. Keep in program range.
IF N_ELEMENTS(az) EQ 0 THEN az = 30
az = az > (-30)
az = az < 210
IF N_ELEMENTS(ax) EQ 0 THEN ax = 30
ax = ax > 0
ax = ax < 90
; Miscellaneous keywords.
IF N_ELEMENTS(noaxes) EQ 0 THEN noaxes = 0
IF N_ELEMENTS(transparent) EQ 0 THEN transparent = 0
transvalue = ((bottom-1)+(transparent*ncolors*0.01)) > 0
IF N_ELEMENTS(charscale) EQ 0 THEN charscale = 1.0
IF N_ELEMENTS(extra) EQ 0 THEN extra = CREATE_STRUCT('title', '')
IF N_ELEMENTS(wid) EQ 0 THEN wid = -1
IF N_ELEMENTS(thisInstance) EQ 0 THEN thisInstance = 1
IF N_ELEMENTS(wtitle) EQ 0 THEN wtitle = 'Slice Controls: '
IF N_ELEMENTS(postscript) EQ 0 THEN postscript = PS_FORM(/Initialize)
; Only one program by this name, please!
registerName = 'xsection_gui' + STRTRIM(thisInstance, 2)
IF XREGISTERED(registerName) THEN BEGIN
ok = WIDGET_MESSAGE(['Sorry, a new display cannot be opened', $
'from this SLICE program. Try the SLICE', $
'program that is now forward on the display.'])
RETURN
ENDIF
; Create the control widgets.
tlb = WIDGET_BASE(COLUMN=1, TLB_FRAME_ATTR=1, $
TITLE=wtitle + STRTRIM(thisInstance, 2))
coordbase = WIDGET_BASE(tlb, COLUMN=1, FRAME=1, $
EVENT_PRO='SLICE_GUI_COORDINATE_SELECT')
label = WIDGET_LABEL(coordbase, Value='Slice Coordinates')
xcoordID = CW_FIELD(coordbase, /INTEGER, Value=xcoord, TITLE='X Coordinate: ', $
RETURN_EVENTS=1)
ycoordID = CW_FIELD(coordbase, /INTEGER, Value=ycoord, TITLE='Y Coordinate: ', $
RETURN_EVENTS=1)
zcoordID = CW_FIELD(coordbase, /INTEGER, Value=zcoord, TITLE='Z Coordinate: ', $
RETURN_EVENTS=1)
slicebase = WIDGET_BASE(tlb, COLUMN=1, FRAME=1)
options = ['X Only', 'Y Only', 'Z Only', 'X and Y', 'X and Z', 'Y and Z', $
'XYZ', 'Interactive XY']
droplistID = WIDGET_DROPLIST(slicebase, Value=options, $
UValue=options, TITLE='Slice Selection: ', $
EVENT_PRO='SLICE_GUI_SLICE_SELECT')
; Find current selection for the droplist.
thisSelection = 0
IF xslice THEN thisSelection = thisSelection + 1
IF yslice THEN thisSelection = thisSelection + 2
IF zslice THEN thisSelection = thisSelection + 4
CASE thisSelection OF
1: WIDGET_CONTROL, droplistID, SET_DROPLIST_SELECT=0
2: WIDGET_CONTROL, droplistID, SET_DROPLIST_SELECT=1
3: WIDGET_CONTROL, droplistID, SET_DROPLIST_SELECT=3
4: WIDGET_CONTROL, droplistID, SET_DROPLIST_SELECT=2
5: WIDGET_CONTROL, droplistID, SET_DROPLIST_SELECT=4
6: WIDGET_CONTROL, droplistID, SET_DROPLIST_SELECT=5
7: WIDGET_CONTROL, droplistID, SET_DROPLIST_SELECT=6
ENDCASE
; Rotation and transparency.
rotbase = WIDGET_BASE(tlb, COLUMN=1, FRAME=1)
azsliderID = WIDGET_SLIDER(rotbase, TITLE='Rotate About Z', MIN=-30, $
EVENT_PRO='SLICE_GUI_ROTATE', MAX=210, VALUE=az, SCR_XSIZE=200)
axsliderID = WIDGET_SLIDER(rotbase, TITLE='Rotate About X', MIN=0, $
EVENT_PRO='SLICE_GUI_ROTATE', MAX=90, VALUE=ax, SCR_XSIZE=200)
transparentID = WIDGET_SLIDER(rotbase, TITLE='Transparency Threshold', $
MIN=0, EVENT_PRO='SLICE_GUI_TRANSPARENT', MAX=100, $
VALUE=transparent, SCR_XSIZE=200)
; Animate pull-down menu.
animateSlice = WIDGET_BUTTON(tlb, VALUE='Animate Slice', MENU=2, $
EVENT_PRO='SLICE_GUI_ANIMATE')
junk = WIDGET_BUTTON(animateSlice, VALUE='X Slice', UVALUE='X')
junk = WIDGET_BUTTON(animateSlice, VALUE='Y Slice', UVALUE='Y')
junk = WIDGET_BUTTON(animateSlice, VALUE='Z Slice', UVALUE='Z')
; Graphics display options.
character = WIDGET_BUTTON(tlb, VALUE='Graphics Display Properties', MENU=2)
changecolorID = WIDGET_BUTTON(character, VALUE='Change Data Colors', $
EVENT_PRO='SLICE_GUI_CHANGE_COLORS')
backcolor = WIDGET_BUTTON(character, VALUE='Change Background Color', $
EVENT_PRO='SLICE_GUI_BACKGROUND_COLOR')
axescolor = WIDGET_BUTTON(character, VALUE='Change Axes Color', $
EVENT_PRO='SLICE_GUI_AXES_COLOR')
IF noaxes THEN noaxesText = ' Turn Axes On ' ELSE noaxesText = 'Turn Axes Off'
axesoff = WIDGET_BUTTON(character, VALUE=noaxesText, $
EVENT_PRO='SLICE_GUI_AXES_OFF')
annotationSize = WIDGET_BUTTON(character, VALUE='Change Character Size', $
EVENT_PRO='SLICE_GUI_CHARSIZE')
saveDisplay = WIDGET_BUTTON(character, VALUE='SAVE Graphic Display', $
EVENT_PRO='SLICE_GUI_SAVE_DISPLAY')
restoreDisplay = WIDGET_BUTTON(character, VALUE='RESTORE Graphic Display', $
EVENT_PRO='SLICE_GUI_RESTORE_DISPLAY')
; Hardcopy output.
outputButton = WIDGET_BUTTON(tlb, Value='File Output', $
Menu=2, Event_Pro='Slice_Create_Files')
psID = WIDGET_BUTTON(outputButton, Value='Create PostScript File', $
EVENT_PRO='SLICE_GUI_POSTSCRIPT', UValue='CREATE')
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='Slice_Configure_Files')
ps_config = WIDGET_BUTTON(configure, Value='Configure PostScript File...', $
EVENT_PRO='SLICE_GUI_POSTSCRIPT', UValue='CONFIGURE')
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...')
; Load new data.
loaddataID = WIDGET_BUTTON(tlb, VALUE='Load New Data', $
EVENT_PRO='SLICE_GUI_LOAD_DATA')
; New graphic display.
newdisplayID = WIDGET_BUTTON(tlb, Value='New Graphic Display', $
EVENT_PRO='SLICE_GUI_NEW_DISPLAY')
; Quit button.
quitID = WIDGET_BUTTON(tlb, VALUE='QUIT', EVENT_PRO='SLICE_GUI_QUITTER')
; Show it.
WIDGET_CONTROL, tlb, /REALIZE
; Set up the info structure.
info = { dataptr:-1L, $
xcoord:xcoord, $
ycoord:ycoord, $
zcoord:zcoord, $
xslice:xslice, $
yslice:yslice, $
zslice:zslice, $
az:az, $
ax:ax, $
wid:wid, $
ncolors:ncolors, $
bottom:bottom, $
psID:psID, $
tiffID:tiffID, $
gifID:gifID, $
jpegID:jpegID, $
transparent:transvalue, $
charscale:charscale, $
background:background, $
color:color, $
noaxes:noaxes, $
extra:extra, $
wtitle:wtitle, $
thisInstance:thisInstance, $
xcoordID:xcoordID, $
ycoordID:ycoordID, $
zcoordID:zcoordID, $
transparentID:transparentID, $
interactive:'', $
pt:!P.T, $
pixmapID:-1, $
pixXsize:-1, $
pixYsize:-1, $
maxx:maxx, $
maxy:maxy, $
maxz:maxz, $
droplistID:droplistID, $
axsliderID:axsliderID, $
azsliderID:azsliderID, $
graphics_tlb:-1L, $
drawID:-1L, $
tlb:tlb, $
postscript:postscript}
; File Output configuration structures.
CD, Current=thisDir
gif = {XWINDOW_GIF,XSIZE:400, YSIZE:400, COLOR:1, $
FILENAME:FilePath(Root_Dir=thisDir,'slice.gif'), $
ORDER:0, QUALITY:-1}
jpeg = {XWINDOW_JPEG,XSIZE:400, YSIZE:400, COLOR:1, $
FILENAME:FilePath(Root_Dir=thisDir,'slice.jpg'), $
ORDER:0, QUALITY:75}
tiff = {XWINDOW_TIFF,XSIZE:400, YSIZE:400, COLOR:1, $
FILENAME:FilePath(Root_Dir=thisDir,'slice.tif'), $
ORDER:1, QUALITY:-1}
info = CREATE_STRUCT(info, 'GIF', gif, 'JPEG', jpeg, 'TIFF', tiff)
; Create the display window.
WIDGET_CONTROL, tlb, TLB_GET_OFFSET=tlb_offsets, TLB_GET_SIZE=tlb_sizes
thisXoff = tlb_offsets(0) + tlb_sizes(0) + 50
thisYoff = tlb_offsets(1)
SLICE_GUI_MAKE_WINDOW, info, XSIZE=400, YSIZE=400, XOFFSET=thisXoff, YOFFSET=thisYoff
; Put initial display into the display window.
SLICE, data, XCOORD=xcoord, YCOORD=ycoord, ZCOORD=zcoord, XSLICE=xslice, $
YSLICE=yslice, ZSLICE=zslice, AX=ax, AZ=az, WID=info.wid, NCOLORS=ncolors, $
BOTTOM=bottom, TRANSPARENT=transparent, BACKGROUND=background, COLOR=color, $
CHARSIZE=1.0*charscale, NOAXES=noaxes, _EXTRA=extra
; Get correct transformation in the info.pt field.
info.pt = !P.T
; Set up pointer to data so data can be easily changed.
info.dataptr = HANDLE_CREATE(VALUE=data, /NO_COPY)
; Store the info structure and set focus on the control panel.
WIDGET_CONTROL, tlb, SET_UVALUE=info, /NO_COPY, $
EVENT_PRO='SLICE_GUI_RESIZE', /SHOW
XMANAGER, registerName, tlb, EVENT_HANDLER='SLICE_GUI_RESIZE', $
GROUP_LEADER=group, CLEANUP = 'SLICE_GUI_CLEANUP'
END ; of SLICE_GUI PROGRAM *************************************************
PRO SLICE, data, XSLICE=xslice, YSLICE=yslice, ZSLICE=zslice, WID=wid, $
NOAXES=noaxes, XCOORD=xcoord, YCOORD=ycoord, ZCOORD=zcoord, $
NCOLORS=ncolors, BOTTOM=bottom, POSTSCRIPT=postscript, BACKGROUND=background, $
COLOR=color, AZ=az, AX=ax, TRANSPARENT=transparent, _EXTRA=extra, $
CHARSIZE=charscale, GUI=gui, WTITLE=wtitle, THISINSTANCE=thisInstance
; Error checking
ON_ERROR, 1
np = N_PARAMS()
; If no data passed in, make some up for demo purposes.
IF np EQ 0 THEN BEGIN
MESSAGE, 'No data passed in. Using jet data...', /INFORMATIONAL
filename = FILEPATH(SUBDIR=['examples', 'data'], 'jet.dat')
CATCH, error
IF error NE 0 THEN BEGIN
ok = WIDGET_MESSAGE("Can't find JET.DAT. Returning...")
RETURN
ENDIF
OPENR, lun, filename, /GET_LUN
CATCH, /CANCEL
data = BYTARR(81, 40, 101)
READU, lun, data
data = CONGRID(TEMPORARY(data), 20, 10, 25, /INTERP)
FREE_LUN, lun
ENDIF
; Make sure data is 3D. Pick appropriate row and column slices.
s = SIZE(data)
IF s(0) NE 3 THEN MESSAGE, 'Data set must be 3D.'
xs = s(1)
ys = s(2)
zs = s(3)
IF N_ELEMENTS(xcoord) EQ 0 THEN xcoord= xs / 2
IF N_ELEMENTS(ycoord) EQ 0 THEN ycoord= ys / 2
IF N_ELEMENTS(zcoord) EQ 0 THEN zcoord= zs / 2
; What slices do you want. Must have something! X Slice is default.
xslice = KEYWORD_SET(xslice)
yslice = KEYWORD_SET(yslice)
zslice = KEYWORD_SET(zslice)
IF NOT xslice AND NOT yslice AND NOT zslice THEN xslice = 1
; Set colors.
IF N_ELEMENTS(ncolors) EQ 0 THEN ncolors=(!D.N_COLORS < 256)
IF N_ELEMENTS(bottom) EQ 0 THEN bottom = 0
IF N_ELEMENTS(transparent) EQ 0 THEN transparent = 0
transparent = transparent > 0
transparent = transparent < 100
IF N_ELEMENTS(background) EQ 0 THEN BEGIN
IF KEYWORD_SET(postscript) THEN background = 255 ELSE background = bottom
ENDIF
IF N_ELEMENTS(color) EQ 0 THEN BEGIN
IF KEYWORD_SET(postscript) THEN color = 0 ELSE color = (ncolors-1) + bottom
ENDIF
; Miscellaneous keywords.
IF N_ELEMENTS(charscale) EQ 0 THEN charscale = 1.0
IF N_ELEMENTS(extra) EQ 0 THEN extra = CREATE_STRUCT('title', '')
IF N_ELEMENTS(wid) EQ 0 THEN wid = !D.WINDOW
IF N_ELEMENTS(wtitle) EQ 0 THEN wtitle='Slice Graphics Window'
IF N_ELEMENTS(thisInstance) EQ 0 THEN thisInstance = 1
noaxes = KEYWORD_SET(noaxes)
; Default axes rotations.
IF N_ELEMENTS(az) EQ 0 THEN az = 30
IF N_ELEMENTS(ax) EQ 0 THEN ax = 30
; Does user want a widget program?
IF KEYWORD_SET(gui) THEN BEGIN
SLICE_GUI, data, XSLICE=xslice, YSLICE=yslice, ZSLICE=zslice, $
WID=wid, NOAXES=noaxes, XCOORD=xcoord, YCOORD=ycoord, ZCOORD=zcoord, $
NCOLORS=ncolors, BOTTOM=bottom, BACKGROUND=background, GROUP=group, $
COLOR=color, AZ=az, AX=ax, TRANSPARENT=transparent, _EXTRA=extra, $
CHARSIZE=charscale, WTITLE='Slice Controls: ', THISINSTANCE=thisInstance, $
POSTSCRIPT=postscript
RETURN
ENDIF
; Create a window if one is needed.
IF wid EQ -1 THEN BEGIN
IF NOT KEYWORD_SET(postscript) THEN $
WINDOW, /FREE, XSIZE=400, YSIZE=400, TITLE=wtitle
wid = !D.WINDOW
ENDIF
; Make sure requested slices are inside the data.
maxX = xs - 1
maxY = ys - 1
maxZ = zs - 1
maxData = MAX(data, MIN=minData)
xcoord = 0 > xcoord
xcoord = xcoord < maxX
ycoord = 0 > ycoord
ycoord = ycoord < maxY
zcoord = 0 > zcoord
zcoord = zcoord < maxZ
; Obtain the slice planes.
xplane = [ [xcoord, 0, 0], [xcoord, 0, maxz], [xcoord, maxy, maxz], [xcoord, maxy, 0] ]
yplane = [ [0, ycoord, 0], [0, ycoord, maxz], [maxx, ycoord, maxz], [maxx, ycoord, 0] ]
zplane = [ [ 0, 0, zcoord], [maxx, 0, zcoord], [maxx, maxy, zcoord], [0, maxy, zcoord] ]
; Obtain the slice images.
ximage = data(xcoord, *, *)
yimage = data(*, ycoord, *)
zimage = data(*, *, zcoord)
; Make a 2D image out of the images.
ximage = REFORM(ximage)
yimage = REFORM(yimage)
zimage = REFORM(zimage)
; Scale images appropriately for number of colors.
ximage = BYTSCL(ximage, TOP=ncolors-1, MAX=maxData, MIN=minData) + BYTE(bottom)
yimage = BYTSCL(yimage, TOP=ncolors-1, MAX=maxData, MIN=minData) + BYTE(bottom)
zimage = BYTSCL(zimage, TOP=ncolors-1, MAX=maxData, MIN=minData) + BYTE(bottom)
; If the window index number doesn't exist, create it.
CATCH, error
IF error NE 0 THEN BEGIN
wid = wid < 31
WINDOW, wid, XSIZE=400, YSIZE=400, TITLE=wtitle
ENDIF
IF NOT KEYWORD_SET(postscript) THEN WSET, wid
CATCH, /CANCEL
; The slices will be rendered in the Z-Buffer.
; Set Z-Buffer size.
IF KEYWORD_SET(postscript) THEN xsize=400 ELSE xsize = !D.X_SIZE
IF KEYWORD_SET(postscript) THEN ysize=400 ELSE ysize = !D.Y_SIZE
oldDevice = !D.NAME
SET_PLOT, 'Z'
DEVICE, SET_RESOLUTION=[xsize, ysize], SET_COLORS=ncolors
; Set up 3D coordinate system.
SURFACE, dist(30), /NODATA, XRANGE=[0,maxx], YRANGE=[0,maxy], ZRANGE=[0,maxz], $
XSTYLE=5, YSTYLE=5, ZSTYLE=5, POSITION=[0.15, 0.15, 0.95, 0.95, 0.1, 0.95], $
/SAVE, AZ=az, AX=ax
; Set up background color.
ERASE, COLOR=background
; Render the slices.
IF xslice THEN POLYFILL, xplane, /T3D, PATTERN=ximage, $
IMAGE_COORD=[ [0,0], [0, zs-1], [ys-1, zs-1], [ys-1, 0] ], /IMAGE_INTERP, $
TRANSPARENT=transparent
IF yslice THEN POLYFILL, yplane, /T3D, PATTERN=yimage, $
IMAGE_COORD=[ [0,0], [0, zs-1], [xs-1, zs-1], [xs-1, 0] ], /IMAGE_INTERP, $
TRANSPARENT=transparent
IF zslice THEN POLYFILL, zplane, /T3D, PATTERN=zimage, $
IMAGE_COORD=[ [0,0], [xs-1, 0], [xs-1, ys-1], [0, ys-1] ], /IMAGE_INTERP, $
TRANSPARENT=transparent
; Add axes if needed and not in PostScript mode.
IF NOT KEYWORD_SET(postscript) THEN $
IF NOT noaxes THEN SURFACE, dist(30), /NODATA, XRANGE=[0,maxx], $
YRANGE=[0,maxy], ZRANGE=[0,maxz], XSTYLE=1, YSTYLE=1, ZSTYLE=1, /NOERASE, $
POSITION=[0.15, 0.15, 0.95, 0.95, 0.1, 0.95], XTITLE='X Coordinate', $
YTITLE='Y Coordinate', ZTITLE='Z Coordinate', CHARSIZE=1.0*charscale, $
COLOR=color, AZ=az, AX=ax, _EXTRA=extra
; Take a snap-shot.
picture = TVRD(0, 0, xsize-1, ysize-1)
; Display the data in the display window.
; Make sure window is valid and whether the device is PostScript.
SET_PLOT, oldDevice
; Can ask for a window that is not available. Anticipate!!
CATCH, error
IF error NE 0 THEN BEGIN
ok = WIDGET_MESSAGE(['Requested window index number '+ STRTRIM(wid,2) + ' is', $
'not available. Using current window index.'])
wid = !D.WINDOW
IF wid EQ -1 THEN BEGIN
ok = WIDGET_MESSAGE("Can't find valid display window. Returning...")
RETURN
ENDIF
ENDIF
IF NOT KEYWORD_SET(postscript) THEN WSET, wid
CATCH, /CANCEL
; Special handling if in PostScript.
IF KEYWORD_SET(postscript) THEN BEGIN
; Get instructions for configuring the device from the user.
deviceKeywords = PS_FORM(INITIALIZE=1, LOCALDEFAULTS=postscript)
; Let user know something is going on.
notice = SLICE_DELAY_NOTICE('Please be patient while writing the file...')
; Configure PostScript device.
oldDevice = !D.NAME
IF oldDevice NE 'PS' THEN BEGIN
SET_PLOT, 'PS'
setBack = 1
ENDIF ELSE setBack = 0
DEVICE, _EXTRA=deviceKeywords
filename = deviceKeywords.filename
; Special PostScript processing for backgrounds and axes color.
index = WHERE(picture EQ background, count)
IF count GT 0 THEN picture(index) = 255
TVLCT, r, g, b, /GET
rThis = r(0)
gThis = g(0)
bThis = b(0)
TVLCT, 0, 0, 0, 0
color = 0
; Display the image.
inches = deviceKeywords.inches
IF inches THEN TV, picture, XSIZE=deviceKeywords.xsize, $
YSIZE=deviceKeywords.ysize, Inches=1 ELSE $
TV, picture, XSIZE=deviceKeywords.xsize, $
YSIZE=deviceKeywords.ysize, Centimeters=1
; Add axes if needed.
IF NOT noaxes THEN SURFACE, DIST(30,30), /NODATA, XRANGE=[0,maxx], $
YRANGE=[0,maxy], ZRANGE=[0,maxz], XSTYLE=1, YSTYLE=1, ZSTYLE=1, /NOERASE, $
POSITION=[0.15, 0.15, 0.95, 0.95, 0.1, 0.95], XTITLE='X Coordinate', $
YTITLE='Y Coordinate', ZTITLE='Z Coordinate', _EXTRA=extra, $
COLOR=color, CHARSIZE=1.0*charscale, AZ=az, AX=ax
TVLCT, rThis, gThis, bThis, 0
DEVICE, /CLOSE
WIDGET_CONTROL, notice, /DESTROY
IF setBack THEN SET_PLOT, oldDevice
ENDIF ELSE TV, picture
END ; of SLICE PROGRAM **********************************************************
; EXAMPLE program to see how it works.
PRO EXAMPLE
; How many colors?
thisWindow = !D.WINDOW
WINDOW, /FREE, /PIXMAP, XSIZE=10, YSIZE=10
WDELETE, !D.WINDOW
IF thisWindow GE 0 THEN WSET, thisWindow
ncolors = ((!D.N_COLORS-4) < 256)
; Load data and drawing colors
LOADCT, 5, NCOLORS=ncolors-2, BOTTOM=0
TVLCT, [70, 255], [70, 255], [70, 0], ncolors-2
; Run the SLICE program.
SLICE, /GUI, BACKGROUND=ncolors-2, COLOR=ncolors-1, NCOLORS=ncolors-2, $
BOTTOM=0, /XSLICE, /YSLICE
END