From: cilix42 Date: Mon, 16 Jun 2008 15:45:16 +0000 (+0000) Subject: First step towards making helper paths for LPE items work better X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=04c99c338ffdc6e10cb6f5c18f6f06b3f555e8eb;p=inkscape.git First step towards making helper paths for LPE items work better --- diff --git a/src/display/canvas-temporary-item.cpp b/src/display/canvas-temporary-item.cpp index d31323b72..ccef4d0cb 100644 --- a/src/display/canvas-temporary-item.cpp +++ b/src/display/canvas-temporary-item.cpp @@ -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); diff --git a/src/display/canvas-temporary-item.h b/src/display/canvas-temporary-item.h index ec1e3b999..5077fb55b 100644 --- a/src/display/canvas-temporary-item.h +++ b/src/display/canvas-temporary-item.h @@ -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 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 diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 551b23a1d..0497d0e37 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -21,6 +21,9 @@ #include #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 */ diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index f1241c54b..32917f8c8 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -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 param_vector; std::vector > 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&); }; diff --git a/src/live_effects/lpe-mirror_reflect.cpp b/src/live_effects/lpe-mirror_reflect.cpp index 093841c8d..6a149dfc5 100644 --- a/src/live_effects/lpe-mirror_reflect.cpp +++ b/src/live_effects/lpe-mirror_reflect.cpp @@ -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(&reflection_line) ); } diff --git a/src/live_effects/lpe-perp_bisector.cpp b/src/live_effects/lpe-perp_bisector.cpp index 7c08bdb08..bcfe57614 100644 --- a/src/live_effects/lpe-perp_bisector.cpp +++ b/src/live_effects/lpe-perp_bisector.cpp @@ -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(&length_left) ); registerParameter( dynamic_cast(&length_right) ); diff --git a/src/live_effects/lpe-tangent_to_curve.cpp b/src/live_effects/lpe-tangent_to_curve.cpp index 6ca785001..9e63ef4a4 100644 --- a/src/live_effects/lpe-tangent_to_curve.cpp +++ b/src/live_effects/lpe-tangent_to_curve.cpp @@ -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(&angle) ); registerParameter( dynamic_cast(&t_attach) ); registerParameter( dynamic_cast(&length_left) ); diff --git a/src/node-context.cpp b/src/node-context.cpp index 40b983360..88ea1667d 100644 --- a/src/node-context.cpp +++ b/src/node-context.cpp @@ -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) { diff --git a/src/node-context.h b/src/node-context.h index baa37af91..f67a32f6b 100644 --- a/src/node-context.h +++ b/src/node-context.h @@ -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 : diff --git a/src/nodepath.cpp b/src/nodepath.cpp index 7e7e19870..ee8e5e123 100644 --- a/src/nodepath.cpp +++ b/src/nodepath.cpp @@ -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; diff --git a/src/nodepath.h b/src/nodepath.h index 4b39388e5..42bfcfd21 100644 --- a/src/nodepath.h +++ b/src/nodepath.h @@ -307,6 +307,7 @@ NR::Rect sp_node_selected_bbox (Inkscape::NodePath::Path *nodepath); NR::Maybe 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); diff --git a/src/selection.cpp b/src/selection.cpp index acab9396c..33be17a8e 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -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); } diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index abcf00ad2..4c2ca3857 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -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::iterator i; + for (i = lpeitem->lpe_helperpaths.begin(); i != lpeitem->lpe_helperpaths.end(); ++i) { + desktop->remove_temporary_canvasitem(*i); + } +} + /* Local Variables: mode:c++ diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h index 3aba7b8a7..7691ce980 100644 --- a/src/sp-lpe-item.h +++ b/src/sp-lpe-item.h @@ -40,6 +40,7 @@ struct SPLPEItem : public SPItem { PathEffectList* path_effect_list; Inkscape::LivePathEffect::LPEObjectReference* current_path_effect; + std::vector 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 */