#
# Module for browsing around in Canvas widgets
#


# where is an index of characters, starting from 0. Puts cursor at $where,
# and makes cursor visible. Works on whichever canvas item has the focus.
# This is not interactive, it needs a canvas item to go to.
proc th_Canvas_goto {w where {dont_stay 1}} {
  if {[set i [$w focus]] == ""} {bell ; return}
  if {[catch {$w index $i insert}]} {bell ; return}

  if {$dont_stay && ([$w index $i $where] == [$w index $i insert])} {bell ; return 0}
  $w icursor $i $where

  th_Canvas_make_cursor_visible $w $i
}

# Ensures cursor is visible. (A rather ugly procedure, anyone got a better
# idea?)
proc th_Canvas_make_cursor_visible {w i} {
  if {[catch {$w index $i 0}]} {bell ; return}

  set box [$w bbox $i]
  set viewx [$w canvasx 0]
  set viewy [$w canvasy 0]
  set width [$w cget -width]
  set height [$w cget -height]
  set box_width [expr [lindex $box 2] - [lindex $box 0]]
  set box_height [expr [lindex $box 3] - [lindex $box 1]]
  set region [$w cget -scrollregion]
  if {$region == ""} {return}
  if {[regexp -- {.*[cmpi].*} $region]} {set region "0 0 1 1" ; return}
# Yes, this ignores the problem...better solutions are welcome!

  set tl_xview [expr [lindex $box 0] - [lindex $region 0]]
  set tl_yview [expr [lindex $box 1] - [lindex $region 1]]
  set br_xview [expr [lindex $box 2] - $width - [lindex $region 0]]
  set br_yview [expr [lindex $box 3] - $height - [lindex $region 1]]

# If box is smaller than view, make sure box is totally inside.
  if {($box_width <= $width) && ($box_height <= $height)} {
    if {([lindex $box 0] < $viewx) || ([lindex $box 2] > [expr $viewx + $width]) || \
        ([lindex $box 1] < $viewy) || ([lindex $box 3] > [expr $viewy + $height])} {
      $w xview moveto [expr $tl_xview / [lindex $region 2]]
      $w yview moveto [expr $tl_yview / [lindex $region 3]]
  }} else {

# OK, box is too big. If cursor is in first half, move view to proportion of
# box that hopefully contains cursor. (Yes I know this is chancy).
    set ratio [expr [$w index $i insert].0 / [$w index $i end].0]
    $w xview [expr ($tl_xview + int(($br_xview - $tl_xview) * $ratio)) / [lindex $region 2]]
    $w yview [expr ($tl_yview + int(($br_yview - $tl_yview) * $ratio)) / [lindex $region 3]]
}}


# Selects from cursor to end.
proc th_Canvas_select_next_line {w i} {
  if {[catch {$w index $i 0}]} {bell ; return}

  if {[catch "$w index $i sel.last"]} { set start insert
  } elseif {([$w index $i sel.first] > [$w index $i insert]) ||
      ([$w index $i sel.last] < [$w index $i insert])} {
    $w select clear
    set start insert
  } else {set start sel.first}
  $w select from $i $start
  $w select to $i end
}

# Selects range of text in item i.
proc th_Canvas_select_range {w i start end} { 
  set s [$w index $i $start]
  set e [$w index $i $end]
  if {$s > $e} {bell ; return}
  $w select from $i $s
  $w select to $i $e
  global TH
  if {[catch "set TH(Mark,$w,$i)"]} {bell ; return}
  if {$i == $s} {set TH(Mark,$w,$i) $e
  } else {  set TH(Mark,$w,$i) $s
}}

# Selects from mark to cursor.
proc th_Canvas_select_region {w i} {
  if {[catch {$w index $i 0}]} {bell ; return}

  global TH
  if {[catch "set TH(Mark,$w,$i)"]} {bell ; return}
  if {[$w index $i insert] > $TH(Mark,$w,$i)} {
    th_Canvas_select_range $w $i $TH(Mark,$w,$i) [expr [$w index $i insert] -1]
  } else {th_Canvas_select_range $w $i insert [expr $TH(Mark,$w,$i) -1]
}}


# Exchanges cursor with mark in currently focused item.
proc th_Canvas_exchange_mark {w} {
  if {[set i [$w focus]] == ""} {bell ; return}

  global TH
  if {[catch "set TH(Mark,$w,$i)"]} {bell ; return}
  set x [$w index $i insert]
  $w focus $i
  th_Canvas_goto $w $TH(Mark,$w,$i)
  set TH(Mark,$w,$i) $x
}
