/** Returns the bottommost item from the list which is at the point, or NULL if none. */ SPItem* sp_document_item_from_list_at_point_bottom(unsigned int dkey, SPGroup *group, GSList const *list, Geom::Point const p, bool take_insensitive) { g_return_val_if_fail(group, NULL); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0); for (SPObject *o = sp_object_first_child(SP_OBJECT(group)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) { if (!SP_IS_ITEM(o)) continue; SPItem *item = SP_ITEM(o); NRArenaItem *arenaitem = sp_item_get_arenaitem(item, dkey); if (arenaitem && nr_arena_item_invoke_pick(arenaitem, p, delta, 1) != NULL && (take_insensitive || item->isVisibleAndUnlocked(dkey))) { if (g_slist_find((GSList *) list, item) != NULL) return item; } if (SP_IS_GROUP(o)) { SPItem *found = sp_document_item_from_list_at_point_bottom(dkey, SP_GROUP(o), list, p, take_insensitive); if (found) return found; } } return NULL; }
/** Returns the topmost non-layer group from the descendants of group which is at point p, or NULL if none. Recurses into layers but not into groups. */ SPItem* find_group_at_point(unsigned int dkey, SPGroup *group, Geom::Point const p) { SPItem *seen = NULL; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0); for (SPObject *o = sp_object_first_child(SP_OBJECT(group)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) { if (!SP_IS_ITEM(o)) continue; if (SP_IS_GROUP(o) && SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER) { SPItem *newseen = find_group_at_point(dkey, SP_GROUP(o), p); if (newseen) { seen = newseen; } } if (SP_IS_GROUP(o) && SP_GROUP(o)->effectiveLayerMode(dkey) != SPGroup::LAYER ) { SPItem *child = SP_ITEM(o); NRArenaItem *arenaitem = sp_item_get_arenaitem(child, dkey); // seen remembers the last (topmost) of groups pickable at this point if (arenaitem && nr_arena_item_invoke_pick(arenaitem, p, delta, 1) != NULL) { seen = child; } } } return seen; }
static void sp_canvas_arena_update (SPCanvasItem *item, double *affine, unsigned int flags) { SPCanvasArena *arena; guint reset; arena = SP_CANVAS_ARENA (item); if (((SPCanvasItemClass *) parent_class)->update) (* ((SPCanvasItemClass *) parent_class)->update) (item, affine, flags); memcpy (NR_MATRIX_D_TO_DOUBLE (&arena->gc.transform), affine, 6 * sizeof (double)); if (flags & SP_CANVAS_UPDATE_AFFINE) { reset = NR_ARENA_ITEM_STATE_ALL; } else { reset = NR_ARENA_ITEM_STATE_NONE; } nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_ALL, reset); item->x1 = arena->root->bbox.x0 - 1; item->y1 = arena->root->bbox.y0 - 1; item->x2 = arena->root->bbox.x1 + 1; item->y2 = arena->root->bbox.y1 + 1; if (arena->cursor) { NRArenaItem *new_arena; /* Mess with enter/leave notifiers */ new_arena = nr_arena_item_invoke_pick (arena->root, arena->cx, arena->cy, nr_arena_global_delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; ec.window = GTK_WIDGET (item->canvas)->window; ec.send_event = TRUE; ec.subwindow = ec.window; ec.time = GDK_CURRENT_TIME; ec.x = arena->cx; ec.y = arena->cy; /* fixme: */ if (arena->active) { ec.type = GDK_LEAVE_NOTIFY; sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); } /* fixme: This is not optimal - better track ::destroy (Lauris) */ if (arena->active) nr_object_unref ((NRObject *) arena->active); arena->active = new_arena; if (arena->active) nr_object_ref ((NRObject *) arena->active); if (arena->active) { ec.type = GDK_ENTER_NOTIFY; sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); } } } }
static NRArenaItem * nr_arena_group_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int flags) { NRArenaGroup *group = NR_ARENA_GROUP (item); for (NRArenaItem *child = group->last; child != NULL; child = child->prev) { NRArenaItem *picked = nr_arena_item_invoke_pick (child, p, delta, flags); if (picked) return (group->transparent) ? picked : item; } return NULL; }
static NRArenaItem * nr_arena_group_pick (NRArenaItem *item, double x, double y, double delta, unsigned int sticky) { NRArenaGroup *group; NRArenaItem *child, *picked; group = NR_ARENA_GROUP (item); for (child = group->last; child != NULL; child = child->prev) { picked = nr_arena_item_invoke_pick (child, x, y, delta, sticky); if (picked) return (group->transparent) ? picked : item; } return NULL; }
static double sp_canvas_arena_point (SPCanvasItem *item, double x, double y, SPCanvasItem **actual_item) { SPCanvasArena *arena; NRArenaItem *picked; arena = SP_CANVAS_ARENA (item); nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); picked = nr_arena_item_invoke_pick (arena->root, x, y, nr_arena_global_delta, arena->sticky); arena->picked = picked; if (picked) { *actual_item = item; return 0.0; } return 1e18; }
/** Returns the topmost (in z-order) item from the descendants of group (recursively) which is at the point p, or NULL if none. Honors into_groups on whether to recurse into non-layer groups or not. Honors take_insensitive on whether to return insensitive items. If upto != NULL, then if item upto is encountered (at any level), stops searching upwards in z-order and returns what it has found so far (i.e. the found item is guaranteed to be lower than upto). */ SPItem* find_item_at_point(unsigned int dkey, SPGroup *group, Geom::Point const p, gboolean into_groups, bool take_insensitive = false, SPItem *upto = NULL) { SPItem *seen = NULL, *newseen = NULL; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0); for (SPObject *o = sp_object_first_child(SP_OBJECT(group)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) { if (!SP_IS_ITEM(o)) continue; if (upto && SP_ITEM(o) == upto) break; if (SP_IS_GROUP(o) && (SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER || into_groups)) { // if nothing found yet, recurse into the group newseen = find_item_at_point(dkey, SP_GROUP(o), p, into_groups, take_insensitive, upto); if (newseen) { seen = newseen; newseen = NULL; } if (item_is_in_group(upto, SP_GROUP(o))) break; } else { SPItem *child = SP_ITEM(o); NRArenaItem *arenaitem = sp_item_get_arenaitem(child, dkey); // seen remembers the last (topmost) of items pickable at this point if (arenaitem && nr_arena_item_invoke_pick(arenaitem, p, delta, 1) != NULL && (take_insensitive || child->isVisibleAndUnlocked(dkey))) { seen = child; } } } return seen; }
static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) { SPCanvasArena *arena; NRArenaItem *new_arena; gint ret; /* fixme: This sucks, we have to handle enter/leave notifiers */ arena = SP_CANVAS_ARENA (item); ret = FALSE; switch (event->type) { case GDK_ENTER_NOTIFY: if (!arena->cursor) { if (arena->active) { g_warning ("Cursor entered to arena with already active item"); nr_object_unref ((NRObject *) arena->active); } arena->cursor = TRUE; #if 0 gnome_canvas_w2c_d (item->canvas, event->crossing.x, event->crossing.y, &arena->cx, &arena->cy); #else arena->cx = event->crossing.x; arena->cy = event->crossing.y; #endif /* fixme: Not sure abut this, but seems the right thing (Lauris) */ nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); arena->active = nr_arena_item_invoke_pick (arena->root, arena->cx, arena->cy, nr_arena_global_delta, arena->sticky); if (arena->active) nr_object_ref ((NRObject *) arena->active); ret = sp_canvas_arena_send_event (arena, event); } break; case GDK_LEAVE_NOTIFY: if (arena->cursor) { ret = sp_canvas_arena_send_event (arena, event); if (arena->active) nr_object_unref ((NRObject *) arena->active); arena->active = NULL; arena->cursor = FALSE; } break; case GDK_MOTION_NOTIFY: #if 0 gnome_canvas_w2c_d (item->canvas, event->motion.x, event->motion.y, &arena->cx, &arena->cy); #else arena->cx = event->motion.x; arena->cy = event->motion.y; #endif /* fixme: Not sure abut this, but seems the right thing (Lauris) */ nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); new_arena = nr_arena_item_invoke_pick (arena->root, arena->cx, arena->cy, nr_arena_global_delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; ec.window = event->motion.window; ec.send_event = event->motion.send_event; ec.subwindow = event->motion.window; ec.time = event->motion.time; ec.x = event->motion.x; ec.y = event->motion.y; /* fixme: */ if (arena->active) { ec.type = GDK_LEAVE_NOTIFY; ret = sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); } if (arena->active) nr_object_unref ((NRObject *) arena->active); arena->active = new_arena; if (arena->active) nr_object_ref ((NRObject *) arena->active); if (arena->active) { ec.type = GDK_ENTER_NOTIFY; ret = sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); } } ret = sp_canvas_arena_send_event (arena, event); break; default: /* Just send event */ ret = sp_canvas_arena_send_event (arena, event); break; } return ret; }