#
# shplot.tcl: Main Tcl script for the PLOTXY GUI
#
# ------------------------------------------------
# Mumit Khan <khan@xraylith.wisc.edu>
# Center for X-ray Lithography
# University of Wisconsin-Madison
# 3731 Schneider Dr., Stoughton, WI, 53589
# ------------------------------------------------
#
# Copyright (c) 1996 Mumit Khan
#

######################### Initialize options ##############################

#
# shplot:init:env is really executed ONLY once per interpreter. It has
# checks to avoid reinventing the wheel if we get here by "New Window"
# command.
#

proc shplot:init:env {rwin} {
    global shplot shadow_library
    if [info exists shplot(initialized)] {
        incr shplot(instances)
        incr shplot(total_instances)
	shplot:vputs "instance # $shplot(instances)"
        return
    } else {
        set shplot(instances) 1
        set shplot(total_instances) 1
	shplot:vputs "first instance"
    }
    #
    # make all the globals available here.
    #
    eval global [uplevel \#0 info vars]
    # Handle Tcl library environment variables
    if ![info exists env(SHADOW_GUI_ROOT)] {
        puts stderr "Warning: env(SHADOW_GUI_ROOT) does not exist."
	set env(SHADOW_GUI_ROOT) [pwd]
    }

    if [catch {set env(SHADOW_GUI_ROOT)} shplot(shadow_gui_root)] {
	set shplot(shadow_gui_root) $shplot(shadow_root)
    }

    if ![info exists shadow_library] {
        puts stderr "Warning: shadow_library variable is not set."
	set shadow_library [pwd]
    }
    set shplot(shadow_tcl_library) $shadow_library

    set tcl_precision 17

    # Set-up various paths
    lappend auto_path $shplot(shadow_tcl_library) 
    if [catch {file join x y}] {
	lappend auto_path $shplot(shadow_tcl_library)/shplot
    } else {
	lappend auto_path [file join $shplot(shadow_tcl_library) shplot]
    }
    lappend auto_path [pwd]
    lappend auto_path [pwd]/../tcl
    lappend auto_path $blt_library

    # Check for correct Tcl version
    if {[info tclversion] < 7.0} {
	puts stderr "shplot: Tcl version < 7.0 cannot be used with shplot"
	exit 1
    }

    #
    # Win32 lacks a few standard variables, so fix those here.
    #
    set platform $tcl_platform(platform)
    if {$platform == "windows"} {
	if [catch {set env(HOME)} shplot(homedir)] {
	    if [catch {set env(windir)} shplot(homedir)] {
		set shplot(homedir) [pwd]
	    }
	}
	if [catch {set env(USER)} shplot(username)] {set shplot(username) ""}
	if [catch {set env(TEMP)} shplot(tmpdir)] {
	    if [file isdir c:/temp] {
		set shplot(tmpdir) c:/temp
	    } elseif [file isdir c:/tmp] {
		set shplot(tmpdir) c:/tmp
	    } else {
		set shplot(tmpdir) .
	    }
	    # cygwin32 likes TMPDIR env variable; this way we avoid having to
	    # have a /tmp (per P_tmpdir in <stdio.h>
	    if ![info exists env(TMPDIR)] {set env(TMPDIR) $shplot(tmpdir)}
	}
	# sanitize pathnames for C strings.
	set shplot(homedir) [cvt_filename_to_tcl $shplot(homedir)]
	set shplot(tmpdir) [cvt_filename_to_tcl $shplot(tmpdir)]
    } elseif {$platform == "unix"} {
	if [catch {set env(HOME)} shplot(homedir)] {
	    set shplot(homedir) [pwd]
	}
	if [catch {set env(USER)} shplot(username)] {
	    set shplot(username) "unknown"
	}
	if [catch {set env(TMPDIR)} shplot(tmpdir)] {
	    set shplot(tmpdir) "/tmp"
	}
    } else {
	error "Only works on Unix and Windows platforms for now. Sorry"
    }
}

######################### Initialize globals ##############################

# initialization that only happen once per interpreter, like the 
# shplot:init:env, but only for shplot specific globals.

proc shplot:init:_once_globals {} {
    global env shplot

    if [info exists shplot(initialized)] {return}

    # datasets and files
    #
    set shplot(datasets)	""	;#   and list of active datasets

    # multiple toplevels?
    set shplot(toplevels)	""

    #
    # general SHADOW related names.
    #
    set shplot(col_names,1)	X
    set shplot(col_names,2)	Y
    set shplot(col_names,3)	Z
    set shplot(col_names,4)	X'
    set shplot(col_names,5)	Y'
    set shplot(col_names,6)	Z'

    set shplot(color_good)	magenta
    set shplot(color_lost)	red

    set shplot(plot_body_width)	10i
    set shplot(plot_body_height) 8i
    set shplot(plot_scatter_width) 6i
    set shplot(plot_scatter_height) 5i
    set shplot(plot_basemargin)	0

    # following are computed in shplot:graph:make
    set shplot(scatter_llx) 	0
    set shplot(scatter_lly)	0
    set shplot(histo_t_llx)	0
    set shplot(histo_t_lly)	0
    set shplot(histo_s_llx)	0
    set shplot(histo_s_lly)	0
    set shplot(info_lly)	0
    set shplot(info_llx)	0
    set shplot(info_height)	0
    set shplot(info_width)	0
    set shplot(title_lly)	0
    set shplot(title_llx)	0

    set shplot(verbose)		0
}

proc shplot:init:globals {rwin} {
    global env shplot

    shplot:init:_once_globals

    # datasets and files
    #
    set shplot($rwin,curfile)		""	;# current datafile name
    set shplot($rwin,curdataset) 	""	;#  ... dataset being viewed
    set shplot($rwin,instance)		$shplot(total_instances)

    #
    # plot states
    #
    set shplot($rwin,showing_plot)	0
    set shplot($rwin,col_x)		1
    set shplot($rwin,col_y)		3
    set shplot($rwin,plot_scatter)	1
    set shplot($rwin,plot_histo_t)	1
    set shplot($rwin,plot_histo_s)	1
    set shplot($rwin,plot_info)		1
    set shplot($rwin,rays)		good
    set shplot($rwin,cur_limits) 	""	;# {xmin, xmax, ymin, ymax}
    set shplot($rwin,plot_grid)		0
    set shplot($rwin,xbins)		25
    set shplot($rwin,ybins)		25

    # cmds to change various plot states (eval these with values)
    set shplot($rwin,ray_choices_cmd)	""
    set shplot($rwin,plot_choices_cmd)	""
    set shplot($rwin,scale_choices_cmd)	""

    # allowed scaling types are -- auto, cart, fill and user
    set shplot($rwin,scale)		auto
    set shplot($rwin,user_limits)	""	;# {xmin, xmax, ymin, ymax}

    set shplot(color_good)		magenta
    set shplot(color_lost)		red

    # interface globals (various window paths typically)
    if {$shplot(total_instances) == 1} {
        set inst ""
    } else {
        set inst "#$shplot(total_instances)"
    }
    set shplot($rwin,win_title)		"SHADOW Plot$inst"
    set shplot($rwin,plot_master_w)	""	;# parent window of BLT graph
    set shplot($rwin,info_w)		".info"	;# for min/max/etc image info.
    set shplot($rwin,consle_w)		""
    set shplot($rwin,consle_w_stub)	""
    #set shplot($rwin,toolbar_w)	""	;# Toolbar at top
    #set shplot($rwin,balloon_w)	""	;# main balloon help widget
    #set shplot($rwin,popup_w)		""	;# popup menu for interface
}

######################### Initialize preferences, startup etc 

#
# initialize user preferences
#
proc shplot:init:preferences {rwin} { }

#
# initialize fonts. Should be called *after* init:preferences
# We should really use "tix resetoptions" and change the scheme used by
# Tix, but Tix only has 12 and 14 point font schemes and we need smaller
# ones esp on laptops.
#
proc shplot:init:fonts {rwin} {
    global shplot shplot_prefs
}

#
# initialize the image to be loaded and such. Called after all other
# intialization is done.
#
proc shplot:init:startup {rwin} {
    global shplot shplot_prefs

    #
    # now do the initial GUI loading if specified.
    #
    if {$shplot($rwin,curfile) != ""} {
	set file $shplot($rwin,curfile)
	if [catch {shplot:_load_image $rwin $file} msg] {
	    dialog .load_error "Load Error" \
		"Error loading SHADOW ray file $file. ($msg)" \
		error 0 Dismiss
	    return
	}
    } else {
	shplot:misc:add_file_to_title $rwin ""
    }
    return 0
}

######################### Utilities #######################################


#----------------------------------------------------------------------#
# Misc front-end Routines 
#----------------------------------------------------------------------#

proc shplot:cleanup_and_exit {{status 0}} {
    global shplot
    # REMOVE any temp files ...
    exit $status
}

# effects - Print usage message and exist
proc shplot:usage {{status 1}} {
    puts stderr {
Usage: shplot [-hv] SHADOW_IMAGE_FILE
 
    -v:         turn on verbose mode (default: off)
    -h:         print this info
    SHADOW_IMAGE:  Loads the shadow image file and plot
 
Examples:

    % shplot                  ;# Start up SHADOW workspace with def options.
    % shplot star.02          ;# Start up and load star.02 (OE 2)

    }
    exit $status
}


# verbose mode puts
proc shplot:vputs {args} {
    global shplot
    if {[info exists shplot(verbose)] && $shplot(verbose)} {
	puts stderr "shplot: [join $args]"
    }
}

# parse the command line arguments and fill up the shplot array elements.
proc shplot:parse_args {rwin} {
    global argv shplot
    shplot:vputs "parsing argv: $argv"
    while {[llength $argv] != 0} {
	set arg [lindex $argv 0]
	set argv [lrange $argv 1 end]
	shplot:vputs "arg = $arg, argv = $argv"

	case $arg in {
	    -h* {
		# don't exit with an error status - not an error
		shplot:usage 0
	    }
	    -v* {
		set shplot(verbose) 1
		shplot:vputs "setting verbose mode to on"
	    }
	    -* {
		puts stderr "shplot: bad option \"$arg\"."
		shplot:usage
	    }
	    * {
		if {$shplot($rwin,curfile) != ""} {
		    puts stderr "shplot: Can only load one image at a time."
		    shplot:usage 
		} else {
		    set shplot($rwin,curfile) "$arg"
		}
	    }
	}
    }

    shplot:vputs "current image file:       $shplot($rwin,curfile)"
}


####################### Plotting routines ################################

####################### Zooming utilitis

#
# Zooming modified from BLT 2.1 to include x2 and y2 axes and also to
# zoom multiple plots at the same time.
#

proc shplot:Blt_ZoomStack { graph histo_t histo_s } {
    global shplot

    set shplot(bltZoom,$graph,A,x) {}
    set shplot(bltZoom,$graph,A,y) {}
    set shplot(bltZoom,$graph,B,x) {}
    set shplot(bltZoom,$graph,B,y) {}
    set shplot(bltZoom,$graph,stack) {}
    set shplot(bltZoom,$graph,corner) A

    set shplot(bltZoom,$graph,histo_t) $histo_t
    set shplot(bltZoom,$graph,histo_s) $histo_s

    bind $graph <1> { 
	shplot:BltSetZoomPoint %W %x %y 
    }
    bind $graph <ButtonPress-3> {
	shplot:BltResetZoom %W 
    }
}


proc shplot:BltGetCoords { graph x y index } {

    set coords [$graph invtransform $x $y]
    set x [lindex $coords 0]
    set y [lindex $coords 1]

    scan [$graph xaxis limits] "%s %s" xmin xmax
    scan [$graph yaxis limits] "%s %s" ymin ymax

    if { $x > $xmax } { 
	set x $xmax 
    } elseif { $x < $xmin } { 
	set x $xmin 
    }

    if { $y > $ymax } { 
	set y $ymax 
    } elseif { $y < $ymin } { 
	set y $ymin 
    }
    global shplot
    set shplot(bltZoom,$graph,$index,x) $x
    set shplot(bltZoom,$graph,$index,y) $y
}

proc shplot:BltPopZoom { graph } {
    global shplot

    set zoomStack $shplot(bltZoom,$graph,stack)
    if { [llength $zoomStack] > 0 } {
	set cmd [lindex $zoomStack 0]
	set shplot(bltZoom,$graph,stack) [lrange $zoomStack 1 end]
	eval $cmd
	shplot:BltZoomTitleLast $graph
	catch {busy hold $graph}
	update
	set cmd [format {
	    if { $shplot(bltZoom,%s,corner) == "A" } {
		%s marker delete "bltZoom_title"
	    }
	} $graph $graph ]
	after 2000 $cmd
	catch {busy release $graph}
    } else {
	$graph marker delete "bltZoom_title"
    }
}

# Push the old axis limits on the stack and set the new ones

proc shplot:BltPushZoom { graph } {
    $graph marker delete "bltZoom_*" 

    global shplot
    set x1 $shplot(bltZoom,$graph,A,x)
    set y1 $shplot(bltZoom,$graph,A,y)
    set x2 $shplot(bltZoom,$graph,B,x)
    set y2 $shplot(bltZoom,$graph,B,y)

    if { ($x1 == $x2) && ($y1 == $y2) } { 
	# No delta, revert to start
	return
    }

    set histo_t $shplot(bltZoom,$graph,histo_t)
    set histo_s $shplot(bltZoom,$graph,histo_s)

    set xmin_old [$graph xaxis cget -min]
    set xmax_old [$graph xaxis cget -max]
    set ymin_old [$graph yaxis cget -min]
    set ymax_old [$graph yaxis cget -max]

    set cmd " \n\
	$graph yaxis configure -min $ymin_old -max $ymax_old \n\
	$graph y2axis configure -min $ymin_old -max $ymax_old \n\
	foreach g \"$graph $histo_t\" { \n\
	    \$g xaxis configure -min $xmin_old -max $xmax_old \n\
	    \$g x2axis configure -min $xmin_old -max $xmax_old \n\
	} \n\
	$histo_s xaxis configure -min $ymin_old -max $ymax_old \n\
	$histo_s x2axis configure -min $ymin_old -max $ymax_old \n\
    "
    if { $x1 > $x2 } { 
	set xmin $x2
        set xmax $x1
    } else {
	set xmin $x1
        set xmax $x2
    }
    if { $y1 > $y2 } {
        set ymin $y2
        set ymax $y1
    } else {
        set ymin $y1
        set ymax $y2
    }
    $graph yaxis configure -min $ymin -max $ymax
    $graph y2axis configure -min $ymin -max $ymax

    foreach g "$graph $histo_t" {
	$g xaxis configure -min $xmin -max $xmax
	$g x2axis configure -min $xmin -max $xmax
    }
    $histo_s xaxis configure -min $ymin -max $ymax
    $histo_s x2axis configure -min $ymin -max $ymax

    set shplot(bltZoom,$graph,stack) \
        [linsert $shplot(bltZoom,$graph,stack) 0 $cmd]

    catch {busy hold $graph}
    update
    catch {busy release $graph}
}

proc shplot:BltResetZoom { graph } {
    global shplot

    $graph marker delete "bltZoom_*" 
    if { $shplot(bltZoom,$graph,corner) == "A" } {
	# Reset the whole axis
	shplot:BltPopZoom $graph
    } else {
	set shplot(bltZoom,$graph,corner) A
	bind $graph <Motion> { }
    }
}

proc shplot:BltZoomTitleNext { graph } {
    global shplot

    set level [expr [llength $shplot(bltZoom,$graph,stack)] + 1]
    set title "Zoom #$level"
    $graph marker create text -name "bltZoom_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} 
}

proc shplot:BltZoomTitleLast { graph } {
    global shplot

    set level [llength $shplot(bltZoom,$graph,stack)]
    if { $level > 0 } {
	set title "Zoom #$level"
     	$graph marker create text -name "bltZoom_title" -text $title \
		-coords {-Inf Inf} -anchor nw -bg {} 
    }
}

proc shplot:BltSetZoomPoint { graph x y } {
    global shplot

    shplot:BltGetCoords $graph $x $y $shplot(bltZoom,$graph,corner)
    if { $shplot(bltZoom,$graph,corner) == "A" } {
	# First corner selected, start watching motion events

	shplot:BltZoomTitleNext $graph 
	bind $graph <Any-Motion> { 
	    shplot:BltGetCoords %W %x %y B
	    shplot:BltBox %W
	}
	set shplot(bltZoom,$graph,corner) B
    } else {
	bind $graph <Any-Motion> { }
	shplot:BltPushZoom $graph 
	set shplot(bltZoom,$graph,corner) A
    }
}

proc shplot:BltBox { graph } {
    global shplot

    if { $shplot(bltZoom,$graph,A,x) > $shplot(bltZoom,$graph,B,x) } { 
	set x1 $shplot(bltZoom,$graph,B,x)
	set x2 $shplot(bltZoom,$graph,A,x) 
	set y1 $shplot(bltZoom,$graph,B,y)
	set y2 $shplot(bltZoom,$graph,A,y) 
    } else {
	set x1 $shplot(bltZoom,$graph,A,x)
	set x2 $shplot(bltZoom,$graph,B,x) 
	set y1 $shplot(bltZoom,$graph,A,y)
	set y2 $shplot(bltZoom,$graph,B,y) 
    }
    set coords {
	$x1 $y1 $x1 $y2 $x1 $y1 $x2 $y1 $x2 $y1 $x2 $y2 $x1 $y2 $x2 $y2 
    }
    if [$graph marker exists "bltZoom_outline"] {
	$graph marker configure "bltZoom_outline" -coords $coords
    } else {
	$graph marker create line -coords $coords -name "bltZoom_outline" \
	    -dashes { 4 2 }
    }
    $graph marker before "bltZoom_outline"
}

####################### End of Zooming routines

####################### Plotting routines ################################

proc shplot:graph:make {rwin} {
    global shplot

    set w $shplot($rwin,plot_master_w)

    set plotrelief sunken

    # make scatter plot and the barcharts for histogram
    graph ${w}.scatter -title "" \
	-bufferelements 1 \
	-topmargin 0 -rightmargin 0 \
	-plotrelief $plotrelief \
	;#-width $scatterw \
	;#-height $scatterh
    ${w}.scatter grid configure \
	-mapx both -mapy both \
	-mapped $shplot(plot_grid)

    ${w}.scatter postscript configure -decorations 0

    barchart ${w}.histo_t -title "" \
	-bufferelements 1 \
	-bottommargin 0 \
	-plotrelief $plotrelief

    ${w}.histo_t postscript configure -decorations 0

    # the side histogram needs X/Y axis inversion as well.
    barchart ${w}.histo_s -title "" \
	-invertxy 1 \
	-bufferelements 1 \
	-leftmargin 0 \
	-plotrelief $plotrelief

    ${w}.histo_s postscript configure -decorations 0

    # initialize the common options
    foreach i "scatter histo_t histo_s" {
	set g ${w}.${i}
	$g legend configure -mapped 0
	$g xaxis configure -title "" 
	$g yaxis configure -title "" 
	$g x2axis configure -title "" -mapped true -showticks 0
	$g y2axis configure -title "" -mapped true -showticks 0
    }

    # only allow user to zoom the scatter plot area. 
    # TODO: (un)zooming scatter plot should also correspondingly zoom
    # the histograms.

    shplot:Blt_ZoomStack ${w}.scatter ${w}.histo_t ${w}.histo_s
    Blt_Crosshairs ${w}.scatter
    Blt_Crosshairs ${w}.histo_t
    Blt_Crosshairs ${w}.histo_s

    # make the graph elements right now, and supply the data vectors
    # when needed (in shplot:graph:plot and procs called it).
    foreach ray "good lost" {
	${w}.scatter element create $ray -mapx both -mapy both \
	    -linewidth 0 -symbol circle -color $shplot(color_$ray) \
	    -pixels 1.5 -scalesymbols 1
    }
    foreach histo "histo_t histo_s" {
	${w}.${histo} element create histo -mapx both -mapy both
    }

    # now the various sizes and placements.
    set scatterw [winfo reqwidth ${w}.scatter]
    set scatterh [winfo reqheight ${w}.scatter]
    set histo_t_h [expr round($scatterh / 2.5)]
    set histo_s_w [expr round($scatterw / 2.0)]
    ${w}.histo_t configure -height $histo_t_h
    ${w}.histo_s configure -width $histo_s_w

    set rwidth [winfo reqwidth $w]
    set rheight [winfo reqheight $w]

    set basemargin $shplot(plot_basemargin)

    set shplot(title_llx) 50
    set shplot(title_lly) 0

    set shplot(histo_t_llx) $basemargin
    set shplot(histo_t_lly) [expr {$basemargin + $histo_t_h + 30}]

    set shplot(scatter_llx) $basemargin
    set shplot(scatter_lly) \
        [expr {$shplot(histo_t_lly) + $basemargin + $scatterh}]

    set shplot(histo_s_llx) \
        [expr {$shplot(scatter_llx) + $basemargin + $scatterw}]
    set shplot(histo_s_lly) $shplot(scatter_lly)

    set shplot(info_llx) \
        [expr {$shplot(histo_s_llx) + $basemargin + $histo_s_w}]
    set shplot(info_lly) $shplot(histo_s_lly)

    set shplot(info_height) $scatterh
    set shplot(info_width) [expr {$histo_s_w * 0.85}]
}

proc shplot:graph:set_limits {rwin xmin xmax ymin ymax} {
    global shplot

    set w $shplot($rwin,plot_master_w)
    foreach i "scatter histo_t" {
	set g ${w}.${i}
	$g xaxis configure -min $xmin -max $xmax
	$g x2axis configure -min $xmin -max $xmax
    }
    foreach i "histo_s" {
	set g ${w}.${i}
	$g xaxis configure -min $ymin -max $ymax
	$g x2axis configure -min $ymin -max $ymax
    }
    foreach i "scatter" {
	set g ${w}.${i}
	$g yaxis configure -min $ymin -max $ymax
	$g y2axis configure -min $ymin -max $ymax
    }
    set shplot($rwin,cur_limits) "$xmin $xmax $ymin $ymax"
}

#
# CHECK/FIXME/TODO: MEMORY LEAK in the vectors when these windows are
# closed.
#
proc shplot:graph:show_scatter_plot {rwin} {
    global shplot
    set llx $shplot(scatter_llx)
    set lly $shplot(scatter_lly)
    set w $shplot($rwin,plot_master_w)
    set scatter ${w}.scatter
    $w create window $llx $lly -window $scatter -anchor sw

    set dataset $shplot($rwin,curdataset)
    set col1 $shplot($rwin,col_x)
    set col2 $shplot($rwin,col_y)
    set limit $shplot($rwin,scale)
    global Xgood_vector_$rwin Ygood_vector_$rwin 
    global Xlost_vector_$rwin Ylost_vector_$rwin
    if {$shplot($rwin,rays) == "good"} {
	$dataset column $col1 good Xgood_vector_$rwin
	$dataset column $col2 good Ygood_vector_$rwin
	if [info exists Xlost_vector_$rwin] {
	    Xlost_vector_$rwin set {}
	    Ylost_vector_$rwin set {}
	}
	$scatter element configure good \
	    -xdata Xgood_vector_$rwin \
	    -ydata Ygood_vector_$rwin
	shplot:vputs "scatter: good rays"
	shplot:vputs "x veclen = [Xgood_vector_$rwin length]"
    } elseif {$shplot($rwin,rays) == "lost"} {
	$dataset column $col1 lost Xlost_vector_$rwin
	$dataset column $col2 lost Ylost_vector_$rwin
	if [info exists Xgood_vector_$rwin] {
	    Xgood_vector_$rwin set {}
	    Ygood_vector_$rwin set {}
	}
	$scatter element configure lost \
	    -xdata Xlost_vector_$rwin \
	    -ydata Ylost_vector_$rwin
    } else {
	$dataset column $col1 good Xgood_vector_$rwin lost Xlost_vector_$rwin
	$dataset column $col2 good Ygood_vector_$rwin lost Ylost_vector_$rwin
	$scatter element configure good \
	    -xdata Xgood_vector_$rwin \
	    -ydata Ygood_vector_$rwin
	$scatter element configure lost \
	    -xdata Xlost_vector_$rwin \
	    -ydata Ylost_vector_$rwin
    }
}

#
# CHECK/FIXME/TODO: MEMORY LEAK in the vectors when these windows are
# closed.
#
proc shplot:graph:show_histogram {rwin histo_which col bins} {
    global shplot
    set llx $shplot(${histo_which}_llx)
    set lly $shplot(${histo_which}_lly)
    set w $shplot($rwin,plot_master_w)
    set histo ${w}.${histo_which}
    $w create window $llx $lly -window $histo -anchor sw

    if {$histo_which == "histo_t"} {
	set min [lindex $shplot($rwin,cur_limits) 0]
	set max [lindex $shplot($rwin,cur_limits) 1]
    } else {
	set min [lindex $shplot($rwin,cur_limits) 2]
	set max [lindex $shplot($rwin,cur_limits) 3]
    }
    set dataset $shplot($rwin,curdataset)
    global  ${histo_which}_xvector_$rwin ${histo_which}_vector_$rwin
    $dataset histogram $bins $col \
	${histo_which}_xvector_$rwin ${histo_which}_vector_$rwin \
	$min $max

    $histo element configure histo \
	-xdata ${histo_which}_xvector_$rwin \
	-ydata ${histo_which}_vector_$rwin

    # set the barwidth from min/max info
    set step [expr ($max - $min)/($bins - 1)]
    $histo configure -barwidth [expr $step * 1.0]
}

proc shplot:graph:show_info {rwin} {
    global shplot
    set dataset $shplot($rwin,curdataset)

    set ray_info   [$dataset info rays]
    set total_rays [lindex $ray_info 0]
    set good_rays  [lindex $ray_info 1]
    set lost_rays  [expr $total_rays - $good_rays]

    set horiz_min    [lindex $shplot($rwin,cur_limits) 0]
    set horiz_max    [lindex $shplot($rwin,cur_limits) 1]
    set horiz_length [expr $horiz_max - $horiz_min]
    set horiz_center [expr $horiz_max - $horiz_length/2.0]

    set vert_min     [lindex $shplot($rwin,cur_limits) 2]
    set vert_max     [lindex $shplot($rwin,cur_limits) 3]
    set vert_length  [expr $vert_max - $vert_min]
    set vert_center  [expr $vert_max - $vert_length/2.0]

    set horiz_col [set shplot(col_names,$shplot($rwin,col_x))]
    set vert_col  [set shplot(col_names,$shplot($rwin,col_y))]

    set text ""
    append text "H Length: $horiz_length\n"
    append text "H Center: $horiz_center\n"
    append text "V Length: $vert_length\n"
    append text "V Center: $vert_center\n\n"

    append text "Limits:   $shplot($rwin,scale)\n\n"

    append text "Rays:     $shplot($rwin,rays)\n\n"

    append text "Total:    $total_rays\n"
    append text "Lost:     $lost_rays\n\n"

    append text "Horiz:    $shplot(col_names,$shplot($rwin,col_x))\n"
    append text "Vert:     $shplot(col_names,$shplot($rwin,col_y))\n"

    set w $shplot($rwin,plot_master_w)
    set llx $shplot(info_llx)
    set lly $shplot(info_lly)
    set urx [expr $llx + $shplot(info_width)]
    set ury [expr $lly - $shplot(info_height)]
    $w create rectangle $llx $lly $urx $ury -width 2 ;#-outline red
    set x [expr $llx + 10]
    set y [expr $ury + 10]

    set font -*-fixed-bold-r-normal-*-14-*-*-*-*-*-*-*
    set font -*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*
    set font -*-courier-medium-r-normal-*-*-120-*-*-*-*-*-*

    $w create text $x $y -text $text -anchor nw -font $font
}

proc shplot:graph:show_title {rwin} {
    global shplot
    set file [string trim $shplot($rwin,curfile)]

    set text "Filename : $file\n\n"

    set w $shplot($rwin,plot_master_w)
    set x $shplot(title_llx)
    set y $shplot(title_lly)

    #set font -*-Helvetica-bold-o-normal-*-18-*-*-*-*-*-*-*
    set font -*-Helvetica-bold-o-normal-*-*-240-*-*-*-*-*-*

    $w create text $x $y -text $text -anchor nw -font $font
}

proc shplot:graph:clear {rwin} {
    global shplot
    set w $shplot($rwin,plot_master_w)
    $w delete all
    set shplot($rwin,showing_plots) 0
}

proc shplot:graph:print {rwin {file ""}} {
    global shplot
    set w $shplot($rwin,plot_master_w)
    set file [string trim $file]
    if {[string length $file] == 0} {
	set types {
	    {{Postscript Files}		{.ps}}
	    {{Postscript Files}		{.eps}}
	    {{All Files}		*}
	}
	set file [tk_getSaveFile \
	    -parent $rwin \
	    -defaultextension ".ps" \
	    -filetypes $types \
	    -title "Print to Postscript file" \
	    -initialfile "shplot.ps" \
	]
	if {[string length $file] == 0} {
	    return
	}
    }
    set canvas $shplot($rwin,plot_master_w)
    set bbox [$canvas bbox all]
    $shplot($rwin,plot_master_w) postscript -file $file -rotate 1 \
        -x [lindex $bbox 0] \
        -y [lindex $bbox 1] \
        -width [lindex $bbox 2] \
        -height [lindex $bbox 3]
}

proc shplot:graph:show_plots {rwin} {
    global shplot

    set w $shplot($rwin,plot_master_w)
    set scatter ${w}.scatter
    set histo_t ${w}.histo_t
    set histo_s ${w}.histo_s
    set info ${w}.info
    catch [list shplot:graph:show_title $rwin]

    if $shplot($rwin,plot_scatter) {
	catch [list shplot:graph:show_scatter_plot $rwin]
    }
    if $shplot($rwin,plot_histo_t) {
	catch [list shplot:graph:show_histogram $rwin histo_t \
	    $shplot($rwin,col_x) \
	    $shplot($rwin,xbins)]
    }
    if $shplot($rwin,plot_histo_s) {
	catch [list shplot:graph:show_histogram $rwin histo_s \
	    $shplot($rwin,col_y) \
	    $shplot($rwin,ybins)]
    }
    if $shplot($rwin,plot_info) {
	catch [list shplot:graph:show_info $rwin]
    }
    set shplot($rwin,showing_plot) 1
    catch {busy hold $rwin}
    update
    catch {busy release $rwin}
}

proc shplot:graph:plot {rwin} {
    global shplot
    set dataset $shplot($rwin,curdataset)

    if {$dataset == ""} {
	dialog .plot_error "Plot Error" \
	    "Please load a dataset before trying to plot." \
	    error 0 Dismiss
        return
    }

    set col1 $shplot($rwin,col_x)
    set col2 $shplot($rwin,col_y)

    $dataset select $shplot($rwin,rays)
    
    set scale $shplot($rwin,scale)
    if ![string compare $scale "user"] {
        set limits $shplot($rwin,user_limits)
    } else {
	set limits [$dataset compute limits columns $col1 $col2 $scale]
    }
    set xmin [lindex $limits 0]
    set xmax [lindex $limits 1]
    set ymin [lindex $limits 2]
    set ymax [lindex $limits 3]

    shplot:vputs "plotting: limits $limits"
    shplot:vputs "plotting: scale type = $scale"

    shplot:graph:clear $rwin

    # the placements are computed previously in shplot:graph:make

    if {$xmax <= $xmin || $ymax <= $ymin} {
	dialog .plot_error "Plot Error" \
	    [build_msg \
	    "Bad limits (plotting columns with no rays?)\n" \
	    "(xmin,xmax) = ($xmin,$xmax) and (ymin,ymax)=($ymin,$ymax)" \
	    ] \
	    error 0 Dismiss 7i
        return
    }

    shplot:graph:set_limits $rwin $xmin $xmax $ymin $ymax
    shplot:graph:show_plots $rwin
}

# refresh the current options and plot again. If plots are not visible,
# return.
proc shplot:graph:replot {rwin} {
    global shplot

    if {$shplot($rwin,curdataset) != "" && $shplot($rwin,showing_plot)} {
	shplot:graph:plot $rwin
    }
}

####################### Command callbacks ################################

proc shplot:close_cmd {rwin} {
    global shplot
    # release resources. CHECK
    catch {shdata delete $shplot($rwin,curdataset)}
    destroy $rwin
}

proc shplot:exit_cmd {rwin {status 0}} {
    shplot:cleanup_and_exit $status
}

proc shplot:new_window_cmd {} {
    for {set cnt 1} {$cnt <= 50} {incr cnt} {
	set toplevel .shplot#$cnt
	if ![winfo exists $toplevel] {
	    shplot:main $toplevel
	    return
	}
    }
    error "Too many (50) Shadow plot windows open. Please close some"
}

#
# this has to happen for ALL the toplevels, so the rwin parameter (for
# specifying the "this" toplevel) is  not needed here.
# really not used.
proc shplot:show_console_cmd {} {
    global shplot shplot_prefs
    foreach rwin $shplot(toplevels) {
	shplot:vputs "console for toplevel $rwin"
	catch "pack unpack $shplot($rwin,consle_w)"
	if {$shplot_prefs(show_console)} {
	    pack $shplot($rwin,consle_w) \
		-after $shplot($rwin,consle_w_stub) -fill x 
	}
    }
}

proc shplot:plot_grid_cmd {rwin} {
    global shplot
    set w $shplot($rwin,plot_master_w)
    set scatter ${w}.scatter
    catch {busy hold $rwin}
    ${w}.scatter grid configure -mapped $shplot($rwin,plot_grid)
    update
    catch {busy release $rwin}
}

proc shplot:_export_histogram {rwin histo_which file} {
    shplot:vputs "_export_histogram: rwin = $rwin, histo = $histo_which"
    if [catch {open $file "w"} fid] {
	dialog .export "Export Error" \
	    "Error opening output file \"$file\"\n\t(Message: $msg)" \
	    error 0 Dismiss 
	return
    }
    global shplot
    global  ${histo_which}_xvector_$rwin ${histo_which}_vector_$rwin
    set npoints [${histo_which}_xvector_$rwin length]
    for {set i 0} {$i < $npoints} {incr i} {
	set var ${histo_which}_xvector_${rwin}($i)
	set xval [set $var]
	set var ${histo_which}_vector_${rwin}($i)
	set yval [set $var]
	puts $fid [format "%12.5E    %12.5E" $xval $yval]
    }
    close $fid
}

proc shplot:export_histogram_cmd {rwin histo_which {file {}}} {
    global shplot
    if {$shplot($rwin,curdataset) == ""} {
	dialog .export "Export Error" \
	    "Must load a dataset before you can export data from it" \
	    error 0 Dismiss 
	return
    }
    if {$file == ""} {
	set types {
	    {{Misc Data Files}		{.dat}}
	    {{SHADOW Workspace Files}	{.ws}}
	    {{SHADOW Namelist Files}	{start.*}}
	    {{SHADOW Source Image}	{begin.dat}}
	    {{SHADOW Image Files}	{star.*}}
	    {{SHADOW Image Files}	{mirr.*}}
	    {{All Files}		*}
	}
        set file [tk_getSaveFile \
	    -parent $rwin \
	    -title "Export SHADOW histogram data to file" \
	    -initialfile "${histo_which}.dat" \
	    -defaultextension ".dat" \
	    -filetypes $types \
        ]
	set file [string trim $file]
	if {[string length $file] != 0} {
	    shplot:_export_histogram $rwin $histo_which $file
	}
    }
}

proc shplot:_export_scatter {rwin file} {
    if [catch {open $file "w"} fid] {
	dialog .export "Export Error" \
	    "Error opening output file \"$file\"\n\t(Message: $msg)" \
	    error 0 Dismiss 
	return
    }
    global shplot
    catch {busy hold $rwin}
    if {$shplot($rwin,rays) == "all" || $shplot($rwin,rays) == "good"} {
	global Xgood_vector_${rwin} Ygood_vector_${rwin}
	set npoints [Xgood_vector_${rwin} length]
	shplot:vputs "_export_scatter: npoints = $npoints"
	for {set i 0} {$i < $npoints} {incr i} {
	    set var Xgood_vector_${rwin}($i)
	    set xval [set $var]
	    set var Ygood_vector_${rwin}($i)
	    set yval [set $var]
	    puts $fid [format "%12.5E    %12.5E" $xval $yval]
	}
    } 
    if {$shplot($rwin,rays) == "all" || $shplot($rwin,rays) == "lost"} {
	global Xlost_vector_${rwin} Ylost_vector_${rwin}
	set npoints [Xlost_vector_${rwin} length]
	shplot:vputs "_export_scatter: npoints = $npoints"
	for {set i 0} {$i < $npoints} {incr i} {
	    set var Xlost_vector_${rwin}($i)
	    set xval [set $var]
	    set var Ylost_vector_${rwin}($i)
	    set yval [set $var]
	    puts $fid [format "%12.5E    %12.5E" $xval $yval]
	}
    } 
    close $fid
    catch {busy release $rwin}
}

proc shplot:export_scatter_cmd {rwin {file {}}} {
    global shplot
    if {$shplot($rwin,curdataset) == ""} {
	dialog .export "Export Error" \
	    "Must load a dataset before you can export data from it" \
	    error 0 Dismiss 
	return
    }
    if {$file == ""} {
	set types {
	    {{Misc Data Files}		{.dat}}
	    {{SHADOW Workspace Files}	{.ws}}
	    {{SHADOW Namelist Files}	{start.*}}
	    {{SHADOW Source Image}	{begin.dat}}
	    {{SHADOW Image Files}	{star.*}}
	    {{SHADOW Image Files}	{mirr.*}}
	    {{All Files}		*}
	}
        set file [tk_getSaveFile \
	    -parent $rwin \
	    -title "Export SHADOW scatter data to file" \
	    -initialfile "scatter.dat" \
	    -defaultextension ".dat" \
	    -filetypes $types \
        ]
	set file [string trim $file]
	if {[string length $file] != 0} {
	    shplot:_export_scatter $rwin $file
	}
    }
}

####################### Menubar callbacks ################################

# This command is called whenever the background of the grid needs to
# be reformatted. The x1, y1, x2, y2 sprcifies the four corners of the area
# that needs to be reformatted.
#
proc shplot:info:gformat {w area x1 y1 x2 y2} {
    global margin
    set bg(s-margin) gray65
    set bg(x-margin) gray65
    set bg(y-margin) gray65
    set bg(main)     gray20

    case $area {
	main {
	    for {set y [expr ($y1/2) * 2]} {$y <= $y2} {incr y 2} {
		$w format border $x1 $y $x2 $y \
		    -relief flat -filled 1\
		    -bd 0 ;#-bg #80b080 -selectbackground #80b0ff
	    }
	    $w format grid $x1 $y1 $x2 $y2 \
		-relief raised -bd 1 -bordercolor $bg($area) -filled 0 -bg red\
		-xon 1 -yon 1 -xoff 0 -yoff 0 -anchor se
	}
	y-margin {
	    $w format border $x1 $y1 $x2 $y2 \
		-fill 1 -relief raised -bd 1 -bg $bg($area) \
		-selectbackground gray80
	}

	default {
	    $w format border $x1 $y1 $x2 $y2 \
		-filled 1 \
		-relief raised -bd 1 -bg $bg($area) \
		;#-selectbackground gray80
	}
    }
}

proc shplot:info:make {w dataset which_rays} {
    set headers {
	"NpCol"
	"Parameter"
	"Minimum"
	"Maximum"
	"Center"
	"Std. Dev."
    }

    global shplot
    set data ""
    foreach column "1 2 3 4 5 6 11 20" {
        set coldata [$dataset info column $column $which_rays]
	lappend data $coldata
    }

    # Create the grid
    #
    tixScrolledGrid $w.g -bd 0
    pack $w.g -expand yes -fill both -padx 3 -pady 3

    set grid [$w.g subwidget grid]
    $grid config -formatcmd "shplot:info:gformat $grid"

    # Set the size of the columns
    #
    $grid size col 0 -size auto
    $grid size col 1 -size auto
    $grid size col 2 -size auto
    $grid size col 3 -size auto
    $grid size col 4 -size auto
    $grid size col 5 -size auto
    $grid size col 6 -size auto

    # set the default size of the column and rows. these sizes will be used
    # if the size of a row or column has not be set via the "size col ?"
    # command
    $grid size col default -size 5char
    $grid size row default -size 1.1char -pad0 3

    set margin [tixDisplayStyle text -refwindow $grid   \
	-anchor c -padx 3 -font [tix option get bold_font]]
    set name [tixDisplayStyle text  -refwindow $grid  \
	-anchor w]
    set number [tixDisplayStyle text  -refwindow $grid  \
	-anchor e]

    # Create the headers
    #
    set x 1
    foreach h $headers {
	$grid set $x 0 -itemtype text -text $h -style $margin
	incr x
    }

    set i         1
    foreach line $data {
	set col    [lindex $line 0]
	set npcol  [lindex $line 1]
	set par    [lindex $line 2]
	set min    [lindex $line 3]
	set max    [lindex $line 4]
	set center [lindex $line 5]
	set stddev [lindex $line 6]

	$grid set 0 $i -itemtype text -style $margin -text $col
	$grid set 1 $i -itemtype text -style $number -text $npcol
	$grid set 2 $i -itemtype text -style $name -text $par
	$grid set 3 $i -itemtype text -style $number -text $min
	$grid set 4 $i -itemtype text -style $number -text $max
	$grid set 5 $i -itemtype text -style $number -text $center
	$grid set 6 $i -itemtype text -style $number -text $stddev

	incr i
    }
}

proc shplot:show_info {rwin {dataset {}}} {
    global shplot
    set w $shplot($rwin,info_w)
    catch {destroy $w}
    set dataset [string trim $dataset]
    if {[string length $dataset] == 0} {
        set dataset $shplot($rwin,curdataset)
    }
    set dataset [string trim $dataset]
    if {[string length $dataset] == 0} {
	set info "No dataset loaded."
	dialog .image_info "Image Info" "$info" {} 0 Dismiss
	return
    }

    toplevel $w -class Info
    wm title $w "Image Info"
    shplot:info:make $w $dataset $shplot($rwin,rays)
}

proc shplot:load {rwin file} {
    global shplot

    # for now assume that we only have one dataset loaded.
    # set cnt [expr [llength $shplot(datasets)]]
    # set dataset dataset#${cnt}
    catch {shdata delete $shplot($rwin,curdataset)}
    set dataset dataset,$rwin
    shdata create $dataset -load $file
    $dataset compute minmax
    $dataset select $shplot($rwin,rays)
    set shplot($rwin,curdataset) $dataset
    lappend shplot(datasets) $dataset
    shplot:show_info $rwin $dataset
}

proc shplot:_load_image {rwin file} {
    global shplot
    if [catch {shplot:load $rwin [cvt_filename_to_tcl $file]} msg] {
	error "Error reading SHADOW data file \"$file\" ($msg)?"
    }
    shplot:misc:add_file_to_title $rwin $file
    set shplot($rwin,curfile) $file
    catch {shplot:graph:plot $rwin}
}

proc shplot:load_image_cmd {rwin} {
    global shplot
    # globbing does not work on windows as on Unix
    global tcl_platform
    set platform $tcl_platform(platform)
    if {$platform == "unix"} {
	set types {
	    {{SHADOW Source Image}	{begin.dat}}
	    {{SHADOW Image Files}	{star.\[0-9\]\[0-9\]}}
	    {{SHADOW Image Files}	{mirr.\[0-9\]\[0-9\]}}
	    {{SHADOW Workspace Files}	{.ws}}
	    {{SHADOW Namelist Files}	{start.\[0-9\]\[0-9\]}}
	    {{Misc Data Files}		{.dat}}
	    {{All Files}		*}
	}
    } else {
	set types {
	    {{SHADOW Source Image}	{begin.dat}}
	    {{SHADOW Image Files}	{star.*}}
	    {{SHADOW Image Files}	{mirr.*}}
	    {{SHADOW Workspace Files}	{.ws}}
	    {{SHADOW Namelist Files}	{start.*}}
	    {{Misc Data Files}		{.dat}}
	    {{All Files}		*}
	}
    }
    set file [tk_getOpenFile \
	-parent $rwin \
	-title "Load SHADOW Image Data From File" \
	-initialfile "" \
	-filetypes $types \
    ]
    if {$file != ""} {
	shplot:_load_image $rwin $file
    }
}

proc shplot:plot_cmd {rwin} {
    shplot:graph:plot $rwin
}

proc shplot:print_image_cmd {rwin} {
    shplot:graph:print $rwin
}

proc shplot:exec_tcl_command {w} {
    set cmd [$w get]
    # set_msg "Executing command \"$cmd\" ..."
    if {[catch [list uplevel #0 $cmd] msg]} {
	dialog .exec {Execute Command} \
	    "Error executing XMenu(Tcl) command \"$cmd\"\n($msg)" \
	    "error" 0 Dismiss
	# set_msg "Executing command \"$cmd\" ... ERROR!"
    } else {
	if {$msg != ""} {
	    dialog .exec {Execute Command} "$msg" "info" 0 Dismiss
	}
	# set_msg "Executing command \"$cmd\" ... done"
    }
    $w delete 0 end
}


####################### PlotOpts callbacks ###############################

proc shplot:choose_axis {rwin axis value} {
    global shplot
    shplot:vputs "shplot:choose_axis: $rwin,$axis ==> $value"
    set shplot($rwin,$axis) $value
    shplot:vputs "shplot($rwin,$axis) ==> $value"
}

proc shplot:choose_rays {rwin ray value} {
    global shplot
    if {$value == 1} {
	shplot:vputs "shplot:choose_rays: ==> $rwin,$ray $value"
	set shplot($rwin,rays) $ray
	shplot:graph:replot $rwin
    }
}

proc shplot:choose_plots {rwin plot show} {
    global shplot
    shplot:vputs "shplot:choose_plots: ==> $rwin,$plot $show"
    set shplot($rwin,plot_${plot}) $show
    shplot:graph:replot $rwin
}

proc shplot:choose_scale {rwin scale value} {
    global shplot
    if {$value == 1} {
	shplot:vputs "shplot:choose_scale: ==> $rwin,$scale $value"
	set shplot($rwin,scale) $scale
	shplot:graph:replot $rwin
    }
}

######################## GUI routines ####################################

proc shplot:GUI:topmenu {rwin menu_name} {
    global shplot shplot_prefs

    lappend menu_names $menu_name.mFile
    # build widget $menu_name.mFile
    menubutton $menu_name.mFile \
	-background {LightGray} \
	-foreground {black} \
	-menu "$menu_name.mFile.m" \
	-text {File} \
	-underline {0}

    # build widget $menu_name.mFile.m
    menu $menu_name.mFile.m \
	-background {LightGrey} \
	-foreground {black} \
	-tearoff 0

    $menu_name.mFile.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-command "shplot:load_image_cmd $rwin" \
	-label {Load ...} \
	-underline {-1}

    $menu_name.mFile.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-command "shplot:print_image_cmd $rwin" \
	-label {Print ...} \
	-underline {-1}

    $menu_name.mFile.m add separator

    # ============================================== 

    # build cascade menu for importing/export shadow namelist files
    $menu_name.mFile.m add cascade \
	-menu "$menu_name.mFile.m.mImport" \
	-label {Import Data} \
	-underline {-1}

    # build widget $menu_name.mFile.m.mImport
    menu $menu_name.mFile.m.mImport \
	-background {LightGrey} \
	-foreground {black} \
	-tearoff 0

    $menu_name.mFile.m.mImport add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Scatter ...} \
	-state disabled \
	-underline {-1}

    $menu_name.mFile.m.mImport add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Histogram ...} \
	-state disabled \
	-underline {-1}

    # build cascade menu for importing/export shadow namelist files
    $menu_name.mFile.m add cascade \
	-menu "$menu_name.mFile.m.mExport" \
	-label {Export Data} \
	-underline {-1}

    # build widget $menu_name.mFile.m.mExport
    menu $menu_name.mFile.m.mExport \
	-background {LightGrey} \
	-foreground {black} \
	-tearoff 0

    $menu_name.mFile.m.mExport add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Scatter ...} \
	-command "shplot:export_scatter_cmd $rwin" \
	-underline {-1}

    $menu_name.mFile.m.mExport add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Side Histogram ...} \
	-command "shplot:export_histogram_cmd $rwin histo_s" \
	-underline {-1}

    $menu_name.mFile.m.mExport add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Top Histogram ...} \
	-command "shplot:export_histogram_cmd $rwin histo_t" \
	-underline {-1}

    $menu_name.mFile.m add separator

    $menu_name.mFile.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-command "shplot:new_window_cmd" \
	-label {New Window} \

    $menu_name.mFile.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-command "shplot:close_cmd $rwin" \
	-label {Close Window} \
	-underline {1}

    # only toplevel "." gets the exit command. this makes sure that if
    # we're running under SHADOW GUI, we don't exit the entire GUI when
    # closing the Plot window.
    if ![string compare $rwin "."] {
	$menu_name.mFile.m add separator
	$menu_name.mFile.m add command \
	    -activebackground {SteelBlue2} \
	    -background {LightGray} \
	    -command "shplot:exit_cmd $rwin" \
	    -label {Exit} \
	    -underline {1} \
	    -accelerator {Ctrl-x}
    }

    lappend menu_names $menu_name.mPlot
    # build widget $menu_name.mPlot
    menubutton $menu_name.mPlot \
	-background {LightGray} \
	-foreground {black} \
	-menu "$menu_name.mPlot.m" \
	-text {Plot} \
	-underline {0}

    # build widget $menu_name.mPlot.m
    menu $menu_name.mPlot.m \
	-background {LightGrey} \
	-foreground {black} \
	-tearoff 0

    $menu_name.mPlot.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Plot} \
	-command "shplot:plot_cmd $rwin" \
	-underline {-1}

    $menu_name.mPlot.m add separator

    $menu_name.mPlot.m add checkbutton \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Scatter plot} \
	-variable shplot(plot_scatter) \
	-command "shplot:show_plot_cmd $rwin scatter" \
	-underline {-1}

    $menu_name.mPlot.m add checkbutton \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Top Histogram} \
	-variable shplot(plot_histo_t) \
	-command "shplot:show_plot_cmd $rwin histo_t" \
	-underline {-1}

    $menu_name.mPlot.m add checkbutton \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Side Histogram} \
	-variable shplot(plot_histo_s) \
	-command "shplot:show_plot_cmd $rwin histo_s" \
	-underline {-1}

    $menu_name.mPlot.m add checkbutton \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Text Information} \
	-variable shplot(plot_info) \
	-command "shplot:show_plot_cmd $rwin info" \
	-underline {-1}

    lappend menu_names $menu_name.mOptions
    # build widget $menu_name.mOptions
    menubutton $menu_name.mOptions \
	-background {LightGray} \
	-foreground {black} \
	-menu "$menu_name.mOptions.m" \
	-text {Options} \
	-underline {0}

    # build widget $menu_name.mOptions.m
    menu $menu_name.mOptions.m \
	-background {LightGrey} \
	-foreground {black} \
	-tearoff 0

    $menu_name.mOptions.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Refresh Plots} \
	-command "shplot:plot_cmd $rwin" \
	-underline {-1}

    $menu_name.mOptions.m add checkbutton \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Verbose Mode} \
	-variable shplot(verbose) \
	-underline {-1}

    global tcl_platform
    if ![string compare $tcl_platform(platform) unix] {
	$menu_name.mOptions.m add checkbutton \
	    -activebackground {SteelBlue2} \
	    -background {LightGray} \
	    -label {Strict Motif} \
	    -variable tk_strictMotif \
	    -onvalue 1 -offvalue 0 \
	    -underline {-1}
    }

    $menu_name.mOptions.m add checkbutton \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Show Grid} \
	-variable shplot(plot_grid) \
	-command "shplot:plot_grid_cmd $rwin" \
	-underline {-1}

    $menu_name.mOptions.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Change directory} \
	-state disabled \
	-command "shplot:chdir_cmd $rwin" \
	-underline {-1}

    $menu_name.mOptions.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Reread Data} \
	-state disabled \
	-command "shplot:reread_plots $rwin" \
	-underline {-1}

    $menu_name.mOptions.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Show Info} \
	-command "shplot:show_info $rwin" \
	-underline {-1}

    $menu_name.mOptions.m add separator

    # build cascade menu for Preferences
    $menu_name.mOptions.m add cascade \
	-menu "$menu_name.mOptions.m.mPreferences" \
	-label {Preferences} \
	-underline {-1}

    # build cascaded menu for $menu_name.mDelete
    menu $menu_name.mOptions.m.mPreferences \
	-background {LightGrey} \
	-foreground {black} \
	-tearoff 0

    $menu_name.mOptions.m.mPreferences add checkbutton \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Show Plot at Startup} \
	-state disabled \
	-variable shplot_prefs(show_plot_at_startup) \
	-underline {-1}

    $menu_name.mOptions.m.mPreferences add checkbutton \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Show Info at Startup} \
	-state disabled \
	-variable shplot_prefs(show_info_at_startup) \
	-underline {-1}

    $menu_name.mOptions.m.mPreferences add checkbutton \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Show Console Window} \
	-variable shplot_prefs(show_console) \
	-command "shplot:show_console_cmd" \
	-underline {-1}

    $menu_name.mOptions.m.mPreferences add separator

    $menu_name.mOptions.m.mPreferences add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Reload preferences} \
	-state disabled \
	-command "shplot:load_prefs_cmd $rwin" \
	-underline {-1}

    $menu_name.mOptions.m.mPreferences add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Save preferences} \
	-state disabled \
	-command "shplot:save_prefs_cmd $rwin" \
	-underline {-1}

    $menu_name.mOptions.m.mPreferences add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-label {Reset to defaults} \
	-state disabled \
	-command "shplot:reset_prefs_cmd $rwin" \
	-underline {-1}

    lappend menu_names $menu_name.mHelp
    # build widget $menu_name.mHelp
    menubutton $menu_name.mHelp \
	-background {LightGray} \
	-foreground {black} \
	-menu "$menu_name.mHelp.m" \
	-text {Help} \
	-underline {0}

    # build widget $menu_name.mHelp.m
    menu $menu_name.mHelp.m \
	-background {LightGrey} \
	-foreground {black} \
	-tearoff 0

    $menu_name.mHelp.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-command "shplot:about_cmd $rwin" \
	-label {About} \
	-state disabled \
	-underline {0}

    $menu_name.mHelp.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-command "shplot:about_author_cmd $rwin" \
	-label {Author} \
	-state disabled \
	-underline {0}

    $menu_name.mHelp.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-command "shplot:help_on_topmenu_cmd $rwin" \
	-label {On pulldown menu} \
	-state disabled \
	-underline {3}

    $menu_name.mHelp.m add command \
	-activebackground {SteelBlue2} \
	-background {LightGray} \
	-command "shplot:help_on_commands_cmd $rwin" \
	-label {On Tcl commands} \
	-state disabled \
	-underline {7}

    # pack widget $menu_name
    pack append $menu_name \
	$menu_name.mFile {left frame center} \
	$menu_name.mOptions {left frame center} \
	$menu_name.mHelp {right frame center}

    focus $menu_name

    #
    # install the global bindings (accelerators).
    #
    bind all	<Control-x>	"shplot:exit_cmd $rwin"
    bind Entry	<Control-x>	"shplot:exit_cmd $rwin"
    bind Text	<Control-x>	"shplot:exit_cmd $rwin"

    return $menu_name
}

proc shplot:GUI:make_console_window {rwin w} {
    global shplot
    label $w.label -text "Console:: "
    entry $w.entry -relief sunken
    bind $w.entry <Return> {shplot:exec_tcl_command %W}
    pack $w.label -side left -anchor w -expand 0 
    pack $w.entry -side left -anchor w -expand 1 -fill x
    return $w
}

proc shplot:GUI:axis_choices {rwin w} {
    global shplot
    set name [tixOptionName $w]
    option add *$name*TixOptionMenu*label.anchor e

    tixOptionMenu $w.xmenu -label "X axis: "  \
	-disablecallback true -command [list shplot:choose_axis $rwin col_x]

    tixOptionMenu $w.ymenu -label "Y axis: " \
	-disablecallback true -command [list shplot:choose_axis $rwin col_y]

    foreach menu "xmenu ymenu" {
	set cnt 1
        foreach axis "X Y Z X' Y' Z'" {
	    $w.${menu} add command $cnt -label "$axis  "
	    incr cnt
	}
    }

    $w.xmenu config -value $shplot($rwin,col_x)
    $w.ymenu config -value $shplot($rwin,col_y)
    $w.xmenu config -disablecallback false
    $w.ymenu config -disablecallback false

    pack $w.xmenu -padx 5 -pady 3 -fill y -side top
    pack $w.ymenu -padx 5 -pady 3 -fill y -side top

    button $w.apply -text "Apply" -command "shplot:graph:plot $rwin"
    pack $w.apply -padx 5 -pady 3 -fill x -side bottom
}

proc shplot:GUI:ray_choices {rwin w} {
    global shplot
    set name [tixOptionName $w]
    option add *$name*TixSelect*label.anchor c
    option add *$name*TixSelect*orientation vertical
    option add *$name*TixSelect*labelSide top

    tixSelect $w.rays -label "" -radio true \
	-disablecallback true -command [list shplot:choose_rays $rwin]

    $w.rays add good -text Good
    $w.rays add lost -text Lost
    $w.rays add all  -text All

    $w.rays config -value $shplot($rwin,rays)
    $w.rays config -disablecallback false

    set shplot($rwin,ray_choices_cmd) "$w.rays config -value"

    pack $w.rays -side left -padx 5 -pady 3 -fill x
}

proc shplot:GUI:plot_choices {rwin w} {
    global shplot
    set name [tixOptionName $w]
    option add *$name*TixSelect*label.anchor c
    option add *$name*TixSelect*orientation vertical
    option add *$name*TixSelect*labelSide top

    tixSelect $w.plots -label "" -allowzero true -radio false \
	-disablecallback true -command [list shplot:choose_plots $rwin]

    $w.plots add scatter -text "Scatter Plot"
    $w.plots add histo_t -text "Top Histogram"
    $w.plots add histo_s -text "Side Histogram"
    $w.plots add info    -text "Image Info"

    set plots ""
    foreach plot "scatter histo_t histo_s info" {
	if $shplot($rwin,plot_$plot) {lappend plots $plot}
    }
    $w.plots config -value $plots
    $w.plots config -disablecallback false

    set shplot($rwin,plot_choices_cmd) "$w.plots config -value"

    pack $w.plots -side left -padx 5 -pady 3 -fill x
}

proc shplot:GUI:scale_choices {rwin w} {
    global shplot
    set name [tixOptionName $w]
    option add *$name*TixSelect*label.anchor c
    option add *$name*TixSelect*orientation vertical
    option add *$name*TixSelect*labelSide top

    tixSelect $w.scale -label "" -radio true \
	-disablecallback true -command [list shplot:choose_scale $rwin]

    $w.scale add auto  -text "Automatic"
    $w.scale add cart  -text "Cartesian"
    $w.scale add fill  -text "Fill"
    $w.scale add user  -text "User-defined" -state disabled

    $w.scale config -value $shplot($rwin,scale)
    $w.scale config -disablecallback false

    set shplot($rwin,scale_choices_cmd) "$w.scale config -value"

    pack $w.scale -side left -padx 5 -pady 3 -fill x
}

proc shplot:GUI:plotopts {rwin w} {

    tixLabelFrame $w.axis  -label "Columns"
    tixLabelFrame $w.rays  -label "Rays"
    tixLabelFrame $w.plots -label "Plots"
    tixLabelFrame $w.scale -label "Scaling"

    shplot:GUI:axis_choices  $rwin [$w.axis subwidget frame]
    shplot:GUI:ray_choices   $rwin [$w.rays subwidget frame]
    shplot:GUI:plot_choices  $rwin [$w.plots subwidget frame]
    shplot:GUI:scale_choices $rwin [$w.scale subwidget frame]

    #pack $w.axis  -side top -padx 5 -pady 3 -fill x
    #pack $w.rays  -side top -padx 5 -pady 3 -fill x
    #pack $w.plots -side top -padx 5 -pady 3 -fill x
    #pack $w.scale -side top -padx 5 -pady 3 -fill x

    #grid columnconfig $w 0 -weight 1 -minsize 0
    #grid rowconfig $w 0 -weight 1 -minsize 0

    grid $w.axis -row 0 -column 0 -columnspan 1 -rowspan 1 -sticky news
    grid $w.rays -row 1 -column 0 -columnspan 1 -rowspan 1 -sticky news
    grid $w.plots -row 2 -column 0 -columnspan 1 -rowspan 1 -sticky news
    grid $w.scale -row 3 -column 0 -columnspan 1 -rowspan 1 -sticky news
}

#
# The BLT graphs are placed into a canvas (so we can print multiple plots),
# and this canvas is then placed inside of tixScrolledWindow.
#
proc shplot:GUI:old_plotbody {w} {
    global shplot shplot_prefs

    set scrolled [tixScrolledWindow ${w}.scrolled \
        -width $shplot(plot_body_width) \
	-height $shplot(plot_body_height) \
	-relief sunken -bd 2 \
	-expand 1]

    set wparent [$scrolled subwidget window]
    set shplot(plot_master_w) [canvas ${wparent}.c \
        -width $shplot(plot_body_width) -height $shplot(plot_body_height)]

    pack $shplot(plot_master_w)
    pack $scrolled
}

proc shplot:GUI:plotbody {rwin w} {
    global shplot shplot_prefs

    scrollbar ${w}.hscroll -orient horizontal \
        -command "${w}.c xview"

    scrollbar ${w}.vscroll -orient vertical \
        -command "${w}.c yview"

    canvas ${w}.c \
        -xscrollcommand "${w}.hscroll set" \
        -yscrollcommand "${w}.vscroll set" \
        -width $shplot(plot_body_width) \
	-height $shplot(plot_body_height) \
        -scrollregion [list \
	    0 0 $shplot(plot_body_width) $shplot(plot_body_height)]
    
    set shplot($rwin,plot_master_w) ${w}.c
    
    grid columnconfig $w 0 -weight 1 -minsize 0
    grid rowconfig $w 0 -weight 1 -minsize 0
    grid ${w}.c -column 0 -row 0 \
        -rowspan 1 -columnspan 1 -sticky news
    grid ${w}.vscroll -column 1 -row 0 \
        -rowspan 1 -columnspan 1 -sticky news
    grid ${w}.hscroll -column 0 -row 1 \
        -rowspan 1 -columnspan 1 -sticky news
}

proc shplot:GUI:make {rwin} {
    global shplot

    wm title $rwin $shplot($rwin,win_title)
    wm protocol $rwin WM_SAVE_YOURSELF "shplot:exit_cmd $rwin"
    wm protocol $rwin WM_DELETE_YOURSELF "shplot:exit_cmd $rwin"

    set topmenu    [frame ${rwin}.topmenu -relief raised -bd 1]
    set consle_w_stub [frame ${rwin}.consle_w_stub]
    set body       [frame ${rwin}.body]
    set plotopts   [frame ${body}.plotopts -relief sunken -bd 1]
    set plotbody   [frame ${body}.plotbody -relief sunken -bd 1]

    set shplot($rwin,consle_w_stub) $consle_w_stub
    set shplot($rwin,consle_w) \
	[shplot:GUI:make_console_window $rwin [frame ${rwin}.consle_w -bd 2]]

    shplot:GUI:topmenu $rwin $topmenu
    shplot:GUI:plotopts $rwin $plotopts
    shplot:GUI:plotbody $rwin $plotbody

    grid $plotopts -row 0 -column 0 -sticky nw
    grid $plotbody -row 0 -column 1 -sticky news
    grid columnconfigure $body 1 -weight 1
    grid rowconfigure $body 0 -weight 1

    pack $topmenu -side top -fill x ;# -expand 1
    pack $consle_w_stub -side top -fill x ;# -expand 1
    pack $body -side top -expand 1 -fill both

    lappend shplot(toplevels) $rwin

    shplot:show_console_cmd
    update
}

################################ Misc #####################################

proc shplot:misc:add_file_to_title {rwin file} {
    global shplot
    if {$file == ""} {
	set filepart "\[No dataset loaded\]"
    } else {
	set filepart "\[$file\]"
    }
    wm title $rwin "$shplot($rwin,win_title)   $filepart"
}

################################ Main #####################################

#
# parse the command line and initialize the interface etc
#
proc shplot:main {{rwin .}} {
    global shplot
    if [string compare $rwin "."] {		;# need toplevel
	toplevel $rwin -class ShadowPlot
    }

    shplot:init:env $rwin
    shplot:init:globals $rwin
    shplot:parse_args $rwin
    shplot:init:preferences $rwin
    shplot:init:fonts $rwin
    shplot:GUI:make $rwin
    shplot:graph:make $rwin
    shplot:init:startup $rwin
    set shplot(initialized) 1
}

######################## Start program ####################################
#

#
# DO NOT call shplot:main if running under SHADOW GUI!
#
if ![info exists gvars] {
    shplot:main
}
