by Theo Verelst
I've recently made interactive command composer, which contains rudimentary, but working routines to take the list of procedures from the bwise procs_window -generated dialog window to select a procedure name, and extends dialog window with the possiblity to automatically present the list of a (double) clicked procedures' arguments, which in turn can be (double) clicked to be added to an editable list of argument-value pairs, from which with one button-push, an executable command can be generated.
On the bottom of that page, I've examplified a routine to generate a block on the bwise canvas based on a procedure, for which a further version is presented here.
The procedures on this page make little sense without the bwise package loaded first. See Bwise page for pointer to latest (one file, txt or tcl extension, prepend https:// for secure download) version which can be downloaded from the tclhttpd server I run, and distributed linked bwise for a list of bwise pages.
You'll either need to edit (a copy of) the bwise source file, to make sure the 'procs_window' procedure isn't called before the new one on this page is sourced, or use destroy .f to get rid of the old procedure window. The latter can (as I did) also be done from a script which automatically loads the standard bwise source file, destroys the .f window, loads the new stuff, calls procs_window again, and resizes some fonts when desired.
# Generate a unique name for a bwise block with given basename # It checks for existing number-extended blocks, and generates # an incremented number proc block_genname { {blockname {a}} } { set l {}; # find all basic block rectangles (third tag = block), find out the name (by the first tag) # and list those names foreach i [tag_and {block}] {lappend l "[block_name_fromid $i]"} # find all blocks starting with given name, and sort results set b [lsort -int -dict -decr [lsearch -all $l $blockname*]] # get names from sorted indices set m {}; foreach i $b {lappend m [lindex $l $i]} #puts $b,$m # when one or more existing block with same basename exists if {$m != {}} { # extract highest extension set mm [string range [lindex $m 0] [string length $blockname] end] #puts $mm # if non-existing yet, but basename exists, extend with 1 if {$mm == {}} {set mm 0} incr mm set blockname "$blockname$mm" } return $blockname } # The actual generate a bwise canvas 'block' from a procedure name proc. # extracts arguments and defaults, can generate a non conflicting block name # or be given one, and can have certain arguments set to specified value proc proc_toblock { {procname} {args {}} {blockname {}} } { if {$blockname== ""} {set blockname $procname} set blockname [block_genname $blockname] set c "$procname" # generate a list of arguments, based on the block base name, postpended by .argname foreach i [info args $procname] { append c " \$\{$blockname.[list $i]\}" } # prepare the invokation of the general bwise function block generator function 'newproc' # using pro_args to deal with argument order and default control set ret [eval pro_args newproc "{{f {set $blockname.out \[$c\] }} {in {[info args $procname]}} {out {out}} {x {300}} {y {200}} {name $blockname} } " ] puts $ret # and execute it eval $ret # set block input pin variables to default corresponding argument values foreach i [info args $procname] { uplevel #0 "info default $procname $i $procname.$i" } # override pin variable initial values by gives specific argument-value pairs foreach i $args { # puts $i uplevel #0 "set $blockname.[lindex $i 0] [lindex $i 1 end]" } return $blockname } # augmented toplevel procedure window .f generator proc # this one has an argument list, entries for 2 step command generating # and a 'generate bwise block for current procedure' button added. proc procs_window { } { global defaultprocs # The procedures which are listed in this list are not shown if {[info exists defaultprocs] != 1} { set defaultprocs {bgerror history loadvfs unknown} } # get_procvanilla toplevel .f wm title .f "Procedure Window" frame .f.fu ; pack .f.fu -expand n -fill x; # top frame with two scrollable lists listbox .f.fu.l -height 5 -yscroll ".f.fu.s set"; # left list pack .f.fu.l -expand y -fill x -side left scrollbar .f.fu.s -command ".f.fu.l yview" pack .f.fu.s -side left -expand n -fill y listbox .f.fu.lr -height 5 -yscroll ".f.fu.sr set"; # right list pack .f.fu.lr -expand y -fill x -side left scrollbar .f.fu.sr -command ".f.fu.lr yview" pack .f.fu.sr -side left -expand n -fill y frame .f.fe ; pack .f.fe -expand n -fill x ; # Entries proc_entry fargs {set fcom [pro_args [lindex $fcom 0] $fargs]} "Form Command" proc_entry fcom {} Execute frame .f.ft ; pack .f.ft -expand y -fill both ; # Text area pack .f.ft -expand y -fill both text .f.ft.t -width 20 -height 4 -wrap none -yscroll ".f.ft.s set";; pack .f.ft.t -expand y -fill both -side left scrollbar .f.ft.s -command ".f.ft.t yview" pack .f.ft.s -side right -expand n -fill y frame .f.f; pack .f.f -expand n -fill x button .f.f.b -text {Update Proc} -command { global procs; set p [.f.ft.t get 0.0 end]; eval $p; set procs([lindex $p 1]) $p } pack .f.f.b -side right bind .f.fu.l <Double-Button-1> { global cf; set cf [selection get]; .f.ft.t del 0.0 end; .f.ft.t insert end "proc $cf \{" .f.fu.lr del 0 end; foreach i [info args $cf] { .f.fu.lr insert end $i } foreach a [info args $cf] { if { [info default $cf $a b] == 1} { .f.ft.t insert end " {$a {$b}}" } { .f.ft.t insert end " {$a}" } } .f.ft.t insert end " \} \{[info body $cf]\} " global fargs fcom set fcom $cf set fargs "pro_args " } button .f.f.b2 -text "Refresh List" -command { set o {}; # Don't list certain procs foreach i [info procs] { if {[string match {tk*} $i] == 0 && [string match {tcl*} $i] == 0 && [string match {pkg_*} $i] == 0 && [string match {auto_*} $i] == 0 && [lsearch $defaultprocs $i] == -1 } { lappend o $i } }; .f.fu.l del 0 end; foreach i [lsort $o] {.f.fu.l insert end $i} }; pack .f.f.b2 -side right entry .f.f.f -width 15 -textvar procsfile pack .f.f.f -side left button .f.f.bs -text {Save Procs} -command { global procsfile procs set o {} foreach i [lsort [array names procs]] { eval append o { $procs($i) } \n } set f [open $procsfile w]; puts $f $o; close $f } pack .f.f.bs -side left bind .f.fu.lr <Double-Button-1> { append fargs " \{" [selection get] " \{" .f.fe.ffargs.e icursor end append fargs "\}\} " } button .f.f.b3 -text Block -command { proc_toblock [lindex $fcom 0] [lrange $fargs 1 end] } pack .f.f.b3 -side right -expand n -fill none bind .f.fu.l <F1> [bind .f.fu.l [bind .f.fu.l ]] .f.f.b2 invoke .f.ft.t insert end "Use refresh list when you made a new procedure.\n" .f.ft.t insert end "Double click a procedure name to make it appear \n" .f.ft.t insert end "in the bottom window.\n\n" .f.ft.t insert end "After editing it, press Update to resource the proc.\n\n" .f.ft.t insert end "There is no extra storage except regular tcl procs,\n" .f.ft.t insert end "loading another proc destroys you edits: \nUPDATE FIRST.\n\n" .f.ft.t insert end "Save button saves EDITED procs, \nsee filebox entry on the left.\n" .f.ft.t insert end "Most Bwise regular windows can be resized." }
How can the thus upgraged bwise be used?
In short, we can make a (or take an existing) procedure by typing or adapting one in the text edit window and pressing 'update proc', which basically sources the typed/edited tcl in, and press the 'block' button to automatically make a bwise block appear which has pins for the arguments of that procedure, calls the procedure correctly as eval-associated function variable script-line, and places the result on the output pin.
The function can also simply be clicked from the left upper list, and the arguments be set by double clicking them and filling them in by setting the cursor in the upper entry, executed after forming the command, and then blockified with the selected arguments initialized as typed by pressing 'block'.
The approach allows repeated pressing if block, which will generate more than one blocks, with numbered names, executing the same procedure.
Of course the blocks can be connected together à la Bwise, and 'run' or (net_)funprop-ed (which makes sure blocks are fired when their inputs are all available), or values can be passed one by one by hand (bwise block popup) transfering them, and the blocks can be examined by using the popup 'data' option, which opens a small window listing all its pins, and the value of the associated variables, and allowing an 'eval' of the block function, setting the output variable.