Code

LPE: add on-canvas editing of path parameters!
authorjohanengelen <johanengelen@users.sourceforge.net>
Sat, 20 Oct 2007 15:43:07 +0000 (15:43 +0000)
committerjohanengelen <johanengelen@users.sourceforge.net>
Sat, 20 Oct 2007 15:43:07 +0000 (15:43 +0000)
src/live_effects/effect.cpp
src/live_effects/effect.h
src/live_effects/lpeobject.cpp
src/live_effects/parameter/path.cpp
src/live_effects/parameter/path.h
src/nodepath.cpp
src/nodepath.h
src/shape-editor.cpp
src/shape-editor.h

index 1c0f5318f4d9fa3e55179ab38b2ed4c01517c90e..cfabc88b429df8b48febb5a8e4a6368e0fcbf30a 100644 (file)
@@ -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
index 5169ff22f5d6345239138627e044244fecb1917c..8c647e5994840c942e46d16b9ff585402d5bef5b 100644 (file)
@@ -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);
index a8321b72d660641f281e172258e9c5a41948ff84..90a49e2ff7a75da3c6391281e406c2d71ac1adb9 100644 (file)
@@ -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);
 }
index ff596bfc6dde589f5fa68d8000e1d164d315d93c..15ba663bee81a5c39af0c23370b75896d758031c 100644 (file)
 #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<Gtk::HBox*>(_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
index e966b7ebdb56a0dc66b301458f7ece1bf0a675c4..14387f4194c7aad942c3febfe840c0bf3fec164f 100644 (file)
 
 #include <sigc++/sigc++.h>
 
+namespace Gtk {
+    class Button;
+}
+
 namespace Inkscape {
 
 namespace LivePathEffect {
@@ -56,6 +60,8 @@ private:
     void on_paste_button_click();
 
     gchar * defvalue;
+
+    Gtk::Button * edit_button;
 };
 
 
index 09c030aecc119c16b26430cb16118b2971491f32..fa80f3baad0b579078c32c1168e854c95751230b 100644 (file)
@@ -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);
     }
 }
 
index 8c6c4ff8b283272525e3181e3e029ae76f049f7a..6ed9e22256ac7fd6566bd13cd69f2a5f2ca7fc86 100644 (file)
@@ -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);
index d0dbb8937ba17b03aa40d9b53e6f9280f2606dd6..abffeefc4b7463089b0592aa05081c108d75da31 100644 (file)
@@ -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);
index 0e5bc22ef6b92f3629ead0953d08bb953bef35a2..2df1bb0e005ee9190d1a72ea2b5e49c6a4851341 100644 (file)
@@ -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 ();