
# This code is shared by all the ICEM CFD GUI's.
#
# Copyright (c) 1996 Pacific Marketing and Consulting, Inc,
#       and ICEM Systems, GmbH.  All rights reserved.
# Author:  Wayne A. Christopher, wayne@icemcfd.com
#

proc boco_find_available {} {
    global boco_solvers_available env boco_solver
    
    if ![info exists boco_solvers_available] {
	source $env(ICEM_ACN)/icemcfd/output-interfaces/solver_table.tcl
	foreach i $solver_interfaces {
	    if [lindex $i 3] {
		foreach name [lindex $i 0] {
		    set boco_solvers_available($name) [lindex $i 1]
		}
	    }
	}
    }
    set boco_solvers_available(Generic) generic
    if ![info exists boco_solver] {
	set boco_solver [boco_solver_default]
    }
}

proc boco_edit_sol {prefix} {
    global boco_data boco_nument boco_numbc boco_modified boco_famdata
    global boco_solvers_available env boco_solver boco_sol_curfam
    global solver_boco_info boco_sol_prefix boco_sol_modified
    
    set boco_sol_prefix $prefix
    set pref ""
    if {$prefix != ""} { set pref $prefix, }
    
    if ![info exists boco_numbc(${pref}domain)] {
	user_error "No boco data is currently available"
	return
    }
    boco_find_available
    boco_sol_setsolver
    
    boco_sol_convert $pref 1 1

    if ![info exists boco_famdata] { user_error "There is no boco data"; return }
    
    set boco_sol_modified 1
    
    boco_sol_form .boco_sol 1
    boco_sol_setfam [lindex [lsort [array names boco_famdata]] 0]
    if ![form_wait .boco_sol] return
    if [info exists boco_sol_modified] boco_sol_write
    
    boco_sol_convert $pref 0 0
    set boco_modified($prefix) 1
}

proc boco_edit_sol_new_format {bocofile} {
    global boco_data boco_famdata
    global boco_solvers_available env boco_solver boco_sol_curfam
    global solver_boco_info boco_sol_prefix
    
    set boco_sol_prefix ""
    
    boco_find_available
    boco_sol_setsolver
    
    catch {unset boco_famdata}
    foreach fn [array names boco_data] {
	set boco_famdata($fn) ""
	foreach bc $boco_data($fn) {
	    set bfd ""
	    set str [lindex $bc 0]
	    lappend bfd [string range $str 0 4]
	    lappend bfd [string range $str 5 9]
	    foreach v [lrange $bc 1 end] {
		lappend bfd $v
	    }
	    lappend boco_famdata($fn) $bfd
	}
    }
    
    if ![info exists boco_famdata] { user_error "There is no boco data"; return }
    
    boco_sol_form .boco_sol 0
    boco_sol_setfam [lindex [lsort [array names boco_famdata]] 0]
    if ![form_wait .boco_sol] return
    
    catch {unset boco_data}
    foreach fn [array names boco_famdata] {
	set boco_data($fn) ""
	foreach bc $boco_famdata($fn) {
	    set bfd ""
	    set str1 [lindex $bc 0]
	    set str2 [lindex $bc 1]
	    lappend bfd [format %-5s%-5s $str1 $str2]
	    foreach v [lrange $bc 2 end] {
		lappend bfd $v
	    }
	    lappend boco_data($fn) $bfd
	}
    }
    
    boco_save $bocofile
}

proc boco_edit_sol_famdata {} {
    global boco_data boco_famdata
    global boco_solvers_available env boco_solver boco_sol_curfam
    global solver_boco_info boco_sol_prefix
    
    set boco_sol_prefix ""
    
    boco_find_available    
    boco_sol_setsolver
    
    boco_sol_form .boco_sol 0
    boco_sol_setfam [lindex [lsort [array names boco_famdata]] 0]
    return [form_wait .boco_sol]
}

proc boco_sol_write {} {
    global boco_sol_prefix boco_solvers_available boco_solver
    global boco_file boco_sol_modified
    
    boco_sol_convert $boco_sol_prefix, 0 0
    
    set f $boco_file.$boco_solvers_available($boco_solver)
    
    set f [futil_get_file "Select the boco file to write." \
	       [file dirname $f] [file tail $f]]
    if {$f == ""} return
    boco_save_full $f $boco_sol_prefix
    catch {unset boco_sol_modified}
}

proc boco_solver_default {} {
    global boco_solvers_available
    
    set file [glob -nocomplain ~]/.iceman_modals
    if [file exists $file] {
	source $file
    }
    if {![info exists solver] || \
	    ![info exists boco_solvers_available($solver)]} {
	set solver Generic
    }
    return $solver
}

# This takes all the existing bocos and converts them to the new format.

proc boco_sol_convert {prefix in try_makeup} {
    global boco_data boco_nument boco_numbc boco_fam_used_star
    global boco_famdata boco_fam_to_ent boco_ent_to_fam boco_sol_fakefamily
    global boco_sol_etypes_for_fam
    
    catch {unset boco_sol_etypes_for_fam}
    
    if !$try_makeup { set make_up_families 0 }
    
    set types {domain subface edge vertex}
    set typeabbrev(domain)  D
    set typeabbrev(subface) S
    set typeabbrev(edge)    E
    set typeabbrev(vertex)  V
    
    if $in {
	catch {unset boco_fam_to_ent}
	catch {unset boco_ent_to_fam}
	catch {unset boco_famdata}
	catch {unset boco_sol_fakefamily}
	set boco_fam_used_star 0
    }
    
    foreach et $types {
	if !$in { set boco_numbc($prefix$et) 0 }
	
	for {set i 1} {$i <= $boco_nument($prefix$et)} {incr i} {
	    # First figure out what family this entity is in.  First check
	    # for name types and * at the front of family names, and then
	    # check for cases where flag2 is "" and the values are all 0.
	    set fam ""
	    set famindex -1
	    foreach data $boco_data($prefix$et,$i) {
		incr famindex
		set f [string trim [string range [lindex $data 0] 0 4]]
		set t [string trim [string range [lindex $data 0] 5 9]]
		set p [lrange $data 1 end]
		if {$t == "name"} { set fam $f; break }
		if {[string index $f 0] == "*"} {
		    set fam [string trim [string range $f$t 1 end]]
		    set boco_fam_used_star 1
		    break
		}
	    }
	    if {$fam == ""} {
		set famindex -1
		foreach data $boco_data($prefix$et,$i) {
		    incr famindex
		    set f [string trim [string range [lindex $data 0] 0 4]]
		    set t [string trim [string range [lindex $data 0] 5 9]]
		    set p [lrange $data 1 end]
		    if {($f == "") || ($t != "")} continue
		    set okay 1
		    foreach pv $p { if {$pv != 0.0} { set okay 0 } }
		    if !$okay continue
		    
		    set fam $f
		    break
		}
	    }
	    if $in {
		# Creating the family data from the old-style data.
		set ndata ""
		
		if {$fam == ""} {
		    if ![info exists make_up_families] {
			set mess "Some topological entities do not\
				have families defined -- ignore them,\
				or use default names?"
			set make_up_families [tk_dialog .make_up "Defaults" \
						  $mess "" -1 \
						  Ignore "Use defaults"]
		    }
		    if !$make_up_families continue
		    
		    set fam $typeabbrev($et)$i
		    set famindex -1
		    set boco_sol_fakefamily($fam) 1
		    lappend boco_sol_fakefamily($et) $fam
		}
		
		set ind -1
		foreach data $boco_data($prefix$et,$i) {
		    incr ind
		    if {$ind == $famindex} continue
		    
		    set string1 [string trim [string range [lindex $data 0] 0 4]]
		    set type [string trim [string range [lindex $data 0] 5 9]]
		    set params [lrange $data 1 end]
		    
		    lappend ndata [concat [list $string1 $type] $params]
		}
		if [info exists boco_famdata($fam)] {
		    if [string compare $ndata $boco_famdata($fam)] {
			error "Boco data is different for family $fam"
		    }
		}
		set boco_famdata($fam) $ndata
		
		set "boco_ent_to_fam($et $i)" $fam
		lappend boco_fam_to_ent($fam) "$et $i"
		set boco_sol_etypes_for_fam($fam,$et) 1
		
	    } else {
		# Create the old-style data from the family data.
		
		# If we had to make up a family then figure it out.
		
		if {$fam == ""} {
		    set fch $typeabbrev($et)$i
		    if {[info exists boco_famdata($fch)] && \
			    ($boco_famdata($fch) != "")} { set fam $fch }
		}
		
		if {$fam == ""} {
		    set boco_data($prefix$et,$i) ""
		    
		} else {
		    set ndata [list [concat [list [format "%-10s" $fam]] \
					 { 0 0 0 0 0 0 0 0 0 0}]]
		    
		    foreach ff $boco_famdata($fam) {
			set str1 [lindex $ff 0]
			set str2 [lindex $ff 1]
			set nd [concat [list [format "%-5s%-5s" $str1 $str2]] \
				    [lrange $ff 2 end]]
			lappend ndata $nd
		    }
		    set boco_data($prefix$et,$i) $ndata
		    incr boco_numbc($prefix$et) [llength $ndata]
		    
		    set families_to_create($fam) 1
		}
	    }
	}
    }

    if [info exists families_to_create] {
	set fams [lsort [array names families_to_create]]
	set nfams [llength $fams]
	set boco_nument(${prefix}family) $nfams
	set boco_numbc(${prefix}family) $nfams
	set i 1
	foreach f $fams {
	    if $boco_fam_used_star {
		if {[string index $f 0] != "*"} { set f *$f }
	    } else {
		set f [format "%-5.5sname" $f]
	    }
	    set boco_data(${prefix}family,$i) \
		[list [concat [list $f] { 0 0 0 0 0 0 0 0 0 0}]]
	    incr i
	}
    }
}

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

proc boco_sol_form {w write_button} {
    global boco_solver boco_famdata boco_sol_text boco_sol_fakefamily
    
    if $write_button {
	set buts [list done {{Write boco} boco_sol_write} cancel]
    } else {
	set buts [list done cancel]
    }
    set d [form_init $w "Boundary condition data" bocos $buts]
    if {$d != ""} {
	form_frame $d.f1 flat 0 {0 0}
	form_frame $d.f2 flat 0 {0 1}
	form_label $d.f1.soll "Solver" {0 0}
	futil_listentry $d.f1.sol boco_solver boco_sol_list_solvers {0 1} \
	    "" boco_sol_setsolver
	form_listbox $d.f1.fams "Available families" \
	    [lsort [array names boco_famdata]] boco_sol_setfam "" \
	    10x10 {1 0 -cols 3}
	
	set boco_sol_text [form_text $d.f2.b "Boundary conditions for family" \
			       "" {0 0 -cols 3} "" 40x10]
	form_button $d.f2.addbc Add boco_sol_add {1 0}
	form_button $d.f2.delbc Delete boco_sol_delete {1 1}
	form_button $d.f2.modbc Modify boco_sol_modify {1 2}

	form_finish -0-0
    }
    set realnames ""
    foreach ff [array names boco_famdata] {
	if ![info exists boco_sol_fakefamily($ff)] { lappend realnames $ff }
    }
    set names [lsort $realnames]
    foreach t {domain subface edge vertex} {
	if [info exists boco_sol_fakefamily($t)] {
	    set names [concat $names $boco_sol_fakefamily($t)]
	}
    }

    form_listbox_set $w.main.f1.fams $names
    form_listbox_select $w.main.f1.fams [lindex $names 0]
}

proc boco_sol_list_solvers {} {
    global boco_solvers_available
    return [lsort [array names boco_solvers_available]]
}

proc boco_sol_okay_for_fam {t} {
    global boco_sol_current boco_sol_has_typecats boco_sol_curfam
    global boco_sol_etypes_for_fam
    
    if ![info exists boco_sol_etypes_for_fam] { return 1 }
    
    set etypes ""
    foreach et {domain subface edge vertex family} {
	if [info exists boco_sol_etypes_for_fam($boco_sol_curfam,$et)] {
	    lappend etypes $et
	}
    }
    
    if $boco_sol_has_typecats {
	set constr [lindex $boco_sol_current($t) 2]
    } else {
	set constr [lindex $boco_sol_current($t) 1]
    }
    if {$constr == ""} { return 1 }
    
    foreach et $etypes {
	foreach con $constr {
	    if {$et == $con} { return 1 }
	}
    }
    return 0
}

proc boco_sol_list_types {cat} {
    global boco_sol_current boco_sol_has_typecats
    
    set types ""
    foreach t [array names boco_sol_current] {
	if ![boco_sol_okay_for_fam $t] continue
	
	if {$boco_sol_has_typecats && ($cat != "")} {
	    set bcat [lindex $boco_sol_current($t) 1]
	    if {$bcat != $cat} continue
	}
	lappend types [lindex $boco_sol_current($t) 0]
    }
    return [lsort $types]
}

proc boco_sol_list_typecats {} {
    global boco_sol_current boco_sol_has_typecats
    
    if !$boco_sol_has_typecats { return "" }
    
    foreach t [array names boco_sol_current] {
	set found([lindex $boco_sol_current($t) 1]) 1
    }
    return [lsort [array names found]]
}

proc boco_sol_get_typecat {type} {
    global boco_sol_current boco_sol_has_typecats
    
    if !$boco_sol_has_typecats { return "" }
    
    foreach t [array names boco_sol_current] {
	if {[lindex $boco_sol_current($t) 0] == $type} {
	    return [lindex $boco_sol_current($t) 1]
	}
    }
    return ""
}

proc boco_sol_setfam {fam} {
    global boco_famdata boco_sol_text boco_sol_curfam
    
    if [info exists boco_sol_curfam] { set prev_fam $boco_sol_curfam }
    
    set boco_sol_curfam $fam
    
    $boco_sol_text configure -state normal
    $boco_sol_text delete 1.0 end
    boco_sol_seltext $boco_sol_text ""
    
    set pos 0
    foreach data $boco_famdata($boco_sol_curfam) {
	boco_sol_addtext $boco_sol_text $data $pos
	incr pos
    }
    $boco_sol_text configure -state disabled
    
    if [info exists prev_fam] { boco_sol_showfam $prev_fam 0 }
    boco_sol_showfam $boco_sol_curfam 1
}

proc boco_sol_showfam {fam on} {
    global boco_fam_to_ent
    
    if {[info commands boco_edit_sol_show_fam] != ""} {
	boco_edit_sol_show_fam $fam $on
    } else {
	if [info exists boco_fam_to_ent($fam)] {
	    foreach e $boco_fam_to_ent($fam) {
		eval boco_edit_sol_show $e $on
	    }
	}
    }
}

proc boco_sol_addtext {w data pos} {
    global boco_sol_current solver_boco_info boco_sol_has_typecats
    
    set tag t$pos
    
    set t [boco_sol_typeof $data]
    if {$t != "ANY"} {
	set params $boco_sol_current($t)
    } else {
	set params [lrange [lindex $solver_boco_info(generic) 0] 1 end]
    }
    
    $w insert end "[lindex $params 0]:\n" $tag
    
    if $boco_sol_has_typecats { set ii 4 } else { set ii 3 }
    foreach info [lindex $params $ii] {
	set name [lindex $info 0]
	set place [lindex $info 1]
	set type [lindex $info 2]
	switch [lindex $place 0] {
	    flag  { set val [lindex $data [expr {[lindex $place 1] - 1}]] }
	    value { set val [lindex $data [expr {[lindex $place 1] + 1}]] }
	    default { error }
	}
	switch $type {
	    string {}
	    float  { catch {set val [format %f $val]} }
	    int    { catch {set val [expr int($val)]} }
	}
	$w insert end "    $name = $val\n" $tag
    }
    $w insert end \n
    $w tag bind $tag <1> "boco_sol_seltext $w $pos"
}

proc boco_sol_typeof {data} {
    global boco_sol_current solver_boco_info
    
    if [info exists boco_sol_current([lindex $data 0])] {
	return [lindex $data 0]
    } elseif [info exists boco_sol_current([lindex $data 1])] {
	return [lindex $data 1]
    } else {
	return ANY
    }
}

proc boco_sol_seltext {w pos} {
    global boco_sol_seltext_cur
    
    if [info exists boco_sol_seltext_cur] {
	$w tag configure t$boco_sol_seltext_cur -background ""
    }
    if {$pos == ""} {
	catch {unset boco_sol_seltext_cur}
	return
    }
    set boco_sol_seltext_cur $pos
    $w tag configure t$pos -background yellow
}

# Need to check the existing stuff to see if it matches, but for
# now we just load the data if necessary.

proc boco_sol_setsolver {} {
    global boco_solver boco_solvers_available boco_sol_current
    global solver_boco_info env boco_sol_curfam  boco_sol_has_typecats
    
    catch {unset boco_sol_current}
    
    set key $boco_solvers_available($boco_solver)
    if ![info exists solver_boco_info($key)] {
	set file $env(ICEM_ACN)/icemcfd/output-interfaces/$key.tcl
	#set file [glob ~wayne]/iceman/solvers/$key.tcl
	source $file
    }
    set boco_sol_has_typecats 0
    foreach type $solver_boco_info($key) {
	set boco_sol_current([lindex $type 0]) [lrange $type 1 end]
	if {[llength $type] == 6} {
	    set boco_sol_has_typecats 1
	}
    }
    if [info exists boco_sol_curfam] {
	boco_sol_setfam $boco_sol_curfam
    }
}

proc boco_sol_add {} {
    global boco_sol_etype boco_sol_current boco_sol_modified
    global boco_sol_has_typecats  boco_sol_etypecat
    
    if {![info exists boco_sol_etype] || \
	    ![info exists boco_sol_current($boco_sol_etype)]} {
	set boco_sol_etype [lindex [boco_sol_list_types ""] 0]
	if $boco_sol_has_typecats {
	    set boco_sol_etypecat [boco_sol_get_typecat $boco_sol_etype]
	}
    }
    boco_sol_editone end
    set boco_sol_modified 1
}

proc boco_sol_delete {} {
    global boco_sol_seltext_cur boco_sol_curfam boco_famdata boco_sol_modified
    
    if ![info exists boco_sol_seltext_cur] {
	user_error "You need to select a boundary condition first from the list\
		using the left mouse button."
	return
    }
    set pos $boco_sol_seltext_cur
    set boco_famdata($boco_sol_curfam) \
	[lreplace $boco_famdata($boco_sol_curfam) $pos $pos]
    boco_sol_setfam $boco_sol_curfam
    set boco_sol_modified 1
}

proc boco_sol_modify {} {
    global boco_sol_seltext_cur boco_sol_curfam boco_famdata boco_sol_etype
    global boco_sol_modified
    
    if ![info exists boco_sol_seltext_cur] {
	user_error "You need to select a boundary condition first from the list\
		using the left mouse button."
	return
    }
    set pos $boco_sol_seltext_cur
    set t [boco_sol_typeof [lindex $boco_famdata($boco_sol_curfam) $pos]]
    set boco_sol_etype $t
    boco_sol_editone $pos
    set boco_sol_modified 1
}

proc boco_sol_editone {pos} {
    global boco_sol_tinfo boco_sol_etype boco_new_value boco_famdata has_blt
    global boco_sol_curfam boco_sol_current boco_sol_has_typecats tcl_version
    
    set names {
	flag1 flag2 value1 value2 value3 value4 value5
	value6 value7 value8 value9 value10
    }
    
    if {$pos != "end"} {
	set nd [lindex $boco_famdata($boco_sol_curfam) $pos]
	for {set i 0} {$i < 12} {incr i} {
	    set boco_new_value([lindex $names $i]) [lindex $nd $i]
	}
	set this_type [boco_sol_typeof $nd]
    }
    set d [form_init .boco_sol_add "Boundary condition data" \
	       "bocos sub" "done cancel"]
    if {$d != ""} {
	form_frame $d.f1 flat 0 {0 0 -fill x -anchor n}
	form_frame $d.f2 flat 0 {0 1 -fill x -anchor n}
	
	form_label $d.f1.typel "Available types" {0 0 -fill x}
	form_listbox $d.f1.typecats "" "" "boco_sol_settypecat $d 1" \
	    "" 16x1 {1 0 -fill x}
	form_listbox $d.f1.types "" "" "boco_sol_settype $d 1" \
	    "" 16x1 {2 0 -fill x}
	#form_frame $d.f1.dummy flat 0 {1 0}
	#$d.f1.dummy configure -height 0 -width 1
	
	form_label $d.f2.title "" {0 0}
	form_frame $d.f2.info flat 0 {1 0 -fill x -anchor n}
	
	# This is a bit of a work-a-round.
	set c 0
	foreach i $names {
	    form_label $d.f2.info.l$i "" "$c 0"
	    form_entry $d.f2.info.e$i boco_new_value($i) string "$c 1"
	    $d.f2.info.l$i configure -width 20 -justify r
	    if !$has_blt {
		set boco_sol_tinfo($d.f2.info.l$i) [grid info $d.f2.info.l$i]
		set boco_sol_tinfo($d.f2.info.e$i) [grid info $d.f2.info.e$i]
	    } elseif {$tcl_version >= 8.0} {
		set boco_sol_tinfo($d.f2.info.l$i) \
		    [lrange [blt_table info $d.f2.info $d.f2.info.l$i] 0 2]
		set boco_sol_tinfo($d.f2.info.e$i) \
		    [lrange [blt_table info $d.f2.info $d.f2.info.e$i] 0 2]
	    } else {
		set boco_sol_tinfo($d.f2.info.l$i) \
		    [blt_table info $d.f2.info.l$i]
		set boco_sol_tinfo($d.f2.info.e$i) \
		    [blt_table info $d.f2.info.e$i]
	    }
	    incr c
	}
	
	form_finish -0-0
    }
    set d .boco_sol_add.main
    if $boco_sol_has_typecats {
	form_dotab $d.f1.typecats {1 0 -fill x} news
	form_dotab $d.f1.types {2 0 -fill x} news
	$d.f1.typecats.list configure -height 7
	$d.f1.types.list configure -height 7
    } else {
	form_dotab $d.f1.types {1 0 -fill x -rows 2} news
	$d.f1.types.list configure -height 14
	if $has_blt {
	    catch {blt_table forget $d.f1.typecats}
	} else {
	    catch {grid forget $d.f1.typecats}
	}
    }
    set types [boco_sol_list_types ""]
    form_listbox_set .boco_sol_add.main.f1.types $types
    form_listbox_set .boco_sol_add.main.f1.typecats [boco_sol_list_typecats]
    if {$pos == "end"} {
	set tt [lindex $types 0]
	boco_sol_settype .boco_sol_add.main 1 $tt
    } else {
	set tt [lindex $boco_sol_current($this_type) 0]
	boco_sol_settype .boco_sol_add.main 0 $tt
    }
    
    if ![form_wait .boco_sol_add] return
    
    # Now, take a look at the boco info and see where the type should go,
    # either flag 1 or flag 2.  If the key is "" then it won't go anywhere.
    if $boco_sol_has_typecats {
	set place [lindex $boco_sol_current($boco_sol_etype) 3]
    } else {
	set place [lindex $boco_sol_current($boco_sol_etype) 2]
    }
    set boco_new_value(flag[lindex $place 1]) $boco_sol_etype
    
    # Now put the stuff in the table and also in the data structure.
    set nd ""
    foreach n $names {
	lappend nd $boco_new_value($n)
    }
    if {$pos == "end"} {
	lappend boco_famdata($boco_sol_curfam) $nd
    } else {
	set boco_famdata($boco_sol_curfam) \
	    [lreplace $boco_famdata($boco_sol_curfam) $pos $pos $nd]
    }
    boco_sol_setfam $boco_sol_curfam
}

proc boco_sol_settype {d reset what} {
    global boco_sol_current boco_sol_etype boco_new_value form_entry_datatype
    global boco_sol_tinfo boco_sol_curfam boco_sol_has_typecats tcl_version
    global has_blt
    
    set boco_sol_etype ""
    foreach t [array names boco_sol_current] {
	if {[lindex $boco_sol_current($t) 0] == $what} {
	    set boco_sol_etype $t
	    break
	}
    }
    if {$boco_sol_etype == ""} { user_error "Unknown boco type \"$what\""; return }

    set c [boco_sol_get_typecat $what]
    if {$c != ""} { boco_sol_settypecat $d 1 $c }
    form_listbox_select $d.f1.types $what
    
    foreach i [array names boco_sol_tinfo] {
	if $has_blt {
	    catch {blt_table forget $i}
	} else {
	    catch {grid forget $i}
	}
    }
    
    if $reset {
	for {set n 1} {$n <= 2} {incr n} { set boco_new_value(flag$n) "" }
	for {set n 1} {$n <= 10} {incr n} { set boco_new_value(value$n) 0.0 }
    }
    if $boco_sol_has_typecats {
	set stuff [lindex $boco_sol_current($boco_sol_etype) 4]
    } else {
	set stuff [lindex $boco_sol_current($boco_sol_etype) 3]
    }
    foreach info $stuff {
	set key [lindex [lindex $info 1] 0][lindex [lindex $info 1] 1]
	$d.f2.info.l$key configure -text [lindex $info 0]
	
	if $reset {
	    switch -- [lindex $info 3] {
		*famname* {
		    set boco_new_value($key) $boco_sol_curfam
		}
		default {
		    set boco_new_value($key) [lindex $info 3]
		}
	    }
	}
	set form_entry_datatype($d.f2.info.e$key) [lindex $info 2]
	
	if !$has_blt {
	    eval grid $d.f2.info.l$key $boco_sol_tinfo($d.f2.info.l$key)
	    eval grid $d.f2.info.e$key $boco_sol_tinfo($d.f2.info.e$key)
	    
	} elseif ![string compare $tcl_version "8.0"] {
	    eval blt_table $boco_sol_tinfo($d.f2.info.l$key)
	    eval blt_table $boco_sol_tinfo($d.f2.info.e$key)
	} else {
	    eval blt_table $d.f2.info $boco_sol_tinfo($d.f2.info.l$key)
	    eval blt_table $d.f2.info $boco_sol_tinfo($d.f2.info.e$key)
	}
    }
    $d.f2.title configure -text [lindex $boco_sol_current($boco_sol_etype) 0]
}

proc boco_sol_settypecat {d settype what} {
    form_listbox_select $d.f1.typecats $what
    if $settype {
	set types [boco_sol_list_types $what]
	form_listbox_set $d.f1.types $types
    }
}
