A PRIMER FOR PROGRAMMING PAD++ IN TCL/TK

Coordinates

Coordinates are specified and are returned in the current Pad++ units. The default units are pixels (see -units configuration option). All coordinates relating to the Pad++ surface are stored as floating-point numbers. All coordinates refer to the Pad++ surface and are independent of the current view. Therefore if the view happens to have a magnification (zoom) of 2.0, and you create an item that is 50 pixels wide, it will appear 100 pixels wide for this specific view.

The origin of the Pad++ coordinate system is in the center of the window upon startup. As with a normal cartesian coordinate system, larger y-coordinates refer to points higher on the screen; larger x-coordinates refer to points farther to the right. Notice that the y coordinate is inverted as compared to the Tk canvas.

There are two parts to pad's coordinate system. First, every item on the pad surface exists at a specific place, and can be moved and scaled on the surface. In addition, there is a view which specifies what portion of the pad surface is visible and at what magnification. Thus, the appearance of an item on the screen depends both on the position and scale of the item (the item's transformation) as well as the location and magnification of the current view.

The following code draws a simple ruler:

pad .pad -units inches
pack .pad
.pad create rectangle 0 0 5 1 -fill white -penwidth .05
for {set x 0} {$x <= 5} {set x [expr $x + 0.125]} {
 if {[expr int($x) == $x]} {
    # Draw inch markers
  .pad create line $x .5 $x 1 -penwidth .04
 } elseif {[expr int($x / .5) * .5 == $x]} {
    # Draw half-inch markers
  .pad create line $x .65 $x 1 -penwidth .04
 } elseif {[expr int($x / .25) * .25 == $x]} {
    # Draw quarter-inch markers
  .pad create line $x .8 $x 1 -penwidth .04
 } else {
    # Draw eighth-inch markers
  .pad create line $x .9 $x 1 -penwidth .04
 }
}
.pad config -units pixels   ;# Return to default units

Views are defined by a list of three numbers which specify the (x, y) point at the center of the window, and the magnification of the view, respectively. The default view, (0, 0, 1), has the origin at the center of the screen and is not magnified. The getview command returns the current view, and the moveto command modifies the current view with an optional animation.

.pad getview
=> 0 0 1
  # This command makes the ruler appear twice as big
.pad moveto 0 0 2
  # This command smoothly animates the view back to its 
  # starting point, and takes 1000 milliseconds for the animation.
.pad moveto 0 0 1 1000

Coordinates can also be managed in another way. Sometimes it is useful to specify coordinates relative to something else, instead of with the absolute coordinate system just described. Pad++ maintains a stack of coordinate frames. Suppose you wanted to create a layout of nested boxes. These coordinates would not be quite as easy to compute if we remain in the original coordinate system. But we can use relative coordinate frames to do this. Each coordinate frame is a bounding box on the Pad++ surface. All coordinates are specified as a unit square within this coordinate frame, i.e., (0, 0)-(1, 1). That is, when a coordinate frame is specified, coordinates are no longer absolute units. Instead they are relative to the specified frame. Coordinate frames may be specified by any bounding box, or by an item (thereby using the item's bounding box). Note that pen width and minsize and maxsize are also relative to the coordinate frame. In these cases, a value of 1 refers to the average of the width and height of the frame.

The following example draws a box with four boxes inside of it, and four boxes inside of each of those, and so on, four levels deep. New coordinate frames are placed on the top of the coordinate frame stack using the pushcoordframe command and removed from the top of the stack with the popcoordframe command. Note that from now on, the examples assume a pad widget called .pad has already been created with pixels as the current units, and packed with:

pad .pad
pack .pad

proc draw_a_box {x1 y1 x2 y2 level} {
 set id [.pad create rectangle $x1 $y1 $x2 $y2 -penwidth .01]
 puts $id
 .pad pushcoordframe $id
 draw_nested_boxes [expr $level + 1]
 .pad popcoordframe
}

proc draw_nested_boxes {level} {
 if {$level >= 5} {return}
 draw_a_box .1  .1  .45 .45 $level      ;# Draw lower-left box
 draw_a_box .55 .1   .9 .45 $level      ;# Draw lower-right box
 draw_a_box .1  .55 .45  .9 $level      ;# Draw upper-left box
 draw_a_box .55 .55  .9  .9 $level      ;# Draw upper-right box
}

draw_a_box 0 0 300 300 1



See the pushcoordframe, popcoordframe, and resetcoordframe commands for more information.


Pad++ Programmer's Guide - 10 JUN 1996

Generated with Harlequin WebMaker

Web Accessibility