Version 10 of bwise

Updated 2003-03-09 08:56:34

by Theo Verelst who holds copyrights but grants free use and modification, preferably informing me in the case of modification, for non-commercial purposes when source is clearly mentioned by email, name and/or url; commercial use requires written permission, meaning I don't give the exploitation rights away just like that.

Download info is here: Bwise - a graphical programming setup

Bwise is a package written completely in tcl/tk, even is pretty basic for the major part, to make graphs with blocks and compose programs with them, by letting data flow and executing procedures on them. Though some of the code is pretty heavy on the extended eval use side (read impossible to read but with some effort fine to follow and compact), the idea is that very simple and basic Tcl use should suffice on the application side, where the blocks are put to use.

This page contains a description, example use and probably some function descriptions.


The starting screen is the main window recogniseable by the buttons and the scrollable gray canvas. Also the function editor pops up, which in the top part has a scrollable (press mouse and roll under or above window boundaries) list of all user functions, and in the middle part shows a function when a name in the list is double clicked.

The main window is shown in figure 1,

http://195.241.128.75/Bwise/Picts/bw1.jpg 'figure 1' startup bwise main canvas and buttons.

where I used the middle mouse button on the bare canvas to pop up a block creation menu.

This is the result:

http://195.241.128.75/Bwise/Picts/bw2.jpg 'figure 2' a single unconnected procedure block with one input and one output

After clicking middle mouse on the yellow block and selecting 'data', a data window for this block is shown, and left on top.

http://195.241.128.75/Bwise/Picts/bw3.jpg 'figure 3' The data window with all variables defining the blocks' data and procedures

The window is a list of fields, one for each tcl variable starting with the name of the block followed by a dot, (in this case "proc1."). The blocks are automatically numbered uniquely when they are created, unless they are given a unique name which is possible by manually calling "new***", (in this case "newproc",) from the console or a console bwise block which can be created by pressing the paper icon in the top menu bar.

The variables proc1.in and procin.out contain the input and output data of the block, which are stored per block, even when they are connected up.

The most important variable contains the block function, called ***.bfunc (in this case proc1.bfunc). In fact this is a string which contains what could be seen as the body of a procedure, or however: a tcl (when desired also tk) script, in this case an assignment which simply sets the output variable equal to the input variable. Note that because of the dot "." in the name of the variables, the use of the dollar $ to access the content of the variable requires surrounding the whole name of the variable in curly braces, a bit annoying but it works. The left side of the "set" assignment doesn't require this.

One could also simply put the cursor in the editable field in the proc1 info window next to the 'proc1.bfunc' variable name and edit the function associated with the block, for instance to:

   set proc1.out [[expr ${proc1.in} * 2]]

when we now put the text cursor in the in proc1.in field by clicking on the entry to the right of the name in the proc1 info window and insert a 1 in the field, and press the "'eval'" button on the bottom of the window, the function in the bfunc field will be evaluated at the highest interpreter level, so that the proc1.out variable, which is real time linked with the entry in the info or data window, will be set to "2".

You could make a celcius to farenheit conversion as an example, I don't have that formula handy, or a dollar to euro, or preferably the reverse.

Now what's the block on the canvas doing in all this? It's mainly the graphical representation linked with the variables we just discussed. Calling up the block menu by clicking the middle mouse (or right if you have 2, I'm not sure that doesn't require you to change the 'canmeny' procedure in the 'bwise03.tcl' file for instance, I'll check it out), while pointing over the yellow block with proc1 written under it shows a menu entry "'eval'" which does the same as the button in the info window.

Now lets create a few more blocks by right clicking on a free spot on the canvas and selecting entry, mon, and another time proc, on different places on the canvas, and dragging the new blocks around by simply holding the left mouse button down somewhere in their yellow block.

http://195.241.128.75/Bwise/Picts/bw4.jpg Figure 4, having added some more blocks, calling up the block menu.

Now we click on first the Entry1.out pin with the left mouse button, and on the Proc1.in pin, so that both have turned green, and press the green 'wire' button: a wire appears between the Entry and the Proc1 blocks. When you move the blocks around, the wires stay connected to the same pins.

Pressing somewhere on the wire we just made will make both pins between which the wire runs green. Now when the 'wire' button is pressed again, the wire disappears, leaving the two pins green.

Clearly, we can repeat the wireing idea to connect all blocks up with eachother, for instance in order. We could also do this by commands in the console window:

   connect wirea Proc1 out Proc2 in
   connect wireb Proc2 out Mon1 in

The result is shown graphically in figure 5.

http://195.241.128.75/Bwise/Picts/bw5.jpg Figure 5, blocks connected up through wires, block menu popped up for first block in the chain.

The first block, 'Entry1', is shown to have been edited, it contains an entry as part of the block on the canvas, which moves along as part of the block, which can be given the text cursor by simply left clicking in the entry field. The value has become "1.0", which is immedeately available at the output of the block which has variable name "Entry.out" associated with it.

http://195.241.128.75/Bwise/Picts/bw6.jpg Figure 6, The data associated with each of the 4 blocks shown in the info windows.

Assume we have invoked the transfer menu on the block Entry1, then we would have tranfered that date from the output pin "out" from that block to the connected block(s) in this case the input "in" from block Proc1. Then Proc2.in would also show 1.0 instead of 1, or whatever it was before. We could now press the 'eval' button or evoke the menu on Proc1 with the same name, and have that block compute the outcome of its computation on its inputs data, which is "2.0".

Now we could perform a transfer operation on Proc1 by invoking the block menu, eval Proc2, transfer proc2, and eval Mon. And easier way to achieve this is to start at Entry1, and invoke propagate, run or funprop, which in this case have all similar effect: the data is transfered between the output (usually right side) of the block to the input (left) of the connected block(s), then that block is eval-ed, after which its output is transfered over all links present to connected blocks, etc.

We could check the info windows of al blocks and see the data is transfered and processed along the way, to finally arrive at the input of Mon1, after which finally the block function of Mon1 is executed, which is programmed to empty the little text widget in it, and display the latest input in it, in this case the outcome of

   ((${Entry1.out} +1)) = 2.0

In a slowly animated form (little pictures to save image size):

http://195.241.128.75/Bwise/Picts/bwiseanis.gif Figure 7, Animated actions and transfer.


Now lets add some other types of blocks, such as the shell, which like a console window in a bwise block, with as input a command, and as output the return value of the latest commmand.

We first use that shell to create a block with 2 inputs and outputs:

   eval [pro_args newproc {{in {i1 i2}} {out {o1 o2}}}]

which works the same as on the console window or in a normal tcl script. I used the aid function 'pro_args' to create a well formed command from a number of non-default arguments, and immedeately execute that command through eval.

That created the 4 pin proc3 in figure 8, which I put in place and connected up. The function newproc makes a new procedure block, and it creates and initializes the associated variables.

http://195.241.128.75/Bwise/Picts/bw8.jpg Figure 8. A graph extended with an interactive tcl shell block

Furthermore 2 entries have been connected, and between one onather, currently simply data passing, function block has been inserted.

http://195.241.128.75/Bwise/Picts/bw9.jpg Figure 9, example merge block.

The above figure examplifies how the merge block works, the two inputs, which both need to have received data by transfering it from the connnected blocks are simply put after eachother in a string which is put in the output variable.

http://195.241.128.75/Bwise/Picts/bw10.jpg Figure 10, globbing files through a joining of command parts and a shell block

I filled in glob for globbing files, a normal tcl command, which needs an argument, which is usually a wildcard file description pattern. The pattern feeds through a block which might change, correct, or check it, is merged with the glob command, and the result is fed to the shell command input.

When the shell received input it is executed, making the glob command print the resulting matching files in the top little history window, which scrolls, and the outcome is then also sent over the out pin to the monitor block, which remembers only the last output.

Both these blocks have an initialization function, which is in the block menu, which is programmed to clear the window.

I made a larger canvas with a lot more examples of the different blocks, some old some new it is in figure 11.

http://195.241.128.75/Bwise/Picts/bw11.jpg Figure 11, Lots of blocks are possible.

Below, a list of block creation possibilities.

 newproc { {f {}} {name {}} {in {in}} {out {out}} {width {40}} {height {}} {tags {}} {x {10}} {y {10}} }

Make a new function, f is the code which gets executed in the block. These blocks are properly saved and restored, except their variables and functions are NOT. One may want to use save_vars from the bwise lib for that purpose, which works fine in principle, except then all variables are saved and restored, which is not always a brilliant combination with some counters and system variables, and should only happen immedeately in the same point in time as the reading of the canvas.

 newarray { {nx {3}} {ny {3}} {bn {array}} {fs {}} {ib {}} {ipi {}} {jb {}} {jpi {}} {x {100}} {y {120}} }

Make an array of blocks, with default arguments 3 rows and three columns and a function which concatenates the two per block inputs.

 newdisp { {name {display}} {x {0}} {y {0}} }

Put a display model on the canvas with 5x7 led simulations (old function)

 newentry { {width {60}} {height {30}} {tags {}} {name {}} {x {0}} {y {0}} {in {}} {out {out}} }

Make a entry block, with an empty block function and an entry text variable corresponding with the output pin. Entries cannot be properly restored after they've been saved, the best remedy is to simply make new ones after reloading a canvas which had them.

 newimage { {file} }

Make a block out of a rectangular image. Don't forget to

 package require Img

of some version unless you're reading gif or p?m images. After the img package is loaded images can almost allways be loaded easily, and then be more visual attractive blocks. Image block can be saved, don't remember which limitations.

 newmon { {keep {0}} {width {80}} {height {65}} {tags {}} {name {}} {x {0}} {y {0}} }

Creates a small scrollable text window which show the latest input, you can change the function but that requires tk knowledge. Keep 0 means that at every new input, the previous data is erased from the text window.

 newseq { {n {8}} {name {}} {del {500}} }

The sequencer block is yet another means of imposing a ordered firing regime, it has outputs which normally connect to trigger inputs on other blocks, which are dataless connections, only used to trigger block, i.e. call their blockfunction when one of the outputs of the sequencer block finds that block on the other end of the wire it has connected. The eight main outputs become active in sequence, beginning with q0, every half a second the next, active means that it makes the blocks which are connected to it run their blockfunction and immedeately after transfer their outputs to connected block inputs.

http://195.241.128.75/Bwise/Picts/bw12.jpg Figure 12, The function window