summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 285b96e)
raw | patch | inline | side by side (parent: 285b96e)
author | Krzysztof Kosiński <tweenk.pl@gmail.com> | |
Sun, 10 Jan 2010 00:46:28 +0000 (01:46 +0100) | ||
committer | Krzysztof Kosiński <tweenk.pl@gmail.com> | |
Sun, 10 Jan 2010 00:46:28 +0000 (01:46 +0100) |
* Fix minor bug in linear grow.
* Add --fixes.
* Move some node selection-related functions to ControlPointSelection.
* Add --fixes.
* Move some node selection-related functions to ControlPointSelection.
21 files changed:
diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp
index 981c9f044717747981ad3c7a85a3d42d5495c7cc..88c7a99b9df9af99c8d1e3112cfb8e03c7825700 100644 (file)
--- a/src/2geom/path.cpp
+++ b/src/2geom/path.cpp
{
//return a single nearest point for each curve in this path
std::vector<double> np;
- const Path& _path = *this;
- for (Sequence::const_iterator it = _path.get_curves().begin() ; it != _path.get_curves().end()-1 ; ++it)
+ for (const_iterator it = begin() ; it != end_default(); ++it)
//for (std::vector<Path>::const_iterator it = _path.begin(); it != _path.end(), ++it){
{
- np.push_back((*it)->nearestPoint(_point));
+ np.push_back(it->nearestPoint(_point));
}
return np;
}
diff --git a/src/event-context.cpp b/src/event-context.cpp
index ec0169573db6a8aa81d13ae9168ae7753d9eade4..13e7e941054f348bcdfdb777fc5e8ee110b45a7a 100644 (file)
--- a/src/event-context.cpp
+++ b/src/event-context.cpp
#include "rubberband.h"
#include "selcue.h"
#include "lpe-tool-context.h"
+#include "ui/tool/control-point.h"
static void sp_event_context_class_init(SPEventContextClass *klass);
static void sp_event_context_init(SPEventContext *event_context);
@@ -1238,6 +1239,7 @@ void sp_event_context_snap_delay_handler(SPEventContext *ec, SPItem* const item,
gboolean sp_event_context_snap_watchdog_callback(gpointer data)
{
+ if (!data) return FALSE;
// Snap NOW! For this the "postponed" flag will be reset and the last motion event will be repeated
DelayedSnapEvent *dse = reinterpret_cast<DelayedSnapEvent*>(data);
}
}
break;
+ case DelayedSnapEvent::CONTROL_POINT_HANDLER: {
+ using Inkscape::UI::ControlPoint;
+ ControlPoint *point = reinterpret_cast<ControlPoint*>(dse->getKnot());
+ point->_eventHandler(dse->getEvent());
+ } break;
default:
g_warning("Origin of snap-delay event has not been defined!;");
break;
diff --git a/src/event-context.h b/src/event-context.h
index 5285bdb877938362f21e4c628ebd1184fdf5b83a..5be2e19fb4a2163eafb87c51ff51ff66bd85f086 100644 (file)
--- a/src/event-context.h
+++ b/src/event-context.h
UNDEFINED_HANDLER = 0,
EVENTCONTEXT_ROOT_HANDLER,
EVENTCONTEXT_ITEM_HANDLER,
- KNOT_HANDLER
+ KNOT_HANDLER,
+ CONTROL_POINT_HANDLER
};
DelayedSnapEvent(SPEventContext *event_context, SPItem* const item, SPKnot* knot, GdkEventMotion const *event, DelayedSnapEvent::DelayedSnapEventOrigin const origin)
diff --git a/src/node-context.cpp b/src/node-context.cpp
--- a/src/node-context.cpp
+++ /dev/null
@@ -1,868 +0,0 @@
-#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
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-#include <cstring>
-#include <string>
-#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 "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 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 SPEventContextClass *parent_class;
-
-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();
-
- 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);
- 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();
-
- delete ec->shape_editor;
-
- 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);
-
- Inkscape::Selection *selection = sp_desktop_selection (ec->desktop);
- nc->sel_changed_connection.disconnect();
- nc->sel_changed_connection =
- selection->connectChanged(sigc::bind(sigc::ptr_fun(&sp_node_context_selection_changed), (gpointer)nc));
-
- SPItem *item = selection->singleItem();
-
- ec->shape_editor = new ShapeEditor(ec->desktop);
-
- nc->rb_escaped = false;
-
- nc->cursor_drag = false;
-
- nc->added_node = false;
-
- nc->current_state = SP_NODE_CONTEXT_INACTIVE;
-
- if (item) {
- ec->shape_editor->set_item(item, SH_NODEPATH);
- ec->shape_editor->set_item(item, SH_KNOTHOLDER);
- }
-
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- if (prefs->getBool("/tools/nodes/selcue")) {
- ec->enableSelectionCue();
- }
- if (prefs->getBool("/tools/nodes/gradientdrag")) {
- ec->enableGrDrag();
- }
-
- ec->desktop->emitToolSubselectionChanged(NULL); // sets the coord entry fields to inactive
-
- nc->_node_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack());
-
- ec->shape_editor->update_statusbar();
-}
-
-static void
-sp_node_context_flash_path(SPEventContext *event_context, SPItem *item, guint timeout) {
- SPNodeContext *nc = SP_NODE_CONTEXT(event_context);
-
- 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;
- }
-
- SPCanvasItem *canvasitem = sp_nodepath_generate_helperpath(desktop, item);
-
- if (canvasitem) {
- nc->flash_tempitem = desktop->add_temporary_canvasitem (canvasitem, timeout);
- }
- }
-}
-
-/**
-\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)
-{
- SPEventContext *ec = SP_EVENT_CONTEXT(data);
-
- // 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
-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"));
-}
-
-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;
-
- switch (event->type) {
- 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;
-
-
- 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;
- }
- }
- 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;
-
- default:
- break;
- }
-
- 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;
- 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->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 && !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;
- se->cancel_hit();
-
- 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);
- 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 && !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;
-
- // 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 (!se->has_nodepath() || selection->singleItem() == NULL) {
- break;
- }
-
- bool over_stroke = 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;
- 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_2BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- 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;
-
- bool over_stroke = false;
- if (se->has_nodepath()) {
- over_stroke = se->is_over_stroke(Geom::Point(event->button.x, event->button.y), false);
- }
-
- 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;
- }
- 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;
- }
- }
- break;
- case GDK_KEY_PRESS:
- switch (get_group0_keyval(&event->key)) {
- case GDK_Insert:
- case GDK_KP_Insert:
- // with any modifiers
- 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:
- 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) {
- se->set_node_type(Inkscape::NodePath::NODE_CUSP);
- ret = TRUE;
- }
- break;
- case GDK_S:
- case GDK_s:
- if (MOD__SHIFT_ONLY) {
- 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) {
- se->set_node_type(Inkscape::NodePath::NODE_SYMM);
- ret = TRUE;
- }
- break;
- case GDK_B:
- case GDK_b:
- if (MOD__SHIFT_ONLY) {
- se->break_at_nodes();
- ret = TRUE;
- }
- break;
- case GDK_J:
- case GDK_j:
- if (MOD__SHIFT_ONLY) {
- se->join_nodes();
- ret = TRUE;
- }
- break;
- case GDK_D:
- case GDK_d:
- if (MOD__SHIFT_ONLY) {
- se->duplicate_nodes();
- ret = TRUE;
- }
- break;
- case GDK_L:
- case GDK_l:
- if (MOD__SHIFT_ONLY) {
- se->set_type_of_segments(NR_LINETO);
- ret = TRUE;
- }
- break;
- case GDK_U:
- case GDK_u:
- if (MOD__SHIFT_ONLY) {
- se->set_type_of_segments(NR_CURVETO);
- ret = TRUE;
- }
- break;
- case GDK_R:
- case GDK_r:
- if (MOD__SHIFT_ONLY) {
- // FIXME: add top panel button
- 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_Left: // move selection left
- 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) 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) se->move_nodes(mul*-10*nudge, 0); // shift
- else se->move_nodes(mul*-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
- gint mul = 1 + gobble_key_events(
- get_group0_keyval(&event->key), 0); // with any mask
- if (MOD__ALT) { // alt
- 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) se->move_nodes(0, mul*10*nudge); // shift
- else se->move_nodes(0, mul*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
- gint mul = 1 + gobble_key_events(
- get_group0_keyval(&event->key), 0); // with any mask
- if (MOD__ALT) { // alt
- 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) se->move_nodes(mul*10*nudge, 0); // shift
- else se->move_nodes(mul*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
- gint mul = 1 + gobble_key_events(
- get_group0_keyval(&event->key), 0); // with any mask
- if (MOD__ALT) { // alt
- 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) se->move_nodes(0, mul*-10*nudge); // shift
- else se->move_nodes(0, mul*-nudge); // no shift
- }
- ret = TRUE;
- }
- break;
- case GDK_Escape:
- {
- 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 (se->has_selection()) {
- se->deselect();
- } else {
- sp_desktop_selection(desktop)->clear();
- }
- }
- ret = TRUE;
- break;
- }
-
- case GDK_bracketleft:
- if ( MOD__CTRL && !MOD__ALT && ( snaps != 0 ) ) {
- if (nc->leftctrl)
- se->rotate_nodes (M_PI/snaps, -1, false);
- if (nc->rightctrl)
- se->rotate_nodes (M_PI/snaps, 1, false);
- } else if ( MOD__ALT && !MOD__CTRL ) {
- if (nc->leftalt && nc->rightalt)
- se->rotate_nodes (1, 0, true);
- else {
- if (nc->leftalt)
- se->rotate_nodes (1, -1, true);
- if (nc->rightalt)
- se->rotate_nodes (1, 1, true);
- }
- } else if ( snaps != 0 ) {
- se->rotate_nodes (M_PI/snaps, 0, false);
- }
- ret = TRUE;
- break;
- case GDK_bracketright:
- if ( MOD__CTRL && !MOD__ALT && ( snaps != 0 ) ) {
- if (nc->leftctrl)
- se->rotate_nodes (-M_PI/snaps, -1, false);
- if (nc->rightctrl)
- se->rotate_nodes (-M_PI/snaps, 1, false);
- } else if ( MOD__ALT && !MOD__CTRL ) {
- if (nc->leftalt && nc->rightalt)
- se->rotate_nodes (-1, 0, true);
- else {
- if (nc->leftalt)
- se->rotate_nodes (-1, -1, true);
- if (nc->rightalt)
- se->rotate_nodes (-1, 1, true);
- }
- } else if ( snaps != 0 ) {
- se->rotate_nodes (-M_PI/snaps, 0, false);
- }
- ret = TRUE;
- break;
- case GDK_less:
- case GDK_comma:
- if (MOD__CTRL) {
- if (nc->leftctrl)
- se->scale_nodes(-offset, -1);
- if (nc->rightctrl)
- se->scale_nodes(-offset, 1);
- } else if (MOD__ALT) {
- if (nc->leftalt && nc->rightalt)
- se->scale_nodes_screen (-1, 0);
- else {
- if (nc->leftalt)
- se->scale_nodes_screen (-1, -1);
- if (nc->rightalt)
- se->scale_nodes_screen (-1, 1);
- }
- } else {
- se->scale_nodes (-offset, 0);
- }
- ret = TRUE;
- break;
- case GDK_greater:
- case GDK_period:
- if (MOD__CTRL) {
- if (nc->leftctrl)
- se->scale_nodes (offset, -1);
- if (nc->rightctrl)
- se->scale_nodes (offset, 1);
- } else if (MOD__ALT) {
- if (nc->leftalt && nc->rightalt)
- se->scale_nodes_screen (1, 0);
- else {
- if (nc->leftalt)
- se->scale_nodes_screen (1, -1);
- if (nc->rightalt)
- se->scale_nodes_screen (1, 1);
- }
- } else {
- se->scale_nodes (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 :
diff --git a/src/node-context.h b/src/node-context.h
--- a/src/node-context.h
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef __SP_NODE_CONTEXT_H__
-#define __SP_NODE_CONTEXT_H__
-
-/*
- * Node editing context
- *
- * Authors:
- * Lauris Kaplinski <lauris@kaplinski.com>
- * bulia byak <buliabyak@users.sf.net>
- *
- * This code is in public domain
- */
-
-#include <gtk/gtktypeutils.h>
-#include <sigc++/sigc++.h>
-#include "event-context.h"
-#include "forward.h"
-#include "display/display-forward.h"
-#include "nodepath.h"
-namespace Inkscape { class Selection; }
-
-#define SP_TYPE_NODE_CONTEXT (sp_node_context_get_type ())
-#define SP_NODE_CONTEXT(obj) (GTK_CHECK_CAST ((obj), SP_TYPE_NODE_CONTEXT, SPNodeContext))
-#define SP_NODE_CONTEXT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), SP_TYPE_NODE_CONTEXT, SPNodeContextClass))
-#define SP_IS_NODE_CONTEXT(obj) (GTK_CHECK_TYPE ((obj), SP_TYPE_NODE_CONTEXT))
-#define SP_IS_NODE_CONTEXT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), SP_TYPE_NODE_CONTEXT))
-
-enum { SP_NODE_CONTEXT_INACTIVE,
- SP_NODE_CONTEXT_NODE_DRAGGING,
- SP_NODE_CONTEXT_RUBBERBAND_DRAGGING };
-
-class SPNodeContext;
-class SPNodeContextClass;
-
-struct SPNodeContext {
- // FIXME: shouldn't this be a pointer???
- SPEventContext event_context;
-
- guint drag : 1;
-
- gboolean leftalt;
- gboolean rightalt;
- gboolean leftctrl;
- gboolean rightctrl;
-
- /// If true, rubberband was cancelled by esc, so the next button release should not deselect.
- bool rb_escaped;
-
- sigc::connection sel_changed_connection;
-
- Inkscape::MessageContext *_node_message_context;
-
- bool cursor_drag;
-
- bool added_node;
-
- unsigned int current_state;
-
- SPItem * flashed_item;
- SPCanvasItem *grabbed;
- Inkscape::Display::TemporaryItem * flash_tempitem;
- int remove_flash_counter;
-};
-
-struct SPNodeContextClass {
- SPEventContextClass parent_class;
-};
-
-/* Standard Gtk function */
-
-GtkType sp_node_context_get_type (void);
-
-void sp_node_context_selection_changed (Inkscape::Selection * selection, gpointer data);
-void sp_node_context_selection_modified (Inkscape::Selection * selection, guint flags, gpointer data);
-
-#endif
-
-/*
- 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 :
diff --git a/src/snap.cpp b/src/snap.cpp
index 545607889c48e13f21da41c2e05150b2028be135..558f61814b169b7fae26a9656bc9cea6366c78d3 100644 (file)
--- a/src/snap.cpp
+++ b/src/snap.cpp
#include "inkscape.h"
#include "desktop.h"
+#include "selection.h"
#include "sp-guide.h"
#include "preferences.h"
#include "event-context.h"
@@ -206,29 +207,15 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapPreferences::PointTyp
bool first_point,
Geom::OptRect const &bbox_to_snap) const
{
- if (!someSnapperMightSnap()) {
+ if (!someSnapperMightSnap()) {
return Inkscape::SnappedPoint(p, source_type, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false);
}
- std::vector<SPItem const *> *items_to_ignore;
- if (_item_to_ignore) { // If we have only a single item to ignore
- // then build a list containing this single item;
- // This single-item list will prevail over any other _items_to_ignore list, should that exist
- items_to_ignore = new std::vector<SPItem const *>;
- items_to_ignore->push_back(_item_to_ignore);
- } else {
- items_to_ignore = _items_to_ignore;
- }
-
SnappedConstraints sc;
SnapperList const snappers = getSnappers();
for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
- (*i)->freeSnap(sc, point_type, p, source_type, first_point, bbox_to_snap, items_to_ignore, _unselected_nodes);
- }
-
- if (_item_to_ignore) {
- delete items_to_ignore;
+ (*i)->freeSnap(sc, point_type, p, source_type, first_point, bbox_to_snap, &_items_to_ignore, _unselected_nodes);
}
return findBestSnap(p, source_type, sc, false);
@@ -368,17 +355,6 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::SnapPreferences::P
return Inkscape::SnappedPoint(p, source_type, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false);
}
- std::vector<SPItem const *> *items_to_ignore;
- if (_item_to_ignore) { // If we have only a single item to ignore
- // then build a list containing this single item;
- // This single-item list will prevail over any other _items_to_ignore list, should that exist
- items_to_ignore = new std::vector<SPItem const *>;
- items_to_ignore->push_back(_item_to_ignore);
- } else {
- items_to_ignore = _items_to_ignore;
- }
-
-
// First project the mouse pointer onto the constraint
Geom::Point pp = constraint.projection(p);
// Then try to snap the projected point
@@ -386,11 +362,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::SnapPreferences::P
SnappedConstraints sc;
SnapperList const snappers = getSnappers();
for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
- (*i)->constrainedSnap(sc, point_type, pp, source_type, first_point, bbox_to_snap, constraint, items_to_ignore);
- }
-
- if (_item_to_ignore) {
- delete items_to_ignore;
+ (*i)->constrainedSnap(sc, point_type, pp, source_type, first_point, bbox_to_snap, constraint, &_items_to_ignore);
}
return findBestSnap(pp, source_type, sc, true);
return bestSnappedPoint;
}
-/**
- * \brief Prepare the snap manager for the actual snapping, which includes building a list of snap targets
- * to ignore and toggling the snap indicator
- *
- * There are two overloaded setup() methods, of which this one only allows for a single item to be ignored
- * whereas the other one will take a list of items to ignore
- *
- * \param desktop Reference to the desktop to which this snap manager is attached
- * \param snapindicator If true then a snap indicator will be displayed automatically (when enabled in the preferences)
- * \param item_to_ignore This item will not be snapped to, e.g. the item that is currently being dragged. This avoids "self-snapping"
- * \param unselected_nodes Stationary nodes of the path that is currently being edited in the node tool and
- * that can be snapped too. Nodes not in this list will not be snapped to, to avoid "self-snapping". Of each
- * unselected node both the position (Geom::Point) and the type (Inkscape::SnapTargetType) will be stored
- * \param guide_to_ignore Guide that is currently being dragged and should not be snapped to
- */
-
+/// Convenience shortcut when there is only one item to ignore
void SnapManager::setup(SPDesktop const *desktop,
bool snapindicator,
SPItem const *item_to_ignore,
SPGuide *guide_to_ignore)
{
g_assert(desktop != NULL);
- _item_to_ignore = item_to_ignore;
- _items_to_ignore = NULL;
+ _items_to_ignore.clear();
+ _items_to_ignore.push_back(item_to_ignore);
_desktop = desktop;
_snapindicator = snapindicator;
_unselected_nodes = unselected_nodes;
void SnapManager::setup(SPDesktop const *desktop,
bool snapindicator,
- std::vector<SPItem const *> &items_to_ignore,
+ std::vector<SPItem const *> const &items_to_ignore,
std::vector<std::pair<Geom::Point, int> > *unselected_nodes,
SPGuide *guide_to_ignore)
{
g_assert(desktop != NULL);
- _item_to_ignore = NULL;
- _items_to_ignore = &items_to_ignore;
+ _items_to_ignore = items_to_ignore;
+ _desktop = desktop;
+ _snapindicator = snapindicator;
+ _unselected_nodes = unselected_nodes;
+ _guide_to_ignore = guide_to_ignore;
+}
+
+/// Setup, taking the list of items to ignore from the desktop's selection.
+void SnapManager::setupIgnoreSelection(SPDesktop const *desktop,
+ bool snapindicator,
+ std::vector<std::pair<Geom::Point, int> > *unselected_nodes,
+ SPGuide *guide_to_ignore)
+{
_desktop = desktop;
_snapindicator = snapindicator;
_unselected_nodes = unselected_nodes;
_guide_to_ignore = guide_to_ignore;
+ _items_to_ignore.clear();
+
+ Inkscape::Selection *sel = _desktop->selection;
+ GSList const *items = sel->itemList();
+ for (GSList *i = const_cast<GSList*>(items); i; i = i->next) {
+ _items_to_ignore.push_back(static_cast<SPItem const *>(i->data));
+ }
}
SPDocument *SnapManager::getDocument() const
diff --git a/src/snap.h b/src/snap.h
index e621bdb605334cb1b1e0fa4619368d2c09ca69f4..5696dcd536a3fe3cac2441c04bcd92ec42174c11 100644 (file)
--- a/src/snap.h
+++ b/src/snap.h
-#ifndef SEEN_SNAP_H
-#define SEEN_SNAP_H
-
/**
* \file snap.h
- * \brief SnapManager class.
- *
- * The SnapManager class handles most (if not all) of the interfacing of the snapping mechanisms with the
- * other parts of the code base. It stores the references to the various types of snappers for grid, guides
- * and objects, and it stores most of the snapping preferences. Besides that it provides methods to setup
- * the snapping environment (e.g. keeps a list of the items to ignore when looking for snap target candidates,
- * and toggling of the snap indicator), and it provides many different methods for the snapping itself (free
- * snapping vs. constrained snapping, returning the result by reference or through a return statement, etc.)
- *
+ * \brief Per-desktop object that handles snapping queries
+ *//*
* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* Frank Felfe <innerspace@iname.com>
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <vector>
+#ifndef SEEN_SNAP_H
+#define SEEN_SNAP_H
+#include <vector>
#include "guide-snapper.h"
#include "object-snapper.h"
#include "snap-preferences.h"
class SPNamedView;
/// Class to coordinate snapping operations
-
/**
- * Each SPNamedView has one of these. It offers methods to snap points to whatever
- * snappers are defined (e.g. grid, guides etc.). It also allows callers to snap
- * points which have undergone some transformation (e.g. translation, scaling etc.)
+ * The SnapManager class handles most (if not all) of the interfacing of the snapping mechanisms
+ * with the other parts of the code base. It stores the references to the various types of snappers
+ * for grid, guides and objects, and it stores most of the snapping preferences. Besides that
+ * it provides methods to setup the snapping environment (e.g. keeps a list of the items to ignore
+ * when looking for snap target candidates, and toggling of the snap indicator), and it provides
+ * many different methods for snapping queries (free snapping vs. constrained snapping,
+ * returning the result by reference or through a return statement, etc.)
+ *
+ * Each SPNamedView has one of these. It offers methods to snap points to whatever
+ * snappers are defined (e.g. grid, guides etc.). It also allows callers to snap
+ * points which have undergone some transformation (e.g. translation, scaling etc.)
+ *
+ * \par How snapping is implemented in Inkscape
+ * \par
+ * The snapping system consists of two key elements. The first one is the snap manager
+ * (this class), which keeps some data about objects in the document and answers queries
+ * of the type "given this point and type of transformation, what is the best place
+ * to snap to?".
+ *
+ * The second is in event-context.cpp and implements the snapping timeout. Whenever a motion
+ * events happens over the canvas, it stores it for later use and initiates a timeout.
+ * This timeout is discarded whenever a new motion event occurs. When the timeout expires,
+ * a global flag in SnapManager, accessed via getSnapPostponedGlobally(), is set to true
+ * and the stored event is replayed, but this time with snapping enabled. This way you can
+ * write snapping code directly in your control point's dragged handler as if there was
+ * no timeout.
*/
class SnapManager
void setup(SPDesktop const *desktop,
bool snapindicator,
- std::vector<SPItem const *> &items_to_ignore,
+ std::vector<SPItem const *> const &items_to_ignore,
std::vector<std::pair<Geom::Point, int> > *unselected_nodes = NULL,
SPGuide *guide_to_ignore = NULL);
+ void setupIgnoreSelection(SPDesktop const *desktop,
+ bool snapindicator = true,
+ std::vector<std::pair<Geom::Point, int> > *unselected_nodes = NULL,
+ SPGuide *guide_to_ignore = NULL);
// freeSnapReturnByRef() is preferred over freeSnap(), because it only returns a
// point if snapping has occurred (by overwriting p); otherwise p is untouched
SPNamedView const *_named_view;
private:
- std::vector<SPItem const *> *_items_to_ignore; ///< Items that should not be snapped to, for example the items that are currently being dragged. Set using the setup() method
- SPItem const *_item_to_ignore; ///< Single item that should not be snapped to. If not NULL then this takes precedence over _items_to_ignore. Set using the setup() method
+ std::vector<SPItem const *> _items_to_ignore; ///< Items that should not be snapped to, for example the items that are currently being dragged. Set using the setup() method
SPGuide *_guide_to_ignore; ///< A guide that should not be snapped to, e.g. the guide that is currently being dragged
SPDesktop const *_desktop;
bool _snapindicator; ///< When true, an indicator will be drawn at the position that was being snapped to
diff --git a/src/snapper.h b/src/snapper.h
index 110b3d36ad5292fa721e1db7e55b76af01c5ce19..1801f309c807790fc701a77f55925080ff90489f 100644 (file)
--- a/src/snapper.h
+++ b/src/snapper.h
public:
ConstraintLine(Geom::Point const &d) : _has_point(false), _direction(d) {}
ConstraintLine(Geom::Point const &p, Geom::Point const &d) : _has_point(true), _point(p), _direction(d) {}
+ ConstraintLine(Geom::Line const &l) : _has_point(true), _point(l.origin()), _direction(l.versor()) {}
bool hasPoint() const {
return _has_point;
index d10045c623598dffffaf1ae545837c2aeed5fc0f..5a84592b69113dbf0a47ea055fa206de877996dc 100644 (file)
erase(i++);
}
-/** Transform all selected control points by the supplied affine transformation. */
+/** Select all points that this selection can contain. */
+void ControlPointSelection::selectAll()
+{
+ for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
+ insert(*i);
+ }
+}
+/** Select all points inside the given rectangle (in desktop coordinates). */
+void ControlPointSelection::selectArea(Geom::Rect const &r)
+{
+ for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
+ if (r.contains(**i))
+ insert(*i);
+ }
+}
+/** Unselect all selected points and select all unselected points. */
+void ControlPointSelection::invertSelection()
+{
+ for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
+ if ((*i)->selected()) erase(*i);
+ else insert(*i);
+ }
+}
+void ControlPointSelection::spatialGrow(SelectableControlPoint *origin, int dir)
+{
+ bool grow = (dir > 0);
+ Geom::Point p = origin->position();
+ double best_dist = grow ? HUGE_VAL : 0;
+ SelectableControlPoint *match = NULL;
+ for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
+ bool selected = (*i)->selected();
+ if (grow && !selected) {
+ double dist = Geom::distance((*i)->position(), p);
+ if (dist < best_dist) {
+ best_dist = dist;
+ match = *i;
+ }
+ }
+ if (!grow && selected) {
+ double dist = Geom::distance((*i)->position(), p);
+ // use >= to also deselect the origin node when it's the last one selected
+ if (dist >= best_dist) {
+ best_dist = dist;
+ match = *i;
+ }
+ }
+ }
+ if (match) {
+ if (grow) insert(match);
+ else erase(match);
+ }
+}
+
+/** Transform all selected control points by the given affine transformation. */
void ControlPointSelection::transform(Geom::Matrix const &m)
{
for (iterator i = _points.begin(); i != _points.end(); ++i) {
index 0f0daffaa4cdb0143d8e546d03c80a9c86cd7209..38df5c7e5f76802cdda10fe75173c7a34f74c1a2 100644 (file)
#include <memory>
#include <tr1/unordered_map>
+#include <tr1/unordered_set>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/optional.hpp>
typedef std::list<sigc::connection> connlist_type;
typedef std::unordered_map< SelectableControlPoint *,
boost::shared_ptr<connlist_type> > map_type;
+ typedef std::unordered_set< SelectableControlPoint * > set_type;
+ typedef set_type Set; // convenience alias
- // boilerplate typedefs
typedef map_type::iterator iterator;
typedef map_type::const_iterator const_iterator;
typedef map_type::size_type size_type;
-
typedef SelectableControlPoint *value_type;
typedef SelectableControlPoint *key_type;
// find
iterator find(const key_type &k) { return _points.find(k); }
+ // Sometimes it is very useful to keep a list of all selectable points.
+ set_type const &allPoints() const { return _all_points; }
+ set_type &allPoints() { return _all_points; }
+ // ...for example in these methods. Another useful case is snapping.
+ void selectAll();
+ void selectArea(Geom::Rect const &);
+ void invertSelection();
+ void spatialGrow(SelectableControlPoint *origin, int dir);
+
virtual bool event(GdkEvent *);
void transform(Geom::Matrix const &m);
void _keyboardTransform(Geom::Matrix const &);
void _commitTransform(CommitEvent ce);
map_type _points;
+ set_type _all_points;
boost::optional<double> _rot_radius;
TransformHandleSet *_handles;
SelectableControlPoint *_grabbed_point;
index 74dd6e31c52acb063def3b1213aead0a7189a906..0d076a5ab2ce3fcc0bd6621128a0a71e6590c77d 100644 (file)
#include <gdkmm.h>
#include <gtkmm.h>
#include <2geom/point.h>
-#include "ui/tool/control-point.h"
-#include "ui/tool/event-utils.h"
-#include "preferences.h"
#include "desktop.h"
#include "desktop-handles.h"
+#include "display/snap-indicator.h"
#include "event-context.h"
#include "message-context.h"
+#include "preferences.h"
+#include "ui/tool/control-point.h"
+#include "ui/tool/event-utils.h"
namespace Inkscape {
namespace UI {
case GDK_MOTION_NOTIFY:
if (held_button<1>(event->motion) && !_desktop->event_context->space_panning) {
+ _desktop->snapindicator->remove_snaptarget();
bool transferred = false;
if (!_drag_initiated) {
bool t = fabs(event->motion.x - _drag_event_origin[Geom::X]) <= drag_tolerance &&
_drag_initiated = true;
}
}
- if (transferred) return true;
- // the point was moved beyond the drag tolerance
- Geom::Point new_pos = _desktop->w2d(event_point(event->motion)) + pointer_offset;
-
- // the new position is passed by reference and can be changed in the handlers.
- signal_dragged.emit(_position, new_pos, &event->motion);
- move(new_pos);
- _updateDragTip(&event->motion); // update dragging tip after moving to new position
-
- _desktop->scroll_to_point(new_pos);
- _desktop->set_coordinate_status(_position);
+ if (!transferred) {
+ // dragging in progress
+ Geom::Point new_pos = _desktop->w2d(event_point(event->motion)) + pointer_offset;
+
+ // the new position is passed by reference and can be changed in the handlers.
+ signal_dragged.emit(_position, new_pos, &event->motion);
+ move(new_pos);
+ _updateDragTip(&event->motion); // update dragging tip after moving to new position
+
+ _desktop->scroll_to_point(new_pos);
+ _desktop->set_coordinate_status(_position);
+ sp_event_context_snap_delay_handler(_desktop->event_context, NULL,
+ reinterpret_cast<SPKnot*>(this), &event->motion,
+ DelayedSnapEvent::CONTROL_POINT_HANDLER);
+ }
return true;
}
break;
case GDK_BUTTON_RELEASE:
- if (_event_grab) {
- sp_canvas_item_ungrab(_canvas_item, event->button.time);
- _setMouseover(this, event->button.state);
- _event_grab = false;
+ if (!_event_grab) break;
- if (_drag_initiated) {
- sp_canvas_end_forced_full_redraws(_desktop->canvas);
- }
+ // TODO I think this "feature" is wrong.
+ // sp_event_context_snap_watchdog_callback(_desktop->event_context->_delayed_snap_event);
+ sp_event_context_discard_delayed_snap_event(_desktop->event_context);
+ _desktop->snapindicator->remove_snaptarget();
+
+ sp_canvas_item_ungrab(_canvas_item, event->button.time);
+ _setMouseover(this, event->button.state);
+ _event_grab = false;
- if (event->button.button == next_release_doubleclick) {
+ if (_drag_initiated) {
+ sp_canvas_end_forced_full_redraws(_desktop->canvas);
+ }
+
+ if (event->button.button == next_release_doubleclick) {
+ _drag_initiated = false;
+ return signal_doubleclicked.emit(&event->button);
+ }
+ if (event->button.button == 1) {
+ if (_drag_initiated) {
+ // it is the end of a drag
+ signal_ungrabbed.emit(&event->button);
_drag_initiated = false;
- return signal_doubleclicked.emit(&event->button);
+ return true;
+ } else {
+ // it is the end of a click
+ return signal_clicked.emit(&event->button);
}
- if (event->button.button == 1) {
- if (_drag_initiated) {
- // it is the end of a drag
- signal_ungrabbed.emit(&event->button);
- _drag_initiated = false;
- return true;
- } else {
- // it is the end of a click
- return signal_clicked.emit(&event->button);
- }
- }
- _drag_initiated = false;
}
+ _drag_initiated = false;
break;
case GDK_ENTER_NOTIFY:
index c4b0a42be18ff54bc43000a50636c36e93c4e2ee..4997c5ef4d07a797cef09d377e93818bfbc094fa 100644 (file)
static sigc::signal<void, ControlPoint*> signal_mouseover_change;
static Glib::ustring format_tip(char const *format, ...) G_GNUC_PRINTF(1,2);
+ // temporarily public, until snapping is refactored a little
+ virtual bool _eventHandler(GdkEvent *event);
+
protected:
ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, Gtk::AnchorType anchor,
SPCtrlShapeType shape, unsigned int size, ColorSet *cset = 0, SPCanvasGroup *group = 0);
void _setPixbuf(Glib::RefPtr<Gdk::Pixbuf>);
/// @}
- virtual bool _eventHandler(GdkEvent *event);
virtual Glib::ustring _getTip(unsigned state) { return ""; }
virtual Glib::ustring _getDragTip(GdkEventMotion *event) { return ""; }
virtual bool _hasDragTips() { return false; }
SPDesktop *const _desktop; ///< The desktop this control point resides on.
SPCanvasItem * _canvas_item; ///< Visual representation of the control point.
- ColorSet *_cset; ///< Describes the colors used to represent the point
+ ColorSet *_cset; ///< Colors used to represent the point
State _state;
static int const _grab_event_mask;
index ac0165e1a1a62882dc12059f6eed8e610def6e7d..33d96c7064967149b11b69ccbb7d3159e10832b4 100644 (file)
void MultiPathManipulator::selectSubpaths()
{
if (_selection.empty()) {
- invokeForAll(&PathManipulator::selectAll);
+ _selection.selectAll();
} else {
invokeForAll(&PathManipulator::selectSubpaths);
}
}
-void MultiPathManipulator::selectAll()
-{
- invokeForAll(&PathManipulator::selectAll);
-}
-
-void MultiPathManipulator::selectArea(Geom::Rect const &area, bool take)
-{
- if (take) _selection.clear();
- invokeForAll(&PathManipulator::selectArea, area);
-}
void MultiPathManipulator::shiftSelection(int dir)
{
invokeForAll(&PathManipulator::shiftSelection, dir);
}
-void MultiPathManipulator::spatialGrow(NodeList::iterator origin, int dir)
-{
- double extr_dist = dir > 0 ? HUGE_VAL : -HUGE_VAL;
- NodeList::iterator target;
- do { // this substitutes for goto
- if ((dir > 0 && !origin->selected())) {
- target = origin;
- break;
- }
-
- bool closest = dir > 0; // when growing, find closest node
- bool selected = dir < 0; // when growing, consider only unselected nodes
-
- for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) {
- NodeList::iterator t = i->second->extremeNode(origin, selected, !selected, closest);
- if (!t) continue;
- double dist = Geom::distance(*t, *origin);
- bool cond = closest ? (dist < extr_dist) : (dist > extr_dist);
- if (cond) {
- extr_dist = dist;
- target = t;
- }
- }
- } while (0);
-
- if (!target) return;
- if (dir > 0) {
- _selection.insert(target.ptr());
- } else {
- _selection.erase(target.ptr());
- }
-}
-void MultiPathManipulator::invertSelection()
-{
- invokeForAll(&PathManipulator::invertSelection);
-}
void MultiPathManipulator::invertSelectionInSubpaths()
{
invokeForAll(&PathManipulator::invertSelectionInSubpaths);
}
-void MultiPathManipulator::deselect()
-{
- _selection.clear();
-}
void MultiPathManipulator::setNodeType(NodeType type)
{
index 4fbbf1b054415dd798f60c2616e843285b7e5c2a..46ad3a8d22f054b81863c9a90f9347c70340714d 100644 (file)
void cleanup();
void selectSubpaths();
- void selectAll();
- void selectArea(Geom::Rect const &area, bool take);
void shiftSelection(int dir);
- void spatialGrow(NodeList::iterator center, int dir);
- void invertSelection();
void invertSelectionInSubpaths();
- void deselect();
void setNodeType(NodeType t);
void setSegmentType(SegmentType t);
index 735ddf87ef61c97a8f2f4a3ca7d227ea7e59a59c..c1ba3394e53cdd0b1fc335cdd95dca8fcd0bcbe6 100644 (file)
* it might handle all shapes. Handles XML commit of actions that affect all paths or
* the node selection and removes PathManipulators that have no nodes left after e.g. node
* deletes.
- * - ControlPointSelection: keeps track of node selection. Performs actions that require no
+ * - ControlPointSelection: keeps track of node selection and a set of nodes that can potentially
+ * be selected. There can be more than one selection. Performs actions that require no
* knowledge about the path, only about the nodes, like dragging and transforms. It is not
* specific to nodes and can accomodate any control point derived from SelectableControlPoint.
* Transforms nodes in response to transform handle events.
* - TransformHandleSet: displays nodeset transform handles and emits transform events. The aim
* is to eventually use a common class for object and control point transforms.
+ * - SelectableControlPoint: base for any type of selectable point. It can belong to only one
+ * selection.
*
* @par Plans for the future
* @par
std::set<ShapeRecord> shapes;
- // TODO this is ugly!!!
- //typedef std::map<SPItem*, std::pair<Geom::Matrix, guint32> > TransMap;
- //typedef std::map<SPPath*, std::pair<Geom::Matrix, guint32> > PathMap;
GSList const *ilist = sel->itemList();
for (GSList *i = const_cast<GSList*>(ilist); i; i = i->next) {
case GDK_a:
if (held_control(event->key)) {
if (held_alt(event->key)) {
- nt->_multipath->selectAll();
+ nt->_selected_nodes->selectAll();
} else {
// select all nodes in subpaths that have something selected
// if nothing is selected, select everything
@@ -554,7 +554,7 @@ void ink_node_tool_select_area(InkNodeTool *nt, Geom::Rect const &sel, GdkEventB
selection->setList(items);
g_slist_free(items);
} else {
- nt->_multipath->selectArea(sel, !held_shift(*event));
+ nt->_selected_nodes->selectArea(sel);
}
}
void ink_node_tool_select_point(InkNodeTool *nt, Geom::Point const &sel, GdkEventButton *event)
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index 22d4ddc47f1ef2b6ed47cb8ba90eb0e0b2743f0b..adef8e5a7e93b3fc7f7f9489427ba9828e7caef7 100644 (file)
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
#include "desktop.h"
#include "desktop-handles.h"
#include "preferences.h"
+#include "snap.h"
+#include "snap-preferences.h"
#include "sp-metrics.h"
#include "sp-namedview.h"
#include "ui/tool/control-point-selection.h"
} else if (event->scroll.direction == GDK_SCROLL_DOWN) {
dir = -1;
} else break;
- origin = NodeList::get_iterator(this);
-
if (held_control(event->scroll)) {
- list()->_list._path_manipulator._multi_path_manipulator.spatialGrow(origin, dir);
+ _selection.spatialGrow(this, dir);
} else {
_linearGrow(dir);
}
@@ -658,7 +658,6 @@ static double bezier_length (Geom::Point a0, Geom::Point a1, Geom::Point a2, Geo
double lower = Geom::distance(a0, a3);
double upper = Geom::distance(a0, a1) + Geom::distance(a1, a2) + Geom::distance(a2, a3);
- // TODO maybe EPSILON is this is too big in this case?
if (upper - lower < Geom::EPSILON) return (lower + upper)/2;
Geom::Point // Casteljau subdivision
} else {
// both iterators that store last selected nodes are initially empty
NodeList::iterator last_fwd, last_rev;
- double last_distance_back, last_distance_front;
+ double last_distance_back = 0, last_distance_front = 0;
while (rev || fwd) {
if (fwd && (!rev || distance_front <= distance_back)) {
last_distance_front = distance_front;
}
NodeList::iterator n = fwd.next();
- distance_front += bezier_length(*fwd, fwd->_front, n->_back, *n);
+ if (n) distance_front += bezier_length(*fwd, fwd->_front, n->_back, *n);
fwd = n;
} else if (rev && (!fwd || distance_front > distance_back)) {
if (rev->selected()) {
last_distance_back = distance_back;
}
NodeList::iterator p = rev.prev();
- distance_back += bezier_length(*rev, rev->_back, p->_front, *p);
+ if (p) distance_back += bezier_length(*rev, rev->_back, p->_front, *p);
rev = p;
}
// Check whether we walked the entire cyclic subpath.
// This is initially true because both iterators start from this node,
// so this check cannot go in the while condition.
- if (fwd == rev) break;
+ // When this happens, we need to check the last node, pointed to by the iterators.
+ if (fwd && fwd == rev) {
+ if (!fwd->selected()) break;
+ NodeList::iterator fwdp = fwd.prev(), revn = rev.next();
+ double df = distance_front + bezier_length(*fwdp, fwdp->_front, fwd->_back, *fwd);
+ double db = distance_back + bezier_length(*revn, revn->_back, rev->_front, *rev);
+ if (df > db) {
+ last_fwd = fwd;
+ last_distance_front = df;
+ } else {
+ last_rev = rev;
+ last_distance_back = db;
+ }
+ break;
+ }
}
NodeList::iterator t;
void Node::_draggedHandler(Geom::Point &new_pos, GdkEventMotion *event)
{
+ // For a note on how snapping is implemented in Inkscape, see snap.h.
+ SnapManager &sm = _desktop->namedview->snap_manager;
+ Inkscape::SnapPreferences::PointType t = Inkscape::SnapPreferences::SNAPPOINT_NODE;
+ bool snap = sm.someSnapperMightSnap();
+ std::vector< std::pair<Geom::Point, int> > unselected;
+ if (snap) {
+ // setup
+ // TODO we are doing this every time a snap happens. It should once be done only once
+ // per drag - maybe in the grabbed handler?
+ // TODO "unselected" must be valid during the snap run, because it is not copied.
+ // Fix this in snap.h and snap.cpp, then the above.
+
+ // Build the list of unselected nodes.
+ typedef ControlPointSelection::Set Set;
+ Set nodes = _selection.allPoints();
+ for (Set::iterator i = nodes.begin(); i != nodes.end(); ++i) {
+ if (!(*i)->selected()) {
+ Node *n = static_cast<Node*>(*i);
+ unselected.push_back(std::make_pair((*i)->position(), (int) n->_snapTargetType()));
+ }
+ }
+ sm.setupIgnoreSelection(_desktop, true, &unselected);
+ }
+
if (held_control(*event)) {
+ Geom::Point origin = _last_drag_origin();
if (held_alt(*event)) {
// with Ctrl+Alt, constrain to handle lines
// project the new position onto a handle line that is closer
- Geom::Point origin = _last_drag_origin();
- Geom::Line line_front(origin, origin + _front.relativePos());
- Geom::Line line_back(origin, origin + _back.relativePos());
- double dist_front, dist_back;
- dist_front = Geom::distance(new_pos, line_front);
- dist_back = Geom::distance(new_pos, line_back);
- if (dist_front < dist_back) {
- new_pos = Geom::projection(new_pos, line_front);
+ Inkscape::Snapper::ConstraintLine line_front(origin, _front.relativePos());
+ Inkscape::Snapper::ConstraintLine line_back(origin, _back.relativePos());
+
+ // TODO: combine these two branches by modifying snap.h / snap.cpp
+ if (snap) {
+ Inkscape::SnappedPoint fp, bp;
+ fp = sm.constrainedSnap(t, position(), _snapSourceType(), line_front);
+ bp = sm.constrainedSnap(t, position(), _snapSourceType(), line_back);
+
+ if (fp.isOtherSnapBetter(bp, false)) {
+ bp.getPoint(new_pos);
+ } else {
+ fp.getPoint(new_pos);
+ }
} else {
- new_pos = Geom::projection(new_pos, line_back);
+ Geom::Point p_front = line_front.projection(new_pos);
+ Geom::Point p_back = line_back.projection(new_pos);
+ if (Geom::distance(new_pos, p_front) < Geom::distance(new_pos, p_back)) {
+ new_pos = p_front;
+ } else {
+ new_pos = p_back;
+ }
}
} else {
// with Ctrl, constrain to axes
- // TODO maybe add diagonals when the distance from origin is large enough?
- Geom::Point origin = _last_drag_origin();
- Geom::Point delta = new_pos - origin;
- Geom::Dim2 d = (fabs(delta[Geom::X]) < fabs(delta[Geom::Y])) ? Geom::X : Geom::Y;
- new_pos[d] = origin[d];
+ // TODO combine the two branches
+ if (snap) {
+ Inkscape::SnappedPoint fp, bp;
+ Inkscape::Snapper::ConstraintLine line_x(origin, Geom::Point(1, 0));
+ Inkscape::Snapper::ConstraintLine line_y(origin, Geom::Point(0, 1));
+ fp = sm.constrainedSnap(t, position(), _snapSourceType(), line_x);
+ bp = sm.constrainedSnap(t, position(), _snapSourceType(), line_y);
+
+ if (fp.isOtherSnapBetter(bp, false)) {
+ fp = bp;
+ }
+ fp.getPoint(new_pos);
+ } else {
+ Geom::Point origin = _last_drag_origin();
+ Geom::Point delta = new_pos - origin;
+ Geom::Dim2 d = (fabs(delta[Geom::X]) < fabs(delta[Geom::Y])) ? Geom::X : Geom::Y;
+ new_pos[d] = origin[d];
+ }
}
- } else {
- // TODO snapping?
+ } else if (snap) {
+ sm.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, new_pos, _snapSourceType());
}
}
+Inkscape::SnapSourceType Node::_snapSourceType()
+{
+ if (_type == NODE_SMOOTH || _type == NODE_AUTO)
+ return SNAPSOURCE_NODE_SMOOTH;
+ return SNAPSOURCE_NODE_CUSP;
+}
+Inkscape::SnapTargetType Node::_snapTargetType()
+{
+ if (_type == NODE_SMOOTH || _type == NODE_AUTO)
+ return SNAPTARGET_NODE_SMOOTH;
+ return SNAPTARGET_NODE_CUSP;
+}
+
Glib::ustring Node::_getTip(unsigned state)
{
if (state_held_shift(state)) {
diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h
index 167cf90b871e63c20816a050c481ec70f1004ba7..a85877d5ca996345e572b41de689f88a8de04480 100644 (file)
--- a/src/ui/tool/node.h
+++ b/src/ui/tool/node.h
#include <boost/shared_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/operators.hpp>
+#include "snapped-point.h"
#include "ui/tool/selectable-control-point.h"
#include "ui/tool/node-types.h"
void sink();
static char const *node_type_to_localized_string(NodeType type);
-protected:
+ // temporarily public
virtual bool _eventHandler(GdkEvent *event);
+protected:
virtual void _setState(State state);
virtual Glib::ustring _getTip(unsigned state);
virtual Glib::ustring _getDragTip(GdkEventMotion *event);
void _linearGrow(int dir);
Node *_next();
Node *_prev();
+ Inkscape::SnapSourceType _snapSourceType();
+ Inkscape::SnapTargetType _snapTargetType();
static SPCtrlShapeType _node_type_to_shape(NodeType type);
static bool _is_line_segment(Node *first, Node *second);
index 2755d6fb35c94cb4bd8d0bde7258d862b706e6e1..cfa3846f86495a5b37aa2206db5e369817bbde9b 100644 (file)
}
}
-/** Select all nodes in the path. */
-void PathManipulator::selectAll()
-{
- for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
- for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
- _selection.insert(j.ptr());
- }
- }
-}
-
-/** Select points inside the given rectangle. If all points inside it are already selected,
- * they will be deselected.
- * @param area Area to select
- */
-void PathManipulator::selectArea(Geom::Rect const &area)
-{
- bool nothing_selected = true;
- std::vector<Node*> in_area;
- for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
- for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
- if (area.contains(j->position())) {
- in_area.push_back(j.ptr());
- if (!j->selected()) {
- _selection.insert(j.ptr());
- nothing_selected = false;
- }
- }
- }
- }
- if (nothing_selected) {
- for (std::vector<Node*>::iterator i = in_area.begin(); i != in_area.end(); ++i) {
- _selection.erase(*i);
- }
- }
-}
-
/** Move the selection forward or backward by one node in each subpath, based on the sign
* of the parameter. */
void PathManipulator::shiftSelection(int dir)
}
}
-/** Invert selection in the entire path. */
-void PathManipulator::invertSelection()
-{
- for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
- for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
- if (j->selected()) _selection.erase(j.ptr());
- else _selection.insert(j.ptr());
- }
- }
-}
-
/** Invert selection in the selected subpaths. */
void PathManipulator::invertSelectionInSubpaths()
{
_createGeometryFromControlPoints();
}
+/** Hide the curve drag point until the next motion event. */
void PathManipulator::hideDragPoint()
{
_dragpoint->setVisible(false);
index 38f66dee0a0f62d5a0e4c381c087c64facb90ab6..99e183b4530c656ecca0c4ab9ec929394ab974e6 100644 (file)
SPPath *item() { return _path; }
void selectSubpaths();
- void selectAll();
- void selectArea(Geom::Rect const &);
void shiftSelection(int dir);
- void invertSelection();
void invertSelectionInSubpaths();
void insertNodes();
index b189a713f845716c515c0524315b64aee68be5c8..5b9aa4fc838207a1b42753503b4f5c3abdeae4d4 100644 (file)
@@ -50,10 +50,12 @@ SelectableControlPoint::SelectableControlPoint(SPDesktop *d, Geom::Point const &
SelectableControlPoint::~SelectableControlPoint()
{
_selection.erase(this);
+ _selection.allPoints().erase(this);
}
void SelectableControlPoint::_connectHandlers()
{
+ _selection.allPoints().insert(this);
signal_clicked.connect(
sigc::mem_fun(*this, &SelectableControlPoint::_clickedHandler));
signal_grabbed.connect(
diff --git a/src/verbs.cpp b/src/verbs.cpp
index d26a4e6d5cf87c018e7c57f152c2986edef1a747..f03be681a631d68ae11ffb88df3ae7f27a3a2bbc 100644 (file)
--- a/src/verbs.cpp
+++ b/src/verbs.cpp
#include "ui/dialog/layers.h"
#include "ui/dialog/swatches.h"
#include "ui/icon-names.h"
+#include "ui/tool/control-point-selection.h"
#include "ui/tool/multi-path-manipulator.h"
#include "ui/tool/node-tool.h"
case SP_VERB_EDIT_SELECT_ALL_IN_ALL_LAYERS:
if (tools_isactive(dt, TOOLS_NODES)) {
InkNodeTool *nt = static_cast<InkNodeTool*>(dt->event_context);
- nt->_multipath->selectAll();
+ nt->_selected_nodes->selectAll();
} else {
sp_edit_select_all_in_all_layers(dt);
}
case SP_VERB_EDIT_INVERT_IN_ALL_LAYERS:
if (tools_isactive(dt, TOOLS_NODES)) {
InkNodeTool *nt = static_cast<InkNodeTool*>(dt->event_context);
- nt->_multipath->invertSelection();
+ nt->_selected_nodes->invertSelection();
} else {
sp_edit_invert_in_all_layers(dt);
}
case SP_VERB_EDIT_DESELECT:
if (tools_isactive(dt, TOOLS_NODES)) {
InkNodeTool *nt = static_cast<InkNodeTool*>(dt->event_context);
- nt->_multipath->deselect();
+ nt->_selected_nodes->clear();
} else {
sp_desktop_selection(dt)->clear();
}