Index: Makefile.in =================================================================== diff -u -r187fbd20a453ae9d73e9b48f88b8d6a8c79685c2 -r2076ef459f42cdf6426522aab56be490b66c2436 --- Makefile.in (.../Makefile.in) (revision 187fbd20a453ae9d73e9b48f88b8d6a8c79685c2) +++ Makefile.in (.../Makefile.in) (revision 2076ef459f42cdf6426522aab56be490b66c2436) @@ -226,6 +226,7 @@ EXAMPLE_SCRIPTS = \ $(src_doc_dir)/example-scripts/bagel.html \ + $(src_doc_dir)/example-scripts/per-object-mixins.html \ $(src_doc_dir)/example-scripts/rosetta-abstract-type.html \ $(src_doc_dir)/example-scripts/rosetta-classes.html \ $(src_doc_dir)/example-scripts/rosetta-constraint-genericity.html \ @@ -236,7 +237,12 @@ $(src_doc_dir)/example-scripts/rosetta-serialization.html \ $(src_doc_dir)/example-scripts/rosetta-singleton.html \ $(src_doc_dir)/example-scripts/rosetta-unknown-method.html \ + $(src_doc_dir)/example-scripts/tk-mini.html \ + $(src_doc_dir)/example-scripts/tk-horse-race.html \ + $(src_doc_dir)/example-scripts/traits-composite.html \ + $(src_doc_dir)/example-scripts/traits-simple.html \ + %.html : %.tcl $(TCLSH) $(src_app_dir_native)/utils/source-doc-beautifier.tcl $< asciidoc $*.txt Index: TODO =================================================================== diff -u -ra390a38437dec2a7c3461f9fadef108ebf74b928 -r2076ef459f42cdf6426522aab56be490b66c2436 --- TODO (.../TODO) (revision a390a38437dec2a7c3461f9fadef108ebf74b928) +++ TODO (.../TODO) (revision 2076ef459f42cdf6426522aab56be490b66c2436) @@ -3651,8 +3651,22 @@ "/obj/ info lookup methods") * extend regression test +- nx-traits: + * use "info methods -closure" instead of instantiating a + class at trait-insertion time + * added trait as package nx::callback +- example scripts: added tk-mini and tk-horse-race + + TODO: + - add tk-spreadsheet and tk-railroad to example scripts + - allow traits to be added to objects (maybe use :trait + instead of "useTrait" and allow modifier "class") + - naming of traits. Predefined traits have a leading "T" + (convetion by ducasse); how should the package and file + be named? currently nx::trait nx-trait.tcl. + - warnings for "numeric" names for args and nonpos-args? - special handling of values looking like nonpos-flags, but wich are not ones (-1, "- a b c", ....) in detection Index: doc/example-scripts/tk-horse-race.html =================================================================== diff -u --- doc/example-scripts/tk-horse-race.html (revision 0) +++ doc/example-scripts/tk-horse-race.html (revision 2076ef459f42cdf6426522aab56be490b66c2436) @@ -0,0 +1,896 @@ + + + + + +Listing of doc/example-scripts/tk-horse-race.tcl + + + + + +
+
+
+

A small Horse Race game, originally developed by Richard Suchenwirth +in plain Tcl (see http://wiki.tcl.tk/3467). The game was rewritten +as a design study in NX by Gustaf Neumann in May 2011.

+
+
+tk-horse-race.png +
+
+
+
+
package require Tk
+package require nx::callback
+
+ ##############################################################################
+ # Trait ListUtils
+ #
+ # Some list utilities, not part of a package we can require here.
+ ##############################################################################
+
+ nx::Trait create TListUtils {
+
+   :protected method lpick {list} {
+     # return a random entry from a given list
+     lindex $list [expr {int(rand()*[llength $list])}]
+   }
+   :protected method lremove {listName what} {
+     # remove a list element referenced by the elements value
+     :upvar $listName list
+     set pos  [lsearch $list $what]
+     set list [lreplace $list $pos $pos]
+   }
+ }
+
+ ##############################################################################
+ # Class Horse
+ #
+ # This class defines the logic, how and where a single horse and
+ # jockey are drawn. The painting of the horse happens just at startup
+ # time, later the horses are moved via their tags.
+ ##############################################################################
+
+ nx::Class create Horse {
+   :property name:required      ;# name is the external name of the horse
+   :property tag:required       ;# tag is an internal id
+   :property canvas:required    ;# the canvas, on which the horse is drawn
+   :property n:integer,required ;# the position on the canvas
+
+   :useTrait nx::TCallback
+   :useTrait TListUtils
+
+   :method draw {x y} {
+     set hide [:lpick {black brown white gray brown3 brown4}]
+     set c1 [:lpick {red yellow blue purple pink green}]
+     set c2 [:lpick {red yellow blue purple pink green}]
+     ${:canvas} create oval 0 -1 18 4 -fill $hide -outline $hide -tag ${:tag}
+     ${:canvas} create line 1 12 3 0 5 12 -fill $hide -tag ${:tag} -width 2
+     ${:canvas} create line 15 12 17 0 19 12 -fill $hide -tag ${:tag} -width 2
+     ${:canvas} create line 16 0 20 -7 24 -5 -fill $hide -tag ${:tag} -width 3
+     # Jockey:
+     ${:canvas} create line 9 4 11 1 7 -1 -fill $c1 -width 2 -tag ${:tag}
+     ${:canvas} create line 7 -2 10 -6 15 -3 -fill $c2 -width 2 -tag ${:tag}
+     ${:canvas} create oval 9 -7 12 -10 -fill orange -outline orange -tag ${:tag}
+     ${:canvas} move ${:tag} $x $y
+   }
+
+   :method init {} {
+     set w [entry ${:canvas}.e${:n} -textvar [:bindvar name] -width 7 -bg green3]
+     ${:canvas} create window 5 [expr {${:n}*30+5}] -window $w -anchor nw
+     :draw 70 [expr {${:n}*30+14}]
+   }
+ }
+
+ ##############################################################################
+ # Class HorseGame
+ #
+ # Defines the main canvas of the Game and contains the logic of
+ # starting, resetting etc.
+ ##############################################################################
+
+ nx::Class create HorseGame {
+   :property {bg1 green4}   ;# background color of the canvas
+   :property {bg2 green3}   ;# background color of the result label
+   :property {width 750}    ;# width of the canvas
+   :property {height 330}   ;# height of the canvas
+   :property {horses}       ;# a list of horse names participating in the game
+
+   :useTrait nx::TCallback
+   :useTrait TListUtils
+
+   :method init {} {
+     #
+     # create the canvas
+     #
+     set :canvas [canvas .c -bg ${:bg1} -width ${:width} -height ${:height}]
+     pack ${:canvas}
+     #
+     # create the Horses
+     #
+     set n 0
+     foreach name ${:horses} {
+       set h [::Horse create horse$n -name $name -canvas ${:canvas} -n $n -tag horse$n]
+       lappend :tags horse$n
+       incr n
+     }
+
+     # finish line
+     set w [expr {${:width} - 20}]
+     ${:canvas} create line $w 0 $w ${:height} -fill white -tag finish
+
+     # start button
+     button ${:canvas}.button -text Start -pady 0 -width 0 \
+         -command [:callback start ${:tags}]
+     ${:canvas} create window 5 [expr {$n*30}] -window ${:canvas}.button -anchor nw
+
+     # label for the results
+     label ${:canvas}.winners -textvar [:bindvar winners] -bg ${:bg2} -width 80
+     ${:canvas} create window 70 [expr {$n*30}] -window ${:canvas}.winners -anchor nw
+   }
+
+   :public method start {running} {
+     #
+     # When the "Start" button is pressed, we turn this button into a
+     # "Reset" button and the horse race starts. We stop, when more
+     # than two horses pass the finish line.
+     #
+     ${:canvas}.button config -text Reset -command [:callback reset]
+     set :winners {}
+     set finish [expr {[lindex [${:canvas} bbox finish] 2]+10}]
+     while {[llength ${:winners}]<3} {
+       set this [:lpick $running]
+       ${:canvas} move $this [:lpick {0 1 2 3}] 0
+       update
+       if {[lindex [${:canvas} bbox $this] 2] > $finish} {
+         lappend :winners [expr {[llength ${:winners}]+1}]:[$this name]
+         :lremove running $this
+       }
+     }
+   }
+
+   :public method reset {} {
+     #
+     # When the "Reset" button is pressed, we switch back to the start
+     # configuration, the horses come back to the start.
+     #
+     ${:canvas}.button config -text Start -command [:callback start ${:tags}]
+     foreach tag ${:tags} {
+       set x [lindex [${:canvas} bbox $tag] 0]
+       ${:canvas} move $tag [expr {70-$x}] 0
+     }
+   }
+ }
+
+ #
+ # everything is defined, create the game
+ #
+ bind . <space> {exec wish $argv0 &; exit}
+ HorseGame new -horses {Blaise NX Animal Ada Alan XOTcl Grace itcl John Linus}
+
+
+
+

+ + + Index: doc/example-scripts/tk-horse-race.png =================================================================== diff -u Binary files differ Index: doc/example-scripts/tk-horse-race.tcl =================================================================== diff -u --- doc/example-scripts/tk-horse-race.tcl (revision 0) +++ doc/example-scripts/tk-horse-race.tcl (revision 2076ef459f42cdf6426522aab56be490b66c2436) @@ -0,0 +1,153 @@ +# A small Horse Race game, originally developed by Richard Suchenwirth +# in plain Tcl (see http://wiki.tcl.tk/3467). The game was rewritten +# as a design study in NX by Gustaf Neumann in May 2011. +# +# image::tk-horse-race.png[] +# +package require Tk +package require nx::callback + + ############################################################################## + # Trait ListUtils + # + # Some list utilities, not part of a package we can require here. + ############################################################################## + + nx::Trait create TListUtils { + + :protected method lpick {list} { + # return a random entry from a given list + lindex $list [expr {int(rand()*[llength $list])}] + } + :protected method lremove {listName what} { + # remove a list element referenced by the elements value + :upvar $listName list + set pos [lsearch $list $what] + set list [lreplace $list $pos $pos] + } + } + + ############################################################################## + # Class Horse + # + # This class defines the logic, how and where a single horse and + # jockey are drawn. The painting of the horse happens just at startup + # time, later the horses are moved via their tags. + ############################################################################## + + nx::Class create Horse { + :property name:required ;# name is the external name of the horse + :property tag:required ;# tag is an internal id + :property canvas:required ;# the canvas, on which the horse is drawn + :property n:integer,required ;# the position on the canvas + + :useTrait nx::TCallback + :useTrait TListUtils + + :method draw {x y} { + set hide [:lpick {black brown white gray brown3 brown4}] + set c1 [:lpick {red yellow blue purple pink green}] + set c2 [:lpick {red yellow blue purple pink green}] + ${:canvas} create oval 0 -1 18 4 -fill $hide -outline $hide -tag ${:tag} + ${:canvas} create line 1 12 3 0 5 12 -fill $hide -tag ${:tag} -width 2 + ${:canvas} create line 15 12 17 0 19 12 -fill $hide -tag ${:tag} -width 2 + ${:canvas} create line 16 0 20 -7 24 -5 -fill $hide -tag ${:tag} -width 3 + # Jockey: + ${:canvas} create line 9 4 11 1 7 -1 -fill $c1 -width 2 -tag ${:tag} + ${:canvas} create line 7 -2 10 -6 15 -3 -fill $c2 -width 2 -tag ${:tag} + ${:canvas} create oval 9 -7 12 -10 -fill orange -outline orange -tag ${:tag} + ${:canvas} move ${:tag} $x $y + } + + :method init {} { + set w [entry ${:canvas}.e${:n} -textvar [:bindvar name] -width 7 -bg green3] + ${:canvas} create window 5 [expr {${:n}*30+5}] -window $w -anchor nw + :draw 70 [expr {${:n}*30+14}] + } + } + + ############################################################################## + # Class HorseGame + # + # Defines the main canvas of the Game and contains the logic of + # starting, resetting etc. + ############################################################################## + + nx::Class create HorseGame { + :property {bg1 green4} ;# background color of the canvas + :property {bg2 green3} ;# background color of the result label + :property {width 750} ;# width of the canvas + :property {height 330} ;# height of the canvas + :property {horses} ;# a list of horse names participating in the game + + :useTrait nx::TCallback + :useTrait TListUtils + + :method init {} { + # + # create the canvas + # + set :canvas [canvas .c -bg ${:bg1} -width ${:width} -height ${:height}] + pack ${:canvas} + # + # create the Horses + # + set n 0 + foreach name ${:horses} { + set h [::Horse create horse$n -name $name -canvas ${:canvas} -n $n -tag horse$n] + lappend :tags horse$n + incr n + } + + # finish line + set w [expr {${:width} - 20}] + ${:canvas} create line $w 0 $w ${:height} -fill white -tag finish + + # start button + button ${:canvas}.button -text Start -pady 0 -width 0 \ + -command [:callback start ${:tags}] + ${:canvas} create window 5 [expr {$n*30}] -window ${:canvas}.button -anchor nw + + # label for the results + label ${:canvas}.winners -textvar [:bindvar winners] -bg ${:bg2} -width 80 + ${:canvas} create window 70 [expr {$n*30}] -window ${:canvas}.winners -anchor nw + } + + :public method start {running} { + # + # When the "Start" button is pressed, we turn this button into a + # "Reset" button and the horse race starts. We stop, when more + # than two horses pass the finish line. + # + ${:canvas}.button config -text Reset -command [:callback reset] + set :winners {} + set finish [expr {[lindex [${:canvas} bbox finish] 2]+10}] + while {[llength ${:winners}]<3} { + set this [:lpick $running] + ${:canvas} move $this [:lpick {0 1 2 3}] 0 + update + if {[lindex [${:canvas} bbox $this] 2] > $finish} { + lappend :winners [expr {[llength ${:winners}]+1}]:[$this name] + :lremove running $this + } + } + } + + :public method reset {} { + # + # When the "Reset" button is pressed, we switch back to the start + # configuration, the horses come back to the start. + # + ${:canvas}.button config -text Start -command [:callback start ${:tags}] + foreach tag ${:tags} { + set x [lindex [${:canvas} bbox $tag] 0] + ${:canvas} move $tag [expr {70-$x}] 0 + } + } + } + + # + # everything is defined, create the game + # + bind . {exec wish $argv0 &; exit} + HorseGame new -horses {Blaise NX Animal Ada Alan XOTcl Grace itcl John Linus} Index: doc/example-scripts/tk-mini.html =================================================================== diff -u --- doc/example-scripts/tk-mini.html (revision 0) +++ doc/example-scripts/tk-mini.html (revision 2076ef459f42cdf6426522aab56be490b66c2436) @@ -0,0 +1,778 @@ + + + + + +Listing of doc/example-scripts/tk-mini.tcl + + + + + +
+
+
+

Tiny Tk example scriped based on NX.

+
+
+tk-mini.png +
+
+
+
+
package require Tk
+package require nx::callback
+
+nx::Class create MyClass {
+  #
+  # A sample application class that creates a text entry field bound
+  # to an instance variable. When the provided button is pressed, the
+  # content of the variable is placed into an additional output label.
+
+  #
+  # The trait TCallback imports methods "callback" and "bindvar"
+  #
+  :useTrait nx::TCallback
+
+  :public method button-pressed {} {
+    # When this method is invoked, the content of the ".label" widget
+    # is updated with the content of the instance variable "myvar".
+    .label configure -text ${:myvar}
+  }
+
+  :method init {} {
+    wm geometry . -500+500
+    pack [label .title -text "Type something and press the start button ..."]
+    pack [entry .text -textvariable [:bindvar myvar]]
+    pack [label .label]
+    pack [button .button -text start -command [:callback button-pressed]]
+  }
+}
+
+MyClass new
+
+
+
+
+

+ + + Index: doc/example-scripts/tk-mini.png =================================================================== diff -u Binary files differ Index: doc/example-scripts/tk-mini.tcl =================================================================== diff -u --- doc/example-scripts/tk-mini.tcl (revision 0) +++ doc/example-scripts/tk-mini.tcl (revision 2076ef459f42cdf6426522aab56be490b66c2436) @@ -0,0 +1,37 @@ +# +# Tiny Tk example scriped based on NX. +# +# image::tk-mini.png[] +# + +package require Tk +package require nx::callback + +nx::Class create MyClass { + # + # A sample application class that creates a text entry field bound + # to an instance variable. When the provided button is pressed, the + # content of the variable is placed into an additional output label. + + # + # The trait TCallback imports methods "callback" and "bindvar" + # + :useTrait nx::TCallback + + :public method button-pressed {} { + # When this method is invoked, the content of the ".label" widget + # is updated with the content of the instance variable "myvar". + .label configure -text ${:myvar} + } + + :method init {} { + wm geometry . -500+500 + pack [label .title -text "Type something and press the start button ..."] + pack [entry .text -textvariable [:bindvar myvar]] + pack [label .label] + pack [button .button -text start -command [:callback button-pressed]] + } +} + +MyClass new + \ No newline at end of file Index: doc/example-scripts/traits-simple.html =================================================================== diff -u -r444fa56b72c6d35bd3cbbe46a44b12a4ea33088f -r2076ef459f42cdf6426522aab56be490b66c2436 --- doc/example-scripts/traits-simple.html (.../traits-simple.html) (revision 444fa56b72c6d35bd3cbbe46a44b12a4ea33088f) +++ doc/example-scripts/traits-simple.html (.../traits-simple.html) (revision 2076ef459f42cdf6426522aab56be490b66c2436) @@ -778,7 +778,8 @@ # This trait requires a method "position" and a variable # "collection" from the base class. The definition is incomplete in # these regards. - :requiredMethods position + + :requiredMethods position :requiredVariables collection }

Define the class ReadStream with properties position and @@ -839,7 +840,7 @@


Index: library/lib/nx-callback.tcl =================================================================== diff -u --- library/lib/nx-callback.tcl (revision 0) +++ library/lib/nx-callback.tcl (revision 2076ef459f42cdf6426522aab56be490b66c2436) @@ -0,0 +1,17 @@ +package require nx +package require nx::trait +package provide nx::callback 1.0 + +nx::Trait create nx::TCallback { + # + # A small support trait to ease syntactically the reference to + # instance variables and the registration of callbacks. + # + :method bindvar {name} { + :require namespace + return [nx::self]::$name + } + :method callback {name args} { + return [list [nx::self] $name {*}$args] + } +} \ No newline at end of file Index: library/lib/nx-traits.tcl =================================================================== diff -u -r444fa56b72c6d35bd3cbbe46a44b12a4ea33088f -r2076ef459f42cdf6426522aab56be490b66c2436 --- library/lib/nx-traits.tcl (.../nx-traits.tcl) (revision 444fa56b72c6d35bd3cbbe46a44b12a4ea33088f) +++ library/lib/nx-traits.tcl (.../nx-traits.tcl) (revision 2076ef459f42cdf6426522aab56be490b66c2436) @@ -40,23 +40,20 @@ nsf::proc nx::addTrait {obj traitName {nameMap ""}} { array set map $nameMap - foreach m [$traitName info methods] { + foreach m [$traitName info methods -callprotection all] { if {[info exists map($m)]} {set newName $map($m)} else {set newName $m} $obj public alias $newName [$traitName info method handle $m] } } nx::Class public method useTrait {traitName {nameMap ""}} { # adding a trait to a class - set obj [:new] foreach m [$traitName requiredMethods] { - # it would be nice to have a ":info methods -closure $m", we would not have to instantiate the class. #puts "$m ok? [:info methods -closure $m]" - if {[$obj info lookup method $m] eq ""} { + if {[:info methods -closure $m] eq ""} { error "trait $traitName requires $m, which is not defined" } } - $obj destroy nx::addTrait [self] $traitName $nameMap } Index: library/lib/pkgIndex.tcl =================================================================== diff -u -r187fbd20a453ae9d73e9b48f88b8d6a8c79685c2 -r2076ef459f42cdf6426522aab56be490b66c2436 --- library/lib/pkgIndex.tcl (.../pkgIndex.tcl) (revision 187fbd20a453ae9d73e9b48f88b8d6a8c79685c2) +++ library/lib/pkgIndex.tcl (.../pkgIndex.tcl) (revision 2076ef459f42cdf6426522aab56be490b66c2436) @@ -8,6 +8,7 @@ # script is sourced, the variable $dir must contain the # full path name of this file's directory. +package ifneeded nx::callback 1.0 [list source [file join $dir nx-callback.tcl]] package ifneeded nx::doc 1.0 [list source [file join $dir nxdoc-core.tcl]] package ifneeded nx::doc::dc 1.0 [list source [file join $dir nxdoc-dc.tcl]] package ifneeded nx::doc::html 1.0 [list source [file join $dir nxdoc-html.tcl]]