# This code creates the user interface for the hexa mesher.
#
# Copyright (c) 1993 - 1995 Pacific Marketing and Consulting, Inc,
#       and ICEM Systems, GmbH.  All rights reserved.
# Author:   Ganesan Harihara, ganesan.hariharaputhiran@ansys.com
#           Jari Spaete, jari.spaete@ansys.com

proc select_hexa {what {max_num 0} {mess ""} {opts ""} {take_first_press 0} {select_duplicate 0}} {
    global select_action options use_output_blocks tdv_default tdv_mouse_bindings
    global button_instructions tdv_click_preset options
    global select_type select_poly select_families select_vect
    global display_flag last_line hexa_select select_premesh_families
    global use_banner hexa_family_selected hexa_corners_selected
    global hexa_selection_display

    # Display the entities if not ON 
    if {$what != "compcurve" && $what != "block" && (!$display_flag(edge) )} {
	    hex_command "display_edge_mesh [range_string] m [volume_activename_string] volume  -not_blanked"
	    set hexa_selection_display "display_edge_mesh [range_string] m [volume_activename_string] volume  -not_blanked"
	    if {[info exists use_output_blocks] && $use_output_blocks} {
	        append hexa_selection_display " output_blocks"
	    }
    }

    if {[set i [lsearch $opts showIJK]] >= 0} {
	    set display_opts orientation
	    set opts [lreplace $opts $i $i]
    } else {
	    set display_opts ""
    }
    
    switch $what {
        edge {
            set reset_edge_display 0
            if {[set i [lsearch $opts reset_edge_display]] >= 0} {
	            set opts [lreplace $opts $i $i]
	            if {$display_flag(edge_nodes) || $display_flag(edge_shape)} { set reset_edge_display 1 }
            }
            if $reset_edge_display {
	            set display_cmd "display_edge_mesh [range_string] m [family_activename_string]"
                if $use_output_blocks { append display_cmd " output_blocks" }
                if $display_flag(edge_vol)     { append display_cmd " volume" }
                if $display_flag(edge_bunch)   { append display_cmd " bunching" }
                if $display_flag(edge_counts)  { append display_cmd " counts" }
                if $display_flag(edge_proj)    { append display_cmd " proj" }
                if $display_flag(edge_mset)    { append display_cmd " highlight_set" }
                if $display_flag(edge_shape_source) { append display_cmd " shape_source" }
                if $display_flag(edge_simple) { append display_cmd " -simple" }
                if $display_flag(use_blanking) { append display_cmd " -not_blanked" }
                if $display_flag(color_by_count) { append display_cmd " color_by_count" }
	            hex_command "$display_cmd"
	            set hexa_selection_display $display_cmd
	        }
        }
	    face {
	        set display_cmd "display_super_faces [range_string] [family_activename_string] only_icons -not_blanked"
	        if {[lsearch $opts boundary] > -1} {
		        append display_cmd " boundary"
		        set options(face_mode) 1
	        } else {
	            set options(face_mode) 0
	        }
            if {[lsearch $opts sblock_top] > -1} {
                append display_cmd " sblock_top"
            }
	        if {[info exists use_output_blocks] && $use_output_blocks && ([lsearch $opts super_face] > -1)} {
		        append display_cmd " output_blocks"
	        }
	        hex_command "$display_cmd"
	        set hexa_selection_display $display_cmd
	    }
	    block {
	        if { ! $display_flag(block_struct) } {
		        append display_opts " -hide_struct"
	        }
	        if { ! $display_flag(block_unstruct) } {
		        append display_opts " -hide_unstruct"
	        }
	        if { ! $display_flag(block_swept) } {
		        append display_opts " -hide_swept"
	        }
	        if $display_flag(block_solid) {
		        append display_opts " -solid"
	        }
	        if {[info exists use_output_blocks] && $use_output_blocks} {
		        append display_opts " output_blocks"
	        }
	        set display_cmd "display_elements [range_string] m [volume_activename_string] $display_opts super -not_blanked"
	        hex_command "$display_cmd"
	        set hexa_selection_display $display_cmd
	    }	
    }

    set hex_selsubset [format %d [ic_hex_create_subset selection]]

    set finished 0
    set not_cancel 0
    set xypos ""
    set how select

    switch $what {
        vertex  { select_set_bindings 8 1 0 0 "Select Blocking-$what" }
        edge    { select_set_bindings 8-2 1 0 0 "Select Blocking-$what" }
        face    { select_set_bindings 8-3 1 0 0 "Select Blocking-$what" }
        block   { select_set_bindings 8-4 1 0 0 "Select Blocking-$what" }
        default { select_set_bindings 8 1 0 0 "Select Blocking-$what" }
    }

    if [info exists use_banner] {
	    set dispmess $use_banner
    } else {
	    foreach s { select done cancel } {
	        set b_$s [lindex {"" left middle right} $tdv_mouse_bindings($s)]
	    }
	    if {$max_num == 1} {
	        set dispmess "$mess with the $b_select button; $b_cancel = cancel; '?' = list options."
	    } else {
	        set dispmess "$mess with the $b_select button; $b_done = done, $b_cancel = back up / cancel, '?' = list options."
	    }
    }	
    banner $dispmess
    catch {unset use_banner}

    set selected ""
    set select_type pick
    set poly ""
    set nstuff 0
    set num_sel 0
    set waiting_for_circle 0
    set hexa_select 1
    set pressed 0

    set hexa_family_selected ""
    set hexa_corners_selected ""
    set options(select_toggle_corners) 0
    while {!$finished} {
	tkwait variable select_action
	switch [lindex $select_action 0] {
	    done {
            if [info exists pline] {
                set poly ""
                if {[$pline get -npts] > 2} {
                    for {set i 0} {$i < [$pline get -npts]} {incr i} {
                        set p [lindex [$pline get_point $i] 0]
                        if {$what == "compcurve"} {
                            lappend poly [list [lindex $p 0] [lindex $p 1]]
                        } else {
                            set v [$tdv_default screen2world [lindex $p 0] [lindex $p 1]]
                            if !$i { set select_vect [lindex $v 1] }
                            lappend poly [lindex $v 0]
                        }
                    }
                    set select_type polygon
                    set select_poly $poly
                    set picked [select_change_subset number $hex_selsubset $what add $how "" 1 $opts]
                    set selected [concat $selected $picked]
                    set num_sel [llength $selected]
                    if {$max_num && ($num_sel >= $max_num)} {
                        set finished 1
                    }
                }
                $pline delete
                unset pline
                set poly ""
                set select_type ""
                set select_poly ""
                tdv_cur $tdv_default pick
                set nstuff [llength $selected]
            } else {
               set finished -1
            }
	    }
	    back {
            if [info exists pline] {
                set n [$pline get -npts]
                incr n -1
                if {$n < 2} {
                    $pline delete
                    unset pline
                    tdv_cur $tdv_default pick
                } else {
                    $pline delete_point $n
                }
            } else {
                change_subset number $hex_selsubset $what remove_last $how $opts [lindex $selected end]
            }
            set selected [lrange $selected 0 [expr [llength $selected] - 2]] 
            incr nstuff -1
            if {$nstuff < 0} {
                set finished -1
            }
        }
	    cancel {
            # the blocking was unloaded (e.g. project closed) and cancel was set
            if ![ic_hex_blocking_loaded] {
                foreach child [winfo children .] {
	                if [string match .select_opts_* $child] {
                        catch { destroy $child }
                    }
                }
                select_unset_bindings 1
                return ""
            }
            if [info exists pline] {
                $pline delete
                unset pline
            }
            change_subset number $hex_selsubset $what remove_all $how $opts
            set selected ""
            set finished -1
	    }
	    press {
            set pressed 1
            set num_sel [llength $selected]	
            if {$max_num && ($num_sel >= $max_num)} {
                set finished 1 
            } elseif {$take_first_press == 1} {
                set startx [lindex $select_action 1]
                set starty [lindex $select_action 2]
                set tdv_click_preset(x) $startx
                set tdv_click_preset(y) $starty
                set picked [select_change_subset number $hex_selsubset $what add $how "" 1 $opts]
                set selected [concat $selected $picked]
                set select_type ""
                set nstuff 1
                set finished 1
            } else {
                set startx [lindex $select_action 1]
                set starty [lindex $select_action 2]
                if [info exists pline] {
                    set n [$pline get -npts]
                    $pline set_point $n "$startx $starty 0" "0 0 0" "0 0 0"
                    if !$n {
                        $pline set_point 1 "$startx $starty 0" "0 0 0" "0 0 0"
                    }
                } elseif $waiting_for_circle {
                    set circle [select_circle $startx $starty $startx $starty]
                }
            }
        }
	    circle {
            set waiting_for_circle 1
            tdv_cur $tdv_default circlepick
        }
        polygon {
            set num_sel 0		
            if {$max_num && ($num_sel >= $max_num)} {
                set finished 1
            } else {
                if ![info exists pline] {
                    set pline [select_pline]
                }
            }
            tdv_cur $tdv_default polypick
	    }
	    move {
            set x [lindex $select_action 1]
            set y [lindex $select_action 2]
            if [info exists circle] {
                $circle configure -x2 $x -y2 $y
            } elseif [info exists rbox] {
                $rbox configure -x2 $x -y2 $y
            } elseif { [ info exists startx ] && [ info exists starty ] && !$max_num} {
                set dx [expr {abs($x - $startx)}]
                set dy [expr {abs($y - $starty)}]
                if {($dx > 3) || ($dy > 3)} {
                    set rbox [select_rbox $startx $starty $x $y]
                }
            }
        }
	    nb_move {
            set x [lindex $select_action 1]
            set y [lindex $select_action 2]
            if [info exists pline] {
                set n [$pline get -npts]
                if $n {
                    $pline set_point [expr $n - 1] "$x $y 0" "0 0 0" "0 0 0"
                }
            }
	    }
	    release - shiftrelease {
            if !$pressed {
                continue
            } else {
                set pressed 0
            }

            set num_sel [llength $selected]		
            if {$max_num && ($num_sel >= $max_num)} {
                set finished 1
            } else {
                set x [lindex $select_action 1]
                set y [lindex $select_action 2]
                if [info exists circle] {
                    set select_type circle
                    set centv [$tdv_default screen2world [$circle get -x1] [$circle get -y1]]
                    set radv [$tdv_default screen2world [$circle get -x2] [$circle get -y2]]
                    set poly ""
                    lappend poly [lindex $centv 0]
                    lappend poly [lindex $radv 0]
                    $circle delete
                    unset circle
                    set waiting_for_circle 0
                    tdv_cur $tdv_default pick
                } elseif [info exists rbox] {
                    set select_type inregion
                    set poly ""
                    foreach p [list "[$rbox get -x1] [$rbox get -y1]" "[$rbox get -x1] $y" "$x $y" "$x [$rbox get -y1]"] {
                        set v [$tdv_default screen2world [lindex $p 0] [lindex $p 1]]
                        set select_vect [lindex $v 1]
                        lappend poly [lindex $v 0]
                    }
                    $rbox delete
                    unset rbox			
                } 
                if ![info exists pline] {		    
                    if {$poly != ""} {
                        # do region select
                        set select_poly $poly
                    } elseif {[info exists startx] && [info exists starty]} {
                        set tdv_click_preset(x) $startx
                        set tdv_click_preset(y) $starty
                    }
                    set shift [expr {[lindex $select_action 0] == "shiftrelease"}]
                    if  $shift {
                        set picked [select_change_subset number $hex_selsubset $what remove $how "" 1 $opts]
                        foreach pick $picked {
                            set index [lsearch $selected $pick]
                            if {$index >= 0} {
                                set selected [lreplace $selected $index $index]
                            }
                        }
                    } else {
                        set picked [select_change_subset number $hex_selsubset $what add $how "" 1 $opts]
                        set selected [concat $selected $picked]
                    }
                    set num_sel [llength $selected]
                    if {$max_num && ($num_sel >= $max_num)} {
                        set finished 1
                    }
                    set select_type ""
                    set select_poly ""
                    set poly ""
                    set nstuff $num_sel
                }
            }
	    }
	    region_type {
            if {$options(select_mode) == "some"} {
                set options(select_mode) all
                mess "Objects entirely in region will be selected\n"
            } else {
               set options(select_mode) some
                mess "Objects partially in region will be selected\n"
            }
        }
	    visible - blanked {
            set select_type [lindex $select_action 0]
            set selected [select_change_subset number $hex_selsubset $what add $how "" 1 $opts]
            mess "Selected [lindex $select_action 0] ${what}s\n"
            set finished 1
	    }
	    all {
            mess "Warning: Select all not availabe for Blocking entities\n" red
            continue
	    }
	    family - part - subset {
            if {[lindex $select_action 0] == "subset"} {
                set subs [ic_hex_list_subsets]
                set fams [choose_multiple "Select one or more subsets." $subs +200+200 "Select Block Subsets"]
            } else {
                if {[info exists select_premesh_families] && ($what == "face" || $what == "vertex" || $what == "block")} {
                    set fams [select_families_by_premesh $what 1 0]
                } elseif {$what == "face" && ([lsearch $opts boundary] > -1)} {
                    set parts [ic_hex_list_surface_families]
                    set fams [choose_multiple "Select one or more parts." $parts +200+200 "Select Blocking parts"]
                } else {
                    set parts [ic_hex_list_blocking_parts]
                    set fams [choose_multiple "Select one or more parts." $parts +200+200 "Select Blocking parts"]
                }
            }
            if {$fams != ""} {
                set select_type family
                set select_families $fams 
                set picked [select_change_subset number $hex_selsubset $what add $how "" 1 $opts]
                set selected [concat $selected $picked]
                set num_sel [llength $selected]
                if {[info exists select_premesh_families] && ($what == "face" || $what == "vertex" || $what == "block")} {
                    mess "Selected $num_sel ${what}s in Part: $fams\n"
                } else {
                    mess "Selected ${what}s in Part/Subset: $fams\n"
                }
                if {$max_num && ($num_sel >= $max_num)} {
                    set finished 1
                }
                set hexa_family_selected $fams
                set select_type ""
                set select_families ""
                set nstuff $num_sel
                set finished 1
                set not_cancel 1
            }
        }	    
	    corners {
            if {!($what == "face" || $what == "block" || $what == "edge")} {
                mess "Error: Selection by Corners only for Faces/Blocks/Edges"
                continue
            }
            if {$what == "block"} {
                if $nstuff {
                    set hexa_selection_display "display_subset number $hex_selsubset $what $display_cmd only"
                    eval ic_hex_display_subset number $hex_selsubset $what $display_cmd only
                } else {
                    set hexa_selection_display "display_elements erase"
                    eval ic_hex_display_elements erase
                }
            }
            set picked [select_change_subset number $hex_selsubset $what add corners "" 1 $opts]
            set selected [concat $selected $picked]	
            set num_sel [llength $selected]
            if {$max_num && ($num_sel >= $max_num)} {
                set finished 1
            }
            set nstuff $num_sel
            banner $dispmess
        }
	    hnum {
            if {$what == "block"} {
                set nums [question "Enter the block numbers to\nselect separated by spaces\nand/or ranges as N1-N2."]
                if {$nums != ""} {
                    set num_sel 0
                    if [regexp -- "-" $nums] {
		                set numbers ""
		                foreach n $nums {
		                    set nfound [regexp -all -- {-} $n]
		                    if $nfound {
		                        set from [lindex [split $n -] 0]
		                        set to [lindex [split $n -] 1]
		                        for {set i $from} {$i <= $to} {incr i} {
		                            append numbers "$i "
		                        }
		                    } else {
		                        append numbers "$n "
		                    }
		                }
		                set selected [concat $selected $numbers]
		                set num_sel [llength $selected]
		                set nstuff $num_sel
		            } else {
		                set selected [concat $selected $nums]
		                set num_sel [llength $selected]
		                set nstuff $num_sel
		            }
		            if $num_sel {
		                mess "Selected $num_sel block(s). Press middle button to confirm.\n"
		            }
		        }
		    } elseif {$what == "vertex"} {
		        set nums [question "Enter the vertex number(s) to\nselect separated by spaces."]
		        if {$nums != ""} {
		            set selected [concat $selected $nums]
		            set num_sel [llength $selected]
		            set nstuff $num_sel		        
		            mess "Selected $num_sel vertices. Press middle button to confirm.\n"
		        }
		    }
	    }
	    block_by_vertex {
	        set nums [question "Enter the vertex number(s) for block selection to\nselect separated by spaces."]
		    if {$nums != ""} {
		        set blocksbyvertex ""
		        set output_value ""
		        if $use_output_blocks { set output_value "output_blocks" }
		        foreach n $nums {
		            foreach nn [string trimright [ic_hex_get_vertex_blocks $n $output_value] \n] {
		                if {[lsearch $blocksbyvertex $nn] < 0} {
		                    append blocksbyvertex "$nn "
		                }
		            }
		        }
		        set selected $blocksbyvertex
		        set num_sel [llength $selected]
		        set nstuff $num_sel
		        mess "Selected $num_sel block(s). Press middle button to confirm.\n"
		    }
	    }
	    highlight_segment {
	        if {$what == "edge" && [lsearch $opts edge_segment] >= 0 && [llength $selected] > 0} {
	            set edge [lindex $selected end]
	            set e1 [lindex $edge 0]
	            set e2 [lindex $edge 1]
	            set e3 [lindex $edge 2]
	            if {$e3 != "-1"} {
	                set n [ic_hex_get_edge_segment_number $e1 $e2]
	                if {$n > 0} {
	                    if {$e3 < $n} {
	                        incr e3
	                    }
	                    if {$e3 == $n} {
	                        set e3 0
	                    }
	                    set selected [lreplace $selected end end " $e1 $e2 $e3 "]
                        mess "Selected edge segement $e3 for edge \"$e1 $e2\"\n"
                        change_subset number $hex_selsubset edge remove_last $how $opts [lindex $selected end]
                        change_subset number $hex_selsubset edge add "" $opts $selected
	                    #hex_display_edge_segment "$e1 $e2" $e3
	                }
	            }
	        }
	    }
	    default {
            puts "Internal Error in hexa entity selection"
	    }
	}	
    }
    catch { unset tdv_click_preset }
    catch { unset hexa_selection_display }
    ic_hex_delete_subset number $hex_selsubset
    banner ""
    select_unset_bindings 1
    
    switch $what {
        edge - block {
            if { $max_num == 1 } {
                if {[llength $selected] > 1} {
                    mess "Warning: selecting only the first $what in the list\n" red
                    set selected [lindex $selected 0]
                }
                set selected [join $selected]
            }	
        }
        face {
            hex_command "display_super_faces [range_string] [family_activename_string] erase_icon  -not_blanked"
        }    
    }

    if { !($what == "edge" && $max_num == 1)} {
        hex_update_display $what
        if !$display_flag(edge) {
            hex_update_display edge
        }
    }
    
    if {$what == "compcurve"} {
        global aie_ShowDormant
        # remove dormant curves from selection if not visible
        if {[info exists aie_ShowDormant(curve)] && !$aie_ShowDormant(curve)} {
            set new_selected ""
            set ignored_selection ""
            foreach c $selected {
                if ![ic_geo_get_dormant_entity curve $c] {
                    append new_selected "$c "
                } else {
                    append ignored_selection "$c "
                }
            }
            set selected $new_selected
            if {[llength $ignored_selection] > 0} {
                mess "Dormant curve(s) $ignored_selection removed from selection: set Curves->Show Dormant to on\
                    to select also dormant curves\n" red
            }
       }
    }
    catch { unset hexa_select }

    # uniquify
    if $select_duplicate {
        set actual_selected $selected
    } else {
        set duplicate ""
        set nmax [llength $selected]
        for {set i 0} {$i < [expr $nmax -1]} {incr i} {
            for {set j [expr $i + 1]} {$j < $nmax} {incr j} {	
                if {[lindex $selected $i] == [lindex $selected $j]} {
                    lappend duplicate $i
                }
            }
        }
        set actual_selected ""
        for {set i 0} {$i < $nmax} {incr i} {
            if {[lsearch $duplicate $i] < 0} {
                lappend actual_selected [lindex $selected $i]
            }
        }
    }
    set len [llength $actual_selected]
    if $len {
        if {$what == "vertex"} {
            if {$len > 1} {
                mess "Selected [llength $actual_selected] vertices\n"
            } else {
                mess "Selected 1 vertex\n"
            }
        } else {
            if {$len > 1} {
                if {$what == "edge" && [llength $actual_selected] == 3 && [lindex $actual_selected end] == -1} {
                    mess "Selected 1 ${what}\n"
                } else {
                    if {$what == "edge"} {
                        if [string match "*new_format*" $opts] {
                            mess "Selected [llength $actual_selected] ${what}s\n"
                        }
                    } else {
                        mess "Selected [llength $actual_selected] ${what}s\n"
                    }
                }
            } else {
                mess "Selected 1 ${what}\n"
            }
        }
    }
    return $actual_selected 
}

proc select_corners {{max_num 2} {mess ""}} {
    global select_action tdv_default tdv_mouse_bindings
    global button_instructions tdv_click_preset
    global select_type select_poly select_families
    global display_flag last_line hexa_corners_selected options
    
    set hex_selsubset [format %d [ic_hex_create_subset selection]]
    set finished 0
    set xypos ""
    set how select

    set selected ""
    set hexa_corners_selected ""
    set select_type pick
    set poly ""
    set nstuff 0
    set what vertex
    set opts node_numbers

    if {$mess == ""} { set mess corners }
    
    foreach s { select done cancel } {
        set b_$s [lindex {"" left middle right} $tdv_mouse_bindings($s)]
    }
    set dispmess "Select $mess with the $b_select button; $b_done = done, $b_cancel = back up / cancel, '?' = list options."
    banner $dispmess
    set how corners
    while {!$finished} {
	    tkwait variable select_action
	    switch [lindex $select_action 0] {
	        done {
		        set finished 1
	        }
	        back {
		        change_subset number $hex_selsubset $what remove_last $how
		        set selected [lrange $selected 0 [expr [llength $selected] - 2]]
		        incr nstuff -1
		        if {$nstuff < 0} {
		            set finished -1
		        }

	        }
	        cancel {
		        change_subset number $hex_selsubset $what remove_all $how
		        set selected ""
		        set finished -1
	        }
	        press {
		        set num_sel [llength $selected]
		        if {$max_num && ($num_sel >= $max_num) && !$options(select_toggle_corners)} {
		            set finished 1 
		        } else {
		            set startx [lindex $select_action 1]
		            set starty [lindex $select_action 2]
		        }
	        }	   
	        release - shiftrelease {
		        set num_sel [llength $selected]		        
		        if {$max_num && ($num_sel >= $max_num) && !$options(select_toggle_corners)} {
		            set finished 1
		        } else {
		            set x [lindex $select_action 1]
		            set y [lindex $select_action 2]		   
		            if {[info exists startx] && [info exists starty]} {
			            set tdv_click_preset(x) $startx
			            set tdv_click_preset(y) $starty
		            }
		            set picked [select_change_subset number $hex_selsubset $what add $how "" 1 $opts]
		            set selected [concat $selected $picked]
		            #set selected [ic_hex_list_subset_entities number $hex_selsubset $what]
		            set num_sel [llength $selected]
		            if {$max_num && ($num_sel >= $max_num) && !$options(select_toggle_corners)} {
			            set finished 1
		            }
		            set select_type ""
		            set nstuff $num_sel
		        }
	        }	   
	    }
    }
    banner ""
    ic_hex_delete_subset number $hex_selsubset
    set select_type ""       
    set hexa_corners_selected $selected
    set options(select_toggle_corners) 0
    return $selected 
}

proc select_change_subset {type subset what action how mess max opts} {    
    global hexa_select

    if ![info exists hexa_select] { return "" }
    set picked ""
    if {$what == "face" || $what == "block" || $what == "edge"} {
	    set picked [select_${what} $how $mess $max $opts]
    } else {
	    set picked [select_${what} $mess $max $opts]
    }
    change_subset $type $subset $what $action $how $opts $picked
    return $picked
}

proc change_subset {type sub what action {how select} {opts ""} {ents ""}} {
    global display_flag hexa_selection_display
    global use_output_blocks

    if {$what == "compcurve"} {
	    set on ""
	    switch $action {
	        remove_last - remove {
		        set on 0
	        }
	        add { 
		        set on 1
	        }
	    }
	    if {$on == ""} { return }
	    set proj_curves ""
	    foreach compcurve $ents {
	        set proj_curves [ic_hex_get_proj_curves $compcurve]
	        foreach curve $proj_curves {
		        ic_show_geo_selected curve $curve $on
	        }
	    }	
	    return
    }

    if ![eval ic_hex_subset_exist number $sub] return
    switch $action {
	    remove_all {
	        hex_command "subset_remove_items $type $sub $what all"
	    }
	    remove_last {
	        hex_command "subset_remove_items $type $sub $what last"
	    }	
	    add - remove {
	        set items ""
	        switch $what {
		        vertex {
		            foreach v $ents {
			            if {$v != ""} {
			                if {[llength $v] == 1} {
				                lappend v 0 -1
			                }				
			                lappend items $v
			            }
		            }
		        }
		        edge {
		            foreach e $ents {
			            if {[lindex $opts 0] == "new_format"} {
			                lappend items [list [lindex $e 0] [lindex $e 1] [lindex $e 2]]
			            } else {
			                set ijk [lindex $e 0]
			                set dim [lindex $e 1]
			                set seg -1
			                if [catch {ic_hex_vertex_number $ijk} node_num] {
				                #mess "Could not use O-grid indices for unstruct blocking\n" red
				                return
			                }
			                set n1 [format %d $node_num]
			                set n2 [format %d [ic_hex_get_edge_node $ijk $dim]]
			                if {$n2 != -1} {
				                lappend items [list $n1 $n2 $seg]
			                }
			            }
		            }
		        }
		        face {
                    foreach e $ents {
		                if {[lindex [join $e] end] == "u"} { # for unstruct faces
		                    set uitems ""
			                foreach n [join $e] {
			                    if [regexp {[0-9]} $n] {
				                    lappend uitems $n
			                    }
			                }
				            lappend uitems -1 -1
			                set uitems [list $uitems]
			                hex_command "subset_${action}_items $type $sub $what [llength $uitems] [join $uitems]"
		                } else { 
			                lappend items $e
		                }
		            }
		        }
		        default {
		            set items $ents
		        }
	        }
	        if {$items != ""} {
	            hex_command "subset_${action}_items $type $sub $what [llength $items] [join $items]"
	        }
	    }
    }

    set disp_opts ""
    
    switch $what {
	    edge {
	        set disp_opts "[range_string] m [volume_activename_string] -not_blanked"
	        if $display_flag(edge_vol) {
		        append disp_opts " volume"
	        }
	        if {[lsearch $opts selected_bunching] > -1} {
		        append disp_opts " selected_bunching"
	        }
	    }
	    block {	   
	        set disp_opts "display_elements [range_string] m [volume_activename_string] super -not_blanked"
	        if $display_flag(block_solid) {
		        append disp_opts " -solid"
	        }
	        if { ! $display_flag(block_struct) } {
		        append disp_opts " -hide_struct"
	        }
	        if { ! $display_flag(block_unstruct) } {
		        append disp_opts " -hide_unstruct"
	        }
	        if { ! $display_flag(block_swept) } {
		        append disp_opts " -hide_swept"
	        }
	    }
    }
    if {[info exists use_output_blocks] && $use_output_blocks} {
	    append disp_opts " output_blocks"
    }
    set hexa_selection_display "display_subset $type $sub $what $disp_opts"
    eval ic_hex_display_subset $type $sub $what $disp_opts
}

proc select_hexa_toggle_dynamics {} {
    global tdv_default select_in_dynamics_prev_banner
    global select_in_dynamics
    
    if ![info exists select_in_dynamics] return
	
    if $select_in_dynamics {
        set select_in_dynamics 0
        tdv_cur $tdv_default pick
        if [info exists select_in_dynamics_prev_banner] {
            banner $select_in_dynamics_prev_banner
            unset select_in_dynamics_prev_banner
        }
    } else {
        bind $tdv_default c "do_center %x %y"
        set select_in_dynamics 1
        tdv_cur $tdv_default dynamics
        set select_in_dynamics_prev_banner [banner "Dynamics mode - hit F9 to return to selection mode."]
    }
}

proc select_compcurve {mess {num 1} {opts ""}} {
    global tdv_default select_action
    global select_type select_poly select_vect
    global options last_line

    if {$mess != ""} {
	    banner $mess
    }

    set tags ""
    set picked ""

    lappend tags geom_curve
    switch $select_type {
	inregion {
	    foreach i {0 1 2 3} {
		set pt$i [lindex $select_poly $i]
	    }
	    set picked [$tdv_default pick_region $tags $select_vect \
			    $pt0 $pt1 $pt2 $pt3 $options(select_mode)] 
	}
	circle { 	    
	    set centv [lindex $select_poly 0]
	    set radv [lindex $select_poly 1]
	    foreach xx [$tdv_default pick_circle $tags $select_vect \
			    $centv $radv $options(select_mode)] {
		lappend picked [lindex $xx 0]
	    }
	}
	polygon { 
	    set picked [$tdv_default pick_polygon $tags $select_poly \
			    $options(select_mode)]
	}
	visible - family - part - subset { 
	    set picked [geom_get_objects curve $select_type]
	}
	default {
	    set x [lindex $select_action 1]
	    set y [lindex $select_action 2]
	    set picked [lindex [$tdv_default pick $x $y $tags "" 0] 0]
	}
    }
    
    # Get the composite curve
    set scomp_curves ""
    foreach im $picked {
	set curve [object_name_of_image $im]
	hex_command "find_comp_curve $curve"
	set comp_curve [lindex $last_line 0]
	if {$comp_curve != "(null)"} {
	    lappend scomp_curves [lindex $last_line 0]
	}
    }
    
    # uniquify the list
    set ucomp_curves ""
    catch {unset selected}
    foreach curve $scomp_curves {
	if ![info exists selected($curve)] {
	    lappend ucomp_curves $curve
	    set  selected($curve) 1
	}
    }
	
    if {$mess != ""} {
	banner ""
    }
	
    return $ucomp_curves
}

proc select_vertex {mess {num 1} {opts ""}} {
    return [select_node $mess $num $opts]
}

proc select_node {mess {num 1} {opts ""}} {
    global last_line display_flag hexa_display_selection
    global select_type select_families select_premesh_families
  
    set active_families ""
    if {[info exists select_type] && ($select_type ==  "family")} {
        set fams $select_families
        if [info exists select_premesh_families] {          
            set active_families [family_activename_string]
        }
    } else {
        set fams [volume_activename_string]
    }
    if {$mess != ""} { banner $mess }
    if {[info exists select_type] && ($select_type ==  "family") && [info exists select_premesh_families]} {
        set cmd "select_nodes $num [get_select_options vertex] active_families \"$active_families\" [range_string] m $fams $opts"
    } else {
        set cmd "select_nodes $num [get_select_options vertex] [range_string] m $fams $opts"
    }
    if !$display_flag(edge_vol) { append cmd " surface" }
    if $display_flag(use_blanking) {
	    append cmd " -not_blanked"
    }
    hex_command $cmd
    if {$mess != ""} { banner "" }
    return $last_line
}

proc select_node_text {mess num text} {
    global last_line display_flag hexa_display_selection
    
    banner $mess
    set cmd "select_nodes $num [range_string] m [volume_activename_string]"
    if !$display_flag(edge_vol) { append cmd " surface" }
    append cmd " text $text"
    set hexa_display_selection $cmd
    hex_command $cmd
    banner ""
    return $last_line
}

proc select_curve_parameter {mess} {
    global last_line display_flag
    
    banner $mess
    hex_command "select_curve parameter 1"   
    banner ""
    return $last_line
}
proc select_point {mess} {
    global last_line display_flag
    
    banner $mess
    set pp $display_flag(point)
    set display_flag(point) 1
    hex_command "select_point [point_activename_string]"  
    set display_flag(point) $pp
    banner ""
    return $last_line
}

proc get_select_options {what {opts ""}} {
    global select_type select_poly select_families
    global options
    
    set opt ""
    switch $what {
	    edge {
	        append opt no_highlight
	    }
	    block {
	        append opt no_highlight
	    }
    }
    switch $select_type {
	    inregion - polygon - circle {
	        set polypts ""
	        foreach pt $select_poly {
		        foreach {x y z} $pt {
		            lappend polypts $x $y $z
		        }
	        }
	        set mode ""
	        if {$options(select_mode) == "some"} {
		        set mode partial
	        }
	        append opt " inpoly $mode [llength $select_poly] $polypts"
	    }
	    visible { append opt " all" }
	    blanked { append opt " blanked" }
	    family { append opt " all"}
	    pick {}
    }
    return $opt
}

proc select_edge {{how select} {mess ""} {max_sel 1} {opts ""}} {
    global last_line display_flag use_output_blocks
    global select_type select_families 

    if $display_flag(edge_vol)     { append opts " volume" }
    if $use_output_blocks          { append opts " output_blocks" }
    if $display_flag(edge_proj)    { append opts " proj" }
    if $display_flag(edge_counts)  { append opts " counts" }
    if $display_flag(edge_bunch)   { append opts " bunching" }
    if $display_flag(edge_nodes)   { append opts " nodes" }
    if $display_flag(edge_proj)    { append opts " proj" }
    if $display_flag(edge_mset)    { append opts " highlight_set" }
    if $display_flag(edge_shape_source)   { append opts " shape_source" }
    if $display_flag(edge_shape)   { append opts " edge_shape" }
    if $display_flag(use_blanking) { append opts " -not_blanked" }

    if {$mess != ""} {
	    banner $mess
    }

    if {$how == "corners"} {
	    if {[lindex $opts 0] != "new_format"} {
	        mess "Corner selection not available for this operation\n" red
	        return ""
	    }
	    set nodes [select_corners 2 "corners of the edge"]
	    if {[llength $nodes] != 2} {return ""}
	    set first [join [lindex $nodes 0]]
	    set second [join [lindex $nodes 1]]
	    set edge [list [list $first $second -2]]
	    mess "Edge: $edge\n"
	    return $edge
    }

    if {[info exists select_type] && ($select_type ==  "family")} {
        set fams $select_families
    } else {
        set fams [volume_activename_string]
    }
    
    set cmd "select_edge [get_select_options edge $opts] [range_string] max $max_sel m $fams $opts"
    hex_command $cmd
    if {$last_line == ""} { return "" }
    set ret ""
    if {([lindex $opts 0] != "new_format") && ($max_sel == 1)} {
        set edge [lindex $last_line 0]
        set vert [lindex $edge 0]
        set dim [lindex $edge 1]
        if {$dim < 3} {
	        set ind [lindex $vert $dim]
        } else {
	        set ind 0
	        foreach i $vert {
	            if {[scan $i "%d:%d" ndim nind] == 2} {
                    if {$ndim == $dim} {
                        set ind $nind
                        break
                    }
                }
            }
        }
	    set ret [list [list $vert $dim $ind]]
    } else {
	    set ret $last_line
    }
    if {$mess != ""} {
	    banner ""
    }
    return $ret
}

# options: max and opts not used
proc select_face {{how select} {mess ""} {max 1} {opts ""}} {
    global last_line button_instructions
    global display_flag select_premesh_families
    global select_type select_families use_output_blocks

    set active_families ""
    if {[info exists select_type] && ($select_type ==  "family")} {
        set fams $select_families
        if [info exists select_premesh_families] {           
            set active_families [family_activename_string]
        }
    } else {
        set fams [family_activename_string]
    }

    if {$mess != ""} {
        banner $mess
    }

    # boundary is not supported in selection
    set nitem [lsearch $opts boundary]
    if {$nitem > -1} {
        set opts [lreplace $opts $nitem $nitem]
    }
    set nitem [lsearch $opts only_free]
    if {$nitem > -1} {
        set opts [lreplace $opts $nitem $nitem]
        set only_free 1
    }
    set nitem [lsearch $opts only_mapped]
    if {$nitem > -1} {
        set opts [lreplace $opts $nitem $nitem]
        set only_mapped 1
    }

    set cmd ""
    switch $how {
        corners {
	        set nodes [select_corners 2 "corners of the face"]
	        set len [llength $nodes]
	        if {[expr $len % 2] != 0} { return "" }
	        set faces ""
	        foreach "first second" $nodes {
	            set method "corners $first $second"
                if {[info exists use_output_blocks] && $use_output_blocks} {
                    set options [get_select_options face]
                    if {[lsearch $opts super_face] > -1} {
                        append options " output_blocks"
	                }
                    set cmd "select_super_faces $options max $max active_families \"$active_families\" $method [range_string] $fams $opts"
                } else {
                    set cmd "select_super_faces [get_select_options face] max $max active_families \"$active_families\" $method [range_string] $fams $opts"
                }
                if $display_flag(use_blanking) { append cmd " -not_blanked" }
                hex_command $cmd
                append faces "[string trimright $last_line \n] "
            }
            if {$mess != ""} { banner "" }
            return $faces
	    }
	    select {
	        set method icon
	    }
	    default {
	        mess "Error: Unknown method $how to select_face\n" red
	        return ""
	    }
    }

    if {[info exists use_output_blocks] && $use_output_blocks} {
        set options [get_select_options face]
        if {[lsearch $opts super_face] > -1} {
            append options " output_blocks"
	    }
        set cmd "select_super_faces $options max $max active_families \"$active_families\" $method [range_string] $fams $opts"
    } else {
        set cmd "select_super_faces [get_select_options face] max $max active_families \"$active_families\" $method [range_string] $fams $opts"
    }
    if $display_flag(use_blanking) { append cmd " -not_blanked" }
    hex_command $cmd
    set face $last_line
    if [info exists only_free] {
        set freeFaces ""
        if {[string trim [get_select_options face]] == "all"} {
            set freeFaces [select_hex_get_free_faces]
        } elseif {[string trim [lindex [get_select_options face] 0]] == "inpoly"} {
            foreach f $face {
                 if {[lindex [join $f] end] == "u"} {
                    lappend freeFaces $f
                 }
            }
        } else {
            foreach f $face {
                 if {[lindex [join $f] end] == "u"} {
                    lappend freeFaces $f
                 } else {
                    mess "Selected face \"$f\" is not type free, skipped\n" red
                 }
            }
        }
        if {$freeFaces != ""} {
            set face "$freeFaces"
        } else {
            set face ""
        }
        unset only_free
    }
    if [info exists only_mapped] {
        set mappedFaces ""
        if {([string trim [get_select_options face]] == "all") || ([string trim [lindex [get_select_options face] 0]] == "inpoly")} {
            foreach f $face {
                 if {[lindex [join $f] end] != "u"} {
                    lappend mappedFaces $f
                 }
            }
        } else {
            foreach f $face {
                 if {[lindex [join $f] end] != "u"} {
                    lappend mappedFaces $f
                 } else {
                    mess "Selected face \"$f\" is not type mapped, skipped\n" red
                 }
            }
        }
        if {$mappedFaces != ""} {
            set face "$mappedFaces"
        } else {
            set face ""
        }
        unset only_mapped
    }
    if {$mess != ""} { banner "" }
    return [string trimright $face \n]
}

proc select_hex_get_free_faces {} {
    global display_flag use_output_blocks batch_mode 
    global last_line

    if $batch_mode return
    if ![ic_hex_blocking_loaded] return
	set cmd "display_super_faces [range_string] [family_activename_string]"
	if $use_output_blocks {
        append cmd " output_blocks"
	}
	if $display_flag(use_blanking) {
        append cmd " -not_blanked"
	}
    append cmd " ublock_free_faces"
	hex_command $cmd
    set face $last_line
    return [string trimright $face \n]
}


proc select_block {{how select} {mess ""} {max 1} {opts ""}} {
    global display_flag last_line use_output_blocks
    global button_instructions
    global select_type select_families

    if {[info exists select_type] && ($select_type ==  "family")} {
        set fams $select_families
    } else {
        set fams [volume_activename_string]
    }

    if {$mess != ""} {
        banner $mess
    }
    
    set nitem [lsearch $opts only_free]
    if {$nitem > -1} {
        set opts [lreplace $opts $nitem $nitem]
        set only_free 1
    }
    set nitem [lsearch $opts only_mapped]
    if {$nitem > -1} {
        set opts [lreplace $opts $nitem $nitem]
        set only_mapped 1
    }
    set nitem [lsearch $opts only_swept]
    if {$nitem > -1} {
        set opts [lreplace $opts $nitem $nitem]
        set only_swept 1
    }
    set nitem [lsearch $opts ignore_free]
    if {$nitem > -1} {
        set opts [lreplace $opts $nitem $nitem]
        set ignore_free 1
    }
    set nitem [lsearch $opts ignore_mapped]
    if {$nitem > -1} {
        set opts [lreplace $opts $nitem $nitem]
        set ignore_mapped 1
    }
    set nitem [lsearch $opts ignore_swept]
    if {$nitem > -1} {
        set opts [lreplace $opts $nitem $nitem]
        set ignore_swept 1
    }
    
    set blocks ""
    switch $how {
        corners {
	        set nodes [select_corners 2 "corners of the blocks"]
	        set len [llength $nodes]
	        if !$len { return "" } 
	        if {[expr $len % 2] != 0} { return "" }
	        set blocks ""
	        foreach "first second" $nodes {
	            set first [lindex $nodes 0]
	            set second [lindex $nodes 1]
	            set cmd "select_blocks $max [get_select_options block] corners $first $second [range_string] m $fams -not_blanked"
                if $use_output_blocks { append cmd " output_blocks" }
                if $display_flag(block_ijk) { append cmd " orientation" }
                if $display_flag(block_super) { append cmd " super" }
                if $display_flag(block_solid) { append cmd " -solid" }
                if {!$display_flag(block_struct)} { append cmd " -hide_struct" }
                if {!$display_flag(block_unstruct) } { append cmd " -hide_unstruct" }
                if {!$display_flag(block_swept)} { append cmd " -hide_swept" }
                append cmd " -keep_unstruct3d"
                hex_command $cmd
                append blocks "[string trimright $last_line \n] "
                if {$mess != ""} { banner "" }
                return $blocks
	        }
	    }
        select {
	        set cmd "select_blocks $max [get_select_options block] [range_string] m $fams -not_blanked"
	    }	
        default {
	        mess "Illegal value $how for how\n"
	        return ""
        }
    }
    
    if $use_output_blocks { append cmd " output_blocks" }
    if $display_flag(block_ijk) { append cmd " orientation" }
    if $display_flag(block_super) { append cmd " super" }
    if $display_flag(block_solid) { append cmd " -solid" }
    if {!$display_flag(block_struct)} { append cmd " -hide_struct" }
    if {!$display_flag(block_unstruct)} { append cmd " -hide_unstruct" }
    if {!$display_flag(block_swept)} { append cmd " -hide_swept" }
    # Allow unstruct blocks to be selected by "inpoly" methods
    append cmd " -keep_unstruct3d"  
    hex_command $cmd
    
    set blocks "[string trimright $last_line \n]"
    if {$mess != ""} { banner "" }
    set blocks [lsort -unique $blocks]
    
    if [info exists only_free] {
        set freeBlocks ""
        foreach b $blocks {
            if {[string trimright [ic_hex_print_block_type_info $b] \n] == "free"} {
                append freeBlocks "$b "
            } else {
                if {$how == "select" && [llength $blocks] == "1"} {
                    mess "Selected block \"$b\" is not type free, skipped\n" red
                }
            }
        }
        set blocks "$freeBlocks"
        unset only_free
    }
    if [info exists only_mapped] {
        set mappedBlocks ""
        foreach b $blocks {
            if {[string trimright [ic_hex_print_block_type_info $b] \n] == "mapped"} {
                append mappedBlocks "$b "
            } else {
                if {$how == "select" && [llength $blocks] == "1"} {
                    mess "Selected block \"$b\" is not type mapped, skipped\n" red
                }
            }
        }
        set blocks "$mappedBlocks"
        unset only_mapped
    }
    if [info exists only_swept] {
        set sweptBlocks ""
        foreach b $blocks {
            if {[string trimright [ic_hex_print_block_type_info $b] \n] == "swept"} {
                append sweptBlocks "$b "
            } else {
                if {$how == "select" && [llength $blocks] == "1"} {
                    mess "Selected block \"$b\" is not type swept, skipped\n" red
                }
            }
        }
        set blocks "$sweptBlocks"
        unset only_swept
    }
    if [info exists ignore_free] {
        set nofreeBlocks ""
        foreach b $blocks {
            if {[string trimright [ic_hex_print_block_type_info $b] \n] != "free"} {
                append nofreeBlocks "$b "
            } else {
                if {$how == "select" && [llength $blocks] == "1"} {
                    mess "Selected block \"$b\" is type free, skipped\n" red
                }
            }
        }
        set blocks "$nofreeBlocks"
        unset ignore_free
    }
    if [info exists ignore_mapped] {
        set nomappedBlocks ""
        foreach b $blocks {
            if {[string trimright [ic_hex_print_block_type_info $b] \n] != "mapped"} {
                append nomappedBlocks "$b "
            } else {
                if {$how == "select" && [llength $blocks] == "1"} {
                     mess "Selected block \"$b\" is type mapped, skipped\n" red
                }
            }
        }
        set blocks "$nomappedBlocks"
        unset ignore_mapped
    }
    if [info exists ignore_swept] {
        set nosweptBlocks ""
        foreach b $blocks {
            if {[string trimright [ic_hex_print_block_type_info $b] \n] != "swept"} {
                append nosweptBlocks "$b "
            } else {
                if {$how == "select" && [llength $blocks] == "1"} {
                    mess "Selected block \"$b\" is type swept, skipped\n" red
                }
            }
        }
        set blocks "$nosweptBlocks"
        unset ignore_swept
    }
    return $blocks
}

proc select_surface {mess} {
    global last_line display_flag
    
    if !$display_flag(surf) { set display_flag(surf) 1; hex_update_display surf }
    banner $mess
    hex_command "select_surface"
    banner ""
    return $last_line
}

proc select_curve {mess {max 1} {opts ""}} {
    global last_line display_flag
    
    if !$display_flag(curve) {
	set display_flag(curve) 1; hex_update_display curve
    }
    
    banner $mess
    hex_command "select_curve 1"
    banner ""
    
    return $last_line
}

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

proc block_mark_families {var {one 0} {del_opts ""}} {
    global $var family_name
    mess "block_mark_families var = $var\n"
    
    set ff ""
    if $one {
	set ff $family_name([set $var])
    } else {
	set ff ""
	foreach f [array names $var] {
	    if [set ${var}($f)] { lappend ff $family_name($f) }
	}
    }
    hex_command "mark_blocks unmark" 0
    if {$ff != ""} {
	hex_command "mark_blocks $ff" 0
    }
    hex_command "display_elements -solid marked $del_opts" 0
}

proc surface_mark_families {var {one 0}} {
    global $var family_name
    
    set ff ""
    if $one {
	set val [ set $var ]
	if { $val != "" } {
		set ff $family_name($val)
	}
    } else {
	set ff ""
	foreach f [array names $var] {
	    if [set ${var}($f)] { lappend ff $family_name($f) }
	}
    }
    if {$ff != ""} {
	hex_command "display_surfaces simpler -solid $ff" 0
    } else {
	hex_command "erase_surfaces" 0
    }
}

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

proc block_unmark {} {
    hex_command "mark_blocks unmark" 0
    hex_update_display edge face block
}

proc block_mark {on face {del_opts ""}} {
    global enable_exec
    global button_instructions
    
    if !$enable_exec {
	mess "Please complete the operation on the screen first.\n" red
	return 0
    }
    
    set first ""
    set second ""
    if {$face == 3} {
	set first [select_node "Please select the vertex \
			$button_instructions" ]
	if {$first == ""} { return 0 }
	set second $first
    } else {
	set nns [select_node "Please select the two vertices  \
		$button_instructions" 3]
	set first [lindex $nns 0]
	set second [lindex $nns 1]
	if {($first == "") || ($second == "")} { return 0 }
    }
    set cmd "mark_blocks \{ $first \} \{ $second \}"
    if !$on  { append cmd " unmark" }
    switch $face {
	1 { append cmd " face_neighbors" }
	2 { append cmd " edge_neighbors" }
	3 { append cmd " vertex_neighbors" }
    }
    
    hex_command $cmd 0
    hex_command "display_elements marked -solid $del_opts" 0
    return 1
}

proc block_mark_fams {on face {del_opts ""}} {
    set ff [select_some_volume_families]
    if {$ff == ""} return
    
    set cmd "mark_blocks $ff [range_string]"
    if !$on  { append cmd " unmark" }
    switch $face {
	1 { append cmd " face_neighbors" }
	2 { append cmd " edge_neighbors" }
	3 { append cmd " vertex_neighbors" }
    }
    
    hex_command $cmd 0
    hex_command "display_elements marked -solid $del_opts" 0 
}

proc block_mark_all { on mess {del_opts {}} } {
	set cmd "mark_blocks  [volume_activename_string] [range_string]"
	if { $on == 0 } {
		lappend cmd "unmark"
	}
	hex_command $cmd
	hex_command "display_elements marked -solid $del_opts" 0
}

proc block_mark_super {blocks} {
    global last_line use_output_blocks display_flag

    foreach n $blocks {
        set cmd "mark_blocks superblock $n"
        if $use_output_blocks {
            append cmd " output_blocks"
        }
        if $display_flag(use_blanking) {
            append cmd " -not_blanked"
        }
        hex_command $cmd
    }
}

proc block_mark_numbers {on mess {del_opts {}}} {
    global select_block_numbers display_flag
    
#    set bnums_save $display_flag(block_numbers)
#    if { $bnums_save == 0 } {
## turn on block_numbers
#	set display_flag(block_numbers) 1
#	update_display block
#    }
    set nb [get_hexa_nsuperblocks]
    for {set i 1} {$i <= $nb} {incr i} {
	set select_block_numbers($i) 0
    }
#
# highlight selected blocks so far -- need hex_command to add to del
# of form 
# hex_command "display_elements marked ... "
#
    set r [form_block_numbers select_block_numbers 0 $mess]
    
    if $r {
	for {set i 1} {$i <= $nb} {incr i} {
	    if $select_block_numbers($i) {
		if $on {
		    hex_command "mark_blocks superblock $i" 0
		} else {
		    hex_command "mark_blocks unmark superblock $i" 0
		}
	    }
	}
    }
    hex_command "display_elements marked -solid $del_opts" 0
#    if { $bnums_save == 0 } {
## turn block numbers back off
#	set $display_flag(block_numbers) 0
#	update_display block
#    }
	
     return $r
}

proc select_material {mess} {
    global families family_name family_dims last_line family_active
    
    set appvols [volume_name_string]
    set vols ""
    foreach f $appvols {
	lappend vols $f
    }
    
    set mat [choose_one $mess $vols "" upright]
    if {$mat == ""} { return "" }
    
    if { [ string index $mat 0 ] == "$" } {
	return $mat
    }
    foreach f $families {
	if {($family_dims($f) == 3) && ($mat == $family_name($f))} {
	    return $mat
	}
    }
    define_family $mat
    return $mat
}

proc define_family { mat } {
# create a new volume family
    global last_line family_name  family_dims family_active

    hex_command "define_family $mat"
}

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

# Not really selection-oriented things....

proc get_families {} {
    global all_lines families family_dims family_active family_name
    
    hex_command "list_families dims"
    catch {unset family_dims}
    catch {unset family_active}
    set families "-1 0"
    set family_name(-1) VORFN
    set family_dims(-1) 3
    set family_active(-1) 0
    set family_name(0) ORFN
    set family_dims(0) 2
    set family_active(0) 1
    set i 1
    foreach line $all_lines {
	if {$line == ""} continue
	set f [lindex $line 0]
	set d [lindex $line 1]
	if {$f != "__PARAMS__"} {
	    lappend families $i
	}
	set family_dims($i) $d
	set family_name($i) $f
	set family_active($i) 1
	incr i
    }
}

proc reset_families {} {
    global families family_active
    
    foreach f $families {
	set family_active($f) 1
    }
    set family_active(0) 0
    set family_active(-1) 0
}

# reset 0 don't change index_min or index_max
# reset 1 set index_min to 0  and index_max to index_max_limit
# reset 2 obsolete
# reset 3 increment changed indices only
proc get_indices {reset} {
    global last_line index_min index_max index_min_limit index_max_limit
    global index_form
    
    if [info exists index_max_limit] {
        foreach i [array names index_max_limit] {
            set old_limits($i) $index_max_limit($i)
        }
    }
    catch {unset index_min_limit}
    catch {unset index_max_limit}
    
    set should_update 0
    
    hex_command "ijk_max"
    set i 0
    set nnew 0
    if { $reset == 3 } {
        # don't change if index form is open
        if {[info exists index_form] && [winfo exists $index_form]} {
            set reset 0
            set reset_changed 0
        } else {
            set reset 0
            set reset_changed 1
        }
    } elseif { $reset } {
        set reset_changed 1
    } else {
        set reset_changed 0
    }
    foreach m $last_line {
        if {[scan $m %d:%d dim val] != 2} {
            set dim $i
            set val $m
        }
        if {($dim > 2) && ![info exists index_min($dim)]} { incr nnew }
        if {$reset || ![info exists index_min($dim)] || ($index_min($dim) == "")} {
            set index_min($dim) 0
        }
        set index_min_limit($dim) 0
        if {$reset || ![info exists index_max($dim)] || ($index_max($dim) == "")} {
            set index_max($dim) $val
        } 
        if {$reset_changed && [info exists old_limits($dim)] && ($old_limits($dim) < $val)} {
            # in this dimension the range has increased.
            set index_max($dim) $val
            set should_update 1
        }
        set index_max_limit($dim) $val
        set index_min_limit($dim) 0
        if {$index_max($dim) > $index_max_limit($dim)} {
	        set index_max($dim)  $index_max_limit($dim)
	    }
        if {$index_min($dim) > $index_max_limit($dim)} {
	        set index_min($dim) $index_max_limit($dim)
        }
        if {$reset == 2} {
            incr index_min($dim)
            incr index_max($dim) -1
        }
        incr i
    }
    if {$nnew == 1} {
        mess "1 new O-grid index defined\n"
    } elseif {$nnew > 1} {
        mess "$nnew new O-grid indices defined\n"
    }
    
    foreach i [array names index_min] {
        if ![info exists index_min_limit($i)] { unset index_min($i) }
    }
    foreach i [array names index_max] {
        if ![info exists index_max_limit($i)] { unset index_max($i) }
    }

    if {[info exists index_form] && [winfo exists $index_form]} {
        set parent [winfo parent $index_form]
        if {$parent == "."} {
            setup_index_box ""
        } else {
            setup_index_box $parent
        }
    }
    if $should_update {
        hex_update_display edge face block vert
        scan_reset
    }
    readjust_edit_geometry
}

proc select_some_volume_families {} {
    global select_some_families
    global family_active family_dims families family_name
    
    set fams ""
    foreach f $families {
	if {$family_dims($f) == 3} {
	    lappend fams "$f -text $family_name($f)"
	    set select_some_families($f) $family_active($f)
	}
    }
    if {$fams == ""} { 
        tk_dialog .err "Error" "No volume families are visible" "" 0 Ok
    }
    
    form_kill .mark_fams
    set d [form_init .mark_fams "Volume families" "" "done cancel"]
    form_frame $d.fams flat 0 {0 0}
    check_box $d.fams $fams 6 select_some_families
    form_finish +300+300
    if ![form_wait .mark_fams] { return "" }
    
    set fams ""
    foreach i [array names select_some_families] {
        if $select_some_families($i) { lappend fams $i }
    }
    return $fams
}

proc select_one_family {mess} {
    global families family_dims family_name
    
    set appfam [family_name_string]
    set fams ""
    foreach f $appfam {
        lappend fams $f
    }
    return [choose_one $mess $fams "" +300+300]
}

############################# More hexa commands ##########################

proc hex_command {args} {
    global last_line
    global env ai_environment

    set cmd "ic_hex_[lindex $args 0]"

    if [info exists env(HEXA_DEBUG)] {
	    mess "cmd: $cmd\n" blue
    }

    if [catch {eval $cmd} res] {
	    set mess [hex_trim_error $res]
	    set last_line $res
	    if {[info exists ai_environment] && ($ai_environment)} {
	        if {[llength $mess] > 0} { msg ERROR $mess }
	    } else {
	        mess "$mess\n" red
	    }
	    return -code return
    }

    set cmd [lindex $cmd 0]
    if ![b info exists dont_record_command($cmd)] {
	    ic_hex_is_modified 1
    }

    set last_line $res
    if [info exists env(HEXA_DEBUG)] {
	    mess "res: $res\n" blue
    }
    return $res
}

proc hex_trim_error {res} {
    set mess ""
    regsub -all ";" $res "" res
    regsub -all "\"" $res "" res
    regsub -all "\{" $res "" res
    regsub -all "\}" $res "" res
    foreach s $res {
	if [string match "executing" $s] {
	    break
	} else {
	    lappend mess $s
	}
    }
    
    if {$mess != ""} {
	puts $mess
	#set last [expr ([llength $mess] - 2) / 2]
	#set mess [lrange $mess 0 $last]
    }
    return $mess
}

proc hex_init_globals {} {
    global display_flag project_type surface_detail use_output_blocks
    global display_linked_to dim_to_mesh
    global enable_exec
    global button_instructions
    global proj_type

    foreach type {point curve surf vert face block scan edge_nodes mesh \
		      block_classes block_refinement use_blanking block_solid \
		      block_ijk block_numbers block_worst \
		      face_periodic face_boundary output_blocks use_blanking face_norm \
		      edge_bunch edge_proj edge_vol edge_counts edge_mset \
			mesh_mesh } {
	set display_flag($type) 0
    }
    set display_flag(block_super) 1
    set display_flag(edge) 1
    set dim_to_mesh 2
    set proj_type -1
    set project_type -1
    set surface_detail 0
    set use_output_blocks 0
    set enable_exec 1
    set button_instructions \
        "left button = select; middle = accept, right = back up / cancel."
}

proc volume_activename_string {} {
    global fam_visible

    set vfams ""
    set fams [ic_hex_list_subsets]
    foreach {fam dim} [ic_hex_list_families dims] {
	# if {$dim == 3} {
	    lappend fams $fam
	# }
    }

    foreach fam $fams {
	if {[info exists fam_visible($fam)] && ($fam_visible($fam))} {
	    lappend vfams $fam
	}
    }
    
    if {[info exists fam_visible(VORFN)] && ($fam_visible(VORFN) == 1)} {
	lappend vfams VORFN
    }
    return $vfams
}

proc family_activename_string {} {
    global fam_visible

    set vfams ""
    foreach name [array names fam_visible] {
	if [ic_geo_check_family $name] {
	    if { $name == "ORFN" } {
		set name VORFN
	    }
	    if {([info exists fam_visible($name)]) && $fam_visible($name)} {	    
		lappend vfams $name
	    }
	}
    }

    return $vfams
}

proc surface_activename_string {} {
}

proc del_dim {ijk1 ijk2} {
    for {set i 0} {$i < 3} {incr i} {
        if {[lindex $ijk1 $i] != [lindex $ijk2 $i]} {
            return $i
        }
    }
    # now look at the remainder of the coordinates
    set l1 [llength $ijk1]
    set l2 [llength $ijk2]
    set mn [expr {($l1 < $l2) ? $l1 : $l2}]

    for {set i 3} {$i < $mn} {incr i} {
        set hp [lindex $ijk1 $i]
        if {[scan [lindex $ijk1 $i] "%d:%d" d1 i1] != 2} {
            mess "internal error 1\n" red
            return ""
        }
        if {[scan [lindex $ijk2 $i] "%d:%d" d2 i2] != 2} {
            mess "internal error 2\n" red
            return ""
        }
        if {$d1 < $d2} {
            return $d1
        }
        if {$d2 < $d1} {
            return $d2
        }
        if {$i1 != $i2} {
            return $d1
        }
    }
   if {$l1 < $l2} {
        incr l2 -1
        if {$l1 != $l2} {
            mess "internal error 3\n" red
            return ""
        }
        if {[scan [lindex $ijk2 $l2] "%d:%d" d2 i2] != 2} {
            mess "internal error 4\n" red
            return ""
        }
        return $d2
    }
    if {$l2 < $l1} {
        incr l1 -1
        if {$l1 != $l2} {
            mess "internal error 5\n" red
            return ""
        }
        if {[scan [lindex $ijk1 $l1] "%d:%d" d1 i1] != 2} {
            mess "internal error 6\n" red
            return ""
        }
        return $d1
    }
    mess "identical nodes\n" red
    return ""
}

proc node_index {ijk dim} {
    if {$dim < 3} {
        return [lindex $ijk $dim]
    }
    set len [llength $ijk]
    for {set i 3} {$i < $len} {incr i} {
        set hp [lindex $ijk $i]
        if {[scan [lindex $ijk $i] "%d:%d" d ind] != 2} {
            mess "internal error 7\n" red
            return ""
        }
        if {$d == $dim} {
            return $ind
        }
    }
    return 0
}

# called from batch
proc hex_set_return_vars {args} {
    global _tempx _tempy _tempz 
    global _temp2x _temp2y _temp2z

    foreach {n v} $args {	
	set $n $v
	script_interp eval "global $n; set $n $v"
    }
}

################### dummy procs ###############

proc readjust_edit_geometry {} {
}

##############################################

proc select_hexa_reset {} {
    global select_action tdv_waiting_for_click tdv_default hexa_select
    global select_in_dynamics

    set select_action cancel
    if [info exists hexa_select] {
	unset hexa_select
	if [info exists tdv_waiting_for_click($tdv_default)] {
	    set tdv_waiting_for_click($tdv_default) {3 0 0}
	}	
    }
}

proc hook_hexa_F9 {} {
    global select_in_dynamics

    set select_in_dynamics 0
    tdv_set_key_command F9 select_hexa_toggle_dynamics
}
