The point method is used
to determine which canvas item is located at a given
point. The canvas uses this information to decide which
item should receive events. A point method calculates the
distance from some point to the canvas item. Canvas items
must correctly report a distance
of 0 if the point is on the canvas item, or they will not
receive events; they must report
non-zero if the point is not on the item, or they will
receive too many events. The exact value returned is not
nearly as important as the zero/non-zero distinction.
For convenience, the point method receives the same point
pre-translated into both item and canvas pixel
coordinates.
The point method also receives a pointer to a pointer to
a GnomeCanvasItem;
non-group canvas items should store a pointer to
themselves in this space. Groups store the *actual_item received from the
topmost child which returns 0 from its point method. If
you think about it for a while, you will see the
implication: the root canvas group's point method stores
a pointer to the deepest child in the item tree at the
point in question. The canvas sends events occurring at
that point to this most-junior child. Note that the
canvas item tree corresponds to the item stacking order
(i.e. the root group is on the bottom), so events go to
the topmost items, as you might expect. Remember that
events are then propagated up the item tree hierarchy.
Here is the point method for
GnomeCanvasRect:
static double
gnome_canvas_rect_point (GnomeCanvasItem *item,
double x, double y, int cx, int cy,
GnomeCanvasItem **actual_item)
{
GnomeCanvasRE *re;
double x1, y1, x2, y2;
double hwidth;
double dx, dy;
double tmp;
re = GNOME_CANVAS_RE (item);
*actual_item = item;
/* Find the bounds for the rectangle plus its outline width */
x1 = re->x1;
y1 = re->y1;
x2 = re->x2;
y2 = re->y2;
if (re->outline_set) {
if (re->width_pixels)
hwidth = (re->width / item->canvas->pixels_per_unit) / 2.0;
else
hwidth = re->width / 2.0;
x1 -= hwidth;
y1 -= hwidth;
x2 += hwidth;
y2 += hwidth;
} else
hwidth = 0.0;
/* Is point inside rectangle (which can be hollow if it has no fill set)? */
if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
if (re->fill_set || !re->outline_set)
return 0.0;
dx = x - x1;
tmp = x2 - x;
if (tmp < dx)
dx = tmp;
dy = y - y1;
tmp = y2 - y;
if (tmp < dy)
dy = tmp;
if (dy < dx)
dx = dy;
dx -= 2.0 * hwidth;
if (dx < 0.0)
return 0.0;
else
return dx;
}
/* Point is outside rectangle */
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);
}
|
It should be obvious how this function works; it is
simple geometry. Again, notice the line:
If your item isn't receiving any events, make sure you
included a similar statement.