diff options
| author | MenTaLguY <mental@rydia.net> | 2006-01-16 02:36:01 +0000 |
|---|---|---|
| committer | mental <mental@users.sourceforge.net> | 2006-01-16 02:36:01 +0000 |
| commit | 179fa413b047bede6e32109e2ce82437c5fb8d34 (patch) | |
| tree | a5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/node-context.cpp | |
| download | inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip | |
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/node-context.cpp')
| -rw-r--r-- | src/node-context.cpp | 964 |
1 files changed, 964 insertions, 0 deletions
diff --git a/src/node-context.cpp b/src/node-context.cpp new file mode 100644 index 000000000..747fa65b3 --- /dev/null +++ b/src/node-context.cpp @@ -0,0 +1,964 @@ +#define __SP_NODE_CONTEXT_C__ + +/* + * Node editing context + * + * Authors: + * 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 + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include <gdk/gdkkeysyms.h> +#include "macros.h" +#include <glibmm/i18n.h> +#include "display/sp-canvas-util.h" +#include "object-edit.h" +#include "sp-path.h" +#include "path-chemistry.h" +#include "rubberband.h" +#include "desktop.h" +#include "desktop-handles.h" +#include "selection.h" +#include "pixmaps/cursor-node.xpm" +#include "message-context.h" +#include "node-context.h" +#include "pixmaps/cursor-node-d.xpm" +#include "prefs-utils.h" +#include "xml/node-event-vector.h" +#include "style.h" +#include "splivarot.h" + +static void sp_node_context_class_init(SPNodeContextClass *klass); +static void sp_node_context_init(SPNodeContext *node_context); +static void sp_node_context_dispose(GObject *object); + +static void sp_node_context_setup(SPEventContext *ec); +static gint sp_node_context_root_handler(SPEventContext *event_context, GdkEvent *event); +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; + +static gchar *undo_label_1 = "dragcurve:1"; +static gchar *undo_label_2 = "dragcurve:2"; +static gchar *undo_label = undo_label_1; + +GType +sp_node_context_get_type() +{ + static GType type = 0; + if (!type) { + GTypeInfo info = { + sizeof(SPNodeContextClass), + NULL, NULL, + (GClassInitFunc) sp_node_context_class_init, + NULL, NULL, + sizeof(SPNodeContext), + 4, + (GInstanceInitFunc) sp_node_context_init, + NULL, /* value_table */ + }; + type = g_type_register_static(SP_TYPE_EVENT_CONTEXT, "SPNodeContext", &info, (GTypeFlags)0); + } + return type; +} + +static void +sp_node_context_class_init(SPNodeContextClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + SPEventContextClass *event_context_class = (SPEventContextClass *) klass; + + parent_class = (SPEventContextClass*)g_type_class_peek_parent(klass); + + object_class->dispose = sp_node_context_dispose; + + event_context_class->setup = sp_node_context_setup; + event_context_class->root_handler = sp_node_context_root_handler; + event_context_class->item_handler = sp_node_context_item_handler; +} + +static void +sp_node_context_init(SPNodeContext *node_context) +{ + SPEventContext *event_context = SP_EVENT_CONTEXT(node_context); + + event_context->cursor_shape = cursor_node_xpm; + event_context->hot_x = 1; + event_context->hot_y = 1; + + node_context->leftalt = FALSE; + node_context->rightalt = FALSE; + node_context->leftctrl = FALSE; + node_context->rightctrl = FALSE; + + new (&node_context->sel_changed_connection) sigc::connection(); +} + +static void +sp_node_context_dispose(GObject *object) +{ + SPNodeContext *nc = SP_NODE_CONTEXT(object); + SPEventContext *ec = SP_EVENT_CONTEXT(object); + + ec->enableGrDrag(false); + + 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; + } + + if (nc->_node_message_context) { + delete nc->_node_message_context; + } + + G_OBJECT_CLASS(parent_class)->dispose(object); +} + +static void +sp_node_context_setup(SPEventContext *ec) +{ + SPNodeContext *nc = SP_NODE_CONTEXT(ec); + + if (((SPEventContextClass *) parent_class)->setup) + ((SPEventContextClass *) parent_class)->setup(ec); + + 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)); + + Inkscape::Selection *selection = SP_DT_SELECTION(ec->desktop); + SPItem *item = selection->singleItem(); + + nc->nodepath = NULL; + ec->shape_knot_holder = NULL; + + nc->rb_escaped = false; + + nc->cursor_drag = false; + + nc->added_node = false; + + 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); + sp_repr_synthesize_events(repr, &nodepath_repr_events, ec); + } + } + } + + if (prefs_get_int_attribute("tools.nodes", "selcue", 0) != 0) { + ec->enableSelectionCue(); + } + + if (prefs_get_int_attribute("tools.nodes", "gradientdrag", 0) != 0) { + 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); + + Inkscape::XML::Node *old_repr = NULL; + + if (nc->nodepath) { + old_repr = nc->nodepath->repr; + sp_nodepath_destroy(nc->nodepath); + } + 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(); + + 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_repr_synthesize_events(repr, &nodepath_repr_events, ec); + } + } + } + sp_nodepath_update_statusbar(nc->nodepath); +} + +/** +\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); + } + + if (ec->shape_knot_holder) { + sp_knot_holder_destroy(ec->shape_knot_holder); + } + + Inkscape::Selection *selection = SP_DT_SELECTION(desktop); + item = selection->singleItem(); + + 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); + } + 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 +*/ +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) +{ + SPItem *item = NULL; + char const *newd = NULL, *newtypestr = 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")) { + newd = new_value; + changed = nodepath_repr_d_changed(np, new_value); + } else if (!strcmp(name, "sodipodi:nodetypes")) { + newtypestr = new_value; + changed = nodepath_repr_typestr_changed(np, new_value); + } else { + return; + // With paths, we only need to act if one of the path-affecting attributes has changed. + } + } 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); + + 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); +} + +void +sp_node_context_show_modifier_tip(SPEventContext *event_context, GdkEvent *event) +{ + sp_event_show_modifier_tip + (event_context->defaultMessageContext(), event, + _("<b>Ctrl</b>: toggle node type, snap handle angle, move hor/vert; <b>Ctrl+Alt</b>: move along handles"), + _("<b>Shift</b>: toggle node selection, disable snapping, rotate both handles"), + _("<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(item, nc->curvepoint_doc); + NR::Point nearest = get_point_on_Path(item, 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; + + 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(item_over, 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(item_over, nc->curvepoint_doc, true); + } else { + sp_nodepath_select_segment_near_point(item_over, nc->curvepoint_doc, false); + } + } + break; + case GDK_2BUTTON_PRESS: + //add a node + sp_nodepath_add_node_near_point(item_over, 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; + } + 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(item_over, nc->curvepoint_doc, false); + ret = TRUE; + } else { + break; + } + } else { + break; + } + + ret = TRUE; + } + break; + } + break; + default: + break; + } + + if (!ret) { + if (((SPEventContextClass *) parent_class)->item_handler) + ret = ((SPEventContextClass *) parent_class)->item_handler(event_context, item, event); + } + + return ret; +} + +static gint +sp_node_context_root_handler(SPEventContext *event_context, GdkEvent *event) +{ + SPDesktop *desktop = event_context->desktop; + Inkscape::Selection *selection = SP_DT_SELECTION (desktop); + + 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); + + gint ret = FALSE; + + switch (event->type) { + case GDK_BUTTON_PRESS: + if (event->button.button == 1) { + // 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; + + NR::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); + ret = TRUE; + } + break; + case GDK_MOTION_NOTIFY: + if (event->motion.state & GDK_BUTTON1_MASK) { + + 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 + } + // 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, undo_label); + 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); + } + nc->drag = TRUE; + ret = TRUE; + } else { + if (!nc->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); + } + + if (nc->cursor_drag && !over_stroke) { + event_context->cursor_shape = cursor_node_xpm; + event_context->hot_x = 1; + event_context->hot_y = 1; + sp_event_context_update_cursor(event_context); + nc->cursor_drag = false; + } else if (!nc->cursor_drag && over_stroke) { + event_context->cursor_shape = cursor_node_d_xpm; + event_context->hot_x = 1; + event_context->hot_y = 1; + sp_event_context_update_cursor(event_context); + nc->cursor_drag = true; + } + } + break; + case GDK_BUTTON_RELEASE: + event_context->xp = event_context->yp = 0; + if (event->button.button == 1) { + + NR::Maybe<NR::Rect> b = Inkscape::Rubberband::get()->getRectangle(); + + if (nc->hit && !event_context->within_tolerance) { //drag curve + if (undo_label == undo_label_1) + undo_label = undo_label_2; + else + undo_label = undo_label_1; + } 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); + } + } 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; + Inkscape::Rubberband::get()->stop(); + nc->rb_escaped = false; + nc->drag = FALSE; + nc->hit = false; + break; + } + break; + case GDK_KEY_PRESS: + switch (get_group0_keyval(&event->key)) { + case GDK_Insert: + case GDK_KP_Insert: + // with any modifiers + sp_node_selected_add_node(); + ret = TRUE; + break; + case GDK_Delete: + case GDK_KP_Delete: + case GDK_BackSpace: + // with any modifiers + sp_node_selected_delete(); + ret = TRUE; + break; + case GDK_C: + case GDK_c: + if (MOD__SHIFT_ONLY) { + sp_node_selected_set_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); + ret = TRUE; + } + break; + case GDK_Y: + case GDK_y: + if (MOD__SHIFT_ONLY) { + sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM); + ret = TRUE; + } + break; + case GDK_B: + case GDK_b: + if (MOD__SHIFT_ONLY) { + sp_node_selected_break(); + ret = TRUE; + } + break; + case GDK_J: + case GDK_j: + if (MOD__SHIFT_ONLY) { + sp_node_selected_join(); + ret = TRUE; + } + break; + case GDK_D: + case GDK_d: + if (MOD__SHIFT_ONLY) { + sp_node_selected_duplicate(); + ret = TRUE; + } + break; + case GDK_L: + case GDK_l: + if (MOD__SHIFT_ONLY) { + sp_node_selected_set_line_type(NR_LINETO); + ret = TRUE; + } + break; + case GDK_U: + case GDK_u: + if (MOD__SHIFT_ONLY) { + sp_node_selected_set_line_type(NR_CURVETO); + ret = TRUE; + } + break; + case GDK_R: + case GDK_r: + if (MOD__SHIFT_ONLY) { + // FIXME: add top panel button + sp_selected_path_reverse(); + ret = TRUE; + } + break; + case GDK_Left: // move selection left + case GDK_KP_Left: + case GDK_KP_4: + if (!MOD__CTRL) { // not ctrl + 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 + } + else { // no alt + if (MOD__SHIFT) sp_node_selected_move(-10*nudge, 0); // shift + else sp_node_selected_move(-nudge, 0); // no shift + } + ret = TRUE; + } + break; + case GDK_Up: // move selection up + case GDK_KP_Up: + case GDK_KP_8: + if (!MOD__CTRL) { // not ctrl + 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 + } + else { // no alt + if (MOD__SHIFT) sp_node_selected_move(0, 10*nudge); // shift + else sp_node_selected_move(0, nudge); // no shift + } + ret = TRUE; + } + break; + case GDK_Right: // move selection right + case GDK_KP_Right: + case GDK_KP_6: + if (!MOD__CTRL) { // not ctrl + 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 + } + else { // no alt + if (MOD__SHIFT) sp_node_selected_move(10*nudge, 0); // shift + else sp_node_selected_move(nudge, 0); // no shift + } + ret = TRUE; + } + break; + case GDK_Down: // move selection down + case GDK_KP_Down: + case GDK_KP_2: + if (!MOD__CTRL) { // not ctrl + 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 + } + else { // no alt + if (MOD__SHIFT) sp_node_selected_move(0, -10*nudge); // shift + else sp_node_selected_move(0, -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(); + nc->rb_escaped = true; + } else { + if (nc->nodepath && nc->nodepath->selected) { + sp_nodepath_deselect(nc->nodepath); + } else { + SP_DT_SELECTION(desktop)->clear(); + } + } + ret = TRUE; + break; + } + + 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); + if (nc->rightctrl) + sp_nodepath_selected_nodes_rotate (nc->nodepath, 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); + else { + if (nc->leftalt) + sp_nodepath_selected_nodes_rotate (nc->nodepath, 1, -1, true); + if (nc->rightalt) + sp_nodepath_selected_nodes_rotate (nc->nodepath, 1, 1, true); + } + } else if ( snaps != 0 ) { + sp_nodepath_selected_nodes_rotate (nc->nodepath, 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); + if (nc->rightctrl) + sp_nodepath_selected_nodes_rotate (nc->nodepath, -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); + else { + if (nc->leftalt) + sp_nodepath_selected_nodes_rotate (nc->nodepath, -1, -1, true); + if (nc->rightalt) + sp_nodepath_selected_nodes_rotate (nc->nodepath, -1, 1, true); + } + } else if ( snaps != 0 ) { + sp_nodepath_selected_nodes_rotate (nc->nodepath, -M_PI/snaps, 0, false); + } + ret = TRUE; + break; + case GDK_less: + case GDK_comma: + if (MOD__CTRL) { + if (nc->leftctrl) + sp_nodepath_selected_nodes_scale(nc->nodepath, -offset, -1); + if (nc->rightctrl) + sp_nodepath_selected_nodes_scale(nc->nodepath, -offset, 1); + } else if (MOD__ALT) { + if (nc->leftalt && nc->rightalt) + sp_nodepath_selected_nodes_scale_screen(nc->nodepath, -1, 0); + else { + if (nc->leftalt) + sp_nodepath_selected_nodes_scale_screen(nc->nodepath, -1, -1); + if (nc->rightalt) + sp_nodepath_selected_nodes_scale_screen(nc->nodepath, -1, 1); + } + } else { + sp_nodepath_selected_nodes_scale(nc->nodepath, -offset, 0); + } + ret = TRUE; + break; + case GDK_greater: + case GDK_period: + if (MOD__CTRL) { + if (nc->leftctrl) + sp_nodepath_selected_nodes_scale(nc->nodepath, offset, -1); + if (nc->rightctrl) + sp_nodepath_selected_nodes_scale(nc->nodepath, offset, 1); + } else if (MOD__ALT) { + if (nc->leftalt && nc->rightalt) + sp_nodepath_selected_nodes_scale_screen(nc->nodepath, 1, 0); + else { + if (nc->leftalt) + sp_nodepath_selected_nodes_scale_screen(nc->nodepath, 1, -1); + if (nc->rightalt) + sp_nodepath_selected_nodes_scale_screen(nc->nodepath, 1, 1); + } + } else { + sp_nodepath_selected_nodes_scale(nc->nodepath, offset, 0); + } + ret = TRUE; + break; + + case GDK_Alt_L: + nc->leftalt = TRUE; + sp_node_context_show_modifier_tip(event_context, event); + break; + case GDK_Alt_R: + nc->rightalt = TRUE; + sp_node_context_show_modifier_tip(event_context, event); + break; + case GDK_Control_L: + nc->leftctrl = TRUE; + sp_node_context_show_modifier_tip(event_context, event); + break; + case GDK_Control_R: + nc->rightctrl = TRUE; + sp_node_context_show_modifier_tip(event_context, event); + break; + case GDK_Shift_L: + case GDK_Shift_R: + case GDK_Meta_L: + case GDK_Meta_R: + sp_node_context_show_modifier_tip(event_context, event); + break; + default: + ret = node_key(event); + break; + } + break; + case GDK_KEY_RELEASE: + switch (get_group0_keyval(&event->key)) { + case GDK_Alt_L: + nc->leftalt = FALSE; + event_context->defaultMessageContext()->clear(); + break; + case GDK_Alt_R: + nc->rightalt = FALSE; + event_context->defaultMessageContext()->clear(); + break; + case GDK_Control_L: + nc->leftctrl = FALSE; + event_context->defaultMessageContext()->clear(); + break; + case GDK_Control_R: + nc->rightctrl = FALSE; + event_context->defaultMessageContext()->clear(); + break; + case GDK_Shift_L: + case GDK_Shift_R: + case GDK_Meta_L: + case GDK_Meta_R: + event_context->defaultMessageContext()->clear(); + break; + } + break; + default: + break; + } + + if (!ret) { + if (((SPEventContextClass *) parent_class)->root_handler) + ret = ((SPEventContextClass *) parent_class)->root_handler(event_context, event); + } + + return ret; +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : |
