FF 2007-05-20 - Today a little problem came to me, and quicly found a solution. Many thanks to tclers guys.
Issue was: encapsulating and hiding the interface of a widget, instead of just overloading/extending it
Practical application: this widget actually does nothing useful, but it does pretty nice, and maybe it can be useful to rip off the concept (though I could clean it up a bit)
I'm not used to put many comments... proc names this time should be auto-explanatory! O;)
#!/usr/bin/env wish proc tracker {w args} { global tracker_struct # set default options set tracker_struct($w:-width) 500 set tracker_struct($w:-height) 300 set tracker_struct($w:-rows) 16 set tracker_struct($w:-cols) 6 set tracker_struct($w:-spacing) 3 # parse options set valid_opts {-width -height -rows -cols} foreach {opt val} $args { if {[lsearch -exact $valid_opts $opt] == -1} { return -code error -errorinfo \ "tracker($w): unknown option: $opt" } else { set tracker_struct($w:$opt) $val } } set c [canvas $w \ -width $tracker_struct($w:-width) \ -height $tracker_struct($w:-height) \ -takefocus 1] rename $c ${w}_canvas set tracker_struct($w:canvas) ${w}_canvas set tracker_struct($w:window) $w set tracker_struct($w:font) [font create -family Courier -size 10 -weight bold \ -slant roman -underline false -overstrike false] set tracker_struct($w:font:-ascent) [font metrics $tracker_struct($w:font) -ascent] set tracker_struct($w:font:-descent) [font metrics $tracker_struct($w:font) -descent] set tracker_struct($w:font:-linespace) [font metrics $tracker_struct($w:font) -linespace] set tracker_struct($w:font:-width) [font measure $tracker_struct($w:font) m] set tracker_struct($w:-charwidth) $tracker_struct($w:font:-width) set tracker_struct($w:-charheight) $tracker_struct($w:font:-linespace) set tracker_struct($w:cursor:x) 0 set tracker_struct($w:cursor:y) 0 # setup callback proc proc $w args "return \[eval tracker_callback $w \$args\]" if [tracker_init $w] { return $c } else { return -code error -errorinfo \ "tracker($w): init failed" } } proc tracker_callback {w command {args {}}} { global tracker_struct if {[llength [info procs tracker_$command]] > 0} { return [eval tracker_$command $w $args] } else { return -code error -errorinfo \ "tracker($w): no such command: $command" } } proc tracker_init {w} { global tracker_struct for {set y 0} {$y < $tracker_struct($w:-rows)} {incr y} { for {set x 0} {$x < $tracker_struct($w:-cols)} {incr x} { set rw $tracker_struct($w:-charwidth) set rh $tracker_struct($w:-charheight) set rx [expr 1+$x*($rw+$tracker_struct($w:-spacing))] set ry [expr 1+$y*($rh+$tracker_struct($w:-spacing))] $tracker_struct($w:canvas) create rectangle \ $rx $ry [expr $rx+$rw] [expr $ry+$rh] \ -fill {} -outline black \ -tags [list bg xy$x$y] } } bind $tracker_struct($w:window) <KeyPress> "tracker_keypress $w %K" bind $tracker_struct($w:window) <ButtonPress-1> "focus $w" tracker_move $w 0 0 return 1 } proc tracker_move {w dx dy} { global tracker_struct $tracker_struct($w:canvas) itemconfigure bg -fill {} incr tracker_struct($w:cursor:x) $dx incr tracker_struct($w:cursor:y) $dy if {$tracker_struct($w:cursor:x) < 0} { incr tracker_struct($w:cursor:x) $tracker_struct($w:-cols) } if {$tracker_struct($w:cursor:y) < 0} { incr tracker_struct($w:cursor:y) $tracker_struct($w:-rows) } set tracker_struct($w:cursor:x) [expr $tracker_struct($w:cursor:x) \ %$tracker_struct($w:-cols)] set tracker_struct($w:cursor:y) [expr $tracker_struct($w:cursor:y) \ %$tracker_struct($w:-rows)] set xy $tracker_struct($w:cursor:x)$tracker_struct($w:cursor:y) $tracker_struct($w:canvas) itemconfigure xy$xy -fill black } proc tracker_keypress {w ks} { #puts "[lindex [info level 0] 0]: $w $ks" switch $ks { Left {tracker_move $w -1 0} Right {tracker_move $w 1 0} Up {tracker_move $w 0 -1} Down {tracker_move $w 0 1} } } pack [tracker .t -width 400 -height 400]