Piddle Reference

## Sections:

###

1. class Canvas
2. class Color
3. class Font
4. Interactive Callbacks
5. class StateSaver

# Canvas

piddle.Canvas is the base class for any drawing canvas. Derived classes will implement a particular drawing backend. The general approach to drawing with PIDDLE is as follows:

1. instantiate a class derived from piddle.Canvas
2. call drawing methods on that object, such as drawLine or drawString
3. flush the canvas's buffer (flushes the graphics pipeline, updates the screen, or whatever)
4. Finally, if a file-based backend is being used, you'll need to save the canvas to a file.

The Canvas methods are shown below. Note that the first parameter (self) is implied, just as it would be when calling such a method on a Canvas instance.

### .isInteractive()

This method returns 1 if onClick and onOver events are possible, 0 otherwise. Your app can use this to check whether the particular Canvas you're using is interactive (e.g., screen graphics) or not (e.g., drawing to a PostScript file).

### .canUpdate()

This method returns 1 if the drawing can be meaningfully updated over time (e.g., screen graphics), 0 otherwise (e.g., drawing to a file). Note that for some Canvases, updates might be possible but grow expensive -- for example, each drawing command might be stored in a list, and if you continue to draw for hours, performance will suffer or memory will be exhausted. Such a canvas may return 0.5 for canUpdate(). In that case, your app may want to call .clear() whenever possible, as that should reset things.

### .clear()

Call this method to clear and reset the Canvas. For screen graphics, the drawing area should be erased; for file Canvases, the file should be emptied or reset to the beginning, or possibly start a new page if the Canvas supports multipage files; and so on. Some types of Canvases may not be able to meaningfully clear(), and may raise an exception if you try.

### .flush()

Call this method whenever you're done drawing or pausing long enough that you want the drawing to be updated. Screen Canvases will then make sure the screen is up to date; file canvases will flush their file buffers; etc. Some Canvases have no need to flush(), and will simply do nothing, but you should always call this method just to be safe.

### .save(file=None, format=None)

- file: an optional file name or file object to save to. By default, the name of the canvas specified in the constructor is used as a filename.
- format: an optional file type specifying a specific file format This argument is specific to the backend used and may be ignored.

Call this method to write a the current canvas to a file. Only applies to file-based backends such as piddlePDF, piddlePS, and piddlePIL. Will do nothing when called for backends that do not support saving to a file. You may pass a filename as the 'file' argument or a file object which implements a "write" method. The default is to use the Canvas's 'name' attribute as the file name. The optional type argument may be used by a backend to select different file formats when available. This should be the final action for a canvas. Though some backends may allow further drawing after a save() call, you should assume that the canvas is immutable for maximum portability.

### .setInfoLine(s)

- s: a string to display

This method applies only to interactive Canvases, and is used to display a string to the user in a non-blocking way. Generally it will appear in a one-line display at the top or bottom of the window or screen. Appropriate uses are showing coordinates, or providing a bit of help or instruction to the user. The string given is not saved and is completely ignored by noninteractive renderers, so it's OK to call this function frequently (e.g., whenever the mouse moves), but don't use it for any information you would want stored to a printout or file.

### .drawLine(x1, y1, x2, y2, [color], [width])

- x1: horizontal (right) coordinate of the starting point
- y1: vertical (down) coordinate of the starting point
- x2: horizontal (right) coordinate of the ending point
- y2: vertical (down) coordinate of the ending point
- color: Color of the line to draw; defaults to the Canvas's defaultLineColor
- width: width of the line to draw; defaults to the Canvas's defaultLineWidth

This function draws a straight line between the points x1,y1 and x2,y2. Thick lines will be centered on the given coordinates. Line end style varies with the particular canvas, and is more noticable with thick lines.

### .drawLines(lineList, [color], [width])

- lineList: a list of line coordinates, each an (x1,y1,x2,y2) tuple or list
- color: Color of the line to draw; defaults to the Canvas's defaultLineColor
- width: width of the line to draw; defaults to the Canvas's defaultLineWidth

This function draws a set of lines of uniform color and width. When drawing a large number of lines (e.g., a grid), this function is likely to be more efficient than calling drawLine() for each one. Note that the lines are not joined together; each one is drawn separately. The final result should look the same as if drawLine() had been called for each element of lineList.

### .drawString(s, x, y, [font], [color], [angle])

- s: the string to draw
- x: horizontal (right) coordinate of the starting position for the text
- y: vertical (down) coordinate of the starting position for the text
- font: font face and style for drawing; defaults to the Canvas's defaultFont
- color: Color of the drawn text; defaults to the Canvas's defaultLineColor
- angle: angle (degrees counter-clockwise from +X) at which the text should be drawn; defaults to 0

This method draws a string. The starting position is the left side of the first character, on the baseline (e.g., the bottom-left pixel in an "m"). Carriage returns ('\n') in the string will cause the drawing "pen" to move to the next line, at the normal single-spaced line spacing for the font. (If you need more control over line spacing, justification, etc., then break the string into lines yourself, measure the strings to be drawn, and draw them in position one line at a time.)

angle is used to draw rotated text. It should be noted that on some backends, rotated text may be rather slow, but it should always be supported.

### .drawPolygon(pointlist, [edgeColor], [edgeWidth], [fillColor], [closed])

- pointlist: a list of (x,y) tuples defining the edges of the polygon
- edgeColor: color of the polygon edges; defaults to the Canvas's defaultLineColor
- edgeWidth: width of the polygon edges; defaults to the Canvas's defaultLineWidth
- fillColor: color of the polygon interior; defaults to the Canvas's defaultFillColor
- closed: if 1, adds an extra segment smoothly connecting the first vertex to the last; defaults to 0

This method draws a polygon, and is a real workhorse; it forms the basis of the default implementations of most other drawing methods. New piddle backends must implement this method, and do so carefully, keeping in mind the following points.

Filling: we use the "odd-even" rule of filling. As a result, if you make a five-pointed star, the center pentagon is not filled.

Closure: the filling of a polygon is automatically "closed" in that there will be a straight line of color from the last vertex to the first. The "closed" parameter applies to the edge; if true, then there will also be an edge drawn between those points.

Users should use the "closed" parameter rather than passing a vertex list with the first and last vertices the same. This allows high-resolution backends (like postscript) to make sure all the edges join together properly.

Finally, note that when thick edges are drawn, the exact shape of the corners is undefined and may vary from one piddle implementation to another.

### .drawRect(x1, y1, x2, y2, [edgeColor], [edgeWidth], [fillColor], [closed])

- x1: left side of rectangle to draw
- y1: top of rectangle to draw
- x2: right side of rectangle to draw
- y2: bottom of rectangle to draw
- edgeColor: color of the rectangle edges; defaults to the Canvas's defaultLineColor
- edgeWidth: width of the rectangle edges; defaults to the Canvas's defaultLineWidth
- fillColor: color of the rectangle interior; defaults to the Canvas's defaultFillColor

This function draws a rectangle, aligned with to the coordinate system (i.e., top and bottom are horizontal, sides are vertical). x1 should be less than x2, and y1 should be less than y2. This call is functionally equivalent to:

    	.drawPolygon([(x1,y1),(x2,y1),(x2,y2),(x1,y2)],
    	             edgeColor, edgeWidth, fillColor, closed=1)

But using drawRect is easier to read, and may be considerably faster in some implementations, so its use is recommended whenever possible.

### .drawRoundRect(x1, y1, x2, y2, [rx], [ry], [edgeColor], [edgeWidth], [fillColor], [closed])

- x1: left side of rectangle to draw
- y1: top of rectangle to draw
- x2: right side of rectangle to draw
- y2: bottom of rectangle to draw
- rx: horizontal radius of corner ellipse; defaults to 8
- ry: vertical radius of corner ellipse; defaults to 8
- edgeColor: color of the roundrect edges; defaults to the Canvas's defaultLineColor
- edgeWidth: width of the roundrect edges; defaults to the Canvas's defaultLineWidth
- fillColor: color of the roundrect interior; defaults to the Canvas's defaultFillColor

This function draws a rectangle with rounded corners. The horizontal straight edges stop rx units away from the vertical sides, and the vertical sides stop ry units away from the top and bottom. The gaps are joined with arcs having radii rx and ry.

### .drawEllipse(x1, y1, x2, y2, [edgeColor], [edgeWidth], [fillColor], [closed])

- x1: leftmost point of ellipse to draw
- y1: topmost point of ellipse to draw
- x2: rightmost point of ellipse to draw
- y2: bottommost point of ellipse to draw
- edgeColor: color of the ellipse edges; defaults to the Canvas's defaultLineColor
- edgeWidth: width of the ellipse edges; defaults to the Canvas's defaultLineWidth
- fillColor: color of the ellipse interior; defaults to the Canvas's defaultFillColor

This functions draws an ellipse inscribed within the rectangle x1,y1, x2,y2. Note that the same restrictions on coordinates which apply to drawRect, also apply to drawRoundRect, drawOval, and drawArc.

### .drawArc(x1, y1, x2, y2, [startAng], [extent], [edgeColor], [edgeWidth], [fillColor], [closed])

- x1: leftmost point of ellipse to draw
- y1: topmost point of ellipse to draw
- x2: rightmost point of ellipse to draw
- y2: bottommost point of ellipse to draw
- startAng: angle at which the arc begins; defaults to 0 (zero)
- extent: angle covered by the arc; defaults to 360
- edgeColor: color of the arc edge; defaults to the Canvas's defaultLineColor
- edgeWidth: width of the arc edge; defaults to the Canvas's defaultLineWidth
- fillColor: color of the wedge; defaults to the Canvas's defaultFillColor

This functions draws part of an ellipse. Angles are given in degrees, where 0 (zero) is to the right at location (x2,(y1+y2)/2), and increase counter-clockwise. When filled, the filled portion is a wedge, like a slice of pie.

### .drawFigure(partList, [edgeColor], [edgeWidth], [fillColor], [closed])

- partList: list of lines, curves, and arcs (see below)
- edgeColor: color of the arc edge; defaults to the Canvas's defaultLineColor
- edgeWidth: width of the arc edge; defaults to the Canvas's defaultLineWidth
- fillColor: color of the wedge; defaults to the Canvas's defaultFillColor
- closed: if 1, adds an extra segment smoothly connecting the first vertex to the last; defaults to 0

This method is used to define a complex figure, much like a polygon, but the sides of which may be arcs or curves. The required parameter partList is a list of tuples, each tuple having one of the following formats:

(figureLine, x1, y1, x2, y2)
(figureArc, x1, y1, x2, y2, startAng, extent)
(figureCurve, x1, y1, x2, y2, x3, y3, x4, y4)

figureLine, figureArc, and figureCurve are constants defined in piddle.py, and the remaining elements are numerical parameters defining the line, arc, or curve respectively. These elements are joined by straight lines, from the end of one to the start of the next. The resulting figure can be filled like a polygon, or just outlined.

This method is likely to be slower for screen graphics than separate calls to drawArc, drawCurve, and drawLine (where applicable). On the other hand, drawFigure is likely to produce a higher-quality result for high-resolution renderers such as PostScript and PDF.

### .drawImage(image, x1, y1, [x2], [y2])

- image: a Python Imaging Library Image object
- x1: leftmost edge of destination rectangle
- y1: topmost edge of destination rectangle
- x2: rightmost edge of destination rectangle (defaults to x1 plus the image width)
- y2: bottom of destination rectangle (defaults to y1 plus the image height)

Use this method to plot a pixel image, in the form of a PIL Image object. If you just specify x1 and y1, the image will be drawn with with its top-left corner at that location, without scaling. If you also specify x2 and y2, then the image will be scaled as needed to fit the given rectangle.

Note that there is no way in piddle to plot a subregion of an image; however, PIL itself provides ways to create a new image as a subregion of an existing one.

# Color

piddle.Color is an encapsulation of the red/green/blue color space, used for specifying all colors in PIDDLE. Member variables red, green, and blue are public and may be safely read or modified.

You can also use standard arithmatic operators (+, -, *, /) to modify colors; e.g., if you have a color "aqua", then "aqua/2" would be half as intense.

Colors have a comparison function; two colors are considered equal if their red, green, and blue components are all equal. Otherwise, the colors are ordered first by red, then by green, and finally by blue.

Colors are hashable. So if, for example, you use a color as a key in a dictionary, another color equal to it will map to the same entry, even if it is a different Color object in memory.

Colors may be constructed by passing the red, green, and blue values to the constructor, e.g.:

    myColor = Color(1, 0.6, 0)      # light brown

Alternatively, a factory function called HexColor may be used. This converts a hex string (such as "AABBCC") or an integer (such as 0xAABBCC) into a color. Each byte (in our example, "AA" for red, "BB" for blue, and "CC" for green) is mapped to a color component value between 0 and 1 inclusive. This is the way colors are defined in HTML, and is often a convenient means of specification.

### Color Constants

PIDDLE defines a large number of color constants, mostly taken from the HTML standard. The predefined color constants are shown in the table below.

aliceblue
antiquewhite
aqua
aquamarine
azure
beige
bisque
black
blanchedalmond
blue
blueviolet
brown
burlywood
cadetblue
chartreuse
chocolate
coral
cornflower
cornsilk
crimson
cyan
darkblue
darkcyan
darkgoldenrod
darkgray
darkgreen
darkkhaki
darkmagenta
darkolivegreen
darkorange
darkorchid
darkred
darksalmon
darkseagreen
darkslateblue

darkslategray
darkturquoise
darkviolet
deeppink
deepskyblue
dimgray
dodgerblue
firebrick
floralwhite
forestgreen
fuchsia
gainsboro
ghostwhite
gold
goldenrod
gray (or grey)
green
greenyellow
honeydew
hotpink
indianred
indigo
ivory
khaki
lavender
lavenderblush
lawngreen
lemonchiffon
lightblue
lightcoral
lightcyan
lightgoldenrodyellow
lightgreen
lightgrey
lightpink

lightsalmon
lightseagreen
lightskyblue
lightslategray
lightsteelblue
lightyellow
lime
limegreen
linen
magenta
maroon
mediumaquamarine
mediumblue
mediumorchid
mediumpurple
mediumseagreen
mediumslateblue
mediumspringgreen
mediumturquoise
mediumvioletred
midnightblue
mintcream
mistyrose
moccasin
navajowhite
navy
oldlace
olive
olivedrab
orange
orangered
orchid
palegoldenrod
palegreen
paleturquoise

palevioletred
papayawhip
peachpuff
peru
pink
plum
powderblue
purple
red
rosybrown
royalblue
saddlebrown
salmon
sandybrown
seagreen
seashell
sienna
silver
skyblue
slateblue
slategray
snow
springgreen
steelblue
tan
teal
thistle
tomato
turquoise
violet
wheat
white
whitesmoke
yellow
yellowgreen

### "Transparent"

There is a special predefined color used to indicate where no drawing should be done. It is called transparent and is defined as Color(-1, -1, -1). Specify this as the fill color for shapes you don't want filled, or the line color for shapes you don't want outlined.

# Font

Font encapsulates a font and font style. It is used to tell PIDDLE what font should be used for drawing text; it does not contain the actual font definition (which is specific to the backend), but only a request for a certain font and style. It contains the following public data members:

- face: this is a font name (e.g., "helvetica"), or a list of font names (e.g., ["times", "helvetica", "serif"]). When a list is given, PIDDLE will use the first name on the list which matches a font available in the backend. All PIDDLE canvases should support at least the following fonts:
  - times
  - helvetica
  - courier
  - symbol
  - monospaced (often equivalent to courier)
  - serif (often equivalent to times)
  - sansserif (often equivalent to helvetica)

  Thus, it's advisable to always end your list of fonts with one of the six names above, which should always be available.

- bold: indicates that the font should be drawn in boldface.
- italic: indicates that the font should be italicized.
- underline: indicates that the font should be underlined.
- size: the size of the font, in points; roughly equal to the distance between baselines if two lines of text were drawn such that the descenders of one line touch the tall letters of the next.

It's important to note that the attributes above are merely requests to the PIDDLE backend. Font handling and capability varies widely among various backends; some options may not be supported.

# Interactive Callbacks

Some PIDDLE canvases may be interactive; that is, they provide support not only for drawing, but also for receiving input from the user. Such interaction takes place through callbacks: functions you define and attach to your canvas, to be called by the canvas whenever an event occurs.

### onClick(canvas, x, y)

- canvas: the Canvas which was clicked
- x: the distance between the point clicked and the left side of the canvas
- y: the distance between the point clicked and the top of the canvas

This callback is invoked when the user clicks the primary mouse button on the canvas. Your function receives a reference to the canvas clicked, and the x,y coordinates of the location clicked (in canvas coordinates, i.e., the same coordinate system used for drawing).

### onOver(canvas, x, y)

- canvas: the Canvas the mouse cursor is over
- x: the distance between the mouse cursor and the left side of the canvas
- y: the distance between the mouse cursor and the top of the canvas

This callback is invoked whenever the mouse cursor is moved into or within a Canvas. Your function receives a reference to the canvas the cursor is over, and cursor's x,y coordinates.

### onKey(canvas, key, modifiers)

- canvas: the Canvas receiving a keypress
- key: the character of the key pressed
- modifiers: modifier keys also pressed (see below)

This callback is invoked when a key is pressed while your canvas is "active" (the exact meaning of which depends on the particulars of the backend and its environment). The key parameter is generally the character of the key pressed; e.g., "a" if the user presses the "a" key. Special keys will be indicated with one of the following constants defined in piddle.py:

    		keyBksp = '\010'		# (erases char to left of cursor)
    		keyDel = '\177'			# (erases char to right of cursor)
    		keyLeft = '\034'		# arrow keys...
    		keyRight = '\035'
    		keyUp = '\036'
    		keyDown = '\037'
    		keyPgUp = '\013'		# page-up
    		keyPgDn = '\014'		# page-down
    		keyHome = '\001'		# "home" (top of document)
    		keyEnd = '\004'			# "end" (bottom of document)
    		keyClear = '\033'		# "clear" (clear all data)
    		keyTab = '\t'			# tab key

Keys which are not printable and not one of the above special cases, (e.g., "F6") may not be reported by the canvas -- certainly, they cannot be reported in a portable manner.

The modifiers parameter is an integer, and may be any combination of the following two constants:

    		modShift = 1		# shift key was also held
    		modControl = 2		# control key was also held

Note, however, that "shift key" and "control" key may not be literal; certain platforms may need to use other keys ("Alt", "Meta", "Command", etc.) instead. Users of such backends will need to consult the notes which come with that particular Canvas type.

# StateSaver

This is a little utility class for saving and restoring the default drawing parameters of a canvas. To use it, add a line like this before changing any of the parameters:

    		saver = StateSaver(myCanvas)

then, when "saver" goes out of scope, it will automagically restore the drawing parameters of myCanvas.

Last Updated: 16 January 2000