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

proc make_display_window {} {
    global disp_window_visible
    
    array set disp_window_visible { geom 1 struct 1 unstruct 1 }
    
    top_window .e 0 Display "" .v 0 1
    .e configure -width 150
    
    # Three major windows: geom, struct, and unstruct.
    
    frame .e.fam -borderwidth 2 -relief ridge
    checkbutton .e.vis_geom -text Geometry \
	-variable disp_window_visible(geom) \
	-command "disp_pack_edit_toplevel 0"
    checkbutton .e.vis_struct -text Structured \
	-variable disp_window_visible(struct) \
	-command "disp_pack_edit_toplevel 0"
    checkbutton .e.vis_unstruct -text Unstructured \
	-variable disp_window_visible(unstruct) \
	-command "disp_pack_edit_toplevel 0"
    frame .e.geom -borderwidth 2 -relief ridge
    frame .e.struct -borderwidth 2 -relief ridge
    frame .e.unstruct -borderwidth 2 -relief ridge
    frame .e.spacer -height 0 -width 150
    
    make_fam_window .e.fam
    make_geom_window .e.geom
    make_struct_window .e.struct
    make_unstruct_window .e.unstruct
}

proc disp_new_stuff {} {
    global data_available str_option
    global tk_version   

    if ![info exists tk_version] return
    
    set data_available(geom) [ic_geo_is_loaded]
    set data_available(geom_facet) [ic_geo_is_loaded]
    set data_available(unstruct) [ic_uns_is_loaded]
    set data_available(struct) [ic_str_is_loaded]
    set data_available(mesh) \
	[expr {$data_available(unstruct) || $data_available(struct)}]
    
    disp_pack_edit_toplevel 1
    
    if $data_available(struct) {
	set str_option(domain,outlines) 1
	set str_option(domain,simplify) 0
	disp_set_option domain
	disp_change_overall_visible domain
    }
    update_fam_window
    update_uns_available
    update_str_visible
}

# note that the arg list of ic_display_update depends on this one
# see doc there.
proc display_update {{mode ""} {new_fams 1} {types ""}} {
    global data_available str_option tk_version disp_window_visible
    global uns_type_visible
    
    if ![info exists tk_version] return
    
    if {"" == $mode} {
	set mode all
    } elseif {"uns" == $mode} { 
	set mode unstruct 
    } elseif {"geo" == $mode} {
	set mode geom
    }
    
    switch $mode {
	geom {
	    set geom_data_before $data_available(geom)
	    set data_available(geom) [ic_geo_is_loaded]
	    set data_available(geom_facet) $data_available(geom) ;##?
	    
	    if {!$geom_data_before && $data_available(geom)} {
		if {"" != $types} { foreach t $types { set geom_visible($t) 1 } }
		set disp_window_visible(geom) 1
		disp_pack_edit_toplevel 0
	    }
	    if $new_fams { update_fam_window }
	}
	unstruct {
	    # mod_state: this is a hack--this branch modifies mesh state
	    set mod_state [ic_uns_is_modified]
	    if !$data_available(unstruct) {
		set data_available(unstruct) [ic_uns_is_loaded]		
		if $data_available(unstruct) {
		    if {"" != $types} { foreach t $types { set uns_type_visible($t) 1 } }
		    set data_available(mesh) 1
		    set disp_window_visible(unstruct) 1
		    disp_pack_edit_toplevel 0
		}
	    }
	    if $data_available(unstruct) {		
		if {"" != $types} { foreach t $types { set uns_type_visible($t) 1 } }
		update_uns_available
		update_uns_visible		
		if $new_fams {
		    ic_uns_families_changed
		    update_fam_window 
		}
	    }
	    ic_uns_set_modified $mod_state
	}    
	struct {
	    if !$data_available(struct) {
		set data_available(struct) [ic_str_is_loaded]
		
		if $data_available(struct) {
		    if {"" != $types} { foreach t $types { set str_type_visible($t) 1 } }
		    set data_available(mesh) 1
		    set str_option(domain,outlines) 1
		    set str_option(domain,simplify) 0
		    disp_set_option domain
		    disp_change_overall_visible domain	
		    update_str_visible  ;# this does update_fam_window
		}
	    }
	    if $new_fams {
		ic_str_families_changed
		update_fam_window
	    }
	    set disp_window_visible(struct) 1
	    disp_pack_edit_toplevel 0
	}
	all { disp_new_stuff }
	default {
	    mess "display_update: invalid mode. valid modes: all, unstruct, struct, geo\n"
	    return
	}
    }
}

proc disp_pack_edit_toplevel {reset} {
    global data_available disp_window_visible disp_struct_row_number    
    
    if {[info commands winfo] == ""} return
    
    set data_available(geom)     [ic_geo_is_loaded]
    set data_available(unstruct) [ic_uns_is_loaded]
    set data_available(struct)   [ic_str_is_loaded]
    
    foreach r {0 1 2 3 4 5 6 7 8 9 10} { grid rowconfigure .e $r -weight 0 }
    
    foreach s [grid slaves .e] { grid forget $s }
    set row 0
    grid .e.spacer -row $row -column 0
    
    incr row
    grid .e.fam -row $row -column 0 -sticky nsew
    grid rowconfigure .e $row -weight 2

    foreach t {geom struct unstruct} {
	if $data_available($t) {
	    incr row
	    grid .e.vis_$t -row $row -column 0 -sticky nswe
	    if $disp_window_visible($t) {
		incr row
		grid .e.$t -row $row -column 0 -sticky nswe
		switch $t {
		    unstruct {
			grid rowconfigure .e $row -weight 1
		    }
		    struct {
			set disp_struct_row_number $row
		    }
		}
	    }
	}
    }
    update
    
    top_geometry .e -0+0
    top_resize_dot
}

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

proc make_fam_window {w} {
    global fam_window_list
    
    label $w.l -text Families
    frame $w.f
    
    grid $w.l -row 0 -column 0 -sticky news
    grid $w.f -row 1 -column 0 -sticky news
    grid columnconfigure $w 0  -weight 1000  ;# XXXXX
    grid rowconfigure $w 1  -weight 1000  ;# XXXXX
    
    lappend fam_window_list $w
}

proc fam_new_window {} {
    for {set i 0} {[winfo exists .family_edit$i]} {incr i} {}
    set w .family_edit$i
    top_window $w 1 "Family list"
    make_fam_window $w
    top_geometry $w -100+100
    update_fam_window $w
}

proc fam_del_window {w} {
    global fam_window_list
    
    set fam_window_list [ldelete $fam_window_list $w]
    check_box_remove_trace $w.f
    top_destroy $w
}

proc update_fam_window {{which ""} {force 0}} {
    global fam_visible tk_version fam_listsize fam_sorttype
    global fam_window_list fam_active
    global last_family_list last_which
    
    if ![info exists fam_window_list] return

    if ![info exists tk_version] return

    set allfams [fam_get_current_list]
    if { [ info exists last_family_list ] &&
		[ info exists last_which ] && !$force} {
	if { $allfams == $last_family_list &&
		$which == $last_which } {
# families didn't change
		return
	}
    }
    set last_which $which
    set last_family_list $allfams
    
    set opts ""
    set newf 0
    foreach f $allfams {
	set col [family_color_for_name $f]
	set fname $f
	lappend opts [list $f -text $f -command "update_fam_visible 0" \
			 -selectbackground $col -foreground $col]
	incr newf [fam_check_new $f 0]
    }
    
    if {$which == ""} { set which $fam_window_list }
    
    foreach w $which {
	set buts ""
	if {$w != ".e.fam"} { lappend buts nl }
	lappend buts [list edit Edit fam_edit]
	if {$w != ".e.fam"} {
	    lappend buts [list close Close "fam_del_window $w"]
	    set size "10 10"
	} else {
	    if {$fam_listsize < 2} { set fam_listsize 2 }
	    set size $fam_listsize
	}

	check_box $w.f $opts $size fam_visible 1 \
	    "update_fam_visible 0" "" $buts
	
	if {[bind $w.f <Leave>] == ""} {
	    bind $w.f <Leave> "update_fam_visible 1"
	}
    }
    
# reset the active families
    set fam_active ""
    foreach f [array names fam_visible] {
	if $fam_visible($f) { lappend fam_active $f }
    }

    if $newf { ic_uns_families_changed }
    update_family_labels
}

proc add_new_family {f v} {
    global fam_visible
    set fam_visible($f) $v
}

proc update_fam_visible {leaving} {
    global batch_mode fam_update_mode fam_needs_update
    
    if $batch_mode return
    
    switch $fam_update_mode {
	always {
	    if $leaving return
	}
	leave {
	    if !$leaving { set fam_needs_update 1; return }
	    if ![info exists fam_needs_update] return
	}
    }
    
    update_family_labels
# don't redraw here since we do it below
    update_geom_visible all v 0
    update_uns_visible
    update_str_visible
    catch {unset fam_needs_update}
}

proc update_family_labels {} {
    global fam_visible fam_window_list
    
    if ![info exists fam_window_list] return
    
    set t 0; set v 0
    foreach f [array names fam_visible] {
	incr t
	if $fam_visible($f) { incr v }
    }
    foreach w $fam_window_list {
	$w.l configure -text "Families ($v/$t)"
    }
}

proc disp_set_tearoff_name {title m1 m2} {
    top_title $m2 "$title options"
}

proc fam_get_id {f} {
    set id [ic_geo_lookup_family_pid $f]
    if {$id == ""} {
	set id [ic_uns_lookup_family_pid $f]
    }
    return $id
}

proc fam_get_current_list {} {
    global fam_visible
    foreach f [concat [ic_geo_list_families] [ic_uns_list_families] \
		   [ic_str_list_families] [ic_boco_list_families]] {
	if ![info exists fam_visible($f)] { set fam_visible($f) 1 }
    }
    return [fam_get_sorted]
}

proc fam_edit {} {
    global fam_visible fam_visible_prev fam_edit
    
    set fams [fam_get_current_list]
    
    catch {unset fam_edit}
    
    form_kill .fam_edit
    set buts {accept {Reset fam_reset} cancel}
    set d [form_init .fam_edit "Family edit" "" $buts]
    set scr [form_scroller $d.scr 400 {1 0 -cols 2}]
    set i 3
    foreach f $fams {
	set f [string toupper $f]
	set id [fam_get_id $f]
	if {$f == "ORFN"} continue
	set fam_edit(name,$f) $f
	set fam_edit(color,$f) [family_color_for_name $f]
	form_label $scr.name$i "$f ($id)" "$i 0"
	form_entry $scr.nname$i fam_edit(name,$f) string "$i 1"
	futil_colorentry $scr.color$i fam_edit(color,$f) \
	    "$i 2"
	incr i
    }
    form_button $d.delun "Delete unused" "fam_delete_unused" {2 0 -sticky ew}
    form_button $d.crnew "New family" "fam_create_new" {2 1 -sticky ew}
    form_button $d.bestc "Good colors" "fam_good_colors" {3 0 -sticky ew}
    form_button $d.newl "New window" "fam_new_window" {3 1 -sticky ew}
    form_label $d.sizel "List size" {4 0}
    form_entry $d.size fam_listsize int {4 1}
    form_frame $d.sort flat 0 {5 0 -cols 2}
    form_label $d.sort.l "Sort:" {0 0}
    form_radiobutton $d.sort.n Name fam_sorttype name {0 1}
    form_radiobutton $d.sort.c Color fam_sorttype color {0 2}
    form_radiobutton $d.sort.p Id fam_sorttype id {0 3}
    form_label $d.sort.ul "Update:" {1 0}
    form_radiobutton $d.sort.al "Always" fam_update_mode always {1 1}
    form_radiobutton $d.sort.mm "Mouse exit" fam_update_mode leave {1 2 -cols 2}
    form_finish -0+0
    form_scroller_hack $d.scr
    
    set r [form_wait .fam_edit]
    form_kill .fam_edit
    if !$r return
    
    foreach f [array names fam_visible] {
	if {$f == "ORFN"} continue
	ic_set_family_color_for_name $f $fam_edit(color,$f)
	set nf [string toupper $fam_edit(name,$f)]
	if {$nf != $f} {
	    set fam_visible($nf) $fam_visible($f)
	    ic_geo_rename_family $f $nf
	    ic_uns_rename_family $f $nf
	    unset fam_visible($f)
	    # unset fam_visible_prev
	    foreach what {surface curve point material density loop body} {
		if [info exists fam_visible_prev($what,$f)] {
		    set fam_visible_prev($what,$nf) fam_visible_prev($what,$f)
		    unset fam_visible_prev($what,$f)
		}
	    }
	}
    }
    
    fam_stuff_changed
}

proc fam_good_colors {} {
    global fam_visible fam_edit
    
    set fams [lsort -command "family_name_compare -1" [array names fam_visible]]
    set k 0
    foreach f $fams {
	if {$f == "ORFN"} continue
	set fam_edit(color,$f) [family_color_for_angle $k] ; # ?? -JKA
	incr k 100
    }
}

proc fam_stuff_changed {} {
    #color might have changed, so do force update
    update_fam_window "" 1 
    disp_set_option all
    ic_uns_families_changed
    ic_str_families_changed
}

proc fam_delete_unused {{quiet 0}} {
    global fam_visible

    set fams [array names fam_visible]
    if [ic_uns_is_loaded] {
        set uns_counts [ic_uns_count_in_families $fams]
    } else {
        set uns_counts ""
    }
    set str_counts ""
    if [ic_str_is_loaded] {
        set str_counts [ic_str_count_in_families $fams]
    } else {
        set str_counts ""
    }

    set del_list ""
    set ind 0
    foreach f $fams {
        if {$f != "ORFN"} {
            
            set ok 0
            if {[ic_geo_get_objects all $f] != ""} {
                set ok 1
            }
            
            if {([lindex $uns_counts $ind] != "") && [lindex $uns_counts $ind]} {
                set ok 1
            }
            if {([lindex $str_counts $ind] != "") && [lindex $str_counts $ind]} {
                set ok 1
            }
            if !$ok {
                if {!$quiet} {
                    mess "Deleting empty family $f\n"
                }
                unset fam_visible($f)
                lappend del_list $f
            }
        }
        incr ind
    }
    if { 1 > [llength $del_list]} return    
    ic_uns_delete_family $del_list
    ic_geo_delete_family $del_list
    update_fam_window
    if {([info commands winfo] != "") && [winfo exists .fam_edit] && \
            [winfo ismapped .fam_edit]} {
        form_cancel .fam_edit
        update
        fam_edit
    }
}

proc fam_delete_unused_on_unload {{quiet 0}} {
# should check for surfaces curves points etc.
    if {![ic_uns_is_loaded] && ![ic_str_is_loaded] && ![ic_hex_blocking_loaded]} {
        fam_delete_unused $quiet
    }
}

proc fam_create_new {} {
    global fam_visible
    
    set f [string toupper [question "New family name?"]]
    if {$f != ""} {
	fam_check_new $f
    }
}

proc fam_reset {} {
    global fam_edit
    
    foreach e [array names fam_edit] {
	set f [lindex [split $e ,] 1]
	switch [lindex [split $e ,] 0] {
	    color {
		set fam_edit($e) [family_color_for_name $f 1]
	    }
	    name {
		set fam_edit($e) $f
	    }
	}
    }
}

proc fam_check_new {fam {do_update 1}} {
    global fam_visible
    
    set new 0
    if [ic_geo_is_loaded] {
	if ![ic_geo_check_family $fam] {
	    ic_geo_new_family $fam 0
	    set new 1
	}
    }
    if [ic_uns_is_loaded] {
	if ![ic_uns_check_family $fam] {
	    ic_uns_new_family $fam
	    set new 1
	}
    }
    if $new {
	if $do_update {
	    update_fam_window
	    
	    if [winfo exists .fam_edit] {
		form_cancel .fam_edit
		update
		fam_edit
	    }
	}
    }
    if ![info exists fam_visible($fam)] { set fam_visible($fam) 1 }
    return $new
}

proc fam_toggle_highlight {fam var} {
    global $var
    set on [set ${var}($fam)]
    ic_uns_show_selected "" $fam $on white 1
}

proc gui_change_visibility {type what on} {
    global geom_visible uns_type_visible fam_visible
    
    switch $type {
	geometry {
	    set geom_visible($what) $on
	    update_geom_visible $what v
	}
	unstruct {
	    set uns_type_visible($what) $on
	    update_uns_visible
	}
	family {
	    set fam_visible($what) $on
	    update_fam_visible 0
	}
	default {
	    error "Unknown type value"
	}
    }
}

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

proc undo_redo_update {nu nr} {
    global tk_version menus_are_disabled button_status
    
    # Geom-Undo supports multi level undo-redo whereas
    # only one Mesh-Undo canbe done. So enable both
    # undo-redo all time. Needs tobe fixed. -HG
    set nu 1; set nr 1;

    if {![info exists menus_are_disabled] && [info exists tk_version]} {
	set button_status(undo) $nu
	set button_status(redo) $nr
	
	# This is the old style stuff.
	set undos .v.top.extras.extra3
	set redos .v.top.extras.extra4
	
	foreach un $undos {
	    if [winfo exists $un] {
		$un configure -state [expr {$nu ? "normal" : "disabled"}]
	    }
	}
	foreach re $redos {
	    if [winfo exists $re] {
		$re configure -state [expr {$nr ? "normal" : "disabled"}]
	    }
	}
    }
}

# Clear the fam_visible_prev list so that it objects can be added 
# in define_geom_object. This is called from clear_objects.
proc clear_fam_visible_prev { what } {
    global fam_visible fam_visible_prev

    foreach f [array names fam_visible] {		
	if [info exists fam_visible_prev($what,$f)]  {
	    unset fam_visible_prev($what,$f)
	}
    }
}
