
# This code creates the user interface for global.
#
# Copyright (c) 1993 - 1995 Pacific Marketing and Consulting, Inc,
#       and ICEM Systems, GmbH.  All rights reserved.
# Author:  Wayne A. Christopher, wayne@icemcfd.com

proc make_display_window {} {
    global display_flag index_min index_max tool_dir
    global guibase_dir background_color hgrid_plane
    
    top_window .e 0 Display "" .v 0

    # Now create menu
    
    frame .e.buts -relief ridge -borderwidth 2
    
    checkbutton .e.buts.curve -text Curves -variable display_flag(curve) \
	    -command "update_display curve" -anchor w
    checkbutton .e.buts.surf -text Surfaces -variable display_flag(surf) \
	    -command "update_display surf" -anchor w
    checkbutton .e.buts.block -text Blocks -variable display_flag(block) \
	    -command "update_display block" -anchor w
    checkbutton .e.buts.quad -text Staircase -variable display_flag(quad) \
	    -command "update_display quad" -anchor w
    checkbutton .e.buts.edge -text Edges -variable display_flag(edge) \
	    -command "update_display edge" -anchor w
    checkbutton .e.buts.hgrid -text H-grid -variable display_flag(hgrid) \
	    -command "update_display hgrid" -anchor w
    checkbutton .e.buts.mesh -text Mesh -variable display_flag(mesh) \
	    -command "update_display mesh" -anchor w
    checkbutton .e.buts.planes -text "Planes/Boxes" \
	-variable display_flag(planes) -command "update_display iplane"
    
    set display_flag(slice) 0
    #checkbutton .e.buts.slice -text "Slices"
    # -variable display_flag(slice) -command "update_display slice"
    
    checkbutton .e.buts.point -text Points -variable display_flag(point) \
	    -command "update_display point" -anchor w
    button .e.buts.scan -text "Scan planes" -command "mesh_scan_planes"
    #button .e.buts.iplanes -text "Index planes" -command "mesh_index_planes"
    
    menubutton .e.buts.curveopt -text "Opts" \
	    -menu .e.buts.curveopt.m -relief raised -borderwidth 2 \
	    -state disabled
    menubutton .e.buts.surfopt  -text "Opts" \
	    -menu .e.buts.surfopt.m -relief raised -borderwidth 2
    menubutton .e.buts.blockopt -text "Opts" \
	    -menu .e.buts.blockopt.m -relief raised -borderwidth 2
    menubutton .e.buts.quadopt -text "Opts" \
	    -menu .e.buts.quadopt.m -relief raised -borderwidth 2
    menubutton .e.buts.edgeopt -text "Opts" \
	    -menu .e.buts.edgeopt.m -relief raised -borderwidth 2
    menubutton .e.buts.hgridopt -text "Opts" \
	    -menu .e.buts.hgridopt.m -relief raised -borderwidth 2
    menubutton .e.buts.meshopt  -text "Opts" \
	    -menu .e.buts.meshopt.m -relief raised -borderwidth 2
    menubutton .e.buts.planesopt  -text "Opts" \
	    -menu .e.buts.planesopt.m -relief raised -borderwidth 2
    # menubutton .e.buts.sliceopt  -text "Opts" 
    # -menu .e.buts.sliceopt.m -relief raised -borderwidth 2
    menubutton .e.buts.pointopt  -text "Opts" \
	    -menu .e.buts.pointopt.m -relief raised -borderwidth 2
    
    frame .e.buts.hplane
    radiobutton .e.buts.hplane.x -text X -variable hgrid_plane -value x \
	    -command "update_display hgrid"
    radiobutton .e.buts.hplane.y -text Y -variable hgrid_plane -value y \
	    -command "update_display hgrid"
    radiobutton .e.buts.hplane.z -text Z -variable hgrid_plane -value z \
	    -command "update_display hgrid"
    pack .e.buts.hplane.x .e.buts.hplane.y .e.buts.hplane.z -side left
    set hgrid_plane "x"
    
    frame .e.buts.hval
    button .e.buts.hval.less -text <- -command "hgrid_incr_val -0.05"
    button .e.buts.hval.more -text -> -command "hgrid_incr_val 0.05"
    entry .e.buts.hval.v -relief sunken -background white -borderwidth 2 \
	    -textvariable hgrid_value -width 8
    bind .e.buts.hval.v <Return> "update_display hgrid"
    pack .e.buts.hval.less .e.buts.hval.v .e.buts.hval.more -side left
    
    button .e.buts.hselect -text "Screen select" -command hgrid_get_val
    
    blt_table .e.buts .e.buts.curve      5,1 -columnspan 2 -anchor w
    blt_table .e.buts .e.buts.curveopt   5,3 -columnspan 1 -fill x -anchor w
    blt_table .e.buts .e.buts.surf       7,1 -columnspan 2 -anchor w
    blt_table .e.buts .e.buts.surfopt    7,3 -columnspan 1 -fill x -anchor w
    blt_table .e.buts .e.buts.block      9,1 -columnspan 2 -anchor w
    blt_table .e.buts .e.buts.blockopt   9,3 -columnspan 1 -fill x -anchor w
    blt_table .e.buts .e.buts.quad      11,1 -columnspan 2 -anchor w
    blt_table .e.buts .e.buts.quadopt   11,3 -columnspan 1 -fill x -anchor w
    blt_table .e.buts .e.buts.edge      12,1 -columnspan 2 -anchor w
    blt_table .e.buts .e.buts.edgeopt   12,3 -columnspan 1 -fill x -anchor w
    blt_table .e.buts .e.buts.planes    13,1 -columnspan 2 -anchor w
    blt_table .e.buts .e.buts.planesopt 13,3 -columnspan 1 -fill x -anchor w
    # blt_table .e.buts .e.buts.slice    13,1 -columnspan 2 -anchor w
    # blt_table .e.buts .e.buts.sliceopt 13,3 -columnspan 1 -fill x -anchor w
    blt_table .e.buts .e.buts.point     14,1 -columnspan 2 -anchor w
    blt_table .e.buts .e.buts.pointopt  14,3 -columnspan 1 -fill x -anchor w
    blt_table .e.buts .e.buts.hgrid     15,1 -columnspan 2 -anchor w
    blt_table .e.buts .e.buts.hgridopt  15,3 -columnspan 1 -fill x -anchor w
    blt_table .e.buts .e.buts.hplane    16,2 -columnspan 3 -fill x -anchor w
    blt_table .e.buts .e.buts.hval      17,2 -columnspan 3 -fill x -anchor w
    blt_table .e.buts .e.buts.hselect   18,2 -columnspan 3 -fill x -anchor w
    blt_table .e.buts .e.buts.mesh      19,1 -columnspan 2 -anchor w
    blt_table .e.buts .e.buts.meshopt   19,3 -columnspan 1 -fill x -anchor w
    blt_table .e.buts .e.buts.scan      20,2 -columnspan 2 -fill x -anchor w
    
    menu .e.buts.curveopt.m
    menu .e.buts.surfopt.m
    menu .e.buts.blockopt.m
    menu .e.buts.quadopt.m
    menu .e.buts.edgeopt.m
    menu .e.buts.hgridopt.m
    menu .e.buts.planesopt.m
    # menu .e.buts.sliceopt.m
    menu .e.buts.pointopt.m
    menu .e.buts.meshopt.m
    
    # .e.buts.pointopt configure -state disabled
    .e.buts.planesopt configure -state disabled

    # options that are currently disabled or obsolete
    
    # obsolete
    
    # "Cell centered"   quad cell_centered
    
    # obsolete ?
    
    # "Outer"           quad outer
    # "Outer"           mesh outer
    
    # disabled
    
    # "Ids"		slice ids 0
    
    foreach vv {
	{ "Full"               surf full surf }
	{ "Params"             surf params surf }
	{ "Solid"              surf solid surf }

	{ "Outer"              block outer block}
	{ "Boundary"           block boundary block}
	{ "Full"               block full block}
	{ "Solid"              block solid block 0 }
	{ "Grid"               block grid  block 0 }
	{ "Surf. Icepts"       block sicepts block 0 }

	{ "Quads"              quad quad "quad edge" }
	{ "Bars"               quad bar "quad edge" }
	{ "Solid"              quad solid "quad edge" }
	{ "Hid. wire"	       quad hidden "quad edge" }
	{ "No Highlight"       quad unneeded quad 0 0 }
	{ "Highlight Unneeded" quad unneeded quad 1 ""}
	{ "Only Unneeded"      quad unneeded quad 2 ""}
	{ __separator__        quad}
	{ "No Check"           quad ff_type quad -none ""}
	{ "Check Staircase"    quad ff_type quad -standard -standard}
	{ "Restricted Check"   quad ff_type quad -restrict ""}
	{ __separator__        quad}
	{ "Show Marking Path"  quad marking __none__}
	{ "AutoFix"            quad autofix __none__}
	{ "Fix Volume Ids"     quad fixvolid __none__}
	{ __separator__        quad}
	{ "Shrinkwrap"         quad shrinkwrap}
	{ "Special Mat Only"   quad specialmat}
	{ "Outside Boundary"   quad outside}
	{ "Save ORFN Mat Quads" quad saveallquads}
	{ __separator__        quad}
	{ "Assign Unknown"     quad assignmat quad -assignmat ""}
	{ "Assign Unk. to ORFN" quad assignmat quad -ORFN ""}
	{ "Fix Unknown"        quad assignmat quad -fixwall ""}
	{ __separator__        quad}
	{ "Rebuild Staircase"  quad rebuild __command__ edit_rebuild_stair}
	
	{ "Single"          edge dispval edge single single}
	{ "2 Singles"       edge dispval edge 2singles "" }
	{ "Double"          edge dispval edge double "" }
	{ "Multiple"        edge dispval edge multiple "" }
	{ "Single+Multiple" edge dispval edge s+m "" }
	{ "Single&Multiple" edge dispval edge s&m "" }

	{ "Prescribed"      point pres point 1 }
	{ "Material"        point mater point }
	
	{ "Solid"           hgrid solid hgrid }
	{ "Cut plane"       hgrid cut hgrid }
	{ "Volume"          hgrid volume hgrid }

	{ "Solid"           mesh solid mesh }
	{ "Auto Fix"        mesh autofix mesh 1}
	{ "No Materials"    mesh no_mat mesh }
    } {
	set label [lindex $vv 0]
	set group [lindex $vv 1]
	set m .e.buts.${group}opt.m
	if {$label == "__separator__"} {
	    $m add separator
	} else {
	    set m .e.buts.${group}opt.m
	    set v ${group}_[lindex $vv 2]
	    set ud [lindex $vv 3]
	    if {$ud == "__command__"} {
		$m add command -label $label -command [lindex $vv 4]
	    } else {
		if {$ud == "__none__"} {
		    set upcom ""
		} else {
		    set upcom "-command {update_display $ud}"
		}
		if {[llength $vv] <= 5} {
		    if {[lindex $vv 4] != ""} {
			set display_flag($v) [lindex $vv 4]
		    }
		    eval $m add checkbutton -label \"[lindex $vv 0]\" \
			-variable display_flag($v) $upcom
		} else {
		    set val [lindex $vv 4]
		    set curval [lindex $vv 5]
		    if {$curval != ""} { set display_flag($v) $curval }
		    eval $m add radiobutton -label \"$label\" \
			-variable display_flag($v) -value $val $upcom
		}
	    }
	}
    }
       
    set display_flag(edge_dispval) s&m
    set display_flag(edge_dispval_modal) edges_quads
    .e.buts.edgeopt.m add separator
    .e.buts.edgeopt.m add radiobutton -label "Display Edges Only" \
	-variable display_flag(edge_dispval_modal) -value edges_only \
	-command "update_display edge"
    .e.buts.edgeopt.m add radiobutton -label "Display Edge Quads" \
	-variable display_flag(edge_dispval_modal) -value edges_quads \
	-command "update_display edge"
    
    .e.buts.edgeopt.m add separator
    .e.buts.edgeopt.m add checkbutton -label "Solid" \
	-variable display_flag(quad_solid) \
	-command "update_display quad edge"
    .e.buts.edgeopt.m add checkbutton -label "Hid. Wire" \
	-variable display_flag(quad_hidden) \
	-command "update_display quad edge"
    
    .e.buts.edgeopt.m add separator
    .e.buts.edgeopt.m add command -label "Single color" \
	-command "edge_color single"
    .e.buts.edgeopt.m add command -label "Double color" \
	-command "edge_color double"
    .e.buts.edgeopt.m add command -label "Multiple color" \
	-command "edge_color multiple"
  
    global_edge_modal
    if 0 {
	frame .e.buts.line1 -borderwidth 1 -background black -relief raised
	blt_table .e.buts .e.buts.line1 15,1 -columnspan 3 \
		-anchor w -pady 5 -fill x
    }
    
    set r 20
    
    blt_table_row .e.buts configure 0 -height 2
    blt_table_column .e.buts configure 0 -width 5
    blt_table_column .e.buts configure 4 -width 5
    blt_table_column .e.buts configure 1 -width 20

    if 0 {
	frame .e.buts.line2 -borderwidth 1 -background black -relief raised
	checkbutton .e.buts.depth -text Depthcue -variable display_depthcue \
	    -command depthcue_update
	checkbutton .e.buts.axes -text Axes -variable display_axes \
	    -command "axes_update 1"
	button .e.buts.back -text "Background color" -command set_background
	#button .e.buts.node -text "Node IJK" -command node_ijk    
	
	blt_table .e.buts .e.buts.line2 30,1 -columnspan 3 \
	    -anchor w -pady 5 -fill x
	blt_table .e.buts .e.buts.depth 31,1 -columnspan 3 -anchor w -pady -2
	blt_table .e.buts .e.buts.axes 32,1 -columnspan 3 -anchor w -pady -2
	blt_table .e.buts .e.buts.back 33,1 -columnspan 3 -anchor w
	#blt_table .e.buts .e.buts.node 34,1 -columnspan 3 -anchor w
    }
    
    # ----------------
    
    frame .e.fam -relief ridge -borderwidth 2
    
    label .e.fam.sl -text "Surface families"
    frame .e.fam.s
    
    label .e.fam.vl -text "Volume families"
    frame .e.fam.v
    
    pack .e.fam.sl .e.fam.s .e.fam.vl .e.fam.v -side top -fill both -expand 1
    
    # ----------------
    
    frame .e.ind -relief ridge -borderwidth 2
    
    label .e.ind.lab -text "Index control"
    button .e.ind.reset -text "Reset" -command index_reset
    button .e.ind.query -text "Query" -command index_query
    
    canvas .e.ind.c -width 10 -height 10
    frame .e.ind.c.win
    set fitem [.e.ind.c create window 0 0 -window .e.ind.c.win -anchor nw]
    frame .e.ind.c.win.ch
    pack .e.ind.c.win.ch -side left -fill both
    
    scrollbar .e.ind.scroll -command ".e.ind.c yview"  -relief sunken \
	    -borderwidth 2 -orient v
    .e.ind.c configure -yscrollcommand ".e.ind.scroll set"
    
    pack .e.ind.lab -side top
    pack .e.ind.query .e.ind.reset -side bottom -fill both -padx 20
    pack .e.ind.scroll .e.ind.c -side right -fill both
    
    # ----------------
    
    pack .e.buts .e.fam .e.ind -side top -fill both -padx 2 -pady 2
    set background_color #000000
}

# which = single, double, multiple

proc global_edge_modal {} {
    global display_flag
    
    set m .e.buts.edgeopt.m
    if {$display_flag(edge_dispval_modal) == "edges_quads"} {
	$m entryconfigure 2 -state normal
	$m entryconfigure 3 -state disabled
	$m entryconfigure 5 -state disabled
	$m entryconfigure 6 -state normal
	$m entryconfigure 11 -state normal
	$m entryconfigure 12 -state normal
    } else {
	$m entryconfigure 2 -state disabled
	$m entryconfigure 3 -state normal
	$m entryconfigure 5 -state normal
	$m entryconfigure 6 -state disabled
	$m entryconfigure 11 -state disabled
	$m entryconfigure 12 -state disabled
    }
}

proc edge_color {which} {
    global edge_color
    
    set def $edge_color($which)
    
    set col [edit_one_color "Please define the $which edge color." $def]
    if {[scan $col \#%2x%2x%2x r g b] != 3} {
	mess "Bad color $col\n" red
	return
    }
    set edge_color($which) $col
    update_display edge
}

proc node_ijk {} {
    set banner "Select a node with the left button; right = done."
    while 1 {
	set last_line [select_node $banner node 1]
	if {$last_line == ""} break
	mess "IJK = $last_line\n"
    }
}

proc hgrid_get_val {} {
    global hgrid_value hgrid_plane last_line
    
    banner "Select a location with the left button; right = cancel."
    command graphics_loc 0
    banner ""
    if {$last_line == ""} return
    switch $hgrid_plane {
	x { set hgrid_value [lindex $last_line 0] }
	y { set hgrid_value [lindex $last_line 1] }
	z { set hgrid_value [lindex $last_line 2] }
    }
    update_display hgrid
}

proc hgrid_incr_val {amt} {
    global hgrid_value hgrid_plane hgrid_bbox display_flag
    
    set display_flag(hgrid_cut) 1
    switch $hgrid_plane {
	x { set i 0 } y { set i 1 } z { set i 2 }
    }
    
    if ![info exists hgrid_bbox] hgrid_assign_bbox
    
    set min [lindex [lindex $hgrid_bbox 0] $i]
    set max [lindex [lindex $hgrid_bbox 1] $i]
    if {$hgrid_value == ""} {
	set hgrid_value [expr ($min+$max)/2]
    }
    set hgrid_value [expr {$hgrid_value + ($max - $min) * $amt}]
    if {$hgrid_value < $min} { set hgrid_value $min }
    if {$hgrid_value > $max} { set hgrid_value $max }
    update_display hgrid
}

proc hgrid_assign_bbox {} {
    global hgrid_bbox last_line
    
    command "bounding_box" 0
    set hgrid_bbox [list [lrange $last_line 0 2] [lrange $last_line 3 5]]
}

proc setup_index_box {} {
    global index_min_limit index_max_limit prev_index_dims guibase_dir
    
    set index_dims [lsort -integer [array names index_min_limit]]
    if {[info exists prev_index_dims] && ($prev_index_dims == $index_dims)} {
	return
    }
    set prev_index_dims $index_dims
    
    set w .e.ind.c.win.ch
    foreach ch [winfo children $w] { destroy $ch }
    
    set up @$guibase_dir/goup.xbm
    set dn @$guibase_dir/godown.xbm
    
    set row 0
    foreach dim $index_dims {
	if {$dim < 3} {
	    set dname [lindex {I J K} $dim]
	} else {
	    set dname O$dim
	}
	label $w.lab$dim -text $dname:
	label $w.col$dim -text "-"
	entry $w.low$dim -width 3 -background white -borderwidth 2 \
		-relief sunken -textvariable index_min($dim)
	button $w.lup$dim -bitmap $up -command "index_modify $dim 0 1"
	button $w.ldn$dim -bitmap $dn -command "index_modify $dim 0 -1"
	entry $w.hi$dim -width 3 -background white -borderwidth 2 \
		-relief sunken -textvariable index_max($dim)
	button $w.hup$dim -bitmap $up -command "index_modify $dim 1 1"
	button $w.hdn$dim -bitmap $dn -command "index_modify $dim 1 -1"
	
	bind $w.low$dim <Return> { update_display quad edge block mesh vert }
	bind $w.hi$dim <Return>  { update_display quad edge block mesh vert }
	
	set one_height [expr {[winfo reqheight $w.hdn$dim] + \
		[winfo reqheight $w.hi$dim]} + 1]
	
	blt_table $w $w.lab$dim $row,0
	blt_table $w $w.low$dim $row,1 -columnspan 2 -fill x
	blt_table $w $w.col$dim $row,3
	blt_table $w $w.hi$dim  $row,4 -columnspan 2 -fill x
	incr row
	blt_table $w $w.lup$dim $row,1
	blt_table $w $w.ldn$dim $row,2
	blt_table $w $w.hup$dim $row,4
	blt_table $w $w.hdn$dim $row,5
	incr row
    }
    # Needed, otherwise winfo reqwidth doesn't work.
    update
    .e.ind.c configure -scrollregion \
	    "0 0 [winfo reqwidth $w] [winfo reqheight $w]"
    .e.ind.c configure -width [winfo reqwidth $w] \
	    -height [expr {$one_height * 3}]
}

# -----------------------------------

proc index_update_all {{update 1}} {
    foreach i {0 1 2} {
	index_modify $i 0 0 0
	index_modify $i 1 0 0
    }
    if $update { update_display block mesh vert }
}

proc index_modify {ind max dir {update 1}} {
    global index_min index_max index_min_limit index_max_limit
    
    set minl $index_min_limit($ind)
    set maxl $index_max_limit($ind)
    if $max {
	incr index_max($ind) $dir
	set v $index_max($ind)
	if {$v < $minl} { set index_max($ind) $minl }
	if {$v > $maxl} { set index_max($ind) $maxl }
	if {$index_max($ind) < $index_min($ind)} {
	    set index_min($ind) $index_max($ind)
	}
    } else {
	incr index_min($ind) $dir
	set v $index_min($ind)
	if {$v < $minl} { set index_min($ind) $minl }
	if {$v > $maxl} { set index_min($ind) $maxl }
	if {$index_max($ind) < $index_min($ind)} {
	    set index_max($ind) $index_min($ind)
	}
    }
    if $update { update_display quad edge block scan mesh vert }
}

proc index_reset {} {
    global index_min index_max index_min_limit index_max_limit
    
    foreach v [array names index_min] {
	set index_min($v) $index_min_limit($v)
    }
    foreach v [array names index_max] {
	set index_max($v) $index_max_limit($v)
    }
    update_display quad edge block scan mesh vert
}

proc index_query {} {
    set banner "Select the two nodes with the left button; right = cancel."
    set last_line [select_node $banner node 2]
    
    if {[llength $last_line] < 2} return
    set l1 [lindex $last_line 0]; set l2 [lindex $last_line 1]
    mess "Node 1: $l1\n"
    mess "Node 2: $l2\n"
    set d ""
    foreach i {0 1 2} {
	lappend d [expr {[lindex $l2 $i] - [lindex $l1 $i]}]
    }
    mess "Difference: $d\n"
}

proc add_new_families {} {
    global all_lines family_name
    
    # first get all current family names
    
    set allfams ""
    foreach i [array names family_name] {
	lappend allfams $family_name($i)
    }
    
    set newone 0
    command "list_families dims" 0
    foreach line $all_lines {
	if {$line == ""} continue
	
	set f [lindex $line 0]
	if {[lsearch $allfams $f] < 0} {
	    set newone 1
	    break;
	}
    }
    
    if $newone {
	add_families
    }
}

proc families_in_order {} {
    global families family_name
    
    get_families
    set allnams ""
    foreach f $families {
	lappend allnams [list $family_name($f) $f]
    }
    return [lsort $allnams]
}

proc add_families {} {
    global family_dims family_active family_name
    
    set allnams [families_in_order]
    set vols ""
    set surfs ""
    foreach desc $allnams {
	set name [lindex $desc 0]
	set f [lindex $desc 1]
	set xx [list $f -text $name -pady -2 \
		-command "update_display block mesh quad edge \
scan surf curve point iplane hgrid slice"]
	
	if {$name == "ORFN"} {
	    lappend vols $xx
	    lappend surfs $xx
	} else {
	    if {$family_dims($f) == 3} {
		lappend vols $xx
	    } else {
		lappend surfs $xx
	    }
	}
    }
    check_box .e.fam.v $vols 4 family_active 1 \
	"update_display block mesh quad edge scan surf curve point \
iplane hgrid slice"
    check_box .e.fam.s $surfs 4 family_active 1 \
	"update_display block mesh quad edge scan surf curve point \
iplane hgrid slice"
}

proc family_choice_list {} {
    global families family_name
    
    set fams ""
    foreach f $families {
	lappend fams $family_name($f)
    }
    return [lsort $fams]
}

proc check_new_family {fam ndim} {
    global families family_name family_dims family_active
    
    set maxfam 0
    set found 0
    foreach f $families {
	if [info exists family_name($f)] {
	    if {$family_name($f) == $fam} {
		if {$ndim != $family_dims($f)} {
		    set family_dims($f) $ndim
		}
		set found 1
		break
	    }
	}
	if {$f > $maxfam} { set maxfam $f }
    }
    
    if !$found {
	incr maxfam
    
	lappend families $maxfam
	set family_dims($maxfam) $ndim
	set family_name($maxfam) $fam
	set family_active($maxfam) 1
    
	command "define_new_family $fam $ndim"
    }
    add_new_families
}

proc update_display {args} {
    global display_flag hgrid_plane hgrid_value hgrid_bbox
    global edge_color families global_options
    
    if {$args == ""} {
	foreach w {quad curve surf edge block hgrid mesh point scan \
		       iplane slice} {
	    update_display $w noaddfamilies
	}
	add_new_families
	return
    }
    
    set addfamilies 1
    foreach what $args {
	switch $what {
	    noaddfamilies { set addfamilies 0 }
	    curve {
		set surf [surface_family_string]
		if {!$display_flag(curve) || ($surf == "")} {
		    command "display_curves erase" 0
		} else {
		    command "display_curves $surf" 0
		}
	    }
	    surf -
	    surf_full -
	    surf_solid -
	    surf_params {
		set fam [surface_family_string]
		if {!$display_flag(surf) || ($fam == "")} {
		    command "erase_surface" 0
		} else {
		    set cmd display_surfaces
		    if $display_flag(surf_full)   {
			append cmd " full"
		    } else {
			append cmd " simple"
		    }
		    if $display_flag(surf_params) { append cmd " params" }
		    if $display_flag(surf_solid)  { append cmd " solid" }
		    append cmd " $fam"
		    command $cmd 0
		}
	    }
	    block -
	    block_outer -
	    block_boundary -
	    block_full -
	    block_solid -
	    block_grid -
	    block_sicepts {
		set vols [volume_string]
		if {!$display_flag(block) || $vols == ""} {
		    command "eg" 0
		    command "em" 0
		} else {
		    set opts "[range_string] m $vols"
		    set type ""
		    if $display_flag(block_outer) {
			append type " outer"
		    }
		    
		    if $display_flag(block_boundary) {
			append type " boundary"
		    }
		    
		    if $display_flag(block_full) {
			append type " full"
		    }
		    
		    append opts $type
		    
		    if $display_flag(block_solid) {
			append opts " solid"
		    }
		    if $display_flag(block_sicepts) {
			append opts " in sicepts"
		    }
		    
		    if $display_flag(block_grid) {
			if {$display_flag(block_boundary)} {
			    command "dm $opts"
			} else {
			    command "em" 0
			}
			command "dg" 0
		    } else {
			set cmd "dm $opts"
			command $cmd 0
			command "eg" 0
		    }
		}
	    }
	    quad -
	    quad_quad -
	    quad_bar -
	    quad_outer -
	    quad_solid -
	    quad_hidden -
	    quad_cell_centered -
	    quad_ff_type -
	    quad_unneeded -
	    quad_shrinkwrap -
	    quad_specialmat -
	    quad_outside -
	    quad_saveallquads {
		
		# see if any family selected
		
		set opts [surface_string]
		if !$display_flag(quad_quad) {
		    if $display_flag(quad_bar) {
			append opts " -onlybars"
		    } else {
			set opts ""
		    }
		}
		
		if {!$display_flag(quad) || ($opts == "")} {
		    set ok 1
		    command "display_unstruct_quads erase" 0
		    
		} else {
		    
		    if {$display_flag(quad_ff_type) != "-none"} {
			set ffok [flood_fill_exec 1 1]
			set ok 1
		    } else {
			set ffok 0
			
			# see if staircase computation needs to
			# be carried out.  If it does, either do
			# it locally or remotely.

			set ok [global_build_staircase]
		    }
		    
		    # add the range of i,j,k selected
		    
		    append opts " [range_string]"		    
		    set old_edge_disp $display_flag(edge)
		    if $ok {
			
			# if $display_flag(quad_outer) {
			#    append opts " outer"
			# }
			
			if $display_flag(quad_solid) {
			    append opts " solid"
			} elseif $display_flag(quad_hidden) {
			    append opts " hidden"
			}

			if $display_flag(quad_bar) {
			    append opts " -bars"
			}
			
			if {$display_flag(quad_unneeded) > 0} {
			    
			    if $ffok {
				if {$display_flag(quad_unneeded) == 1} {
				    append opts " -unneeded"
				} else {
				    append opts " -onlyunneeded"
				}
			    } else {
				set msg "Unneeded quad results not valid. \
 Showing all Quads\n"
				mess $msg blue
			    }
			}
				
			# if $display_flag(quad_cell_centered) {
			#    append opts " cell_centered"
			# }

			command "display_unstruct_quads $opts"
		    }
		}
	    }
	    edge -
	    edge_dispval {
		global_edge_modal
		command "display_edges erase" 0
		command "display_edges_quads erase" 0
		if $display_flag(edge) {
		    set opts ""
		    if {$display_flag(edge_dispval_modal) == "edges_quads"} {
			if $display_flag(quad_solid) {
			    append opts " -solid"
			} elseif $display_flag(quad_hidden) {
			    append opts " -hidden"
			}
		    }

		    switch $display_flag(edge_dispval_modal) {
			edges_only {
			    set com display_edges
			    set viacolors {single double multiple}
			    set viaoptions {{single 1} {double 2} \
						{multiple m} {s+m s/m}}
			}
			
			edges_quads {
			    set com display_edges_quads
			    set viacolors {single multiple}
			    set viaoptions {{single 1} {2singles 2} \
						{multiple m} {s&m s/m}}
			}
		    }
		    foreach vc $viacolors {
			if [info exists edge_color($vc)] {
			    if {[scan $edge_color($vc) \#%2x%2x%2x r g b]\
				    ==3} {
				set gg [format %2.2x%2.2x%2.2x $b $g $r]
				lappend opts ${vc}_color $gg
			    }
			}
		    }
		    foreach i $viaoptions {
			set dispval [lindex $i 0]
			set optval [lindex $i 1]
			if {$display_flag(edge_dispval) == $dispval} {
			    lappend opts $optval
			    break
			}
		    }
		    
		    if {$display_flag(edge_dispval_modal) == "edges_quads"} {
			append opts " -surfs [surface_string]"
		    }
		    set old_quad_disp $display_flag(quad)
		    command "$com $opts" 0
		}
	    }
	    hgrid -
	    hgrid_cut -
	    hgrid_volume -
	    hgrid_solid {
		set opts [surface_string]
		if {!$display_flag(hgrid) || ($opts == "")} {
		    command "display_hgrid erase" 0
		} else {
		    if $display_flag(hgrid_solid) { append opts " solid" }
		    if $display_flag(hgrid_cut) {
			if {$hgrid_plane == ""} { set hgrid_plane x }
			if {$hgrid_value == ""} {
			    hgrid_assign_bbox
			    switch $hgrid_plane {
				x { set i 0 }
				y { set i 1 }
				z { set i 2 }
			    }
			    mess "Min coordinates: [lindex $hgrid_bbox 0]\n"
			    mess "Max coordinates: [lindex $hgrid_bbox 1]\n"
			    set bmin [lindex [lindex $hgrid_bbox 0] $i]
			    set bmax [lindex [lindex $hgrid_bbox 1] $i]
			    set hgrid_value [expr {($bmin + $bmax) / 2}]
			}
			append opts " $hgrid_plane $hgrid_value"
			if $display_flag(hgrid_volume) {
			    append opts " volume [volume_string]"
			}
		    }
		    if [check_compute_hgrid] {		    
			command "display_hgrid $opts"
		    }
		}
	    }
	    mesh -
	    mesh_solid -
	    mesh_autofix -
	    mesh_no_mat {
		if !$display_flag(mesh) {
		    command "erase_surface_mesh" 0
		} else {
		    
		    # Compute the material
		    
		    set ff [volume_string]
		    if {[llength $ff] > 0} {
			if {[llength $ff] > 1} { set ff -1 }
		    
			# add on the surface families
			
			append ff " " [surface_family_string_ids]
			set cmd \
			    "display_surface_mesh $ff [boundry_range_string]"
			
			if $display_flag(mesh_solid) {
			    append cmd " solid"
			}
			
			if $display_flag(mesh_no_mat) {
			    append cmd " no_mat"
			}
			
			if $display_flag(mesh_autofix) {
			    append cmd " uae"
			}
			command $cmd 0
		    } else {
			command "erase_surface_mesh" 0
		    }
		}
	    }
	    point -
	    point_pres -
	    point_mater {
		if !$display_flag(point) {
		    points_update_list_families 0  \
			$display_flag(point_pres) $display_flag(point_mater)
		} else {
		    points_update_list_families 1 \
			$display_flag(point_pres) $display_flag(point_mater)
		}
	    }
	    scan {
		scan_update last
	    }
	    slice -
	    slice_ids {
		if !$display_flag(slice) {
		    # command "erase_slices" 0
		} else {
		    if $display_flag(slice_ids) {
			set slice_ids ""
		    } else {
			set slice_ids "-noid"
		    }
		    # command "display_slices -all $slice_ids" 0
		}
	    }
	    iplane {
		if !$display_flag(planes) {
		    iplane_update_list_families 0
		} else {
		    iplane_update_list_families 1
		}
	    }
	}
    }
    
    if $addfamilies { add_new_families }
}

# -------------------------

proc range_string {} {
    global index_min index_max
    
    return "i $index_min(0) $index_max(0)\
	    j $index_min(1) $index_max(1)\
	    k $index_min(2) $index_max(2)"
}

proc boundry_range_string {} {
    global index_min index_max
    
    return "i $index_min(0) $index_max(0) \
	    j $index_min(1) $index_max(1) \
	    k $index_min(2) $index_max(2)"
}

proc range_string_sp {ind val} {
    global index_min index_max
    
    set rr ""
    foreach i {0 1 2} {
	append rr "[lindex {i j k} $i] "
	if {$i == $ind} {
	    append rr "$val [expr $val + 1] "
	} else {
	    append rr "$index_min($i) $index_max($i) "
	}
    }
    return $rr
}

proc range_string_sp2 {ind val} {
    global index_min index_max
    
    set rr ""
    foreach i {0 1 2} {
	if {$i == $ind} {
	    append rr "[lindex {i j k} $i]const $val "
	} else {
	    append rr "[lindex {i j k} $i] $index_min($i) $index_max($i) "
	}
    }
    return $rr
}

proc family_string {} {
    global family_active families
    
    set fams ""
    foreach f $families {
	if $family_active($f) { lappend fams $f }
    }
    return $fams
}

proc family_name_string {} {
    global family_active families family_name
    
    set fams ""
    foreach f $families {
	if $family_active($f) { lappend fams $family_name($f)/* }
    }
    return $fams
}

proc surface_string {} {
    global family_active family_dims families
    
    set fams ""
    foreach f $families {
	if {($family_active($f) && ($family_dims($f) < 3)) || $f == 0} {
	    append fams " $f"
	}
    }
    return $fams
}

proc surface_family_string {} {
    global family_active family_dims families family_name global_info
    
    set fams ""
    foreach f $families {
	if {$family_active($f)} {
	    if {$family_dims($f) < 3} {
		lappend fams $family_name($f)/*
	    } elseif {$f == 0} {
		lappend fams "ORFN"
	    }
	}
    }
    
    # add all new names for curves and surfs that don't obey naming
    # protocol
    
    foreach idx {init_surfs init_curves} {
	foreach desc $global_info($idx) {
	    set f [lindex $desc 0]
	    set n [lindex $desc 1]
	    if {$family_active($f) && $n != $family_name($f)} {
		lappend fams $n*
	    }
	}
    }
    
    return $fams
}

proc surface_family_string_ids {} {
    global family_active family_dims families family_name
    
    set fams ""
    foreach f $families {
	if {$family_active($f) && ($family_dims($f) < 3)} {
	    lappend fams $f
	}
    }
    return $fams
}

proc volume_string {} {
    global family_active family_dims families
    
    set fams ""
    foreach f $families {
	if {$family_active($f) && ($family_dims($f) == 3)} {
	    append fams " $f"
	}
    }
    return $fams
}

proc volume_name_string {} {
    global family_active family_dims families family_name
    
    set fams ""
    foreach f $families {
	if {$family_active($f) && ($family_dims($f) == 3)} {
	    append fams " $family_name($f)"
	}
    }
    return $fams
}

proc flood_fill_modals {{use_autofix 1} {can_display 1}} {
    global display_flag
    
    set quad_opts ""
    if {$can_display && $display_flag(quad_marking)} {
	lappend quad_opts "-marking"
    }
    
    if {$display_flag(quad_autofix) && $use_autofix} {
	lappend quad_opts "-autofix"
    }
    
    if {$display_flag(quad_fixvolid)} {
	if {!$display_flag(quad_shrinkwrap) || \
		!$display_flag(quad_specialmat)} {
	    lappend quad_opts "-fixvolid"
	}
    }
    
    if {$display_flag(quad_assignmat) == "-assignmat"} {
	lappend quad_opts "-assignmat"
    }
    
    if {$display_flag(quad_assignmat) == "-fixwall"} {
	lappend quad_opts "-fixwall"
    }
    
    if $display_flag(quad_shrinkwrap) {
	lappend quad_opts "-shrinkwrap"
    }
    
    if $display_flag(quad_specialmat) {
	lappend quad_opts "-specialmat"
    }
    
    if $display_flag(quad_outside) {
	lappend quad_opts "-outshrink"
    }
    
    if $display_flag(quad_saveallquads) {
	lappend quad_opts "-save_all_quads"
    } else {
	lappend quad_opts "-nosave_all_quads"
    }
    
    # standard (-standard), restricted (-restrict),
    
    if {$display_flag(quad_ff_type) != "-none"} {
	lappend quad_opts $display_flag(quad_ff_type)
    }
    
    return $quad_opts
}

proc flood_fill_exec {{use_autofix 1} {can_display 1}} {
    global last_line all_lines display_flag
    
    set ffm [flood_fill_modals $use_autofix $can_display]
    set cmd "flood_fill_staircase $ffm -surfs [surface_string] -vols "
    append cmd [volume_string]
    
    # evade command's error protocol to catch the error ourselves
    # add display the error message if an error
    
    command $cmd 0
    
    if [regexp -nocase "error" $last_line] {
	set ret 0
	mess "$cmd\n" green
	foreach l $all_lines {
	    mess "$l\n" red
	}
	mess "Please Fix Model and/or Staircase Mesh\n" red
    } else {
	if [regexp -nocase "WARNING" $all_lines] {
	    mess "$cmd\n" green
	    foreach l $all_lines {
		mess "$l\n" blue
	    }
	    mess "Flood Fill Staircase Succeeded\n" green
	}
	set ret 1
    }
    return $ret
}

#---- Index Planes / Boxes

proc iplane_update_list_families {{on ""}} {
    global iplane_family families family_active family_name
    
    init_index_planes
    command "redraw_flag 0" 0
    foreach fam $families {
	
	catch {
	    if {$on != "" && !$family_active($fam)} {
		set ton 0
	    } else {
		set ton $on
	    }
	
	    foreach n [array names iplane_family] {
		if {$iplane_family($n) == $family_name($fam)} {
		    iplane_active_update $n $ton "-noredraw" 1
		}
	    }
	}
    }
    command "redraw_flag 1" 0
}

#---- Points

proc points_update_list_families {{on ""} {pres 1} {mater 0}} {
    global iplane_family families family_active family_name
    
    command "redraw_flag 0" 0
    
    set all_families ""
    foreach fam $families {
	    
	catch {
	    if {$on == "" || !$family_active($fam)} {
		set ton 0
	    } else {
		set ton $on
	    }
	    
	    if $ton {
		append all_families $family_name($fam) " "
	    }
	}
    }
    set cmd "display_points"
    if $pres {
	append cmd " -pres"
    }
    
    if $mater {
	append cmd " -mater"
    }
    
    if !$on {
	append cmd " -erase"
	set show_cmd 0
    } else {
	set show_cmd ""
    }
    
    # append cmd " $all_families"
    catch {command "$cmd" $show_cmd}
    
    command "redraw_flag 1" 0
}

# building a staircase

proc global_build_staircase {} {
    global last_line global_options global_exec_remote_flag display_flag
    
    set ok 1
    set last_line ""
    set opts ""
    
    if $display_flag(quad_shrinkwrap) {
	lappend opts "-shrinkwrap"
    }
    
    if $display_flag(quad_specialmat) {
	lappend opts "-specialmat"
    }
        
    if $display_flag(quad_outside) {
	lappend opts "-outshrink"
    }
        
    command "needs_build_staircase $display_flag(quad_shrinkwrap)" 0
    mess "After needs_build_stair -- last_line = $last_line\n"
    if $last_line {
	if {![info exists global_exec_remote_flag] ||
	    !$global_exec_remote_flag} {
	    
	    if {$global_options(Staircase) && \
		    $global_options(remote) != ""} {
		
		# mark that we should not reenter
		
		set global_exec_remote_flag 1
		set ok [global_execute_remote_staircase];
		set global_exec_remote_flag 0
		
	    } else {
		
		# put up stop button by hand
		
		# set stop_button_pid \
		    \# [stop_button 1 "" [pid] "Stop Staircase Computation" 2]
		
		command "build_staircase $opts" 0
		
		# stop_button 0 "" $stop_button_pid
	    }
	} else {
	    set ok 0
	}
    }
    return $ok
}

proc global_execute_remote_staircase {} {
    global global_options global_files global_exec_remote_flag
    global global_pid global_epiloge
    
    # build the command line.  remote shell command
    
    set cmd_line \
	"[get_path rsh 1] $global_options(remote) -l $global_options(ruser)"
    
    # figure out the current directory.  If the user has not
    # set the current directory path, then determine it.
    
    if {$global_options(curdir) == ""} {
	# First, determine the home directory then strip it off
	# the current directory.  This is because rsh
	# will login to the home directory and we want to
	# set the directory relative to that directory
	# See Wayne's mesher_tetra for example.
	
	set cur [pwd]; cd; set home [pwd]; cd $cur
	if {![regexp "$home/(.*)" $cur dummy place]} { set place $cur }
    } else {
	set place $global_options(curdir)
    }
    append cmd_line " \"cd $place;"
    
    # build the command line:  The environment variables
    
    append cmd_line " setenv ICEM_ACN $global_options(icemacn);"
    if {$global_options(license) != ""} {
	append cmd_line " setenv LM_LICENSE_FILE $global_options(license);"
    }
    
    # the execute command files
    
    set bf "$global_options(transdir)/temp"
    set firstId [global_next_file $bf]
    
    set global_files(stairin)  $bf$firstId
    incr firstId
    set outId $firstId
    set global_files(stairout) $bf$outId
    incr firstId
    set global_files(execout)  $bf$firstId
    
    # the execute command
    
    set cart_file \
	"$global_options(meshdir)/$global_options(cart_file_name)"
    
    set fd [open $global_files(stairin) w]
    puts $fd "build_staircase"
    puts $fd "write_ceg_staircase_file temp$outId"
    close $fd
    
    set execute \
	" $global_options(bin) -i $cart_file < $global_files(stairin)\""
    
    # entire command line
    
    append cmd_line $execute
    
    # ready to execute in the background
    
    set logfile $global_files(execout)
    command "global_remote 1" 0
    set global_pid [eval exec $cmd_line >& $logfile &]
    mess "global rsh pid is $global_pid\n"
    
    # Now wait for the log file.
    
    for {set i 0} {$i < 60} {incr i} {
	if [file exists $logfile] break
	after 500
    }
    if {$i == 60} {
	global_cleanup_remote
	mess "Error: global didn't start -- can't find log file\n" red
	return 0
    }
    # mess "Global is running: logfile = [file tail $logfile].\n"
    
    set ok [global_show_logfile $logfile]
    if $ok {
	command "merge_gorf_file temp$outId" 0
	add_new_families
    }
    global_cleanup_remote
    return $ok
}

proc global_show_logfile {file} {
	
    global global_pid global_finished
    
    # put up stop button by hand
    
    # set stop_button_pid [stop_button 1 "" $global_pid \
	"Stop Remote Global" 15]
    
    set fp [open $file r]
    tail_dashf $fp "tail_global_log $fp"
    
    tkwait variable global_finished
    
    if $global_finished {
	mess "Remote Global has finished.\n"
	set ok 1
    } else {
	mess "Remote Global has exited.\n"
	set ok 0
    }
	
    # done with stop button
	
    # stop_button 0 "" $stop_button_pid
    return $ok
}

proc tail_global_log {fp line} {
    global global_finished global_pid
    
    if {![info exists global_pid] && [string match "process *" $line]} {
	set global_pid [lindex $line 2]
    }
    
    if ![string compare $line "global done"] {
	close $fp
	set global_finished 1
	return;
    }
    
    if [regexp "global exit" $line] {
	if {[string compare $line "global exit"] != 0} {
	    mess "Error -- Remote Global Failed due to: $line\n" red
	}
	close $fp
	set global_finished 0
	return;
    }
}

proc global_cleanup_remote {} {
    global global_files global_exec_remote_flag
    
    # clear the "semaphores:  tcl semaphore global_exec_remote_flag
    # and executable remote flag remote_global
    
    set global_exec_remote_flag 0
    command "global_remote 0" 0
    
    # free temporary files
    
    foreach f [array names global_files] {
	if [file exists $global_files($f)] {
	    cmd_rm $global_files($f)
	}
    }
}

proc global_next_file {basename} {
    set i 0
    while 1 {
	if ![file exist $basename$i] { return $i }
	incr i
    }
}
