~valavanisalex/ubuntu/oneiric/inkscape/inkscape_0.48.1-2ubuntu4

« back to all changes in this revision

Viewing changes to src/gradient-context.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook, Kees Cook, Ted Gould
  • Date: 2008-02-10 14:20:16 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20080210142016-vcnb2zqyhszu0xvb
Tags: 0.46~pre1-0ubuntu1
[ Kees Cook ]
* debian/control:
  - add libgtkspell-dev build-dep to gain GtkSpell features (LP: #183547).
  - update Standards version (no changes needed).
  - add Vcs and Homepage fields.
  - switch to new python-lxml dep.
* debian/{control,rules}: switch from dpatch to quilt for more sanity.
* debian/patches/20_fix_glib_and_gxx43_ftbfs.patch:
  - merged against upstream fixes.
  - added additional fixes for newly written code.
* debian/rules: enable parallel building.

[ Ted Gould ]
* Updating POTFILES.in to make it so things build correctly.
* debian/control:
  - add ImageMagick++ and libboost-dev to build-deps

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 *
6
6
 * Authors:
7
7
 *   bulia byak <buliabyak@users.sf.net>
 
8
 *   Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
8
9
 *
 
10
 * Copyright (C) 2007 Johan Engelen
9
11
 * Copyright (C) 2005 Authors
10
12
 *
11
13
 * Released under GNU GPL, read the file 'COPYING' for more information
26
28
#include "message-context.h"
27
29
#include "message-stack.h"
28
30
#include "pixmaps/cursor-gradient.xpm"
 
31
#include "pixmaps/cursor-gradient-add.xpm"
29
32
#include "gradient-context.h"
 
33
#include "gradient-chemistry.h"
30
34
#include <glibmm/i18n.h>
31
35
#include "prefs-utils.h"
32
36
#include "gradient-drag.h"
33
37
#include "gradient-chemistry.h"
34
38
#include "xml/repr.h"
35
39
#include "sp-item.h"
 
40
#include "display/sp-ctrlline.h"
 
41
#include "sp-linear-gradient.h"
 
42
#include "sp-radial-gradient.h"
 
43
#include "sp-stop.h"
 
44
#include "svg/css-ostringstream.h"
 
45
#include "svg/svg-color.h"
 
46
#include "snap.h"
 
47
#include "sp-namedview.h"
 
48
#include "rubberband.h"
 
49
 
 
50
 
36
51
 
37
52
static void sp_gradient_context_class_init(SPGradientContextClass *klass);
38
53
static void sp_gradient_context_init(SPGradientContext *gr_context);
83
98
{
84
99
    SPEventContext *event_context = SP_EVENT_CONTEXT(gr_context);
85
100
 
 
101
    gr_context->cursor_addnode = false;
86
102
    event_context->cursor_shape = cursor_gradient_xpm;
87
103
    event_context->hot_x = 4;
88
104
    event_context->hot_y = 4;
89
105
    event_context->xp = 0;
90
106
    event_context->yp = 0;
91
 
    event_context->tolerance = 0;
 
107
    event_context->tolerance = 6;
92
108
    event_context->within_tolerance = false;
93
109
    event_context->item_to_select = NULL;
94
110
}
104
120
        delete rc->_message_context;
105
121
    }
106
122
 
 
123
    rc->selcon->disconnect();
 
124
    delete rc->selcon;
 
125
    rc->subselcon->disconnect();
 
126
    delete rc->subselcon;
 
127
 
107
128
    G_OBJECT_CLASS(parent_class)->dispose(object);
108
129
}
109
130
 
 
131
const gchar *gr_handle_descr [] = {
 
132
    N_("Linear gradient <b>start</b>"), //POINT_LG_BEGIN
 
133
    N_("Linear gradient <b>end</b>"),
 
134
    N_("Linear gradient <b>mid stop</b>"),
 
135
    N_("Radial gradient <b>center</b>"),
 
136
    N_("Radial gradient <b>radius</b>"),
 
137
    N_("Radial gradient <b>radius</b>"),
 
138
    N_("Radial gradient <b>focus</b>"), // POINT_RG_FOCUS
 
139
    N_("Radial gradient <b>mid stop</b>"),
 
140
    N_("Radial gradient <b>mid stop</b>")
 
141
};
 
142
 
 
143
static void 
 
144
gradient_selection_changed (Inkscape::Selection *, gpointer data)
 
145
{
 
146
    SPGradientContext *rc = (SPGradientContext *) data;
 
147
 
 
148
    GrDrag *drag = rc->_grdrag;
 
149
    Inkscape::Selection *selection = sp_desktop_selection(SP_EVENT_CONTEXT(rc)->desktop);
 
150
    guint n_obj = g_slist_length((GSList *) selection->itemList());
 
151
 
 
152
    if (!drag->isNonEmpty() || selection->isEmpty())
 
153
        return;
 
154
    guint n_tot = drag->numDraggers();
 
155
    guint n_sel = drag->numSelected();
 
156
 
 
157
    if (n_sel == 1) {
 
158
        if (drag->singleSelectedDraggerNumDraggables() == 1) {
 
159
            rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,
 
160
                    _("%s selected out of %d gradient handles on %d selected object(s)"), gr_handle_descr[drag->singleSelectedDraggerSingleDraggableType()], n_tot, n_obj);
 
161
        } else {
 
162
            rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,
 
163
                    _("One handle merging %d stops (drag with <b>Shift</b> to separate) selected out of %d gradient handles on %d selected object(s)"), drag->singleSelectedDraggerNumDraggables(), n_tot, n_obj);
 
164
        }
 
165
    } else if (n_sel > 1) {
 
166
        rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,
 
167
                                   _("<b>%d</b> gradient handles selected out of %d on %d selected object(s)"), n_sel, n_tot, n_obj);
 
168
    } else if (n_sel == 0) {
 
169
        rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,
 
170
                                   _("<b>No</b> gradient handles selected out of %d on %d selected object(s)"), n_tot, n_obj);
 
171
    }
 
172
}
 
173
 
 
174
static void
 
175
gradient_subselection_changed (gpointer, gpointer data)
 
176
{
 
177
    gradient_selection_changed (NULL, data);
 
178
}
 
179
 
 
180
 
110
181
static void sp_gradient_context_setup(SPEventContext *ec)
111
182
{
112
183
    SPGradientContext *rc = SP_GRADIENT_CONTEXT(ec);
120
191
    }
121
192
 
122
193
    ec->enableGrDrag();
 
194
    Inkscape::Selection *selection = sp_desktop_selection(ec->desktop);
123
195
 
124
196
    rc->_message_context = new Inkscape::MessageContext(sp_desktop_message_stack(ec->desktop));
 
197
 
 
198
    rc->selcon = new sigc::connection (selection->connectChanged( sigc::bind (sigc::ptr_fun(&gradient_selection_changed), rc)));
 
199
    rc->subselcon = new sigc::connection (ec->desktop->connectToolSubselectionChanged(sigc::bind (sigc::ptr_fun(&gradient_subselection_changed), rc)));
 
200
    gradient_selection_changed(selection, rc);
125
201
}
126
202
 
127
 
void 
 
203
void
128
204
sp_gradient_context_select_next (SPEventContext *event_context)
129
205
{
130
206
    GrDrag *drag = event_context->_grdrag;
131
207
    g_assert (drag);
132
208
 
133
 
    drag->select_next();
 
209
    GrDragger *d = drag->select_next();
 
210
 
 
211
    event_context->desktop->scroll_to_point(&(d->point), 1.0);
134
212
}
135
213
 
136
 
void 
 
214
void
137
215
sp_gradient_context_select_prev (SPEventContext *event_context)
138
216
{
139
217
    GrDrag *drag = event_context->_grdrag;
140
218
    g_assert (drag);
141
219
 
142
 
    drag->select_prev();
143
 
}
144
 
 
145
 
static gint sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
 
220
    GrDragger *d = drag->select_prev();
 
221
 
 
222
    event_context->desktop->scroll_to_point(&(d->point), 1.0);
 
223
}
 
224
 
 
225
static bool
 
226
sp_gradient_context_is_over_line (SPGradientContext *rc, SPItem *item, NR::Point event_p)
 
227
{
 
228
    SPDesktop *desktop = SP_EVENT_CONTEXT (rc)->desktop;
 
229
 
 
230
    //Translate mouse point into proper coord system
 
231
    rc->mousepoint_doc = desktop->w2d(event_p);
 
232
 
 
233
    SPCtrlLine* line = SP_CTRLLINE(item);
 
234
 
 
235
    NR::Point nearest = snap_vector_midpoint (rc->mousepoint_doc, line->s, line->e, 0);
 
236
    double dist_screen = NR::L2 (rc->mousepoint_doc - nearest) * desktop->current_zoom();
 
237
 
 
238
    double tolerance = (double) SP_EVENT_CONTEXT(rc)->tolerance;
 
239
 
 
240
    bool close = (dist_screen < tolerance);
 
241
 
 
242
    return close;
 
243
}
 
244
 
 
245
std::vector<NR::Point>
 
246
sp_gradient_context_get_stop_intervals (GrDrag *drag, GSList **these_stops, GSList **next_stops)
 
247
{
 
248
    std::vector<NR::Point> coords;
 
249
 
 
250
    // for all selected draggers
 
251
    for (GList *i = drag->selected; i != NULL; i = i->next) {
 
252
        GrDragger *dragger = (GrDragger *) i->data;
 
253
        // remember the coord of the dragger to reselect it later
 
254
        coords.push_back(dragger->point);
 
255
        // for all draggables of dragger
 
256
        for (GSList const* j = dragger->draggables; j != NULL; j = j->next) { 
 
257
            GrDraggable *d = (GrDraggable *) j->data;
 
258
 
 
259
            // find the gradient
 
260
            SPGradient *gradient = sp_item_gradient (d->item, d->fill_or_stroke);
 
261
            SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (gradient, false);
 
262
 
 
263
            // these draggable types cannot have a next draggabe to insert a stop between them
 
264
            if (d->point_type == POINT_LG_END || 
 
265
                d->point_type == POINT_RG_FOCUS || 
 
266
                d->point_type == POINT_RG_R1 || 
 
267
                d->point_type == POINT_RG_R2) {
 
268
                continue;
 
269
            }
 
270
 
 
271
            // from draggables to stops
 
272
            SPStop *this_stop = sp_get_stop_i (vector, d->point_i);
 
273
            SPStop *next_stop = sp_next_stop (this_stop);
 
274
            SPStop *last_stop = sp_last_stop (vector);
 
275
 
 
276
            gint fs = d->fill_or_stroke;
 
277
            SPItem *item = d->item;
 
278
            gint type = d->point_type;
 
279
            gint p_i = d->point_i;
 
280
 
 
281
            // if there's a next stop,
 
282
            if (next_stop) {
 
283
                GrDragger *dnext = NULL;
 
284
                // find its dragger 
 
285
                // (complex because it may have different types, and because in radial,
 
286
                // more than one dragger may correspond to a stop, so we must distinguish)
 
287
                if (type == POINT_LG_BEGIN || type == POINT_LG_MID) {
 
288
                    if (next_stop == last_stop)
 
289
                        dnext = drag->getDraggerFor (item, POINT_LG_END, p_i+1, fs);
 
290
                    else
 
291
                        dnext = drag->getDraggerFor (item, POINT_LG_MID, p_i+1, fs);
 
292
                } else { // radial
 
293
                    if (type == POINT_RG_CENTER || type == POINT_RG_MID1) {
 
294
                        if (next_stop == last_stop)
 
295
                            dnext = drag->getDraggerFor (item, POINT_RG_R1, p_i+1, fs);
 
296
                        else 
 
297
                            dnext = drag->getDraggerFor (item, POINT_RG_MID1, p_i+1, fs);
 
298
                    } 
 
299
                    if ((type == POINT_RG_MID2) || 
 
300
                        (type == POINT_RG_CENTER && dnext && !dnext->isSelected())) {
 
301
                        if (next_stop == last_stop)
 
302
                            dnext = drag->getDraggerFor (item, POINT_RG_R2, p_i+1, fs);
 
303
                        else 
 
304
                            dnext = drag->getDraggerFor (item, POINT_RG_MID2, p_i+1, fs);
 
305
                    }
 
306
                }
 
307
 
 
308
                // if both adjacent draggers selected,
 
309
                if (!g_slist_find(*these_stops, this_stop) && dnext && dnext->isSelected()) {
 
310
 
 
311
                    // remember the coords of the future dragger to select it
 
312
                    coords.push_back(0.5*(dragger->point + dnext->point));
 
313
 
 
314
                    // do not insert a stop now, it will confuse the loop;
 
315
                    // just remember the stops
 
316
                    *these_stops = g_slist_prepend (*these_stops, this_stop);
 
317
                    *next_stops = g_slist_prepend (*next_stops, next_stop);
 
318
                }
 
319
            }
 
320
        }
 
321
    }
 
322
    return coords;
 
323
}
 
324
 
 
325
static void
 
326
sp_gradient_context_add_stops_between_selected_stops (SPGradientContext *rc)
 
327
{
 
328
    SPDocument *doc = NULL;
 
329
    GrDrag *drag = rc->_grdrag;
 
330
 
 
331
    GSList *these_stops = NULL;
 
332
    GSList *next_stops = NULL;
 
333
 
 
334
    std::vector<NR::Point> coords = sp_gradient_context_get_stop_intervals (drag, &these_stops, &next_stops);
 
335
 
 
336
    if (g_slist_length(these_stops) == 0 && drag->numSelected() == 1) {
 
337
        // if a single stop is selected, add between that stop and the next one
 
338
        GrDragger *dragger = (GrDragger *) drag->selected->data;
 
339
        for (GSList const* j = dragger->draggables; j != NULL; j = j->next) { 
 
340
            GrDraggable *d = (GrDraggable *) j->data;
 
341
            SPGradient *gradient = sp_item_gradient (d->item, d->fill_or_stroke);
 
342
            SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (gradient, false);
 
343
            SPStop *this_stop = sp_get_stop_i (vector, d->point_i);
 
344
            SPStop *next_stop = sp_next_stop (this_stop);
 
345
            if (this_stop && next_stop) {
 
346
                these_stops = g_slist_prepend (these_stops, this_stop);
 
347
                next_stops = g_slist_prepend (next_stops, next_stop);
 
348
            }
 
349
        }
 
350
    }
 
351
 
 
352
    // now actually create the new stops
 
353
    GSList *i = these_stops;
 
354
    GSList *j = next_stops;
 
355
    for (; i != NULL && j != NULL; i = i->next, j = j->next) {
 
356
        SPStop *this_stop = (SPStop *) i->data;
 
357
        SPStop *next_stop = (SPStop *) j->data;
 
358
        gfloat offset = 0.5*(this_stop->offset + next_stop->offset);
 
359
        SPObject *parent = SP_OBJECT_PARENT(this_stop);
 
360
        if (SP_IS_GRADIENT (parent)) {
 
361
            doc = SP_OBJECT_DOCUMENT (parent);
 
362
            sp_vector_add_stop (SP_GRADIENT (parent), this_stop, next_stop, offset);
 
363
            sp_gradient_ensure_vector (SP_GRADIENT (parent));
 
364
        }
 
365
    }
 
366
 
 
367
    if (g_slist_length(these_stops) > 0 && doc) {
 
368
        sp_document_done (doc, SP_VERB_CONTEXT_GRADIENT, _("Add gradient stop"));
 
369
        drag->updateDraggers();
 
370
        // so that it does not automatically update draggers in idle loop, as this would deselect
 
371
        drag->local_change = true;
 
372
        // select all the old selected and new created draggers
 
373
        drag->selectByCoords(coords);
 
374
    }
 
375
 
 
376
    g_slist_free (these_stops);
 
377
    g_slist_free (next_stops);
 
378
}
 
379
 
 
380
double sqr(double x) {return x*x;}
 
381
 
 
382
static void
 
383
sp_gradient_simplify(SPGradientContext *rc, double tolerance)
 
384
{
 
385
    SPDocument *doc = NULL;
 
386
    GrDrag *drag = rc->_grdrag;
 
387
 
 
388
    GSList *these_stops = NULL;
 
389
    GSList *next_stops = NULL;
 
390
 
 
391
    std::vector<NR::Point> coords = sp_gradient_context_get_stop_intervals (drag, &these_stops, &next_stops);
 
392
 
 
393
    GSList *todel = NULL;
 
394
 
 
395
    GSList *i = these_stops;
 
396
    GSList *j = next_stops;
 
397
    for (; i != NULL && j != NULL; i = i->next, j = j->next) {
 
398
        SPStop *stop0 = (SPStop *) i->data;
 
399
        SPStop *stop1 = (SPStop *) j->data;
 
400
 
 
401
        gint i1 = g_slist_index(these_stops, stop1);
 
402
        if (i1 != -1) {
 
403
            GSList *next_next = g_slist_nth (next_stops, i1);
 
404
            if (next_next) {
 
405
                SPStop *stop2 = (SPStop *) next_next->data;
 
406
 
 
407
                if (g_slist_find(todel, stop0) || g_slist_find(todel, stop2))
 
408
                    continue;
 
409
 
 
410
                guint32 const c0 = sp_stop_get_rgba32(stop0);
 
411
                guint32 const c2 = sp_stop_get_rgba32(stop2);
 
412
                guint32 const c1r = sp_stop_get_rgba32(stop1);
 
413
                guint32 c1 = average_color (c0, c2, 
 
414
                       (stop1->offset - stop0->offset) / (stop2->offset - stop0->offset));
 
415
 
 
416
                double diff = 
 
417
                    sqr(SP_RGBA32_R_F(c1) - SP_RGBA32_R_F(c1r)) +
 
418
                    sqr(SP_RGBA32_G_F(c1) - SP_RGBA32_G_F(c1r)) +
 
419
                    sqr(SP_RGBA32_B_F(c1) - SP_RGBA32_B_F(c1r)) +
 
420
                    sqr(SP_RGBA32_A_F(c1) - SP_RGBA32_A_F(c1r));
 
421
 
 
422
                if (diff < tolerance)
 
423
                    todel = g_slist_prepend (todel, stop1);
 
424
            }
 
425
        }
 
426
    }
 
427
 
 
428
    for (i = todel; i != NULL; i = i->next) {
 
429
        SPStop *stop = (SPStop*) i->data;
 
430
        doc = SP_OBJECT_DOCUMENT (stop);
 
431
        Inkscape::XML::Node * parent = SP_OBJECT_REPR(stop)->parent();
 
432
        parent->removeChild(SP_OBJECT_REPR(stop));
 
433
    }
 
434
 
 
435
    if (g_slist_length(todel) > 0) {
 
436
        sp_document_done (doc, SP_VERB_CONTEXT_GRADIENT, _("Simplify gradient"));
 
437
        drag->local_change = true;
 
438
        drag->updateDraggers();
 
439
        drag->selectByCoords(coords);
 
440
    }
 
441
 
 
442
    g_slist_free (todel);
 
443
    g_slist_free (these_stops);
 
444
    g_slist_free (next_stops);
 
445
}
 
446
 
 
447
 
 
448
static void
 
449
sp_gradient_context_add_stop_near_point (SPGradientContext *rc, SPItem *item,  NR::Point mouse_p, guint32 /*etime*/)
 
450
{
 
451
    // item is the selected item. mouse_p the location in doc coordinates of where to add the stop
 
452
 
 
453
    SPEventContext *ec = SP_EVENT_CONTEXT(rc);
 
454
    SPDesktop *desktop = SP_EVENT_CONTEXT (rc)->desktop;
 
455
 
 
456
    double tolerance = (double) ec->tolerance;
 
457
 
 
458
    ec->get_drag()->addStopNearPoint (item, mouse_p, tolerance/desktop->current_zoom());
 
459
 
 
460
    sp_document_done (sp_desktop_document (desktop), SP_VERB_CONTEXT_GRADIENT,
 
461
                      _("Add gradient stop"));
 
462
 
 
463
    ec->get_drag()->updateDraggers();
 
464
}
 
465
 
 
466
 
 
467
static gint
 
468
sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
146
469
{
147
470
    static bool dragging;
148
471
 
161
484
    switch (event->type) {
162
485
    case GDK_2BUTTON_PRESS:
163
486
        if ( event->button.button == 1 ) {
164
 
            for (GSList const* i = selection->itemList(); i != NULL; i = i->next) {
165
 
                SPItem *item = SP_ITEM(i->data);
166
 
                SPGradientType new_type = (SPGradientType) prefs_get_int_attribute ("tools.gradient", "newgradient", SP_GRADIENT_TYPE_LINEAR);
167
 
                guint new_fill = prefs_get_int_attribute ("tools.gradient", "newfillorstroke", 1);
168
 
 
169
 
                SPGradient *vector = sp_gradient_vector_for_object(sp_desktop_document(desktop), desktop,                                                                                   SP_OBJECT (item), new_fill);
170
 
 
171
 
                SPGradient *priv = sp_item_set_gradient(item, vector, new_type, new_fill);
172
 
                sp_gradient_reset_to_userspace(priv, item);
173
 
            }
174
 
 
175
 
            sp_document_done (sp_desktop_document (desktop), SP_VERB_CONTEXT_GRADIENT,
176
 
                              _("Create default gradient"));
177
 
 
 
487
            bool over_line = false;
 
488
            SPCtrlLine *line = NULL;
 
489
            if (drag->lines) {
 
490
                for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) {
 
491
                    line = (SPCtrlLine*) l->data;
 
492
                    over_line |= sp_gradient_context_is_over_line (rc, (SPItem*) line, NR::Point(event->motion.x, event->motion.y));
 
493
                }
 
494
            }
 
495
            if (over_line) {
 
496
                // we take the first item in selection, because with doubleclick, the first click
 
497
                // always resets selection to the single object under cursor
 
498
                sp_gradient_context_add_stop_near_point(rc, SP_ITEM(selection->itemList()->data), rc->mousepoint_doc, event->button.time);
 
499
            } else {
 
500
                for (GSList const* i = selection->itemList(); i != NULL; i = i->next) {
 
501
                    SPItem *item = SP_ITEM(i->data);
 
502
                    SPGradientType new_type = (SPGradientType) prefs_get_int_attribute ("tools.gradient", "newgradient", SP_GRADIENT_TYPE_LINEAR);
 
503
                    guint new_fill = prefs_get_int_attribute ("tools.gradient", "newfillorstroke", 1);
 
504
 
 
505
                    SPGradient *vector = sp_gradient_vector_for_object(sp_desktop_document(desktop), desktop,                                                                                   SP_OBJECT (item), new_fill);
 
506
 
 
507
                    SPGradient *priv = sp_item_set_gradient(item, vector, new_type, new_fill);
 
508
                    sp_gradient_reset_to_userspace(priv, item);
 
509
                }
 
510
 
 
511
                sp_document_done (sp_desktop_document (desktop), SP_VERB_CONTEXT_GRADIENT,
 
512
                                  _("Create default gradient"));
 
513
            }
178
514
            ret = TRUE;
179
515
        }
180
516
        break;
181
517
    case GDK_BUTTON_PRESS:
182
 
        if ( event->button.button == 1 ) {
 
518
        if ( event->button.button == 1 && !event_context->space_panning ) {
183
519
            NR::Point const button_w(event->button.x, event->button.y);
184
520
 
185
521
            // save drag origin
187
523
            event_context->yp = (gint) button_w[NR::Y];
188
524
            event_context->within_tolerance = true;
189
525
 
190
 
            // remember clicked item, disregarding groups, honoring Alt; do nothing with Crtl to
191
 
            // enable Ctrl+doubleclick of exactly the selected item(s)
192
 
            if (!(event->button.state & GDK_CONTROL_MASK))
193
 
                event_context->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE);
194
 
 
195
526
            dragging = true;
196
 
            /* Position center */
 
527
 
197
528
            NR::Point const button_dt = desktop->w2d(button_w);
198
 
            /* Snap center to nearest magnetic point */
 
529
            if (event->button.state & GDK_SHIFT_MASK) {
 
530
                Inkscape::Rubberband::get()->start(desktop, button_dt);
 
531
            } else {
 
532
                // remember clicked item, disregarding groups, honoring Alt; do nothing with Crtl to
 
533
                // enable Ctrl+doubleclick of exactly the selected item(s)
 
534
                if (!(event->button.state & GDK_CONTROL_MASK))
 
535
                    event_context->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE);
199
536
 
200
 
            rc->origin = button_dt;
 
537
                /* Snap center to nearest magnetic point */
 
538
                SnapManager const &m = desktop->namedview->snap_manager;
 
539
                rc->origin = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, button_dt, NULL).getPoint();
 
540
            }
201
541
 
202
542
            ret = TRUE;
203
543
        }
204
544
        break;
205
545
    case GDK_MOTION_NOTIFY:
206
546
        if ( dragging
207
 
             && ( event->motion.state & GDK_BUTTON1_MASK ) )
 
547
             && ( event->motion.state & GDK_BUTTON1_MASK ) && !event_context->space_panning )
208
548
        {
209
549
            if ( event_context->within_tolerance
210
550
                 && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance )
220
560
                                     event->motion.y);
221
561
            NR::Point const motion_dt = event_context->desktop->w2d(motion_w);
222
562
 
223
 
            sp_gradient_drag(*rc, motion_dt, event->motion.state, event->motion.time);
 
563
            if (Inkscape::Rubberband::get()->is_started()) {
 
564
                Inkscape::Rubberband::get()->move(motion_dt);
 
565
                event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw around</b> handles to select them"));
 
566
            } else {
 
567
                sp_gradient_drag(*rc, motion_dt, event->motion.state, event->motion.time);
 
568
            }
 
569
            gobble_motion_events(GDK_BUTTON1_MASK);
224
570
 
225
571
            ret = TRUE;
 
572
        } else {
 
573
            bool over_line = false;
 
574
            if (drag->lines) {
 
575
                for (GSList *l = drag->lines; l != NULL; l = l->next) {
 
576
                    over_line |= sp_gradient_context_is_over_line (rc, (SPItem*) l->data, NR::Point(event->motion.x, event->motion.y));
 
577
                }
 
578
            }
 
579
 
 
580
            if (rc->cursor_addnode && !over_line) {
 
581
                event_context->cursor_shape = cursor_gradient_xpm;
 
582
                sp_event_context_update_cursor(event_context);
 
583
                rc->cursor_addnode = false;
 
584
            } else if (!rc->cursor_addnode && over_line) {
 
585
                event_context->cursor_shape = cursor_gradient_add_xpm;
 
586
                sp_event_context_update_cursor(event_context);
 
587
                rc->cursor_addnode = true;
 
588
            }
226
589
        }
227
590
        break;
228
591
    case GDK_BUTTON_RELEASE:
229
592
        event_context->xp = event_context->yp = 0;
230
 
        if ( event->button.button == 1 ) {
231
 
            dragging = false;
232
 
 
233
 
            // unless clicked with Ctrl (to enable Ctrl+doubleclick)
234
 
            if (event->button.state & GDK_CONTROL_MASK) {
 
593
        if ( event->button.button == 1 && !event_context->space_panning ) {
 
594
            if ( (event->button.state & GDK_CONTROL_MASK) && (event->button.state & GDK_MOD1_MASK ) ) {
 
595
                bool over_line = false;
 
596
                SPCtrlLine *line = NULL;
 
597
                if (drag->lines) {
 
598
                    for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) {
 
599
                        line = (SPCtrlLine*) l->data;
 
600
                        over_line = sp_gradient_context_is_over_line (rc, (SPItem*) line, NR::Point(event->motion.x, event->motion.y));
 
601
                        if (over_line)
 
602
                            break;
 
603
                    }
 
604
                }
 
605
                if (over_line && line) {
 
606
                    sp_gradient_context_add_stop_near_point(rc, line->item, rc->mousepoint_doc, 0);
 
607
                    ret = TRUE;
 
608
                }
 
609
            } else {
 
610
                dragging = false;
 
611
 
 
612
                // unless clicked with Ctrl (to enable Ctrl+doubleclick).  
 
613
                if (event->button.state & GDK_CONTROL_MASK) {
 
614
                    ret = TRUE;
 
615
                    break;
 
616
                }
 
617
 
 
618
                if (!event_context->within_tolerance) {
 
619
                    // we've been dragging, either do nothing (grdrag handles that),
 
620
                    // or rubberband-select if we have rubberband
 
621
                    Inkscape::Rubberband::Rubberband *r = Inkscape::Rubberband::get();
 
622
                    if (r->is_started() && !event_context->within_tolerance) {
 
623
                        // this was a rubberband drag
 
624
                        if (r->getMode() == RUBBERBAND_MODE_RECT) {
 
625
                            NR::Maybe<NR::Rect> const b = r->getRectangle();
 
626
                            drag->selectRect(*b);
 
627
                        }
 
628
                    }
 
629
 
 
630
                } else if (event_context->item_to_select) {
 
631
                    // no dragging, select clicked item if any
 
632
                    if (event->button.state & GDK_SHIFT_MASK) {
 
633
                        selection->toggle(event_context->item_to_select);
 
634
                    } else {
 
635
                        selection->set(event_context->item_to_select);
 
636
                    }
 
637
                } else {
 
638
                    // click in an empty space; do the same as Esc
 
639
                    if (drag->selected) {
 
640
                        drag->deselectAll();
 
641
                    } else {
 
642
                        selection->clear();
 
643
                    }
 
644
                }
 
645
 
 
646
                event_context->item_to_select = NULL;
235
647
                ret = TRUE;
236
 
                break;
237
 
            }
238
 
 
239
 
            if (!event_context->within_tolerance) {
240
 
                // we've been dragging, do nothing (grdrag handles that)
241
 
            } else if (event_context->item_to_select) {
242
 
                // no dragging, select clicked item if any
243
 
                if (event->button.state & GDK_SHIFT_MASK) {
244
 
                    selection->toggle(event_context->item_to_select);
245
 
                } else {
246
 
                    selection->set(event_context->item_to_select);
247
 
                }
248
 
            } else {
249
 
                // click in an empty space; do the same as Esc
250
 
                if (drag->selected) {
251
 
                    drag->setSelected (NULL);
252
 
                } else {
253
 
                    selection->clear();
254
 
                }
255
 
            }
256
 
 
257
 
            event_context->item_to_select = NULL;
258
 
            ret = TRUE;
 
648
            }
 
649
            Inkscape::Rubberband::get()->stop(); 
259
650
        }
260
651
        break;
261
652
    case GDK_KEY_PRESS:
282
673
            }
283
674
            break;
284
675
 
 
676
        case GDK_A:
 
677
        case GDK_a:
 
678
            if (MOD__CTRL_ONLY && drag->isNonEmpty()) {
 
679
                drag->selectAll();
 
680
                ret = TRUE;
 
681
            }
 
682
            break;
 
683
 
 
684
        case GDK_L:
 
685
        case GDK_l:
 
686
            if (MOD__CTRL_ONLY && drag->isNonEmpty() && drag->hasSelection()) {
 
687
                sp_gradient_simplify(rc, 1e-4);
 
688
                ret = TRUE;
 
689
            }
 
690
            break;
 
691
 
285
692
        case GDK_Escape:
286
693
            if (drag->selected) {
287
 
                drag->setSelected (NULL);
 
694
                drag->deselectAll();
288
695
            } else {
289
696
                selection->clear();
290
697
            }
296
703
        case GDK_KP_Left:
297
704
        case GDK_KP_4:
298
705
            if (!MOD__CTRL) { // not ctrl
 
706
                gint mul = 1 + gobble_key_events(
 
707
                    get_group0_keyval(&event->key), 0); // with any mask
299
708
                if (MOD__ALT) { // alt
300
 
                    if (MOD__SHIFT) drag->selected_move_screen(-10, 0); // shift
301
 
                    else drag->selected_move_screen(-1, 0); // no shift
 
709
                    if (MOD__SHIFT) drag->selected_move_screen(mul*-10, 0); // shift
 
710
                    else drag->selected_move_screen(mul*-1, 0); // no shift
302
711
                }
303
712
                else { // no alt
304
 
                    if (MOD__SHIFT) drag->selected_move(-10*nudge, 0); // shift
305
 
                    else drag->selected_move(-nudge, 0); // no shift
 
713
                    if (MOD__SHIFT) drag->selected_move(mul*-10*nudge, 0); // shift
 
714
                    else drag->selected_move(mul*-nudge, 0); // no shift
306
715
                }
307
716
                ret = TRUE;
308
717
            }
311
720
        case GDK_KP_Up:
312
721
        case GDK_KP_8:
313
722
            if (!MOD__CTRL) { // not ctrl
 
723
                gint mul = 1 + gobble_key_events(
 
724
                    get_group0_keyval(&event->key), 0); // with any mask
314
725
                if (MOD__ALT) { // alt
315
 
                    if (MOD__SHIFT) drag->selected_move_screen(0, 10); // shift
316
 
                    else drag->selected_move_screen(0, 1); // no shift
 
726
                    if (MOD__SHIFT) drag->selected_move_screen(0, mul*10); // shift
 
727
                    else drag->selected_move_screen(0, mul*1); // no shift
317
728
                }
318
729
                else { // no alt
319
 
                    if (MOD__SHIFT) drag->selected_move(0, 10*nudge); // shift
320
 
                    else drag->selected_move(0, nudge); // no shift
 
730
                    if (MOD__SHIFT) drag->selected_move(0, mul*10*nudge); // shift
 
731
                    else drag->selected_move(0, mul*nudge); // no shift
321
732
                }
322
733
                ret = TRUE;
323
734
            }
326
737
        case GDK_KP_Right:
327
738
        case GDK_KP_6:
328
739
            if (!MOD__CTRL) { // not ctrl
 
740
                gint mul = 1 + gobble_key_events(
 
741
                    get_group0_keyval(&event->key), 0); // with any mask
329
742
                if (MOD__ALT) { // alt
330
 
                    if (MOD__SHIFT) drag->selected_move_screen(10, 0); // shift
331
 
                    else drag->selected_move_screen(1, 0); // no shift
 
743
                    if (MOD__SHIFT) drag->selected_move_screen(mul*10, 0); // shift
 
744
                    else drag->selected_move_screen(mul*1, 0); // no shift
332
745
                }
333
746
                else { // no alt
334
 
                    if (MOD__SHIFT) drag->selected_move(10*nudge, 0); // shift
335
 
                    else drag->selected_move(nudge, 0); // no shift
 
747
                    if (MOD__SHIFT) drag->selected_move(mul*10*nudge, 0); // shift
 
748
                    else drag->selected_move(mul*nudge, 0); // no shift
336
749
                }
337
750
                ret = TRUE;
338
751
            }
341
754
        case GDK_KP_Down:
342
755
        case GDK_KP_2:
343
756
            if (!MOD__CTRL) { // not ctrl
 
757
                gint mul = 1 + gobble_key_events(
 
758
                    get_group0_keyval(&event->key), 0); // with any mask
344
759
                if (MOD__ALT) { // alt
345
 
                    if (MOD__SHIFT) drag->selected_move_screen(0, -10); // shift
346
 
                    else drag->selected_move_screen(0, -1); // no shift
 
760
                    if (MOD__SHIFT) drag->selected_move_screen(0, mul*-10); // shift
 
761
                    else drag->selected_move_screen(0, mul*-1); // no shift
347
762
                }
348
763
                else { // no alt
349
 
                    if (MOD__SHIFT) drag->selected_move(0, -10*nudge); // shift
350
 
                    else drag->selected_move(0, -nudge); // no shift
 
764
                    if (MOD__SHIFT) drag->selected_move(0, mul*-10*nudge); // shift
 
765
                    else drag->selected_move(0, mul*-nudge); // no shift
351
766
                }
352
767
                ret = TRUE;
353
768
            }
370
785
                ret = TRUE;
371
786
            }
372
787
            break;
 
788
 
 
789
        case GDK_Insert:
 
790
        case GDK_KP_Insert:
 
791
            // with any modifiers:
 
792
            sp_gradient_context_add_stops_between_selected_stops (rc);
 
793
            ret = TRUE;
 
794
            break;
 
795
 
 
796
        case GDK_Delete:
 
797
        case GDK_KP_Delete:
 
798
        case GDK_BackSpace:
 
799
            if ( drag->selected ) {
 
800
                drag->deleteSelected(MOD__CTRL_ONLY);
 
801
                ret = TRUE;
 
802
            }
 
803
            break;
373
804
        default:
374
805
            break;
375
806
        }
403
834
    return ret;
404
835
}
405
836
 
406
 
static void sp_gradient_drag(SPGradientContext &rc, NR::Point const pt, guint state, guint32 etime)
 
837
static void sp_gradient_drag(SPGradientContext &rc, NR::Point const pt, guint /*state*/, guint32 etime)
407
838
{
408
839
    SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop;
409
840
    Inkscape::Selection *selection = sp_desktop_selection(desktop);
433
864
            sp_item_set_gradient(SP_ITEM(i->data), vector, (SPGradientType) type, fill_or_stroke);
434
865
 
435
866
            if (type == SP_GRADIENT_TYPE_LINEAR) {
436
 
                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_LG_P1, rc.origin, fill_or_stroke, true, false);
437
 
                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_LG_P2, pt, fill_or_stroke, true, false);
 
867
                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_LG_BEGIN, 0, rc.origin, fill_or_stroke, true, false);
 
868
                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_LG_END, 0, pt, fill_or_stroke, true, false);
438
869
            } else if (type == SP_GRADIENT_TYPE_RADIAL) {
439
 
                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_CENTER, rc.origin, fill_or_stroke, true, false);
440
 
                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_R1, pt, fill_or_stroke, true, false);
 
870
                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_CENTER, 0, rc.origin, fill_or_stroke, true, false);
 
871
                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_R1, 0, pt, fill_or_stroke, true, false);
441
872
            }
442
873
            SP_OBJECT (i->data)->requestModified(SP_OBJECT_MODIFIED_FLAG);
443
874
        }
449
880
            // give the grab out-of-bounds values of xp/yp because we're already dragging
450
881
            // and therefore are already out of tolerance
451
882
            ec->_grdrag->grabKnot (SP_ITEM(selection->itemList()->data),
452
 
                                   type == SP_GRADIENT_TYPE_LINEAR? POINT_LG_P2 : POINT_RG_R1,
 
883
                                   type == SP_GRADIENT_TYPE_LINEAR? POINT_LG_END : POINT_RG_R1,
 
884
                                   -1, // ignore number (though it is always 1)
453
885
                                   fill_or_stroke, 99999, 99999, etime);
454
886
        }
455
887
        // We did an undoable action, but sp_document_done will be called by the knot when released