###########################################################################
#                                                                         #
# Procedures to create the various bindings on the tged editor.           #
#                                                                         #
# This file is part of the tged package.                                  #
#                                                                         #
###########################################################################

# Copyright (c) 2000-2003, JYL Software Inc.
# 
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

# Add the tree edit binding tag to this tree widget:

proc ::tged::addTreeEditBindings {tree} {
    set bindtags [bindtags $tree.c]
    if {![string equal TreeEditBindings [lindex $bindtags 0]]} {
	bindtags $tree.c [eval list TreeEditBindings $bindtags]
    }
}

# Remove the tree edit binding tag from this tree widget:

proc ::tged::removeTreeEditBindings {tree} {
    set bindtags [bindtags $tree.c]
    if {[string equal TreeEditBindings [lindex $bindtags 0]]} {
	bindtags $tree.c [lrange $bindtags 1 end]
    }
}

# Add the value edit binding tag to this text widget:

proc ::tged::addValueEditBindings {text} {
    set bindtags [bindtags $text]
    if {![string equal ValueEditBindings [lindex $bindtags 0]]} {
	bindtags $text \
	    [eval list ValueEditBindings ValueMaskEverything $bindtags]
    }
}

# Remove the value edit binding tag from this text widget:

proc ::tged::removeValueEditBindings {text} {
    set bindtags [bindtags $text]
    if {[string equal ValueEditBindings [lindex $bindtags 0]]} {
	bindtags $text [lrange $bindtags 2 end]
    }
}

# Add the value no-edit binding tags to this text widget:

proc ::tged::addValueNoEditBindings {text} {
    set bindtags [bindtags $text]
    if {![string equal ValueNoEditBindings [lindex $bindtags 0]]} {
	bindtags $text \
	    [eval list ValueNoEditBindings ValueMaskEverything $bindtags]
    }
}

# Remove the value no-edit binding tags from this text widget:

proc ::tged::removeValueNoEditBindings {text} {
    set bindtags [bindtags $text]
    if {[string equal ValueNoEditBindings [lindex $bindtags 0]]} {
	bindtags $text [lrange $bindtags 2 end]
    }
}

# Set the appropriate edit value mask depending on the type of the value. Also
# updates the contents of the text widget depending on the selected type:
# * First of all discard the current contents.
# * Next, if an existing vertex is being edited and the selected type
#   is the same as the type of the existing vertex, insert the value of
#   the vertex as the initial contents of the text widget.

proc ::tged::setValueEditMaskAndContents {text combo {vertex ""}} {

    # Figure out what type the user asked for:

    set type [getVertexTypeChoice $combo]

    # Throw away the current contents of the text widget:

    $text delete 1.0 end

    # If the vertex exists already and the new type is the same as
    # its existing type, then insert the current value of the vertex
    # into the text widget.

    if {![string equal "" $vertex]} {

	# The type from the combobox has a leading '-'...

	if {[string equal -[$vertex type] $type]} {
	    $text insert insert [$vertex get]
	}
    }

    # First strip any existing value edit mask:

    set bindtags [bindtags $text]
    if {([string equal ValueEditMaskNumeric [lindex $bindtags 0]]) ||
	([string equal ValueEditMaskFloatingPoint [lindex $bindtags 0]])} {
	set bindtags [lrange $bindtags 1 end]
    }

    # If the type is empty, return right away.

    if {[string equal "" $type]} {
	return
    }
    if {[string match "-*" $type]} {
	set type [string range $type 1 end]
    }

    # Next, install the new edit value mask based on the type selected.

    switch $type {
	int {
	    set bindtags [eval list ValueEditMaskNumeric $bindtags]
	}
	double {
	    set bindtags [eval list ValueEditMaskFloatingPoint $bindtags]
	}
    }

    bindtags $text $bindtags
}
	    
# Create the tag and bindings for the tree display:

proc ::tged::createTreeEditBindings {} {
    bind TreeEditBindings <Destroy> \
	{::tged::cleanupTreeWidget [::tged::stripCanvasName %W]}
    bind TreeEditBindings <Enter> {
	focus %W
    }
    bind TreeEditBindings <KeyPress-c> \
	{::tged::commitDisplayedStorage [::tged::stripCanvasName %W]}
    bind TreeEditBindings <KeyPress-d> \
	{::tged::deleteSelectedNode [::tged::stripCanvasName %W]}
    bind TreeEditBindings <KeyPress-n> \
	{::tged::addNodeToSelectedNode [::tged::stripCanvasName %W]}
    bind TreeEditBindings <KeyPress-a> \
	{::tged::addValueToSelectedNode [::tged::stripCanvasName %W]}
    bind TreeEditBindings <KeyPress-v> \
	{::tged::addValueToSelectedNode [::tged::stripCanvasName %W]}
}

# Create the tag and bindings for the value display:

proc ::tged::createValueEditBindings {} {
    bind ValueEditBindings <Enter> {
	focus %W
    }
    bind ValueEditBindings <KeyPress-c> {
	::tged::commitDisplayedStorage [::tged::associatedTreeWidget %W]
	break
    }
    bind ValueEditBindings <KeyPress-e> {
	::tged::editDisplayedValue %W
	break
    }
    bind ValueEditBindings <KeyPress-Return> {
	::tged::editDisplayedValue %W
	break
    }
    bind ValueEditBindings <Double-Button-1> {
	::tged::editDisplayedValue %W
	break
    }
    bind ValueEditBindings <KeyPress-d> {
	::tged::deleteDisplayedValue %W
	break
    }
    bind ValueEditBindings <Button-1> {
	::tged::selectDisplayedValue %W %x %y
	break
    }
    bind ValueEditBindings <KeyPress-Up> {
	::tged::selectNextDisplayedValue %W -1
	break
    }
    bind ValueEditBindings <KeyPress-Down> {
	::tged::selectNextDisplayedValue %W 1
	break
    }
    bind ValueEditBindings <KeyPress> "bell; break"
}

# Create the tag and bindings for the value no-edit bindings:

proc ::tged::createValueNoEditBindings {} {
    bind ValueMaskEverything <KeyPress> "bell; break;"
}

# Helper procedure to create binding masks for the value editor:

proc ::tged::createValueEditMasks {} {

    # Allow only numeric keys

    foreach i {0 1 2 3 4 5 6 7 8 9 plus minus} {
	bind ValueEditMaskNumeric <KeyPress-$i> continue
    }
    foreach i {<KeyPress-BackSpace> <KeyPress-Delete>
	       <KeyPress-Right> <KeyPress-Left>
	       <Control-KeyPress-h>} {
	bind ValueEditMaskNumeric $i continue
    }
    bind ValueEditMaskNumeric <KeyPress-Tab> {
	focus [tk_focusNext %W]; break
    }
    bind ValueEditMaskNumeric <KeyPress> "bell; break;"

    # Make a binding tag that allows numeric keys and 'e', 'E', '.'

    foreach i {0 1 2 3 4 5 6 7 8 9 plus minus period e E} {
	bind ValueEditMaskFloatingPoint <KeyPress-$i> continue
    }
    foreach i {<KeyPress-BackSpace> <KeyPress-Delete>
	       <KeyPress-Right> <KeyPress-Left>
	       <Control-KeyPress-h>} {
	bind ValueEditMaskFloatingPoint $i continue
    }
    bind ValueEditMaskFloatingPoint <KeyPress-Tab> {
	focus [tk_focusNext %W]; break
    }
    bind ValueEditMaskFloatingPoint <KeyPress> "bell; break;"
}

# Given a text widget, figure out what the associated tree widget is.

proc ::tged::associatedTreeWidget {text} {
    variable data

    return $data(i,$text,tree)
}

# Utility procedure to strip the canvas widget out of the passed tree
# widget name. The bindings are on the canvas contained within the tree,
# hence the window name passed will have the canvas as its last component.
# But operations such as selection should be done relative to the whole
# tree widget, so we need to strip off that last component.

proc ::tged::stripCanvasName {tree} {
    join [lrange [split $tree .] 0 end-1] .
}
