~ubuntu-branches/debian/experimental/inkscape/experimental

« back to all changes in this revision

Viewing changes to src/live_effects/effect.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-09-09 23:29:02 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20080909232902-c50iujhk1w79u8e7
Tags: 0.46-2.1
* Non-maintainer upload.
* Add upstream patch fixing a crash in the open dialog
  in the zh_CN.utf8 locale. Closes: #487623.
  Thanks to Luca Bruno for the patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define INKSCAPE_LIVEPATHEFFECT_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/effect.h"
 
10
 
 
11
#include "display/display-forward.h"
 
12
#include "xml/node-event-vector.h"
 
13
#include "sp-object.h"
 
14
#include "attributes.h"
 
15
#include "message-stack.h"
 
16
#include "desktop.h"
 
17
#include "inkscape.h"
 
18
#include "document.h"
 
19
#include <glibmm/i18n.h>
 
20
 
 
21
#include "live_effects/lpeobject.h"
 
22
#include "live_effects/parameter/parameter.h"
 
23
#include <glibmm/ustring.h>
 
24
#include "live_effects/n-art-bpath-2geom.h"
 
25
#include "display/curve.h"
 
26
#include <gtkmm.h>
 
27
 
 
28
#include <exception>
 
29
 
 
30
#include <2geom/sbasis-to-bezier.h>
 
31
#include <2geom/matrix.h>
 
32
 
 
33
 
 
34
// include effects:
 
35
#include "live_effects/lpe-skeletalstrokes.h"
 
36
#include "live_effects/lpe-pathalongpath.h"
 
37
#include "live_effects/lpe-slant.h"
 
38
#include "live_effects/lpe-test-doEffect-stack.h"
 
39
#include "live_effects/lpe-gears.h"
 
40
#include "live_effects/lpe-curvestitch.h"
 
41
 
 
42
#include "nodepath.h"
 
43
 
 
44
namespace Inkscape {
 
45
 
 
46
namespace LivePathEffect {
 
47
 
 
48
const Util::EnumData<EffectType> LPETypeData[INVALID_LPE] = {
 
49
    // {constant defined in effect.h, N_("name of your effect"), "name of your effect in SVG"}
 
50
    {PATH_ALONG_PATH,       N_("Bend Path"),             "bend_path"},
 
51
    {SKELETAL_STROKES,      N_("Pattern Along Path"),    "skeletal"},
 
52
#ifdef LPE_ENABLE_TEST_EFFECTS
 
53
    {SLANT,                 N_("Slant"),                 "slant"},
 
54
    {DOEFFECTSTACK_TEST,    N_("doEffect stack test"),   "doeffectstacktest"},
 
55
#endif
 
56
    {GEARS,                 N_("Gears"),                 "gears"},
 
57
    {CURVE_STITCH,          N_("Stitch Sub-Paths"),       "curvestitching"},
 
58
};
 
59
const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, INVALID_LPE);
 
60
 
 
61
Effect*
 
62
Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
 
63
{
 
64
    Effect* neweffect = NULL;
 
65
    switch (lpenr) {
 
66
        case SKELETAL_STROKES:
 
67
            neweffect = (Effect*) new LPESkeletalStrokes(lpeobj);
 
68
            break;
 
69
        case PATH_ALONG_PATH:
 
70
            neweffect = (Effect*) new LPEPathAlongPath(lpeobj);
 
71
            break;
 
72
#ifdef LPE_ENABLE_TEST_EFFECTS
 
73
            case SLANT:
 
74
            neweffect = (Effect*) new LPESlant(lpeobj);
 
75
            break;
 
76
        case DOEFFECTSTACK_TEST:
 
77
            neweffect = (Effect*) new LPEdoEffectStackTest(lpeobj);
 
78
            break;
 
79
#endif
 
80
        case GEARS:
 
81
            neweffect = (Effect*) new LPEGears(lpeobj);
 
82
            break;
 
83
        case CURVE_STITCH:
 
84
            neweffect = (Effect*) new LPECurveStitch(lpeobj);
 
85
            break;
 
86
        default:
 
87
            g_warning("LivePathEffect::Effect::New   called with invalid patheffect type (%d)", lpenr);
 
88
            neweffect = NULL;
 
89
            break;
 
90
    }
 
91
 
 
92
    if (neweffect) {
 
93
        neweffect->readallParameters(SP_OBJECT_REPR(lpeobj));
 
94
    }
 
95
 
 
96
    return neweffect;
 
97
}
 
98
 
 
99
Effect::Effect(LivePathEffectObject *lpeobject)
 
100
{
 
101
    lpeobj = lpeobject;
 
102
    oncanvasedit_it = 0;
 
103
}
 
104
 
 
105
Effect::~Effect()
 
106
{
 
107
}
 
108
 
 
109
Glib::ustring
 
110
Effect::getName()
 
111
{
 
112
    if (lpeobj->effecttype_set && lpeobj->effecttype < INVALID_LPE)
 
113
        return Glib::ustring( _(LPETypeConverter.get_label(lpeobj->effecttype).c_str()) );
 
114
    else
 
115
        return Glib::ustring( _("No effect") );
 
116
}
 
117
 
 
118
/*
 
119
 *  Here be the doEffect function chain:
 
120
 */
 
121
void
 
122
Effect::doEffect (SPCurve * curve)
 
123
{
 
124
    NArtBpath *new_bpath = doEffect_nartbpath(SP_CURVE_BPATH(curve));
 
125
 
 
126
    if (new_bpath && new_bpath != SP_CURVE_BPATH(curve)) {        // FIXME, add function to SPCurve to change bpath? or a copy function?
 
127
        if (curve->_bpath) {
 
128
            g_free(curve->_bpath); //delete old bpath
 
129
        }
 
130
        curve->_bpath = new_bpath;
 
131
    }
 
132
}
 
133
 
 
134
NArtBpath *
 
135
Effect::doEffect_nartbpath (NArtBpath * path_in)
 
136
{
 
137
    try {
 
138
        std::vector<Geom::Path> orig_pathv = BPath_to_2GeomPath(path_in);
 
139
 
 
140
        std::vector<Geom::Path> result_pathv = doEffect_path(orig_pathv);
 
141
 
 
142
        NArtBpath *new_bpath = BPath_from_2GeomPath(result_pathv);
 
143
 
 
144
        return new_bpath;
 
145
    }
 
146
    catch (std::exception & e) {
 
147
        g_warning("Exception during LPE %s execution. \n %s", getName().c_str(), e.what());
 
148
        SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE,
 
149
            _("An exception occurred during execution of the Path Effect.") );
 
150
 
 
151
        NArtBpath *path_out;
 
152
 
 
153
        unsigned ret = 0;
 
154
        while ( path_in[ret].code != NR_END ) {
 
155
            ++ret;
 
156
        }
 
157
        unsigned len = ++ret;
 
158
 
 
159
        path_out = g_new(NArtBpath, len);
 
160
        memcpy(path_out, path_in, len * sizeof(NArtBpath));
 
161
        return path_out;
 
162
    }
 
163
}
 
164
 
 
165
std::vector<Geom::Path>
 
166
Effect::doEffect_path (std::vector<Geom::Path> & path_in)
 
167
{
 
168
    Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in;
 
169
 
 
170
    for (unsigned int i=0; i < path_in.size(); i++) {
 
171
        pwd2_in.concat( path_in[i].toPwSb() );
 
172
    }
 
173
 
 
174
    Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
 
175
 
 
176
    std::vector<Geom::Path> path_out = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
 
177
 
 
178
    return path_out;
 
179
}
 
180
 
 
181
Geom::Piecewise<Geom::D2<Geom::SBasis> >
 
182
Effect::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in)
 
183
{
 
184
    g_warning("Effect has no doEffect implementation");
 
185
    return pwd2_in;
 
186
}
 
187
 
 
188
void
 
189
Effect::readallParameters(Inkscape::XML::Node * repr)
 
190
{
 
191
    std::vector<Parameter *>::iterator it = param_vector.begin();
 
192
    while (it != param_vector.end()) {
 
193
        Parameter * param = *it;
 
194
        const gchar * key = param->param_key.c_str();
 
195
        const gchar * value = repr->attribute(key);
 
196
        if (value) {
 
197
            bool accepted = param->param_readSVGValue(value);
 
198
            if (!accepted) { 
 
199
                g_warning("Effect::readallParameters - '%s' not accepted for %s", value, key);
 
200
            }
 
201
        } else {
 
202
            // set default value
 
203
            param->param_set_default();
 
204
        }
 
205
 
 
206
        it++;
 
207
    }
 
208
}
 
209
 
 
210
/* This function does not and SHOULD NOT write to XML */
 
211
void
 
212
Effect::setParameter(const gchar * key, const gchar * new_value)
 
213
{
 
214
    Parameter * param = getParameter(key);
 
215
    if (param) {
 
216
        if (new_value) {
 
217
            bool accepted = param->param_readSVGValue(new_value);
 
218
            if (!accepted) { 
 
219
                g_warning("Effect::setParameter - '%s' not accepted for %s", new_value, key);
 
220
            }
 
221
        } else {
 
222
            // set default value
 
223
            param->param_set_default();
 
224
        }
 
225
    }
 
226
}
 
227
 
 
228
void
 
229
Effect::registerParameter(Parameter * param)
 
230
{
 
231
    param_vector.push_back(param);
 
232
}
 
233
 
 
234
/**
 
235
* This *creates* a new widget, management of deletion should be done by the caller
 
236
*/
 
237
Gtk::Widget *
 
238
Effect::newWidget(Gtk::Tooltips * tooltips)
 
239
{
 
240
    // use manage here, because after deletion of Effect object, others might still be pointing to this widget.
 
241
    Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox() );
 
242
 
 
243
    vbox->set_border_width(5);
 
244
 
 
245
    std::vector<Parameter *>::iterator it = param_vector.begin();
 
246
    while (it != param_vector.end()) {
 
247
        Parameter * param = *it;
 
248
        Gtk::Widget * widg = param->param_newWidget(tooltips);
 
249
        Glib::ustring * tip = param->param_getTooltip();
 
250
        if (widg) {
 
251
           vbox->pack_start(*widg, true, true, 2);
 
252
            if (tip != NULL) {
 
253
                tooltips->set_tip(*widg, *tip);
 
254
            }
 
255
        }
 
256
 
 
257
        it++;
 
258
    }
 
259
 
 
260
    return dynamic_cast<Gtk::Widget *>(vbox);
 
261
}
 
262
 
 
263
 
 
264
Inkscape::XML::Node *
 
265
Effect::getRepr()
 
266
{
 
267
    return SP_OBJECT_REPR(lpeobj);
 
268
}
 
269
 
 
270
SPDocument *
 
271
Effect::getSPDoc()
 
272
{
 
273
    if (SP_OBJECT_DOCUMENT(lpeobj) == NULL) g_message("Effect::getSPDoc() returns NULL");
 
274
    return SP_OBJECT_DOCUMENT(lpeobj);
 
275
}
 
276
 
 
277
Parameter *
 
278
Effect::getParameter(const char * key)
 
279
{
 
280
    Glib::ustring stringkey(key);
 
281
 
 
282
    std::vector<Parameter *>::iterator it = param_vector.begin();
 
283
    while (it != param_vector.end()) {
 
284
        Parameter * param = *it;
 
285
        if ( param->param_key == key) {
 
286
            return param;
 
287
        }
 
288
 
 
289
        it++;
 
290
    }
 
291
 
 
292
    return NULL;
 
293
}
 
294
 
 
295
Parameter *
 
296
Effect::getNextOncanvasEditableParam()
 
297
{
 
298
    oncanvasedit_it++;
 
299
    if (oncanvasedit_it == static_cast<int>(param_vector.size())) {
 
300
        oncanvasedit_it = 0;
 
301
    }
 
302
    int old_it = oncanvasedit_it;
 
303
 
 
304
    do {
 
305
        Parameter * param = param_vector[oncanvasedit_it];
 
306
        if(param && param->oncanvas_editable) {
 
307
            return param;
 
308
        } else {
 
309
            oncanvasedit_it++;
 
310
            if (oncanvasedit_it == static_cast<int>(param_vector.size())) {  // loop round the map
 
311
                oncanvasedit_it = 0;
 
312
            }
 
313
        }
 
314
    } while (oncanvasedit_it != old_it); // iterate until complete loop through map has been made
 
315
 
 
316
    return NULL;
 
317
}
 
318
 
 
319
void
 
320
Effect::editNextParamOncanvas(SPItem * item, SPDesktop * desktop)
 
321
{
 
322
    if (!desktop) return;
 
323
 
 
324
    Parameter * param = getNextOncanvasEditableParam();
 
325
    if (param) {
 
326
        param->param_editOncanvas(item, desktop);
 
327
        gchar *message = g_strdup_printf(_("Editing parameter <b>%s</b>."), param->param_label.c_str());
 
328
        desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, message);
 
329
        g_free(message);
 
330
    } else {
 
331
        desktop->messageStack()->flash( Inkscape::WARNING_MESSAGE,
 
332
                                        _("None of the applied path effect's parameters can be edited on-canvas.") );
 
333
    }
 
334
}
 
335
 
 
336
/* This function should reset the defaults and is used for example to initialize an effect right after it has been applied to a path
 
337
* The nice thing about this is that this function can use knowledge of the original path and set things accordingly for example to the size or origin of the original path!
 
338
*/
 
339
void
 
340
Effect::resetDefaults(SPItem * /*item*/)
 
341
{
 
342
    // do nothing for simple effects
 
343
}
 
344
 
 
345
void
 
346
Effect::setup_nodepath(Inkscape::NodePath::Path *np)
 
347
{
 
348
    np->show_helperpath = true;
 
349
    np->helperpath_rgba = 0xff0000ff;
 
350
    np->helperpath_width = 1.0;
 
351
}
 
352
 
 
353
void
 
354
Effect::transform_multiply(Geom::Matrix const& postmul, bool set)
 
355
{
 
356
    // cycle through all parameters. Most parameters will not need transformation, but path and point params do.
 
357
    for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); it++) {
 
358
        Parameter * param = *it;
 
359
        param->param_transform_multiply(postmul, set);
 
360
    }
 
361
}
 
362
 
 
363
} /* namespace LivePathEffect */
 
364
 
 
365
} /* namespace Inkscape */
 
366
 
 
367
/*
 
368
  Local Variables:
 
369
  mode:c++
 
370
  c-file-style:"stroustrup"
 
371
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
372
  indent-tabs-mode:nil
 
373
  fill-column:99
 
374
  End:
 
375
*/
 
376
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :