#
# $Id: user_interf.tcl,v 1.33 1998/10/07 22:00:34 cthulhu Exp $
#

#
# This file contain the main functions involved in the user interface
#

#
# This is the main state machine controlling the modal 
# interaction with the user
#


proc stateMachine {widget event {arg1 0} {arg2 2} {arg3 0}} {
    source [xxl_library]/globalvars.tcl
    global px py typedText ipx ipy
    global keysPressed

#    puts "$widget $event"
#    puts $globalState
#    puts $globalState2    
#    puts $globalState3
#    puts /**************************/

    switch $globalState {
        normal {
            switch $event {
                focus {
                    focus $widget
                }
                return {
                    if {$globalState2 == "copyConfirm"} {
                        copyExec
			highlightActiveCell
			HelpMessage Ready
                    }
                    if {$globalState2 == "moveConfirm"} {
                        moveExec
			highlightActiveCell
			HelpMessage Ready
                    }
                    set globalState normal
                    set globalState2 normal
                    unhighlightCurrentRange $widget
                }
                press {
		    if {$cols_selected != ""} {
			unhighlightColSelection
		    }
		    if {$rows_selected != ""} {
			unhighlightRowSelection
		    }
                    set px $arg1
                    set py $arg2
                }
                release {
                    set s [setCell $widget $arg1 $arg2]
                    set activeCellCol [lindex $s 0]
                    set activeCellRow [lindex $s 1]
                    switch $globalState2 {
                        normal {
                            if {$globalState3 == "normal"} {
#                                focus .$activeSheet.fr.header.entry.active
#                                set globalState cellEnter
                                unhighlightCurrentRange \
				    [canvasFromSheet $activeSheet]
                                highlightActiveCell
                            }
                        }
                        copyData {
                            set globalState2 copyConfirm
                            if {$globalState3 == "normal" } {
                                highlightActiveCell 
                            }
                        }
                        moveData {
                            set globalState2 moveConfirm
                            if {$globalState3 == "normal" } {
                                highlightActiveCell 
                            }
                        }
			moveConfirm {
                            if {$globalState3 == "normal"} {
				unhighlightCurrentRange \
				    [canvasFromSheet $activeSheet]
				highlightActiveCell
			    }
			}
			copyConfirm {
                            if {$globalState3 == "normal"} {
				unhighlightCurrentRange \
				    [canvasFromSheet $activeSheet]
				highlightActiveCell
			    }
			}
                    }
                }
                left {
		    if {$cols_selected != ""} {
			unhighlightColSelection
		    }
		    if {$rows_selected != ""} {
			unhighlightRowSelection
		    }
		    if {$currentRange != ""} {
			unhighlightCurrentRange [canvasFromSheet $activeSheet]
		    }
                    incr keysPressed
                    incr activeCellCol -$keysPressed 
                    if {$activeCellCol < 0} {set activeCellCol 0}
                    highlightActiveCell 
                    needToScroll $widget $activeCellCol $activeCellRow
                    set keysPressed 0
                }
                right {
		    if {$cols_selected != ""} {
			unhighlightColSelection
		    }
		    if {$rows_selected != ""} {
			unhighlightRowSelection
		    }
		    if {$currentRange != ""} {
			unhighlightCurrentRange [canvasFromSheet $activeSheet]
		    }
                    incr keysPressed
		    if { [expr ($activeCellCol + $keysPressed) \
			      < [DefSheetWidth]] } {
			incr activeCellCol $keysPressed 
			if {$activeCellCol < 0} {set activeCellCol 0}
			highlightActiveCell 
			needToScroll $widget $activeCellCol $activeCellRow
		    }
		    set keysPressed 0
                }
                down {
		    if {$cols_selected != ""} {
			unhighlightColSelection
		    }
		    if {$rows_selected != ""} {
			unhighlightRowSelection
		    }
		    if {$currentRange != ""} {
			unhighlightCurrentRange [canvasFromSheet $activeSheet]
		    }
                    incr keysPressed
		    if { [expr ($activeCellRow + $keysPressed) \
			      < [DefSheetHeight]] } {
			incr activeCellRow $keysPressed
			if {$activeCellRow < 0} {set activeCellRow 0}
			highlightActiveCell 
			needToScroll $widget $activeCellCol $activeCellRow
		    }
                    set keysPressed 0
                }
                up {
		    if {$cols_selected != ""} {
			unhighlightColSelection
		    }
		    if {$rows_selected != ""} {
			unhighlightRowSelection
		    }
		    if {$currentRange != ""} {
			unhighlightCurrentRange [canvasFromSheet $activeSheet]
		    }
                    incr keysPressed
                    incr activeCellRow -$keysPressed
                    if {$activeCellRow < 0} {set activeCellRow 0}
                    highlightActiveCell 
                    needToScroll $widget $activeCellCol $activeCellRow
                    set keysPressed 0
                }
                equal {
		    if {$cols_selected != ""} {
			unhighlightColSelection
		    }
		    if {$rows_selected != ""} {
			unhighlightRowSelection
		    }
		    if {$currentRange != ""} {
			unhighlightCurrentRange [canvasFromSheet $activeSheet]
		    }
                    focus .$activeSheet.fr.header.entry.active
                    set globalState formulaEnter                    
                    highlightActiveCell 
                    set activeText($activeSheet) $arg1
		    .$activeSheet.fr.header.entry.active icursor 1
                }
		shift {
		    if {$cols_selected != ""} {
			unhighlightColSelection
		    }
		    if {$rows_selected != ""} {
			unhighlightRowSelection
		    }
		    if {$currentRange != ""} {
			unhighlightCurrentRange [canvasFromSheet $activeSheet]
		    }
                    focus .$activeSheet.fr.header.entry.active
                    set globalState cellEnter                    
                    highlightActiveCell
		    set activeText($activeSheet) \
			[CellGet $activeSheet $activeCellCol $activeCellRow]
		    .$activeSheet.fr.header.entry.active icursor \
			[string length [.$activeSheet.fr.header.entry.active \
					    get]]
		}
		control {
		    if {$cols_selected != ""} {
			unhighlightColSelection
		    }
		    if {$rows_selected != ""} {
			unhighlightRowSelection
		    }
		    if {$currentRange != ""} {
			unhighlightCurrentRange [canvasFromSheet $activeSheet]
		    }
                    focus .$activeSheet.fr.header.entry.active
                    set globalState cellEnter                    
                    highlightActiveCell
		    set activeText($activeSheet) \
			[CellGet $activeSheet $activeCellCol $activeCellRow]
		    .$activeSheet.fr.header.entry.active select from 0
		    .$activeSheet.fr.header.entry.active select to end
		    .$activeSheet.fr.header.entry.active icursor \
			[string length [.$activeSheet.fr.header.entry.active \
					    get]]
		}
                PressInEntry {
		    if {$cols_selected != ""} {
			unhighlightColSelection
		    }
		    if {$rows_selected != ""} {
			unhighlightRowSelection
		    }
		    if {$currentRange != ""} {
			unhighlightCurrentRange [canvasFromSheet $activeSheet]
		    }
                    focus .$activeSheet.fr.header.entry.active
                    if {[string range $activeText($activeSheet) 0 0] == "="}  {
                        set globalState formulaEnter
                    } else {
                        set globalState cellEnter
                    }
                }
                keyInEntry {
		    if {$cols_selected != ""} {
			unhighlightColSelection
		    }
		    if {$rows_selected != ""} {
			unhighlightRowSelection
		    }
		    if {$currentRange != ""} {
			unhighlightCurrentRange [canvasFromSheet $activeSheet]
		    }
                    focus .$activeSheet.fr.header.entry.active
                    if {[string range $activeText($activeSheet) 0 0] == "="}  {
                        set globalState formulaEnter
                    } else {
                        set globalState cellEnter
                    }
                }
                key
		{
		    if {$cols_selected != ""} {
			unhighlightColSelection
		    }
		    if {$rows_selected != ""} {
			unhighlightRowSelection
		    }
		    if {$currentRange != ""} {
			unhighlightCurrentRange [canvasFromSheet $activeSheet]
		    }
                    focus .$activeSheet.fr.header.entry.active
                    set globalState cellEnter                    
                    highlightActiveCell
		    set activeText($activeSheet) $arg1
		    .$activeSheet.fr.header.entry.active icursor 1
                }
                B1Outside -
                B1Motion {
                }
                returnInEntry {
                    enterCell $activeSheet $activeCellCol $activeCellRow \
                            $activeText($activeSheet)
                    set globalState normal
                    nextCell
                }
                default {
                    tkerror "Unknown event $event in stateMachine \
                        in state $globalState"
                }
            }
        }

        formulaEnter -
        cellEnter {
            switch $event {
                focus {
                }
                equal {
                    set globalState formulaEnter
                }
                press {
                    set px $arg1
                    set py $arg2
                    set ipx [$widget canvasx $px]
                    set ipy [$widget canvasy $py]
                    switch $globalState {
                        cellEnter {
                            # User gave up entering this cell
                            set globalState normal
                        }
                        formulaEnter {
                            set s [setCell $widget $arg1 $arg2]
                            set s [ColName [lindex $s 0]][expr [lindex $s 1]+1]
                            insertTextInEntry .$activeSheet.fr.header $s 0
#                            set typedText $activeText($activeSheet)
#                            set activeText($activeSheet) \
#                                    "$typedText$s"
                        }
                    }
                }
                B1Outside -
                B1Motion {
                    set dx [expr abs($arg1-$px)]
                    set dy [expr abs($arg2-$py)]
                    if {$dx > 8 || $dy > 8} {
                        defineCurrentRange $widget $arg1 $arg2 $event
                        set s [rangeName $currentRange]
                        insertTextInEntry .$activeSheet.fr.header $s 1
#                        set activeText($activeSheet) $typedText$s
                    }
                    
                }
                release {
#                    unhighlightCurrentRange [canvasFromSheet $activeSheet]
                }
                returnInEntry {
                    enterCell $activeSheet $activeCellCol $activeCellRow \
                            $activeText($activeSheet)
                    set globalState normal
                    focus [canvasFromSheet $activeSheet]
                    incr activeCellRow
                    needToScroll [canvasFromSheet $activeSheet] \
                            $activeCellCol $activeCellRow
                    highlightActiveCell
                    unhighlightCurrentRange [canvasFromSheet $activeSheet]
                }
                keyInEntry {
                    if {[string range $activeText($activeSheet) 0 0] == "="}  {
                        set globalState formulaEnter
                    } else {
                        set globalState cellEnter
                    }
                    
                }
                PressInEntry -
                key {
                }
                default {
                    tkerror "Unknown event $event in stateMachine \
                        in state $globalState"
                }
            }

        }
    }
    switch $globalState3 {
        normal {
            switch $event {
                B1Outside -
                B1Motion {
                    set dx [expr abs($arg1-$px)]
                    set dy [expr abs($arg2-$py)]
                    if {$dx > 8 || $dy > 8} { 
                        set globalState3 defRange
                        set ipx [$widget canvasx $px]
                        set ipy [$widget canvasy $py]
                        if {$globalState == "normal"} {
                            unhighlightActiveCell
                        }
                    }
                }
            }

        }
        defRange {
            switch $event {
                B1Outside -
                B1Motion {
                    defineCurrentRange $widget $arg1 $arg2 $event
                }
                release {
                    set px $arg1
                    set py $arg2
                    set globalState3 normal
                    switch $globalState2 {
                        copyData {
                            set globalState normal
                            set globalState2 copyConfirm
                        }
                        moveData {
                            set globalState normal
                            set globalState2 moveConfirm
                        }
                    }
                }
            }
        }
    }
}

proc countKeys {} {
    global keysPressed

    incr keysPressed
}

proc enterCell {sheet column row st} {
    source [xxl_library]/globalvars.tcl


    CellSet $sheet $column $row $st
#    set f [setFontName]
#    SetFont $activeSheet [lindex $f 0] [lindex $f 1] \
\#	[lindex $f 2] [lindex $f 3] \
\#	$activeCellCol $activeCellRow 0 -1
}

proc nextCell {} {
    global activeSheet activeCellRow activeCellCol

    focus [canvasFromSheet $activeSheet]
    incr activeCellRow
    needToScroll [canvasFromSheet $activeSheet] \
            $activeCellCol $activeCellRow
    highlightActiveCell
    unhighlightCurrentRange [canvasFromSheet $activeSheet]

}

proc setCell {canvas x y } {
    source "[xxl_library]/globalvars.tcl"


    set col [cellCol $activeSheet [$canvas canvasx $x]]
    set row [cellRow $activeSheet [$canvas canvasy $y]]

    return "$col $row"
}

proc moveTo {col row mode} {
    switch $mode {
        rel {puts "Relative move $col $row" }
        abs {puts "Absolute move $col $row" }
    }
}

proc unhighlightActiveCell {} {
    source "[xxl_library]/globalvars.tcl"

    set c [canvasFromSheet $activeSheet]

    catch {$c delete highlight}
}

proc highlightActiveCell {{flag 1}} {
    source "[xxl_library]/globalvars.tcl"
    global  fontNameIndex fontSizeIndex
    global fontBoldIndex fontItalicIndex shadeIndex
    global bordertop borderbottom borderleft borderright
    global formatStrings positionLRC formatValue
    global activeColName

    set activeColName [ColName $activeCellCol]
    set activeCellName [ColName $activeCellCol]$activeCellRow

    if {$flag == 1} {
        set activeText($activeSheet) \
                [CellGet $activeSheet $activeCellCol $activeCellRow]
    }
    set s [GetFormat $activeSheet $activeCellCol $activeCellRow]
    if {$s != ""} {
        set fontNameIndex [lindex $s 0]
        set fontSizeIndex [lindex $s 1]
        set fontBoldIndex [lindex $s 2] 
        setFontName
        set fontItalicIndex [lindex $s 3]
#        set bordertop [lindex $s 4]
#        set borderbottom [lindex $s 5]
#        set borderleft [lindex $s 6]
#        set borderright [lindex $s 7]
        set shadeIndex [lindex $s 8]
        set positionLRC [lindex $s 9]
        set formatValue [lindex $s 10]
    }

    set c [canvasFromSheet $activeSheet]

    catch {$c delete highlight}
    $c  create rect \
            0 0 0 0 X \
            $activeCellCol \
            $activeCellRow \
            [expr $activeCellCol+1] \
            [expr $activeCellRow+1] -width 3 \
                   -tag highlight -outline red 

}

proc unhighlightCurrentRange {canvas {reset 1}} {
    global currentRange
    
    set aux $currentRange
    set currentRange ""
    catch {$canvas delete highlightRange}
    if {$reset==0} {
	set currentRange $aux
    }
}


proc highlightCurrentRange {canvas} {
    global currentRange currentRangeName

    catch {$canvas delete highlightRange}

    $canvas  create rect \
            0 0 0 0 X \
            [lindex $currentRange 0] \
            [lindex $currentRange 1] \
            [expr (1+[lindex $currentRange 2])] \
            [expr (1+[lindex $currentRange 3])] \
            -width 2 -tag highlightRange -outline darkgreen -width 3 \
            -fill green -stipple gray11
    
#    $canvas lower highlightRange
   set currentRangeName [rangeName $currentRange]

}

proc needToScroll {widget col row} {
    global activeSheet
    
    NeedToScroll $activeSheet $col $row

#    set y [$widget canvasy [defDispHeight]]
#    if {[expr $activeCellRow+1] > [cellRow $activeSheet $y]} {
#        scrollVSheet $activeSheet yview scroll 1 unit
#    }
#    set y [$widget canvasy 0]
#    if {[expr $activeCellRow-1] < [cellRow $activeSheet $y]} {
#        scrollVSheet $activeSheet yview scroll -1 unit
#    }
#    set x [$widget canvasx [defDispWidth]]
#    if {[expr $activeCellCol+1] > [cellCol $activeSheet $x]} {
#        scrollHSheet $activeSheet xview scroll 1 unit
#    }
#    set x [$widget canvasx 0]
#    if {[expr $activeCellCol-1] < [cellCol $activeSheet $x]} {
#        scrollHSheet $activeSheet xview scroll -1 unit
#    }
    update idletasks
}

proc needToScroll2 {widget col row arg1 arg2 event} {
#    source "[xxl_library]/globalvars.tcl"
    global sc2_arg1 sc2_arg2 sc2_widget sc2_pending activeSheet

    set sc2_widget $widget
    set sc2_arg1 $arg1
    set sc2_arg2 $arg2
    

#    puts "$widget $col $row $arg1 $arg2 $event"
    set need [NeedToScroll $activeSheet $col $row]

    if {$sc2_pending == 0 && $need == 1 } {
        set sc2_pending 1
        after idle {
            update 
            after 20 {
                set sc2_pending 0
                stateMachine $sc2_widget B1Outside $sc2_arg1 $sc2_arg2 
            }
            
        }
    }


    update idletasks
   
}



proc defineCurrentRange {widget arg1 arg2 event} {
    source [xxl_library]/globalvars.tcl
    global px py typedText ipx ipy

    set ox [cellCol $activeSheet $ipx]
    set oy [cellRow $activeSheet $ipy]

    set x [$widget canvasx $arg1]
    set y [$widget canvasy $arg2]
    set col [cellCol $activeSheet $x]
    set row [cellRow $activeSheet $y]
    
#    if {$col < $ox} {incr col -1 ; incr ox}
#    if {$row < $oy} {incr row -1 ; incr oy}

#    if {$x < $ipx} {incr col -1}
#    if {$y < $ipy} {incr row -1}
    
    set currentRange \
            "[min $ox $col] [min $oy $row] [max $ox $col] [max $oy $row]"
    needToScroll2 $widget $col $row $arg1 $arg2 $event
    highlightCurrentRange $widget
}

#
# $Log: user_interf.tcl,v $
# Revision 1.33  1998/10/07 22:00:34  cthulhu
# GlobalState changes so that Pasting and Moving are more intuitive.
#
# Revision 1.32  1998/10/06 19:27:21  cthulhu
# User interface updated for moveConfirm and copyConfirm globalstate2 cases,
# 	where it should behave normally until the paste is pressed.
#
# Revision 1.32  1998/10/06 19:21:56  cthulhu
# highlight active cell is now called when user is in globalState2 == copyConfirm
# 	or moveConfirm.
#
# Revision 1.31  1998/09/27 20:44:56  cthulhu
# Added bindings for control and alt events to edit cells in entry box proper
# when navigating in cells.
#
# Revision 1.30  1998/08/06 21:08:35  aml
# Released alpha version of Abacus.
#
# Revision 1.29  1997/03/27 10:00:39  aml
# Started implementing graphs.
# Fixed bug in tkCanvasPs.c
# Created bindings for composite characters in Portuguese.
#
# Revision 1.28  1997/01/07  01:07:44  aml
# Error propagation for formulas fixed.
# Edit operations in place.
#
# Revision 1.27  1996/12/31  17:38:38  aml
# On-demand calculation improved. Loops are detected.
# Automatic recalculation can now be disabled.
# Printing was improved.
#
# Revision 1.26  1996/12/11 21:39:58  aml
# Sumif implemented.
# Diverse time functions implemented.
# Fixed needtoscroll2 to avoid out of control scroll.
#
# Revision 1.25  1996/11/22  16:29:13  aml
# First cut at transforming canvas into a true cell widget.
# Text, lines and rectangles are now relative to row and colunm numbers.
# It still has a bug with wrong estimation of column widths.
#
# Revision 1.24  1996/09/17 15:16:17  aml
# Fixed problems with copying of cells with non-default formats.
# Created printing formats, alignment formats.
# Format toolbar now reflects format of active cell.
#
# Revision 1.23  1996/09/17 14:40:14  aml
# Fixed problems with copying of cells with non-default formats.
# Created printing formats, alignment formats.
# Format toolbar now reflects format of active cell.
#
# Revision 1.22  1996/08/29 12:05:43  aml
# Fixed problem with initialization of formulas.
# Insertion in entry is now done properly.
# Focus is slightly better handled.
# Fixed serious problem when canvas changes name and old
# references exist. Also removed double call to redraw that
# was slowing things a lot.
#
# Revision 1.21  1996/08/28 17:17:49  aml
# Load and save now accept string_value for formula cells.
# This fixes previous thought problem of formula values not
# being stored.
# Functions upper,lower and proper created.
# Function if can now return labels.
# Fixed problem with function count.
# Reasonably stable version, very used to manipulate notas.wk1.
#
# Revision 1.20  1996/08/24 10:16:05  aml
# Scroll almost fixed. We are missing scroll steps.
# Several sheets work again, but need to be fixed right.
#
# Revision 1.19  1996/08/23  16:13:34  aml
# Top window resizing now works well.
# Range selection now uses a filled rectangle with overall good results.
# Intermediate version, does not work well.
#
# Revision 1.18  1996/07/18  10:19:20  aml
# Created formats for cells.
# Load cell now makes copy of old file.
#
# Revision 1.17  1996/04/27  11:12:34  aml
# Inserted check and delete button.
# Font selection widget created.
# Fixed bug canvas_information destructor.
#
# Revision 1.16  1996/04/23 09:42:49  aml
# Data structures for ordered scans of rows and columns are in place.
# Cell overlap is working.
# Forward cell dependences inserted. Automatic recalculation created.
# Uniformizaed label entry procedure.
#
# Revision 1.15  1996/04/21 13:28:08  aml
# Sped up scroll functions, caching keys presses.
# First cut at handling overflowing cells.
# Overflow into ajoining filled cells not solved.
#
# Revision 1.14  1996/03/29 21:45:34  aml
# Changed key based scrolls to be synchronous. Work fine, but are somewhat slow.
# Fixed abnormaly in state machine after range defition causing canvas scroll.
# Solid, working version.
#
# Revision 1.13  1996/03/09 08:32:39  aml
# Fixed problem in string_single_arg macro
# Created if function, boolean evaluations and so on.
# Improved print controls.
#
# Revision 1.12  1996/03/01  13:08:46  aml
# Stack references are now pushed instead of double value.
# Fixed problem with integers too large on formulas.
# Scroll with cursors now works better.
#
# Revision 1.11  1996/02/19 15:47:36  aml
# Fixed abnormality with mouse click.
# Variable width columns implemented, but not yet saved.
# Labels are now a lex element, fixing some aberrant behavior that existed.
#
# Revision 1.10  1996/02/16  23:09:34  aml
# Improved user interf state machine.
# Centralized range definitions.
# Range defined outiside current view work properly.
#
# Revision 1.9  1996/02/16  18:04:04  aml
# Fixed a memory bug in formula copy with purify.
# Fixed a few minor bugs. Functional, stable version.
#
# Revision 1.8  1996/02/13 21:55:21  aml
# Fixed problems with change to elf.
# RangeCopy created. Works !
# Pressed mouse leaving canvas will cause scroll. Works, but needs to
# keep moving.
#
# Revision 1.7  1996/02/13  12:03:44  aml
# Fixed bug with range definition via mouse.
# Fixed bug in range iterators.
#
# Revision 1.6  1996/01/27  23:10:29  aml
# CellCopy created.
# CellGet fixed.
# Tcl range operators created.
# User interface improved. Cell references and ranges
# can now be defined with the mouse.
#
# Revision 1.5  1996/01/10  18:53:40  aml
# Fixed limited integer range of cells.
# Fixed incorrect code in spreadsheet type.
# Users interface improved. Cursors and mouse clicks
# now work in the most basic modes.
#
# Revision 1.4  1996/01/09  18:34:50  aml
# Load, save, open, close and exit now work properly (hopefuly).
# Sheet utility functions also work : SheetExists, SheetEmpty, SheetModified
#
# Revision 1.3  1995/12/27  23:15:10  aml
# First version of Sheet::display
#
# Revision 1.2  1995/12/14  12:13:05  aml
# Version 0.4.2
#
# Revision 1.1  1995/12/06  14:17:54  aml
# Initial revision
#
#