/Cairo-Tutorial

Simple C++ code samples to get a feeling for Cairo and how to animate your graphics. See https://youtu.be/19ad04-MQcA

Primary LanguageC++GNU General Public License v2.0GPL-2.0

Cairo-Tutorial

Simple C++ code samples to get a feeling for Cairo and how to animate your graohics

How to compile

  • enter a sample directory, e.g. 8-collision
  • call: ../compile.sh

what's in there?

0-empty-program

an empty C++ program

1-empty-cairo-program

an empty Cairo program

let us open a GDK window filled with Cairo filled with nothing

2-a-red-line

a Cairo program showing a line

we need to override default signal handler

bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;

this is, what we do override it for

bool on_draw(Cairo::RefPtr<Cairo::Context> const & cr)
    {
    cr->set_source_rgb(1.,.5,.0);
    cr->set_line_width(3);

    cr->move_to( 11, 11);
    cr->line_to(111,111);
    cr->stroke();

    return true;
    }
  • inform the context about the next colour
  • inform it about the next line width
  • move the pencil to 11,11
  • propose a line to the context, to 111,111
  • request the context to draw this line using all accumulated information

3-a-total-line

showing a line trough the complete window.

To enable this, we need to know the visible coordinates range of the cairo render context:

Gtk::Allocation allocation{ get_allocation() };
auto const width { (double)allocation.get_width() };
auto const height{ (double)allocation.get_height() };

now the total line:

cr->move_to(    0,      0);
cr->line_to(width, height);
cr->stroke();

and a funny gray circle in the middle:

cr->set_source_rgb(.7,.7,.7);
cr->arc(width/2, height/2, 100, 0, 2*M_PI);
cr->fill();

4-picture-png

a Cairo program showing a png picture

static Glib::RefPtr<Gdk::Pixbuf> const image  = Gdk::Pixbuf::create_from_file("CairoTut.png");
static Glib::RefPtr<Gdk::Pixbuf>       imageS = image->scale_simple( 180, 180, Gdk::INTERP_BILINEAR);
Gdk::Cairo::set_source_pixbuf(cr, imageS, width/2-90, height/2-90 );
cr->rectangle( width/2-90, height/2-90, 180, 180 );
cr->fill();
  • load picture static Glib::RefPtrGdk::Pixbuf const image = Gdk::Pixbuf::create_from_file("CairoTut.png");
  • scale picture to destination size static Glib::RefPtrGdk::Pixbuf imageS = image->scale_simple( 180, 180, Gdk::INTERP_BILINEAR);
  • place scaled pictures to specified position in render context Gdk::Cairo::set_source_pixbuf(cr, imageS, width/2-90, height/2-90 );
  • open a hole for the pixels cr->rectangle( width/2-90, height/2-90, 180, 180 );
  • show the hole

5-picture-svg

a Cairo program showing a svg drawing

6-mouse-position

a Cairo program tracking the mouse pointer

intoducing the first GDK callback into the Cairo application

bool on_motion_notify_event(GdkEventMotion *event)
    {
    tMousePos = SPoint{*event};
    queue_draw();
    return true;
    }
  • saving the current mouse position to draw a point there later
  • from Cairo request a call to bool on_draw(...)
  • return true because we have consumed the event

show the result utilizing on_draw(...)

cr->set_source_rgb(.0,.0,.9);
cr->arc(tMousePos.x, tMousePos.y, 3, 0, 2*M_PI);
cr->fill();
  • set the colour to blue
  • declare a circle at saved mouse position
  • fill the declared circle with the set colour

7-mouse-complete

a Cairo program tracking the mouse pointer and intractively drawing a line

bool CCanvas::on_button_press_event(GdkEventButton *event)
    {
    m_tMouseColor = { .0,.0,.9 };
    queue_draw();
    return true;
    }
  • if a mouse button is pressed, the mouse color becomes blue
  • to show thw change, a redraw is queued
bool CCanvas::on_button_release_event(GdkEventButton* event)
    {
    m_tMouseColor = { .5,.5,.5 };
    m_vMouseTrail.emplace_back( SPoint{ *event } );
    queue_draw();
    return true;
    }
  • if a mouse button is released, the position becomes queued
bool CCanvas::on_draw(Cairo::RefPtr<Cairo::Context> const & cr)
    {
    cr->set_source_rgb( .0,.0,.0 );
    cr->set_line_width(3);
    if ( m_vMouseTrail.size() )
        {
        cr->move_to(m_vMouseTrail[0].x,m_vMouseTrail[0].y);
        for (auto const & a:m_vMouseTrail)
            {
            cr->line_to( a.x, a.y);
            }
        cr->stroke();
        }
  • draw lines connecting all trigger points

8-collision

a Cairo program demonstraing the collision between the mouse pointer and graphucal objects

9-shift

a Cairo program showing how to move the canvas whilst keeping the mouse collider functional

a-shift+move

a Cairo program adding moving of objects by mouse

b-shift+zoom+move

a Cairo program adding zooming of tha canvas whilst keeping the canvas shifter and the mouse collider functional

c-animation

a Cairo program adding two different animation clocks to the mix, demonstrating multi animation

d-text

a Cairo program adding text to all other functions

e-ui-button-bar

adding a button bar

f-drawing-helpers

adding an elastic line

g-app-draw

a simple drawing application

h-3-lagen-synthese

a mechanism sythese application

i-4-bar-analytics

a mechanism analyse application

k-like-cad

an experimental CAD application

o-gaming

an experimental game with potential