Calico Graphics

From IPRE Wiki
Jump to: navigation, search

This page describes Calico Graphics, a 2D, Object-Oriented graphics library for creating art, games, visualizations, and animations in any of the Calico languages.

See also Calico Differences which lists the differences between CPython Myro and IDLE.

You will find a set of examples at http://svn.cs.brynmawr.edu/viewvc/Calico/trunk/examples/ in various languages.

Importing Graphics

The Calico Graphics library allows for the creation of graphical objects in a window. The library Calico Myro contains just a few of the Graphics functions:

  • Window(...)
  • Color(...)
  • getColorNames()
  • getPixels(...)
  • Vector(...)
  • copyPicture(...)
  • getWindow()
  • getMouse()
  • getMouseNow()
  • getMouseState()
  • getKeyState()
  • getKeyPressed()
  • makePicture(...) (for Picture())

The full Graphics module is available for many Calico languages, including Python, Ruby, F#, Java, and Scheme. For Jigsaw, you might be more interested in using Calico Shapes, a functional interface to Calico Graphics.

Importing in Languages

To import Calico Graphics in each language requires to use the syntax from each specific language.

Python:

python> import Graphics

Ruby:

ruby> require "Graphics"

Scheme:

scheme> (using "Graphics")

F#:

fsharp> #r "Graphics.dll";;

Calico Python

The rest of this page describes the Graphics library using Python syntax.

For example, you can use:

from Myro import *

to include the subset of Graphics functions and classes contained in the Calico Myro module. To directly load all of the defined functions from the Graphics library in Calico, one could:

from Graphics import *

This will make all of the functions and classes available directly:

circle = Circle((100,200), 20)

Or, you could also:

import Graphics

However, then you must always use the "Graphics." prefix on functions and classes:

circle = Graphics.Circle((100,200), 20)

You can also just import the items you want, like so:

from Graphics import Circle

The following code assumes that you have imported all of the functions and classes from Graphics. The term "shape" is used to describe generic graphical objects.

Windows

Shapes can be drawn on a Window. You must create a window before you can see any shape:

win = Window("My Title", width, height)
win = Window("Title of Window")
win = Window(width, height)
win = Window()

Window can take three optional arguments: title, width, and height. The defaults are "Calico Graphics" and 300 width by 300 height. For example:

win2 = Window("My Second Window")           # creates a window with title "My Second Window" that is 300 x 300
win3 = Window("My Third Window", 400)       # creates a window with title "My Third Window" that is 400 x 300
win4 = Window("My Fourth Window", 400, 600) # creates a window with title "My Fourth Window" that is 400 x 600
win5 = Window(500, 500) #creates an anonymous window that is 500 x 500

Coordinates for Calico graphics have (0,0) as the top left-hand corner, with the horizontal direction increasing as it goes to the right, and the vertical direction increasing as it goes down.

You can always recall the last window created using the getWindow() function:

Window("New Window")
win = getWindow()             # gets last created window
win = getWindow("New Window") # gets window by title

Note that Graphics will use reuse windows based on the title. For example:

win1 = Window()
win2 = Window()

will only create one window, and both win1 and win2 will refer to it. To create two windows, use different titles:

win1 = Window("Window 1")
win2 = Window("Window 2")

Canvas

There also exist a Canvas() object that is similar to a Window. A Canvas has no visual representation, unless you are working in an ICalico environment. Canvases are created with width and height parameters. Canvases are like Windows in "bitmap" mode (see below).

Functional API

You can also make windows using the following functions:

  • makeWindow (title, width, height)
  • makeWindowFast (title, width, height) # made to reuse quickly
  • makeWindow (title, widget)

Windows Methods

window.addScrollbars(width, height)

Adds scrollbars on a window and expand the underlying canvas to width x height.

  • saveToSVG(filename) - save Picture to a SVG file
  • toSVG() - returns a SVG string

Window Modes

Calico Windows operate in one of four modes: "auto", "manual", "bitmap", "bitmapmanual", or "physics". If in "auto", "bitmap", or "physics" mode, then changes to the window are made as soon as possible so that you can see their effect. However, if too many updates are made, then you will only see the changes occur every win.updateInterval seconds. By default, win.updateInterval is .1 seconds (100 milliseconds).

The "bitmap" and "bitmapmanual" modes will not render shapes as shapes, which are redrawn each time them window needs to be re-rendered, but draws them once to a bitmap area associated with the window. This makes redrawing very fast, but at the cost of being unable to treat shapes as objects. For example, you would not be able to "move" a shape if it were drawn in bitmap mode.

The "manual" and "bitmapmanual" modes are designed so that you can control how fast the window updates, and makes sure that all of the objects update together. You must use the win.step() (or win.step(SECONDS)) method when you have the win.mode set to "manual" or "bitmapmanual". The window will not update faster than SECONDS. By default, SECONDS is 0, so it will update as soon as you call step().

Examples:

If you want the system to update automatically (the default), use:

win.mode = "auto"               # this line is not needed, as this is the default
win.setMode("auto")             # another method to set the mode (same as above)
win.updateInterval = .1         # this line is optional

That will update the window no more than every .1 seconds. This helps make your computer more efficient, so that it only makes updates every so often. You wouldn't want the computer to update the screen for every pixel change or else your graphics would slow to a crawl. If you want to force an update in this mode, use:

win.update()

If you want to control exactly when a window updates, then use:

win.mode = "manual"
...
win.step(.1)                    # or win.step()

This will force the update when you call step(.1), but will make sure that it doesn't update faster than every 100 ms. That number allows you to speed up and slow down animations.

Setting mode to "auto" is good for interactive use, but "manual" and using step() is good for making animations.

win.mode = "bitmap"
Line((0, 0), (100, 100)).draw(win)

Here the Line is created, and drawn to the bitmap of the window. There is no use saving the Line object. You can switch back and fourth between bitmap and manual/auto. That will allow you to have some objects, and some drawings.

Related functions:

win.getMode() # returns the mode
win.mode      # returns the mode

The "physics" mode is discussed below.

Mouse

There are three main functions for dealing with mouse events:

  • getMouse() - waits until user clicks and returns (x, y) of location in window
  • getMouseNow() - gets (x, y) of mouse location, relative to window
  • getMouseState() - gets current mouse state ("up" or "down")

You can also attach functions to mouse events so that the function will define what to do.

  • onMouseMovement(function)
  • onMouseDown(function)
  • onMouseUp(function)

You can attach as many functions as you like. Each function takes the window and the event:

def handleMouseUp(obj, event):
    print("Up")

def handleMouseDown(obj, event):
    print("Down")

def handleMouseMovement(obj, event):
    print("Movement")

win = Window()
onMouseMovement(handleMouseMovement)
onMouseUp(handleMouseUp)
onMouseDown(handleMouseDown)

All of these mouse functions are also methods of the Window class. So if you have multiple windows, you can call the function directly:

win = Window()
win.getMouse()
win.getMouseNow()
win.getMouseState()

win.onMouseMovement(handleMouseMovement)
win.onMouseUp(handleMouseUp)
win.onMouseDown(handleMouseDown)

The obj argument is (in these cases) a Graphics.WindowClass instance, and the event is an Event object:

  • event.x - x component of event
  • event.y - y component of event
  • event.time - time of event, in global seconds
  • event.type - returns name of event type: "mouse-release", "mouse-press", "mouse-motion", "key-press", "key-release"
  • event.key - returns string key name from a key event

And for key events:

  • event.type - "mouse-motion", "mouse-press", "mouse-release", "key-press", "key-release"
  • event.key - key name of press or release (e.g., "Return", "A", "Tab", etc.)

Other events have various obj and event properties:

  • event.type = "click"; obj is Button - for Button widget
  • event.type = "change-value", event.value is 0 to 101; obj is Slider - for HSlider and VSlider

See also the joystick(), getGamePad() and getGamepadNow() functions of the Calico Myro library.

See also the new Calico Events module for event-driven programming.

Key Presses

To use the key handling functions, you need to have a window created.

There are two main functions for dealing with keyboard events:

  • getKeyPressed() - gets a string of the last key pressed
  • getKeyState() - gets the state of the keyboard (a key "up" or a key "down")

Using these functions, you might miss a key press because you only have access to the last key press and key state from the last Graphics.Window created.

To handle every key press from any Window, as with handling every mouse action, you should attach functions to keyboard activity:

  • onKeyPress(function)
  • onKeyRelease(function)

These functions, like the mouse event handlers, are passed the window and the event:

def handleKeyPress(win, event):
    print("Down")

def handleKeyRelease(win, event):
    print("Up")

win = Window()
onKeyPress(handleKeyPress)
onKeyRelease(handleKeyRelease)

The KeyPress event will be called continuously while the key is down.

The win argument is a Graphics.WindowClass instance, and the event is a Event object (see above).

See also the new Calico Events module for event-driven programming.

New in Calico 3.0.0

To use the key handling functions, you need to have a window created.

There are three main functions for dealing with keyboard events:

  • getKeyPressed() - returns True if any key is currently pressed, False otherwise.
  • getKeyPressed(key) - returns True if key is currently being pressed, False otherwise.
  • getLastKey() - returns the last key that was pressed. (This method does not consume the event upon reading.)

Shapes

You can create and draw a variety of shapes in a window. Each shape results in a representation on a window when drawn. However, it is also an object which can be moved around, changed in various ways, and even undrawn.

Shapes require Points to define their boundaries or center. Wherever a Point is required, you can optionally use a list or tuple.

Shape Properties

All shapes have the following properties:

  • border - thickness of border of shape
  • center - center of shape
    • center.x - x coordinate
    • center.y - x coordinate
  • color - shortcut for setting both fill and outline (need to set to a color first)
  • fill - color of area of shape
  • gradient - (as opposed to fill) - a Gradient() of colors (see below)
  • outline - color of border of shape
  • pen - leaves trail if penDown()
  • points - points that make up a shape (if needed)
  • rotation - direction of rotation
  • scaleFactor - amount of scaling
  • tag - string for labeling item
  • window - the (last) window a shape is drawn in

In addition, a shape can have Physics properties, if it is drawn on a window when the window is in "physics" mode:

  • body - represents the Physical object
  • bodyType - either "static" or "dynamic"
  • bounce - 1.0 is 100% bounce; 0.0 is no bounce
  • density - set this before you draw it
  • friction - amount of friction
  • mass - set this after you draw it (with win.mode set to "physics")
  • wrap - set to True to keep shape on the screen

Shape Methods

All shapes (which includes anything that you would draw on a window) have the following methods:

  • shape.draw(window) - put shape on window's list of items to draw
  • shape.undraw() - Remove shape from a windows list of items to draw
  • shape1.draw(shape2) - draw shape1 into shape2's reference frame
  • shape.drawAt(window, position) - put shape on window's list of items to draw
  • shape1.drawAt(shape2, position) - draw shape1 into shape2's reference frame
  • shape.forward(distance) - move shape in its zero rotate direction
  • shape.getP1() - returns first point of a shape in screen coordinates
  • shape.getP2() - returns second point of a shape in screen coordinates
  • shape.getScreenPoint(p) - given a point relative to the center of a shape, returns a point in global screen coordinates
  • shape.getX() - get the x component of the center of a shape
  • shape.getY() - get the y component of the center of a shape
  • shape.move(dx, dy) - move by delta dx, delta dy
  • shape.moveTo(x, y) - move to x, y
  • shape.penDown() - put the shapes pen down to allow trace when it moves
  • shape.penUp() - put the pen up and stop trace.
  • line = shape.penUp(True) - put the pen up and stop trace, erase trace, and return line
  • shape.setPenColor(color) - short for:
    line = shape.penUp(True)
    line.color = shape.pen.color
    line.draw(window)
    line.drawAt(window, position)
    shape.penDown()
    shape.pen.color = color
  • shape.rotate(degrees) - rotate by degrees (positive is counter-clockwise)
  • shape.rotateTo(degrees) - rotate to degrees (0 is to the right, moving positive clockwise)
  • shape.scale(factor) - scale by a percent (.1 is 10% of original; 1.1 is 10% larger)
  • shape.scaleTo(factor) - set scale to factor (1 is 100% of original)
  • shape.setX(x) - set the x component of the center of a shape
  • shape.setY(y) - set the y component of the center of a shape
  • shape.speak(text) - a speech bubble will appear next to shape

Gradient

A Gradient is composed of two colors and a transition between them.

  • Gradient("linear", point1, color1, point2, color2)
  • Gradient("radial", point1, radius1, color1, point2, radius2, color2)
Gradient.gif
from Graphics import *

win = Window()

sq = Rectangle((100, 100), (200, 200))
sq.gradient = Gradient("linear", (-50, 0), Color("red"), (50, 0), Color("blue"))
sq.draw(win)

c = Circle((250, 250), 50)
c.gradient = Gradient("radial", (0, 0), 10, Color("red"),
                      (0, 0), 30, Color(0, 0, 0, 0))
c.outline = None
c.draw(win)


The rest of this section enumerates all of the specific types of shapes.

Arrow

  • Arrow((x, y), degrees) - create an arrow at (x,y) facing degrees (0 is to right)
  • Arrow(Point(x, y), degrees) - create an arrow at (x,y) facing degrees (0 is to right)

An arrow is a triangular pointer. Often used as the shape for creating "turtle graphics".

Turtle Graphics
# Turtle Graphics Example for Calico Python
# After http://en.wikipedia.org/wiki/File:Turtle-Graphics_Polyspiral.svg
# Doug Blank <dblank@cs.brynmawr.edu>

from Graphics import *

size = 600
win = Window("Turtle Graphics", size, size)
turtle = Arrow((size/2, size/2), 0)
turtle.draw(win)
turtle.penDown()

def f(dist, angle, incr, segs):
  for i in range(segs):
    turtle.forward(dist * (size * .35))
    turtle.rotate(-angle)
    dist += incr

f(.01, 89.5, .01, 184)


Spirals
from Graphics import *
win = Window()
def spiral(x, y, d, loops, color):
   arrow = Arrow((150, 150))
   arrow.pen.color = color
   arrow.draw(win)
   arrow.moveTo(x, y)
   arrow.rotateTo(d)
   arrow.penDown()
   i = 0.0
   while i < .180 * loops:
       arrow.rotate(-2)
       arrow.forward(.1 + i)
       i = i + .001

spiral(150, 150, 0, 18, Color("black"))
spiral(148, 158, 180, 18, Color("red"))


Dot

You cannot draw a Point; use Dot instead.

  • Dot((x,y)) - draw a point at (x,y)
  • Dot(Point(x,y)) - draw a point at (x,y)
Dot.gif
from Graphics import *
import random
win = Window("Shapes", 200, 200)
for i in range(5000):
    shape = Dot(random.random() * 200, random.random() * 200)
    shape.draw(win)


Curve

P1 and P4 are the end points; P2 and P3 are control points.

  • Curve((x1, y1), (x2, y2), (x3, y3), (x4, y4))
  • Curve(Point(x1, y1), Point(x2, y2), Point(x3, y3), Point(x4, y4))
Curve.gif
from Graphics import *
win = Window("Shapes", 200, 200)
curve = Curve((10, 10), (50, 150), (150, 50), (190, 190))
curve.border = 3
curve.draw(win)


SpeechBubble

Draws a speech bubble on the window.

  • SpeechBubble((x1,y1), (x2,y2), text, (x3,y3)))

where:

  • (x1,y1) is the upper-left hand corner
  • (x2,y2) is the lower-right hand corner
  • text is the words in the bubble
  • (x3,y3) is the anchor point (origin of speech)

The SpeechBubble object also uses all of the text attributes (below).

SppechBubble.gif
from Graphics import *
win = Window(300, 300)
sb = SpeechBubble((10, 10), (200, 200), "Hello, world!", (100, 250))
sb.draw(win)


Text

Place text on the window.

  • Text((x, y), text)
  • Text(Point(x, y), text)
  • text.fontFace - typeface of font
  • text.fontWeight - bold?
  • text.fontSlant - italics?
  • text.fontSize - size of font
  • text.xJustification - "center" (or "left" or "right")
  • text.yJustification - "center" (or "top" or "bottom")
  • text.width - (read-only) width of text in pixels
  • text.height - (read-only) height of text in pixels


Text.gif
from Graphics import *
win = Window("Shapes", 200, 200)
shape = Text((100, 100), "Hello, World!")
shape.fill = Color("blue")
shape.rotate(45)
shape.draw(win)


You can find examples of using justification here:

http://nbviewer.ipython.org/urls/bitbucket.org/ipre/calico/raw/master/notebooks/Python/Graphics%20Text%20Justification.ipynb

Line

Draw a line.

  • Line((x1, y1), (x2, y2))
  • Line(Point(x1, y1), Point(x2, y2))

or

  • line = Line()
  • line.append(Point(x,y))
  • line.set_points()
Line.gif
from Graphics import *
win = Window("Shapes", 200, 200)
shape = Line((10, 10), (190, 190))
shape.color = Color("blue")
shape.border = 3
shape.draw(win)


Picture

Create a picture.

  • Picture(filename) - filename is a string including path
  • Picture(window) - make a picture of the contents of a window
  • Picture(URL) - get a picture from the web
  • Picture(width, height) - make a blank picture width by height
  • Picture(width, height, color) - make a blank picture width by height of a particular color
  • Picture(picture) - makes a copy

Additional functions:

  • savePicture(filename, picture) - saves image in GIF, JPG or PNG format
  • savePicture("filename.gif", picture, ...) - saves an animated GIF
  • savePicture("filename.gif", [picture, ...]) - saves an animated GIF
  • savePicture("filename.gif", delay, [picture, ...]) - saves an animated GIF
  • savePicture("filename.gif", delay, loop?, [picture, ...]) - saves an animated GIF
  • setTransparent(picture, color) - sets all pixels that match color to be transparent
  • copyPicture(picture) - returns a copy of a picture
  • Can also use makePicture(...) for all versions of Picture(...)

See also Animated Gif Interface

Properties:

  • alpha - change the alpha of all pixels
  • width - width of image
  • height - height of image
Picture.gif
from Graphics import *
win = Window("Shapes", 200, 200)
shape = Picture(190, 190, Color("lightblue"))
shape.draw(win)


ObamasHead.gif
from Graphics import *
shape = Picture("http://4.bp.blogspot.com/__Y5vVtebEEE/SIeNV78jvAI/AAAAAAAABBY/9FIVWXy_Kho/s400/BarackObamaHead.jpg")
win = Window("Shapes", shape.width, shape.height)
shape.draw(win)


Picture Methods

  • getRegion(center_point, width, height, degrees) - get a region of an image
  • setRegion(center_point, width, height, degrees, color) - set a region of an image to color
  • setAlpha(byte) - set alpha for entire picture
  • flipHorizontal() - flip the image horizontally around a vertical axis
  • flipVertical() - flip the image vertically around a horizontal axis
  • toBitmap([option]) - return a Bitmap
  • toPixbuf() - return a Gdk.Pixbuf

There is support for moving an Image from Calico Processing to Calico Graphics, and back:

from Myro import makePicture
from Processing import createImage

p = makePicture(100, 100)
i = createImage(p.toBitmap())   # turn Graphics.Picture into a Bitmap and load in Processing
i.loadPixels()                  # load the Pixels
p2 = makePicture(i.toBitmap())  # turn Processing.Image into a Bitmap and load in Graphics

Bitmap formats are:

"Alpha", "Canonical", "DontCare", "Extended", "Format16bppArgb1555", "Format16bppGrayScale",
"Format16bppRgb555", "Format16bppRgb565", "Format1bppIndexed", "Format24bppRgb",
"Format32bppArgb", "Format32bppPArgb, "Format32bppRgb", "Format48bppRgb",
"Format4bppIndexed", "Format64bppArgb", "Format64bppPArgb", "Format8bppIndexed",
"Gdi", "Indexed", "Max", "PAlpha", "Undefined"

Pixel

Pixels are generally not created outside of the context of a Picture.

Properties of pixels:

  • x - (read-only) x location in picture from whence it came
  • y - (read-only) y location in picture from whence it came
  • picture - (read-only) reference to the picture from whence it came

Global Pixel Functions:

  • getPixel(picture, x, y)
  • getPixels(picture)
  • setPixels(picture1, picture2)
  • setPixel(picture, x, y, pixel)
  • setPixel(picture, x, y, color)

Pixels don't have color themselves, but you can get the color components:

  • getRed()
  • getGreen()
  • getBlue()
  • getAlpha()
  • getRGB()
  • getRGBA()
  • getColor()
  • setColor(pixel, color)
  • setRed(pixel, integer)
  • setGreen(pixel, integer)
  • setBlue(pixel, integer)
  • setAlpha(pixel, integer)

What is the difference between Color and Pixel?

  • Colors are independent
  • Colors know their red, green, blue, and alpha
  • Pixels depend on a particular Picture
  • Pixels known their x, y, and associated picture

You can set the color of a pixel in a picture with:

  • setPixel(pic, x, y, pixel)
  • setPixel(pic, x, y, color)

Colors

Colors are composed of 4 components: red, green, blue, and alpha. All values are integers between 0 (dark) and 255 (bright). Alpha is the transparency of the color. An alpha of 255 is completely opaque, and an alpha of 0 is completely transparent.

Constructors:

  • Color(r, g, b)
  • Color(color_name)
  • Color(hexcolor)

Functions:

  • makeColor(r, g, b)
  • makeColor(color_name)
  • makeColor(hexcolor)

Properties:

  • red - (read/write) integer value of red component (0 - 255)
  • green - (read/write) integer value of green component (0 - 255)
  • blue - (read/write) integer value of blue component (0 - 255)
  • alpha - (read/write) integer value of alpha component (0 - 255)

Color is used:

  • for each Pixel of a Picture
  • for the color of a Picture
  • fill of any shape
  • outline of any shape

See also the function pickAColor() from the Myro library.

Rectangle

Draw a rectangle or square.

  • Rectangle((x1, y1), (x2, y2))
  • Rectangle(Point(x1, y1), Point(x2, y2))
Rectangle.gif
from Graphics import *
win = Window("Shapes", 200, 200)
shape = Rectangle((10, 10), (190, 190))
shape.fill = Color("lightblue")
shape.draw(win)


RoundedRectangle

Draw a rounded rectangle or square. New in Calico 1.0.4.

  • RoundedRectangle((x1, y1), (x2, y2), radius)
  • RoundedRectangle(Point(x1, y1), Point(x2, y2), radius)
RoundedRectangle.gif
from Graphics import *
win = Window("Shapes", 200, 200)
shape = RoundedRectangle((10, 10), (190, 190), 10)
shape.fill = Color("lightblue")
shape.draw(win)


Polygon

Draw a polygon by listing its points.

  • Polygon((x1, y1), ...)
  • Polygon(Point(x1, y1), ...)
Polygon.gif
from Graphics import *
win = Window("Shapes", 200, 200)
shape = Polygon((10, 10), (190, 10), (100, 190))
shape.fill = Color("lightblue")
shape.draw(win)


Circle

Draw a circle.

  • Circle((x, y), radius)
  • Circle(Point(x, y), radius)
Circle.gif
from Graphics import *
win = Window("Shapes", 200, 200)
shape = Circle((100, 100), 90)
shape.fill = Color("lightblue")
shape.draw(win)


Oval

Draw an oval.

  • Oval((x, y), xradius, yradius)
  • Oval(Point(x, y), xradius, yradius)

xradius is the distance (the width) when initially drawn; yradius is the distance (the height) when initially drawn.

Pulse Animation
# Pulse Example
# Indicator that the computer is busy
# Doug Blank <dblank@cs.brynmawr.edu>

from Graphics import *
from Myro import wait
import math

win = Window()

alphas = list(reversed([x/10 * 255 for x in range(10)]))

ovals = []
for i in range(0, 360, 36):
    oval = Oval((150, 150), 50, 20)
    oval.rotate(-i)
    oval.color = Color("purple")
    position = int(abs(oval.rotation/(2 * math.pi) * 10))
    oval.color.alpha = alphas[9 - position]
    oval.draw(win)
    oval.forward(60)
    ovals.append(oval)

alphas.append(alphas.pop(0))

while True:
    for oval in ovals:
        position = int(abs(oval.rotation/(2 * math.pi) * 10))
        oval.color.alpha = alphas[9 - position]
        win.step(.0075)
    alphas.append(alphas.pop(0))


Pie

Draw a slice of pie.

  • Pie((x, y), radius, startDegree, stopDegree) - zero to right
  • Pie(Point(x, y), radius, startDegree, stopDegree) - zero to right

The following example draws a Pacman-like shape.

Pie.gif
from Graphics import *
win = Window("Shapes", 200, 200)
shape = Pie((100, 100), 90, 45, 360 - 45)
shape.fill = Color("lightblue")
shape.draw(win)


Arc

Draw an arc.

  • Arc((x, y), radius, startDegree, stopDegree) - zero to right
  • Arc(Point(x, y), radius, startDegree, stopDegree) - zero to right
Arc.gif
from Graphics import *
win = Window("Shapes", 200, 200)
shape = Arc((100, 100), 90, 360 - 45, 360 + 45)
shape.border = 3
shape.draw(win)


Sprite

Sprites are graphical objects composed of costumes. Costumes are composed of 1 or more frames. If a costume has more than one frame, then it can be animated.

  • Sprite() - create an empty sprite that you can add costumes
  • Sprite(name) - create a sprite from the known name
  • Sprite((x, y), name) - create a sprite at (x, y) from the known name.

There are a number of built-in sprites that you can create by using their name:

  • "bear"
  • "bear-with-spear"
  • "woman"
  • "stickman"
  • "slug"
  • "gem"
  • "card"
  • "crate"
  • "example"
  • "explosion"
  • "spaceship"

Each costume is composed of one or more "frames".

Sprite.gif
from Graphics import *
win = Window("Shapes", 200, 200)
sprite = Sprite((100, 100), "bear")
sprite.draw(win)

Sprites have the following properties:

  • name - the name of the sprite (eg, "bear")
  • costume - name of current costume (eg, "left")
  • shape - the current shape being drawn
  • frame - number of current frame of animation (defaults to 0)
  • costumes - dictionary of all costumes associated to the list of frames

The primary function of a sprite is that it can easily change costumes using these functions:

  • getDefaultCostumeName()
  • getCostumeNames()
  • changeCostume(name)
  • addCostume(name, shape)

If a costume has multiple frames, then you can:

  • animate(iterations)
  • animate(iterations, delay)
  • animate(seconds)
  • animate(seconds, delay)
  • animateTo((x, y), seconds)
  • animateTo((x, y), seconds, delay)

You can also manually move between frames of an animation:

  • flipToFirstFrame()
  • flipToLastFrame()
  • flipToNextFrame() # wraps around
  • flipToPreviousFrame() # wraps around
  • flipToFrame(number)

Additional frame methods:

  • addFrame(shape)
  • getFrames()
  • getFrames(costume)
  • selectFrameByTag(tag)
  • getFrameTags()
  • isFirstFrame()
  • isLastFrame()


GUI Widgets

Calico Graphics also has a set of GUI widgets. These have additional uses for providing control.

Button

Draw an button, and alternatively connect a function to it. New in Calico 1.0.4; updated in 1.1.0

  • Button((x, y), text)
  • Button(Point(x, y), text)

You connect a function to it like so:

button.connect("click", function)
Button.jpg
from Graphics import *
win = Window()
button = Button(Point(150, 150), "Press me!")
button.draw(win)

def printit(o, e):
    print(e)

button.connect("click", printit)


See more about Gtk.Button here: http://docs.go-mono.com/?link=T%3aGtk.Button%2f*

HSlider

Horizontal slider. New in Calico Graphics 1.1.0.

  • HSlider((x,y), width)
  • HSlider(Point(x,y), width)
HSlider.jpg
from Graphics import *
from Myro import getFilenames

files = getFilenames("../images/brain/*.jpg")

pics = []

for file in files:
    pics.append(makePicture(file))

window = Window("Laura's Brain", pics[0].width, pics[1].height + 50)

last = 0
pics[last].draw(window)
pics[last].moveTo(pics[0].width/2, pics[0].height/2)

slider = HSlider((0,pics[0].height), pics[0].width)
slider.draw(window)

def showimage(obj, event):
    global last
    v = event.value
    pos = int(v/101 * len(pics) )
    if pos != last:
        window.undraw(pics[last])
        pics[pos].draw(window)
        pics[pos].moveTo(pics[0].width/2, pics[0].height/2)
        last = pos

slider.connect("change-value", showimage)


See more about Gtk.HScale here: http://docs.go-mono.com/?link=T%3aGtk.HScale%2f*

VSlider

Vertical slider. New in Calico Graphics 3.0.1.

  • VSlider((x,y), height)
  • VSlider(Point(x,y), height)
from Graphics import *

win = Window(300, 300)

def change_value(o, e):
    print("Change!", o , e)

vslider = VSlider((10,10), 100)
vslider.draw(win)

vslider.connect("change-value", change_value)

RadioButton

Radio button. New in Calico Graphics 3.0.1.

  • RadioButton((x,y), text)
  • RadioButton((x,y), text, radio_button)

Use the second form after an initial radio button, for constructing groups of radio buttons. See examples below.

from Graphics import *

win = Window(300, 300)

def change_value(o, e):
    print("Change!", o , e)

radiobutton1 = RadioButton((10, 150), "Option 1")
radiobutton2 = RadioButton((10, 170), "Option 2", radiobutton1)
radiobutton3 = RadioButton((10, 190), "Option 3", radiobutton1)

radiobutton1.draw(win)
radiobutton2.draw(win)
radiobutton3.draw(win)

radiobutton1.connect("change-value", change_value)
radiobutton2.connect("change-value", change_value)
radiobutton3.connect("change-value", change_value)

CheckButton

Check box. New in Calico Graphics 3.0.1.

  • CheckButton((x,y), text)
  • CheckButton(Point(x,y), text)


from Graphics import *

win = Window(300, 300)

def change_value(o, e):
    print("Change!", o , e)

checkbutton = CheckButton((10, 200), "Check Button")
checkbutton.draw(win)

checkbutton.connect("change-value", change_value)

checkbutton.moveTo(10, 120)

Low-Level Graphics

You can really do anything you want at this level. Calico is written using the Gtk, Graphics Tool Kit.

One complication with using the Gtk interactively is that there are some functions that can only be called in the Graphics Thread. To do that, you use the Gtk.Application.Invoke function. Here is a helper alias:

invoke = Gtk.Application.Invoke

Some examples:

import Gtk
window = Gtk.Window("Title")
vbox = Gtk.VBox()
entry = Gtk.Entry()
vbox.PackStart(entry)
window.Add(vbox)
invoke(lambda obj, event: window.ShowAll())

If you tried to run window.ShowAll() without invoking it in the Graphics Thread (by using the invoke function) then your application will eventually crash, and perhaps bring down all of Calico with it.

It isn't always obvious what needs to be invoked in the Graphics Thread.

You can build an entire GUI with the Gtk, including menus, buttons, entry fields... the whole of Calico even. To find out more about the low-level graphics Gtk API, see:

http://docs.go-mono.com/index.aspx?link=N:Gtk

Groups of Shapes

There are two ways to group shapes: the Group and the Frame.

The Group is used for making a group out of existing shapes, so that you can easily perform a rotation to all of them.

The Frame is useful for creating a set of shapes all in the same frame of reference. Actually, a Frame is just an invisible Shape, and behaves like all shapes. You create a Frame, and then draw objects onto it.

Frame

Construct a frame-of-reference, for different reference for rotate, x,y, etc.

  • Frame(x, y)
  • Frame((x, y))

You create a frame, and then draw onto it:

  • frame = frame(150, 150)
  • rectangle.draw(frame)
Frame.gif
from Graphics import *
win = Window()
car = Frame(150, 150)
wheel1 = Rectangle((-10, -10), (10, -5))
wheel2 = Rectangle((-10, 10), (10, 5))
wheel1.draw(car)
wheel2.draw(car)
car.draw(win)

car.rotate(45)
car.forward(10)



Clock.gif
from Graphics import *
import time

win = Window("Clock")
win.mode = "manual"

face = Circle((150, 150), 125)
face.fill = None
face.draw(win)

s = Frame(150, 150)
line = Line((0, 0), (100, 0))
line.color = Color("red")
line.draw(s)

m = Frame(150, 150)
line = Line((0, 0), (75, 0))
line.color = Color("blue")
line.border = 2
line.draw(m)

h = Frame(150, 150)
line = Line((0, 0), (50, 0))
line.color = Color("black")
line.border = 3
line.draw(h)

s.draw(win)
m.draw(win)
h.draw(win)

def main():
    while True:
        t = time.localtime()
        s.rotateTo(t[5]/60 * 360 - 90)
        m.rotateTo(t[4]/60 * 360 - 90)
        h.rotateTo(t[3]/12 * 360 - 90)
        win.step(1)

win.run(main)


Graphs

HelloWorld.jpg
from Graphics import *
g = Graph()
g.addEdge("Hello", "World")
g.layout()
g.draw()


Graph properties:

  • addEdge(from, to)
  • addNode(name)
  • draw(window | None)
  • edges - the edges
  • getEdgeLines()
  • getNode()
  • graph - the graph
  • graph_count - count
  • graphEdges - the edges
  • graphNodes - the nodes
  • layout() - call GraphViz to get layout
  • layout(list) - call GraphViz to get Binary Tree layout of a list, where list is [left-tree, node, right-tree]
  • layout(list, a, b, c) - call GraphViz to get Binary Tree layout of a list, where a is left-position, b is node, and c is right-position
  • lookupNode()
  • options - the options
  • parser - the parser
  • post_text - the text after GraphViz processing
  • pre_text - the text before GraphViz processing
  • processDot() - call the dot external
  • recurseEdges() - internal call to process edges
  • recurseNodes() - internal call to process nodes
  • vertices - internal vertices
  • window - the Graphics window, if one

You can also get a Graphics.Canvas object from a Graph:

  • graph.render(options) - returns a Canvas with these options applied
  • graph.render() - returns a Canvas using default options
  • graph.rerender() - return a Canvas with the shapes redrawn

Scheme Example

(define show-tree
   (lambda (tree)
      (using "Graphics")
      (define! g (Graphics.Graph))
      (g.layout tree 1 0 2) ;; left-index root-index right-index
      (g.draw)))

(show-tree '(42 () ()))

Examples:

Fsm.jpg

Binarytree.jpg

Petrinet.jpg

Kennedy.jpg

Group

Create a group of shapes.

  • Group(shape1, shape2, ...)

By creating a group, you can move/change all of the shapes at once.

Error creating thumbnail: /bin/bash: /usr/bin/convert: No such file or directory

Error code: 127
from Graphics import *
win = Window("USFlag", 700, 400)

def make_star(x, y, segment):
    arrow = Arrow(Point(x, y), 1)
    arrow.draw(win)
    arrow.penDown()
    for i in range(5):
        arrow.forward(segment)
        arrow.rotate(72)
        arrow.forward(segment)
        arrow.rotate(-72)
        arrow.rotate(-72)
    polygon = Polygon(*arrow.penUp())
    polygon.draw(win)
    polygon.color = makeColor("white")
    arrow.undraw()
    return polygon

for row in range(13):
    band = Rectangle(Point(0,row * 400/13), Point(700, row * 400/13 + 400/13))
    band.draw(win)
    if row % 2 == 1: # odd, white
        band.color = makeColor("white")
    else:
        band.color = makeColor("red")

blue = Rectangle(Point(0,0), Point(300, 214))
blue.color = makeColor("blue")
blue.draw(win)
stars = []
for col in range(6):
    for row in range(9):
        if row % 2 == 1: # odd row
            if col == 5:
                continue
            x = col * 50 + 25
        else:
            x = col * 50
        y = row * 22
        star = make_star(x + 10, y + 13, 5)
        stars.append(star)

And now to demonstrate the Group() constructor:

def animate():
    g = Group(*stars)
    win.mode = "manual"
    for i in range(20):
        g.rotate(10)
        win.step(.5)

AnimatedGifInterface

age = AnimatedGifEncoder()

Methods

SetDelay(ms)

Sets the delay time between each frame, or changes it for subsequent frames (applies to last frame added).

SetDispose(code)

Sets the GIF frame disposal code for the last added frame and any subsequent frames. Default is 0 if no transparent color has been set, otherwise 2.

SetRepeat(n)

Sets the number of times the set of GIF frames should be played. Default is 1; 0 means play indefinitely. Must be invoked before the first image is added.

SetTransparent(c)

Sets the transparent color for the last added frame and any subsequent frames. Since all colors are subject to modification in the quantization process, the color in the final palette for each frame closest to the given color becomes the transparent color for that frame. May be set to null to indicate no transparent color.

AddFrame(picture)

Adds next GIF frame. The frame is not written immediately, but is actually deferred until the next frame is received so that timing data can be inserted. Invoking finish() flushes all frames. If setSize was not invoked, the size of the first image is used for all subsequent frames.

Finish()

Flushes any pending data and closes output file. If writing to an OutputStream, the stream is not closed.

SetFrameRate(fps)

Sets frame rate in frames per second. Equivalent to setDelay(1000/fps).

SetQuality(quality)

Sets quality of color quantization (conversion of images to the maximum 256 colors allowed by the GIF specification). Lower values (minimum = 1) produce better colors, but slow processing significantly. 10 is the default, and produces good color mapping at reasonable speeds. Values greater than 20 do not yield significant improvements in speed.

SetSize(w, h)

Sets the GIF frame size. The default size is the size of the first frame added if this method is not invoked.

Start()

Initiates GIF file creation on the given stream. The stream is not closed automatically.

Output()

Initiates writing of a GIF file with the specified name.

Window Features

Windows can operate in a number of modes.

modes

  • "auto"
  • "manual"
  • "physics"
  • "bitmap"

You can also "run" the window, which automatically calls the window.step() function, or you can call your own function.

  • win.run()
  • win.run(function)

Miscellaneous

Shapes will be stacked in the order that they were drawn on the window (e.g., first drawn are on the bottom). However, one can change the order with the following methods:

  • window.clear() - clears all shapes drawn on window
  • window.stackOnTop(shape) - moves shape to top
  • window.stackOnBottom(shape) - moves shape to bottom
SolarSystem.gif
from Graphics import *

win = Window()
win.setBackground(Color("black"))

sun = Circle((150, 150), 50)
sun.fill = Color("yellow")
sun.draw(win)

earth = Circle((70, 70), 20)
earth.fill = Color("green")
earth.draw(sun)

moon = Circle((20, 20), 5)
moon.fill = Color("grey")
moon.draw(earth)

pen = Pen(Color("white"), True) # True means that pen is down
pen.draw(win)
pen.stackOnBottom()

def main():
    win.mode = "manual"
    for s in range(360):
        sun.rotate(1)
        earth.rotate(5)
        win.step(.1)
        pen.appendPath(Point(moon.gx, moon.gy)) # gx,gy is global position in window, after render

win.run(main)


Physics

The window can be in "physics" mode. The following window properties are then useful.

  • win.gravity = Vector(x, y)
  • win.time - total time of simulation so far
  • win.simulationStepTime - time to advance simulation on each step (default is .01 seconds)

The following shape properties are then useful in "physics" mode.

  • shape.body.ApplyForce(Vector(x, y))
  • shape.body.ResetDynamics()
  • shape.wrap = boolean
  • shape.bounce - 1.0 is 100% bounce; 0.0 is no bounce
  • shape.friction - amount of friction

Demonstrations:

Low Level Graphics

You can also create your own shapes in Calico Graphics. One easy way is to subclass the Shape class and override the render method, like so:

class MyShape(Shape):
    def render(self, cr):
        cr.LineTo(0, 0)
        cr.LineTo(100, 100)
        cr.Stroke()

Render takes a Cairo Graphics context (cr). You can read more about what you can do with Cairo Graphics. Those examples are in C#.

To convert to Calico Python:

  • leave out the word "new"
  • Color is the Calico Graphics Color so use Color(...).getCairo()
  • semi-colons are optional
  • don't list the type of variables

For example, this C# code:

cr.LineWidth = 0.1;
cr.Color = new Color(0, 0, 0);
cr.Rectangle(0.25, 0.25, 0.5, 0.5);
cr.Stroke();

would become this Calico Python code:

cr.LineWidth = 0.1
cr.Color = Color(0, 0, 0).getCairo()
cr.Rectangle(0.25, 0.25, 0.5, 0.5)
cr.Stroke()

Full example:

from Graphics import *
win = Window()
class MyShape(Shape):
    def render(self, cr):
        cr.LineTo(0, 0)
        cr.LineTo(100, 100)
        cr.Stroke()
s = MyShape()
s.draw(win)

Plot

The Plot object allows you to create a graph of data.

  • Plot("Title", width, height)
  • Plot(data)
  • plot.xLabel.text
  • plot.yLabel.text
  • plot.append(data)
Sample Plot
from Graphics import Plot

plot = Plot("Sample Plot", 600, 300)
plot.xLabel.text = "time"
plot.yLabel.text = "balls in the air"

for data in [10, 30, 40, 50, 0, 100, 110, 40, 50]:
    plot.append(data)