Code

First (very limited) version of the 3D box tool; allows for drawing of new boxes...
[inkscape.git] / src / knotholder.cpp
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 "rect-context.h"
24 #include "sp-rect.h"
25 #include "arc-context.h"
26 #include "sp-ellipse.h"
27 #include "star-context.h"
28 #include "sp-star.h"
29 #include "spiral-context.h"
30 #include "sp-spiral.h"
31 #include "sp-offset.h"
32 #include "box3d.h"
34 #include <libnr/nr-matrix-div.h>
35 #include <glibmm/i18n.h>
37 class SPDesktop;
39 static void knot_clicked_handler (SPKnot *knot, guint state, gpointer data);
40 static void knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state, gpointer data);
41 static void knot_ungrabbed_handler (SPKnot *knot, unsigned int state, SPKnotHolder *kh);
42 static void sp_knot_holder_class_init(SPKnotHolderClass *klass);
44 void sp_knot_holder_dispose(GObject *object);
46 #ifdef KNOT_HOLDER_DEBUG
48 static void sp_knot_holder_debug(GtkObject *object, gpointer data)
49 {
50     g_print("sp-knot-holder-debug: [type=%s] [data=%s]\n", gtk_type_name(GTK_OBJECT_TYPE(object)), (const gchar *) data);
51 }
52 #endif
54 static GObjectClass *parent_class;
56 /**
57  * Registers SPKnotHolder class and returns its type number.
58  */
59 GType sp_knot_holder_get_type()
60 {
61     static GType type = 0;
62     if (!type) {
63         GTypeInfo info = {
64             sizeof(SPKnotHolderClass),
65             NULL,       /* base_init */
66             NULL,       /* base_finalize */
67             (GClassInitFunc) sp_knot_holder_class_init,
68             NULL,       /* class_finalize */
69             NULL,       /* class_data */
70             sizeof (SPKnotHolder),
71             16, /* n_preallocs */
72             NULL,
73             NULL
74         };
75         type = g_type_register_static (G_TYPE_OBJECT, "SPKnotHolder", &info, (GTypeFlags) 0);
76     }
77     return type;
78 }
80 /**
81  * SPKnotHolder vtable initialization.
82  */
83 static void sp_knot_holder_class_init(SPKnotHolderClass *klass){
84     parent_class = (GObjectClass*) g_type_class_peek_parent(klass);
85     klass->dispose = sp_knot_holder_dispose;
86 }
88 SPKnotHolder *sp_knot_holder_new(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler)
89 {
90     Inkscape::XML::Node *repr = SP_OBJECT(item)->repr;
92     g_return_val_if_fail(desktop != NULL, NULL);
93     g_return_val_if_fail(item != NULL, NULL);
94     g_return_val_if_fail(SP_IS_ITEM(item), NULL);
96     SPKnotHolder *knot_holder = (SPKnotHolder*)g_object_new (SP_TYPE_KNOT_HOLDER, 0);
97     knot_holder->desktop = desktop;
98     knot_holder->item = item;
99     g_object_ref(G_OBJECT(item));
100     knot_holder->entity = NULL;
102     knot_holder->released = relhandler;
104     knot_holder->repr = repr;
105     knot_holder->local_change = FALSE;
107 #ifdef KNOT_HOLDER_DEBUG
108     g_signal_connect(G_OBJECT(desktop), "destroy", sp_knot_holder_debug, (gpointer) "SPKnotHolder::item");
109 #endif
111     return knot_holder;
114 void sp_knot_holder_dispose(GObject *object) {
115     SPKnotHolder *kh = G_TYPE_CHECK_INSTANCE_CAST((object), SP_TYPE_KNOT_HOLDER, SPKnotHolder);
117     g_object_unref(G_OBJECT(kh->item));
118     while (kh->entity) {
119         SPKnotHolderEntity *e = (SPKnotHolderEntity *) kh->entity->data;
120         g_signal_handler_disconnect(e->knot, e->_click_handler_id);
121         g_signal_handler_disconnect(e->knot, e->_ungrab_handler_id);
122         /* unref should call destroy */
123         g_object_unref(e->knot);
124         g_free(e);
125         kh->entity = g_slist_remove(kh->entity, e);
126     }
129 void sp_knot_holder_destroy(SPKnotHolder *kh) {
130     g_object_unref(kh);
131     }
133 void sp_knot_holder_add(
134     SPKnotHolder *knot_holder,
135     SPKnotHolderSetFunc knot_set,
136     SPKnotHolderGetFunc knot_get,
137     void (* knot_click) (SPItem *item, guint state),
138     const gchar *tip
139     )
141     sp_knot_holder_add_full(knot_holder, knot_set, knot_get, knot_click, SP_KNOT_SHAPE_DIAMOND, SP_KNOT_MODE_XOR, tip);
144 void sp_knot_holder_add_full(
145     SPKnotHolder *knot_holder,
146     SPKnotHolderSetFunc knot_set,
147     SPKnotHolderGetFunc knot_get,
148     void (* knot_click) (SPItem *item, guint state),
149     SPKnotShapeType     shape,
150     SPKnotModeType      mode,
151     const gchar *tip
152     )
154     g_return_if_fail(knot_holder != NULL);
155     g_return_if_fail(knot_set != NULL);
156     g_return_if_fail(knot_get != NULL);
157         
158     SPItem *item = SP_ITEM(knot_holder->item);
160     /* create new SPKnotHolderEntry */
161     SPKnotHolderEntity *e = g_new(SPKnotHolderEntity, 1);
162     e->knot = sp_knot_new(knot_holder->desktop, tip);
163     e->knot_set = knot_set;
164     e->knot_get = knot_get;
165     if (knot_click) {
166         e->knot_click = knot_click;
167     } else {
168         e->knot_click = NULL;
169     }
171     g_object_set(G_OBJECT (e->knot->item), "shape", shape, NULL);
172     g_object_set(G_OBJECT (e->knot->item), "mode", mode, NULL);
174     // TODO: add a color argument
175     //e->knot->fill [SP_KNOT_STATE_NORMAL] = 0x00ff0000;
176     //g_object_set (G_OBJECT (e->knot->item), "fill_color", 0x00ff0000, NULL);
178     knot_holder->entity = g_slist_append(knot_holder->entity, e);
180     /* Move to current point. */
181     NR::Point dp = e->knot_get(item) * sp_item_i2d_affine(item);
182     sp_knot_set_position(e->knot, &dp, SP_KNOT_STATE_NORMAL);
184     e->handler_id = g_signal_connect(e->knot, "moved", G_CALLBACK(knot_moved_handler), knot_holder);
185     e->_click_handler_id = g_signal_connect(e->knot, "clicked", G_CALLBACK(knot_clicked_handler), knot_holder);
186     e->_ungrab_handler_id = g_signal_connect(e->knot, "ungrabbed", G_CALLBACK(knot_ungrabbed_handler), knot_holder);
188 #ifdef KNOT_HOLDER_DEBUG
189     g_signal_connect(ob, "destroy", sp_knot_holder_debug, "SPKnotHolder::knot");
190 #endif
191     sp_knot_show(e->knot);
194 /**
195  * \param p In desktop coordinates.
196  */
198 static void knotholder_update_knots(SPKnotHolder *knot_holder, SPItem *item)
200     NR::Matrix const i2d(sp_item_i2d_affine(item));
202     for (GSList *el = knot_holder->entity; el; el = el->next) {
203         SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data;
204         GObject *kob = e->knot;
206         NR::Point dp( e->knot_get(item) * i2d );
207         g_signal_handler_block(kob, e->handler_id);
208         sp_knot_set_position(e->knot, &dp, SP_KNOT_STATE_NORMAL);
209         g_signal_handler_unblock(kob, e->handler_id);
210     }
213 static void knot_clicked_handler(SPKnot *knot, guint state, gpointer data)
215     SPKnotHolder *knot_holder = (SPKnotHolder *) data;
216     SPItem *item  = SP_ITEM (knot_holder->item);
218     g_object_ref(knot_holder);
219     for (GSList *el = knot_holder->entity; el; el = el->next) {
220         SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data;
221         if (e->knot == knot) {
222             if (e->knot_click) {
223                 e->knot_click(item, state);
224             }
225             break;
226         }
227     }
229     if (SP_IS_SHAPE(item)) {
230         sp_shape_set_shape(SP_SHAPE(item));
231     }
233     knotholder_update_knots(knot_holder, item);
234     g_object_unref(knot_holder);
236     unsigned int object_verb = SP_VERB_NONE;
238     if (SP_IS_RECT(item))
239         object_verb = SP_VERB_CONTEXT_RECT;
240     else if (SP_IS_3DBOX(item))
241         object_verb = SP_VERB_CONTEXT_3DBOX;
242     else if (SP_IS_GENERICELLIPSE(item))
243         object_verb = SP_VERB_CONTEXT_ARC;
244     else if (SP_IS_STAR(item))
245         object_verb = SP_VERB_CONTEXT_STAR;
246     else if (SP_IS_SPIRAL(item))
247         object_verb = SP_VERB_CONTEXT_SPIRAL;
248     else if (SP_IS_OFFSET(item)) {
249         if (SP_OFFSET(item)->sourceHref)
250             object_verb = SP_VERB_SELECTION_LINKED_OFFSET;
251         else
252             object_verb = SP_VERB_SELECTION_DYNAMIC_OFFSET;
253     }
255     // for drag, this is done by ungrabbed_handler, but for click we must do it here
256     sp_document_done(SP_OBJECT_DOCUMENT(knot_holder->item), object_verb, 
257                      _("Change handle"));
260 static void knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state, gpointer data)
262     SPKnotHolder *knot_holder = (SPKnotHolder *) data;
263     SPItem *item  = SP_ITEM (knot_holder->item);
264     // this was a local change and the knotholder does not need to be recreated:
265     knot_holder->local_change = TRUE;
267     for (GSList *el = knot_holder->entity; el; el = el->next) {
268         SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data;
269         if (e->knot == knot) {
270             NR::Point const q = *p / sp_item_i2d_affine(item);
271             e->knot_set(item, q, e->knot->drag_origin / sp_item_i2d_affine(item), state);
272             break;
273         }
274     }
276     if (SP_IS_SHAPE (item)) {
277         sp_shape_set_shape(SP_SHAPE (item));
278     }
280     knotholder_update_knots(knot_holder, item);
283 static void knot_ungrabbed_handler(SPKnot *knot, unsigned int state, SPKnotHolder *kh)
285     if (kh->released) {
286         kh->released(kh->item);
287     } else {
288         SPObject *object = (SPObject *) kh->item;
289         object->updateRepr(object->repr, SP_OBJECT_WRITE_EXT);
291         unsigned int object_verb = SP_VERB_NONE;
293         if (SP_IS_RECT(object))
294             object_verb = SP_VERB_CONTEXT_RECT;
295         else if (SP_IS_3DBOX(object))
296             object_verb = SP_VERB_CONTEXT_3DBOX;
297         else if (SP_IS_GENERICELLIPSE(object))
298             object_verb = SP_VERB_CONTEXT_ARC;
299         else if (SP_IS_STAR(object))
300             object_verb = SP_VERB_CONTEXT_STAR;
301         else if (SP_IS_SPIRAL(object))
302             object_verb = SP_VERB_CONTEXT_SPIRAL;
303         else if (SP_IS_OFFSET(object)) {
304             if (SP_OFFSET(object)->sourceHref)
305                 object_verb = SP_VERB_SELECTION_LINKED_OFFSET;
306             else
307                 object_verb = SP_VERB_SELECTION_DYNAMIC_OFFSET;
308         }
309         
310         sp_document_done(SP_OBJECT_DOCUMENT (object), object_verb,
311                          _("Move handle"));
312     }
315 /*
316   Local Variables:
317   mode:c++
318   c-file-style:"stroustrup"
319   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
320   indent-tabs-mode:nil
321   fill-column:99
322   End:
323 */
324 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :