From 0fc5ce7045233dae7e15fdc86774370f1b1d73cb Mon Sep 17 00:00:00 2001 From: johanengelen Date: Sat, 20 Oct 2007 15:43:07 +0000 Subject: [PATCH] LPE: add on-canvas editing of path parameters! --- src/live_effects/effect.cpp | 8 ++--- src/live_effects/effect.h | 3 +- src/live_effects/lpeobject.cpp | 2 +- src/live_effects/parameter/path.cpp | 22 ++++++++++--- src/live_effects/parameter/path.h | 6 ++++ src/nodepath.cpp | 49 +++++++++++++++++------------ src/nodepath.h | 6 +++- src/shape-editor.cpp | 22 ++++++------- src/shape-editor.h | 2 +- 9 files changed, 75 insertions(+), 45 deletions(-) diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 1c0f5318f..cfabc88b4 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -186,14 +186,15 @@ Effect::readallParameters(Inkscape::XML::Node * repr) const gchar * key = (*it).first.c_str(); const gchar * value = repr->attribute(key); if(value) { - setParameter(repr, key, NULL, value); + setParameter(key, value); } it++; } } +/* This function does not and SHOULD NOT write to XML */ void -Effect::setParameter(Inkscape::XML::Node * repr, const gchar * key, const gchar * old_value, const gchar * new_value) +Effect::setParameter(const gchar * key, const gchar * new_value) { Glib::ustring stringkey(key); @@ -203,9 +204,6 @@ Effect::setParameter(Inkscape::XML::Node * repr, const gchar * key, const gchar bool accepted = it->second->param_readSVGValue(new_value); if (!accepted) { g_warning("Effect::setParameter - '%s' not accepted for %s", new_value, key); - // change was not accepted, so change it back. - // think: can this backfire and create infinite loop when started with unacceptable old_value? - // repr->setAttribute(key, old_value); } } else { // set default value diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 5169ff22f..8c647e599 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -70,9 +70,10 @@ public: Inkscape::XML::Node * getRepr(); SPDocument * getSPDoc(); + LivePathEffectObject * getLPEObj() {return lpeobj;}; void readallParameters(Inkscape::XML::Node * repr); - void setParameter(Inkscape::XML::Node * repr, const gchar * key, const gchar * old_value, const gchar * new_value); + void setParameter(const gchar * key, const gchar * new_value); protected: Effect(LivePathEffectObject *lpeobject); diff --git a/src/live_effects/lpeobject.cpp b/src/live_effects/lpeobject.cpp index a8321b72d..90a49e2ff 100644 --- a/src/live_effects/lpeobject.cpp +++ b/src/live_effects/lpeobject.cpp @@ -246,7 +246,7 @@ livepatheffect_on_repr_attr_changed ( Inkscape::XML::Node * repr, if (!lpeobj->lpe) return; - lpeobj->lpe->setParameter(repr, key, oldval, newval); + lpeobj->lpe->setParameter(key, newval); lpeobj->requestModified(SP_OBJECT_MODIFIED_FLAG); } diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index ff596bfc6..15ba663be 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -25,7 +25,12 @@ #include "verbs.h" #include "document.h" -#define noLPEPATHPARAM_DEBUG +#define LPEPATHPARAM_DEBUG +#include "tools-switch.h" +#include "shape-editor.h" +#include "node-context.h" +#include "desktop-handles.h" +#include "selection.h" namespace Inkscape { @@ -38,6 +43,7 @@ PathParam::PathParam( const Glib::ustring& label, const Glib::ustring& tip, { _widget = NULL; _tooltips = NULL; + edit_button = NULL; defvalue = g_strdup(default_value); param_readSVGValue(defvalue); } @@ -103,8 +109,9 @@ PathParam::param_getWidget() pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_edit_button_click)); static_cast(_widget)->pack_start(*pButton, true, true); _tooltips->set_tip(*pButton, _("Edit on-canvas")); + edit_button = pButton; #ifndef LPEPATHPARAM_DEBUG - pButton->set_sensitive(false); + edit_button->set_sensitive(false); #endif pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_PASTE, Inkscape::ICON_SIZE_BUTTON) ); @@ -126,7 +133,13 @@ PathParam::param_getWidget() void PathParam::on_edit_button_click() { - g_message("give this path to edit on canvas!"); + // Switch to node edit tool: + tools_switch_current(TOOLS_NODES); + + // set this parameter to edit: + ShapeEditor * shape_editor = SP_NODE_CONTEXT( SP_ACTIVE_DESKTOP->event_context )->shape_editor; + SPItem * item = sp_desktop_selection(SP_ACTIVE_DESKTOP)->singleItem(); + shape_editor->set_item_livepatheffect_parameter(item, SP_OBJECT(param_effect->getLPEObj()), param_key.c_str()); } void @@ -146,6 +159,7 @@ PathParam::on_paste_button_click() if (strchr(svgd,'A')) { // FIXME: temporary hack until 2Geom supports arcs in SVGD SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE, _("This effect does not support arcs yet, try to convert to path.") ); + return; } else { param_write_to_repr(svgd); signal_path_pasted.emit(); @@ -155,8 +169,8 @@ PathParam::on_paste_button_click() } } else { SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Clipboard does not contain a path.")); + return; } - } void diff --git a/src/live_effects/parameter/path.h b/src/live_effects/parameter/path.h index e966b7ebd..14387f419 100644 --- a/src/live_effects/parameter/path.h +++ b/src/live_effects/parameter/path.h @@ -19,6 +19,10 @@ #include +namespace Gtk { + class Button; +} + namespace Inkscape { namespace LivePathEffect { @@ -56,6 +60,8 @@ private: void on_paste_button_click(); gchar * defvalue; + + Gtk::Button * edit_button; }; diff --git a/src/nodepath.cpp b/src/nodepath.cpp index 09c030aec..fa80f3baa 100644 --- a/src/nodepath.cpp +++ b/src/nodepath.cpp @@ -139,16 +139,15 @@ static Inkscape::NodePath::NodeSide *sp_node_opposite_side(Inkscape::NodePath::N static NRPathcode sp_node_path_code_from_side(Inkscape::NodePath::Node *node,Inkscape::NodePath::NodeSide *me); static SPCurve* sp_nodepath_object_get_curve(SPObject *object, const gchar *key); -static void sp_nodepath_object_set_curve (SPObject *object, SPCurve *curve); +static void sp_nodepath_set_curve (Inkscape::NodePath::Path *np, SPCurve *curve); // active_node indicates mouseover node Inkscape::NodePath::Node * Inkscape::NodePath::Path::active_node = NULL; /** * \brief Creates new nodepath from item -* repr_key_in should be NULL, unless you are called Johan or really know what you are doing! (See "if (repr_key_in)" below) */ -Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object, bool show_handles, const char * repr_key_in) +Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object, bool show_handles, const char * repr_key_in, SPItem *item) { Inkscape::XML::Node *repr = object->repr; @@ -201,18 +200,22 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object, np->curve = sp_curve_copy(curve); np->show_helperpath = false; np->straight_path = false; - + if (IS_LIVEPATHEFFECT(object) && item) { + np->item = item; + } else { + np->item = SP_ITEM(object); + } // we need to update item's transform from the repr here, // because they may be out of sync when we respond // to a change in repr by regenerating nodepath --bb - sp_object_read_attr(object, "transform"); + sp_object_read_attr(SP_OBJECT(np->item), "transform"); - np->i2d = sp_item_i2d_affine(SP_ITEM(object)); + np->i2d = sp_item_i2d_affine(np->item); np->d2i = np->i2d.inverse(); np->repr = repr; - if (repr_key_in) { + if (repr_key_in) { // apparantly the object is an LPEObject np->repr_key = g_strdup(repr_key_in); np->repr_nodetypes_key = g_strconcat(np->repr_key, "-nodetypes", NULL); np->show_helperpath = true; @@ -308,7 +311,7 @@ void sp_nodepath_destroy(Inkscape::NodePath::Path *np) { void sp_nodepath_ensure_livarot_path(Inkscape::NodePath::Path *np) { - if (np && np->livarot_path == NULL && np->object && SP_IS_ITEM(np->object)) { + if (np && np->livarot_path == NULL) { SPCurve *curve = create_curve(np); NArtBpath *bpath = SP_CURVE_BPATH(curve); np->livarot_path = bpath_to_Path(bpath); @@ -516,7 +519,7 @@ static void update_object(Inkscape::NodePath::Path *np) sp_curve_unref(np->curve); np->curve = create_curve(np); - sp_nodepath_object_set_curve(np->object, np->curve); + sp_nodepath_set_curve(np, np->curve); if (np->show_helperpath) { SPCurve * helper_curve = sp_curve_copy(np->curve); @@ -1077,7 +1080,7 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath, for (GList *l = nodepath->selected; l != NULL; l = l->next) { Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data; - Inkscape::SnappedPoint const s = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, n->pos + delta, SP_PATH(n->subpath->nodepath->object)); + Inkscape::SnappedPoint const s = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, n->pos + delta, SP_PATH(n->subpath->nodepath->item)); if (s.getDistance() < best) { best = s.getDistance(); best_pt = s.getPoint() - n->pos; @@ -3455,9 +3458,9 @@ static gboolean node_handle_request(SPKnot *knot, NR::Point *p, guint state, gpo NR::Coord const scal = dot(delta, ndelta) / linelen; (*p) = n->pos + (scal / linelen) * ndelta; } - *p = m.constrainedSnap(Inkscape::Snapper::SNAPPOINT_NODE, *p, Inkscape::Snapper::ConstraintLine(*p, ndelta), SP_ITEM(n->subpath->nodepath->object)).getPoint(); + *p = m.constrainedSnap(Inkscape::Snapper::SNAPPOINT_NODE, *p, Inkscape::Snapper::ConstraintLine(*p, ndelta), n->subpath->nodepath->item).getPoint(); } else { - *p = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, *p, SP_ITEM(n->subpath->nodepath->object)).getPoint(); + *p = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, *p, n->subpath->nodepath->item).getPoint(); } sp_node_adjust_handle(n, -which); @@ -4443,18 +4446,24 @@ SPCurve* sp_nodepath_object_get_curve(SPObject *object, const gchar *key) { return curve; } -void sp_nodepath_object_set_curve (SPObject *object, SPCurve *curve) { - if (!object || !curve) +void sp_nodepath_set_curve (Inkscape::NodePath::Path *np, SPCurve *curve) { + if (!np || !np->object || !curve) return; - if (SP_IS_PATH(object)) { - if (SP_SHAPE(object)->path_effect_href) { - sp_path_set_original_curve(SP_PATH(object), curve, true, false); + if (SP_IS_PATH(np->object)) { + if (SP_SHAPE(np->object)->path_effect_href) { + sp_path_set_original_curve(SP_PATH(np->object), curve, true, false); } else { - sp_shape_set_curve(SP_SHAPE(object), curve, true); + sp_shape_set_curve(SP_SHAPE(np->object), curve, true); } - } else if ( IS_LIVEPATHEFFECT(object) ) { - g_warning("sp_nodepath_set_curve not implemented yet for lpeobjects"); + } else if ( IS_LIVEPATHEFFECT(np->object) ) { + // FIXME: this writing to string and then reading from string is bound to be slow. + // create a method to convert from curve directly to 2geom... + gchar *svgpath = sp_svg_write_path(SP_CURVE_BPATH(np->curve)); + LIVEPATHEFFECT(np->object)->lpe->setParameter(np->repr_key, svgpath); + g_free(svgpath); + + np->object->requestModified(SP_OBJECT_MODIFIED_FLAG); } } diff --git a/src/nodepath.h b/src/nodepath.h index 8c6c4ff8b..6ed9e2225 100644 --- a/src/nodepath.h +++ b/src/nodepath.h @@ -24,6 +24,7 @@ class SPDesktop; class SPPath; class SPKnot; +class LivePathEffectObject; namespace Inkscape { namespace XML { @@ -208,6 +209,8 @@ class Path { SPDesktop * desktop; /** The parent path of this nodepath */ SPObject * object; +/** The parent livepatheffect of this nodepath, if applicable */ + SPItem * item; /** The context which created this nodepath. Important if this nodepath is deleted */ ShapeEditor *shape_editor; /** The subpaths which comprise this NodePath */ @@ -242,6 +245,7 @@ class Path { bool show_handles; /// true if the path cannot contain curves, just straight lines + // FIXME: NOT IMPLEMENTED YET bool straight_path; /// active_node points to the node that is currently mouseovered (= NULL if @@ -260,7 +264,7 @@ enum { }; // Do function documentation in nodepath.cpp -Inkscape::NodePath::Path * sp_nodepath_new (SPDesktop * desktop, SPObject *object, bool show_handles, const char * repr_key = NULL); +Inkscape::NodePath::Path * sp_nodepath_new (SPDesktop * desktop, SPObject *object, bool show_handles, const char * repr_key = NULL, SPItem *item = NULL); void sp_nodepath_destroy (Inkscape::NodePath::Path * nodepath); void sp_nodepath_ensure_livarot_path(Inkscape::NodePath::Path *np); void sp_nodepath_deselect (Inkscape::NodePath::Path *nodepath); diff --git a/src/shape-editor.cpp b/src/shape-editor.cpp index d0dbb8937..abffeefc4 100644 --- a/src/shape-editor.cpp +++ b/src/shape-editor.cpp @@ -16,6 +16,7 @@ #include "sp-object.h" #include "sp-item.h" +#include "live_effects/lpeobject.h" #include "selection.h" #include "desktop.h" #include "desktop-handles.h" @@ -113,7 +114,7 @@ void ShapeEditor::decrement_local_change () { SPItem *ShapeEditor::get_item () { SPItem *item = NULL; if (this->has_nodepath()) { - item = SP_ITEM(this->nodepath->object); + item = this->nodepath->item; } else if (this->has_knotholder()) { item = SP_ITEM(this->knotholder->item); } @@ -208,29 +209,26 @@ void ShapeEditor::set_item(SPItem *item) { } } -void ShapeEditor::set_livepatheffect_parameter(SPObject *lpeobject, const char * key) { +/** Please note that this function only works for path parameters. +* All other parameters probably will crash Inkscape! +* Fortunately, there are no other on-canvas edittable objects at this moment :) +*/ +void ShapeEditor::set_item_livepatheffect_parameter(SPItem *item, SPObject *lpeobject, const char * key) { unset_item(); this->grab_node = -1; if (lpeobject) { + this->knotholder = NULL; // it's a path, no special knotholder needed. this->nodepath = sp_nodepath_new( desktop, lpeobject, (prefs_get_int_attribute("tools.nodes", "show_handles", 1) != 0), - key); + key, item); if (this->nodepath) { this->nodepath->shape_editor = this; - } - //this->knotholder = sp_item_knot_holder(item, desktop); - g_message("create knotholder?"); - if (this->nodepath || this->knotholder) { // setting new listener - Inkscape::XML::Node *repr; - if (this->knotholder) - repr = this->knotholder->repr; - else - repr = SP_OBJECT_REPR(lpeobject); + Inkscape::XML::Node *repr = SP_OBJECT_REPR(lpeobject); if (repr) { Inkscape::GC::anchor(repr); sp_repr_add_listener(repr, &shapeeditor_repr_events, this); diff --git a/src/shape-editor.h b/src/shape-editor.h index 0e5bc22ef..2df1bb0e0 100644 --- a/src/shape-editor.h +++ b/src/shape-editor.h @@ -36,7 +36,7 @@ public: ~ShapeEditor(); void set_item (SPItem *item); - void set_livepatheffect_parameter(SPObject *lpeobject, const char * key); + void set_item_livepatheffect_parameter(SPItem *item, SPObject *lpeobject, const char * key); void unset_item (); SPItem *get_item (); -- 2.30.2