1 #define __KNOT_HOLDER_C__
3 /*
4 * Container for SPKnot visual handles
5 *
6 * Authors:
7 * Mitsuru Oka <oka326@parkcity.ne.jp>
8 * bulia byak <buliabyak@users.sf.net>
9 *
10 * Copyright (C) 2001-2005 authors
11 *
12 * Released under GNU GPL, read the file 'COPYING' for more information
13 */
15 #define noKNOT_HOLDER_DEBUG
18 #include "document.h"
19 #include "sp-shape.h"
20 #include "knot.h"
21 #include "knotholder.h"
22 #include "knot-holder-entity.h"
23 #include <libnr/nr-matrix-div.h>
25 class SPDesktop;
27 static void knot_clicked_handler (SPKnot *knot, guint state, gpointer data);
28 static void knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state, gpointer data);
29 static void knot_ungrabbed_handler (SPKnot *knot, unsigned int state, SPKnotHolder *kh);
31 #ifdef KNOT_HOLDER_DEBUG
33 static void sp_knot_holder_debug(GtkObject *object, gpointer data)
34 {
35 g_print("sp-knot-holder-debug: [type=%s] [data=%s]\n", gtk_type_name(GTK_OBJECT_TYPE(object)), (const gchar *) data);
36 }
37 #endif
39 SPKnotHolder *sp_knot_holder_new(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler)
40 {
41 Inkscape::XML::Node *repr = SP_OBJECT(item)->repr;
43 g_return_val_if_fail(desktop != NULL, NULL);
44 g_return_val_if_fail(item != NULL, NULL);
45 g_return_val_if_fail(SP_IS_ITEM(item), NULL);
47 SPKnotHolder *knot_holder = g_new(SPKnotHolder, 1);
48 knot_holder->desktop = desktop;
49 knot_holder->item = item;
50 g_object_ref(G_OBJECT(item));
51 knot_holder->entity = NULL;
53 knot_holder->released = relhandler;
55 knot_holder->repr = repr;
56 knot_holder->local_change = FALSE;
58 #ifdef KNOT_HOLDER_DEBUG
59 g_signal_connect(G_OBJECT(desktop), "destroy", sp_knot_holder_debug, (gpointer) "SPKnotHolder::item");
60 #endif
62 return knot_holder;
63 }
65 void sp_knot_holder_destroy(SPKnotHolder *kh)
66 {
67 if (kh) {
68 g_object_unref(G_OBJECT(kh->item));
69 while (kh->entity) {
70 SPKnotHolderEntity *e = (SPKnotHolderEntity *) kh->entity->data;
71 /* unref should call destroy */
72 g_object_unref(G_OBJECT(e->knot));
73 g_free(e);
74 kh->entity = g_slist_remove(kh->entity, e);
75 }
77 g_free(kh);
78 }
79 }
81 void sp_knot_holder_add(
82 SPKnotHolder *knot_holder,
83 SPKnotHolderSetFunc knot_set,
84 SPKnotHolderGetFunc knot_get,
85 void (* knot_click) (SPItem *item, guint state),
86 const gchar *tip
87 )
88 {
89 sp_knot_holder_add_full(knot_holder, knot_set, knot_get, knot_click, SP_KNOT_SHAPE_DIAMOND, SP_KNOT_MODE_XOR, tip);
90 }
92 void sp_knot_holder_add_full(
93 SPKnotHolder *knot_holder,
94 SPKnotHolderSetFunc knot_set,
95 SPKnotHolderGetFunc knot_get,
96 void (* knot_click) (SPItem *item, guint state),
97 SPKnotShapeType shape,
98 SPKnotModeType mode,
99 const gchar *tip
100 )
101 {
102 g_return_if_fail(knot_holder != NULL);
103 g_return_if_fail(knot_set != NULL);
104 g_return_if_fail(knot_get != NULL);
106 SPItem *item = SP_ITEM(knot_holder->item);
108 /* create new SPKnotHolderEntry */
109 SPKnotHolderEntity *e = g_new(SPKnotHolderEntity, 1);
110 e->knot = sp_knot_new(knot_holder->desktop, tip);
111 e->knot_set = knot_set;
112 e->knot_get = knot_get;
113 if (knot_click) {
114 e->knot_click = knot_click;
115 } else {
116 e->knot_click = NULL;
117 }
119 g_object_set(G_OBJECT (e->knot->item), "shape", shape, NULL);
120 g_object_set(G_OBJECT (e->knot->item), "mode", mode, NULL);
122 // TODO: add a color argument
123 //e->knot->fill [SP_KNOT_STATE_NORMAL] = 0x00ff0000;
124 //g_object_set (G_OBJECT (e->knot->item), "fill_color", 0x00ff0000, NULL);
126 knot_holder->entity = g_slist_append(knot_holder->entity, e);
128 /* Move to current point. */
129 NR::Point dp = e->knot_get(item) * sp_item_i2d_affine(item);
130 sp_knot_set_position(e->knot, &dp, SP_KNOT_STATE_NORMAL);
132 e->handler_id = g_signal_connect(G_OBJECT(e->knot), "moved", G_CALLBACK(knot_moved_handler), knot_holder);
133 g_signal_connect(G_OBJECT(e->knot), "clicked", G_CALLBACK(knot_clicked_handler), knot_holder);
134 g_signal_connect(G_OBJECT(e->knot), "ungrabbed", G_CALLBACK(knot_ungrabbed_handler), knot_holder);
136 #ifdef KNOT_HOLDER_DEBUG
137 g_signal_connect(ob, "destroy", sp_knot_holder_debug, "SPKnotHolder::knot");
138 #endif
139 sp_knot_show(e->knot);
140 }
142 /**
143 * \param p In desktop coordinates.
144 */
146 static void knotholder_update_knots(SPKnotHolder *knot_holder, SPItem *item)
147 {
148 NR::Matrix const i2d(sp_item_i2d_affine(item));
150 for (GSList *el = knot_holder->entity; el; el = el->next) {
151 SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data;
152 GObject *kob = G_OBJECT(e->knot);
154 NR::Point dp( e->knot_get(item) * i2d );
155 g_signal_handler_block(kob, e->handler_id);
156 sp_knot_set_position(e->knot, &dp, SP_KNOT_STATE_NORMAL);
157 g_signal_handler_unblock(kob, e->handler_id);
158 }
159 }
161 static void knot_clicked_handler(SPKnot *knot, guint state, gpointer data)
162 {
163 SPKnotHolder *knot_holder = (SPKnotHolder *) data;
164 SPItem *item = SP_ITEM (knot_holder->item);
166 for (GSList *el = knot_holder->entity; el; el = el->next) {
167 SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data;
168 if (e->knot == knot) {
169 if (e->knot_click) {
170 e->knot_click(item, state);
171 }
172 break;
173 }
174 }
176 if (SP_IS_SHAPE(item)) {
177 sp_shape_set_shape(SP_SHAPE(item));
178 }
180 knotholder_update_knots(knot_holder, item);
182 // for drag, this is done by ungrabbed_handler, but for click we must do it here
183 sp_document_done(SP_OBJECT_DOCUMENT(knot_holder->item));
184 }
186 static void knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state, gpointer data)
187 {
188 SPKnotHolder *knot_holder = (SPKnotHolder *) data;
189 SPItem *item = SP_ITEM (knot_holder->item);
190 // this was a local change and the knotholder does not need to be recreated:
191 knot_holder->local_change = TRUE;
193 for (GSList *el = knot_holder->entity; el; el = el->next) {
194 SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data;
195 if (e->knot == knot) {
196 NR::Point const q = *p / sp_item_i2d_affine(item);
197 e->knot_set(item, q, e->knot->drag_origin / sp_item_i2d_affine(item), state);
198 break;
199 }
200 }
202 if (SP_IS_SHAPE (item)) {
203 sp_shape_set_shape(SP_SHAPE (item));
204 }
206 knotholder_update_knots(knot_holder, item);
207 }
209 static void knot_ungrabbed_handler(SPKnot *knot, unsigned int state, SPKnotHolder *kh)
210 {
211 if (kh->released) {
212 kh->released(kh->item);
213 } else {
214 SPObject *object = (SPObject *) kh->item;
215 object->updateRepr(object->repr, SP_OBJECT_WRITE_EXT);
216 sp_document_done(SP_OBJECT_DOCUMENT (object));
217 }
218 }
220 /*
221 Local Variables:
222 mode:c++
223 c-file-style:"stroustrup"
224 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
225 indent-tabs-mode:nil
226 fill-column:99
227 End:
228 */
229 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :