From ad092a3d734fcec79273f957e8d86c7a9ceb767b Mon Sep 17 00:00:00 2001 From: Maximilian Albert Date: Sun, 8 Jun 2008 17:33:58 +0000 Subject: Make knotholders for LPE items finally work; each effect can now overload the addKnotHolderHandles() method to add handles which control its parameters. There is now also a virtual onKnotUngrabbed() method for each knotholder entity which can be used to do cleanup tasks (for LPE parameters it currently writes the value to SVG, although this should probably happen automatically) (bzr r5855) --- src/live_effects/effect.cpp | 30 +++- src/live_effects/effect.h | 6 +- src/live_effects/lpe-tangent_to_curve.cpp | 229 +++++++++++++++++++----------- src/live_effects/lpe-tangent_to_curve.h | 19 ++- src/live_effects/parameter/parameter.h | 3 +- src/live_effects/parameter/point.cpp | 21 +++ src/live_effects/parameter/point.h | 11 +- 7 files changed, 213 insertions(+), 106 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 0749e4e93..db395c81b 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -321,21 +321,39 @@ Effect::registerParameter(Parameter * param) param_vector.push_back(param); } +// TODO: Does it still make sense to use this? E.g., should we keep a list of knotholder entities +// in the effect itself and add them here in a semi-automatic manner (similarly to how it is +// done with parameters) instead of adding each one separately in the overloaded function +// addKnotHolderHandles()? void Effect::registerKnotHolderHandle(SPKnotHolderSetFunc set_func, SPKnotHolderGetFunc get_func) { - knotholder_func_vector.push_back(std::make_pair(set_func, get_func)); + //knotholder_func_vector.push_back(std::make_pair(set_func, get_func)); } -// TODO: allow for adding click_functions and description strings, too void -Effect::addHandles(KnotHolder *knotholder) { - std::vector >::iterator i; - for (i = knotholder_func_vector.begin(); i != knotholder_func_vector.end(); ++i) { - //knotholder->add(i->first, i->second, NULL, ("")); +Effect::addPointParamHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { + using namespace std; + for (std::vector::iterator p = param_vector.begin(); p != param_vector.end(); ++p) { + if ((*p)->paramType() == Inkscape::LivePathEffect::POINT_PARAM) { + g_print ("Parameter is of type PointParam\n"); + KnotHolderEntity *e = dynamic_cast(*p); + e->create(desktop, item, knotholder); + knotholder->add(e); + } else { + g_print ("Parameter is *not* of type PointParam\n"); + } } } +/** + * Virtual method to add knotholder handles for LPE items + */ +void +Effect::addKnotHolderHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +{ +} + /** * 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 a8cb525b8..c46c145b5 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -101,8 +101,9 @@ public: virtual void transform_multiply(Geom::Matrix const& postmul, bool set); - bool providesKnotholder() { return knotholder_func_vector.size() > 0; } - void addHandles(KnotHolder *knotholder); + virtual bool providesKnotholder() { return false; } + void addPointParamHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + virtual void addKnotHolderHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); Glib::ustring getName(); Inkscape::XML::Node * getRepr(); @@ -135,7 +136,6 @@ protected: Parameter * getNextOncanvasEditableParam(); std::vector param_vector; - std::vector > knotholder_func_vector; int oncanvasedit_it; BoolParam is_visible; diff --git a/src/live_effects/lpe-tangent_to_curve.cpp b/src/live_effects/lpe-tangent_to_curve.cpp index 80158e2f4..b61a078a4 100644 --- a/src/live_effects/lpe-tangent_to_curve.cpp +++ b/src/live_effects/lpe-tangent_to_curve.cpp @@ -27,28 +27,110 @@ namespace Inkscape { namespace LivePathEffect { -/* FIXME: We should make these member functions of LPETangentToCurve. - Is there an easy way to register member functions with knotholder? - KNOWN BUG: Because of the above, this effect does not work well when in an LPE stack -*/ -NR::Point attach_pt_get(SPItem *item) { - Inkscape::LivePathEffect::LPETangentToCurve *lpe = - dynamic_cast (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item))); - - if (lpe) - return lpe->ptA; - else - return NR::Point(0,0); +LPETangentToCurve::LPETangentToCurve(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + angle(_("Angle"), _("Additional angle between tangent and curve"), "angle", &wr, this, 0.0), + t_attach(_("Location along curve"), _("Location of the point of attachment along the curve (between 0.0 and number-of-segments)"), "t_attach", &wr, this, 0.5), + 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) +{ + registerParameter( dynamic_cast(&angle) ); + registerParameter( dynamic_cast(&t_attach) ); + registerParameter( dynamic_cast(&length_left) ); + registerParameter( dynamic_cast(&length_right) ); } -void attach_pt_set(SPItem *item, NR::Point const &p, NR::Point const &origin, guint state) { - Inkscape::LivePathEffect::LPETangentToCurve *lpe = - dynamic_cast (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item))); - - if (!lpe) - return; +LPETangentToCurve::~LPETangentToCurve() +{ +} +Geom::Piecewise > +LPETangentToCurve::doEffect_pwd2 (Geom::Piecewise > const & pwd2_in) +{ using namespace Geom; + Piecewise > output; + + ptA = pwd2_in.valueAt(t_attach); + derivA = unit_vector(derivative(pwd2_in).valueAt(t_attach)); + + // TODO: Why are positive angles measured clockwise, not counterclockwise? + Geom::Rotate rot(Geom::Rotate::from_degrees(-angle)); + derivA = derivA * rot; + + C = ptA - derivA * length_left; + D = ptA + derivA * length_right; + + output = Piecewise >(D2(Linear(C[X], D[X]), Linear(C[Y], D[Y]))); + + return output; +} + +class KnotHolderEntityAttachPt : public KnotHolderEntity +{ +public: + virtual bool isLPEParam() { return true; } + + virtual void knot_set(NR::Point const &p, NR::Point const &origin, guint state); + virtual NR::Point knot_get(); + virtual void onKnotUngrabbed(); +}; + +class KnotHolderEntityLeftEnd : public KnotHolderEntity +{ +public: + virtual bool isLPEParam() { return true; } + + virtual void knot_set(NR::Point const &p, NR::Point const &origin, guint state); + virtual NR::Point knot_get(); + virtual void onKnotUngrabbed(); +}; + +class KnotHolderEntityRightEnd : public KnotHolderEntity +{ +public: + virtual bool isLPEParam() { return true; } + + virtual void knot_set(NR::Point const &p, NR::Point const &origin, guint state); + virtual NR::Point knot_get(); + virtual void onKnotUngrabbed(); +}; + +void +LPETangentToCurve::addKnotHolderHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +{ + KnotHolderEntityLeftEnd *entity_left_end = new KnotHolderEntityLeftEnd(); + KnotHolderEntityRightEnd *entity_right_end = new KnotHolderEntityRightEnd(); + KnotHolderEntityAttachPt *entity_attach_pt = new KnotHolderEntityAttachPt(); + + entity_left_end->create(desktop, item, knotholder, + _("Adjust the \"left\" end of the tangent")); + entity_right_end->create(desktop, item, knotholder, + _("Adjust the \"right\" end of the tangent")); + entity_attach_pt->create(desktop, item, knotholder, + _("Adjust the point of attachment of the tangent")); + + knotholder->add(entity_left_end); + knotholder->add(entity_right_end); + knotholder->add(entity_attach_pt); +} + +static LPETangentToCurve * +get_effect(SPItem *item) +{ + Effect *effect = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)); + if (effect->effectType() != TANGENT_TO_CURVE) { + g_print ("Warning: Effect is not of type LPETangentToCurve!\n"); + return NULL; + } + return static_cast(effect); +} + +void +KnotHolderEntityAttachPt::knot_set(NR::Point const &p, NR::Point const &origin, guint state) +{ + using namespace Geom; + + LPETangentToCurve* lpe = get_effect(item); // FIXME: There must be a better way of converting the path's SPCurve* to pwd2. SPCurve *curve = sp_path_get_curve_for_edit (SP_PATH(item)); @@ -66,94 +148,73 @@ void attach_pt_set(SPItem *item, NR::Point const &p, NR::Point const &origin, gu sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), true, true); } -NR::Point left_end_get(SPItem *item) { - Inkscape::LivePathEffect::LPETangentToCurve *lpe = - dynamic_cast (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item))); - - if (lpe) - return lpe->C; - else - return NR::Point(0,0); -} - -NR::Point right_end_get(SPItem *item) { - Inkscape::LivePathEffect::LPETangentToCurve *lpe = - dynamic_cast (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item))); - - if (lpe) - return lpe->D; - else - return NR::Point(0,0); -} - -void left_end_set(SPItem *item, NR::Point const &p, NR::Point const &origin, guint state) { - Inkscape::LivePathEffect::LPETangentToCurve *lpe = - dynamic_cast (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item))); - - if (!lpe) - return; - +void +KnotHolderEntityLeftEnd::knot_set(NR::Point const &p, NR::Point const &origin, guint state) +{ + LPETangentToCurve *lpe = get_effect(item); + double lambda = Geom::nearest_point(p.to_2geom(), lpe->ptA, lpe->derivA); lpe->length_left.param_set_value(-lambda); - // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. - sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), true, true); + sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); } -void right_end_set(SPItem *item, NR::Point const &p, NR::Point const &origin, guint state) { - Inkscape::LivePathEffect::LPETangentToCurve *lpe = - dynamic_cast (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item))); - - if (!lpe) - return; - +void +KnotHolderEntityRightEnd::knot_set(NR::Point const &p, NR::Point const &origin, guint state) +{ + LPETangentToCurve *lpe = get_effect(item); + double lambda = Geom::nearest_point(p.to_2geom(), lpe->ptA, lpe->derivA); lpe->length_right.param_set_value(lambda); - // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. - sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), true, true); + sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); } -LPETangentToCurve::LPETangentToCurve(LivePathEffectObject *lpeobject) : - Effect(lpeobject), - t_attach(_("Location along curve"), _("Location of the point of attachment along the curve (between 0.0 and number-of-segments)"), "t_attach", &wr, this, 0.5), - 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), - angle(_("Angle"), _("Additional angle between tangent and curve"), "angle", &wr, this, 0.0) +NR::Point +KnotHolderEntityAttachPt::knot_get() { - registerParameter( dynamic_cast(&t_attach) ); - registerParameter( dynamic_cast(&length_left) ); - registerParameter( dynamic_cast(&length_right) ); - registerParameter( dynamic_cast(&angle) ); - registerKnotHolderHandle(attach_pt_set, attach_pt_get); - registerKnotHolderHandle(left_end_set, left_end_get); - registerKnotHolderHandle(right_end_set, right_end_get); + LPETangentToCurve* lpe = get_effect(item); + return lpe->ptA; } -LPETangentToCurve::~LPETangentToCurve() +NR::Point +KnotHolderEntityLeftEnd::knot_get() { + LPETangentToCurve *lpe = get_effect(item); + return lpe->C; } -Geom::Piecewise > -LPETangentToCurve::doEffect_pwd2 (Geom::Piecewise > const & pwd2_in) +NR::Point +KnotHolderEntityRightEnd::knot_get() { - using namespace Geom; - Piecewise > output; + LPETangentToCurve *lpe = get_effect(item); + return lpe->D; +} - ptA = pwd2_in.valueAt(t_attach); - derivA = unit_vector(derivative(pwd2_in).valueAt(t_attach)); +void +KnotHolderEntityAttachPt::onKnotUngrabbed() +{ + LPETangentToCurve *lpe = get_effect(item); + lpe->t_attach.write_to_SVG(); +} - // TODO: Why are positive angles measured clockwise, not counterclockwise? - Geom::Rotate rot(Geom::Rotate::from_degrees(-angle)); - derivA = derivA * rot; +void +KnotHolderEntityLeftEnd::onKnotUngrabbed() +{ + LPETangentToCurve *lpe = get_effect(item); + lpe->length_left.write_to_SVG(); +} - C = ptA - derivA * length_left; - D = ptA + derivA * length_right; +void +KnotHolderEntityRightEnd::onKnotUngrabbed() +{ + LPETangentToCurve *lpe = get_effect(item); + lpe->length_right.write_to_SVG(); +} + + - output = Piecewise >(D2(Linear(C[X], D[X]), Linear(C[Y], D[Y]))); - return output; -} } //namespace LivePathEffect } /* namespace Inkscape */ diff --git a/src/live_effects/lpe-tangent_to_curve.h b/src/live_effects/lpe-tangent_to_curve.h index 3bddc11fb..0de2baf56 100644 --- a/src/live_effects/lpe-tangent_to_curve.h +++ b/src/live_effects/lpe-tangent_to_curve.h @@ -28,25 +28,24 @@ public: LPETangentToCurve(LivePathEffectObject *lpeobject); virtual ~LPETangentToCurve(); + bool providesKnotholder() { return true; } + virtual void addKnotHolderHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); - /* the knotholder functions must be declared friends */ - friend NR::Point attach_pt_get(SPItem *item); - friend NR::Point left_end_get(SPItem *item); - friend NR::Point right_end_get(SPItem *item); - friend void attach_pt_set(SPItem *item, NR::Point const &p, NR::Point const &origin, guint state); - friend void left_end_set(SPItem *item, NR::Point const &p, NR::Point const &origin, guint state); - friend void right_end_set(SPItem *item, NR::Point const &p, NR::Point const &origin, guint state); + /* the knotholder entity classes must be declared friends */ + friend class KnotHolderEntityLeftEnd; + friend class KnotHolderEntityRightEnd; + friend class KnotHolderEntityAttachPt; private: - ScalarParam t_attach; + ScalarParam angle; + ScalarParam t_attach; ScalarParam length_left; ScalarParam length_right; - ScalarParam angle; - Geom::Point ptA; // point of attachment to the curve Geom::Point derivA; diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index 511ce46a2..c4e58c8d5 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -58,7 +58,8 @@ public: virtual bool param_readSVGValue(const gchar * strvalue) = 0; // returns true if new value is valid / accepted. virtual gchar * param_getSVGValue() const = 0; - + void write_to_SVG() { param_write_to_repr(param_getSVGValue()); } + virtual void param_set_default() = 0; void printTypeName(); diff --git a/src/live_effects/parameter/point.cpp b/src/live_effects/parameter/point.cpp index 49a47660f..502af1f23 100644 --- a/src/live_effects/parameter/point.cpp +++ b/src/live_effects/parameter/point.cpp @@ -162,12 +162,33 @@ PointParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint knot_color = color; } +void +PointParam::knot_set(NR::Point const &p, NR::Point const &origin, guint state) +{ + g_print ("PointParam::knot_set() was called!\n"); + param_setValue(p.to_2geom()); +} + +NR::Point +PointParam::knot_get() +{ + g_print ("PointParam::knot_get() was called.\n"); + g_print ("We return (%f, %f)\n", (*this)[0], (*this)[1]); + return *this; +} + +void +PointParam::knot_click(guint state) +{ + g_print ("PointParam::knot_click() was called!\n"); +} // CALLBACKS: void PointParam::on_button_click() { + g_print ("PointParam::on_button_click()\n"); SPDesktop *desktop = SP_ACTIVE_DESKTOP; SPItem * item = sp_desktop_selection(desktop)->singleItem(); if (item != NULL) { diff --git a/src/live_effects/parameter/point.h b/src/live_effects/parameter/point.h index d963d835a..3e8dc843a 100644 --- a/src/live_effects/parameter/point.h +++ b/src/live_effects/parameter/point.h @@ -16,14 +16,14 @@ #include "live_effects/parameter/parameter.h" -#include "knot-enums.h" +#include "knot-holder-entity.h" namespace Inkscape { namespace LivePathEffect { -class PointParam : public Geom::Point, public Parameter { +class PointParam : public Geom::Point, public Parameter, public KnotHolderEntity { public: PointParam( const Glib::ustring& label, const Glib::ustring& tip, @@ -51,6 +51,13 @@ public: void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); + /* these are overloaded from KnotHolderEntity */ + virtual void knot_set(NR::Point const &p, NR::Point const &origin, guint state); + virtual NR::Point knot_get(); + virtual void knot_click(guint state); + + virtual bool isLPEParam() { return true; } + private: PointParam(const PointParam&); PointParam& operator=(const PointParam&); -- cgit v1.2.3