~valavanisalex/ubuntu/precise/inkscape/fix-943984

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/live_effects/parameter/path.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_PATH_CPP
 
2
 
 
3
/*
 
4
 * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
 
5
 *
 
6
 * Released under GNU GPL, read the file 'COPYING' for more information
 
7
 */
 
8
 
 
9
#include "live_effects/parameter/path.h"
 
10
#include "live_effects/effect.h"
 
11
#include "svg/svg.h"
 
12
#include <2geom/svg-path-parser.h>
 
13
#include <2geom/sbasis-to-bezier.h>
 
14
#include <2geom/pathvector.h>
 
15
#include <2geom/d2.h>
 
16
 
 
17
#include "ui/widget/point.h"
 
18
#include "widgets/icon.h"
 
19
#include <gtk/gtkstock.h>
 
20
#include "selection-chemistry.h"
 
21
#include "xml/repr.h"
 
22
#include "desktop.h"
 
23
#include "inkscape.h"
 
24
#include "message-stack.h"
 
25
#include "verbs.h"
 
26
#include "document.h"
 
27
 
 
28
// needed for on-canvas editting:
 
29
#include "tools-switch.h"
 
30
#include "shape-editor.h"
 
31
#include "node-context.h"
 
32
#include "desktop-handles.h"
 
33
#include "selection.h"
 
34
#include "nodepath.h"
 
35
// clipboard support
 
36
#include "ui/clipboard.h"
 
37
// required for linking to other paths
 
38
#include "uri.h"
 
39
#include "sp-shape.h"
 
40
#include "sp-text.h"
 
41
#include "display/curve.h"
 
42
 
 
43
 
 
44
namespace Inkscape {
 
45
 
 
46
namespace LivePathEffect {
 
47
 
 
48
PathParam::PathParam( const Glib::ustring& label, const Glib::ustring& tip,
 
49
                      const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
 
50
                      Effect* effect, const gchar * default_value)
 
51
    : Parameter(label, tip, key, wr, effect),
 
52
      changed(true),
 
53
      _pathvector(),
 
54
      _pwd2(),
 
55
      must_recalculate_pwd2(false),
 
56
      href(NULL),
 
57
      ref( (SPObject*)effect->getLPEObj() )
 
58
{
 
59
    defvalue = g_strdup(default_value);
 
60
    param_readSVGValue(defvalue);
 
61
    oncanvas_editable = true;
 
62
 
 
63
    ref_changed_connection = ref.changedSignal().connect(sigc::mem_fun(*this, &PathParam::ref_changed));
 
64
}
 
65
 
 
66
PathParam::~PathParam()
 
67
{
 
68
    remove_link();
 
69
 
 
70
    g_free(defvalue);
 
71
}
 
72
 
 
73
std::vector<Geom::Path> const &
 
74
PathParam::get_pathvector()
 
75
{
 
76
    return _pathvector;
 
77
}
 
78
 
 
79
Geom::Piecewise<Geom::D2<Geom::SBasis> > const &
 
80
PathParam::get_pwd2()
 
81
{
 
82
    ensure_pwd2();
 
83
    return _pwd2;
 
84
}
 
85
 
 
86
void
 
87
PathParam::param_set_default()
 
88
{
 
89
    param_readSVGValue(defvalue);
 
90
}
 
91
 
 
92
void
 
93
PathParam::param_set_and_write_default()
 
94
{
 
95
    param_write_to_repr(defvalue);
 
96
}
 
97
 
 
98
bool
 
99
PathParam::param_readSVGValue(const gchar * strvalue)
 
100
{
 
101
    if (strvalue) {
 
102
        _pathvector.clear();
 
103
        remove_link();
 
104
        must_recalculate_pwd2 = true;
 
105
 
 
106
        if (strvalue[0] == '#') {
 
107
            if (href)
 
108
                g_free(href);
 
109
            href = g_strdup(strvalue);
 
110
 
 
111
            // Now do the attaching, which emits the changed signal.
 
112
            try {
 
113
                ref.attach(Inkscape::URI(href));
 
114
            } catch (Inkscape::BadURIException &e) {
 
115
                g_warning("%s", e.what());
 
116
                ref.detach();
 
117
                _pathvector = sp_svg_read_pathv(defvalue);
 
118
            }
 
119
        } else {
 
120
            _pathvector = sp_svg_read_pathv(strvalue);
 
121
        }
 
122
 
 
123
        emit_changed();
 
124
        return true;
 
125
    }
 
126
 
 
127
    return false;
 
128
}
 
129
 
 
130
gchar *
 
131
PathParam::param_getSVGValue() const
 
132
{
 
133
    if (href) {
 
134
        return href;
 
135
    } else {
 
136
        gchar * svgd = sp_svg_write_path( _pathvector );
 
137
        return svgd;
 
138
    }
 
139
}
 
140
 
 
141
Gtk::Widget *
 
142
PathParam::param_newWidget(Gtk::Tooltips * tooltips)
 
143
{
 
144
    Gtk::HBox * _widget = Gtk::manage(new Gtk::HBox());
 
145
 
 
146
    Gtk::Label* pLabel = Gtk::manage(new Gtk::Label(param_label));
 
147
    static_cast<Gtk::HBox*>(_widget)->pack_start(*pLabel, true, true);
 
148
    tooltips->set_tip(*pLabel, param_tooltip);
 
149
 
 
150
    Gtk::Widget*  pIcon = Gtk::manage( sp_icon_get_icon( "tool-node-editor", Inkscape::ICON_SIZE_BUTTON) );
 
151
    Gtk::Button * pButton = Gtk::manage(new Gtk::Button());
 
152
    pButton->set_relief(Gtk::RELIEF_NONE);
 
153
    pIcon->show();
 
154
    pButton->add(*pIcon);
 
155
    pButton->show();
 
156
    pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_edit_button_click));
 
157
    static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
 
158
    tooltips->set_tip(*pButton, _("Edit on-canvas"));
 
159
 
 
160
    pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_COPY, Inkscape::ICON_SIZE_BUTTON) );
 
161
    pButton = Gtk::manage(new Gtk::Button());
 
162
    pButton->set_relief(Gtk::RELIEF_NONE);
 
163
    pIcon->show();
 
164
    pButton->add(*pIcon);
 
165
    pButton->show();
 
166
    pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_copy_button_click));
 
167
    static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
 
168
    tooltips->set_tip(*pButton, _("Copy path"));
 
169
 
 
170
    pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_PASTE, Inkscape::ICON_SIZE_BUTTON) );
 
171
    pButton = Gtk::manage(new Gtk::Button());
 
172
    pButton->set_relief(Gtk::RELIEF_NONE);
 
173
    pIcon->show();
 
174
    pButton->add(*pIcon);
 
175
    pButton->show();
 
176
    pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_paste_button_click));
 
177
    static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
 
178
    tooltips->set_tip(*pButton, _("Paste path"));
 
179
 
 
180
    pIcon = Gtk::manage( sp_icon_get_icon( "edit-clone", Inkscape::ICON_SIZE_BUTTON) );
 
181
    pButton = Gtk::manage(new Gtk::Button());
 
182
    pButton->set_relief(Gtk::RELIEF_NONE);
 
183
    pIcon->show();
 
184
    pButton->add(*pIcon);
 
185
    pButton->show();
 
186
    pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_link_button_click));
 
187
    static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
 
188
    tooltips->set_tip(*pButton, _("Link to path"));
 
189
 
 
190
    static_cast<Gtk::HBox*>(_widget)->show_all_children();
 
191
 
 
192
    return dynamic_cast<Gtk::Widget *> (_widget);
 
193
}
 
194
 
 
195
void
 
196
PathParam::param_editOncanvas(SPItem * item, SPDesktop * dt)
 
197
{
 
198
    // If not already in nodecontext, goto it!
 
199
    if (!tools_isactive(dt, TOOLS_NODES)) {
 
200
        tools_switch(dt, TOOLS_NODES);
 
201
    }
 
202
 
 
203
    ShapeEditor * shape_editor = dt->event_context->shape_editor;
 
204
    if (!href) {
 
205
        shape_editor->set_item_lpe_path_parameter(item, param_effect->getLPEObj(), param_key.c_str());
 
206
    } else {
 
207
        // set referred item for editing
 
208
        shape_editor->set_item(ref.getObject(), SH_NODEPATH);
 
209
    }
 
210
}
 
211
 
 
212
void
 
213
PathParam::param_setup_nodepath(Inkscape::NodePath::Path *np)
 
214
{
 
215
    np->show_helperpath = true;
 
216
    np->helperpath_rgba = 0x009000ff;
 
217
    np->helperpath_width = 1.0;
 
218
}
 
219
 
 
220
void
 
221
PathParam::addCanvasIndicators(SPLPEItem */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
 
222
{
 
223
    hp_vec.push_back(_pathvector);
 
224
}
 
225
 
 
226
/*
 
227
 * Only applies transform when not referring to other path!
 
228
 */
 
229
void
 
230
PathParam::param_transform_multiply(Geom::Matrix const& postmul, bool /*set*/)
 
231
{
 
232
    // only apply transform when not referring to other path
 
233
    if (!href) {
 
234
        set_new_value( _pathvector * postmul, true );
 
235
    }
 
236
}
 
237
 
 
238
/*
 
239
 * See comments for set_new_value(std::vector<Geom::Path>).
 
240
 */
 
241
void
 
242
PathParam::set_new_value (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & newpath, bool write_to_svg)
 
243
{
 
244
    remove_link();
 
245
    _pathvector = Geom::path_from_piecewise(newpath, LPE_CONVERSION_TOLERANCE);
 
246
 
 
247
    if (write_to_svg) {
 
248
        gchar * svgd = sp_svg_write_path( _pathvector );
 
249
        param_write_to_repr(svgd);
 
250
        g_free(svgd);
 
251
 
 
252
        // After the whole "writing to svg avalanche of function calling": force value upon pwd2 and don't recalculate.
 
253
        _pwd2 = newpath;
 
254
        must_recalculate_pwd2 = false;
 
255
    } else {
 
256
        _pwd2 = newpath;
 
257
        must_recalculate_pwd2 = false;
 
258
        emit_changed();
 
259
    }
 
260
}
 
261
 
 
262
/*
 
263
 * This method sets new path data.
 
264
 * If this PathParam refers to another path, this link is removed (and replaced with explicit path data).
 
265
 *
 
266
 * If write_to_svg = true :
 
267
 *          The new path data is written to SVG. In this case the signal_path_changed signal
 
268
 *          is not directly emited in this method, because writing to SVG
 
269
 *          triggers the LPEObject to which this belongs to call Effect::setParameter which calls
 
270
 *          PathParam::readSVGValue, which finally emits the signal_path_changed signal.
 
271
 * If write_to_svg = false :
 
272
 *          The new path data is not written to SVG. This method will emit the signal_path_changed signal.
 
273
 */
 
274
void
 
275
PathParam::set_new_value (std::vector<Geom::Path> const &newpath, bool write_to_svg)
 
276
{
 
277
    remove_link();
 
278
    _pathvector = newpath;
 
279
    must_recalculate_pwd2 = true;
 
280
 
 
281
    if (write_to_svg) {
 
282
        gchar * svgd = sp_svg_write_path( _pathvector );
 
283
        param_write_to_repr(svgd);
 
284
        g_free(svgd);
 
285
    } else {
 
286
        emit_changed();
 
287
    }
 
288
}
 
289
 
 
290
void
 
291
PathParam::ensure_pwd2()
 
292
{
 
293
    if (must_recalculate_pwd2) {
 
294
        _pwd2.clear();
 
295
        for (unsigned int i=0; i < _pathvector.size(); i++) {
 
296
            _pwd2.concat( _pathvector[i].toPwSb() );
 
297
        }
 
298
 
 
299
        must_recalculate_pwd2 = false;
 
300
    }
 
301
}
 
302
 
 
303
void
 
304
PathParam::emit_changed()
 
305
{
 
306
    changed = true;
 
307
    signal_path_changed.emit();
 
308
}
 
309
 
 
310
void
 
311
PathParam::start_listening(SPObject * to)
 
312
{
 
313
    if ( to == NULL ) {
 
314
        return;
 
315
    }
 
316
    linked_delete_connection = to->connectDelete(sigc::mem_fun(*this, &PathParam::linked_delete));
 
317
    linked_modified_connection = to->connectModified(sigc::mem_fun(*this, &PathParam::linked_modified));
 
318
    linked_modified(to, SP_OBJECT_MODIFIED_FLAG); // simulate linked_modified signal, so that path data is updated
 
319
}
 
320
 
 
321
void
 
322
PathParam::quit_listening(void)
 
323
{
 
324
    linked_modified_connection.disconnect();
 
325
    linked_delete_connection.disconnect();
 
326
}
 
327
 
 
328
void
 
329
PathParam::ref_changed(SPObject */*old_ref*/, SPObject *new_ref)
 
330
{
 
331
    quit_listening();
 
332
    if ( new_ref ) {
 
333
        start_listening(new_ref);
 
334
    }
 
335
}
 
336
 
 
337
void
 
338
PathParam::remove_link()
 
339
{
 
340
    if (href) {
 
341
        ref.detach();
 
342
        g_free(href);
 
343
        href = NULL;
 
344
    }
 
345
}
 
346
 
 
347
void
 
348
PathParam::linked_delete(SPObject */*deleted*/)
 
349
{
 
350
    quit_listening();
 
351
    remove_link();
 
352
    set_new_value (_pathvector, true);
 
353
}
 
354
 
 
355
void
 
356
PathParam::linked_modified(SPObject *linked_obj, guint /*flags*/)
 
357
{
 
358
    SPCurve *curve = NULL;
 
359
    if (SP_IS_SHAPE(linked_obj)) {
 
360
        curve = sp_shape_get_curve(SP_SHAPE(linked_obj));
 
361
    }
 
362
    if (SP_IS_TEXT(linked_obj)) {
 
363
        curve = SP_TEXT(linked_obj)->getNormalizedBpath();
 
364
    }
 
365
 
 
366
    if (curve == NULL) {
 
367
        // curve invalid, set default value
 
368
        _pathvector = sp_svg_read_pathv(defvalue);
 
369
    } else {
 
370
        _pathvector = curve->get_pathvector();
 
371
        curve->unref();
 
372
    }
 
373
 
 
374
    must_recalculate_pwd2 = true;
 
375
    emit_changed();
 
376
    SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG);
 
377
}
 
378
 
 
379
/* CALLBACK FUNCTIONS FOR THE BUTTONS */
 
380
void
 
381
PathParam::on_edit_button_click()
 
382
{
 
383
    SPItem * item = sp_desktop_selection(SP_ACTIVE_DESKTOP)->singleItem();
 
384
    if (item != NULL) {
 
385
        param_editOncanvas(item, SP_ACTIVE_DESKTOP);
 
386
    }
 
387
}
 
388
 
 
389
void
 
390
PathParam::paste_param_path(const char *svgd)
 
391
{
 
392
    // only recognize a non-null, non-empty string
 
393
    if (svgd && *svgd) {
 
394
        // remove possible link to path
 
395
        remove_link();
 
396
 
 
397
        param_write_to_repr(svgd);
 
398
        signal_path_pasted.emit();
 
399
    }
 
400
}
 
401
 
 
402
void
 
403
PathParam::on_paste_button_click()
 
404
{
 
405
    Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
 
406
    Glib::ustring svgd = cm->getPathParameter();
 
407
    paste_param_path(svgd.data());
 
408
    sp_document_done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
 
409
                     _("Paste path parameter"));
 
410
}
 
411
 
 
412
void
 
413
PathParam::on_copy_button_click()
 
414
{
 
415
    Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
 
416
    cm->copyPathParameter(this);
 
417
}
 
418
 
 
419
void
 
420
PathParam::on_link_button_click()
 
421
{
 
422
    Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
 
423
    Glib::ustring pathid = cm->getShapeOrTextObjectId();
 
424
 
 
425
    if (pathid == "") {
 
426
        return;
 
427
    }
 
428
 
 
429
    // add '#' at start to make it an uri.
 
430
    pathid.insert(pathid.begin(), '#');
 
431
    if ( href && strcmp(pathid.c_str(), href) == 0 ) {
 
432
        // no change, do nothing
 
433
        return;
 
434
    } else {
 
435
        // TODO:
 
436
        // check if id really exists in document, or only in clipboard document: if only in clipboard then invalid
 
437
        // check if linking to object to which LPE is applied (maybe delegated to PathReference
 
438
 
 
439
        param_write_to_repr(pathid.c_str());
 
440
        sp_document_done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
 
441
                         _("Link path parameter to path"));
 
442
    }
 
443
}
 
444
 
 
445
} /* namespace LivePathEffect */
 
446
 
 
447
} /* namespace Inkscape */
 
448
 
 
449
/*
 
450
  Local Variables:
 
451
  mode:c++
 
452
  c-file-style:"stroustrup"
 
453
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
454
  indent-tabs-mode:nil
 
455
  fill-column:99
 
456
  End:
 
457
*/
 
458
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :