1 #define INKSCAPE_LPE_POINTPARAM_KNOTHOLDER_C\r
2 \r
3 /*\r
4 * Container for PointParamKnotHolder visual handles\r
5 *\r
6 * Authors:\r
7 * Johan Engelen <goejendaagh@zonnet.nl>\r
8 *\r
9 * Copyright (C) 2008 authors\r
10 *\r
11 * Released under GNU GPL, read the file 'COPYING' for more information\r
12 */\r
13 \r
14 #include "live_effects/parameter/pointparam-knotholder.h"\r
15 #include "live_effects/lpeobject.h"\r
16 #include "document.h"\r
17 #include "sp-shape.h"\r
18 #include "knot.h"\r
19 #include "knotholder.h"\r
20 #include "knot-holder-entity.h"\r
21 \r
22 #include <libnr/nr-matrix-div.h>\r
23 #include <glibmm/i18n.h>\r
24 #include <2geom/point.h>\r
25 #include <2geom/matrix.h>\r
26 #include "svg/stringstream.h"\r
27 #include "xml/repr.h"\r
28 \r
29 class SPDesktop;\r
30 \r
31 static void pointparam_knot_clicked_handler (SPKnot *knot, guint state, gpointer data);\r
32 static void pointparam_knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state, gpointer data);\r
33 static void pointparam_knot_ungrabbed_handler (SPKnot *knot, unsigned int state, PointParamKnotHolder *kh);\r
34 static void pointparam_knot_holder_class_init(PointParamKnotHolderClass *klass);\r
35 \r
36 void pointparam_knot_holder_dispose(GObject *object);\r
37 \r
38 static SPKnotHolderClass *parent_class;\r
39 \r
40 /**\r
41 * Registers SPKnotHolder class and returns its type number.\r
42 */\r
43 GType pointparam_knot_holder_get_type()\r
44 {\r
45 static GType type = 0;\r
46 if (!type) {\r
47 GTypeInfo info = {\r
48 sizeof(PointParamKnotHolderClass),\r
49 NULL, /* base_init */\r
50 NULL, /* base_finalize */\r
51 (GClassInitFunc) pointparam_knot_holder_class_init,\r
52 NULL, /* class_finalize */\r
53 NULL, /* class_data */\r
54 sizeof (PointParamKnotHolder),\r
55 16, /* n_preallocs */\r
56 NULL,\r
57 NULL\r
58 };\r
59 type = g_type_register_static (G_TYPE_OBJECT, "InkscapePointParamKnotHolder", &info, (GTypeFlags) 0);\r
60 }\r
61 return type;\r
62 }\r
63 \r
64 /**\r
65 * PointParamKnotHolder vtable initialization.\r
66 */\r
67 static void pointparam_knot_holder_class_init(PointParamKnotHolderClass *klass)\r
68 {\r
69 GObjectClass *gobject_class;\r
70 gobject_class = (GObjectClass *) klass;\r
71 \r
72 parent_class = (SPKnotHolderClass*) g_type_class_peek_parent(klass);\r
73 gobject_class->dispose = pointparam_knot_holder_dispose;\r
74 }\r
75 \r
76 PointParamKnotHolder *pointparam_knot_holder_new(SPDesktop *desktop, SPObject *lpeobject, const gchar * key, SPItem *item)\r
77 {\r
78 g_return_val_if_fail(desktop != NULL, NULL);\r
79 g_return_val_if_fail(item != NULL, NULL);\r
80 g_return_val_if_fail(SP_IS_ITEM(item), NULL);\r
81 \r
82 PointParamKnotHolder *knot_holder = (PointParamKnotHolder*)g_object_new (INKSCAPE_TYPE_POINTPARAM_KNOT_HOLDER, 0);\r
83 knot_holder->desktop = desktop;\r
84 knot_holder->item = item;\r
85 knot_holder->lpeobject = LIVEPATHEFFECT(lpeobject);\r
86 g_object_ref(G_OBJECT(item));\r
87 g_object_ref(G_OBJECT(lpeobject));\r
88 knot_holder->entity = NULL;\r
89 \r
90 knot_holder->released = NULL;\r
91 \r
92 knot_holder->repr = lpeobject->repr;\r
93 knot_holder->repr_key = key;\r
94 \r
95 knot_holder->local_change = FALSE;\r
96 \r
97 return knot_holder;\r
98 }\r
99 \r
100 void pointparam_knot_holder_dispose(GObject *object) {\r
101 PointParamKnotHolder *kh = G_TYPE_CHECK_INSTANCE_CAST((object), INKSCAPE_TYPE_POINTPARAM_KNOT_HOLDER, PointParamKnotHolder);\r
102 \r
103 g_object_unref(G_OBJECT(kh->item));\r
104 g_object_unref(G_OBJECT(kh->lpeobject));\r
105 while (kh->entity) {\r
106 SPKnotHolderEntity *e = (SPKnotHolderEntity *) kh->entity->data;\r
107 g_signal_handler_disconnect(e->knot, e->_click_handler_id);\r
108 g_signal_handler_disconnect(e->knot, e->_ungrab_handler_id);\r
109 /* unref should call destroy */\r
110 g_object_unref(e->knot);\r
111 g_free(e);\r
112 kh->entity = g_slist_remove(kh->entity, e);\r
113 }\r
114 }\r
115 \r
116 void pointparam_knot_holder_destroy(PointParamKnotHolder *kh) {\r
117 g_object_unref(kh);\r
118 }\r
119 \r
120 void pointparam_knot_holder_add_full(\r
121 PointParamKnotHolder *knot_holder,\r
122 Geom::Point & p,\r
123 void (* knot_click) (SPItem *item, guint state),\r
124 SPKnotShapeType shape,\r
125 SPKnotModeType mode,\r
126 guint32 color,\r
127 const gchar *tip )\r
128 {\r
129 g_return_if_fail(knot_holder != NULL);\r
130 \r
131 SPItem *item = SP_ITEM(knot_holder->item);\r
132 \r
133 /* create new SPKnotHolderEntry */\r
134 SPKnotHolderEntity *e = g_new(SPKnotHolderEntity, 1);\r
135 e->knot = sp_knot_new(knot_holder->desktop, tip);\r
136 e->knot_set = NULL;\r
137 e->knot_get = NULL;\r
138 if (knot_click) {\r
139 e->knot_click = knot_click;\r
140 } else {\r
141 e->knot_click = NULL;\r
142 }\r
143 \r
144 g_object_set(G_OBJECT (e->knot->item), "shape", shape, NULL);\r
145 g_object_set(G_OBJECT (e->knot->item), "mode", mode, NULL);\r
146 \r
147 e->knot->fill [SP_KNOT_STATE_NORMAL] = color;\r
148 g_object_set (G_OBJECT (e->knot->item), "fill_color", color, NULL);\r
149 \r
150 knot_holder->entity = g_slist_append(knot_holder->entity, e);\r
151 \r
152 /* Move to current point. */\r
153 NR::Point dp = p * sp_item_i2d_affine(item);\r
154 sp_knot_set_position(e->knot, &dp, SP_KNOT_STATE_NORMAL);\r
155 \r
156 e->handler_id = g_signal_connect(e->knot, "moved", G_CALLBACK(pointparam_knot_moved_handler), knot_holder);\r
157 e->_click_handler_id = g_signal_connect(e->knot, "clicked", G_CALLBACK(pointparam_knot_clicked_handler), knot_holder);\r
158 e->_ungrab_handler_id = g_signal_connect(e->knot, "ungrabbed", G_CALLBACK(pointparam_knot_ungrabbed_handler), knot_holder);\r
159 \r
160 sp_knot_show(e->knot);\r
161 }\r
162 \r
163 /**\r
164 * \param p In desktop coordinates.\r
165 */\r
166 \r
167 // don't write to XML yet...\r
168 //static\r
169 void pointparam_knotholder_update_knots(PointParamKnotHolder *knot_holder, SPItem *item)\r
170 {\r
171 \r
172 NR::Matrix const i2d(sp_item_i2d_affine(item));\r
173 /*\r
174 for (GSList *el = knot_holder->entity; el; el = el->next) {\r
175 SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data;\r
176 GObject *kob = e->knot;\r
177 \r
178 NR::Point dp( e->knot_get(item) * i2d );\r
179 g_signal_handler_block(kob, e->handler_id);\r
180 sp_knot_set_position(e->knot, &dp, SP_KNOT_STATE_NORMAL);\r
181 g_signal_handler_unblock(kob, e->handler_id);\r
182 }\r
183 \r
184 knot_holder->lpeobject->lpe->setParameter(np->repr_key, svgpath);\r
185 \r
186 knot_holder->lpeobject->requestModified(SP_OBJECT_MODIFIED_FLAG);\r
187 */\r
188 }\r
189 \r
190 static void pointparam_knot_clicked_handler(SPKnot *knot, guint state, gpointer data)\r
191 {\r
192 \r
193 SPKnotHolder *knot_holder = (SPKnotHolder *) data;\r
194 SPItem *item = SP_ITEM (knot_holder->item);\r
195 /*\r
196 g_object_ref(knot_holder);\r
197 for (GSList *el = knot_holder->entity; el; el = el->next) {\r
198 SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data;\r
199 if (e->knot == knot) {\r
200 if (e->knot_click) {\r
201 e->knot_click(item, state);\r
202 }\r
203 break;\r
204 }\r
205 }\r
206 \r
207 if (SP_IS_SHAPE(item)) {\r
208 sp_shape_set_shape(SP_SHAPE(item));\r
209 }\r
210 \r
211 knotholder_update_knots(knot_holder, item);\r
212 g_object_unref(knot_holder);\r
213 \r
214 // for drag, this is done by ungrabbed_handler, but for click we must do it here\r
215 sp_document_done(SP_OBJECT_DOCUMENT(knot_holder->item), SP_VERB_CONTEXT_LPE, \r
216 _("Change LPE point parameter"));\r
217 */\r
218 }\r
219 \r
220 static void pointparam_knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state, gpointer data)\r
221 {\r
222 \r
223 SPKnotHolder *knot_holder = (SPKnotHolder *) data;\r
224 SPItem *item = SP_ITEM (knot_holder->item);\r
225 /* // this was a local change and the knotholder does not need to be recreated:\r
226 knot_holder->local_change = TRUE;\r
227 \r
228 for (GSList *el = knot_holder->entity; el; el = el->next) {\r
229 SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data;\r
230 if (e->knot == knot) {\r
231 NR::Point const q = *p / sp_item_i2d_affine(item);\r
232 e->knot_set(item, q, e->knot->drag_origin / sp_item_i2d_affine(item), state);\r
233 break;\r
234 }\r
235 }\r
236 \r
237 if (SP_IS_SHAPE (item)) {\r
238 sp_shape_set_shape(SP_SHAPE (item));\r
239 }\r
240 \r
241 knotholder_update_knots(knot_holder, item);\r
242 */\r
243 }\r
244 \r
245 static void pointparam_knot_ungrabbed_handler(SPKnot *knot, unsigned int /*state*/, PointParamKnotHolder *kh)\r
246 {\r
247 NR::Matrix const i2d(sp_item_i2d_affine(kh->item));\r
248 NR::Point pos = sp_knot_position(knot) / i2d;\r
249 \r
250 Inkscape::SVGOStringStream os;\r
251 os << pos[0] << "," << pos[1];\r
252 \r
253 kh->repr->setAttribute(kh->repr_key , os.str().c_str());\r
254 \r
255 sp_document_done(SP_OBJECT_DOCUMENT (kh->lpeobject), SP_VERB_CONTEXT_LPE, _("Change LPE point parameter"));\r
256 }\r
257 \r
258 /*\r
259 Local Variables:\r
260 mode:c++\r
261 c-file-style:"stroustrup"\r
262 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
263 indent-tabs-mode:nil\r
264 fill-column:99\r
265 End:\r
266 */\r
267 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r