Drawing thumbnails for non visible widgets



I have a Notebook in my application and instead of using tabs I would like
to show the user a ListBox with a set of thumbnails one for each page.
Drawing the currently visible page is no problem, however the pages that
are not visible are proving challenging.

My current code is shown below and uses an OffscreenWindow to manage it but
I dislike this solution for several reasons as follows:

a. I'd prefer to keep the re-parenting to a minimum,

b. having to run the event loop so the window actually draws is worrisome
to me

c. I'm getting GTK critical errors under 3.18 (Gdk-CRITICAL **:
gdk_window_move_resize_internal: assertion 'GDK_IS_WINDOW (window)' failed)

d. The solution is flakey. Showing the listbox is bound to a GAction which
is in turn bound to a ToggleButton. If I press the toggle button it works
fine and I get a thumbnail, if I execute the action through a shortcut it
fails and I get a complaint from the pixbuf: GdkPixbuf-CRITICAL **:
gdk_pixbuf_scale_simple: assertion 'dest_width > 0' failed

In short I can't help but feel this is all a bit of kludge and there's got
to be a better way. As shown in the code below, getting the thumbnail of
widget which is drawable is clean and simple in comparison. Is there no way
to call the draw method and override the check for isDrawable to force a
non-visible widget to be drawn?

My only other solution is to simply take and store a thumbnail of each page
as the user switches to a new page. This is less then ideal though since
activity can be happening in that page while it is non-visible and I'd
really prefer to show a current view if possible.

The code below is done in D and GtkD but should be easy enough to follow
for people more familiar with C or python.

Pixbuf getWidgetImage(Widget widget, double factor) {
    int w = widget.getAllocatedWidth();
    int h = widget.getAllocatedHeight();
    int pw = to!int(w * factor);
    int ph = to!int(h * factor);

    // If widget is drawable get thumbnail directly
    if (widget.isDrawable()) {
        Surface surface =
widget.getWindow().createSimilarSurface(gtkc.cairotypes.cairo_content_t.COLOR,
pw, ph);
        Context cr = Context.create(surface);
        cr.scale(factor, factor);
        widget.draw(cr);
        return gdk.Pixbuf.getFromSurface(surface, 0, 0, pw, ph);
    } else {
        RenderWindow window = new RenderWindow();
        window.setDefaultSize(w,h);
        Container parent = cast(Container) widget.getParent();
        if (parent is null) {
            error("Parent is not a Container, cannot draw offscreen image");
            return null;
        }
        widget.reparent(window);
        window.show();
        StopWatch sw = StopWatch(AutoStart.yes);
        Pixbuf pb = window.pixbuf;
        while (pb is null && sw.peek().msecs<500) {
            gtk.Main.Main.iteration();
            pb = window.pixbuf;
        }
        sw.stop();
        if (pb is null) {
            error("Pixbuf from renderwindow is null");
            pb = window.getPixbuf();
        }
        pb = pb.scaleSimple(pw, ph , GdkInterpType.BILINEAR);
        widget.reparent(parent);
        window.destroy();
        return pb;
    }
}

private:
class RenderWindow: OffscreenWindow {
    Pixbuf pb;

    bool onDamage(gdk.Event.Event, Widget) {
        trace("Damage event received");
        pb = getPixbuf();
        return false;
    }

public:
    this() {
        super();
        addOnDamage(&onDamage);
    }

    @property Pixbuf pixbuf() {
        return pb;
    }
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]