static gboolean i7_goo_canvas_item_get_onscreen_coordinates(GooCanvasItem *item, GooCanvas *canvas, gint *x, gint *y) { GooCanvasBounds bounds; GtkAllocation allocation; gdouble canvas_x, canvas_y; gdouble top, bottom, left, right, item_x, item_y; /* Find out the size and coordinates of the current viewport */ goo_canvas_get_bounds(canvas, &canvas_x, &canvas_y, NULL, NULL); GtkWidget *scrolled_window = gtk_widget_get_parent(GTK_WIDGET(canvas)); g_assert(GTK_IS_SCROLLED_WINDOW(scrolled_window)); GtkAdjustment *adj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scrolled_window)); left = canvas_x + gtk_adjustment_get_value(adj); right = left + gtk_adjustment_get_page_size(adj); adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrolled_window)); top = canvas_y + gtk_adjustment_get_value(adj); bottom = top + gtk_adjustment_get_page_size(adj); /* Make sure item is currently displayed */ goo_canvas_item_get_bounds(item, &bounds); if(bounds.x1 > right || bounds.x2 < left || bounds.y1 > bottom || bounds.y2 < top) { g_warning("Node not onscreen in canvas"); return FALSE; } /* Find out the onscreen coordinates of the canvas viewport */ gtk_widget_get_allocation(GTK_WIDGET(canvas), &allocation); if(x) { item_x = bounds.x1; *x = (gint)(item_x - left) + allocation.x; } if(y) { item_y = bounds.y1; *y = (gint)(item_y - top) + allocation.y; } return TRUE; }
/** * change the zoom by factor * * zoom origin when zooming in is the cursor * zoom origin when zooming out is the center of the current viewport * * @param sheet * @param factor values should be in the range of [0.5 .. 2] */ void sheet_change_zoom (Sheet *sheet, gdouble factor) { g_return_if_fail (sheet); g_return_if_fail (IS_SHEET (sheet)); Coords adju, r, pointer, delta, center, pagesize; GtkAdjustment *hadj = NULL, *vadj = NULL; GooCanvas *canvas; gboolean b = FALSE; canvas = GOO_CANVAS (sheet); // if we scroll out, just use the center as focus // mouse curser centered scroll out "feels" awkward if (factor < 1.) { goo_canvas_set_scale (canvas, factor * goo_canvas_get_scale (canvas)); return; } // get pointer position in pixels // just skip the correction if we can not get the pointer if (!sheet_get_pointer_pixel (sheet, &pointer.x, &pointer.y)) { goo_canvas_set_scale (canvas, factor * goo_canvas_get_scale (canvas)); g_warning ("Failed to get cursor position."); return; } // top left corner in pixels b = sheet_get_adjustments (sheet, &hadj, &vadj); if (b) { adju.x = gtk_adjustment_get_value (hadj); adju.y = gtk_adjustment_get_value (vadj); // get the page size in pixels pagesize.x = gtk_adjustment_get_page_size (hadj); pagesize.y = gtk_adjustment_get_page_size (vadj); } else { //FIXME untested codepath, check for variable space conversion //FIXME Pixel vs GooUnits gdouble left, right, top, bottom; goo_canvas_get_bounds (canvas, &left, &top, &right, &bottom); pagesize.x = bottom - top; pagesize.y = right - left; adju.x = adju.y = 0.; } // calculate the center of the widget in pixels center.x = adju.x + pagesize.x/2.; center.y = adju.y + pagesize.y/2.; // calculate the delta between the center and the pointer in pixels // this is required as the center is the zoom target delta.x = pointer.x - center.x; delta.y = pointer.y - center.y; // increase the top left position in pixels by our calculated delta adju.x += delta.x; adju.y += delta.y; //convert to canvas coords goo_canvas_convert_from_pixels (canvas, &adju.x, &adju.y); //the center of the canvas is now our cursor position goo_canvas_scroll_to (canvas, adju.x, adju.y); //calculate a correction term //for the case that we can not scroll the pane far enough to //compensate the whole off-due-to-wrong-center-error if (b) { r.x = gtk_adjustment_get_value (hadj); r.y = gtk_adjustment_get_value (vadj); goo_canvas_convert_from_pixels (canvas, &r.x, &r.y); //the correction term in goo coordinates, to be subtracted from the backscroll distance r.x -= adju.x; r.y -= adju.y; } else { r.x = r.y = 0.; } // no the center is our cursor position and we can safely call scale goo_canvas_set_scale (canvas, factor * goo_canvas_get_scale (canvas)); // top left corner in pixels after scaling if (b) { adju.x = gtk_adjustment_get_value (hadj); adju.y = gtk_adjustment_get_value (vadj); } else { adju.x = adju.y = 0.; } // gtk_adjustment_get_page_size is constant before and after scale adju.x -= (delta.x) / sheet->priv->zoom; adju.y -= (delta.y) / sheet->priv->zoom; goo_canvas_convert_from_pixels (canvas, &adju.x, &adju.y); goo_canvas_scroll_to (canvas, adju.x-r.x, adju.y-r.y); gtk_widget_queue_draw (GTK_WIDGET (canvas)); }