Updated 2007-05-20 21:29:50 by FF

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]

[ Category Widget ]