#
# <20200602.1828.10>
#
# An alternate for the history menu to make the whole history available
# We bring up a listbox and scroll bar to the right of the console
# window.

# TKCON History manual, i.e. how to use this history command/menu
#
# To call up the history click on the "History" button at the top of
# the "tkcon" command window. This will extend the command window on
# the right with a "listbox" and a "scroll bar". The whole history is
# available by just scrolling (mouse wheel also works here). The
# "extended" "listbox" selection rules work on this window, i.e.
# <1> selects what's under the mouse
# <1> drag  selects items mouse moves over
# <Shift-1> selects what's under the mouse and all between that and last selection
# <Control-1> toggles selection under the mouse
# <Control-Drag-1> toggles what ever the mouse passes over
#
# To cancel all the history selection, selecte item 0 at the top of the "listbox"
# For multiple selections the code keeps track of the order.
# It is also aware if an item is dropped from the selection.
# When the mouse <Leave>s the history "listbox" the selected history items (if any)
# are executed in the order they were selected. Also the "listbox" and its scroll bar
# are removed from the window.
#
package require BLT
proc ::tkcon::HistoryMenu {m} {
  variable PRIV
  set PRIV(hisSel) {}
  frputs m
  if {![winfo exists $m]} return
  set w .tkcon.hisListbox
  set ws .tkcon.hisScroll
  if {![winfo exists $w]} {
    blt::treeview $w \
	-width 40\
	-selectmode multiple\
	-yscrollcommand "$ws set"\
	-bg $::tkcon::COLOR(bg)\
	-fg $::tkcon::COLOR(stdout)\
	-font $::tkcon::OPT(font)
    scrollbar $ws -relief sunken -command "$w yview"
    # ::autoscroll::autoscroll $w.scroll
  }
  set id [EvalSlave history nextid]
  set PRIV(values) [list "$id: Cancel History command"]
  # if {$PRIV(histid)==$id} return
  $m delete 0 end
  set PRIV(histid) $id
  while {($id>1) && \
	     ![catch {EvalSlave history event [incr id -1]} tmp]} {
    set lbl $tmp
    if {[string len $lbl]>32} { set lbl [string range $tmp 0 28]... }
    lappend PRIV(values) "$id: $lbl"
  }
  $m insert 0 -seperator ":" PRIV(values)
  # frputs w
  grid $w -row 1 -column 3 -sticky sn
  grid $ws -row 1 -column 4 -sticky news
  bind $w <<ListboxSelect>> [list ::tkcon::selHistory $w $ws]
  bind $w <Leave> [list ::tkcon::goToHistory $w $ws]
}

proc ::tkcon::selHistory {w ws} {
  variable PRIV
  # PRIV(hisSel) is a list of the currently selected commands
  # if empty, just add what we find now...
  frputs w ws
  if {[set cus [$w curselection]] == {} || $cus == 0} {
    set PRIV(hisSel) {}
    $w selection clear 0 end
    return
  }
  if {$PRIV(hisSel) == {}} {
    set PRIV(hisSel) $cus
    return
  }
  # We want to build an ordered list of the selections
  # First if any of the old selections are no longer in
  # the selection, remove them.
  set newSel {}
  foreach sel $PRIV(hisSel) {
    if {$sel ni $cus} {continue}
    lappend newSel $sel
  }
  # Now add any new selections to the end
  foreach sel $cus {
    if {$sel in $newSel} {continue}
    lappend newSel $sel
  }
  set PRIV(hisSel) $newSel
  return
}

# We come to goToHistory on <Leave>. If their is a selection
# it is set to execute here.

proc ::tkcon::goToHistory {w ws} {
  variable PRIV
  # frputs w ws cus "[winfo exists $w] "
  set cmd {}
  foreach sel $PRIV(hisSel) {
    set id [regsub {([0-9]+):.*} [lindex $PRIV(values) $sel] {\1}]
    if {![catch {EvalSlave history event $id} tmp]} {
      if {$cmd != {}} {
	append cmd "\n"
      }
      append cmd "$tmp"
    }
  }
  if {$cmd != {}} {
    $::tkcon::PRIV(console) delete limit end
    $::tkcon::PRIV(console) insert limit $cmd\n
    $::tkcon::PRIV(console) see end
    ::tkcon::Eval $::tkcon::PRIV(console)
  }
  
  grid remove $w $ws
}

