1 #define __SP_NODE_CONTEXT_C__
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 */
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16 #include <gdk/gdkkeysyms.h>
17 #include "macros.h"
18 #include <glibmm/i18n.h>
19 #include "display/sp-canvas-util.h"
20 #include "object-edit.h"
21 #include "sp-path.h"
22 #include "path-chemistry.h"
23 #include "rubberband.h"
24 #include "desktop.h"
25 #include "desktop-handles.h"
26 #include "selection.h"
27 #include "pixmaps/cursor-node.xpm"
28 #include "message-context.h"
29 #include "node-context.h"
30 #include "pixmaps/cursor-node-d.xpm"
31 #include "prefs-utils.h"
32 #include "xml/node-event-vector.h"
33 #include "style.h"
34 #include "splivarot.h"
35 #include "shape-editor.h"
37 static void sp_node_context_class_init(SPNodeContextClass *klass);
38 static void sp_node_context_init(SPNodeContext *node_context);
39 static void sp_node_context_dispose(GObject *object);
41 static void sp_node_context_setup(SPEventContext *ec);
42 static gint sp_node_context_root_handler(SPEventContext *event_context, GdkEvent *event);
43 static gint sp_node_context_item_handler(SPEventContext *event_context,
44 SPItem *item, GdkEvent *event);
46 static SPEventContextClass *parent_class;
48 GType
49 sp_node_context_get_type()
50 {
51 static GType type = 0;
52 if (!type) {
53 GTypeInfo info = {
54 sizeof(SPNodeContextClass),
55 NULL, NULL,
56 (GClassInitFunc) sp_node_context_class_init,
57 NULL, NULL,
58 sizeof(SPNodeContext),
59 4,
60 (GInstanceInitFunc) sp_node_context_init,
61 NULL, /* value_table */
62 };
63 type = g_type_register_static(SP_TYPE_EVENT_CONTEXT, "SPNodeContext", &info, (GTypeFlags)0);
64 }
65 return type;
66 }
68 static void
69 sp_node_context_class_init(SPNodeContextClass *klass)
70 {
71 GObjectClass *object_class = (GObjectClass *) klass;
72 SPEventContextClass *event_context_class = (SPEventContextClass *) klass;
74 parent_class = (SPEventContextClass*)g_type_class_peek_parent(klass);
76 object_class->dispose = sp_node_context_dispose;
78 event_context_class->setup = sp_node_context_setup;
79 event_context_class->root_handler = sp_node_context_root_handler;
80 event_context_class->item_handler = sp_node_context_item_handler;
81 }
83 static void
84 sp_node_context_init(SPNodeContext *node_context)
85 {
86 SPEventContext *event_context = SP_EVENT_CONTEXT(node_context);
88 event_context->cursor_shape = cursor_node_xpm;
89 event_context->hot_x = 1;
90 event_context->hot_y = 1;
92 node_context->leftalt = FALSE;
93 node_context->rightalt = FALSE;
94 node_context->leftctrl = FALSE;
95 node_context->rightctrl = FALSE;
97 new (&node_context->sel_changed_connection) sigc::connection();
98 }
100 static void
101 sp_node_context_dispose(GObject *object)
102 {
103 SPNodeContext *nc = SP_NODE_CONTEXT(object);
104 SPEventContext *ec = SP_EVENT_CONTEXT(object);
106 ec->enableGrDrag(false);
108 nc->sel_changed_connection.disconnect();
109 nc->sel_changed_connection.~connection();
111 delete nc->shape_editor;
113 if (nc->_node_message_context) {
114 delete nc->_node_message_context;
115 }
117 G_OBJECT_CLASS(parent_class)->dispose(object);
118 }
120 static void
121 sp_node_context_setup(SPEventContext *ec)
122 {
123 SPNodeContext *nc = SP_NODE_CONTEXT(ec);
125 if (((SPEventContextClass *) parent_class)->setup)
126 ((SPEventContextClass *) parent_class)->setup(ec);
128 nc->sel_changed_connection.disconnect();
129 nc->sel_changed_connection = sp_desktop_selection(ec->desktop)->connectChanged(sigc::bind(sigc::ptr_fun(&sp_node_context_selection_changed), (gpointer)nc));
131 Inkscape::Selection *selection = sp_desktop_selection(ec->desktop);
132 SPItem *item = selection->singleItem();
134 nc->shape_editor = new ShapeEditor(ec->desktop);
136 nc->rb_escaped = false;
138 nc->cursor_drag = false;
140 nc->added_node = false;
142 nc->current_state = SP_NODE_CONTEXT_INACTIVE;
144 if (item) {
145 nc->shape_editor->set_item(item);
146 }
148 if (prefs_get_int_attribute("tools.nodes", "selcue", 0) != 0) {
149 ec->enableSelectionCue();
150 }
152 if (prefs_get_int_attribute("tools.nodes", "gradientdrag", 0) != 0) {
153 ec->enableGrDrag();
154 }
156 nc->_node_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack());
158 nc->shape_editor->update_statusbar();
159 }
161 /**
162 \brief Callback that processes the "changed" signal on the selection;
163 destroys old and creates new nodepath and reassigns listeners to the new selected item's repr
164 */
165 void
166 sp_node_context_selection_changed(Inkscape::Selection *selection, gpointer data)
167 {
168 SPNodeContext *nc = SP_NODE_CONTEXT(data);
170 // TODO: update ShapeEditorsCollective instead
171 nc->shape_editor->unset_item();
172 SPItem *item = selection->singleItem();
173 nc->shape_editor->set_item(item);
175 nc->shape_editor->update_statusbar();
176 }
178 void
179 sp_node_context_show_modifier_tip(SPEventContext *event_context, GdkEvent *event)
180 {
181 sp_event_show_modifier_tip
182 (event_context->defaultMessageContext(), event,
183 _("<b>Ctrl</b>: toggle node type, snap handle angle, move hor/vert; <b>Ctrl+Alt</b>: move along handles"),
184 _("<b>Shift</b>: toggle node selection, disable snapping, rotate both handles"),
185 _("<b>Alt</b>: lock handle length; <b>Ctrl+Alt</b>: move along handles"));
186 }
189 static gint
190 sp_node_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event)
191 {
192 gint ret = FALSE;
194 if (((SPEventContextClass *) parent_class)->item_handler)
195 ret = ((SPEventContextClass *) parent_class)->item_handler(event_context, item, event);
197 return ret;
198 }
200 static gint
201 sp_node_context_root_handler(SPEventContext *event_context, GdkEvent *event)
202 {
203 SPDesktop *desktop = event_context->desktop;
204 Inkscape::Selection *selection = sp_desktop_selection (desktop);
206 SPNodeContext *nc = SP_NODE_CONTEXT(event_context);
207 double const nudge = prefs_get_double_attribute_limited("options.nudgedistance", "value", 2, 0, 1000); // in px
208 event_context->tolerance = prefs_get_int_attribute_limited("options.dragtolerance", "value", 0, 0, 100); // read every time, to make prefs changes really live
209 int const snaps = prefs_get_int_attribute("options.rotationsnapsperpi", "value", 12);
210 double const offset = prefs_get_double_attribute_limited("options.defaultscale", "value", 2, 0, 1000);
212 gint ret = FALSE;
213 switch (event->type) {
214 case GDK_BUTTON_PRESS:
215 if (event->button.button == 1 && !event_context->space_panning) {
216 // save drag origin
217 event_context->xp = (gint) event->button.x;
218 event_context->yp = (gint) event->button.y;
219 event_context->within_tolerance = true;
220 nc->shape_editor->cancel_hit();
222 if (!(event->button.state & GDK_SHIFT_MASK)) {
223 if (!nc->drag) {
224 if (nc->shape_editor->has_nodepath() && selection->single() /* && item_over */) {
225 // save drag origin
226 bool over_stroke = nc->shape_editor->is_over_stroke(NR::Point(event->button.x, event->button.y), true);
227 //only dragging curves
228 if (over_stroke) {
229 ret = TRUE;
230 break;
231 }
232 }
233 }
234 }
235 NR::Point const button_w(event->button.x,
236 event->button.y);
237 NR::Point const button_dt(desktop->w2d(button_w));
238 Inkscape::Rubberband::get()->start(desktop, button_dt);
239 nc->current_state = SP_NODE_CONTEXT_INACTIVE;
240 desktop->updateNow();
241 ret = TRUE;
242 }
243 break;
244 case GDK_MOTION_NOTIFY:
245 if (event->motion.state & GDK_BUTTON1_MASK && !event_context->space_panning) {
247 if ( event_context->within_tolerance
248 && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance )
249 && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) {
250 break; // do not drag if we're within tolerance from origin
251 }
253 // The path went away while dragging; throw away any further motion
254 // events until the mouse pointer is released.
256 if (nc->shape_editor->hits_curve() && !nc->shape_editor->has_nodepath()) {
257 break;
258 }
260 // Once the user has moved farther than tolerance from the original location
261 // (indicating they intend to move the object, not click), then always process the
262 // motion notify coordinates as given (no snapping back to origin)
263 event_context->within_tolerance = false;
265 // Once we determine what the user is doing (dragging either a node or the
266 // selection rubberband), make sure we continue to perform that operation
267 // until the mouse pointer is lifted.
268 if (nc->current_state == SP_NODE_CONTEXT_INACTIVE) {
269 if (nc->shape_editor->hits_curve() && nc->shape_editor->has_nodepath()) {
270 nc->current_state = SP_NODE_CONTEXT_NODE_DRAGGING;
271 } else {
272 nc->current_state = SP_NODE_CONTEXT_RUBBERBAND_DRAGGING;
273 }
274 }
276 switch (nc->current_state) {
277 case SP_NODE_CONTEXT_NODE_DRAGGING:
278 {
279 nc->shape_editor->curve_drag (event->motion.x, event->motion.y);
281 gobble_motion_events(GDK_BUTTON1_MASK);
282 break;
283 }
284 case SP_NODE_CONTEXT_RUBBERBAND_DRAGGING:
285 if (Inkscape::Rubberband::get()->is_started()) {
286 NR::Point const motion_w(event->motion.x,
287 event->motion.y);
288 NR::Point const motion_dt(desktop->w2d(motion_w));
289 Inkscape::Rubberband::get()->move(motion_dt);
290 }
291 break;
292 }
294 nc->drag = TRUE;
295 ret = TRUE;
296 } else {
297 if (!nc->shape_editor->has_nodepath() || selection->singleItem() == NULL) {
298 break;
299 }
301 bool over_stroke = false;
302 over_stroke = nc->shape_editor->is_over_stroke(NR::Point(event->motion.x, event->motion.y), false);
304 if (nc->cursor_drag && !over_stroke) {
305 event_context->cursor_shape = cursor_node_xpm;
306 event_context->hot_x = 1;
307 event_context->hot_y = 1;
308 sp_event_context_update_cursor(event_context);
309 nc->cursor_drag = false;
310 } else if (!nc->cursor_drag && over_stroke) {
311 event_context->cursor_shape = cursor_node_d_xpm;
312 event_context->hot_x = 1;
313 event_context->hot_y = 1;
314 sp_event_context_update_cursor(event_context);
315 nc->cursor_drag = true;
316 }
317 }
318 break;
320 case GDK_2BUTTON_PRESS:
321 case GDK_BUTTON_RELEASE:
322 if ( (event->button.button == 1) && (!nc->drag) && !event_context->space_panning) {
323 // find out clicked item, disregarding groups, honoring Alt
324 SPItem *item_clicked = sp_event_context_find_item (desktop,
325 NR::Point(event->button.x, event->button.y),
326 (event->button.state & GDK_MOD1_MASK) && !(event->button.state & GDK_CONTROL_MASK), TRUE);
328 event_context->xp = event_context->yp = 0;
330 bool over_stroke = false;
331 if (nc->shape_editor->has_nodepath()) {
332 over_stroke = nc->shape_editor->is_over_stroke(NR::Point(event->button.x, event->button.y), false);
333 }
335 if (item_clicked || over_stroke) {
336 if (over_stroke || nc->added_node) {
337 switch (event->type) {
338 case GDK_BUTTON_RELEASE:
339 if (event->button.state & GDK_CONTROL_MASK && event->button.state & GDK_MOD1_MASK) {
340 //add a node
341 nc->shape_editor->add_node_near_point();
342 } else {
343 if (nc->added_node) { // we just received double click, ignore release
344 nc->added_node = false;
345 break;
346 }
347 //select the segment
348 if (event->button.state & GDK_SHIFT_MASK) {
349 nc->shape_editor->select_segment_near_point(true);
350 } else {
351 nc->shape_editor->select_segment_near_point(false);
352 }
353 desktop->updateNow();
354 }
355 break;
356 case GDK_2BUTTON_PRESS:
357 //add a node
358 nc->shape_editor->add_node_near_point();
359 nc->added_node = true;
360 break;
361 default:
362 break;
363 }
364 } else if (event->button.state & GDK_SHIFT_MASK) {
365 selection->toggle(item_clicked);
366 desktop->updateNow();
367 } else {
368 selection->set(item_clicked);
369 desktop->updateNow();
370 }
371 Inkscape::Rubberband::get()->stop();
372 ret = TRUE;
373 break;
374 }
375 }
376 if (event->type == GDK_BUTTON_RELEASE) {
377 event_context->xp = event_context->yp = 0;
378 if (event->button.button == 1) {
379 NR::Maybe<NR::Rect> b = Inkscape::Rubberband::get()->getRectangle();
381 if (nc->shape_editor->hits_curve() && !event_context->within_tolerance) { //drag curve
382 nc->shape_editor->finish_drag();
383 } else if (b && !event_context->within_tolerance) { // drag to select
384 nc->shape_editor->select_rect(*b, event->button.state & GDK_SHIFT_MASK);
385 } else {
386 if (!(nc->rb_escaped)) { // unless something was cancelled
387 if (nc->shape_editor->has_selection())
388 nc->shape_editor->deselect();
389 else
390 sp_desktop_selection(desktop)->clear();
391 }
392 }
393 ret = TRUE;
394 Inkscape::Rubberband::get()->stop();
395 desktop->updateNow();
396 nc->rb_escaped = false;
397 nc->drag = FALSE;
398 nc->shape_editor->cancel_hit();
399 nc->current_state = SP_NODE_CONTEXT_INACTIVE;
400 }
401 }
402 break;
403 case GDK_KEY_PRESS:
404 switch (get_group0_keyval(&event->key)) {
405 case GDK_Insert:
406 case GDK_KP_Insert:
407 // with any modifiers
408 nc->shape_editor->add_node();
409 ret = TRUE;
410 break;
411 case GDK_Delete:
412 case GDK_KP_Delete:
413 case GDK_BackSpace:
414 if (MOD__CTRL_ONLY) {
415 nc->shape_editor->delete_nodes();
416 } else {
417 nc->shape_editor->delete_nodes_preserving_shape();
418 }
419 ret = TRUE;
420 break;
421 case GDK_C:
422 case GDK_c:
423 if (MOD__SHIFT_ONLY) {
424 nc->shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
425 ret = TRUE;
426 }
427 break;
428 case GDK_S:
429 case GDK_s:
430 if (MOD__SHIFT_ONLY) {
431 nc->shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
432 ret = TRUE;
433 }
434 break;
435 case GDK_Y:
436 case GDK_y:
437 if (MOD__SHIFT_ONLY) {
438 nc->shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
439 ret = TRUE;
440 }
441 break;
442 case GDK_B:
443 case GDK_b:
444 if (MOD__SHIFT_ONLY) {
445 nc->shape_editor->break_at_nodes();
446 ret = TRUE;
447 }
448 break;
449 case GDK_J:
450 case GDK_j:
451 if (MOD__SHIFT_ONLY) {
452 nc->shape_editor->join_nodes();
453 ret = TRUE;
454 }
455 break;
456 case GDK_D:
457 case GDK_d:
458 if (MOD__SHIFT_ONLY) {
459 nc->shape_editor->duplicate_nodes();
460 ret = TRUE;
461 }
462 break;
463 case GDK_L:
464 case GDK_l:
465 if (MOD__SHIFT_ONLY) {
466 nc->shape_editor->set_type_of_segments(NR_LINETO);
467 ret = TRUE;
468 }
469 break;
470 case GDK_U:
471 case GDK_u:
472 if (MOD__SHIFT_ONLY) {
473 nc->shape_editor->set_type_of_segments(NR_CURVETO);
474 ret = TRUE;
475 }
476 break;
477 case GDK_R:
478 case GDK_r:
479 if (MOD__SHIFT_ONLY) {
480 // FIXME: add top panel button
481 sp_selected_path_reverse();
482 ret = TRUE;
483 }
484 break;
485 case GDK_Left: // move selection left
486 case GDK_KP_Left:
487 case GDK_KP_4:
488 if (!MOD__CTRL) { // not ctrl
489 if (MOD__ALT) { // alt
490 if (MOD__SHIFT) nc->shape_editor->move_nodes_screen(-10, 0); // shift
491 else nc->shape_editor->move_nodes_screen(-1, 0); // no shift
492 }
493 else { // no alt
494 if (MOD__SHIFT) nc->shape_editor->move_nodes(-10*nudge, 0); // shift
495 else nc->shape_editor->move_nodes(-nudge, 0); // no shift
496 }
497 ret = TRUE;
498 }
499 break;
500 case GDK_Up: // move selection up
501 case GDK_KP_Up:
502 case GDK_KP_8:
503 if (!MOD__CTRL) { // not ctrl
504 if (MOD__ALT) { // alt
505 if (MOD__SHIFT) nc->shape_editor->move_nodes_screen(0, 10); // shift
506 else nc->shape_editor->move_nodes_screen(0, 1); // no shift
507 }
508 else { // no alt
509 if (MOD__SHIFT) nc->shape_editor->move_nodes(0, 10*nudge); // shift
510 else nc->shape_editor->move_nodes(0, nudge); // no shift
511 }
512 ret = TRUE;
513 }
514 break;
515 case GDK_Right: // move selection right
516 case GDK_KP_Right:
517 case GDK_KP_6:
518 if (!MOD__CTRL) { // not ctrl
519 if (MOD__ALT) { // alt
520 if (MOD__SHIFT) nc->shape_editor->move_nodes_screen(10, 0); // shift
521 else nc->shape_editor->move_nodes_screen(1, 0); // no shift
522 }
523 else { // no alt
524 if (MOD__SHIFT) nc->shape_editor->move_nodes(10*nudge, 0); // shift
525 else nc->shape_editor->move_nodes(nudge, 0); // no shift
526 }
527 ret = TRUE;
528 }
529 break;
530 case GDK_Down: // move selection down
531 case GDK_KP_Down:
532 case GDK_KP_2:
533 if (!MOD__CTRL) { // not ctrl
534 if (MOD__ALT) { // alt
535 if (MOD__SHIFT) nc->shape_editor->move_nodes_screen(0, -10); // shift
536 else nc->shape_editor->move_nodes_screen(0, -1); // no shift
537 }
538 else { // no alt
539 if (MOD__SHIFT) nc->shape_editor->move_nodes(0, -10*nudge); // shift
540 else nc->shape_editor->move_nodes(0, -nudge); // no shift
541 }
542 ret = TRUE;
543 }
544 break;
545 case GDK_Escape:
546 {
547 NR::Maybe<NR::Rect> const b = Inkscape::Rubberband::get()->getRectangle();
548 if (b) {
549 Inkscape::Rubberband::get()->stop();
550 nc->current_state = SP_NODE_CONTEXT_INACTIVE;
551 nc->rb_escaped = true;
552 } else {
553 if (nc->shape_editor->has_selection()) {
554 nc->shape_editor->deselect();
555 } else {
556 sp_desktop_selection(desktop)->clear();
557 }
558 }
559 ret = TRUE;
560 break;
561 }
563 case GDK_bracketleft:
564 if ( MOD__CTRL && !MOD__ALT && ( snaps != 0 ) ) {
565 if (nc->leftctrl)
566 nc->shape_editor->rotate_nodes (M_PI/snaps, -1, false);
567 if (nc->rightctrl)
568 nc->shape_editor->rotate_nodes (M_PI/snaps, 1, false);
569 } else if ( MOD__ALT && !MOD__CTRL ) {
570 if (nc->leftalt && nc->rightalt)
571 nc->shape_editor->rotate_nodes (1, 0, true);
572 else {
573 if (nc->leftalt)
574 nc->shape_editor->rotate_nodes (1, -1, true);
575 if (nc->rightalt)
576 nc->shape_editor->rotate_nodes (1, 1, true);
577 }
578 } else if ( snaps != 0 ) {
579 nc->shape_editor->rotate_nodes (M_PI/snaps, 0, false);
580 }
581 ret = TRUE;
582 break;
583 case GDK_bracketright:
584 if ( MOD__CTRL && !MOD__ALT && ( snaps != 0 ) ) {
585 if (nc->leftctrl)
586 nc->shape_editor->rotate_nodes (-M_PI/snaps, -1, false);
587 if (nc->rightctrl)
588 nc->shape_editor->rotate_nodes (-M_PI/snaps, 1, false);
589 } else if ( MOD__ALT && !MOD__CTRL ) {
590 if (nc->leftalt && nc->rightalt)
591 nc->shape_editor->rotate_nodes (-1, 0, true);
592 else {
593 if (nc->leftalt)
594 nc->shape_editor->rotate_nodes (-1, -1, true);
595 if (nc->rightalt)
596 nc->shape_editor->rotate_nodes (-1, 1, true);
597 }
598 } else if ( snaps != 0 ) {
599 nc->shape_editor->rotate_nodes (-M_PI/snaps, 0, false);
600 }
601 ret = TRUE;
602 break;
603 case GDK_less:
604 case GDK_comma:
605 if (MOD__CTRL) {
606 if (nc->leftctrl)
607 nc->shape_editor->scale_nodes(-offset, -1);
608 if (nc->rightctrl)
609 nc->shape_editor->scale_nodes(-offset, 1);
610 } else if (MOD__ALT) {
611 if (nc->leftalt && nc->rightalt)
612 nc->shape_editor->scale_nodes_screen (-1, 0);
613 else {
614 if (nc->leftalt)
615 nc->shape_editor->scale_nodes_screen (-1, -1);
616 if (nc->rightalt)
617 nc->shape_editor->scale_nodes_screen (-1, 1);
618 }
619 } else {
620 nc->shape_editor->scale_nodes (-offset, 0);
621 }
622 ret = TRUE;
623 break;
624 case GDK_greater:
625 case GDK_period:
626 if (MOD__CTRL) {
627 if (nc->leftctrl)
628 nc->shape_editor->scale_nodes (offset, -1);
629 if (nc->rightctrl)
630 nc->shape_editor->scale_nodes (offset, 1);
631 } else if (MOD__ALT) {
632 if (nc->leftalt && nc->rightalt)
633 nc->shape_editor->scale_nodes_screen (1, 0);
634 else {
635 if (nc->leftalt)
636 nc->shape_editor->scale_nodes_screen (1, -1);
637 if (nc->rightalt)
638 nc->shape_editor->scale_nodes_screen (1, 1);
639 }
640 } else {
641 nc->shape_editor->scale_nodes (offset, 0);
642 }
643 ret = TRUE;
644 break;
646 case GDK_Alt_L:
647 nc->leftalt = TRUE;
648 sp_node_context_show_modifier_tip(event_context, event);
649 break;
650 case GDK_Alt_R:
651 nc->rightalt = TRUE;
652 sp_node_context_show_modifier_tip(event_context, event);
653 break;
654 case GDK_Control_L:
655 nc->leftctrl = TRUE;
656 sp_node_context_show_modifier_tip(event_context, event);
657 break;
658 case GDK_Control_R:
659 nc->rightctrl = TRUE;
660 sp_node_context_show_modifier_tip(event_context, event);
661 break;
662 case GDK_Shift_L:
663 case GDK_Shift_R:
664 case GDK_Meta_L:
665 case GDK_Meta_R:
666 sp_node_context_show_modifier_tip(event_context, event);
667 break;
668 default:
669 ret = node_key(event);
670 break;
671 }
672 break;
673 case GDK_KEY_RELEASE:
674 switch (get_group0_keyval(&event->key)) {
675 case GDK_Alt_L:
676 nc->leftalt = FALSE;
677 event_context->defaultMessageContext()->clear();
678 break;
679 case GDK_Alt_R:
680 nc->rightalt = FALSE;
681 event_context->defaultMessageContext()->clear();
682 break;
683 case GDK_Control_L:
684 nc->leftctrl = FALSE;
685 event_context->defaultMessageContext()->clear();
686 break;
687 case GDK_Control_R:
688 nc->rightctrl = FALSE;
689 event_context->defaultMessageContext()->clear();
690 break;
691 case GDK_Shift_L:
692 case GDK_Shift_R:
693 case GDK_Meta_L:
694 case GDK_Meta_R:
695 event_context->defaultMessageContext()->clear();
696 break;
697 }
698 break;
699 default:
700 break;
701 }
703 if (!ret) {
704 if (((SPEventContextClass *) parent_class)->root_handler)
705 ret = ((SPEventContextClass *) parent_class)->root_handler(event_context, event);
706 }
708 return ret;
709 }
712 /*
713 Local Variables:
714 mode:c++
715 c-file-style:"stroustrup"
716 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
717 indent-tabs-mode:nil
718 fill-column:99
719 End:
720 */
721 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :