diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2015-07-30 22:58:35 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx.marker.es> | 2015-07-30 22:58:35 +0000 |
| commit | 5f5e9e2b956b22445a576fbfffef951a76f55fa3 (patch) | |
| tree | 270a25bcf15567f61ce8d062fa11f4beda02d4e9 /src | |
| parent | update to trunk (diff) | |
| parent | Merge lp:~inkscape.dev/inkscape/bendFromClipboard into lp:inkscape (diff) | |
| download | inkscape-5f5e9e2b956b22445a576fbfffef951a76f55fa3.tar.gz inkscape-5f5e9e2b956b22445a576fbfffef951a76f55fa3.zip | |
update to trunk
(bzr r13879.1.19)
Diffstat (limited to 'src')
| -rw-r--r-- | src/knot.cpp | 249 | ||||
| -rw-r--r-- | src/live_effects/lpe-simplify.cpp | 1 | ||||
| -rw-r--r-- | src/sp-factory.cpp | 2 | ||||
| -rw-r--r-- | src/sp-filter-primitive.cpp | 4 | ||||
| -rw-r--r-- | src/sp-item.cpp | 4 | ||||
| -rw-r--r-- | src/text-editing.cpp | 12 | ||||
| -rw-r--r-- | src/ui/tools/freehand-base.cpp | 113 | ||||
| -rw-r--r-- | src/ui/tools/pen-tool.cpp | 3 | ||||
| -rw-r--r-- | src/ui/tools/pencil-tool.cpp | 14 | ||||
| -rw-r--r-- | src/widgets/pencil-toolbar.cpp | 92 | ||||
| -rw-r--r-- | src/widgets/toolbox.cpp | 2 |
11 files changed, 351 insertions, 145 deletions
diff --git a/src/knot.cpp b/src/knot.cpp index b3813ab53..bfc0c4f0b 100644 --- a/src/knot.cpp +++ b/src/knot.cpp @@ -206,6 +206,8 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot return true; } + bool key_press_event_unconsumed = FALSE; + knot_ref(knot); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -213,158 +215,163 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot switch (event->type) { case GDK_2BUTTON_PRESS: - if (event->button.button == 1) { - knot->doubleclicked_signal.emit(knot, event->button.state); + if (event->button.button == 1) { + knot->doubleclicked_signal.emit(knot, event->button.state); - grabbed = FALSE; - moved = FALSE; - consumed = TRUE; - } - break; + grabbed = FALSE; + moved = FALSE; + consumed = TRUE; + } + break; case GDK_BUTTON_PRESS: - if ((event->button.button == 1) && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) { - Geom::Point const p = knot->desktop->w2d(Geom::Point(event->button.x, event->button.y)); - knot->startDragging(p, (gint) event->button.x, (gint) event->button.y, event->button.time); + if ((event->button.button == 1) && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) { + Geom::Point const p = knot->desktop->w2d(Geom::Point(event->button.x, event->button.y)); + knot->startDragging(p, (gint) event->button.x, (gint) event->button.y, event->button.time); - consumed = TRUE; - } - break; + consumed = TRUE; + } + break; case GDK_BUTTON_RELEASE: - if (event->button.button == 1 && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) { - // If we have any pending snap event, then invoke it now - if (knot->desktop->event_context->_delayed_snap_event) { - sp_event_context_snap_watchdog_callback(knot->desktop->event_context->_delayed_snap_event); - } - - sp_event_context_discard_delayed_snap_event(knot->desktop->event_context); - - knot->pressure = 0; - - if (transform_escaped) { - transform_escaped = false; - consumed = TRUE; - } else { - knot->setFlag(SP_KNOT_GRABBED, FALSE); - - if (!nograb) { - sp_canvas_item_ungrab(knot->item, event->button.time); - } + if (event->button.button == 1 && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) { + // If we have any pending snap event, then invoke it now + if (knot->desktop->event_context->_delayed_snap_event) { + sp_event_context_snap_watchdog_callback(knot->desktop->event_context->_delayed_snap_event); + } - if (moved) { - knot->setFlag(SP_KNOT_DRAGGING, FALSE); + sp_event_context_discard_delayed_snap_event(knot->desktop->event_context); - knot->ungrabbed_signal.emit(knot, event->button.state); - } else { - knot->click_signal.emit(knot, event->button.state); - } + knot->pressure = 0; - grabbed = FALSE; - moved = FALSE; - consumed = TRUE; - } - } - if (tools_isactive(knot->desktop, TOOLS_NODES)) { - Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(knot->desktop->event_context); - nt->update_helperpath(); - } - break; - case GDK_MOTION_NOTIFY: - if (grabbed && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) { + if (transform_escaped) { + transform_escaped = false; consumed = TRUE; + } else { + knot->setFlag(SP_KNOT_GRABBED, FALSE); - if ( within_tolerance - && ( abs( (gint) event->motion.x - xp ) < tolerance ) - && ( abs( (gint) event->motion.y - yp ) < tolerance ) ) { - break; // do not drag if we're within tolerance from origin + if (!nograb) { + sp_canvas_item_ungrab(knot->item, event->button.time); } - // Once the user has moved farther than tolerance from the original location - // (indicating they intend to move the object, not click), then always process the - // motion notify coordinates as given (no snapping back to origin) - within_tolerance = false; + if (moved) { + knot->setFlag(SP_KNOT_DRAGGING, FALSE); - if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &knot->pressure)) { - knot->pressure = CLAMP (knot->pressure, 0, 1); + knot->ungrabbed_signal.emit(knot, event->button.state); } else { - knot->pressure = 0.5; + knot->click_signal.emit(knot, event->button.state); } - if (!moved) { - knot->grabbed_signal.emit(knot, event->motion.state); + grabbed = FALSE; + moved = FALSE; + consumed = TRUE; + } + } + if (tools_isactive(knot->desktop, TOOLS_NODES)) { + Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(knot->desktop->event_context); + nt->update_helperpath(); + } + break; + case GDK_MOTION_NOTIFY: + if (grabbed && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) { + consumed = TRUE; - knot->setFlag(SP_KNOT_DRAGGING, TRUE); - } + if ( within_tolerance + && ( abs( (gint) event->motion.x - xp ) < tolerance ) + && ( abs( (gint) event->motion.y - yp ) < tolerance ) ) { + break; // do not drag if we're within tolerance from origin + } + + // Once the user has moved farther than tolerance from the original location + // (indicating they intend to move the object, not click), then always process the + // motion notify coordinates as given (no snapping back to origin) + within_tolerance = false; - sp_event_context_snap_delay_handler(knot->desktop->event_context, NULL, knot, (GdkEventMotion *)event, Inkscape::UI::Tools::DelayedSnapEvent::KNOT_HANDLER); - sp_knot_handler_request_position(event, knot); - moved = TRUE; + if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &knot->pressure)) { + knot->pressure = CLAMP (knot->pressure, 0, 1); + } else { + knot->pressure = 0.5; } - if (tools_isactive(knot->desktop, TOOLS_NODES)) { - Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(knot->desktop->event_context); - nt->update_helperpath(); + + if (!moved) { + knot->grabbed_signal.emit(knot, event->motion.state); + + knot->setFlag(SP_KNOT_DRAGGING, TRUE); } - break; + + sp_event_context_snap_delay_handler(knot->desktop->event_context, NULL, knot, (GdkEventMotion *)event, Inkscape::UI::Tools::DelayedSnapEvent::KNOT_HANDLER); + sp_knot_handler_request_position(event, knot); + moved = TRUE; + } + if (tools_isactive(knot->desktop, TOOLS_NODES)) { + Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(knot->desktop->event_context); + nt->update_helperpath(); + } + break; case GDK_ENTER_NOTIFY: - knot->setFlag(SP_KNOT_MOUSEOVER, TRUE); - knot->setFlag(SP_KNOT_GRABBED, FALSE); + knot->setFlag(SP_KNOT_MOUSEOVER, TRUE); + knot->setFlag(SP_KNOT_GRABBED, FALSE); - if (knot->tip && knot->desktop && knot->desktop->event_context) { - knot->desktop->event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, knot->tip); - } + if (knot->tip && knot->desktop && knot->desktop->event_context) { + knot->desktop->event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, knot->tip); + } - grabbed = FALSE; - moved = FALSE; - consumed = TRUE; - break; + grabbed = FALSE; + moved = FALSE; + consumed = TRUE; + break; case GDK_LEAVE_NOTIFY: - knot->setFlag(SP_KNOT_MOUSEOVER, FALSE); - knot->setFlag(SP_KNOT_GRABBED, FALSE); + knot->setFlag(SP_KNOT_MOUSEOVER, FALSE); + knot->setFlag(SP_KNOT_GRABBED, FALSE); - if (knot->tip && knot->desktop && knot->desktop->event_context) { - knot->desktop->event_context->defaultMessageContext()->clear(); - } + if (knot->tip && knot->desktop && knot->desktop->event_context) { + knot->desktop->event_context->defaultMessageContext()->clear(); + } - grabbed = FALSE; - moved = FALSE; - consumed = TRUE; - break; + grabbed = FALSE; + moved = FALSE; + consumed = TRUE; + break; case GDK_KEY_PRESS: // keybindings for knot - switch (Inkscape::UI::Tools::get_group0_keyval(&event->key)) { - case GDK_KEY_Escape: - knot->setFlag(SP_KNOT_GRABBED, FALSE); - - if (!nograb) { - sp_canvas_item_ungrab(knot->item, event->button.time); - } - - if (moved) { - knot->setFlag(SP_KNOT_DRAGGING, FALSE); - - knot->ungrabbed_signal.emit(knot, event->button.state); - - DocumentUndo::undo(knot->desktop->getDocument()); - knot->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Node or handle drag canceled.")); - transform_escaped = true; - consumed = TRUE; - } - - grabbed = FALSE; - moved = FALSE; - - sp_event_context_discard_delayed_snap_event(knot->desktop->event_context); - break; - default: - consumed = FALSE; - break; - } - break; + switch (Inkscape::UI::Tools::get_group0_keyval(&event->key)) { + case GDK_KEY_Escape: + knot->setFlag(SP_KNOT_GRABBED, FALSE); + + if (!nograb) { + sp_canvas_item_ungrab(knot->item, event->button.time); + } + + if (moved) { + knot->setFlag(SP_KNOT_DRAGGING, FALSE); + + knot->ungrabbed_signal.emit(knot, event->button.state); + + DocumentUndo::undo(knot->desktop->getDocument()); + knot->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Node or handle drag canceled.")); + transform_escaped = true; + consumed = TRUE; + } + + grabbed = FALSE; + moved = FALSE; + + sp_event_context_discard_delayed_snap_event(knot->desktop->event_context); + break; + default: + consumed = FALSE; + key_press_event_unconsumed = TRUE; + break; + } + break; default: - break; + break; } knot_unref(knot); - return consumed || grabbed; + if (key_press_event_unconsumed) { + return false; // e.g. in case "%" was pressed to toggle snapping, or Q for quick zoom (while dragging a handle) + } else { + return consumed || grabbed; + } } void sp_knot_handler_request_position(GdkEvent *event, SPKnot *knot) { diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index 265192a17..f6842a030 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -82,6 +82,7 @@ LPESimplify::newWidget() { // use manage here, because after deletion of Effect object, others might still be pointing to this widget. Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox(Effect::newWidget()) ); + vbox->set_border_width(5); vbox->set_homogeneous(false); vbox->set_spacing(2); diff --git a/src/sp-factory.cpp b/src/sp-factory.cpp index 55e673c4a..84329eaaf 100644 --- a/src/sp-factory.cpp +++ b/src/sp-factory.cpp @@ -297,7 +297,7 @@ SPObject *SPFactory::createObject(std::string const& id) else if (id.empty()) // comments {} else { - fprintf(stderr, "WARNING: unknown type: %s", id.c_str()); + fprintf(stderr, "WARNING: unknown type: %s\n", id.c_str()); } return ret; diff --git a/src/sp-filter-primitive.cpp b/src/sp-filter-primitive.cpp index 1f85c8193..b18850914 100644 --- a/src/sp-filter-primitive.cpp +++ b/src/sp-filter-primitive.cpp @@ -194,7 +194,9 @@ Inkscape::XML::Node* SPFilterPrimitive::write(Inkscape::XML::Document *doc, Inks int sp_filter_primitive_read_in(SPFilterPrimitive *prim, gchar const *name) { - if (!name) return Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; + if (!name || !prim){ + return Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; + } // TODO: are these case sensitive or not? (assumed yes) switch (name[0]) { case 'S': diff --git a/src/sp-item.cpp b/src/sp-item.cpp index 410fd9b37..4937e6c76 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -351,8 +351,8 @@ void SPItem::lowerToBottom() { SPObject * bottom=parent->firstChild(); while(dynamic_cast<SPObject*>(bottom) && dynamic_cast<SPObject*>(bottom->next) && bottom!=this && !is_item(*(bottom->next))) bottom=bottom->next; - if (bottom) { - Inkscape::XML::Node *ref = ( bottom ? bottom->getRepr() : NULL ); + if (bottom && bottom != this) { + Inkscape::XML::Node *ref = bottom->getRepr() ; parent->getRepr()->changeOrder(getRepr(), ref); } } diff --git a/src/text-editing.cpp b/src/text-editing.cpp index 050e223eb..d9cebc625 100644 --- a/src/text-editing.cpp +++ b/src/text-editing.cpp @@ -1805,6 +1805,14 @@ static bool tidy_operator_redundant_semi_nesting(SPObject **item, bool /*has_tex return false; } + +/* tidy_operator_styled_whitespace commented out: not only did it have bugs, + * but it did *not* preserve the rendering: spaces in different font sizes, + * for instance, have different width, so moving them out of tspans changes + * the document. cf https://bugs.launchpad.net/inkscape/+bug/1477723 +*/ + +#if 0 /** helper for tidy_operator_styled_whitespace(), finds the last string object in a paragraph which is not \a not_obj. */ static SPString* find_last_string_child_not_equal_to(SPObject *root, SPObject *not_obj) @@ -1883,6 +1891,7 @@ static bool tidy_operator_styled_whitespace(SPObject **item, bool has_text_decor delete_obj->deleteObject(); return true; } +#endif /* possible tidy operators that are not yet implemented, either because they are difficult, occur infrequently, or because I'm not sure that the @@ -1917,8 +1926,7 @@ static bool tidy_xml_tree_recursively(SPObject *root, bool has_text_decoration) tidy_operator_repeated_spans, tidy_operator_excessive_nesting, tidy_operator_redundant_double_nesting, - tidy_operator_redundant_semi_nesting, - tidy_operator_styled_whitespace + tidy_operator_redundant_semi_nesting }; bool changes = false; diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp index e8cbfcdbf..fa45d8dbb 100644 --- a/src/ui/tools/freehand-base.cpp +++ b/src/ui/tools/freehand-base.cpp @@ -20,7 +20,9 @@ # include "config.h" #endif +#include "live_effects/lpe-bendpath.h" #include "live_effects/lpe-patternalongpath.h" +#include "live_effects/lpe-simplify.h" #include "display/canvas-bpath.h" #include "xml/repr.h" #include "svg/svg.h" @@ -266,12 +268,53 @@ static void spdc_apply_powerstroke_shape(const std::vector<Geom::Point> & points lpe->getRepr()->setAttribute("offset_points", s.str().c_str()); } +static void spdc_apply_bend_shape(gchar const *svgd, FreehandBase *dc, SPItem *item) +{ + using namespace Inkscape::LivePathEffect; + if(!SP_LPE_ITEM(item)->hasPathEffectOfType(BEND_PATH)){ + Effect::createAndApply(BEND_PATH, dc->desktop->doc(), item); + } + Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE(); + + // write bend parameters: + lpe->getRepr()->setAttribute("bendpath", svgd); + lpe->getRepr()->setAttribute("prop_scale", "1"); + lpe->getRepr()->setAttribute("scale_y_rel", "false"); + lpe->getRepr()->setAttribute("vertical", "false"); +} + +static void spdc_apply_simplify(std::string threshold, FreehandBase *dc, SPItem *item) +{ + using namespace Inkscape::LivePathEffect; + + Effect::createAndApply(SIMPLIFY, dc->desktop->doc(), item); + Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE(); + // write powerstroke parameters: + lpe->getRepr()->setAttribute("steps", "1"); + lpe->getRepr()->setAttribute("threshold", threshold); + lpe->getRepr()->setAttribute("smooth_angles", "360"); + lpe->getRepr()->setAttribute("helper_size", "0"); + lpe->getRepr()->setAttribute("simplifyindividualpaths", "false"); + lpe->getRepr()->setAttribute("simplifyJustCoalesce", "false"); +} + +enum shapeType { NONE, TRIANGLE_IN, TRIANGLE_OUT, ELLIPSE, CLIPBOARD, BEND_CLIPBOARD, LAST_APPLIED }; +static shapeType previous_shape_type = NONE; + static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, SPCurve *curve) { using namespace Inkscape::LivePathEffect; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (item && SP_IS_LPE_ITEM(item)) { + bool simplify = prefs->getInt(tool_name(dc) + "/simplify", 0); + if(simplify){ + double tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0); + tol = tol/(100.0*(102.0-tol)); + std::ostringstream ss; + ss << tol; + spdc_apply_simplify(ss.str(), dc, item); + } if (prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 1) { Effect::createAndApply(SPIRO, dc->desktop->doc(), item); } @@ -281,22 +324,25 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, } //Store the clipboard path to apply in the future without the use of clipboard + static Geom::PathVector previous_shape_pathv; - enum shapeType { NONE, TRIANGLE_IN, TRIANGLE_OUT, ELLIPSE, CLIPBOARD, LAST_APPLIED }; - static shapeType previous_shape_type = NONE; + shapeType shape = (shapeType)prefs->getInt(tool_name(dc) + "/shape", 0); 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"); + static SPItem *bend_item; #define SHAPE_LENGTH 10 #define SHAPE_HEIGHT 10 + if(shape == LAST_APPLIED){ + shape = previous_shape_type; - if(shape == CLIPBOARD){ + if(shape == CLIPBOARD || shape == BEND_CLIPBOARD){ shape = LAST_APPLIED; } } @@ -356,15 +402,52 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, shape_applied = true; break; } + case BEND_CLIPBOARD: + { + Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get(); + if(cm->paste(SP_ACTIVE_DESKTOP,true) == true){ + gchar const *svgd = item->getRepr()->attribute("d"); + Geom::PathVector path = sp_svg_read_pathv(svgd); + path *= item->i2doc_affine().inverse(); + svgd = sp_svg_write_path( path ); + bend_item = dc->selection->singleItem(); + bend_item->moveTo(item,false); + spdc_apply_bend_shape(svgd, dc, bend_item); + bend_item->transform = Geom::Affine(1,0,0,1,0,0); + dc->selection->add(SP_OBJECT(bend_item)); + } else { + shape = NONE; + } + break; + } case LAST_APPLIED: { - if(previous_shape_pathv.size() != 0){ - SPCurve * c = new SPCurve(); - c->set_pathvector(previous_shape_pathv); - spdc_paste_curve_as_freehand_shape(c, dc, item); - c->unref(); - - shape_applied = true; + if(previous_shape_type == CLIPBOARD){ + if(previous_shape_pathv.size() != 0){ + SPCurve * c = new SPCurve(); + c->set_pathvector(previous_shape_pathv); + spdc_paste_curve_as_freehand_shape(c, dc, item); + c->unref(); + + shape_applied = true; + } + shape = CLIPBOARD; + } else { + if(bend_item != NULL && bend_item->getRepr() != NULL){ + gchar const *svgd = item->getRepr()->attribute("d"); + Geom::PathVector path = sp_svg_read_pathv(svgd); + path *= item->i2doc_affine().inverse(); + svgd = sp_svg_write_path( path ); + dc->selection->add(SP_OBJECT(bend_item)); + sp_selection_duplicate(dc->desktop); + dc->selection->remove(SP_OBJECT(bend_item)); + bend_item = dc->selection->singleItem(); + bend_item->moveTo(item,false); + spdc_apply_bend_shape(svgd, dc, bend_item); + bend_item->transform = Geom::Affine(1,0,0,1,0,0); + dc->selection->add(SP_OBJECT(bend_item)); + } + shape = BEND_CLIPBOARD; } break; } @@ -643,7 +726,6 @@ void spdc_concat_colors_and_flush(FreehandBase *dc, gboolean forceclosed) static void spdc_flush_white(FreehandBase *dc, SPCurve *gc) { SPCurve *c; - if (dc->white_curves) { g_assert(dc->white_item); c = SPCurve::concat(dc->white_curves); @@ -695,14 +777,17 @@ static void spdc_flush_white(FreehandBase *dc, SPCurve *gc) // Attach repr SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr)); - // we finished the path; now apply any waiting LPEs or freehand shapes spdc_check_for_and_apply_waiting_LPE(dc, item, c); - - dc->selection->set(repr); + if(previous_shape_type != BEND_CLIPBOARD){ + dc->selection->set(repr); + } Inkscape::GC::release(repr); item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); item->updateRepr(); item->doWriteTransform(item->getRepr(), item->transform, NULL, true); + if(previous_shape_type == BEND_CLIPBOARD){ + repr->parent()->removeChild(repr); + } } DocumentUndo::done(doc, SP_IS_PEN_CONTEXT(dc)? SP_VERB_CONTEXT_PEN : SP_VERB_CONTEXT_PENCIL, diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index 827dbf5c3..d924d8773 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -268,6 +268,9 @@ void PenTool::_endpointSnap(Geom::Point &p, guint const state) const { if ((state & GDK_CONTROL_MASK) && !this->polylines_paraxial) { //CTRL enables angular snapping if (this->npoints > 0) { spdc_endpoint_snap_rotation(this, p, this->p[0], state); + } else { + boost::optional<Geom::Point> origin = boost::optional<Geom::Point>(); + spdc_endpoint_snap_free(this, p, origin, state); } } else { // We cannot use shift here to disable snapping because the shift-key is already used diff --git a/src/ui/tools/pencil-tool.cpp b/src/ui/tools/pencil-tool.cpp index 16c26546f..bfb1c67f0 100644 --- a/src/ui/tools/pencil-tool.cpp +++ b/src/ui/tools/pencil-tool.cpp @@ -635,8 +635,11 @@ void PencilTool::_interpolate() { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); double const tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0) * 0.4; - double const tolerance_sq = 0.02 * square(this->desktop->w2d().descrim() * tol) * exp(0.2 * tol - 2); - + double tolerance_sq = 0.02 * square(this->desktop->w2d().descrim() * tol) * exp(0.2 * tol - 2); + bool simplify = prefs->getInt("/tools/freehand/pencil/simplify", 0); + if(simplify){ + tolerance_sq = 0; + } g_assert(is_zero(this->req_tangent) || is_unit_vector(this->req_tangent)); this->green_curve->reset(); @@ -703,8 +706,11 @@ void PencilTool::_sketchInterpolate() { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); double const tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0) * 0.4; - double const tolerance_sq = 0.02 * square(this->desktop->w2d().descrim() * tol) * exp(0.2 * tol - 2); - + double tolerance_sq = 0.02 * square(this->desktop->w2d().descrim() * tol) * exp(0.2 * tol - 2); + bool simplify = prefs->getInt("/tools/freehand/pencil/simplify", 0); + if(simplify){ + tolerance_sq = 0; + } bool average_all_sketches = prefs->getBool("/tools/freehand/pencil/average_all_sketches", true); g_assert(is_zero(this->req_tangent) || is_unit_vector(this->req_tangent)); diff --git a/src/widgets/pencil-toolbar.cpp b/src/widgets/pencil-toolbar.cpp index 1214a378a..aef9b4560 100644 --- a/src/widgets/pencil-toolbar.cpp +++ b/src/widgets/pencil-toolbar.cpp @@ -28,7 +28,9 @@ # include "config.h" #endif +#include <gtkmm.h> #include <glibmm/i18n.h> +#include <list> #include "pencil-toolbar.h" #include "desktop.h" @@ -43,6 +45,14 @@ #include "ui/tools/pen-tool.h" #include "ui/uxmanager.h" #include "widgets/spinbutton-events.h" +#include <selection.h> +#include "live_effects/effect.h" +#include "live_effects/lpe-simplify.h" +#include "live_effects/effect-enum.h" +#include "live_effects/lpeobject.h" +#include "live_effects/lpeobject-reference.h" +#include "sp-lpe-item.h" +#include "util/glib-list-iterators.h" using Inkscape::UI::UXManager; using Inkscape::DocumentUndo; @@ -151,6 +161,12 @@ static void freehand_change_shape(EgeSelectOneAction* act, GObject *dataKludge) prefs->setInt(freehand_tool_name(dataKludge) + "/shape", shape); } +static void freehand_simplify_lpe(InkToggleAction* itact, GObject *dataKludge) { + gint simplify = gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(itact) ); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt(freehand_tool_name(dataKludge) + "/simplify", simplify); +} + /** * Generate the list of freehand advanced shape option entries. */ @@ -162,6 +178,7 @@ static GList * freehand_shape_dropdown_items_list() { glist = g_list_append (glist, _("Triangle out")); glist = g_list_append (glist, _("Ellipse")); glist = g_list_append (glist, _("From clipboard")); + glist = g_list_append (glist, _("Bend from clipboard")); glist = g_list_append (glist, _("Last applied")); return glist; @@ -220,6 +237,41 @@ static void sp_pencil_tb_defaults(GtkWidget * /*widget*/, GObject *obj) spinbutton_defocus(tbl); } +static void sp_simplify_flatten(GtkWidget * /*widget*/, GObject *obj) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(obj, "desktop")); + std::vector<SPItem *> selected = desktop->getSelection()->itemList(); + for (std::vector<SPItem *>::iterator it(selected.begin()); it != selected.end(); ++it){ + SPLPEItem* lpeitem = dynamic_cast<SPLPEItem*>(*it); + if (lpeitem && lpeitem->hasPathEffect()){ + PathEffectList lpelist = lpeitem->getEffectList(); + std::list<Inkscape::LivePathEffect::LPEObjectReference *>::iterator i; + for (i = lpelist.begin(); i != lpelist.end(); ++i) { + LivePathEffectObject *lpeobj = (*i)->lpeobject; + if (lpeobj) { + Inkscape::LivePathEffect::Effect *lpe = lpeobj->get_lpe(); + if (dynamic_cast<Inkscape::LivePathEffect::LPESimplify *>(lpe)) { + SPShape * shape = dynamic_cast<SPShape *>(lpeitem); + if(shape){ + SPCurve * c = shape->getCurveBeforeLPE(); + lpe->doEffect(c); + lpeitem->setCurrentPathEffect(*i); + if (lpelist.size() > 1){ + lpeitem->removeCurrentPathEffect(true); + shape->setCurveBeforeLPE(c); + } else { + lpeitem->removeCurrentPathEffect(false); + shape->setCurve(c,0); + } + break; + } + } + } + } + } + } +} + static void sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl) { // quit if run by the attr_changed listener @@ -232,6 +284,24 @@ static void sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tb prefs->setDouble("/tools/freehand/pencil/tolerance", gtk_adjustment_get_value(adj)); g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(tbl, "desktop")); + std::vector<SPItem *> selected = desktop->getSelection()->itemList(); + for (std::vector<SPItem *>::iterator it(selected.begin()); it != selected.end(); ++it){ + SPLPEItem* lpeitem = dynamic_cast<SPLPEItem*>(*it); + if (lpeitem && lpeitem->hasPathEffect()){ + Inkscape::LivePathEffect::Effect* thisEffect = lpeitem->getPathEffectOfType(Inkscape::LivePathEffect::SIMPLIFY); + if(thisEffect){ + Inkscape::LivePathEffect::LPESimplify *lpe = dynamic_cast<Inkscape::LivePathEffect::LPESimplify*>(thisEffect->getLPEObj()->get_lpe()); + if (lpe) { + double tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0); + tol = tol/(100.0*(102.0-tol)); + std::ostringstream ss; + ss << tol; + lpe->getRepr()->setAttribute("threshold", ss.str()); + } + } + } + } } /* @@ -303,6 +373,28 @@ void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_pencil_tb_defaults), holder ); gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); } + /* LPE simplify based tolerance */ + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + InkToggleAction* itact = ink_toggle_action_new( "PencilLpeSimplify", + _("LPE based interactive simplify"), + _("LPE based interactive simplify"), + INKSCAPE_ICON("interactive_simplify"), + Inkscape::ICON_SIZE_SMALL_TOOLBAR ); + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(itact), prefs->getInt("/tools/freehand/pencil/simplify", 0) ); + g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(freehand_simplify_lpe), holder) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(itact) ); + } + /* LPE simplify flatten */ + { + InkAction* inky = ink_action_new( "PencilLpeSimplifyFlatten", + _("LPE simplify flatten"), + _("LPE simplify flatten"), + INKSCAPE_ICON("flatten_simplify"), + Inkscape::ICON_SIZE_SMALL_TOOLBAR ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_simplify_flatten), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index d56b91f5e..cdf39e9ef 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -398,6 +398,8 @@ static gchar const * ui_descr = " <toolitem action='FreehandModeActionPencil' />" " <separator />" " <toolitem action='PencilToleranceAction' />" + " <toolitem action='PencilLpeSimplify' />" + " <toolitem action='PencilLpeSimplifyFlatten' />" " <separator />" " <toolitem action='PencilResetAction' />" " <separator />" |
