# jtext.tcl - constrained interface to Text widget
#
######################################################################
# 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.     #
######################################################################

# TO DO:
#   logging
#   integrate more tightly w/jtexttags (so can log tags as well)

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

######################################################################
# j:text:insert w text -
#   insert text into w at insert point
#   * detects if tags are being used and uses j:tag:insert_string 
#   * handles deletion of selection if needed
######################################################################
### PROBLEM - checking J_PREFS(typeover) shouldn't really be here; it's
###   only appropriate if a user event is generating the text to insert

proc j:text:insert_string { w text } {
  j:debug
  global j_text
  global j_tag
  global J_PREFS
  
  # in typeover mode, all insertions replace selection:
  if $J_PREFS(typeover) {
    if [j:text:insert_touches_selection $w] {	;# else might be off-screen!
      j:text:delete $w sel.first sel.last
    }
  }
  
  # if we're using tagged-insertion...
  if [info exists j_tag(tags,$w)] {		;# using tagged text
    j:tag:insert_string $w $text
  } else {
    set start [$w index insert]			;# ????? USED ?????
    $w insert insert $text
    j:tk3 {
      $w yview -pickplace insert
    }
    j:tk4 {
      $w see insert
    }
  }
  set j_text(dirty,$w) 1
}

######################################################################
# j:text:move w index -
#   move insert mark in w to index
######################################################################

proc j:text:move { w index } {
  j:debug
  $w mark set insert $index
  $w yview -pickplace insert
}

######################################################################
# j:text:delete w from to -
#   delete from index from to index to in w
######################################################################

proc j:text:delete { w from to } {
  j:debug
  j:text:move $w $from
  $w delete $from $to
  set j_text(dirty,$w) 1
}

######################################################################
# j:text:replace w from to string -
#   replace range with string, preserving tags at from
######################################################################

proc j:text:replace { w from to string } {
  set start [$w index $from]
  set tags [$w tag names $from]
  
  $w mark set insert $from
  $w delete insert $to
  $w insert insert $string
  
  foreach tag [$w tag names $start] {
    $w tag remove $tag $start insert
  }
  foreach tag $tags {
    $w tag add $tag $start insert
  }
  set j_text(dirty,$w) 1
  
  j:tk4 {
    $w see insert
  }
}

######################################################################
# j:text:mark_dirty w - mark widget w as dirty (modified)
######################################################################

proc j:text:mark_dirty { w } {
  global j_text
  set j_text(dirty,$w) 1
}

######################################################################
# j:text:mark_clean w - mark widget w as clean (unmodified)
######################################################################

proc j:text:mark_clean { w } {
  global j_text
  set j_text(dirty,$w) 0
}

######################################################################
# j:text:is_dirty w -
#   return 1 if w is dirty (modified) else 0
#   (returns 1 if w hasn't been set dirty or clean)
######################################################################

proc j:text:is_dirty { w } {
  global j_text
  if [info exists j_text(dirty,$w)] {
    return $j_text(dirty,$w)
  } else {
    return 1
  }
}

######################################################################
# j:selection_if_any - return selection if it exists, else {}
#   this is from kjx@comp.vuw.ac.nz (R. James Noble)
#   defined elsewhere, but copied here so the bindings libraries
#   don't depend on jtkutils
######################################################################

if {[info procs j:selection_if_any] == {}} {
  proc j:selection_if_any {} {
    if {[catch {selection get} s]} {return ""} {return $s}
  }
}

######################################################################
# j:text:has_selection t -
#   return true if selection made in t, else false
######################################################################

proc j:text:has_selection { t } {
  set selrange [$t tag nextrange sel 1.0]
  
  if {"x$selrange" == "x"} {                    ;# returns {} if none
    return 0
  } else {
    return 1
  }
}

######################################################################
# j:text:insert_touches_selection t -
#   return true if selection exists in t and insert is inside or next
#   to it (as will be the case if you just made the selection with
#   the mouse)
######################################################################

proc j:text:insert_touches_selection { t } {
  if {! [j:text:has_selection $t]} {		;# no selection
    return 0
  }
  if [$t compare insert < sel.first] {		;# insert before selection
    return 0
  }
  if [$t compare insert > sel.last] {		;# insert after selection
    return 0
  }
  return 1
}

