| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| package require Tk |
|
|
| ::tk::Megawidget create ::tk::IconList ::tk::FocusableWidget { |
| variable w canvas sbar accel accelCB fill font index \ |
| itemList itemsPerColumn list maxIH maxIW maxTH maxTW noScroll \ |
| numItems oldX oldY options rect selected selection textList |
| constructor args { |
| next {*}$args |
| set accelCB {} |
| } |
| destructor { |
| my Reset |
| next |
| } |
|
|
| method GetSpecs {} { |
| concat [next] { |
| {-command "" "" ""} |
| {-font "" "" "TkIconFont"} |
| {-multiple "" "" "0"} |
| } |
| } |
|
|
| |
|
|
| method index i { |
| if {![info exist list]} { |
| set list {} |
| } |
| switch -regexp -- $i { |
| "^-?[0-9]+$" { |
| if {$i < 0} { |
| set i 0 |
| } |
| if {$i >= [llength $list]} { |
| set i [expr {[llength $list] - 1}] |
| } |
| return $i |
| } |
| "^anchor$" { |
| return $index(anchor) |
| } |
| "^end$" { |
| return [llength $list] |
| } |
| "@-?[0-9]+,-?[0-9]+" { |
| scan $i "@%d,%d" x y |
| set item [$canvas find closest \ |
| [$canvas canvasx $x] [$canvas canvasy $y]] |
| return [lindex [$canvas itemcget $item -tags] 1] |
| } |
| } |
| } |
|
|
| method selection {op args} { |
| switch -exact -- $op { |
| anchor { |
| if {[llength $args] == 1} { |
| set index(anchor) [$w index [lindex $args 0]] |
| } else { |
| return $index(anchor) |
| } |
| } |
| clear { |
| switch [llength $args] { |
| 2 { |
| lassign $args first last |
| } |
| 1 { |
| set first [set last [lindex $args 0]] |
| } |
| default { |
| return -code error -errorcode {TCL WRONGARGS} \ |
| "wrong # args: should be\ |
| \"[lrange [info level 0] 0 1] first ?last?\"" |
| } |
| } |
|
|
| set first [$w index $first] |
| set last [$w index $last] |
| if {$first > $last} { |
| set tmp $first |
| set first $last |
| set last $tmp |
| } |
| set ind 0 |
| foreach item $selection { |
| if {$item >= $first} { |
| set first $ind |
| break |
| } |
| incr ind |
| } |
| set ind [expr {[llength $selection] - 1}] |
| for {} {$ind >= 0} {incr ind -1} { |
| set item [lindex $selection $ind] |
| if {$item <= $last} { |
| set last $ind |
| break |
| } |
| } |
|
|
| if {$first > $last} { |
| return |
| } |
| set selection [lreplace $selection $first $last] |
| event generate $w <<ListboxSelect>> |
| my DrawSelection |
| } |
| get { |
| return $selection |
| } |
| includes { |
| return [expr {[lindex $args 0] in $selection}] |
| } |
| set { |
| switch [llength $args] { |
| 2 { |
| lassign $args first last |
| } |
| 1 { |
| set first [set last [lindex $args 0]] |
| } |
| default { |
| return -code error -errorcode {TCL WRONGARGS} \ |
| "wrong # args: should be\ |
| \"[lrange [info level 0] 0 1] first ?last?\"" |
| } |
| } |
|
|
| set first [$w index $first] |
| set last [$w index $last] |
| if {$first > $last} { |
| set tmp $first |
| set first $last |
| set last $tmp |
| } |
|
|
| for {set i $first} {$i <= $last} {incr i} { |
| lappend selection $i |
| } |
| set selection [lsort -integer -unique $selection] |
| event generate $w <<ListboxSelect>> |
| my DrawSelection |
| } |
| } |
| } |
|
|
| method get item { |
| set rTag [lindex $list $item 2] |
| lassign $itemList($rTag) iTag tTag text serial |
| return $text |
| } |
|
|
| |
| |
| |
| method deleteall {} { |
| $canvas delete all |
| unset -nocomplain selected rect list itemList |
| set maxIW 1 |
| set maxIH 1 |
| set maxTW 1 |
| set maxTH 1 |
| set numItems 0 |
| set noScroll 1 |
| set selection {} |
| set index(anchor) "" |
| $sbar set 0.0 1.0 |
| $canvas xview moveto 0 |
| } |
|
|
| |
| |
| method add {image items} { |
| foreach text $items { |
| set iID item$numItems |
| set iTag [$canvas create image 0 0 -image $image -anchor nw \ |
| -tags [list icon $numItems $iID]] |
| set tTag [$canvas create text 0 0 -text $text -anchor nw \ |
| -font $options(-font) -fill $fill \ |
| -tags [list text $numItems $iID]] |
| set rTag [$canvas create rect 0 0 0 0 -fill "" -outline "" \ |
| -tags [list rect $numItems $iID]] |
|
|
| lassign [$canvas bbox $iTag] x1 y1 x2 y2 |
| set iW [expr {$x2 - $x1}] |
| set iH [expr {$y2 - $y1}] |
| if {$maxIW < $iW} { |
| set maxIW $iW |
| } |
| if {$maxIH < $iH} { |
| set maxIH $iH |
| } |
|
|
| lassign [$canvas bbox $tTag] x1 y1 x2 y2 |
| set tW [expr {$x2 - $x1}] |
| set tH [expr {$y2 - $y1}] |
| if {$maxTW < $tW} { |
| set maxTW $tW |
| } |
| if {$maxTH < $tH} { |
| set maxTH $tH |
| } |
|
|
| lappend list [list $iTag $tTag $rTag $iW $iH $tW $tH $numItems] |
| set itemList($rTag) [list $iTag $tTag $text $numItems] |
| set textList($numItems) [string tolower $text] |
| incr numItems |
| } |
| my WhenIdle Arrange |
| return |
| } |
|
|
| |
| |
| |
| method invoke {} { |
| if {$options(-command) ne "" && [llength $selection]} { |
| uplevel #0 $options(-command) |
| } |
| } |
|
|
| |
| |
| |
| method see rTag { |
| if {$noScroll} { |
| return |
| } |
| set sRegion [$canvas cget -scrollregion] |
| if {$sRegion eq ""} { |
| return |
| } |
|
|
| if {$rTag < 0 || $rTag >= [llength $list]} { |
| return |
| } |
|
|
| set bbox [$canvas bbox item$rTag] |
| set pad [expr {[$canvas cget -highlightthickness]+[$canvas cget -bd]}] |
|
|
| set x1 [lindex $bbox 0] |
| set x2 [lindex $bbox 2] |
| incr x1 [expr {$pad * -2}] |
| incr x2 [expr {$pad * -1}] |
|
|
| set cW [expr {[winfo width $canvas] - $pad*2}] |
|
|
| set scrollW [expr {[lindex $sRegion 2]-[lindex $sRegion 0]+1}] |
| set dispX [expr {int([lindex [$canvas xview] 0]*$scrollW)}] |
| set oldDispX $dispX |
|
|
| |
| |
| if {($x2 - $dispX) >= $cW} { |
| set dispX [expr {$x2 - $cW}] |
| } |
| |
| |
| if {($x1 - $dispX) < 0} { |
| set dispX $x1 |
| } |
|
|
| if {$oldDispX ne $dispX} { |
| set fraction [expr {double($dispX) / double($scrollW)}] |
| $canvas xview moveto $fraction |
| } |
| } |
|
|
| |
|
|
| |
| |
| method Arrange {} { |
| if {![info exists list]} { |
| if {[info exists canvas] && [winfo exists $canvas]} { |
| set noScroll 1 |
| $sbar configure -command "" |
| } |
| return |
| } |
|
|
| set W [winfo width $canvas] |
| set H [winfo height $canvas] |
| set pad [expr {[$canvas cget -highlightthickness]+[$canvas cget -bd]}] |
| if {$pad < 2} { |
| set pad 2 |
| } |
|
|
| incr W [expr {$pad*-2}] |
| incr H [expr {$pad*-2}] |
|
|
| set dx [expr {$maxIW + $maxTW + 8}] |
| if {$maxTH > $maxIH} { |
| set dy $maxTH |
| } else { |
| set dy $maxIH |
| } |
| incr dy 2 |
| set shift [expr {$maxIW + 4}] |
|
|
| set x [expr {$pad * 2}] |
| set y [expr {$pad * 1}] |
| set usedColumn 0 |
| foreach sublist $list { |
| set usedColumn 1 |
| lassign $sublist iTag tTag rTag iW iH tW tH |
|
|
| set i_dy [expr {($dy - $iH)/2}] |
| set t_dy [expr {($dy - $tH)/2}] |
|
|
| $canvas coords $iTag $x [expr {$y + $i_dy}] |
| $canvas coords $tTag [expr {$x + $shift}] [expr {$y + $t_dy}] |
| $canvas coords $rTag $x $y [expr {$x+$dx}] [expr {$y+$dy}] |
|
|
| incr y $dy |
| if {($y + $dy) > $H} { |
| set y [expr {$pad * 1}] |
| incr x $dx |
| set usedColumn 0 |
| } |
| } |
|
|
| if {$usedColumn} { |
| set sW [expr {$x + $dx}] |
| } else { |
| set sW $x |
| } |
|
|
| if {$sW < $W} { |
| $canvas configure -scrollregion [list $pad $pad $sW $H] |
| $sbar configure -command "" |
| $canvas xview moveto 0 |
| set noScroll 1 |
| } else { |
| $canvas configure -scrollregion [list $pad $pad $sW $H] |
| $sbar configure -command [list $canvas xview] |
| set noScroll 0 |
| } |
|
|
| set itemsPerColumn [expr {($H-$pad) / $dy}] |
| if {$itemsPerColumn < 1} { |
| set itemsPerColumn 1 |
| } |
|
|
| my DrawSelection |
| } |
|
|
| method DrawSelection {} { |
| $canvas delete selection |
| $canvas itemconfigure selectionText -fill $fill |
| $canvas dtag selectionText |
| set cbg [ttk::style lookup TEntry -selectbackground focus] |
| set cfg [ttk::style lookup TEntry -selectforeground focus] |
| foreach item $selection { |
| set rTag [lindex $list $item 2] |
| foreach {iTag tTag text serial} $itemList($rTag) { |
| break |
| } |
|
|
| set bbox [$canvas bbox $tTag] |
| $canvas create rect $bbox -fill $cbg -outline $cbg \ |
| -tags selection |
| $canvas itemconfigure $tTag -fill $cfg -tags selectionText |
| } |
| $canvas lower selection |
| return |
| } |
|
|
| |
| |
| |
| |
| method Create {} { |
| variable hull |
| set sbar [ttk::scrollbar $hull.sbar -orient horizontal -takefocus 0] |
| catch {$sbar configure -highlightthickness 0} |
| set canvas [canvas $hull.canvas -highlightthick 0 -takefocus 1 \ |
| -width 400 -height 120 -background white] |
| pack $sbar -side bottom -fill x -padx 2 -pady {0 2} |
| pack $canvas -expand yes -fill both -padx 2 -pady {2 0} |
|
|
| $sbar configure -command [list $canvas xview] |
| $canvas configure -xscrollcommand [list $sbar set] |
|
|
| |
| |
| set maxIW 1 |
| set maxIH 1 |
| set maxTW 1 |
| set maxTH 1 |
| set numItems 0 |
| set noScroll 1 |
| set selection {} |
| set index(anchor) "" |
| set fill black |
|
|
| |
| |
| bind $canvas <Configure> [namespace code {my WhenIdle Arrange}] |
|
|
| bind $canvas <Button-1> [namespace code {my Btn1 %x %y}] |
| bind $canvas <B1-Motion> [namespace code {my Motion1 %x %y}] |
| bind $canvas <B1-Leave> [namespace code {my Leave1 %x %y}] |
| bind $canvas <Control-Button-1> [namespace code {my CtrlBtn1 %x %y}] |
| bind $canvas <Shift-Button-1> [namespace code {my ShiftBtn1 %x %y}] |
| bind $canvas <B1-Enter> [list tk::CancelRepeat] |
| bind $canvas <ButtonRelease-1> [list tk::CancelRepeat] |
| bind $canvas <Double-ButtonRelease-1> \ |
| [namespace code {my Double1 %x %y}] |
|
|
| bind $canvas <Control-B1-Motion> {;} |
| bind $canvas <Shift-B1-Motion> [namespace code {my ShiftMotion1 %x %y}] |
|
|
| if {[tk windowingsystem] eq "aqua"} { |
| bind $canvas <Shift-MouseWheel> [namespace code {my MouseWheel [expr {40 * (%D)}]}] |
| bind $canvas <Option-Shift-MouseWheel> [namespace code {my MouseWheel [expr {400 * (%D)}]}] |
| bind $canvas <Command-Key> {# nothing} |
| bind $canvas <Mod4-Key> {# nothing} |
| } else { |
| bind $canvas <Shift-MouseWheel> [namespace code {my MouseWheel %D}] |
| } |
| if {[tk windowingsystem] eq "x11"} { |
| bind $canvas <Shift-Button-4> [namespace code {my MouseWheel 120}] |
| bind $canvas <Shift-Button-5> [namespace code {my MouseWheel -120}] |
| } |
|
|
| bind $canvas <<PrevLine>> [namespace code {my UpDown -1}] |
| bind $canvas <<NextLine>> [namespace code {my UpDown 1}] |
| bind $canvas <<PrevChar>> [namespace code {my LeftRight -1}] |
| bind $canvas <<NextChar>> [namespace code {my LeftRight 1}] |
| bind $canvas <Return> [namespace code {my ReturnKey}] |
| bind $canvas <Key> [namespace code {my KeyPress %A}] |
| bind $canvas <Alt-Key> {# nothing} |
| bind $canvas <Meta-Key> {# nothing} |
| bind $canvas <Control-Key> {# nothing} |
|
|
| bind $canvas <FocusIn> [namespace code {my FocusIn}] |
| bind $canvas <FocusOut> [namespace code {my FocusOut}] |
|
|
| return $w |
| } |
|
|
| |
| |
| |
| |
| |
| |
| method AutoScan {} { |
| if {![winfo exists $w]} return |
| set x $oldX |
| set y $oldY |
| if {$noScroll} { |
| return |
| } |
| if {$x >= [winfo width $canvas]} { |
| $canvas xview scroll 1 units |
| } elseif {$x < 0} { |
| $canvas xview scroll -1 units |
| } elseif {$y >= [winfo height $canvas]} { |
| |
| } elseif {$y < 0} { |
| |
| } else { |
| return |
| } |
| my Motion1 $x $y |
| set ::tk::Priv(afterId) [after 50 [namespace code {my AutoScan}]] |
| } |
|
|
| |
|
|
| |
| method MouseWheel {amount} { |
| if {$noScroll || $::tk_strictMotif} { |
| return |
| } |
| if {$amount > 0} { |
| $canvas xview scroll [expr {(-119-$amount) / 120}] units |
| } else { |
| $canvas xview scroll [expr {-($amount / 120)}] units |
| } |
| } |
| method Btn1 {x y} { |
| focus $canvas |
| set i [$w index @$x,$y] |
| if {$i eq ""} { |
| return |
| } |
| $w selection clear 0 end |
| $w selection set $i |
| $w selection anchor $i |
| } |
| method CtrlBtn1 {x y} { |
| if {$options(-multiple)} { |
| focus $canvas |
| set i [$w index @$x,$y] |
| if {$i eq ""} { |
| return |
| } |
| if {[$w selection includes $i]} { |
| $w selection clear $i |
| } else { |
| $w selection set $i |
| $w selection anchor $i |
| } |
| } |
| } |
| method ShiftBtn1 {x y} { |
| if {$options(-multiple)} { |
| focus $canvas |
| set i [$w index @$x,$y] |
| if {$i eq ""} { |
| return |
| } |
| if {[$w index anchor] eq ""} { |
| $w selection anchor $i |
| } |
| $w selection clear 0 end |
| $w selection set anchor $i |
| } |
| } |
|
|
| |
| |
| method Motion1 {x y} { |
| set oldX $x |
| set oldY $y |
| set i [$w index @$x,$y] |
| if {$i eq ""} { |
| return |
| } |
| $w selection clear 0 end |
| $w selection set $i |
| } |
| method ShiftMotion1 {x y} { |
| set oldX $x |
| set oldY $y |
| set i [$w index @$x,$y] |
| if {$i eq ""} { |
| return |
| } |
| $w selection clear 0 end |
| $w selection set anchor $i |
| } |
| method Double1 {x y} { |
| if {[llength $selection]} { |
| $w invoke |
| } |
| } |
| method ReturnKey {} { |
| $w invoke |
| } |
| method Leave1 {x y} { |
| set oldX $x |
| set oldY $y |
| my AutoScan |
| } |
| method FocusIn {} { |
| $w state focus |
| if {![info exists list]} { |
| return |
| } |
| if {[llength $selection]} { |
| my DrawSelection |
| } |
| } |
| method FocusOut {} { |
| $w state !focus |
| $w selection clear 0 end |
| } |
|
|
| |
| |
| |
| |
| |
| method UpDown amount { |
| if {![info exists list]} { |
| return |
| } |
| set curr [$w selection get] |
| if {[llength $curr] == 0} { |
| set i 0 |
| } else { |
| set i [$w index anchor] |
| if {$i eq ""} { |
| return |
| } |
| incr i $amount |
| } |
| $w selection clear 0 end |
| $w selection set $i |
| $w selection anchor $i |
| $w see $i |
| } |
|
|
| |
| |
| |
| |
| |
| |
| method LeftRight amount { |
| if {![info exists list]} { |
| return |
| } |
| set curr [$w selection get] |
| if {[llength $curr] == 0} { |
| set i 0 |
| } else { |
| set i [$w index anchor] |
| if {$i eq ""} { |
| return |
| } |
| incr i [expr {$amount * $itemsPerColumn}] |
| } |
| $w selection clear 0 end |
| $w selection set $i |
| $w selection anchor $i |
| $w see $i |
| } |
|
|
| |
| |
| method KeyPress key { |
| append accel $key |
| my Goto $accel |
| after cancel $accelCB |
| set accelCB [after 500 [namespace code {my Reset}]] |
| } |
|
|
| method Goto text { |
| if {![info exists list]} { |
| return |
| } |
| if {$text eq "" || $numItems == 0} { |
| return |
| } |
|
|
| if {[llength [$w selection get]]} { |
| set start [$w index anchor] |
| } else { |
| set start 0 |
| } |
| set theIndex -1 |
| set less 0 |
| set len [string length $text] |
| set len0 [expr {$len - 1}] |
| set i $start |
|
|
| |
| |
| while {1} { |
| if {[string equal -nocase -length $len0 $textList($i) $text]} { |
| set theIndex $i |
| break |
| } |
| incr i |
| if {$i == $numItems} { |
| set i 0 |
| } |
| if {$i == $start} { |
| break |
| } |
| } |
|
|
| if {$theIndex >= 0} { |
| $w selection clear 0 end |
| $w selection set $theIndex |
| $w selection anchor $theIndex |
| $w see $theIndex |
| } |
| } |
| method Reset {} { |
| unset -nocomplain accel |
| } |
| } |
| |
| return |
|
|
| |
| |
| |
| |
|
|