1 /*
2 * Inkscape::ShapeEditor
3 *
4 * Authors:
5 * bulia byak <buliabyak@users.sf.net>
6 * Krzysztof KosiĆski <tweenk.pl@gmail.com>
7 *
8 */
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
14 #include <string.h>
15 #include <glibmm/i18n.h>
17 #include "sp-object.h"
18 #include "sp-item.h"
19 #include "sp-lpe-item.h"
20 #include "live_effects/lpeobject.h"
21 #include "selection.h"
22 #include "desktop.h"
23 #include "document.h"
24 #include "desktop-handles.h"
25 #include "knotholder.h"
26 #include "live_effects/parameter/point.h"
27 #include "xml/node-event-vector.h"
28 #include "preferences.h"
29 #include "object-edit.h"
30 #include "style.h"
31 #include "display/curve.h"
32 #include <2geom/pathvector.h>
34 #include "shape-editor.h"
36 ShapeEditor::ShapeEditor(SPDesktop *dt) {
37 this->desktop = dt;
38 this->knotholder = NULL;
39 this->knotholder_listener_attached_for = NULL;
40 }
42 ShapeEditor::~ShapeEditor() {
43 unset_item(SH_KNOTHOLDER);
44 }
46 void ShapeEditor::unset_item(SubType type, bool keep_knotholder) {
47 Inkscape::XML::Node *old_repr = NULL;
49 switch (type) {
50 case SH_NODEPATH:
51 // defunct
52 break;
53 case SH_KNOTHOLDER:
54 if (this->knotholder) {
55 old_repr = this->knotholder->repr;
56 if (old_repr && old_repr == knotholder_listener_attached_for) {
57 sp_repr_remove_listener_by_data(old_repr, this);
58 Inkscape::GC::release(old_repr);
59 knotholder_listener_attached_for = NULL;
60 }
62 if (!keep_knotholder) {
63 delete this->knotholder;
64 this->knotholder = NULL;
65 }
66 }
67 break;
68 }
69 }
71 bool ShapeEditor::has_nodepath () {
72 return false;
73 }
75 bool ShapeEditor::has_knotholder () {
76 return (this->knotholder != NULL);
77 }
79 void ShapeEditor::update_knotholder () {
80 if (this->knotholder)
81 this->knotholder->update_knots();
82 }
84 bool ShapeEditor::has_local_change (SubType type) {
85 switch (type) {
86 case SH_NODEPATH:
87 // defunct
88 return false;
89 case SH_KNOTHOLDER:
90 return (this->knotholder && this->knotholder->local_change != 0);
91 default:
92 g_assert_not_reached();
93 }
94 }
96 void ShapeEditor::decrement_local_change (SubType type) {
97 switch (type) {
98 case SH_NODEPATH:
99 // defunct
100 break;
101 case SH_KNOTHOLDER:
102 if (this->knotholder) {
103 this->knotholder->local_change = FALSE;
104 }
105 break;
106 default:
107 g_assert_not_reached();
108 }
109 }
111 const SPItem *ShapeEditor::get_item (SubType type) {
112 const SPItem *item = NULL;
113 switch (type) {
114 case SH_NODEPATH:
115 // defunct
116 break;
117 case SH_KNOTHOLDER:
118 if (this->has_knotholder()) {
119 item = this->knotholder->getItem();
120 }
121 break;
122 }
123 return item;
124 }
126 GList *ShapeEditor::save_nodepath_selection () {
127 // defunct stub
128 return NULL;
129 }
131 void ShapeEditor::restore_nodepath_selection (GList */*saved*/) {
132 // defunct stub
133 }
135 void ShapeEditor::shapeeditor_event_attr_changed(gchar const *name)
136 {
137 gboolean changed_kh = FALSE;
139 if (has_knotholder())
140 {
141 changed_kh = !has_local_change(SH_KNOTHOLDER);
142 decrement_local_change(SH_KNOTHOLDER);
143 if (changed_kh) {
144 // this can happen if an LPEItem's knotholder handle was dragged, in which case we want
145 // to keep the knotholder; in all other cases (e.g., if the LPE itself changes) we delete it
146 reset_item(SH_KNOTHOLDER, !strcmp(name, "d"));
147 }
148 }
149 }
152 static void shapeeditor_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const *name,
153 gchar const */*old_value*/, gchar const */*new_value*/,
154 bool /*is_interactive*/, gpointer data)
155 {
156 g_assert(data);
157 ShapeEditor *sh = ((ShapeEditor *) data);
159 sh->shapeeditor_event_attr_changed(name);
160 }
162 static Inkscape::XML::NodeEventVector shapeeditor_repr_events = {
163 NULL, /* child_added */
164 NULL, /* child_removed */
165 shapeeditor_event_attr_changed,
166 NULL, /* content_changed */
167 NULL /* order_changed */
168 };
171 void ShapeEditor::set_item(SPItem *item, SubType type, bool keep_knotholder) {
172 // this happens (and should only happen) when for an LPEItem having both knotholder and
173 // nodepath the knotholder is adapted; in this case we don't want to delete the knotholder
174 // since this freezes the handles
175 unset_item(type, keep_knotholder);
177 if (item) {
178 Inkscape::XML::Node *repr;
179 switch(type) {
180 case SH_NODEPATH:
181 // defunct
182 break;
184 case SH_KNOTHOLDER:
185 if (!this->knotholder) {
186 // only recreate knotholder if none is present
187 this->knotholder = sp_item_knot_holder(item, desktop);
188 }
189 if (this->knotholder) {
190 this->knotholder->update_knots();
191 // setting new listener
192 repr = this->knotholder->repr;
193 if (repr != knotholder_listener_attached_for) {
194 Inkscape::GC::anchor(repr);
195 sp_repr_add_listener(repr, &shapeeditor_repr_events, this);
196 knotholder_listener_attached_for = repr;
197 }
198 }
199 break;
200 }
201 }
202 }
205 /** FIXME: This thing is only called when the item needs to be updated in response to repr change.
206 Why not make a reload function in NodePath and in KnotHolder? */
207 void ShapeEditor::reset_item (SubType type, bool keep_knotholder)
208 {
209 switch (type) {
210 case SH_NODEPATH:
211 // defunct
212 break;
213 case SH_KNOTHOLDER:
214 if ( knotholder ) {
215 SPObject *obj = sp_desktop_document(desktop)->getObjectByRepr(knotholder_listener_attached_for); /// note that it is not certain that this is an SPItem; it could be a LivePathEffectObject.
216 set_item(SP_ITEM(obj), SH_KNOTHOLDER, keep_knotholder);
217 }
218 break;
219 }
220 }
222 void ShapeEditor::nodepath_destroyed () {
223 }
225 bool ShapeEditor::has_selection() {
226 return false; // so far, knotholder cannot have selection
227 }
229 /**
230 * \brief Returns true if this ShapeEditor has a knot above which the mouse currently hovers
231 */
232 bool ShapeEditor::knot_mouseover()
233 {
234 if (this->knotholder) {
235 return knotholder->knot_mouseover();
236 }
237 return false;
238 }
240 /*
241 Local Variables:
242 mode:c++
243 c-file-style:"stroustrup"
244 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
245 indent-tabs-mode:nil
246 fill-column:99
247 End:
248 */
249 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :