BWise block coordinate extraction


Considering bwise is not a full blown, user-perfect application, with all bells and whisles, but that it on the other hand is a interesting enough application and OK use of various Tcl/Tk facilities, a short page on how to get coordinates from blocks on a Bwise canvas, using the default assumptions on block composition.

Bwise makes direct use of th Tk canvas, which already existed a decade ago, and as it is uses only very backward compatible commands.

The way to deal with (graphical) canvas items and their grouping is the use of tags, which is a list of identifiers attached to each item.

Creating some canvas items

I assume BWise has been started, with a console window open to type interactive commands (either using 'console show' on windows, or source-ing the console for Unix, or using tkcon ). In bwise, for one window only, the variable mc points at .mw.c usually as the active bwise canvas widget. So one could

$mc create text 100 100 -text test -tag mytext

To get a little word 'test' on the canvas a position 100 100 (a but away from the left upper corner). The option '-tag' indicates we have given that text item a label which we can at any later time use to refer to it.

In bwise, the first tag is seen as the block name, that is, when we make another item, let us say a circle:

#                 x1 y1  x2  y2
$mc create oval 50 50 150 150 -fill green -tag {mytext myoval}

and make it visible under the text item by lowering it:

$mc lower myoval

Because the text and the oval have the same first tag, they are seen as part of one block by bwise, so they can be moved together, by mouse dragging.

Getting current item coordinates

After dragging, it we want to know where the oval ended up we can inquire:

$mc coords myoval

which will return the same type of 4-tuple as we used to create the oval with. Because the text has no unique tag of its own, we need to use the item-number returned by the canvas create command to get it's coordinates, or maybe we could ask the canvas for all items with tag mytext (both the text and the oval item) and filter out the oval id:

foreach id [$mc find withtag mytext] {
    if {[$mc find withtag myoval] != $id} {puts "[$mc type $id] item $id coords [$mc coords $id]"}

Or a nice set-based command would do. It could be handy to give the parts of a block common and separate tags.

Analysing a bwise block

Let see what a average bwise block does with tags. I used the pro_args command (in fact as graphically accessable part of the latest procs_window upgrade) to make sure a default arguments 'newproc' procedure is called to create a block

eval [ pro_args  newproc { {width {100}}  {height {100}}  {x {50}}  {y {50}} } ]
# equivalent to: 
# newproc {} {} in out 100 100 {} 50 50

(Alternatively, the right popup menu somewhere on the canvas invoking 'newproc' would also create such a block, except it would get the default size.)

The new block covers our circle-with-text, so let us raise the latter by:

$mc raise mytext

Now it appears as if the circle is contained in the block, but bwise treats them as separate, for instance either can be dragged by the mouse, and appear to be separate from the other.

Bwise creates the following tags for its block elements, when this type of block is created:

foreach id [tag_and Proc1] {
    puts "Proc1 [format "%9s" [$mc type $id]] id $id tags: {[$mc itemcget $id -tags]}"


proc1 rectangle id 18 tags: {Proc1 newblock block}
proc1      text id 19 tags: {Proc1 crb label}
proc1      text id 20 tags: {Proc1 crb pinname in}
proc1      line id 21 tags: {Proc1 newblock pin in typein}
proc1      text id 22 tags: {Proc1 crb pinname out}
proc1      line id 23 tags: {Proc1 newblock pin out typeout}

For every element of the block (which I found using the tag_and command, which (also for older Tk versions) takes its argument as a list of tags, and returns all $mc canvas items with all of those tags), we see that the first tag identical, and equal to the name of the block.

That makes the block displace as a whole when dragged by one of its elements, and it makes a double click generate a red bounding box containing exactly all these items.

Also, it can be seen the yellow rectangle being the heart of the block has 'block' as its third tag, which enables the popup menu on it and some other things.

Pins have a third tag called 'pin', to make them clickable. The second tag is for historical reasons, it should signify something like the block creator function type. Further tags are possible like for the pins they have the special meaning of pin name and type.

It is usually harmless to add more tags, for whatever reason, the block create functions even have an option for this, for instance to group blocks.

Adding a tag to the circle and text canvas items

Now we could add a tag to all mytext items (the text and the oval) automatically, using:

foreach id [
    $mc find withtag mytext
] {
    $mc itemco $id -tags [
        list Proc1 [
            $mc itemco $id -tags

The oval and the text have become part of the Proc1 block by tag definition, and are dragged as a whole.

Image Bwise bwiseoval1.jpg

It could be we had displaced either or both of the block or the oval before joining them, so they would join in a displaced fashion. Bwise takes them as belonging together anyway in that case, but probably it isn't very practical that way.

Let us see how we can determine conglomerate coordinates and make sure the oval gets in proper place before joining.

Bwise block coordinate extraction

It is assumed normally that the upper left coordinate of the bwise block is indicative of it and its sub-parts global position on the canvas, even though that is not the same as the corner of the rectangular bounding box of the whole block and all its parts, because the input pins normally stick out to the left. This is most easily used by noting that the yellow centre block is the block anchor, and has as only bwise block subpart the third tag 'block'.

So we would get the bock upper left central coordinates by:

lrange [ 
    $mc coords [
        tag_and {Proc1 block}
] 0 1

Now we can place any other item set by computing the difference between the coordinates and their group upper-left coordinates.

Alternatively, one can list the upper-left base-block coords by:

foreach i [tag_and block] {
    puts "[block_name_fromid $i] [lrange [ $mc coords $i] 0 1]"

Note that it is possible to mess this 'database' up by having other items with the same tags as blocks.