# jtextedt.tcl - support for EDT text bindings
# 
# Copyright 1994-1995 by Achim Bohnet <ach@rosat.mpe-garching.mpg.de>.
# This file may be freely redistributed in whole or in part.
#
# Modified by Jay Sekora.  Achim's version was more general, sharing a lot
# of procedures between Entry and Text bindings.  That's a direction I want
# to go in, but I didn't have time to integrate it into my sources. ---j.

#	 EDT (emulation of the standard VAX/VMS AXP/VMS editor)

###############################################################################
# to do:   	- all commands repeatable (j:text does it but why j:text:bof??
#		- use private selection for edt-/paste/cut/append/clear
#		- edt:page does not work (see comment in jmouse* ??)
###############################################################################

proc j:tb:edt_init { {t Text} } {
  global j_teb
  j:debug "'edt' bound to '$t'"

  set j_teb(cutbuffer) {}
  set j_teb(dragscroll,txnd) 0
  set j_teb(dragscroll,delay) 50
  set j_teb(scanpaste_time) 0
  set j_teb(scanpaste_paste) 1

  set j_teb(keymap,$t) edt-normal
  
  # not impl. up to now: set j_ed(edt,$t,select,on) 0

  j:tb:key_bind $t
  j:tb:mouse_bind $t
  
  j:tkb:mkmap Text edt-normal edt-normal {
    {Up				j:tkb:up}
    {Down			j:tkb:down}
    {Left			j:tkb:left}
    {Right			j:tkb:right}

    {Find			j:tb:beep}
    {Insert			j:tb:beep}
    {apLineDel			j:tb:beep}
    {Select			j:tb:beep}
    {Prior			j:tb:beep}
    {Next			j:tb:beep}

    {KP_F1			j:tkb:edt:gold}
    {KP_F2			j:tb:beep}
    {KP_F2_X			j:tkb:edt:help-bindings}
    {KP_F3			j:tb:beep}
    {KP_F3_X			j:tkb:find-next}
    {KP_F4			j:tkb:edt:del-line}

    {KP_0			j:tkb:edt:line}
    {KP_1			j:tkb:edt:word}
    {KP_2			j:tkb:edt:eol}
    {KP_3			j:tkb:edt:char}
    {KP_4			j:tkb:edt:advance}
    {KP_5			j:tkb:edt:backup}
    {KP_6			j:tb:beep}
    {KP_6_X			j:tkb:edt:cut-range}
    {KP_7			j:tkb:edt:page}
    {KP_8			j:tb:beep}
    {KP_8_X			j:tkb:edt:append}
    {KP_9			j:tb:beep}
    {KP_9_X			j:tkb:edt:replace}

    {KP_Subtract		j:tkb:edt:del-word}
    {KP_Separator		j:tkb:edt:del-char}
    {KP_Enter			j:tb:beep}
    {KP_Decimal			j:tb:beep}
    {KP_Decimal_X		j:tkb:edt:sel-range}

    {Return			j:tkb:insert_newline}
    {BackSpace			j:tkb:delete_left}
    {Delete			j:tkb:delete_left}

    {Control-DEFAULT		j:tkb:self_insert}
    {DEFAULT			j:tkb:self_insert}
    {Shift-DEFAULT		j:tkb:self_insert}
  }

  j:tkb:mkmap Text edt-gold edt-normal {
    {Up				j:tkb:up}
    {Down			j:tkb:down}
    {Left			j:tkb:left}
    {Right			j:tkb:right}
    
    {Find			j:tb:beep}
    {Insert			j:tb:beep}
    {apLineDel			j:tb:beep}
    {Select			j:tb:beep}
    {Prior			j:tb:beep}
    {Next			j:tb:beep}

    {KP_F1			j:tb:beep}
    {KP_F2			j:tb:beep}
    {KP_F2_X			j:tkb:edt:help}
    {KP_F3			j:tb:beep}
    {KP_F3_X			j:tkb:find-string}
    {KP_F4			j:tkb:edt:restore-line}

    {KP_2			j:tb:beep}
    {KP_2_X			j:tkb:edt:open-line}
    {KP_1			j:tb:beep}
    {KP_1_X			j:tkb:change-case}
    {KP_2			j:tkb:edt:del-eol}
    {KP_3			j:tb:beep}
    {KP_3_X			j:tkb:literal-insert}
    {KP_4			j:tkb:eof}
    {KP_5			j:tkb:bof}
    {KP_6			j:tkb:edt:ins-buffer paste}
    {KP_7			j:tb:beep}
    {KP_7_X			j:tkb:edt:command}
    {KP_8			j:tb:beep}
    {KP_8_X			j:tkb:edt:fill}
    {KP_9			j:tb:beep}
    {KP_9_X			j:tkb:edt:replace}

    {KP_Subtract		j:tkb:edt:restore-word}
    {KP_Separator		j:tkb:edt:restore-char}
    {KP_Enter			j:tb:beep}
    {KP_Enter_X			j:tkb:edt:g-enter}
    {KP_Decimal			j:tb:beep}
    {KP_Decimal_X		j:tkb:edt:g-decimal}

    {0				j:tkb:continue_number}
    {1				j:tkb:continue_number}
    {2				j:tkb:continue_number}
    {3				j:tkb:continue_number}
    {4				j:tkb:continue_number}
    {5				j:tkb:continue_number}
    {6				j:tkb:continue_number}
    {7				j:tkb:continue_number}
    {8				j:tkb:continue_number}
    {9				j:tkb:continue_number}

    {Control-DEFAULT		j:tb:beep}
    {DEFAULT			j:tb:beep}
    {Shift-DEFAULT		j:tb:beep}
  }

#  j:bind:set_map edt-normal $class
#		{Alt-a			literal-insert ä}
#		{Alt-A			literal-insert ä}
#		{Alt-o			literal-insert ö}
#		{Alt-O			literal-insert Ö}
#		{Alt-u			literal-insert ü}
#		{Alt-U			literal-insert Ü}
#		{Alt-s			literal-insert ß}
}

#####################################################################
# Public routines

#####################################################################

proc j:tkb:edt:gold { w k a } {
  j:tkb:new_mode edt-gold $w $k $a
}

#####################################################################

proc j:tkb:edt:char { w k a } { j:tb:edt:move tkb "" $w $k $a }

proc j:tkb:edt:word { w k a } { j:tb:edt:move tkb word_ $w $k $a }

proc j:tb:edt:move { sfx range w k a } {
  if [j:tb:edt:isForw $w] {
    j:$sfx:${range}right $w $k $a
  } else {
    j:$sfx:${range}left $w $k $a
  }
}

proc j:tkb:edt:line { w k a } { j:tb:edt:line tkb bol $w $k $a }

proc j:tkb:edt:eol { w k a } { j:tb:edt:line tkb eol $w $k $a }

proc j:tb:edt:line { sfx to w k a } {
  if [j:tb:edt:isForw $w] {
    if [j:tb:is_$to $w] {
      j:$sfx:down $w $k $a
    }
  } else {
    if [j:tb:is_$to $w] {
      j:$sfx:up $w $k $a
    }
  }
  j:tkb:$to $w $k $a
}

proc j:tkb:edt:page { w k a } { j:tb:edt:page tkb TO $w $k $a }

proc j:tb:edt:page { sfx to w k a } {
  if [j:tb:edt:isForw $w] {
    j:tkb:scroll_down
  } else {
    j:tkb:scroll_up
  }
}

#####################################################################

proc j:tkb:edt:del-char { w k a } { j:tb:edt:delChar tkb $w $k $a }

proc j:tb:edt:delChar { sfx w k a} {
  global j_tkb
  
  if [j:tb:edt:isForw $w] {
    set j_tkb(edtcharbuf,$w) [$w get insert insert]
    j:$sfx:delete_right $w $k $a
  } else {
    set j_tkb(edtcharbuf,$w) [$w get {insert - 1 char} {insert - 1 char}]
    j:$sfx:delete_left $w $k $a
  }
}

proc j:tkb:edt:restore-char { w k a } {
  global j_tkb
  if [info exists j_tkb(edtcharbuf,$w)] {
    j:text:insert_string $w $j_tkb(edtcharbuf,$w)
  }
}

proc j:tkb:edt:del-word { w k a } { j:tb:edt:delWord tkb $w $k $a}

proc j:tb:edt:delWord { sfx w k a } {
  global j_tkb
  
  if ![info exists j_tkb(edt-word-warned)] {
    j:alert -text "word buffer not implemented"
    set j_tkb(edt-word-warned) 1
  }
  if [j:tb:edt:isForw $w] {
    j:$sfx:delete_right_word $w $k $a
  } else {
    j:$sfx:delete_left_word $w $k $a
  }
}

proc j:tkb:edt:restore-word { w k a } {
  j:tb:beep $w
}

proc j:tkb:edt:del-eol { w k a } {
  j:text:delete [$w index insert] [$w index "insert lineend"]
}

proc j:tkb:edt:del-line { w k a } {
  global j_tkb
  
  set start [$w index insert]
  set final [$w index "insert lineend + 1 char"]
  set j_tkb(edtlinebuf,$w) [$w get $start $final]
  j:text:delete $w $start $final
}

proc j:tkb:edt:restore-line { w k a } {
  global j_tkb
  if [info exists j_tkb(edtlinebuf,$w)] {
    j:text:insert_string $w $j_tkb(edtlinebuf,$w)
  }
}

proc j:tkb:edt:ins-buffer { name w k a } {
  set oldpos [$w index insert]
  # j:tb:edt:buf:get $w $name insert			########
  $w mark set insert $oldpos
}

#####################################################################

proc j:tkb:edt:page { w k a } {
  if [j:tb:edt:isForw $w] {
    j:tkb:scroll_down $w $k $a
  } else {
    j:tkb:scroll_up $w $k $a
  }
}

#####################################################################

proc j:tkb:edt:advance { w k a } {
  j:tb:edt:setForw $w
}

proc j:tkb:edt:backup { w k a } {
  j:tb:edt:setBack $w
}

#####################################################################
#####################################################################
# Internally used routines
#####################################################################
#####################################################################


#####################################################################
# Prodecure set for editing direction handling

proc j:tb:edt:isForw { w } {
  global j_ed
  
  if { ! [info exists j_ed(edt,$w,forward)]} {
    set j_ed(edt,$w,forward) 1
  }
  return $j_ed(edt,$w,forward)
}

proc j:tb:edt:setForw { w } { global j_ed; set j_ed(edt,$w,forward) 1 }
proc j:tb:edt:setBack { w } { global j_ed; set j_ed(edt,$w,forward) 0 }

######################################################################
# following are from Achim's file "jediInit.tcl":

#####################################################################
# Buffer handling. 2 modes:
#
#	- passed by indices  {1/0 on success/failure)
#		j:tb:edt:buf:insert $w $bufname $start $final
#		j:tb:edt:buf:get	$w $bufname $start
#
#	- passed as text (alla read/write file)
#		j:tb:edt:buf:write $w $name $text
#		j:tb:edt:buf:read  $w $name  -> return text or {}
#

proc j:tb:edt:buf:insert { w name start final } {
  global j_ed
  set j_ed(buf,$w,$name) [$w get $start $final]
}
proc j:tb:edt:buf:write { w name text } {
  global j_ed
  set j_ed(buf,$w,$name) $text
}

proc j:tb:edt:buf:get { w name start} {
  global j_ed
  if [info exists j_ed(buf,$w,$name)] {
    j:text:move $start
    j:text:insert_string $j_ed(buf,$w,$name)
    return 1
  } else {
    j:alert -text "$w: Buffer `$name' is empty."
    return 0
  }
}
proc j:tb:edt:buf:read { w name } {
  global j_ed
  if [info exists j_ed(buf,$w,$name)] {
    return $j_ed(buf,$w,$name)
  } else {
    j:alert -text "$w: Buffer `$name' is empty."
    return {}
  }
}
