~ubuntu-branches/ubuntu/oneiric/inkscape/oneiric-updates

« back to all changes in this revision

Viewing changes to src/node-context.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alex Valavanis
  • Date: 2010-09-12 19:44:58 UTC
  • mfrom: (1.1.12 upstream) (45.1.3 maverick)
  • Revision ID: james.westby@ubuntu.com-20100912194458-4sjwmbl7dlsrk5dc
Tags: 0.48.0-1ubuntu1
* Merge with Debian unstable (LP: #628048, LP: #401567, LP: #456248, 
  LP: #463602, LP: #591986)
* debian/control: 
  - Ubuntu maintainers
  - Promote python-lxml, python-numpy, python-uniconvertor to Recommends.
  - Demote pstoedit to Suggests (universe package).
  - Suggests ttf-dejavu instead of ttf-bitstream-vera (LP: #513319)
* debian/rules:
  - Run intltool-update on build (Ubuntu-specific).
  - Add translation domain to .desktop files (Ubuntu-specific).
* debian/dirs:
  - Add usr/share/pixmaps.  Allow inkscape.xpm installation
* drop 50-poppler-API.dpatch (now upstream)
* drop 51-paste-in-unwritable-directory.dpatch (now upstream) 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#define __SP_NODE_CONTEXT_C__
2
 
 
3
 
/*
4
 
 * Node editing context
5
 
 *
6
 
 * Authors:
7
 
 *   Lauris Kaplinski <lauris@kaplinski.com>
8
 
 *   bulia byak <buliabyak@users.sf.net>
9
 
 *
10
 
 * This code is in public domain
11
 
 */
12
 
 
13
 
#ifdef HAVE_CONFIG_H
14
 
# include "config.h"
15
 
#endif
16
 
#include <cstring>
17
 
#include <string>
18
 
#include <gdk/gdkkeysyms.h>
19
 
#include "macros.h"
20
 
#include <glibmm/i18n.h>
21
 
#include "display/sp-canvas-util.h"
22
 
#include "object-edit.h"
23
 
#include "sp-path.h"
24
 
#include "path-chemistry.h"
25
 
#include "rubberband.h"
26
 
#include "desktop.h"
27
 
#include "desktop-handles.h"
28
 
#include "selection.h"
29
 
#include "pixmaps/cursor-node.xpm"
30
 
#include "message-context.h"
31
 
#include "node-context.h"
32
 
#include "pixmaps/cursor-node-d.xpm"
33
 
#include "preferences.h"
34
 
#include "xml/node-event-vector.h"
35
 
#include "style.h"
36
 
#include "splivarot.h"
37
 
#include "shape-editor.h"
38
 
#include "live_effects/effect.h"
39
 
 
40
 
#include "sp-lpe-item.h"
41
 
 
42
 
// needed for flash nodepath upon mouseover:
43
 
#include "display/canvas-bpath.h"
44
 
#include "display/curve.h"
45
 
 
46
 
static void sp_node_context_class_init(SPNodeContextClass *klass);
47
 
static void sp_node_context_init(SPNodeContext *node_context);
48
 
static void sp_node_context_dispose(GObject *object);
49
 
 
50
 
static void sp_node_context_setup(SPEventContext *ec);
51
 
static gint sp_node_context_root_handler(SPEventContext *event_context, GdkEvent *event);
52
 
static gint sp_node_context_item_handler(SPEventContext *event_context,
53
 
                                         SPItem *item, GdkEvent *event);
54
 
 
55
 
static SPEventContextClass *parent_class;
56
 
 
57
 
GType
58
 
sp_node_context_get_type()
59
 
{
60
 
    static GType type = 0;
61
 
    if (!type) {
62
 
        GTypeInfo info = {
63
 
            sizeof(SPNodeContextClass),
64
 
            NULL, NULL,
65
 
            (GClassInitFunc) sp_node_context_class_init,
66
 
            NULL, NULL,
67
 
            sizeof(SPNodeContext),
68
 
            4,
69
 
            (GInstanceInitFunc) sp_node_context_init,
70
 
            NULL,    /* value_table */
71
 
        };
72
 
        type = g_type_register_static(SP_TYPE_EVENT_CONTEXT, "SPNodeContext", &info, (GTypeFlags)0);
73
 
    }
74
 
    return type;
75
 
}
76
 
 
77
 
static void
78
 
sp_node_context_class_init(SPNodeContextClass *klass)
79
 
{
80
 
    GObjectClass *object_class = (GObjectClass *) klass;
81
 
    SPEventContextClass *event_context_class = (SPEventContextClass *) klass;
82
 
 
83
 
    parent_class = (SPEventContextClass*)g_type_class_peek_parent(klass);
84
 
 
85
 
    object_class->dispose = sp_node_context_dispose;
86
 
 
87
 
    event_context_class->setup = sp_node_context_setup;
88
 
    event_context_class->root_handler = sp_node_context_root_handler;
89
 
    event_context_class->item_handler = sp_node_context_item_handler;
90
 
}
91
 
 
92
 
static void
93
 
sp_node_context_init(SPNodeContext *node_context)
94
 
{
95
 
    SPEventContext *event_context = SP_EVENT_CONTEXT(node_context);
96
 
 
97
 
    event_context->cursor_shape = cursor_node_xpm;
98
 
    event_context->hot_x = 1;
99
 
    event_context->hot_y = 1;
100
 
 
101
 
    node_context->leftalt = FALSE;
102
 
    node_context->rightalt = FALSE;
103
 
    node_context->leftctrl = FALSE;
104
 
    node_context->rightctrl = FALSE;
105
 
 
106
 
    new (&node_context->sel_changed_connection) sigc::connection();
107
 
 
108
 
    node_context->flash_tempitem = NULL;
109
 
    node_context->flashed_item = NULL;
110
 
    node_context->remove_flash_counter = 0;
111
 
}
112
 
 
113
 
static void
114
 
sp_node_context_dispose(GObject *object)
115
 
{
116
 
        SPNodeContext *nc = SP_NODE_CONTEXT(object);
117
 
    SPEventContext *ec = SP_EVENT_CONTEXT(object);
118
 
 
119
 
    ec->enableGrDrag(false);
120
 
        
121
 
    if (nc->grabbed) {
122
 
        sp_canvas_item_ungrab(nc->grabbed, GDK_CURRENT_TIME);
123
 
        nc->grabbed = NULL;
124
 
    }
125
 
 
126
 
    nc->sel_changed_connection.disconnect();
127
 
    nc->sel_changed_connection.~connection();
128
 
 
129
 
    delete ec->shape_editor;
130
 
 
131
 
    if (nc->_node_message_context) {
132
 
        delete nc->_node_message_context;
133
 
    }
134
 
 
135
 
    G_OBJECT_CLASS(parent_class)->dispose(object);
136
 
}
137
 
 
138
 
static void
139
 
sp_node_context_setup(SPEventContext *ec)
140
 
{
141
 
    SPNodeContext *nc = SP_NODE_CONTEXT(ec);
142
 
 
143
 
    if (((SPEventContextClass *) parent_class)->setup)
144
 
        ((SPEventContextClass *) parent_class)->setup(ec);
145
 
 
146
 
    Inkscape::Selection *selection = sp_desktop_selection (ec->desktop);
147
 
    nc->sel_changed_connection.disconnect();
148
 
    nc->sel_changed_connection =
149
 
        selection->connectChanged(sigc::bind(sigc::ptr_fun(&sp_node_context_selection_changed), (gpointer)nc));
150
 
 
151
 
    SPItem *item = selection->singleItem();
152
 
 
153
 
    ec->shape_editor = new ShapeEditor(ec->desktop);
154
 
 
155
 
    nc->rb_escaped = false;
156
 
 
157
 
    nc->cursor_drag = false;
158
 
 
159
 
    nc->added_node = false;
160
 
 
161
 
    nc->current_state = SP_NODE_CONTEXT_INACTIVE;
162
 
 
163
 
    if (item) {
164
 
        ec->shape_editor->set_item(item, SH_NODEPATH);
165
 
        ec->shape_editor->set_item(item, SH_KNOTHOLDER);
166
 
    }
167
 
 
168
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
169
 
    if (prefs->getBool("/tools/nodes/selcue")) {
170
 
        ec->enableSelectionCue();
171
 
    }
172
 
    if (prefs->getBool("/tools/nodes/gradientdrag")) {
173
 
        ec->enableGrDrag();
174
 
    }
175
 
 
176
 
    ec->desktop->emitToolSubselectionChanged(NULL); // sets the coord entry fields to inactive
177
 
 
178
 
    nc->_node_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack());
179
 
 
180
 
    ec->shape_editor->update_statusbar();
181
 
}
182
 
 
183
 
static void
184
 
sp_node_context_flash_path(SPEventContext *event_context, SPItem *item, guint timeout) {
185
 
    SPNodeContext *nc = SP_NODE_CONTEXT(event_context);
186
 
 
187
 
    nc->remove_flash_counter = 3; // for some reason root_handler is called twice after each item_handler...
188
 
    if (nc->flashed_item != item) {
189
 
        // we entered a new item
190
 
        nc->flashed_item = item;
191
 
        SPDesktop *desktop = event_context->desktop;
192
 
        if (nc->flash_tempitem) {
193
 
            desktop->remove_temporary_canvasitem(nc->flash_tempitem);
194
 
            nc->flash_tempitem = NULL;
195
 
        }
196
 
 
197
 
        SPCanvasItem *canvasitem = sp_nodepath_generate_helperpath(desktop, item);
198
 
 
199
 
        if (canvasitem) {
200
 
            nc->flash_tempitem = desktop->add_temporary_canvasitem (canvasitem, timeout);
201
 
        }
202
 
    }
203
 
}
204
 
 
205
 
/**
206
 
\brief  Callback that processes the "changed" signal on the selection;
207
 
destroys old and creates new nodepath and reassigns listeners to the new selected item's repr
208
 
*/
209
 
void
210
 
sp_node_context_selection_changed(Inkscape::Selection *selection, gpointer data)
211
 
{
212
 
    SPEventContext *ec = SP_EVENT_CONTEXT(data);
213
 
 
214
 
    // TODO: update ShapeEditorsCollective instead
215
 
    ec->shape_editor->unset_item(SH_NODEPATH);
216
 
    ec->shape_editor->unset_item(SH_KNOTHOLDER);
217
 
    SPItem *item = selection->singleItem();
218
 
    ec->shape_editor->set_item(item, SH_NODEPATH);
219
 
    ec->shape_editor->set_item(item, SH_KNOTHOLDER);
220
 
    ec->shape_editor->update_statusbar();
221
 
}
222
 
 
223
 
void
224
 
sp_node_context_show_modifier_tip(SPEventContext *event_context, GdkEvent *event)
225
 
{
226
 
    sp_event_show_modifier_tip
227
 
        (event_context->defaultMessageContext(), event,
228
 
         _("<b>Ctrl</b>: toggle node type, snap handle angle, move hor/vert; <b>Ctrl+Alt</b>: move along handles"),
229
 
         _("<b>Shift</b>: toggle node selection, disable snapping, rotate both handles"),
230
 
         _("<b>Alt</b>: lock handle length; <b>Ctrl+Alt</b>: move along handles"));
231
 
}
232
 
 
233
 
static gint
234
 
sp_node_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event)
235
 
{
236
 
    gint ret = FALSE;
237
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
238
 
    SPDesktop *desktop = event_context->desktop;
239
 
 
240
 
    switch (event->type) {
241
 
        case GDK_MOTION_NOTIFY:
242
 
        {
243
 
            // find out actual item we're over, disregarding groups
244
 
            SPItem *actual_item = sp_event_context_find_item (desktop,
245
 
                                                              Geom::Point(event->button.x, event->button.y), FALSE, TRUE);
246
 
            if (!actual_item)
247
 
                break;
248
 
 
249
 
 
250
 
            if (prefs->getBool("/tools/nodes/pathflash_enabled")) {
251
 
                if (prefs->getBool("/tools/nodes/pathflash_unselected")) {
252
 
                    // do not flash if we have some path selected and a single item in selection (i.e. it
253
 
                    // is the same path that we're editing)
254
 
                    SPDesktop *desktop = event_context->desktop;
255
 
                    ShapeEditor* se = event_context->shape_editor;
256
 
                    Inkscape::Selection *selection = sp_desktop_selection (desktop);
257
 
                    if (se->has_nodepath() && selection->singleItem()) {
258
 
                        break;
259
 
                    }
260
 
                }
261
 
                if (SP_IS_LPE_ITEM(actual_item)) {
262
 
                    Inkscape::LivePathEffect::Effect *lpe = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(actual_item));
263
 
                    if (lpe && (lpe->providesOwnFlashPaths() ||
264
 
                                lpe->pathFlashType() == Inkscape::LivePathEffect::SUPPRESS_FLASH)) {
265
 
                        // path should be suppressed or permanent; this is handled in
266
 
                        // sp_node_context_selection_changed()
267
 
                        break;
268
 
                    }
269
 
                }
270
 
                guint timeout = prefs->getInt("/tools/nodes/pathflash_timeout", 500);
271
 
                sp_node_context_flash_path(event_context, actual_item, timeout);
272
 
            }
273
 
        }
274
 
        break;
275
 
 
276
 
        default:
277
 
            break;
278
 
    }
279
 
 
280
 
    if (((SPEventContextClass *) parent_class)->item_handler)
281
 
        ret = ((SPEventContextClass *) parent_class)->item_handler(event_context, item, event);
282
 
 
283
 
    return ret;
284
 
}
285
 
 
286
 
static gint
287
 
sp_node_context_root_handler(SPEventContext *event_context, GdkEvent *event)
288
 
{
289
 
    SPDesktop *desktop = event_context->desktop;
290
 
    ShapeEditor* se = event_context->shape_editor;
291
 
    Inkscape::Selection *selection = sp_desktop_selection (desktop);
292
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
293
 
 
294
 
    SPNodeContext *nc = SP_NODE_CONTEXT(event_context);
295
 
    double const nudge = prefs->getDoubleLimited("/options/nudgedistance/value", 2, 0, 1000); // in px
296
 
    event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); // read every time, to make prefs changes really live
297
 
    int const snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12);
298
 
    double const offset = prefs->getDoubleLimited("/options/defaultscale/value", 2, 0, 1000);
299
 
 
300
 
    if ( (nc->flash_tempitem) && (nc->remove_flash_counter <= 0) ) {
301
 
        desktop->remove_temporary_canvasitem(nc->flash_tempitem);
302
 
        nc->flash_tempitem = NULL;
303
 
        nc->flashed_item = NULL; // also reset this one, so the next time the same object is hovered over it shows again the highlight
304
 
    } else {
305
 
        nc->remove_flash_counter--;
306
 
    }
307
 
 
308
 
    gint ret = FALSE;
309
 
    switch (event->type) {
310
 
        case GDK_BUTTON_PRESS:
311
 
            if (event->button.button == 1 && !event_context->space_panning) {
312
 
                // save drag origin
313
 
                event_context->xp = (gint) event->button.x;
314
 
                event_context->yp = (gint) event->button.y;
315
 
                event_context->within_tolerance = true;
316
 
                se->cancel_hit();
317
 
 
318
 
                if (!(event->button.state & GDK_SHIFT_MASK)) {
319
 
                    if (!nc->drag) {
320
 
                        if (se->has_nodepath() && selection->single() /* && item_over */) {
321
 
                                // save drag origin
322
 
                            bool over_stroke = se->is_over_stroke(Geom::Point(event->button.x, event->button.y), true);
323
 
                            //only dragging curves
324
 
                            if (over_stroke) {
325
 
                                ret = TRUE;
326
 
                                break;
327
 
                            }
328
 
                        }
329
 
                    }
330
 
                }
331
 
                Geom::Point const button_w(event->button.x,
332
 
                                         event->button.y);
333
 
                Geom::Point const button_dt(desktop->w2d(button_w));
334
 
                Inkscape::Rubberband::get(desktop)->start(desktop, button_dt);
335
 
 
336
 
                if (nc->grabbed) {
337
 
                    sp_canvas_item_ungrab(nc->grabbed, event->button.time);
338
 
                    nc->grabbed = NULL;
339
 
                }
340
 
                                
341
 
                sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
342
 
                                    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,
343
 
                                    NULL, event->button.time);
344
 
                                nc->grabbed = SP_CANVAS_ITEM(desktop->acetate);
345
 
                                
346
 
                nc->current_state = SP_NODE_CONTEXT_INACTIVE;
347
 
                desktop->updateNow();
348
 
                ret = TRUE;
349
 
            }
350
 
            break;
351
 
        case GDK_MOTION_NOTIFY:
352
 
            if (event->motion.state & GDK_BUTTON1_MASK && !event_context->space_panning) {
353
 
 
354
 
                if ( event_context->within_tolerance
355
 
                     && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance )
356
 
                     && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) {
357
 
                    break; // do not drag if we're within tolerance from origin
358
 
                }
359
 
 
360
 
                // The path went away while dragging; throw away any further motion
361
 
                // events until the mouse pointer is released.
362
 
 
363
 
                if (se->hits_curve() && !se->has_nodepath()) {
364
 
                  break;
365
 
                }
366
 
 
367
 
                // Once the user has moved farther than tolerance from the original location
368
 
                // (indicating they intend to move the object, not click), then always process the
369
 
                // motion notify coordinates as given (no snapping back to origin)
370
 
                event_context->within_tolerance = false;
371
 
 
372
 
                // Once we determine what the user is doing (dragging either a node or the
373
 
                // selection rubberband), make sure we continue to perform that operation
374
 
                // until the mouse pointer is lifted.
375
 
                if (nc->current_state == SP_NODE_CONTEXT_INACTIVE) {
376
 
                    if (se->hits_curve() && se->has_nodepath()) {
377
 
                        nc->current_state = SP_NODE_CONTEXT_NODE_DRAGGING;
378
 
                    } else {
379
 
                        nc->current_state = SP_NODE_CONTEXT_RUBBERBAND_DRAGGING;
380
 
                    }
381
 
                }
382
 
 
383
 
                switch (nc->current_state) {
384
 
                    case SP_NODE_CONTEXT_NODE_DRAGGING:
385
 
                        {
386
 
                            se->curve_drag (event->motion.x, event->motion.y);
387
 
 
388
 
                            gobble_motion_events(GDK_BUTTON1_MASK);
389
 
                            break;
390
 
                        }
391
 
                    case SP_NODE_CONTEXT_RUBBERBAND_DRAGGING:
392
 
                        if (Inkscape::Rubberband::get(desktop)->is_started()) {
393
 
                            Geom::Point const motion_w(event->motion.x,
394
 
                                                event->motion.y);
395
 
                            Geom::Point const motion_dt(desktop->w2d(motion_w));
396
 
                            Inkscape::Rubberband::get(desktop)->move(motion_dt);
397
 
                        }
398
 
                        break;
399
 
                }
400
 
 
401
 
                nc->drag = TRUE;
402
 
                ret = TRUE;
403
 
            } else {
404
 
                if (!se->has_nodepath() || selection->singleItem() == NULL) {
405
 
                    break;
406
 
                }
407
 
 
408
 
                bool over_stroke = false;
409
 
                over_stroke = se->is_over_stroke(Geom::Point(event->motion.x, event->motion.y), false);
410
 
 
411
 
                if (nc->cursor_drag && !over_stroke) {
412
 
                    event_context->cursor_shape = cursor_node_xpm;
413
 
                    event_context->hot_x = 1;
414
 
                    event_context->hot_y = 1;
415
 
                    sp_event_context_update_cursor(event_context);
416
 
                    nc->cursor_drag = false;
417
 
                } else if (!nc->cursor_drag && over_stroke) {
418
 
                    event_context->cursor_shape = cursor_node_d_xpm;
419
 
                    event_context->hot_x = 1;
420
 
                    event_context->hot_y = 1;
421
 
                    sp_event_context_update_cursor(event_context);
422
 
                    nc->cursor_drag = true;
423
 
                }
424
 
            }
425
 
            break;
426
 
 
427
 
        case GDK_2BUTTON_PRESS:
428
 
        case GDK_BUTTON_RELEASE:
429
 
            if ( (event->button.button == 1) && (!nc->drag) && !event_context->space_panning) {
430
 
                // find out clicked item, disregarding groups, honoring Alt
431
 
                SPItem *item_clicked = sp_event_context_find_item (desktop,
432
 
                        Geom::Point(event->button.x, event->button.y),
433
 
                        (event->button.state & GDK_MOD1_MASK) && !(event->button.state & GDK_CONTROL_MASK), TRUE);
434
 
 
435
 
                event_context->xp = event_context->yp = 0;
436
 
 
437
 
                bool over_stroke = false;
438
 
                if (se->has_nodepath()) {
439
 
                    over_stroke = se->is_over_stroke(Geom::Point(event->button.x, event->button.y), false);
440
 
                }
441
 
 
442
 
                if (item_clicked || over_stroke) {
443
 
                    if (over_stroke || nc->added_node) {
444
 
                        switch (event->type) {
445
 
                            case GDK_BUTTON_RELEASE:
446
 
                                if (event->button.state & GDK_CONTROL_MASK && event->button.state & GDK_MOD1_MASK) {
447
 
                                    //add a node
448
 
                                    se->add_node_near_point();
449
 
                                } else {
450
 
                                    if (nc->added_node) { // we just received double click, ignore release
451
 
                                        nc->added_node = false;
452
 
                                        break;
453
 
                                    }
454
 
                                    //select the segment
455
 
                                    if (event->button.state & GDK_SHIFT_MASK) {
456
 
                                        se->select_segment_near_point(true);
457
 
                                    } else {
458
 
                                        se->select_segment_near_point(false);
459
 
                                    }
460
 
                                    desktop->updateNow();
461
 
                                }
462
 
                                break;
463
 
                            case GDK_2BUTTON_PRESS:
464
 
                                //add a node
465
 
                                se->add_node_near_point();
466
 
                                nc->added_node = true;
467
 
                                break;
468
 
                            default:
469
 
                                break;
470
 
                        }
471
 
                    } else if (event->button.state & GDK_SHIFT_MASK) {
472
 
                        selection->toggle(item_clicked);
473
 
                        desktop->updateNow();
474
 
                    } else {
475
 
                        selection->set(item_clicked);
476
 
                        desktop->updateNow();
477
 
                    }
478
 
                    Inkscape::Rubberband::get(desktop)->stop();
479
 
                    if (nc->grabbed) {
480
 
                        sp_canvas_item_ungrab(nc->grabbed, event->button.time);
481
 
                        nc->grabbed = NULL;
482
 
                    }
483
 
                    ret = TRUE;
484
 
                    break;
485
 
                }
486
 
            }
487
 
            if (event->type == GDK_BUTTON_RELEASE) {
488
 
                event_context->xp = event_context->yp = 0;
489
 
                if (event->button.button == 1) {
490
 
                        Geom::OptRect b = Inkscape::Rubberband::get(desktop)->getRectangle();
491
 
 
492
 
                    if (se->hits_curve() && !event_context->within_tolerance) { //drag curve
493
 
                        se->finish_drag();
494
 
                    } else if (b && !event_context->within_tolerance) { // drag to select
495
 
                        se->select_rect(*b, event->button.state & GDK_SHIFT_MASK);
496
 
                    } else {
497
 
                        if (!(nc->rb_escaped)) { // unless something was canceled
498
 
                            if (se->has_selection())
499
 
                                se->deselect();
500
 
                            else
501
 
                                sp_desktop_selection(desktop)->clear();
502
 
                        }
503
 
                    }
504
 
                    ret = TRUE;
505
 
                    Inkscape::Rubberband::get(desktop)->stop();
506
 
                                        
507
 
                                        if (nc->grabbed) {
508
 
                                                sp_canvas_item_ungrab(nc->grabbed, event->button.time);
509
 
                                                nc->grabbed = NULL;
510
 
                                        }
511
 
                                        
512
 
                    desktop->updateNow();
513
 
                    nc->rb_escaped = false;
514
 
                    nc->drag = FALSE;
515
 
                    se->cancel_hit();
516
 
                    nc->current_state = SP_NODE_CONTEXT_INACTIVE;
517
 
                }
518
 
            }
519
 
            break;
520
 
        case GDK_KEY_PRESS:
521
 
            switch (get_group0_keyval(&event->key)) {
522
 
                case GDK_Insert:
523
 
                case GDK_KP_Insert:
524
 
                    // with any modifiers
525
 
                    se->add_node();
526
 
                    ret = TRUE;
527
 
                    break;
528
 
                case GDK_I:
529
 
                case GDK_i:
530
 
                    // apple keyboards have no Insert
531
 
                    if (MOD__SHIFT_ONLY) {
532
 
                        se->add_node();
533
 
                        ret = TRUE;
534
 
                    }
535
 
                    break;
536
 
                case GDK_Delete:
537
 
                case GDK_KP_Delete:
538
 
                case GDK_BackSpace:
539
 
                    if (MOD__CTRL_ONLY) {
540
 
                        se->delete_nodes();
541
 
                    } else {
542
 
                        se->delete_nodes_preserving_shape();
543
 
                    }
544
 
                    ret = TRUE;
545
 
                    break;
546
 
                case GDK_C:
547
 
                case GDK_c:
548
 
                    if (MOD__SHIFT_ONLY) {
549
 
                        se->set_node_type(Inkscape::NodePath::NODE_CUSP);
550
 
                        ret = TRUE;
551
 
                    }
552
 
                    break;
553
 
                case GDK_S:
554
 
                case GDK_s:
555
 
                    if (MOD__SHIFT_ONLY) {
556
 
                        se->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
557
 
                        ret = TRUE;
558
 
                    }
559
 
                    break;
560
 
                case GDK_A:
561
 
                case GDK_a:
562
 
                    if (MOD__SHIFT_ONLY) {
563
 
                        se->set_node_type(Inkscape::NodePath::NODE_AUTO);
564
 
                        ret = TRUE;
565
 
                    }
566
 
                    break;
567
 
                case GDK_Y:
568
 
                case GDK_y:
569
 
                    if (MOD__SHIFT_ONLY) {
570
 
                        se->set_node_type(Inkscape::NodePath::NODE_SYMM);
571
 
                        ret = TRUE;
572
 
                    }
573
 
                    break;
574
 
                case GDK_B:
575
 
                case GDK_b:
576
 
                    if (MOD__SHIFT_ONLY) {
577
 
                        se->break_at_nodes();
578
 
                        ret = TRUE;
579
 
                    }
580
 
                    break;
581
 
                case GDK_J:
582
 
                case GDK_j:
583
 
                    if (MOD__SHIFT_ONLY) {
584
 
                        se->join_nodes();
585
 
                        ret = TRUE;
586
 
                    }
587
 
                    break;
588
 
                case GDK_D:
589
 
                case GDK_d:
590
 
                    if (MOD__SHIFT_ONLY) {
591
 
                        se->duplicate_nodes();
592
 
                        ret = TRUE;
593
 
                    }
594
 
                    break;
595
 
                case GDK_L:
596
 
                case GDK_l:
597
 
                    if (MOD__SHIFT_ONLY) {
598
 
                        se->set_type_of_segments(NR_LINETO);
599
 
                        ret = TRUE;
600
 
                    }
601
 
                    break;
602
 
                case GDK_U:
603
 
                case GDK_u:
604
 
                    if (MOD__SHIFT_ONLY) {
605
 
                        se->set_type_of_segments(NR_CURVETO);
606
 
                        ret = TRUE;
607
 
                    }
608
 
                    break;
609
 
                case GDK_R:
610
 
                case GDK_r:
611
 
                    if (MOD__SHIFT_ONLY) {
612
 
                        // FIXME: add top panel button
613
 
                        sp_selected_path_reverse(desktop);
614
 
                        ret = TRUE;
615
 
                    }
616
 
                    break;
617
 
                case GDK_x:
618
 
                case GDK_X:
619
 
                    if (MOD__ALT_ONLY) {
620
 
                        desktop->setToolboxFocusTo ("altx-nodes");
621
 
                        ret = TRUE;
622
 
                    }
623
 
                    break;
624
 
                case GDK_Left: // move selection left
625
 
                case GDK_KP_Left:
626
 
                case GDK_KP_4:
627
 
                    if (!MOD__CTRL) { // not ctrl
628
 
                        gint mul = 1 + gobble_key_events(
629
 
                            get_group0_keyval(&event->key), 0); // with any mask
630
 
                        if (MOD__ALT) { // alt
631
 
                            if (MOD__SHIFT) se->move_nodes_screen(desktop, mul*-10, 0); // shift
632
 
                            else se->move_nodes_screen(desktop, mul*-1, 0); // no shift
633
 
                        }
634
 
                        else { // no alt
635
 
                            if (MOD__SHIFT) se->move_nodes(mul*-10*nudge, 0); // shift
636
 
                            else se->move_nodes(mul*-nudge, 0); // no shift
637
 
                        }
638
 
                        ret = TRUE;
639
 
                    }
640
 
                    break;
641
 
                case GDK_Up: // move selection up
642
 
                case GDK_KP_Up:
643
 
                case GDK_KP_8:
644
 
                    if (!MOD__CTRL) { // not ctrl
645
 
                        gint mul = 1 + gobble_key_events(
646
 
                            get_group0_keyval(&event->key), 0); // with any mask
647
 
                        if (MOD__ALT) { // alt
648
 
                            if (MOD__SHIFT) se->move_nodes_screen(desktop, 0, mul*10); // shift
649
 
                            else se->move_nodes_screen(desktop, 0, mul*1); // no shift
650
 
                        }
651
 
                        else { // no alt
652
 
                            if (MOD__SHIFT) se->move_nodes(0, mul*10*nudge); // shift
653
 
                            else se->move_nodes(0, mul*nudge); // no shift
654
 
                        }
655
 
                        ret = TRUE;
656
 
                    }
657
 
                    break;
658
 
                case GDK_Right: // move selection right
659
 
                case GDK_KP_Right:
660
 
                case GDK_KP_6:
661
 
                    if (!MOD__CTRL) { // not ctrl
662
 
                        gint mul = 1 + gobble_key_events(
663
 
                            get_group0_keyval(&event->key), 0); // with any mask
664
 
                        if (MOD__ALT) { // alt
665
 
                            if (MOD__SHIFT) se->move_nodes_screen(desktop, mul*10, 0); // shift
666
 
                            else se->move_nodes_screen(desktop, mul*1, 0); // no shift
667
 
                        }
668
 
                        else { // no alt
669
 
                            if (MOD__SHIFT) se->move_nodes(mul*10*nudge, 0); // shift
670
 
                            else se->move_nodes(mul*nudge, 0); // no shift
671
 
                        }
672
 
                        ret = TRUE;
673
 
                    }
674
 
                    break;
675
 
                case GDK_Down: // move selection down
676
 
                case GDK_KP_Down:
677
 
                case GDK_KP_2:
678
 
                    if (!MOD__CTRL) { // not ctrl
679
 
                        gint mul = 1 + gobble_key_events(
680
 
                            get_group0_keyval(&event->key), 0); // with any mask
681
 
                        if (MOD__ALT) { // alt
682
 
                            if (MOD__SHIFT) se->move_nodes_screen(desktop, 0, mul*-10); // shift
683
 
                            else se->move_nodes_screen(desktop, 0, mul*-1); // no shift
684
 
                        }
685
 
                        else { // no alt
686
 
                            if (MOD__SHIFT) se->move_nodes(0, mul*-10*nudge); // shift
687
 
                            else se->move_nodes(0, mul*-nudge); // no shift
688
 
                        }
689
 
                        ret = TRUE;
690
 
                    }
691
 
                    break;
692
 
                case GDK_Escape:
693
 
                {
694
 
                    Geom::OptRect const b = Inkscape::Rubberband::get(desktop)->getRectangle();
695
 
                    if (b) {
696
 
                        Inkscape::Rubberband::get(desktop)->stop();
697
 
                        nc->current_state = SP_NODE_CONTEXT_INACTIVE;
698
 
                        nc->rb_escaped = true;
699
 
                    } else {
700
 
                        if (se->has_selection()) {
701
 
                            se->deselect();
702
 
                        } else {
703
 
                            sp_desktop_selection(desktop)->clear();
704
 
                        }
705
 
                    }
706
 
                    ret = TRUE;
707
 
                    break;
708
 
                }
709
 
 
710
 
                case GDK_bracketleft:
711
 
                    if ( MOD__CTRL && !MOD__ALT && ( snaps != 0 ) ) {
712
 
                        if (nc->leftctrl)
713
 
                            se->rotate_nodes (M_PI/snaps, -1, false);
714
 
                        if (nc->rightctrl)
715
 
                            se->rotate_nodes (M_PI/snaps, 1, false);
716
 
                    } else if ( MOD__ALT && !MOD__CTRL ) {
717
 
                        if (nc->leftalt && nc->rightalt)
718
 
                            se->rotate_nodes (1, 0, true);
719
 
                        else {
720
 
                            if (nc->leftalt)
721
 
                                se->rotate_nodes (1, -1, true);
722
 
                            if (nc->rightalt)
723
 
                                se->rotate_nodes (1, 1, true);
724
 
                        }
725
 
                    } else if ( snaps != 0 ) {
726
 
                        se->rotate_nodes (M_PI/snaps, 0, false);
727
 
                    }
728
 
                    ret = TRUE;
729
 
                    break;
730
 
                case GDK_bracketright:
731
 
                    if ( MOD__CTRL && !MOD__ALT && ( snaps != 0 ) ) {
732
 
                        if (nc->leftctrl)
733
 
                            se->rotate_nodes (-M_PI/snaps, -1, false);
734
 
                        if (nc->rightctrl)
735
 
                            se->rotate_nodes (-M_PI/snaps, 1, false);
736
 
                    } else if ( MOD__ALT && !MOD__CTRL ) {
737
 
                        if (nc->leftalt && nc->rightalt)
738
 
                            se->rotate_nodes (-1, 0, true);
739
 
                        else {
740
 
                            if (nc->leftalt)
741
 
                                se->rotate_nodes (-1, -1, true);
742
 
                            if (nc->rightalt)
743
 
                                se->rotate_nodes (-1, 1, true);
744
 
                        }
745
 
                    } else if ( snaps != 0 ) {
746
 
                        se->rotate_nodes (-M_PI/snaps, 0, false);
747
 
                    }
748
 
                    ret = TRUE;
749
 
                    break;
750
 
                case GDK_less:
751
 
                case GDK_comma:
752
 
                    if (MOD__CTRL) {
753
 
                        if (nc->leftctrl)
754
 
                            se->scale_nodes(-offset, -1);
755
 
                        if (nc->rightctrl)
756
 
                            se->scale_nodes(-offset, 1);
757
 
                    } else if (MOD__ALT) {
758
 
                        if (nc->leftalt && nc->rightalt)
759
 
                            se->scale_nodes_screen (-1, 0);
760
 
                        else {
761
 
                            if (nc->leftalt)
762
 
                                se->scale_nodes_screen (-1, -1);
763
 
                            if (nc->rightalt)
764
 
                                se->scale_nodes_screen (-1, 1);
765
 
                        }
766
 
                    } else {
767
 
                        se->scale_nodes (-offset, 0);
768
 
                    }
769
 
                    ret = TRUE;
770
 
                    break;
771
 
                case GDK_greater:
772
 
                case GDK_period:
773
 
                    if (MOD__CTRL) {
774
 
                        if (nc->leftctrl)
775
 
                            se->scale_nodes (offset, -1);
776
 
                        if (nc->rightctrl)
777
 
                            se->scale_nodes (offset, 1);
778
 
                    } else if (MOD__ALT) {
779
 
                        if (nc->leftalt && nc->rightalt)
780
 
                            se->scale_nodes_screen (1, 0);
781
 
                        else {
782
 
                            if (nc->leftalt)
783
 
                                se->scale_nodes_screen (1, -1);
784
 
                            if (nc->rightalt)
785
 
                                se->scale_nodes_screen (1, 1);
786
 
                        }
787
 
                    } else {
788
 
                        se->scale_nodes (offset, 0);
789
 
                    }
790
 
                    ret = TRUE;
791
 
                    break;
792
 
 
793
 
                case GDK_Alt_L:
794
 
                    nc->leftalt = TRUE;
795
 
                    sp_node_context_show_modifier_tip(event_context, event);
796
 
                    break;
797
 
                case GDK_Alt_R:
798
 
                    nc->rightalt = TRUE;
799
 
                    sp_node_context_show_modifier_tip(event_context, event);
800
 
                    break;
801
 
                case GDK_Control_L:
802
 
                    nc->leftctrl = TRUE;
803
 
                    sp_node_context_show_modifier_tip(event_context, event);
804
 
                    break;
805
 
                case GDK_Control_R:
806
 
                    nc->rightctrl = TRUE;
807
 
                    sp_node_context_show_modifier_tip(event_context, event);
808
 
                    break;
809
 
                case GDK_Shift_L:
810
 
                case GDK_Shift_R:
811
 
                case GDK_Meta_L:
812
 
                case GDK_Meta_R:
813
 
                    sp_node_context_show_modifier_tip(event_context, event);
814
 
                    break;
815
 
                default:
816
 
                    ret = node_key(event);
817
 
                    break;
818
 
            }
819
 
            break;
820
 
        case GDK_KEY_RELEASE:
821
 
            switch (get_group0_keyval(&event->key)) {
822
 
                case GDK_Alt_L:
823
 
                    nc->leftalt = FALSE;
824
 
                    event_context->defaultMessageContext()->clear();
825
 
                    break;
826
 
                case GDK_Alt_R:
827
 
                    nc->rightalt = FALSE;
828
 
                    event_context->defaultMessageContext()->clear();
829
 
                    break;
830
 
                case GDK_Control_L:
831
 
                    nc->leftctrl = FALSE;
832
 
                    event_context->defaultMessageContext()->clear();
833
 
                    break;
834
 
                case GDK_Control_R:
835
 
                    nc->rightctrl = FALSE;
836
 
                    event_context->defaultMessageContext()->clear();
837
 
                    break;
838
 
                case GDK_Shift_L:
839
 
                case GDK_Shift_R:
840
 
                case GDK_Meta_L:
841
 
                case GDK_Meta_R:
842
 
                    event_context->defaultMessageContext()->clear();
843
 
                    break;
844
 
            }
845
 
            break;
846
 
        default:
847
 
            break;
848
 
    }
849
 
 
850
 
    if (!ret) {
851
 
        if (((SPEventContextClass *) parent_class)->root_handler)
852
 
            ret = ((SPEventContextClass *) parent_class)->root_handler(event_context, event);
853
 
    }
854
 
 
855
 
    return ret;
856
 
}
857
 
 
858
 
 
859
 
/*
860
 
  Local Variables:
861
 
  mode:c++
862
 
  c-file-style:"stroustrup"
863
 
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
864
 
  indent-tabs-mode:nil
865
 
  fill-column:99
866
 
  End:
867
 
*/
868
 
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :