X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fknotholder.cpp;h=eeddf2eb083d8d57fc87eccd53f4fd4d866d5c44;hb=8d358698ecbf192ba7c6dc05d4f7de7592753d9f;hp=d8776cca7219db5a91f417fbdd32f7c55bd28c9d;hpb=b2dfb5760b4ff97eabdaa0272ba7ed7f0dd8c6eb;p=inkscape.git diff --git a/src/knotholder.cpp b/src/knotholder.cpp index d8776cca7..eeddf2eb0 100644 --- a/src/knotholder.cpp +++ b/src/knotholder.cpp @@ -6,20 +6,17 @@ * Authors: * Mitsuru Oka * bulia byak + * Maximilian Albert * - * Copyright (C) 2001-2005 authors + * Copyright (C) 2001-2008 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" @@ -30,199 +27,77 @@ #include "sp-spiral.h" #include "sp-offset.h" #include "box3d.h" +#include "sp-pattern.h" +#include "style.h" +#include "live_effects/lpeobject.h" + +#include "xml/repr.h" // for debugging only #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) +KnotHolder::KnotHolder(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); + if (!desktop || !item || !SP_IS_ITEM(item)) { + g_print ("Error! Throw an exception, please!\n"); } -} -void sp_knot_holder_destroy(SPKnotHolder *kh) { - g_object_unref(kh); - } + this->desktop = desktop; + this->item = item; + g_object_ref(G_OBJECT(item)); // TODO: is this still needed after C++-ification? -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); + this->released = relhandler; + + this->repr = repr; + this->local_change = FALSE; } -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; +KnotHolder::~KnotHolder() { + g_object_unref(G_OBJECT(item)); + for(std::list::iterator i = entity.begin(); i != entity.end(); ++i) { + KnotHolderEntity* e = (*i); + if (!e->isLPEParam()) { + // knotholder entity may be deleted + delete (*i); + } else { + // we must not delete the entity since it's an LPE parameter, + // but the handle should be destroyed + g_object_unref(e->knot); + } + (*i) = 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); + entity.clear(); // this shouldn't be necessary, though } /** * \param p In desktop coordinates. */ -//static -void knotholder_update_knots(SPKnotHolder *knot_holder, SPItem *item) +void +KnotHolder::update_knots() { - NR::Matrix const i2d(sp_item_i2d_affine(item)); + NR::Matrix const i2d(from_2geom(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); + for(std::list::iterator i = entity.begin(); i != entity.end(); ++i) { + KnotHolderEntity *e = *i; + e->update_knot(); } } -static void knot_clicked_handler(SPKnot *knot, guint state, gpointer data) +void +KnotHolder::knot_clicked_handler(SPKnot *knot, guint state) { - SPKnotHolder *knot_holder = (SPKnotHolder *) data; - SPItem *item = SP_ITEM (knot_holder->item); + KnotHolder *knot_holder = this; - g_object_ref(knot_holder); - for (GSList *el = knot_holder->entity; el; el = el->next) { - SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data; + for(std::list::iterator i = knot_holder->entity.begin(); i != knot_holder->entity.end(); ++i) { + KnotHolderEntity *e = *i; if (e->knot == knot) { - if (e->knot_click) { - e->knot_click(item, state); - } + // no need to test whether knot_click exists since it's virtual now + e->knot_click(state); break; } } @@ -231,14 +106,13 @@ static void knot_clicked_handler(SPKnot *knot, guint state, gpointer data) sp_shape_set_shape(SP_SHAPE(item)); } - knotholder_update_knots(knot_holder, item); - g_object_unref(knot_holder); + knot_holder->update_knots(); unsigned int object_verb = SP_VERB_NONE; if (SP_IS_RECT(item)) object_verb = SP_VERB_CONTEXT_RECT; - else if (SP_IS_3DBOX(item)) + else if (SP_IS_BOX3D(item)) object_verb = SP_VERB_CONTEXT_3DBOX; else if (SP_IS_GENERICELLIPSE(item)) object_verb = SP_VERB_CONTEXT_ARC; @@ -254,22 +128,21 @@ static void knot_clicked_handler(SPKnot *knot, guint state, gpointer data) } // 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, + sp_document_done(SP_OBJECT_DOCUMENT(item), object_verb, _("Change handle")); } -static void knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state, gpointer data) +void +KnotHolder::knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state) { - 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; + this->local_change = TRUE; - for (GSList *el = knot_holder->entity; el; el = el->next) { - SPKnotHolderEntity *e = (SPKnotHolderEntity *) el->data; + for(std::list::iterator i = this->entity.begin(); i != this->entity.end(); ++i) { + KnotHolderEntity *e = *i; 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); + NR::Point const q = *p / from_2geom(sp_item_i2d_affine(item)); + e->knot_set(q, e->knot->drag_origin / from_2geom(sp_item_i2d_affine(item)), state); break; } } @@ -278,22 +151,44 @@ static void knot_moved_handler(SPKnot *knot, NR::Point const *p, guint state, gp sp_shape_set_shape(SP_SHAPE (item)); } - knotholder_update_knots(knot_holder, item); + this->update_knots(); } -static void knot_ungrabbed_handler(SPKnot *knot, unsigned int state, SPKnotHolder *kh) +void +KnotHolder::knot_ungrabbed_handler(SPKnot *knot) { - if (kh->released) { - kh->released(kh->item); + if (this->released) { + this->released(this->item); } else { - SPObject *object = (SPObject *) kh->item; - object->updateRepr(object->repr, SP_OBJECT_WRITE_EXT); + SPObject *object = (SPObject *) this->item; + object->updateRepr(); + + /* do cleanup tasks (e.g., for LPE items write the parameter values + * that were changed by dragging the handle to SVG) + */ + if (SP_IS_LPE_ITEM(item)) { + // This writes all parameters to SVG. Is this sufficiently efficient or should we only write + // the ones that were changed (e.g., via the individual handles' onKnotUngrabbed() method? + Inkscape::LivePathEffect::Effect *lpe = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)); + if (lpe) { + LivePathEffectObject *lpeobj = lpe->getLPEObj(); + SP_OBJECT(lpeobj)->updateRepr(); + } + } + // this was once used to write individual parameter values to SVG but this is now done globally above; + // we leave the calls to onKnotUngrabbed, anyway, in case any other cleanup tasks need to be done + for(std::list::iterator i = this->entity.begin(); i != this->entity.end(); ++i) { + KnotHolderEntity *e = *i; + if (e->knot == knot) { + e->onKnotUngrabbed(); // for most KnotHolderEntitys this does nothing + } + } unsigned int object_verb = SP_VERB_NONE; if (SP_IS_RECT(object)) object_verb = SP_VERB_CONTEXT_RECT; - else if (SP_IS_3DBOX(object)) + else if (SP_IS_BOX3D(object)) object_verb = SP_VERB_CONTEXT_3DBOX; else if (SP_IS_GENERICELLIPSE(object)) object_verb = SP_VERB_CONTEXT_ARC; @@ -313,6 +208,37 @@ static void knot_ungrabbed_handler(SPKnot *knot, unsigned int state, SPKnotHolde } } +void +KnotHolder::add(KnotHolderEntity *e) +{ + entity.push_back(e); +} + +void +KnotHolder::add_pattern_knotholder() +{ + if ((SP_OBJECT(item)->style->fill.isPaintserver()) + && SP_IS_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style))) + { + PatternKnotHolderEntityXY *entity_xy = new PatternKnotHolderEntityXY(); + PatternKnotHolderEntityAngle *entity_angle = new PatternKnotHolderEntityAngle(); + PatternKnotHolderEntityScale *entity_scale = new PatternKnotHolderEntityScale(); + entity_xy->create(desktop, item, this, + // TRANSLATORS: This refers to the pattern that's inside the object + _("Move the pattern fill inside the object"), + SP_KNOT_SHAPE_CROSS); + entity_angle->create(desktop, item, this, + _("Scale the pattern fill uniformly"), + SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR); + entity_scale->create(desktop, item, this, + _("Rotate the pattern fill; with Ctrl to snap angle"), + SP_KNOT_SHAPE_CIRCLE, SP_KNOT_MODE_XOR); + entity.push_back(entity_xy); + entity.push_back(entity_angle); + entity.push_back(entity_scale); + } +} + /* Local Variables: mode:c++