From b3a95d0299386bccbdebb967d15f4df02cf15891 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 10 Oct 2010 02:31:45 +0200 Subject: gnome-canvas: Change GnomeCanvasItem->point vfunc Previously the function returned the distance to the nearest item. Now it only returns an item that is hit. This slightly changes semantics (button events are no longer dispatched to the nearest item, but only to the item actually clicked on), but makes the code way simpler and actually does what one would expect. --- libgnomecanvas/gnome-canvas-line.c | 12 +++---- libgnomecanvas/gnome-canvas-pixbuf.c | 28 +++++++-------- libgnomecanvas/gnome-canvas-rich-text.c | 32 ++++------------- libgnomecanvas/gnome-canvas-shape.c | 39 ++++++-------------- libgnomecanvas/gnome-canvas-text.c | 45 ++++++----------------- libgnomecanvas/gnome-canvas-widget.c | 31 ++++------------ libgnomecanvas/gnome-canvas.c | 64 +++++++++------------------------ libgnomecanvas/gnome-canvas.h | 13 ++++--- 8 files changed, 74 insertions(+), 190 deletions(-) (limited to 'libgnomecanvas') diff --git a/libgnomecanvas/gnome-canvas-line.c b/libgnomecanvas/gnome-canvas-line.c index 4e6364d7e0..20cde8a6d9 100644 --- a/libgnomecanvas/gnome-canvas-line.c +++ b/libgnomecanvas/gnome-canvas-line.c @@ -95,8 +95,8 @@ static void gnome_canvas_line_get_property (GObject *object, static void gnome_canvas_line_update (GnomeCanvasItem *item, gdouble *affine, ArtSVP *clip_path, gint flags); static void gnome_canvas_line_draw (GnomeCanvasItem *item, GdkDrawable *drawable, gint x, gint y, gint width, gint height); -static gdouble gnome_canvas_line_point (GnomeCanvasItem *item, gdouble x, gdouble y, - gint cx, gint cy, GnomeCanvasItem **actual_item); +static GnomeCanvasItem *gnome_canvas_line_point (GnomeCanvasItem *item, gdouble x, gdouble y, + gint cx, gint cy); static void gnome_canvas_line_bounds (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2); static GnomeCanvasItemClass *parent_class; @@ -995,9 +995,9 @@ gnome_canvas_line_draw (GnomeCanvasItem *item, GdkDrawable *drawable, } } -static double +static GnomeCanvasItem * gnome_canvas_line_point (GnomeCanvasItem *item, gdouble x, gdouble y, - gint cx, gint cy, GnomeCanvasItem **actual_item) + gint cx, gint cy) { GnomeCanvasLine *line; gdouble *line_points = NULL, *coords; @@ -1015,8 +1015,6 @@ gnome_canvas_line_point (GnomeCanvasItem *item, gdouble x, gdouble y, line = GNOME_CANVAS_LINE (item); - *actual_item = item; - best = 1.0e36; /* Handle smoothed lines by generating an expanded set ot points */ @@ -1174,7 +1172,7 @@ done: if ((line_points != static_points) && (line_points != line->coords)) g_free (line_points); - return best; + return best == 0.0 ? item : NULL; } static void diff --git a/libgnomecanvas/gnome-canvas-pixbuf.c b/libgnomecanvas/gnome-canvas-pixbuf.c index b591724153..bb824cb53a 100644 --- a/libgnomecanvas/gnome-canvas-pixbuf.c +++ b/libgnomecanvas/gnome-canvas-pixbuf.c @@ -93,12 +93,11 @@ static void gnome_canvas_pixbuf_update (GnomeCanvasItem *item, gdouble *affine, ArtSVP *clip_path, gint flags); static void gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, GdkDrawable *drawable, gint x, gint y, gint width, gint height); -static gdouble gnome_canvas_pixbuf_point (GnomeCanvasItem *item, - gdouble x, - gdouble y, - gint cx, - gint cy, - GnomeCanvasItem **actual_item); +static GnomeCanvasItem *gnome_canvas_pixbuf_point (GnomeCanvasItem *item, + gdouble x, + gdouble y, + gint cx, + gint cy); static void gnome_canvas_pixbuf_bounds (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2); @@ -816,13 +815,12 @@ gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, GdkDrawable *drawable, /* Point handler for the pixbuf canvas item */ -static double +static GnomeCanvasItem * gnome_canvas_pixbuf_point (GnomeCanvasItem *item, gdouble x, gdouble y, gint cx, - gint cy, - GnomeCanvasItem **actual_item) + gint cy) { GnomeCanvasPixbuf *gcp; PixbufPrivate *priv; @@ -837,12 +835,10 @@ gnome_canvas_pixbuf_point (GnomeCanvasItem *item, priv = gcp->priv; pixbuf = priv->pixbuf; - *actual_item = item; - no_hit = item->canvas->pixels_per_unit * 2 + 10; if (!priv->pixbuf) - return no_hit; + return NULL; gnome_canvas_item_i2c_affine (item, i2c); compute_render_affine (gcp, render_affine, i2c); @@ -856,19 +852,19 @@ gnome_canvas_pixbuf_point (GnomeCanvasItem *item, if (px < 0 || px >= gdk_pixbuf_get_width (pixbuf) || py < 0 || py >= gdk_pixbuf_get_height (pixbuf)) - return no_hit; + return NULL; if (!gdk_pixbuf_get_has_alpha (pixbuf)) - return 0.0; + return item; src = gdk_pixbuf_get_pixels (pixbuf) + py * gdk_pixbuf_get_rowstride (pixbuf) + px * gdk_pixbuf_get_n_channels (pixbuf); if (src[3] < 128) - return no_hit; + return NULL; else - return 0.0; + return item; } diff --git a/libgnomecanvas/gnome-canvas-rich-text.c b/libgnomecanvas/gnome-canvas-rich-text.c index 5c7ed05709..64efcbddd7 100644 --- a/libgnomecanvas/gnome-canvas-rich-text.c +++ b/libgnomecanvas/gnome-canvas-rich-text.c @@ -121,10 +121,9 @@ static void gnome_canvas_rich_text_update (GnomeCanvasItem *item, gdouble *affin ArtSVP *clip_path, gint flags); static void gnome_canvas_rich_text_realize (GnomeCanvasItem *item); static void gnome_canvas_rich_text_unrealize (GnomeCanvasItem *item); -static gdouble gnome_canvas_rich_text_point (GnomeCanvasItem *item, - gdouble x, gdouble y, - gint cx, gint cy, - GnomeCanvasItem **actual_item); +static GnomeCanvasItem * gnome_canvas_rich_text_point (GnomeCanvasItem *item, + gdouble x, gdouble y, + gint cx, gint cy); static void gnome_canvas_rich_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable, gint x, gint y, gint width, gint height); @@ -2008,16 +2007,13 @@ gnome_canvas_rich_text_update (GnomeCanvasItem *item, gdouble *affine, gnome_canvas_update_bbox (item, x1, y1, x2, y2); } /* gnome_canvas_rich_text_update */ -static double +static GnomeCanvasItem * gnome_canvas_rich_text_point (GnomeCanvasItem *item, gdouble x, gdouble y, - gint cx, gint cy, GnomeCanvasItem **actual_item) + gint cx, gint cy) { GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT (item); gdouble ax, ay; gdouble x1, x2, y1, y2; - gdouble dx, dy; - - *actual_item = item; /* This is a lame cop-out. Anywhere inside of the bounding box. */ @@ -2030,23 +2026,9 @@ gnome_canvas_rich_text_point (GnomeCanvasItem *item, gdouble x, gdouble y, y2 = ay + text->_priv->height; if ((x > x1) && (y > y1) && (x < x2) && (y < y2)) - return 0.0; - - if (x < x1) - dx = x1 - x; - else if (x > x2) - dx = x - x2; - else - dx = 0.0; - - if (y < y1) - dy = y1 - y; - else if (y > y2) - dy = y - y2; - else - dy = 0.0; + return item; - return sqrt (dx * dx + dy * dy); + return NULL; } /* gnome_canvas_rich_text_point */ static void diff --git a/libgnomecanvas/gnome-canvas-shape.c b/libgnomecanvas/gnome-canvas-shape.c index 70f3516160..d1e7c1c3c3 100644 --- a/libgnomecanvas/gnome-canvas-shape.c +++ b/libgnomecanvas/gnome-canvas-shape.c @@ -75,8 +75,8 @@ static void gnome_canvas_shape_realize (GnomeCanvasItem *item); static void gnome_canvas_shape_unrealize (GnomeCanvasItem *item); static void gnome_canvas_shape_draw (GnomeCanvasItem *item, GdkDrawable *drawable, gint x, gint y, gint width, gint height); -static gdouble gnome_canvas_shape_point (GnomeCanvasItem *item, gdouble x, gdouble y, - gint cx, gint cy, GnomeCanvasItem **actual_item); +static GnomeCanvasItem *gnome_canvas_shape_point (GnomeCanvasItem *item, gdouble x, gdouble y, + gint cx, gint cy); static void gnome_canvas_shape_bounds (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2); @@ -1084,12 +1084,11 @@ gnome_canvas_shape_update (GnomeCanvasItem *item, gdouble *affine, ArtSVP *clip_ gnome_canvas_shape_update_gdk (shape, affine, clip_path, flags); } -static double +static GnomeCanvasItem * gnome_canvas_shape_point (GnomeCanvasItem *item, gdouble x, gdouble y, - gint cx, gint cy, GnomeCanvasItem **actual_item) + gint cx, gint cy) { GnomeCanvasShape *shape; - gdouble dist; gint wind; #if 0 @@ -1104,35 +1103,19 @@ gnome_canvas_shape_point (GnomeCanvasItem *item, gdouble x, gdouble y, /* todo: update? */ if (shape->priv->fill_set && shape->priv->fill_svp) { wind = art_svp_point_wind (shape->priv->fill_svp, cx, cy); - if ((shape->priv->wind == ART_WIND_RULE_NONZERO) && (wind != 0)) { - *actual_item = item; - return 0.0; - } - if ((shape->priv->wind == ART_WIND_RULE_ODDEVEN) && ((wind & 0x1) != 0)) { - *actual_item = item; - return 0.0; - } + if ((shape->priv->wind == ART_WIND_RULE_NONZERO) && (wind != 0)) + return item; + if ((shape->priv->wind == ART_WIND_RULE_ODDEVEN) && ((wind & 0x1) != 0)) + return item; } if (shape->priv->outline_set && shape->priv->outline_svp) { wind = art_svp_point_wind (shape->priv->outline_svp, cx, cy); - if (wind) { - *actual_item = item; - return 0.0; - } - } - - if (shape->priv->outline_set && shape->priv->outline_svp) { - dist = art_svp_point_dist (shape->priv->outline_svp, cx, cy); - } else if (shape->priv->fill_set && shape->priv->outline_svp) { - dist = art_svp_point_dist (shape->priv->fill_svp, cx, cy); - } else { - return 1e12; + if (wind) + return item; } - *actual_item = item; - - return dist; + return NULL; } /* Helpers */ diff --git a/libgnomecanvas/gnome-canvas-text.c b/libgnomecanvas/gnome-canvas-text.c index f85df6666a..d857eceac0 100644 --- a/libgnomecanvas/gnome-canvas-text.c +++ b/libgnomecanvas/gnome-canvas-text.c @@ -119,12 +119,11 @@ static void gnome_canvas_text_realize (GnomeCanvasItem *item); static void gnome_canvas_text_unrealize (GnomeCanvasItem *item); static void gnome_canvas_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable, gint x, gint y, gint width, gint height); -static gdouble gnome_canvas_text_point (GnomeCanvasItem *item, - gdouble x, - gdouble y, - gint cx, - gint cy, - GnomeCanvasItem **actual_item); +static GnomeCanvasItem *gnome_canvas_text_point (GnomeCanvasItem *item, + gdouble x, + gdouble y, + gint cx, + gint cy); static void gnome_canvas_text_bounds (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2); @@ -1348,28 +1347,22 @@ gnome_canvas_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable, } /* Point handler for the text item */ -static double +static GnomeCanvasItem * gnome_canvas_text_point (GnomeCanvasItem *item, gdouble x, gdouble y, - gint cx, gint cy, GnomeCanvasItem **actual_item) + gint cx, gint cy) { GnomeCanvasText *text; PangoLayoutIter *iter; gint x1, y1, x2, y2; - gint dx, dy; - gdouble dist, best; text = GNOME_CANVAS_TEXT (item); - *actual_item = item; - /* The idea is to build bounding rectangles for each of the lines of * text (clipped by the clipping rectangle, if it is activated) and see * whether the point is inside any of these. If it is, we are done. * Otherwise, calculate the distance to the nearest rectangle. */ - best = 1.0e36; - iter = pango_layout_get_iter (text->layout); do { PangoRectangle log_rect; @@ -1400,34 +1393,16 @@ gnome_canvas_text_point (GnomeCanvasItem *item, gdouble x, gdouble y, /* Calculate distance from point to rectangle */ - if (cx < x1) - dx = x1 - cx; - else if (cx >= x2) - dx = cx - x2 + 1; - else - dx = 0; - - if (cy < y1) - dy = y1 - cy; - else if (cy >= y2) - dy = cy - y2 + 1; - else - dy = 0; - - if ((dx == 0) && (dy == 0)) { + if (cx >= x1 && cx < x2 && cy >= y1 && cy < y2) { pango_layout_iter_free (iter); - return 0.0; + return item; } - dist = sqrt (dx * dx + dy * dy); - if (dist < best) - best = dist; - } while (pango_layout_iter_next_line (iter)); pango_layout_iter_free (iter); - return best / item->canvas->pixels_per_unit; + return NULL; } /* Bounds handler for the text item */ diff --git a/libgnomecanvas/gnome-canvas-widget.c b/libgnomecanvas/gnome-canvas-widget.c index 2229803872..84450bc080 100644 --- a/libgnomecanvas/gnome-canvas-widget.c +++ b/libgnomecanvas/gnome-canvas-widget.c @@ -62,12 +62,11 @@ static void gnome_canvas_widget_update (GnomeCanvasItem *item, gdouble *affine, ArtSVP *clip_path, gint flags); -static gdouble gnome_canvas_widget_point (GnomeCanvasItem *item, +static GnomeCanvasItem *gnome_canvas_widget_point (GnomeCanvasItem *item, gdouble x, gdouble y, gint cx, - gint cy, - GnomeCanvasItem **actual_item); + gint cy); static void gnome_canvas_widget_bounds (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, @@ -424,18 +423,15 @@ gnome_canvas_widget_draw (GnomeCanvasItem *item, #endif } -static double +static GnomeCanvasItem * gnome_canvas_widget_point (GnomeCanvasItem *item, gdouble x, gdouble y, - gint cx, gint cy, GnomeCanvasItem **actual_item) + gint cx, gint cy) { GnomeCanvasWidget *witem; gdouble x1, y1, x2, y2; - gdouble dx, dy; witem = GNOME_CANVAS_WIDGET (item); - *actual_item = item; - gnome_canvas_c2w (item->canvas, witem->cx, witem->cy, &x1, &y1); x2 = x1 + (witem->cwidth - 1) / item->canvas->pixels_per_unit; @@ -444,25 +440,10 @@ gnome_canvas_widget_point (GnomeCanvasItem *item, gdouble x, gdouble y, /* Is point inside widget bounds? */ if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) - return 0.0; + return item; /* Point is outside widget bounds */ - - if (x < x1) - dx = x1 - x; - else if (x > x2) - dx = x - x2; - else - dx = 0.0; - - if (y < y1) - dy = y1 - y; - else if (y > y2) - dy = y - y2; - else - dy = 0.0; - - return sqrt (dx * dx + dy * dy); + return NULL; } static void diff --git a/libgnomecanvas/gnome-canvas.c b/libgnomecanvas/gnome-canvas.c index f79b37e75e..958fc45e1c 100644 --- a/libgnomecanvas/gnome-canvas.c +++ b/libgnomecanvas/gnome-canvas.c @@ -512,13 +512,12 @@ gnome_canvas_item_invoke_update (GnomeCanvasItem *item, * This is potentially evil, as we are relying on matrix inversion (Lauris) */ -static double +static GnomeCanvasItem * gnome_canvas_item_invoke_point (GnomeCanvasItem *item, gdouble x, gdouble y, gint cx, - gint cy, - GnomeCanvasItem **actual_item) + gint cy) { /* Calculate x & y in item local coordinates */ @@ -555,9 +554,9 @@ gnome_canvas_item_invoke_point (GnomeCanvasItem *item, #endif if (GNOME_CANVAS_ITEM_GET_CLASS (item)->point) - return GNOME_CANVAS_ITEM_GET_CLASS (item)->point (item, x, y, cx, cy, actual_item); + return GNOME_CANVAS_ITEM_GET_CLASS (item)->point (item, x, y, cx, cy); - return 1e18; + return NULL; } /** @@ -1400,10 +1399,9 @@ static void gnome_canvas_group_draw (GnomeCanvasItem *item, GdkDrawable *drawable, gint x, gint y, gint width, gint height); -static gdouble gnome_canvas_group_point (GnomeCanvasItem *item, +static GnomeCanvasItem *gnome_canvas_group_point (GnomeCanvasItem *item, gdouble x, gdouble y, - gint cx, gint cy, - GnomeCanvasItem **actual_item); + gint cx, gint cy); static void gnome_canvas_group_bounds (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2); @@ -1746,55 +1744,34 @@ gnome_canvas_group_draw (GnomeCanvasItem *item, GdkDrawable *drawable, } /* Point handler for canvas groups */ -static double +static GnomeCanvasItem * gnome_canvas_group_point (GnomeCanvasItem *item, gdouble x, gdouble y, gint cx, - gint cy, - GnomeCanvasItem **actual_item) + gint cy) { GnomeCanvasGroup *group; GList *list; GnomeCanvasItem *child, *point_item; - gdouble gx, gy; - gdouble dist, best; - gint has_point; group = GNOME_CANVAS_GROUP (item); - best = 0.0; - *actual_item = NULL; - - gx = x; - gy = y; - - dist = 0.0; /* keep gcc happy */ - - for (list = group->item_list; list; list = list->next) { + for (list = g_list_last (group->item_list); list; list = list->prev) { child = list->data; if ((child->x1 > cx) || (child->y1 > cy) || (child->x2 < cx) || (child->y2 < cy)) continue; - point_item = NULL; /* cater for incomplete item implementations */ - - if ((child->flags & GNOME_CANVAS_ITEM_VISIBLE) - && GNOME_CANVAS_ITEM_GET_CLASS (child)->point) { - dist = gnome_canvas_item_invoke_point (child, gx, gy, cx, cy, &point_item); - has_point = TRUE; - } else - has_point = FALSE; + if (!(child->flags & GNOME_CANVAS_ITEM_VISIBLE)) + continue; - if (has_point - && point_item - && ((gint) (dist * item->canvas->pixels_per_unit + 0.5) <= 0)) { - best = dist; - *actual_item = point_item; - } + point_item = gnome_canvas_item_invoke_point (child, x, y, cx, cy); + if (point_item) + return point_item; } - return best; + return NULL; } /* Bounds handler for canvas groups */ @@ -2690,8 +2667,7 @@ pick_current_item (GnomeCanvas *canvas, GdkEvent *event) /* find the closest item */ if (canvas->root->flags & GNOME_CANVAS_ITEM_VISIBLE) - gnome_canvas_item_invoke_point (canvas->root, x, y, cx, cy, - &canvas->new_current_item); + canvas->new_current_item = gnome_canvas_item_invoke_point (canvas->root, x, y, cx, cy); else canvas->new_current_item = NULL; } else @@ -3570,19 +3546,13 @@ gnome_canvas_update_now (GnomeCanvas *canvas) GnomeCanvasItem * gnome_canvas_get_item_at (GnomeCanvas *canvas, gdouble x, gdouble y) { - GnomeCanvasItem *item; - gdouble dist; gint cx, cy; g_return_val_if_fail (GNOME_IS_CANVAS (canvas), NULL); gnome_canvas_w2c (canvas, x, y, &cx, &cy); - dist = gnome_canvas_item_invoke_point (canvas->root, x, y, cx, cy, &item); - if ((gint) (dist * canvas->pixels_per_unit + 0.5) <= 0) - return item; - else - return NULL; + return gnome_canvas_item_invoke_point (canvas->root, x, y, cx, cy); } /* Queues an update of the canvas */ diff --git a/libgnomecanvas/gnome-canvas.h b/libgnomecanvas/gnome-canvas.h index 864f9e649f..70a8f5c736 100644 --- a/libgnomecanvas/gnome-canvas.h +++ b/libgnomecanvas/gnome-canvas.h @@ -171,14 +171,13 @@ struct _GnomeCanvasItemClass { void (* draw) (GnomeCanvasItem *item, GdkDrawable *drawable, gint x, gint y, gint width, gint height); - /* Calculate the distance from an item to the specified point. It also - * returns a canvas item which is the item itself in the case of the - * object being an actual leaf item, or a child in case of the object - * being a canvas group. (cx, cy) are the canvas pixel coordinates that - * correspond to the item-relative coordinates (x, y). + /* Returns the canvas item which is at the given location. This is the + * item itself in the case of the object being an actual leaf item, or + * a child in case of the object being a canvas group. (cx, cy) are + * the canvas pixel coordinates that correspond to the item-relative + * coordinates (x, y). */ - gdouble (* point) (GnomeCanvasItem *item, gdouble x, gdouble y, gint cx, gint cy, - GnomeCanvasItem **actual_item); + GnomeCanvasItem * (* point) (GnomeCanvasItem *item, gdouble x, gdouble y, gint cx, gint cy); /* Fetch the item's bounding box (need not be exactly tight). This * should be in item-relative coordinates. -- cgit v1.2.3