Code

0ea3ed98ab49ab9c1c377aa7236c81dbc37ee8a6
[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 <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     )
102     g_return_if_fail(knot_holder != NULL);
103     g_return_if_fail(knot_set != NULL);
104     g_return_if_fail(knot_get != NULL);
105         
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);
142 /**
143  * \param p In desktop coordinates.
144  */
146 static void knotholder_update_knots(SPKnotHolder *knot_holder, SPItem *item)
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     }
161 static void knot_clicked_handler(SPKnot *knot, guint state, gpointer data)
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));
186 static void knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state, gpointer data)
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);
209 static void knot_ungrabbed_handler(SPKnot *knot, unsigned int state, SPKnotHolder *kh)
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     }
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 :