
# Default bindings and utility routines for the viewer.
#
# Copyright (c) 1994 ICEM CFD Engineering
# Author:  Wayne A. Christopher, wayne@icemcfd.com
#          ICEM CFD Engineering, Berkeley, California

# This routine creates the viewer and sets various variables and parameters.

# --- the following line may cause problem for application without
#     med's graphic window. 
#if ![info exists tdv_default] { set tdv_default .v.view }

if [info exist tool_dir2] {
   set b [file join $tool_dir2 wb_binding.tcl]
   if [file exist $b] { uplevel \#0 source \"$b\" }
}

proc tdv_init {w width height gsys bgcolor debug {dbuffer 1}
	       {twod 0} {master NULL} {minw 0}} {
    global tdv_pos tdv_rot tdv_scale tdv_center tdv_x tdv_y
    global tdv_height tdv_width tdv_cursor_path
    global tdv_library tdv_title_string tdv_twod_var
    global tdv_library tdv_angled_text_string tdv_twod_var
    global tdv_no_redraw_ms tdv_dbuffer_var tdv_pickable_tags
    global display_type host_vendor initial_warning tdv_track_mouse
    global tdv_mouse_bindings env is_win tdv_dynamics_speed_thresh
    global tdv_user_views tdv_last_viewer_clicked tdv_nonuniform_scale
    global tdv_start_spaceball
    
    # Stuff that might or might not be defined.
    if {[info command blt_bell] == ""} {
	proc blt_bell {} { puts -nonewline \007 }
    }
    
    if {[info command tdv_mess] == ""} {
	if {[info command mess] == ""} {
	    proc tdv_mess {text {color ""} {font ""}} {
		puts -nonewline $text
	    }
	} else {
	    proc tdv_mess {text {color ""} {font ""}} {
		mess $text $color $font
	    }
	}
    }
    
    if ![info exists tdv_user_views] { set tdv_user_views "" }
    
    # These variables are updated whenever the window changes size.
    set tdv_width($w) $width
    set tdv_height($w) $height
    
    if ![info exists tdv_dynamics_speed_thresh] {
	set tdv_dynamics_speed_thresh 200
    }

#    global use_workbench
#    if {[info exists use_workbench] && $use_workbench == 1} {
#	set sb_func 0
#    } else {set sb_func tdv_sb_func}

    if {[info exists tdv_start_spaceball] && $tdv_start_spaceball} {
        set sb_func tdv_sb_func
    } else {
        set sb_func 0
    }
    
    if {$is_win && ($gsys == "X11")} { set gsys Mswin }

    # Create the viewer with the given options.  It is the responsibility
    # of the caller to handle the geometry management.
    set DL 1
    if {$twod} {set DL 0}
    tdv_viewer $w -background $bgcolor -borderwidth 0 -debug $debug \
	-gsys $gsys -sizechange "tdv_win_change $w" -dbuffer $dbuffer \
	-directlight $DL -width $width -height $height -twod $twod \
	-master_viewer $master -min_width $minw \
	-spaceball_func $sb_func
    
    catch {$w configure -busy_cursor "@$tdv_library/busy.cur orange"}

    set gsys [$w get -gsys]
    if {$gsys != "X11"} {
	switch -glob "$display_type $host_vendor" {
	    "hp hp*" - "sol sol*" - "sun* sol*" {
		if [string match hp* $display_type] {
		    # set depth [set_large_visual $w direct 24]
		    set depth [set_large_visual $w true 24]
		} else {
		    set depth [set_large_visual $w true 24]
		}
		if {![info exists env(ICEPAK_OPENGL_NO_CMAP)] || \
			!$env(ICEPAK_OPENGL_NO_CMAP)} {
		    if {$depth < 24} {
			puts "Warning: couldn't get 24 planes\
                        for graphics -- only $depth are available.\n\
			Reverting to X11.\n"
			$w configure -gsys X11
		    }
		}
	    }
	}
    }
    
    # These variables can be attached to checkbuttons, and the traces
    # below will call routines to automatically update the viewer variables,
    # etc.
    set vars {
	depthcue axes origin {dbuffer 1} hiddenline
	rulers date title {xgouraud 1} track_mouse two_d_grid
    }
    lappend vars [list twod $twod]
    if {[$w get -gsys] == "X11"} {
	lappend vars [list directlight 0]
	$w configure -directlight 0
    } else {
	lappend vars [list directlight 1]
    }

    foreach n {ambient diffuse specular shininess dir} {
       global tdv_lighting
       if [info exist tdv_lighting($n)] {
          $w configure -light_$n $tdv_lighting($n)
       }
    }
    
    foreach v $vars {
	set i [lindex $v 0]
	global tdv_${i}_var
	if ![info exists tdv_${i}_var($w)] {
	    if {($i != "twod") && [info exists tdv_${i}_var(all)]} {
		set vv [set tdv_${i}_var(all)]
	    } elseif {[lindex $v 1] != ""} {
	        set vv [lindex $v 1]
	    } else {
		set vv 0
	    }
	    set tdv_${i}_var($w) $vv
	}
	if ![info exists tdv_${i}_var(all)] {
	    set tdv_${i}_var(all) [set tdv_${i}_var($w)]
	}
	
	trace variable tdv_${i}_var($w) w "tdv_toggle_$i $w; list"
    }
    
    # These variables contain the current transformation data for the viewer.
    # The routine tdv_trans_update moves them to the viewer.
    set tdv_pos($w) "0 0 0"
    set tdv_rot($w) "0 0 0 1"
    set tdv_scale($w) "1 1 1"
    set tdv_center($w) "0 0 0"
    set tdv_pickable_tags($w) ""
    
    if ![info exists tdv_nonuniform_scale] {
	array set tdv_nonuniform_scale {0 "" 1 "" 2 ""}
    }
    if ![info exists tdv_no_redraw_ms] {
	set tdv_no_redraw_ms 2000
    }
    if ![info exists tdv_title_string($w)] {
	if {$master == "NULL"} {
	    set tdv_title_string($w) "3D Viewer $w"
	} else {
	    set tdv_title_string($w) $tdv_title_string($master)
	}
    }
    if ![info exists tdv_angled_text_string($w)] {
	set tdv_angled_text_string($w) "This is at an angle."
    }
    
    foreach i {x y z} {
	global tdv_${i}sym_var
	set tdv_${i}sym_var($w) 0
    }

    global tdv_mirrors
    set tdv_mirrors($w,list) ""
    foreach c {A B C D} {set tdv_mirrors($w,$c) 0}

    global tdv_replica
    set tdv_replica($w) 0
    set tdv_replica($w,nrep) 1 
    set tdv_replica($w,type) rot
    set tdv_replica($w,angle) 0
    foreach i {x y z} {
       set tdv_replica($w,${i}0) 0
       set tdv_replica($w,a${i}) 0
       set tdv_replica($w,d${i}) 0
    }
    set tdv_last_viewer_clicked $w
    
    # The cursor path is the list of directories that the tdv_cur routine
    # looks in for cursor bitmaps.
    if ![info exists tdv_cursor_path] {
	lappend tdv_cursor_path $tdv_library
    }
    
    bindtags $w [list $w all]
}

# This routine sets up the bindings to do 3-D positioning.  It is
# a separate routine because the program may want to switch bindings
# at various times.  The shiftin and shiftout arguments can be used to
# temporarily set the center point. not in use and removed.

proc tdv_dynamics_bindings {w args} {
    global tdv_twod_var tdv_button_map tdv_mouse_bindings batch_mode tdv_enable_smooth_move
 
    if $batch_mode return
   
    if {$args != ""} {
      # just in case some old code use this
       mess "OLD shiftin and shiftout args to tdv_dynamics_bindings removed\n" red
    }

    if ![info exists tdv_mouse_bindings] {
        tdv_reset_bindings $w 0
    }
    
    foreach i {rot trans scale} {
        set b$i $tdv_mouse_bindings($i)
    }
    set td $tdv_twod_var($w)

    if $td {
        foreach i [list ButtonPress-$brot Button$brot-Motion \
		   ButtonRelease-$brot Shift-ButtonPress-$brot \
		   Shift-Button$brot-Motion Shift-ButtonRelease-$brot] {
		    bind $w <$i> ""
        }
    }
    
    set pressList ""

    if !$td { lappend pressList <ButtonPress-$brot> $brot rot }

    lappend pressList <ButtonPress-$btrans> $btrans trans
    lappend pressList <ButtonPress-$bscale> $bscale scale

    if {$btrans == 2} {
        lappend pressList <Button1-ButtonPress-3> $btrans trans
        lappend pressList <Button3-ButtonPress-1> $btrans trans
    } else {
        lappend pressList <Button1-ButtonPress-3> $bscale scale
        lappend pressList <Button3-ButtonPress-1> $bscale scale
    }

    if !$td { lappend pressList <Shift-ButtonPress-1> 1 rot }
    lappend pressList <Shift-ButtonPress-2> 2 trans
    lappend pressList <Shift-ButtonPress-3> 3 scale

    if !$td { lappend pressList <Control-ButtonPress-1> 1 rot }
    lappend pressList <Control-ButtonPress-2> 2 trans
    lappend pressList <Control-ButtonPress-3> 3 scale

    global tdv_binding

    foreach {e i b} $pressList {
       if {[info exist tdv_binding($w,$e)] && ($tdv_binding($w,$e) != "")} {
          tdv_set_mouse_press_binding $w $e $i $tdv_binding($w,$e)
       } elseif {[info exist tdv_mouse_bindings($e)] && ($tdv_mouse_bindings($e) != "")} {
          tdv_set_mouse_press_binding $w $e $i $tdv_mouse_bindings($e)
       } else {
          tdv_set_mouse_press_binding $w $e $i $b
       }
    }
          
    if !$td { tdv_set_mouse_motion_binding $w <Button$brot-Motion> }
    tdv_set_mouse_motion_binding $w <Button$btrans-Motion>
    tdv_set_mouse_motion_binding $w <Button$bscale-Motion>
    if {$btrans == 2} {
       tdv_set_mouse_motion_binding $w <Button1-Button3-Motion>
    } else {
       tdv_set_mouse_motion_binding $w <Button$bscale-Motion>
    }

    if !$td { tdv_set_mouse_release_binding $w <ButtonRelease-$brot> }
    tdv_set_mouse_release_binding $w <ButtonRelease-$btrans>
    tdv_set_mouse_release_binding $w <ButtonRelease-$bscale>
    tdv_set_mouse_release_binding $w <Button1-ButtonRelease-3>
    tdv_set_mouse_release_binding $w <Button3-ButtonRelease-1>

    if !$td { tdv_set_mouse_motion_binding $w <Shift-Button1-Motion> }
    tdv_set_mouse_motion_binding $w <Shift-Button2-Motion>
    tdv_set_mouse_motion_binding $w <Shift-Button3-Motion>

    if !$td { tdv_set_mouse_release_binding $w <Shift-ButtonRelease-1> }
    tdv_set_mouse_release_binding $w <Shift-ButtonRelease-2>
    tdv_set_mouse_release_binding $w <Shift-ButtonRelease-3>
    
    if !$td {tdv_set_mouse_motion_binding $w <Control-Button1-Motion> }
    tdv_set_mouse_motion_binding $w <Control-Button2-Motion>
    tdv_set_mouse_motion_binding $w <Control-Button3-Motion>

    if !$td { tdv_set_mouse_release_binding $w <Control-ButtonRelease-1> }
    tdv_set_mouse_release_binding $w <Control-ButtonRelease-2>
    tdv_set_mouse_release_binding $w <Control-ButtonRelease-3>

    #bind $w <F9> "tdv_temporary_dynamics $w"  this is handled by tdv_key_command
    bind $w <F9> ""
    
    # This is for the wheel
    bind $w <Button-4> "tdv_wheelzoom $w 50"
    bind $w <Button-5> "tdv_wheelzoom $w -50"
    # We have to bind to . because the wheel can be moved without clicking in the window
    # Need to identify which window that the current pointer located
    # in order to make it work for multiple windows. 
    bind . <MouseWheel> "tdv_wheelzoom %W %D %t %X %Y"
    bind $w <MouseWheel> "tdv_wheelzoom $w %D %t %X %Y"
    
    if {[info exists tdv_enable_smooth_move] && $tdv_enable_smooth_move == 1} {
        bind $w <Double-Button-1> "tdv_smooth_move_double_click $w %x %y"
    }
    bind $w <Motion> "tdv_motion $w %x %y"
    tdv_cur $w dynamics
}

proc tdv_selection_bindings {w} {
    global is_win toplevel batch_mode
    
    if $batch_mode return

    global tdv_mouse_bindings_autohex_names
    if ![info exists tdv_mouse_bindings_autohex_names] {return}
    
    if $is_win {
        set par [winfo parent $w]
    } else {
        set par $w
    }
    if {[info exists toplevel(single)] && $toplevel(single)} {
	    bind $w <Enter> "tdv_unfocus_entries"
	    bind $w <Leave> "tdv_update_track_mouse $w out"
    }
    
    foreach nn {_L _R ""} {
	catch {bind all <KeyPress-Shift$nn> "tdv_shiftkey $w 1 %X %Y"}
	catch {bind all <KeyRelease-Shift$nn> "tdv_shiftkey $w 0 %X %Y"}
	catch {bind all <KeyPress-Control$nn> "tdv_shiftkey $w 1 %X %Y"}
	catch {bind all <KeyRelease-Control$nn> "tdv_shiftkey $w 0 %X %Y"}
    }
    
    foreach b {1 2 3} {
	bind $w <Shift-ButtonPress-$b> "tdv_do_select $w $b 0 %x %y"
	bind $w <Shift-Button$b-Motion> "tdv_do_move $w $b %x %y"
	bind $w <Shift-ButtonRelease-$b> "tdv_do_release $w $b %x %y 1"
    }
    bind $w <Control-ButtonPress-1> "tdv_do_select $w 1 0 %x %y"
    bind $w <Control-Button1-Motion> "tdv_do_move $w 1 %x %y"
    bind $w <Control-ButtonRelease-1> "tdv_do_release $w 1 %x %y 2"
    
    bind $w <Shift-Button1-ButtonPress-3> "tdv_do_select $w 2 0 %x %y"
    bind $w <Shift-Button3-ButtonPress-1> "tdv_do_select $w 2 0 %x %y"
    bind $w <Shift-Button1-Button3-Motion> "tdv_do_move $w 2 %x %y"
    bind $w <Shift-Button1-ButtonRelease-3> "tdv_do_release $w 2 %x %y 1"
    bind $w <Shift-Button3-ButtonRelease-1> "tdv_do_release $w 2 %x %y 1"
    
    # This is a bit esoteric ...
    # bind $w <Shift-Button3-ButtonPress-1> "tdv_selection_setloc $w %x %y"
    # bind $w <Shift-Button3-ButtonRelease-1> break
}

proc tdv_unfocus_entries {} {
    set w [focus]
    if {$w == ""} return
    switch [winfo class $w] {
	Entry - Text {
	    if {[winfo name $w] != "txt"} {focus . }
	}
    }
}

proc tdv_shiftkey {w on x y} {
    global tdv_shift_on select_in_dynamics tdv_shift_window
    global tdv_click_function tdv_waiting_for_click tdv_waiting_for_motion

    if {([array names tdv_click_function] != "") && \
	    ([array names tdv_waiting_for_click] == "") && \
	    ([array names tdv_waiting_for_motion] == "")} return
    
    if [info exists select_in_dynamics] return
    if [info exists tdv_waiting_for_click($w)] return

    set ww [winfo containing $x $y]
    if {[winfo exists $ww] && ([winfo class $ww] == "Tdv_Viewer")} {
	if $on {
	    tdv_cur $ww pick
	    set tdv_shift_window $ww
	} else {
	    if [info exists tdv_shift_window] {
		tdv_cur $tdv_shift_window dynamics
		unset tdv_shift_window
	    }
	    if $tdv_shift_on {
		tdv_release_action $ww "" "" $x $y
	    }
	}
	set tdv_shift_on $on
    }
}

proc tdv_selection_bindings2 {w mod cur fn1 fn2 fn3} {
    global is_win
    if $is_win {
	set par [winfo parent $w]
    } else {
	set par $w
    }
    foreach nn {_L _R ""} {
	catch {bind $par <KeyPress-$mod$nn> "tdv_cur $w $cur"}
	catch {bind $par <KeyRelease-$mod$nn> "tdv_cur $w dynamics"}
    }
    
    foreach b {2 3} {  # control button 1 is used to select by region
	bind $w <$mod-ButtonPress-$b> "$fn1 $w $b 0 %x %y"
	bind $w <$mod-Button$b-Motion> "$fn2 $w $b %x %y"
	bind $w <$mod-ButtonRelease-$b> "$fn3 $w $b %x %y"
    }
    bind $w <$mod-Button1-ButtonPress-3> "$fn1 $w 2 0 %x %y"
    bind $w <$mod-Button1-Button3-Motion> "$fn2 $w 2 %x %y"
    bind $w <$mod-Button1-ButtonRelease-3> "$fn3 $w 2 %x %y"
}

proc tdv_sb_func {w what args} {
global tdv_pos tdv_rot tdv_scale tdv_center

    set scale 0.5
    switch $what {
	motion {
	    foreach n {x y z a b c} v $args {
		set $n [expr {$v * $scale}]
	    }

	    set rat [expr {1 - $z * 0.0009}];  # Last number is for scaling
	    if {$rat <= 0.0} {set rat 0.01};  #  Scale increment can't be <= zero
	    foreach i {0 1 2} {lappend nscale [expr {[lindex $tdv_scale($w) $i] * $rat}]}
	    set tdv_scale($w) $nscale

	    set tdv_pos($w) [list [expr {([lindex $tdv_pos($w) 0] + $x) * $rat}] [expr {([lindex $tdv_pos($w) 1] + $y) * $rat}] 0]

	    set len [expr {sqrt($a*$a + $b*$b + $c*$c)}]
	    if {$len != 0.0} {
		set s [expr {sin($len/500)}];  # denominator is for scaling
		set x [expr {$a/$len*$s*-1}]
		set y [expr {$b/$len*$s*-1}]
		set z [expr {$c/$len*$s}]
		set q [expr {cos($len/500)}];  # denominator is for scaling
		set incr "$x $y $z $q"
		set nrot [tdv_qcomp $tdv_rot($w) $incr]
		if {$nrot != "0 0 0 0"} {set tdv_rot($w) $nrot}
	    }

	    $w configure -pos $tdv_pos($w) -rot $tdv_rot($w) -scale $tdv_scale($w) -center $tdv_center($w)
	    $w just_redraw 0
	}

	buttonrelease {
	    switch [lindex $args 0] {
		9 { tdv_scale_to_fit $w 0 }
		10 {tdv_sb_center $w}
		11 {tdv_sb_toggle_solid_display $w}
	    }
	}
    }
}

proc tdv_sb_center {w} {
    global tdv_pos
    set w [tdv_what_window $w]

    set tdv_pos($w) "0 0 [lindex $tdv_pos($w) 2]"
    tdv_trans_update $w
}

proc tdv_sb_toggle_solid_display {w} {
    global env

    # ICEM 5.0 old GUI implementation
    if ![info exists env(ICEM_AI_ENVIRONMENT)] {
    global geom_visible str_option disp_options uns_type_visible
    global str_type_visible scanp prevStyle

    if {[ic_geo_is_loaded] && $geom_visible(surface)} {
	if {$str_option(surface,stype) == "solid" || $str_option(surface,stype) == "flat_wire"} {
	    set prevStyle(geoSolid) $str_option(surface,stype)
	    set str_option(surface,stype) wire
	} else {
	    if ![info exists prevStyle(geoSolid)] {set prevStyle(geoSolid) solid}
	    set str_option(surface,stype) $prevStyle(geoSolid)
	}
	update_geom_visible surface p
    }
    if [ic_uns_is_loaded] {
	set do_mesh_solid 0
	set solid_types {TRI_* QUAD_* HEXA_* TETRA_*	PENTA_* PYRA_*}
	set types_in_mesh [ic_uns_list_types]
	foreach el_type $solid_types {
	    set i [lsearch -glob $types_in_mesh $el_type]
	    if { $i >= 0 && $uns_type_visible([lindex $types_in_mesh $i])} {
		set do_mesh_solid 1
		break
	    }
	}
	if $do_mesh_solid {
	    if {$disp_options(uns_disp) == "Solid/wire" || $disp_options(uns_disp) == "Solid" } {
		set prevStyle(unsSolid) $disp_options(uns_disp)
		if ![info exists prevStyle(unsWire)] {set prevStyle(unsWire) Wire}
		set disp_options(uns_disp) $prevStyle(unsWire)
	    } else {
		set prevStyle(unsWire) $disp_options(uns_disp)
		if ![info exists prevStyle(unsSolid)] {set prevStyle(unsSolid) Solid/wire}
		set disp_options(uns_disp) $prevStyle(unsSolid)
	    }
	    update_uns_disp
	}
    } elseif [ic_str_is_loaded] {
	if $str_type_visible(domain) {
	    if {$str_option(domain,shade) == "flat_wire" || $str_option(domain,shade) == "solid"} {
		set prevStyle(strDomSolid) $str_option(domain,shade)
		if ![info exists prevStyle(strDomWire)] {set prevStyle(strDomWire) wire}
		set str_option(domain,shade) $prevStyle(strDomWire)
	    } else {
		set prevStyle(strDomWire) $str_option(domain,shade)
		if ![info exists prevStyle(strDomSolid)] {set prevStyle(strDomSolid) flat_wire}
		set str_option(domain,shade) $prevStyle(strDomSolid)
	    }
	    disp_set_option domain
	}
	if $str_type_visible(subface) {
	    if {$str_option(subface,shade) == "flat_wire" || $str_option(subface,shade) == "solid"} {
		set prevStyle(strFaceSolid) $str_option(subface,shade)
		if ![info exists prevStyle(strFaceWire)] {set prevStyle(strFaceWire) wire}
		set str_option(subface,shade) $prevStyle(strFaceWire)
	    } else {
		set prevStyle(strFaceWire) $str_option(subface,shade)
		if ![info exists prevStyle(strFaceSolid)] {set prevStyle(strFaceSolid) flat_wire}
		set str_option(subface,shade) $prevStyle(strFaceSolid)
	    }
	    disp_set_option subface
	}
	if {$scanp(visible) && [info exists scanp(cur)]} {
	    if {$scanp(shade) == "flat_wire" || $scanp(shade) == "solid"} {
		set prevStyle(strScanpSolid) $scanp(shade)
		if ![info exists prevStyle(strScanpWire)] {set prevStyle(strScanpWire) wire}
		set scanp(shade) $prevStyle(strScanpWire)
	    } else {
		set prevStyle(strScanpWire) $scanp(shade)
		if ![info exists prevStyle(strScanpSolid)] {set prevStyle(strScanpSolid) flat_wire}
		set scanp(shade) $prevStyle(strScanpSolid)
	    }
	    scanp_set_options
	}
    }
    }

    # ICEM 5.0 new GUI implementation
    if [info exists env(ICEM_AI_ENVIRONMENT)] {
    global aie_SurfStyle aie_geoTypeVis aie_meshTypeVis aie_meshStyle
    global display_flag aie_blockMeshStyle prevStyle

    if {[ic_geo_is_loaded] && $aie_geoTypeVis(surface)} {
	foreach st {solid flat_wire grey_scale} {
	    if $aie_SurfStyle($st) {
		set prevStyle(geoSolid) $st
		set geoStyle wire;	break
	    }
	}
	if ![info exists geoStyle] {
	    if ![info exists prevStyle(geoSolid)] {set prevStyle(geoSolid) solid}
	    set geoStyle $prevStyle(geoSolid)
	}
	set aie_SurfStyle($geoStyle) 1
	aie_changeSurfStyle $geoStyle
    }
    if {[ic_uns_is_loaded] && ($aie_meshTypeVis(shell) || $aie_meshTypeVis(volume))} {
	if {$aie_meshStyle(Solid/wire) || $aie_meshStyle(Solid)} {
	    if $aie_meshStyle(Solid/wire) {set prevStyle(unsSolid) Solid/wire} else {set prevStyle(unsSolid) Solid}
	    if ![info exists prevStyle(unsWire)] {set prevStyle(unsWire) Wire}
	    set meshStyle $prevStyle(unsWire)
	} else {
	    if $aie_meshStyle(Wire) {set prevStyle(unsWire) Wire} else {set prevStyle(unsWire) "Hidden line"}
	    if ![info exists prevStyle(unsSolid)] {set prevStyle(unsSolid) Solid/wire}
	    set meshStyle $prevStyle(unsSolid)
	}
	set aie_meshStyle($meshStyle) 1
	aie_changeMeshDisplay style $meshStyle
    } elseif [ic_str_is_loaded] {
	# This will not be implemented until ICEM 5.1
    }
    if [ic_hex_blocking_loaded] {
	if $display_flag(block) {
	    set display_flag(block_solid) [expr {!$display_flag(block_solid)}]
	    hex_update_display block
	}
	if $display_flag(mesh) {
	    if $aie_blockMeshStyle(2) {set blockMeshStyle 1} else {set blockMeshStyle 2}
	    set aie_blockMeshStyle($blockMeshStyle) 1
	    aie_change_meshstyle $blockMeshStyle
	}
    }
    }
}

proc tdv_sb_start_driver_unix {} {
    global env tdv_start_spaceball
    
    if {[info exists tdv_start_spaceball] && !$tdv_start_spaceball} return
    
    # Return immediately if remote displayed
    if {[info exists env(DISPLAY)] && ($env(DISPLAY) != 0) && \
	![string match 0.* $env(DISPLAY)] && ![string match :0* $env(DISPLAY)] && \
	![string match [info hostname]:* $env(DISPLAY)]} return

    # Check if the spaceball driver is already running
    set 3dxsrv_ps 0
    set xdriver_ps 0
    if [catch {exec ps -e} ret] {return -code error}
    foreach ps [split $ret \n] {
	set psname [lindex $ps end]
	if {$psname == "3dxsrv"} {incr 3dxsrv_ps} \
	elseif {$psname == "xdriver"} {incr xdriver_ps; lappend xd_pids [lindex $ps 0]}
    }

    # If the driver is not running, try to find it first.
    # The spaceball xdriver starts 2 processes called "xdriver"
    # The newer 3dxsrv starts only one process
    set xdriver_need 2
    if  {!$3dxsrv_ps && $xdriver_ps < $xdriver_need} {

	if {$xdriver_ps > 0} {foreach pid $xd_pids {catch {exec kill -9 $pid}}}
	set try_path /etc/3DxWare/daemon
	if [file exists $try_path/3dxsrv] {set 3dxsrv $try_path/3dxsrv}
	set try_path [list /usr/magellan]
	if {[info exists env(HOME)] && $env(HOME) != ""} {lappend try_path $env(HOME)/magellan}
#	eval lappend try_path [split $env(PATH) :]
	lappend try_path ./magellan /magellan
      	foreach path $try_path {
	    if [file exists $path/xdriver] {set xdriver $path/xdriver; break}
	}

	# Could not find driver
	if {![info exists 3dxsrv] && ![info exists xdriver]} {return -code error}

	if [info exists 3dxsrv] {
	    # found the newer driver. Try starting it.
	    # first try to start usb spaceball. If usb fails, try serial connection
	    set ports [list usb]
	    switch $::tcl_platform(os) {
		HP-UX {lappend ports /dev/tty0p0 /dev/tty1p0}
		SunOS {lappend ports /dev/term/a /dev/term/b}
		AIX5 {lappend ports /dev/tty0 /dev/tty1}
		Linux {lappend ports /dev/ttyS0 /dev/ttyS1}
		default {return -code error}
	    }
	    # This is turned off because it takes too long
	    if 0 {
		mess "Starting spaceball 3dxsrv driver\n"
		foreach p $ports {
		    if ![catch {exec $3dxsrv -devOnPort $p}] {
			if ![catch {exec $3dxsrv -d $p &} err] {
			    #It takes about 18 seconds to start the driver.  It 3dxsrv is still running after that, then it was successful.
			    after 20000
			    if {![catch {exec ps -e | grep 3dxsrv} ret] && [llength [split $ret \n]] > 0} {
				# It's running
				return
			    }
			} else {mess $err\n}
			break
		    }
		}
	    } else {
		mess "Please start the Spaceball driver first with:\n\"$3dxsrv -d \[[lindex $ports 0]|[lindex $ports 1]|[lindex $ports 2]\]\"\n"
		return -code error
	    }
	}
	if [info exists xdriver] {
	    # found the older driver. Try starting it.
	    mess "Starting spaceball xdriver\n"
	    if ![catch {exec $xdriver &} err] {
		for {set i 0} {$i < 15} {incr i} {
		    after 1000
		    if [catch {exec ps -e | grep xdriver} ret] break
		    if {[llength [split $ret \n]] >= $xdriver_need} {
			# It's running
			return
		    }
		}
	    } else {mess $err\n}
	}
	# found driver but could not start it
	mess "Could not start spaceball driver\n"
	return -code error
    }
}

proc tdv_sb_copy_config_win {} {
    global env
    set lang en_us
    set config_file ICEMCFD.scg
    if ![file exists $env(ICEM_ACN)/lib/tdv/$config_file] return
    catch {load $env(ICEM_ACN)/bin/tclreg83.dll registry}
    if [catch {registry get HKEY_LOCAL_MACHINE\\software\\3dconnexion\\3dxware {Home Directory}} sz] return
    if {$sz == ""} return
    regsub -all {\\} $sz / sb_home
    set sb_home [string trimright $sb_home /]
    if [file exists $sb_home/$lang/profiles/default/$config_file] return
    cmd_cp $env(ICEM_ACN)/lib/tdv/$config_file $sb_home/$lang/profiles/default/$config_file
}

proc tdv_sb_wb_manage_grab {grab} {
    global sb_has_grab use_workbench

    if {![info exists use_workbench] || !$use_workbench} return
    if ![info exists sb_has_grab] {
	bind . <FocusOut> {+tdv_sb_wb_manage_grab release}
	bind . <FocusIn> {+tdv_sb_wb_manage_grab grab}
	set sb_has_grab 0
    }
	
    if {!$sb_has_grab && $grab == "grab"} {set sb_has_grab [sb_grab]} \
    elseif {$sb_has_grab && $grab == "release"} {
	sb_release_grab
	set sb_has_grab 0
    }
}

proc tdv_wheelzoom {w in {t ""} {X ""} {Y ""}} {
    global tdv_dynamics tdv_x tdv_y tdv_initial_x tdv_initial_y queuetime
    global tdv_mouse_bindings

    # A single threaded process blocks all but the frist and last events
    # that are sent while the thread is busy.  We want to skip the last one.
    # t is received time, not sent time
    if {$t != ""} {
	if ![info exists queuetime] {set queuetime $t} \
	elseif {$t <= ($queuetime+30)} return
    }

    # Wheel events will have X and Y, whereas button events will not
    if {($X != "") && ($Y != "")} {
	if {[info exists tdv_mouse_bindings(wheelactive)] && !$tdv_mouse_bindings(wheelactive)} return
	if {($w == ".") || ([winfo class $w] != "Tdv_Viewer")} {
	    set w [winfo containing $X $Y]
	    if {[catch {winfo class $w} class] || $class != "Tdv_Viewer"} return
	}
	if {$in < -120} {set in -120} \
	elseif {$in > 120} {set in 120}
	if [info exists tdv_mouse_bindings(wheel)] {
	    if ![string is double -strict $tdv_mouse_bindings(wheel)] {
		set tdv_mouse_bindings(wheel) 0
	    }
	    set in [expr {$tdv_mouse_bindings(wheel) * 0.2 * $in}]
	}
    }

    # This makes it look smoother
    set time [time {
	set incr 20
	set loops [ceil [expr {abs([expr {$in / $incr}])}]] ;# see ai_env/init.tcl
	if {$loops <= 0} return
	set inc [expr {$in / $loops}]
	set tdv_dynamics($w) 1
	for {set i 0} {$i < $loops} {incr i} {
	    set tdv_initial_x($w) 0; set tdv_initial_y($w) 0
	    set tdv_x($w) 0; set tdv_y($w) 0
	    tdv_scale $w 0 $inc
	    update idletasks
	}
	catch {unset tdv_dynamics($w)}
    }]

    if {$t != ""} {set queuetime [expr {([lindex $time 0] / 1000.0) + $t}]}
}

proc tdv_motion {w x y} {
    tdv_update_track_mouse $w $x $y

    tdv_track_wb_mouse  $w $x $y
}

proc tdv_update_track_mouse {w {x ""} {y ""}} {
    global tdv_track_mouse_pos tdv_track_mouse_pos_loc
    
    if ![info exists tdv_track_mouse_pos($w)] return
    
    set figs 4
    
    if {$x == "out"} {
	set tdv_track_mouse_pos($w) ""
	return
	
    } elseif {$x == ""} {
	if [info exists tdv_track_mouse_pos_loc($w)] {
	    set x [lindex $tdv_track_mouse_pos_loc($w) 0]
	    set y [lindex $tdv_track_mouse_pos_loc($w) 1]
	} else {
	    return
	}
    }
    set tdv_track_mouse_pos_loc($w) [list $x $y]
    
    set line [$w screen2world $x $y]
    set pos [lindex $line 0]; set vec [lindex $line 1]
    # This shouldn't be here but ...
    set units ""
    if {[info command coords_in_units] != ""} {
	set pos [coords_in_units $pos]
	set units " [lindex $pos 3]"
	set pos [lrange $pos 0 2]
    }
    set d 0
    set n 0
    foreach i {0 1 2} {
	set vv [expr abs([lindex $vec $i])]
	if {$vv > $d} {
	    set d $vv
	    set n $i
	}
    }
    switch $n {
	0 { set str "Y = [format %.${figs}g [lindex $pos 1]],\
		     Z = [format %.${figs}g [lindex $pos 2]]" }
	1 { set str "X = [format %.${figs}g [lindex $pos 0]],\
		     Z = [format %.${figs}g [lindex $pos 2]]" }
	2 { set str "X = [format %.${figs}g [lindex $pos 0]],\
		     Y = [format %.${figs}g [lindex $pos 1]]" }
    }
    set tdv_track_mouse_pos($w) $str$units
}

proc tdv_selection_setloc {w x y} {
    global tdv_setloc_val tdv_setloc_exclude
    
    set pt ""
    if [info exists tdv_setloc_exclude($w)] {
	set pt !$tdv_setloc_exclude($w)
    }
    
    #puts "$w pick $x $y \"\" $pt 10"
    set stuff [$w pick $x $y $pt node 10]
    #puts $stuff
    set pos [lindex $stuff 2]
    if {$pos == ""} {
	mess "Unset location\n"
	set tdv_setloc_val($w) ""
    } else {
	mess "Set location: $pos\n"
	set im [tdv_point_im -point $pos -color green -size 2]
	$w add_image $im
	$w redraw
	$im delete
	set tdv_setloc_val($w) $pos
    }
}

# This has to be separate because it requires the window to be mapped first.

proc tdv_init_2 {w} {
    tdv_cur $w dynamics
    tdv_define_keys $w
    tdv_calc_bbox $w
    tdv_trans_update $w
    $w redraw
}

# This routine changes the cursor for the window, based on the path.
# If the cur argument is not given, then the value of tdv_mode_cursor
# is used instead.

proc tdv_cur {wlist {cur ""} {prev 0} {col orange}} {
    global tdv_cursor_path tdv_cursor_location tdv_mode_cursor tdv_prevcursor
    global is_win
    
    foreach w $wlist {
	set w [tdv_what_window $w]
	
	if {$cur == ""} { set cur $tdv_mode_cursor($w) }
	
	if $prev {
	    set tdv_prevcursor($w) [$w get -cursor]
	}
	
	if $is_win {
	    # Needed for some special cases
	    switch $cur {
		crosshair - wait - center_ptr - icon - arrow {
		    set_cursor $w $cur
		    return
		}
	    }
	}
	
	if ![info exists tdv_cursor_location($cur)] {
	    foreach d $tdv_cursor_path {
		if [file exists $d/$cur.cur] {
		    set tdv_cursor_location($cur) $d/$cur.cur
		    break
		}
	    }
	    if ![info exists tdv_cursor_location($cur)] {
		error "No such cursor \"$cur\""
	    }
	}
	set_cursor $w [list @$tdv_cursor_location($cur) $col]
    }
}

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

# This routine gets called whenever the window changes size.  Its basic
# action is to change the current scale to keep the image in roughtly the
# same relation to the window as before.

proc tdv_win_change {w width height} {
    global tdv_width tdv_height tdv_scale tdv_win_change_command

    if {($tdv_width($w) != $width) || ($tdv_height($w) != $height) && \
	    ($tdv_width($w) > 0) && ($tdv_height($w) > 0)} {
	set wrat [expr {$width / ($tdv_width($w) + 0.0)}]
	set hrat [expr {$height / ($tdv_height($w) + 0.0)}]
	if {$wrat > $hrat} { set rat $hrat } else { set rat $wrat }
	
	set nsc [expr {[lindex $tdv_scale($w) 0] * $rat}]
	set tdv_scale($w) "$nsc $nsc $nsc"
	tdv_trans_update $w 0
    }
    set tdv_width($w) $width
    set tdv_height($w) $height
    
    if [info exists tdv_win_change_command($w)] {
	eval $tdv_win_change_command($w)
    }
}

proc tdv_dyn_reset {w} {
    global tdv_x tdv_y
    set tdv_x($w) 0
    set tdv_y($w) 0
}

# This routine defines all the key bindings for dynamics mode, etc.  The bw
# argument is the window that the bindings are set for, which might be the
# parent window, and the w argument is the viewer window.

proc tdv_define_keys {bw w} {
    global tdv_twod_var display_type host_vendor
    
    set dt unknown; set hv unknown
    if [info exists display_type] { set dt $display_type }
    if [info exists host_vendor] { set hv $host_vendor }
    
    bind $bw <Key-Left>  "tdv_dyn_reset $w; tdv_translate $w -10 0"
    bind $bw <Key-Right> "tdv_dyn_reset $w; tdv_translate $w 10 0"
    bind $bw <Key-Up>    "tdv_dyn_reset $w; tdv_translate $w 0 -10"
    bind $bw <Key-Down>  "tdv_dyn_reset $w; tdv_translate $w 0 10"
    bind $bw <Key-Prior> "tdv_dyn_reset $w; tdv_scale $w 0 -10"
    bind $bw <Key-Next>  "tdv_dyn_reset $w; tdv_scale $w 0 10"
    
    bind $bw <Shift-Key-Left>  "tdv_dyn_reset $w; tdv_translate $w -50 0"
    bind $bw <Shift-Key-Right> "tdv_dyn_reset $w; tdv_translate $w 50 0"
    bind $bw <Shift-Key-Up>    "tdv_dyn_reset $w; tdv_translate $w 0 -50"
    bind $bw <Shift-Key-Down>  "tdv_dyn_reset $w; tdv_translate $w 0 50"
    bind $bw <Shift-Key-Prior> "tdv_dyn_reset $w; tdv_scale $w -50 0"
    bind $bw <Shift-Key-Next>  "tdv_dyn_reset $w; tdv_scale $w 50 0"
    
    if !$tdv_twod_var($w) {
	catch {
	    bind $bw <Key-KP_Left>  "tdv_dyn_reset $w; tdv_rotate $w -10 0"
	    bind $bw <Key-KP_Right> "tdv_dyn_reset $w; tdv_rotate $w 10 0"
	    bind $bw <Key-KP_Up>    "tdv_dyn_reset $w; tdv_rotate $w 0 -10"
	    bind $bw <Key-KP_Down>  "tdv_dyn_reset $w; tdv_rotate $w 0 10"
	    bind $bw <Shift-Key-KP_Left> \
		    "tdv_dyn_reset; tdv_rotate $w -50 0"
	    bind $bw <Shift-Key-KP_Right> \
		    "tdv_dyn_reset; tdv_rotate $w 50 0"
	    bind $bw <Shift-Key-KP_Up> \
		    "tdv_dyn_reset; tdv_rotate $w 0 -50"
	    bind $bw <Shift-Key-KP_Down> \
		    "tdv_dyn_reset; tdv_rotate $w 0 50"
	    
	    bind $bw <Key-KP_4> "tdv_dyn_reset $w; tdv_rotate $w -50 0"
	    bind $bw <Key-KP_6> "tdv_dyn_reset $w; tdv_rotate $w 50 0"
	    bind $bw <Key-KP_8> "tdv_dyn_reset $w; tdv_rotate $w 0 -50"
	    bind $bw <Key-KP_2> "tdv_dyn_reset $w; tdv_rotate $w 0 50"
	    
	}
    }
    
    # There should be a better way to do this one.
    bind $bw <Key-F7> "tdv_modify_zoff $w 0.1"
    bind $bw <Key-F8> "tdv_modify_zoff $w -0.1"
    bind $bw <Shift-Key-F7> "tdv_modify_zoff $w 1"
    bind $bw <Shift-Key-F8> "tdv_modify_zoff $w -1"
    bind $bw <Control-Key-F7> "tdv_modify_zoff $w 0.01"
    bind $bw <Control-Key-F8> "tdv_modify_zoff $w -0.01"
    bind $bw <Key-F6> "tdv_set_zoff $w 0"
    bind $bw <Key-F5> "tdv_set_zoff $w toggle_largest"
}

# This gets called to change the Z offset of the viewer.

proc tdv_modify_zoff {w factor} {
    set zoff [$w get -zoff]
    if {$zoff == 0} { set zoff 1e-4 }
    set zoff [expr {$zoff + $factor * 0.01}]
    tdv_set_zoff $w $zoff
}

proc tdv_set_zoff {w zval} {
    set w [tdv_what_window $w]
    if {$zval == "toggle_largest"} {
	if [$w get -offset_uses_largest] {
	    $w configure -offset_uses_largest 0
	    tdv_mess "Z offset is now based on the smallest model dimension\n"
	} else {
	    $w configure -offset_uses_largest 1
	    tdv_mess "Z offset is now based on the largest model dimension\n"
	}
	$w redraw
	return
    }
    $w configure -zoff $zval
    $w redraw
    tdv_mess "Z offset is $zval of total Z range\n"
}

# Mouse stuff.  ---------------------------------------------

proc tdv_obtain_line {wlist {nice 0}} {
    global tdv_waiting_for_click tdv_last_viewer_clicked
    
    foreach w $wlist {
	tdv_cancel_rubbox $w
	set w [tdv_what_window $w]
	set pcursor($w) [$w get -cursor]
	tdv_cur $w pick
	set tdv_waiting_for_click($w) 1
    }
    tkwait variable tdv_waiting_for_click
    set vv $tdv_last_viewer_clicked
    if ![info exists tdv_waiting_for_click($vv)] { return "" }
    if {[lindex $tdv_waiting_for_click($vv) 0] == 1} {
	set cmd screen2world
	if $nice { append cmd _nice }
	set line [eval $vv $cmd [lrange $tdv_waiting_for_click($vv) 1 end]]
    } else {
	set line ""
    }
    
    foreach w $wlist {
	unset tdv_waiting_for_click($w)
	$w configure -cursor $pcursor($w)
    }
    return $line
}

proc tdv_obtain_screen_pos {wlist} {
    global tdv_waiting_for_click tdv_obtain_screen_pos_button
    global tdv_last_viewer_clicked
    
    foreach w $wlist {
	tdv_cancel_rubbox $w
    }
    set tdv_obtain_screen_pos_button ""
    foreach w $wlist {
	set pcursor($w) [$w get -cursor]
	tdv_cur $w pick
	set tdv_waiting_for_click($w) 1
    }
    tkwait variable tdv_waiting_for_click
    set vv $tdv_last_viewer_clicked
    if ![info exists tdv_waiting_for_click($vv)] { return "" }
    if {[lindex $tdv_waiting_for_click($vv) 0] == 1} {
	set pos [lrange $tdv_waiting_for_click($vv) 1 end]
    } else {
	set tdv_obtain_screen_pos_button [lindex $tdv_waiting_for_click($vv) 0]
	set pos ""
    }
    
    foreach w $wlist {
	unset tdv_waiting_for_click($w)
	$w configure -cursor $pcursor($w)
    }
    return $pos
}

proc tdv_trans_update {w {redraw 1}} {
    global tdv_pos tdv_rot tdv_scale tdv_center tdv_nonuniform_scale tdv_follow_trans
    
    set mscale "1 1 1"
    if [info exists tdv_nonuniform_scale] {
        set mscale ""
        foreach i {0 1 2} {
	        if {$tdv_nonuniform_scale($i) != ""} {
		        lappend mscale $tdv_nonuniform_scale($i)
	        } else {
		        lappend mscale 1
	        }
	    }
    }
    $w configure -pos $tdv_pos($w) -rot $tdv_rot($w) -scale $tdv_scale($w) -center $tdv_center($w) -mscale $mscale
    
    if $redraw {
       $w just_redraw 0
       tdv_update_track_mouse $w
    }
    if [info exist tdv_follow_trans($w)] {
       set in [$w get -in_dynamics]
       foreach v $tdv_follow_trans($w) {
          set tdv_pos($v)  $tdv_pos($w)
          set tdv_rot($v)  $tdv_rot($w)
          set tdv_scale($v) $tdv_scale($w)
          set tdv_center($v) $tdv_center($w)
          $v configure -pos $tdv_pos($v) -rot $tdv_rot($v) -scale $tdv_scale($v) -center $tdv_center($w) -mscale $mscale -in_dynamics $in
          if $redraw { $v just_redraw 0 }
       }
    }
}


proc tdv_save_position {w} {
    global tdv_pos tdv_rot tdv_scale tdv_center tdv_nonuniform_scale
    
    return [list pos $tdv_pos($w) rot $tdv_rot($w) scale $tdv_scale($w) \
		center $tdv_center($w)]
}

proc tdv_load_position {w pos} {
    foreach {t v} $pos {
	global tdv_$t
	set tdv_${t}($w) $v
    }
    tdv_trans_update $w
}

proc tdv_temporary_dynamics {w} {
    global tdv_temporary_dynamics_cursor
    global tdv_click_function tdv_waiting_for_click tdv_waiting_for_motion
    
    if {([array names tdv_click_function] == "") && \
	    ([array names tdv_waiting_for_click] == "") && \
	    ([array names tdv_waiting_for_motion] == "")} return
    
    if [info exists tdv_temporary_dynamics_cursor($w)] {
	tdv_cur $w $tdv_temporary_dynamics_cursor($w)
	unset tdv_temporary_dynamics_cursor($w)
    } else {
	set fn [string trimleft [lindex [$w get -cursor] 0] @]
	set tdv_temporary_dynamics_cursor($w) [file tail [file rootname $fn]]
	tdv_cur $w dynamics
    }
}

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

proc tdv_begin_op {w but x y curfile {change_cur 1} {device mouse}} {
    global tdv_x tdv_y tdv_prevcursor tdv_dynamics tdv_click_function
    global tdv_waiting_for_click tdv_no_redraw_ms
    global tdv_temporary_dynamics_cursor tdv_center
    global tdv_initial_x tdv_initial_y tdv_current_op tdv_end_op_after
    global tdv_dynamics_speed_thresh tdv_last_viewer_clicked
    global select_in_dynamics tdv_waiting_for_rubbox_click
    global tdv_mouse_active tdv_sb_active tdv_enable_smooth_move 

    switch $device {
        sb {set tdv_sb_active 1}
        mouse {set tdv_mouse_active 1}
    }

    tdv_set_last_viewer_clicked $w
    
    if [info exists tdv_end_op_after($w)] {
        after cancel $tdv_end_op_after($w)
        unset tdv_end_op_after($w)
    }
    
    if {$device != "sb"} {
	    switch $curfile {
	        trans - trans_delay { set tdv_current_op($w) translate; set cent 0 }
	        scale - scale_delay { set tdv_current_op($w) scale;     set cent 1  }
	        rot   - rot_delay   { set tdv_current_op($w) rotate;    set cent 1  }
            wb_rot   { set tdv_current_op($w) rotate;    set cent 1  }
            wb_roll  { set tdv_current_op($w) wb_roll; set cent 0  }
            wb_pitch { set tdv_current_op($w) wb_pitch; set cent 0  }
            wb_yaw   { set tdv_current_op($w) wb_yaw;   set cent 0  }
	    }
	    if ![info exists tdv_temporary_dynamics_cursor($w)] {
	        if [info exists tdv_click_function($w,$but)] {
		        eval $tdv_click_function($w,$but) $w $but $x $y
		        return
	        }
	        # This one is different because we have to be able to do zoom
	        # in temporary dynamics mode.  In that case we are also waiting for
	        # a click for selection in a higher-level loop.  Ideally the waiting for click stuff
	        # would be a stack.
	        if [info exists tdv_waiting_for_rubbox_click($w)] {
		        if [catch {set tdv_waiting_for_rubbox_click($w) "$but $x $y"} res] {
			        puts "ERROR $res"
		        }
		        catch {unset tdv_x($w)}
		        return
	        }
	        if {!([info exists select_in_dynamics] && ($select_in_dynamics))} {
		        if [info exists tdv_waiting_for_click($w)] {
		            if [catch {set tdv_waiting_for_click($w) "$but $x $y"} res] {
			            puts "ERROR $res"
		            }
		            catch {unset tdv_x($w)}
		            return
		        }
	        }
	    }

	    set tdv_x($w) $x
	    set tdv_y($w) $y
	    set tdv_initial_x($w) $x
	    set tdv_initial_y($w) $y
    }
    
    global tdv_counting
    set tdv_counting($w) 0
    set tdv_dynamics($w) 1

    set tdv_prevcursor($w) [$w get -cursor]
    if $change_cur {tdv_cur $w $curfile}

    if ![$w get -in_dynamics] {
        if {![info exists tdv_enable_smooth_move] || $tdv_enable_smooth_move != 1} {
	        set max_sp $tdv_dynamics_speed_thresh
            if {$max_sp >= 0} {
                if {[$w get -last_speed] > $max_sp} {
                    $w configure -in_dynamics 2
                } else {
                    $w configure -in_dynamics 1
                }
            }
        }
    }

    if [info exists tdv_enable_smooth_move] {
        if {$device != "sb" && $cent && $tdv_enable_smooth_move != 1} {
	        catch {
	            set cpt [$w get_3d_oglpt $x $y 0]
	            if {$cpt != ""} {
		            tdv_set_center $w [lrange $cpt 0 2]
		        }
	        }
	    }
    } else {
        if {$device != "sb" && $cent} {
	        catch {
	            set cpt [$w get_3d_oglpt $x $y 0]
	            if {$cpt != ""} {
		            tdv_set_center $w [lrange $cpt 0 2]
		        }
	        }
	    }
    }
    if [info exists tdv_enable_smooth_move] {
        if {$tdv_enable_smooth_move != 1} {
            update idletasks
        }
    } else {
        update idletasks
    }
}

proc tdv_end_op_reset {w {m 0}} {
    global tdv_follow_trans tdv_enable_smooth_move 

    set red [$w cget -in_dynamics]
    $w configure -in_dynamics 0
    if {$red == 2} {
        if [info exists tdv_enable_smooth_move] {
            if {$tdv_enable_smooth_move != 1} {
	            $w redraw
	        }
	    } else {
            $w redraw
        }
    }
    if [info exist tdv_follow_trans($w)] {
	    foreach v $tdv_follow_trans($w) {
	        set red [$v cget -in_dynamics]
	        $v configure -in_dynamics 0
	        if {$red == 2} {
	            if [info exists tdv_enable_smooth_move] {
	                if {$tdv_enable_smooth_move != 1} {
	                    $v redraw
	                }
	            } else {
	                $v redraw
	            }
	        }
	    }
    }
    if $m {
        if [info exists tdv_enable_smooth_move] {
            if {$tdv_enable_smooth_move != 1} {
                update idletasks
            }
        } else {
            update idletasks
        }
    }
}

proc tdv_smooth_move_double_click {w x y} {
    global tdv_enable_smooth_move
    if {![info exists tdv_enable_smooth_move] || $tdv_enable_smooth_move == 0} return
    catch {
        busy 1
        set cpt [$w get_3d_oglpt $x $y 0]
	    if {$cpt != ""} {
		    tdv_set_center $w [lrange $cpt 0 2]
		}
		busy reset
    }
}

proc tdv_end_op {w {device mouse}} {
    global tdv_prevcursor tdv_waiting_for_motion tdv_dynamics
    global tdv_temporary_dynamics_cursor tdv_end_op_after tdv_end_function
    global tdv_waiting_for_click
    global select_in_dynamics
    global tdv_mouse_active tdv_sb_active

    switch $device {
	    sb {catch {unset tdv_sb_active}}
	    mouse {catch {unset tdv_mouse_active}}
    }
    if {[info exists tdv_mouse_active] || [info exists tdv_sb_active]} return

    if [info exists tdv_end_function($w)] {
	    eval $tdv_end_function($w) $w
	    return
    }
    
    if {![info exists tdv_temporary_dynamics_cursor($w)] && \
	    [info exists tdv_waiting_for_motion($w)]} {
	    set tdv_waiting_for_motion($w) ""
	    return
    }
    
    if {!([info exists select_in_dynamics] && ($select_in_dynamics))} {
	    if [info exists tdv_waiting_for_click($w)] return
    }
    
    if {[info exists tdv_dynamics($w)] && !$tdv_dynamics($w)} {
	    $w configure -active 1
    }
    catch {unset tdv_dynamics($w)}
    
    set m 0
    if [info exists tdv_prevcursor($w)] {
	    $w configure -cursor $tdv_prevcursor($w)
	    unset tdv_prevcursor($w)
        set m 1
    }
    
    if ![info exists tdv_end_op_after($w)] {
	    set tdv_end_op_after($w) [after 500 "tdv_end_op_reset $w $m"]
        # time should be configurable
    }
}

proc tdv_doit_op {w x y} {
    global tdv_current_op tdv_motion_function

    if [info exists tdv_motion_function($w)] {
	    eval $tdv_motion_function($w) $w $x $y 
	    return
    }
    
    if ![info exists tdv_current_op($w)] {
	    return
    }
    
    #tdv_motion $w $x $y
    tdv_$tdv_current_op($w) $w $x $y

    global tdv_no_redraw_ms tdv_dynamics tdv_counting
    set tm [$w get -last_speed]
    if {$tdv_no_redraw_ms && ($tm > $tdv_no_redraw_ms)} {
       set mskip [expr ($tm / $tdv_no_redraw_ms)*10]
       set ns [expr $tdv_counting($w) % $mskip]
       if {$ns == 0} {
          $w configure -active 1
          set tdv_dynamics($w) 1
       } else {
          $w configure -active 0
         # set curfile ${curfile}_delay
          set tdv_dynamics($w) 0
       }
       incr tdv_counting($w)
    }
}

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

proc tdv_translate {w x y} {
    global tdv_pos tdv_x tdv_y tdv_waiting_for_motion tdv_dynamics
    global tdv_temporary_dynamics_cursor tdv_click_function
    
    if ![info exists tdv_temporary_dynamics_cursor($w)] {
        if [info exists tdv_waiting_for_motion($w)] {
            set tdv_waiting_for_motion($w) "$x $y"
            return
        }
        if [info exists tdv_click_function($w,2)] return
    }
    if {![info exists tdv_dynamics($w)] || ![info exists tdv_x($w)]} return     
    set tdv_pos($w) [list [expr {[lindex $tdv_pos($w) 0] + $x - $tdv_x($w)}] [expr {[lindex $tdv_pos($w) 1] - $y + $tdv_y($w)}] 0]
    set tdv_x($w) $x
    set tdv_y($w) $y
    tdv_trans_update $w
}

proc tdv_rotate {w x y} {
    global tdv_rot tdv_x tdv_y tdv_waiting_for_motion tdv_dynamics
    global tdv_temporary_dynamics_cursor tdv_click_function

    if ![info exists tdv_temporary_dynamics_cursor($w)] {
	if [info exists tdv_waiting_for_motion($w)] {
	    set tdv_waiting_for_motion($w) "$x $y"
	    return
	}
	if [info exists tdv_click_function($w,1)] return
    }
    if {![info exists tdv_dynamics($w)] || ![info exists tdv_x($w)]} return
    set incr [$w getscreenrot $x $tdv_y($w) 0 $tdv_x($w) $y 0]
    if {$incr == "0 0 0 0"} return

    set ng 0
    foreach r $incr {
       if ![string is double -strict $r] {incr ng}
    }
    if {$ng > 0} {
       mess "get $incr from $w getscreenrot $x $tdv_y($w) 0 $tdv_x($w) $y 0\n" red
       return
    }

    set nrot [tdv_qcomp $tdv_rot($w) $incr]
    if {$nrot == "0 0 0 0"} return
    
    set tdv_rot($w) $nrot
    set tdv_x($w) $x
    set tdv_y($w) $y
    
    tdv_trans_update $w
}

proc tdv_rotate_axis {w x y z t} {
    global tdv_rot
    set incr [$w getaxisrot $x $y $z $t]
    if {$incr == "0 0 0 0"} return
    set nrot [tdv_qcomp $tdv_rot($w) $incr]
    if {$nrot == "0 0 0 0"} return
    set tdv_rot($w) $nrot
}

proc tdv_scale {w x y} {
    global tdv_scale tdv_pos tdv_rot tdv_height tdv_x tdv_y
    global tdv_waiting_for_motion tdv_dynamics tdv_twod_var
    global tdv_temporary_dynamics_cursor tdv_click_function
    global tdv_initial_x tdv_initial_y tdv_scale_backwards
    global tdv_mouse_bindings
    
    set backw [expr {([info exists tdv_scale_backwards] || \
			  ($tdv_mouse_bindings(scale_dir) < 0))} ? -1 : 1]
    
    if ![info exists tdv_temporary_dynamics_cursor($w)] {
	if [info exists tdv_waiting_for_motion($w)] {
	    set tdv_waiting_for_motion($w) "$x $y"
	    return
	}
	if [info exists tdv_click_function($w,3)] return
    }
    if {![info exists tdv_dynamics($w)] || ![info exists tdv_x($w)]} return
    
    set sx $tdv_x($w)
    set sy $tdv_y($w)

    set dx [expr {abs($sx - $x)}]
    set dy [expr {abs($sy - $y)}]
    set tdx [expr {abs($tdv_initial_x($w) - $x)}]
    
    if {$dy > $dx} {
        # work for twod --- {$tdv_twod_var($w) || ($dy > $dx)}
	set rat [expr {1 + ($sy - $y) * $backw / ($tdv_height($w) + 0.0)}]
	set nscale {}
	foreach i {0 1 2} {
	    lappend nscale [expr {[lindex $tdv_scale($w) $i] * $rat}]
	}
	set tdv_scale($w) $nscale
	set tdv_pos($w) [list [expr {[lindex $tdv_pos($w) 0] * $rat}] \
		              [expr {[lindex $tdv_pos($w) 1] * $rat}] 0]
    } elseif {$tdx > 10} {
	set incr [$w getscreenrot 0 0 $x 0 0 $sx]
	if {$incr == "0 0 0 0"} return
	set nrot [tdv_qcomp $tdv_rot($w) $incr]
	if {$nrot == "0 0 0 0"} return
	set tdv_rot($w) $nrot
    }
    set tdv_x($w) $x
    set tdv_y($w) $y

    tdv_trans_update $w
}

# Multiply two quarternions.

proc tdv_qcomp {qt1 qt2} {
    set x1 [lindex $qt1 0]
    set y1 [lindex $qt1 1]
    set z1 [lindex $qt1 2]
    set q1 [lindex $qt1 3]

    set x2 [lindex $qt2 0]
    set y2 [lindex $qt2 1]
    set z2 [lindex $qt2 2]
    set q2 [lindex $qt2 3]
    
    set x3 [expr {$x2 * $q1 + $x1 * $q2 - $z1 * $y2 + $z2 * $y1}]
    set y3 [expr {$y2 * $q1 + $y1 * $q2 - $z2 * $x1 + $z1 * $x2}]
    set z3 [expr {$z2 * $q1 + $z1 * $q2 - $y1 * $x2 + $x1 * $y2}]
    set q3 [expr {$q1 * $q2 - $x1 * $x2 - $y1 * $y2 - $z1 * $z2}]
    
    set qt3 "$x3 $y3 $z3 $q3"
    
    if {!$x3 && !$y3 && !$z3 && !$q3} {
	puts "NULL quaternion: qt1 $qt1 qt2 $qt2"
    }

    return $qt3
}

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

proc tdv_begin_anno_move {w x y} {
    global tdv_picked_axes tdv_x tdv_y tdv_prevcursor tdv_axes 
    global cmap_image cmap_picked_image tdv_date tdv_title tdv_angled_text
    global tdv_picked_date tdv_picked_title tdv_picked_angled_text
    global tdv_picked_app_anno tdv_default
        
    set tdv_x($w) $x
    set tdv_y($w) $y

    set proc tdv_app_pick_annotation
    if {[info command $proc] != ""} {
	set im [$proc $w $x $y]
	if {$im != ""} {
	    set tdv_picked_app_anno($w) $im
	    return
	}
    }
    
    # This is a totally bogus way to do this.
    if {[info exists tdv_axes($w)] && ([$w pick $x $y $tdv_axes($w) none 15] != "")} {
	set tdv_picked_axes($w) $tdv_axes($w)
	tdv_cur $w point_move 1
	return 1
    } elseif {[info exists cmap_image($w)] && ([$cmap_image($w) pick $x $y] != "")} {
	set cmap_picked_image($w) $cmap_image($w)
	tdv_cur $w point_move 1
	return 1
    } elseif {[info exists tdv_date($w)] && ([$w pick $x $y $tdv_date($w) none 5] != "")} {
	set tdv_picked_date($w) $tdv_date($w)
	tdv_cur $w point_move 1
	return 1
    } elseif {[info exists tdv_title($w)] && ([$w pick $x $y $tdv_title($w) none 5] != "")} {
	set tdv_picked_title($w) $tdv_title($w)
	tdv_cur $w point_move 1
	return 1
    }
    return 0
}

proc tdv_anno_move {w x y} {
    global tdv_picked_axes cmap_picked_image tdv_x tdv_y
    global tdv_picked_date tdv_picked_title tdv_picked_app_anno
    
    if ![info exists tdv_x($w)] return
    
    set proc tdv_app_move_annotation
    if {[info exists tdv_picked_app_anno($w)] && ([info command $proc] != "")} {
	$proc $tdv_picked_app_anno($w) $w $tdv_x($w) $tdv_y($w) $x $y
	set tdv_x($w) $x
	set tdv_y($w) $y
	$w redraw
	return
    }
    
    if [info exists tdv_picked_axes($w)] {
	set pos [$tdv_picked_axes($w) get -pos]
	set nx [expr {[lindex $pos 0] - $tdv_x($w) + $x}]
	set ny [expr {[lindex $pos 1] + $tdv_y($w) - $y}]
	set tdv_x($w) $x
	set tdv_y($w) $y
	$tdv_picked_axes($w) configure -pos "$nx $ny 0"
	$w redraw
    } elseif [info exists cmap_picked_image($w)] {
	set pos [$cmap_picked_image($w) get -pos]
	set nx [expr {[lindex $pos 0] - $tdv_x($w) + $x}]
	set ny [expr {[lindex $pos 1] - $tdv_y($w) + $y}]
	set tdv_x($w) $x
	set tdv_y($w) $y
	$cmap_picked_image($w) configure -pos "$nx $ny 0"
	$w redraw
    } elseif [info exists tdv_picked_title($w)] {
	set pos [$tdv_picked_title($w) get -point]
	set nx [expr {[lindex $pos 0] - $tdv_x($w) + $x}]
	set ny [expr {[lindex $pos 1] + $tdv_y($w) - $y}]
	set tdv_x($w) $x
	set tdv_y($w) $y
	$tdv_picked_title($w) configure -point "$nx $ny 0"
	$w redraw
    } elseif [info exists tdv_picked_date($w)] {
	set pos [$tdv_picked_date($w) get -pos]
	set nx [expr {[lindex $pos 0] - $tdv_x($w) + $x}]
	set ny [expr {[lindex $pos 1] + $tdv_y($w) - $y}]
	set tdv_x($w) $x
	set tdv_y($w) $y
	$tdv_picked_date($w) configure -pos "$nx $ny 0"
	$w redraw
    }
}

proc tdv_end_anno_move {w} {
    global tdv_picked_axes cmap_picked_image tdv_prevcursor
    global tdv_picked_date tdv_picked_title tdv_picked_app_anno
    
    set proc tdv_app_release_annotation
    if {[info exists tdv_picked_app_anno($w)] && ([info command $proc] != "")} {
	$proc $tdv_picked_app_anno($w) $w
    }
    if [info exists tdv_prevcursor($w)] {
	catch {unset tdv_picked_axes($w)}
	catch {unset cmap_picked_image($w)}
	catch {unset tdv_picked_date($w)}
	catch {unset tdv_picked_title($w)}
	catch {unset tdv_picked_app_anno($w)}
	
	$w configure -cursor $tdv_prevcursor($w)
	unset tdv_prevcursor($w)
	update idletasks
    }
}

proc tdv_begin_anno_edit {w x y} {
    global cmap_picked_image cmap_image_entry tdv_x tdv_y
    global cmap_image_pixels cmap_image tdv_prevcursor
    
    set tdv_x($w) $x
    set tdv_y($w) $y
    
    if [info exists cmap_image($w)] {
	set pick [$cmap_image($w) pick $x $y]
	if {$pick == ""} { return 0 }
	set cmap_image_entry($w) [lindex $pick 0]
	set cmap_image_pixels($w) [lindex $pick 1]
	set cmap_picked_image($w) $cmap_image($w)
	set tdv_prevcursor($w) [$w get -cursor]
	tdv_cur $w point_edit
	return 1
    }
    return 0
}

proc tdv_anno_edit {w x y} {
    global cmap_image_entry cmap_picked_image
    global tdv_x tdv_y cmap_image_pixels
    
    if [info exists cmap_picked_image($w)] {
	cmap_drag $w $cmap_picked_image($w) $cmap_image_entry($w) $tdv_y($w) \
	    $y $cmap_image_pixels($w)
	$w redraw
    }
    
    set tdv_x($w) $x
    set tdv_y($w) $y
}

proc tdv_end_anno_edit {w} {
    global cmap_picked_image tdv_prevcursor
    
    if [info exists tdv_prevcursor($w)] {
	catch {unset cmap_picked_image($w)}
	$w configure -cursor $tdv_prevcursor($w)
	unset tdv_prevcursor($w)
	update idletasks
    }
}

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

set tdv_shift_on 0

proc tdv_do_select {w button double x y} {
    global tdv_pickable_tags tdv_setloc_val tdv_shift_on
    global tdv_interact_only_shape tdv_do_select_last
    
    #puts "tdv_do_select $w $button $double $x $y shift $tdv_shift_on"
    
    if !$tdv_shift_on {
	switch $button {
	    1 { tdv_begin_op $w 1 $x $y rot }
	    2 { tdv_begin_op $w 2 $x $y trans }
	    3 { tdv_begin_op $w 3 $x $y scale }
	}
	return
    }
    
    set tags ""
    if [info exists tdv_pickable_tags($w)] { set tags $tdv_pickable_tags($w) }
    
    if [info exists tdv_interact_only_shape] {
	foreach sh $tdv_interact_only_shape {
	    $w add_tag $sh interact_only_shape
	}
	set tags interact_only_shape
    }
    
    set tdv_setloc_val($w) ""
    
    set close 0
    set tags_all $tags
    if [info exists tdv_do_select_last($w)] {
	# This is to support multiple-clicking to select objects on top of
	# each other.
	set lastxy [lrange [lindex $tdv_do_select_last($w) 0] 0 1]
	if {$lastxy != ""} {
	    set lx [lindex $lastxy 0]; set ly [lindex $lastxy 1]
	    set dist [expr sqrt(($x - $lx) * ($x - $lx) + \
				    ($y - $ly) * ($y - $ly))]
	    if {$dist < 5} {
		foreach last $tdv_do_select_last($w) {
		    set im [lindex $last 2]
		    lappend tags !$im
		}
		set close 1
	    }
	}
	if !$close { unset tdv_do_select_last($w) }
    }
    
    #puts "$w pick $x $y $tags \"\" 10"
    #foreach t $tags { puts "with tag $t : [$w list_with_tag $t]" }
    set stuff [$w pick $x $y $tags "" 10]
    #puts $stuff
    if {$close && ($stuff == "")} {
	set stuff [$w pick $x $y $tags_all "" 10]
	set tdv_do_select_last($w) ""
    }
    set pos [lindex [$w screen2world $x $y] 0]
    
    set button [tdv_select_translate_button_number $button]
    
    if {$stuff != ""} {
	lappend tdv_do_select_last($w) [list $x $y [lindex $stuff 0] \
					    [lindex $stuff 1]] 
	tdv_select_action $w $button $double [lindex $stuff 0] \
		[lindex $stuff 1] [lindex $stuff 2] $pos $x $y
    } else {
	tdv_select_action $w $button $double {} {} {} $pos $x $y
    }
}

proc tdv_do_move {w button x y} {
    global tdv_shift_on tdv_button_map

    if [info exists tdv_button_map($button)] {
	set button $tdv_button_map($button)
    }
    
    if !$tdv_shift_on {
	switch $button {
	    1 { tdv_rotate $w $x $y }
	    2 { tdv_translate $w $x $y }
	    3 { tdv_scale $w $x $y }
	}
	return
    }
    
    tdv_motion $w $x $y
    
    set pos [lindex [$w screen2world $x $y] 0]
    set button [tdv_select_translate_button_number $button]
    tdv_move_action $w $button $pos $x $y
}

# what_mod: 1 == shift, 2 == control

proc tdv_do_release {w button x y {what_mod 1}} {
    global tdv_shift_on

    if !$tdv_shift_on {
	switch $button {
	    1 { tdv_end_op $w }
	    2 { tdv_end_op $w }
	    3 { tdv_end_op $w }
	}
	return
    }
    
    set pos [lindex [$w screen2world $x $y] 0]
    set button [tdv_select_translate_button_number $button]
    tdv_release_action $w $button $pos $x $y $what_mod
}

proc tdv_select_translate_button_number {n} {
    global tdv_mouse_bindings
    foreach op {select done cancel} n2 {1 2 3} {
	if {$tdv_mouse_bindings($op) == $n} {
	    return $n2
	}
    }
}

# Various view commands.  -----------------------------------------------

proc tdv_home_init {w {dir ""}} {
   global tdv_home_direction tdv_home_init_win

   if {$dir != ""} {set tdv_home_direction($w) $dir}

   if [info exist tdv_home_init_win] {
      return 1
   } else {
      set tdv_home_init_win $w
      tdv_home_init_recur
      tkwait variable tdv_home_init_win
      unset tdv_home_init_win
      return 0
   }
}

proc tdv_home_init_recur {} {
   global tdv_home_init_win

   if [winfo ismapped $tdv_home_init_win] {
      tdv_home $tdv_home_init_win
      set tdv_home_init_win ""
   } else {
      after 50 {tdv_home_init_recur}
   }
}

proc tdv_redraw {w} {
    $w redraw
}

proc tdv_maxview {w} {
    set w [tdv_what_window $w]
    
    set bbox [$w bbox interesting]
    if {$bbox == ""} return
    set dd 0; set dir ""; set dm ""
    foreach {m c} {0 -x 1 -y 2 -z} {
	set d [expr [lindex [lindex $bbox 1] $m] \
		   - [lindex [lindex $bbox 0] $m]]
	set dd [expr $dd + $d * $d]
	if {($dm == "") || ($d < $dm)} {set dm $d; set dir $c}
    }
    
    if {$dm > 0.2588 * sqrt($dd)} {
	tdv_isoview $w
    } else {
	tdv_home $w $dir
    }
}

proc tdv_home {w {what_dir ""}} {
    global tdv_home_direction tdv_home_is_iso tdv_default
    
    set dim [tdv_get_win_dim $w]
    if {$dim == 1} { 
       if {[info command OneDWin::cmd] != ""} {
            OneDWin::cmd $w home_fit
       }
       return ""
    }

    if [info exists tdv_home_is_iso] {
	tdv_isoview $w
	return
    }
    
    set w [tdv_what_window $w]
    
    if {$what_dir == ""} {
	if [info exists tdv_home_direction($w)] {
	    set what_dir $tdv_home_direction($w)
	} elseif {[info exist tdv_default] && \
                  [info exist tdv_home_direction($tdv_default)]} {
	    set what_dir $tdv_home_direction($tdv_default)
	} else {
            set what_dir -z
        }
    }
    tdv_along_axis $w $what_dir
    tdv_trans_update $w 0
    tdv_calc_bbox $w
    tdv_trans_update $w
    
    tdv_toggle_origin $w
}

proc tdv_isoview {w} {
    global tdv_rot tdv_home_direction tdv_default
    
    set w [tdv_what_window $w]
    
    if [info exists tdv_home_direction($w)] {
	set dir $tdv_home_direction($w)
    } elseif {[info exist tdv_default] && \
                  [info exist tdv_home_direction($tdv_default)]} {
	set dir $tdv_home_direction($tdv_default)
    } else {
	set dir -z
    }
    
    switch -- $dir {
	-z {
	    # Y direction up.
	    set tdv_rot($w) {0 0 0 1}
	    tdv_rotate_axis $w 0 1 0 [expr {3.1415926 / 4}]
	    tdv_rotate_axis $w 1 0 0 [expr {-3.1415926 / 4}]
	}
	+y {
	    # Z direction up.
	    set tdv_rot($w) {0 0 0 1}
	    tdv_rotate_axis $w 0 0 1 [expr {-3.1415926 / 4}]
	    tdv_rotate_axis $w 1 0 0 [expr {3 * 3.1415926 / 4}]
	}
    }
    tdv_trans_update $w 0
    tdv_calc_bbox $w
    tdv_trans_update $w
}

proc tdv_three_points {w p1 p2 p3} {
    global tdv_rot
    set tdv_rot($w) [$w getplanerot $p1 $p2 $p3]
    tdv_trans_update $w
}

proc tdv_reverse {w} {
    global tdv_rot
    set w [tdv_what_window $w]
    tdv_rotate_axis $w 0 1 0 3.1415926
    tdv_trans_update $w
}

proc tdv_nearest_axis {w} {
    set w [tdv_what_window $w]
    set vec [lindex [$w screen2world 0 0] 1]
    set m 0
    if {abs([lindex $vec 1]) > abs([lindex $vec 0])} { set m 1 }
    if {abs([lindex $vec 2]) > abs([lindex $vec $m])} { set m 2 }
    if {[lindex $vec 2] > 0} { set s - } else { set s + }
    tdv_along_axis $w $s[lindex {x y z} $m]
}

proc tdv_view_direction {w} {
    global tdv_center tdv_rot
    
    set pt [question "Center point?" [$w get -center]]
    if {$pt == ""} return
    set dir [question "Direction?" "0 0 1"]
    if {$dir == ""} return
    tdv_view_point_direction $w $pt $dir
}

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

proc tdv_save_current_orientation {w} {
    global tdv_pos tdv_rot tdv_scale tdv_center
    
    set w [tdv_what_window $w]
    set orient [list $tdv_pos($w) $tdv_rot($w) $tdv_scale($w) $tdv_center($w)]
   
    for {set i 1} {[command_check_exists "View $i"]} {incr i} {}
    set name [question "Name for new viewing position?" "View $i"]
    if {$name == ""} return
    
    tdv_add_user_view $name $orient
}

proc tdv_add_user_view {name orient} {
    global tdv_user_views
    
    set replace [command_check_exists "User view: $name"]
    
    set ents [command_get_menu_entries Orient]
    if {$ents == ""} return
    
    if {[lsearch $ents separator] < 0} {
	command_add_to_menu Orient separator
    }
    
    command_define "User view: $name" $name no_icon \
	"tdv_set_current_orientation current $orient" {
	} no_help always
    
    if !$replace {
	command_add_to_menu Orient [list [list "User view: $name"]]
    }
    lappend tdv_user_views [list $name $orient]
}

proc tdv_set_current_orientation {w pos rot scale center} {
    set w [tdv_what_window $w]
    foreach v {pos rot scale center} {
	global tdv_$v
	set tdv_${v}($w) [set $v]
    }
    tdv_trans_update $w
}

proc tdv_clear_user_views {} {
    global tdv_user_views
    set ents [command_get_menu_entries Orient]
    set del 0
    set nents ""
    foreach e $ents {
	if {$e == "separator"} { set del 1 }
	if !$del { lappend nents $e }
    }
    command_reset_menu Orient $nents
    foreach v $tdv_user_views {
	set name "User view: [lindex $v 0]"
	command_delete $name
    }
    set tdv_user_views ""
}

proc tdv_reset_user_views {} {
    global tdv_user_views
    set uvs $tdv_user_views
    tdv_clear_user_views
    foreach uv $uvs {
	tdv_add_user_view [lindex $uv 0] [lindex $uv 1]
    }
}

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

proc tdv_view_point_direction {w pt dir} {
    global tdv_center tdv_rot
    
    set tdv_rot($w) [$w getvecrot $dir]
    set tdv_center($w) $pt
    tdv_trans_update $w
}

proc tdv_changebg {w {col ""}} {
    set w [tdv_what_window $w]
    
    if {$col == ""} {
	set ocol [$w get -background]
	set col [edit_one_color "Select the new background color." $ocol]
	if {$col == "*cancel*"} return
    }
    $w configure -background $col
    $w redraw
}

proc tdv_getbg {w} {
    set w [tdv_what_window $w]
    return [$w get -background]
}

proc tdv_scale_to_fit {w {show_mes 1}} {
    set w [tdv_what_window $w]
    set dim [tdv_get_win_dim $w]
    if {$dim == 1} {
	    if {[info command OneDWin::cmd] != ""} {
	        OneDWin::cmd $w home_fit
	    }
    } else {
	    tdv_calc_bbox $w
	    tdv_trans_update $w
	    tdv_toggle_origin $w
	
	    if $show_mes {   
	        set bbox [$w bbox visible]
	        set val min
	        foreach v $bbox {
	            foreach num $v {
	                if {![string is double $num] && ![string is integer $num]} {
	                    tdv_mess "Expected floating-point number for $val value but got \"$v\"\n"
	                    return
	                }
	            }
	            set val max
	        }
	        if {$bbox == ""} {
		        tdv_mess "Nothing visible\n"
	        } else {
		        tdv_mess "Visible images:\n"
		        tdv_mess "    min: [eval format \"%g %g %g\" [lindex $bbox 0]]\n"
		        tdv_mess "    max: [eval format \"%g %g %g\" [lindex $bbox 1]]\n"
		        set bbox [$w bbox interesting]
		        if {$bbox != ""} {
		            tdv_mess "Data objects:\n"
		            tdv_mess "    min: [eval format \"%g %g %g\" [lindex $bbox 0]]\n"
		            tdv_mess "    max: [eval format \"%g %g %g\" [lindex $bbox 1]]\n"
		        }
	        }
	    }
    }
}

proc tdv_rotate_screen_y {w} {
    set w [tdv_what_window $w]
    tdv_rotate_axis $w 0 1 0 1.57075 ;# pi/2 about the Y axis
    tdv_scale_to_fit $w
}

proc tdv_rotate_screen_z {w} {
    set w [tdv_what_window $w]
    tdv_rotate_axis $w 0 0 1 1.57075 ;# pi/2 about the Y axis
    tdv_scale_to_fit $w
}

proc tdv_calc_bbox {w} {
    global tdv_pos tdv_rot tdv_scale tdv_center
    global tdv_height tdv_width tdv_home_shrink
    
    set bbox [$w bbox interesting]
    if {$bbox == ""} return
    if {$bbox == ""} {set bbox {{-1 -1 -1} {1 1 1}}}
    
    tdv_toggle_origin $w
    
    set lo [lindex $bbox 0]
    set hi [lindex $bbox 1]
    set centroid {}
    foreach i {0 1 2} {
        if {(![string is double -strict [lindex $lo $i]] && ![string is integer -strict [lindex $lo $i]]) || \
            (![string is double -strict [lindex $hi $i]] && ![string is integer -strict [lindex $hi $i]])} return
	lappend centroid [expr {([format %g [lindex $lo $i]] + [format %g [lindex $hi $i]]) / 2.0}]
    }
    set tdv_scale($w) "1 1 1"
    set tdv_center($w) "0 0 0"
    $w configure -scale $tdv_scale($w) -center $tdv_center($w)
    
    set mm [tdv_get_screen_minmax $w $bbox]
    foreach i {0 1 2 3} { set [lindex {minx maxx miny maxy} $i] [lindex $mm $i] }
    set centx [expr {($minx + $maxx) / 2.0}]
    set centy [expr {($miny + $maxy) / 2.0}]
    $w configure -pos "[expr -$centx] $centy 0"
    set mm [tdv_get_screen_minmax $w $bbox]
    foreach i {0 1 2 3} { set [lindex {minx maxx miny maxy} $i] [lindex $mm $i] }
    
    set diffx [expr {$maxx - $minx}]; if {$diffx == 0.0} { set diffx 1 }
    set diffy [expr {$maxy - $miny}]; if {$diffy == 0.0} { set diffy 1 }

    if ![info exist tdv_home_shrink] {set tdv_home_shrink 0.95}
    set xrat [expr {($tdv_width($w) * $tdv_home_shrink) / ($diffx + 0.0)}]
    set yrat [expr {($tdv_height($w) * $tdv_home_shrink) / ($diffy + 0.0)}]
    if {$xrat < $yrat} { set rat $xrat } else { set rat $yrat }
    set sc [expr {$rat * [lindex $tdv_scale($w) 0]}]
    if {$sc == 0.0} { set sc 0.0001 }

    set tdv_scale($w) "$sc $sc $sc"
    set tdv_pos($w) "0 0 0"
    set tdv_center($w) $centroid
}

proc tdv_get_screen_minmax {w bbox} {
    set minx ""; set miny ""; set maxx ""; set maxy ""
    foreach ii {
	{0 0 0} {0 0 1} {0 1 0} {0 1 1}
	{1 0 0} {1 0 1} {1 1 0} {1 1 1}
    } {
	set pt {}
	foreach i {0 1 2} {
	    lappend pt [lindex [lindex $bbox [lindex $ii $i]] $i]
	}
	set sp [eval $w world2screen $pt]
	#puts "PT $pt -> $sp"
	set x [lindex $sp 0]; set y [lindex $sp 1]
	
	if {($minx == "") || ($x < $minx)} { set minx $x }
	if {($maxx == "") || ($x > $maxx)} { set maxx $x }
	if {($miny == "") || ($y < $miny)} { set miny $y }
	if {($maxy == "") || ($y > $maxy)} { set maxy $y }
    }
    return [list $minx $maxx $miny $maxy]
}

proc tdv_get_centroid {w} {
    set bbox [$w bbox interesting]
    if {$bbox == ""} {set bbox {{-1 -1 -1} {1 1 1}}}
    
    set lo [lindex $bbox 0]
    set hi [lindex $bbox 1]

    set centroid {}
    foreach i {0 1 2} {
	lappend centroid [expr {([lindex $lo $i] + [lindex $hi $i]) / 2.0}]
    }
    return $centroid
}

proc tdv_get_diameter {w} {
    set bbox [$w bbox interesting]
    if {$bbox == ""} {set bbox {{-1 -1 -1} {1 1 1}}}
    
    set lo [lindex $bbox 0]
    set hi [lindex $bbox 1]

    set tot 0.0
    foreach i {0 1 2} {
	set d [expr {[lindex $hi $i] - [lindex $lo $i]}]
	set tot [expr $tot + $d * $d]
    }
    return [expr sqrt($tot)]
}

proc tdv_along_axis {w axis} {
    set w [tdv_what_window $w]
    tdv_axis $w $axis
    tdv_trans_update $w
}

proc tdv_align_axes {w} {
   global tdv_pos tdv_rot tdv_scale tdv_center
 
   set tdv_rot($w) [$w align_axes 0]
   tdv_trans_update $w
}

proc tdv_axis {w axis} {
    global tdv_pos tdv_rot tdv_scale tdv_center
    global tdv_home_direction tdv_default
    
    if [info exists tdv_home_direction($w)] {
	set what_dir $tdv_home_direction($w)
    } elseif {[info exist tdv_default] && \
                  [info exist tdv_home_direction($tdv_default)]} {
	set what_dir $tdv_home_direction($tdv_default)
    } else {
	set what_dir -z
    }
    if {$what_dir == "+y"} { set zup 1 } else { set zup 0 }

    set tdv_rot($w) {0 0 0 1}
    set pi 3.1415926
    set pi2 [expr {$pi / 2.0}]
    case $axis in {
	+x {
	    tdv_rotate_axis $w 0 1 0 -$pi2
	    if $zup {
		tdv_rotate_axis $w 0 0 1 -$pi2
	    }
	}
	-x {
	    tdv_rotate_axis $w 0 1 0 $pi2
	    if $zup {
		tdv_rotate_axis $w 0 0 1 $pi2
	    }
	}
	+y {
	    tdv_rotate_axis $w 1 0 0 $pi2
	}
	-y {
	    tdv_rotate_axis $w 1 0 0 -$pi2
	    tdv_rotate_axis $w 0 0 1 $pi
	}
	+z {tdv_rotate_axis $w 0 1 0 $pi}
	-z {}
    }
}

proc tdv_set_center {w cent} {
    global tdv_center tdv_pos
    
    # Figure out where the old center is on the screen, and where the new
    # one is.  Then add the difference to the position.
    set op [eval $w world2screen $tdv_center($w)]
    set np [eval $w world2screen $cent]
    
    set x [expr {[lindex $tdv_pos($w) 0] + [lindex $np 0] - [lindex $op 0]}]
    set y [expr {[lindex $tdv_pos($w) 1] - [lindex $np 1] + [lindex $op 1]}]
    set z [lindex $tdv_pos($w) 2]
    set tdv_pos($w) "$x $y $z"
    set tdv_center($w) $cent
}

# Routines to handle checkbutton options.  --------------------------------

proc tdv_toggle_axes {w {v ""}} {
    global tdv_axes_var tdv_axes tdv_twod_var tdv_color
    global small_screen_hack

    if ![info exists tdv_axes_var($w)] return
    
    if {$v != ""} { set tdv_axes_var($w) $v }
    
    if {$w == "all"} {
        foreach w [array names tdv_axes_var] {
            if [winfo exists $w] {
                tdv_toggle_axes $w $tdv_axes_var(all)
            }
        }
        return
    }
    if $small_screen_hack {
        set pos "40 40 0"; set size 30
    } else {
        set pos "80 80 0"; set size 60
    }
    set size -15 ;# make it 1/15 of the screen size
    
    if {$tdv_axes_var($w) && ![info exists tdv_axes($w)]} {
        set tdv_axes($w) [tdv_axes_im -pos $pos -transform 0 -size $size -y_dir_up 1 -twod $tdv_twod_var($w)]
        $w add_image $tdv_axes($w)
        $w add_tag $tdv_axes($w) anno_pickable
    } elseif {!$tdv_axes_var($w) && [info exists tdv_axes($w)]} {
        $tdv_axes($w) delete
        unset tdv_axes($w)
    }
    if {[info exists tdv_axes($w)] && [info exists tdv_color(axes)]} { 
        $tdv_axes($w) configure -color $tdv_color(axes)
    }
}

proc tdv_toggle_two_d_grid {w {v ""}} {
    global tdv_two_d_grid_var tdv_two_d_grid tdv_two_d_grid_start
    global tdv_two_d_grid_incr tdv_color
    
    if ![info exists tdv_two_d_grid_var($w)] return
    
    if {$v != ""} { set tdv_two_d_grid_var($w) $v }
    
    if {$w == "all"} {
	foreach w [array names tdv_two_d_grid_var] {
	    if [winfo exists $w] {
		tdv_toggle_two_d_grid $w $tdv_two_d_grid_var(all)
	    }
	}
	return
    }
    
    if {$tdv_two_d_grid_var($w) && ![info exists tdv_two_d_grid($w)]} {
	set tdv_two_d_grid($w) [tdv_two_d_grid_im -color \#443333]
	$w add_image $tdv_two_d_grid($w)
    } elseif {!$tdv_two_d_grid_var($w) && [info exists tdv_two_d_grid($w)]} {
	$tdv_two_d_grid($w) delete
	unset tdv_two_d_grid($w)
    }
    if [info exists tdv_two_d_grid($w)] {
	if [info exists tdv_color(two_d_grid)] { 
	    $tdv_two_d_grid($w) configure -color $tdv_color(two_d_grid)
	}
	
	if [info exists tdv_two_d_grid_incr($w)] {
	    set incr $tdv_two_d_grid_incr($w)
	} elseif [info exists tdv_two_d_grid_incr(all)] {
	    set incr $tdv_two_d_grid_incr(all)
	} else {
	    set incr "1 1 1"
	}
	if [info exists tdv_two_d_grid_start($w)] {
	    set start $tdv_two_d_grid_start($w)
	} elseif [info exists tdv_two_d_grid_start(all)] {
	    set start $tdv_two_d_grid_start(all)
	} else {
	    set start "0 0 0"
	}
	$tdv_two_d_grid($w) configure -start $start -incr $incr
    }
}

proc tdv_toggle_twod {w {v ""}} {
    global tdv_twod_var tdv_axes

    if {$v != ""} { set tdv_twod_var($w) $v }
    
    if ![info exists tdv_twod_var($w)] return
    
    if [info exists tdv_axes($w)] {
	$tdv_axes($w) configure -twod $tdv_twod_var($w)
    }
    tdv_along_axis $w -z
    tdv_dynamics_bindings $w
}

proc tdv_toggle_rulers {w {v ""}} {
    global tdv_rulers tdv_rulers_var
    
    if ![info exists tdv_rulers_var($w)] return
    
    if {$v != ""} { set tdv_rulers_var($w) $v }
    
    if {$w == "all"} {
	foreach w [array names tdv_rulers_var] {
	    if [winfo exists $w] {
		tdv_toggle_rulers $w $tdv_rulers_var(all)
	    }
	}
	return
    }
    
    if {$tdv_rulers_var($w) && ![info exists tdv_rulers($w)]} {
	set tdv_rulers($w) [tdv_rulers_im]
	
	# This is a work-a-round since we shouldn't know about this variable ...
	global unit_data unit_default
	if {[info exists unit_default(length)] && \
		[info exists unit_data($unit_default(length))]} {
	    eval tdv_set_ruler_units $w \
		[lrange $unit_data($unit_default(length)) 0 2] \
		\"$unit_default(length)\"
	}
	
	$w add_image $tdv_rulers($w)
    } elseif {!$tdv_rulers_var($w) && [info exists tdv_rulers($w)]} {
	$tdv_rulers($w) delete
	unset tdv_rulers($w)
    }
}

proc tdv_set_ruler_units {w y0 c x0 name} {
    global tdv_rulers
    
    if [info exists tdv_rulers($w)] {
	$tdv_rulers($w) configure -unit_y0 $y0 -unit_c $c -unit_x0 $x0 \
	    -unit_name $name
    }
}

proc tdv_lowerleft_ypos {w} {
    set maxy -5
    foreach {var pvar} {date pos title point track_mouse point} {
	global tdv_$var
	
	if [info exists tdv_${var}($w)] {
	    set y [lindex [[set tdv_${var}($w)] cget -$pvar] 1]
	    if {$y > $maxy} { set maxy $y }
	}
    }
    return [expr $maxy + 12]
}

proc tdv_toggle_date {w {v ""}} {
    global tdv_date tdv_height graph_color
    global tdv_saved_date_position tdv_date_var
    
    if ![info exists tdv_date_var($w)] return

    if {$v != ""} { set tdv_date_var($w) $v }
    
    if {$w == "all"} {
	foreach w [array names tdv_date_var] {
	    if [winfo exists $w] {
		tdv_toggle_date $w $tdv_date_var(all)
	    }
	}
	return
    }
    
    if [info exists tdv_date($w)] {
	set tdv_saved_date_position($w) [$tdv_date($w) get -pos]
	$tdv_date($w) delete
	unset tdv_date($w)
    }
    
    set color white
    if [info exists graph_color(date)] {
	set color $graph_color(date)
    }
    
    if $tdv_date_var($w) {
	if [info exists tdv_saved_date_position($w)] {
	    set x [lindex $tdv_saved_date_position($w) 0]
	    set y [lindex $tdv_saved_date_position($w) 1]
	} else {
	    set x 5
	    set y [tdv_lowerleft_ypos $w]
	}
	set tdv_date($w) [tdv_date_im -pos "$x $y 0" -transform 0 \
			      -y_dir_up 1 -color $color]
	$w add_image $tdv_date($w)
	$w add_tag $tdv_date($w) anno_pickable
    }
}

proc tdv_toggle_title {w {v ""}} {
    global tdv_title tdv_height tdv_title_string
    global tdv_saved_title_position tdv_title_var
    global graph_color
    
    if {$v != ""} { set tdv_title_var($w) $v }
    
    if {$w == "all"} {
	foreach w [array names tdv_title_var] {
	    if [winfo exists $w] {
		tdv_toggle_title $w $tdv_title_var(all)
	    }
	}
	return
    }
    
    if [info exists tdv_title($w)] {
	set tdv_saved_title_position($w) [$tdv_title($w) get -point]
	$tdv_title($w) delete
	unset tdv_title($w)
    }
    
    set color white
    if [info exists graph_color(title)] {
	set color $graph_color(title)
    }
    
    if $tdv_title_var($w)  {
	if [info exists tdv_saved_title_position($w)] {
	    set x [lindex $tdv_saved_title_position($w) 0]
	    set y [lindex $tdv_saved_title_position($w) 1]
	} else {
	    set x 5
	    set y [tdv_lowerleft_ypos $w]
	}
	set tdv_title($w) [tdv_text_im -point "$x $y 0" -y_dir_up 1 \
		-transform 0 -text $tdv_title_string($w) -color $color]
	$w add_image $tdv_title($w)
	$w add_tag $tdv_title($w) anno_pickable
    }
}

proc tdv_toggle_track_mouse {w {v ""}} {
    global tdv_track_mouse tdv_height tdv_track_mouse_string
    global tdv_saved_track_mouse_position tdv_track_mouse_var
    global graph_color tdv_track_mouse_pos
    
    if {$v != ""} { set tdv_track_mouse_var($w) $v }
    
    if {$w == "all"} {
	foreach w [array names tdv_track_mouse_var] {
	    if [winfo exists $w] {
		tdv_toggle_track_mouse $w $tdv_track_mouse_var(all)
	    }
	}
	return
    }
    
    if [info exists tdv_track_mouse($w)] {
	set tdv_saved_track_mouse_position($w) [$tdv_track_mouse($w) get -point]
	$tdv_track_mouse($w) delete
	unset tdv_track_mouse($w)
	unset tdv_track_mouse_pos($w)
    }
    
    set color white
    if [info exists graph_color(title)] {
	set color $graph_color(title)
    }
    
    if $tdv_track_mouse_var($w) {
	if [info exists tdv_saved_track_mouse_position($w)] {
	    set x [lindex $tdv_saved_track_mouse_position($w) 0]
	    set y [lindex $tdv_saved_track_mouse_position($w) 1]
	} else {
	    set x 5
	    set y [tdv_lowerleft_ypos $w]
	}
	set tdv_track_mouse($w) [tdv_text_im -point "$x $y 0" \
		-transform 0 -y_dir_up 1 -text "" -color $color]
	$w add_image $tdv_track_mouse($w)
	$w add_tag $tdv_track_mouse($w) anno_pickable
	set tdv_track_mouse_pos($w) ""
	trace variable tdv_track_mouse_pos($w) w \
	    "$tdv_track_mouse($w) configure -text \
		\"\$tdv_track_mouse_pos($w)\"; list"
    }
}

# This function will toggle the string tdv_angled_text_string and draw
# it at theta degrees clockwise

proc tdv_toggle_angled_text {w theta {v ""}} {
    global tdv_angled_text tdv_height tdv_angled_text_string
    global tdv_saved_angled_text_position tdv_angled_text_var
    
    if {$v != ""} { set tdv_angled_text_var($w) $v }
    
    if {$tdv_angled_text_var($w) && ![info exists tdv_angled_text($w)]} {
	if [info exists tdv_saved_angled_text_position($w)] {
	    set x [lindex $tdv_saved_angled_text_position($w) 0]
	    set y [lindex $tdv_saved_angled_text_position($w) 1]
	} else {
	    set x 10
	    set y [expr {$tdv_height($w) - 5}]
	}
	set tdv_angled_text($w) [tdv_angled_text_im -point "$x $y 0" \
		-transform 0 -angle $theta -text $tdv_angled_text_string($w)]
	$w add_image $tdv_angled_text($w)
	$w add_tag $tdv_angled_text($w) anno_pickable
	
    } elseif {!$tdv_angled_text_var($w) && [info exists tdv_angled_text($w)]} {
	set saved_angled_text_position($w) [$tdv_angled_text($w) get -pos]
	$tdv_angled_text($w) delete
	unset tdv_angled_text($w)
    
    } elseif {[info exists tdv_angled_text($w)] && \
		  [string compare [$tdv_angled_text($w) get -text] \
		       $tdv_angled_text_string($w)]} {
	$tdv_angled_text($w) configure -text $tdv_angled_text_string($w)
    }
}

proc tdv_toggle_origin {w {v ""}} {
    global tdv_origin_var
    
    if {$v != ""} { set tdv_origin_var($w) $v }
    
    if {$w == "all"} {
	foreach w [array names tdv_origin_var] {
	    if [winfo exists $w] {
		tdv_toggle_origin $w $tdv_origin_var(all)
	    }
	}
	return
    }
    
    $w delete_with_tag origin
    if !$tdv_origin_var($w) return
    
    # Use the middle dimension so that the origin marker size is 
    # always constant proportion in 2-D (view plane) - Ganesan
    set bbox [$w bbox interesting]
    if {$bbox == ""} {set bbox {{-1 -1 -1} {1 1 1}}}
    foreach i {0 1 2} {
	lappend d [expr abs([lindex [lindex $bbox 1] $i] - \
				[lindex [lindex $bbox 0] $i])]
    }
    set ss [expr [lindex [lsort $d] 1] / 100.0]

    set l1 [tdv_line_im -point1 "$ss 0 0" -point2 "-$ss 0 0" \
		    -color red -interesting 0 -pickable 0]
    set l2 [tdv_line_im -point1 "0 $ss 0" -point2 "0 -$ss 0" \
		-color green -interesting 0 -pickable 0]
    set l3 [tdv_line_im -point1 "0 0 $ss" -point2 "0 0 -$ss" \
	    -color blue -interesting 0 -pickable 0]
    
    foreach i {1 2 3} {
	$w add_image [set l$i]
	$w add_tag [set l$i] origin
    }
}

proc tdv_toggle_dbuffer {w {v ""}} {
    global tdv_dbuffer_var
    
    if {$v != ""} { set tdv_dbuffer_var($w) $v }
    
    $w configure -dbuffer $tdv_dbuffer_var($w)
    $w redraw
}

proc tdv_toggle_hiddenline {w {v ""}} {
    global tdv_hiddenline_var
    
    if {$v != ""} { set tdv_hiddenline_var($w) $v }
    
    $w configure -hiddenline $tdv_hiddenline_var($w) \
	    -xhidden $tdv_hiddenline_var($w)
    $w redraw
}

proc tdv_toggle_directlight {w {v ""}} {
    global tdv_directlight_var
    
    if {$v != ""} { set tdv_directlight_var($w) $v }
    
    $w configure -directlight $tdv_directlight_var($w)
    $w redraw
}

proc tdv_toggle_xgouraud {w {v ""}} {
    global tdv_xgouraud_var
    
    if {$v != ""} { set tdv_xgouraud_var($w) $v }
    
    $w configure -xgouraud $tdv_xgouraud_var($w)
    $w redraw
}

proc tdv_toggle_depthcue {w {v ""}} {
    global tdv_depthcue_var
    
    if {$v != ""} { set tdv_depthcue_var($w) $v }
    
    if {$w == "all"} {
	foreach w [array names tdv_depthcue_var] {
	    if [winfo exists $w] {
		tdv_toggle_depthcue $w $tdv_depthcue_var(all)
	    }
	}
	return
    }
    
    if $tdv_depthcue_var($w) {
	$w configure -depth "0 1"
    } else {
	$w configure -depth {}
    }
    $w redraw
}

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

proc tdv_set_last_viewer_clicked {w} {
    global tdv_last_viewer_clicked tdv_highlight_frame
    
    if {[info exists tdv_last_viewer_clicked] && [info exists tdv_highlight_frame($tdv_last_viewer_clicked)]} {
        $tdv_highlight_frame($tdv_last_viewer_clicked) configure -bg #d9d9d9
    }
    set tdv_last_viewer_clicked $w
    if {[info exists tdv_highlight_frame($w)]} {
        $tdv_highlight_frame($w) configure -bg red
    }
}

proc tdv_what_window {w} {
    global tdv_last_viewer_clicked tdv_default
    if {$w == "current"} {
	if {[info exists tdv_last_viewer_clicked] && \
		[winfo exists $tdv_last_viewer_clicked] && \
		[winfo ismapped $tdv_last_viewer_clicked]}  {
	    return $tdv_last_viewer_clicked
	} else {
	    return $tdv_default
	} 
    } else {
	return $w
    }
}

proc tdv_zoomout {w} {

    set w [tdv_what_window $w]

    # Somebody might hold down the z key while zooming and cause auto-repeat.
    # If so ignore the command.
    if {[info exists tdv_waiting_for_click($w)] || \
            [info exists tdv_waiting_for_motion($w)]} return

    banner "Select the zoom OUT region with the left button." $w
    set stuff [tdv_get_rubbox $w]
    banner "" $w

    set p1 [lindex $stuff 0]
    set p2 [lindex $stuff 1]

    set dim [tdv_get_win_dim $w]
    if {$dim == 1} {
       if {[info command OneDWin::cmd] != ""} {
          OneDWin::cmd $w zoomout_axes $p1 $p2
       }
       return $dim
    } else {
  #    tdv_calc_bbox $w

       global tdv_scale tdv_pos

       set ww [winfo width $w]
       set hh [winfo height $w]
       set wr [expr double([lindex $p2 0] - [lindex $p1 0])/$ww]
       set hr [expr double([lindex $p2 1] - [lindex $p1 1])/$hh]
       set sr $wr
       if {$hr > $sr} {set sr $hr}
       set s [expr $sr * [lindex $tdv_scale($w) 0]]
       set tdv_scale($w) "$s $s $s"

       set dw [expr ([lindex $p2 0] + [lindex $p1 0] - $ww)/2]
       set dh [expr ($hh - [lindex $p2 1] - [lindex $p1 1])/2]
       set x0 [expr [lindex $tdv_pos($w) 0]*$sr + $dw]
       set y0 [expr [lindex $tdv_pos($w) 1]*$sr + $dh]

       set tdv_pos($w) "$x0 $y0 [lindex $tdv_pos($w) 2]"

       tdv_trans_update $w
    }
}


proc tdv_zoomin {w} {
    global tdv_zoomin_box_loc
    global tdv_waiting_for_click tdv_waiting_for_motion
    global tdv_scale tdv_pos tdv_width tdv_height tdv_center

    set w [tdv_what_window $w]

    # Somebody might hold down the z key while zooming and cause auto-repeat.
    # If so ignore the command.
    if {[info exists tdv_waiting_for_click($w)] || \
            [info exists tdv_waiting_for_motion($w)]} return ""

    banner "Select the zoom region with the left button." $w
    set stuff [tdv_get_rubbox $w]
    banner "" $w
 
    set p1 [lindex $stuff 0]
    set p2 [lindex $stuff 1]

    set tdv_zoomin_box_loc($w)  $stuff

    if {($p1 == "") || ($p2 == "")} {return ""}

    tdv_zoomin_do $w
}

proc tdv_zoomin_do {w} {
    global tdv_zoomin_box_loc
    global tdv_scale tdv_pos tdv_width tdv_height tdv_center

    if {![info exist tdv_zoomin_box_loc($w)] || \
               ($tdv_zoomin_box_loc($w) == "")} {return ""}

    set p1 [lindex $tdv_zoomin_box_loc($w) 0]
    set p2 [lindex $tdv_zoomin_box_loc($w) 1]
    unset tdv_zoomin_box_loc($w)

    set dim [tdv_get_win_dim $w]
    if {$dim == 1} {
       if {[info command OneDWin::cmd] != ""} {
          OneDWin::cmd $w zoomin_plots $p1 $p2
       }
       return $dim
    }

    set bw [expr {[lindex $p1 0] - [lindex $p2 0]}]
    set bh [expr {[lindex $p1 1] - [lindex $p2 1]}]
    if {$bw < 0} {set bw [expr -$bw]}
    if {$bh < 0} {set bh [expr -$bh]}
    if {!$bw || !$bh} { tdv_mess "No box drawn\n" red; return }
    
    set s1 [lindex [eval $w screen2world $p1] 0]
    set s2 [lindex [eval $w screen2world $p2] 0]
    set m ""; foreach s $s1 { lappend m [format %g $s] }
    tdv_mess "Zoom point 1: $m\n"
    set m ""; foreach s $s2 { lappend m [format %g $s] }
    tdv_mess "Zoom point 2: $m\n"
    
    set cent [$w screen2world [expr {([lindex $p1 0] + [lindex $p2 0]) / 2}] \
	      [expr {([lindex $p1 1] + [lindex $p2 1]) / 2}]]
    
    set wrat [expr {$tdv_width($w) / ($bw + 0.0)}]
    set hrat [expr {$tdv_height($w) / ($bh + 0.0)}]
    if {$wrat < $hrat} {set rat $wrat} {set rat $hrat}

    set nsc [expr {[lindex $tdv_scale($w) 0] * $rat * 0.95}]
    
    set tdv_scale($w) "$nsc $nsc $nsc"
    $w configure -scale $tdv_scale($w) -pos "0 0 0"
    
    set c1 [eval $w world2screen [lindex $cent 0]]
    set c2 [eval $w world2screen $tdv_center($w)]
    
    set tdv_pos($w) [list [expr {[lindex $c2 0] - [lindex $c1 0]}] \
	    [expr {-([lindex $c2 1] - [lindex $c1 1])}] 0]
    
    tdv_trans_update $w
}

proc tdv_scale_to_box {w lo hi pct} {
    global tdv_pos tdv_rot tdv_scale tdv_center
    global tdv_height tdv_width
    
#puts "bb $lo $hi"
    tdv_toggle_origin $w
    
    set centroid {}
    foreach i {0 1 2} {
	lappend centroid [expr {([lindex $lo $i] + [lindex $hi $i]) / 2.0}]
    }
#puts "cent $centroid"
    set tdv_scale($w) "1 1 1"
    set tdv_center($w) "0 0 0"
    $w configure -scale $tdv_scale($w) -center $tdv_center($w)
    
    set mm [tdv_get_screen_minmax $w [list $lo $hi]]
#puts "mm $mm"
    foreach i {0 1 2 3} { set [lindex {minx maxx miny maxy} $i] [lindex $mm $i] }
    set centx [expr {($minx + $maxx) / 2.0}]
    set centy [expr {($miny + $maxy) / 2.0}]
    $w configure -pos "[expr -$centx] $centy 0"
    set mm [tdv_get_screen_minmax $w [list $lo $hi]]
    foreach i {0 1 2 3} { set [lindex {minx maxx miny maxy} $i] [lindex $mm $i] }
    
    set diffx [expr {$maxx - $minx}]; if {$diffx == 0.0} { set diffx 1 }
    set diffy [expr {$maxy - $miny}]; if {$diffy == 0.0} { set diffy 1 }
#puts "diffx $diffx diffy $diffy"
    set xrat [expr {($tdv_width($w) * 0.95) / ($diffx + 0.0)}]
    set yrat [expr {($tdv_height($w) * 0.95) / ($diffy + 0.0)}]
    if {$xrat < $yrat} { set rat $xrat } else { set rat $yrat }
#puts "xrat $xrat yrat $yrat"
    set sc [expr {$rat * [lindex $tdv_scale($w) 0] / $pct}]
#puts "sc $sc"
    if {$sc == 0.0} { set sc 0.0001 }

    set tdv_scale($w) "$sc $sc $sc"
    set tdv_pos($w) "0 0 0"
    set tdv_center($w) $centroid
    tdv_trans_update $w
}

set tdv_rubbox_overlay [expr ![info exists env(ICEM_NO_OVERLAY)]]

proc tdv_get_rubbox {w} {
    global tdv_waiting_for_rubbox_click tdv_waiting_for_motion
    global tdv_scale tdv_pos tdv_width tdv_height is_win tdv_rubbox_overlay
    
    tdv_cur $w zoomin
    
    set bb [busy 0]
    
    # This is a work-a-round
    if {[bind $w <Button-1>] == ""} {
    	bind $w <Button-1> "set tdv_waiting_for_rubbox_click($w) \"1 %x %y\""
	bind $w <ButtonRelease-1> "set tdv_waiting_for_motion($w) \"\""
	bind $w <B1-Motion> "set tdv_waiting_for_motion($w) \"%x %y\""
        set empty_but1_binding [list <Button-1> <ButtonRelease-1> <B1-Motion>]
    }
    
    set tdv_waiting_for_rubbox_click($w) 1
    tkwait variable tdv_waiting_for_rubbox_click($w)
    if {![info exists tdv_waiting_for_rubbox_click($w)] ||
	([lindex $tdv_waiting_for_rubbox_click($w) 0] != 1)} {
	catch {unset tdv_waiting_for_rubbox_click($w)}
	tdv_cur $w dynamics
	busy $bb
	return ""
    }
    set p1 [lrange $tdv_waiting_for_rubbox_click($w) 1 end]
    unset tdv_waiting_for_rubbox_click($w)
    set tdv_waiting_for_motion($w) 1

    set over $tdv_rubbox_overlay
    if [$w cget -use_grad_bg] {set over 0}

    while 1 {
	tkwait variable tdv_waiting_for_motion($w)

	if {$tdv_waiting_for_motion($w) == ""} break
	set p2 $tdv_waiting_for_motion($w)
	if ![info exists rubbox] {
	    set rubbox [tdv_rubbox_im -color orange -transform 0 \
	    		    -x1 [lindex $p1 0] -y1 [lindex $p1 1] \
			    -x2 [lindex $p2 0] -y2 [lindex $p2 1]]
	    $w add_image $rubbox
	    $rubbox configure -overlay $over
	}
	$rubbox configure -x1 [lindex $p1 0] -y1 [lindex $p1 1] \
	    -x2 [lindex $p2 0] -y2 [lindex $p2 1]
    }
    unset tdv_waiting_for_motion($w)
    
    if [info exists rubbox] { $rubbox delete }
    tdv_cur $w dynamics

    if [info exist empty_but1_binding] {
       foreach b $empty_but1_binding { bind $w $b "" }
       unset empty_but1_binding
    }
    
    busy $bb
    if ![info exists p2] { return "" }
    
    return [list $p1 $p2]
}

proc tdv_cancel_rubbox {w} {
    global tdv_waiting_for_rubbox_click
    if [info exists tdv_waiting_for_rubbox_click($w)] {
	unset tdv_waiting_for_rubbox_click($w)
    }
}
    
proc tdv_multiple_rubbox {w cmd} {
    global tdv_waiting_for_click tdv_waiting_for_motion
    global tdv_scale tdv_pos tdv_width tdv_height is_win tdv_rubbox_overlay
    
    if {$cmd == ""} { set tdv_waiting_for_click($w) STOP; return "" }
    
    tdv_cur $w zoomin
    
    while 1 {
	set tdv_waiting_for_click($w) 1
	tkwait variable tdv_waiting_for_click($w)
	if ![info exists tdv_waiting_for_click($w)] { return "" }

	if {$tdv_waiting_for_click($w) == "STOP"} {
	    unset tdv_waiting_for_click($w)
	    break
	}
	set p1 [lrange $tdv_waiting_for_click($w) 1 end]
	unset tdv_waiting_for_click($w)
	set tdv_waiting_for_motion($w) 1
	while 1 {
	    tkwait variable tdv_waiting_for_motion($w)
	    
	    if {$tdv_waiting_for_motion($w) == ""} break
	    set p2 $tdv_waiting_for_motion($w)
	    if ![info exists rubbox] {
		set rubbox [tdv_rubbox_im -color orange -transform 0 \
				-x1 [lindex $p1 0] -y1 [lindex $p1 1] \
				-x2 [lindex $p2 0] -y2 [lindex $p2 1]]
		$w add_image $rubbox
		$rubbox configure -overlay $tdv_rubbox_overlay
	    }
	    $rubbox configure -x1 [lindex $p1 0] -y1 [lindex $p1 1] \
		-x2 [lindex $p2 0] -y2 [lindex $p2 1]
	}
	unset tdv_waiting_for_motion($w)
	
	if [info exists rubbox] { $rubbox delete; unset rubbox }
	
	eval $cmd \"$p1\" \"$p2\"
    }
    tdv_cur $w dynamics
}

proc tdv_set_waiting_func {w i x y} {
    global tdv_waiting_for_click
    set tdv_waiting_for_click($w) "$i $x $y"
}

proc tdv_multiple_lines {w} {
    global tdv_waiting_for_click tdv_waiting_for_motion
    global tdv_scale tdv_pos tdv_width tdv_height is_win tdv_rubbox_overlay
    
    tdv_cur $w zoomin
    
    foreach i {n x} {
	set pb($i) [tdv_set_key_command $i "set tdv_waiting_for_click($w) $i"]
    }
    foreach i {h v} {
	set pb($i) [tdv_set_key_command $i "tdv_set_waiting_func $w $i %x %y"]
    }
    #tdv_set_key_command F9 "tdv_temporary_dynamics $w"
    
    set lines ""
    set ok 1
    while 1 {
	set tdv_waiting_for_click($w) 1
	tkwait variable tdv_waiting_for_click($w)
	if ![info exists tdv_waiting_for_click($w)] { return "" }
	set but [lindex $tdv_waiting_for_click($w) 0]
	set p1 [lrange $tdv_waiting_for_click($w) 1 end]
	unset tdv_waiting_for_click($w)
	
	switch $but {
	    2 { break }
	    3 {
		set nl [llength $lines]
		if !$nl {
		    set ok 0
		    break
		} else {
		    set last [lindex $lines [expr $nl - 1]]
		    set lines [lrange $lines 0 [expr $nl - 2]]
		    $last delete
		    continue
		}
	    }
	    h {
		set vw [winfo width $w]
		set l [tdv_line_im -color orange -transform 0 \
				-point1 "0 [lindex $p1 1] 0" \
				-point2 "$vw [lindex $p1 1] 0"]
		$w add_image $l
		$l configure -overlay $tdv_rubbox_overlay
		lappend lines $l
		tdv_set_key_command F9 off
		continue
	    }
	    v {
		set vh [winfo height $w]
		set l [tdv_line_im -color orange -transform 0 \
				-point1 "[lindex $p1 0] 0 0" \
				-point2 "[lindex $p1 0] $vh 0"]
		$w add_image $l
		$l configure -overlay $tdv_rubbox_overlay
		lappend lines $l
		tdv_set_key_command F9 off	
		continue
	    }
	    n {
		set nl [llength $lines]
		if {$nl < 2} { tdv_mess "Must draw 2 lines first\n" red; continue }
		set l0 [lindex $lines [expr $nl - 2]]
		set l1 [lindex $lines [expr $nl - 1]]
		set x0a [lindex [$l0 get -point1] 0]
		set y0a [lindex [$l0 get -point1] 1]
		set x1a [lindex [$l1 get -point1] 0]
		set y1a [lindex [$l1 get -point1] 1]
		set x0b [lindex [$l0 get -point2] 0]
		set y0b [lindex [$l0 get -point2] 1]
		set x1b [lindex [$l1 get -point2] 0]
		set y1b [lindex [$l1 get -point2] 1]
		set p1 [list [expr $x1a + ($x1a - $x0a)] \
			     [expr $y1a + ($y1a - $y0a)] 0]
		set p2 [list [expr $x1b + ($x1b - $x0b)] \
			     [expr $y1b + ($y1b - $y0b)] 0]
		
		set lineim [tdv_line_im -color orange -transform 0 \
				-point1 $p1 -point2 $p2]
		$w add_image $lineim
		$lineim configure -overlay $tdv_rubbox_overlay
		lappend lines $lineim
		tdv_set_key_command F9 off
		continue
	    }
	    x {
		set ok 0
		break
	    }
	}
	set tdv_waiting_for_motion($w) 1
	while 1 {
	    tkwait variable tdv_waiting_for_motion($w)
	    
	    if {$tdv_waiting_for_motion($w) == ""} break
	    if [info exists cancel_drag] break
	    set p2 $tdv_waiting_for_motion($w)
	    if ![info exists lineim] {
		set lineim [tdv_line_im -color orange -transform 0 \
				-point1 "[lindex $p1 0] [lindex $p1 1] 0" \
				-point2 "[lindex $p2 0] [lindex $p2 1] 0"]
		$w add_image $lineim
		$lineim configure -overlay $tdv_rubbox_overlay
		lappend lines $lineim
	    } else {
		$lineim configure -point2 "[lindex $p2 0] [lindex $p2 1] 0"
	    }
	}
	catch {unset lineim}
	unset tdv_waiting_for_motion($w)
	
	# After the first line we don't allow dynamics any more.
	tdv_set_key_command F9 off
    }
    
    tdv_cur $w dynamics
    foreach i [array names pb] {
	tdv_set_key_command $i $pb($i)
    }
    tdv_set_key_command F9 ""
    
    set ret ""
    foreach l $lines {
	if $ok { lappend ret [$l get -point1] [$l get -point2] }
	$l delete
    }
    $w redraw
    return $ret
}

proc tdv_multiple_planes {w} {
    global tdv_waiting_for_click tdv_waiting_for_motion select_action
    global tdv_scale tdv_pos tdv_width tdv_height is_win tdv_rubbox_overlay
    
    tdv_cur $w zoomin
    
    foreach i {n x} {
	set pb($i) [tdv_set_key_command $i "set tdv_waiting_for_click($w) $i"]
    }
    
    select_set_bindings 1 0 0 0 ""
    
    set bb [$w bbox interesting]
    if {$bb == ""} return
    
    set planes ""
    set ok 1
    while 1 {
	tkwait variable select_action

	switch [lindex $select_action 0] {
	    done { break }
	    back {
		set nl [llength $planes]
		if !$nl {
		    set ok 0
		    break
		} else {
		    set last [lindex $planes [expr $nl - 1]]
		    set planes [lrange $planes 0 [expr $nl - 2]]
		    [lindex $last 0] delete
		    continue
		}
	    }
	    cancel {
		set ok 0
		break
	    }
	    press {
		set lineim [tdv_line_im -color orange -transform 0 \
				-point1 "[lindex $select_action 1] \
					 [lindex $select_action 2] 0" \
				-point2 "[lindex $select_action 1] \
					 [lindex $select_action 2] 0"]
		$w add_image $lineim
		$lineim configure -overlay $tdv_rubbox_overlay
	    }
	    move {
		$lineim configure -point2 "[lindex $select_action 1] \
					   [lindex $select_action 2] 0"
	    }
	    release {
		if ![info exists lineim] continue
		
		set inv [lindex [$w screen2world 0 0] 1]
		set p1 [lindex [eval $w screen2world \
				    [lrange [$lineim get -point1] 0 1]] 0]
		set p2 [lindex [eval $w screen2world \
				    [lrange [$lineim get -point2] 0 1]] 0]
		set poly [poly_from_line_and_bbox $p1 $p2 $inv [lindex $bb 0] [lindex $bb 1]]
		if {[llength $poly] > 2} {
		    set im [tdv_poly_line_im -color orange -interesting 0]
		    set norm [lindex $poly 0]
		    foreach p [lrange $poly 1 end] { $im add_point $p }
		    $im add_point [lindex $poly 1]
		    
		    $w add_image $im
		    lappend planes [list $im [lindex $poly 1] $norm]
		}
		$lineim delete
		unset lineim
	    }
	}
    }
    
    select_unset_bindings 0
    
    foreach i [array names pb] {
	tdv_set_key_command $i $pb($i)
    }
    
    tdv_cur $w dynamics
    
    set ret ""
    foreach l $planes {
	if $ok { lappend ret [concat [lindex $l 1] [lindex $l 2]] }
	[lindex $l 0] delete
    }
    $w redraw
    return $ret
}

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

proc tdv_pick {{what ""} {max_num 0} {mess ""} {v ""} {maxd 0}} {
    global tdv_select_action tdv_default
    
    if {$v == ""} { set v $tdv_default }
    
    if {$mess == ""} {
	set thing $what
	if {$thing == ""} { set thing item }
	if $max_num {
	    if {$max_num == 1} { set s "" } else { set s s }
	    set mess "$max_num ${thing}$s"
	} else {
	    set mess "${thing}s"
	}
    }
    banner "Select $mess with the left button; middle = done,\
	right = back up / cancel."
    tdv_select_set_bindings $v
    set finished 0
    
    set stuff ""
    set nstuff 0
    while {!$finished} {
	tkwait variable tdv_select_action
	
	switch [lindex $tdv_select_action 0] {
	    done {
		set finished 1
	    }
	    back {
		if !$nstuff {
		    set finished 1
		} else {
		    incr nstuff -1
		    set stuff [lrange $stuff 0 [expr $nstuff - 1]]
		}
	    }
	    release {
		set x [lindex $tdv_select_action 1]
		set y [lindex $tdv_select_action 2]
		set tags ""
		foreach im $stuff { lappend tags ![lindex $im 0] }
		#puts "$v pick $x $y $tags $what $maxd"
		set im [$v pick $x $y $tags $what $maxd]
		#puts "im $im"
		if {$im != ""} {
		    lappend stuff $im
		    incr nstuff
		}
	    }
	}
    }
    
    tdv_select_unset_bindings $v
    banner ""
    
    mess "$nstuff ${what}s\n"
    return $stuff
}

proc tdv_select_set_bindings {v} {
    global tdv_select_in_dynamics
    
    foreach i {1 2 3} {
	bind $v <Button$i-Motion> ""
	bind $v <Shift-Button$i-Motion> ""
	bind $v <ButtonPress-$i> ""
	bind $v <ButtonRelease-$i> ""
	bind $v <Shift-ButtonRelease-$i> ""
    }
    bind $v <ButtonRelease-1>      { set tdv_select_action "release %x %y" }
    bind $v <ButtonPress-2>        { set tdv_select_action "done" }
    bind $v <ButtonPress-3>        { set tdv_select_action "back" }
    
    bind $v <F9> "tdv_select_toggle_dynamics $v"
    bind [winfo parent $v] <F9> "tdv_select_toggle_dynamics $v"
    
    tdv_cur $v pick
    
    set tdv_select_in_dynamics($v) 0    
}

proc tdv_select_unset_bindings {v} {
    global tdv_select_in_dynamics
    tdv_dynamics_bindings $v
    tdv_cur $v dynamics
    catch {unset tdv_select_in_dynamics($v)}
}

proc tdv_select_toggle_dynamics {v} {
    global tdv_select_in_dynamics tdv_select_in_dynamics_prev_banner

    if ![info exists tdv_select_in_dynamics($v)] return
    
    if $tdv_select_in_dynamics($v) {
	tdv_select_set_bindings $v
	set tdv_select_in_dynamics($v) 0
	if [info exists tdv_select_in_dynamics_prev_banner($v)] {
	    banner $tdv_select_in_dynamics_prev_banner($v)
	    unset tdv_select_in_dynamics_prev_banner($v)
	}
    } else {
	tdv_dynamics_bindings $v
	bind $v <F9> "tdv_select_toggle_dynamics $v"
	bind [winfo parent $v] <F9> "tdv_select_toggle_dynamics $v"
	tdv_cur $v dynamics
	set tdv_select_in_dynamics($v) 1
	set tdv_select_in_dynamics_prev_banner($v) \
	    [banner "Dynamics mode - hit F9 to return to selection mode."]
    }
}

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

proc tdv_push_key_command {key cmd {help ""}} {
    global tdv_key_command_stack tdv_key_help
    
    if [info exists tdv_key_help($key)] {
	set prevh $tdv_key_help($key)
    } else {
	set prevh ""
    }
    set prev [tdv_set_key_command $key $cmd $help]
    lappend tdv_key_command_stack($key) [list $prev $prevh]
    return $prev
}

proc tdv_pop_key_command {key} {
    global tdv_key_command_stack tdv_key_command tdv_key_help
    
    if {![info exists tdv_key_command_stack($key)] || ![llength $tdv_key_command_stack($key)]} {
	return
    }
    
    set prev [lindex $tdv_key_command_stack($key) end]
    set tdv_key_command_stack($key) [lrange $tdv_key_command_stack($key) 0 end-1]
    if {[lindex [lindex $prev 0] 0] == "actvar"} {
	set tdv_key_command($key) [lindex $prev 0]
	set tdv_key_help($key) [lindex $prev 1]
    } else {
	tdv_set_key_command $key [lindex $prev 0] [lindex $prev 1]
    }
}

proc tdv_set_key_command {key cmd {help ""} {actvar ""} {actvals ""}} {
    global tdv_key_command tdv_key_help tdv_key_saved
    
    #puts [list tdv_set_key_command $key $cmd $help $actvar $actvals]
    
    if 0 {
	if {($cmd == "") && [info exists tdv_key_saved($key)]} {
	    set cmd [lindex $tdv_key_saved($key) 0]
	    set help [lindex $tdv_key_saved($key) 1]
	    unset tdv_key_saved($key)
	} elseif {![info exists tdv_key_saved($key)] &&
		  [info exists tdv_key_command($key)] &&
		  [info exists tdv_key_help($key)]} {
	    set tdv_key_saved($key) [list $tdv_key_command($key) $tdv_key_help($key)]
	}
    }
    
    if [info exists tdv_key_command($key)] {
	set prev $tdv_key_command($key)
    } else {
	set prev ""
    }
    if {$cmd == ""} {
	catch {unset tdv_key_command($key)}
	catch {unset tdv_key_help($key)}
    } else {
	if {$actvar == ""} {
	    set tdv_key_command($key) $cmd
	} else {
	    lappend tdv_key_command($key) actvar $actvar $actvals $cmd
	}
    }
    if {$help == ""} { set help $cmd }
    set helpstr ""
    foreach line [split $help \n] {
	append helpstr "[string trim $line] "
    }
    set helpstr [string trim $helpstr]
    if {$actvar == ""} {
	set tdv_key_help($key) $helpstr
    } else {
	lappend tdv_key_help($key) actvar $actvar $actvals $helpstr
    }
    return $prev
}

proc tdv_keyboard_command {target key x y state} {
    global tdv_key_command tdv_key_help tdv_keys_active_everywhere
    
    # On win2k these keys have strange names
    switch $key {
	L1 { set key F11 }
	L2 { set key F12 }
    }
    
    set state [expr $state & 7] ;# mask out num lock and all higher bits
    switch $state {
	1 { set key Shift-$key }
	4 { set key Control-$key }
	5 { set key Control-Shift-[string tolower $key] }
    }
    if {$key == "question"} { set key Shift-question } ;# wierdness
    
    set fw [focus]
    set ww [winfo containing $x $y]
    
    if {$ww == ""} return
    
    if {$fw != ""} {
	switch [winfo class $fw] {
	    Text - Entry { return }
	}
    }
    if {[info exists tdv_keys_active_everywhere] || \
	    ([winfo exists $ww] && ([winfo class $ww] == "Tdv_Viewer"))} {
	
	set sbind [bind $ww <Key-$key>]
	if {$sbind != ""} {
	    return
	    # This is probably not necessary ... ****
	    uplevel \#0 eval $sbind
	
	} elseif [info exists tdv_key_command($key)] {
	    set cmd $tdv_key_command($key)
	    if {$tdv_key_command($key) == "off"} return
	    
	    if {[lindex $cmd 0] == "actvar"} {
		set gotcmd ""
		foreach {dummy actvar actvals actcmd} $cmd {
		    upvar \#0 $actvar lvar
		    if {[lsearch $actvals $lvar] >= 0} {
			set gotcmd $actcmd
			break
		    }
		}
		if {$gotcmd == ""} return
		set cmd $gotcmd
	    }
	    set rx [expr {$x - [winfo rootx $ww]}]
	    set ry [expr {$y - [winfo rooty $ww]}]
	    regsub -all %x $cmd $rx cmd
	    regsub -all %y $cmd $ry cmd
	    regsub -all %w $cmd $ww cmd
	    uplevel \#0 $cmd
	
	} else {
	    switch -- $key {
		F9 {
		    # if we haven't bound this to something different, 
		    # do temporary dynamics.
		    if {[bind $ww <Key-F9>] == ""} {
			tdv_temporary_dynamics $ww
		    }
		}
	    }
	}
    }
}

proc tdv_init_shortcuts {control {change_bindings ""}} {
    global tdv_default command
    
    bind all <KeyPress> "tdv_keyboard_command $tdv_default \"%K\" %X %Y %s"
    
    array set cbind $change_bindings
    
    foreach {k1 k2 cmd help} {
	Control-h h { tdv_home current } "Home position"
	Control-o z { tdv_zoomin current } "Zoom in"
	Control-s s { tdv_scale_to_fit current } "Scale to fit"
	Control-x Shift-X { tdv_along_axis current +x } "View in X direction"
	Control-y Shift-Y { tdv_along_axis current +y } "View in Y direction"
	Control-z Shift-Z { tdv_along_axis current -z } "View in Z direction"
	Control-r Shift-R { tdv_reverse current } "Reverse view"
	Control-i Shift-I { tdv_isoview current } "Isometric view"
	Control-question Shift-question { tdv_print_shortcuts } "Print shortcuts"
	F5 F5 { tdv_set_zoff current toggle_largest } "Set wireframe offset"
	F6 F6 { tdv_set_zoff current 0 } "Set wireframe offset to 0"
	F7 F7 { tdv_change_zoffset current 1 } "Increment wireframe offset"
	F8 F8 { tdv_change_zoffset current 0 } "Decrement wireframe offset"
    } {
	if [info exists cbind($k1)] { set k1 $cbind($k1) }
	if [info exists cbind($k2)] { set k2 $cbind($k2) }
	
	set help [form_label_text $help]
	if [info exists command(longname,$help)] {
	    set help $command(longname,$help)
	}
	if $control {
	    tdv_set_key_command $k1 $cmd $help
	} else {
	    tdv_set_key_command $k2 $cmd $help
	}
    }
    
    # This is to handle the case where the user hits ? in the message window
    proc ? args tdv_print_shortcuts
}

proc tdv_change_zoffset {w farther} {
    set w [tdv_what_window $w]
    set vv [$w get -zoff]
    if {$vv <= 0} { set vv 0.0001 }
    if $farther {
	set vv [expr $vv * 0.75]
    } else {
	set vv [expr $vv / 0.75]
    }
    $w configure -zoff $vv
    $w redraw
    mess "Z offset is $vv of total Z range\n"
}

proc tdv_print_shortcuts {} {
    global tdv_key_help tdv_key_command
    
    mess "Currently defined keyboard shortcuts ------\n"
    
    foreach k [lsort [array names tdv_key_help]] {
	if ![info exists tdv_key_command($k)] continue
	if [info exists tdv_key_help($k)] {
	    set help $tdv_key_help($k)
	    if {[lindex $help 0] == "actvar"} {
		set gothelp ""
		foreach {dummy actvar actvals acthelp} $help {
		    upvar \#0 $actvar lvar
		    if {[lsearch $actvals $lvar] >= 0} {
			set gothelp $acthelp
			break
		    }
		}
		if {$gothelp == ""} continue
		set help $gothelp
	    }
	    
	    if {($tdv_key_help($k) != "*hidden*") && ($help != "off")} {
		mess "[format %-16s $k] $help\n"
	    }
	}
    }
    mess "\n"
}

proc tdv_edit_bindings {{w ""} {buts ""}} {
    global tdv_mouse_bindings tdv_mouse_bindings_autohex_names tdv_default
    global tdv_mouse_bindings_save env
    
    if {$buts == ""} {
        if {[info exists env(ICEM_AI_ENVIRONMENT)] && $env(ICEM_AI_ENVIRONMENT)} {
            set buts {accept reset cancel {Save tdv_edit_bindings_save} \
                     {Help "ContextDEZHelp Help-1_5_4_"}}
        } else {
            set buts {accept reset cancel {Save tdv_edit_bindings_save} help}
        }
    }
    while 1 {
	set d [form_init .mouse_bindings "Mouse bindings" "" $buts]
	if {$d != ""} {
	    tdv_edit_bindings_form $d
	    form_finish +300+300
	    bind .mouse_bindings <MouseWheel> "tdv_wheelzoom %W %D %t %X %Y"
	}
	form_wait .mouse_bindings
	
	catch {unset s1}
	foreach i {rot trans scale} { set s1($tdv_mouse_bindings($i)) 1 }
	if {![info exists s1(1)] || ![info exists s1(2)] || \
		![info exists s1(3)]} {
	    mess "Error: you must assign rotate, translate, and scale to different buttons\n" red
	    continue
	}
	catch {unset s1}
	foreach i {select done cancel} { set s1($tdv_mouse_bindings($i)) 1 }
	if {![info exists s1(1)] || ![info exists s1(2)] || \
		![info exists s1(3)]} {
	    mess "Error: you must assign select, done, and cancel to different buttons\n" red
	    continue
	}
	break
    }
    tdv_edit_bindings_done $w
    if [info exists tdv_mouse_bindings_save] {
        tdv_edit_bindings_save 1
        unset tdv_mouse_bindings_save
    }
}

proc tdv_edit_bindings_done {args} {
    global tdv_scale tdv_mouse_bindings_autohex_names
    global tdv_twod_var
    
    foreach w [array names tdv_scale] {
	if {[winfo exists $w] && [info exist tdv_twod_var($w)]} {
	    tdv_dynamics_bindings $w
	    if [info exists tdv_mouse_bindings_autohex_names] {
		tdv_selection_bindings $w
	    }
	}
    }
}

proc tdv_edit_bindings_form {d} {
    form_label $d.rotb "3D Rotate button" {0 0}
    form_label $d.trab "Translate button" {1 0}
    form_label $d.scab "Scale/2D Rotate button" {2 0}

    set opts [list rot 0 trans 1 scale 2]

    if [info exists tdv_mouse_bindings_autohex_names] {
	form_label $d.selb "Select button" {5 0}
	form_label $d.donb "Move button" {6 0}
	form_label $d.canb "Resize button" {7 0}

        lappend opts  select 5 done 6 cancel 7
    } else {
	# form_label $d.selb "Select button" {5 0}
	# form_label $d.donb "Done button" {6 0}
	# form_label $d.canb "Cancel button" {7 0}

	# lappend opts  select 5 done 6 cancel 7
    }
    foreach {o r} $opts {
	form_radiobutton $d.${o}1 Left tdv_mouse_bindings($o) \
	    1 "$r 1"
	form_radiobutton $d.${o}2 Middle tdv_mouse_bindings($o) \
	    2 "$r 2"
	form_radiobutton $d.${o}3 Right tdv_mouse_bindings($o) \
	    3 "$r 3"
    }
    form_radiobutton $d.scap "Zoom in = up" \
	tdv_mouse_bindings(scale_dir) 1 {3 1 -cols 3}
    form_radiobutton $d.scan "Zoom in = down" \
	tdv_mouse_bindings(scale_dir) -1 {4 1 -cols 3}

    if {$::tcl_platform(platform) == "windows" || [string tolower $::tcl_platform(os)] == "linux"} {
	global tdv_mouse_bindings
	form_label $d.wheellabel "Wheel sensitivity" {5 0}
	if ![info exists tdv_mouse_bindings(wheel)] {set tdv_mouse_bindings(wheel) 5}
	if ![info exists tdv_mouse_bindings(wheelactive)] {set tdv_mouse_bindings(wheelactive) 1}
	form_checkbutton $d.wheelactive "On/off" tdv_mouse_bindings(wheelactive) {6 0}
	form_scale $d.scale tdv_mouse_bindings(wheel) {} h 0.1 10 0.1 {5 1 -cols 3 -rows 2} [list tdv_mouse_bindings(wheelactive) 1]
	set color [$d.scale cget -troughcolor]
	trace variable ::tdv_mouse_bindings(wheelactive) w \
	    "if \{\$::tdv_mouse_bindings(wheelactive) == \"0\"\} \{
		$d.scale configure -troughcolor $color
	    \} else \{
		$d.scale configure -troughcolor white
	    \}
	    list"
	# Activate the trace
	after idle {set tdv_mouse_bindings(wheelactive) $::tdv_mouse_bindings(wheelactive)}
    }
}

proc tdv_reset_bindings {w callup} {
    global tdv_mouse_bindings
    
    array set tdv_mouse_bindings {
	rot 1
	trans 2
	scale 3
	scale_dir 1
	select 1
	done 2
	cancel 3
	wheel 5
	wheelactive 1
    }
    if $callup {
	tdv_dynamics_bindings $w
    }
}

proc tdv_edit_bindings_save {{save 0}} {
    global tdv_mouse_bindings_save tdv_mouse_bindings
        
    if !$save {
        set tdv_mouse_bindings_save 1
        form_accept_hack .mouse_bindings
    } else {
        set fp [open [home_directory]/.icemcfd_mouse_bindings w]
        puts $fp "global tdv_mouse_bindings"
        foreach b [array names tdv_mouse_bindings] {
            puts $fp "set tdv_mouse_bindings($b) $tdv_mouse_bindings($b)"
        }
        close $fp
        mess "Mouse bindings saved to [home_directory]/.icemcfd_mouse_bindings.\n"
    }
}

proc tdv_mswin_printers {w} {
    return [$w mswin_print "" "" "" "" "" "" 0]
}

proc tdv_bbox_of_images {ims} {
    set bbs ""
    foreach im $ims {
	set bb [$im get_bbox]
	if {$bb == ""} continue
	lappend bbs $bb
    }
    return [tdv_merge_bboxes $bbs]
}

proc tdv_merge_bboxes {bbs} {
    if {$bbs == ""} { return "" }
    
    foreach bb $bbs {
	foreach c {0 1 2} {
	    set v1 [lindex [lindex $bb 0] $c]
	    set v2 [lindex [lindex $bb 1] $c]
	    if {![info exists minv($c)] || ($minv($c) > $v1)} {
		set minv($c) $v1
	    }
	    if {![info exists maxv($c)] || ($maxv($c) < $v2)} {
		set maxv($c) $v2
	    }
	}
    }
    return [list "$minv(0) $minv(1) $minv(2)" "$maxv(0) $maxv(1) $maxv(2)"]
}

proc tdv_bbox_of_pts {pts} {
    if {$pts == ""} { return "" }
    
    foreach pt $pts {
	foreach c {0 1 2} {
	    set v1 [lindex $pt $c]
	    if {![info exists minv($c)] || ($minv($c) > $v1)} {
		set minv($c) $v1
	    }
	    if {![info exists maxv($c)] || ($maxv($c) < $v1)} {
		set maxv($c) $v1
	    }
	}
    }
    return [list "$minv(0) $minv(1) $minv(2)" "$maxv(0) $maxv(1) $maxv(2)"]
}

proc tdv_check_bbox {} { 
    set w [tdv_what_window current]
    set bb [$w bbox interesting]
    if {$bb != ""} {
	mess "Minimum: [eval format \"%g %g %g\" [lindex $bb 0]]\n"
	mess "Maximum: [eval format \"%g %g %g\" [lindex $bb 1]]\n"
    }
}

proc tdv_check_angle {} {
    set w [tdv_what_window current]
    
    tdv_cur $w pick
    banner "Select the vertex point on the screen with the left button."
    set pt1 [get_graphics_loc]
    banner ""
    if {$pt1 == ""} { tdv_cur $w dynamics; return }
    
    set im1 [tdv_point_im -point $pt1 -size 3 -color blue]
    $w add_image $im1
    $w redraw
    
    banner "Select the first vector end on the screen with the left button."
    set pt2 [get_graphics_loc]
    banner ""
    if {$pt2 == ""} { tdv_cur $w dynamics; $im1 delete; return }
    
    set im2 [tdv_point_im -point $pt2 -size 3 -color white]
    $w add_image $im2
    $w redraw
    
    banner "Select the second vector end on the screen with the left button."
    set pt3 [get_graphics_loc]
    banner ""
    if {$pt3 == ""} { tdv_cur $w dynamics; $im1 delete; return }
    
    set im3 [tdv_point_im -point $pt3 -size 3 -color white]
    $w add_image $im3
    $w redraw
    
    after 100
    
    set angle 0
    set dist 0
    foreach i {0 1 2} {
	set p  [expr {[lindex $pt2 $i] - [lindex $pt3 $i]}]
	set dist [expr {$dist + $p * $p}]
    }
    set l23 [expr {sqrt($dist)}]
    set dist 0
    foreach i {0 1 2} {
	set p  [expr {[lindex $pt1 $i] - [lindex $pt2 $i]}]
	set dist [expr {$dist + $p * $p}]
    }
    set l12 [expr {sqrt($dist)}]
    set dist 0
    foreach i {0 1 2} {
	set p  [expr {[lindex $pt1 $i] - [lindex $pt3 $i]}]
	set dist [expr {$dist + $p * $p}]
    }
    set l13 [expr {sqrt($dist)}]
    set temp [expr {acos(($l12*$l12+$l13*$l13-$l23*$l23)/(2*$l12*$l13))}]
    set angle [expr {$temp*180/3.1415926}]
    $im1 delete
    $im2 delete
    $im3 delete
    tdv_cur $w dynamics
    
    mess "Angle is [format %g $angle] degrees\n"
}

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

proc tdv_set_anno_icon {w which text is_bitmap} {
    global tdv_anno_icon
    
    if {$text == ""} {
	if [info exists tdv_anno_icon($which)] {
	    $tdv_anno_icon($which) delete
	    unset tdv_anno_icon($which)
	}
	return
    }
    if {$w == ""} {
	set w [tdv_what_window current]
    }
    if ![info exists tdv_anno_icon($which)] {
	switch $which {
	    left { set pos "20 10 0" }
	    right {
		set ww [winfo width $w]
		set pos "[expr $ww - 200] 10 0"
	    }
            "upper left" {
                 set vh [winfo height $w]
                 set pos "20 [expr $vh - 200] 0"
             }
             "upper right" {
                 set vh [winfo height $w]
                 set ww [winfo width $w]
                 set pos_x [expr $ww - 120]
                 set pos_y [expr $vh - 150]
                 set pos "$pos_x $pos_y 0"
             }
	}
	
	if $is_bitmap {
	    set tdv_anno_icon($which) [tdv_pixmap_im -pos $pos \
					   -transform 0 -y_dir_up 1]
	    $w add_image $tdv_anno_icon($which)
	} else {
	    set tdv_anno_icon($which) [tdv_text_im -point $pos -color white \
					   -transform 0 -y_dir_up 1 -fontsize 1]
	    $w add_image $tdv_anno_icon($which)
	}
    }
    if $is_bitmap {
	$tdv_anno_icon($which) configure -ppmfile $text
    } else {
	$tdv_anno_icon($which) configure -text $text
    }
}

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

proc tdv_update_symmetry {w} {
   global tdv_mirrors tdv_replica tdv_xsym_var tdv_ysym_var tdv_zsym_var
    
   set mm ""

   foreach {i c} {0 x 1 y 2 z} {
      set k [set tdv_${c}sym_var($w)]
      if {$k > 0} {
         if ![info exist tdv_mirrors($w,$c,D)] {
            set j [expr ($k == 2) ? 1 : 0]
            set tdv_mirrors($w,$c,D) \
                  [lindex [lindex [$w bbox interesting] $j] $i]
            set rr [list 0 0 0]
            set rr [lreplace $rr $i $i 1]
            set tdv_mirrors($w,$c,A) [lindex $rr 0]
            set tdv_mirrors($w,$c,B) [lindex $rr 1]
            set tdv_mirrors($w,$c,C) [lindex $rr 2]
         }
         lappend mm [list $tdv_mirrors($w,$c,A) $tdv_mirrors($w,$c,B) \
                          $tdv_mirrors($w,$c,C) $tdv_mirrors($w,$c,D)]
      }
   }

   foreach i $tdv_mirrors($w,list) {
      lappend mm [list $tdv_mirrors($w,$i,A) $tdv_mirrors($w,$i,B) \
                       $tdv_mirrors($w,$i,C) $tdv_mirrors($w,$i,D)]
   }

   set sm ""
   if {$tdv_replica($w)} {
      if {$tdv_replica($w,type) == "shift"} {
         set sm [list $tdv_replica($w,nrep) $tdv_replica($w,dx) \
                      $tdv_replica($w,dy) $tdv_replica($w,dz) 0 0 0 0]
      } else {
         set sm [list $tdv_replica($w,nrep) $tdv_replica($w,x0) \
                      $tdv_replica($w,y0) $tdv_replica($w,z0) \
                      $tdv_replica($w,ax) $tdv_replica($w,ay) \
                      $tdv_replica($w,az) $tdv_replica($w,angle)]
      }
   }
    
   if {($mm != "") || ($sm != "")} {
      $w reset_symmetry $sm $mm
      $w configure -use_symmtry 1
   } else {
      $w configure -use_symmtry 0   
   }
   $w redraw
}


proc tdv_get_workspace_topviewer {{dims ""}} {
   global tdv_workspace

   if {![info exist tdv_workspace] || ![winfo exist $tdv_workspace]} {
      return ""
   }

   set rr [winfo children $tdv_workspace]
   set n  [expr [llength $rr] -1]
   for {set j $n} {$j >= 0} {incr j -1} {
      set w [lindex $rr $j]
      if {([winfo class $w] != "Tdv_Viewer") || ![winfo ismapped $w]} continue
      if {($dims == "") || \
          ([string first [tdv_get_win_dim $w] $dims] >= 0)} { return $w }
   }

   return ""
}

proc tdv_get_win_dim {w} {
   global tdv_twod_var tdv_win_type

   set win_dim 3
   if {[info exist tdv_win_type($w)] && ($tdv_win_type($w) == "1d")} {
      set win_dim 1
   } elseif {[info exist tdv_twod_var($w)] && $tdv_twod_var($w)} {
      set win_dim 2
   }

   return $win_dim
}

# the following is used to post a menu for a Tdv_Viewer window

proc tdv_post_cmd {w what {sub ""} args} {
   global tdv_rot tdv_post_menu
   global anno_data mview_data

   switch -- $what {
       hardcopy {
          global hardcopy

          if {$sub != ""} { set hardcopy(format) $sub }
          set hardcopy(startcmd_current) ""
          set hardcopy(endcmd_current) ""
          set hardcopy(sub_current) $w
          set hardcopy(top_current) .[lindex [split $w \.] 1]

          hardcopy_create
       }
       post_menu {
          if {![info exist tdv_post_menu($w)] || \
              ![winfo exist $tdv_post_menu($w)]} {
             if {[info command tdv_post_menu_cmd] == ""} {return ""}
             tdv_post_menu_cmd $w
          }
  
          set xp [lindex $args 0]
          set yp [lindex $args 1]
          if {$xp == ""} {set xp [winfo pointerx $w]}
          if {$yp == ""} {set yp [winfo pointery $w]}
          
          tk_popup $tdv_post_menu($w) $xp $yp
       }
       background {
          set col [tk_chooseColor -initialcolor [$w get -background] \
                          -title "Choose background color"]
          $w configure -background $col
          $w redraw
       }
       borderwidth {
          if {$sub == ""} {
             set sub [question_box .text "Windows' 3D Border" \
                  "Enter border width for the window" [$w get -borderwidth]]
             if {$sub  == ""} {return}
          }
          $w configure -borderwidth $sub
          $w redraw
       }
       bordercolor {
          if {$sub == ""} {
             set sub [tk_chooseColor -initialcolor [$w get -bordercolor] \
                          -title "Choose a color a the boder"]
             if {$sub  == ""} {return}
          }
          $w configure -bordercolor $sub
          $w redraw
       }
       relief {
          if {$sub == ""} {
              set n [tk_dialog  .choices "Choose One" \
                       "Choose a 3D relief style for the window" "" "" \
                       flat ridge groove sunken raised solid]
              if [winfo exists .choices] { destroy .choices; return }
              if {$n == ""} {return}
              set sub [lindex "flat ridge groove sunken raised solid" $n]
              if {$sub  == ""} {return}
          }
          $w configure -relief $sub
          $w redraw
       }
       vframe {
          if [info exist mview_data($w,parent)] {
             setup_anno_mg $mview_data($w,parent)
             set anno_data(win) $mview_data($w,parent)
             set anno_data(model) 0

             update_anno_pick $mview_data($w,vfm)
          }
       } 
       flip {
          if {$sub == "x"} {
             tdv_post_cmd $w rotate -180.0 0 1 0
          } else {
             tdv_post_cmd $w rotate -180.0 1 0 0
          }
       }
       mv_vfm {
          if [info exist mview_data($w,parent)] {
             setup_anno_mg $mview_data($w,parent)
             set anno_data(win) $mview_data($w,parent)
             set anno_data(model) 0

             update_anno_pick $mview_data($w,vfm)
             set anno_data(vframe,draw_im) 1
             modify_anno_pick vframe
             anno_action move 0 0 $mview_data($w,vfm)
             set anno_data(vframe,draw_im) 0
             modify_anno_pick vframe
          }
       }
       rotate {
          if {$sub == ""} {set sub 90}
          if {[llength $args] > 2} {
             set axis [lrange $args 0 2]
          } else {
             set axis "0 0 1"
          }
          set ang [expr -$sub * (3.14159265358979323846/180.0)]
          set incr [eval $w getaxisrot $axis $ang]
          if {$incr == "0 0 0 0"} return
          set nrot [tdv_qcomp $tdv_rot($w) $incr]
          if {$nrot == "0 0 0 0"} return
          set tdv_rot($w) $nrot
          tdv_trans_update $w
       }
   }
}

proc tdv_active {on} {
    global tdv_default env tk_version
    
    # This is only for debugging -Wayne
    if [info exists env(ICEM_TDV_ALWAYS_ACTIVE)] { return 1 }
    
    if {![info exists tdv_default] || ($tdv_default == "") ||
	![info exists tk_version] || ![winfo exists $tdv_default]} {
	return 0
    }
    set prev [$tdv_default get -active]
    if {$on && !$prev} {
	$tdv_default configure -active 1
	if {[$tdv_default get -skipped_redraw]} {
	    $tdv_default redraw
	}
    } elseif {!$on && $prev} {
	$tdv_default configure -active 0 -skipped_redraw 0
    }
    return $prev
}

proc tdv_mouse_pick {args} {
    global tdv_waiting_for_click tdv_obtain_screen_pos_button
    global tdv_default tdv_last_viewer_clicked
    global tdv_click_preset tdv_picked

    set w $tdv_default
    catch {unset tdv_picked}
    if ![info exists tdv_click_preset] {
	set tdv_obtain_screen_pos_button ""
	set pcursor($w) [$w get -cursor]
	tdv_cur $w pick
	set tdv_waiting_for_click($w) 1

	tkwait variable tdv_waiting_for_click
	if ![info exists tdv_waiting_for_click($w)] { return "" }

	#mess "tdv_click: $tdv_waiting_for_click($w)\n" red
	set button_click [lindex $tdv_waiting_for_click($w) 0]
	set x [lindex $tdv_waiting_for_click($w) 1];   set y [lindex $tdv_waiting_for_click($w) 2];

	unset tdv_waiting_for_click($w)
	$w configure -cursor $pcursor($w)
    } else {
	set x $tdv_click_preset(x)
	set y $tdv_click_preset(y)
	set button_click 1
	unset tdv_click_preset
    }
	
	set pt3d ""
	if {$args == "region_select"} {
		set pt3d [lindex [$w screen2world $x $y] 0]
	} else {
		set pt3d [$w get_3d_point $x $y 1]
	}
	
	if {$pt3d != ""} {
		set vec [lindex [$w screen2world $x $y] 1]
	} else {
		set pt3d {1.0e24 1.0e24 1.0e24}
		set vec {0 0 0}
	}
	
	set tdv_picked(aloc) [lrange $pt3d 0 2]
	set tdv_picked(vec) $vec

    return "$button_click [lrange $pt3d 0 2] $vec"
}

set i 0
proc tdv_mouse_state {args} {
    global tdv_default i

    set w $tdv_default
    set x [expr {[winfo pointerx $w] - [winfo rootx $w]}]
    set y [expr {[winfo pointery $w] - [winfo rooty $w]}]
    #set pt3d [$w get_3d_point $x $y 1]
    #set vec [lindex [$w screen2world $x $y] 1]
    set pos [$w screen2world $x $y]
    
    #mess "x = $x, y = $y\n" blue
    return "0 [lindex $pos 0] [lindex $pos 1]"
}

proc tdv_select_rbox {x1 y1 x2 y2} {
    global tdv_default
    global tdv_rubbox_overlay

    set rbox [tdv_rubbox_im -color orange -x1 $x1 \
		  -y1 $y1 -x2 $x2 -y2 $y2]
    $tdv_default add_image $rbox
    $rbox configure -overlay $tdv_rubbox_overlay

    $tdv_default redraw
    return $rbox
}

proc tdv_configure_select_rbox {rbox x2 y2} {
    global tdv_default
    $rbox configure -x2 $x2 -y2 $y2    
    $tdv_default redraw
}

proc tdv_delete_select_rbox {rbox} {
    $rbox delete
}

proc tdv_fixed_text {x y text} {
    global tdv_default

    set w $tdv_default
    set tim [tdv_text_im -point "$x $y 0" -y_dir_up 1 \
                 -transform 0 -text $text]
    $w add_image $tim
}

proc tdv_lighting_params {} {
    global tdv_lights_settings tdv_default tdv_material_settings
    global view_panes
    
    set lighting_string ""    

    foreach pane $view_panes(all_viewers) {
	set lighting_string ""    
	if {$tdv_lights_settings(complex) == 0} {
	    # disable lighting
	    $pane configure -lighting_string "lighting_off"
	    $pane redraw
	} else {
	    foreach {lt id} {ambient ambient light1 0  light2 1 light3 2  light4 3} {
		# convert the rrggbb value to 3 floats	    	    
		set c [string range [string tolower $tdv_lights_settings(${lt}_color)] 1 6]
		scan $c "%2x%2x%2x" r g b
		if {[set tdv_lights_settings(${lt})] == 1} {
		    set r  [expr  $tdv_lights_settings(${lt}_intensity)*($r/(255.0 + 0.0))]
		    set g  [expr  $tdv_lights_settings(${lt}_intensity)*($g/(255.0 + 0.0))]
		    set b  [expr  $tdv_lights_settings(${lt}_intensity)*($b/(255.0 + 0.0))]
		    if {$id != "ambient"} {
			$pane configure -${lt}_string "$r $g $b $tdv_lights_settings(${lt}_x) $tdv_lights_settings(${lt}_y) $tdv_lights_settings(${lt}_z) $tdv_lights_settings(${lt}_pos)"
		    } else {
			set mod_string "$r $g $b "
			$pane configure -gl_model "$mod_string"
		    }
		} else {
		    if {$id != "ambient"} { 		    
			set ${lt}_string "0.0 0.0 0.0 0.0 0.0 0.0 0"
			$pane configure -${lt}_string "0.0 0.0 0.0 0.0 0.0 0.0 0"
		    } else {
			set lighting_string "mod 0.0 0.0 0.0 "
			$pane configure -gl_model "0.0 0.0 0.0"
		    }
		}
		
	    }
	    
	    
	    # enable and set material reflectance properties
	    set m_d  $tdv_material_settings(m_d)
	    set m_a  $tdv_material_settings(m_a)
	    set m_s  $tdv_material_settings(m_s)
	    set m_sh  $tdv_material_settings(m_sh)
	    set material_string "$m_a $m_d $m_s"
	    
	    $pane configure -gl_material "$material_string"
	    $pane configure -shiny $m_sh
	    $pane configure -lighting_string "lighting_on"
	    $pane redraw
	}
	
    }
}

proc tdv_lights_edit {} {
    global tdv_lights_settings tdv_material_settings
    set buts [list {"Update" tdv_lighting_params} {"Done" {form_done .tdv_lights_options;tdv_lighting_params}} cancel]
    set d [form_init .tdv_lights_options "Lighting options" "" $buts ]
    
    
    if {$d != ""} {
	set d0 [form_label_frame $d.old "Advanced lighting" {0 0}]
	form_radiobutton ${d0}.simple "Simple lighting" tdv_lights_settings(complex) 0 "0 0"
	form_radiobutton ${d0}.complex "Complex lighting" tdv_lights_settings(complex) 1 "0 1"
	set act {{tdv_lights_settings(complex) "1"}}	
	form_button ${d0}.def "Reset complex defaults" "reset_default_lighting" "0 2"  $act
	
	set d1 [form_label_frame $d.light "Lights" {10 0} $act]
	set d2 [form_label_frame $d.mat "Materials" {20 0} $act]


	form_label ${d1}.labi "Intensity" "0 1" $act
	form_label ${d1}.labc "Color" "0 2" $act
	form_label ${d1}.labx "X" "0 6" $act
	form_label ${d1}.laby "Y" "0 7" $act
	form_label ${d1}.labz "Z" "0 8" $act
	set i 1
	foreach {lt lt_title}  {ambient "Ambient" light1 "Light 1" light2 "Light 2" light3 "Light 3" light4 "Light 4"} {
	    form_checkbutton ${d1}.lt$i $lt_title tdv_lights_settings(${lt}) "$i 0" $act
	    set act1 [concat $act [list [list tdv_lights_settings(${lt}) "1"]]]
	    form_entry  ${d1}.sc${i} tdv_lights_settings(${lt}_intensity) float "$i 1" ${act1}
	    	    
	    futil_colorentry $d1.col$i tdv_lights_settings(${lt}_color) "$i 2" ${act1}
	    if {$lt != "ambient"} {
		form_entry  ${d1}.slx${i} tdv_lights_settings(${lt}_x) float "$i 6" $act1
		form_entry  ${d1}.sly${i} tdv_lights_settings(${lt}_y) float "$i 7" $act1
		form_entry  ${d1}.slz${i} tdv_lights_settings(${lt}_z) float "$i 8" $act1
	    }
	    incr i   
	}
	
	set i 0
	foreach {mt mt_title min max inc} {m_d "Diffuse reflectance" 0.0 1.0 0.01 m_a "Ambient reflectance" 0.0 1.0 0.01 m_sh "Shininess" 1 128 1 m_s "Specular reflectance" 0.0 1.0 0.01} {
	    form_label ${d2}.lab${i} $mt_title "$i 0" $act
	    form_scale ${d2}.sc${i} tdv_material_settings(${mt}) "" horizontal $min $max $inc "$i 1" $act
	    form_entry ${d2}.e${i} tdv_material_settings(${mt}) float "$i 2" $act
	    incr i
	}

	
	form_finish bot	
    }
}

proc reset_default_lighting {} {
    global tdv_lights_settings tdv_material_settings
    
    array set tdv_lights_settings { complex 1 ambient_color \#ffffff ambient 1 ambient_intensity 0.3 light1 1 light2 1 light3 1 light1_color \#ffffff light1_intensity 0.75 light2_color \#ffffff light2_intensity 0.6  light3_color \#ffffff light3_intensity 0.4 light4 0 light4_color \#ffffff light4_intensity 0.0 light1_x 0.0 light1_y 0.0 light1_z 10.0 light1_pos 0 light2_x 0.0 light2_y 1.0 light2_z -1.0 light2_pos 0 light3_x 1.0 light3_y -2.0 light3_z -1.0 light3_pos 0 light4_x -2.0 light4_y 1.0 light4_z -1.0 light4_pos 0}
    
    array set tdv_material_settings { m_a 0.35 m_d 1.0 m_s 0.35 m_sh 15 } 
    tdv_lighting_params
}

