Code

First step towards making helper paths for LPE items work better
authorcilix42 <cilix42@users.sourceforge.net>
Mon, 16 Jun 2008 15:45:16 +0000 (15:45 +0000)
committercilix42 <cilix42@users.sourceforge.net>
Mon, 16 Jun 2008 15:45:16 +0000 (15:45 +0000)
14 files changed:
src/display/canvas-temporary-item.cpp
src/display/canvas-temporary-item.h
src/live_effects/effect.cpp
src/live_effects/effect.h
src/live_effects/lpe-mirror_reflect.cpp
src/live_effects/lpe-perp_bisector.cpp
src/live_effects/lpe-tangent_to_curve.cpp
src/node-context.cpp
src/node-context.h
src/nodepath.cpp
src/nodepath.h
src/selection.cpp
src/sp-lpe-item.cpp
src/sp-lpe-item.h

index d31323b72a190f7c43cdc8207f865dc64178ca91..ccef4d0cbd8f5815ad38dbc2313272c9ac38186b 100644 (file)
@@ -23,10 +23,15 @@ namespace Display {
 
 /** lifetime is measured in milliseconds
  */
-TemporaryItem::TemporaryItem(SPCanvasItem *item, guint lifetime)
+TemporaryItem::TemporaryItem(SPCanvasItem *item, guint lifetime, bool deselect_destroy)
     : canvasitem(item),
-      timeout_id(0)
+      timeout_id(0),
+      destroy_on_deselect(deselect_destroy)
 {
+    if (lifetime > 0 && destroy_on_deselect) {
+        g_print ("Warning: lifetime should be 0 when destroy_on_deselect is true\n");
+        lifetime = 0;
+    }
     // zero lifetime means stay forever, so do not add timeout event.
     if (lifetime > 0) {
         timeout_id = g_timeout_add(lifetime, &TemporaryItem::_timeout, this);
index ec1e3b999ae85adcd1407f880cb019f01789b252..5077fb55ba7125fae6adc159da22a14cbf399610 100644 (file)
@@ -21,7 +21,7 @@ namespace Display {
 
 class TemporaryItem  {
 public:
-    TemporaryItem(SPCanvasItem *item, guint lifetime);
+    TemporaryItem(SPCanvasItem *item, guint lifetime, bool destroy_on_deselect = false);
     virtual ~TemporaryItem();
 
     sigc::signal<void, TemporaryItem *> signal_timeout;
@@ -31,6 +31,7 @@ protected:
 
     SPCanvasItem * canvasitem;   /** The item we are holding on to */
     guint timeout_id;     /** ID by which glib knows the timeout event */
+    bool destroy_on_deselect; // only destroy when parent item is deselected, not when mouse leaves
 
     static gboolean _timeout(gpointer data); ///< callback for when lifetime expired
 
index 551b23a1db1fc84931587195f6d8b7b344cecebe..0497d0e375c3e63fa60611dc6dc1da30664a4545 100644 (file)
@@ -21,6 +21,9 @@
 #include <glibmm/i18n.h>
 #include "pen-context.h"
 #include "tools-switch.h"
+#include "message-stack.h"
+#include "desktop.h"
+#include "nodepath.h"
 
 #include "live_effects/lpeobject.h"
 #include "live_effects/parameter/parameter.h"
@@ -55,8 +58,6 @@
 #include "live_effects/lpe-mirror_reflect.h"
 // end of includes
 
-#include "nodepath.h"
-
 namespace Inkscape {
 
 namespace LivePathEffect {
@@ -186,6 +187,8 @@ Effect::Effect(LivePathEffectObject *lpeobject)
     : oncanvasedit_it(0),
       is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true),
       done_pathparam_set(false),
+      provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden
+      show_orig_path(false),
       lpeobj(lpeobject),
       concatenate_before_pwd2(false)
 {
@@ -400,6 +403,27 @@ Effect::addPointParamHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem
     }
 }
 
+void
+Effect::addHelperPaths(SPLPEItem *lpeitem, SPDesktop *desktop)
+{
+    g_return_if_fail(SP_IS_PATH(lpeitem));
+
+    if (show_orig_path) {
+        SPCanvasItem *canvasitem = sp_nodepath_generate_helperpath(desktop, SP_PATH(lpeitem));
+        // TODO: Make sure the tempitem doesn't get destroyed when the mouse leaves the item
+        Inkscape::Display::TemporaryItem* tmpitem = desktop->add_temporary_canvasitem (canvasitem, 0);
+        lpeitem->lpe_helperpaths.push_back(tmpitem);
+    }
+    addHelperPathsImpl(lpeitem, desktop);
+}
+
+void
+Effect::addHelperPathsImpl(SPLPEItem *lpeitem, SPDesktop *desktop)
+{
+    // if this method is overloaded in derived classes, provides_own_flash_paths will be true
+    provides_own_flash_paths = false;
+}
+
 /**
  * This *creates* a new widget, management of deletion should be done by the caller
  */
index f1241c54b8a79ff305913a30138b2031af4e3de5..32917f8c8e4531a88f89946a0d182d05912bbf7a 100644 (file)
@@ -27,6 +27,7 @@
 struct SPDocument;
 struct SPDesktop;
 struct SPItem;
+class SPNodeContext;
 class NArtBpath;
 struct LivePathEffectObject;
 
@@ -119,6 +120,11 @@ public:
     virtual LPEPathFlashType pathFlashType() { return DEFAULT; }
     void addHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
 
+    void addHelperPaths(SPLPEItem *lpeitem, SPDesktop *desktop);
+    inline bool providesOwnFlashPaths() {
+        return provides_own_flash_paths || show_orig_path;
+    }
+
     Glib::ustring          getName();
     Inkscape::XML::Node *  getRepr();
     SPDocument *           getSPDoc();
@@ -150,12 +156,17 @@ protected:
     void addPointParamHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
     Parameter * getNextOncanvasEditableParam();
 
+    virtual void addHelperPathsImpl(SPLPEItem *lpeitem, SPDesktop *desktop);
+
     std::vector<Parameter *> param_vector;
     std::vector<std::pair<KnotHolderEntity*, const char*> > kh_entity_vector;
     int oncanvasedit_it;
     BoolParam is_visible;
     bool done_pathparam_set;
 
+    bool show_orig_path; // set this to true in derived effects to automatically have the original
+                         // path displayed as helperpath
+
     Inkscape::UI::Widget::Registry wr;
 
     LivePathEffectObject *lpeobj;
@@ -165,6 +176,8 @@ protected:
     bool concatenate_before_pwd2;
 
 private:
+    bool provides_own_flash_paths; // if true, the standard flash path is suppressed
+
     Effect(const Effect&);
     Effect& operator=(const Effect&);
 };
index 093841c8d61101b547c496edd77282b0f7026b51..6a149dfc540d07cf216b2e40f96bc651d19ad6d6 100644 (file)
@@ -29,6 +29,8 @@ LPEMirrorReflect::LPEMirrorReflect(LivePathEffectObject *lpeobject) :
     Effect(lpeobject),
     reflection_line(_("Reflection line"), _("Line which serves as 'mirror' for the reflection"), "reflection_line", &wr, this, "M0,0 L100,100")
 {
+    show_orig_path = true;
+
     registerParameter( dynamic_cast<Parameter *>(&reflection_line) );
 }
 
index 7c08bdb08ff07488675e944b58cc277c22f65fbb..bcfe57614002efdf2f74c66531d9f1fdb062fe58 100644 (file)
@@ -157,6 +157,8 @@ LPEPerpBisector::LPEPerpBisector(LivePathEffectObject *lpeobject) :
     length_right(_("Length right"), _("Specifies the right end of the bisector"), "length-right", &wr, this, 200),
     A(0,0), B(0,0), M(0,0), C(0,0), D(0,0), perp_dir(0,0)
 {
+    show_orig_path = true;
+
     // register all your parameters here, so Inkscape knows which parameters this effect has:
     registerParameter( dynamic_cast<Parameter *>(&length_left) );
     registerParameter( dynamic_cast<Parameter *>(&length_right) );
index 6ca785001da5b6cf46630d052760de2c75ea637e..9e63ef4a4c4e9e8dc4a697e727d4238d5c00e187 100644 (file)
@@ -65,6 +65,8 @@ LPETangentToCurve::LPETangentToCurve(LivePathEffectObject *lpeobject) :
     length_left(_("Length left"), _("Specifies the left end of the tangent"), "length-left", &wr, this, 150),
     length_right(_("Length right"), _("Specifies the right end of the tangent"), "length-right", &wr, this, 150)
 {
+    show_orig_path = true;
+
     registerParameter( dynamic_cast<Parameter *>(&angle) );
     registerParameter( dynamic_cast<Parameter *>(&t_attach) );
     registerParameter( dynamic_cast<Parameter *>(&length_left) );
index 40b98336095ff5e84f2d5bc6f52f99ac3420497e..88ea1667d24e40632208f8e9225dbb13073fc3c7 100644 (file)
@@ -116,12 +116,6 @@ sp_node_context_dispose(GObject *object)
 
     ec->enableGrDrag(false);
 
-    if (nc->flash_permitem) {
-        // hack!!! (we add a temporary canvasitem with life time 1 ms)
-        nc->flash_tempitem = nc->event_context.desktop->add_temporary_canvasitem (nc->flash_permitem, 1);
-        nc->flash_permitem = NULL;
-    }
-
     nc->sel_changed_connection.disconnect();
     nc->sel_changed_connection.~connection();
 
@@ -142,10 +136,14 @@ sp_node_context_setup(SPEventContext *ec)
     if (((SPEventContextClass *) parent_class)->setup)
         ((SPEventContextClass *) parent_class)->setup(ec);
 
+    Inkscape::Selection *selection = sp_desktop_selection (ec->desktop);
     nc->sel_changed_connection.disconnect();
-    nc->sel_changed_connection = sp_desktop_selection(ec->desktop)->connectChanged(sigc::bind(sigc::ptr_fun(&sp_node_context_selection_changed), (gpointer)nc));
+    nc->sel_modified_connection.disconnect();
+    nc->sel_changed_connection =
+        selection->connectChanged(sigc::bind(sigc::ptr_fun(&sp_node_context_selection_changed), (gpointer)nc));
+    nc->sel_modified_connection =
+        selection->connectModified(sigc::bind(sigc::ptr_fun(&sp_node_context_selection_modified), (gpointer)nc));
 
-    Inkscape::Selection *selection = sp_desktop_selection(ec->desktop);
     SPItem *item = selection->singleItem();
 
     nc->shape_editor = new ShapeEditor(ec->desktop);
@@ -177,23 +175,6 @@ sp_node_context_setup(SPEventContext *ec)
     nc->shape_editor->update_statusbar();
 }
 
-static SPCanvasItem *
-sp_node_context_generate_helperpath(SPDesktop *desktop, SPPath *path) {
-    // This should be put somewhere else under the name of "generate helperpath" or something. Because basically this is copied of code from nodepath...
-    SPCurve *curve_new = sp_path_get_curve_for_edit(path);
-    SPCurve *flash_curve = curve_new->copy();
-    flash_curve->transform(from_2geom(sp_item_i2d_affine(SP_ITEM(path))));
-    SPCanvasItem * canvasitem = sp_canvas_bpath_new(sp_desktop_tempgroup(desktop), flash_curve);
-    // would be nice if its color could be XORed or something, now it is invisible for red stroked objects...
-    // unless we also flash the nodes...
-    guint32 color = prefs_get_int_attribute("tools.nodes", "highlight_color", 0xff0000ff);
-    sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvasitem), color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
-    sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(canvasitem), 0, SP_WIND_RULE_NONZERO);
-    sp_canvas_item_show(canvasitem);
-    flash_curve->unref();
-    return canvasitem;
-}
-
 static void
 sp_node_context_flash_path(SPEventContext *event_context, SPItem *item, guint timeout) {
     SPNodeContext *nc = SP_NODE_CONTEXT(event_context);
@@ -209,7 +190,7 @@ sp_node_context_flash_path(SPEventContext *event_context, SPItem *item, guint ti
         }
 
         if (SP_IS_PATH(item)) {
-            SPCanvasItem *canvasitem = sp_node_context_generate_helperpath(desktop, SP_PATH(item));
+            SPCanvasItem *canvasitem = sp_nodepath_generate_helperpath(desktop, SP_PATH(item));
             nc->flash_tempitem = desktop->add_temporary_canvasitem (canvasitem, timeout);
         }
     }
@@ -228,23 +209,28 @@ sp_node_context_selection_changed(Inkscape::Selection *selection, gpointer data)
     nc->shape_editor->unset_item();
     SPItem *item = selection->singleItem(); 
     nc->shape_editor->set_item(item);
+    nc->shape_editor->update_statusbar();
+}
 
-    if (nc->flash_permitem) {
-        // hack!!! (we add a temporary canvasitem with life time 1 ms)
-        nc->flash_tempitem = nc->event_context.desktop->add_temporary_canvasitem (nc->flash_permitem, 1);
-        nc->flash_permitem = NULL;
-    }
-    if (SP_IS_LPE_ITEM(item)) {
-        Inkscape::LivePathEffect::Effect *lpe = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item));
-        if (lpe && lpe->pathFlashType() == Inkscape::LivePathEffect::PERMANENT_FLASH) {
-            if (SP_IS_PATH(item)) {
-                SPCanvasItem *canvasitem = sp_node_context_generate_helperpath(nc->event_context.desktop, SP_PATH(item));
-                nc->flash_permitem = canvasitem;
-            }
-        }
-    }
+/**
+\brief  Callback that processes the "modified" signal on the selection;
+updates temporary canvasitems associated to LPEItems in the selection
+*/
+void
+sp_node_context_selection_modified(Inkscape::Selection *selection, guint /*flags*/, gpointer /*data*/)
+{
+    // TODO: do this for *all* items in the selection
+    SPItem *item = selection->singleItem();
 
-    nc->shape_editor->update_statusbar();
+    // TODO: This is *very* inefficient! Can we avoid destroying and recreating the temporary
+    // items? Also, we should only update those that actually need it!
+    if (item && SP_IS_LPE_ITEM(item)) {
+        SPLPEItem *lpeitem = SP_LPE_ITEM(item);
+        SPDesktop *desktop = selection->desktop();
+
+        sp_lpe_item_remove_temporary_canvasitems(lpeitem, desktop);
+        sp_lpe_item_add_temporary_canvasitems(lpeitem, desktop);
+    }
 }
 
 void
@@ -268,8 +254,8 @@ sp_node_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEve
             Inkscape::LivePathEffect::Effect *lpe = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item));
             if (lpe) {
                 if (lpe->pathFlashType() == Inkscape::LivePathEffect::SUPPRESS_FLASH) {
-                    // return if flash is suppressed or if we want a permanent "flash" (this is handled
-                    // in sp_node_context_selection_changed()
+                    // suppressed and permanent flashes for LPE items are handled in
+                    // sp_node_context_selection_changed()
                     return ret;
                 }
                 if (lpe->pathFlashType() == Inkscape::LivePathEffect::PERMANENT_FLASH) {
index baa37af915f6658d82c3c60d8db66b2aecc68109..f67a32f6b7784fe3d211fcf3ddaf72e6edcca0c1 100644 (file)
@@ -48,6 +48,7 @@ struct SPNodeContext {
        bool rb_escaped;
 
        sigc::connection sel_changed_connection;
+       sigc::connection sel_modified_connection;
 
        Inkscape::MessageContext *_node_message_context;
 
@@ -59,7 +60,6 @@ struct SPNodeContext {
  
     SPItem * flashed_item;
     Inkscape::Display::TemporaryItem * flash_tempitem;
-    SPCanvasItem * flash_permitem;
     int remove_flash_counter;
 };
 
@@ -72,5 +72,17 @@ struct SPNodeContextClass {
 GtkType sp_node_context_get_type (void);
 
 void sp_node_context_selection_changed (Inkscape::Selection * selection, gpointer data);
+void sp_node_context_selection_modified (Inkscape::Selection * selection, guint flags, gpointer data);
 
 #endif
+
+/*
+  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 :
index 7e7e19870a5587c132aa3a8bfa39406d2ac8ecaa..ee8e5e1237983194f3f11632312b944615a5e0ce 100644 (file)
@@ -4730,6 +4730,23 @@ void sp_nodepath_set_curve (Inkscape::NodePath::Path *np, SPCurve *curve) {
     }
 }
 
+SPCanvasItem *
+sp_nodepath_generate_helperpath(SPDesktop *desktop, SPPath *path) {
+    // This should be put somewhere else under the name of "generate helperpath" or something. Because basically this is copied of code from nodepath...
+    SPCurve *curve_new = sp_path_get_curve_for_edit(path);
+    SPCurve *flash_curve = curve_new->copy();
+    flash_curve->transform(sp_item_i2d_affine(SP_ITEM(path)));
+    SPCanvasItem * canvasitem = sp_canvas_bpath_new(sp_desktop_tempgroup(desktop), flash_curve);
+    // would be nice if its color could be XORed or something, now it is invisible for red stroked objects...
+    // unless we also flash the nodes...
+    guint32 color = prefs_get_int_attribute("tools.nodes", "highlight_color", 0xff0000ff);
+    sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvasitem), color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
+    sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(canvasitem), 0, SP_WIND_RULE_NONZERO);
+    sp_canvas_item_show(canvasitem);
+    flash_curve->unref();
+    return canvasitem;
+}
+
 void sp_nodepath_show_helperpath(Inkscape::NodePath::Path *np, bool show) {
     np->show_helperpath = show;
 
index 4b39388e50d67d0ecae08f03bc5050fe7f22e228..42bfcfd212ec484e0d64bc6166c45304a151e383 100644 (file)
@@ -307,6 +307,7 @@ NR::Rect sp_node_selected_bbox (Inkscape::NodePath::Path *nodepath);
 NR::Maybe<NR::Coord> sp_node_selected_common_coord (Inkscape::NodePath::Path *nodepath, NR::Dim2 axis);
 
 void sp_nodepath_show_handles(Inkscape::NodePath::Path *nodepath, bool show);
+SPCanvasItem *sp_nodepath_generate_helperpath(SPDesktop *desktop, SPPath *path);
 void sp_nodepath_show_helperpath(Inkscape::NodePath::Path *nodepath, bool show);
 void sp_nodepath_make_straight_path(Inkscape::NodePath::Path *np);
 
index acab9396c86bb29b758a951e8b06d9dfb888373f..33be17a8ef19528943e33b6b7ec8bf92d2da0373 100644 (file)
@@ -192,6 +192,10 @@ void Selection::_add(SPObject *obj) {
 
     add_3D_boxes_recursively(obj);
 
+    if (SP_IS_LPE_ITEM(obj)) {
+        sp_lpe_item_add_temporary_canvasitems(SP_LPE_ITEM(obj), desktop());
+    }
+
     _release_connections[obj] = obj->connectRelease(sigc::mem_fun(*this, (void (Selection::*)(SPObject *))&Selection::remove));
     _modified_connections[obj] = obj->connectModified(sigc::mem_fun(*this, &Selection::_schedule_modified));
 }
@@ -258,6 +262,10 @@ void Selection::_remove(SPObject *obj) {
 
     remove_3D_boxes_recursively(obj);
 
+    if (SP_IS_LPE_ITEM(obj)) {
+        sp_lpe_item_remove_temporary_canvasitems(SP_LPE_ITEM(obj), desktop());
+    }
+
     _objs = g_slist_remove(_objs, obj);
 }
 
index abcf00ad2dc7cbdc2b312f7f25db33a96c121c53..4c2ca3857f6bc28b920a68799ebc85c9f3728328 100644 (file)
@@ -708,6 +708,25 @@ bool sp_lpe_item_path_effects_enabled(SPLPEItem *lpeitem)
     return lpeitem->path_effects_enabled > 0;
 }
 
+void
+sp_lpe_item_add_temporary_canvasitems(SPLPEItem *lpeitem, SPDesktop *desktop)
+{
+    Inkscape::LivePathEffect::Effect *lpe = sp_lpe_item_get_current_lpe(lpeitem);
+    if (lpe) {
+        lpe->addHelperPaths(lpeitem, desktop);
+    }
+}
+
+void
+sp_lpe_item_remove_temporary_canvasitems(SPLPEItem *lpeitem, SPDesktop *desktop)
+{
+    // destroy all temporary canvasitems created by LPEs
+    std::vector<Inkscape::Display::TemporaryItem*>::iterator i;
+    for (i = lpeitem->lpe_helperpaths.begin(); i != lpeitem->lpe_helperpaths.end(); ++i) {
+        desktop->remove_temporary_canvasitem(*i);
+    }
+}
+
 /*
   Local Variables:
   mode:c++
index 3aba7b8a7a4aa16de87c5ae5a16e8c7e709bb819..7691ce9803525898d5e177cfa5ae6eefb3acfdae 100644 (file)
@@ -40,6 +40,7 @@ struct SPLPEItem : public SPItem {
 
     PathEffectList* path_effect_list;
     Inkscape::LivePathEffect::LPEObjectReference* current_path_effect;
+    std::vector<Inkscape::Display::TemporaryItem*> lpe_helperpaths;
 
     sigc::connection lpe_modified_connection;
 };
@@ -70,6 +71,8 @@ Inkscape::LivePathEffect::LPEObjectReference* sp_lpe_item_get_current_lpereferen
 Inkscape::LivePathEffect::Effect* sp_lpe_item_get_current_lpe(SPLPEItem *lpeitem);
 bool sp_lpe_item_set_current_path_effect(SPLPEItem *lpeitem, Inkscape::LivePathEffect::LPEObjectReference* lperef);
 bool sp_lpe_item_path_effects_enabled(SPLPEItem *lpeitem);
+void sp_lpe_item_add_temporary_canvasitems(SPLPEItem *lpeitem, SPDesktop *desktop);
+void sp_lpe_item_remove_temporary_canvasitems(SPLPEItem *lpeitem, SPDesktop *desktop);
 
 #endif /* !SP_LPE_ITEM_H_SEEN */