# jentrymouse.tcl - support for Entry mouse bindings
#
######################################################################
# Copyright 1992-1995 by Jay Sekora.  This file may be freely        #
# distributed, modified or unmodified, for any purpose, provided     #
# that this copyright notice is retained verbatim in all copies and  #
# no attempt is made to obscure the authorship of this file.  If you #
# distribute any modified versions, I ask, but do not require, that  #
# you clearly mark any changes you make as such and that you provide #
# your users with instructions for getting the original sources.     #
######################################################################
# 
# Essentially, call
#   j:eb:basic_bind Entry   ---   for basic Entry bindings
#   j:eb:emacs_bind Entry   ---   for Emacs-like Entry bindings
#   j:eb:vi_bind Entry      ---   for Emacs-like Entry bindings
# (the emacs_bind and vi_bind procedures include the basic_bind 
# procedures; you don't have to call both.)

# TO DO:
# ^L
# sentence-manipulation stuff
# case change commands, transposition commands
# commands to do with mark?
# word deletion - fix to use buffer
# generalise movement to copying-to-cutbuffer and deletion
# IMPROVE ENTRY BINDINGS
# literal-insert for entry

######################################################################
# global variables:
#
global J_PREFS env
if {! [info exists J_PREFS(typeover)]} {set J_PREFS(typeover) 1}
#
######################################################################

######################################################################
# front-ends to hide differences between Tk4 and Tk3
######################################################################

proc j:entry_see_insert { W } {
  j:tk3 {
    tk_entrySeeCaret $W
  }
  j:tk4 {
    tkEntrySeeInsert $W
  }
}

######################################################################
# routines for dragging the selection - fix timing problems
######################################################################

# j:emb:move_sel W x y t - move/start selection, clearing existing selection

proc j:emb:move_sel { W x y t } {
  global j_teb
  
  $W icursor @$x
  $W select from @$x
  if {[lindex [$W config -state] 4] == "normal"} {focus $W}
  
  set j_teb(eselstart,x) $x
}

# j:emb:continue_sel W x y t - drag out a selection if enough time has passed

proc j:emb:continue_sel { W x y t } {
  global j_teb
  
  set xdiff [expr {abs($x - $j_teb(eselstart,x))}]
  if {$xdiff < 3} {
    return
  }
  
  $W select to @$x
}

######################################################################
# routines to let scanning and pasting double-up on the same button
# based on code by Tom Phelps <phelps@cs.berkeley.edu>
######################################################################

# j:emb:start_scan_or_paste W x y t - start a drag or paste, recording
#   current location and time so we can later decide whether to paste or drag
# BIND TO <ButtonPress-N>
proc j:emb:start_scan_or_paste { W x y t } {
  global j_teb
  $W scan mark $x
  set j_teb(scanpaste_time) $t
  set j_teb(scanpaste_paste) 1
}

# j:emb:continue_scan W x y t - scan the entry, and mark the fact that
#   we're scanning, not pasting.
# BIND TO <BN-Motion>
proc j:emb:continue_scan { W x y t } {
  global j_teb
  $W scan dragto $x
  set j_teb(scanpaste_paste) 0
}

# j:emb:end_scan_or_paste W x y t - if we haven't been scanning, and it's
#   been less than 500ms since button-down, paste selection
# BIND TO <ButtonRelease-N>
proc j:emb:end_scan_or_paste { W x y t } {
  global j_teb
  if {$j_teb(scanpaste_paste) &&
      [expr {$t-$j_teb(scanpaste_time)}] < 500} {
    focus $W
    j:eb:paste_selection $W
  }
}

######################################################################
# j:emb:sel_word W - select current word (at insert point)
# hacked from tk_entryBackword in entry.tcl
######################################################################

proc j:emb:sel_word { W args } {
  set string [$W get]
  set length [string length $string]
  set curs [expr [$W index insert]-1]
  if {$curs < 0} return
  for {set x $curs} {$x > 0} {incr x -1} {
    if {[string first [string index $string $x] " \t\n"] >= 0} {
      incr x
      break
    }
    if {([string first [string index $string $x] " \t\n"] < 0)
    	&& ([string first [string index $string [expr $x-1]] " \t"]
    	>= 0)} {
      break
    }
  }
  set start $x
  for {set x $curs} {$x < $length} {incr x 1} {
    if {([string first [string index $string $x] " \t\n"] < 0)
    	&& ([string first [string index $string [expr $x+1]] " \t"]
    	>= 0)} {
      break
    }
  }
  set end $x
  $W select from $start
  j:tk3 {
    $W select to $end
  }
  j:tk4 {
    $W select to [expr $end+1]
  }
  $W icursor $start
  j:entry_see_insert $W
}

# j:emb:sel_line W - select entire entry
proc j:emb:sel_line { W args } {
  $W select from 0
  $W select to end
  $W icursor 0
  j:entry_see_insert $W
}

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

# j:eb:mouse_bind W - set up W (normally "Entry") for basic editing
proc j:eb:mouse_bind { W args } {
  global j_teb
  
  # mouse bindings for selection:
  bind $W <1>			{j:emb:move_sel %W %x %y %t}
  bind $W <B1-Motion>		{j:emb:continue_sel %W %x %y %t}
  
  bind $W <Double-1>		{j:emb:sel_word %W %x %y %t}
  j:tk4 {bind $W <Double-1>	"+\nbreak\n"}
  bind $W <Triple-1>		{j:emb:sel_line %W %x %y %t}
  j:tk4 {bind $W <Triple-1>	"+\nbreak\n"}
  
  # mouse bindings for scanning and pasting:
  bind $W <2>			{j:emb:start_scan_or_paste %W %x %y %t}
  bind $W <B2-Motion>		{j:emb:continue_scan %W %x %y %t}
  bind $W <ButtonRelease-2>	{j:emb:end_scan_or_paste %W %x %y %t}
  
  # mouse bindings for scanning and pasting:
  bind $W <3>			{j:emb:start_scan_or_paste %W %x %y %t}
  bind $W <B3-Motion>		{j:emb:continue_scan %W %x %y %t}
  bind $W <ButtonRelease-3>	{j:emb:end_scan_or_paste %W %x %y %t}
}



