#!/afs/ece/usr/tcl/bin/wish -f
# The next line is executed by most shells, but not Tcl \
wish $0 $*


set Bind_Keyword [file tail [info script]]
source "[file dirname [info script]]/../aux/bind.tcl"


# Help text.
set Help "" ; append Help {Focuth -- Add bindings to switch keyboard focus

Any program that needs you to enter a lot of information will usually have
lots of entries and other widgets for you to use when entering them.
Unfortunately, some programs don't give you any way to switch the keyboard
focus between these widgets.

That's what this program is for. After clicking on Teach, you can select a
'focus list' of widgets. Each widget you click on will learn to switch to the
next widget you click on, and the previous one you clicked on. You can thus
create a 'focus list' of widgets to talk to. Or, by finishing your widget
sequence with the first widget, you can close that list and create a 'focus
ring'.

You can also switch automatically between all widgets of the same class (all
Entries for instance) This is useful in that it saves you from selecting the
focus list yourself, and it works even new widgets are created of the same class
or old widgets are destroyed.

Since you can change keybindings and menu entries, you can add multiple focus
lists to widgets. For example, you could implement many small focus rings using
<Control-n>, and then a 'large' focus ring including one widget from each of the
small rights using <Meta-n>.

} $TH_Bindings_Help {

Widgets of Focuth

The Teach Menu

Select an entry in this menu to teach focus switching. You can set up your own
focus ring, or you can define one based on widget classes (such as all the
Entrys, or all the Buttons). The menu options are as follows:

  Widget Keybindings

This lets you set up a 'focus list', where each widget, when it receives a
certain key, sets the focus to the next widget in the list, and when it receives
a different key, sets the focus to the previous widget in the list. Each remote
widget you click on gets added to the list. You can close the list by clicking
on the same widget twice, thereby creating a 'focus ring'. Click outside the
remote application to signify the list is complete.

  Widget Menus

This works the same as 'Widget Keybindings', except that menu options are added
to each widget and no keybindings are set.

  Class Keybindings

This adds a special type of focus code to that widget class. From now on, any
widget of the class of the remote widget you select will pass the focus on to
the next widget of the same class, upon a certain keypress.

  Class Menus

This works like 'Class Keybindings', except that a menu is created over the
widget you click on. The menu lets you shift focus between the previous and next
widgets in that class. However, unlike 'Class Keybindings', only one widget is
affected; no other widgets in that class learn about the focus ring.

You can teach both keybindings and menus to a widget. When you teach a widget
menus, using either 'Class Menus' or 'Widget Menus', if it already received the
corresponding keybindings, it adds those as accelerators on the menu entries
whose functions match the keybindings. This serves as a handy key 'reference
chart'.

  Class Code

This lets you teach the code necessary for the previous functions to a remote
application, but no bindings or menus are created. This option is implicitly
done whenever you select 'Class Keybindings' or 'Class Menus'.

} $TH_Bind_Help {

Bindings made to canvas widget items apply to the canvas widgets themselves. So
in general, all canvas items can only switch focus to one other widget, or item.

Using a Default Menubar while creating a focus list is a rather ridiculous
combination.}


proc teach_code {} {include_files {focus.tcl th_next_widget}}
proc widget_bindings {} {global Bindings ; return $Bindings(Focus)}

proc add_focus_classbinding {b} {
  if {![get_widget]} {bell ; return}
  clear_output
  teach_code
  switch $b {
    1 {global Class ; teach_keybindings $Class [widget_bindings]
  } 2 {teach_menubindings [widget_bindings]}}
}

proc add_focus_binding {b} {
  global App Widget Class
  set prev_app "" ; set prev_widget ""
  while {[get_widget]} {
    set root_x [send $App winfo rootx $Widget]
    set root_y [send $App winfo rooty $Widget]
    if {$Class == "Canvas"} {
      global X Y
      set new_x [send $App $Widget canvasx [expr $X - $root_x]]
      set new_y [send $App $Widget canvasy [expr $Y - $root_y]]
      set item [lindex [send $App $Widget find overlapping $new_x $new_y $new_x $new_y] 0]
    } else {set item ""}

    if {$prev_widget == ""} {
      set prev_app $App ; set prev_widget $Widget ; set prev_item $item
      clear_output

    } else {if {$prev_app != $App} {break}
      if {$prev_item != ""} {
        set prev_binding "\{Focus_Previous \{catch \{focus $prev_widget ; $prev_widget focus $prev_item\}\}\}"
      } else {
        set prev_binding "\{Focus_Previous \{catch \{focus $prev_widget\}\}\}"}
      if {$item != ""} {
        set next_binding "\{Focus_Next \{catch \{focus $Widget ; $Widget focus $item\}\}\}"
      } else {
        set next_binding "\{Focus_Next \{catch \{focus $Widget\}\}\}"}

      switch $b {
        1 {teach_keybindings $Widget $prev_binding
      } 2 {teach_menubindings $prev_binding
      }}
      set tmp $Widget ; set Widget $prev_widget ; set prev_widget $tmp
      set tmp $prev_item ; set prev_item $item ; set item $tmp
      switch $b {
        1 {teach_keybindings $Widget $next_binding
      } 2 {teach_menubindings $next_binding
      }}
   }}
   bell
}


set menu .buttons.teach.m
$menu add command -label "Widget Keybindings" -command {add_focus_binding 1}
$menu add command -label "Widget Menus" -command {add_focus_binding 2}
$menu add command -label "Class Keybindings" -command {add_focus_classbinding 1}
$menu add command -label "Class Menus" -command {add_focus_classbinding 2}
$menu add command -label "Class Code" -command {add_focus_classbinding 3}
