5526
by joncruz
Added missing eraser files |
1 |
/*
|
2 |
* Eraser drawing mode
|
|
3 |
*
|
|
4 |
* Authors:
|
|
5 |
* Mitsuru Oka <oka326@parkcity.ne.jp>
|
|
6 |
* Lauris Kaplinski <lauris@kaplinski.com>
|
|
7 |
* bulia byak <buliabyak@users.sf.net>
|
|
8 |
* MenTaLguY <mental@rydia.net>
|
|
9 |
* Jon A. Cruz <jon@joncruz.org>
|
|
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
10 |
* Abhishek Sharma
|
5526
by joncruz
Added missing eraser files |
11 |
*
|
12 |
* The original dynadraw code:
|
|
13 |
* Paul Haeberli <paul@sgi.com>
|
|
14 |
*
|
|
15 |
* Copyright (C) 1998 The Free Software Foundation
|
|
16 |
* Copyright (C) 1999-2005 authors
|
|
17 |
* Copyright (C) 2001-2002 Ximian, Inc.
|
|
18 |
* Copyright (C) 2005-2007 bulia byak
|
|
19 |
* Copyright (C) 2006 MenTaLguY
|
|
20 |
* Copyright (C) 2008 Jon A. Cruz
|
|
21 |
*
|
|
22 |
* Released under GNU GPL, read the file 'COPYING' for more information
|
|
23 |
*/
|
|
24 |
||
25 |
#define noERASER_VERBOSE
|
|
26 |
||
27 |
#include "config.h" |
|
28 |
||
29 |
#include <gtk/gtk.h> |
|
30 |
#include <gdk/gdkkeysyms.h> |
|
31 |
#include <glibmm/i18n.h> |
|
32 |
#include <string> |
|
33 |
#include <cstring> |
|
34 |
#include <numeric> |
|
35 |
||
36 |
#include "svg/svg.h" |
|
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
37 |
#include "display/sp-canvas.h" |
5526
by joncruz
Added missing eraser files |
38 |
#include "display/canvas-bpath.h" |
6983
by johanengelen
use 2geom bezier fitting (is copy of inkscape's) |
39 |
#include <2geom/bezier-utils.h> |
5526
by joncruz
Added missing eraser files |
40 |
|
41 |
#include <glib/gmem.h> |
|
42 |
#include "macros.h" |
|
43 |
#include "document.h" |
|
44 |
#include "selection.h" |
|
45 |
#include "desktop.h" |
|
46 |
#include "desktop-events.h" |
|
47 |
#include "desktop-handles.h" |
|
48 |
#include "desktop-style.h" |
|
49 |
#include "message-context.h" |
|
6885
by Ted Gould
From trunk |
50 |
#include "preferences.h" |
5526
by joncruz
Added missing eraser files |
51 |
#include "pixmaps/cursor-eraser.xpm" |
52 |
#include "xml/repr.h" |
|
53 |
#include "context-fns.h" |
|
54 |
#include "sp-item.h" |
|
55 |
#include "color.h" |
|
5593
by joncruz
Initial cut of touch-delete mode |
56 |
#include "rubberband.h" |
5526
by joncruz
Added missing eraser files |
57 |
#include "splivarot.h" |
58 |
#include "sp-item-group.h" |
|
59 |
#include "sp-shape.h" |
|
60 |
#include "sp-path.h" |
|
61 |
#include "sp-text.h" |
|
62 |
#include "display/canvas-bpath.h" |
|
63 |
#include "display/canvas-arena.h" |
|
64 |
#include "livarot/Shape.h" |
|
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
65 |
#include <2geom/math-utils.h> |
6228
by johanengelen
* 2geomify polygon svg writing |
66 |
#include <2geom/pathvector.h> |
5526
by joncruz
Added missing eraser files |
67 |
|
68 |
#include "eraser-context.h" |
|
69 |
||
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
70 |
using Inkscape::DocumentUndo; |
71 |
||
5526
by joncruz
Added missing eraser files |
72 |
#define ERC_RED_RGBA 0xff0000ff
|
73 |
||
74 |
#define TOLERANCE_ERASER 0.1
|
|
75 |
||
76 |
#define ERASER_EPSILON 0.5e-6
|
|
77 |
#define ERASER_EPSILON_START 0.5e-2
|
|
78 |
#define ERASER_VEL_START 1e-5
|
|
79 |
||
80 |
#define DRAG_MIN 0.0
|
|
81 |
#define DRAG_DEFAULT 1.0
|
|
82 |
#define DRAG_MAX 1.0
|
|
83 |
||
84 |
||
85 |
static void sp_eraser_context_class_init(SPEraserContextClass *klass); |
|
86 |
static void sp_eraser_context_init(SPEraserContext *erc); |
|
87 |
static void sp_eraser_context_dispose(GObject *object); |
|
88 |
||
89 |
static void sp_eraser_context_setup(SPEventContext *ec); |
|
6885
by Ted Gould
From trunk |
90 |
static void sp_eraser_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); |
5526
by joncruz
Added missing eraser files |
91 |
static gint sp_eraser_context_root_handler(SPEventContext *ec, GdkEvent *event); |
92 |
||
93 |
static void clear_current(SPEraserContext *dc); |
|
94 |
static void set_to_accumulated(SPEraserContext *dc); |
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
95 |
static void add_cap(SPCurve *curve, Geom::Point const &pre, Geom::Point const &from, Geom::Point const &to, Geom::Point const &post, double rounding); |
5526
by joncruz
Added missing eraser files |
96 |
static void accumulate_eraser(SPEraserContext *dc); |
97 |
||
98 |
static void fit_and_split(SPEraserContext *erc, gboolean release); |
|
99 |
||
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
100 |
static void sp_eraser_reset(SPEraserContext *erc, Geom::Point p); |
101 |
static Geom::Point sp_eraser_get_npoint(SPEraserContext const *erc, Geom::Point v); |
|
102 |
static Geom::Point sp_eraser_get_vpoint(SPEraserContext const *erc, Geom::Point n); |
|
5526
by joncruz
Added missing eraser files |
103 |
static void draw_temporary_box(SPEraserContext *dc); |
104 |
||
105 |
||
5717
by joncruz
Refactoring begining |
106 |
static SPEventContextClass *eraser_parent_class = 0; |
5526
by joncruz
Added missing eraser files |
107 |
|
5717
by joncruz
Refactoring begining |
108 |
GType sp_eraser_context_get_type(void) |
5526
by joncruz
Added missing eraser files |
109 |
{
|
110 |
static GType type = 0; |
|
111 |
if (!type) { |
|
112 |
GTypeInfo info = { |
|
113 |
sizeof(SPEraserContextClass), |
|
5717
by joncruz
Refactoring begining |
114 |
0, // base_init |
115 |
0, // base_finalize |
|
116 |
(GClassInitFunc)sp_eraser_context_class_init, |
|
117 |
0, // class_finalize |
|
118 |
0, // class_data |
|
5526
by joncruz
Added missing eraser files |
119 |
sizeof(SPEraserContext), |
5717
by joncruz
Refactoring begining |
120 |
0, // n_preallocs |
121 |
(GInstanceInitFunc)sp_eraser_context_init, |
|
122 |
0 // value_table |
|
5526
by joncruz
Added missing eraser files |
123 |
};
|
5759
by joncruz
Refactoring out common code |
124 |
type = g_type_register_static(SP_TYPE_COMMON_CONTEXT, "SPEraserContext", &info, static_cast<GTypeFlags>(0)); |
5526
by joncruz
Added missing eraser files |
125 |
}
|
126 |
return type; |
|
127 |
}
|
|
128 |
||
129 |
static void |
|
130 |
sp_eraser_context_class_init(SPEraserContextClass *klass) |
|
131 |
{
|
|
132 |
GObjectClass *object_class = (GObjectClass *) klass; |
|
133 |
SPEventContextClass *event_context_class = (SPEventContextClass *) klass; |
|
134 |
||
5717
by joncruz
Refactoring begining |
135 |
eraser_parent_class = (SPEventContextClass*)g_type_class_peek_parent(klass); |
5526
by joncruz
Added missing eraser files |
136 |
|
137 |
object_class->dispose = sp_eraser_context_dispose; |
|
138 |
||
139 |
event_context_class->setup = sp_eraser_context_setup; |
|
140 |
event_context_class->set = sp_eraser_context_set; |
|
141 |
event_context_class->root_handler = sp_eraser_context_root_handler; |
|
142 |
}
|
|
143 |
||
144 |
static void |
|
145 |
sp_eraser_context_init(SPEraserContext *erc) |
|
146 |
{
|
|
5759
by joncruz
Refactoring out common code |
147 |
erc->cursor_shape = cursor_eraser_xpm; |
148 |
erc->hot_x = 4; |
|
149 |
erc->hot_y = 4; |
|
5526
by joncruz
Added missing eraser files |
150 |
}
|
151 |
||
152 |
static void |
|
153 |
sp_eraser_context_dispose(GObject *object) |
|
154 |
{
|
|
5759
by joncruz
Refactoring out common code |
155 |
//SPEraserContext *erc = SP_ERASER_CONTEXT(object);
|
5526
by joncruz
Added missing eraser files |
156 |
|
5717
by joncruz
Refactoring begining |
157 |
G_OBJECT_CLASS(eraser_parent_class)->dispose(object); |
5526
by joncruz
Added missing eraser files |
158 |
}
|
159 |
||
160 |
static void |
|
161 |
sp_eraser_context_setup(SPEventContext *ec) |
|
162 |
{
|
|
163 |
SPEraserContext *erc = SP_ERASER_CONTEXT(ec); |
|
6621
by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP |
164 |
SPDesktop *desktop = ec->desktop; |
5526
by joncruz
Added missing eraser files |
165 |
|
5717
by joncruz
Refactoring begining |
166 |
if (((SPEventContextClass *) eraser_parent_class)->setup) |
167 |
((SPEventContextClass *) eraser_parent_class)->setup(ec); |
|
5526
by joncruz
Added missing eraser files |
168 |
|
6339
by johanengelen
convert all SPCurve's points and matrices arguments and return types to 2Geom |
169 |
erc->accumulated = new SPCurve(); |
170 |
erc->currentcurve = new SPCurve(); |
|
5526
by joncruz
Added missing eraser files |
171 |
|
6339
by johanengelen
convert all SPCurve's points and matrices arguments and return types to 2Geom |
172 |
erc->cal1 = new SPCurve(); |
173 |
erc->cal2 = new SPCurve(); |
|
5526
by joncruz
Added missing eraser files |
174 |
|
6621
by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP |
175 |
erc->currentshape = sp_canvas_item_new(sp_desktop_sketch(desktop), SP_TYPE_CANVAS_BPATH, NULL); |
5526
by joncruz
Added missing eraser files |
176 |
sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(erc->currentshape), ERC_RED_RGBA, SP_WIND_RULE_EVENODD); |
177 |
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(erc->currentshape), 0x00000000, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); |
|
178 |
/* fixme: Cannot we cascade it to root more clearly? */
|
|
6621
by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP |
179 |
g_signal_connect(G_OBJECT(erc->currentshape), "event", G_CALLBACK(sp_desktop_root_handler), desktop); |
5526
by joncruz
Added missing eraser files |
180 |
|
181 |
/*
|
|
182 |
static ProfileFloatElement f_profile[PROFILE_FLOAT_SIZE] = {
|
|
183 |
{"mass",0.02, 0.0, 1.0},
|
|
184 |
{"wiggle",0.0, 0.0, 1.0},
|
|
185 |
{"angle",30.0, -90.0, 90.0},
|
|
186 |
{"thinning",0.1, -1.0, 1.0},
|
|
187 |
{"tremor",0.0, 0.0, 1.0},
|
|
188 |
{"flatness",0.9, 0.0, 1.0},
|
|
189 |
{"cap_rounding",0.0, 0.0, 5.0}
|
|
190 |
};
|
|
191 |
*/
|
|
192 |
||
193 |
sp_event_context_read(ec, "mass"); |
|
194 |
sp_event_context_read(ec, "wiggle"); |
|
195 |
sp_event_context_read(ec, "angle"); |
|
196 |
sp_event_context_read(ec, "width"); |
|
197 |
sp_event_context_read(ec, "thinning"); |
|
198 |
sp_event_context_read(ec, "tremor"); |
|
199 |
sp_event_context_read(ec, "flatness"); |
|
200 |
sp_event_context_read(ec, "tracebackground"); |
|
201 |
sp_event_context_read(ec, "usepressure"); |
|
202 |
sp_event_context_read(ec, "usetilt"); |
|
203 |
sp_event_context_read(ec, "abs_width"); |
|
204 |
sp_event_context_read(ec, "cap_rounding"); |
|
205 |
||
206 |
erc->is_drawing = false; |
|
207 |
||
6621
by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP |
208 |
erc->_message_context = new Inkscape::MessageContext(desktop->messageStack()); |
5526
by joncruz
Added missing eraser files |
209 |
|
6885
by Ted Gould
From trunk |
210 |
Inkscape::Preferences *prefs = Inkscape::Preferences::get(); |
211 |
if (prefs->getBool("/tools/eraser/selcue", 0) != 0) { |
|
5526
by joncruz
Added missing eraser files |
212 |
ec->enableSelectionCue(); |
213 |
}
|
|
214 |
// TODO temp force:
|
|
215 |
ec->enableSelectionCue(); |
|
216 |
||
217 |
}
|
|
218 |
||
219 |
static void |
|
6885
by Ted Gould
From trunk |
220 |
sp_eraser_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) |
5526
by joncruz
Added missing eraser files |
221 |
{
|
5780
by joncruz
Pass through more calls to parent contexts, and added more common property handling. |
222 |
//pass on up to parent class to handle common attributes.
|
223 |
if ( eraser_parent_class->set ) { |
|
6885
by Ted Gould
From trunk |
224 |
eraser_parent_class->set(ec, val); |
5526
by joncruz
Added missing eraser files |
225 |
}
|
226 |
}
|
|
227 |
||
228 |
static double |
|
229 |
flerp(double f0, double f1, double p) |
|
230 |
{
|
|
231 |
return f0 + ( f1 - f0 ) * p; |
|
232 |
}
|
|
233 |
||
234 |
/* Get normalized point */
|
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
235 |
static Geom::Point |
236 |
sp_eraser_get_npoint(SPEraserContext const *dc, Geom::Point v) |
|
5526
by joncruz
Added missing eraser files |
237 |
{
|
6839
by cilix42
Next roud of NR ==> Geom conversion |
238 |
Geom::Rect drect = SP_EVENT_CONTEXT(dc)->desktop->get_display_area(); |
239 |
double const max = MAX ( drect.dimensions()[Geom::X], drect.dimensions()[Geom::Y] ); |
|
240 |
return Geom::Point(( v[Geom::X] - drect.min()[Geom::X] ) / max, ( v[Geom::Y] - drect.min()[Geom::Y] ) / max); |
|
5526
by joncruz
Added missing eraser files |
241 |
}
|
242 |
||
243 |
/* Get view point */
|
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
244 |
static Geom::Point |
245 |
sp_eraser_get_vpoint(SPEraserContext const *dc, Geom::Point n) |
|
5526
by joncruz
Added missing eraser files |
246 |
{
|
6839
by cilix42
Next roud of NR ==> Geom conversion |
247 |
Geom::Rect drect = SP_EVENT_CONTEXT(dc)->desktop->get_display_area(); |
248 |
double const max = MAX ( drect.dimensions()[Geom::X], drect.dimensions()[Geom::Y] ); |
|
249 |
return Geom::Point(n[Geom::X] * max + drect.min()[Geom::X], n[Geom::Y] * max + drect.min()[Geom::Y]); |
|
5526
by joncruz
Added missing eraser files |
250 |
}
|
251 |
||
252 |
static void |
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
253 |
sp_eraser_reset(SPEraserContext *dc, Geom::Point p) |
5526
by joncruz
Added missing eraser files |
254 |
{
|
255 |
dc->last = dc->cur = sp_eraser_get_npoint(dc, p); |
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
256 |
dc->vel = Geom::Point(0,0); |
5526
by joncruz
Added missing eraser files |
257 |
dc->vel_max = 0; |
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
258 |
dc->acc = Geom::Point(0,0); |
259 |
dc->ang = Geom::Point(0,0); |
|
260 |
dc->del = Geom::Point(0,0); |
|
5526
by joncruz
Added missing eraser files |
261 |
}
|
262 |
||
263 |
static void |
|
264 |
sp_eraser_extinput(SPEraserContext *dc, GdkEvent *event) |
|
265 |
{
|
|
266 |
if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &dc->pressure)) |
|
267 |
dc->pressure = CLAMP (dc->pressure, ERC_MIN_PRESSURE, ERC_MAX_PRESSURE); |
|
268 |
else
|
|
269 |
dc->pressure = ERC_DEFAULT_PRESSURE; |
|
270 |
||
271 |
if (gdk_event_get_axis (event, GDK_AXIS_XTILT, &dc->xtilt)) |
|
272 |
dc->xtilt = CLAMP (dc->xtilt, ERC_MIN_TILT, ERC_MAX_TILT); |
|
273 |
else
|
|
274 |
dc->xtilt = ERC_DEFAULT_TILT; |
|
275 |
||
276 |
if (gdk_event_get_axis (event, GDK_AXIS_YTILT, &dc->ytilt)) |
|
277 |
dc->ytilt = CLAMP (dc->ytilt, ERC_MIN_TILT, ERC_MAX_TILT); |
|
278 |
else
|
|
279 |
dc->ytilt = ERC_DEFAULT_TILT; |
|
280 |
}
|
|
281 |
||
282 |
||
283 |
static gboolean |
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
284 |
sp_eraser_apply(SPEraserContext *dc, Geom::Point p) |
5526
by joncruz
Added missing eraser files |
285 |
{
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
286 |
Geom::Point n = sp_eraser_get_npoint(dc, p); |
5526
by joncruz
Added missing eraser files |
287 |
|
288 |
/* Calculate mass and drag */
|
|
289 |
double const mass = flerp(1.0, 160.0, dc->mass); |
|
290 |
double const drag = flerp(0.0, 0.5, dc->drag * dc->drag); |
|
291 |
||
292 |
/* Calculate force and acceleration */
|
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
293 |
Geom::Point force = n - dc->cur; |
5526
by joncruz
Added missing eraser files |
294 |
|
295 |
// If force is below the absolute threshold ERASER_EPSILON,
|
|
296 |
// or we haven't yet reached ERASER_VEL_START (i.e. at the beginning of stroke)
|
|
297 |
// _and_ the force is below the (higher) ERASER_EPSILON_START threshold,
|
|
298 |
// discard this move.
|
|
299 |
// This prevents flips, blobs, and jerks caused by microscopic tremor of the tablet pen,
|
|
300 |
// especially bothersome at the start of the stroke where we don't yet have the inertia to
|
|
301 |
// smooth them out.
|
|
6885
by Ted Gould
From trunk |
302 |
if ( Geom::L2(force) < ERASER_EPSILON || (dc->vel_max < ERASER_VEL_START && Geom::L2(force) < ERASER_EPSILON_START)) { |
5526
by joncruz
Added missing eraser files |
303 |
return FALSE; |
304 |
}
|
|
305 |
||
306 |
dc->acc = force / mass; |
|
307 |
||
308 |
/* Calculate new velocity */
|
|
309 |
dc->vel += dc->acc; |
|
310 |
||
6885
by Ted Gould
From trunk |
311 |
if (Geom::L2(dc->vel) > dc->vel_max) |
312 |
dc->vel_max = Geom::L2(dc->vel); |
|
5526
by joncruz
Added missing eraser files |
313 |
|
314 |
/* Calculate angle of drawing tool */
|
|
315 |
||
316 |
double a1; |
|
317 |
if (dc->usetilt) { |
|
318 |
// 1a. calculate nib angle from input device tilt:
|
|
319 |
gdouble length = std::sqrt(dc->xtilt*dc->xtilt + dc->ytilt*dc->ytilt);; |
|
320 |
||
321 |
if (length > 0) { |
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
322 |
Geom::Point ang1 = Geom::Point(dc->ytilt/length, dc->xtilt/length); |
5526
by joncruz
Added missing eraser files |
323 |
a1 = atan2(ang1); |
324 |
}
|
|
325 |
else
|
|
326 |
a1 = 0.0; |
|
327 |
}
|
|
328 |
else { |
|
329 |
// 1b. fixed dc->angle (absolutely flat nib):
|
|
330 |
double const radians = ( (dc->angle - 90) / 180.0 ) * M_PI; |
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
331 |
Geom::Point ang1 = Geom::Point(-sin(radians), cos(radians)); |
5526
by joncruz
Added missing eraser files |
332 |
a1 = atan2(ang1); |
333 |
}
|
|
334 |
||
335 |
// 2. perpendicular to dc->vel (absolutely non-flat nib):
|
|
6954
by johanengelen
2geom eraser tool |
336 |
gdouble const mag_vel = Geom::L2(dc->vel); |
5526
by joncruz
Added missing eraser files |
337 |
if ( mag_vel < ERASER_EPSILON ) { |
338 |
return FALSE; |
|
339 |
}
|
|
6954
by johanengelen
2geom eraser tool |
340 |
Geom::Point ang2 = Geom::rot90(dc->vel) / mag_vel; |
5526
by joncruz
Added missing eraser files |
341 |
|
342 |
// 3. Average them using flatness parameter:
|
|
343 |
// calculate angles
|
|
344 |
double a2 = atan2(ang2); |
|
345 |
// flip a2 to force it to be in the same half-circle as a1
|
|
346 |
bool flipped = false; |
|
347 |
if (fabs (a2-a1) > 0.5*M_PI) { |
|
348 |
a2 += M_PI; |
|
349 |
flipped = true; |
|
350 |
}
|
|
351 |
// normalize a2
|
|
352 |
if (a2 > M_PI) |
|
353 |
a2 -= 2*M_PI; |
|
354 |
if (a2 < -M_PI) |
|
355 |
a2 += 2*M_PI; |
|
356 |
// find the flatness-weighted bisector angle, unflip if a2 was flipped
|
|
357 |
// FIXME: when dc->vel is oscillating around the fixed angle, the new_ang flips back and forth. How to avoid this?
|
|
358 |
double new_ang = a1 + (1 - dc->flatness) * (a2 - a1) - (flipped? M_PI : 0); |
|
359 |
||
360 |
// Try to detect a sudden flip when the new angle differs too much from the previous for the
|
|
361 |
// current velocity; in that case discard this move
|
|
6954
by johanengelen
2geom eraser tool |
362 |
double angle_delta = Geom::L2(Geom::Point (cos (new_ang), sin (new_ang)) - dc->ang); |
363 |
if ( angle_delta / Geom::L2(dc->vel) > 4000 ) { |
|
5526
by joncruz
Added missing eraser files |
364 |
return FALSE; |
365 |
}
|
|
366 |
||
367 |
// convert to point
|
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
368 |
dc->ang = Geom::Point (cos (new_ang), sin (new_ang)); |
5526
by joncruz
Added missing eraser files |
369 |
|
6954
by johanengelen
2geom eraser tool |
370 |
// g_print ("force %g acc %g vel_max %g vel %g a1 %g a2 %g new_ang %g\n", Geom::L2(force), Geom::L2(dc->acc), dc->vel_max, Geom::L2(dc->vel), a1, a2, new_ang);
|
5526
by joncruz
Added missing eraser files |
371 |
|
372 |
/* Apply drag */
|
|
373 |
dc->vel *= 1.0 - drag; |
|
374 |
||
375 |
/* Update position */
|
|
376 |
dc->last = dc->cur; |
|
377 |
dc->cur += dc->vel; |
|
378 |
||
379 |
return TRUE; |
|
380 |
}
|
|
381 |
||
382 |
static void |
|
383 |
sp_eraser_brush(SPEraserContext *dc) |
|
384 |
{
|
|
385 |
g_assert( dc->npoints >= 0 && dc->npoints < SAMPLING_SIZE ); |
|
386 |
||
387 |
// How much velocity thins strokestyle
|
|
388 |
double vel_thin = flerp (0, 160, dc->vel_thin); |
|
389 |
||
390 |
// Influence of pressure on thickness
|
|
391 |
double pressure_thick = (dc->usepressure ? dc->pressure : 1.0); |
|
392 |
||
393 |
// get the real brush point, not the same as pointer (affected by hatch tracking and/or mass
|
|
394 |
// drag)
|
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
395 |
Geom::Point brush = sp_eraser_get_vpoint(dc, dc->cur); |
396 |
Geom::Point brush_w = SP_EVENT_CONTEXT(dc)->desktop->d2w(brush); |
|
5526
by joncruz
Added missing eraser files |
397 |
|
398 |
double trace_thick = 1; |
|
399 |
||
6954
by johanengelen
2geom eraser tool |
400 |
double width = (pressure_thick * trace_thick - vel_thin * Geom::L2(dc->vel)) * dc->width; |
5526
by joncruz
Added missing eraser files |
401 |
|
402 |
double tremble_left = 0, tremble_right = 0; |
|
403 |
if (dc->tremor > 0) { |
|
404 |
// obtain two normally distributed random variables, using polar Box-Muller transform
|
|
405 |
double x1, x2, w, y1, y2; |
|
406 |
do { |
|
407 |
x1 = 2.0 * g_random_double_range(0,1) - 1.0; |
|
408 |
x2 = 2.0 * g_random_double_range(0,1) - 1.0; |
|
409 |
w = x1 * x1 + x2 * x2; |
|
410 |
} while ( w >= 1.0 ); |
|
411 |
w = sqrt( (-2.0 * log( w ) ) / w ); |
|
412 |
y1 = x1 * w; |
|
413 |
y2 = x2 * w; |
|
414 |
||
415 |
// deflect both left and right edges randomly and independently, so that:
|
|
416 |
// (1) dc->tremor=1 corresponds to sigma=1, decreasing dc->tremor narrows the bell curve;
|
|
417 |
// (2) deflection depends on width, but is upped for small widths for better visual uniformity across widths;
|
|
418 |
// (3) deflection somewhat depends on speed, to prevent fast strokes looking
|
|
419 |
// comparatively smooth and slow ones excessively jittery
|
|
6954
by johanengelen
2geom eraser tool |
420 |
tremble_left = (y1)*dc->tremor * (0.15 + 0.8*width) * (0.35 + 14*Geom::L2(dc->vel)); |
421 |
tremble_right = (y2)*dc->tremor * (0.15 + 0.8*width) * (0.35 + 14*Geom::L2(dc->vel)); |
|
5526
by joncruz
Added missing eraser files |
422 |
}
|
423 |
||
424 |
if ( width < 0.02 * dc->width ) { |
|
425 |
width = 0.02 * dc->width; |
|
426 |
}
|
|
427 |
||
428 |
double dezoomify_factor = 0.05 * 1000; |
|
429 |
if (!dc->abs_width) { |
|
430 |
dezoomify_factor /= SP_EVENT_CONTEXT(dc)->desktop->current_zoom(); |
|
431 |
}
|
|
432 |
||
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
433 |
Geom::Point del_left = dezoomify_factor * (width + tremble_left) * dc->ang; |
434 |
Geom::Point del_right = dezoomify_factor * (width + tremble_right) * dc->ang; |
|
5526
by joncruz
Added missing eraser files |
435 |
|
436 |
dc->point1[dc->npoints] = brush + del_left; |
|
437 |
dc->point2[dc->npoints] = brush - del_right; |
|
438 |
||
439 |
dc->del = 0.5*(del_left + del_right); |
|
440 |
||
441 |
dc->npoints++; |
|
442 |
}
|
|
443 |
||
444 |
void
|
|
445 |
sp_erc_update_toolbox (SPDesktop *desktop, const gchar *id, double value) |
|
446 |
{
|
|
447 |
desktop->setToolboxAdjustmentValue (id, value); |
|
448 |
}
|
|
449 |
||
450 |
static void |
|
451 |
eraser_cancel(SPEraserContext *dc) |
|
452 |
{
|
|
453 |
SPDesktop *desktop = SP_EVENT_CONTEXT(dc)->desktop; |
|
454 |
dc->dragging = FALSE; |
|
455 |
dc->is_drawing = false; |
|
456 |
sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0); |
|
457 |
/* Remove all temporary line segments */
|
|
458 |
while (dc->segments) { |
|
459 |
gtk_object_destroy(GTK_OBJECT(dc->segments->data)); |
|
460 |
dc->segments = g_slist_remove(dc->segments, dc->segments->data); |
|
461 |
}
|
|
462 |
/* reset accumulated curve */
|
|
5609
by johanengelen
struct SPCurve => class SPCurve |
463 |
dc->accumulated->reset(); |
5526
by joncruz
Added missing eraser files |
464 |
clear_current(dc); |
465 |
if (dc->repr) { |
|
466 |
dc->repr = NULL; |
|
467 |
}
|
|
468 |
}
|
|
469 |
||
470 |
||
471 |
gint
|
|
472 |
sp_eraser_context_root_handler(SPEventContext *event_context, |
|
473 |
GdkEvent *event) |
|
474 |
{
|
|
475 |
SPEraserContext *dc = SP_ERASER_CONTEXT(event_context); |
|
476 |
SPDesktop *desktop = event_context->desktop; |
|
477 |
||
478 |
gint ret = FALSE; |
|
479 |
||
480 |
switch (event->type) { |
|
481 |
case GDK_BUTTON_PRESS: |
|
482 |
if (event->button.button == 1 && !event_context->space_panning) { |
|
483 |
||
484 |
if (Inkscape::have_viable_layer(desktop, dc->_message_context) == false) { |
|
485 |
return TRUE; |
|
486 |
}
|
|
487 |
||
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
488 |
Geom::Point const button_w(event->button.x, |
5526
by joncruz
Added missing eraser files |
489 |
event->button.y); |
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
490 |
Geom::Point const button_dt(desktop->w2d(button_w)); |
5526
by joncruz
Added missing eraser files |
491 |
sp_eraser_reset(dc, button_dt); |
492 |
sp_eraser_extinput(dc, event); |
|
493 |
sp_eraser_apply(dc, button_dt); |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
494 |
dc->accumulated->reset(); |
5526
by joncruz
Added missing eraser files |
495 |
if (dc->repr) { |
496 |
dc->repr = NULL; |
|
497 |
}
|
|
498 |
||
6630
by cilix42
Removal of SP_ACTIVE_DESKTOP, next take |
499 |
Inkscape::Rubberband::get(desktop)->start(desktop, button_dt); |
500 |
Inkscape::Rubberband::get(desktop)->setMode(RUBBERBAND_MODE_TOUCHPATH); |
|
5593
by joncruz
Initial cut of touch-delete mode |
501 |
|
5526
by joncruz
Added missing eraser files |
502 |
/* initialize first point */
|
503 |
dc->npoints = 0; |
|
504 |
||
505 |
sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), |
|
506 |
( GDK_KEY_PRESS_MASK | |
|
507 |
GDK_BUTTON_RELEASE_MASK | |
|
508 |
GDK_POINTER_MOTION_MASK | |
|
509 |
GDK_BUTTON_PRESS_MASK ), |
|
510 |
NULL, |
|
511 |
event->button.time); |
|
512 |
||
513 |
ret = TRUE; |
|
514 |
||
515 |
sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3); |
|
516 |
dc->is_drawing = true; |
|
517 |
}
|
|
518 |
break; |
|
519 |
case GDK_MOTION_NOTIFY: |
|
520 |
{
|
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
521 |
Geom::Point const motion_w(event->motion.x, |
5526
by joncruz
Added missing eraser files |
522 |
event->motion.y); |
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
523 |
Geom::Point motion_dt(desktop->w2d(motion_w)); |
5526
by joncruz
Added missing eraser files |
524 |
sp_eraser_extinput(dc, event); |
525 |
||
526 |
dc->_message_context->clear(); |
|
527 |
||
528 |
if ( dc->is_drawing && (event->motion.state & GDK_BUTTON1_MASK) && !event_context->space_panning) { |
|
529 |
dc->dragging = TRUE; |
|
530 |
||
5593
by joncruz
Initial cut of touch-delete mode |
531 |
dc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Drawing</b> an eraser stroke")); |
5526
by joncruz
Added missing eraser files |
532 |
|
533 |
if (!sp_eraser_apply(dc, motion_dt)) { |
|
534 |
ret = TRUE; |
|
535 |
break; |
|
536 |
}
|
|
537 |
||
538 |
if ( dc->cur != dc->last ) { |
|
539 |
sp_eraser_brush(dc); |
|
540 |
g_assert( dc->npoints > 0 ); |
|
541 |
fit_and_split(dc, FALSE); |
|
542 |
}
|
|
543 |
ret = TRUE; |
|
544 |
}
|
|
6630
by cilix42
Removal of SP_ACTIVE_DESKTOP, next take |
545 |
Inkscape::Rubberband::get(desktop)->move(motion_dt); |
5526
by joncruz
Added missing eraser files |
546 |
}
|
547 |
break; |
|
548 |
||
549 |
||
550 |
case GDK_BUTTON_RELEASE: |
|
551 |
{
|
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
552 |
Geom::Point const motion_w(event->button.x, event->button.y); |
553 |
Geom::Point const motion_dt(desktop->w2d(motion_w)); |
|
5526
by joncruz
Added missing eraser files |
554 |
|
555 |
sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); |
|
556 |
sp_canvas_end_forced_full_redraws(desktop->canvas); |
|
557 |
dc->is_drawing = false; |
|
558 |
||
559 |
if (dc->dragging && event->button.button == 1 && !event_context->space_panning) { |
|
560 |
dc->dragging = FALSE; |
|
561 |
||
562 |
sp_eraser_apply(dc, motion_dt); |
|
563 |
||
564 |
/* Remove all temporary line segments */
|
|
565 |
while (dc->segments) { |
|
566 |
gtk_object_destroy(GTK_OBJECT(dc->segments->data)); |
|
567 |
dc->segments = g_slist_remove(dc->segments, dc->segments->data); |
|
568 |
}
|
|
569 |
||
570 |
/* Create object */
|
|
571 |
fit_and_split(dc, TRUE); |
|
572 |
accumulate_eraser(dc); |
|
573 |
set_to_accumulated(dc); // performs document_done |
|
574 |
||
575 |
/* reset accumulated curve */
|
|
5609
by johanengelen
struct SPCurve => class SPCurve |
576 |
dc->accumulated->reset(); |
5526
by joncruz
Added missing eraser files |
577 |
|
578 |
clear_current(dc); |
|
579 |
if (dc->repr) { |
|
580 |
dc->repr = NULL; |
|
581 |
}
|
|
582 |
||
583 |
dc->_message_context->clear(); |
|
584 |
ret = TRUE; |
|
585 |
}
|
|
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
586 |
if (Inkscape::Rubberband::get(desktop)->is_started()) { |
587 |
Inkscape::Rubberband::get(desktop)->stop(); |
|
588 |
}
|
|
589 |
||
5526
by joncruz
Added missing eraser files |
590 |
break; |
591 |
}
|
|
592 |
||
593 |
case GDK_KEY_PRESS: |
|
594 |
switch (get_group0_keyval (&event->key)) { |
|
595 |
case GDK_Up: |
|
596 |
case GDK_KP_Up: |
|
597 |
if (!MOD__CTRL_ONLY) { |
|
598 |
dc->angle += 5.0; |
|
599 |
if (dc->angle > 90.0) |
|
600 |
dc->angle = 90.0; |
|
601 |
sp_erc_update_toolbox (desktop, "eraser-angle", dc->angle); |
|
602 |
ret = TRUE; |
|
603 |
}
|
|
604 |
break; |
|
605 |
case GDK_Down: |
|
606 |
case GDK_KP_Down: |
|
607 |
if (!MOD__CTRL_ONLY) { |
|
608 |
dc->angle -= 5.0; |
|
609 |
if (dc->angle < -90.0) |
|
610 |
dc->angle = -90.0; |
|
611 |
sp_erc_update_toolbox (desktop, "eraser-angle", dc->angle); |
|
612 |
ret = TRUE; |
|
613 |
}
|
|
614 |
break; |
|
615 |
case GDK_Right: |
|
616 |
case GDK_KP_Right: |
|
617 |
if (!MOD__CTRL_ONLY) { |
|
618 |
dc->width += 0.01; |
|
619 |
if (dc->width > 1.0) |
|
620 |
dc->width = 1.0; |
|
621 |
sp_erc_update_toolbox (desktop, "altx-eraser", dc->width * 100); // the same spinbutton is for alt+x |
|
622 |
ret = TRUE; |
|
623 |
}
|
|
624 |
break; |
|
625 |
case GDK_Left: |
|
626 |
case GDK_KP_Left: |
|
627 |
if (!MOD__CTRL_ONLY) { |
|
628 |
dc->width -= 0.01; |
|
629 |
if (dc->width < 0.01) |
|
630 |
dc->width = 0.01; |
|
631 |
sp_erc_update_toolbox (desktop, "altx-eraser", dc->width * 100); |
|
632 |
ret = TRUE; |
|
633 |
}
|
|
634 |
break; |
|
635 |
case GDK_Home: |
|
636 |
case GDK_KP_Home: |
|
637 |
dc->width = 0.01; |
|
638 |
sp_erc_update_toolbox (desktop, "altx-eraser", dc->width * 100); |
|
639 |
ret = TRUE; |
|
640 |
break; |
|
641 |
case GDK_End: |
|
642 |
case GDK_KP_End: |
|
643 |
dc->width = 1.0; |
|
644 |
sp_erc_update_toolbox (desktop, "altx-eraser", dc->width * 100); |
|
645 |
ret = TRUE; |
|
646 |
break; |
|
647 |
case GDK_x: |
|
648 |
case GDK_X: |
|
649 |
if (MOD__ALT_ONLY) { |
|
650 |
desktop->setToolboxFocusTo ("altx-eraser"); |
|
651 |
ret = TRUE; |
|
652 |
}
|
|
653 |
break; |
|
654 |
case GDK_Escape: |
|
6630
by cilix42
Removal of SP_ACTIVE_DESKTOP, next take |
655 |
Inkscape::Rubberband::get(desktop)->stop(); |
5526
by joncruz
Added missing eraser files |
656 |
if (dc->is_drawing) { |
657 |
// if drawing, cancel, otherwise pass it up for deselecting
|
|
658 |
eraser_cancel (dc); |
|
659 |
ret = TRUE; |
|
660 |
}
|
|
661 |
break; |
|
662 |
case GDK_z: |
|
663 |
case GDK_Z: |
|
664 |
if (MOD__CTRL_ONLY && dc->is_drawing) { |
|
665 |
// if drawing, cancel, otherwise pass it up for undo
|
|
666 |
eraser_cancel (dc); |
|
667 |
ret = TRUE; |
|
668 |
}
|
|
669 |
break; |
|
670 |
default: |
|
671 |
break; |
|
672 |
}
|
|
673 |
break; |
|
674 |
||
675 |
case GDK_KEY_RELEASE: |
|
676 |
switch (get_group0_keyval(&event->key)) { |
|
677 |
case GDK_Control_L: |
|
678 |
case GDK_Control_R: |
|
679 |
dc->_message_context->clear(); |
|
680 |
break; |
|
681 |
default: |
|
682 |
break; |
|
683 |
}
|
|
684 |
||
685 |
default: |
|
686 |
break; |
|
687 |
}
|
|
688 |
||
689 |
if (!ret) { |
|
5717
by joncruz
Refactoring begining |
690 |
if (((SPEventContextClass *) eraser_parent_class)->root_handler) { |
691 |
ret = ((SPEventContextClass *) eraser_parent_class)->root_handler(event_context, event); |
|
5526
by joncruz
Added missing eraser files |
692 |
}
|
693 |
}
|
|
694 |
||
695 |
return ret; |
|
696 |
}
|
|
697 |
||
698 |
||
699 |
static void |
|
700 |
clear_current(SPEraserContext *dc) |
|
701 |
{
|
|
5593
by joncruz
Initial cut of touch-delete mode |
702 |
// reset bpath
|
5526
by joncruz
Added missing eraser files |
703 |
sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(dc->currentshape), NULL); |
5593
by joncruz
Initial cut of touch-delete mode |
704 |
|
705 |
// reset curve
|
|
5609
by johanengelen
struct SPCurve => class SPCurve |
706 |
dc->currentcurve->reset(); |
707 |
dc->cal1->reset(); |
|
708 |
dc->cal2->reset(); |
|
5593
by joncruz
Initial cut of touch-delete mode |
709 |
|
710 |
// reset points
|
|
5526
by joncruz
Added missing eraser files |
711 |
dc->npoints = 0; |
712 |
}
|
|
713 |
||
714 |
static void |
|
715 |
set_to_accumulated(SPEraserContext *dc) |
|
716 |
{
|
|
717 |
SPDesktop *desktop = SP_EVENT_CONTEXT(dc)->desktop; |
|
5529
by joncruz
Reduce undo history items when nothing is selected |
718 |
bool workDone = false; |
5526
by joncruz
Added missing eraser files |
719 |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
720 |
if (!dc->accumulated->is_empty()) { |
5526
by joncruz
Added missing eraser files |
721 |
if (!dc->repr) { |
722 |
/* Create object */
|
|
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
723 |
Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); |
5526
by joncruz
Added missing eraser files |
724 |
Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); |
725 |
||
726 |
/* Set style */
|
|
6885
by Ted Gould
From trunk |
727 |
sp_desktop_apply_style_tool (desktop, repr, "/tools/eraser", false); |
5526
by joncruz
Added missing eraser files |
728 |
|
729 |
dc->repr = repr; |
|
730 |
||
731 |
SPItem *item=SP_ITEM(desktop->currentLayer()->appendChildRepr(dc->repr)); |
|
732 |
Inkscape::GC::release(dc->repr); |
|
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
733 |
item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); |
5526
by joncruz
Added missing eraser files |
734 |
item->updateRepr(); |
735 |
}
|
|
7478
by speleo3
remove desktop-affine.h and refactor sp_desktop_dt2doc_* calls |
736 |
Geom::PathVector pathv = dc->accumulated->get_pathvector() * desktop->dt2doc(); |
6228
by johanengelen
* 2geomify polygon svg writing |
737 |
gchar *str = sp_svg_write_path(pathv); |
5526
by joncruz
Added missing eraser files |
738 |
g_assert( str != NULL ); |
739 |
dc->repr->setAttribute("d", str); |
|
740 |
g_free(str); |
|
741 |
||
742 |
if ( dc->repr ) { |
|
5535
by joncruz
Refining eraser |
743 |
bool wasSelection = false; |
5526
by joncruz
Added missing eraser files |
744 |
Inkscape::Selection *selection = sp_desktop_selection(desktop); |
6885
by Ted Gould
From trunk |
745 |
Inkscape::Preferences *prefs = Inkscape::Preferences::get(); |
746 |
||
747 |
gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0; |
|
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
748 |
Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); |
5535
by joncruz
Refining eraser |
749 |
|
750 |
SPItem* acid = SP_ITEM(desktop->doc()->getObjectByRepr(dc->repr)); |
|
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
751 |
Geom::OptRect eraserBbox = acid->visualBounds(); |
6839
by cilix42
Next roud of NR ==> Geom conversion |
752 |
Geom::Rect bounds = (*eraserBbox) * desktop->doc2dt(); |
5535
by joncruz
Refining eraser |
753 |
std::vector<SPItem*> remainingItems; |
754 |
GSList* toWorkOn = 0; |
|
755 |
if (selection->isEmpty()) { |
|
5593
by joncruz
Initial cut of touch-delete mode |
756 |
if ( eraserMode ) { |
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
757 |
toWorkOn = sp_desktop_document(desktop)->getItemsPartiallyInBox(desktop->dkey, bounds); |
5593
by joncruz
Initial cut of touch-delete mode |
758 |
} else { |
9012.1.255
by Josh Andler
Patch by Daniel_J for 522327 |
759 |
Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); |
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
760 |
toWorkOn = sp_desktop_document(desktop)->getItemsAtPoints(desktop->dkey, r->getPoints()); |
5593
by joncruz
Initial cut of touch-delete mode |
761 |
}
|
5535
by joncruz
Refining eraser |
762 |
toWorkOn = g_slist_remove( toWorkOn, acid ); |
763 |
} else { |
|
764 |
toWorkOn = g_slist_copy(const_cast<GSList*>(selection->itemList())); |
|
765 |
wasSelection = true; |
|
766 |
}
|
|
767 |
||
768 |
if ( g_slist_length(toWorkOn) > 0 ) { |
|
5593
by joncruz
Initial cut of touch-delete mode |
769 |
if ( eraserMode ) { |
770 |
for (GSList *i = toWorkOn ; i ; i = i->next ) { |
|
771 |
SPItem *item = SP_ITEM(i->data); |
|
772 |
if ( eraserMode ) { |
|
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
773 |
Geom::OptRect bbox = item->visualBounds(); |
5593
by joncruz
Initial cut of touch-delete mode |
774 |
if (bbox && bbox->intersects(*eraserBbox)) { |
775 |
Inkscape::XML::Node* dup = dc->repr->duplicate(xml_doc); |
|
776 |
dc->repr->parent()->appendChild(dup); |
|
777 |
Inkscape::GC::release(dup); // parent takes over |
|
5526
by joncruz
Added missing eraser files |
778 |
|
5593
by joncruz
Initial cut of touch-delete mode |
779 |
selection->set(item); |
780 |
selection->add(dup); |
|
6633
by cilix42
Eliminate more of SP_ACTIVE_DESKTOP |
781 |
sp_selected_path_diff_skip_undo(desktop); |
5593
by joncruz
Initial cut of touch-delete mode |
782 |
workDone = true; // TODO set this only if something was cut. |
783 |
if ( !selection->isEmpty() ) { |
|
784 |
// If the item was not completely erased, track the new remainder.
|
|
785 |
GSList *nowSel = g_slist_copy(const_cast<GSList *>(selection->itemList())); |
|
786 |
for (GSList const *i2 = nowSel ; i2 ; i2 = i2->next ) { |
|
787 |
remainingItems.push_back(SP_ITEM(i2->data)); |
|
788 |
}
|
|
789 |
g_slist_free(nowSel); |
|
790 |
}
|
|
791 |
} else { |
|
792 |
remainingItems.push_back(item); |
|
5526
by joncruz
Added missing eraser files |
793 |
}
|
794 |
}
|
|
5593
by joncruz
Initial cut of touch-delete mode |
795 |
}
|
796 |
} else { |
|
797 |
for (GSList *i = toWorkOn ; i ; i = i->next ) { |
|
798 |
sp_object_ref( SP_ITEM(i->data), 0 ); |
|
799 |
}
|
|
800 |
for (GSList *i = toWorkOn ; i ; i = i->next ) { |
|
801 |
SPItem *item = SP_ITEM(i->data); |
|
802 |
item->deleteObject(true); |
|
803 |
sp_object_unref(item); |
|
804 |
workDone = true; |
|
5535
by joncruz
Refining eraser |
805 |
}
|
806 |
}
|
|
807 |
||
808 |
g_slist_free(toWorkOn); |
|
809 |
||
5593
by joncruz
Initial cut of touch-delete mode |
810 |
if ( !eraserMode ) { |
6629
by cilix42
Get rid of a whole bunch of further instances of SP_ACTIVE_DESKTOP (where the desktop is readily available in the calling function) |
811 |
//sp_selection_delete(desktop);
|
5593
by joncruz
Initial cut of touch-delete mode |
812 |
remainingItems.clear(); |
813 |
}
|
|
814 |
||
5535
by joncruz
Refining eraser |
815 |
selection->clear(); |
816 |
if ( wasSelection ) { |
|
817 |
if ( !remainingItems.empty() ) { |
|
818 |
selection->add(remainingItems.begin(), remainingItems.end()); |
|
819 |
}
|
|
820 |
}
|
|
5526
by joncruz
Added missing eraser files |
821 |
}
|
822 |
||
823 |
// Remove the eraser stroke itself:
|
|
824 |
sp_repr_unparent( dc->repr ); |
|
825 |
dc->repr = 0; |
|
826 |
}
|
|
827 |
} else { |
|
828 |
if (dc->repr) { |
|
829 |
sp_repr_unparent(dc->repr); |
|
830 |
dc->repr = 0; |
|
831 |
}
|
|
832 |
}
|
|
833 |
||
5529
by joncruz
Reduce undo history items when nothing is selected |
834 |
|
835 |
if ( workDone ) { |
|
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
836 |
DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ERASER, |
837 |
_("Draw eraser stroke")); |
|
5529
by joncruz
Reduce undo history items when nothing is selected |
838 |
} else { |
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
839 |
DocumentUndo::cancel(sp_desktop_document(desktop)); |
5529
by joncruz
Reduce undo history items when nothing is selected |
840 |
}
|
5526
by joncruz
Added missing eraser files |
841 |
}
|
842 |
||
843 |
static void |
|
844 |
add_cap(SPCurve *curve, |
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
845 |
Geom::Point const &pre, Geom::Point const &from, |
846 |
Geom::Point const &to, Geom::Point const &post, |
|
5526
by joncruz
Added missing eraser files |
847 |
double rounding) |
848 |
{
|
|
6954
by johanengelen
2geom eraser tool |
849 |
Geom::Point vel = rounding * Geom::rot90( to - from ) / sqrt(2.0); |
850 |
double mag = Geom::L2(vel); |
|
5526
by joncruz
Added missing eraser files |
851 |
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
852 |
Geom::Point v_in = from - pre; |
6954
by johanengelen
2geom eraser tool |
853 |
double mag_in = Geom::L2(v_in); |
5526
by joncruz
Added missing eraser files |
854 |
if ( mag_in > ERASER_EPSILON ) { |
855 |
v_in = mag * v_in / mag_in; |
|
856 |
} else { |
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
857 |
v_in = Geom::Point(0, 0); |
5526
by joncruz
Added missing eraser files |
858 |
}
|
859 |
||
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
860 |
Geom::Point v_out = to - post; |
6954
by johanengelen
2geom eraser tool |
861 |
double mag_out = Geom::L2(v_out); |
5526
by joncruz
Added missing eraser files |
862 |
if ( mag_out > ERASER_EPSILON ) { |
863 |
v_out = mag * v_out / mag_out; |
|
864 |
} else { |
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
865 |
v_out = Geom::Point(0, 0); |
5526
by joncruz
Added missing eraser files |
866 |
}
|
867 |
||
6954
by johanengelen
2geom eraser tool |
868 |
if ( Geom::L2(v_in) > ERASER_EPSILON || Geom::L2(v_out) > ERASER_EPSILON ) { |
5609
by johanengelen
struct SPCurve => class SPCurve |
869 |
curve->curveto(from + v_in, to + v_out, to); |
5526
by joncruz
Added missing eraser files |
870 |
}
|
871 |
}
|
|
872 |
||
873 |
static void |
|
874 |
accumulate_eraser(SPEraserContext *dc) |
|
875 |
{
|
|
5609
by johanengelen
struct SPCurve => class SPCurve |
876 |
if ( !dc->cal1->is_empty() && !dc->cal2->is_empty() ) { |
877 |
dc->accumulated->reset(); /* Is this required ?? */ |
|
5636
by johanengelen
- try to use more forward declarations for less dependencies on display/curve.h |
878 |
SPCurve *rev_cal2 = dc->cal2->create_reverse(); |
5526
by joncruz
Added missing eraser files |
879 |
|
6204
by johanengelen
change part of calligraphic/eraser code to 2geom. |
880 |
g_assert(dc->cal1->get_segment_count() > 0); |
881 |
g_assert(rev_cal2->get_segment_count() > 0); |
|
882 |
g_assert( ! dc->cal1->first_path()->closed() ); |
|
883 |
g_assert( ! rev_cal2->first_path()->closed() ); |
|
884 |
||
885 |
Geom::CubicBezier const * dc_cal1_firstseg = dynamic_cast<Geom::CubicBezier const *>( dc->cal1->first_segment() ); |
|
886 |
Geom::CubicBezier const * rev_cal2_firstseg = dynamic_cast<Geom::CubicBezier const *>( rev_cal2->first_segment() ); |
|
887 |
Geom::CubicBezier const * dc_cal1_lastseg = dynamic_cast<Geom::CubicBezier const *>( dc->cal1->last_segment() ); |
|
888 |
Geom::CubicBezier const * rev_cal2_lastseg = dynamic_cast<Geom::CubicBezier const *>( rev_cal2->last_segment() ); |
|
889 |
g_assert( dc_cal1_firstseg ); |
|
890 |
g_assert( rev_cal2_firstseg ); |
|
891 |
g_assert( dc_cal1_lastseg ); |
|
892 |
g_assert( rev_cal2_lastseg ); |
|
5526
by joncruz
Added missing eraser files |
893 |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
894 |
dc->accumulated->append(dc->cal1, FALSE); |
5526
by joncruz
Added missing eraser files |
895 |
|
6237
by johanengelen
fix calligraphy and erasertools bugs introduced by rev19197 |
896 |
add_cap(dc->accumulated, (*dc_cal1_lastseg)[2], (*dc_cal1_lastseg)[3], (*rev_cal2_firstseg)[0], (*rev_cal2_firstseg)[1], dc->cap_rounding); |
5526
by joncruz
Added missing eraser files |
897 |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
898 |
dc->accumulated->append(rev_cal2, TRUE); |
5526
by joncruz
Added missing eraser files |
899 |
|
6237
by johanengelen
fix calligraphy and erasertools bugs introduced by rev19197 |
900 |
add_cap(dc->accumulated, (*rev_cal2_lastseg)[2], (*rev_cal2_lastseg)[3], (*dc_cal1_firstseg)[0], (*dc_cal1_firstseg)[1], dc->cap_rounding); |
5526
by joncruz
Added missing eraser files |
901 |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
902 |
dc->accumulated->closepath(); |
903 |
||
904 |
rev_cal2->unref(); |
|
905 |
||
906 |
dc->cal1->reset(); |
|
907 |
dc->cal2->reset(); |
|
5526
by joncruz
Added missing eraser files |
908 |
}
|
909 |
}
|
|
910 |
||
911 |
static double square(double const x) |
|
912 |
{
|
|
913 |
return x * x; |
|
914 |
}
|
|
915 |
||
916 |
static void |
|
917 |
fit_and_split(SPEraserContext *dc, gboolean release) |
|
918 |
{
|
|
6621
by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP |
919 |
SPDesktop *desktop = SP_EVENT_CONTEXT(dc)->desktop; |
920 |
||
6839
by cilix42
Next roud of NR ==> Geom conversion |
921 |
double const tolerance_sq = square( desktop->w2d().descrim() * TOLERANCE_ERASER ); |
5526
by joncruz
Added missing eraser files |
922 |
|
923 |
#ifdef ERASER_VERBOSE
|
|
924 |
g_print("[F&S:R=%c]", release?'T':'F'); |
|
925 |
#endif
|
|
926 |
||
927 |
if (!( dc->npoints > 0 && dc->npoints < SAMPLING_SIZE )) |
|
928 |
return; // just clicked |
|
929 |
||
930 |
if ( dc->npoints == SAMPLING_SIZE - 1 || release ) { |
|
931 |
#define BEZIER_SIZE 4
|
|
932 |
#define BEZIER_MAX_BEZIERS 8
|
|
933 |
#define BEZIER_MAX_LENGTH ( BEZIER_SIZE * BEZIER_MAX_BEZIERS )
|
|
934 |
||
935 |
#ifdef ERASER_VERBOSE
|
|
936 |
g_print("[F&S:#] dc->npoints:%d, release:%s\n", |
|
937 |
dc->npoints, release ? "TRUE" : "FALSE"); |
|
938 |
#endif
|
|
939 |
||
940 |
/* Current eraser */
|
|
6301
by johanengelen
dyna-draw-context and eraser-context: replace check for empty path with 2geomified method of spcurve |
941 |
if ( dc->cal1->is_empty() || dc->cal2->is_empty() ) { |
5526
by joncruz
Added missing eraser files |
942 |
/* dc->npoints > 0 */
|
943 |
/* g_print("erasers(1|2) reset\n"); */
|
|
5609
by johanengelen
struct SPCurve => class SPCurve |
944 |
dc->cal1->reset(); |
945 |
dc->cal2->reset(); |
|
5526
by joncruz
Added missing eraser files |
946 |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
947 |
dc->cal1->moveto(dc->point1[0]); |
948 |
dc->cal2->moveto(dc->point2[0]); |
|
5526
by joncruz
Added missing eraser files |
949 |
}
|
950 |
||
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
951 |
Geom::Point b1[BEZIER_MAX_LENGTH]; |
6983
by johanengelen
use 2geom bezier fitting (is copy of inkscape's) |
952 |
gint const nb1 = Geom::bezier_fit_cubic_r(b1, dc->point1, dc->npoints, |
5526
by joncruz
Added missing eraser files |
953 |
tolerance_sq, BEZIER_MAX_BEZIERS); |
954 |
g_assert( nb1 * BEZIER_SIZE <= gint(G_N_ELEMENTS(b1)) ); |
|
955 |
||
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
956 |
Geom::Point b2[BEZIER_MAX_LENGTH]; |
6983
by johanengelen
use 2geom bezier fitting (is copy of inkscape's) |
957 |
gint const nb2 = Geom::bezier_fit_cubic_r(b2, dc->point2, dc->npoints, |
5526
by joncruz
Added missing eraser files |
958 |
tolerance_sq, BEZIER_MAX_BEZIERS); |
959 |
g_assert( nb2 * BEZIER_SIZE <= gint(G_N_ELEMENTS(b2)) ); |
|
960 |
||
961 |
if ( nb1 != -1 && nb2 != -1 ) { |
|
962 |
/* Fit and draw and reset state */
|
|
963 |
#ifdef ERASER_VERBOSE
|
|
964 |
g_print("nb1:%d nb2:%d\n", nb1, nb2); |
|
965 |
#endif
|
|
966 |
/* CanvasShape */
|
|
967 |
if (! release) { |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
968 |
dc->currentcurve->reset(); |
969 |
dc->currentcurve->moveto(b1[0]); |
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
970 |
for (Geom::Point *bp1 = b1; bp1 < b1 + BEZIER_SIZE * nb1; bp1 += BEZIER_SIZE) { |
5609
by johanengelen
struct SPCurve => class SPCurve |
971 |
dc->currentcurve->curveto(bp1[1], |
5526
by joncruz
Added missing eraser files |
972 |
bp1[2], bp1[3]); |
973 |
}
|
|
5609
by johanengelen
struct SPCurve => class SPCurve |
974 |
dc->currentcurve->lineto(b2[BEZIER_SIZE*(nb2-1) + 3]); |
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
975 |
for (Geom::Point *bp2 = b2 + BEZIER_SIZE * ( nb2 - 1 ); bp2 >= b2; bp2 -= BEZIER_SIZE) { |
5609
by johanengelen
struct SPCurve => class SPCurve |
976 |
dc->currentcurve->curveto(bp2[2], bp2[1], bp2[0]); |
5526
by joncruz
Added missing eraser files |
977 |
}
|
978 |
// FIXME: dc->segments is always NULL at this point??
|
|
979 |
if (!dc->segments) { // first segment |
|
980 |
add_cap(dc->currentcurve, b2[1], b2[0], b1[0], b1[1], dc->cap_rounding); |
|
981 |
}
|
|
5609
by johanengelen
struct SPCurve => class SPCurve |
982 |
dc->currentcurve->closepath(); |
5526
by joncruz
Added missing eraser files |
983 |
sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(dc->currentshape), dc->currentcurve); |
984 |
}
|
|
985 |
||
986 |
/* Current eraser */
|
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
987 |
for (Geom::Point *bp1 = b1; bp1 < b1 + BEZIER_SIZE * nb1; bp1 += BEZIER_SIZE) { |
5609
by johanengelen
struct SPCurve => class SPCurve |
988 |
dc->cal1->curveto(bp1[1], bp1[2], bp1[3]); |
5526
by joncruz
Added missing eraser files |
989 |
}
|
6835
by cilix42
Some NR::Point ==> Geom::Point replacements |
990 |
for (Geom::Point *bp2 = b2; bp2 < b2 + BEZIER_SIZE * nb2; bp2 += BEZIER_SIZE) { |
5609
by johanengelen
struct SPCurve => class SPCurve |
991 |
dc->cal2->curveto(bp2[1], bp2[2], bp2[3]); |
5526
by joncruz
Added missing eraser files |
992 |
}
|
993 |
} else { |
|
994 |
/* fixme: ??? */
|
|
995 |
#ifdef ERASER_VERBOSE
|
|
996 |
g_print("[fit_and_split] failed to fit-cubic.\n"); |
|
997 |
#endif
|
|
998 |
draw_temporary_box(dc); |
|
999 |
||
1000 |
for (gint i = 1; i < dc->npoints; i++) { |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
1001 |
dc->cal1->lineto(dc->point1[i]); |
5526
by joncruz
Added missing eraser files |
1002 |
}
|
1003 |
for (gint i = 1; i < dc->npoints; i++) { |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
1004 |
dc->cal2->lineto(dc->point2[i]); |
5526
by joncruz
Added missing eraser files |
1005 |
}
|
1006 |
}
|
|
1007 |
||
1008 |
/* Fit and draw and copy last point */
|
|
1009 |
#ifdef ERASER_VERBOSE
|
|
1010 |
g_print("[%d]Yup\n", dc->npoints); |
|
1011 |
#endif
|
|
1012 |
if (!release) { |
|
6885
by Ted Gould
From trunk |
1013 |
Inkscape::Preferences *prefs = Inkscape::Preferences::get(); |
1014 |
gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0; |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
1015 |
g_assert(!dc->currentcurve->is_empty()); |
5526
by joncruz
Added missing eraser files |
1016 |
|
6621
by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP |
1017 |
SPCanvasItem *cbp = sp_canvas_item_new(sp_desktop_sketch(desktop), |
5526
by joncruz
Added missing eraser files |
1018 |
SP_TYPE_CANVAS_BPATH, |
1019 |
NULL); |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
1020 |
SPCurve *curve = dc->currentcurve->copy(); |
5526
by joncruz
Added missing eraser files |
1021 |
sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH (cbp), curve); |
5609
by johanengelen
struct SPCurve => class SPCurve |
1022 |
curve->unref(); |
5526
by joncruz
Added missing eraser files |
1023 |
|
6885
by Ted Gould
From trunk |
1024 |
guint32 fillColor = sp_desktop_get_color_tool (desktop, "/tools/eraser", true); |
1025 |
//guint32 strokeColor = sp_desktop_get_color_tool (desktop, "/tools/eraser", false);
|
|
1026 |
double opacity = sp_desktop_get_master_opacity_tool (desktop, "/tools/eraser"); |
|
1027 |
double fillOpacity = sp_desktop_get_opacity_tool (desktop, "/tools/eraser", true); |
|
1028 |
//double strokeOpacity = sp_desktop_get_opacity_tool (desktop, "/tools/eraser", false);
|
|
5526
by joncruz
Added missing eraser files |
1029 |
sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(cbp), ((fillColor & 0xffffff00) | SP_COLOR_F_TO_U(opacity*fillOpacity)), SP_WIND_RULE_EVENODD); |
1030 |
//on second thougtht don't do stroke yet because we don't have stoke-width yet and because stoke appears between segments while drawing
|
|
1031 |
//sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cbp), ((strokeColor & 0xffffff00) | SP_COLOR_F_TO_U(opacity*strokeOpacity)), 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
|
|
1032 |
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cbp), 0x00000000, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); |
|
1033 |
/* fixme: Cannot we cascade it to root more clearly? */
|
|
6621
by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP |
1034 |
g_signal_connect(G_OBJECT(cbp), "event", G_CALLBACK(sp_desktop_root_handler), desktop); |
5526
by joncruz
Added missing eraser files |
1035 |
|
1036 |
dc->segments = g_slist_prepend(dc->segments, cbp); |
|
5593
by joncruz
Initial cut of touch-delete mode |
1037 |
|
1038 |
if ( !eraserMode ) { |
|
1039 |
sp_canvas_item_hide(cbp); |
|
1040 |
sp_canvas_item_hide(dc->currentshape); |
|
1041 |
}
|
|
5526
by joncruz
Added missing eraser files |
1042 |
}
|
1043 |
||
1044 |
dc->point1[0] = dc->point1[dc->npoints - 1]; |
|
1045 |
dc->point2[0] = dc->point2[dc->npoints - 1]; |
|
1046 |
dc->npoints = 1; |
|
1047 |
} else { |
|
1048 |
draw_temporary_box(dc); |
|
1049 |
}
|
|
1050 |
}
|
|
1051 |
||
1052 |
static void |
|
1053 |
draw_temporary_box(SPEraserContext *dc) |
|
1054 |
{
|
|
5609
by johanengelen
struct SPCurve => class SPCurve |
1055 |
dc->currentcurve->reset(); |
5526
by joncruz
Added missing eraser files |
1056 |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
1057 |
dc->currentcurve->moveto(dc->point1[dc->npoints-1]); |
5526
by joncruz
Added missing eraser files |
1058 |
for (gint i = dc->npoints-2; i >= 0; i--) { |
5609
by johanengelen
struct SPCurve => class SPCurve |
1059 |
dc->currentcurve->lineto(dc->point1[i]); |
5526
by joncruz
Added missing eraser files |
1060 |
}
|
1061 |
for (gint i = 0; i < dc->npoints; i++) { |
|
5609
by johanengelen
struct SPCurve => class SPCurve |
1062 |
dc->currentcurve->lineto(dc->point2[i]); |
5526
by joncruz
Added missing eraser files |
1063 |
}
|
1064 |
if (dc->npoints >= 2) { |
|
1065 |
add_cap(dc->currentcurve, dc->point2[dc->npoints-2], dc->point2[dc->npoints-1], dc->point1[dc->npoints-1], dc->point1[dc->npoints-2], dc->cap_rounding); |
|
1066 |
}
|
|
1067 |
||
5609
by johanengelen
struct SPCurve => class SPCurve |
1068 |
dc->currentcurve->closepath(); |
5526
by joncruz
Added missing eraser files |
1069 |
sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(dc->currentshape), dc->currentcurve); |
1070 |
}
|
|
1071 |
||
1072 |
/*
|
|
1073 |
Local Variables:
|
|
1074 |
mode:c++
|
|
1075 |
c-file-style:"stroustrup"
|
|
1076 |
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
|
|
1077 |
indent-tabs-mode:nil
|
|
1078 |
fill-column:99
|
|
1079 |
End:
|
|
1080 |
*/
|
|
9020
by JazzyNico
Code refactoring and merging with trunk (revision 10599). |
1081 |
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
|