Code

fixed broken page unit changing in Document Properties
[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);
30 static void sp_knot_holder_class_init(SPKnotHolderClass *klass);
32 void sp_knot_holder_dispose(GObject *object);
34 #ifdef KNOT_HOLDER_DEBUG
36 static void sp_knot_holder_debug(GtkObject *object, gpointer data)
37 {
38     g_print("sp-knot-holder-debug: [type=%s] [data=%s]\n", gtk_type_name(GTK_OBJECT_TYPE(object)), (const gchar *) data);
39 }
40 #endif
42 static GObjectClass *parent_class;
44 /**
45  * Registers SPKnotHolder class and returns its type number.
46  */
47 GType sp_knot_holder_get_type()
48 {
49     static GType type = 0;
50     if (!type) {
51         GTypeInfo info = {
52             sizeof(SPKnotHolderClass),
53             NULL,       /* base_init */
54             NULL,       /* base_finalize */
55             (GClassInitFunc) sp_knot_holder_class_init,
56             NULL,       /* class_finalize */
57             NULL,       /* class_data */
58             sizeof (SPKnotHolder),
59             16, /* n_preallocs */
60             NULL,
61             NULL
62         };
63         type = g_type_register_static (G_TYPE_OBJECT, "SPKnotHolder", &info, (GTypeFlags) 0);
64     }
65     return type;
66 }
68 /**
69  * SPKnotHolder vtable initialization.
70  */
71 static void sp_knot_holder_class_init(SPKnotHolderClass *klass){
72     parent_class = (GObjectClass*) g_type_class_peek_parent(klass);
73     klass->dispose = sp_knot_holder_dispose;
74 }
76 SPKnotHolder *sp_knot_holder_new(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler)
77 {
78     Inkscape::XML::Node *repr = SP_OBJECT(item)->repr;
80     g_return_val_if_fail(desktop != NULL, NULL);
81     g_return_val_if_fail(item != NULL, NULL);
82     g_return_val_if_fail(SP_IS_ITEM(item), NULL);
84     SPKnotHolder *knot_holder = (SPKnotHolder*)g_object_new (SP_TYPE_KNOT_HOLDER, 0);
85     knot_holder->desktop = desktop;
86     knot_holder->item = item;
87     g_object_ref(G_OBJECT(item));
88     knot_holder->entity = NULL;
90     knot_holder->released = relhandler;
92     knot_holder->repr = repr;
93     knot_holder->local_change = FALSE;
95 #ifdef KNOT_HOLDER_DEBUG
96     g_signal_connect(G_OBJECT(desktop), "destroy", sp_knot_holder_debug, (gpointer) "SPKnotHolder::item");
97 #endif
99     return knot_holder;
102 void sp_knot_holder_dispose(GObject *object) {
103     SPKnotHolder *kh = G_TYPE_CHECK_INSTANCE_CAST((object), SP_TYPE_KNOT_HOLDER, SPKnotHolder);
105     g_object_unref(G_OBJECT(kh->item));
106     while (kh->entity) {
107         SPKnotHolderEntity *e = (SPKnotHolderEntity *) kh->entity->data;
108         g_signal_handler_disconnect(e->knot, e->_click_handler_id);
109         g_signal_handler_disconnect(e->knot, e->_ungrab_handler_id);
110         /* unref should call destroy */
111         g_object_unref(e->knot);
112         g_free(e);
113         kh->entity = g_slist_remove(kh->entity, e);
114     }
117 void sp_knot_holder_destroy(SPKnotHolder *kh) {
118     g_object_unref(kh);
119     }
121 void sp_knot_holder_add(
122     SPKnotHolder *knot_holder,
123     SPKnotHolderSetFunc knot_set,
124     SPKnotHolderGetFunc knot_get,
125     void (* knot_click) (SPItem *item, guint state),
126     const gchar *tip
127     )
129     sp_knot_holder_add_full(knot_holder, knot_set, knot_get, knot_click, SP_KNOT_SHAPE_DIAMOND, SP_KNOT_MODE_XOR, tip);
132 void sp_knot_holder_add_full(
133     SPKnotHolder *knot_holder,
134     SPKnotHolderSetFunc knot_set,
135     SPKnotHolderGetFunc knot_get,
136     void (* knot_click) (SPItem *item, guint state),
137     SPKnotShapeType     shape,
138     SPKnotModeType      mode,
139     const gchar *tip
140     )
142     g_return_if_fail(knot_holder != NULL);
143     g_return_if_fail(knot_set != NULL);
144     g_return_if_fail(knot_get != NULL);
145         
146     SPItem *item = SP_ITEM(knot_holder->item);
148     /* create new SPKnotHolderEntry */
149     SPKnotHolderEntity *e = g_new(SPKnotHolderEntity, 1);
150     e->knot = sp_knot_new(knot_holder->desktop, tip);
151     e->knot_set = knot_set;
152     e->knot_get = knot_get;
153     if (knot_click) {
154         e->knot_click = knot_click;
155     } else {
156         e->knot_click = NULL;
157     }
159     g_object_set(G_OBJECT (e->knot->item), "shape", shape, NULL);
160     g_object_set(G_OBJECT (e->knot->item), "mode", mode, NULL);
162     // TODO: add a color argument
163     //e->knot->fill [SP_KNOT_STATE_NORMAL] = 0x00ff0000;
164     //g_object_set (G_OBJECT (e->knot->item), "fill_color", 0x00ff0000, NULL);
166     knot_holder->entity = g_slist_append(knot_holder->entity, e);
168     /* Move to current point. */
169     NR::Point dp = e->knot_get(item) * sp_item_i2d_affine(item);
170     sp_knot_set_position(e->knot, &dp, SP_KNOT_STATE_NORMAL);
172     e->handler_id = g_signal_connect(e->knot, "moved", G_CALLBACK(knot_moved_handler), knot_holder);
173     e->_click_handler_id = g_signal_connect(e->knot, "clicked", G_CALLBACK(knot_clicked_handler), knot_holder);
174     e->_ungrab_handler_id = g_signal_connect(e->knot, "ungrabbed", G_CALLBACK(knot_ungrabbed_handler), knot_holder);
176 #ifdef KNOT_HOLDER_DEBUG
177     g_signal_connect(ob, "destroy", sp_knot_holder_debug, "SPKnotHolder::knot");
178 #endif
179     sp_knot_show(e->knot);
182 /**
183  * \param p In desktop coordinates.
184  */
186 static void knotholder_update_knots(SPKnotHolder *knot_holder, SPItem *item)
188     NR::Matrix const i2d(sp_item_i2d_affine(item));
190     for (GSList *el = knot_holder->entity; el; el = el->next) {
191         SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data;
192         GObject *kob = e->knot;
194         NR::Point dp( e->knot_get(item) * i2d );
195         g_signal_handler_block(kob, e->handler_id);
196         sp_knot_set_position(e->knot, &dp, SP_KNOT_STATE_NORMAL);
197         g_signal_handler_unblock(kob, e->handler_id);
198     }
201 static void knot_clicked_handler(SPKnot *knot, guint state, gpointer data)
203     SPKnotHolder *knot_holder = (SPKnotHolder *) data;
204     SPItem *item  = SP_ITEM (knot_holder->item);
206     g_object_ref(knot_holder);
207     for (GSList *el = knot_holder->entity; el; el = el->next) {
208         SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data;
209         if (e->knot == knot) {
210             if (e->knot_click) {
211                 e->knot_click(item, state);
212             }
213             break;
214         }
215     }
217     if (SP_IS_SHAPE(item)) {
218         sp_shape_set_shape(SP_SHAPE(item));
219     }
221     knotholder_update_knots(knot_holder, item);
222     g_object_unref(knot_holder);
224     // for drag, this is done by ungrabbed_handler, but for click we must do it here
225     sp_document_done(SP_OBJECT_DOCUMENT(knot_holder->item));
228 static void knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state, gpointer data)
230     SPKnotHolder *knot_holder = (SPKnotHolder *) data;
231     SPItem *item  = SP_ITEM (knot_holder->item);
232     // this was a local change and the knotholder does not need to be recreated:
233     knot_holder->local_change = TRUE;
235     for (GSList *el = knot_holder->entity; el; el = el->next) {
236         SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data;
237         if (e->knot == knot) {
238             NR::Point const q = *p / sp_item_i2d_affine(item);
239             e->knot_set(item, q, e->knot->drag_origin / sp_item_i2d_affine(item), state);
240             break;
241         }
242     }
244     if (SP_IS_SHAPE (item)) {
245         sp_shape_set_shape(SP_SHAPE (item));
246     }
248     knotholder_update_knots(knot_holder, item);
251 static void knot_ungrabbed_handler(SPKnot *knot, unsigned int state, SPKnotHolder *kh)
253     if (kh->released) {
254         kh->released(kh->item);
255     } else {
256         SPObject *object = (SPObject *) kh->item;
257         object->updateRepr(object->repr, SP_OBJECT_WRITE_EXT);
258         sp_document_done(SP_OBJECT_DOCUMENT (object));
259     }
262 /*
263   Local Variables:
264   mode:c++
265   c-file-style:"stroustrup"
266   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
267   indent-tabs-mode:nil
268   fill-column:99
269   End:
270 */
271 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :