diff --git a/src/node-context.cpp b/src/node-context.cpp
index 1e01b1af9ac59e00602c3087623db0455cd4e89e..7efa57290832fb23565c020ddf57e4f448cc8183 100644 (file)
--- a/src/node-context.cpp
+++ b/src/node-context.cpp
* Lauris Kaplinski <lauris@kaplinski.com>
* bulia byak <buliabyak@users.sf.net>
*
- * This code is in public domain, except stamping code,
- * which is Copyright (C) Masatake Yamato 2002
+ * This code is in public domain
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
+#include <cstring>
+#include <string>
#include <gdk/gdkkeysyms.h>
#include "macros.h"
#include <glibmm/i18n.h>
#include "message-context.h"
#include "node-context.h"
#include "pixmaps/cursor-node-d.xpm"
-#include "prefs-utils.h"
+#include "preferences.h"
#include "xml/node-event-vector.h"
#include "style.h"
#include "splivarot.h"
+#include "shape-editor.h"
+#include "live_effects/effect.h"
+
+#include "sp-lpe-item.h"
+
+// needed for flash nodepath upon mouseover:
+#include "display/canvas-bpath.h"
+#include "display/curve.h"
static void sp_node_context_class_init(SPNodeContextClass *klass);
static void sp_node_context_init(SPNodeContext *node_context);
static gint sp_node_context_item_handler(SPEventContext *event_context,
SPItem *item, GdkEvent *event);
-static void nodepath_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
- gchar const *old_value, gchar const *new_value,
- bool is_interactive, gpointer data);
-
-static Inkscape::XML::NodeEventVector nodepath_repr_events = {
- NULL, /* child_added */
- NULL, /* child_removed */
- nodepath_event_attr_changed,
- NULL, /* content_changed */
- NULL /* order_changed */
-};
-
static SPEventContextClass *parent_class;
GType
node_context->rightctrl = FALSE;
new (&node_context->sel_changed_connection) sigc::connection();
+
+ node_context->flash_tempitem = NULL;
+ node_context->flashed_item = NULL;
+ node_context->remove_flash_counter = 0;
}
static void
sp_node_context_dispose(GObject *object)
{
- SPNodeContext *nc = SP_NODE_CONTEXT(object);
+ SPNodeContext *nc = SP_NODE_CONTEXT(object);
SPEventContext *ec = SP_EVENT_CONTEXT(object);
ec->enableGrDrag(false);
+
+ if (nc->grabbed) {
+ sp_canvas_item_ungrab(nc->grabbed, GDK_CURRENT_TIME);
+ nc->grabbed = NULL;
+ }
nc->sel_changed_connection.disconnect();
nc->sel_changed_connection.~connection();
- Inkscape::XML::Node *repr = NULL;
- if (nc->nodepath) {
- repr = nc->nodepath->repr;
- }
- if (!repr && ec->shape_knot_holder) {
- repr = ec->shape_knot_holder->repr;
- }
-
- if (repr) {
- sp_repr_remove_listener_by_data(repr, ec);
- Inkscape::GC::release(repr);
- }
-
- if (nc->nodepath) {
- sp_nodepath_destroy(nc->nodepath);
- nc->nodepath = NULL;
- }
-
- if (ec->shape_knot_holder) {
- sp_knot_holder_destroy(ec->shape_knot_holder);
- ec->shape_knot_holder = NULL;
- }
+ delete ec->shape_editor;
if (nc->_node_message_context) {
delete nc->_node_message_context;
if (((SPEventContextClass *) parent_class)->setup)
((SPEventContextClass *) parent_class)->setup(ec);
+ Inkscape::Selection *selection = sp_desktop_selection (ec->desktop);
nc->sel_changed_connection.disconnect();
- nc->sel_changed_connection = SP_DT_SELECTION(ec->desktop)->connectChanged(sigc::bind(sigc::ptr_fun(&sp_node_context_selection_changed), (gpointer)nc));
+ nc->sel_changed_connection =
+ selection->connectChanged(sigc::bind(sigc::ptr_fun(&sp_node_context_selection_changed), (gpointer)nc));
- Inkscape::Selection *selection = SP_DT_SELECTION(ec->desktop);
SPItem *item = selection->singleItem();
- nc->nodepath = NULL;
- ec->shape_knot_holder = NULL;
+ ec->shape_editor = new ShapeEditor(ec->desktop);
nc->rb_escaped = false;
nc->added_node = false;
+ nc->current_state = SP_NODE_CONTEXT_INACTIVE;
+
if (item) {
- nc->nodepath = sp_nodepath_new(ec->desktop, item);
- if ( nc->nodepath) {
- //point pack to parent in case nodepath is deleted
- nc->nodepath->nodeContext = nc;
- }
- ec->shape_knot_holder = sp_item_knot_holder(item, ec->desktop);
-
- if (nc->nodepath || ec->shape_knot_holder) {
- // setting listener
- Inkscape::XML::Node *repr;
- if (ec->shape_knot_holder)
- repr = ec->shape_knot_holder->repr;
- else
- repr = SP_OBJECT_REPR(item);
- if (repr) {
- Inkscape::GC::anchor(repr);
- sp_repr_add_listener(repr, &nodepath_repr_events, ec);
- }
- }
+ ec->shape_editor->set_item(item, SH_NODEPATH);
+ ec->shape_editor->set_item(item, SH_KNOTHOLDER);
}
- if (prefs_get_int_attribute("tools.nodes", "selcue", 0) != 0) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ if (prefs->getBool("/tools/nodes/selcue")) {
ec->enableSelectionCue();
}
-
- if (prefs_get_int_attribute("tools.nodes", "gradientdrag", 0) != 0) {
+ if (prefs->getBool("/tools/nodes/gradientdrag")) {
ec->enableGrDrag();
}
- nc->_node_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack());
- sp_nodepath_update_statusbar(nc->nodepath);
-}
-
-/**
-\brief Callback that processes the "changed" signal on the selection;
-destroys old and creates new nodepath and reassigns listeners to the new selected item's repr
-*/
-void
-sp_node_context_selection_changed(Inkscape::Selection *selection, gpointer data)
-{
- SPNodeContext *nc = SP_NODE_CONTEXT(data);
- SPEventContext *ec = SP_EVENT_CONTEXT(nc);
+ ec->desktop->emitToolSubselectionChanged(NULL); // sets the coord entry fields to inactive
- Inkscape::XML::Node *old_repr = NULL;
-
- if (nc->nodepath) {
- old_repr = nc->nodepath->repr;
- sp_nodepath_destroy(nc->nodepath);
- nc->nodepath = NULL;
- }
-
- if (ec->shape_knot_holder) {
- old_repr = ec->shape_knot_holder->repr;
- sp_knot_holder_destroy(ec->shape_knot_holder);
- }
-
- if (old_repr) { // remove old listener
- sp_repr_remove_listener_by_data(old_repr, ec);
- Inkscape::GC::release(old_repr);
- }
-
- SPItem *item = selection->singleItem();
+ nc->_node_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack());
- SPDesktop *desktop = selection->desktop();
- nc->nodepath = NULL;
- ec->shape_knot_holder = NULL;
- if (item) {
- nc->nodepath = sp_nodepath_new(desktop, item);
- if (nc->nodepath) {
- nc->nodepath->nodeContext = nc;
- }
- ec->shape_knot_holder = sp_item_knot_holder(item, desktop);
-
- if (nc->nodepath || ec->shape_knot_holder) {
- // setting new listener
- Inkscape::XML::Node *repr;
- if (ec->shape_knot_holder)
- repr = ec->shape_knot_holder->repr;
- else
- repr = SP_OBJECT_REPR(item);
- if (repr) {
- Inkscape::GC::anchor(repr);
- sp_repr_add_listener(repr, &nodepath_repr_events, ec);
- }
- }
- }
- sp_nodepath_update_statusbar(nc->nodepath);
+ ec->shape_editor->update_statusbar();
}
-/**
-\brief Regenerates nodepath when the item's repr was change outside of node edit
-(e.g. by undo, or xml editor, or edited in another view). The item is assumed to be the same
-(otherwise sp_node_context_selection_changed() would have been called), so repr and listeners
-are not changed.
-*/
-void
-sp_nodepath_update_from_item(SPNodeContext *nc, SPItem *item)
-{
- g_assert(nc);
- SPEventContext *ec = ((SPEventContext *) nc);
-
- SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(SP_EVENT_CONTEXT(nc));
- g_assert(desktop);
-
- if (nc->nodepath) {
- sp_nodepath_destroy(nc->nodepath);
- nc->nodepath = NULL;
- }
+static void
+sp_node_context_flash_path(SPEventContext *event_context, SPItem *item, guint timeout) {
+ SPNodeContext *nc = SP_NODE_CONTEXT(event_context);
- if (ec->shape_knot_holder) {
- sp_knot_holder_destroy(ec->shape_knot_holder);
- ec->shape_knot_holder = NULL;
- }
+ nc->remove_flash_counter = 3; // for some reason root_handler is called twice after each item_handler...
+ if (nc->flashed_item != item) {
+ // we entered a new item
+ nc->flashed_item = item;
+ SPDesktop *desktop = event_context->desktop;
+ if (nc->flash_tempitem) {
+ desktop->remove_temporary_canvasitem(nc->flash_tempitem);
+ nc->flash_tempitem = NULL;
+ }
- Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
- item = selection->singleItem();
+ SPCanvasItem *canvasitem = sp_nodepath_generate_helperpath(desktop, item);
- if (item) {
- nc->nodepath = sp_nodepath_new(desktop, item);
- if (nc->nodepath) {
- nc->nodepath->nodeContext = nc;
+ if (canvasitem) {
+ nc->flash_tempitem = desktop->add_temporary_canvasitem (canvasitem, timeout);
}
- ec->shape_knot_holder = sp_item_knot_holder(item, desktop);
}
- sp_nodepath_update_statusbar(nc->nodepath);
}
/**
-\brief Callback that is fired whenever an attribute of the selected item (which we have in the nodepath) changes
+\brief Callback that processes the "changed" signal on the selection;
+destroys old and creates new nodepath and reassigns listeners to the new selected item's repr
*/
-static void
-nodepath_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
- gchar const *old_value, gchar const *new_value,
- bool is_interactive, gpointer data)
+void
+sp_node_context_selection_changed(Inkscape::Selection *selection, gpointer data)
{
- SPItem *item = NULL;
- gboolean changed = FALSE;
-
- g_assert(data);
- SPNodeContext *nc = ((SPNodeContext *) data);
- SPEventContext *ec = ((SPEventContext *) data);
- g_assert(nc);
- Inkscape::NodePath::Path *np = nc->nodepath;
- SPKnotHolder *kh = ec->shape_knot_holder;
-
- if (np) {
- item = SP_ITEM(np->path);
- if (!strcmp(name, "d") || !strcmp(name, "sodipodi:nodetypes")) { // With paths, we only need to act if one of the path-affecting attributes has changed.
- changed = (np->local_change == 0);
- if (np->local_change > 0)
- np->local_change--;
- }
-
- } else if (kh) {
- item = SP_ITEM(kh->item);
- changed = !(kh->local_change);
- kh->local_change = FALSE;
- }
-
- if (np && changed) {
- GList *saved = NULL;
- SPDesktop *desktop = np->desktop;
- g_assert(desktop);
- Inkscape::Selection *selection = desktop->selection;
- g_assert(selection);
+ SPEventContext *ec = SP_EVENT_CONTEXT(data);
- saved = save_nodepath_selection(nc->nodepath);
- sp_nodepath_update_from_item(nc, item);
- if (nc->nodepath && saved) restore_nodepath_selection(nc->nodepath, saved);
-
- } else if (kh && changed) {
- sp_nodepath_update_from_item(nc, item);
- }
-
- sp_nodepath_update_statusbar(nc->nodepath);
+ // TODO: update ShapeEditorsCollective instead
+ ec->shape_editor->unset_item(SH_NODEPATH);
+ ec->shape_editor->unset_item(SH_KNOTHOLDER);
+ SPItem *item = selection->singleItem();
+ ec->shape_editor->set_item(item, SH_NODEPATH);
+ ec->shape_editor->set_item(item, SH_KNOTHOLDER);
+ ec->shape_editor->update_statusbar();
}
void
@@ -361,152 +230,55 @@ sp_node_context_show_modifier_tip(SPEventContext *event_context, GdkEvent *event
_("<b>Alt</b>: lock handle length; <b>Ctrl+Alt</b>: move along handles"));
}
-bool
-sp_node_context_is_over_stroke (SPNodeContext *nc, SPItem *item, NR::Point event_p, bool remember)
-{
- SPDesktop *desktop = SP_EVENT_CONTEXT (nc)->desktop;
-
- //Translate click point into proper coord system
- nc->curvepoint_doc = desktop->w2d(event_p);
- nc->curvepoint_doc *= sp_item_dt2i_affine(item);
- nc->curvepoint_doc *= sp_item_i2doc_affine(item);
-
- NR::Maybe<Path::cut_position> position = get_nearest_position_on_Path(nc->nodepath->livarot_path, nc->curvepoint_doc);
- NR::Point nearest = get_point_on_Path(nc->nodepath->livarot_path, position.assume().piece, position.assume().t);
- NR::Point delta = nearest - nc->curvepoint_doc;
-
- delta = desktop->d2w(delta);
-
- double stroke_tolerance =
- (SP_OBJECT_STYLE (item)->stroke.type != SP_PAINT_TYPE_NONE?
- desktop->current_zoom() *
- SP_OBJECT_STYLE (item)->stroke_width.computed *
- sp_item_i2d_affine (item).expansion() * 0.5
- : 0.0)
- + (double) SP_EVENT_CONTEXT(nc)->tolerance;
-
- bool close = (NR::L2 (delta) < stroke_tolerance);
-
- if (remember && close) {
- nc->curvepoint_event[NR::X] = (gint) event_p [NR::X];
- nc->curvepoint_event[NR::Y] = (gint) event_p [NR::Y];
- nc->hit = true;
- nc->grab_t = position.assume().t;
- nc->grab_node = sp_nodepath_get_node_by_index(position.assume().piece);
- }
-
- return close;
-}
-
-
static gint
sp_node_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event)
{
gint ret = FALSE;
-
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
SPDesktop *desktop = event_context->desktop;
- Inkscape::Selection *selection = SP_DT_SELECTION (desktop);
-
- SPNodeContext *nc = SP_NODE_CONTEXT(event_context);
switch (event->type) {
- case GDK_2BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- if (event->button.button == 1) {
- if (!nc->drag) {
-
- // find out clicked item, disregarding groups, honoring Alt
- SPItem *item_clicked = sp_event_context_find_item (desktop,
- NR::Point(event->button.x, event->button.y),
- (event->button.state & GDK_MOD1_MASK) && !(event->button.state & GDK_CONTROL_MASK), TRUE);
- // find out if we're over the selected item, disregarding groups
- SPItem *item_over = sp_event_context_over_item (desktop, selection->singleItem(),
- NR::Point(event->button.x, event->button.y));
-
- bool over_stroke = false;
- if (item_over && nc->nodepath) {
- over_stroke = sp_node_context_is_over_stroke (nc, item_over, NR::Point(event->button.x, event->button.y), false);
- }
-
- if (over_stroke || nc->added_node) {
- switch (event->type) {
- case GDK_BUTTON_RELEASE:
- if (event->button.state & GDK_CONTROL_MASK && event->button.state & GDK_MOD1_MASK) {
- //add a node
- sp_nodepath_add_node_near_point(nc->nodepath, nc->curvepoint_doc);
- } else {
- if (nc->added_node) { // we just received double click, ignore release
- nc->added_node = false;
- break;
- }
- //select the segment
- if (event->button.state & GDK_SHIFT_MASK) {
- sp_nodepath_select_segment_near_point(nc->nodepath, nc->curvepoint_doc, true);
- } else {
- sp_nodepath_select_segment_near_point(nc->nodepath, nc->curvepoint_doc, false);
- }
- }
- break;
- case GDK_2BUTTON_PRESS:
- //add a node
- sp_nodepath_add_node_near_point(nc->nodepath, nc->curvepoint_doc);
- nc->added_node = true;
- break;
- default:
- break;
- }
- } else if (event->button.state & GDK_SHIFT_MASK) {
- selection->toggle(item_clicked);
- } else {
- selection->set(item_clicked);
- }
-
- ret = TRUE;
- }
+ case GDK_MOTION_NOTIFY:
+ {
+ // find out actual item we're over, disregarding groups
+ SPItem *actual_item = sp_event_context_find_item (desktop,
+ Geom::Point(event->button.x, event->button.y), FALSE, TRUE);
+ if (!actual_item)
break;
- }
- break;
- case GDK_BUTTON_PRESS:
- if (event->button.button == 1 && !(event->button.state & GDK_SHIFT_MASK)) {
- // save drag origin
- event_context->xp = (gint) event->button.x;
- event_context->yp = (gint) event->button.y;
- event_context->within_tolerance = true;
- nc->hit = false;
-
- if (!nc->drag) {
- // find out if we're over the selected item, disregarding groups
- SPItem *item_over = sp_event_context_over_item (desktop, selection->singleItem(),
- NR::Point(event->button.x, event->button.y));
- if (nc->nodepath && selection->single() && item_over) {
-
- // save drag origin
- bool over_stroke = sp_node_context_is_over_stroke (nc, item_over, NR::Point(event->button.x, event->button.y), true);
- //only dragging curves
- if (over_stroke) {
- sp_nodepath_select_segment_near_point(nc->nodepath, nc->curvepoint_doc, false);
- ret = TRUE;
- } else {
- break;
- }
- } else {
- break;
- }
- ret = TRUE;
+ if (prefs->getBool("/tools/nodes/pathflash_enabled")) {
+ if (prefs->getBool("/tools/nodes/pathflash_unselected")) {
+ // do not flash if we have some path selected and a single item in selection (i.e. it
+ // is the same path that we're editing)
+ SPDesktop *desktop = event_context->desktop;
+ ShapeEditor* se = event_context->shape_editor;
+ Inkscape::Selection *selection = sp_desktop_selection (desktop);
+ if (se->has_nodepath() && selection->singleItem()) {
+ break;
+ }
}
- break;
+ if (SP_IS_LPE_ITEM(actual_item)) {
+ Inkscape::LivePathEffect::Effect *lpe = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(actual_item));
+ if (lpe && (lpe->providesOwnFlashPaths() ||
+ lpe->pathFlashType() == Inkscape::LivePathEffect::SUPPRESS_FLASH)) {
+ // path should be suppressed or permanent; this is handled in
+ // sp_node_context_selection_changed()
+ break;
+ }
+ }
+ guint timeout = prefs->getInt("/tools/nodes/pathflash_timeout", 500);
+ sp_node_context_flash_path(event_context, actual_item, timeout);
}
- break;
+ }
+ break;
+
default:
break;
}
- if (!ret) {
- if (((SPEventContextClass *) parent_class)->item_handler)
- ret = ((SPEventContextClass *) parent_class)->item_handler(event_context, item, event);
- }
+ if (((SPEventContextClass *) parent_class)->item_handler)
+ ret = ((SPEventContextClass *) parent_class)->item_handler(event_context, item, event);
return ret;
}
sp_node_context_root_handler(SPEventContext *event_context, GdkEvent *event)
{
SPDesktop *desktop = event_context->desktop;
- Inkscape::Selection *selection = SP_DT_SELECTION (desktop);
+ ShapeEditor* se = event_context->shape_editor;
+ Inkscape::Selection *selection = sp_desktop_selection (desktop);
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
SPNodeContext *nc = SP_NODE_CONTEXT(event_context);
- double const nudge = prefs_get_double_attribute_limited("options.nudgedistance", "value", 2, 0, 1000); // in px
- event_context->tolerance = prefs_get_int_attribute_limited("options.dragtolerance", "value", 0, 0, 100); // read every time, to make prefs changes really live
- int const snaps = prefs_get_int_attribute("options.rotationsnapsperpi", "value", 12);
- double const offset = prefs_get_double_attribute_limited("options.defaultscale", "value", 2, 0, 1000);
+ double const nudge = prefs->getDoubleLimited("/options/nudgedistance/value", 2, 0, 1000); // in px
+ event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); // read every time, to make prefs changes really live
+ int const snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12);
+ double const offset = prefs->getDoubleLimited("/options/defaultscale/value", 2, 0, 1000);
+
+ if ( (nc->flash_tempitem) && (nc->remove_flash_counter <= 0) ) {
+ desktop->remove_temporary_canvasitem(nc->flash_tempitem);
+ nc->flash_tempitem = NULL;
+ nc->flashed_item = NULL; // also reset this one, so the next time the same object is hovered over it shows again the highlight
+ } else {
+ nc->remove_flash_counter--;
+ }
gint ret = FALSE;
-
switch (event->type) {
case GDK_BUTTON_PRESS:
- if (event->button.button == 1) {
+ if (event->button.button == 1 && !event_context->space_panning) {
// save drag origin
event_context->xp = (gint) event->button.x;
event_context->yp = (gint) event->button.y;
event_context->within_tolerance = true;
- nc->hit = false;
+ se->cancel_hit();
- NR::Point const button_w(event->button.x,
+ if (!(event->button.state & GDK_SHIFT_MASK)) {
+ if (!nc->drag) {
+ if (se->has_nodepath() && selection->single() /* && item_over */) {
+ // save drag origin
+ bool over_stroke = se->is_over_stroke(Geom::Point(event->button.x, event->button.y), true);
+ //only dragging curves
+ if (over_stroke) {
+ ret = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ Geom::Point const button_w(event->button.x,
event->button.y);
- NR::Point const button_dt(desktop->w2d(button_w));
- Inkscape::Rubberband::get()->start(desktop, button_dt);
+ Geom::Point const button_dt(desktop->w2d(button_w));
+ Inkscape::Rubberband::get(desktop)->start(desktop, button_dt);
+
+ if (nc->grabbed) {
+ sp_canvas_item_ungrab(nc->grabbed, event->button.time);
+ nc->grabbed = NULL;
+ }
+
+ sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK,
+ NULL, event->button.time);
+ nc->grabbed = SP_CANVAS_ITEM(desktop->acetate);
+
+ nc->current_state = SP_NODE_CONTEXT_INACTIVE;
+ desktop->updateNow();
ret = TRUE;
}
break;
case GDK_MOTION_NOTIFY:
- if (event->motion.state & GDK_BUTTON1_MASK) {
+ if (event->motion.state & GDK_BUTTON1_MASK && !event_context->space_panning) {
if ( event_context->within_tolerance
&& ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance )
&& ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) {
break; // do not drag if we're within tolerance from origin
}
+
+ // The path went away while dragging; throw away any further motion
+ // events until the mouse pointer is released.
+
+ if (se->hits_curve() && !se->has_nodepath()) {
+ break;
+ }
+
// Once the user has moved farther than tolerance from the original location
// (indicating they intend to move the object, not click), then always process the
// motion notify coordinates as given (no snapping back to origin)
event_context->within_tolerance = false;
- if (nc->nodepath && nc->hit) {
- NR::Point const delta_w(event->motion.x - nc->curvepoint_event[NR::X],
- event->motion.y - nc->curvepoint_event[NR::Y]);
- NR::Point const delta_dt(desktop->w2d(delta_w));
- sp_nodepath_curve_drag (nc->grab_node, nc->grab_t, delta_dt);
- nc->curvepoint_event[NR::X] = (gint) event->motion.x;
- nc->curvepoint_event[NR::Y] = (gint) event->motion.y;
- gobble_motion_events(GDK_BUTTON1_MASK);
- } else {
- NR::Point const motion_w(event->motion.x,
- event->motion.y);
- NR::Point const motion_dt(desktop->w2d(motion_w));
- Inkscape::Rubberband::get()->move(motion_dt);
+ // Once we determine what the user is doing (dragging either a node or the
+ // selection rubberband), make sure we continue to perform that operation
+ // until the mouse pointer is lifted.
+ if (nc->current_state == SP_NODE_CONTEXT_INACTIVE) {
+ if (se->hits_curve() && se->has_nodepath()) {
+ nc->current_state = SP_NODE_CONTEXT_NODE_DRAGGING;
+ } else {
+ nc->current_state = SP_NODE_CONTEXT_RUBBERBAND_DRAGGING;
+ }
+ }
+
+ switch (nc->current_state) {
+ case SP_NODE_CONTEXT_NODE_DRAGGING:
+ {
+ se->curve_drag (event->motion.x, event->motion.y);
+
+ gobble_motion_events(GDK_BUTTON1_MASK);
+ break;
+ }
+ case SP_NODE_CONTEXT_RUBBERBAND_DRAGGING:
+ if (Inkscape::Rubberband::get(desktop)->is_started()) {
+ Geom::Point const motion_w(event->motion.x,
+ event->motion.y);
+ Geom::Point const motion_dt(desktop->w2d(motion_w));
+ Inkscape::Rubberband::get(desktop)->move(motion_dt);
+ }
+ break;
}
+
nc->drag = TRUE;
ret = TRUE;
} else {
- if (!nc->nodepath || selection->singleItem() == NULL) {
+ if (!se->has_nodepath() || selection->singleItem() == NULL) {
break;
}
- SPItem *item_over = sp_event_context_over_item (desktop, selection->singleItem(),
- NR::Point(event->motion.x, event->motion.y));
bool over_stroke = false;
- if (item_over && nc->nodepath) {
- over_stroke = sp_node_context_is_over_stroke (nc, item_over, NR::Point(event->motion.x, event->motion.y), false);
- }
+ over_stroke = se->is_over_stroke(Geom::Point(event->motion.x, event->motion.y), false);
if (nc->cursor_drag && !over_stroke) {
event_context->cursor_shape = cursor_node_xpm;
}
}
break;
+
+ case GDK_2BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
- event_context->xp = event_context->yp = 0;
- if (event->button.button == 1) {
+ if ( (event->button.button == 1) && (!nc->drag) && !event_context->space_panning) {
+ // find out clicked item, disregarding groups, honoring Alt
+ SPItem *item_clicked = sp_event_context_find_item (desktop,
+ Geom::Point(event->button.x, event->button.y),
+ (event->button.state & GDK_MOD1_MASK) && !(event->button.state & GDK_CONTROL_MASK), TRUE);
+
+ event_context->xp = event_context->yp = 0;
- NR::Maybe<NR::Rect> b = Inkscape::Rubberband::get()->getRectangle();
+ bool over_stroke = false;
+ if (se->has_nodepath()) {
+ over_stroke = se->is_over_stroke(Geom::Point(event->button.x, event->button.y), false);
+ }
- if (nc->hit && !event_context->within_tolerance) { //drag curve
- sp_nodepath_update_repr (nc->nodepath);
- } else if (b != NR::Nothing() && !event_context->within_tolerance) { // drag to select
- if (nc->nodepath) {
- sp_nodepath_select_rect(nc->nodepath, b.assume(), event->button.state & GDK_SHIFT_MASK);
+ if (item_clicked || over_stroke) {
+ if (over_stroke || nc->added_node) {
+ switch (event->type) {
+ case GDK_BUTTON_RELEASE:
+ if (event->button.state & GDK_CONTROL_MASK && event->button.state & GDK_MOD1_MASK) {
+ //add a node
+ se->add_node_near_point();
+ } else {
+ if (nc->added_node) { // we just received double click, ignore release
+ nc->added_node = false;
+ break;
+ }
+ //select the segment
+ if (event->button.state & GDK_SHIFT_MASK) {
+ se->select_segment_near_point(true);
+ } else {
+ se->select_segment_near_point(false);
+ }
+ desktop->updateNow();
+ }
+ break;
+ case GDK_2BUTTON_PRESS:
+ //add a node
+ se->add_node_near_point();
+ nc->added_node = true;
+ break;
+ default:
+ break;
+ }
+ } else if (event->button.state & GDK_SHIFT_MASK) {
+ selection->toggle(item_clicked);
+ desktop->updateNow();
+ } else {
+ selection->set(item_clicked);
+ desktop->updateNow();
+ }
+ Inkscape::Rubberband::get(desktop)->stop();
+ if (nc->grabbed) {
+ sp_canvas_item_ungrab(nc->grabbed, event->button.time);
+ nc->grabbed = NULL;
}
- } else {
- if (!(nc->rb_escaped)) { // unless something was cancelled
- if (nc->nodepath && nc->nodepath->selected)
- sp_nodepath_deselect(nc->nodepath);
- else
- SP_DT_SELECTION(desktop)->clear();
+ ret = TRUE;
+ break;
+ }
+ }
+ if (event->type == GDK_BUTTON_RELEASE) {
+ event_context->xp = event_context->yp = 0;
+ if (event->button.button == 1) {
+ Geom::OptRect b = Inkscape::Rubberband::get(desktop)->getRectangle();
+
+ if (se->hits_curve() && !event_context->within_tolerance) { //drag curve
+ se->finish_drag();
+ } else if (b && !event_context->within_tolerance) { // drag to select
+ se->select_rect(*b, event->button.state & GDK_SHIFT_MASK);
+ } else {
+ if (!(nc->rb_escaped)) { // unless something was canceled
+ if (se->has_selection())
+ se->deselect();
+ else
+ sp_desktop_selection(desktop)->clear();
+ }
}
+ ret = TRUE;
+ Inkscape::Rubberband::get(desktop)->stop();
+
+ if (nc->grabbed) {
+ sp_canvas_item_ungrab(nc->grabbed, event->button.time);
+ nc->grabbed = NULL;
+ }
+
+ desktop->updateNow();
+ nc->rb_escaped = false;
+ nc->drag = FALSE;
+ se->cancel_hit();
+ nc->current_state = SP_NODE_CONTEXT_INACTIVE;
}
- ret = TRUE;
- Inkscape::Rubberband::get()->stop();
- nc->rb_escaped = false;
- nc->drag = FALSE;
- nc->hit = false;
- break;
}
break;
case GDK_KEY_PRESS:
case GDK_Insert:
case GDK_KP_Insert:
// with any modifiers
- sp_node_selected_add_node();
+ se->add_node();
ret = TRUE;
break;
+ case GDK_I:
+ case GDK_i:
+ // apple keyboards have no Insert
+ if (MOD__SHIFT_ONLY) {
+ se->add_node();
+ ret = TRUE;
+ }
+ break;
case GDK_Delete:
case GDK_KP_Delete:
case GDK_BackSpace:
- // with any modifiers
- sp_node_selected_delete();
+ if (MOD__CTRL_ONLY) {
+ se->delete_nodes();
+ } else {
+ se->delete_nodes_preserving_shape();
+ }
ret = TRUE;
break;
case GDK_C:
case GDK_c:
if (MOD__SHIFT_ONLY) {
- sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
+ se->set_node_type(Inkscape::NodePath::NODE_CUSP);
ret = TRUE;
}
break;
case GDK_S:
case GDK_s:
if (MOD__SHIFT_ONLY) {
- sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
+ se->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
+ ret = TRUE;
+ }
+ break;
+ case GDK_A:
+ case GDK_a:
+ if (MOD__SHIFT_ONLY) {
+ se->set_node_type(Inkscape::NodePath::NODE_AUTO);
ret = TRUE;
}
break;
case GDK_Y:
case GDK_y:
if (MOD__SHIFT_ONLY) {
- sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
+ se->set_node_type(Inkscape::NodePath::NODE_SYMM);
ret = TRUE;
}
break;
case GDK_B:
case GDK_b:
if (MOD__SHIFT_ONLY) {
- sp_node_selected_break();
+ se->break_at_nodes();
ret = TRUE;
}
break;
case GDK_J:
case GDK_j:
if (MOD__SHIFT_ONLY) {
- sp_node_selected_join();
+ se->join_nodes();
ret = TRUE;
}
break;
case GDK_D:
case GDK_d:
if (MOD__SHIFT_ONLY) {
- sp_node_selected_duplicate();
+ se->duplicate_nodes();
ret = TRUE;
}
break;
case GDK_L:
case GDK_l:
if (MOD__SHIFT_ONLY) {
- sp_node_selected_set_line_type(NR_LINETO);
+ se->set_type_of_segments(NR_LINETO);
ret = TRUE;
}
break;
case GDK_U:
case GDK_u:
if (MOD__SHIFT_ONLY) {
- sp_node_selected_set_line_type(NR_CURVETO);
+ se->set_type_of_segments(NR_CURVETO);
ret = TRUE;
}
break;
case GDK_r:
if (MOD__SHIFT_ONLY) {
// FIXME: add top panel button
- sp_selected_path_reverse();
+ sp_selected_path_reverse(desktop);
+ ret = TRUE;
+ }
+ break;
+ case GDK_x:
+ case GDK_X:
+ if (MOD__ALT_ONLY) {
+ desktop->setToolboxFocusTo ("altx-nodes");
ret = TRUE;
}
break;
case GDK_KP_Left:
case GDK_KP_4:
if (!MOD__CTRL) { // not ctrl
+ gint mul = 1 + gobble_key_events(
+ get_group0_keyval(&event->key), 0); // with any mask
if (MOD__ALT) { // alt
- if (MOD__SHIFT) sp_node_selected_move_screen(-10, 0); // shift
- else sp_node_selected_move_screen(-1, 0); // no shift
+ if (MOD__SHIFT) se->move_nodes_screen(desktop, mul*-10, 0); // shift
+ else se->move_nodes_screen(desktop, mul*-1, 0); // no shift
}
else { // no alt
- if (MOD__SHIFT) sp_node_selected_move(-10*nudge, 0); // shift
- else sp_node_selected_move(-nudge, 0); // no shift
+ if (MOD__SHIFT) se->move_nodes(mul*-10*nudge, 0); // shift
+ else se->move_nodes(mul*-nudge, 0); // no shift
}
ret = TRUE;
}
case GDK_KP_Up:
case GDK_KP_8:
if (!MOD__CTRL) { // not ctrl
+ gint mul = 1 + gobble_key_events(
+ get_group0_keyval(&event->key), 0); // with any mask
if (MOD__ALT) { // alt
- if (MOD__SHIFT) sp_node_selected_move_screen(0, 10); // shift
- else sp_node_selected_move_screen(0, 1); // no shift
+ if (MOD__SHIFT) se->move_nodes_screen(desktop, 0, mul*10); // shift
+ else se->move_nodes_screen(desktop, 0, mul*1); // no shift
}
else { // no alt
- if (MOD__SHIFT) sp_node_selected_move(0, 10*nudge); // shift
- else sp_node_selected_move(0, nudge); // no shift
+ if (MOD__SHIFT) se->move_nodes(0, mul*10*nudge); // shift
+ else se->move_nodes(0, mul*nudge); // no shift
}
ret = TRUE;
}
case GDK_KP_Right:
case GDK_KP_6:
if (!MOD__CTRL) { // not ctrl
+ gint mul = 1 + gobble_key_events(
+ get_group0_keyval(&event->key), 0); // with any mask
if (MOD__ALT) { // alt
- if (MOD__SHIFT) sp_node_selected_move_screen(10, 0); // shift
- else sp_node_selected_move_screen(1, 0); // no shift
+ if (MOD__SHIFT) se->move_nodes_screen(desktop, mul*10, 0); // shift
+ else se->move_nodes_screen(desktop, mul*1, 0); // no shift
}
else { // no alt
- if (MOD__SHIFT) sp_node_selected_move(10*nudge, 0); // shift
- else sp_node_selected_move(nudge, 0); // no shift
+ if (MOD__SHIFT) se->move_nodes(mul*10*nudge, 0); // shift
+ else se->move_nodes(mul*nudge, 0); // no shift
}
ret = TRUE;
}
case GDK_KP_Down:
case GDK_KP_2:
if (!MOD__CTRL) { // not ctrl
+ gint mul = 1 + gobble_key_events(
+ get_group0_keyval(&event->key), 0); // with any mask
if (MOD__ALT) { // alt
- if (MOD__SHIFT) sp_node_selected_move_screen(0, -10); // shift
- else sp_node_selected_move_screen(0, -1); // no shift
+ if (MOD__SHIFT) se->move_nodes_screen(desktop, 0, mul*-10); // shift
+ else se->move_nodes_screen(desktop, 0, mul*-1); // no shift
}
else { // no alt
- if (MOD__SHIFT) sp_node_selected_move(0, -10*nudge); // shift
- else sp_node_selected_move(0, -nudge); // no shift
+ if (MOD__SHIFT) se->move_nodes(0, mul*-10*nudge); // shift
+ else se->move_nodes(0, mul*-nudge); // no shift
}
ret = TRUE;
}
break;
- case GDK_Tab: // Tab - cycle selection forward
- if (!(MOD__CTRL_ONLY || (MOD__CTRL && MOD__SHIFT))) {
- sp_nodepath_select_next(nc->nodepath);
- ret = TRUE;
- }
- break;
- case GDK_ISO_Left_Tab: // Shift Tab - cycle selection backward
- if (!(MOD__CTRL_ONLY || (MOD__CTRL && MOD__SHIFT))) {
- sp_nodepath_select_prev(nc->nodepath);
- ret = TRUE;
- }
- break;
case GDK_Escape:
{
- NR::Maybe<NR::Rect> const b = Inkscape::Rubberband::get()->getRectangle();
- if (b != NR::Nothing()) {
- Inkscape::Rubberband::get()->stop();
+ Geom::OptRect const b = Inkscape::Rubberband::get(desktop)->getRectangle();
+ if (b) {
+ Inkscape::Rubberband::get(desktop)->stop();
+ nc->current_state = SP_NODE_CONTEXT_INACTIVE;
nc->rb_escaped = true;
} else {
- if (nc->nodepath && nc->nodepath->selected) {
- sp_nodepath_deselect(nc->nodepath);
+ if (se->has_selection()) {
+ se->deselect();
} else {
- SP_DT_SELECTION(desktop)->clear();
+ sp_desktop_selection(desktop)->clear();
}
}
ret = TRUE;
case GDK_bracketleft:
if ( MOD__CTRL && !MOD__ALT && ( snaps != 0 ) ) {
if (nc->leftctrl)
- sp_nodepath_selected_nodes_rotate (nc->nodepath, M_PI/snaps, -1, false);
+ se->rotate_nodes (M_PI/snaps, -1, false);
if (nc->rightctrl)
- sp_nodepath_selected_nodes_rotate (nc->nodepath, M_PI/snaps, 1, false);
+ se->rotate_nodes (M_PI/snaps, 1, false);
} else if ( MOD__ALT && !MOD__CTRL ) {
if (nc->leftalt && nc->rightalt)
- sp_nodepath_selected_nodes_rotate (nc->nodepath, 1, 0, true);
+ se->rotate_nodes (1, 0, true);
else {
if (nc->leftalt)
- sp_nodepath_selected_nodes_rotate (nc->nodepath, 1, -1, true);
+ se->rotate_nodes (1, -1, true);
if (nc->rightalt)
- sp_nodepath_selected_nodes_rotate (nc->nodepath, 1, 1, true);
+ se->rotate_nodes (1, 1, true);
}
} else if ( snaps != 0 ) {
- sp_nodepath_selected_nodes_rotate (nc->nodepath, M_PI/snaps, 0, false);
+ se->rotate_nodes (M_PI/snaps, 0, false);
}
ret = TRUE;
break;
case GDK_bracketright:
if ( MOD__CTRL && !MOD__ALT && ( snaps != 0 ) ) {
if (nc->leftctrl)
- sp_nodepath_selected_nodes_rotate (nc->nodepath, -M_PI/snaps, -1, false);
+ se->rotate_nodes (-M_PI/snaps, -1, false);
if (nc->rightctrl)
- sp_nodepath_selected_nodes_rotate (nc->nodepath, -M_PI/snaps, 1, false);
+ se->rotate_nodes (-M_PI/snaps, 1, false);
} else if ( MOD__ALT && !MOD__CTRL ) {
if (nc->leftalt && nc->rightalt)
- sp_nodepath_selected_nodes_rotate (nc->nodepath, -1, 0, true);
+ se->rotate_nodes (-1, 0, true);
else {
if (nc->leftalt)
- sp_nodepath_selected_nodes_rotate (nc->nodepath, -1, -1, true);
+ se->rotate_nodes (-1, -1, true);
if (nc->rightalt)
- sp_nodepath_selected_nodes_rotate (nc->nodepath, -1, 1, true);
+ se->rotate_nodes (-1, 1, true);
}
} else if ( snaps != 0 ) {
- sp_nodepath_selected_nodes_rotate (nc->nodepath, -M_PI/snaps, 0, false);
+ se->rotate_nodes (-M_PI/snaps, 0, false);
}
ret = TRUE;
break;
case GDK_comma:
if (MOD__CTRL) {
if (nc->leftctrl)
- sp_nodepath_selected_nodes_scale(nc->nodepath, -offset, -1);
+ se->scale_nodes(-offset, -1);
if (nc->rightctrl)
- sp_nodepath_selected_nodes_scale(nc->nodepath, -offset, 1);
+ se->scale_nodes(-offset, 1);
} else if (MOD__ALT) {
if (nc->leftalt && nc->rightalt)
- sp_nodepath_selected_nodes_scale_screen(nc->nodepath, -1, 0);
+ se->scale_nodes_screen (-1, 0);
else {
if (nc->leftalt)
- sp_nodepath_selected_nodes_scale_screen(nc->nodepath, -1, -1);
+ se->scale_nodes_screen (-1, -1);
if (nc->rightalt)
- sp_nodepath_selected_nodes_scale_screen(nc->nodepath, -1, 1);
+ se->scale_nodes_screen (-1, 1);
}
} else {
- sp_nodepath_selected_nodes_scale(nc->nodepath, -offset, 0);
+ se->scale_nodes (-offset, 0);
}
ret = TRUE;
break;
case GDK_period:
if (MOD__CTRL) {
if (nc->leftctrl)
- sp_nodepath_selected_nodes_scale(nc->nodepath, offset, -1);
+ se->scale_nodes (offset, -1);
if (nc->rightctrl)
- sp_nodepath_selected_nodes_scale(nc->nodepath, offset, 1);
+ se->scale_nodes (offset, 1);
} else if (MOD__ALT) {
if (nc->leftalt && nc->rightalt)
- sp_nodepath_selected_nodes_scale_screen(nc->nodepath, 1, 0);
+ se->scale_nodes_screen (1, 0);
else {
if (nc->leftalt)
- sp_nodepath_selected_nodes_scale_screen(nc->nodepath, 1, -1);
+ se->scale_nodes_screen (1, -1);
if (nc->rightalt)
- sp_nodepath_selected_nodes_scale_screen(nc->nodepath, 1, 1);
+ se->scale_nodes_screen (1, 1);
}
} else {
- sp_nodepath_selected_nodes_scale(nc->nodepath, offset, 0);
+ se->scale_nodes (offset, 0);
}
ret = TRUE;
break;