Code

Merge and cleanup of GSoC C++-ification project.
[inkscape.git] / src / knot.cpp
1 /** \file
2  * SPKnot implementation
3  *
4  * Authors:
5  *   Lauris Kaplinski <lauris@kaplinski.com>
6  *   bulia byak <buliabyak@users.sf.net>
7  *   Abhishek Sharma
8  *
9  * Copyright (C) 1999-2005 authors
10  * Copyright (C) 2001-2002 Ximian, Inc.
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
15 #ifdef HAVE_CONFIG_H
16 # include <config.h>
17 #endif
18 #include <gdk/gdkkeysyms.h>
19 #include <glibmm/i18n.h>
20 #include "helper/sp-marshal.h"
21 #include "display/sodipodi-ctrl.h"
22 #include "desktop.h"
23 #include "desktop-handles.h"
24 #include "knot.h"
25 #include "document.h"
26 #include "preferences.h"
27 #include "message-stack.h"
28 #include "message-context.h"
29 #include "event-context.h"
31 using Inkscape::DocumentUndo;
33 #define KNOT_EVENT_MASK (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | \
34                          GDK_POINTER_MOTION_MASK | \
35                          GDK_POINTER_MOTION_HINT_MASK | \
36                          GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK)
38 static bool nograb = false;
40 static bool grabbed = FALSE;
41 static bool moved = FALSE;
43 static gint xp = 0, yp = 0; // where drag started
44 static gint tolerance = 0;
45 static bool within_tolerance = false;
47 static bool transform_escaped = false; // true iff resize or rotate was cancelled by esc.
49 enum {
50     EVENT,
51     CLICKED,
52     DOUBLECLICKED,
53     GRABBED,
54     UNGRABBED,
55     MOVED,
56     REQUEST,
57     DISTANCE,
58     LAST_SIGNAL
59 };
61 static void sp_knot_class_init(SPKnotClass *klass);
62 static void sp_knot_init(SPKnot *knot);
63 static void sp_knot_dispose(GObject *object);
65 static int sp_knot_handler(SPCanvasItem *item, GdkEvent *event, SPKnot *knot);
66 static void sp_knot_set_ctrl_state(SPKnot *knot);
68 static GObjectClass *parent_class;
69 static guint knot_signals[LAST_SIGNAL] = { 0 };
71 /**
72  * Registers SPKnot class and returns its type number.
73  */
74 GType sp_knot_get_type()
75 {
76     static GType type = 0;
77     if (!type) {
78         GTypeInfo info = {
79             sizeof(SPKnotClass),
80             NULL,       /* base_init */
81             NULL,       /* base_finalize */
82             (GClassInitFunc) sp_knot_class_init,
83             NULL,       /* class_finalize */
84             NULL,       /* class_data */
85             sizeof (SPKnot),
86             16, /* n_preallocs */
87             (GInstanceInitFunc) sp_knot_init,
88             NULL
89         };
90         type = g_type_register_static (G_TYPE_OBJECT, "SPKnot", &info, (GTypeFlags) 0);
91     }
92     return type;
93 }
95 /**
96  * SPKnot vtable initialization.
97  */
98 static void sp_knot_class_init(SPKnotClass *klass)
99 {
100     GObjectClass *object_class = (GObjectClass*)klass;
102     parent_class = (GObjectClass*) g_type_class_peek_parent(klass);
104     object_class->dispose = sp_knot_dispose;
106     knot_signals[EVENT] = g_signal_new("event",
107                                        G_TYPE_FROM_CLASS(klass),
108                                        G_SIGNAL_RUN_LAST,
109                                        G_STRUCT_OFFSET(SPKnotClass, event),
110                                        NULL, NULL,
111                                        sp_marshal_BOOLEAN__POINTER,
112                                        G_TYPE_BOOLEAN, 1,
113                                        GDK_TYPE_EVENT);
115     knot_signals[CLICKED] = g_signal_new("clicked",
116                                          G_TYPE_FROM_CLASS(klass),
117                                          G_SIGNAL_RUN_FIRST,
118                                          G_STRUCT_OFFSET(SPKnotClass, clicked),
119                                          NULL, NULL,
120                                          g_cclosure_marshal_VOID__UINT,
121                                          G_TYPE_NONE, 1,
122                                          G_TYPE_UINT);
124     knot_signals[DOUBLECLICKED] = g_signal_new("doubleclicked",
125                                                G_TYPE_FROM_CLASS(klass),
126                                                G_SIGNAL_RUN_FIRST,
127                                                G_STRUCT_OFFSET(SPKnotClass, doubleclicked),
128                                                NULL, NULL,
129                                                g_cclosure_marshal_VOID__UINT,
130                                                G_TYPE_NONE, 1,
131                                                G_TYPE_UINT);
133     knot_signals[GRABBED] = g_signal_new("grabbed",
134                                           G_TYPE_FROM_CLASS(klass),
135                                           G_SIGNAL_RUN_FIRST,
136                                           G_STRUCT_OFFSET(SPKnotClass, grabbed),
137                                           NULL, NULL,
138                                           g_cclosure_marshal_VOID__UINT,
139                                           G_TYPE_NONE, 1,
140                                           G_TYPE_UINT);
142     knot_signals[UNGRABBED] = g_signal_new("ungrabbed",
143                                             G_TYPE_FROM_CLASS(klass),
144                                             G_SIGNAL_RUN_FIRST,
145                                             G_STRUCT_OFFSET(SPKnotClass, ungrabbed),
146                                             NULL, NULL,
147                                             g_cclosure_marshal_VOID__UINT,
148                                             G_TYPE_NONE, 1,
149                                             G_TYPE_UINT);
151     knot_signals[MOVED] = g_signal_new("moved",
152                                         G_TYPE_FROM_CLASS(klass),
153                                         G_SIGNAL_RUN_FIRST,
154                                         G_STRUCT_OFFSET(SPKnotClass, moved),
155                                         NULL, NULL,
156                                         sp_marshal_NONE__POINTER_UINT,
157                                         G_TYPE_NONE, 2,
158                                         G_TYPE_POINTER, G_TYPE_UINT);
160     knot_signals[REQUEST] = g_signal_new("request",
161                                          G_TYPE_FROM_CLASS(klass),
162                                          G_SIGNAL_RUN_LAST,
163                                          G_STRUCT_OFFSET(SPKnotClass, request),
164                                          NULL, NULL,
165                                          sp_marshal_BOOLEAN__POINTER_UINT,
166                                          G_TYPE_BOOLEAN, 2,
167                                          G_TYPE_POINTER, G_TYPE_UINT);
169     knot_signals[DISTANCE] = g_signal_new("distance",
170                                            G_TYPE_FROM_CLASS(klass),
171                                            G_SIGNAL_RUN_LAST,
172                                            G_STRUCT_OFFSET(SPKnotClass, distance),
173                                            NULL, NULL,
174                                            sp_marshal_DOUBLE__POINTER_UINT,
175                                            G_TYPE_DOUBLE, 2,
176                                            G_TYPE_POINTER, G_TYPE_UINT);
178     const gchar *nograbenv = getenv("INKSCAPE_NO_GRAB");
179     nograb = (nograbenv && *nograbenv && (*nograbenv != '0'));
182 /**
183  * Callback for SPKnot initialization.
184  */
185 static void sp_knot_init(SPKnot *knot)
187     knot->desktop = NULL;
188     knot->item = NULL;
189     knot->flags = 0;
191     knot->size = 8;
192     knot->pos = Geom::Point(0, 0);
193     knot->grabbed_rel_pos = Geom::Point(0, 0);
194     knot->anchor = GTK_ANCHOR_CENTER;
195     knot->shape = SP_KNOT_SHAPE_SQUARE;
196     knot->mode = SP_KNOT_MODE_XOR;
197     knot->tip = NULL;
198     knot->_event_handler_id = 0;
199     knot->pressure = 0;
201     knot->fill[SP_KNOT_STATE_NORMAL] = 0xffffff00;
202     knot->fill[SP_KNOT_STATE_MOUSEOVER] = 0xff0000ff;
203     knot->fill[SP_KNOT_STATE_DRAGGING] = 0x0000ffff;
205     knot->stroke[SP_KNOT_STATE_NORMAL] = 0x01000000;
206     knot->stroke[SP_KNOT_STATE_MOUSEOVER] = 0x01000000;
207     knot->stroke[SP_KNOT_STATE_DRAGGING] = 0x01000000;
209     knot->image[SP_KNOT_STATE_NORMAL] = NULL;
210     knot->image[SP_KNOT_STATE_MOUSEOVER] = NULL;
211     knot->image[SP_KNOT_STATE_DRAGGING] = NULL;
213     knot->cursor[SP_KNOT_STATE_NORMAL] = NULL;
214     knot->cursor[SP_KNOT_STATE_MOUSEOVER] = NULL;
215     knot->cursor[SP_KNOT_STATE_DRAGGING] = NULL;
217     knot->saved_cursor = NULL;
218     knot->pixbuf = NULL;
221 /**
222  * Called before SPKnot destruction.
223  */
224 static void sp_knot_dispose(GObject *object)
226     SPKnot *knot = (SPKnot *) object;
228     if ((knot->flags & SP_KNOT_GRABBED) && gdk_pointer_is_grabbed ()) {
229         // This happens e.g. when deleting a node in node tool while dragging it
230         gdk_pointer_ungrab (GDK_CURRENT_TIME);
231     }
233     if (knot->_event_handler_id > 0)
234         {
235         g_signal_handler_disconnect(G_OBJECT (knot->item), knot->_event_handler_id);
236         knot->_event_handler_id = 0;
237         }
239     if (knot->item) {
240         gtk_object_destroy (GTK_OBJECT (knot->item));
241         knot->item = NULL;
242     }
244     for (gint i = 0; i < SP_KNOT_VISIBLE_STATES; i++) {
245         if (knot->cursor[i]) {
246             gdk_cursor_unref(knot->cursor[i]);
247             knot->cursor[i] = NULL;
248         }
249     }
251     if (knot->tip) {
252         g_free(knot->tip);
253         knot->tip = NULL;
254     }
256     if (parent_class->dispose) {
257         (*parent_class->dispose) (object);
258     }
261 /**
262  * Update knot for dragging and tell canvas an item was grabbed.
263  */
264 void sp_knot_start_dragging(SPKnot *knot, Geom::Point const &p, gint x, gint y, guint32 etime)
266     // save drag origin
267     xp = x;
268     yp = y;
269     within_tolerance = true;
271     knot->grabbed_rel_pos = p - knot->pos;
272     knot->drag_origin = knot->pos;
273     if (!nograb) {
274         sp_canvas_item_grab(knot->item,
275                             KNOT_EVENT_MASK,
276                             knot->cursor[SP_KNOT_STATE_DRAGGING],
277                             etime);
278     }
279     sp_knot_set_flag(knot, SP_KNOT_GRABBED, TRUE);
280     grabbed = TRUE;
283 /**
284  * Called to handle events on knots.
285  */
286 static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot)
288     g_assert(knot != NULL);
289     g_assert(SP_IS_KNOT(knot));
291     /* Run client universal event handler, if present */
293     gboolean consumed = FALSE;
295     g_signal_emit(knot, knot_signals[EVENT], 0, event, &consumed);
297     if (consumed) {
298         return TRUE;
299     }
301     g_object_ref(knot);
302     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
303     tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
305     switch (event->type) {
306     case GDK_2BUTTON_PRESS:
307             if (event->button.button == 1) {
308                 g_signal_emit(knot, knot_signals[DOUBLECLICKED], 0, event->button.state);
310                 grabbed = FALSE;
311                 moved = FALSE;
312                 consumed = TRUE;
313             }
314             break;
315     case GDK_BUTTON_PRESS:
316             if (event->button.button == 1 && !knot->desktop->event_context->space_panning) {
317                 Geom::Point const p = knot->desktop->w2d(Geom::Point(event->button.x, event->button.y));
318                 sp_knot_start_dragging(knot, p, (gint) event->button.x, (gint) event->button.y, event->button.time);
319                 consumed = TRUE;
320             }
321             break;
322     case GDK_BUTTON_RELEASE:
323             if (event->button.button == 1 && !knot->desktop->event_context->space_panning) {
324                 // If we have any pending snap event, then invoke it now
325                 if (knot->desktop->event_context->_delayed_snap_event) {
326                     sp_event_context_snap_watchdog_callback(knot->desktop->event_context->_delayed_snap_event);
327                 }
329                 sp_event_context_discard_delayed_snap_event(knot->desktop->event_context);
331                 knot->pressure = 0;
332                 if (transform_escaped) {
333                     transform_escaped = false;
334                     consumed = TRUE;
335                 } else {
336                     sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE);
337                     if (!nograb) {
338                         sp_canvas_item_ungrab(knot->item, event->button.time);
339                     }
340                     if (moved) {
341                         sp_knot_set_flag(knot,
342                                          SP_KNOT_DRAGGING,
343                                          FALSE);
344                         g_signal_emit(knot,
345                                       knot_signals[UNGRABBED], 0,
346                                       event->button.state);
347                         knot->_ungrabbed_signal.emit(knot);
348                     } else {
349                         g_signal_emit(knot,
350                                       knot_signals[CLICKED], 0,
351                                       event->button.state);
352                         knot->_click_signal.emit(knot, event->button.state);
353                     }
354                     grabbed = FALSE;
355                     moved = FALSE;
356                     consumed = TRUE;
357                 }
358             }
359             break;
360     case GDK_MOTION_NOTIFY:
361             if (grabbed && !knot->desktop->event_context->space_panning) {
362                 consumed = TRUE;
364                 if ( within_tolerance
365                      && ( abs( (gint) event->motion.x - xp ) < tolerance )
366                      && ( abs( (gint) event->motion.y - yp ) < tolerance ) ) {
367                     break; // do not drag if we're within tolerance from origin
368                 }
370                 // Once the user has moved farther than tolerance from the original location
371                 // (indicating they intend to move the object, not click), then always process the
372                 // motion notify coordinates as given (no snapping back to origin)
373                 within_tolerance = false;
375                 if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &knot->pressure))
376                     knot->pressure = CLAMP (knot->pressure, 0, 1);
377                 else
378                     knot->pressure = 0.5;
380                 if (!moved) {
381                     g_signal_emit(knot,
382                                   knot_signals[GRABBED], 0,
383                                   event->motion.state);
384                     sp_knot_set_flag(knot,
385                                      SP_KNOT_DRAGGING,
386                                      TRUE);
387                 }
388                 sp_event_context_snap_delay_handler(knot->desktop->event_context, NULL, (gpointer) knot, (GdkEventMotion *)event, DelayedSnapEvent::KNOT_HANDLER);
389                 sp_knot_handler_request_position(event, knot);
390                 moved = TRUE;
391             }
392             break;
393     case GDK_ENTER_NOTIFY:
394             sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, TRUE);
395             sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE);
397             if (knot->tip) {
398                 knot->desktop->event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, knot->tip);
399             }
401             grabbed = FALSE;
402             moved = FALSE;
403             consumed = TRUE;
404             break;
405     case GDK_LEAVE_NOTIFY:
406             sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, FALSE);
407             sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE);
409             if (knot->tip) {
410                 knot->desktop->event_context->defaultMessageContext()->clear();
411             }
413             grabbed = FALSE;
414             moved = FALSE;
415             consumed = TRUE;
416             break;
417     case GDK_KEY_PRESS: // keybindings for knot
418             switch (get_group0_keyval(&event->key)) {
419                 case GDK_Escape:
420                             sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE);
421                             if (!nograb) {
422                                 sp_canvas_item_ungrab(knot->item, event->button.time);
423                             }
424                             if (moved) {
425                                 sp_knot_set_flag(knot,
426                                                  SP_KNOT_DRAGGING,
427                                                  FALSE);
428                                 g_signal_emit(knot,
429                                               knot_signals[UNGRABBED], 0,
430                                               event->button.state);
431                                 DocumentUndo::undo(sp_desktop_document(knot->desktop));
432                                 knot->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Node or handle drag canceled."));
433                                 transform_escaped = true;
434                                 consumed = TRUE;
435                             }
436                             grabbed = FALSE;
437                             moved = FALSE;
438                             sp_event_context_discard_delayed_snap_event(knot->desktop->event_context);
439                             break;
440                 default:
441                             consumed = FALSE;
442                             break;
443                     }
444                     break;
445     default:
446             break;
447     }
449     g_object_unref(knot);
451     return consumed || grabbed;
454 void sp_knot_handler_request_position(GdkEvent *event, SPKnot *knot)
456     Geom::Point const motion_w(event->motion.x, event->motion.y);
457     Geom::Point const motion_dt = knot->desktop->w2d(motion_w);
458     Geom::Point p = motion_dt - knot->grabbed_rel_pos;
459     sp_knot_request_position (knot, p, event->motion.state);
460     knot->desktop->scroll_to_point (motion_dt);
461     knot->desktop->set_coordinate_status(knot->pos); // display the coordinate of knot, not cursor - they may be different!
462     if (event->motion.state & GDK_BUTTON1_MASK)
463         gobble_motion_events(GDK_BUTTON1_MASK);
466 /**
467  * Return new knot object.
468  */
469 SPKnot *sp_knot_new(SPDesktop *desktop, const gchar *tip)
471     g_return_val_if_fail(desktop != NULL, NULL);
473     SPKnot * knot = (SPKnot*) g_object_new(SP_TYPE_KNOT, 0);
475     knot->desktop = desktop;
476     knot->flags = SP_KNOT_VISIBLE;
477     if (tip) {
478         knot->tip = g_strdup (tip);
479     }
481     knot->item = sp_canvas_item_new(sp_desktop_controls (desktop),
482                                     SP_TYPE_CTRL,
483                                     "anchor", GTK_ANCHOR_CENTER,
484                                     "size", 8.0,
485                                     "filled", TRUE,
486                                     "fill_color", 0xffffff00,
487                                     "stroked", TRUE,
488                                     "stroke_color", 0x01000000,
489                                     "mode", SP_KNOT_MODE_XOR,
490                                     NULL);
492     knot->_event_handler_id = gtk_signal_connect(GTK_OBJECT(knot->item), "event",
493                                                  GTK_SIGNAL_FUNC(sp_knot_handler), knot);
495     return knot;
498 /**
499  * Show knot on its canvas.
500  */
501 void sp_knot_show(SPKnot *knot)
503     g_return_if_fail(knot != NULL);
504     g_return_if_fail(SP_IS_KNOT (knot));
506     sp_knot_set_flag(knot, SP_KNOT_VISIBLE, TRUE);
509 /**
510  * Hide knot on its canvas.
511  */
512 void sp_knot_hide(SPKnot *knot)
514     g_return_if_fail(knot != NULL);
515     g_return_if_fail(SP_IS_KNOT(knot));
517     sp_knot_set_flag(knot, SP_KNOT_VISIBLE, FALSE);
520 /**
521  * Request or set new position for knot.
522  */
523 void sp_knot_request_position(SPKnot *knot, Geom::Point const &p, guint state)
525     g_return_if_fail(knot != NULL);
526     g_return_if_fail(SP_IS_KNOT(knot));
528     gboolean done = FALSE;
530     g_signal_emit(knot,
531                   knot_signals[REQUEST], 0,
532                   &p,
533                   state,
534                   &done);
536     /* If user did not complete, we simply move knot to new position */
538     if (!done) {
539         sp_knot_set_position (knot, p, state);
540     }
543 /**
544  * Return distance of point to knot's position; unused.
545  */
546 gdouble sp_knot_distance(SPKnot * knot, Geom::Point const &p, guint state)
548     g_return_val_if_fail(knot != NULL, 1e18);
549     g_return_val_if_fail(SP_IS_KNOT(knot), 1e18);
551     gdouble distance = Geom::L2(p - knot->pos);
553     g_signal_emit(knot,
554                   knot_signals[DISTANCE], 0,
555                   &p,
556                   state,
557                   &distance);
559     return distance;
562 /**
563  * Move knot to new position.
564  */
565 void sp_knot_set_position(SPKnot *knot, Geom::Point const &p, guint state)
567     g_return_if_fail(knot != NULL);
568     g_return_if_fail(SP_IS_KNOT (knot));
570     knot->pos = p;
572     if (knot->item) {
573         SP_CTRL(knot->item)->moveto (p);
574     }
576     g_signal_emit(knot,
577                   knot_signals[MOVED], 0,
578                   &p,
579                   state);
580     knot->_moved_signal.emit(knot, p, state);
583 /**
584  * Move knot to new position, without emitting a MOVED signal.
585  */
586 void sp_knot_moveto(SPKnot *knot, Geom::Point const &p)
588     g_return_if_fail(knot != NULL);
589     g_return_if_fail(SP_IS_KNOT(knot));
591     knot->pos = p;
593     if (knot->item) {
594         SP_CTRL(knot->item)->moveto (p);
595     }
598 /**
599  * Returns position of knot.
600  */
601 Geom::Point sp_knot_position(SPKnot const *knot)
603     g_assert(knot != NULL);
604     g_assert(SP_IS_KNOT (knot));
606     return knot->pos;
609 /**
610  * Set flag in knot, with side effects.
611  */
612 void sp_knot_set_flag(SPKnot *knot, guint flag, bool set)
614     g_assert(knot != NULL);
615     g_assert(SP_IS_KNOT(knot));
617     if (set) {
618         knot->flags |= flag;
619     } else {
620         knot->flags &= ~flag;
621     }
623     switch (flag) {
624     case SP_KNOT_VISIBLE:
625             if (set) {
626                 sp_canvas_item_show(knot->item);
627             } else {
628                 sp_canvas_item_hide(knot->item);
629             }
630             break;
631     case SP_KNOT_MOUSEOVER:
632     case SP_KNOT_DRAGGING:
633             sp_knot_set_ctrl_state(knot);
634             break;
635     case SP_KNOT_GRABBED:
636             break;
637     default:
638             g_assert_not_reached();
639             break;
640     }
643 /**
644  * Update knot's pixbuf and set its control state.
645  */
646 void sp_knot_update_ctrl(SPKnot *knot)
648     if (!knot->item) {
649         return;
650     }
652     gtk_object_set(GTK_OBJECT(knot->item), "shape", knot->shape, NULL);
653     gtk_object_set(GTK_OBJECT(knot->item), "mode", knot->mode, NULL);
654     gtk_object_set(GTK_OBJECT(knot->item), "size", (gdouble) knot->size, NULL);
655     gtk_object_set(GTK_OBJECT(knot->item), "anchor", knot->anchor, NULL);
656     if (knot->pixbuf) {
657         gtk_object_set(GTK_OBJECT (knot->item), "pixbuf", knot->pixbuf, NULL);
658     }
660     sp_knot_set_ctrl_state(knot);
663 /**
664  * Set knot control state (dragging/mouseover/normal).
665  */
666 static void sp_knot_set_ctrl_state(SPKnot *knot)
668     if (knot->flags & SP_KNOT_DRAGGING) {
669         gtk_object_set(GTK_OBJECT (knot->item),
670                        "fill_color",
671                        knot->fill[SP_KNOT_STATE_DRAGGING],
672                        NULL);
673         gtk_object_set(GTK_OBJECT (knot->item),
674                        "stroke_color",
675                        knot->stroke[SP_KNOT_STATE_DRAGGING],
676                        NULL);
677     } else if (knot->flags & SP_KNOT_MOUSEOVER) {
678         gtk_object_set(GTK_OBJECT(knot->item),
679                        "fill_color",
680                        knot->fill[SP_KNOT_STATE_MOUSEOVER],
681                        NULL);
682         gtk_object_set(GTK_OBJECT(knot->item),
683                        "stroke_color",
684                        knot->stroke[SP_KNOT_STATE_MOUSEOVER],
685                        NULL);
686     } else {
687         gtk_object_set(GTK_OBJECT(knot->item),
688                        "fill_color",
689                         knot->fill[SP_KNOT_STATE_NORMAL],
690                        NULL);
691         gtk_object_set(GTK_OBJECT(knot->item),
692                        "stroke_color",
693                        knot->stroke[SP_KNOT_STATE_NORMAL],
694                        NULL);
695     }
700 /*
701   Local Variables:
702   mode:c++
703   c-file-style:"stroustrup"
704   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
705   indent-tabs-mode:nil
706   fill-column:99
707   End:
708 */
709 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :