# load tktable
# package require BWidget
if [batch_interp eval {expr {$batch_mode}}] return

set ::ImageCheckOff [image create photo -data {
    R0lGODdhDQANAJEAAKysnPz8/HRsZPTs5CwAAAAADQANAAACMYSPFkDycQKE
    4t8ECGKQBULxbwIEMcgCofg3AYIYZIFQ/JsAQQyyQCj+TQDNx6H4iAUAOw==
}]
set ::ImageCheckOn [image create photo -data {
    R0lGODdhDQANAKIAAKysnPz8/HRsZPTs5AQEBP///////////ywAAAAADQAN
    AAADSQi6rIGAossTCIKhuxMIgqEbFDgBgqFLFDgBEoShRBQ4ARKEFEQUGBMg
    gaQaETgBEoGkERE4ARKBQRiqE4CCobsTCDi6PBi6zAkAOw==
}]

proc part_table {w datavar args} {
    global options part_data
    variable ::AIEnv::GUIManagement::GUIDisplayData 

    set win [lindex [split $w .] end]
    upvar ::$win var
    upvar \#0 $datavar data
    if {![info exists var(headings)] || $var(headings) == ""} return
    set var(mergecells) 0
    # Use this to pass additional options
    set argl [llength $args]
    for {set i 0} {$i < $argl} {incr i} {
	    # incr i again for argument pairs, and set value to $i+1 index
	    # handling for var(mergecells) not done yet
	    switch -- [lindex $args $i] {
	        -allow_mergecells {set var(mergecells) 1}
	    }
    }

    frame $w -bd 2 -relief sunken -highlightthickness 0 -takefocus 0
    scrollbar $w.yscroll -orient vertical -command [list part_table_YScroll $w] -takefocus 0
    scrollbar $w.xscroll -orient horizontal -command [list part_table_XScroll $w] -takefocus 0
    set rows 0
    set cols [llength $var(headings)]
    # The var(changes) variable only records row changes made through the table, not the array trace
    set var(changes) ""
    set var(order) ""
    catch {unset ::$win:displayData}
    # I have to configure the number of rows before setting tags
      
    if [array exists data] {
	    set names [array names data]
	    foreach name $names {
	        if {[scan $name %d,%d r c] == 2 && $r > $rows} {set rows $r}
	    }
	    incr rows
	    for {set r 0} {$r < $rows} {incr r} {
	        lappend var(order) $r
	    }
    }

    ResizeButs $w.headings \
	    -resizecommand [list part_table_ResizeColumns $w] \
	    -side left \
	    -orient horizontal \
	    -ordercommand [list part_table_ReArrange $w $datavar] \
	    -orderbutton [list 0 increasing] \
	    -bg bisque3 \
	    -scrollcommand [list $w.xscroll set] \
	    -showcommand [list part_table_ShowColumns $w $datavar] \
	    -font $::AIEnv::GUIManagement::GUIDisplayData("DefaultFont")

    # skip header menu selection for the stand-alone version
    if {[lindex [split $w .] 1] == "standalone_win"} {
        bind $w.headings <Button-3> break
    }

    canvas $w.can \
        -takefocus 0 \
        -yscrollcommand [list $w.yscroll set] \
        -bd 0 \
        -highlightthickness 0

    set font $::AIEnv::GUIManagement::GUIDisplayData("DefaultFont")
    set bd 1
    set rhgt [expr {[font metrics $font -linespace] + 2 + 2 * $bd}]

    table $w.can.table \
	-maxwidth 2000 \
	-maxheight [expr {$rows * $rhgt}] \
	-anchor center \
	-rowseparator \n \
	-colseparator "\t " \
	-cols $cols \
	-rows $rows \
	-titlerows 0 \
	-titlecols 0 \
	-roworigin 0 \
	-colorigin 0 \
	-rowstretchmode none \
	-colstretchmode none \
	-bg white \
	-fg black \
	-bd $bd \
	-selectmode single \
	-resizeborders none \
	-multiline 0 \
	-autoclear 0 \
	-cache 0 \
	-variable ::$win:displayData \
	-browsecommand [list part_table_Browse $w $datavar %s] \
	-highlightthickness 0 \
	-takefocus 1 \
	-usecommand 0 \
	-insertofftime 0
	
    $w.can create window 0 0 -window $w.can.table -anchor nw
    if [array exists data] {
        foreach rc $names {
            if {[scan $rc %d,%d r c] != 2} continue
            if {[set val $data($rc)] != ""} {
                if {$val == "__NA__"} {
                    $w.can.table tag cell disabled $rc
                } else {
                    switch [lindex $var(headings) $c] {
                        Color {
                            part_table_SetCellBgColor $w $rc $val
                        }
                        Prism - Hexa-core - "Internal wall" - "Split wall" {
                            if {$val == 1} {
                                $w.can.table tag cell checkon $rc
                            } else {
                                $w.can.table tag cell checkoff $rc
                            }
                        }
                        Property {
                            set val [lindex $var(bc_text) [string index $val 0]]
                        }
                    }
                    set ::$win:displayData($rc) $val
                }
            }
        }
    }

    if {[aie_wb2_is_running] && [array exists data]} {
        aie_set_global wb_part_labels [lrange $var(headings) 1 end-1]
        set labels [aie_get_global wb_part_labels]
        set size [ic_geo_get_ref_size]
        foreach rc $names {
            if {[scan $rc %d,%d r c] != 2} continue
            if {[set val $data($rc)] == ""} continue
            if {$val == "__NA__"} continue
            switch [lindex $var(headings) $c] {
                "Parameter" {
                    set param $data($r,0)
                    set Button [button $w.can.table.btn$rc -relief ridge -width 3 -bg white -activebackground white -activeforeground white \
                        -text "P" -fg white -font $::AIEnv::GUIManagement::GUIDisplayData("ButtonBoldFont")]
                    $w.can.table.btn$rc configure -command "aie_wb2_parameter_part_dialog $Button $param $w.can.table $r"
                    $w.can.table window configure $rc -window $Button
                    $w.can.table tag cell wbpartname $r,0
                    set wbp [ic_wb2_get_parameters_by_pattern input "Part $param: *"]
                    if {$wbp == ""} continue
                    set p 0
                    foreach "p1 p2" $wbp {
                        set pp [lrange $p1 2 end]
                        set nn [lsearch $labels $pp]
                        if {$nn >= 0} {
                            set p 1
                            $w.can.table tag cell wbparam $r,[expr $nn + 1]
                            set value [ic_wb2_get_parameter input "Part $param: $pp"]
                            switch -- $pp {
                                "Maximum size" - "Min size limit" - "Max deviation" {
                                    if !$options(show_factor) {
                                        if {([string is double $size] || [string is integer $size]) && $size > 0} {
                                            set value [expr $value * $size]
                                        }
                                    }
                                }
                                Prism - Hexa-core - "Internal wall" - "Split wall" {
                                    if {$value == 1} {
                                        $w.can.table tag cell wbcheckon $r,[expr $nn + 1]
                                     } else {
                                        $w.can.table tag cell wbcheckoff $r,[expr $nn + 1]
                                    }
                                }
                            }
                        }
                    }
                    if $p {
                        $w.can.table.btn$rc configure -fg blue -text "P"
                    }
                }
            }
        }
        global wb_TableID
        set wb_TableID [list $w.can.table $rows]
    }

    if ![info exists var(heading_widths)] {set var(heading_widths) ""}
    set c 0
    foreach win $var(headings) width $var(heading_widths) {
	    if {$width == ""} {set width 100}
	    $w.headings add -text $win -width $width
	    incr width [expr {2 * [$w.headings cget -bd] + 2 * [$w.headings cget -highlightthickness]}]
	    $w.can.table width $c -$width
	    switch $win {
	        Part { $w.headings itemconfigure $c -lockshow 1 }
	        Prism - Hexa-core - "Internal wall" - "Split wall" { if ![aie_wb2_is_running] { $w.can.table tag col bg $c } }
	        Property - "Element type" { $w.can.table tag col disabled $c }
	    }
	    incr c
    }
    set var(visColumns) [$w.headings visible]
    set var(cursor) [$w.can.table cget -cursor]

    $w.can.table tag configure active -fg black -bg #33FFFF -relief raised
    set colorw [$w cget -bg]
    if {$colorw != ""} {
        set color #
        set colord [winfo rgb $w $colorw]
        foreach dec $colord {append color [string range [format %02X $dec] 0 1]}
    } else {
        set color #D0D0D0
    }
    if ![aie_wb2_is_running] {
        $w.can.table tag configure bg -bg $color
    }
    $w.can.table tag configure checkon -image $::ImageCheckOn
    $w.can.table tag configure checkoff -image $::ImageCheckOff
    $w.can.table tag configure disabled -bg #D0D0D0 -state disabled
    if [aie_wb2_is_running] {
        $w.can.table tag configure enabled -bg white -fg black -state normal
        $w.can.table tag configure wbpartname -anchor nw 
        $w.can.table tag configure wbparam -bg lightblue -state disabled
        $w.can.table tag configure wbcheckon -image $::ImageCheckOn -bg lightblue -state disabled
        $w.can.table tag configure wbcheckoff -image $::ImageCheckOff -bg lightblue -state disabled
        $w.can.table tag configure wbraised -bg #33FFFF -state disabled -relief raised
        $w.can.table tag configure wbraisedon -image $::ImageCheckOn -bg #33FFFF -state disabled -relief raised
        $w.can.table tag configure wbraisedoff -image $::ImageCheckOff -bg #33FFFF -state disabled -relief raised
    }

    set height [winfo height $w.can.table]
    $w.can configure -scrollregion "0 0 [winfo width $w.can.table] $height" -height $height

    grid $w.headings $w.yscroll -sticky nwe
    grid $w.yscroll -sticky nse
    grid $w.can ^ -sticky nwe
    grid $w.xscroll -sticky nwe
    grid columnconfigure $w 0 -weight 1
    grid rowconfigure $w 1 -weight 1

    # The "breaks" allow us to override the default table bindings
    bind $w.can.table <ButtonRelease-1> break
    bind $w.can.table <Motion> "part_table_Motion $w %x %y"
    bind $w.can.table <Enter> "part_table_Motion $w %x %y"
    bind $w.can.table <Leave> "part_table_Motion $w %x %y"
    bind $w.can.table <B1-Motion> "part_table_Motion1 $w %x %y; break"
    bind $w.can.table <Button-1> "part_table_Btn1 $w $datavar %x %y; break"
    bind $w.can.table <Button-3> "part_table_Btn1 $w $datavar %x %y; break"
    bind $w.can.table <KeyPress> "if \[part_table_KeyPress $w $datavar %K\] break"
    bind $w.can.table <Shift-Key-Left> "part_table_KeyPress $w $datavar Shift-Key-Left"
    bind $w.can.table <Shift-Key-Right> "part_table_KeyPress $w $datavar Shift-Key-Right"
    bind $w.can.table <Shift-Key-Up> "part_table_KeyPress $w $datavar Shift-Key-Up"
    bind $w.can.table <Shift-Key-Down> "part_table_KeyPress $w $datavar Shift-Key-Down"
    bind $w.can.table <Control-v> "part_table_KeyPress $w $datavar Control-Key-V"
    bind $w.can.table <Control-c> "part_table_KeyPress $w $datavar Control-Key-C"
    bind $w <Destroy> "part_table_Destroy $w $datavar"
    trace variable data wu [list part_table_ArrayTrace $w]
    return $w
}

# Use this procedure to set values to the array when entries in the table are typed in (not from popup)
proc part_table_Browse {w datavar old_in} {
    upvar ::[winfo name $w] var
    upvar \#0 $datavar data
    if {$old_in == ""} {return 0}
    if {$old_in == "active"} {
	if [catch {$w.can.table index active} old_in] {return 0}
    }
    if {[scan $old_in %d,%d r c] != 2} {return 0}

    set C [lindex $var(visColumns) $c]
    set heading [lindex $var(headings) $C]
    set R [lindex $var(order) $r]
    if [info exists data($R,$C)] {set oldData $data($R,$C)} else {set oldData ""}
    set newData [$w.can.table get $old_in]
    switch $heading {
	Part {
	    set newPart [string toupper $newData]
	    set oldPart [string toupper $oldData]
	    if {$newPart != $oldPart} {
		set badname 0
		if {$newPart == ""} {
		    if {$oldPart != ""} {
			set title "Empty name"
			set mess "You must type a name"
			set badname 1
		    }
		} else {
		    foreach row $var(order) {
			if {$row == $R} continue
			if {[info exists data($row,$C)] && $newPart == [string toupper $data($row,$C)]} {
			    set title "Duplicate name"
			    set mess "Part name \"$newPart\" already exists"
			    set badname 1
			    break
			}
		    }
		}
		if $badname {
		    $w.can.table set $old_in $oldPart
		    $w.can.table activate $old_in
		    tk_messageBox -type ok -parent $w.can.table -icon warning -title $title -message $mess
		    return 1
		}

		set i 0
		foreach row $var(order) {
		    if {([info exists data($row,$C)] && $data($row,$C) == $oldData) || $row == $R} {
			$w.can.table set $i,$c $newPart
			part_table_SetArraySilently $datavar $row,$C $newPart
			if {[lsearch $var(changes) $row] < 0} {lappend var(changes) $row}
		    }
		    incr i
		}
	    }
	}
	Color - Property - Material - "Element type" {
	    # already handled with part_table_Btn1
	}
	Prism - Hexa-core - "Internal wall" - "Split wall" {
	    # already handled with part_table_Btn1 and part_table_KeyPress
	}
	"Num layers" - "Tetra width" {
	    if {[string is integer -strict $newData] && $newData != $oldData} {
		part_table_SetArraySilently $datavar $R,$C $newData
		if {[lsearch $var(changes) $R] < 0} {lappend var(changes) $R}
	    }
	}
	default {
	    if {[string is double -strict $newData] && $newData != $oldData} {
		part_table_SetArraySilently $datavar $R,$C $newData
		if {[lsearch $var(changes) $R] < 0} {lappend var(changes) $R}
	    }
	}
    }
    return 0
}

proc aie_update_part_table_value {part param value} {
    global batch_mode wb_TableID options part_data

    if $batch_mode return  
    if ![info exists wb_TableID] return
    set table [lindex $wb_TableID 0]
    if ![winfo exists $table] return
    set col [expr [lsearch [aie_wb2_parameter_set_part_params [aie_get_global wb_part_labels]] $param] + 1]
    if {$col < 1} return
    set size [ic_geo_get_ref_size]
    for {set row 0} {$row < [lindex $wb_TableID 1]} {incr row} {
        set p [$table get $row,0]
        if {$p == "$part"} {
            switch -- $param {
                emax - emin - edev {
                    if !$options(show_factor) {
                        if {([string is double $size] || [string is integer $size]) && $size > 0} {
                            set value [expr $value * $size]
                        }
                    }
                }
                "prism" - "hexcore" - "internal_wall" - "split_wall" {
                    if {$value == 1} {
                        $table tag cell wbcheckon $row,$col
                    } else {
                        $table tag cell wbcheckoff $row,$col
                    }
                }
                law {
                    set law [aie_get_prism_grow_law_num $value]
		            set value $law
		        }
            }
            $table set $row,$col $value
            set part_data($row,$col) $value
            break
        }
    }
}

proc part_table_ResizeColumns {w index width} {
    set index [$w.headings index -shown $index]
    $w.can.table width $index -$width
    $w.can configure -scrollregion "0 0 [winfo width $w.can.table] [winfo height $w.can.table]"
}

proc part_table_ShowColumns {w datavar index width} {
    set win [winfo name $w]
    upvar ::$win var

    set index [$w.headings index -shown $index]
    set var(visColumns) [$w.headings visible]
    if {$width == 0} {
        $w.can.table delete cols $index 1
    } else {
        set end [expr {[llength $var(visColumns)] - 1}]
        $w.can.table insert cols $index [expr {$index == $end ? 1 : -1}]
        $w.can.table width $index -$width
        eval part_table_ReArrange $w $datavar [$w.headings cget -orderbutton]
    }
    $w.can configure -scrollregion "0 0 [winfo width $w.can.table] [winfo height $w.can.table]"
}

proc part_table_XScroll {w args} {
    eval $w.can xview $args
    eval $w.headings view $args
}

proc part_table_YScroll {w args} {
    eval $w.can yview $args
}

proc part_table_SetArraySilently {datavar index value} {
    upvar \#0 $datavar data

    set traces [trace vinfo data]
    foreach trace $traces {eval trace vdelete data $trace}
    set data($index) $value
    foreach trace $traces {eval trace variable data $trace}
}

proc part_table_ReArrange {w datavar col order} {
    set win [winfo name $w]
    upvar ::$win var
    upvar \#0 $datavar data
    if {[lindex [split $w .] 1] == "standalone_win"} {
        # no reorder for the stand-alone window
        # but deselect/select all checkbuttons
        switch [lindex $var(headings) $col] {
            Prism - Hexa-core - "Internal wall" - "Split wall" {
                foreach rc [array names data] {
                    if {[lindex [split $rc ,] 1] == $col} {
                        if {$data($rc) == "__NA__"} continue
                        if [aie_wb2_is_running] {
                            set param "Part $data([lindex [split $rc ,] 0],0): [lindex $var(headings) $col]"
                            if {[ic_wb2_get_parameter input "$param"] != "___NA___"} continue
                        }
                        if {$order == "increasing"} {
                            if {[lindex $var(headings) $col] == "Internal wall"} {
                                set icol [expr $col + 1]
                                set irow [lindex [split $rc ,] 0]
                                $w.can.table tag cell checkoff $irow,$icol
                                part_table_SetArraySilently $datavar $irow,$icol 0
                            } elseif {[lindex $var(headings) $col] == "Split wall"} {
                                set icol [expr $col - 1]
                                set irow [lindex [split $rc ,] 0]
                                $w.can.table tag cell checkoff $irow,$icol
                                part_table_SetArraySilently $datavar $irow,$icol 0
                            }
                            $w.can.table tag cell checkon $rc
                            set val 1
                        } else {
                            $w.can.table tag cell checkoff $rc
                            set val 0
                        }
                        part_table_SetArraySilently $datavar $rc $val
                        set r [lindex [split $rc ,] 0]
                        if {[lsearch $var(changes) $r] < 0} {
                            lappend var(changes) $r
                        }
                    }
                }
            }
            Part - Color - Property - "Element type" - Parameter {}
            default {
                set x [winfo rootx $w]; set y [winfo rooty $w]
                set heading [lindex $var(headings) $col]
                if {$heading != "Prism growth law"} {
                    set val [part_table_heading_window $w $heading $x $y]
                    if {$val == "" || (![string is integer $val] && ![string is double $val])} return
                } else {
                    set val [part_table_prism_law_window $w $heading $x $y]
                    if {$val == ""} return
                }
                foreach r $var(order) {
                    set rc $r,$col
                    if {[info exists data($rc)] && $data($rc) == "__NA__"} continue
                    if [aie_wb2_is_running] {
                        set param "Part $data([lindex [split $rc ,] 0],0): [lindex $var(headings) $col]"
                        if {[ic_wb2_get_parameter input "$param"] != "___NA___"} continue
                    }
                    $w.can.table set $rc $val
                    part_table_SetArraySilently $datavar $rc $val
                    if {[lsearch $var(changes) $r] < 0} {
                         lappend var(changes) $r
                    }
                }
            }
        }
        return
    }

    part_table_Browse $w $datavar active
    set heading [lindex $var(headings) $col]
    switch $heading {
        Thickness - "Maximum size" - Height - "Height ratio" - "Num layers" - "Tetra size ratio" - "Tetra width" - "Min size limit" - "Max deviation" {
            set method integer
        }
        default {set method dictionary}
    }
    set var(order) [lsort -command "part_table_ListSortCommand $datavar $method $col $order" $var(order)]

    $w.can.table clear tags
    set col 0
    foreach c $var(visColumns) {
	switch [lindex $var(headings) $c] {
	    Prism - Hexa-core - "Internal wall" - "Split wall" {$w.can.table tag col bg $col}
	    Property - "Element type" {$w.can.table tag col disabled $col}
	}
	incr col
    }
    set row 0
    set pc [lsearch $var(headings) Part]
    if {$pc > -1} {set pcol [lsearch $var(visColumns) $pc]}
    catch {unset ::$win:displayData}
    foreach trow $var(order) {
	set col 0
	foreach tcol $var(visColumns) {
	    set trc $trow,$tcol
	    set rc $row,$col
	    if {[info exists data($trc)] && [set val $data($trc)] != ""} {
		if {$val == "__NA__"} {$w.can.table tag cell disabled $rc} \
		else {
		    switch [lindex $var(headings) $tcol] {
			Color {part_table_SetCellBgColor $w $rc $val}
			Prism - Hexa-core - "Internal wall" - "Split wall" {
			    if {$val == 1} {$w.can.table tag cell checkon $rc} \
			    else {$w.can.table tag cell checkoff $rc}
			}
			Property {
			    set val [lindex $var(bc_text) [string index $val 0]]
			}
		    }
		    $w.can.table set $rc $val
		}
	    }
	    incr col
	}
	if {$pcol > -1 && [lsearch $var(yellow_parts) $trow] > -1} {part_table_SetCellBgColor $w $row,$pcol yellow}
        incr row
    }
}

proc part_table_heading_window {w heading x y} {
    set top .part_table_bt3_window
    if [winfo exists $top] { destroy $top }
    set d [form_init $top [string toupper $heading] "" {accept cancel}]
    if {$d == ""} return ""
    catch { unset ::value(val,$heading) }
    switch $heading {
        "Num layers" - "Tetra width" {
            set type int
        }
        default {
            set type float
        }
    }
    form_label $d.lval "$heading" {0 0}
    form_entry $d.vval ::value(val,$heading) $type {0 1}
    wm transient .part_table_bt3_window $w
    form_finish +$x+$y
    raise .part_table_bt3_window
    if ![form_wait $top] { return "" }
    return $::value(val,$heading)
}

proc part_table_ListSortCommand {array method col order a b} {
    upvar \#0 $array data

    if [info exists data($a,$col)] {set a $data($a,$col)} else {set a ""}
    if [info exists data($b,$col)] {set b $data($b,$col)} else {set b ""}
    if {$a == "__NA__"} {
	if {$b != "__NA__"} {return 1} else {return 0}
    } elseif {$b == "__NA__"} {
        return -1
    }
    if {$order == "decreasing" || $a == "" || $b == ""} {set t $a;	set a $b;	set b $t}
    switch $method {
        dictionary {return [string compare -nocase $a $b]}
        integer {return [expr {$a<$b ? -1 : $a>$b}]}
    }
}

proc part_table_Destroy {w datavar} {
    set win [lindex [split $w .] end]
    upvar \#0 $datavar data
    foreach trace [trace vinfo data] {
	    eval trace vdelete data $trace
    }
    catch {unset ::$win:displayData}

}

# Currently not used and may need updating
# This is to update the table when array elements are changed after the table is plotted
proc part_table_ArrayTrace {w name1 name2 op} {
    upvar ::[winfo name $w] var
    upvar \#0 $name1 data
    if ![array exists data] {
	# When the entire array is unset, this variable trace is also removed
	set order ""
	$w.can.table selection set origin end
	$w.can.table curselection ""
	$w.can.table selection clear origin end
	$w.can.table clear tags
	$w.can.table configure -rows 1
	return
    }
    if {[scan $name2 %d,%d R C] != 2} return
    set heading [lindex $var(headings) $C]
    set r [lsearch $var(order) $R]
    set c [lsearch $var(visColumns) $C]
    set cell $r,$c
    if {$op == "w"} {
	if {$r < 0 && $data($name2) != ""} {
	    lappend var(order) $R
	    foreach {col order} [$w.headings cget -orderbutton] break
	    switch $heading {
		Thickness - "Maximum size" - Height - "Height ratio" - "Num layers" - "Tetra size ratio" - "Tetra width" - "Min size limit" - "Max deviation" {
		    set method integer
		}
		default {set method dictionary}
	    }
	    set var(order) [lsort -command "part_table_ListSortCommand $name1 $method $col $order" $var(order)]
	    set r [lsearch $var(order) $R]
	    set cell $r,$c
	    if {$R == [lindex $var(order) end]} {
		$w.can.table insert rows [expr {$r - 1}] 1
	    } else {
		$w.can.table insert rows $r -1
	    }
	}
	$w.can.table set $cell $data($name2)
	if {$heading == "Color"} {
	    part_table_SetCellBgColor $w $cell $data($name2)
	}
    } elseif {$op == "u"} {
	if {$heading == "Color"} {$w.can.table clear tags $cell}
	$w.can.table set $cell ""
    }
    set remove 1
    set cols [llength $var(headings)]
    for {set C 0} {$C < $cols} {incr C} {
	if {[info exists data($R,$C)] && $data($R,$C) != ""} {
	    set remove 0
	    break
	}
    }
    if $remove {
	$w.can.table delete rows $r 1
	set var(order) [lreplace $var(order) $r $r]
    }
}

proc part_table_Btn1 {w datavar x y {rc ""}} {
    set gvar ::[winfo name $w]
    upvar \#0 $datavar data
    upvar $gvar var
    if {$rc == ""} {
        focus $w.can.table
        $w.can.table activate @$x,$y
        set rc [$w.can.table index active]
    }
    foreach {x y width height} [$w.can.table bbox active] break
    incr x [winfo rootx $w.can.table]
    set y [expr {[winfo rooty $w.can.table] + $y + $height}]
    if {[scan $rc %d,%d r c] != 2} return
    set R [lindex $var(order) $r]
    set C [lindex $var(visColumns) $c]
    if {$R == "" || $C == ""} return
    set RC $R,$C
    set heading [lindex $var(headings) $C]
    switch -- $heading {
	Color {
	    set args ""
	    if [info exists data($RC)] {
		set oldColor $data($RC)
		if {$oldColor == "__NA__"} return
		if {$oldColor != ""} {set args "-initialcolor $oldColor"}
	    }
	    set color [eval {tk_chooseColor -parent $w.can.table -title "Choose color"} $args]
	    if {$color != ""} {
		set color [string tolower $color]
		set pc [lsearch $var(headings) "Part"]
		if {$pc > -1 && [info exists data($R,$pc)]} {
		    set part $data($R,$pc)
		    set row_list $var(order)
		    set i 0
		} else {
		    set row_list $R
		    set i $r
		}
		foreach row $row_list {
		    if {([info exists data($row,$pc)] && $data($row,$pc) == $part) || $row == $R} {
			$w.can.table set $i,$c $color
			part_table_SetCellBgColor $w $i,$c $color
			part_table_SetArraySilently $datavar $row,$C $color
			if {[lsearch $var(changes) $row] < 0} {lappend var(changes) $row}
		    }
		     incr i
		}
	     }
	}
	Material  {
	    # set switch option to "material - "element type"" to add functionality back for element type
	    if {[info exists data($RC)] && $data($RC) == "__NA__"} return
	    set prc [lsearch $var(headings) "Property"]
	    set elc [lsearch $var(headings) "Element type"]
	    if {$prc < 0 || ![info exists data($R,$prc)]} return
	    set prop $data($R,$prc)
	    if {$elc > 0 && [info exists data($R,$elc)]} {
		set bctype $data($R,$elc)
	    } else {
		set bctype ""
	    }
	    if {$heading == "Element type"} {
		set heading [string tolower $heading,$prop]
	    } elseif {$heading == "Material"} {
		# Point properties should not allow a material on them
		if {$prop == "0d"} return
		if {$prop == "1d" && ($bctype != "PBAR" && $bctype != "PBARL" && $bctype != "PBEAM" && $bctype != "PBEAML"  && $bctype != "IROD")} return
		if {$prop == "2d" && $bctype == "PCOMP"} return
		set var(material) [lsort [array names ::material_data]]
	    }
	    if {[info exists var($heading)] && $var($heading) != ""} {
		if {[llength $var($heading)] < 2} return
		if [winfo exists $w.can.table.popup] {destroy $w.can.table.popup}
		menu $w.can.table.popup -bd 2 -relief raised -tearoff 0 -type normal -cursor arrow
		foreach type $var($heading) {
		    $w.can.table.popup add command -label $type -command "
			$w.can.table set $rc [list $type]
			part_table_SetArraySilently $datavar $RC [list $type]
			if \{\[lsearch \[set ${gvar}(changes)\] $R\] < 0\} \{lappend ${gvar}(changes) $R\}
		    "	
		}
		set var(popUpPosted) 1
		$w.can.table configure -cursor arrow
		tk_popup $w.can.table.popup $x $y
		$w.can.table configure -cursor $var(cursor)
		unset var(popUpPosted)
	    }
	}
	"Prism growth law" {
	    if [info exists data($RC)] {
            if {$data($RC) == "__NA__"} return
		}
	    if [aie_wb2_is_running] {
	        set param "Part $data($R,0): [string toupper $heading 0 0]"
	        if {[ic_wb2_get_parameter input "$param"] != "___NA___"} return
	    }
		if [winfo exists $w.can.table.popup] { destroy $w.can.table.popup }
		menu $w.can.table.popup -bd 2 -relief raised -tearoff 0 -type normal -cursor arrow
		foreach type {undefined linear exponential wb-exponential} {
		    $w.can.table.popup add command -label $type -command "$w.can.table set $rc [list $type] 
		    part_table_SetArraySilently $datavar $RC [list $type]
			if \{\[lsearch \[set ${gvar}(changes)\] $R\] < 0\} \{lappend ${gvar}(changes) $R\}
			"	
		}
		set var(popUpPosted) 1
		$w.can.table configure -cursor arrow
		tk_popup $w.can.table.popup $x $y
		$w.can.table configure -cursor $var(cursor)
		unset var(popUpPosted)
	}
	Prism - Hexa-core - "Internal wall" - "Split wall" {
	    if [info exists data($RC)] {
		if {$data($RC) == "__NA__"} return
		if {$data($RC) == 1} {set val 0} else {set val 1}
	    } else {
		if {[$w.can.table get $rc] == 1} {set val 0} else {set val 1}
	    }
	    if [aie_wb2_is_running] {
	        set param "Part $data($R,0): [string toupper $heading 0 0]"
	        if {[ic_wb2_get_parameter input "$param"] != "___NA___"} return
	    }
	    $w.can.table set $rc $val
	    part_table_SetArraySilently $datavar $RC $val
	    if {$val == 1} {
		set iwc [lsearch $var(headings) "Internal wall"]; set swc [lsearch $var(headings) "Split wall"]
		if {$heading == "Internal wall"} {
		    if {$swc > -1} {
			set cl [lsearch $var(visColumns) $swc]
			$w.can.table set $r,$cl 0
			part_table_SetArraySilently $datavar $R,$swc 0
			$w.can.table tag cell checkoff $r,$cl
		    }
		} elseif {$heading == "Split wall"} {
		    if {$iwc > -1} {
			set cl [lsearch $var(visColumns) $iwc]
			$w.can.table set $r,$cl 0
			part_table_SetArraySilently $datavar $R,$iwc 0
			$w.can.table tag cell checkoff $r,$cl
		    }
		}
		$w.can.table tag cell checkon $rc
	    } else {
		$w.can.table tag cell checkoff $rc
	    }
	    if {[lsearch $var(changes) $R] < 0} {lappend var(changes) $R}
	}
    }
}

proc part_table_prism_law_window {w heading x y} {

    set top .part_table_bt3_window
    if [winfo exists $top] { destroy $top }
    set d [form_init $top "$heading" "" { accept cancel }]
    if {$d == ""} return ""
    form_radiobutton $d.lval1 "undefined" ::value(val,$heading) undefined "0 0" "" ""
    form_radiobutton $d.lval2 "linear" ::value(val,$heading) linear "1 0" "" ""
    form_radiobutton $d.lval3 "exponential" ::value(val,$heading) exponential "2 0" "" ""
    form_radiobutton $d.lval4 "wb-exponential" ::value(val,$heading) wb-exponential "3 0" "" ""
    wm transient .part_table_bt3_window $w
    form_finish +$x+$y
    raise .part_table_bt3_window
    if ![form_wait $top] { return "" }
    return $::value(val,$heading)
}

proc part_table_KeyPress {w datavar K} {
    global is_win

    if !$is_win {
        if {[regexp {KP_([0-9])} $K]} {
            regexp {[0-9]} $K dummy
            set K $dummy
        } elseif {[string match KP_Decimal $K]} {
            set K .
        } elseif {[string match KP_Insert $K]} {
            set K 0
        } elseif {[string match KP_End $K]} {
            set K 1
        } elseif {[string match KP_Down $K]} {
            set K 2
        } elseif {[string match KP_Next $K]} {
            set K 3
        } elseif {[string match KP_Left $K]} {
            set K 4
        } elseif {[string match KP_Begin $K]} {
            set K 5
        } elseif {[string match KP_Right $K]} {
            set K 6
        } elseif {[string match KP_Home $K]} {
            set K 7
        } elseif {[string match KP_Up $K]} {
            set K 8
        } elseif {[string match KP_Prior $K]} {
            set K 9
        } elseif {[string match KP_Delete $K]} {
            set K .
        } 
    }
    
    upvar ::[winfo name $w] var
    upvar \#0 $datavar data
    if [catch {$w.can.table index active} rc] {return 0}
    if {[scan $rc %d,%d r c] != 2} {return 0}
    set C [lindex $var(visColumns) $c]
    set heading [lindex $var(headings) $C]
    set R [lindex $var(order) $r]
    set RC $R,$C
    set cols [expr {[$w.can.table cget -cols] - 1}]
    set rows [expr {[$w.can.table cget -rows] - 1}]
    set ret 1
    switch $K {
        Return - Shift-Key-Down {
            if {$r < $rows} {event generate $w.can.table <Key-Down>}
        }
        Shift-Key-Left {
            if {$c > 0} {$w.can.table activate $r,[expr {$c - 1}]}
        }
        Shift-Key-Right {
            if {$c < $cols} {$w.can.table activate $r,[expr {$c + 1}]}
        }
        Shift-Key-Up {
            if {$r > 0} {event generate $w.can.table <Key-Up>}
        }
        Left {
            if {$heading == "Part"} {
                set icur [$w.can.table icursor]
                $w.can.table icursor [expr {$icur - 1}]
                if {$icur == [$w.can.table icursor] && $c > 0} {$w.can.table activate $r,[expr {$c - 1}]}
            } else {set ret 0}
        }
        Right {
            if {$heading == "Part"} {
                set icur [$w.can.table icursor]
                $w.can.table icursor [expr {$icur + 1}]
                if {$icur == [$w.can.table icursor] && $c < $cols} {$w.can.table activate $r,[expr {$c + 1}]}
            } else {set ret 0}
        }
        Escape - Up - Down - Shift_L - Shift_R - Home -	End - Caps_Lock - Control_L - Control_R - Alt_L - Alt_R - \
            F1 - F2 - F3 - F4 - F5 - F6 - F7 - F8 - F9 - F10 - F11 - F12 - Print - Break - Insert - Num_Lock - Scroll_Lock - \
            Prior - Next - Pause - App - ?? - Win_L - Win_R - Sys_Req {set ret 0}     
        space {}
        default {
            set int [expr {[string is digit $K] || $K == "BackSpace" || $K == "Delete" || $K == "minus" || $K == "-" || $K == "plus" || $K == "+"}]
            set float [expr {$int || $K == "." || $K == "period" || $K == "e" || $K == "E"}]
            switch -- $heading {
                Part {set ret 0}
                Thickness {
                    set prc [lsearch $var(headings) "Property"]
                    if {[info exists data($RC)] && [string is double -strict $data($RC)] && $float} {set ret 0} \
                    elseif {$prc > -1 && [info exists data($R,$prc)] && $data($R,$prc) == "2d" && $float} {set ret 0}
                }
                Color - Property - Material - "Element type" {
                    part_table_Btn1 $w $datavar {} {} $rc
                }
                Prism - Hexa-core - "Internal wall" - "Split wall" {
                    if {$K == 0 || $K == 1} {
			            set existRC [info exists data($RC)]
			            if {!$existRC || $data($RC) != "__NA__"} {
			                $w.can.table set $rc $K
			                if {$K == 1} {
				                set iwc [lsearch $var(headings) "Internal wall"]; set swc [lsearch $var(headings) "Split wall"]
				                if {$heading == "Internal wall"} {
				                    if {$swc > -1} {
					                    set cl [lsearch $var(visColumns) $swc]
					                    $w.can.table set $r,$cl 0
					                    part_table_SetArraySilently $datavar $R,$swc 0
					                    $w.can.table tag cell checkoff $r,$cl
                                    }
                                } elseif {$heading == "Split wall"} {
                                    if {$iwc > -1} {
                                        set cl [lsearch $var(visColumns) $iwc]
                                        $w.can.table set $r,$cl 0
                                        part_table_SetArraySilently $datavar $R,$iwc 0
                                        $w.can.table tag cell checkoff $r,$cl
                                    }
                                }
                                $w.can.table tag cell checkon $rc
                            } else {
                                $w.can.table tag cell checkoff $rc
                        }
                        if {!$existRC || $data($RC) != $K} {if {[lsearch $var(changes) $R] < 0} {lappend var(changes) $R}}
                            part_table_SetArraySilently $datavar $RC $K
                        }
                    }
                }
                "Num layers" - "Tetra width" {
                    if {$K == "Control-Key-V"} {
                        if {![catch {::tk::GetSelection $w CLIPBOARD} sel]} {
                            if {[expr {[string is digit $sel] || [string is integer $sel]}]} {
                                catch {$w.can.table set $rc $sel}
                            }
                        }
                    }
                    if {$K == "Control-Key-C"} {
                        if {![catch {set copy [$w.can.table get $rc]}]} {
                            catch {clipboard clear -displayof $w}
                            catch {clipboard append -displayof $w $copy}
                        }
                    }
                    if $int {set ret 0}
                }
                default {
                    if {$K == "Control-Key-V"} {
                        if {![catch {::tk::GetSelection $w CLIPBOARD} sel]} {
                            if {[expr {[string is digit $sel] || [string is double $sel] || [string is integer $sel]}]} {
                                catch {$w.can.table set $rc $sel}
                            }
                        }
                    }
                    if {$K == "Control-Key-C"} {
                        if {![catch {set copy [$w.can.table get $rc]}]} {
                            catch {clipboard clear -displayof $w}
                            catch {clipboard append -displayof $w $copy}
                        }
                    }
                    if $float {set ret 0}
                }
            }
        }
    }
    return $ret
}

proc part_table_SetCellBgColor {w index {color ""}} {
    if {$color == ""} {
	    $w.can.table clear tags $index
	    return
    }
    $w.can.table tag cell $color $index
    $w.can.table tag configure $color -bg $color
    if {[string index $color 0] != "#"} {
	    foreach c [winfo rgb $w.can.table $color] rgb {r g b} {
	        set $rgb [string range [format %02x $c] 0 1]
	    }
    } else {
	    regexp {#(.{2})(.{2})(.{2})} $color dummy r g b
    }
    set rgb [lsort -integer [list 0x$r 0x$g 0x$b]]
    # This computes a number similar to luminesence
    # Actual luminesence is (max+min)/2.12
    if {([lindex $rgb 0] + [lindex $rgb end]) < 200} {
	    $w.can.table tag configure $color -fg white
    }
}

proc part_table_Motion1 {w x y} {
    upvar ::[winfo name $w] var

    if [info exists var(popUpPosted)] return
    $w.can.table selection clear all
    set rc [$w.can.table index @$x,$y]
    $w.can.table activate $rc
}

proc part_table_Motion {w x y} {
    upvar ::[winfo name $w] var
    set in [$w.can.table index @$x,$y]
    if {[scan $in %d,%d r c] != 2} return
    set C [lindex $var(visColumns) $c]
    if {$C == ""} return
    switch [lindex $var(headings) $C] {
        Prism - Hexa-core - "Internal wall" - "Split wall" {$w.can.table configure -cursor arrow}
        default {$w.can.table configure -cursor $var(cursor)}
    }
}

# End of part_table widget

proc aie_part_table_apply {{single_win 0}} {
    global tdv_default part_data pt part_list options

    if [geo_select force_done] {
	    after 1 aie_part_table_apply
	    return
    }
    if !$single_win {
        set w $tdv_default
    } else {
        set w .standalone_win
    }
    if [part_table_Browse $w.f.f1.pt part_data active] return
    
    aie_part_table_headings
    if {$pc < 0} return
       
    set parts_done ""
    if $options(show_factor) {
	    set fact [ic_geo_get_ref_size]
    } else {
	    set fact 1.0
    }
    
    ic_undo_group_begin
    
    if [aie_wb2_is_running] {
        aie_set_global wb_input_parameter_mode 1
    }
    
    foreach r $pt(changes) {
	    set params ""
	    set fam [lindex $part_list $r]
	    if {[lsearch $parts_done $fam] < 0} {
	        lappend parts_done $fam
	        if {[info exists part_data($r,$pc)]} {
		        set newfam [string toupper $part_data($r,$pc)]
		        if {$newfam != $fam} {
		            set newfam [aie_rename_part $fam $newfam 0]
		            set part_data($r,$pc) $newfam
		            set fam $newfam
		        }
	        }
	        if {$cc > -1 && [info exists part_data($r,$cc)] && [set val $part_data($r,$cc)] != "__NA__"} {
		        aie_color_part $fam $val
	        }
	        if {$pric > -1 && [info exists part_data($r,$pric)] && [set val $part_data($r,$pric)] != "__NA__"} {
		        if {$val == 1} {
		            lappend params prism 1
		        } else { 
		            lappend params prism 0 
		        }
		    }
	        if {$hcc > -1 && [info exists part_data($r,$hcc)] && [set val $part_data($r,$hcc)] != "__NA__"} {
		        if {$val == 1} {
		            lappend params hexcore 1
		        } else {
		            lappend params hexcore 0
		        }
	        }
	        if {$emax > -1 && [info exists part_data($r,$emax)] && [set val $part_data($r,$emax)] != "__NA__"} {
		        if {$val !=""} {
		            lappend params emax [expr {$val * $fact}]
		        } else {
		            lappend params emax 0
		        }
	        }
	        if {$ehgt > -1 && [info exists part_data($r,$ehgt)] && [set val $part_data($r,$ehgt)] != "__NA__"} {
		        #if {$val != ""} { lappend params ehgt [expr {$val * $fact}] }
		        # do not scale ehgt
		        if {$val != ""} { lappend params ehgt $val }
	        }
	        if {$hrat > -1 && [info exists part_data($r,$hrat)] && [set val $part_data($r,$hrat)] != "__NA__"} {
		        if {$val != ""} { lappend params hrat $val }
	        }
	        if {$nlay > -1 && [info exists part_data($r,$nlay)] && [set val $part_data($r,$nlay)] != "__NA__"} {
		        if {$val != ""} { lappend params nlay $val }
	        }
	        if {$erat > -1 && [info exists part_data($r,$erat)] && [set val $part_data($r,$erat)] != "__NA__"} {
		        if {$val != ""} { lappend params erat $val }
	        }
	        if {$ewid > -1 && [info exists part_data($r,$ewid)] && [set val $part_data($r,$ewid)] != "__NA__"} {
		        if {$val != ""} { lappend params ewid $val }
	        }
	        if {$emin > -1 && [info exists part_data($r,$emin)] && [set val $part_data($r,$emin)] != "__NA__"} {
		        if {$val != ""} { lappend params emin [expr {$val * $fact}] }
	        }
	        if {$edev > -1 && [info exists part_data($r,$edev)] && [set val $part_data($r,$edev)] != "__NA__"} {
		        if {$val != ""} { lappend params edev [expr {$val * $fact}] }
	        }       
	        if {$prism_height_limit > -1 && [info exists part_data($r,$prism_height_limit)] && [set val $part_data($r,$prism_height_limit)] != "__NA__"} {
		        if {$val != ""} { lappend params prism_height_limit $val }
	        }
            # Prism growth law: "undefined or linear or exponential or wb-exponential"
	        if {$law > -1 && [info exists part_data($r,$law)] && [set val $part_data($r,$law)] != "__NA__"} {
		        if {$val != ""} {
		            set val [aie_get_prism_grow_law_num $val]
		            lappend params law $val
		        }
	        }
	        # split_wall must be set before internal_wall
	        if {$swc > -1 && [info exists part_data($r,$swc)] && [set val $part_data($r,$swc)] != "__NA__"} {
		        if {$val == 1} {
		            lappend params split_wall 1
		        } else {
		            lappend params split_wall 0
		        }
	        }
	        if {$iwc > -1 && [info exists part_data($r,$iwc)] && [set val $part_data($r,$iwc)] != "__NA__"} {
		        if {$val == 1} {
		            lappend params internal_wall 1
		        } else {
		            lappend params internal_wall 0
		        }
	        }
	    } else {
	        set fam $part_data($r,$pc)
	    }
	    if {$prc > -1 && [info exists part_data($r,$prc)]} {
	        set prop $part_data($r,$prc)
	        if {$mc > -1 && $prop != "0d" && [info exists part_data($r,$mc)]} {
		        set newmat $part_data($r,$mc)
                aie_update_part_props $prop material $fam $newmat
	        }
	        if {$elc > -1 && $prop != "3d" && [info exists part_data($r,$elc)]} {
		        set newel $part_data($r,$elc)
	        }
	        if {$tc > -1 && $prop == "2d" && [info exists part_data($r,$tc)]} {
		        set newthick $part_data($r,$tc)
                aie_update_part_props $prop thickness $fam $newthick
	        }
	    }
	
	    if {$params != ""} {
	        if $options(apply_all) {
		        eval ic_geo_set_family_params $fam $params
	        } elseif $options(remove_all) {
		        eval ic_geo_set_family_params $fam reset_crv_inf $params
	        } else {
		        eval ic_geo_set_family_params $fam no_crv_inf $params
	        }
	    }
    }
    
    set rows [llength $part_list]
    set part_list {}
    for {set R 0} {$R < $rows} {incr R} {
        lappend part_list $part_data($R,$pc)
    }
    if $options(apply_all) {
	    set r 0
	    foreach fam $part_list {
		    if {[lsearch $parts_done $fam] < 0} {
		        set params ""
		        if {$ehgt > -1 && [info exists part_data($r,$ehgt)] && [set val $part_data($r,$ehgt)] != "__NA__"} {
			        #if {$val != ""} { lappend params ehgt [expr {$val * $fact}] }
			        # do not scale ehgt
			        if {$val != ""} { lappend params ehgt $val }
		        }
		        if {$nlay > -1 && [info exists part_data($r,$nlay)] && [set val $part_data($r,$nlay)] != "__NA__"} {
			        if {$val != ""} { lappend params nlay $val }
		        }
		        if {$hrat > -1 && [info exists part_data($r,$hrat)] && [set val $part_data($r,$hrat)] != "__NA__"} {
			        if {$val != ""} { lappend params hrat $val }
		        }
		        if {$ewid > -1 && [info exists part_data($r,$ewid)] && [set val $part_data($r,$ewid)] != "__NA__"} {
			        if {$val != ""} { lappend params ewid $val }
		        }
		        if {$params != ""} {
			        eval ic_geo_set_family_params $fam only_crv_inf $params
		        }
		    }
		    incr r
	    }
    } elseif $options(remove_all) {
	    foreach fam $part_list {
		    if {[lsearch $parts_done $fam] < 0} {
		        ic_geo_set_family_params $fam reset_crv_inf
		    }
	    }
    }
    
    if [aie_wb2_is_running] {
        aie_unset_global wb_input_parameter_mode
    }
    
    ic_undo_group_end
    
    ic_geo_params_blank_done part 1
    mess "Finished setting part parameters\n" blue
}

proc aie_part_table_dismiss {{single_win 0}} {
    global tdv_default part_data part_list pt

    if !$single_win {
        destroy $tdv_default.f
    } else {
        destroy .standalone_win
    }
    catch {unset part_list}
    catch {unset part_data}
    catch {unset pt}
    ic_reset_geo_selected
}

proc aie_get_prism_grow_law_num {val} {

    switch -- "$val" {
        exponential { set law 0 }
        linear { set law 1 }
        wb-exponential { set law 3 }
        default { set law -1 }
    }
    return $law
}

proc aie_get_prism_grow_law_text {val} {

    switch -- "$val" {
        0 { set law exponential }
        1 { set law linear }
        3 { set law wb-exponential }
        default { set law undefined }
    }
    return $law
}

proc aie_update_part_props {propdim proptype fam newprop} {
    global material_data

    set dim ""
    set name ""
    set pid 0
    set type ""
    set lcs 0

    if {$propdim == "0d"} {set dim 0; set type "point"}
    if {$propdim == "1d"} {set dim 1; set type "curve"}
    if {$propdim == "2d"} {set dim 2; set type "surface"}
    if {$propdim == "3d"} {set dim 3; set type "material"}

    set bcs [ic_boco_get $fam]
    if {$bcs == ""} { return}
    set parsed [aie_parse_bcs_element_prop_${dim}d $bcs]
    if {$parsed == ""} { return}
    
    set newparsed ""
    foreach {n v} $parsed {
         if {$n == "name"} {set name $v}
         if {$n == "pid"} {set pid $v}
         if {$n == "LCS"} {set lcs $v}
         if {$proptype == "material"} {
	   if [string match mat* $n] {
               if {$v != ""} {set v1 $newprop}
	      if [string match *_number $n] {
                  if {$v != ""} {set v1 [lindex $material_data($newprop) 0]}
               }
               set v $v1
	   }
         }
         if {$proptype == "thickness"} {
	   if [string match *thick* $n] {
               set v $newprop
	   }
         }
	lappend newparsed $n $v
    }

    applyEleProp $dim $name $pid $type $fam $lcs $newparsed

    return
}

proc aie_part_table_sash_Btn1 {w X} {
    if { $::tcl_platform(platform) != "windows" } {
	    set but $w.f.f2.sash
	    $but configure -relief sunken
    } else {
	    set but $w.f.f2.sep
    }
    set xmin [expr {[winfo width $w.f.f2]/2 + [$w.f cget -bd] + [$w.f cget -highlightthickness]}]
    set xmax [expr {[winfo width $w] - $xmin}]
    if {$xmin & 1} {incr xmin}
    bind $but <B1-Motion> "aie_part_table_sash_Motion1 $w $xmin $xmax %X"
    bind $but <ButtonRelease-1> "aie_part_table_sash_Release1 $w %X $X"
    set h [winfo height $w.f.f2.sep]
    set x [expr {$X - [winfo rootx $w]}]
    set y [expr {[winfo rooty $w.f.f2.sep] - [winfo rooty $w]}]
    frame $w.bar -bd 1 -width 2 -height $h -relief raised -highlightthickness 0
    place $w.bar -anchor n -x $x -y $y
}

proc aie_part_table_sash_Motion1 {w xmin xmax X} {
    set x [expr {$X - [winfo rootx $w]}]
    if {$x < $xmin} {set x $xmin} \
    elseif {$x > $xmax} {set x $xmax}
    place configure $w.bar -x $x
}

proc aie_part_table_sash_Release1 {w X Xi} {
    global part_table

    destroy $w.bar
    set x [expr {$X - $Xi}]
    if { $::tcl_platform(platform) != "windows" } {
	$w.f.f2.sash configure -relief raised
    }
    if $x {
	if [winfo ismapped $w.f.f1] {
	    set width [expr {[winfo width $w.f.f1] + $x}]
	    if {$width < 1} {grid remove $w.f.f1} \
	    else {$w.f.f1 configure -width $width}
	} elseif {$x > 0} {
	    grid $w.f.f1
	    $w.f.f1 configure -width $x
	}
    }
}

# Set ptsetup(headings-meshsizes) and ptsetup(headings-attributes) and ptsetup(headings-all) to control which columns are available
# ex: set ptsetup(headings-meshsizes) [list Part Prism Hex-core]
# The list can take any of the textual names in the first two lists of the procedure 
# "type" can be meshsizes, attributes, prism, or all or a new string if the second part of the variable matches
proc aie_part_table_create {{type meshsizes} {single_win 0}} {
    global pt ptsetup tdv_default options icon_size1 icon_size2
    variable ::AIEnv::GUIManagement::GUIDisplayData

    if [aie_wb2_is_running] {
        set headings_df_meshsizes [list Part 200 Prism 50 Hexa-core 65 "Maximum size" 85 Height 55 "Height ratio" 75 "Num layers" 70 \
        "Tetra size ratio" 90 "Tetra width" 70 "Min size limit" 80 "Max deviation" 85 "Prism height limit factor" 120 "Prism growth law" 90 "Internal wall" 70 "Split wall" 65 "Parameter" 65]
    } else {
        set headings_df_meshsizes [list Part 200 Prism 50 Hexa-core 65 "Maximum size" 85 Height 55 "Height ratio" 75 "Num layers" 70 \
        "Tetra size ratio" 90 "Tetra width" 70 "Min size limit" 80 "Max deviation" 85 "Prism height limit factor" 120 "Prism growth law" 90 "Internal wall" 70 "Split wall" 65]
    }
    set headings_df_attributes [list Part 200 Color 70 Property 80 Material 90 "Element type" 105 Thickness 90]
    set headings_df_all [concat $headings_df_meshsizes [lrange $headings_df_attributes 1 end]]
    if [aie_wb2_is_running] {
        set headings_df_prism [list Part 200 Prism 50 Height 55 "Height ratio" 75 "Num layers" 70 "Prism height limit factor" 120 "Prism growth law" 90 "Parameter" 65]
    } else {
        set headings_df_prism [list Part 200 Prism 50 Height 55 "Height ratio" 75 "Num layers" 70 "Prism height limit factor" 120 "Prism growth law" 90]
    }

    if {$icon_size1 == "35" && $icon_size2 == "35"} {
        set add 6
    } elseif {$icon_size1 == "35" && $icon_size2 == "48"} {
        set add 10
    }
    if [info exists add] {
        set headings_df_meshsizes2 ""
        foreach "n v" $headings_df_meshsizes {
            lappend headings_df_meshsizes2 $n [expr $v + $add]
        }
        set headings_df_meshsizes $headings_df_meshsizes2
        set headings_df_prism2 ""
        foreach "n v" $headings_df_prism {
            lappend headings_df_prism2 $n [expr $v + $add]
        }
        set headings_df_prism $headings_df_prism2
    }

    set ::pt(headings) {}
    set ::pt(heading_widths) {}
    set ::pt(bc_text) [list point line surface volume]
    if ![info exists headings_df_$type] return
    foreach {hd wd} [set headings_df_$type] {
        lappend pt(headings) $hd
        lappend pt(heading_widths) $wd
    } 
    set pc [lsearch $pt(headings) Part]
    if {$pc < 0} {mess "Part column must be included\n" red; return}

    if {![ic_geo_is_loaded] && ![ic_uns_is_loaded] && ![ic_str_is_loaded] && ![ic_hex_blocking_loaded]} {
        mess "No geometry or mesh is loaded!\n" red
        return
    }
    if ![info exists options(apply_all)] {set options(apply_all) 0}
    if ![info exists options(remove_all)] {set options(remove_all) 0}
    if ![info exists options(show_factor)] {set options(show_factor) 1}

    set ::pt(type) $type

    if !$single_win {
        set w $tdv_default
        destroy $w.f
    } else {
        set w .standalone_win
        destroy $w
        toplevel $w
        catch { wm attributes $w -topmost 1 }
        
        if {$type == "meshsizes"} {
            set title "Part Mesh Setup"
        } elseif {$type == "attributes"} {
            set title "Attributes Data"
        } elseif {$type == "prism"} {
            set title "Prism Parts Data"
        }
        wm title $w $title
    }
    frame $w.f -bd 2 -relief sunken -highlightthickness 0 -takefocus 0
    frame $w.f.f1 -bd 0 -highlightthickness 0 -relief flat
    frame $w.f.f1.buts -bd 0 -highlightthickness 0 -takefocus 0
    if !$single_win {
        Button $w.f.f1.buts.accept -text Apply -relief link -takefocus 1 -bd 1 -padx 8 -pady 1 \
            -command "aie_part_table_apply $single_win"  \
            -width $::AIEnv::GUIManagement::GUIDisplayData("ButtonWidth") \
            -font $::AIEnv::GUIManagement::GUIDisplayData("ButtonFont")
        Button $w.f.f1.buts.cancel -text Dismiss -relief link -takefocus 1 -bd 1 -padx 8 -pady 1 \
            -command "aie_part_table_dismiss $single_win" \
            -width $::AIEnv::GUIManagement::GUIDisplayData("ButtonWidth") \
            -font $::AIEnv::GUIManagement::GUIDisplayData("ButtonFont")
    } else {
        Button $w.f.f1.buts.accept -text Apply -relief raised -takefocus 1 -bd 3 -padx 8 -pady 1 \
            -width $::AIEnv::GUIManagement::GUIDisplayData("ButtonWidth") \
            -font $::AIEnv::GUIManagement::GUIDisplayData("ButtonFont") \
            -command "aie_part_table_apply $single_win"
        Button $w.f.f1.buts.cancel -text Dismiss -relief raised -takefocus 1 -bd 3 -padx 8 -pady 1 \
            -width $::AIEnv::GUIManagement::GUIDisplayData("ButtonWidth") \
            -font $::AIEnv::GUIManagement::GUIDisplayData("ButtonFont") \
            -command "aie_part_table_dismiss $single_win"
    }

    if !$single_win {
        frame $w.f.f2 -bd 0 -highlightthickness 0 -relief flat -width 14
        set but [frame $w.f.f2.sep -bd 2 -width 4 -relief raised -highlightthickness 0]
        place $but -relx 0.5 -y 0 -anchor n -relheight 1.0
        if { $::tcl_platform(platform) != "windows" } {
            $but configure -width 2
            set sash_size 6
            set but [frame $w.f.f2.sash -bd 1 -relief raised -highlightthickness 0 -width $sash_size -height $sash_size]
            place $but -relx 0.5 -y 6 -anchor n
        }
        $but configure -cursor sb_h_double_arrow
        bind $but <Button-1> "aie_part_table_sash_Btn1 $w %X"
    } else {
        frame $w.f.f2 -bd 0 -highlightthickness 0 -relief flat -width 1
    }
    
    aie_part_table_get_data part_data

    set table [part_table $w.f.f1.pt part_data]
    foreach r $pt(yellow_parts) {
        set r [lsearch $pt(order) $r]
        if {$r < 0} continue
        part_table_SetCellBgColor $table $r,$pc yellow
        if {[aie_wb2_is_running] && ($type == "meshsizes" || $type == "prism")} {
            $table.can.table tag cell yellow $r,$pc
            $table.can.table tag configure yellow -bg yellow -anchor nw
        }
    }
    if !$single_win {
        pack $w.f.f1.buts.accept $w.f.f1.buts.cancel -side left -pady 2
        pack $w.f.f1.buts -side top -anchor w -fill x -padx 2
    } else {
        pack $w.f.f1.buts.accept $w.f.f1.buts.cancel -side left -pady 5
        pack $w.f.f1.buts -side bottom -anchor w -fill x -padx 2
        grid $w.f.f1.buts.accept -column 1 -row 0 
        grid $w.f.f1.buts.cancel -column 2 -row 0 
    }
    if {$type == "meshsizes" || $type == "prism"} {
        checkbutton $w.f.f1.showfactor -text "Show size params using scale factor" -variable options(show_factor) \
            -font $::AIEnv::GUIManagement::GUIDisplayData("CheckButtonFont")
        $w.f.f1.showfactor configure -command "part_table_ScaleFactor $table part_data"
        if {$type == "prism"} {
            set warn "Highlighted parts have at least one blank field because not all entities in that part\nhave identical parameters"
        } else {
            set warn "Highlighted parts have at least one blank field because not all entities in that part have identical parameters"
        }
        if [aie_wb2_is_running] {
            set wbparam "Existing workbench input parameters using a lightblue background"
            label $w.f.f1.wbparam -bg lightblue -justify left -text $wbparam -font $::AIEnv::GUIManagement::GUIDisplayData("DefaultFont")
        }
        label $w.f.f1.warn -bg yellow -justify left -text $warn -font $::AIEnv::GUIManagement::GUIDisplayData("DefaultFont")
        if [aie_wb2_is_running] {
            pack $w.f.f1.wbparam $w.f.f1.warn $w.f.f1.showfactor -side bottom -anchor sw -padx 2
        } else {
            pack $w.f.f1.warn $w.f.f1.showfactor -side bottom -anchor sw -padx 2
        }
        checkbutton $w.f.f1.applyall -text "Apply inflation parameters to curves" -variable options(apply_all) \
            -font $::AIEnv::GUIManagement::GUIDisplayData("CheckButtonFont")
        checkbutton $w.f.f1.removeall -text "Remove inflation parameters from curves" -variable options(remove_all) \
            -font $::AIEnv::GUIManagement::GUIDisplayData("CheckButtonFont")
        $w.f.f1.applyall configure -command "aie_part_table_toggle_inf_params apply_all"
        $w.f.f1.removeall configure -command "aie_part_table_toggle_inf_params remove_all"
        pack $w.f.f1.removeall $w.f.f1.applyall -after $w.f.f1.warn -side bottom -anchor sw -padx 2
    }
    pack $table -anchor nw -fill x -expand yes
    grid $w.f.f1 $w.f.f2 -sticky nswe
    grid columnconfigure $w.f 0 -weight 1
    grid rowconfigure $w.f 0 -weight 1
    
    if !$single_win {
        pack $w.f -anchor w -expand yes -fill y
    } else {
        pack $w.f -anchor w -expand yes -fill both
    }
    
    if $single_win {
        set wx [expr [winfo rootx .] + 50]
        set wy [expr [winfo rooty .] + 50]
        wm geometry $w +$wx+$wy
    }

    update idletasks
    pack propagate $w.f.f1 0
    grid propagate $w.f.f1 0

    if $single_win {
        set ww [winfo width $w]
        set wh [winfo height $w]
        set wh2 [winfo height $tdv_default]
        if {$wh > $wh2} {
            set wh $wh2
        }
        wm geometry $w ${ww}x${wh}
    }
}

proc aie_part_table_get_data {array {getparts all} {headings all}} {
    global pt part_list options 

    upvar \#0 $array data
    aie_part_table_headings
    if {$pc < 0} return

    if {$headings != "all"} {
	    if {[lsearch $headings Prism] < 0} {set pric -1}
	    if {[lsearch $headings Hexa-core] < 0} {set hcc -1}
	    if {[lsearch $headings "Maximum size"] < 0} {set emax -1}
	    if {[lsearch $headings Height] < 0} {set ehgt -1}
	    if {[lsearch $headings "Height ratio"] < 0} {set hrat -1}
	    if {[lsearch $headings "Num layers"] < 0} {set nlay -1}
	    if {[lsearch $headings "Tetra size ratio"] < 0} {set erat -1}
	    if {[lsearch $headings "Tetra width"] < 0} {set ewid -1}
	    if {[lsearch $headings "Min size limit"] < 0} {set emin -1}
	    if {[lsearch $headings "Max deviation"] < 0} {set edev -1}
	    if {[lsearch $headings "Internal wall"] < 0} {set iwc -1}
	    if {[lsearch $headings "Split wall"] < 0} {set swc -1}
	    if {[lsearch $headings "Prism height limit factor"] < 0} {set prism_height_limit -1}
	    if {[lsearch $headings "Prism growth law"] < 0} {set law -1}
	    if {[lsearch $headings Color] < 0} {set cc -1}
	    if {[lsearch $headings Material] < 0} {set mc -1}
	    if {[lsearch $headings "Element type"] < 0} {set elc -1}
	    if {[lsearch $headings Property] < 0} {set prc -1}
	    if {[lsearch $headings Thickness] < 0} {set tc -1}
	    if [aie_wb2_is_running] {
	        if {[lsearch $headings Parameter] < 0} {set wbp -1}
	    }
    }

    set do_bcs [expr {$mc > -1 || $elc > -1 || $prc > -1 || $tc > -1}]
    if $do_bcs {
	    set exclude_types [list OR LSDYNA_MATERIAL_BEAM LSDYNA_BEAM_FORM]
	    foreach prop {0d 1d 2d 3d} {
	        set "pt(element type,$prop)" ""
	        if [info exists ::aie_bctypes_used(element_prop_$prop)] {
		        foreach type $::aie_bctypes_used(element_prop_$prop) {
		            if {[lsearch $exclude_types $type] < 0} {
		                lappend "pt(element type,$prop)" $type
		            }
		        }
	        }
	    }
    }
    if $options(show_factor) {
	    set fact [ic_geo_get_ref_size]
    } else {
	    set fact 1.0
    }

    if {$getparts == "all"} {
	    set parts [lsort -dictionary [ic_geo_list_parts]]
	    set part_list {}
	    catch {unset data}
	    set r 0
	    set pt(yellow_parts) {}
    } elseif {$getparts == "update"} {
	    set parts $part_list
	    catch {unset data}
	    set r 0
	    set pt(yellow_parts) {}
    } else {
	    set parts $getparts
    }
    set svfams [concat [ic_uns_list_families 2] [ic_list_volume_families]]
    set asms [aie_find_base_assemblies]
    set traces [trace vinfo data]
    foreach trace $traces {eval trace vdelete data $trace}

    foreach pp $parts {
	    if {$pp == "ORFN" || $pp == "VORFN"} continue
	    if {$getparts != "all" && $getparts != "update"} {
	        set r [lsearch $part_list $pp]
	        # should unset params that will be set
	    }
	    set yellow_pp 0
	    set do_common 1
	    set srfs ""
	    set crvs ""
	    set pfams [ic_geo_list_families_in_part $pp]
	    foreach fam $pfams {
	        eval lappend srfs [ic_geo_get_objects surface $fam]
	        eval lappend crvs [ic_geo_get_objects curve $fam]
	    }
	    if {[ic_geo_count_in_family body $pp] && [ic_geo_count_in_family {surface curve point} $pp]} {
            mess "Part $pp contains geometry and body in same part. This is not recommended and could cause problems! Part $pp will be ignored.\n" red
            continue
	    }
	    if {$srfs == "" && $crvs == ""} {
	        set bds 0
	        foreach fam $pfams {
		        if {[ic_geo_get_objects body $fam] != ""} {set bds 1; break}
	        }
	        if {$bds || [lsearch $svfams $pp] > -1} {
		        # parts with bodies and no geometry enities
		        if {$pric > -1} {
		            set data($r,$pric) 0
		            if {[ic_geo_get_family_param $pp prism] == 1} {set data($r,$pric) 1}
		        }
		        if {$hcc > -1} {
		            set data($r,$hcc) 0
		            if {[ic_geo_get_family_param $pp hexcore] == 1} {set data($r,$hcc) 1}
		        }
		        if {$emax > -1} {
		            set v [ic_geo_get_family_param $pp emax]
		            if {$v != ""} {set data($r,$emax) [format %g [expr {$v / $fact}]]}
		        }
		        if [aie_wb2_is_running] {
		            if {$wbp > -1} {
		                set data($r,$wbp) 0
		            }
		        }
		        foreach par [list ehgt hrat nlay erat ewid emin edev iwc swc prism_height_limit law] {
		            set i [set $par]
		            if {$i > -1} {set data($r,$i) __NA__}
		        }
	        } else {
		        set pnts 0
		        foreach fam $pfams {
		            if {[ic_geo_get_objects point $fam] != ""} {set pnts 1; break}
		        }
		        if $pnts {
		            # parts with only points
		            foreach par [list pric hcc emax ehgt hrat nlay erat ewid emin edev iwc swc prism_height_limit law] {
			            set i [set $par]
			            if {$i > -1} {set data($r,$i) __NA__}
		            }
		        } elseif {[lsearch $asms $pp] > -1} {
		            # assemblies
set do_common 0
continue
		            set data($r,$pc) $pp
		            foreach par [list cc mc tc pric hcc emax ehgt hrat nlay erat ewid emin edev iwc swc prism_height_limit law] {
			            set i [set $par]
			            if {$i > -1} {set data($r,$i) __NA__}
		            }
		            set do_common 0
		        } else {
		            # empty parts that are not assemblies
		            continue
		        }
	        }
	    } else {
	        # parts that have any surfaces and/or curves entities
	        if {$srfs == ""} {
		        foreach par [list pric erat iwc swc] {
		            set i [set $par]
		            if {$i > -1} {
		                set data($r,$i) __NA__
		            }
		        }
		        if {$crvs != ""} {
		            if {$pric > -1} {
		                set data($r,$pric) 0
		                foreach fam $pfams {
			                if {[ic_geo_get_family_param $fam prism] == 1} {set data($r,$pric) 1; break}
		                }
		            }
		            if [aie_wb2_is_running] {
		                if {$wbp > -1} {
		                    set data($r,$wbp) 0
		                }
		            }
		        }
	        } else {
		        if {$iwc > -1} {
		            set data($r,$iwc) 0
		            foreach fam $pfams {
			            if {[ic_geo_get_family_param $fam internal_wall] == 1} { set data($r,$iwc) 1; break }
		            }
		        }
		        if {$swc > -1} {
		            set data($r,$swc) 0
		            foreach fam $pfams {
			            if {[ic_geo_get_family_param $fam split_wall] == 1} { set data($r,$swc) 1; break }
		            }
		        }
		        if {$pric > -1} {
		            set data($r,$pric) 0
		            foreach fam $pfams {
			            if {[ic_geo_get_family_param $fam prism] == 1} { set data($r,$pric) 1; break }
		            }
		        }
		        if {$prism_height_limit > -1} {
		            set data($r,$prism_height_limit) 0
		            foreach fam $pfams {
		                set limit [ic_geo_get_family_param $fam prism_height_limit]
			            if {$limit > 0} { set data($r,$prism_height_limit) $limit; break }
		            }
		        }
		        if {$law > -1} {
		            set data($r,$law) undefined
		            foreach fam $pfams {
		                set prism_law [aie_get_prism_grow_law_text [ic_geo_get_family_param $fam law]]
			            set data($r,$law) $prism_law
			            break
		            }
		        }
		        if [aie_wb2_is_running] {
		            if {$wbp > -1} {
		                set data($r,$wbp) 0
		            }
		        }
	        }
	        if {$hcc > -1} {set data($r,$hcc) __NA__}
	        foreach srf $srfs {
		        foreach {n v} [ic_get_meshing_params surface $srf] {
		            switch $n {
			            emax - emin - edev {if {[set $n] < 0} continue; set v [format %g [expr {$v / $fact}]]}
			            ehgt - hrat - nlay - erat - ewid - prism_height_limit {
			                if {[set $n] < 0} continue
			                set v [format %g $v]
			            }
			            law {
			                if {[set $n] < 0} continue
			                set prism_law [aie_get_prism_grow_law_text $v]
		                    set v $prism_law
			            }
			            default continue
		            }
		            set i $r,[set $n]
		            if ![info exists data($i)] {
			            set data($i) $v
		            } elseif {$data($i) != $v} {
			            set data($i) "mixed"
		            }
		        }        
	        }
	        foreach crv $crvs {
		        foreach {n v} [ic_get_meshing_params curve $crv] {
		            switch $n {
			            emax - emin - edev {
			                if {[set $n] < 0} continue
			                set v [format %g [expr {$v / $fact}]]
			            }
			            ehgt {
			                if {$ehgt < 0 || !$options(apply_all)} continue
			                set v [format %g $v]
			            }
			            nlay - hrat {
			                if {[set $n] < 0 || (!$options(apply_all))} continue
			                set v [format %g $v]
			            }
			            ewid - prism_height_limit {
			                if {[set $n] < 0} continue
			                set v [format %g $v]
			            }
			            law {
			                if {[set $n] < 0} continue
			                set prism_law [aie_get_prism_grow_law_text $v]
		                    set v $prism_law
			            }
			            default continue
		            }
		            set i $r,[set $n]
		            if ![info exists data($i)] {
			            set data($i) $v
		            } elseif {$data($i) != $v} {
			            set data($i) "mixed"
		            }
		        }
	        }
	        foreach par [list ehgt hrat nlay] {
		        foreach fam $pfams {
		            set v [ic_geo_get_family_param $fam $par]
		            if {$v == "" || $v < 0} continue
		            set i $r,[set $par]
		            if ![info exists data($i)] {
			            set data($i) $v
			        } elseif {$data($i) != $v} {
			            if {$::pt(type) != "prism"} {
			                set data($i) "mixed"
			            } else {
			                set data($i) $v
			            }
			        }
			        break
		        }
	        }
	        foreach par [list emax ehgt hrat nlay erat ewid emin edev prism_height_limit law] {
		        set i $r,[set $par]
		        if {[info exists data($i)] && $data($i) == "mixed"} {
		            unset data($i)
		            set yellow_pp 1
		        }
	        }
	    }
	    if $do_common {
	        set data($r,$pc) $pp
	        if {$cc > -1} {set data($r,$cc) [family_color_for_name $pp]}
	        if $do_bcs {
		        catch {unset bcprop}
		        set bcs [ic_boco_get $pp]
		        if {$bcs == ""} {
		            foreach par [list mc tc] {
			            set i [set $par]
			            if {$i > -1} {set data($r,$i) __NA__}
		            }
		        }
		        foreach bc $bcs {
		            set bctype [lindex $bc 1]
		            foreach prop {0d 1d 2d 3d} {
			            if {[lsearch "$pt(element type,$prop)" $bctype] > -1} {
			                if [info exists bcprop($prop)] break
			                if [array exists bcprop] {
				                incr r
				                set data($r,$pc) $pp
				                foreach par [list cc pric hcc emax ehgt hrat nlay erat ewid emin edev iwc swc prism_height_limit law] {
				                    set i [set $par]
				                    if {$i > -1} {set data($r,$i) __NA__}
				                }
			                }
			                set bcprop($prop) 1
			                lappend part_list $pp
			                if {$prc > -1} {set data($r,$prc) $prop}
			                if {$mc > -1} {
				                if {$prop == "0d"} {
				                    set data($r,$mc) __NA__
				                } else {
				                    if {$prop == "3d"} {
					                    set mati 2
				                    } elseif {$prop == "2d" && $bctype != "PCOMP"} {
					                    set mati 3
				                    } elseif {$prop == "1d" && ($bctype == "PBAR" || $bctype == "PBARL" \
					                    || $bctype == "PBEAM" || $bctype == "PBEAML"  || $bctype == "IROD")} {
					                    set mati 3
				                    } else {
					                    set mati -1
				                    }
				                    set data($r,$mc) [aie_material_name_from_number [lindex $bc $mati]]
				                }
			                }
			                if {$elc > -1} {set data($r,$elc) $bctype}
			                if {$tc > -1} {
				                if {$prop == "2d" && $bctype != "PCOMP"} {
				                    if {$bctype == "ISHE"} {set data($r,$tc) [lindex $bc 8]}
				                    if {$bctype == "ISHR"} {set data($r,$tc) [lindex $bc 4]}
				                } else {
				                    set data($r,$tc) __NA__
				                }
			                }
			                break
			            }
		            }
		        }
	        }
	    }
	    if {$getparts == "all" && ![array exists bcprop]} {lappend part_list $pp}
	    if {$getparts == "all" || $getparts == "update"} {
	        if $yellow_pp {lappend pt(yellow_parts) $r}
	        incr r
	    } else {
	        set y_in [lsearch $pt(yellow_parts) $r]
	        if $yellow_pp {
		        if {$y_in < 0} {
		            lappend pt(yellow_parts) $r
		        }
	        } elseif {$y_in > -1} {
		        set pt(yellow_parts) [lreplace $pt(yellow_parts) $y_in $y_in]
	        }
	    }
    }
    foreach trace $traces {eval trace variable data $trace}
    if {$getparts == "all" && $r == 0} {
	    mess "No valid parts available!\n" red
	    return
    }
}

proc aie_part_table_headings {} {
        
    if [aie_wb2_is_running] {
        set params [list pc pric hcc emax ehgt hrat nlay erat ewid emin edev iwc swc cc mc elc prc tc prism_height_limit law wbp]
    } else {
        set params [list pc pric hcc emax ehgt hrat nlay erat ewid emin edev iwc swc cc mc elc prc tc prism_height_limit law]
    }
    foreach par $params { uplevel "set $par -1" }
    uplevel {
	    set i 0
	    foreach name $::pt(headings) {
	        switch $name {
		        Part {set pc $i}
		        Prism {set pric $i}
		        Hexa-core {set hcc $i}
		        "Maximum size" {set emax $i}
		        Height {set ehgt $i}
		        "Height ratio" {set hrat $i}
		        "Num layers" {set nlay $i}
		        "Tetra size ratio" {set erat $i}
		        "Tetra width" {set ewid $i}
		        "Min size limit" {set emin $i}
		        "Max deviation" {set edev $i}
		        "Internal wall" {set iwc $i}
		        "Split wall" {set swc $i}
		        "Prism height limit factor" {set prism_height_limit $i}
		        "Prism growth law" {set law $i}
	        	Color {set cc $i}
		        Material {set mc $i}
		        "Element type" {set elc $i}
		        Property {set prc $i}
		        Thickness {set tc $i}
		        Parameter {set wbp $i}
		        default continue
	        }
	        incr i
	    }
    }
}

proc aie_part_table_toggle_inf_params {var} {
    global options

    if {$options($var) == 1} {
	    if {$var == "apply_all"} {
	        set options(remove_all) 0
	    } elseif {$var == "remove_all"} {
	        set options(apply_all) 0
	    }
    }
}

proc part_table_ScaleFactor {w datavar} {
    upvar ::[winfo name $w] var
    upvar \#0 $datavar data
    global options

    if $options(show_factor) {
	    set fact [ic_geo_get_ref_size]
    } else {
	    set fact [expr {1.0 / [ic_geo_get_ref_size]}]
    }
    set traces [trace vinfo data]
    foreach trace $traces {eval trace vdelete data $trace}

    set emax [lsearch $var(headings) "Maximum size"]; set ehgt [lsearch $var(headings) Height]
    set emin [lsearch $var(headings) "Min size limit"]; set edev [lsearch $var(headings) "Max deviation"]
    # do not scale ehgt
    set params [list emax emin edev]
    foreach par $params {
	    set C [set $par]
	    if { $C > -1} {
	        set c [lsearch $var(visColumns) $C]
	        set r 0
	        foreach R $var(order) {
		        set RC $R,$C
		        if {[info exists data($RC)] && [set val $data($RC)] != "__NA__"} {
		            if {$val != ""} {
			            set val [format %g [expr {$val / $fact}]]
			            set data($RC) $val
			            if {$c > -1} {$w.can.table set $r,$c $val}
		            }
		        }
		        incr r
	        }
	    }
    }
    foreach trace $traces {eval trace variable data $trace}
}

# Called from "Settings->geometry Options"
proc aie_part_table_setcols {{type meshsizes}} {
    global ptsetup
    variable ::AIEnv::GUIManagement::GUIDisplayData 

    if [winfo exists .ptsetup-$type] {
        focus .ptsetup-$type
        return
    }
    if {$type == "meshsizes"} {
        set title "Mesh Setup Data"
        set headings_df_meshsizes [list Part Prism Hexa-core "Maximum size" Height "Height ratio" "Num layers" \
            "Tetra size ratio" "Tetra width" "Min size limit" "Max deviation" "Prism height limit factor" "Prism growth law" "Internal wall" "Split wall"]
        set ptsetup(headings-meshsizes) $headings_df_meshsizes
    } elseif {$type == "attributes"} {
        set title "Attributes Data"
        set headings_df_attributes [list Part Color Property Material "Element type" Thickness]
        set ptsetup(headings-attributes) $headings_df_attributes
    } else {
        return
    }

    set top [toplevel .ptsetup-$type]
    wm title $top $title
    wm transient $top .
    set x [expr {([winfo screenwidth $top]-[winfo reqwidth $top])/2}]
    set y [expr {([winfo screenheight $top]-[winfo reqheight $top])/2}]
    wm geometry $top +$x+$y
    focus $top
    set frm [frame $top.cols]
    foreach hd [set headings_df_$type] {
	    if {[lsearch $ptsetup(headings-$type) $hd] > -1} {
	        set ptsetup($type-$hd) 1
	    } else {
	        set ptsetup($type-$hd) 0
	    }
	    checkbutton $frm.n$hd -text $hd -variable ptsetup($type-$hd) -font $::AIEnv::GUIManagement::GUIDisplayData("CheckButtonFont")
	    if {$hd == "Part"} {
	        $frm.n$hd configure -state disabled
	    }
    }
    set children [winfo children $frm]
    # "ceil" is not working in tcl8.4.11
    set float [expr {[llength $children]/2.0}]
    set int [expr {int($float)}]
    set index [expr {($float > $int ? $int + 1 : $int) - 1}]
    set row 0
    set col 0
    foreach win $children {
	    if {$row > $index} {set row 0; incr col}
	    grid $win -row $row -column $col -sticky nw -padx 2
	    incr row
    }

    button $top.apply -text Apply -command "aie_part_table_setcols_apply $type" -bg gray80 -padx 8 -font $::AIEnv::GUIManagement::GUIDisplayData("ButtonFont")
    button $top.dismiss -text Dismiss -command "destroy $top" -bg gray80 -padx 4 -font $::AIEnv::GUIManagement::GUIDisplayData("ButtonFont")
    grid $frm -
    grid $top.apply $top.dismiss -padx 2 -pady 6 -sticky se
    grid $top.dismiss -sticky sw
    wm resizable $top 0 0
}

proc aie_part_table_setcols_apply {type} {
    global ptsetup
    set ptsetup(headings-$type) {}
    foreach win [winfo children .ptsetup-$type.cols] {
        set hd [winfo name $win]
        if $ptsetup($type-[string range $hd 1 end]) {lappend ptsetup(headings-$type) [string range $hd 1 end]}
    }
    if [aie_wb2_is_running] {
        if {$type == "meshsizes"} {
            lappend ptsetup(headings-$type) "Parameter"
        }
    }
}

# What about doing part, color, property, material, element type, and thickness with mesh?
# The checks for srfs, crvs, bds, and pnts uses just geometry

# When applying data, you should do the same part name multiple times for bcs only.

# get rid of __NA__ and check if variable exists or not.
# handle __NA__ when applying data to BC's

# remember to update yellow parts when you press accept and when you toggle the "apply all" and "remove all" checkbuttons (check if all entries for a part are blank or "mixed"?)
# get data again when change "apply all" checkbutton
# Make "apply all" and "remove all" checkbuttons work
# handle pasting of data from Excel or text editor
# maybe use tag for yellow parts instead of list

# don't allow leading zero
# do aie_part_table_accept, handling of fam is wrong for multiple bc's
# Make sure things work right for the attributes method (get and apply bcs)
# You have to apply to all parts when you change any of the curve inflation params checkbuttons
# make sure part_list is correct when undo after apply

# structural ai*environment version should not handle prism parameters.
# maybe see if using ic_geo_count_in_family can speed anything up
# give warning if bodies and other geom (surf, crv, pnt) in same part?
# added stand-alone table windows

