# AC3D
# Copyright (c) 2004, Inivis Limited. All rights reserved.

# AC3D tcl functions


#init the globals
set select_mode "tree"


#if { $tcl_platform(platform) == "windows" } {
    set old_file_dialog 0
#} else {
#    set old_file_dialog 1
#}

set tk_strictMotif 0

proc set_unsaved_changes { what } {
global unsaved_changes
    set unsaved_changes $what;
}

# the last ac file loaded or saved
set acfilename ""

set filetypes  {
{{ AC3D files} {.ac}}
{{ All files} {*.*}}
}

proc show_question { title mess } {

option add *Dialog.msg.wrapLength 60c
return [tk_messageBox -message $mess -title $title -type yesno ]
    update

#option add *Dialog.msg.wrapLength 60c
#option add *Dialog.msg system widgetDefault
#return [tk_dialog .dialog $title $mess "" -1 $b1text $b2text]

#    update
}

proc show_message { mess } {

option add *Dialog.msg.wrapLength 60c
tk_messageBox -message $mess -title "AC3D Message" -type ok
#    tk_dialog .dialog "AC3D message" $mess "" -1 "Close"
    update
}



proc get_opentexturename { title filetypes } {
global fsBox
global prefs_texture_file_path
global tcl_platform
global ac_platform

	set path $prefs_texture_file_path
    # do this on windows

    if { $tcl_platform(platform) == "windows" } {
	regsub -all / $path {\\} path 
    }

    # blank initial path on Mac fails to show dialog - . works
    if { $ac_platform == "Mac" } {
		if {$path == "" } {
	    set path "."
		}

		# dialog won't appear on Mac if this path is no longer valid - check it
		if { ![file exists $path ] } {
			set path [pwd]
		}
    }

	

    set filename [tk_getOpenFile -title $title \
        -filetypes $filetypes -initialdir $path ]

    if { $filename != "" } {
	    set path [file dirname $filename]
		}
	set prefs_texture_file_path $path
    return $filename

}



proc get_loadfilename { title filetypes } {
global tcl_platform
global prefs_load_file_path
global ac_platform

    set path $prefs_load_file_path
    # do this on windows
    if { $tcl_platform(platform) == "windows" } {
	regsub -all / $path {\\} path 
    }

    # blank initial path on Mac fails to show dialog - . works
    if { $ac_platform == "Mac" } {
		if {$path == "" } {
	    set path "."
		}

		# dialog won't appear on Mac if this path is no longer valid - check it
		if { ![file exists $path ] } {
			set path [pwd]
		}

    }

    set filename [tk_getOpenFile -title $title -filetypes $filetypes -initialdir $path ]

    if { $filename != "" } {
	    set path [file dirname $filename]
		}
	set prefs_load_file_path $path
    return $filename
}


proc get_importfilename { title filetypes } {
global tcl_platform ac_platform
global prefs_import_file_path

	set path $prefs_import_file_path
    # do this on windows
    if { $tcl_platform(platform) == "windows" } {
	regsub -all / $path {\\} path 
    }

    # blank initial path on Mac fails to show dialog - . works
    if { $ac_platform == "Mac" } {
		if {$path == "" } {
			set path "."
		}
		# dialog won't appear on Mac if this path is no longer valid - check it
		if { ![file exists $path ] } {
			set path [pwd]
		}

    }

    set filename [tk_getOpenFile -title $title \
        -filetypes $filetypes -initialdir $path ]

    if { $filename != "" } {
	    set path [file dirname $filename]
		}
	set prefs_import_file_path $path
    return $filename
}



proc get_savefilename { title filetypes { defaultextension ""} { name "" } } {
global tcl_platform ac_platform
global prefs_save_file_path

	if { [ac3d get_app_mode] == 3 } {
		ac3d menu_about
		return
	}

    set path $prefs_save_file_path

	# backslash for windows
	if { $tcl_platform(platform) == "windows" } {
		regsub -all / $path {\\} path 
	}

    # blank initial path on Mac fails to show dialog - . works
    if { $ac_platform == "Mac" } {
		if {$path == "" } {
			set path "."
		}
		# dialog won't appear on Mac if this path is no longer valid - check it
		if { ![file exists $path ] } {
			set path [pwd]
		}

    }

        set filename [tk_getSaveFile -title $title -defaultextension $defaultextension \
		     -filetypes $filetypes -initialdir $path -initialfile $name ]

    if { $filename != "" } {
	    set path [file dirname $filename]
	    set prefs_save_file_path $path

    }
    return $filename
}


proc get_exportfilename { title filetypes { defaultextension ""} { name "" } } {
global tcl_platform ac_platform
global prefs_export_file_path

	if { [ac3d get_app_mode] == 3 } {
		ac3d menu_about
		return
	}


	if { [ac3d get_app_mode] == 1 } {
		ac3d menu_about
	}

    set path $prefs_export_file_path

	# backslash for windows
	if { $tcl_platform(platform) == "windows" } {
		regsub -all / $path {\\} path 
	}

    # blank initial path on Mac fails to show dialog - . works
    if { $ac_platform == "Mac" } {
		if {$path == "" } {
			set path "."
		}
		# dialog won't appear on Mac if this path is no longer valid - check it
		if { ![file exists $path ] } {
			set path [pwd]
		}

    }

        set filename [tk_getSaveFile -title $title -defaultextension $defaultextension \
		     -filetypes $filetypes -initialdir $path -initialfile $name ]

    if { $filename != "" } {
	    set path [file dirname $filename]
	    set prefs_export_file_path $path
    }

    return $filename
}


proc get_exportfolder { title } {
global tcl_platform
global prefs_export_file_path

	if { [ac3d get_app_mode] == 3 } {
		ac3d menu_about
		return
	}

	if { [ac3d get_app_mode] == 1 } {
		ac3d menu_about
	}

    set path $prefs_export_file_path

	# backslash for windows
	if { $tcl_platform(platform) == "windows" } {
		regsub -all / $path {\\} path 
	}

    # blank initial path on Mac fails to show dialog - . works
    if { $ac_platform == "Mac" } {
		if {$path == "" } {
			set path "."
		}
		# dialog won't appear on Mac if this path is no longer valid - check it
		if { ![file exists $path ] } {
			set path [pwd]
		}
    }

	set filename [tk_chooseDirectory -title $title \
		    -initialdir $path -mustexist 1 -parent . ]

    return $filename
}



proc update_savefile_menu {} {
global acfilename UI

    set name [file tail $acfilename]
    if { $acfilename != "" } {
        $UI(menu_file) entryconfigure 8 -state normal
        $UI(menu_file) entryconfigure 8 -label "Save $name"
    } else {
	    $UI(menu_file) entryconfigure 8 -label "Save"
#        $UI(menu_file) entryconfigure 8 -state disabled
    }
}


proc update_savefile_name { fname} {
global acfilename UI
global prefs_recentfiles0
global prefs_recentfiles1
global prefs_recentfiles2
global prefs_recentfiles3

	set r [file rootname $fname]
	set extU [file extension $fname]

	#force extensionto lower case
	set ext [ string tolower $extU ]

#	set acfilename "$r.ac"

#	puts "$r  $acfilename"

	if { $ext == ".ac" } {
		set acfilename $fname
	} else {
		set acfilename ""
	}

	update_savefile_menu

	set ver [ac3d get_version_string]

	# if blank filename (to save as ac3d file) - set untitled window label
	if { $ext != ".ac" } {
		wm title . "Inivis AC3D"
	} else {
		# put the file name in the titlebar
		wm title . "Inivis AC3D - $fname"
	}


	if { ($prefs_recentfiles0 != $fname ) && ($fname != "") } {
		set prefs_recentfiles3 $prefs_recentfiles2
		set prefs_recentfiles2 $prefs_recentfiles1
		set prefs_recentfiles1 $prefs_recentfiles0

		set prefs_recentfiles0 $fname

		$UI(menu_recent) entryconfigure 0 -label $prefs_recentfiles0 
		$UI(menu_recent) entryconfigure 1 -label $prefs_recentfiles1 
		$UI(menu_recent) entryconfigure 2 -label $prefs_recentfiles2 
		$UI(menu_recent) entryconfigure 3 -label $prefs_recentfiles3 
	}

}


proc reset_recent_files_menu {} {
global prefs_recentfiles0
global prefs_recentfiles1
global prefs_recentfiles2
global prefs_recentfiles3
global UI

		$UI(menu_recent) entryconfigure 0 -label $prefs_recentfiles0 
		$UI(menu_recent) entryconfigure 1 -label $prefs_recentfiles1 
		$UI(menu_recent) entryconfigure 2 -label $prefs_recentfiles2 
		$UI(menu_recent) entryconfigure 3 -label $prefs_recentfiles3 
}



# insert a file
proc menu_merge {} {
global acfilename
global prefs_load_file_path

set filetypes  {
{{ AC3D files} {.ac}}
{{ All files} *}
}
    set filename [get_loadfilename "Merge an AC3D file" $filetypes]
    if { $filename != "" } {
        ac3d load_file $filename
        set_unsaved_changes TRUE
    }
}



proc check_save_changes { } {

global unsaved_changes
global acfilename
global prefs_load_file_path

set filetypes  {
{{ AC3D model files} {.ac}}
{{ All files} {*}}
}
    if { $unsaved_changes } {
		set answer [tk_messageBox -message "Save changes to current model?" -title "Save changes?" -type yesnocancel -icon question -parent . -default . ]
		
		if { $answer == "yes"} {
			set newname [get_savefilename "Save AC3D file" $filetypes ".ac" $acfilename]
			if { $newname != "" } {
				ac3d save_ac $newname
				update_savefile_name $newname
				set_unsaved_changes false
			} else { 
				return true
			}
		}
		if {$answer == "cancel"} {
			return false
			}
    }


}


# if filename is "" ask the user file, otherwise, ask for any save changes and load it.

proc menu_open { filename } {
global unsaved_changes
global prefs_save_settings_on_exit
global acfilename
global prefs_load_file_path

set filetypes  {
{{ AC3D model files} {.ac}}
{{ All files} {*}}
}
    if { $unsaved_changes } {
		set answer [tk_messageBox -message "Save changes to current model?" -title "Save changes?" -type yesnocancel -icon question -parent .]
		
		if { $answer == "yes"} {
			set newname [get_savefilename "Save AC3D file" $filetypes ".ac" $acfilename]
			if { $newname != "" } {
				ac3d save_ac $newname
				update_savefile_name $newname
				set_unsaved_changes false
			} else { 
				return
			}
		}

		if {$answer == "cancel"} {
			return
			}
    }

	if {$filename == "" } {
		set filename [get_loadfilename "Open an AC3D file" $filetypes]
		}

    if { $filename != "" } {
		ac3d clear_all
		ac3d redraw_all
		sync_ui
		ac3d load_file $filename
		update_savefile_name $filename

		set_unsaved_changes false
    }
	
}




proc menu_import {} {
global unsaved_changes

	ac3d load_file_select "Insert imported file"
}




proc menu_save_ac {} {
global acfilename

set filetypes  {
{{ AC3D model files} {.ac}}
{{ All files} {*}}
}

    set newname [get_savefilename "Save AC3D file" $filetypes ".ac" $acfilename]
    if { $newname != "" } {
	ac3d save_ac $newname
        update_savefile_name $newname
        set_unsaved_changes false

    }
}


proc menu_save_selection {} {

set filetypes  {
{{ AC3D model files} {.ac}}
{{ All files} {*}}
}
    set newname [get_savefilename "Save selection as AC3D file" $filetypes ".ac"]
    if { $newname != "" } {
	ac3d save_selection_ac $newname
    }

}





# save the current model with the last filename used - if blank then get filename

proc menu_save_last {} {
    global acfilename;
    set fsBox(currentfilter) 0

    if { $acfilename != "" } {
        ac3d save_ac $acfilename
        set_unsaved_changes false

    } else {
        menu_save_ac
    }
}




proc menu_quit {} {
global unsaved_changes
global prefs_save_settings_on_exit

    if { $unsaved_changes } {
    set answer [tk_messageBox -message "There are unsaved changes.\n\nExit AC3D without saving?" -title "Exit?" -type yesno -icon question]

    } else {
    set answer [tk_messageBox -message "Exit AC3D?" -title "Exit?" -type yesno -icon question]
    }
    case $answer {
        yes { if { $prefs_save_settings_on_exit } {
				ac3d save_settings
				}
              __exit
            }
        no {}
    }
}

proc menu_clear {} {
global unsaved_changes
#    if { [ tk_dialog .dialog "Delete current model?" "Clear - Are you sure?" "" -1 "Clear" "Cancel"] == 0 } {
#        ac3d clear_all
#        sync_ui
#    }


    set answer [tk_messageBox -message "Clear - Are you sure?" -title "Delete current model?" -type yesno -icon question]
    case $answer {
        yes {
             ac3d clear_all
             ac3d redraw_all
			 update_savefile_name ""
             sync_ui
			set unsaved_changes FALSE
             }
        no {}
    }
}




proc update_selected_message {} {
global select_mode
global select_info

#	set numselected [ac3d selection_get_num_vertices ]
#	set numselectedobjects [ac3d selection_get_num_objects ]
#	set numselectedsurfaces [ac3d selection_get_num_surfaces ]

	set selinfo [ac3d selection_get_info]
	set numselectedobjects	[ lindex $selinfo 0]
	set numselectedsurfaces [ lindex $selinfo 1]
	set numselectededges	[ lindex $selinfo 2]
	set numselected			[ lindex $selinfo 3]


    if { ( $numselected == 0 ) && ( $numselectedobjects == 0 ) && ( $numselectedsurfaces == 0 )} {
        set select_info "Nothing selected"
        return
    }

    if { $select_mode == "tree" } {
        set select_info "Groups/Objects selected: $numselectedobjects"
    } elseif { $select_mode == "object" } {
        set select_info "Objects selected: $numselectedobjects"
   } elseif { $select_mode == "surface" } {
        set select_info "Surfaces selected: $numselectedsurfaces"
    } elseif { $select_mode == "light" } {
        set select_info "Lights selected: $numselectedobjects"
    } else {
        set select_info "Vertices selected: $numselected"
    }
#    set_unsaved_changes true

}




proc menu_set_sensitive { name bool } {
global tcl_version ac_platform

    if { $bool } {
	    set t normal
	} else {
	    set t disabled
	}

	# account for the Macs extra menu
	if { $ac_platform == "Mac" } {
		set offset 1
	} else {
		set offset 0
	}

        set m .mbar
        switch $name {
	        object { $m entryconfigure [expr $offset + 3] -state $t }
	    	surface { $m entryconfigure [expr $offset + 4] -state $t  }
			vertex {$m entryconfigure [expr $offset + 5] -state $t }
	    }

}



proc sync_ui {} {
    global select_mode
    global objects_are_hidden
	global objects_are_locked
    global undo_count
    global undo_string
    global cp toolbar UI

    # the control panel widget

	# get the selection info
	set selinfo [ac3d selection_get_info]
	set numselectedobjects	[ lindex $selinfo 0]
	set numselectedsurfaces [ lindex $selinfo 1]
	set numselectededges	[ lindex $selinfo 2]
	set numselected			[ lindex $selinfo 3]

#puts "tcl objects are locked $objects_are_locked";


#puts "selectedmode $select_mode    $numselected $numselectedobjects"

    if { ( $numselectedobjects == 1 ) } {
        enable_object_data
    } else {
        disable_object_data
    }


    if { ( $numselected == 0 ) && ($numselectedsurfaces == 0 ) && ( $numselectedobjects == 0 ) } {
    # NOTHING IS SELECTED
        set_sensitive false \
              $UI(function_group)\
              $UI(function_ungroup)\
              $UI(hide_selected)\
			  $UI(lock_selected)\
              $toolbar.function_mirrorx \
              $toolbar.function_mirrory \
              $toolbar.function_mirrorz 
#              $cp.function_double_size\
#              $cp.function_half_size\
#              $cp.function_plus_size\
#              $cp.function_minus_size


        menu_set_sensitive object false
        menu_set_sensitive surface false
        menu_set_sensitive vertex false
        set_sensitive false $UI(extrude_button)

        #disable surface type stuff
        set_sensitive false \
           $UI(function_surface_poly) \
           $UI(function_surface_polyline) \
           $UI(function_surface_line) \
           $UI(function_surface_smooth) \
           $UI(function_surface_flat) \
           $UI(function_surface_one_sided) \
           $UI(function_surface_two_sided)

        # DISABLE SOME MENU ITEMS


        # EDIT MENU
        # cut and copy
        .mbar.edit.menu entryconfigure 3 -state disabled
        .mbar.edit.menu entryconfigure 4 -state disabled

        # duplicate
        .mbar.edit.menu entryconfigure 6 -state disabled

        # select nothing
        .mbar.edit.menu entryconfigure 9 -state disabled

        # select whole surfaces
        .mbar.edit.menu entryconfigure 11 -state disabled


		#group/ungroup 
		.mbar.edit.menu entryconfigure 14 -state disabled
		.mbar.edit.menu entryconfigure 15 -state disabled

        # move to , size to, rotate, scale
#        .mbar.edit.menu entryconfigure 12 -state disabled
#        .mbar.edit.menu entryconfigure 13 -state disabled
#        .mbar.edit.menu entryconfigure 14 -state disabled
#        .mbar.edit.menu entryconfigure 15 -state disabled

        #delete
        .mbar.edit.menu entryconfigure 17 -state disabled



        #view->fit&goto selection
        .mbar.view.menu entryconfigure 1 -state disabled
#        .mbar.view.menu entryconfigure 2 -state disabled
        #view->3d_view selection
#        .mbar.view.menu entryconfigure 5 -state disabled



    } else {
    # SOMETHING IS SELECTED

    # enable functions that work on objects and vertices
        set_sensitive true \
              $UI(hide_selected) \
              $UI(lock_selected) \
              $toolbar.function_mirrorx \
              $toolbar.function_mirrory \
              $toolbar.function_mirrorz 
#              $cp.function_double_size\
#              $cp.function_half_size\
#              $cp.function_plus_size\
#             $cp.function_minus_size


        #Enable surface type stuff
        set_sensitive true \
           $UI(function_surface_poly) \
           $UI(function_surface_polyline) \
           $UI(function_surface_line) \
           $UI(function_surface_smooth) \
           $UI(function_surface_flat) \
           $UI(function_surface_one_sided) \
           $UI(function_surface_two_sided)


#        menu_set_sensitive surface true

        # ENABLE SOME MENU ITEMS



        # cut and copy
        .mbar.edit.menu entryconfigure 3 -state normal
        .mbar.edit.menu entryconfigure 4 -state normal

        # duplicate
        .mbar.edit.menu entryconfigure 6 -state normal

        # select nothing
        .mbar.edit.menu entryconfigure 9 -state normal


        # move to , size to, rotate, scale
#        .mbar.edit.menu entryconfigure 12 -state normal
#        .mbar.edit.menu entryconfigure 13 -state normal
#        .mbar.edit.menu entryconfigure 14 -state normal
#        .mbar.edit.menu entryconfigure 15 -state normal

        #delete
        .mbar.edit.menu entryconfigure 17 -state normal


        #view->fit&goto selection
        .mbar.view.menu entryconfigure 1 -state normal
#        .mbar.view.menu entryconfigure 2 -state normal
        #view->3d_view selection
#        .mbar.view.menu entryconfigure 5 -state normal

	# extrude now in any mode - nope, only surface and vertex now
#	set_sensitive true $UI(extrude_button)



        if { $select_mode == "tree"} {

			 if { $numselectedobjects == 0 } {
				 set_sensitive FALSE $UI(function_group) $UI(function_ungroup) 
				 #group/ungroup 
				 .mbar.edit.menu entryconfigure 14 -state disabled
				.mbar.edit.menu entryconfigure 15 -state disabled
			 } elseif { $numselectedobjects == 1 } {
				 set_sensitive TRUE $UI(function_ungroup) 
				 set_sensitive FALSE $UI(function_group)
				# one obejct slected - enable ungroup, diable group
				.mbar.edit.menu entryconfigure 14 -state disabled
				.mbar.edit.menu entryconfigure 15 -state normal
			 } elseif { $numselectedobjects > 1 } {
				 set_sensitive TRUE $UI(function_group) $UI(function_ungroup)
				# group ungroup menus
				 .mbar.edit.menu entryconfigure 14 -state normal
				.mbar.edit.menu entryconfigure 15 -state normal
			 }

        } else { #disable group/ungroup for any mode apart from TREE
            set_sensitive FALSE $UI(function_group) $UI(function_ungroup) 
			# disable group and ungroup menus
			.mbar.edit.menu entryconfigure 14 -state disabled
			.mbar.edit.menu entryconfigure 15 -state disabled

        }


        menu_set_sensitive surface false
        menu_set_sensitive vertex false

		set_sensitive false $UI(extrude_button)

		if {( $select_mode == "object" ) || ( $select_mode == "tree" )} {
            menu_set_sensitive surface true
		}

        if {( $select_mode == "vertex" ) } {
			set_sensitive true $UI(extrude_button)
            menu_set_sensitive surface true
            menu_set_sensitive vertex true

        } else {
#            menu_set_sensitive surface false
#            menu_set_sensitive vertex false
        }

		if { $select_mode == "surface"} {
			set_sensitive true $UI(extrude_button)
            menu_set_sensitive surface true
            menu_set_sensitive vertex true

		} else {
#
		}

        if { $select_mode != "vertex" } {
            #set_sensitive true $UI(extrude_button)
#            menu_set_sensitive vertex false
           # disable EDIT->select whole surfaces
           .mbar.edit.menu entryconfigure 11 -state disabled

        } else {
            #set_sensitive false $UI(extrude_button)
#            menu_set_sensitive vertex true
           # enable EDIT->select whole surfaces
           .mbar.edit.menu entryconfigure 11 -state normal
        }
        


        if { ( $numselectedobjects == 0 ) } {
            menu_set_sensitive object false
        } else {
            menu_set_sensitive object true
        }
    }

    # set up the UNDO buttons and menu item
    .mbar.edit.menu entryconfigure 0 -label "$undo_string"

    if { ( $undo_count != 0 ) } {
#        set_sensitive true $cp.function_undo
        .mbar.edit.menu entryconfigure 0 -state normal
    } else {
#        set_sensitive false $cp.function_undo   
        .mbar.edit.menu entryconfigure 0 -state disabled
     
    }
        
    if { ( $objects_are_hidden ) } {
        set_sensitive true $UI(unhide)
    } else {
        set_sensitive false $UI(unhide)
    }

    if { ( $objects_are_locked ) } {
        set_sensitive true $UI(unlock)
    } else {
        set_sensitive false $UI(unlock)
    }

	update_selected_message

    update idletasks
}


proc set_undo_string {str } {
global undo_string
global cp

    if { $str == "" } {
        set undo_string "Nothing to Undo"
        .mbar.edit.menu entryconfigure 0 -state disabled
    } else {
        set undo_string "Undo $str"
        .mbar.edit.menu entryconfigure 0 -state normal
    }
    # set up the UNDO buttons and menu item
    .mbar.edit.menu entryconfigure 0 -label $undo_string
    # the text on the undo button will update because the variable is linked to it    

    set_unsaved_changes true
}


proc set_redo_string {str } {
global redo_string
global cp

    if { $str == "" } {
        set redo_string "Redo"
        .mbar.edit.menu entryconfigure 1 -state disabled
    } else {
        set redo_string "Redo $str"
        .mbar.edit.menu entryconfigure 1 -state normal
    }
    # set up the UNDO buttons and menu item
    .mbar.edit.menu entryconfigure 1 -label $redo_string

    set_unsaved_changes true
}


proc set_raised { args } {
    foreach i $args {
        $i configure -relief raised
    }
}

proc set_sunken { args } {
    foreach i $args {
        $i configure -relief sunken
    }
}


proc set_select_mode_ui { newmodename } {
global select_mode
#global numselectedobjects
#puts "set_select_mode_ui $select_mode $numselectedobjects new $newmodename\n"

    # set the tcl variable 
    set select_mode $newmodename

    # display message regarding current selection
    sync_ui

}



# a DRAG MODE button was pressed or this proc was called from C prog

proc set_drag_mode_ui { newmodename  } {
global drag_mode

    # set the tcl variables for the DRAG MODE
    set drag_mode $newmodename

}



proc set_draw_mode_ui { newmodename  } {
global draw_mode

    # set the  tcl variables for the DRAW MODE
    set draw_mode $newmodename
}






proc ScrolledHorizCanvas { c width height region } {
	frame $c
	canvas $c.canvas -width $width -height $height \
		-xscrollcommand "$c.xscroll set" \
		-scrollregion $region 

	scrollbar $c.xscroll -orient horizontal  \
		-command "$c.canvas xview" 


	pack $c.xscroll -side bottom -fill x
	pack $c.canvas -side left -fill both -expand true

	set f [frame $c.canvas.f -bd 0]

	$c.canvas create window 0 0 -anchor nw -window $f

	return $c
}

proc WORKINGScrolledHorizCanvas { c width height region } {
	frame $c
	canvas $c.canvas -width $width -height $height \
		-xscrollcommand [list $c.xscroll set] 
#		-scrollregion $region 

#        $c.canvas configure -scrollregion $region

	scrollbar $c.xscroll -orient horizontal \
		-command [list $c.canvas xview]

	pack $c.xscroll -side bottom -fill x
	pack $c.canvas -side left -fill both -expand true
#	pack $c -side top -fill both -expand true

	set f [frame $c.canvas.f -bd 0]

	$c.canvas create window 0 0 -anchor nw -window $f

#	return $c.canvas
}


proc ScrolledCanvas { c width height region } {
	frame $c
	canvas $c.canvas -width $width -height $height \
		-scrollregion $region \
		-xscrollcommand [list $c.xscroll set] \
		-yscrollcommand [list $c.yscroll set]
	scrollbar $c.xscroll -orient horizontal \
		-command [list $c.canvas xview]
	scrollbar $c.yscroll -orient vertical \
		-command [list $c.canvas yview]
	pack $c.xscroll -side bottom -fill x
	pack $c.yscroll -side right -fill y
	pack $c.canvas -side left -fill both -expand true
	pack $c -side top -fill both -expand true

	set f [frame $c.canvas.f -bd 0]

	$c.canvas create window 0 0 -anchor nw -window $f

	return $c.canvas
}




# loop though list of buttons and set their state 

proc set_state {state args } {
    foreach i $args {
        $i configure -state $state
    }
}



proc set_sensitive { bool args } {
global bindings

    if { $bool } {
        set state normal
    } else {
        set state disabled
    }


    foreach i $args {
        set type [winfo class $i]
         if { $type == "Label" } {
            if { $bool } {
			    $i configure -fg black
                catch { 
					if { $bindings($i) != "" } {
						 bindtags $i $bindings($i)
					}               
				}
			} else {  #disable
			    $i configure -fg #a3a3a3
                set poo [bindtags $i]
                if { $poo != "none" } {
				    set bindings($i) [bindtags $i]
                }
				bindtags $i { none }			
			}			 
		 } else {
             $i configure -state $state
         }
    }

}





set update_textures 1

proc update_texture_rep { tx ty} {
global update_textures
    if {!$update_textures} {return}
    ac3d set_texture_repeats $tx $ty
    ac3d redraw_all
}
proc update_texture_offsets { tox toy actual} {
global update_textures

    if {!$update_textures} {return}
    ac3d set_texture_offsets $tox $toy
    ac3d redraw_all
}






set texture_repeat_x 1.0
set texture_repeat_y 1.0
set texture_offset_x 0.0
set texture_offset_y 0.0

proc menu_edit_texture_repeats {} {
global update_textures
global texture_repeat_x texture_repeat_y
global texture_offset_x texture_offset_y

    set texdata [ac3d get_texture_repoff]
    set texture_repeat_x [lindex $texdata 0]
    set texture_repeat_y [lindex $texdata 1]
    set texture_offset_x [lindex $texdata 2]
    set texture_offset_y [lindex $texdata 3]

   if ![winfo exists .t] {
    new_toplevel .t "Set Texture repeats"

    frame .t.f1
    label .t.l1 -text "Texture repeat X"
    entry .t.tx -textvariable texture_repeat_x  -width 5
    button .t.xl -text "<" -command { set texture_repeat_x [expr $texture_repeat_x - 1.0]; if { $update_textures } {update_texture_rep $texture_repeat_x $texture_repeat_y}}
    button .t.xr -text ">" -command { set texture_repeat_x [expr $texture_repeat_x + 1.0]; if { $update_textures } {update_texture_rep $texture_repeat_x $texture_repeat_y}}
    pack .t.l1 .t.tx .t.xl .t.xr -in .t.f1 -side left

    frame .t.f2
    label .t.l2 -text "Texture repeat Y"
    entry .t.ty -textvariable texture_repeat_y  -width 5
    button .t.yl -text "<" -command { set texture_repeat_y [expr $texture_repeat_y - 1.0]; if { $update_textures } {update_texture_rep $texture_repeat_x $texture_repeat_y}}
    button .t.yr -text ">" -command { set texture_repeat_y [expr $texture_repeat_y + 1.0]; if { $update_textures } {update_texture_rep $texture_repeat_x $texture_repeat_y}}
    pack .t.l2 .t.ty .t.yl .t.yr -in .t.f2 -side left
    bind .t.tx <Leave> { update_texture_rep $texture_repeat_x $texture_repeat_y}
    bind .t.tx <Return> { update_texture_rep $texture_repeat_x $texture_repeat_y}
    bind .t.ty <Leave> { update_texture_rep $texture_repeat_x $texture_repeat_y}
    bind .t.ty <Return> { update_texture_rep $texture_repeat_x $texture_repeat_y}

    pack .t.f1 .t.f2 -side top

    frame .t.f3
    label .t.l3 -text "Texture offset X"
    scale .t.stoy -length 5c -from -1.0 -to 1.0  \
        -orient horizontal -resolution 0.001 -variable texture_offset_x -showvalue 0 \
        -command {update_texture_offsets $texture_offset_x $texture_offset_y}
    entry .t.toy -textvariable texture_offset_x -width 5
    pack .t.l3 .t.stoy  .t.toy -side left -in .t.f3
    pack .t.f3 -side top

    frame .t.f4
    label .t.f4.l4 -text "Texture offset Y"
    scale .t.f4.stoy -length 5c -from -1.0 -to 1.0  \
        -orient horizontal -resolution 0.001 -variable texture_offset_y -showvalue 0 \
        -command {update_texture_offsets $texture_offset_x $texture_offset_y}
    entry .t.f4.toy -textvariable texture_offset_y -width 5
    pack .t.f4.l4 .t.f4.stoy .t.f4.toy -side left
    pack .t.f4 -side top





    button .t.ok -text "Close" -command " destroy .t"
    button .t.apply -text "Apply" -command {
        update_texture_rep $texture_repeat_x $texture_repeat_y
        update_texture_offset $texture_offset_x $texture_offset_y 0}

    ac_checkbutton .t.rtu "Realtime update" "ac3d redraw_3d " update_textures "redraw the 3D views after each change"

    pack .t.rtu
    pack .t.ok .t.apply -side left
    centre_window_on_screen .t
    }

}


set balloon_delay 250

if { $ac_platform == "Mac" } { set balloon_delay 1000 }

bind balloon <Enter> {

#&& [%W cget -state] != "disabled"
    if {[info exists balloonHelp(%W)] && $prefs_balloon_help} {
            set balloonHelp(%W,after) [after $balloon_delay {showBalloonHelp %W "$balloonHelp(%W)"}]
    }
}

bind balloon <Leave> {
    unShowBalloonHelp %W
}

bind balloon <Any-KeyPress> {
    unShowBalloonHelp %W
}

bind balloon <Any-Button> {
    unShowBalloonHelp %W
}

proc showBalloonHelp {w message} {
    global balloonHelp
    global tcl_platform ac_platform

    set border 1
    if { $ac_platform == "Mac"} { set border 0 }

        if ![winfo exists .balloon] {
            toplevel .balloon
# mac window takes focus - can't find fix so far ... 
#::tk::unsupported::MacWindowStyle style .balloon help noActivates

            wm overrideredirect .balloon true
	    wm transient .balloon $w
            pack [label .balloon.l \
                    -foreground black \
                    -background #ffffd0 \
                    -relief solid \
                    -borderwidth $border \
                    -highlightthickness 1 \
                    -highlightbackground #000000]
            wm withdraw .balloon
        }
        .balloon.l configure -text $message
        update idletasks


        set x [expr [winfo pointerx .]+16]
        set y [expr [winfo pointery .]+16]

		set width [winfo width .balloon ]
		set height [winfo height .balloon ]

	    set swidth [expr [winfo screenwidth $w] - $width]
		set sheight [expr [winfo screenheight $w] - $height]

		# try to keep the balloon on screen
		if { $x > $swidth } {
			set x $swidth
		}

		if { $y > $sheight } {
			set y $sheight
		}

		if { $y > [expr $sheight/2] } {
			set y [expr $y - $height]
		}

        wm withdraw .balloon 
        raise .balloon 
        wm geometry .balloon "+$x+$y"

        wm deiconify .balloon
        if { $tcl_platform(platform) == "windows" } {
            wm geometry .balloon "+$x+$y"  
        }

}

proc unShowBalloonHelp {w} {
    global balloonHelp
    if [info exists balloonHelp($w,after)] {
        after cancel $balloonHelp($w,after)
        unset balloonHelp($w,after)
    }
    catch {wm withdraw .balloon}
}

proc add_balloon { wid message } {
global balloonHelp

    set balloonHelp($wid) $message
    bindtags $wid "[bindtags $wid] balloon"
}


# change text of an existing balloon
proc set_balloon { wid message } {
global balloonHelp

    set balloonHelp($wid) $message
}


proc add_menu_balloons { win message_list} {
global balloon_menu_help

#puts "adding balloons to $win"
#    bind $win <Motion> {+unShowBalloonHelp %W; balloon_menu_motion %W %y %s}
#    bind $win <Any-KeyPress> {+unShowBalloonHelp %W}
#    bind $win <Leave> {+unShowBalloonHelp %W}
#    bind $win <ButtonRelease> {+unShowBalloonHelp %W}

#puts "add_menu_balloons - index active doesn't work on the mac"

	bind Menu <<MenuSelect>> { handle_balloon_menu_entry %W [%W index active]}

    set balloon_menu_help($win) $message_list
#puts "LIST \n$message_list\n\nend\n\n"
}


proc balloon_menu_motion {w y s} {
global prefs_balloon_help

    set oldy -1
    set idx 0
    set newy [$w yposition $idx]

    if { ! $prefs_balloon_help } {return}
    while {$oldy != $newy} {
        if {$y < $newy} {
            set idx [expr $idx - 1]
            handle_balloon_menu_entry $w $idx
            return
        }
        set oldy $newy
        incr idx
        set newy [$w yposition $idx]
    }
    set idx [expr $idx-1]
    handle_balloon_menu_entry $w $idx
}


proc handle_balloon_menu_entry {w i} {
   global balloon_menu_help
   global balloonHelp
   global prefs_balloon_help

#puts "handle_balloon_menu_entry w=$w i=$i"

if {$i == "none"} {
#puts "sending blank"
#	display_message ""
	return
	}

set start [string range $w 0 5]
set rest [string range $w 7 end]

#    if { $start == ".#mbar" } {
#	set c ""
#	for { set n 0 } { $n < [string length $rest] } {incr n} {
#		set char [string range $rest $n $n]
#		if { $char == "#" } {
#			set char "."
#			}
#		set c "$c$char"
#		}
#		set w $c
#		}


# replace # with .
regsub -all "\\.#" $w "." w
#puts "$w is now $w"

# replace .. with .
regsub -all "#" $w "." w

if { $start == ".#mbar" } {
	#remove .mbar from start
	regsub "\\.mbar" $w "" w
}

#puts "$w is now 2 $w"

    if {!([info exists balloon_menu_help($w)] && $prefs_balloon_help)} {
#        puts "no help for menu $w"
		return;
        }

display_message [lindex $balloon_menu_help($w) $i]
#puts [lindex $balloon_menu_help($w) $i]

return;

}





proc menu_position_cursor {} {
global poscur_x poscur_y poscur_z

	set top .poscursor

	# put current cursor pos into these globals so that they can be editied in the fields
	set c [ac3d get_3d_cursor]
	set poscur_x [lindex $c 0]
	set poscur_y [lindex $c 1]
	set poscur_z [lindex $c 2]

  if ![winfo exists $top] {
		new_toplevel $top "Position cursor"

		set m1 [param_setting_edit_point  $top poscur_x poscur_y poscur_z "Cursor" "XYZ coordinate of new cursor position" 4]
		set mb2 [param_setting_button $top "Get"  { set c [ac3d get_3d_cursor]; set poscur_x [lindex $c 0] ; set poscur_y [lindex $c 1] ; set poscur_z [lindex $c 2] } "put the position of the cursor in these fields" ]

		set tf [param_setting_frame $top]
		set mb [button $tf.b1 -text  "Set" -command {ac3d set_3d_cursor  $poscur_x $poscur_y $poscur_z} ]
		add_balloon $mb "Move the cursor to this point"
		set mb2 [button $tf.b2 -text "Set to origin"  -command {set poscur_x 0;set poscur_y 0; set poscur_z 0; ac3d set_3d_cursor  0 0 0 } ]
		add_balloon $mb2 "set cursor to origin"

		pack $mb -side left
		pack $mb2 -side left

		add_balloon $mb "Move the cursor to 0, 0, 0"

#		set mb [button $tf.b2 -text "Set to selection"  -command {ac3d set_3d_cursor  0 0 0 } ]
#		add_balloon $mb "Move the cursor to the center of the current selection"
#		pack $mb -side left

		set f [param_setting_frame $top]
		set ok [button $f.ok -text "Close" -command "destroy $top"]
		pack $ok -pady 5
	}

    centre_window_on_screen $top
}




proc dialog_addtext {} {
    new_toplevel .at "Add Text"

    label .at.lab -text "Enter text"
    grid .at.lab -row 0 -column 0 -columnspan 2

    label .at.lab2 -text "Font file"
    grid .at.lab2 -row 1 -column 0   -sticky we
    add_balloon .at.lab2 "This should be an AC3D font file"

    entry .at.fp -relief sunken -bd 2 -textvariable prefs_fontpath
    grid .at.fp -row 1 -column 1 -columnspan 2  -sticky we

    label .at.lab3 -text "Text"
    grid .at.lab3 -row 2 -column 0   -sticky we

    entry .at.text -relief sunken -bd 2 
    grid .at.text -row 2 -column 1 -columnspan 2  -sticky we
    bind .at.text <Return> {
        ac3d add_text [%W get]
        destroy .at
        }
    focus .at.text

	frame .at.bf
	grid .at.bf -row 3 -columnspan 2
	 
    button .at.bf.ok -text "Create" -command { ac3d add_text [.at.text get] ; destroy .at }
    button .at.bf.cancel -text "Cancel" -command "destroy .at"
pack .at.bf.ok -side left -expand 1 -padx 3m -pady 2m
pack .at.bf.cancel -side left -expand 1 -padx 3m -pady 2m
#    grid .at.ok -row 3 -column 0 -sticky we
#    grid .at.cancel -row 3 -column 1 -sticky we
    centre_window_on_screen .at
    grab .at

}

proc dialog_select_by_name {} {
global select_mode

    new_toplevel .at "Select by name"

    set poo  "Enter name of object/s to be appended to selection"
    if { $select_mode == "tree" } {
        set poo "TREE edit mode - whole groups containing\nnamed subobject/s will be selected\n\n$poo"
        }
    label .at.lab -text $poo
    grid .at.lab -row 0 -column 0 -columnspan 3

    entry .at.text -relief sunken -bd 2 
    bind .at.text <Return> {
        ac3d select_by_name [%W get]
        destroy .at
        }
    grid .at.text -row 1 -column 0 -columnspan 3  -sticky we

    focus .at.text

    button .at.ok -text "Select" -command { ac3d select_by_name [.at.text get] }
    button .at.ok2 -text "Unselect" -command { ac3d unselect_by_name [.at.text get] }
    button .at.cancel -text "Close" -command "destroy .at"
    grid .at.ok -row 2 -column 0 -sticky we
    grid .at.ok2 -row 2 -column 1 -sticky we
    grid .at.cancel -row 2 -column 2 -sticky we
    centre_window_on_screen .at

    grab .at
}




proc dialog_sizeto {} {
global sizex
global sizey
global sizez

    set size [ac3d get_selection_size]
    set sizex [lindex $size 0]
    set sizey [lindex $size 1]
    set sizez [lindex $size 2]

  if ![winfo exists .st] {
    new_toplevel .st "Size selection"

    label .st.title -text "Size selection \n (-1 for no change)"
    add_balloon .st.title "Resizes the selection to the specified dimensions.\nEnter -1 for no change\nExpressions can be entered."
    label .st.labx -text "X"
    label .st.laby -text "Y"
    label .st.labz -text "Z"
    entry .st.textx -relief sunken -bd 2 -width 9 -justify right -textvariable sizex
    entry .st.texty -relief sunken -bd 2  -width 9 -justify right -textvariable sizey
    entry .st.textz -relief sunken -bd 2  -width 9 -justify right -textvariable sizez

    button .st.get_size -text "Get size" -command {
        set size [ac3d get_selection_size]
        set sizex [lindex $size 0]
        set sizey [lindex $size 1]
        set sizez [lindex $size 2]
	}
    add_balloon .st.get_size "Fill these fields with the size of the current selection"

    grid .st.get_size -row 0 -column 2 -sticky we

    grid .st.title -row 0 -column 0 -columnspan 2 -sticky we
    grid .st.labx -row 1 -column 0 -sticky we
    grid .st.laby -row 2 -column 0 -sticky we
    grid .st.labz -row 3 -column 0 -sticky we
    grid .st.textx -row 1 -column 1 -sticky we
    grid .st.texty -row 2 -column 1 -sticky we
    grid .st.textz -row 3 -column 1 -sticky we
    button .st.ok -text "Size" -command { ac3d size_to [expr $sizex] [expr $sizey] [expr $sizez] }
    button .st.cancel -text "Close" -command "destroy .st"
    grid .st.ok -row 4 -column 0 -sticky we
    grid .st.cancel -row 4 -column 1 -sticky we
    centre_window_on_screen .st
    } else {
        wm deiconify .st
        raise .st

    }

    focus .st.textx
#    grab .st
}


proc dialog_moveto {} {
global posx
global posy
global posz

    set pos [ac3d get_selection_centre]
    set posx [lindex $pos 0]
    set posy [lindex $pos 1]
    set posz [lindex $pos 2]
    
  if ![winfo exists .mt] {

    new_toplevel .mt "Move selection"

    label .mt.title -text "Move selection (centre point of)"
    label .mt.labx -text "X"
    label .mt.laby -text "Y"
    label .mt.labz -text "Z"
    entry .mt.textx -relief sunken -bd 2 -width 9 -justify right -textvariable posx
    entry .mt.texty -relief sunken -bd 2  -width 9 -justify right -textvariable posy
    entry .mt.textz -relief sunken -bd 2  -width 9 -justify right -textvariable posz
    grid .mt.title -row 0 -column 0 -columnspan 2 -sticky we
    grid .mt.labx -row 1 -column 0 -sticky we
    grid .mt.laby -row 2 -column 0 -sticky we
    grid .mt.labz -row 3 -column 0 -sticky we
    grid .mt.textx -row 1 -column 1 -sticky we
    grid .mt.texty -row 2 -column 1 -sticky we
    grid .mt.textz -row 3 -column 1 -sticky we
    button .mt.ok -text "Move" -command { ac3d move_to [expr $posx] [expr $posy] [expr $posz] }
    button .mt.cancel -text "Close" -command "wm withdraw .mt"
    grid .mt.ok -row 4 -column 0 -sticky we
    grid .mt.cancel -row 4 -column 1 -sticky we
    centre_window_on_screen .mt
    } else {
        wm deiconify .mt
        raise .mt
    }
    focus .mt.textx

#    grab .st
}

proc dialog_scale {} {
global scalex
global scaley
global scalez

    set scalex 100
    set scaley 100
    set scalez 100

  if ![winfo exists .sc] {
    new_toplevel .sc "Scale selection"

    label .sc.title -text "Scale selection \n (100% for no change)"
    label .sc.labx -text "X%"
    label .sc.laby -text "Y%"
    label .sc.labz -text "Z%"
    entry .sc.textx -relief sunken -bd 2 -width 9 -justify right -textvariable scalex
    entry .sc.texty -relief sunken -bd 2  -width 9 -justify right -textvariable scaley
    entry .sc.textz -relief sunken -bd 2  -width 9 -justify right -textvariable scalez
    grid .sc.title -row 0 -column 0 -columnspan 2 -sticky we
    grid .sc.labx -row 1 -column 0 -sticky we
    grid .sc.laby -row 2 -column 0 -sticky we
    grid .sc.labz -row 3 -column 0 -sticky we
    grid .sc.textx -row 1 -column 1 -sticky we
    grid .sc.texty -row 2 -column 1 -sticky we
    grid .sc.textz -row 3 -column 1 -sticky we
    button .sc.ok -text "Scale" -command { ac3d scale [expr $scalex/100.0] [expr $scaley/100.0] [expr $scalez/100.0] ; sync_ui}
    button .sc.cancel -text "Close" -command "destroy .sc"
    grid .sc.ok -row 4 -column 0 -sticky we
    grid .sc.cancel -row 4 -column 1 -sticky we
    centre_window_on_screen .sc
    } else {
        wm deiconify .sc
        raise .sc
    }

    focus .sc.textx
}



proc set_FOV { viewid val } {
#called from scale

	ac3d view_camera_set_fov $viewid $val
}


proc dialog_FOV { viewid } {
global prefs_fov

    new_toplevel .at "Field of view"

	set current_dialog_fov [ ac3d view_camera_get_fov $viewid]

    scale .at.scale -label FOV -from 1 -to 180 -orient horizontal -command " set_FOV $viewid"
    .at.scale set $current_dialog_fov

    grid .at.scale -row 0 -column 0 -sticky we  -columnspan 2
    button .at.ok -text "Set default (50)" -command "  ac3d view_camera_set_fov $viewid 50; destroy .at "
    button .at.cancel -text "Close" -command "destroy .at"
    grid .at.ok -row 2 -column 1 -sticky we
    grid .at.cancel -row 2 -column 0 -sticky we
    grab .at
    centre_window_on_screen .at
}

set message_after ""

proc display_message {mess} {
global message
global message_after

#puts "display message '$mess'!!!!!!!!\n"

    if { $message_after != ""} {
        catch {after cancel $message_after }
    }
    set message $mess
    set message_after [after 5000 {set message ""; set message_after "" }]
#update causes probs- allows new events to be processed before orig have finished
    update idletasks
}


proc set_progress_bar {percent} {
#puts "progressbar $percent"

	if { $percent == 0 } {
		.progressbar configure -bd 0
	} else {
		.progressbar configure -bd 2
	}


    set w [winfo width .progressbar]
    set h [winfo width .progressbar]
    set nw [expr $w/100.0*$percent]
    .progressbar coords rect 0 0 $nw  $h
    update idletasks
}




proc make_info_window {w title text {refresh ""}} {
global ac_platform

    new_toplevel $w $title

     text $w.text -width 80 -height 25 \
             -yscrollcommand "$w.ys set" \
             -xscrollcommand "$w.xs set" \
             -wrap none -padx 4 -pady 4 \
             -exportselection true 

     scrollbar $w.ys -command "$w.text yview" 
     scrollbar $w.xs -command "$w.text xview" -orient horizontal

     frame $w.f

     button $w.f.b -text "Close" -command "wm withdraw $w" 
     pack $w.f.b  -side left

    if {$refresh != ""} {
         button $w.f.b2 -text "Refresh" -command $refresh
         pack $w.f.b2  -side left
         }

     pack $w.f  -side bottom
     pack $w.ys -side left -fill y -expand 0
     pack $w.xs  -side bottom -fill both -expand 0
     pack $w.text -side left -fill both -expand 1
     centre_window_on_screen $w


    $w.text insert end $text
    $w.text see end
    wm deiconify $w
    raise $w
}


proc info_window_set_text { w text} {
    $w.text delete 0.0 end
    $w.text insert end $text
    $w.text see end
}




proc menu_info {} {
    set info [ac3d get_info]

    if ![winfo exists .inf] {
        make_info_window .inf "Model Information" $info {info_window_set_text .inf [ac3d get_info]}
    } else {
        wm deiconify .inf
        info_window_set_text .inf [ac3d get_info]
        raise .inf
    }
}


proc menu_about_importers {} {
    set info [ac3d get_importer_info]

    if ![winfo exists .importers] {
        make_info_window .importers "Importer Information" $info } else {
        wm deiconify .importers
        raise .importers
    }
}


proc menu_about_exporters {} {
    set info [ac3d get_exporter_info]

    if ![winfo exists .exporters] {
        make_info_window .exporters "Exporter Information" $info } else {
        wm deiconify .exporters
        raise .exporters
    }
}



proc menu_about_plugins {} {
global plist ac_platform

    set info [ac3d get_plugin_info_all]

	set plist [ac3d get_plugin_list]
	set plist [lsort -dictionary $plist]

	new_toplevel .pinfo "About plugins"
	set w .pinfo

	set f1 [ frame $w.f1] 

	label $f1.t -text "Plugin list:"  -justify left -anchor w
	pack $f1.t -side left -padx 10 -pady 5

	cbutton $f1.cb "Copy to clipboard" {
		set c ""
		foreach i $plist {
			set about [ac3d get_plugin_about $i]
			set c "$c\n$about" 
		} 
		clipboard clear
		clipboard append $c
	} "Copy the list of plugins into the clipboard"

	pack $f1.cb -side right -padx 10 -pady 2
	pack $f1 -side top -fill x

	frame $w.f
	listbox $w.f.list -height 6 -yscrollcommand "$w.f.listscroll set "
    scrollbar $w.f.listscroll -orient vertical \
		-command " $w.f.list yview "


    button .pinfo.b -text "Close" -command "destroy .pinfo" 
    pack .pinfo.b  -side bottom -pady 5

	pack $w.f.listscroll -side left -fill both
	pack $w.f.list -fill x
	pack $w.f -fill x -padx 10 -pady 5

     text $w.text -width 80 -height 10 \
             -yscrollcommand "$w.ys set" \
             -wrap none -padx 4 -pady 4 \
             -exportselection true -wrap word
#			-xscrollcommand "$w.xs set" 

     scrollbar $w.ys -command "$w.text yview" 
#     scrollbar $w.xs -command "$w.text xview" -orient horizontal

     pack $w.ys -side left -fill y -expand 0
#     pack $w.xs  -side bottom -fill both -expand 0
     pack $w.text -side left -fill both -expand 1



	bind $w.f.list <ButtonRelease-1> { 
		set c [.pinfo.f.list curselection]
		set pname [lindex $plist $c]
		set about [ac3d get_plugin_about $pname]
		set info [ac3d get_plugin_info $pname]
		.pinfo.text delete 0.0 end
		.pinfo.text insert end "$about\n$pname\n\n$info"
		.pinfo.text see end 
	}

	foreach i $plist {
		set about [ac3d get_plugin_about $i]
		set info [ac3d get_plugin_info $i]
		$w.f.list insert end $about
		}


	centre_window_on_screen .pinfo
	grab .pinfo

}


proc centre_window_on_screen { w } {
global tcl_platform
    wm withdraw $w
    update idletasks
    set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
	    - [winfo vrootx [winfo parent $w]]]
    set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
	    - [winfo vrooty [winfo parent $w]]]
    wm geom $w +$x+$y
    wm deiconify $w
if { $tcl_platform(platform) == "windows" } {
    wm geom $w +$x+$y
}


}











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


proc menu_object_explode {} {
global dist

    set dist 1.0
    
    new_toplevel .ex "Explode Object"

    label .ex.title -text "Enter explode distance\nEnter a positive number to explode,\na negative number to implode"
    entry .ex.dist -relief sunken -bd 2 -width 9 -justify right -textvariable dist
    grid .ex.title -row 0 -column 0 -columnspan 2 -sticky we
    grid .ex.dist -row 1 -column 1 -sticky we
    button .ex.ok -text "Detonate" -command { ac3d object_explode $dist ; destroy .ex; ac3d redraw_all}
    button .ex.cancel -text "Cancel" -command "destroy .ex"
    grid .ex.ok -row 4 -column 0 -sticky we
    grid .ex.cancel -row 4 -column 1 -sticky we
    centre_window_on_screen .ex
	focus .ex.dist
	grab .ex
}






proc tools_stereo {} {

toplevel .st -width 1280 -height 1024
frame .st.f -width 1280 -height 1024
pack .st.f -fill both -expand 1
togl .st.f.win -rgba true -double true -depth true -stereo true 
pack .st.f.win -fill both -expand 1
wm overrideredirect .st 1
tkwait visibility .st
wm geometry .st 1280x1024+0+0

ac3d go_stereo .st.f.win
}



proc stereo_off {} {

destroy .st.f.win
destroy .st 
}





proc hier_edit_object_data { } {
     global current_object_data
global hier_current
global oblist

#puts "display_object_data $current_object_data"


    set ob $oblist($hier_current)
    set name [ac3d object_get_name $ob]


if [winfo exists .d5] { destroy .d5 }

    new_toplevel .d5 "AC3D Object Data"

    frame .d5.hf
    pack .d5.hf -side top

    frame .d5.bottomhf
    pack .d5.bottomhf -side bottom
    button .d5.bottomhf.close -text "Close" -command "\
        ac3d object_set_data $ob \[.d5.object_data get 0.0 end-1c]; 
        destroy .d5"

    pack .d5.bottomhf.close

    label .d5.object_data_label -text "Object data for: $name"
    add_balloon .d5.object_data_label "Object data string - saved with object (in .ac files)\ninserted in some output formats"
    pack .d5.object_data_label -side top

     text .d5.object_data -width 60 -height 10 \
             -yscrollcommand ".d5.ys set" \
             -xscrollcommand ".d5.xs set" \
             -wrap none -padx 4 -pady 4 \
             -exportselection true 
#             -insertwidth $cursorwidth -insertbackground $cursorcolour 

	bind .d5.object_data <KeyRelease> " ac3d object_set_data $ob \[.d5.object_data get 0.0 end-1c]; "

     scrollbar .d5.ys -command ".d5.object_data yview" 
     scrollbar .d5.xs -command ".d5.object_data xview" -orient horizontal
     pack .d5.ys -in .d5 -side left -fill y -expand 0
     pack .d5.xs -in .d5 -side bottom -fill both -expand 0
     pack .d5.object_data -in .d5 -side left -fill both -expand 1


#    bind .d5.object_data <Leave> {
#        ac3d set_current_object_data  [.d5.object_data get 0.0 end-1c]
#        }




    set data [ac3d object_get_data $ob]

        .d5.object_data delete 0.0 end
        .d5.object_data insert end $data

    # fill in the fields
#    display_object_data
	centre_window_on_screen .d5


}

















proc menu_snap_together_distance {} {

    new_toplevel .getstring "Snap together by distance"

    label .getstring.title -text "Enter the distance:"
    entry .getstring.value -relief sunken -bd 2 -width 5 -textvariable prefs_snap_together_distance
    grid .getstring.title -row 0 -column 0 -columnspan 2 -sticky we
    grid .getstring.value -row 1 -column 0 -columnspan 2 -sticky we


    button .getstring.ok -text "Snap" -command {ac3d snaptogetherdistance $prefs_snap_together_distance ; destroy .getstring }
    button .getstring.cancel -text "Cancel" -command "destroy .getstring"
    grid .getstring.ok -row 4 -column 0 -pady 5
	#-sticky we
    grid .getstring.cancel -row 4 -column 1
	# -sticky we
    centre_window_on_screen .getstring

	focus .getstring.value
	grab .getstring
}









proc menu_spike {} {

    new_toplevel .getstring "Spike"

    label .getstring.title -text "Enter the spike size:"
    entry .getstring.value -relief sunken -bd 2 -width 5 -textvariable prefs_spike_factor
    grid .getstring.title -row 0 -column 0 -columnspan 2 -sticky we
    grid .getstring.value -row 1 -column 0 -columnspan 2 -sticky we


    button .getstring.ok -text "Spike" -command {ac3d surface_spike ; destroy .getstring }
    button .getstring.cancel -text "Cancel" -command "destroy .getstring"
    grid .getstring.ok -row 4 -column 0 -pady 5
	#-sticky we
    grid .getstring.cancel -row 4 -column 1
	# -sticky we
    centre_window_on_screen .getstring

	focus .getstring.value
	grab .getstring
}

proc menu_indent {} {

    new_toplevel .getstring "Indent"

    label .getstring.title -text "Indent distance:"
    entry .getstring.value -relief sunken -bd 2 -width 5 -textvariable prefs_indent_distance
    grid .getstring.title -row 0 -column 0 -columnspan 2 -sticky we
    grid .getstring.value -row 1 -column 0 -columnspan 2 -sticky we


    button .getstring.ok -text "Indent" -command {ac3d surface_indent ; destroy .getstring }
    button .getstring.cancel -text "Cancel" -command "destroy .getstring"
    grid .getstring.ok -row 4 -column 0 -pady 5
	#-sticky we
    grid .getstring.cancel -row 4 -column 1
	# -sticky we
    centre_window_on_screen .getstring

	focus .getstring.value
	grab .getstring
}




proc menu_bevel {} {

    new_toplevel .getstring "Bevel"

    label .getstring.title -text "Indent distance:"
    entry .getstring.value -relief sunken -bd 2 -width 5 -textvariable prefs_bevel_indent
    grid .getstring.title -row 0 -column 0 -columnspan 2 -sticky we
    grid .getstring.value -row 0 -column 2 -columnspan 2 -sticky we


    label .getstring.title2 -text "Out distance:"
    entry .getstring.value2 -relief sunken -bd 2 -width 5 -textvariable prefs_bevel_out
    grid .getstring.title2 -row 1 -column 0 -columnspan 2 -sticky we
    grid .getstring.value2 -row 1 -column 2 -columnspan 2 -sticky we


    button .getstring.ok -text "Bevel" -command {ac3d surface_bevel ; destroy .getstring }
    button .getstring.cancel -text "Cancel" -command "destroy .getstring"
    grid .getstring.ok -row 4 -column 0 -pady 3
	#-sticky we
    grid .getstring.cancel -row 4 -column 1
	# -sticky we
    centre_window_on_screen .getstring

	focus .getstring.value
	grab .getstring
}



proc menu_revolve {} {

    new_toplevel .getstring "Revolve"

    label .getstring.title -text "degrees: "
    entry .getstring.value -relief sunken -bd 2 -width 5 -textvariable prefs_revolve_degs

    label .getstring.atitle -text "  axis: "
	tk_optionMenu .getstring.axis axis X Y Z

    label .getstring.stitle -text "  segments: "
    entry .getstring.segments -relief sunken -bd 2 -width 5 -textvariable prefs_revolve_segments

    label .getstring.otitle -text "  offset: "
    entry .getstring.offset -relief sunken -bd 2 -width 5 -textvariable prefs_revolve_offset

	add_balloon .getstring.otitle "distance to move along the axis every revolution (360 degs)"

    grid .getstring.title -row 0 -column 0 -sticky we
    grid .getstring.value -row 0 -column 1 -sticky we
	grid .getstring.atitle -row 1 -column 0 -sticky we
	grid .getstring.axis -row 1 -column 1 -sticky we
	grid .getstring.stitle -row 2 -column 0 -sticky we
	grid .getstring.segments -row 2 -column 1 -sticky we
	grid .getstring.otitle -row 3 -column 0 -sticky we
	grid .getstring.offset -row 3 -column 1 -sticky we


	frame .getstring.bf
	grid  .getstring.bf -row 4 -columnspan 5

    button .getstring.bf.ok -text "Revolve" -command {if {$axis == "X" } {set a 0}; if {$axis == "Y"} {set a 1}; if {$axis == "Z"} {set a 2}; ac3d revolve $a; destroy .getstring }
    button .getstring.bf.cancel -text "Cancel" -command "destroy .getstring"

pack .getstring.bf.ok -side left -expand 1 -padx 3m -pady 2m
pack .getstring.bf.cancel -side left -expand 1 -padx 3m -pady 2m

#    grid .getstring.ok -row 4 -column 0 -pady 5
#    grid .getstring.cancel -row 4 -column 1

   centre_window_on_screen .getstring

	focus .getstring.value
	grab .getstring
}






proc menu_register {} {
global regkey

    set regkey ""
   
    new_toplevel .reg "Licence AC3D"

    label .reg.title -text "Enter licence key:"
    entry .reg.dist -relief sunken -bd 2 -width 50 -textvariable regkey
    grid .reg.title -row 0 -column 0 -columnspan 2 -sticky we
    grid .reg.dist -row 1 -column 0 -columnspan 2 -sticky we
    button .reg.ok -text "OK" -command { ac3d register $regkey; destroy .reg }
    button .reg.cancel -text "Cancel" -command "destroy .reg"
    grid .reg.ok -row 4 -column 0 -pady 5
	#-sticky we
    grid .reg.cancel -row 4 -column 1
	# -sticky we
    centre_window_on_screen .reg
	focus .reg.dist
	grab .reg
	
}


set reducepercent 90

proc menu_reduce {} {
global reducepercent

if ![winfo exists .reduce] {
    new_toplevel .reduce "Reduce"

    label .reduce.title -text "Reduce number of vertices to %:"
    add_balloon .reduce.title "This specifies the target vertices to leave e.g. 90% will remove 10% of the vertices"

    entry .reduce.value -relief sunken -bd 2 -width 3 -textvariable reducepercent
    grid .reduce.title -row 0 -column 0 -sticky we
    grid .reduce.value -row 0 -column 1  -sticky we
	checkbutton .reduce.keep -text "keep original object/s? " -variable prefs_reduce_keep_original
	add_balloon .reduce.keep "If this is set, the original object will not be deleted"
	grid .reduce.keep -row 1 -column 0 

    button .reduce.ok -text "Reduce" -command {
		if {  ( $reducepercent <= 0 ) || ( $reducepercent > 99)}  {
			 show_message "Enter a percentage from 1 to 99\nThis specifies the proportion of vertices to leave in the object." 
		} else {
			ac3d reduce $reducepercent
			puts $prefs_reduce_keep_original
		}
	}
    button .reduce.cancel -text "Close" -command "destroy .reduce"
    grid .reduce.ok -row 4 -column 0 -pady 5
	#-sticky we
    grid .reduce.cancel -row 4 -column 1
	# -sticky we
}
    centre_window_on_screen .reduce

	focus .reduce.value
}



proc menu_check_for_updates {} {
# removed because server update caused this to fail.

global prefs_last_update_id

puts "last update $prefs_last_update_id"

	set ver [ac3d get_version_number]
	set m [ac3d get_app_mode]
# get the real platform here
	set platform [ac3d get_platform]

	if { [catch { set usock [socket www.ac3d.org 80] }] } {
		show_message "failed connect to update server at www.ac3d.org"
		return
	}

#	puts "socket $usock"

	set getstr "get www.ac3d.org/checkupdate/index.html?v=$ver&p=$platform&m=$m\n"

	if { [catch { puts $usock $getstr ; flush $usock } ] } {
		show_message "failed to send request to update server at www.ac3d.org"
		return
	}


	# read the information
	if { [catch { set i [read $usock 1024] } ] } {
		show_message "failed to read update data from www.ac3d.org"
		return
	}

puts $i


	set latestversion [lindex $i 0]
	set latestversionmess [lindex $i 1]
	set updateid [lindex $i 2]
	set updatemess [lindex $i 3]

#	puts "$i\n\nupdateid=$updateid\nupdatemess=$updatemess\nlatestversion=$latestversion\nlatestversionmess=$latestversionmess";

	set disp ""

	if { $latestversion > $ver } {
		set disp "$disp$latestversionmess\n\n"
	}

	for { set n 2 }  { $n < [llength $i] } { incr n } {
		set updateid [lindex $i $n]
		incr n
		set updatemess [lindex $i $n]

		if { $updateid > $prefs_last_update_id } {
			set disp "$disp$updatemess\n"
		}
	}



	if { $disp == "" } {
		tk_messageBox -message "You have the most recent version of AC3D." -title "No updates available" -type ok
	} else {
		set res [ show_question "Update available" "$disp\nVisit www.ac3d.org now?" ]
		if { $res == 0 } { ac3d start_web_browser http://www.ac3d.org/ }
	}

	# record the last update id - saved in prefs file

	if { $updateid > $prefs_last_update_id } {
		set prefs_last_update_id [ expr $updateid ]
	}

	close $usock
}



proc dialog_windows_print { } {

   new_toplevel .print "Print"
	
	set v0 [ac3d viewid_to_entity 0]
	set p0 [ac3d entity_get_value $v0 "projection" ]
	set v1 [ac3d viewid_to_entity 1]
	set p1 [ac3d entity_get_value $v1 "projection" ]
	set v2 [ac3d viewid_to_entity 2]
	set p2 [ac3d entity_get_value $v2 "projection" ]
	set v3 [ac3d viewid_to_entity 3]
	set p3 [ac3d entity_get_value $v3 "projection" ]

global prefs_view_to_print

set t "prefs_view_label_$p0"
upvar #0 $t lab0
set t "prefs_view_label_$p1"
upvar #0 $t lab1
set t "prefs_view_label_$p2"
upvar #0 $t lab2
set t "prefs_view_label_$p3"
upvar #0 $t lab3




	frame .print.f
	radiobutton .print.f.b1 -text $lab0 -value 0 -variable prefs_view_to_print -indicatoron false -padx 0 -pady 0
	radiobutton .print.f.b2 -text $lab1 -value 1 -variable prefs_view_to_print -indicatoron false
	radiobutton .print.f.b3 -text $lab2 -value 2 -variable prefs_view_to_print -indicatoron false
	radiobutton .print.f.b4 -text $lab3 -value 3 -variable prefs_view_to_print -indicatoron false

	grid .print.f.b1 -row 2 -column 2
	grid .print.f.b2 -row 2 -column 3
	grid .print.f.b3 -row 3 -column 2
	grid .print.f.b4 -row 3 -column 3

	grid .print.f -row 2 -column 1


	label .print.lab -text "View to print:"
	grid .print.lab -row 2 -column 0

	checkbutton .print.forcewhite -text "Force white background" -variable prefs_printing_force_white_background
	grid .print.forcewhite -row 4 -column 1
	add_balloon .print.forcewhite "replace view background color with white?"

    button .print.setup -text "Print setup..." -command { ac3d windows_print_setup_dialog .print}
	grid .print.setup -row 7 -column 1
	add_balloon .print.setup "Change the printer settings"

    button .print.ok -text "Print" -command { destroy .print; ac3d windows_print_dialog $prefs_view_to_print }
    button .print.cancel -text "Cancel" -command "destroy .print"
    grid .print.ok -row 8 -column 0 -pady 5
    grid .print.cancel -row 8 -column 1

	grab .print
    centre_window_on_screen .print

}


set align_by 0
set align_axis_x 0
set align_axis_y 1
set align_axis_z 0


proc menu_align_objects { } {

if ![winfo exists .align] {
	set top .align
   new_toplevel $top "Align objects"
	
	set a [labelframe $top.axis -text "Position" -pady 4 -padx 4]
	checkbutton $a.x -text "X" -variable align_axis_x
	checkbutton $a.y -text "Y" -variable align_axis_y
	checkbutton $a.z -text "Z" -variable align_axis_z
	pack $a.x $a.y $a.z -side top
	grid $a -row 0 -column 0 -sticky n -padx 10

	set b [labelframe $top.by -text "Align" -pady 4 -padx 4]
	radiobutton $b.max -text "Maximum" -variable align_by -value 0
	radiobutton $b.min -text "Minimum" -variable align_by -value 1
	radiobutton $b.mid -text "Mid-point" -variable align_by -value 2
	radiobutton $b.cent -text "Object Centre" -variable align_by -value 3

	pack $b.max $b.min $b.mid $b.cent -anchor w
	grid $b -row 0 -column 1 -sticky n -padx 10



    button .align.ok -text "Align" -command { ac3d align_objects $align_axis_x $align_axis_y $align_axis_z $align_by}
    button .align.cancel -text "Close" -command "destroy .align"
    grid .align.ok -row 8 -column 0 -pady 5
    grid .align.cancel -row 8 -column 1
	}

    centre_window_on_screen .align

}



