/**
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;
}
Пример #3
0
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);
			}
		}
	}
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #8
0
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;
}