summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2015-07-30 22:58:35 +0000
committerJabiertxof <jtx@jtx.marker.es>2015-07-30 22:58:35 +0000
commit5f5e9e2b956b22445a576fbfffef951a76f55fa3 (patch)
tree270a25bcf15567f61ce8d062fa11f4beda02d4e9 /src
parentupdate to trunk (diff)
parentMerge lp:~inkscape.dev/inkscape/bendFromClipboard into lp:inkscape (diff)
downloadinkscape-5f5e9e2b956b22445a576fbfffef951a76f55fa3.tar.gz
inkscape-5f5e9e2b956b22445a576fbfffef951a76f55fa3.zip
update to trunk
(bzr r13879.1.19)
Diffstat (limited to 'src')
-rw-r--r--src/knot.cpp249
-rw-r--r--src/live_effects/lpe-simplify.cpp1
-rw-r--r--src/sp-factory.cpp2
-rw-r--r--src/sp-filter-primitive.cpp4
-rw-r--r--src/sp-item.cpp4
-rw-r--r--src/text-editing.cpp12
-rw-r--r--src/ui/tools/freehand-base.cpp113
-rw-r--r--src/ui/tools/pen-tool.cpp3
-rw-r--r--src/ui/tools/pencil-tool.cpp14
-rw-r--r--src/widgets/pencil-toolbar.cpp92
-rw-r--r--src/widgets/toolbox.cpp2
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 />"