# Focus Management Utilities
# $Header: /u/ra/raines/src/tk/tkmail2/focus.tk,v 1.1.1.1 1995/05/19 18:35:56 raines Exp $
global focus_priv

# whether to take emacs use in to account
if {![info exists focus_priv(emacs)]} {set focus_priv(emacs) 0}
# how to bind to Escape
if {![info exists focus_priv(cancel)]} {set focus_priv(cancel) 0}

# Replace default tk_butLeave to handle focus managemnt
proc tk_butLeave w {
    global tk_priv tk_strictMotif
    if {[focus] == $w} return
    if {[lindex [$w config -state] 4] != "disabled"} {
        if {!$tk_strictMotif} {
            $w config -state normal
        }
    }
    set tk_priv(window) ""
}

bind Button <Any-FocusIn> {tk_butEnter %W}
bind Button <Any-FocusOut> {tk_butLeave %W}
bind Radiobutton <Any-FocusIn> {tk_butEnter %W}
bind Radiobutton <Any-FocusOut> {tk_butLeave %W}
bind Checkbutton <Any-FocusIn> {tk_butEnter %W}
bind Checkbutton <Any-FocusOut> {tk_butLeave %W}

bind Button <KeyPress-space> {tk_butDown %W}
bind Button <KeyRelease-space> {tk_butUp %W}
bind Radiobutton <KeyPress-space> {tk_butDown %W}
bind Radiobutton <KeyRelease-space> {tk_butUp %W}
bind Checkbutton <KeyPress-space> {tk_butDown %W}
bind Checkbutton <KeyRelease-space> {tk_butUp %W}

proc focus:clear { group } {
  global focus_priv
  catch "unset focus_priv($group)"
}

proc focus:register { group wlist {default {}} {cancel {}}} {
  global focus_priv

  if {[info exists focus_priv($group)]} {
    set focus_priv($group) [concat $focus_priv($group) $wlist]
  } else { set focus_priv($group) $wlist }
  foreach w $wlist {
    if {[winfo class $w] == "Text"} {
      bind $w <Control-Tab> "focus:next $w $group"
      bind $w <Shift-Control-Tab> "focus:prev $w $group"
      bind $w <Shift-Return> "focus:prev $w $group"
    } else {
      bind $w <Tab> "focus:next $w $group"
      bind $w <Shift-Tab> "focus:prev $w $group"
      bind $w <Shift-Return> "focus:prev $w $group"
      if {[winfo class $w] != "Listbox"} {
	bind $w <Down> "focus:next $w $group"
	bind $w <Up> "focus:prev $w $group"
	if $focus_priv(emacs) {bind $w <Control-n> "focus:next $w $group"}
	if $focus_priv(emacs) {bind $w <Control-p> "focus:prev $w $group"}
      }
      if {[winfo class $w] != "Entry"} {
	bind $w <Left> "focus:prev $w $group"
	bind $w <Right> "focus:next $w $group"
      }
    }
    if {![string length $default] && [winfo class $w] == "Entry"} {
      bind $w <Return> "focus:next $w $group"
    } elseif {[string length $default] && [winfo class $w] != "Text"} {
      bind $w <Return> $default
    }
    if {[string length $cancel] && [winfo class $w] != "Text"} {
      if $focus_priv(emacs) {
	bind $w <$focus_priv(cancel)Escape> $cancel
      } else {
	bind $w <Escape> $cancel
      }
    }
  }
}

proc focus:enabled { w } {
  if {[lsearch -exact {Button Checkbutton Entry Menubutton Radiobutton \
			   Scale Text} [winfo class $w]] > -1} {
    if {[lindex [$w config -state] 4] == "disabled"} {
      return 0
    }
  }
  return 1
}
    

proc focus:next { wi group} {
  global focus_priv

  set ndx [lsearch -exact $focus_priv($group) $wi]
  if {$ndx == -1} return
  set wlist [concat [lrange $focus_priv($group) [expr $ndx+1] end] \
		 [lrange $focus_priv($group) 0 $ndx]]

  foreach w $wlist {
    if {[winfo ismapped $w] && [focus:enabled $w]} {
      focus $w
      break
    }
  }
}

proc focus:prev { wi group} {
  global focus_priv

  set ndx [lsearch -exact $focus_priv($group) $wi]
  if {$ndx == -1} return
  if {$ndx == 0 } {
    set wlist $focus_priv($group)
  } else {
    set wlist [concat [lrange $focus_priv($group) $ndx end] \
		   [lrange $focus_priv($group) 0 [expr $ndx-1]]]
  }

  for {set i [expr [llength $wlist]-1]} {$i > -1} {incr i -1} {
    set w [lindex $wlist $i]
    if {[winfo ismapped $w] && [focus:enabled $w]} {
      focus $w
      break
    }
  }
}

