From bbde5dbeeb06611e99f9fa7f73dafe3bf70df01c Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Date: Sun, 27 Aug 2017 12:55:26 +0200 Subject: Working on preview over powerpencil --- src/live_effects/lpe-powerstroke.cpp | 31 ++- src/live_effects/lpe-powerstroke.h | 3 +- .../parameter/powerstrokepointarray.cpp | 4 +- src/live_effects/parameter/powerstrokepointarray.h | 3 + src/ui/tools/freehand-base.cpp | 65 +++---- src/ui/tools/pencil-tool.cpp | 215 +++++++++++++++++---- src/ui/tools/pencil-tool.h | 8 +- src/widgets/pencil-toolbar.cpp | 71 ++++++- 8 files changed, 318 insertions(+), 82 deletions(-) (limited to 'src') diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 05ce3b7bd..ae2ce1e65 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -167,6 +167,7 @@ LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) : sort_points(_("Sort points"), _("Sort offset points according to their time value along the curve"), "sort_points", &wr, this, true), interpolator_type(_("Interpolator type:"), _("Determines which kind of interpolator will be used to interpolate between stroke width along the path"), "interpolator_type", InterpolatorTypeConverter, &wr, this, Geom::Interpolate::INTERP_CUBICBEZIER), interpolator_beta(_("Smoothness:"), _("Sets the smoothness for the CubicBezierJohan interpolator; 0 = linear interpolation, 1 = smooth"), "interpolator_beta", &wr, this, 0.2), + scale_width(_("Width scale:"), _("Width scale all points"), "scale_width", &wr, this, 1.0), start_linecap_type(_("Start cap:"), _("Determines the shape of the path's start"), "start_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_BUTT), linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", LineJoinTypeConverter, &wr, this, LINEJOIN_EXTRP_MITER_ARC), miter_limit(_("Miter limit:"), _("Maximum length of the miter (in units of stroke width)"), "miter_limit", &wr, this, 4.), @@ -186,14 +187,22 @@ LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) : registerParameter(&start_linecap_type); registerParameter(&linejoin_type); registerParameter(&miter_limit); + registerParameter(&scale_width); registerParameter(&end_linecap_type); + scale_width.param_set_range(0.0, Geom::infinity()); + scale_width.param_set_increments(1, 1); + scale_width.param_set_digits(4); } LPEPowerStroke::~LPEPowerStroke() { } - +void +LPEPowerStroke::doBeforeEffect(SPLPEItem const *lpeItem) +{ + offset_points.set_scale_width(scale_width); +} void LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem) { @@ -247,6 +256,7 @@ LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem) points.push_back( Geom::Point(size - 0.2,width) ); } } + offset_points.set_scale_width(scale_width); offset_points.param_set_and_write_new_value(points); } else { if (!SP_IS_SHAPE(lpeitem)) { @@ -559,7 +569,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) Geom::Piecewise > pwd2_in = pathv[0].toPwSb(); Piecewise > der = derivative(pwd2_in); Piecewise > n = unitVector(der,0.0001); - if (!n.size()) { + if (!n.size() || !pwd2_in.size() || !n.size()) { return path_in; } n = rot90(n); @@ -568,10 +578,15 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) LineCapType end_linecap = static_cast(end_linecap_type.get_value()); LineCapType start_linecap = static_cast(start_linecap_type.get_value()); - std::vector ts = offset_points.data(); - if (ts.empty()) { + std::vector ts_no_scale = offset_points.data(); + if (ts_no_scale.empty()) { return path_out; } + std::vector ts; + for (std::vector::iterator tsp = ts_no_scale.begin(); tsp != ts_no_scale.end(); ++tsp) { + Geom::Point p = Geom::Point((*tsp)[Geom::X], (*tsp)[Geom::Y] * scale_width); + ts.push_back(p); + } if (sort_points) { sort(ts.begin(), ts.end(), compare_offsets); } @@ -625,10 +640,16 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) LineJoinType jointype = static_cast(linejoin_type.get_value()); + if (!x.size() || !y.size()) { + return path_in; + } Piecewise > pwd2_out_1 = compose(pwd2_in,x); Piecewise > pwd2_out_2 = y*compose(n,x); + if (!pwd2_out_1.size() || !pwd2_out_2.size()) { + return path_in; + } Piecewise > pwd2_out = pwd2_out_1 + pwd2_out_2; - Piecewise > mirrorpath = reverse(compose(pwd2_in,x) - y*compose(n,x)); + Piecewise > mirrorpath = reverse( pwd2_out_1 - pwd2_out_2); Geom::Path fixed_path = path_from_piecewise_fix_cusps( pwd2_out, y, jointype, miter_limit, LPE_CONVERSION_TOLERANCE); Geom::Path fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, reverse(y), jointype, miter_limit, LPE_CONVERSION_TOLERANCE); diff --git a/src/live_effects/lpe-powerstroke.h b/src/live_effects/lpe-powerstroke.h index 135d39274..4a0eda75a 100644 --- a/src/live_effects/lpe-powerstroke.h +++ b/src/live_effects/lpe-powerstroke.h @@ -27,7 +27,7 @@ public: virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); - + virtual void doBeforeEffect(SPLPEItem const *lpeItem); virtual void doOnApply(SPLPEItem const* lpeitem); virtual void doOnRemove(SPLPEItem const* lpeitem); @@ -40,6 +40,7 @@ private: BoolParam sort_points; EnumParam interpolator_type; ScalarParam interpolator_beta; + ScalarParam scale_width; EnumParam start_linecap_type; EnumParam linejoin_type; ScalarParam miter_limit; diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index 25639b406..bc06e42ca 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -163,7 +163,7 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom: Geom::Point const s = snap_knot_position(p, state); double t = nearest_time(s, pwd2); double offset = dot(s - pwd2.valueAt(t), n.valueAt(t)); - _pparam->_vector.at(_index) = Geom::Point(t, offset); + _pparam->_vector.at(_index) = Geom::Point(t, offset/_pparam->_scale_width); if (_pparam->_vector.size() == 1 ) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setDouble("/live_effect/power_stroke/width", offset); @@ -188,7 +188,7 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_get() const g_warning("Broken powerstroke point at %f, I won't try to add that", offset_point[X]); return Geom::Point(infinity(), infinity()); } - Point canvas_point = pwd2.valueAt(offset_point[X]) + offset_point[Y] * n.valueAt(offset_point[X]); + Point canvas_point = pwd2.valueAt(offset_point[X]) + (offset_point[Y] * _pparam->_scale_width) * n.valueAt(offset_point[X]); return canvas_point; } diff --git a/src/live_effects/parameter/powerstrokepointarray.h b/src/live_effects/parameter/powerstrokepointarray.h index a34163ca1..621d3b969 100644 --- a/src/live_effects/parameter/powerstrokepointarray.h +++ b/src/live_effects/parameter/powerstrokepointarray.h @@ -35,6 +35,7 @@ public: void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); + float median_width(); virtual bool providesKnotHolderEntities() const { return true; } @@ -46,6 +47,8 @@ public: Geom::Piecewise > const & get_pwd2_normal() const { return last_pwd2_normal; } void recalculate_controlpoints_for_new_pwd2(Geom::Piecewise > const & pwd2_in); + void set_scale_width(double scale_width){_scale_width = scale_width;}; + double _scale_width; friend class PowerStrokePointArrayParamKnotHolderEntity; private: diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp index 05afd8058..fba3c8397 100644 --- a/src/ui/tools/freehand-base.cpp +++ b/src/ui/tools/freehand-base.cpp @@ -237,40 +237,36 @@ static void spdc_apply_powerstroke_shape(std::vector points, Freeha Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 3) { SPShape *sp_shape = dynamic_cast(item); - Geom::PathVector pathvector; if (sp_shape) { - pathvector = sp_shape->getCurve()->get_pathvector(); - size_t counter = 0; + SPCurve * c = sp_shape->getCurve(); + if (!c) { + return; + } auto wps = pt->wps.begin(); - double previous_pos = 0.0; for (auto pps = pt->pps.begin(); pps != pt->pps.end(); ++pps,++wps) { - counter++; - Geom::Affine transformCoordinate = item->i2dt_affine(); - Geom::Point position = *pps; - position *= transformCoordinate.inverse(); - double pos = Geom::nearest_time(position, paths_to_pw(pathvector)); - double width = *wps; - if(pos > 1e6) { - pos = 0;; - } - if(pos > pathvector[0].size() ) { - pos = pathvector[0].size(); - } - if ((pos - previous_pos) < pt->min_distance || - (counter == pt->wps.size() || (pos - previous_pos) < 0.1) ) - { - continue; - } - previous_pos = pos; - if (!Geom::are_near(width, 0.0, 0.1) ) { - points.push_back(Geom::Point(pos,width)); - } + pt->addPowerStrokePoint(c, *pps, *wps); + } + } + if(pt->points.empty()){ + //if use mouse give a line + double zoom = SP_EVENT_CONTEXT(dc)->desktop->current_zoom() * 5.0; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + double min = prefs->getIntLimited("/tools/freehand/pencil/minpressure", 0, 1, 100) / 100.0; + double max = prefs->getIntLimited("/tools/freehand/pencil/maxpressure", 100, 1, 100) / 100.0; + if (min > max){ + min = max; } + Geom::Affine transformCoordinate = SP_ITEM(SP_ACTIVE_DESKTOP->currentLayer())->i2dt_affine(); + Geom::Coord scale = transformCoordinate.expansionX(); + double pressure_shirnked = (1.0 * (max - min)) + min; + double pressure_computed = (pressure_shirnked * 8.0 * scale) / zoom; + pt->points.push_back(Geom::Point(0,pressure_computed)); } Effect::createAndApply(POWERSTROKE, dc->desktop->doc(), item); Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE(); - static_cast(lpe)->offset_points.param_set_and_write_new_value(points); + static_cast(lpe)->offset_points.param_set_and_write_new_value(pt->points); + pt->points.clear(); return; } } @@ -389,13 +385,7 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, if (sp_shape) { curve = sp_shape->getCurve(); } - if (SP_IS_PENCIL_CONTEXT(dc)) { - if (prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 3) { - std::vector points; - spdc_apply_powerstroke_shape(points, dc, item); - shape = NONE; - } - } + bool shape_applied = false; SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS); const char *cstroke = sp_repr_css_property(css_item, "stroke", "none"); @@ -407,6 +397,15 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, if (!swidth) { swidth = swidth/2; } + if (SP_IS_PENCIL_CONTEXT(dc)) { + if (prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 3) { + std::vector points; + spdc_apply_powerstroke_shape(points, dc, item); + shape = NONE; + //To allow retain color + shape_applied = true; + } + } #define SHAPE_LENGTH 10 #define SHAPE_HEIGHT 10 diff --git a/src/ui/tools/pencil-tool.cpp b/src/ui/tools/pencil-tool.cpp index 23a442b11..9b411297f 100644 --- a/src/ui/tools/pencil-tool.cpp +++ b/src/ui/tools/pencil-tool.cpp @@ -20,6 +20,7 @@ #include "ui/tools/pencil-tool.h" #include "desktop.h" +#include "inkscape.h" #include "selection.h" #include "selection-chemistry.h" @@ -35,9 +36,14 @@ #include #include "context-fns.h" #include "sp-namedview.h" +#include "xml/node.h" +#include "xml/sp-css-attr.h" +#include "svg/svg.h" +#include "display/curve.h" #include "desktop-style.h" #include "display/sp-canvas.h" #include "display/curve.h" +#include "live_effects/lpe-powerstroke.h" #include "ui/tool/event-utils.h" namespace Inkscape { @@ -64,8 +70,9 @@ PencilTool::PencilTool() , req_tangent(0, 0) , is_drawing(false) , previous_pressure(0.0) + , previous_point(Geom::Point(0,0)) + , start(false) , gap_pressure(1.0) - , min_distance(0.2) , start_clamp(DDC_MIN_PRESSURE) , end_clamp(DDC_MAX_PRESSURE) , sketch_n(0) @@ -315,9 +322,6 @@ bool PencilTool::_handleMotionNotify(GdkEventMotion const &mevent) { // - We cannot do this in the button press handler because at that point we don't know yet // wheter we're going into freehand mode or not this->ps.push_back(this->p[0]); - this->pps.push_back(this->p[0]); - double pressure_computed = pow(this->pressure,3); - this->wps.push_back(pressure_computed); } this->_addFreehandPoint(p, mevent.state); ret = true; @@ -421,12 +425,16 @@ bool PencilTool::_handleButtonRelease(GdkEventButton const &revent) { desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Finishing freehand")); this->_interpolate(); + //Remove here because points are recalculated once finish. This is because we want live preview. + this->points.clear(); spdc_concat_colors_and_flush(this, FALSE); this->sa = NULL; this->ea = NULL; this->ps.clear(); this->wps.clear(); this->pps.clear(); + previous_pressure = 0.0; + previous_point = Geom::Point(0,0); if (this->green_anchor) { this->green_anchor = sp_draw_anchor_destroy(this->green_anchor); } @@ -628,52 +636,184 @@ void PencilTool::_finishEndpoint() { } } -void PencilTool::_addFreehandPoint(Geom::Point const &p, guint /*state*/) { - g_assert( this->npoints > 0 ); - g_return_if_fail(unsigned(this->npoints) < G_N_ELEMENTS(this->p)); +void +sp_powerstroke_preview(SPObject *elemref, Geom::PathVector pathvector, const char * item_id, std::vector points) +{ + using namespace Inkscape::LivePathEffect; + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + Geom::Affine transformCoordinate = SP_ITEM(SP_ACTIVE_DESKTOP->currentLayer())->i2dt_affine(); + Geom::Coord scale = transformCoordinate.expansionX(); + Inkscape::XML::Document *xml_doc = document->getReprDoc(); + Inkscape::XML::Node *preview = NULL; + if (elemref) { + Effect* lpe = SP_LPE_ITEM(elemref)->getCurrentLPE(); + if (points.size() != static_cast(lpe)->offset_points.data().size()) { + static_cast(lpe)->offset_points.param_set_and_write_new_value(points); + } + gchar * pvector_str = sp_svg_write_path(pathvector); + elemref->setAttribute("inkscape:original-d" , pvector_str); + g_free(pvector_str); + } else { + preview = xml_doc->createElement("svg:path"); + preview->setAttribute("id", item_id); + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property (css, "fill","none"); + sp_repr_css_set_property (css, "stroke","#DEDEDE"); + sp_repr_css_set_property (css, "opacity","0.9"); + Glib::ustring css_str; + sp_repr_css_write_string(css,css_str); + preview->setAttribute("style", css_str.c_str()); + gchar * pvector_str = sp_svg_write_path(pathvector); + preview->setAttribute("d" , pvector_str); + g_free(pvector_str); + elemref = SP_ITEM(SP_ACTIVE_DESKTOP->currentLayer())->appendChildRepr(preview); + Inkscape::GC::release(preview); + Effect::createAndApply(POWERSTROKE, SP_ACTIVE_DESKTOP->doc(), SP_ITEM(elemref)); + Effect* lpe = SP_LPE_ITEM(elemref)->getCurrentLPE(); + static_cast(lpe)->offset_points.param_set_and_write_new_value(points); + } +} - if ( ( p != this->p[ this->npoints - 1 ] ) - && in_svg_plane(p) ) - { - - this->p[this->npoints++] = p; - this->_fitAndSplit(); - SPCurve *c; +void +PencilTool::addPowerStrokePoint(SPCurve * c, Geom::Point p, double pressure_data) +{ + bool live = false; + SPCurve * curve; + if(!c) { + SPCurve * previous_red = red_curve->copy(); + SPCurve * previous_green = green_curve->copy(); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + //Simplify a bit the base curve to avoid artifacts + //double tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0); + //prefs->setDouble("/tools/freehand/pencil/tolerance", 30.0); + _interpolate(); + //prefs->setDouble("/tools/freehand/pencil/tolerance", tol); + live = true; if (sa) { - c = sa->curve; + curve = sa->curve; if (!green_curve->is_empty()) { - c->append_continuous( green_curve, 0.0625); + curve->append_continuous( green_curve, 0.0625); + if (!red_curve->is_empty()) { + curve->append_continuous( red_curve, 0.0625); + } } } else { if (!green_curve->is_empty()) { - c = green_curve; + curve = green_curve->copy(); + if (!red_curve->is_empty()) { + curve->append_continuous( red_curve, 0.0625); + } } else { - c = new SPCurve(); + curve = NULL; } } - if (red_curve_is_valid && !red_curve->is_empty()) { - c->append_continuous(red_curve, 0.0625); + red_curve = previous_red->copy(); + green_curve = previous_green->copy(); + previous_red->unref(); + previous_green->unref(); + } else { + curve = c->copy(); + } + SPObject *elemref = NULL; + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + const char * item_id = "___pencil_preview_powerstroke___"; + if ((elemref = document->getObjectById(item_id))) { + if (!live && 2==3) { + LivePathEffectObject * lpeobj = SP_LPE_ITEM(elemref)->getCurrentLPE()->getLPEObj(); + SP_OBJECT(lpeobj)->deleteObject(); + lpeobj = NULL; + elemref->deleteObject(); + elemref = NULL; } - Geom::PathVector pathvector = c->get_pathvector(); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - double pressure = prefs->getInt("/tools/freehand/pencil/freehand-mode", 0) == 3 ? this->pressure :1; - this->ps.push_back(p); - double pressure_computed = pow(this->pressure, 3) * 25; -// std::cout << previous_pressure <<"previous_pressure\n"; -// std::cout << pressure_computed <<"pressure_computed\n"; -// std::cout << std::abs(previous_pressure - pressure_computed) <<"std::abs(previous_pressure - pressure_computed)\n"; -// std::cout << gap_pressure <<"gap_pressure\n"; -// std::cout << Geom::distance(this->pps[this->pps.size()-1], p) << "distance\n"; - - if (previous_pressure == 0.0 || - std::abs(previous_pressure - pressure_computed) > gap_pressure ) - { - previous_pressure = pressure_computed; - this->pps.push_back(p); - this->wps.push_back(pressure_computed); + } + if (!curve) { + return; + } + Geom::Affine transformCoordinate = SP_ITEM(SP_ACTIVE_DESKTOP->currentLayer())->i2dt_affine(); + Geom::Coord scale = transformCoordinate.expansionX(); + double zoom = SP_EVENT_CONTEXT(this)->desktop->current_zoom() * 5.0; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + double min = prefs->getIntLimited("/tools/freehand/pencil/minpressure", 0, 1, 100) / 100.0; + double max = prefs->getIntLimited("/tools/freehand/pencil/maxpressure", 100, 1, 100) / 100.0; + if (min > max){ + min = max; + } + //Maybe the 12 POW can be moved to a preferences 12 give a good results of sensibility on my tablet + //But maybe is a tweakable value. less number = less sensibility + //8 give an aceptable max witht to powerstoke + double pressure_base = pow(pressure_data, 12); + double pressure_shirnked = (pressure_base * (max - min)) + min; + double pressure_factor = pressure_base/pressure_shirnked; + double pressure_computed = (pressure_shirnked * 8.0 * scale) / zoom; + bool force = false; + bool buttonrelease = false; + if (pressure_computed < 0.05 && previous_pressure != 0.0 ) { + pressure_computed = previous_pressure; + force = true; + buttonrelease = true; +// } else if (std::abs(previous_pressure - pressure_computed) > 4 && previous_pressure != 0.0) { +// pressure_computed = previous_pressure; +// force = true; + } + if (previous_pressure == 0.0 && pressure_computed != 0.0) { + start = true; + } + double tol = 135.0 / zoom; + Geom::PathVector pathvector = curve->get_pathvector(); + pathvector *= transformCoordinate.inverse(); + if (start || force || std::abs(previous_pressure - pressure_computed) > gap_pressure / (zoom * pressure_factor)) { + previous_pressure = pressure_computed; + double pos = pathvector[0].size(); + if (live) { + p = pathvector[0].finalPoint(); + } else { + pos = Geom::nearest_time(p, paths_to_pw(pathvector)); + } + //This magic number get an acurate result maybe is better move to preferences and optionaly add GUI + + //Force star and end in start and end path position + if(pos > 1e6 || start) { + pos = 0.0; + } else if (buttonrelease) { + pos = pathvector[0].size(); + } else if (pos > 0.0 && Geom::distance(p, previous_point) < tol ) { + sp_powerstroke_preview(elemref, pathvector, item_id, points); + return; + } + start = false; + previous_point = p; + this->points.push_back(Geom::Point(pos, pressure_computed)); + if (live) { + pps.push_back(p); + wps.push_back(pressure_data); } + } + if (live) { + sp_powerstroke_preview(elemref, pathvector, item_id, points); + } +} + +void PencilTool::_addFreehandPoint(Geom::Point const &p, guint /*state*/) { + g_assert( this->npoints > 0 ); + g_return_if_fail(unsigned(this->npoints) < G_N_ELEMENTS(this->p)); + + if ( ( p != this->p[ this->npoints - 1 ] ) + && in_svg_plane(p) ) + { + this->p[this->npoints++] = p; this->_fitAndSplit(); + this->ps.push_back(p); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getInt("/tools/freehand/pencil/freehand-mode", 0) == 3) { + this->addPowerStrokePoint(NULL, p, this->pressure); + } } } @@ -849,6 +989,7 @@ void PencilTool::_sketchInterpolate() { this->ps.clear(); this->pps.clear(); + this->points.clear(); this->wps.clear(); } diff --git a/src/ui/tools/pencil-tool.h b/src/ui/tools/pencil-tool.h index b6e9680d2..607d10c4a 100644 --- a/src/ui/tools/pencil-tool.h +++ b/src/ui/tools/pencil-tool.h @@ -46,13 +46,15 @@ public: std::vector ps; std::vector pps; + std::vector points; std::vector wps; double previous_pressure; + Geom::Point previous_point; + bool start; double gap_pressure; - double min_distance; double start_clamp; double end_clamp; - + void addPowerStrokePoint(SPCurve * c, Geom::Point p, double pressure_data); Geom::Piecewise > sketch_interpolation; // the current proposal from the sketched paths unsigned sketch_n; // number of sketches done @@ -71,8 +73,8 @@ private: bool _handleButtonRelease(GdkEventButton const &revent); bool _handleKeyPress(GdkEventKey const &event); bool _handleKeyRelease(GdkEventKey const &event); - void _setStartpoint(Geom::Point const &p); + void _setEndpoint(Geom::Point const &p); void _finishEndpoint(); void _addFreehandPoint(Geom::Point const &p, guint state); diff --git a/src/widgets/pencil-toolbar.cpp b/src/widgets/pencil-toolbar.cpp index d3c7f5a79..f33a33ecd 100644 --- a/src/widgets/pencil-toolbar.cpp +++ b/src/widgets/pencil-toolbar.cpp @@ -83,6 +83,16 @@ static void freehand_mode_changed(EgeSelectOneAction* act, GObject* tbl) if (SP_IS_PEN_CONTEXT(desktop->event_context)) { Inkscape::UI::Tools::PenTool *pc = SP_PEN_CONTEXT(desktop->event_context); pc->setPolylineMode(); + } else { + if (mode == 3) { + gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "shape_action") ), false ); + gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "minpressure") ), true ); + gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "maxpressure") ), true ); + } else { + gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "shape_action") ), true ); + gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "minpressure") ), false ); + gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "maxpressure") ), false ); + } } if (mode == 1 || mode == 2) { gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "flatten_spiro_bspline") ), true ); @@ -241,6 +251,11 @@ static void freehand_add_advanced_shape_options(GtkActionGroup* mainActions, GOb g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(freehand_change_shape), holder ); gtk_action_group_add_action( mainActions, GTK_ACTION(act1) ); g_object_set_data( holder, "shape_action", act1 ); + if (prefs->getInt("/tools/freehand/pencil/freehand-mode", 0) == 3) { + gtk_action_set_visible( GTK_ACTION(act1), false ); + } else { + gtk_action_set_visible( GTK_ACTION(act1), true ); + } } } @@ -351,6 +366,26 @@ static void sp_simplify_flatten(GtkWidget * /*widget*/, GObject *obj) } } +static void sp_minpressure_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + // quit if run by the attr_changed listener + if (g_object_get_data( tbl, "freeze" )) { + return; + } + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/freehand/pencil/minpressure", gtk_adjustment_get_value(adj)); +} + +static void sp_maxpressure_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + // quit if run by the attr_changed listener + if (g_object_get_data( tbl, "freeze" )) { + return; + } + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/freehand/pencil/maxpressure", gtk_adjustment_get_value(adj)); +} + static void sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl) { // quit if run by the attr_changed listener @@ -445,7 +480,41 @@ void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb sp_add_freehand_mode_toggle(mainActions, holder, true); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); EgeAdjustmentAction* eact = 0; - + /* min pressure */ + { + eact = create_adjustment_action( "MinPressureAction", + _("Min presure"), _("Min:"), _("Min percent of pressure"), + "/tools/freehand/pencil/minpressure", 0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0, 100, 1, 0, + 0, 0, 0, + sp_minpressure_value_changed, NULL, 0 ,0); + + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + g_object_set_data( holder, "minpressure", eact ); + if (prefs->getInt("/tools/freehand/pencil/freehand-mode", 0) == 3) { + gtk_action_set_visible( GTK_ACTION(eact), true ); + } else { + gtk_action_set_visible( GTK_ACTION(eact), false ); + } + } + /* max pressure */ + { + eact = create_adjustment_action( "MaxPressureAction", + _("Max presure"), _("Max:"), _("Max percent of pressure"), + "/tools/freehand/pencil/maxpressure", 100, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0, 100, 1, 0, + 0, 0, 0, + sp_maxpressure_value_changed, NULL, 0 ,0); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + g_object_set_data( holder, "maxpressure", eact ); + if (prefs->getInt("/tools/freehand/pencil/freehand-mode", 0) == 3) { + gtk_action_set_visible( GTK_ACTION(eact), true ); + } else { + gtk_action_set_visible( GTK_ACTION(eact), false ); + } + } /* Tolerance */ { gchar const* labels[] = {_("(many nodes, rough)"), _("(default)"), 0, 0, 0, 0, _("(few nodes, smooth)")}; -- cgit v1.2.3