### Copyright (C) 1995-1997 Jesper K. Pedersen
### This program is free software; you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation; either version 2 of the License, or
### (at your option) any later version.
###
### This program is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
### GNU General Public License for more details.
###
### You should have received a copy of the GNU General Public License
### along with this program; if not, write to the Free Software
### Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

proc indexList {path prefix name minWidth} {
  global elements __widgetArgs __editInfo __scrollBar
  catch "unset __elements"
  set function $__editInfo(name)

  if {![regexp {^(.*)_(.*[^0-9])[0-9]+$} $prefix all superPrefix superName ]} {
    error "Internal error: couldn't parse \"$prefix\""
  }

  if {![regexp "^(.*)\\._$superName\\.row\[0-9\]+\\._$name\$" \
            $path all superPath]} {
    error "Internal error: could't parse \"$path\""
  }

  ### collecting the key elements
  set prefix ${superPrefix}_$superName

  set count [lindex $__scrollBar($prefix) 1]
  set elements {}
  for {set i 0} {$i < $count} {incr i} {
    upvar \#0 ${prefix}${i}_$name elm
    lappend elements $elm
  }
  
  set viewable $__widgetArgs(${function}__${superName}__count)

  set top [lindex $__scrollBar($prefix) 0]
  global ${prefix}${top}_$name
  set index [popUpComboBox $path $elements 25 $minWidth "" [set ${prefix}${top}_$name]]

  if {$index > -1} {
    if {[expr $count-$viewable] < $index} {
      set index [expr $count-$viewable]
    }
    scroll $superPath $superPrefix $superName $index
  }
}

proc popUpComboBox {path elements count minWidth name val} {
  global __Combo
  set w .combo
  toplevel $w -class Dialog -cursor arrow
  wm overrideredirect $w 1

  set bindings [bind all <1>]

  bind all <1> "after cancel \$tkPriv(afterId);if {\"%W\" != \"$w.bar\"} {comboExit $w}"
  ### create the listbox and the scrollbar
  listbox $w.box -cursor left_ptr \
      -height [min $count [llength $elements]]

  if {$count < [llength $elements]} {
    scrollbar $w.bar -command "$w.box yview" -cursor left_ptr
    $w.box configure -yscrollcommand "$w.bar set"
    pack $w.box -side left -fill both -expand 1
    pack $w.bar -fill y -expand 1
  } else {
    pack $w.box -expand 1 -fill both
  }

  ### binding help
  if {$name != ""} {
    bind $w.box <3> "listbox_help $w $name %y $path;break"
  }
  
  foreach elm $elements {
    $w.box insert end $elm
  }
  set index [lsearch -exact $elements $val]
  $w.box yview $index
  bind $w.box <ButtonRelease-1> "after cancel \$tkPriv(afterId);comboReturn $w %y;break"
  bind $w.box <ButtonPress-1> "after cancel \$tkPriv(afterId);comboReturn $w %y;break"
  wm withdraw $w
  update idletasks

  ### calculate the start y coordinate for the window
  set  y [winfo rooty $path.2]
  incr y [winfo height $path.2]
  incr y 3

  ### calculate the reqheight be the widget.
  set bd [$w cget -bd]
  incr bd [$w cget -highlightthickness]
  set height [expr [winfo reqheight $w.box] + 2*$bd]

  ### calculate the width of the widget
  set x1 [winfo rootx $path.2]
  set x2  [winfo rootx $path.combo]
  incr x2 [winfo width $path.combo]
  set width  [max $minWidth [expr $x2 - $x1]]
  
  ### calculate the with we will give the window
  set reqwidth [winfo reqwidth $w]
  if {$reqwidth < $width} {
    set reqwidth $width
  } else {
    if {$reqwidth > [winfo vrootwidth .]} {
	    set reqwidth [winfo vrootwidth .]
    }
  }
  set width $reqwidth

  ### If the listbox is too far right, pull it back to the left
  set scrwidth [winfo vrootwidth .]
  if {[expr $x1 + $width] > $scrwidth} {
    set x1 [expr $scrwidth - $width]
  }

  ### If the listbox is too far left, pull it back to the right
  ### I geues this can only happend if you use a virtual window manager.
  if {$x1 < 0} {
    set x1 0
  }

  ### If the listbox is below bottom of screen, put it upwards
  set scrheight [winfo vrootheight .]
  set bottom [expr $y+$height]
  if {$bottom > $scrheight} {
    set y [expr $y-$height-[winfo height $path.2]-5]
  }

  ### show the window
  wm geometry $w $reqwidth\x$height+$x1+$y
  wm deiconify $w
  grabSet -global $w

  ### Wait for the window to disappear
  tkwait window $w
  set index $__Combo
  unset __Combo
  bind all <1> $bindings
  return $index
}

proc comboReturn {w y} {
  global __Combo
  set __Combo [$w.box nearest $y]
  grab release $w
  destroy $w
  update
}

proc comboExit {w} {
  global __Combo
  set __Combo -1
  grab release $w
  destroy $w
}
