#
# commands.tcl: Various command and callbacks used in the GUI.
#
# ------------------------------------------------
# Mumit Khan <khan@xraylith.wisc.edu>
# Center for X-ray Lithography
# University of Wisconsin-Madison
# 3731 Schneider Dr., Stoughton, WI, 53589
# ------------------------------------------------
#
# Copyright (c) 1994-1996 Mumit Khan
#
#


#----------------------------------------------------------------------#
#
# FILE menu callbacks and helpers.
#
#----------------------------------------------------------------------#

#
# HELPER for load_source_cmd.
#
proc do_load_source {file} {
    if {[get_source] == ""} {
	add_src
    }

    set_msg "Loading SOURCE namelist file \"$file\"..."
    if {[catch "beamline load source $file" msg]} {
	dialog .load_error {Load source} \
	    "ERROR opening SOURCE namelist file \"$file\. ($msg)" \
	    "error" 0 Dismiss
	set_msg "Loading SOURCE namelist file \"$file\"... ERROR"
	return 1
    }
    edit_src
    set_msg "Loading SOURCE namelist file \"$file\"... done."
    return 0
}

#
# LOAD_SOURCE_CMD: loads a SHADOW source namelist.
#
proc load_source_cmd {} {
    global gvars gprefs

    set_msg "Loading SOURCE namelist file..."

    # FIXME: For newer tk releases >= 4.2
    global tk_version
    if {$tk_version < 4.2} {
	set dialog [tix filedialog]
	set fsbox [$dialog subwidget fsbox]
	$fsbox configure -pattern "*.00" -value ""
	$dialog config -title "Load a SOURCE from file" \
	    -command "do_load_source"
	$dialog popup
    } else {
	# globbing does not work on windows as on Unix
	global tcl_platform
	set platform $tcl_platform(platform)
	if {$platform == "unix"} {
	    set types {
		{{SHADOW SOURCE Namelist}	{.00}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	} else {
	    set types {
		{{SHADOW SOURCE Namelist}	{.00}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	}
	set file [tk_getOpenFile \
	    -filetypes $types \
	    -title "Load a SOURCE from file"
	]
	if {$file != ""} {
	    do_load_source $file
	}
    }
    return 0
}

#
# HELPER for load_oe_cmd.
#
proc do_load_oe {file} {
    #
    # CHECK/TODO: do sanity check.
    #
    set cur_oe [get_current_oe]
    if {[catch "open $file r" fin] != 0} {
	dialog .load_error {Load OE} \
	    "ERROR opening OE $cur_oe namelist file \"$file\." \
	    "error" 0 Dismiss
	return 1
    }
    close $fin
    set_msg "Loading OE $cur_oe namelist file \"$file\"..."

    if {[catch "beamline load oe $cur_oe $file" msg]} {
	dialog .load_error {Load OE} \
	    "ERROR loading OE $cur_oe namelist file \"$file\".\n($msg)" \
	    "error" 0 Dismiss
	set_msg "Loading OE $cur_oe namelist file \"$file\"... ERROR."
	return 1
    }

    set_msg "Loading OE $cur_oe namelist file \"$file\"... done."
    fix_oe_filenames
    edit_oe $cur_oe
    return 0
}

#
# LOAD_OE_NML: loads a OE namelist.
#

proc load_oe_cmd {} {
    global gvars gprefs

    set cur_oe [get_current_oe]
    if {$cur_oe == 0} {
	dialog .load_oe {}  \
	    "Not editing an OE currently. Switch to OE menu first." \
	    error 0 Dismiss
	set_msg "Loading OE namelist file...cancelled."
	return 1
    }

    set_msg "Loading OE $cur_oe namelist file..."

    # FIXME: For newer tk releases >= 4.2
    global tk_version
    if {$tk_version < 4.2} {
	set dialog [tix filedialog]
	set fsbox [$dialog subwidget fsbox]
	$fsbox configure -pattern "*.[0-9][1-9]" -value ""
	$dialog config -title "Load an OE from file" \
	    -command "do_load_oe"
	$dialog popup
    } else {
	# globbing does not work on windows as on Unix
	global tcl_platform
	set platform $tcl_platform(platform)
	if {$platform == "unix"} {
	    set types {
		{{SHADOW OE Namelist}		{.\[0-9\]\[1-9\]}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	} else {
	    set types {
		{{SHADOW OE Namelist}		{start.*}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	}
	set file [tk_getOpenFile \
	    -filetypes $types \
	    -title "Load an OE from file"
	]
	if {$file != ""} {
	    do_load_oe $file
	}
    }

    return 0
}

#
# HELPER for load_system_cmd.
#
proc do_load_system {filepath} {
    global gvars
    #
    # since the OE namelist filenames are relative to the directory where
    # the systemfile is located usually, must change directory to it
    # first.
    #
    set save_curdir [pwd]
    set directory [file dirname $filepath]
    if [catch "do_chdir $directory" msg] {
	dialog .load_sys {}  \
	    "$msg" \
	    error 0 Dismiss
	set_msg "Loading SYSTEM file...cancelled."
	return 1
    }

    set file [file tail $filepath]
    if {![file readable $file] || ![file isfile $file]} {
	dialog .load_sys {}  \
	    "SYSTEMFILE $filepath either does not exist or unredable." \
	    error 0 Dismiss
	set_msg "Loading SYSTEM file...cancelled."
	do_chdir $save_curdir
	return 1
    }

    set_msg "loading SYSTEM from \"$directory\"..."
    delete_all_oe_cmd
    if {[catch "beamline load system $file" msg]} {
	dialog .load_sys {}  \
	    "ERROR loading SYSTEM from $file ($msg)." \
	    error 0 Dismiss
	set_msg "Loading SYSTEM file...cancelled."
	return 1
    }
    insert_all_oe_in_editbar
    set gvars(system_saved) 1

    set_msg "loading SYSTEM from \"$directory\"... done"
    do_chdir $save_curdir
    if {[get_num_oe] >= 1} {
	edit_oe 1
    }
    return 0
}

#
# LOAD_SYSTEM_CMD: loads a SHADOW beamline system.
#

proc load_system_cmd {} {
    global gvars

    set_msg "loading SYSTEM file..."

    # FIXME: For newer tk releases >= 4.2
    global tk_version
    if {$tk_version < 4.2} {
	set dialog [tix filedialog]
	set fsbox [$dialog subwidget fsbox]
	$fsbox configure -pattern "*.dat" -value ""
	$dialog config -title "Load SHADOW SYSTEM from file" \
	    -command "do_load_system"
	$dialog popup
    } else {
	# globbing does not work on windows as on Unix
	global tcl_platform
	set platform $tcl_platform(platform)
	if {$platform == "unix"} {
	    set types {
		{{SHADOW System File}		{systemfile.dat}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	} else {
	    set types {
		{{SHADOW System File}		{systemfile.dat}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	}
	set file [tk_getOpenFile \
	    -filetypes $types \
	    -title "Load SHADOW SYSTEM from file"
	]
	if {$file != ""} {
	    do_load_system $file
	}
    }
    return 0
}

#
# HELPER for save_source_cmd
#
proc do_save_source {file} {
    global gvars
    if {[catch "beamline store source $file" msg]} {
	    "ERROR saving SOURCE to \"$file\ ($msg)." \
	    "error" 0 Dismiss
	return 1
    }

    set gvars(source_saved) 1
    set_msg "Saving SOURCE to namelist file \"$file\"... done."
    return 0
}

#
# SAVE_SOURCE_CMD: saves a SHADOW beamline system.
#
proc save_source_cmd {} {
    global gvars gprefs
    #
    # make sure there is a source first
    #
    if {[get_source] == ""} {
	dialog .save_error {Save SOURCE} \
	    "ERROR: Must have a SOURCE to save. Please Add one." \
	    "error" 0 Dismiss
	return 1
    }

    set_msg "Saving SOURCE namelist file..."

    # FIXME: For newer tk releases >= 4.2
    global tk_version
    if {$tk_version < 4.2} {
	set dialog [tix filedialog]
	set fsbox [$dialog subwidget fsbox]
	$fsbox configure -pattern "*.00" -value "start.00"
	$dialog config -title "Save SOURCE to file" \
	    -command "do_save_source"
	$dialog popup
    } else {
	# globbing does not work on windows as on Unix
	global tcl_platform
	set platform $tcl_platform(platform)
	if {$platform == "unix"} {
	    set types {
		{{SHADOW SOURCE Namelist}	{.00}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	} else {
	    set types {
		{{SHADOW SOURCE Namelist}	{.00}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	}
	set file [tk_getSaveFile \
	    -filetypes $types \
	    -defaultextension ".00" \
	    -initialfile start.00 \
	    -title "Save SOURCE to file"
	]
	if {$file != ""} {
	    do_save_source $file
	}
    }
    return 0
}

#
# HELPER for save_oe_cmd
#
proc do_save_oe {file} {
    set cur_oe [get_current_oe]
    if {[catch "beamline store oe $cur_oe $file" msg]} {
	    "ERROR saving OE $cur_oe to \"$file\ ($msg)." \
	    "error" 0 Dismiss
	return 1
    }

    global gvars
    set gvars(oe_saved) 1
    set_msg "Saving OE $cur_oe to namelist file \"$file\"... done."
    return 0
}

#
# SAVE_OE_CMD: saves a SHADOW beamline system.
#
proc save_oe_cmd {} {
    global gvars gprefs
    #
    # make sure there is a oe first
    #
    set cur_oe [get_current_oe]
    if {$cur_oe == 0} {
	dialog .save_oe {}  \
	    "Not editing an OE currently. Switch to OE menu first." \
	    error 0 Dismiss
	set_msg "Saving OE namelist file...cancelled."
	return 1
    }

    set_msg "Saving OE namelist file..."

    # FIXME: For newer tk releases >= 4.2
    global tk_version
    if {$tk_version < 4.2} {
	set dialog [tix filedialog]
	set fsbox [$dialog subwidget fsbox]
	$fsbox configure -pattern "start.*" \
	    -value "start.[format %.2d $cur_oe]"
	$dialog config -title "Save OE $cur_oe to file" \
	    -command "do_save_oe"
	$dialog popup
    } else {
	# globbing does not work on windows as on Unix
	global tcl_platform
	set platform $tcl_platform(platform)
	if {$platform == "unix"} {
	    set types {
		{{SHADOW OE Namelist}		{.\[0-9\]\[1-9\]}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	} else {
	    set types {
		{{SHADOW OE Namelist}		{start.*}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	}
	set file [tk_getSaveFile \
	    -filetypes $types \
	    -defaultextension ".[format %.2d $cur_oe]" \
	    -initialfile "start.[format %.2d $cur_oe]" \
	    -title "Save OE $cur_oe to file"
	]
	if {$file != ""} {
	    do_save_oe $file
	}
    }

    return 0
}

#
# HELPER for save_system_cmd
#
proc do_save_system {filepath} {
    set_msg "saving SYSTEM file \"$filepath\"..."

    #
    # since the OE namelist filenames are relative to the directory where
    # the systemfile is located usually, must change directory to it
    # first.
    #
    set directory [file dirname $filepath]
    set save_curdir [pwd]
    if [catch "do_chdir $directory" msg] {
	dialog .save_sys {}  \
	    "$msg" \
	    error 0 Dismiss
	set_msg "Saving SYSTEM file...cancelled."
	return 1
    }

    set file [file tail $filepath]
    if {[catch "beamline store system $file" msg]} {
	dialog .save_system "Save system" \
	    "ERROR saving SYSTEMFILE \"$filepath\" ($msg)." {} 0 Dismiss
	set_msg "saving SYSTEM file \"$filepath\"... Cancelled"
	do_chdir $save_curdir
	return 1
    }

    global gvars
    set gvars(system_saved) 1

    do_chdir $save_curdir
    set_msg "saving SYSTEM file \"$filepath\"... done"
    return 0
}

#
# SAVE_SYSTEM_CMD: saves a SHADOW beamline system.
#
proc save_system_cmd {} {
    global gvars

    set_msg "saving SYSTEM file..."

    # FIXME: For newer tk releases >= 4.2
    global tk_version
    if {$tk_version < 4.2} {
	set dialog [tix filedialog]
	set fsbox [$dialog subwidget fsbox]
	$fsbox configure -pattern "*.dat" -value ""
	$dialog config -title "Save SHADOW SYSTEM to file" \
	    -command "do_save_system"
	$dialog popup
    } else {
	# globbing does not work on windows as on Unix
	global tcl_platform
	set platform $tcl_platform(platform)
	if {$platform == "unix"} {
	    set types {
		{{SHADOW System File}		{systemfile.dat}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	} else {
	    set types {
		{{SHADOW System File}		{systemfile.dat}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	}
	set file [tk_getSaveFile \
	    -filetypes $types \
	    -defaultextension .dat \
	    -initialfile "systemfile.dat" \
	    -title "Save SHADOW SYSTEM to file"
	]
	if {$file != ""} {
	    do_save_system $file
	}
    }
    return 0
}

proc exit_cmd {} {
    global gvars gprefs
    #
    # needs saving?
    #
    set_msg "Exiting SHADOW ..."
    if $gvars(modified) {
	set dosave [dialog .exit "Save Workspace" \
	    "Workspace not saved! Save now?" questhead 0 \
	    {"Save" "Discard" "Cancel"} \
	]
	if {$dosave == 0} {
	    save_state_cmd
	} elseif {$dosave == 2} {
	    set_msg "Exiting SHADOW ... cancelled"
	    return
	}
    }
    cleanup_and_exit 0
}

#----------------------------------------------------------------------#
#
# ADD SOURCE/OE/SCR menu callbacks and helpers.
#
#----------------------------------------------------------------------#


#
# called by routines that have already pre-processed the correctness
# of adding a source (eg., add_src_cmd).
#
proc add_src {} {
    global gvars gprefs
    beamline add source
    beamline tset source Source
    insert_source_in_editbar
    if $gprefs(edit_added_obj) {
	edit_src
    }
    editbar:highlight $gvars(editbar).toolbox.a [list source Source]
    toolbox:set_state $gvars(tools_w).toolbox.a System.Source disabled
    editbar_select_callback source
    set gvars(modified) 1
    set_msg "Adding SOURCE ... done."
}

proc add_src_cmd {} {
    global gvars gprefs
    set_msg "Adding SOURCE ..."
    if {[get_source] != ""} {
	dialog .info_d "Add Source" \
	    "The system already has a Source!" \
	    {} 0 Dismiss
	set_msg "Adding SOURCE ... cancelled."
    } else {
	return [add_src]
    }
    return 0
}

#
# Fix the OE inspector filenames to contain the right OE number. eg.,
# if PLOTXY is plotting star.03 and we insert a new OE, make this
# filename star.04 (only change the extension, keeping the root, eg.,
# star, the same as before).
#
proc fix_oe_inspector_filenames oe {
    set inspectors [beamline get inspectors oe $oe]
    set num_inspectors [llength $inspectors]
    set image_id [format %.2d $oe]
    set endfile end.${image_id}
    for {set ins 1} {$ins <= $num_inspectors} {incr ins} {
	set inspector_info [lindex $inspectors [expr $ins - 1]]
	set inspector [string toupper [lindex $inspector_info 0]]
	set id [lindex $inspector_info 1]
	global gtool2page
	catch "set inspector $gtool2page($inspector)"
	switch -exact -- $inspector {
	    PLOTXY {
		set imagefile \
		    [beamline vget inspector oe $oe $id PLX_INFILE]
		set root [lindex [split $imagefile .] 0]
		set imagefile ${root}.${image_id}
		beamline vset inspector oe $oe $id PLX_INFILE $imagefile
		#
		# WINDOWS BUG/FIXME:
		#
		if {[tix platform] == "windows"} {
		    beamline vset inspector oe $oe $id PLX_DEVICE "Postscript"
		}
	    }
	    MIRINFO {
		beamline vset inspector oe $oe $id MIR_INFILE $endfile
	    }
	    MINMAX {
		set imagefile \
		    [beamline vget inspector oe $oe $id MIN_INFILE]
		set root [lindex [split $imagefile .] 0]
		set imagefile ${root}.${image_id}
		beamline vset inspector oe $oe $id MIN_INFILE $imagefile
	    }
	    default {			;# includes MIRINFO and friends
		set_msg "fix_oe_inspector_files: BUG ($inspector)"
		puts stderr "fix_oe_inspector_files: BUG ($inspector)"
		return 
	    }
	}
    }
}

proc fix_screen_filenames oe {
    set num_scr [get_num_scr $oe]
    for {set scr 1} {$scr <= $num_scr} {incr scr} {
	set imagefile [format screen.%.2d%.2d $oe $scr]
	set inspectors [beamline get inspectors scr $oe $scr]
	set num_inspectors [llength $inspectors]
	for {set ins 1} {$ins <= $num_inspectors} {incr ins} {
	    set inspector_info [lindex $inspectors [expr $ins - 1]]
	    set inspector [lindex $inspector_info 0]
	    set id [lindex $inspector_info 1]
	    global gtool2page
	    catch "set inspector $gtool2page($inspector)"
	    switch -exact -- $inspector {
		PLOTXY {
		    beamline vset inspector scr $oe $scr $id PLX_INFILE \
		    	$imagefile
		    #
		    # WINDOWS BUG/FIXME:
		    #
		    if {[tix platform] == "windows"} {
			beamline vset inspector scr $oe $scr $id \
			    PLX_DEVICE "Postscript"
		    }
		}
		MINMAX {
		    beamline vset inspector scr $oe $scr $id MIN_INFILE \
		    	$imagefile
		}
		default {
		    set_msg "fix_oe_inspector_files: BUG ($inspector)"
		    puts stderr "fix_oe_inspector_files: BUG ($inspector)"
		    return 
		}
	    }
	}
    }
}

#
# fix_oe_filenames: We simply set the FILE_SOURCE variable for each OE to
# the appropriate BEGIN.DAT or STAR.* files.
#
proc fix_oe_filenames {} {
    set sourcefile begin.dat
    if {[get_source] != ""} {
	set sourcefile [beamline vget source file_source]
    }
    set num_oe [get_num_oe]
    for {set oe 1} {$oe <= $num_oe} {incr oe} {
	if {$oe == 1} {
	    set imagefile $sourcefile
	} else {
	    set imagefile star.[format %.2d [expr $oe - 1]]
	}
	beamline vset oe $oe file_source $imagefile
	fix_screen_filenames $oe
	fix_oe_inspector_filenames $oe
    }
    return 0
}

#
# called by routines that have already pre-processed the correctness
# of adding an OE (eg., add_oe_cmd).
#
proc add_oe {oe_id} {
    global gvars gprefs
    set_msg "Adding OE $oe_id ... "
    if {[catch "beamline add oe $oe_id" msg]} {
	dialog .info_d "Add OE" \
	    "ERROR: Cannot add OE #${oe_id}." \
	    {} 0 Dismiss
	return 1
    }
    fix_oe_filenames
    update_editbar_oe

    set gvars(system_saved) 0
    set_msg "Adding OE $oe_id ... done."

    editbar:highlight $gvars(editbar).toolbox.a [list oe $oe_id]
    editbar_select_callback oe $oe_id
    set gvars(modified) 1

    #
    # some linked filenames may have changed in the current edit window
    # (if any), so redraw just to be safe.
    #
    redraw_current_page_cmd

    if $gprefs(edit_added_obj) {
	edit_oe $oe_id
    }
}

#
# add_oe_cmd: If called from the TOP MENU, then ask for the OE number, but
# not when called from the Toolbox.
#
proc add_oe_cmd {{ask 0}} {
    global gvars gprefs
    set_msg "Adding OE ..."

    #
    # first guess what the new OE number is to be.
    #
    set cur_oe [get_oe_from_selection]
    if {$cur_oe == 0} {
	#
	# if not OE selected, try OE 1 if SOURCE is selected or right 
	# after the highest numbered OE currently in SYSTEM.
	#
        if {[string toupper [get_current_selection]] == "SOURCE"} {
	    set next_oe 1
	} else {
	    set num_oe [get_num_oe]
	    set next_oe [expr $num_oe + 1]
	}
    } else {
	set next_oe [expr $cur_oe + 1]
    }
    if $ask {
	set oe_id [dialog_num .oe_num "" "Enter OE number: " $next_oe]
	if {$oe_id == ""} {
	    set_msg "Adding OE ... cancelled."
	    return 1
	} elseif {$oe_id < 1} {
	    set_msg "Adding OE ... ERROR."
	    dialog .info_d "Add Source" \
		"ERROR: OE number must be >= 1." \
		{} 0 Dismiss
	    return 1

	}
	#
	# we should now normalize oe_id between 1 and num_oe + 1.
	#
	set highest_oe_id [expr [get_num_oe] + 1]
	if {$oe_id > $highest_oe_id} {
	    set oe_id $highest_oe_id
	}
    } else {				;# asked not to prompt, so guess
        set oe_id $next_oe
    }

    return [add_oe $oe_id]
}


#
# called by routines that have already pre-processed the correctness
# of adding a SCR (eg., add_scr_cmd).
#
proc add_scr {oe_id scr_id} {
    global gvars gprefs
    set_msg "Adding SCREEN $scr_id of OE $oe_id ..."
    if {[catch "beamline add scr $oe_id $scr_id" msg]} {
	dialog .info_d "Add Screen" \
	    [build_msg \
		"ERROR: Cannot add Screen <${scr_id}> of OE <${oe_id}>.\n" \
		($msg)
	    ] \
	    {} 0 Dismiss
	return 1
    }

    update_editbar_scr $oe_id
    set gvars(system_saved) 0

    set gvars(cur_scr) $scr_id
    set_msg "Adding Screen $scr_id of OE $oe_id...done."

    editbar:highlight $gvars(editbar).toolbox.a [list scr $oe_id $scr_id]
    editbar_select_callback scr $oe_id $scr_id
    set gvars(modified) 1
    #
    # some linked filenames may have changed in the current edit window
    # (if any), so redraw just to be safe.
    #
    redraw_current_page_cmd


    if $gprefs(edit_added_obj) {
	edit_scr $oe_id $scr_id
    }
}

#
# add_scr_cmd: If called from the TOP MENU, then ask for the OE/SCR numbers,
# but not when called from the Toolbox.
#
proc add_scr_cmd {{ask 0}} {
    global gvars gprefs
    set_msg "Adding SCREEN ..."

    if {[get_num_oe] == 0} {
	dialog .info_d "Add Screen" \
	    "ERROR: No OEs defined in the system to attach SCREEN to" \
	    "error" 0 Dismiss
	set_msg "Adding SCREEN ... cancelled."
	return 1
    }

    # first we try to guess where this SCR goes. If ask == 1, then we
    # prompt even if the guess is completely wrong. Otherwise, the guess
    # is where it goes, and if it's invalid, we show error.

    set2 [get_scr_from_selection] cur_oe cur_scr
    if {$cur_oe == 0} {
	if !$ask {
	    set cur_oe 1
	} else {
	    dialog .info_d "Add Screen" \
		"ERROR: Must select an OE in System to attach Screen to" \
		"error" 0 Dismiss
	    return 1
	}
    }

    #
    # if cur_scr == 0, it just means that we have to SCREENs currently
    # selected in the Editbar. When ask == 1, we should pick the next
    # highest number as the next screen, but when adding from the Toolbox,
    # (ie., ask == 0), select 1 as the next screen. Weird, but works.
    #
    if {$cur_scr == 0} {
	if $ask {
	    set num_scr [get_num_scr $cur_oe]
	    set next_scr [expr $num_scr + 1]
	} else {
	    set next_scr 1
	}
    } else {
	set next_scr [expr $cur_scr + 1]
    }

    if $ask {
	set2 [dialog_2_num .oe_num {} \
	    "Enter OE number: " $cur_oe \
	    "Enter Screen number: " $next_scr 2 \
	] oe_id scr_id

	if {$oe_id == "" || $scr_id == ""} {
	    set_msg "Adding SCREEN $scr_id of OE $oe_id ... cancelled."
	    return 1
	} elseif {$oe_id < 1  || $scr_id < 1} {
	    set_msg "Adding SCREEN $scr_id of OE $oe_id ... ERROR."
	    dialog .info_d "Add Screen" \
		"ERROR: Both Screen and OE numbers must be >= 1" "error" \
		0 Dismiss
	    return 1
	} elseif {$oe_id > [get_num_oe]} {
	    set_msg "Adding SCREEN $scr_id of OE $oe_id ... ERROR."
	    dialog .info_d "Add Screen" \
		"ERROR: OE $oe_id does not exist" \
		"error" 0 Dismiss
	    return 1
	}
	#
	# we should now normalize scr_id between 1 and num_scr + 1.
	#
	set highest_scr_id [expr [get_num_scr $oe_id] + 1]
	if {$scr_id > $highest_scr_id} {
	    set scr_id $highest_scr_id
	}
    } else {
	set oe_id $cur_oe
	set scr_id $next_scr
    }

    return [add_scr $oe_id $scr_id]
}

#
# add_source_inspector:
#
# Called by add_inspector to add a SOURCE inspector.
#
proc add_source_inspector {name args} {
    if {[get_source] == ""} {
	error "add_source_inspector: SOURCE does not exist."
    }

    global gvars gtool2page gpage2tool
    set inspector_info [beamline get inspectors source]
    set num_inspectors [llength $inspector_info]
    set id [expr $num_inspectors + 1]
    set imagefile [beamline vget source FILE_SOURCE]
    switch -exact -- $name {
	PLOTXY {
	    beamline add inspector source [set gpage2tool($name)] $id
	    editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector source PlotXY $id "Plot $id"]
	    beamline vset inspector source $id PLX_PLOT_WHAT SOURCE
	    beamline vset inspector source $id PLX_SPEC_FILE YES
	    beamline vset inspector source $id PLX_INFILE $imagefile
	    beamline vset inspector source $id PLX_COMMENTS "SOURCE"
	    #
	    # WINDOWS BUG/FIXME:
	    #
	    if {[tix platform] == "windows"} {
		beamline vset inspector source $id PLX_DEVICE "Postscript"
	    }
	}
	SRCINFO {
	    beamline add inspector source [set gpage2tool($name)] $id
	    editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector source SRCInfo $id "Info $id"]
	    beamline vset inspector source $id SRI_INFILE end.00
	    beamline vset inspector source $id SRI_TITLE ""
	    beamline vset inspector source $id SRI_COMMENTS ""
	}
	MINMAX {
	    beamline add inspector source [set gpage2tool($name)] $id
	    editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector source MinMax $id "MinMax $id"]
	    beamline vset inspector source $id MIN_INFILE $imagefile
	    beamline vset inspector source $id MIN_COMMENTS "Source image"
	}
	default {			;# includes MIRINFO and friends
	    dialog .info_d "Add Source Inspector" \
		"Cannot inspect SOURCE with $name. Sorry." \
		"error" 0 Dismiss
	    set_msg "Cannot inspector SOURCE with $name. Cancelled."
	    return
	}
    }
    editbar_select_callback inspector source $name $id
    set gvars(modified) 1
    #
    # some linked filenames may have changed in the current edit window
    # (if any), so redraw just to be safe.
    #
    redraw_current_page_cmd
}

#
# add_oe_inspector:
#
# Called by add_inspector to add an OE inspector.
#
proc add_oe_inspector {oe name args} {
    global gvars gtool2page gpage2tool

    if {$oe < 1 || $oe > [get_num_oe]} {
	error "add_oe_inspector: OE $oe does not exist."
    }

    set inspector_info [beamline get inspectors oe $oe]
    set num_inspectors [llength $inspector_info]
    set id [expr $num_inspectors + 1]
    set imagefile star.[format %.2d $oe]
    switch -exact -- $name {
	PLOTXY {
	    vputs "add_oe_inspector: \
		beamline add inspector oe $oe [set gpage2tool($name)] $id"
	    beamline add inspector oe $oe [set gpage2tool($name)] $id
	    vputs "editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector oe $oe PlotXY $id]"
	    editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector oe $oe PlotXY $id "PlotXY $id"]
	    beamline vset inspector oe $oe $id PLX_PLOT_WHAT OE
	    beamline vset inspector oe $oe $id PLX_SPEC_FILE YES
	    beamline vset inspector oe $oe $id PLX_INFILE $imagefile
	    beamline vset inspector oe $oe $id PLX_COMMENTS "OE $oe"
	    #
	    # WINDOWS BUG/FIXME:
	    #
	    if {[tix platform] == "windows"} {
		beamline vset inspector oe $oe $id PLX_DEVICE "Postscript"
	    }
	}
	MIRINFO {
	    vputs "add_oe_inspector: \
		beamline add inspector oe $oe [set gpage2tool($name)] $id"
	    beamline add inspector oe $oe [set gpage2tool($name)] $id
	    vputs "editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector oe $oe MirInfo $id]"
	    editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector oe $oe MirInfo $id "MirInfo $id"]
	    set endfile [format end.%.2d $oe]
	    beamline vset inspector oe $oe $id MIR_INFILE $endfile
	    beamline vset inspector oe $oe $id MIR_TITLE "OE $oe"
	    beamline vset inspector oe $oe $id MIR_COMMENTS ""
	}
	MINMAX {
	    vputs "add_oe_inspector: \
		beamline add inspector oe $oe [set gpage2tool($name)] $id"
	    beamline add inspector oe $oe [set gpage2tool($name)] $id
	    vputs "editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector oe $oe MinMax $id]"
	    editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector oe $oe MinMax $id "MinMax $id"]
	    beamline vset inspector oe $oe $id MIN_INFILE $imagefile
	    beamline vset inspector oe $oe $id MIN_COMMENTS "OE $oe"
	}
	default {			;# includes MIRINFO and friends
	    set_msg "Cannot attach $name to OE. Cancelled."
	    return 
	}
    }
    editbar_select_callback inspector oe $oe $name $id
    set gvars(modified) 1
    #
    # some linked filenames may have changed in the current edit window
    # (if any), so redraw just to be safe.
    #
    redraw_current_page_cmd

}

#
# add_scr_inspector:
#
# Called by add_inspector to add a SCR inspector.
#
proc add_scr_inspector {oe scr name args} {
    global gvars gtool2page gpage2tool
    set inspector_info [beamline get inspectors scr $oe $scr]
    set num_inspectors [llength $inspector_info]
    set id [expr $num_inspectors + 1]
    set imagefile screen.[format %.2d%.2d $oe $scr]
    switch -exact -- $name {
	PLOTXY {
	    vputs "add_scr_inspector: beamline add inspector \
		scr $oe $scr [set gpage2tool($name)] $id"
	    beamline add inspector scr $oe $scr [set gpage2tool($name)] $id
	    vputs "editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector scr $oe $scr PlotXY $id]"
	    editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector scr $oe $scr PlotXY $id "PlotXY $id"]
	    beamline vset inspector scr $oe $scr $id PLX_PLOT_WHAT SCREEN
	    beamline vset inspector scr $oe $scr $id PLX_SPEC_FILE YES
	    beamline vset inspector scr $oe $scr $id PLX_INFILE $imagefile
	    beamline vset inspector scr $oe $scr $id PLX_COMMENTS \
		"SCR $scr of OE $oe"
	    #
	    # WINDOWS BUG/FIXME:
	    #
	    if {[tix platform] == "windows"} {
		beamline vset inspector scr $oe $scr $id \
		    PLX_DEVICE "Postscript"
	    }
	}
	MINMAX {
	    vputs "add_scr_inspector: beamline add inspector \
		scr $oe $scr [set gpage2tool($name)] $id"
	    beamline add inspector scr $oe $scr [set gpage2tool($name)] $id
	    vputs "editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector scr $oe $scr MinMax $id]"
	    editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector scr $oe $scr MinMax $id "PlotXY $id"]
	    beamline vset inspector scr $oe $scr $id MIN_INFILE $imagefile
	    beamline vset inspector scr $oe $scr $id MIN_COMMENTS \
		"SCR $scr of OE $oe"
	}
	default {			;# includes MIRINFO and friends
	    dialog .info_d "Add Screen Inspector" \
		"Cannot inspect Screens with $name. Sorry." \
		"error" 0 Dismiss
	    set_msg "Cannot inspect Screens with $name. Cancelled."
	    return 
	}
    }
    editbar_select_callback inspector scr $oe $scr $name $id
    set gvars(modified) 1
    #
    # some linked filenames may have changed in the current edit window
    # (if any), so redraw just to be safe.
    #
    redraw_current_page_cmd

}

#
# add_inspector: Adds an inspector the beamline. Called by the toolbox
# callback, and NOT available from the top pulldown menu.
#
proc add_inspector {name args} {
    global gvars
    vputs "add_inspector: name, args = $name, $args"
    set name [string toupper $name]
    
    set cur_selection [string trim [get_current_selection]]
    if {$cur_selection == ""} {
	dialog .info_d "Add Inspector" \
	    "Must select SOURCE, OE or SCREEN to attach Inspector to." \
	    "error" 0 Dismiss
        set_msg "Must select SOURCE, OE or a SCREEN first. Cancelled."
	return
    }
    set selection_type [string toupper [lindex $cur_selection 0]]
    switch -glob $selection_type {
	"SOURCE" {
	    return [add_source_inspector $name $args]
	}
	"OE" {
	    set cur_oe [lindex $cur_selection 1]
	    return [add_oe_inspector $cur_oe $name $args]
	}
	"SCR*" {
	    set cur_oe [lindex $cur_selection 1]
	    set cur_scr [lindex $cur_selection 2]
	    return [add_scr_inspector $cur_oe $cur_scr $name $args]
	}
	default {
	    dialog .info_d "Add Inspector" \
		"Inspection tools can only attach to SOURCE, OE or SCREEN." \
		"error" 0 Dismiss
	    set_msg "Must select SOURCE, OE or a SCREEN first. Cancelled."
	    return
	}
    }
}

#
# add_beamline_tool: Called from the Toolbox callback to add a beamline
# element.
#
proc add_beamline_tool {name} {
    set name [string toupper $name]
    switch -exact -- $name {
	SOURCE { 
	    return [add_src_cmd]
	}
	OE { 
	    return [add_oe_cmd]
	}
	SCREEN { 
	    return [add_scr_cmd]
	}
	default {
	    set_msg "Tool $name not recognized! Please report as bug"
	}
    }
}

#----------------------------------------------------------------------#
# DELETE SOURCE/OE/SCR menu callbacks and helpers.
#----------------------------------------------------------------------#

proc delete_selected_cmd {} {
    set_msg "Deleting selected tool ... "
    set cur_selection [string trim [get_current_selection]]
    if {$cur_selection == ""} {
        set_msg "Nothing to delete! Must select a tool first."
	return
    }
    set selection_type [string toupper [lindex $cur_selection 0]]
    switch -glob $selection_type {
	"SOURCE" {
	    return [delete_src_cmd]
	}
	"OE" {
	    set oe [lindex $cur_selection 1]
	    return [delete_oe $oe]
	    return
	}
	"SCR*" {
	    set oe [lindex $cur_selection 1]
	    set scr [lindex $cur_selection 2]
	    return [delete_scr $oe $scr]
	}
	INSPECTOR {
	    set target [string toupper [lindex $cur_selection 1]]
	    set len [llength $cur_selection]
	    #
	    # selection info for inspectors are complex, so be careful
	    # here.
	    #
	    set id [lindex $cur_selection [expr $len - 3]]
	    set inspector [lindex $cur_selection [expr $len - 4]]
	    set inspector_info [lindex $cur_selection [expr $len - 2]]
	    set modified_flag [lindex $cur_selection end]
	    switch -glob $target {
		"SOURCE" {
		    vputs "delete_source_inspector $inspector $id"
		    return [delete_source_inspector $inspector $id]
		}
	        "OE" {
		    set oe [lindex $cur_selection 2]
		    vputs "delete_oe_inspector $oe $inspector $id"
		    return [delete_oe_inspector $oe $inspector $id]
		}
		"SCR*" {
		    set oe [lindex $cur_selection 2]
		    set scr [lindex $cur_selection 3]
		    vputs "delete_scr_inspector $oe $scr $inspector $id"
		    return [delete_scr_inspector $oe $scr $inspector $id]
		}
	    }
	}
	default {
	    dialog .info_d "Run Tool" \
		"Trying to run unknown tool type (internal bug)" \
		"error" 0 Dismiss
	    set_msg "Run Tool cancelled due to internal bug."
	    return
	}
    }
}

proc delete_src {} {
    global gvars
    if {[string toupper [get_current_selection]] == "SOURCE"} {edit_nothing}
    remove_source_from_editbar
    beamline delete source
    set gvars(source_saved) 1
    toolbox:set_state $gvars(tools_w).toolbox.a System.Source enabled
    edit_nothing
    set gvars(modified) 1
    set_msg "Deleting SOURCE ... done."
}

proc delete_src_cmd {} {
    global gvars gprefs
    set_msg "Deleting SOURCE ..."
    if {[get_source] == ""} { 
	dialog .info_d "Delete Source" \
	    "The system does not have a SOURCE to delete!" \
	    {} 0 Dismiss
	set_msg "Deleting SOURCE ... cancelled."
    } else {
	return [delete_src]
    }
    return 0
}

proc delete_all_oe_cmd {} {
    global gvars gprefs
    set_msg "Deleting All OE ..."
    remove_all_oe_from_editbar
    beamline clear oe
    beamline edit none
    edit_nothing
    set_msg "Deleting All OE ...done."
    set gvars(cur_oe) 0
    set gvars(cur_scr) 0
    set gvars(system_saved) 1
    set gvars(modified) 1
    return 0
}

proc delete_oe {oe_id} {
    set_msg "Deleting OE $oe_id ... "

    if {[catch "beamline delete oe $oe_id" msg]} {
	dialog .info_d "Delete OE" \
	    "ERROR: Cannot delete OE #${oe_id}.\n($msg)" \
	    {} 0 Dismiss
	return 1
    }

    #
    # CHECK: Should call "beamline edit none"?
    #
    update_editbar_oe 
    edit_nothing
    set gvars(cur_oe) 0
    set gvars(modified) 1

    set_msg "Deleting OE $oe_id ... done."
    return 0
}

proc delete_oe_cmd {} {
    global gvars gprefs
    set_msg "Deleting OE ..."
    set cur_oe [get_current_oe]
    set oe_id [dialog_num .oe_num "" "Enter OE number to delete: " $cur_oe]
    if {$oe_id == ""} {
	set_msg "Deleting OE ... cancelled."
	return 1
    } elseif {$oe_id < 1} {
	dialog .info_d "Delete OE" \
	    "ERROR: OE number \"$oe_id\" must be >= 1." \
	    {} 0 Dismiss
	set_msg "Deleting OE ... cancelled."
	return 1
    } elseif {$oe_id > [get_num_oe]} {
	dialog .info_d "Delete OE" \
	    "ERROR: OE number \"$oe_id\" must be <= [get_num_oe]." \
	    {} 0 Dismiss
	set_msg "Deleting OE ... cancelled."
	return 1
    }
    return [delete_oe $oe_id]
}

proc delete_scr {oe_id scr_id} {
    set_msg "Deleting Screen $scr_id of OE $oe_id..."
    if {[catch "beamline delete screen $oe_id $scr_id" msg]} {
	dialog .info_d "Delete Screen" \
	    [build_msg \
		"ERROR: Cannot delete Screen #${scr_id} of OE #${oe_id}.\n" \
		($msg)
	    ] \
	    {} 0 Dismiss
	return 1
    }
    #
    # CHECK: Should call "beamline edit none"?
    #
    set gvars(cur_scr) 0
    update_editbar_scr $oe_id
    edit_nothing
    set gvars(modified) 1

    set_msg "Deleting Screen $scr_id of OE $oe_id...done."
    return 0
}

proc delete_scr_cmd {} {
    global gvars gprefs
    set_msg "Deleting SCREEN ..."
    set cur_oe [get_current_oe]
    if {$cur_oe == 0} {
	set cur_oe ""
	set cur_scr ""
    } else {
	set num_scr [get_num_scr $cur_oe]
	set cur_scr $num_scr
    }
    set2 [dialog_2_num .oe_num {} \
	"Enter OE number: " $cur_oe \
	"Enter Screen number: " $cur_scr 1 \
    ] oe_id scr_id

    if {$oe_id == "" || $scr_id == ""} {
	set_msg "Deleting SCREEN ... cancelled."
	return 1
    } elseif {$oe_id < 1  || $scr_id < 1} {
	set_msg "Deleting SCREEN $scr_id of OE $oe_id ... ERROR."
	dialog .info_d "Delete Screen" \
	    "ERROR: Both Screen and OE numbers must be >= 1" "error" 0 Dismiss
	return 1
    } elseif {$oe_id > [get_num_oe]} {
	set_msg "Deleting SCREEN $scr_id of OE $oe_id ... ERROR."
	dialog .info_d "Delete Screen" \
	    "ERROR: OE number must be <= [get_num_oe]" "error" 0 Dismiss
	return 1
    } elseif {$scr_id > [get_num_scr $oe_id]} {
	set_msg "Deleting SCREEN $scr_id of OE $oe_id ... ERROR."
	dialog .info_d "Delete Screen" \
	    "ERROR: SCREEN number must be <= [get_num_scr $scr_id]" \
	    "error" 0 Dismiss
	return 1
    }
    return [delete_scr $oe_id $scr_id]
}

proc delete_source_inspector {name id} {
    set_msg "Deleting Inspector $name $id of SOURCE ..."
    vputs "beamline delete inspector source $id"
    if {[catch "beamline delete inspector source $id" msg]} {
	dialog .info_d "Delete Inspector" \
	    "ERROR: Cannot delete Inspector $name ${id} of SOURCE.\n($msg)" \
	    {} 0 Dismiss
	return 1
    }
    #
    # CHECK: Should call "beamline edit none"?
    #
    update_editbar_source
    edit_nothing
    set gvars(modified) 1

    set_msg "Deleting Inspector $name $id of SOURCE...done."
    return 0
}

proc delete_oe_inspector {oe name id} {
    set_msg "Deleting Inspector $name $id of OE $oe ..."
    vputs "beamline delete inspector oe $oe $id"
    if {[catch "beamline delete inspector oe $oe $id" msg]} {
	dialog .info_d "Delete Inspector" \
	    "ERROR: Cannot delete Inspector $name ${id} of OE $oe.\n($msg)" \
	    {} 0 Dismiss
	return 1
    }
    #
    # CHECK: Should call "beamline edit none"?
    #
    update_editbar_oe
    edit_nothing
    set gvars(modified) 1

    set_msg "Deleting Inspector $name $id of OE $oe...done."
    return 0
}

proc delete_scr_inspector {oe scr name id} {
    set_msg "Deleting Inspector $name $id of SCR $scr/$oe ..."
    if {[catch "beamline delete inspector scr $oe $scr $id" msg]} {
	dialog .info_d "Delete Inspector" \
	    "ERROR: Cannot delete Inspector #${id} of SCR $scr/$oe.\n($msg)" \
	    {} 0 Dismiss
	return 1
    }
    #
    # CHECK: Should call "beamline edit none"?
    #
    update_editbar_scr $oe
    edit_nothing
    set gvars(modified) 1

    set_msg "Deleting Inspector $name $id of SCR $scr/$oe...done."
    return 0
}

#----------------------------------------------------------------------#
# EDIT SOURCE/OE/SCR menu callbacks and helpers.
#----------------------------------------------------------------------#

proc edit_src_cmd {} {
    global gvars
    set_msg "Editing SOURCE..."
    if {[get_source] == ""} { 
	set_msg "SOURCE does not exist ... Adding SOURCE..."
	beamline add source
        insert_source_in_editbar
	set_msg "SOURCE does not exist ... Adding SOURCE...done."
    }
    return [edit_src]
}

proc edit_oe_cmd {} {
    global gvars
    set_msg "Editing OE ..."
    set next_oe $gvars(cur_oe)
    set oe_id [dialog_num .oe_num "" "Enter OE number: " $next_oe]
    if {$oe_id == ""} {
	set_msg "Editing OE ...cancelled."
	return 1
    }
    set num_oe [get_num_oe]
    if {$oe_id < 1 || $oe_id > $num_oe} {
	dialog .info_d "Edit OE" \
	    "ERROR: OE number ${oe_id} doesn't exist." \
	    {} 0 Dismiss
	set_msg "Editing OE ...ERROR."
	return 1
    }
    return [edit_oe $oe_id]
}

proc edit_scr_cmd {} {
    global gvars
    set_msg "Editing SCREEN ..."
    set cur_oe [get_current_oe]
    if {$cur_oe == 0} {
	set cur_oe ""
	set cur_scr ""
    } else {
	set num_scr [get_num_scr $cur_oe]
	set cur_scr $num_scr 
    }
    set2 [dialog_2_num .oe_num {} \
	"Enter OE number: " $cur_oe \
	"Enter Screen number: " $cur_scr 1 \
    ] oe_id scr_id

    if {$oe_id == "" || $scr_id == ""} {
	set_msg "Editing SCREEN ... cancelled."
	vputs "Cancelled by user: No screen added."
	return 1
    }
    set num_oe [get_num_oe]
    if {$oe_id < 1 || $oe_id > $num_oe} {
	dialog .info_d "Edit SCREEN" \
	    "ERROR: OE number ${oe_id} doesn't exist." \
	    {} 0 Dismiss
	set_msg "Editing SCREEN ... ERROR"
	return 1
    }
    set num_scr [get_num_scr $oe_id]
    if {$scr_id < 1 || $scr_id > $num_scr} {
	dialog .info_d "Edit SCREEN" \
	    "ERROR: SCREEN number ${scr_id} of OE $oe_id doesn't exist." \
	    {} 0 Dismiss
	set_msg "Editing SCREEN ... ERROR"
	return 1
    }
    return [edit_scr $oe_id $scr_id]
}

proc edit_selected_cmd {} {
    set_msg "Editing selected tool ... "
    set cur_selection [string trim [get_current_selection]]
    if {$cur_selection == ""} {
        set_msg "Nothing to edit! Must select a tool first."
	return
    }
    return [eval editbar_callback $cur_selection]
}

#----------------------------------------------------------------------#
# COPY menu callbacks and helpers.
#----------------------------------------------------------------------#

proc clear_clipboard_cmd {} {
    global gvars
    set gvars(clipboard) "Empty"
    $gvars(clipboard_w) config -text "Empty"
    beamline clear clipboard
}

proc copy_src {} {
    global gvars
    set_msg "copying Source to clipboard ..."
    set gvars(clipboard) "source"
    beamline selection copy
    set_msg "copying Source to clipboard ... done."
}

proc copy_oe oe {
    global gvars
    set_msg "copying OE $oe to clipboard ..."
    set gvars(clipboard) "oe $oe"
    beamline selection copy
    set_msg "copying OE $oe to clipboard ... done."
}

proc copy_scr {oe scr} {
    global gvars
    set_msg "copying SCREEN $scr of OE $oe to clipboard ..."
    set gvars(clipboard) "scr $oe $scr"
    beamline selection copy
    set_msg "copying SCREEN $scr of OE $oe to clipboard ... done."
}


proc copy_source_inspector {inspector id inspector_info} {
    global gvars
    set_msg "copying SOURCE Inspector $inspector #$id to clipboard ..."
    set gvars(clipboard) "$inspector_info"
    beamline selection copy
    set_msg "copying SOURCE Inspector $inspector #$id to clipboard ...  done"
}

proc copy_oe_inspector {oe inspector id inspector_info} {
    global gvars
    set_msg "copying OE Inspector $inspector #$id to clipboard ..."
    set gvars(clipboard) "$inspector_info"
    beamline selection copy
    set_msg "copying OE Inspector $inspector #$id to clipboard ...  done"
}

proc copy_scr_inspector {oe scr inspector id inspector_info} {
    global gvars
    set_msg "copying SCR Inspector $inspector #$id to clipboard ..."
    set gvars(clipboard) "$inspector_info"
    beamline selection copy
    set_msg "copying SCR Inspector $inspector #$id to clipboard ...  done"
}

proc copy_inspector args {
    global gvars
    set args [join $args]
    set arglen [llength $args]
    set inspector [lindex $args [expr $arglen - 4]]
    set id [lindex $args [expr $arglen - 3]]
    set inspector_info [lindex $args [expr $arglen - 2]]
    set modified_flag [lindex $args end]
    set target [string toupper [lindex $args 0]]
    switch -glob -- $target {
	"SOURCE" {
	    return [copy_source_inspector $inspector $id $inspector_info]
	}
	"OE" {
	    set oe [lindex $args 1]
	    return [copy_oe_inspector $oe $inspector $id $inspector_info]
	}
	"SCR*" {
	    set oe [lindex $args 1]
	    set scr [lindex $args 2]
	    return [copy_scr_inspector $oe $scr $inspector $id $inspector_info]
	}
	default {
	    puts stderr "copy_selected: NOT IMPL"
	}
    }
}

proc copy_selected_cmd {} {
    global gvars
    set_msg "Copying selected tool ... "
    set gvars(clipboard) ""
    set cur_selection [string trim [get_current_selection]]
    if {$cur_selection == ""} {
        set_msg "Nothing to copy! Must select a tool first."
	return
    }
    $gvars(clipboard_w) config -text "[editbar_make_msg $cur_selection]"
    set toolname [string toupper [lindex $cur_selection 0]]
    switch -exact -- $toolname {
	SOURCE { 
	    return [copy_src]
	}
	OE { 
	    set oe_id [lindex $cur_selection 1]
	    return [copy_oe $oe_id]
	}
	SCREEN { 
	    set oe_id [lindex $cur_selection 1]
	    set scr_id [lindex $cur_selection 2]
	    return [copy_scr $oe_id $scr_id]
	}
	INSPECTOR {
	    return [copy_inspector [lrange $cur_selection 1 end]]
	}
    }
}

proc paste_selected_cmd {} {
    global gvars
    if {$gvars(clipboard) == ""} {
        set_msg "Nothing to paste! Must copy something to clipboard first!"
	return
    }
    set cur_selection [string trim [get_current_selection]]
    if {$cur_selection == ""} {
        set_msg "Nothing to paste to! Must select a tool first."
	return
    }
    set_msg "Pasting clipboard to selected tool ... "
    beamline selection paste
    do_redraw_editbar
    edit_nothing
    fix_oe_filenames
    set gvars(modified) 1
    set_msg "Pasting clipboard to selected tool ... done."
}

#----------------------------------------------------------------------#
# OPTION menu callbacks and helpers.
#----------------------------------------------------------------------#

proc list_system_cmd {} {
    global gvars
    set_msg "Listing SYSTEM..."
    set msg ""
    append msg "SOURCE defined: "
    if {[get_source] != ""} { 
	append msg "Yes"
    } else {
	append msg "No"
    }
    append msg "\n"
    set num_oe [get_num_oe]
    append msg "Number of OEs: $num_oe\n"
    append msg "Current OE:       [get_current_oe]\n"
    for {set oe 1} {$oe <= $num_oe} {incr oe} {
	append msg "scrns in OE.$oe: [get_num_scr $oe]\n"
    }
    dialog .info_d "List SYSTEM" "$msg" {} 0 Dismiss
    set_msg "Listing SYSTEM...done."
}

#----------------------------------------------------------------------#
#
# Toolbox callback. Every time an item is selected (single click in this
# case), the Toolbox system calls this routine with the original data
# supplied when building the Toolbox. See GUI:make_toolbox for the data
# supplied.
#
# eg., when OE is chosen, args = {beamline oe}
# eg., when PLOTXY Inspecttor is chosen, args = {inspector plotxy}
#
#----------------------------------------------------------------------#

proc toolbox_callback {args} {
    global gvars
    vputs "toolbox_callback_args: $args"
    set tool_type [lindex $args 0]
    switch -exact $tool_type {
        beamline {
	    if {[llength $args] == 1} {
		show_about_page
	    } else {
	        add_beamline_tool [lindex $args 1]
	    }
	}
        inspector {
	    if {[llength $args] == 1} {
		show_about_page
	    } else {
	        add_inspector [lindex $args 1] [lrange $args 2 end]
	    }
	}
	ray_trace {
	    set trace_what [lindex $args 1]
	    switch -exact -- $trace_what {
	        source {
		    run_source_cmd
		}
		system {
		    run_system_cmd
		}
		default {
		    set_msg "Running $trace_what not implemented yet"
		}
	    }
	}
	default {
	    set_msg "ITEM $tool_type not implemented yet"
	}
    }
}

#----------------------------------------------------------------------#
#
# Miscalleneous command callbacks for buttons.
#
# pop_page_stack and pop_page_stack2 varies only in that the first one
# is called from the BACK button on individual MENU pages, and the latter
# called from the MAIN window (Toolbar) BACK button.
#
#----------------------------------------------------------------------#

proc pop_page_stack2 {} {
    global gvars
    if {[llength $gvars(pagestack)] == 0} {
	return 1
    }
    set page_and_item [pop_curpage]
    set2 $page_and_item newpage newitem
    if {$newpage == ""} {return 1}
    page:display $gvars(cur_page_w) $newpage $newitem
    # $gvars(page_popup) bind $gvars(cur_page_w)
}

proc pop_page_stack {} {
    global gvars
    set page_and_item [pop_curpage]
    set2 $page_and_item newpage newitem
    if {$newpage == ""} {return 1}
    page:display $gvars(cur_page_w) $newpage $newitem
    # $gvars(page_popup) bind $gvars(cur_page_w)
}

#----------------------------------------------------------------------#
#
# EXEC_TCL_COMMAND: Callback for SHOW_CMD_WINDOW. Execs arbitrary Tcl
# command in the current interpreter at level#0.
#
#----------------------------------------------------------------------#

proc 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
}

#----------------------------------------------------------------------#
#
# SET_MSG: Shows the supplied message in the Statusbar.
#
# RESET_MSG: Resets it.
#
#----------------------------------------------------------------------#



proc set_msg {msg} {
    global gvars
    $gvars(statusbar) configure -text "$msg"
    update idletasks
}

proc reset_msg {{msg "Enter `?' in any field for help"}} {
    global gvars gprefs
    $gvars(statusbar) configure -text "$msg"
    update idletasks
}

#----------------------------------------------------------------------#
#
# Options/chdir menu callbacks.
#
#----------------------------------------------------------------------#

#
# directory browser routines.
#

#
# Pop up a directory selection dialog (dirdlg:)
#
proc dirdlg:browse {command {initdir {}}} {
    set dialog .dirdlg_popup
    if ![winfo exists $dialog] {
	tixDirSelectDialog $dialog
    }
    $dialog config -command $command
    set dirbox [$dialog subwidget dirbox]
    if {$initdir != {}} {
        $dirbox config -value $initdir
    }
    $dialog popup
}

proc do_chdir {newdir} {
    set newdir [cvt_filename_to_tcl $newdir]
    cd [cvt_filename_to_tcl $newdir]

    global gvars
    catch "$gvars(cur_directory) config -text $newdir"
}

proc chdir_cmd {} {
    global gvars gprefs
    set_msg "Changing current directory ... "
    set curdir [cvt_filename_to_platform [pwd]]
    dirdlg:browse do_chdir $curdir
    set_msg "Changing current directory to $curdir ... done."
}

proc do_redraw_editbar {} {
    update_editbar_source
    update_editbar_oe
}

proc redraw_editbar_cmd {} {
    set_msg "Redrawing System editor ..."
    do_redraw_editbar
    set_msg "Redrawing System editor ... done."
}

proc do_redraw_current_page {} {
    global gvars
    if {$gvars(cur_page_w) != ""} {
	page:display $gvars(page_w) $gvars(curpage) 
    }
}

proc redraw_current_page_cmd {} {
    set_msg "Redrawing current parameter page ..."
    do_redraw_current_page
    set_msg "Redrawing current parameter page ... done."
}

proc show_run_window_cmd {} {
    show_run_window
}

proc undo_deleted_cmd {} {
    set_msg "Undo not implemented yet."
}

proc enable_undo_delete_cmd {} {
    return [GUI:set_undo_del_btn_state normal]
}

proc disable_undo_delete_cmd {} {
    return [GUI:set_undo_del_btn_state disabled]
}

#----------------------------------------------------------------------#
# PREFERENCE menu callbacks and helpers.
#----------------------------------------------------------------------#


proc load_prefs_cmd {} {
    global gvars
    set_msg "Loading preference from \"$gvars(pref_file)\"... "
    load_prefs
    set_msg "Loading preference from \"$gvars(pref_file)\"... done."
    return 0
}

proc save_prefs_cmd {} {
    global gvars
    set_msg "Saving preference to \"$gvars(pref_file)\"... "
    save_prefs
    set_msg "Saving preference to \"$gvars(pref_file)\"... done."
    return 0
}

proc reset_prefs_cmd {} {
    global gvars
    set_msg "Resetting preferences from the defaults ... "
    reset_prefs_from_default
    #
    # now call the routines that depend on prefs settings.
    #
    show_toolbar_cmd
    show_cmd_window_cmd
    show_msg_window_cmd

    set_msg "Resetting preferences from the defaults ... done. "
    return 0
}


#----------------------------------------------------------------------#
# PREFERENCES menu callbacks and helpers.
#----------------------------------------------------------------------#

proc balloon_help_cmd {} {
    global gvars gprefs 
    if {!$gprefs(balloon_help)} {
        $gvars(balloon) config -state none
    } else {
        $gvars(balloon) config -state both
    }
}

proc show_toolbar_cmd {} {
    global gvars gprefs
    catch "pack unpack $gvars(toolbar)"
    if {$gprefs(show_toolbar)} {
	pack $gvars(toolbar) -after $gvars(toolbar_w_stub) -expand 1 -fill x
    }
}

proc show_msg_window_cmd {} {
    global gvars gprefs
    if {$gprefs(msg_window_at_bottom)} {
	set stub $gvars(msg_w_bot_stub)
    } else {
	set stub $gvars(msg_w_top_stub)
    }
    catch "pack unpack $gvars(msg_w)"
    pack $gvars(msg_w) -after $stub -expand 1 -fill x ;#-padx 4 -pady 4
}

proc show_cmd_window_cmd {} {
    global gvars gprefs
    catch "pack unpack $gvars(cmd_w)"
    if {$gprefs(show_cmd_window)} {
	pack $gvars(cmd_w) -after $gvars(cmd_w_stub) -expand 1 -fill x
    }
}

#----------------------------------------------------------------------#
# HELP menu callbacks and helpers.
#----------------------------------------------------------------------#

proc about_cmd {} {
    show_about_page
}


proc about_author_cmd {} {
    catch {destroy .about}
    toplevel .about -relief sunken -border 1 -bg lightgrey

    label .about.blurb \
	-text {SHADOW GUI}
    label .about.author \
	-text {Author: Mumit Khan <khan@xraylith.wisc.edu>}
    button .about.dismiss -text "Dismiss" -command {destroy .about}  \
	-bg antiquewhite

    pack .about.blurb -side top -padx 5 -pady 5
    pack .about.author -side top -padx 5 -pady 5
    pack .about.dismiss -side top -padx 5 -pady 5
}

proc help_on_topmenu_cmd {} {
    set_msg "Calling help on toplevel pulldown menu ..."
    top_help
    set_msg "Calling help on toplevel pulldown menu ... done."
    return 0
}

proc run_demo_cmd {file} {
    global gvars shadow_library workspace
    set demofile [file join \
	$gvars(shadow_gui_root) doc examples $file]
    if ![file readable $demofile] {
	dialog .info_d "Load DEMO" \
	    "ERROR: DEMO toroid.ws is not installed as $demofile." \
	    error 0 Dismiss
	set_msg "Loading DEMO ... ERROR."
    } else {
	set_msg "Loading DEMO $demofile ... ."
        load_state_cmd $demofile
    }
}
    
#----------------------------------------------------------------------#
# EDIT menu callbacks helpers.
#----------------------------------------------------------------------#

proc edit_nothing {} {
    global gvars
    catch "destroy $gvars(cur_page_w)"
    set gvars(cur_page_w) {}
    set gvars(editing_what) ""
    set_msg "Clearing Edit window ... done."
    beamline edit none
    editbar:highlight $gvars(editbar).toolbox.a ""
    #
    # CHECK/FIXME: Make sure this doesn't cause problems later with the
    # string "None".
    #
    editbar_callback None
    return 0
}

proc edit_src {} {
    global gvars
    if {[catch "beamline edit source" msg]} {
	dialog .info_d "Edit SOURCE" \
	    "Internal ERROR: Error unselecting current OE/SCREEN.\n($msg)" \
	    error 0 Dismiss
	set_msg "Editing SOURCE...ERROR."
	return 
    }
    set gvars(source_saved) 0
    set gvars(cur_scr) 0
    set gvars(cur_oe) 0
    set gvars(cur_page_w) [page:display $gvars(page_w) SOURCE]
    # $gvars(page_popup) bind $gvars(cur_page_w)
    set gvars(editing_what) "SOURCE"
    set_msg "Editing SOURCE...done."

    editbar:highlight $gvars(editbar).toolbox.a [list source]
    return 0
}

proc edit_oe {oe_id} {
    global gvars
    if {[catch "beamline edit oe $oe_id" msg]} {
	dialog .info_d "Edit OE" \
	    "ERROR: Error editing OE number ${oe_id}.\n($msg)" \
	    {} 0 Dismiss
	set_msg "Editing OE $oe_id...cancelled."
	return 1
    }
    set gvars(system_saved) 0
    set gvars(cur_scr) 0
    set gvars(cur_oe) [get_current_oe]
    set gvars(cur_page_w) [page:display $gvars(page_w) OE_DATA]
    # $gvars(page_popup) bind $gvars(cur_page_w)
    set gvars(editing_what) "OE"
    editbar:highlight $gvars(editbar).toolbox.a [list oe $oe_id]
    set_msg "Editing OE $oe_id...done."
    return 0
}

proc edit_scr {oe_id scr_id} {
    global gvars
    if {[catch "beamline edit scr $oe_id $scr_id" msg]} {
	dialog .info_d "" \
	    "ERROR: Error editing SCREEN $scr_id of OE ${oe_id}.\n($msg)." \
	    error 0 Dismiss
	set_msg "Editing SCREEN $scr_id of OE $oe_id...cancelled."
	return 1
    }
    set gvars(system_saved) 0
    set gvars(cur_oe) $oe_id
    set gvars(cur_scr) $scr_id
    set gvars(cur_page_w) [page:display $gvars(page_w) SCR_DATA]
    # $gvars(page_popup) bind $gvars(cur_page_w)
    set gvars(editing_what) "SCREEN"
    editbar:highlight $gvars(editbar).toolbox.a [list screen $oe_id $scr_id]
    set_msg "Editing SCREEN $scr_id of OE $oe_id...done."
    return 0
}

proc edit_tool {toolname page} {
    global gvars
    edit_nothing
    set gvars(cur_page_w) [page:display $gvars(page_w) $page]
    # $gvars(page_popup) bind $gvars(cur_page_w)
    set gvars(editing_what) "$toolname"
    set_msg "Editing TOOL $toolname ...done."
    return 0
}

proc show_about_page {} {
    global gvars
    edit_nothing
    set gvars(cur_page_w) [page:display $gvars(page_w) about: -1]
    # $gvars(page_popup) bind $gvars(cur_page_w)
    set gvars(editing_what) "about:"
    return 0
}

proc show_annotation_page {} {
    global gvars
    set gvars(cur_page_w) [page:display $gvars(page_w) annotation: -1]
    set gvars(editing_what) "annotation:"
    return 0
}

#----------------------------------------------------------------------#
# Editbar routines for editing inspectors.
#----------------------------------------------------------------------#

proc edit_source_inspector {args} {
    global gvars gtool2page gpage2tool
    set args [join $args]
    set inspector [string toupper [lindex $args 0]]
    set id [string toupper [lindex $args 1]]
    vputs "Editing inspector $inspector of SOURCE"
    if {[catch "beamline edit inspector source $id" msg]} {
	dialog .info_d "Edit Inspector" \
	    "ERROR: Error editing $inspector of SOURCE.\n($msg)" \
	    {} 0 Dismiss
	set_msg "Editing Inspector $inspector of SOURCE ...cancelled."
	return 1
    }
    set gvars(cur_inspector) [get_current_inspector]
    set gvars(cur_page_w) [page:display $gvars(page_w) $inspector]
    # $gvars(page_popup) bind $gvars(cur_page_w)
    set gvars(editing_what) "INSPECTOR"
    editbar:highlight $gvars(editbar).toolbox.a \
        [list inspector source $id]
    set_msg "Editing Inspector $inspector of SOURCE ...done."
    return 0
}

proc edit_oe_inspector {args} {
    global gvars gtool2page gpage2tool
    set args [join $args]
    set oe_id [lindex $args 0]
    set inspector [string toupper [lindex $args 1]]
    set id [lindex $args 2]
    vputs "Editing inspector $inspector of OE $oe_id"
    if {[catch "beamline edit inspector oe $oe_id $id" msg]} {
	dialog .info_d "Edit Inspector" \
	    "ERROR: Error editing $inspector of OE ${oe_id}.\n($msg)" \
	    {} 0 Dismiss
	set_msg "Editing Inspector $inspector of OE $oe_id...cancelled."
	return 1
    }
    set gvars(cur_oe) [get_current_oe]
    set gvars(cur_inspector) [get_current_inspector]
    set gvars(cur_page_w) [page:display $gvars(page_w) $inspector]
    # $gvars(page_popup) bind $gvars(cur_page_w)
    set gvars(editing_what) "INSPECTOR"
    editbar:highlight $gvars(editbar).toolbox.a \
        [list inspector oe $oe_id $id]
    set_msg "Editing Inspector $inspector of OE $oe_id...done."
    return 0
}

proc edit_scr_inspector {args} {
    global gvars gtool2page gpage2tool
    set args [join $args]
    set oe_id [lindex $args 0]
    set scr_id [lindex $args 1]
    set inspector [string toupper [lindex $args 2]]
    set id [lindex $args 3]
    vputs "Editing inspector $inspector of SCR $scr_id of OE $oe_id"
    if {[catch "beamline edit inspector scr $oe_id $scr_id $id" msg]} {
	dialog .info_d "Edit Inspector" \
	    "ERROR: Error editing $inspector of SCR $scr_id.\n($msg)" \
	    {} 0 Dismiss
	set_msg "Editing Inspector $inspector of SCR $scr_id...cancelled."
	return 1
    }
    set gvars(cur_oe) [get_current_oe]
    set gvars(cur_scr) [get_current_scr]
    set gvars(cur_inspector) [get_current_inspector]
    set gvars(cur_page_w) [page:display $gvars(page_w) $inspector]
    # $gvars(page_popup) bind $gvars(cur_page_w)
    set gvars(editing_what) "INSPECTOR"
    editbar:highlight $gvars(editbar).toolbox.a \
        [list inspector scr $oe_id $scr_id $id]
    set_msg "Editing Inspector $inspector of SCR $scr_id of OE $oe_id...done."
    return 0
}
                                               
#----------------------------------------------------------------------#
# Load/Save state commands
#----------------------------------------------------------------------#

proc do_save_state {file} {
    global gvars
    State:save [cvt_filename_to_tcl $file]
    set gvars(modified) 0
    set gvars(wkspc_file) $file
    GUI:add_file_to_title $file
}

proc save_state_cmd {} {
    global workspace			;# defined in state.tcl
    # FIXME: For newer tk releases >= 4.2
    global tk_version
    if {$tk_version < 4.2} {
	set dialog [tix filedialog]
	set fsbox [$dialog subwidget fsbox]
	$fsbox configure -pattern "*.ws" -value "$workspace(filename)"
	$dialog config -title "Select a file to save Workspace" \
	    -command "do_save_state"
	$dialog popup
    } else {
	# globbing does not work on windows as on Unix
	global tcl_platform
	set platform $tcl_platform(platform)
	if {$platform == "unix"} {
	    set types {
		{{SHADOW Workspace Files}	{.ws}}
		{{SHADOW Namelist Files}	{start.\[0-9\]\[0-9\]}}
		{{SHADOW Source Image}		{begin.dat}}
		{{SHADOW Image Files}		{star.\[0-9\]\[0-9\]}}
		{{SHADOW Image Files}		{mirr.\[0-9\]\[0-9\]}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	} else {
	    set types {
		{{SHADOW Workspace Files}	{.ws}}
		{{SHADOW Namelist Files}	{start.*}}
		{{SHADOW Source Image}		{begin.dat}}
		{{SHADOW Image Files}		{star.*}}
		{{SHADOW Image Files}		{mirr.*}}
		{{Misc Data Files}		{.dat}}
		{{All Files}			*}
	    }
	}
	set file [tk_getSaveFile \
	    -filetypes $types \
	    -defaultextension ".ws"  \
	    -initialdir "[file dirname $workspace(filename)]" \
	    -initialfile "[file tail $workspace(filename)]" \
	    -title "Save current Workspace to file"
	]
	if {$file != ""} {
	    do_save_state $file
	}
    }
}

proc do_load_state {file} {
    global gvars workspace

    set workspace(filename) ""
    set workspace(title) ""
    set workspace(subtitle) ""
    set workspace(annotation) ""

    State:load [cvt_filename_to_tcl $file]
    GUI:add_file_to_title $file
    set gvars(wkspc_file) $file
    set workspace(filename) $file
    show_annotation_page
    set gvars(modified) 0
}

proc load_state_cmd {{file {}}} {
    global gvars
    if $gvars(modified) {
	set dosave [dialog .load "Save Workspace" \
	    "Current Workspace has been modified. Do you want to save?" \
	    questhead 0 \
	    {"Save" "Discard"} \
	]
	if {$dosave == 0} {
	    set_msg "Saving Workspace ... "
	    save_state_cmd
	}
    }

    if {$file != ""} {
	do_load_state $file
    } else {
	# FIXME: For newer tk releases >= 4.2
	global tk_version
	if {$tk_version < 4.2} {
	    set dialog [tix filedialog]
	    set fsbox [$dialog subwidget fsbox]
	    $fsbox configure -pattern "*.ws" -value ""
	    $dialog config -title "Select a file to load Workspace from" \
		-command "do_load_state"
	    $dialog popup
	} else {
	    # globbing does not work on windows as on Unix
	    global tcl_platform
	    set platform $tcl_platform(platform)
	    if {$platform == "unix"} {
		set types {
		    {{SHADOW Workspace Files}	{.ws}}
		    {{SHADOW Namelist Files}	{start.\[0-9\]\[0-9\]}}
		    {{SHADOW Source Image}	{begin.dat}}
		    {{SHADOW Image Files}	{star.\[0-9\]\[0-9\]}}
		    {{SHADOW Image Files}	{mirr.\[0-9\]\[0-9\]}}
		    {{Misc Data Files}		{.dat}}
		    {{All Files}		*}
		}
	    } else {
		set types {
		    {{SHADOW Workspace Files}	{.ws}}
		    {{SHADOW Namelist Files}	{start.*}}
		    {{SHADOW Source Image}	{begin.dat}}
		    {{SHADOW Image Files}	{star.*}}
		    {{SHADOW Image Files}	{mirr.*}}
		    {{Misc Data Files}		{.dat}}
		    {{All Files}		*}
		}
	    }
	    set file [tk_getOpenFile \
		-filetypes $types \
		-defaultextension ".ws" \
		-title "Load SHADOW Workspace from file" \
	    ]
	    if {$file != ""} {
		set_msg "Loading Workspace from $file ..."
		do_load_state $file
	    }
	}
    }
}

proc new_state_cmd {{do_show_annotation_page 1}} {
    global gvars workspace
    if $gvars(modified) {
	set dosave [dialog .load "Save Workspace" \
	    "Current Workspace has been modified. Do you want to save?" \
	    questhead 0 \
	    {"Save" "Discard"} \
	]
	if {$dosave == 0} {
	    set_msg "Saving Workspace ... "
	    save_state_cmd
	}
    }
    #
    # FIXME: delete_src_cmd is the right thing to do, but needs to be
    # changed before we can use (shut off the error message in there).
    #
    catch "delete_src"
    catch "delete_all_oe_cmd"

    set workspace(filename) "file: (NONE)"
    set workspace(title) "New Workspace (No title)"
    set workspace(subtitle) ""
    set workspace(annotation) {
    Please create Workspace from the Toolbox. You can annotate your
    workspace using the TOOLS | ANNOTATE_WORKSPACE menu option. This
    annotation is saved in the workspace file and can be used to keep
    track of modifications and document the workspace
    }
    set gvars(modified) 0

    GUI:add_file_to_title ""
    if $do_show_annotation_page {
	show_annotation_page
    }
    return 0
}

#
# routines to have the beamline save/restore itself.
#
proc save_beamline_state_cmd {} {
    set_msg "Remembering Workspace state ... "
    beamline state save
    set_msg "Remembering Workspace state ... done."
}

proc restore_beamline_state_cmd {} {
    global gvars
    set_msg "Restoring Workspace state ... "
    if ![beamline state show] {
	dialog .restore "Restore Workspace" \
	    "System state was not saved, so cannot restore" \
	    error 0 Dismiss
	set_msg "Restoring Workspace state ... error."
	return
    }
    beamline state restore
    set gvars(modified) 1
    do_redraw_editbar
    edit_nothing
    fix_oe_filenames
    set_msg "Restoring Workspace state ... done."
}

#----------------------------------------------------------------------#
# RUN menu callbacks and helpers.
#----------------------------------------------------------------------#

proc run_source_cmd {} {
    set_msg "Running SOURCE ... "
    if {[get_source] == ""} {
	dialog .info_d "Run SOURCE" \
	    "ERROR: SOURCE does not exist. Create one first." \
	    {} 0 Dismiss
	set_msg "Running SOURCE ... cancelled"
	return 1
    } 

    global gvars
    #
    # save the source first and then run it. Take care not to save
    # to the default file, since that might be a read-only copy (eg.,
    # an example by someone else).
    #
    set startfile [tmpfile $gvars(tmpdir) start_ .00]
    if {$startfile == ""} {
	error "Cannot create temp file in $gvars(tmpdir)!. Cannot run SOURCE"
    }
    beamline store source $startfile
    run_source $gvars(gen_source) $startfile
    lappend gvars(tmpfiles) $startfile
    set_msg "Running SOURCE ... done"
    return 0
}

proc run_trace_cmd {} {
    set_msg "Running TRACE ... "
    set num_oe [get_num_oe]
    if {$num_oe == 0} {
	dialog .info_d "Run TRACE" \
	    "ERROR: No OEs defined. Must define some OEs first." \
	    {} 0 Dismiss
	set_msg "Running TRACE ... cancelled"
	return 1
    } 

    global gvars
    set systemfile $gvars(loadsavedir)/$gvars(systemfile)

    set_msg "saving SYSTEM file \"$systemfile\"..."
    #
    # and write the SYSTEMFILE
    #
    if {[catch "beamline store system $systemfile" msg]} {
	dialog .save_system "Save system" \
	    "ERROR saving SYSTEMFILE \"$systemfile\" ($msg)." {} 0 Dismiss
	set_msg "saving SYSTEM file \"$systemfile\"... Cancelled"
	return 1
    }
    set gvars(system_saved) 1

    set startprefix $gvars(loadsavedir)/$gvars(startprefix)
    run_system $gvars(run_system) $num_oe $startprefix
    set_msg "Running TRACE ... done"
    return 0
}

proc run_oe_cmd {oe} {
    global gvars
    set_msg "Running OE $oe ... "
    #
    # get input image first.
    #
    set prev_oe [expr $oe - 1]
    set image ""
    if {$oe == 1} {
        if {[get_source] == ""} {
	    set image [dialog_str .dialog_image \
	        "Get SOURCE image" \
		"Must supply an input image for OE number 1" \
		"begin.dat"]
	    if {$image == ""} {
		dialog .info_d "Run OE" \
		    "ERROR: No input image supplied. Cancelled." \
		    {} 0 Dismiss
		set_msg "Running OE $oe ... cancelled"
		return 1
	    }
	} else {
	    set image [beamline vget source FILE_SOURCE]
	}
    } else {
        set image [beamline vget oe $prev_oe FILE_SOURCE]
    }

    #
    # save the OE first and then run it. Take care not to save
    # to the default file, since that might be a read-only copy (eg.,
    # an example by someone else).
    #
    set startfile [tmpfile $gvars(tmpdir) start_ [format %.2d $oe]]

    if {$startfile == ""} {
	error "Cannot create temporary file in $gvars(tmpdir)!. Cannot run OE"
    }
    beamline store oe $oe $startfile
    run_oe $gvars(trace) $oe $startfile $image
    lappend gvars(tmpfiles) $startfile
    set_msg "Running OE $oe ... done"
    return 0
}

proc run_system_cmd {} {
    set_msg "Running SYSTEM ... "
    set num_oe [get_num_oe]
    if {$num_oe == 0} {
	dialog .info_d "Run SYSTEM" \
	    "ERROR: No OEs defined. Must define some OEs first." \
	    {} 0 Dismiss
	set_msg "Running SYSTEM ... cancelled"
	return 1
    } 

    global gvars
    #
    # save the systemfile and then run it. Take care not to save
    # to the default file, since that might be a read-only copy (eg.,
    # an example by someone else).
    #
    set systemfile [tmpfile $gvars(tmpdir) systemfile_ .dat]
    if {$systemfile == ""} {
	error "Cannot create temporary file in $gvars(tmpdir)!. Cannot run SYSTEM"
    }

    set_msg "saving SYSTEM file \"$systemfile\"..."
    #
    # and write the SYSTEMFILE
    #
    set startprefix [tmpfile $gvars(tmpdir) start_]
    if {$startprefix == ""} {
	error "Cannot create temporary file in $gvars(tmpdir)!. Cannot run SYSTEM"
    }
    if {[catch "beamline store system $systemfile $startprefix" msg]} {
	dialog .save_system "Save system" \
	    "ERROR saving SYSTEMFILE \"$systemfile\" ($msg)." {} 0 Dismiss
	set_msg "saving SYSTEM file \"$systemfile\"... Cancelled"
	return 1
    }

    # run_system $gvars(run_system) $num_oe $startprefix
    run_system $gvars(trace) $num_oe $startprefix
    set_msg "Running SYSTEM ... done"

    lappend gvars(tmpfiles) $systemfile
    lappend gvars(tmpfiles) "${startprefix}*"

    return 0
}

proc run_source_inspector {inspector id} {
    global gvars
    set_msg "Running $inspector $id ... "
    set tmpfile [tmpfile $gvars(tmpdir) $inspector${id}_ .g]
    beamline store inspector source $id $tmpfile
    run_${inspector} "source" $gvars(run_${inspector}) $tmpfile
    lappend gvars(tmpfiles) $tmpfile
    set_msg "Running $inspector $id ... done "
}

proc run_oe_inspector {oe inspector id} {
    global gvars
    set_msg "Running $inspector $id ... "
    set tmpfile [tmpfile $gvars(tmpdir) $inspector${id}_ .g]
    beamline store inspector oe $oe $id $tmpfile
    run_${inspector} [list oe $oe] $gvars(run_${inspector}) $tmpfile
    lappend gvars(tmpfiles) $tmpfile
    set_msg "Running $inspector $id ... done "
}

proc run_scr_inspector {oe scr inspector id} {
    global gvars
    set_msg "Running $inspector $id ... "
    set tmpfile [tmpfile $gvars(tmpdir) $inspector${id}_ .g]
    beamline store inspector scr $oe $scr $id $tmpfile
    run_${inspector} [list screen $oe $scr] $gvars(run_${inspector}) $tmpfile
    lappend gvars(tmpfiles) $tmpfile
    set_msg "Running $inspector $id ... done "
}

proc run_inspector {args} {
    set info [join $args]
    set target [string toupper [lindex $info 0]]
    switch -glob -- $target {
        "SOURCE" {
	    set inspector [lindex $info 1]
	    set id [lindex $info 2]
	    run_source_inspector $inspector $id
	    set_msg "Running inspector $inspector $id of SOURCE"
	}
        "OE" {
	    set oe [lindex $info 1]
	    set inspector [lindex $info 2]
	    set id [lindex $info 3]
	    run_oe_inspector $oe $inspector $id
	    set_msg "Running inspector $inspector $id of OE $oe"
	}
	"SCR*" {
	    set oe [lindex $info 1]
	    set scr [lindex $info 2]
	    set inspector [lindex $info 3]
	    set id [lindex $info 4]
	    run_scr_inspector $oe $scr $inspector $id
	    set_msg "Running inspector $inspector $id of SCR $scr/$oe"
	}
	default {
	    set_msg "RUNNING inspector $info not supported yet."
	}
    }
}

proc run_selected_cmd {} {
    set_msg "Running selected tool ... "
    set cur_selection [string trim [get_current_selection]]
    if {$cur_selection == ""} {
	dialog .info_d "Run Tool" \
	    "Must select a tool in BEAMLINE panel to run it." \
	    "error" 0 Dismiss
        set_msg "Must select a tool in BEAMLINE panel to run it. Cancelled"
	return
    }
    set selection_type [string toupper [lindex $cur_selection 0]]
    switch -glob $selection_type {
	"SOURCE" {
	    return [run_source_cmd]
	}
	"OE" {
	    set cur_oe [lindex $cur_selection 1]
	    return [run_oe_cmd $cur_oe]
	}
	"SCR*" {
	    set cur_oe [lindex $cur_selection 1]
	    set cur_scr [lindex $cur_selection 2]
	    return [run_oe_cmd $cur_oe]
	}
	INSPECTOR {
	    return [run_inspector [lrange $cur_selection 1 end]]
	}
	default {
	    dialog .info_d "Run Tool" \
		"Trying to run unknown tool type (internal bug)" \
		"error" 0 Dismiss
	    set_msg "Run Tool cancelled due to internal bug."
	    return
	}
    }
}

#----------------------------------------------------------------------#
# PLOT stuff
#----------------------------------------------------------------------#

proc plot_cmd {} {
    global gvars
    incr gvars(plot_windows)
    set plot_w .shadow_plot$gvars(plot_windows)]
    shplot:main $plot_w
}

#-----------------------------------------------------------------------#
#
# Workspace stuff
#
#-----------------------------------------------------------------------#

proc annotate_workspace_cmd {} {
    global gvars gprefs workspace g_dialog_button
    set annotate_w .annotate

    catch "destroy $annotate_w"
    toplevel $annotate_w -relief sunken -border 1

    set f1 [frame ${annotate_w}.f1 -class Annotation]

    set w0 [label ${f1}.message -justify left -text {
Annotate your current workspace using the form below. This annotation is
saved along with your workspace and is displayed every time you load it.} ]

    set w1 [label ${f1}.title_msg -justify left -text "Title:"]
    set w2 [label ${f1}.subtitle_msg -justify left -text "Subtitle:"]
    set w3 [label ${f1}.ann_msg -justify left -text "Annotation:"]

    set e1 [entry ${f1}.title -width 60]
    set e2 [entry ${f1}.subtitle -width 60]
    set e3 [text ${f1}.ann -width 60 -height 20 -wrap word]

    $e1 insert 0 $workspace(title)
    $e2 insert 0 $workspace(subtitle)
    $e3 insert end $workspace(annotation)

    pack $w0 -side top -pady 20
    pack $w1 -side top
    pack $e1 -side top
    pack $w2 -side top
    pack $e2 -side top
    pack $w3 -side top
    pack $e3 -side top

    bind ${e1} <Escape> 	"set g_dialog_button 0"
    bind ${e2} <Escape> 	"set g_dialog_button 0"
    bind ${e3} <Escape> 	"set g_dialog_button 0"

    set f2 [frame ${annotate_w}.f2]

    button ${f2}.accept -text "Accept" -command "set g_dialog_button 1"
    button ${f2}.cancel -text "Cancel" -command "set g_dialog_button 0"
    pack ${f2}.accept -side left -padx 25 -pady 5
    pack ${f2}.cancel -side right -padx 25 -pady 5

    pack $f1 -side top -padx 5 -pady 5 -expand yes -fill both
    pack $f2 -side top -padx 5 -pady 5 -expand yes -fill both


    #
    # now position at the center of root window.
    #

    # 4. Withdraw the window, then update all the geometry information
    # so we know how big it wants to be, then center the window in the
    # display and de-iconify it.

    wm withdraw $annotate_w
    update idletasks
    set x [expr [winfo screenwidth $annotate_w]/2 - \
        [winfo reqwidth $annotate_w]/2 \
	    - [winfo vrootx [winfo parent $annotate_w]]]
    set y [expr [winfo screenheight $annotate_w]/2 - \
        [winfo reqheight $annotate_w]/2 \
	    - [winfo vrooty [winfo parent $annotate_w]]]
    wm geom $annotate_w +$x+$y
    wm deiconify $annotate_w


    set old_focus [focus]
    catch {grab $annotate_w}
    focus $e1

    tkwait variable g_dialog_button

    # get the values if not cancelled
    if {$g_dialog_button != 0} {
        set workspace(title) [$e1 get]
        set workspace(subtitle) [$e2 get]
        set workspace(annotation) [$e3 get 1.0 end]
	set gvars(modified) 1
	if {$gvars(editing_what) == "annotation:"} {
	    show_annotation_cmd
	}
    }
    grab release $annotate_w
    destroy $annotate_w
    catch {focus -force $old_focus}
    return
}

proc show_annotation_cmd {} {
    show_annotation_page
}

proc show_workspace_info_cmd {{file {}}} {
    if {$file == ""} {
	set types {
	    {{SHADOW Workspace Files}	{.ws}}
	    {{Misc Data Files}		{.dat}}
	    {{All Files}			*}
	}
	set file [tk_getOpenFile \
	    -filetypes $types \
	    -defaultextension ".ws" \
	    -title "Get info on Workspaces saved previously" \
	]
    }
    if {$file == ""} {
	set_msg "Workspace info ... Cancelled"
        return
    }

    State:peek $file info

    global gvars gprefs g_dialog_button
    set workspace_info_w .workspace_info

    catch "destroy $workspace_info_w"
    toplevel $workspace_info_w -relief sunken -border 1

    set f1 [frame ${workspace_info_w}.f1 -class Annotation]

    set w01 [label ${f1}.author -justify left \
        -text "Author: $info(username)"]
    set w02 [label ${f1}.time -justify left \
        -text "Created/Last Modified: $info(timestamp)"]
    set w03 [label ${f1}.machine -justify left \
        -text "On Machine: $info(machine)"]

    set w1 [label ${f1}.title_msg -justify left -text "Title:"]
    set w2 [label ${f1}.subtitle_msg -justify left -text "Subtitle:"]
    set w3 [label ${f1}.ann_msg -justify left -text "Annotation:"]

    set e1 [entry ${f1}.title -width 60]
    set e2 [entry ${f1}.subtitle -width 60]
    set e3 [text ${f1}.ann -width 60 -height 20 -wrap word]

    $e1 insert 0 $info(title)
    $e2 insert 0 $info(subtitle)
    $e3 insert end $info(annotation)

    pack $w01 -side top
    pack $w02 -side top
    pack $w03 -side top
    pack $w1 -side top
    pack $e1 -side top
    pack $w2 -side top
    pack $e2 -side top
    pack $w3 -side top
    pack $e3 -side top

    bind ${workspace_info_w} <Return> 	"set g_dialog_button 0"
    bind ${workspace_info_w} <Escape> 	"set g_dialog_button 0"
    bind ${e1} <Escape> 		"set g_dialog_button 0"
    bind ${e1} <Return> 		"set g_dialog_button 0"
    bind ${e2} <Escape> 		"set g_dialog_button 0"
    bind ${e2} <Return> 		"set g_dialog_button 0"
    bind ${e3} <Escape> 		"set g_dialog_button 0"
    bind ${e3} <Return> 		"set g_dialog_button 0"

    set f2 [frame ${workspace_info_w}.f2]

    button ${f2}.accept -text "OK" -command "set g_dialog_button 0"
    pack ${f2}.accept -side top -padx 25 -pady 5

    pack $f1 -side top -padx 5 -pady 5 -expand yes -fill both
    pack $f2 -side top -padx 5 -pady 5 -expand yes -fill both


    #
    # now position at the center of root window.
    #

    # 4. Withdraw the window, then update all the geometry information
    # so we know how big it wants to be, then center the window in the
    # display and de-iconify it.

    wm withdraw $workspace_info_w
    update idletasks
    set x [expr [winfo screenwidth $workspace_info_w]/2 - \
        [winfo reqwidth $workspace_info_w]/2 \
	    - [winfo vrootx [winfo parent $workspace_info_w]]]
    set y [expr [winfo screenheight $workspace_info_w]/2 - \
        [winfo reqheight $workspace_info_w]/2 \
	    - [winfo vrooty [winfo parent $workspace_info_w]]]
    wm geom $workspace_info_w +$x+$y
    wm deiconify $workspace_info_w

    catch {grab $workspace_info_w}

    tkwait variable g_dialog_button

    grab release $workspace_info_w
    destroy $workspace_info_w
    return
}

#-----------------------------------------------------------------------#
#
# Rename the beamline components for annotations.
#
#-----------------------------------------------------------------------#

proc rename_selected_cmd {} {
    set_msg "Renaming selected tool ... "
    set cur_selection [string trim [get_current_selection]]
    if {$cur_selection == ""} {
	dialog .info_d "Rename Tool" \
	    "Must select a tool in BEAMLINE panel to rename it." \
	    "error" 0 Dismiss
        set_msg "Must select a tool in BEAMLINE panel to rename it. Cancelled"
	return
    }
    set title_cmd_stub ""
    
    set selection_type [string toupper [lindex $cur_selection 0]]
    switch -glob $selection_type {
	"SOURCE" {
	    set title_cmd_stub "source"
	}
	"OE" {
	    set oe [lindex $cur_selection 1]
	    set title_cmd_stub "oe $oe"
	}
	"SCR*" {
	    set oe [lindex $cur_selection 1]
	    set scr [lindex $cur_selection 2]
	    set title_cmd_stub "scr $oe $scr"
	}
	INSPECTOR {
	    set target [string toupper [lindex $cur_selection 1]]
	    set id [lindex $cur_selection [expr [llength $cur_selection] - 3]]
	    puts stderr "Cur selection = $cur_selection"
	    switch -glob -- $target {
		SOURCE {
		    set title_cmd_stub "inspector source $id"
		}
		OE {
		    set oe [lindex $cur_selection 2]
		    set title_cmd_stub "inspector oe $oe $id"
		}
		SCR* {
		    set oe [lindex $cur_selection 2]
		    set scr [lindex $cur_selection 3]
		    set title_cmd_stub "inspector scr $oe $scr $id"
		}
	    }
	}
	default {
	    dialog .info_d "Rename Tool" \
		"Trying to rename unknown tool type (internal bug)" \
		"error" 0 Dismiss
	    set_msg "Rename Tool cancelled due to internal bug."
	    return
	}
    }
    set old_name [eval "beamline tget $title_cmd_stub"]
    set newname [dialog_str .dialog_rename \
	"Rename Tool" "Enter the new title/name" "$old_name"]
    
    if {$newname == ""} {
        set_msg "Rename Tool cancelled by user."
	return
    }

    set new_name_cmd "beamline tset $title_cmd_stub \"$newname\""
    if [catch "$new_name_cmd" msg] {
	dialog .info_d "Rename Error" \
	    "Error renaming selected tool ($msg)." \
	    {} 0 Dismiss
    }
}

#----------------------------------------------------------------------#
# Editbar (tool bar to go edit various entries) routines
#----------------------------------------------------------------------#

proc editbar_make_msg {args} {
    global gvars
    set cur_msg "None"
    set args [join $args]
    set toolname [string toupper [lindex $args 0]]
    switch -glob -- $toolname {
	BEAMLINE { 
	    set cur_msg "System"
	}
	SOURCE { 
	    set cur_msg "Source"
	}
	OE { 
	    set oe_id [lindex $args 1]
	    set cur_msg "OE $oe_id"
	}
	SCR* { 
	    set oe_id [lindex $args 1]
	    set scr_id [lindex $args 2]
	    set cur_msg "Screen $scr_id of OE $oe_id"
	}
	INSPECTOR {
	    set type [string toupper [lindex $args 1]]
	    switch -glob -- $type {
		"SOURCE" {
		    set inspector [lindex $args 2]
		    set id [lindex $args 3]
		    set cur_msg "$inspector $id of SOURCE"
		}
	        "OE" {
		    set oe [lindex $args 2]
		    set inspector [lindex $args 3]
		    set id [lindex $args 4]
		    set cur_msg "$inspector $id of OE $oe"
		}
	        "SCR*" {
		    set oe [lindex $args 2]
		    set scr [lindex $args 3]
		    set inspector [lindex $args 4]
		    set id [lindex $args 5]
		    set cur_msg "$inspector $id of Screen $scr/$oe"
		}
		default {
		    puts stderr "editbar:cur_callback: NOT IMPL"
		}
	    }
	}
    }
    return $cur_msg
}

proc editbar_make_cmd {args} {
    global gvars
    set cur_msg ""
    set args [join $args]
    set toolname [string toupper [lindex $args 0]]
    switch -glob -- $toolname {
	BEAMLINE { 
	    set cur_msg "beamline"
	}
	SOURCE { 
	    set cur_msg "source"
	}
	OE { 
	    set oe_id [lindex $args 1]
	    set cur_msg "oe $oe_id"
	}
	SCR* { 
	    set oe_id [lindex $args 1]
	    set scr_id [lindex $args 2]
	    set cur_msg "screen $oe_id $scr_id"
	}
	INSPECTOR {
	    set type [string toupper [lindex $args 1]]
	    switch -glob -- $type {
		"SOURCE" {
		    set inspector [lindex $args 2]
		    set id [lindex $args 3]
		    set cur_msg "inspector source $id"
		}
	        "OE" {
		    set oe_id [lindex $args 2]
		    set inspector [lindex $args 3]
		    set id [lindex $args 4]
		    set cur_msg "inspector oe $oe_id $id"
		}
	        "SCR*" {
		    set oe_id [lindex $args 2]
		    set scr_id [lindex $args 3]
		    set inspector [lindex $args 4]
		    set id [lindex $args 5]
		    set cur_msg "inspector scr $oe_id $scr_id $id"
		}
		default {
		    puts stderr "editbar:cur_callback: NOT IMPL"
		}
	    }
	}
    }
    return $cur_msg
}

proc editbar_callback {args} {
    global gvars
    $gvars(cur_editbar) config -text "[editbar_make_msg $args]"
    set toolname [string toupper [lindex $args 0]]
    switch -exact -- $toolname {
	SOURCE { 
	    editbar:edit_highlight $gvars(editbar).toolbox.a $args 1
	    return [edit_src]
	}
	OE { 
	    set oe_id [lindex $args 1]
	    editbar:edit_highlight $gvars(editbar).toolbox.a $args 1
	    return [edit_oe $oe_id]
	}
	SCREEN { 
	    set oe_id [lindex $args 1]
	    set scr_id [lindex $args 2]
	    editbar:edit_highlight $gvars(editbar).toolbox.a $args 1
	    return [edit_scr $oe_id $scr_id]
	}
	INSPECTOR {
	    set type [string toupper [lindex $args 1]]
	    editbar:edit_highlight $gvars(editbar).toolbox.a $args 1
	    switch -glob -- $type {
		"SOURCE" {
		    return [edit_source_inspector [lrange $args 2 end]]
		}
	        "OE" {
		    return [edit_oe_inspector [lrange $args 2 end]]
		}
	        "SCR*" {
		    return [edit_scr_inspector [lrange $args 2 end]]
		}
		default {
		    puts stderr "editbar:edit_inspector: NOT IMPL"
		}
	    }
	}
    }
}

proc editbar_select_callback {args} {
    global gvars
    vputs "editbar_select_callback $args"
    $gvars(cur_selectbar) config -text "[editbar_make_msg $args]"
    eval beamline select [editbar_make_cmd $args]
}

proc insert_source_in_editbar {} { 
    global gvars gpage2tool gtool2page
    if {[get_source] == ""} {return}
    set label "[beamline tget source]"
    editbar:add $gvars(editbar).toolbox.a entry [list source "$label"]
    set inspectors [beamline get inspectors source]
    set num_inspectors [llength $inspectors]
    for {set ins 1} {$ins <= $num_inspectors} {incr ins} {
	set inspector_info [lindex $inspectors [expr $ins - 1]]
	set inspector [lindex $inspector_info 0]
	set label [beamline tget inspector source $ins]
	editbar:add $gvars(editbar).toolbox.a entry \
	    [list inspector source [set gtool2page($inspector)] $ins \
	    "$label"]
    }
}

#
# delete the SOURCE and all its inspectors. Note that the editbar deletes
# the entire the SOURCE tree, so we don't have to do anything special for
# the inspectors. 
#
proc remove_source_from_editbar {} {
    global gvars
    catch "editbar:delete $gvars(editbar).toolbox.a [list source]"
}

proc update_editbar_source {} {
    remove_source_from_editbar
    insert_source_in_editbar
}
    

proc remove_all_oe_from_editbar {} {
    global gvars
    #
    # HACK. Adding one to num_oe. This is needed because of the way
    # the status information is kept in the back-end (our information
    # lags behind by one in the GUI front-end after deleting/adding an
    # OE). CHECK/FIXME:
    #
    catch "editbar:delete_all_oe \
        $gvars(editbar).toolbox.a [expr [get_num_oe] + 1]"
}

proc remove_all_scr_from_editbar {oe_id} {
    global gvars
    catch "editbar:delete_all_scr $gvars(editbar).toolbox.a \
	$oe_id [expr [get_num_scr $oe_id] + 1]"
}

proc insert_all_oe_in_editbar {} {
    global gvars gpage2tool gtool2page
    set num_oe [get_num_oe]
    for {set oe 1} {$oe <= $num_oe} {incr oe} {
	set label "[beamline tget oe $oe]"
	editbar:add $gvars(editbar).toolbox.a entry [list oe $oe \
	    "$label"]
	set num_scr [get_num_scr $oe]
	for {set scr 1} {$scr <= $num_scr} {incr scr} {
	    set label "[beamline tget scr $oe $scr]"
	    editbar:add $gvars(editbar).toolbox.a entry \
		[list screen $oe $scr "$label"]
	    set inspectors [beamline get inspectors scr $oe $scr]
	    set num_inspectors [llength $inspectors]
	    for {set ins 1} {$ins <= $num_inspectors} {incr ins} {
		set label "[beamline tget inspector scr $oe $scr $ins]"
		set inspector_info [lindex $inspectors [expr $ins - 1]]
		set inspector [lindex $inspector_info 0]
		editbar:add $gvars(editbar).toolbox.a entry \
		    [list inspector scr $oe $scr \
		    [set gtool2page($inspector)] $ins "$label"]
	    }
	}
	set inspectors [beamline get inspectors oe $oe]
	set num_inspectors [llength $inspectors]
	for {set ins 1} {$ins <= $num_inspectors} {incr ins} {
	    set inspector_info [lindex $inspectors [expr $ins - 1]]
	    set inspector [lindex $inspector_info 0]
	    set label "[beamline tget inspector oe $oe $ins]"
	    editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector oe $oe [set gtool2page($inspector)] \
		$ins "$label"]
	}
    }
}

proc insert_all_scr_in_editbar {oe} {
    global gvars
    set num_scr [get_num_scr $oe]
    for {set scr 1} {$scr <= $num_scr} {incr scr} {
	set label "[beamline tget scr $oe $oe]"
	editbar:add $gvars(editbar).toolbox.a entry \
	    [list screen $oe $scr "$label"]
	set inspectors [beamline get inspectors scr $oe $scr]
	set num_inspectors [llength $inspectors]
	for {set ins 1} {$ins <= $num_inspectors} {incr ins} {
	    set inspector_info [lindex $inspectors [expr $ins - 1]]
	    set inspector [lindex $inspector_info 0]
	    set label "[beamline tget inspector scr $oe $scr $ins]"
	    editbar:add $gvars(editbar).toolbox.a entry \
	        [list inspector scr $oe $scr [set gtool2page($inspector)] \
		$ins "$label"]
	}
    }
}

proc update_editbar_oe {} {
    remove_all_oe_from_editbar
    insert_all_oe_in_editbar
}
    
proc update_editbar_scr {oe} {
    #
    # HACK for now
    #
    # remove_all_scr_from_editbar $oe
    # insert_all_scr_in_editbar $oe
    #
    # end HACK
    update_editbar_oe
}
    

#----------------------------------------------------------------------#
# Miscalleneous access/helper routines
#----------------------------------------------------------------------#

proc push_curpage {page_w page item} {
    global gvars
    vputs "pushing page $page on stack ==> $gvars(pagestack)..."
    set gvars(pagestack) [linsert $gvars(pagestack) 0 $page]
    if {[llength $gvars(pagestack)] > 0} {
	$gvars(backbtn) configure -state normal
    }
    set gvars(itemstack) [linsert $gvars(itemstack) 0 $item]
    set gvars(pagestack_w) [linsert $gvars(pagestack_w) 0 $page_w]
    vputs "pushed page $page on stack ==> $gvars(pagestack)..."
}

proc pop_curpage {} {
    global gvars
    vputs "popping top of page stack ==> $gvars(pagestack)..."
    if {[llength $gvars(pagestack)] == 0} {
	dialog .info_d "Page Error" \
	    "Menu Page stack already empty. Cannot pop up. Internal Error?." \
	    {} 0 Dismiss
	$gvars(backbtn) configure -state disabled
	return ""
    } else {
	set gvars(curpage) [lindex $gvars(pagestack) 0]
	set gvars(pagestack) [lreplace $gvars(pagestack) 0 0]
	if {[llength $gvars(pagestack)] < 1} {
	    $gvars(backbtn) configure -state disabled
	}
	set gvars(curpageitem) [lindex $gvars(itemstack) 0]
	set gvars(itemstack) [lreplace $gvars(itemstack) 0 0]
	vputs "popped top of page stack ==> $gvars(pagestack)..."
	return "$gvars(curpage) $gvars(curpageitem)"
    }
}

