
# This code creates the user interface for the mesh editor.
#
# Copyright (c) 1993 - 1995 Pacific Marketing and Consulting, Inc,
#       and ICEM Systems, GmbH.  All rights reserved.
# Author:  Wayne A. Christopher, wayne@icemcfd.com
#
# Note that many of the functions that used to be here are now in
# guibase/select_geom.tcl and select_common.tcl

proc edit_struct_list {what numbers mess} {
    global edit_struct_list_var
    
    error "not yet implemented"
    
    catch {unset edit_struct_list_var}
    foreach i $numbers {
	if [info exists str_surf($str_cur,entity,$what,$i)] {
	    set edit_struct_list_var($str_surf($str_cur,entity,$what,$i)) 1
	}
    }
    set ss [select_struct_surf $what 0 item edit_struct_list_var]
    if ![string compare $ss "*cancel*"] { return $numbers }
    set ret ""
    foreach s $ss {
	lappend ret [$s get -number]
    }
    return $ret
}

proc get_struct_list {what {mess ""}} {
    return [edit_struct_list $what "" $mess]
}

proc str_select_highlight {what num var_name} {
    if {$var_name != ""} {
	global $var_name
        set ${var_name}($num) 1
    }
    ic_str_highlight $what $num 1 white
}

proc str_select_unhighlight {type num var_name} {
    if {$num == ""} {
	ic_str_highlight $type all 0
    } else {
	ic_str_highlight $type $num 0
    }
    
    if {$var_name != ""} {
	global $var_name
	
	if {$num == ""} {
	    foreach n [array names $var_name] {
		set ${var_name}($n) 0
	    }
	} else {
	    set ${var_name}($num) 0
	}
    }
}


# Return the list of surfaces that were selected.
# what is domain, subface, etc etc
# max is the maximum number allowed or 0 for any number
# how is whether we should return node locations or not
# if var_name is set the keys are the str_surf objects

proc select_struct_surf {what max {how item} {var_name ""} {mess ""}} {
    global select_action select_mess_printed options
    global select_pos str_surf tdv_mouse_bindings
    global str_type_visible tdv_default ai_environment

    foreach s { select done cancel } {
	set b_$s [lindex {"" left middle right} $tdv_mouse_bindings($s)]
    }
    
    if {$mess == ""} {
	set mess "$what objects"
    }
    banner "Select $mess with the $b_select button; $b_done = done, $b_cancel = back up / cancel, '?' = list options."
    
    set reset_visible 0
    if !$str_type_visible($what) {
	set str_type_visible($what) 1
	disp_change_overall_visible $what
	set reset_visible 1
    }
    
    set pre_select ""
    if {$var_name != ""} {
	if {$var_name == "default"} {
	    set var_name select_struct_surf_default_var
	    catch {unset select_struct_surf_default_var}
	}
	
	global $var_name
	
	if [info exists $var_name] {
	    foreach ch [array names $var_name] {
		if [set ${var_name}($ch)] {
		    lappend pre_select $ch
		    str_select_highlight $what $ch $var_name
		}
	    }
	}
	
	set w .selection
	top_window $w 1 Selection
	top_geometry $w -0-0
	listbox $w.list -width 5 -background white -selectmode multiple \
	    -selectbackground cyan -selectborderwidth 0 \
	    -exportselection 0 -yscroll "$w.scroll set"
	scrollbar $w.scroll -command "$w.list yview" -background #cdb79e
	
	frame $w.buts
	button $w.buts.all -text All -command \
	    "select_set $what 1 $w.list $var_name all"
	button $w.buts.none -text None -command \
	    "select_set $what 0 $w.list $var_name all"
	button $w.buts.invert -text Invert -command \
	    "select_set $what t $w.list $var_name all"
	button $w.buts.done -text Done -command \
	    "uplevel \#0 set select_action done"
	button $w.buts.cancel -text Cancel -command \
	    "uplevel \#0 set select_action back"
	grid $w.buts.all    -row 0 -column 0 -sticky news
	grid $w.buts.none   -row 0 -column 1 -sticky news
	grid $w.buts.invert -row 1 -column 0 -sticky news
	grid $w.buts.done   -row 2 -column 0 -sticky news
	grid $w.buts.cancel -row 2 -column 1 -sticky news
	pack $w.buts -side bottom -fill both
	pack $w.list -side left -fill both -expand 1
	pack $w.scroll -side left -fill both
	
	set i 0
	foreach im [ic_str_list_entities_visible $what 1] {
	    if ![info exists ${var_name}($im)] {
		set ${var_name}($im) 0
	    }
	    $w.list insert end $im
	    if [set ${var_name}($im)] {
		$w.list select set $i
	    }
	    set select_pos($im) $i
	    incr i
	}
	
	bind $w.list <1> "select_set $what t $w.list $var_name \[%W get \[%W nearest %y\]\]; break"
	foreach ev {<B1-Motion> <ButtonRelease-1> <B1-Leave> <B1-Enter>} {
	    bind $w.list $ev break
	}
	
	trace variable $var_name w select_trace_proc
    }
    if {[info exists ai_environment] && $ai_environment && \
        ($what == "domain" || $what == "subface" || $what == "edge" || $what == "vertex")} {
        select_set_bindings 10 1 0 0 "Select Structured Mesh"
    } else {
        select_set_bindings 1 0 0 0 ""
    }
    set stuff $pre_select
    set nstuff [llength $stuff]
    set finished 0
    set cancel_if_num $nstuff
    
    while {!$finished} {
	tkwait variable select_action
	switch [lindex $select_action 0] {
	    done {
		if [info exists pline] {
		    if {[$pline get -npts] > 2} {
			set poly ""
			for {set i 0} {$i < [$pline get -npts]} {incr i} {
			    lappend poly [lindex [$pline get_point $i] 0]
			}
			set picks ""
			set specs ""
			set xx [ic_str_pick_polygon $what $poly \
				    $how $options(select_mode)_$how]
			set stuff [concat $stuff $xx]
			incr nstuff [llength $xx]
			if {$how == "item"} {
			    foreach x $xx {
				str_select_highlight $what $x $var_name
			    }
			}
		    }
		    $pline delete
		    unset pline
		    tdv_cur $tdv_default pick
		    if {$max && ($nstuff > $max)} { set finished 1 }
		    
		} 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 {
		    if {$nstuff == $cancel_if_num} {
			set finished -1
		    } else {
			incr nstuff -1
			set prev [lindex $stuff $nstuff]
			set stuff [lrange $stuff 0 [expr {$nstuff - 1}]]
			str_select_unhighlight $what $prev $var_name
		    }
		}
	    }
	    press {
		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"
		    }
		}
	    }
	    polygon {
		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 rbox] {
		    $rbox configure -x2 $x -y2 $y
		} else {
		    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 {
		set x [lindex $select_action 1]
		set y [lindex $select_action 2]
		set new_im ""
		if [info exists rbox] {
		    set poly [list "[$rbox get -x1] [$rbox get -y1]" \
				  "[$rbox get -x1] $y" \
				  "$x $y" \
				  "$x [$rbox get -y1]"]
		    set picks ""
		    set specs ""
		    set xx [ic_str_pick_polygon $what $poly $how \
				 $options(select_mode)_$how]
		    set stuff [concat $stuff $xx]
		    incr nstuff [llength $xx]
		    
		    if {$how == "item"} {
			foreach x $xx {
			    str_select_highlight $what $x $var_name
			}
		    }
		    if {$max && ($nstuff > $max)} {
			set finished 1
		    }
		    
		    $rbox delete
		    unset rbox
		    
		} elseif ![info exists pline] {
		    set xx [ic_str_pick_single $what $x $y $how]
		    
		    if {($xx != "") && ($how == "item")} {
			set num [lindex $xx 0]
			if {[lsearch $stuff $num] < 0} {
			    lappend stuff $num
			    incr nstuff
			    str_select_highlight $what $num $var_name
			    if {$max && ($nstuff > $max)} {
				set finished 1
			    }
			} else {
			    if {($var_name != "") && \
				    [set ${var_name}($num)]} {
				# In this case we unselect it...
				set ${var_name}($num) 0
				
				set l 0
				foreach num2 $stuff {
				    if {$num2 == $num} {
					set stuff [lreplace $stuff $l $l]
					str_select_unhighlight $what $num $var_name
					incr nstuff -1
					break
				    }
				    incr l
				}
			    }
			}
		    }
		}
	    }
	    select {
		foreach {op num} [lrange $select_action 1 end] {
		    if {$op == "select"} {
 			if ![set ${var_name}($num)] {
			    lappend stuff $num
			    incr nstuff
			    str_select_highlight $what $num $var_name
			}
		    } else {
			if [set ${var_name}($num)] {
			    set ${var_name}($num) 0
			    
			    set loc 0
			    foreach num2 $stuff {
				if {$num2 == $num} {
				    set stuff [lreplace $stuff $loc $loc]
				    str_select_unhighlight $what $num $var_name
				    incr nstuff -1
				    break
				}
				incr loc
			    }
			}
		    }
		}
		if {$max && ($nstuff > $max)} { set finished 1 }
	    }
	    unselect_all {
		set stuff ""
		set nstuff 0
		str_select_unhighlight $what "" $var_name
	    }
	    all {
		str_select_unhighlight $what "" $var_name
		ic_str_topo_make_surfs $what 0
		set stuff [ic_str_list_entities $what]
		set nstuff [llength $stuff]
		mess "Selected all ${what}s\n"
		set finished 1
	    }
	    all_boundary {
	        if {$what == "subface"} {
	           set stuff [ic_str_list_boundary_subfaces]
	           set nstuff [llength $stuff]
	           mess "Selected $nstuff boundary subfaces\n"
	           set finished 1
		} else {
	            mess "Only available for subfaces\n"
	            continue
	        }
	    }
	    all_block {
	        if {$what == "subface"} {
	           set stuff [ic_str_list_blockif_subfaces]
	           set nstuff [llength $stuff]
	           mess "Selected $nstuff blockinterfaces\n"
	           set finished 1
		} else {
	            mess "Only available for subfaces\n"
	            continue
	        }
	    }	    
	    visible {
		if ![llength [ic_str_list_entities_visible $what 1]] { 
		    str_select_unhighlight $what "" $var_name
		    ic_str_topo_make_surfs $what 0
		}		
		set stuff [ic_str_list_entities_visible $what 1]
		set nstuff [llength $stuff]
		mess "Selected visible ${what}s\n"
		set finished 1
	    }
	    family - color - part {
		set ttt $select_action
		if {$ttt == "part" && ($what == "domain" || $what == "subface" || \
		                       $what == "edge" || $what == "vertex")} {
		    set fams [select_struct_families $what]
		} else {
		    set ccc [expr {$select_action == "color"}]
		    set fams [select_families $ccc 1 0]
		}
		if {$fams != ""} {
		    str_select_unhighlight $what "" $var_name
		    ic_str_topo_make_surfs $what 0
		    set stuff [ic_str_list_in_families $what $fams]
		    set nstuff [llength $stuff]
		    if {$ttt == "part"} {
		        mess "Selected $nstuff ${what}s in part(s): $fams\n"
		    } else {
		        mess "Selected $nstuff ${what}s in families: $fams\n"
		    }
		    set finished 1
		}
	    }
	    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"
		}
	    }
	    cancel {
		if [info exists pline] {
		    $pline delete
		    unset pline
		}
		set cancel_if_num 1
		set finished -1
	    }
	}
    }
    
    str_select_unhighlight $what "" $var_name
    
    if {$var_name != ""} {
	trace vdelete $var_name w select_trace_proc
	top_destroy .selection
    }
    select_unset_bindings 1
    banner ""
    
    if {($finished == -1) && ($cancel_if_num > 0)} {
	return *cancel*
    }
    
    set nstuff ""
    foreach s $stuff {
	if ![info exists found_surf($s)] {
	    lappend nstuff $s
	    set found_surf($s) 1
	}
    }
    
    if $max {
	set nstuff [lrange $nstuff 0 [expr $max - 1]]
    }

    if $reset_visible {
	set str_type_visible($what) 0
	disp_change_overall_visible $what
    }
    
    return $nstuff
}

proc select_set {what op w var num} {
    global $var select_action
    
    if {$num == "all"} {
	set ims [array names $var]
    } elseif {$num == "none"} {
	set select_action unselect_all
	return
    } else {
	set ims $num
    }
    set ss select
    foreach im $ims {
	set nv $op
	set ov [set ${var}($im)]
	if {$nv == "t"} {
	    set nv [expr !$ov]
	} elseif {$nv == $ov} {
	    continue
	}
	if $nv {
	    lappend ss select $im
	} else {
	    lappend ss unselect $im
	}
    }
    set select_action $ss
}

proc select_trace_proc {var im op} {
    global select_pos $var
    
    if [set ${var}($im)] {
	.selection.list select set $select_pos($im)
    } else {
	.selection.list select clear $select_pos($im)
    }
}

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

# The press_cmd must return the face number that we are going for ...

proc select_struct_surf_node {im action_cmd} {
    global select_action
    global tdv_default

    error "not yet implemented"
    
    select_set_bindings 1 0 0 0 ""
    bind $tdv_default <F9> "select_toggle_dynamics 1"
    
    set node_spec node
    set finished 0
    
    while {!$finished} {
	tkwait variable select_action
	switch [lindex $select_action 0] {
	    done {
		set result 1
		set finished 1
	    }
	    back {
		set result 0
		set finished 1
	    }
	    press {
		set xx [$tdv_default pick [lindex $select_action 1] \
			    [lindex $select_action 2] $im $node_spec 0]
		if {$xx != ""} {
		    set face [eval $action_cmd press \"[lindex $xx 1]\"]
		    if $face {
			set node_spec "node $face"
		    }
		}
	    }
	    move {
		set xx [$tdv_default pick [lindex $select_action 1] \
			    [lindex $select_action 2] $im $node_spec 0]
		if {$xx != ""} {
		    set face [eval $action_cmd move \"[lindex $xx 1]\"]
		    if {$face && ($node_spec == "node")} {
			set node_spec "node $face"
		    }
		}
	    }
	    release {
		set xx [$tdv_default pick [lindex $select_action 1] \
			    [lindex $select_action 2] $im $node_spec 0]
		if {$xx != ""} {
		    eval $action_cmd release \"[lindex $xx 1]\"
		}
	    }
	}
    }
    select_unset_bindings 1
    banner ""
    return $result
}

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

# Here is the new code that selects and modifies struct nodes.
# It returns a str_surf with the selected nodes.

# what is node
# mult is 0 or 1 depending on whether a single one or multiple are wanted
# from_surfs is the currently visible set of str_surfs to select from

proc select_struct_node {{max_num 0} {from_surfs ""} {partial 0}
		    {mess ""} {do_uniq 1} {take_first_press 0}} {
    global select_action disp_options options tdv_mouse_bindings
    global str_cur
    global tdv_default

    set partial [expr {$options(select_mode) == "some"}]
    
    ic_str_create_selection_subset 1 1
    
    if {$mess == ""} {
	if $max_num {
	    if {$max_num == 1} { set s "" } else { set s s }
	    set mess "$max_num node$s"
	} else {
	    set mess "nodes"
	}
    }
    foreach s { select done cancel } {
	set b_$s [lindex {"" left middle right} $tdv_mouse_bindings($s)]
    }
    
    banner "Select $mess with the $b_select button; $b_done = done,\
	$b_cancel = back up / cancel, '?' = list options."
    select_set_bindings 1 0 0 0 ""
    set finished 0
    set xypos ""
    set num_sel 0
    
    set nstuff 0
    while {!$finished} {
	set num_surf [ic_str_selection_numnodes]
	
	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]
			    set v [$tdv_default screen2world [lindex $p 0] [lindex $p 1]]
			    if !$i { set vect [lindex $v 1] }
			    lappend poly [lindex $v 0]
			}
			ic_str_add_pick_polygon node $poly $vect $partial
		    }
		    $pline delete
		    unset pline
		    tdv_cur $tdv_default pick
		    incr nstuff
		} 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 {
		    if !$nstuff {
			set finished 1
		    } else {
			incr nstuff -1
			ic_str_pick_remove_last
		    }
		}
	    }
	    cancel {
		if [info exists pline] {
		    $pline delete
		    unset pline
		}
		set finished -1
	    }
	    press {
		if $take_first_press {
		    set x [lindex $select_action 1]
		    set y [lindex $select_action 2]
		    set v [$tdv_default screen2world $x $y]
		    ic_str_add_pick_single node [lindex $v 0] [lindex $v 1]
		    incr nstuff
		    set xypos "$x $y"
		    set finished 1
		    
		} elseif {$max_num && ($num_sel >= $max_num)} {
		    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"
			}
		    }
		}
	    }
	    polygon {
		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 rbox] {
		    $rbox configure -x2 $x -y2 $y
		} else {
		    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 {
		if {$max_num && ($num_sel >= $max_num)} {
		    set finished 1
		} else {
		    set x [lindex $select_action 1]
		    set y [lindex $select_action 2]
		    set new_im ""
		    if [info exists rbox] {
			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 vect [lindex $v 1]
			    lappend poly [lindex $v 0]
			}
			ic_str_add_pick_polygon node $poly \
			    $vect $partial
			
			$rbox delete
			unset rbox
			incr nstuff
			
		    } elseif ![info exists pline] {
			set v [$tdv_default screen2world $x $y]
			set n [ic_str_add_pick_single node \
				   [lindex $v 0] [lindex $v 1]]
			incr nstuff
		    }
		}
		set num_sel [ic_str_selection_numnodes]
		if {!$options(edit_wait) && $max_num && ($num_sel >= $max_num)} {
		    set finished 1
		}
	    }
	    visible {
		# This means select all nodes in the current scan planes.
		ic_str_pick_scan_plane_nodes
		set num_sel [ic_str_selection_numnodes]
	    }
	    all - family - color {
		mess "Not yet implemented: 'v' will give you all nodes on scan planes\n" red
	    }
	}
    }
    select_unset_bindings 1
    banner ""
    
    if $do_uniq { ic_str_uniqify_selection }
    
#    $sel_surf configure -visible 0
    set cc [ic_str_selection_numnodes]
    if {($cc == 0) || ($finished == -1)} {
	mess "Cancel.\n"
	ic_str_clear_selection_subset
	return ""
    }
    mess "$cc nodes\n"

    if $take_first_press {
	return [list selected $xypos]
    } else {
	return selected
    }
}

# This always moves the selected surface that's in the batch interpreter

proc select_move_str_surf {allow_invert xypos do_proj} {
    global select_action tdv_mouse_bindings
    global tdv_default

    foreach s { select done cancel } {
	set b_$s [lindex {"" left middle right} $tdv_mouse_bindings($s)]
    }
    
    banner "Move all selected with the $b_select button; $b_done = done, $b_cancel = back up / cancel."
    select_set_bindings 0 0 0 0 ""
    set finished 0
    
    set nstuff 0
    set start_pt ""
    
    # Take the position from the previous click as the first press for the move
    if {$xypos != ""} {
	set x [lindex $xypos 0]
	set y [lindex $xypos 1]
	set v [$tdv_default screen2world $x $y]
	set start_pt [lindex $v 0]
	ic_str_push_node_positions
    }
    
    while {!$finished} {
	tkwait variable select_action
	switch [lindex $select_action 0] {
	    done {
		ic_str_clear_node_positions
		set finished 1
	    }
	    back {
		set np [ic_str_pop_node_positions]
		switch $np {
		    0 { set finished 1 }
		}
	    }
	    press {
		if {$start_pt != ""} continue
		set x [lindex $select_action 1]
		set y [lindex $select_action 2]
		set v [$tdv_default screen2world $x $y]
		set start_pt [lindex $v 0]
		set n [ic_str_push_node_positions]
	    }
	    move {
		if {$start_pt == ""} continue
		set x [lindex $select_action 1]
		set y [lindex $select_action 2]
		set v [$tdv_default screen2world $x $y]
		ic_str_drag_nodes $start_pt [lindex $v 0] [lindex $v 1] \
		    $do_proj $allow_invert
	    }
	    release {
		if {$start_pt == ""} continue
		set x [lindex $select_action 1]
		set y [lindex $select_action 2]
		set v [$tdv_default screen2world $x $y]
		ic_str_drag_nodes $start_pt [lindex $v 0] [lindex $v 1] \
		    $do_proj $allow_invert
		set start_pt ""
		if {$xypos != ""} {
		    ic_str_clear_node_positions
		    set finished 1
		}
	    }
	}
    }
    select_unset_bindings 1
    banner ""
}
