Posted to tcl by aspect at Fri Apr 24 03:58:40 GMT 2015view pretty
tcl::tm::path add ../modules # # An experiment in TclOO widgets as a transparent facade layer over Tk # # .. looks pretty good, so far. There's plenty of undesirable overlap with names unless we're very careful. # Capitalising window names might be sufficient safety? # # probably wants more methods for ttk .. # # options needs opts, and learning from snit. # # making classes out of these is going to be the kicker! # package require pkg package require tests package require debug package require repl pkg -export * Window { proc windowcontext {} {} oo::class create Widget { variable w constructor {cmd args} { set w [uplevel 1 windowcontext].[namespace tail [self object]] $cmd $w {*}$args rename $w [set nsw [namespace current]::$w] namespace export $w namespace eval :: [list namespace import $nsw] proc windowcontext {} [list return $w] set griddefaults {} } method w {} {return $w} method widget {cmd name args} { Widget create $name $cmd {*}[my WidgetArgs $args] oo::objdefine [self] forward $name $name return $name } method WidgetArgs {arglist} { set q 0 lmap a $arglist { if {$q} { if {![string match ::* $a]} { debug assert {$a in [info object variables [self]]} set q 0 my varname $a } else { set a } } else { if {[string match -*variable $a]} { set q 1 } set a } } } method configure args { if {![llength $args]} { tailcall $w configure } if {[string match -* [lindex $args 0]]} { tailcall $w configure $args } set args [lassign $args cmd] [$cmd w] configure {*}[my WidgetArgs $args] } method destroy args { if {$args eq ""} { next } else { destroy {*}[my ItemArgs $args] } } variable griddefaults method griddefaults args { set griddefaults $args } method packdefaults args { set griddefaults $args } method grid {cmd args} { if {$cmd in "anchor bbox location size propagate slaves configure rowconfigure columnconfigure"} { grid $cmd $w {*}[my ItemArgs {*}$args] } else { grid {*}[my GridArgs $cmd {*}$args] -in $w } } method pack {cmd args} { if {$cmd in "propagate slaves"} { pack $cmd $w {*}[my ItemArgs {*}$args] } else { pack {*}[my GridArgs $cmd {*}$args] -in $w } } method ItemArgs {args} { set i 0 set args [lmap a $args { if {[string match -* $a]} { incr i } expr {$i ? $a : [$a w]} }] } method GridArgs {args} { set i 0 array set def $griddefaults set args [lmap a $args { if {[string match -* $a]} { unset -nocomplain def($a) incr i } expr {$i ? $a : [$a w]} }] concat $args [array get def] } method bind {event argspec body args} { oo::objdefine [self] method $event [my BindArgs $argspec] $body oo::objdefine [self] export $event set cmdargs [my BindCmdArgs $argspec] bind [my w] $event [list [self] $event {*}$cmdargs {*}$args] } method BindArgs {argspec} { lmap a $argspec { string trimleft $a % } } method BindCmdArgs {argspec} { lmap a $argspec { if {![string match %* $a]} break set a } } method bindtags args { tailcall bindtags [my w] {*}$args } variable options method options {} { lsort -dictionary [concat [array values options] [$w configure]] } method option {option resource class default} { set options($option) [list $resource $class $default $default] # .. learn more from snit } method method {name argspec body} { oo::objdefine [self] method $name $argspec $body oo::objdefine [self] export $name } method variable args { oo::objdefine [self] variable {*}$args } method get {name} { set [my varname $name] } method set args { foreach {name val} $args { set [my varname $name] $val } } method getdict {} { lconcat name [info object variables [self]] { list $name [set [my varname $name]] } } method unknown {args} { if {$args eq ""} { return [my w] } else { tailcall [my w] {*}$args } } } } if 1 { package require Tk Widget create t toplevel t widget entry e1 t widget button b1 -command {puts hello} t griddefaults -sticky nsew t grid e1 t grid b1 t grid [t widget button b2 -text okde] t grid rowconfigure b1 -weight 1 t e1 insert end "lalala" t configure b1 -text "Press me" t bind <1> {%W %x %y a} { ;# implicitly creates a method on the object .. puts "$W $x $y: $ack ($a)" ;# that can resolve object variables! } five ;# remember: % args must come first! t variable ack t configure e1 -textvariable ack ;# ack is resolved in t's scope! } if 1 { chan configure stdin -blocking 0 chan configure stdout -buffering none coroutine repl repl::chan stdin stdout puts vwaiting vwait forever }