[cairo] drag selection box over image surface

Rick W. Chen stuffcorpse at gmail.com
Fri Mar 7 21:30:28 PST 2008


Hello, I'm new here (and to cairo too). I'm trying to draw a selection
box while the mouse is click-dragged on an image surface. Hope I have
the right mailing list. If not let me know where I should bugger off to.

Right now the box is drawn, but if the mouse moves (still dragging)
back, all previous boxes which are not painted over (because the current
box is smaller) remains. I can queue_draw() after painting the box each
time. That gives the desired effect, but it becomes noticeably slower
because on expose event, the image gets scaled to fit the gtk widget.
Plus it makes flickers.

Not sure if I have got the idea right in what I'm trying to do. If
someone can help me with this problem I would really appreciate it.

Below are some code related to this. paint_selection draws the box, and
on_event overloads the one from the widget (a DrawingArea).

void ImageArea::paint_selection(Cairo::RefPtr<Cairo::Context> cr)
{
    if (!active)
        return;

    cr->save();
    cr->set_line_width(2);
    cr->rectangle(x, y, w, h);
    cr->set_source_rgba(1, 1, 0.74, 0.2);
    cr->fill_preserve();
    cr->set_source_rgba(1, 1, 0.74, 0.5);
    cr->stroke();
    cr->restore();
}

bool ImageArea::on_event(GdkEvent *event)
{
    if (!loaded_)
        return true;

    GdkEventButton *bevent;
    GdkEventMotion *mevent;
    GdkEventExpose *xevent;

    int width  = get_allocation().get_width();
    int height = get_allocation().get_height();

    // Create the context for the widget
    Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();

    switch((gint)event->type)
    {
        case Gdk::BUTTON_PRESS:
            bevent = (GdkEventButton *) event;
            if(!select.active)
            {
                select.active = TRUE;
                select.x = bevent->x/scaled_res.x;
                select.y = bevent->y/scaled_res.y;
                select.w = 0;
                select.h = 0;
                queue_draw();
            }
            break;

        case Gdk::BUTTON_RELEASE:
            bevent = (GdkEventButton *) event;
            select.active = FALSE;
            queue_draw();
            break;

        case Gdk::MOTION_NOTIFY:
            mevent = (GdkEventMotion *) event;
            if(select.active)
            {
                select.w = mevent->x/scaled_res.x - select.x;
                select.h = mevent->y/scaled_res.y - select.y;

                cr->rectangle (0.0, 0.0, width, height);
                cr->scale( scaled_res.x, scaled_res.y );
                cr->clip();

                cr->save();
                cr->set_source (image_surface_ptr_, 0.0, 0.0);
                cr->rectangle (select.x, select.y, select.w, select.h);
                cr->clip();

                cr->paint();
                select.paint_selection(cr);

                cr->restore();
            }
            break;

        case Gdk::EXPOSE:
            xevent = (GdkEventExpose *) event;

            // Select the clipping rectangle
            cr->rectangle(xevent->area.x, xevent->area.y,
                          xevent->area.width, xevent->area.height);

            // Scale image to fit drawing surface
            cr->scale( scaled_res.x, scaled_res.y );
            cr->clip();

            cr->save();
            // Draw the source image on the widget context
            cr->set_source (image_surface_ptr_, 0.0, 0.0);
            cr->rectangle (0.0, 0.0, image.width, image.height);
            cr->clip();
            cr->paint();
            cr->restore();

    }
    return true;
}

-- 
  Rick


More information about the cairo mailing list