Merge lp:~inkscape.dev/inkscape/clip_eraser into lp:~inkscape.dev/inkscape/trunk

Proposed by Jabiertxof
Status: Merged
Merged at revision: 15143
Proposed branch: lp:~inkscape.dev/inkscape/clip_eraser
Merge into: lp:~inkscape.dev/inkscape/trunk
Diff against target: 731 lines (+298/-82)
6 files modified
src/selection-chemistry.cpp (+19/-13)
src/selection-chemistry.h (+3/-3)
src/sp-lpe-item.cpp (+21/-15)
src/ui/tools/eraser-tool.cpp (+108/-38)
src/widgets/eraser-toolbar.cpp (+140/-13)
src/widgets/toolbox.cpp (+7/-0)
To merge this branch: bzr merge lp:~inkscape.dev/inkscape/clip_eraser
Reviewer Review Type Date Requested Status
Martin Owens code Approve
Review via email: mp+295399@code.launchpad.net

Description of the change

Add new mode to eraser tool.
Demo: https://www.youtube.com/watch?v=V1o81NxNKwc

To post a comment you must log in.
14876. By Jabiertxof <email address hidden>

first attem to work throught layers

14877. By Jabiertxof

Speed improvements

14878. By Jabiertxof

Added some widgets from caligraphic tool

14879. By Jabiertxof

Update to trunk and some fixes

Revision history for this message
Martin Owens (doctormo) wrote :

The new feature works really well, the code increases the complexity of the eraser, but that was to be expected with the clipping process.

Approved and merged.

review: Approve (code)
Revision history for this message
Martin Owens (doctormo) wrote :

I've removed the std::cout and made the modes a defined set of constants to make reading the code a bit easier.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/selection-chemistry.cpp'
2--- src/selection-chemistry.cpp 2016-09-15 22:31:44 +0000
3+++ src/selection-chemistry.cpp 2016-10-02 22:45:50 +0000
4@@ -1021,6 +1021,7 @@
5 C_("Undo action", "Raise"));
6 }
7
8+
9 void sp_object_set_raise_to_top(ObjectSet *set) {
10 std::vector<Inkscape::XML::Node*> rl(set->xmlNodes().begin(), set->xmlNodes().end());
11 sort(rl.begin(),rl.end(),sp_repr_compare_position_bool);
12@@ -1031,7 +1032,7 @@
13 }
14 }
15
16-void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *desktop)
17+void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *desktop, bool skip_undo)
18 {
19 SPDocument *document = selection->layers()->getDocument();
20
21@@ -1048,8 +1049,10 @@
22
23 sp_object_set_raise_to_top(selection);
24
25- DocumentUndo::done(document, SP_VERB_SELECTION_TO_FRONT,
26- _("Raise to top"));
27+ if (!skip_undo) {
28+ DocumentUndo::done(document, SP_VERB_SELECTION_TO_FRONT,
29+ _("Raise to top"));
30+ }
31 }
32
33 void sp_object_set_lower(ObjectSet *set) {
34@@ -1111,6 +1114,7 @@
35 C_("Undo action", "Lower"));
36 }
37
38+
39 void sp_object_set_lower_to_bottom(ObjectSet *set) {
40 std::vector<Inkscape::XML::Node*> rl(set->xmlNodes().begin(), set->xmlNodes().end());
41 sort(rl.begin(),rl.end(),sp_repr_compare_position_bool);
42@@ -1132,7 +1136,7 @@
43 }
44 }
45
46-void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *desktop)
47+void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *desktop, bool skip_undo)
48 {
49 if (selection->isEmpty()) {
50 selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to lower to bottom."));
51@@ -1146,9 +1150,10 @@
52 }
53
54 sp_object_set_lower_to_bottom(selection);
55-
56- DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_TO_BACK,
57- _("Lower to bottom"));
58+ if (!skip_undo) {
59+ DocumentUndo::done(desktop->getDocument(), SP_VERB_SELECTION_TO_BACK,
60+ _("Lower to bottom"));
61+ }
62 }
63
64 void
65@@ -3859,7 +3864,7 @@
66 * If \a apply_clip_path parameter is true, clipPath is created, otherwise mask
67 *
68 */
69-void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_to_layer)
70+void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_to_layer, bool skip_undo)
71 {
72 if (desktop == NULL) {
73 return;
74@@ -4017,11 +4022,12 @@
75 }
76
77 selection->addList(items_to_select);
78-
79- if (apply_clip_path) {
80- DocumentUndo::done(doc, SP_VERB_OBJECT_SET_CLIPPATH, _("Set clipping path"));
81- } else {
82- DocumentUndo::done(doc, SP_VERB_OBJECT_SET_MASK, _("Set mask"));
83+ if (!skip_undo) {
84+ if (apply_clip_path) {
85+ DocumentUndo::done(doc, SP_VERB_OBJECT_SET_CLIPPATH, _("Set clipping path"));
86+ } else {
87+ DocumentUndo::done(doc, SP_VERB_OBJECT_SET_MASK, _("Set mask"));
88+ }
89 }
90 }
91
92
93=== modified file 'src/selection-chemistry.h'
94--- src/selection-chemistry.h 2016-07-27 10:19:03 +0000
95+++ src/selection-chemistry.h 2016-10-02 22:45:50 +0000
96@@ -85,9 +85,9 @@
97 void sp_object_set_lower_to_bottom(Inkscape::ObjectSet *set);
98
99 void sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop);
100-void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *desktop);
101+void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *desktop, bool skip_undo = false);
102 void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop);
103-void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *desktop);
104+void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *desktop, bool skip_undo = false);
105
106 SPCSSAttr *take_style_from_item (SPObject *object);
107
108@@ -164,7 +164,7 @@
109 void sp_selection_create_bitmap_copy (SPDesktop *desktop);
110
111 void sp_selection_set_clipgroup(SPDesktop *desktop);
112-void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_to_layer);
113+void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_to_layer, bool skip_undo = false);
114 void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path);
115
116 bool fit_canvas_to_selection(SPDesktop *, bool with_margins = false);
117
118=== modified file 'src/sp-lpe-item.cpp'
119--- src/sp-lpe-item.cpp 2016-09-04 09:22:09 +0000
120+++ src/sp-lpe-item.cpp 2016-10-02 22:45:50 +0000
121@@ -337,10 +337,10 @@
122 {
123 sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(mask->firstChild()));
124 }
125- SPClipPath * clipPath = lpeitem->clip_ref->getObject();
126- if(clipPath)
127+ SPClipPath * clip_path = lpeitem->clip_ref->getObject();
128+ if(clip_path)
129 {
130- sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(clipPath->firstChild()));
131+ sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(clip_path->firstChild()));
132 }
133 if (SP_IS_GROUP(lpeitem)) {
134 std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
135@@ -371,10 +371,10 @@
136 {
137 sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(mask->firstChild()));
138 }
139- SPClipPath * clipPath = lpeitem->clip_ref->getObject();
140- if(clipPath)
141+ SPClipPath * clip_path = lpeitem->clip_ref->getObject();
142+ if(clip_path)
143 {
144- sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clipPath->firstChild()));
145+ sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clip_path->firstChild()));
146 }
147 }
148 std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
149@@ -393,10 +393,10 @@
150 {
151 sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(mask->firstChild()));
152 }
153- SPClipPath * clipPath = lpeitem->clip_ref->getObject();
154- if(clipPath)
155+ SPClipPath * clip_path = lpeitem->clip_ref->getObject();
156+ if(clip_path)
157 {
158- sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clipPath->firstChild()));
159+ sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clip_path->firstChild()));
160 }
161 repr->setAttribute("d", repr->attribute("inkscape:original-d"));
162 repr->setAttribute("inkscape:original-d", NULL);
163@@ -628,10 +628,13 @@
164 void
165 SPLPEItem::apply_to_clippath(SPItem *item)
166 {
167- SPClipPath *clipPath = item->clip_ref->getObject();
168- if(clipPath) {
169- SPObject * clip_data = clipPath->firstChild();
170- apply_to_clip_or_mask(SP_ITEM(clip_data), item);
171+ SPClipPath *clip_path = item->clip_ref->getObject();
172+ if(clip_path) {
173+ std::vector<SPObject*> clip_path_list = clip_path->childList(true);
174+ for ( std::vector<SPObject*>::const_iterator iter=clip_path_list.begin();iter!=clip_path_list.end();++iter) {
175+ SPObject * clip_data = *iter;
176+ apply_to_clip_or_mask(SP_ITEM(clip_data), item);
177+ }
178 }
179 if(SP_IS_GROUP(item)){
180 std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(item));
181@@ -647,8 +650,11 @@
182 {
183 SPMask *mask = item->mask_ref->getObject();
184 if(mask) {
185- SPObject *mask_data = mask->firstChild();
186- apply_to_clip_or_mask(SP_ITEM(mask_data), item);
187+ std::vector<SPObject*> mask_list = mask->childList(true);
188+ for ( std::vector<SPObject*>::const_iterator iter=mask_list.begin();iter!=mask_list.end();++iter) {
189+ SPObject * mask_data = *iter;
190+ apply_to_clip_or_mask(SP_ITEM(mask_data), item);
191+ }
192 }
193 if(SP_IS_GROUP(item)){
194 std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(item));
195
196=== modified file 'src/ui/tools/eraser-tool.cpp'
197--- src/ui/tools/eraser-tool.cpp 2016-08-29 20:39:07 +0000
198+++ src/ui/tools/eraser-tool.cpp 2016-10-02 22:45:50 +0000
199@@ -51,15 +51,21 @@
200 #include "sp-item-group.h"
201 #include "sp-shape.h"
202 #include "sp-path.h"
203+#include "sp-clippath.h"
204+#include "sp-rect.h"
205 #include "sp-text.h"
206+#include "sp-root.h"
207+#include "display/canvas-bpath.h"
208 #include "display/canvas-arena.h"
209 #include "document-undo.h"
210 #include "verbs.h"
211 #include "style.h"
212 #include <2geom/pathvector.h>
213 #include "path-chemistry.h"
214+#include "selection-chemistry.h"
215 #include "display/curve.h"
216-
217+#include "layer-model.h"
218+#include "layer-manager.h"
219 #include "ui/tools/eraser-tool.h"
220
221 using Inkscape::DocumentUndo;
222@@ -369,7 +375,7 @@
223 bool EraserTool::root_handler(GdkEvent* event) {
224 gint ret = FALSE;
225 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
226- gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0;
227+ gint eraser_mode = prefs->getInt("/tools/eraser/mode", 2);
228 switch (event->type) {
229 case GDK_BUTTON_PRESS:
230 if (event->button.button == 1 && !this->space_panning) {
231@@ -389,7 +395,7 @@
232 if (this->repr) {
233 this->repr = NULL;
234 }
235- if ( ! eraserMode ) {
236+ if ( eraser_mode == 0 ) {
237 Inkscape::Rubberband::get(desktop)->start(desktop, button_dt);
238 Inkscape::Rubberband::get(desktop)->setMode(RUBBERBAND_MODE_TOUCHPATH);
239 }
240@@ -437,7 +443,7 @@
241
242 ret = TRUE;
243 }
244- if ( !eraserMode ) {
245+ if ( eraser_mode == 0 ) {
246 this->accumulated->reset();
247 Inkscape::Rubberband::get(desktop)->move(motion_dt);
248 }
249@@ -480,7 +486,7 @@
250 ret = TRUE;
251 }
252
253- if (!eraserMode && Inkscape::Rubberband::get(desktop)->is_started()) {
254+ if (eraser_mode == 0 && Inkscape::Rubberband::get(desktop)->is_started()) {
255 Inkscape::Rubberband::get(desktop)->stop();
256 }
257
258@@ -567,7 +573,7 @@
259 break;
260
261 case GDK_KEY_Escape:
262- if ( !eraserMode ) {
263+ if ( eraser_mode == 0 ) {
264 Inkscape::Rubberband::get(desktop)->stop();
265 }
266 if (this->is_drawing) {
267@@ -629,52 +635,54 @@
268
269 void EraserTool::set_to_accumulated() {
270 bool workDone = false;
271-
272+ SPDocument *document = this->desktop->doc();
273 if (!this->accumulated->is_empty()) {
274 if (!this->repr) {
275 /* Create object */
276- Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
277+ Inkscape::XML::Document *xml_doc = this->desktop->doc()->getReprDoc();
278 Inkscape::XML::Node *repr = xml_doc->createElement("svg:path");
279
280 /* Set style */
281- sp_desktop_apply_style_tool (desktop, repr, "/tools/eraser", false);
282+ sp_desktop_apply_style_tool (this->desktop, repr, "/tools/eraser", false);
283
284 this->repr = repr;
285 }
286- SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr(this->repr));
287+ SPObject * top_layer = desktop->layer_manager->nthChildOf(desktop->layers->currentRoot(), 0);
288+ SPItem *item_repr = SP_ITEM(top_layer->appendChildRepr(this->repr));
289+ std::cout << "asffafa\n";
290 Inkscape::GC::release(this->repr);
291- item->updateRepr();
292- Geom::PathVector pathv = this->accumulated->get_pathvector() * desktop->dt2doc();
293- pathv *= item->i2doc_affine().inverse();
294+ item_repr->updateRepr();
295+ Geom::PathVector pathv = this->accumulated->get_pathvector() * this->desktop->dt2doc();
296+ pathv *= item_repr->i2doc_affine().inverse();
297 gchar *str = sp_svg_write_path(pathv);
298 g_assert( str != NULL );
299 this->repr->setAttribute("d", str);
300 g_free(str);
301-
302+ Geom::OptRect eraserBbox;
303 if ( this->repr ) {
304 bool wasSelection = false;
305- Inkscape::Selection *selection = desktop->getSelection();
306+ Inkscape::Selection *selection = this->desktop->getSelection();
307 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
308- gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0;
309- Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
310+ gint eraser_mode = prefs->getInt("/tools/eraser/mode", 2);
311+ Inkscape::XML::Document *xml_doc = this->desktop->doc()->getReprDoc();
312
313- SPItem* acid = SP_ITEM(desktop->doc()->getObjectByRepr(this->repr));
314- Geom::OptRect eraserBbox = acid->desktopVisualBounds();
315+ SPItem* acid = SP_ITEM(this->desktop->doc()->getObjectByRepr(this->repr));
316+ eraserBbox = acid->desktopVisualBounds();
317 std::vector<SPItem*> remainingItems;
318 std::vector<SPItem*> toWorkOn;
319 if (selection->isEmpty()) {
320- if ( eraserMode ) {
321- toWorkOn = desktop->getDocument()->getItemsPartiallyInBox(desktop->dkey, *eraserBbox);
322+ if ( eraser_mode == 1 || eraser_mode == 2) {
323+ toWorkOn = document->getItemsPartiallyInBox(this->desktop->dkey, *eraserBbox);
324 } else {
325- Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
326- toWorkOn = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints());
327+ Inkscape::Rubberband *r = Inkscape::Rubberband::get(this->desktop);
328+ toWorkOn = document->getItemsAtPoints(this->desktop->dkey, r->getPoints());
329 }
330 toWorkOn.erase(std::remove(toWorkOn.begin(), toWorkOn.end(), acid), toWorkOn.end());
331 } else {
332- if ( !eraserMode ) {
333- Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
334+ if ( eraser_mode == 0 ) {
335+ Inkscape::Rubberband *r = Inkscape::Rubberband::get(this->desktop);
336 std::vector<SPItem*> touched;
337- touched = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints());
338+ touched = document->getItemsAtPoints(this->desktop->dkey, r->getPoints());
339 for (std::vector<SPItem*>::const_iterator i = touched.begin();i!=touched.end();++i) {
340 if(selection->includes(*i)){
341 toWorkOn.push_back((*i));
342@@ -687,7 +695,7 @@
343 }
344
345 if ( !toWorkOn.empty() ) {
346- if ( eraserMode ) {
347+ if ( eraser_mode == 1 ) {
348 for (std::vector<SPItem*>::const_iterator i = toWorkOn.begin(); i != toWorkOn.end(); ++i){
349 SPItem *item = *i;
350 SPUse *use = dynamic_cast<SPUse *>(item);
351@@ -713,7 +721,7 @@
352 if(item->style->fill_rule.value == SP_WIND_RULE_EVENODD){
353 SPCSSAttr *css = sp_repr_css_attr_new();
354 sp_repr_css_set_property(css, "fill-rule", "evenodd");
355- sp_desktop_set_style(desktop, css);
356+ sp_desktop_set_style(this->desktop, css);
357 sp_repr_css_attr_unref(css);
358 css = 0;
359 }
360@@ -725,10 +733,10 @@
361 workDone = true; // TODO set this only if something was cut.
362 bool break_apart = prefs->getBool("/tools/eraser/break_apart", false);
363 if(!break_apart){
364- sp_selected_path_combine(desktop, true);
365+ sp_selected_path_combine(this->desktop, true);
366 } else {
367 if(!this->nowidth){
368- sp_selected_path_break_apart(desktop, true);
369+ sp_selected_path_break_apart(this->desktop, true);
370 }
371 }
372 if ( !selection->isEmpty() ) {
373@@ -743,6 +751,70 @@
374 }
375 }
376 }
377+ } else if ( eraser_mode == 2 ) {
378+ if (!this->nowidth) {
379+ remainingItems.clear();
380+ for (std::vector<SPItem*>::const_iterator i = toWorkOn.begin(); i != toWorkOn.end(); ++i){
381+ selection->clear();
382+ SPItem *item = *i;
383+ Geom::OptRect bbox = item->desktopVisualBounds();
384+ Inkscape::XML::Document *xml_doc = this->desktop->doc()->getReprDoc();
385+ Inkscape::XML::Node* dup = this->repr->duplicate(xml_doc);
386+ this->repr->parent()->appendChild(dup);
387+ Inkscape::GC::release(dup); // parent takes over
388+ selection->set(dup);
389+ sp_selected_path_union_skip_undo(selection);
390+ if (bbox && bbox->intersects(*eraserBbox)) {
391+ SPClipPath *clip_path = item->clip_ref->getObject();
392+ if (clip_path) {
393+ SPPath *clip_data = SP_PATH(clip_path->firstChild());
394+ if (clip_data) {
395+ Inkscape::XML::Node *dup_clip = SP_OBJECT(clip_data)->getRepr()->duplicate(xml_doc);
396+ if (dup_clip) {
397+ SPItem * dup_clip_obj = SP_ITEM(item_repr->parent->appendChildRepr(dup_clip));
398+ if (dup_clip_obj) {
399+ dup_clip_obj->doWriteTransform(dup_clip, item->transform);
400+ sp_object_ref(clip_path, 0);
401+ clip_path->deleteObject(true);
402+ sp_object_unref(clip_path);
403+ sp_selection_raise_to_top(selection, this->desktop, true);
404+ selection->add(dup_clip);
405+ sp_selected_path_diff_skip_undo(selection);
406+ SPItem * clip = SP_ITEM(*(selection->items().begin()));
407+ }
408+ }
409+ }
410+ } else {
411+ Inkscape::XML::Node *rect_repr = xml_doc->createElement("svg:rect");
412+ sp_desktop_apply_style_tool (this->desktop, rect_repr, "/tools/eraser", false);
413+ SPRect * rect = SP_RECT(item_repr->parent->appendChildRepr(rect_repr));
414+ Inkscape::GC::release(rect_repr);
415+ rect->setPosition (bbox->left(), bbox->top(), bbox->width(), bbox->height());
416+ rect->transform = SP_ITEM(rect->parent)->i2dt_affine().inverse();
417+ rect->updateRepr();
418+ rect->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
419+ sp_selection_raise_to_top(selection, this->desktop, true);
420+ selection->add(rect);
421+ sp_selected_path_diff_skip_undo(selection);
422+ }
423+ sp_selection_raise_to_top(selection, this->desktop, true);
424+ selection->add(item);
425+ sp_selection_set_mask(this->desktop, true, false, true);
426+ } else {
427+ SPItem *erase_clip = selection->singleItem();
428+ if (erase_clip) {
429+ sp_object_ref(erase_clip, 0);
430+ erase_clip->deleteObject(true);
431+ sp_object_unref(erase_clip);
432+ }
433+ }
434+ workDone = true;
435+ selection->clear();
436+ if (wasSelection) {
437+ remainingItems.push_back(item);
438+ }
439+ }
440+ }
441 } else {
442 for (std::vector<SPItem*> ::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();++i) {
443 sp_object_ref( *i, 0 );
444@@ -756,8 +828,8 @@
445 }
446 }
447
448- if ( !eraserMode ) {
449- //sp_selection_delete(desktop);
450+ if ( eraser_mode == 0 ) {
451+ sp_selection_delete(this->desktop);
452 remainingItems.clear();
453 }
454
455@@ -779,12 +851,10 @@
456 this->repr = 0;
457 }
458 }
459-
460-
461 if ( workDone ) {
462- DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_ERASER, _("Draw eraser stroke"));
463+ DocumentUndo::done(document, SP_VERB_CONTEXT_ERASER, _("Draw eraser stroke"));
464 } else {
465- DocumentUndo::cancel(desktop->getDocument());
466+ DocumentUndo::cancel(document);
467 }
468 }
469
470@@ -975,7 +1045,7 @@
471 g_print("[%d]Yup\n", this->npoints);
472 #endif
473 if (!release) {
474- gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0;
475+ gint eraser_mode = prefs->getInt("/tools/eraser/mode",2);
476 g_assert(!this->currentcurve->is_empty());
477
478 SPCanvasItem *cbp = sp_canvas_item_new(desktop->getSketch(), SP_TYPE_CANVAS_BPATH, NULL);
479@@ -997,7 +1067,7 @@
480
481 this->segments = g_slist_prepend(this->segments, cbp);
482
483- if ( !eraserMode ) {
484+ if ( eraser_mode == 0 ) {
485 sp_canvas_item_hide(cbp);
486 sp_canvas_item_hide(this->currentshape);
487 }
488
489=== modified file 'src/widgets/eraser-toolbar.cpp'
490--- src/widgets/eraser-toolbar.cpp 2016-08-05 18:07:48 +0000
491+++ src/widgets/eraser-toolbar.cpp 2016-10-02 22:45:50 +0000
492@@ -65,22 +65,60 @@
493 update_presets_list(tbl);
494 }
495
496+static void sp_erc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl )
497+{
498+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
499+ prefs->setDouble("/tools/eraser/thinning", gtk_adjustment_get_value(adj) );
500+ update_presets_list(tbl);
501+}
502+
503+static void sp_erc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl )
504+{
505+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
506+ prefs->setDouble( "/tools/eraser/cap_rounding", gtk_adjustment_get_value(adj) );
507+ update_presets_list(tbl);
508+}
509+
510+static void sp_erc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl )
511+{
512+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
513+ prefs->setDouble( "/tools/eraser/tremor", gtk_adjustment_get_value(adj) );
514+ update_presets_list(tbl);
515+}
516+
517+
518 static void sp_erasertb_mode_changed( EgeSelectOneAction *act, GObject *tbl )
519 {
520 SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" ));
521- bool eraserMode = ege_select_one_action_get_active( act ) != 0;
522+ guint eraser_mode = ege_select_one_action_get_active( act );
523 if (DocumentUndo::getUndoSensitive(desktop->getDocument())) {
524 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
525- prefs->setBool( "/tools/eraser/mode", eraserMode );
526+ prefs->setInt( "/tools/eraser/mode", eraser_mode );
527 }
528 GtkAction *split = GTK_ACTION( g_object_get_data(tbl, "split") );
529 GtkAction *mass = GTK_ACTION( g_object_get_data(tbl, "mass") );
530 GtkAction *width = GTK_ACTION( g_object_get_data(tbl, "width") );
531- if(eraserMode == TRUE){
532- gtk_action_set_visible( split, TRUE );
533+ GtkAction *usepressure = GTK_ACTION( g_object_get_data(tbl, "usepressure") );
534+ GtkAction *cap_rounding = GTK_ACTION( g_object_get_data(tbl, "cap_rounding") );
535+ GtkAction *thinning = GTK_ACTION( g_object_get_data(tbl, "thinning") );
536+ GtkAction *tremor = GTK_ACTION( g_object_get_data(tbl, "tremor") );
537+ if (eraser_mode != 0) {
538+ if(eraser_mode == 1) {
539+ gtk_action_set_visible( split, TRUE );
540+ } else {
541+ gtk_action_set_visible( split, FALSE );
542+ }
543+ gtk_action_set_visible(usepressure, TRUE );
544+ gtk_action_set_visible(tremor, TRUE );
545+ gtk_action_set_visible(cap_rounding, TRUE );
546+ gtk_action_set_visible(thinning, TRUE );
547 gtk_action_set_visible( mass, TRUE );
548 gtk_action_set_visible( width, TRUE );
549 } else {
550+ gtk_action_set_visible(usepressure, FALSE );
551+ gtk_action_set_visible(tremor, FALSE );
552+ gtk_action_set_visible(cap_rounding, FALSE );
553+ gtk_action_set_visible(thinning, FALSE );
554 gtk_action_set_visible( split, FALSE );
555 gtk_action_set_visible( mass, FALSE );
556 gtk_action_set_visible( width, FALSE );
557@@ -91,7 +129,7 @@
558 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
559
560 /*
561- if ( eraserMode != 0 ) {
562+ if ( eraser_mode != 0 ) {
563 } else {
564 }
565 */
566@@ -112,7 +150,7 @@
567 {
568 Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
569 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
570- gint eraserMode = FALSE;
571+ gint eraser_mode = FALSE;
572 {
573 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
574 GtkTreeIter iter;
575@@ -126,10 +164,17 @@
576 gtk_list_store_append( model, &iter );
577 gtk_list_store_set( model, &iter,
578 0, _("Cut"),
579- 1, _("Cut out from objects"),
580+ 1, _("Cut out from paths and shapes"),
581 2, INKSCAPE_ICON("path-difference"),
582 -1 );
583
584+ gtk_list_store_append( model, &iter );
585+ gtk_list_store_set( model, &iter,
586+ 0, _("Clip"),
587+ 1, _("Clip from objects"),
588+ 2, INKSCAPE_ICON("path-intersection"),
589+ -1 );
590+
591 EgeSelectOneAction* act = ege_select_one_action_new( "EraserModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
592 g_object_set( act, "short_label", _("Mode:"), NULL );
593 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
594@@ -138,12 +183,13 @@
595 ege_select_one_action_set_appearance( act, "full" );
596 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
597 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
598- ege_select_one_action_set_icon_column( act, 2 );
599- ege_select_one_action_set_tooltip_column( act, 1 );
600+ ege_select_one_action_set_icon_column( act, 2);
601+ ege_select_one_action_set_icon_size( act, secondarySize );
602+ ege_select_one_action_set_tooltip_column( act, 1);
603
604 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
605- eraserMode = prefs->getBool("/tools/eraser/mode") ? TRUE : FALSE;
606- ege_select_one_action_set_active( act, eraserMode );
607+ eraser_mode = prefs->getInt("/tools/eraser/mode", 2);
608+ ege_select_one_action_set_active( act, eraser_mode );
609 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_erasertb_mode_changed), holder );
610 }
611
612@@ -164,6 +210,71 @@
613 g_object_set_data( holder, "width", eact );
614 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
615 }
616+ /* Use Pressure button */
617+ {
618+ InkToggleAction* act = ink_toggle_action_new( "EraserPressureAction",
619+ _("Eraser Pressure"),
620+ _("Use the pressure of the input device to alter the width of the pen"),
621+ INKSCAPE_ICON("draw-use-pressure"),
622+ Inkscape::ICON_SIZE_DECORATION );
623+ gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
624+ PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/eraser/usepressure", update_presets_list, holder);
625+ g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
626+ g_object_set_data( holder, "usepressure", act );
627+ }
628+ {
629+
630+ /* Thinning */
631+ gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
632+ gdouble values[] = {-100, -40, -20, -10, 0, 10, 20, 40, 100};
633+ EgeAdjustmentAction* eact = create_adjustment_action( "EraserThinningAction",
634+ _("Eraser Stroke Thinning"), _("Thinning:"),
635+ _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
636+ "/tools/eraser/thinning", 10,
637+ GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
638+ -100, 100, 1, 10.0,
639+ labels, values, G_N_ELEMENTS(labels),
640+ sp_erc_velthin_value_changed, NULL /*unit tracker*/, 1, 0);
641+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
642+ g_object_set_data( holder, "thinning", eact );
643+ gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
644+ }
645+ {
646+ /* Cap Rounding */
647+ gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
648+ gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
649+ // TRANSLATORS: "cap" means "end" (both start and finish) here
650+ EgeAdjustmentAction* eact = create_adjustment_action( "EraserCapRoundingAction",
651+ _("Eraser Cap rounding"), _("Caps:"),
652+ _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
653+ "/tools/eraser/cap_rounding", 0.0,
654+ GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
655+ 0.0, 5.0, 0.01, 0.1,
656+ labels, values, G_N_ELEMENTS(labels),
657+ sp_erc_cap_rounding_value_changed, NULL /*unit tracker*/, 0.01, 2 );
658+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
659+ g_object_set_data( holder, "cap_rounding", eact );
660+ gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
661+ }
662+
663+ {
664+ /* Tremor */
665+ gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
666+ gdouble values[] = {0, 10, 20, 40, 60, 100};
667+ EgeAdjustmentAction* eact = create_adjustment_action( "EraserTremorAction",
668+ _("EraserStroke Tremor"), _("Tremor:"),
669+ _("Increase to make strokes rugged and trembling"),
670+ "/tools/eraser/tremor", 0.0,
671+ GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
672+ 0.0, 100, 1, 10.0,
673+ labels, values, G_N_ELEMENTS(labels),
674+ sp_erc_tremor_value_changed, NULL /*unit tracker*/, 1, 0);
675+
676+ ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
677+ g_object_set_data( holder, "tremor", eact );
678+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
679+ gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
680+ }
681 {
682 /* Mass */
683 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
684@@ -196,11 +307,27 @@
685 GtkAction *split = GTK_ACTION( g_object_get_data(holder, "split") );
686 GtkAction *mass = GTK_ACTION( g_object_get_data(holder, "mass") );
687 GtkAction *width = GTK_ACTION( g_object_get_data(holder, "width") );
688- if(eraserMode == TRUE){
689- gtk_action_set_visible( split, TRUE );
690+ GtkAction *usepressure = GTK_ACTION( g_object_get_data(holder, "usepressure") );
691+ GtkAction *cap_rounding = GTK_ACTION( g_object_get_data(holder, "cap_rounding") );
692+ GtkAction *thinning = GTK_ACTION( g_object_get_data(holder, "thinning") );
693+ GtkAction *tremor = GTK_ACTION( g_object_get_data(holder, "tremor") );
694+ if (eraser_mode != 0) {
695+ if(eraser_mode == 1) {
696+ gtk_action_set_visible( split, TRUE );
697+ } else {
698+ gtk_action_set_visible( split, FALSE );
699+ }
700+ gtk_action_set_visible(usepressure, TRUE );
701+ gtk_action_set_visible(tremor, TRUE );
702+ gtk_action_set_visible(cap_rounding, TRUE );
703+ gtk_action_set_visible(thinning, TRUE );
704 gtk_action_set_visible( mass, TRUE );
705 gtk_action_set_visible( width, TRUE );
706 } else {
707+ gtk_action_set_visible(usepressure, FALSE );
708+ gtk_action_set_visible(tremor, FALSE );
709+ gtk_action_set_visible(cap_rounding, FALSE );
710+ gtk_action_set_visible(thinning, FALSE );
711 gtk_action_set_visible( split, FALSE );
712 gtk_action_set_visible( mass, FALSE );
713 gtk_action_set_visible( width, FALSE );
714
715=== modified file 'src/widgets/toolbox.cpp'
716--- src/widgets/toolbox.cpp 2016-08-05 18:07:48 +0000
717+++ src/widgets/toolbox.cpp 2016-10-02 22:45:50 +0000
718@@ -493,6 +493,13 @@
719 " <toolitem action='EraserModeAction' />"
720 " <separator />"
721 " <toolitem action='EraserWidthAction' />"
722+ " <toolitem action='EraserPressureAction' />"
723+ " <separator />"
724+ " <toolitem action='EraserThinningAction' />"
725+ " <separator />"
726+ " <toolitem action='EraserCapRoundingAction' />"
727+ " <separator />"
728+ " <toolitem action='EraserTremorAction' />"
729 " <separator />"
730 " <toolitem action='EraserMassAction' />"
731 " <separator />"