Centered zoom with GtkScrolledWindow



Dear GTK developers and users,

It is my first use of the GTK library and maybe I did something wrong.
I stumbled about a problem and cannot find an answer to it, even if I
think, that there might be a more or less simple solution to it. I
looked through the mailing list archives but could not find a solution,
but maybe I did not search good enough, so I also will be happy if you
provide a link to a solution.

Here the overview of my problem:
        I am putting a widget in a GtkScrolledWindow to be able to
        scroll and scale the widget (this works). I connect a signal to
        the widget to call a function when a mouse scroll event appears
        (this works also). In this callback function I zoom in or out
        the widget with the gtk_widget_set_size_request function which
        works fine, but the anchor is in the top left corner of the
        GtkScrolledWindow object and moves the center of the widget
        south-east when zooming in or north-west when zooming out. I
        like to keep the center of the widget where it was, so I
        calculate the center and the appropriate adjustment values of
        the scrolled window and scroll it back to the prior center by
        calling by emitting the signals
        
                g_signal_emit_by_name(hadj, "value_changed");
                g_signal_emit_by_name(vadj, "value_changed");
                
        which also works.
        
        And here comes the problem:
                The user sees that the image is scaled first, so there
                is already a scrolling involved and then it is
                automatically scrolled back.
                
Is there a possibility to block/suspend the scrolling, when resizing the
child widget and do both operations "visibly" at the same time, so that
the user has a clean centered zooming? I understand that this could be
maybe done by sub-classing the GtkScrolledWindow class, but it looks
like a too big task to me and I think there might be another way which I
have overlooked maybe?

Thanks in advance for any suggestions and help
                
reirob

P.S.: Here some code snippets if it might help:
                
1.) I am putting a widget in a GtkScrolledWindow to be able to scroll
and scale the widget:

        GtkWidget *map_area, zoom_map;

        ...
        /* Here the map_area widget is build and ready */
        ...
        /* Adding the call back funtion */
        gtk_widget_add_events(map_area, GDK_SCROLL_MASK);
        g_signal_connect(
                G_OBJECT(map_area), "scroll_event",
                G_CALLBACK(button_scroll_map_cb), NULL
        );

        zoom_map = gtk_scrolled_window_new(NULL, NULL);
        gtk_widget_show(zoom_map);
        gtk_scrolled_window_set_policy(
                GTK_SCROLLED_WINDOW(zoom_map), 
                GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC
        );
        gtk_scrolled_window_add_with_viewport(
                GTK_SCROLLED_WINDOW(zoom_map), map_area
        );

2.) In the callback funtion:

static gint button_scroll_map_cb(
        GtkWidget * area, GdkEventScroll * event,
        G_GNUC_UNUSED gpointer user_data
) {
        gint width, height;
        GtkScrolledWindow *zoom;
        GtkAdjustment *hadj, *vadj;
        gdouble hratio, vratio;
        guint blocked_handlers = 0;

        if (area->window == NULL || gmap->map == NULL)
                return FALSE;

        /* To get the scroll adjustment */
        zoom = GTK_SCROLLED_WINDOW(
                gtk_widget_get_parent(gtk_widget_get_parent(gmap->area))
        );
        /* To get the adjustments */
        hadj = gtk_scrolled_window_get_hadjustment(zoom);
        vadj = gtk_scrolled_window_get_vadjustment(zoom);
        /* Calculate the ratio */
        hratio = hadj->value / (hadj->upper - hadj->page_size);
        vratio = vadj->value / (vadj->upper - vadj->page_size);

        /* Ask the current widget size */
        gtk_widget_get_size_request(gmap->area, &width, &height);
        /* Zoom in or out by increasing or decreasing widget size */
        switch(event->direction) {
                case GDK_SCROLL_UP:
                        width *= 1.1;
                        height *= 1.1;
                        break;
                case GDK_SCROLL_DOWN:
                        if(width >= MAP_WIDTH && height >= MAP_HEIGHT) {
                                width /= 1.1;
                                height /= 1.1;
                        }
                        break;
        }
        /* Recalculate the adjustment values */
        hadj->upper = width;
        vadj->upper = height;
        hadj->value = hratio * (hadj->upper - hadj->page_size);
        vadj->value = vratio * (vadj->upper - vadj->page_size);
        hadj->value = isnan(hadj->value) ? 0.0 : hadj->value;
        vadj->value = isnan(vadj->value) ? 0.0 : vadj->value;
        /* Resize the widget size */
        gtk_widget_set_size_request(gmap->area, width, height);
        /* Change the adjustments of the scroll bars */
        g_signal_emit_by_name(hadj, "value_changed");
        g_signal_emit_by_name(vadj, "value_changed");

        return TRUE;
}






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