You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

202 lines
4.4 KiB

# -*- tcl -*-
# ### ### ### ######### ######### #########
## Terminal packages - string -> action mappings
## (menu objects). For use with 'receive listen'.
## In essence a DFA with tree structure.
# ### ### ### ######### ######### #########
## Requirements
package require snit
package require textutil::repeat
package require textutil::tabify
package require term::ansi::send
package require term::receive::bind
package require term::ansi::code::ctrl
namespace eval ::term::receive::menu {}
# ### ### ### ######### ######### #########
snit::type ::term::interact::menu {
option -in -default stdin
option -out -default stdout
option -column -default 0
option -line -default 0
option -height -default 25
option -actions -default {}
option -hilitleft -default 0
option -hilitright -default end
option -framed -default 0 -readonly 1
# ### ### ### ######### ######### #########
##
constructor {dict args} {
$self configurelist $args
Save $dict
install bind using ::term::receive::bind \
${selfns}::bind $options(-actions)
$bind map [cd::cu] [mymethod Up]
$bind map [cd::cd] [mymethod Down]
$bind map \n [mymethod Select]
#$bind default [mymethod DEF]
return
}
# ### ### ### ######### ######### #########
##
method interact {} {
Show
$bind listen $options(-in)
vwait [myvar done]
$bind unlisten $options(-in)
return $map($done)
}
method done {} {set done $at ; return}
method clear {} {Clear ; return}
# ### ### ### ######### ######### #########
##
component bind
# ### ### ### ######### ######### #########
##
variable map -array {}
variable header
variable labels
variable footer
variable empty
proc Save {dict} {
upvar 1 header header labels labels footer footer
upvar 1 empty empty at at map map top top
upvar 1 options(-height) height
set max 0
foreach {l code} $dict {
if {[set len [string length $l]] > $max} {set max $len}
}
set header [cd::groptim [cd::tlc][textutil::repeat::strRepeat [cd::hl] $max][cd::trc]]
set footer [cd::groptim [cd::blc][textutil::repeat::strRepeat [cd::hl] $max][cd::brc]]
set labels {}
set at 0
foreach {l code} $dict {
set map($at) $code
lappend labels ${l}[textutil::repeat::strRepeat " " [expr {$max-[string length $l]}]]
incr at
}
set h $height
if {$h > [llength $labels]} {set h [llength $labels]}
set eline " [textutil::repeat::strRepeat { } $max]"
set empty $eline
for {set i 0} {$i <= $h} {incr i} {
append empty \n$eline
}
set at 0
set top 0
return
}
variable top 0
variable at 0
variable done .
proc Show {} {
upvar 1 header header labels labels footer footer at at
upvar 1 options(-in) in options(-column) col top top
upvar 1 options(-out) out options(-line) row
upvar 1 options(-height) height options(-framed) framed
upvar 1 options(-hilitleft) left
upvar 1 options(-hilitright) right
set bot [expr {$top + $height - 1}]
set fr [expr {$framed ? [cd::vl] : { }}]
set text $header\n
set i $top
foreach l [lrange $labels $top $bot] {
append text $fr
if {$i != $at} {
append text $l
} else {
append text [string replace $l $left $right \
[cd::sda_revers][string range $l $left $right][cd::sda_reset]]
}
append text $fr \n
incr i
}
append text $footer
vt::wrch $out [cd::showat $row $col $text]
return
}
proc Clear {} {
upvar 1 empty empty options(-column) col
upvar 1 options(-out) out options(-line) row
vt::wrch $out [cd::showat $row $col $empty]
return
}
# ### ### ### ######### ######### #########
##
method Up {str} {
if {$at == 0} return
incr at -1
if {$at < $top} {incr top -1}
Show
return
}
method Down {str} {
upvar 0 options(-height) height
if {$at == ([llength $labels]-1)} return
incr at
set bot [expr {$top + $height - 1}]
if {$at > $bot} {incr top}
Show
return
}
method Select {str} {
$self done
return
}
method DEF {str} {
puts stderr "($str)"
exit
}
##
# ### ### ### ######### ######### #########
}
# ### ### ### ######### ######### #########
## Ready
namespace eval ::term::interact::menu {
term::ansi::code::ctrl::import cd
term::ansi::send::import vt
}
package provide term::interact::menu 0.1
##
# ### ### ### ######### ######### #########