Graphics and hypertext


intro Tcl/Tk programs handler actions to events widgets graphics appendix
[-<--%--^-->-] The Tk toolkit offers powerful facilities for graphics and (hyper)text. See Ousterhout93. In this section we discuss the canvas widget offered by Tk. Instead of looking at the text widget provided by Tk, we will (briefly) look at the hypertext widget, which presents an alternative approach to defining hyperstructures.

The item class

The canvas widget allows the programmer to create a number of built-in graphic items. Items are given a numerical index when created and, in addition, they may be given a (string) tag. Tags allow items to be manipulated in a group-wise fashion. To deal with items in a C++ context, the hush library contains a class item of which the functionality is shown below.
    interface item { 
      operator int();                        // returns item index
      
      void configure(char* cmd);    // calls canvas::itemconfigure
      
      void tag(char* s);                      // sets tag for item
      char* tags();              // delivers tags set for the item
      void move(int x, int y);
      
      bind(char *b, handler* h, char* args = "" );
      bind(char *b, binding* ac, char* args = "" );
      
      handler(class handler* h, char* args = "" );
      handler(binding* ac, char* args = "" );
      
    protected:
      virtual install(action&,char* args="");    // default bindings
    };
  

slide: The item interface

Instances of item may not be created directly by the user, but instead are created by the canvas widget. For an item, its index may be obtained by casting the item to int. If the index does not identify an existing item, it will be zero. Existing items may be moved, in a relative way, by the function move. In a similar way as for widgets, items may be associated with events, either explicitly by using item::bind, or implicitly by using item::handler. The default bindings for items are identical to the default bindings for the canvas widget, but these may be overridden by descendant classes. Similar as the widget class, the item class is derived from the handler class. This allows the user to define possibly compound shapes that have their own handlers.

The canvas widget

The Tk canvas widget offers powerful means for doing structured graphics. The hush class canvas provides merely a simplified interface to the corresponding Tk widget. As an example of the use of a canvas, consider the definition of the move_handler below. The move_handler defines one of the modes of the tablet and allows for moving graphical items on the canvas.
  
    class move_handler : public handler { 
    public:
      
      move_handler( canvas* cv ) : c(cv) { dragging = 0; }
      
      void press( event& e ) {     // if overlapping start dragging
      	  x = e.x(); y = e.y();     
      	  id = c->overlapping(x, y);
      	  if (id) dragging = 1;
      }
      
      void motion( event& e ) {                  // if dragging move
        if (dragging) {                
      	id.move( e.x() - x, e.y() - y );
      	x = e.x(); y = e.y();
      	}
      }
      
      void release( event&  ) { dragging = 0; }     // stop dragging
      
    protected:
      canvas* c; int dragging; item id; int x,y;
    };
  

slide: Moving items on a canvas

The move_handler class is derived from the class handler. It makes use of the dispatch and operator() function defined for handler, but redefines the (virtual) functions press, motion and release. When creating an instance of move_handler, a pointer to the canvas must be given to the constructor. In addition, the class has data members to record position coordinates and whether a particular item is being moved. Actually moving an item occurs by pressing the (left) mouse button on an item and dragging the item along. When the mouse button is released, moving stops. To identify the item, the function overlapping is used. The movement is determined by the distance between the last recorded position and the current position of the cursor. In an analogous manner, a box_handler may be defined, which is used for drawing rectangles and allows for rubberbanding. The box_handler sets dragging to true when the button is pressed and creates a rectangle of zero width and height. Each time the function motion is called, the item created in the previous round is deleted and a new rectangle is created:
    void box_handler::motion( event& e ) {   // if dragging stretch
        if (dragging) {
  	id.del();
  	id = c->rectangle(x,y,e.x(),e.y());  // x and y are fixed
      	}
      }
  

slide: A box handler

where c is a pointer to the canvas and x and y the button pointer coordinates stored when dragging began. For circles and lines, it suffices to replace the call to rectangle with a call to the appropriate figure creation function.

slide: Hypertext help

The hypertext widget

Both the Tk canvas and text widget allow to bind actions to particular items and hence to define dynamically what we may call hyperstructures. A different, in a way more static, approach is offered by the hypertext widget originally developed by George Howlett. %%george.howlett@att.com. The hypertext widget may be used to display text files containing embedded Tcl code. The Tcl code must be placed between escapes, that take the form of %% for both the begin and end of the code. A screen shot of a fragment of the on-line help for drawtool is given in figure Help. Notice, that the on-line help provides a replica of the drawtool application, surrounded by text. When looking at (again a fragment of) the hypertext file specifying the contents of the on-line help, given below, you see that the drawtool command defined in section new is employed to create the embedded widget:
>
    Rubber banding: press the left mouse button
    and release when the rectangle is of appropriate
    size
        %%
    drawtool \$this.draw 
    \$this append \$this.draw 
    \$this.draw create rectangle 20 20 80 80
    \$this.draw create rectangle 10 30 70 90
    \$this.draw create oval 40 40 90 90
    \$this append \$this.draw 
    %%
    For additional information click on the %% 
    button \$this.goto -text instruction -command end-of-text
    \$this append \$this.goto
    %%
    button.  Press %%
    button \$this.quit -command { destroy . } -text quit -bg pink
    \$this append quit
    %% to remove the window.
  

slide: Rubber banding

When specifying the hypertext file, widgets may be given a pathname relative to the pathname of the hypertext widget by using the variable this. In addition the hypertext widget offers the variables thisline and thisfile to identify the current line number and current file name. Any of the widgets and commands offered by Tcl/Tk or supported by hush may be included in a hypertext file, including the ones defined by the program itself.
intro Tcl/Tk programs handler actions to events widgets graphics appendix