GnomeCanvas Widget

While GnomeCanvas widget is inside the libgnomeui library, it definitely deserves a separate chapter. The canvas is a very high level high performance graphics drawing widget and on top of that it's easy to use. It includes support for both Xlib drawn graphics, which is faster especially over the network, and anti-aliased drawing for better looking results.

Creating a Canvas Widget

To create a gnome canvas widget, you call the gnome_canvas_new. You need to make sure that the canvas is created with a proper visual and colormap. For example if you wish to draw imlib images inside it, you should do this:

GtkWidget *canvas;
...
gtk_widget_push_visual(gdk_imlib_get_visual());
gtk_widget_push_colormap(gdk_imlib_get_colormap());
canvas = gnome_canvas_new();
gtk_widget_pop_visual();
gtk_widget_pop_colormap();

After this you also want to call gnome_canvas_set_pixels_per_unit to set the scale of the canvas. You can then do gtk_widget_set_usize to set the size of the widget, and gnome_canvas_set_scroll_region to set the region in which you can scroll around in, this is given in (x1, y1, x2, y2). Basically it's the outer limits of your drawing. So once the canvas was created, you could do:

GnomeCanvas *canvas;
...
/*already created a canvas, now set it up*/
gnome_canvas_set_pixels_per_unit(canvas,10);
gnome_canvas_set_scroll_region(canvas,0.0,0.0,50.0,50.0);

Groups and Items

In the canvas there are items, the actual objects that are on the canvas, and groups, which are just groupings of items. A group is actually derived from a base GnomeCanvasItem object, this is useful to applying functions to all the items inside the group. Such as moving or hiding the entire group. There is also one default group, the root group. You can get this group by calling gnome_canvas_root.

Creating Items

Creating items is slightly different usual. It's using the standard GTK+ object model argument mechanism. Basically you call gnome_canvas_item, with the parent canvas group as the first argument, the type of object as the second argument, and then arguments given in pairs (argument, value), terminated with a NULL. This is best illustrated by an example:

GnomeCanvas *canvas;
GnomeCanvasItem *item;
...
item = gnome_canvas_item_new(gnome_canvas_root(canvas),
			     GNOME_TYPE_CANVAS_RECT,
			     "x1", 1.0,
			     "y1", 1.0,
			     "x2", 23.0,
			     "y2", 20.0,
			     "fill_color", "black",
			     NULL);

Note that it's extremely important that the value be the exact type, since the compiler won't do the cast for you. If you're doing any calculations and aren't sure that you get the right type, just cast it. I believe most if not all numbers for canvas items are doubles.

To find out the arguments that each item takes, consult the gnome documentation or look into the libgnomeui/gnome-canvas*.h header files. They contain a table at the top of the file just like the one that follows (which was taken from libgnomeui/gnome-canvas-rect-ellipse.h).

For example here are arguments for rectangle (GNOME_TYPE_CANVAS_RECT) and ellipse (GNOME_TYPE_CANVAS_ELLIPSE):

Table 3-1. Arguments for rectangle and ellipse canvas items

NameTypeRead/WriteDescription
x1doubleRWLeftmost coordinate of rectangle or ellipse
y1doubleRWTopmost coordinate of rectangle or ellipse
x2doubleRWRightmost coordinate of rectangle or ellipse
y2doubleRWBottommost coordinate of rectangle or ellipse
fill_colorstringWX color specification for fill color, or NULL pointer for no color (transparent)
fill_color_gdkGdkColor*RWAllocated GdkColor for fill
outline_colorstringWX color specification for outline color, or NULL pointer for no color (transparent)
outline_color_gdkGdkColor*RWAllocated GdkColor for outline
fill_stippleGdkBitmap*RWStipple pattern for fill
outline_stippleGdkBitmap*RWStipple pattern for outline
width_pixelsuintRWWidth of the outline in pixels. The outline will not be scaled when the canvas zoom factor is changed.
width_unitsdoubleRWWidth of the outline in canvas units. The outline will be scaled when the canvas zoom factor is changed.

Now suppose we want to change some of these properties. This is done with a call to gnome_canvas_item_set. The first argument to this function is the canvas item object pointer. The next arguments are the same argument pairs as above when creating a new canvas object. For example if we want to set the color to red on the rectangle we created above, we can do this:

GnomeCanvas *canvas;
GnomeCanvasItem *item;
...
gnome_canvas_item_set(item
		      "fill_color", "red",
		      NULL);

Then there are item methods for other operations on items. For example the gnome_canvas_item_move method will take the x and y as second and third argument, and will move the item relative to it's current position by x and y. Or the gnome_canvas_item_hide and gnome_canvas_item_show, which hide and show the item, respectively. To control the z order of the items, you can use the methods gnome_canvas_item_raise_to_top and gnome_canvas_item_lower_to_bottom to raise or lower the item to the top or bottom of it's parent group's z order. To have finer control over z order you can use the gnome_canvas_item_raise and gnome_canvas_item_lower methods which take an extra integer argument which is 1 or larger, and specifies the number of levels the item should move in the z order.

Anti-aliasing canvas

To create a canvas which uses anti aliasing for rendering of it's items, instead of gnome_canvas_new function, you should use the gnome_canvas_new_aa. You should also use the GdkRgb visual and colormap. So you would do this to create a new anti-aliased canvas:

GtkWidget *canvas;
...
gtk_widget_push_visual (gdk_rgb_get_visual ());
gtk_widget_push_colormap (gdk_rgb_get_cmap ());
canvas = gnome_canvas_new_aa ();
gtk_widget_pop_colormap ();
gtk_widget_pop_visual ();

After this you can use the canvas in exactly the same manner as the normal canvas.

Anti-aliased canvas items can generally do more then normal canvas items. This is because of limitations of Xlib as a graphics library. It can for example do any kind of affine transformation on it's objects, where on and Xlib canvas you can only do affine transformations on some objects.