Chapter 18. The DrawingArea Widget

# Chapter 18. The DrawingArea Widget

The `DrawingArea` widget is a blank window that gives you the freedom to create any graphic you desire. Along with that freedom comes the responsibility to draw on the widget. When a widget is first shown, or when it is covered and then uncovered again it needs to redraw itself. Most widgets have code to do this, but the `DrawingArea` does not, allowing you to write your own draw function to determine how the contents of the widget will be drawn. This is done by setting a draw function with a call to the `set_draw_func()` member function.

GTK uses the Cairo drawing API. With gtkmm, you may use the cairomm C++ API for cairo.

You can draw very sophisticated shapes using Cairo, but the methods to do so are quite basic. Cairo provides methods for drawing straight lines, curved lines, and arcs (including circles). These basic shapes can be combined to create more complex shapes and paths which can be filled with solid colors, gradients, patterns, and other things. In addition, Cairo can perform complex transformations, do compositing of images, and render antialiased text.

| Cairo and Pango
Although Cairo can render text, it's not meant to be a replacement for Pango. Pango is a better choice if you need to perform more advanced text rendering such as wrapping or ellipsizing text. Drawing text with Cairo should only be done if the text is part of a graphic.

In this section of the tutorial, we'll cover the basic Cairo drawing model, describe each of the basic drawing elements in some detail (with examples), and then present a simple application that uses Cairo to draw a custom clock widget.

## The Cairo Drawing Model

The basic concept of drawing in Cairo involves defining 'invisible' paths and then stroking or filling them to make them visible.

To do any drawing in gtkmm with Cairo, you must first get a `Cairo::Context` object. This class holds all of the graphics state parameters that describe how drawing is to be done. This includes information such as line width, color, the surface to draw to, and many other things. This allows the actual drawing functions to take fewer arguments to simplify the interface. Usually, you use the `Cairo::Context` that you get as input data to the draw function that you set with the call to `set_draw_func()`. It's also possible to create a `Cairo::Context` by calling the `Gdk::Surface::create_cairo_context()` and `Gdk::CairoContext::cairo_create()` functions. Since Cairo contexts are reference-counted objects, `cairo_create()` returns a `Cairo::RefPtr<Cairo::Context>` object. (Note the difference between `Gdk::CairoContext` and `Cairo::Context`.)

The following example shows how to set up a Cairo context with a foreground color of red and a width of 2. Any drawing functions that use this context will use these settings.

    Gtk::DrawingArea myArea;
    auto gdkCairoContext = myArea.get_surface()->create_cairo_context();
    auto myContext = gdkCairoContext->cairo_create();
    myContext->set_source_rgb(1.0, 0.0, 0.0);
    myContext->set_line_width(2.0);

Each `Cairo::Context` is associated with a particular `Gdk::Surface`, so the first line of the above example creates a `Gtk::DrawingArea` widget and the next two lines use its associated `Gdk::Surface` to create a `Cairo::Context` object. The final two lines change the graphics state of the context.

There are a number of graphics state variables that can be set for a Cairo context. The most common context attributes are color (using `set_source_rgb()` or `set_source_rgba()` for translucent colors), line width (using `set_line_width()`), line dash pattern (using `set_dash()`), line cap style (using `set_line_cap()`), and line join style (using `set_line_join()`), and font styles (using `set_font_size()`, `set_font_face()` and others). There are many other settings as well, such as transformation matrices, fill rules, whether to perform antialiasing, and others. For further information, see the cairomm API documentation.

The current state of a `Cairo::Context` can be saved to an internal stack of saved states and later be restored to the state it was in when you saved it. To do this, use the `save()` method and the `restore()` method. This can be useful if you need to temporarily change the line width and color (or any other graphics setting) in order to draw something and then return to the previous settings. In this situation, you could call `Cairo::Context::save()`, change the graphics settings, draw the lines, and then call `Cairo::Context::restore()` to restore the original graphics state. Multiple calls to `save()` and `restore()` can be nested; each call to `restore()` restores the state from the matching paired `save()`.

| Tip

It is good practice to put all modifications to the graphics state between `save()`/`restore()` function calls. For example, if you have a function that takes a `Cairo::Context` reference as an argument, you might implement it as follows:

    void doSomething(const Cairo::RefPtr<Cairo::Context>& context, int x)
    {
        context->save();
        // change graphics state
        // perform drawing operations
        context->restore();
    }

The draw function that you set with a call to `set_draw_func()` is called with a Cairo context that you shall use for drawing in the `Gtk::DrawingArea` widget. It is not necessary to save and restore this Cairo context in the draw function.

Custom Dialog |  | Drawing Straight Lines