#define __KNOT_HOLDER_C__ /* * Container for SPKnot visual handles * * Authors: * Mitsuru Oka * bulia byak * * Copyright (C) 2001-2005 authors * * Released under GNU GPL, read the file 'COPYING' for more information */ #define noKNOT_HOLDER_DEBUG #include "document.h" #include "sp-shape.h" #include "knot.h" #include "knotholder.h" #include "knot-holder-entity.h" #include "rect-context.h" #include "sp-rect.h" #include "arc-context.h" #include "sp-ellipse.h" #include "star-context.h" #include "sp-star.h" #include "spiral-context.h" #include "sp-spiral.h" #include "sp-offset.h" #include "box3d.h" #include #include class SPDesktop; static void knot_clicked_handler (SPKnot *knot, guint state, gpointer data); static void knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state, gpointer data); static void knot_ungrabbed_handler (SPKnot *knot, unsigned int state, SPKnotHolder *kh); static void sp_knot_holder_class_init(SPKnotHolderClass *klass); void sp_knot_holder_dispose(GObject *object); #ifdef KNOT_HOLDER_DEBUG static void sp_knot_holder_debug(GtkObject *object, gpointer data) { g_print("sp-knot-holder-debug: [type=%s] [data=%s]\n", gtk_type_name(GTK_OBJECT_TYPE(object)), (const gchar *) data); } #endif static GObjectClass *parent_class; /** * Registers SPKnotHolder class and returns its type number. */ GType sp_knot_holder_get_type() { static GType type = 0; if (!type) { GTypeInfo info = { sizeof(SPKnotHolderClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) sp_knot_holder_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (SPKnotHolder), 16, /* n_preallocs */ NULL, NULL }; type = g_type_register_static (G_TYPE_OBJECT, "SPKnotHolder", &info, (GTypeFlags) 0); } return type; } /** * SPKnotHolder vtable initialization. */ static void sp_knot_holder_class_init(SPKnotHolderClass *klass){ parent_class = (GObjectClass*) g_type_class_peek_parent(klass); klass->dispose = sp_knot_holder_dispose; } SPKnotHolder *sp_knot_holder_new(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler) { Inkscape::XML::Node *repr = SP_OBJECT(item)->repr; g_return_val_if_fail(desktop != NULL, NULL); g_return_val_if_fail(item != NULL, NULL); g_return_val_if_fail(SP_IS_ITEM(item), NULL); SPKnotHolder *knot_holder = (SPKnotHolder*)g_object_new (SP_TYPE_KNOT_HOLDER, 0); knot_holder->desktop = desktop; knot_holder->item = item; g_object_ref(G_OBJECT(item)); knot_holder->entity = NULL; knot_holder->released = relhandler; knot_holder->repr = repr; knot_holder->local_change = FALSE; #ifdef KNOT_HOLDER_DEBUG g_signal_connect(G_OBJECT(desktop), "destroy", sp_knot_holder_debug, (gpointer) "SPKnotHolder::item"); #endif return knot_holder; } void sp_knot_holder_dispose(GObject *object) { SPKnotHolder *kh = G_TYPE_CHECK_INSTANCE_CAST((object), SP_TYPE_KNOT_HOLDER, SPKnotHolder); g_object_unref(G_OBJECT(kh->item)); while (kh->entity) { SPKnotHolderEntity *e = (SPKnotHolderEntity *) kh->entity->data; g_signal_handler_disconnect(e->knot, e->_click_handler_id); g_signal_handler_disconnect(e->knot, e->_ungrab_handler_id); /* unref should call destroy */ g_object_unref(e->knot); g_free(e); kh->entity = g_slist_remove(kh->entity, e); } } void sp_knot_holder_destroy(SPKnotHolder *kh) { g_object_unref(kh); } void sp_knot_holder_add( SPKnotHolder *knot_holder, SPKnotHolderSetFunc knot_set, SPKnotHolderGetFunc knot_get, void (* knot_click) (SPItem *item, guint state), const gchar *tip ) { sp_knot_holder_add_full(knot_holder, knot_set, knot_get, knot_click, SP_KNOT_SHAPE_DIAMOND, SP_KNOT_MODE_XOR, tip); } void sp_knot_holder_add_full( SPKnotHolder *knot_holder, SPKnotHolderSetFunc knot_set, SPKnotHolderGetFunc knot_get, void (* knot_click) (SPItem *item, guint state), SPKnotShapeType shape, SPKnotModeType mode, const gchar *tip ) { g_return_if_fail(knot_holder != NULL); g_return_if_fail(knot_set != NULL); g_return_if_fail(knot_get != NULL); SPItem *item = SP_ITEM(knot_holder->item); /* create new SPKnotHolderEntry */ SPKnotHolderEntity *e = g_new(SPKnotHolderEntity, 1); e->knot = sp_knot_new(knot_holder->desktop, tip); e->knot_set = knot_set; e->knot_get = knot_get; if (knot_click) { e->knot_click = knot_click; } else { e->knot_click = NULL; } g_object_set(G_OBJECT (e->knot->item), "shape", shape, NULL); g_object_set(G_OBJECT (e->knot->item), "mode", mode, NULL); // TODO: add a color argument //e->knot->fill [SP_KNOT_STATE_NORMAL] = 0x00ff0000; //g_object_set (G_OBJECT (e->knot->item), "fill_color", 0x00ff0000, NULL); knot_holder->entity = g_slist_append(knot_holder->entity, e); /* Move to current point. */ NR::Point dp = e->knot_get(item) * sp_item_i2d_affine(item); sp_knot_set_position(e->knot, &dp, SP_KNOT_STATE_NORMAL); e->handler_id = g_signal_connect(e->knot, "moved", G_CALLBACK(knot_moved_handler), knot_holder); e->_click_handler_id = g_signal_connect(e->knot, "clicked", G_CALLBACK(knot_clicked_handler), knot_holder); e->_ungrab_handler_id = g_signal_connect(e->knot, "ungrabbed", G_CALLBACK(knot_ungrabbed_handler), knot_holder); #ifdef KNOT_HOLDER_DEBUG g_signal_connect(ob, "destroy", sp_knot_holder_debug, "SPKnotHolder::knot"); #endif sp_knot_show(e->knot); } /** * \param p In desktop coordinates. */ //static void knotholder_update_knots(SPKnotHolder *knot_holder, SPItem *item) { NR::Matrix const i2d(sp_item_i2d_affine(item)); for (GSList *el = knot_holder->entity; el; el = el->next) { SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data; GObject *kob = e->knot; NR::Point dp( e->knot_get(item) * i2d ); g_signal_handler_block(kob, e->handler_id); sp_knot_set_position(e->knot, &dp, SP_KNOT_STATE_NORMAL); g_signal_handler_unblock(kob, e->handler_id); } } static void knot_clicked_handler(SPKnot *knot, guint state, gpointer data) { SPKnotHolder *knot_holder = (SPKnotHolder *) data; SPItem *item = SP_ITEM (knot_holder->item); g_object_ref(knot_holder); for (GSList *el = knot_holder->entity; el; el = el->next) { SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data; if (e->knot == knot) { if (e->knot_click) { e->knot_click(item, state); } break; } } if (SP_IS_SHAPE(item)) { sp_shape_set_shape(SP_SHAPE(item)); } knotholder_update_knots(knot_holder, item); g_object_unref(knot_holder); unsigned int object_verb = SP_VERB_NONE; if (SP_IS_RECT(item)) object_verb = SP_VERB_CONTEXT_RECT; else if (SP_IS_3DBOX(item)) object_verb = SP_VERB_CONTEXT_3DBOX; else if (SP_IS_GENERICELLIPSE(item)) object_verb = SP_VERB_CONTEXT_ARC; else if (SP_IS_STAR(item)) object_verb = SP_VERB_CONTEXT_STAR; else if (SP_IS_SPIRAL(item)) object_verb = SP_VERB_CONTEXT_SPIRAL; else if (SP_IS_OFFSET(item)) { if (SP_OFFSET(item)->sourceHref) object_verb = SP_VERB_SELECTION_LINKED_OFFSET; else object_verb = SP_VERB_SELECTION_DYNAMIC_OFFSET; } // for drag, this is done by ungrabbed_handler, but for click we must do it here sp_document_done(SP_OBJECT_DOCUMENT(knot_holder->item), object_verb, _("Change handle")); } static void knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state, gpointer data) { SPKnotHolder *knot_holder = (SPKnotHolder *) data; SPItem *item = SP_ITEM (knot_holder->item); // this was a local change and the knotholder does not need to be recreated: knot_holder->local_change = TRUE; for (GSList *el = knot_holder->entity; el; el = el->next) { SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data; if (e->knot == knot) { NR::Point const q = *p / sp_item_i2d_affine(item); e->knot_set(item, q, e->knot->drag_origin / sp_item_i2d_affine(item), state); break; } } if (SP_IS_SHAPE (item)) { sp_shape_set_shape(SP_SHAPE (item)); } knotholder_update_knots(knot_holder, item); } static void knot_ungrabbed_handler(SPKnot *knot, unsigned int state, SPKnotHolder *kh) { if (kh->released) { kh->released(kh->item); } else { SPObject *object = (SPObject *) kh->item; object->updateRepr(object->repr, SP_OBJECT_WRITE_EXT); unsigned int object_verb = SP_VERB_NONE; if (SP_IS_RECT(object)) object_verb = SP_VERB_CONTEXT_RECT; else if (SP_IS_3DBOX(object)) object_verb = SP_VERB_CONTEXT_3DBOX; else if (SP_IS_GENERICELLIPSE(object)) object_verb = SP_VERB_CONTEXT_ARC; else if (SP_IS_STAR(object)) object_verb = SP_VERB_CONTEXT_STAR; else if (SP_IS_SPIRAL(object)) object_verb = SP_VERB_CONTEXT_SPIRAL; else if (SP_IS_OFFSET(object)) { if (SP_OFFSET(object)->sourceHref) object_verb = SP_VERB_SELECTION_LINKED_OFFSET; else object_verb = SP_VERB_SELECTION_DYNAMIC_OFFSET; } sp_document_done(SP_OBJECT_DOCUMENT (object), object_verb, _("Move handle")); } } /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :