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