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

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/sp-guide.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 __SP_GUIDE_C__
 
2
 
 
3
/*
 
4
 * Inkscape guideline implementation
 
5
 *
 
6
 * Authors:
 
7
 *   Lauris Kaplinski <lauris@kaplinski.com>
 
8
 *   Peter Moulder <pmoulder@mail.csse.monash.edu.au>
 
9
 *   Johan Engelen
 
10
 *
 
11
 * Copyright (C) 2000-2002 authors
 
12
 * Copyright (C) 2004 Monash University
 
13
 * Copyright (C) 2007 Johan Engelen
 
14
 *
 
15
 * Released under GNU GPL, read the file 'COPYING' for more information
 
16
 */
 
17
 
 
18
#ifdef HAVE_CONFIG_H
 
19
# include <config.h>
 
20
#endif
 
21
 
 
22
#include <algorithm>
 
23
#include <cstring>
 
24
#include <string>
 
25
#include "desktop-handles.h"
 
26
#include "display/guideline.h"
 
27
#include "svg/svg.h"
 
28
#include "svg/stringstream.h"
 
29
#include "attributes.h"
 
30
#include "sp-guide.h"
 
31
#include <sp-item-notify-moveto.h>
 
32
#include <sp-item.h>
 
33
#include <sp-guide-constraint.h>
 
34
#include <glibmm/i18n.h>
 
35
#include <xml/repr.h>
 
36
#include <remove-last.h>
 
37
#include "sp-metrics.h"
 
38
#include "inkscape.h"
 
39
#include "desktop.h"
 
40
#include "sp-namedview.h"
 
41
#include <2geom/angle.h>
 
42
#include "document.h"
 
43
 
 
44
using std::vector;
 
45
 
 
46
enum {
 
47
    PROP_0,
 
48
    PROP_COLOR,
 
49
    PROP_HICOLOR
 
50
};
 
51
 
 
52
static void sp_guide_class_init(SPGuideClass *gc);
 
53
static void sp_guide_init(SPGuide *guide);
 
54
static void sp_guide_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
 
55
static void sp_guide_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
 
56
 
 
57
static void sp_guide_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
 
58
static void sp_guide_release(SPObject *object);
 
59
static void sp_guide_set(SPObject *object, unsigned int key, const gchar *value);
 
60
 
 
61
static SPObjectClass *parent_class;
 
62
 
 
63
GType sp_guide_get_type(void)
 
64
{
 
65
    static GType guide_type = 0;
 
66
 
 
67
    if (!guide_type) {
 
68
        GTypeInfo guide_info = {
 
69
            sizeof(SPGuideClass),
 
70
            NULL, NULL,
 
71
            (GClassInitFunc) sp_guide_class_init,
 
72
            NULL, NULL,
 
73
            sizeof(SPGuide),
 
74
            16,
 
75
            (GInstanceInitFunc) sp_guide_init,
 
76
            NULL,       /* value_table */
 
77
        };
 
78
        guide_type = g_type_register_static(SP_TYPE_OBJECT, "SPGuide", &guide_info, (GTypeFlags) 0);
 
79
    }
 
80
 
 
81
    return guide_type;
 
82
}
 
83
 
 
84
static void sp_guide_class_init(SPGuideClass *gc)
 
85
{
 
86
    GObjectClass *gobject_class = (GObjectClass *) gc;
 
87
    SPObjectClass *sp_object_class = (SPObjectClass *) gc;
 
88
 
 
89
    parent_class = (SPObjectClass*) g_type_class_ref(SP_TYPE_OBJECT);
 
90
 
 
91
    gobject_class->set_property = sp_guide_set_property;
 
92
    gobject_class->get_property = sp_guide_get_property;
 
93
 
 
94
    sp_object_class->build = sp_guide_build;
 
95
    sp_object_class->release = sp_guide_release;
 
96
    sp_object_class->set = sp_guide_set;
 
97
 
 
98
    g_object_class_install_property(gobject_class,
 
99
                                    PROP_COLOR,
 
100
                                    g_param_spec_uint("color", "Color", "Color",
 
101
                                                      0,
 
102
                                                      0xffffffff,
 
103
                                                      0xff000000,
 
104
                                                      (GParamFlags) G_PARAM_READWRITE));
 
105
 
 
106
    g_object_class_install_property(gobject_class,
 
107
                                    PROP_HICOLOR,
 
108
                                    g_param_spec_uint("hicolor", "HiColor", "HiColor",
 
109
                                                      0,
 
110
                                                      0xffffffff,
 
111
                                                      0xff000000,
 
112
                                                      (GParamFlags) G_PARAM_READWRITE));
 
113
}
 
114
 
 
115
static void sp_guide_init(SPGuide *guide)
 
116
{
 
117
    guide->normal_to_line = component_vectors[Geom::Y];
 
118
    guide->point_on_line = Geom::Point(0.,0.);
 
119
    guide->color = 0x0000ff7f;
 
120
    guide->hicolor = 0xff00007f;
 
121
}
 
122
 
 
123
static void sp_guide_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec */*pspec*/)
 
124
{
 
125
    SPGuide &guide = *SP_GUIDE(object);
 
126
 
 
127
    switch (prop_id) {
 
128
        case PROP_COLOR:
 
129
            guide.color = g_value_get_uint(value);
 
130
            for (GSList *l = guide.views; l != NULL; l = l->next) {
 
131
                sp_guideline_set_color(SP_GUIDELINE(l->data), guide.color);
 
132
            }
 
133
            break;
 
134
 
 
135
        case PROP_HICOLOR:
 
136
            guide.hicolor = g_value_get_uint(value);
 
137
            break;
 
138
    }
 
139
}
 
140
 
 
141
static void sp_guide_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec */*pspec*/)
 
142
{
 
143
    SPGuide const &guide = *SP_GUIDE(object);
 
144
 
 
145
    switch (prop_id) {
 
146
        case PROP_COLOR:
 
147
            g_value_set_uint(value, guide.color);
 
148
            break;
 
149
        case PROP_HICOLOR:
 
150
            g_value_set_uint(value, guide.hicolor);
 
151
            break;
 
152
    }
 
153
}
 
154
 
 
155
static void sp_guide_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
 
156
{
 
157
    if (((SPObjectClass *) (parent_class))->build) {
 
158
        (* ((SPObjectClass *) (parent_class))->build)(object, document, repr);
 
159
    }
 
160
 
 
161
    sp_object_read_attr(object, "orientation");
 
162
    sp_object_read_attr(object, "position");
 
163
}
 
164
 
 
165
static void sp_guide_release(SPObject *object)
 
166
{
 
167
    SPGuide *guide = (SPGuide *) object;
 
168
 
 
169
    while (guide->views) {
 
170
        sp_guideline_delete(SP_GUIDELINE(guide->views->data));
 
171
        guide->views = g_slist_remove(guide->views, guide->views->data);
 
172
    }
 
173
 
 
174
    if (((SPObjectClass *) parent_class)->release) {
 
175
        ((SPObjectClass *) parent_class)->release(object);
 
176
    }
 
177
}
 
178
 
 
179
static void sp_guide_set(SPObject *object, unsigned int key, const gchar *value)
 
180
{
 
181
    SPGuide *guide = SP_GUIDE(object);
 
182
 
 
183
    switch (key) {
 
184
    case SP_ATTR_ORIENTATION:
 
185
        {
 
186
            if (value && !strcmp(value, "horizontal")) {
 
187
                /* Visual representation of a horizontal line, constrain vertically (y coordinate). */
 
188
                guide->normal_to_line = component_vectors[Geom::Y];
 
189
            } else if (value && !strcmp(value, "vertical")) {
 
190
                guide->normal_to_line = component_vectors[Geom::X];
 
191
            } else if (value) {
 
192
                gchar ** strarray = g_strsplit(value, ",", 2);
 
193
                double newx, newy;
 
194
                unsigned int success = sp_svg_number_read_d(strarray[0], &newx);
 
195
                success += sp_svg_number_read_d(strarray[1], &newy);
 
196
                g_strfreev (strarray);
 
197
                if (success == 2 && (fabs(newx) > 1e-6 || fabs(newy) > 1e-6)) {
 
198
                    Geom::Point direction(newx, newy);
 
199
                    direction.normalize();
 
200
                    guide->normal_to_line = direction;
 
201
                } else {
 
202
                    // default to vertical line for bad arguments
 
203
                    guide->normal_to_line = component_vectors[Geom::X];
 
204
                }
 
205
            } else {
 
206
                // default to vertical line for bad arguments
 
207
                guide->normal_to_line = component_vectors[Geom::X];
 
208
            }
 
209
            sp_guide_set_normal(*guide, guide->normal_to_line, false);
 
210
        }
 
211
        break;
 
212
    case SP_ATTR_POSITION:
 
213
        {
 
214
            gchar ** strarray = g_strsplit(value, ",", 2);
 
215
            double newx, newy;
 
216
            unsigned int success = sp_svg_number_read_d(strarray[0], &newx);
 
217
            success += sp_svg_number_read_d(strarray[1], &newy);
 
218
            g_strfreev (strarray);
 
219
            if (success == 2) {
 
220
                guide->point_on_line = Geom::Point(newx, newy);
 
221
            } else if (success == 1) {
 
222
                // before 0.46 style guideline definition.
 
223
                const gchar *attr = SP_OBJECT_REPR(object)->attribute("orientation");
 
224
                if (attr && !strcmp(attr, "horizontal")) {
 
225
                    guide->point_on_line = Geom::Point(0, newx);
 
226
                } else {
 
227
                    guide->point_on_line = Geom::Point(newx, 0);
 
228
                }
 
229
            }
 
230
 
 
231
            // update position in non-committing way
 
232
            // fixme: perhaps we need to add an update method instead, and request_update here
 
233
            sp_guide_moveto(*guide, guide->point_on_line, false);
 
234
        }
 
235
        break;
 
236
    default:
 
237
            if (((SPObjectClass *) (parent_class))->set) {
 
238
                ((SPObjectClass *) (parent_class))->set(object, key, value);
 
239
            }
 
240
            break;
 
241
    }
 
242
}
 
243
 
 
244
SPGuide *
 
245
sp_guide_create(SPDesktop *desktop, Geom::Point const &pt1, Geom::Point const &pt2) {
 
246
    SPDocument *doc=sp_desktop_document(desktop);
 
247
    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
 
248
 
 
249
    Inkscape::XML::Node *repr = xml_doc->createElement("sodipodi:guide");
 
250
 
 
251
    Geom::Point n = Geom::rot90(pt2 - pt1);
 
252
 
 
253
    sp_repr_set_point(repr, "position", pt1);
 
254
    sp_repr_set_point(repr, "orientation", n);
 
255
 
 
256
    SP_OBJECT_REPR(desktop->namedview)->appendChild(repr);
 
257
    Inkscape::GC::release(repr);
 
258
 
 
259
    SPGuide *guide= SP_GUIDE(doc->getObjectByRepr(repr));
 
260
    return guide;
 
261
}
 
262
 
 
263
void
 
264
sp_guide_pt_pairs_to_guides(SPDesktop *dt, std::list<std::pair<Geom::Point, Geom::Point> > &pts) {
 
265
    for (std::list<std::pair<Geom::Point, Geom::Point> >::iterator i = pts.begin(); i != pts.end(); ++i) {
 
266
        sp_guide_create(dt, (*i).first, (*i).second);
 
267
    }
 
268
}
 
269
 
 
270
void
 
271
sp_guide_create_guides_around_page(SPDesktop *dt) {
 
272
    SPDocument *doc=sp_desktop_document(dt);
 
273
    std::list<std::pair<Geom::Point, Geom::Point> > pts;
 
274
 
 
275
    Geom::Point A(0, 0);
 
276
    Geom::Point C(sp_document_width(doc), sp_document_height(doc));
 
277
    Geom::Point B(C[Geom::X], 0);
 
278
    Geom::Point D(0, C[Geom::Y]);
 
279
 
 
280
    pts.push_back(std::make_pair<Geom::Point, Geom::Point>(A, B));
 
281
    pts.push_back(std::make_pair<Geom::Point, Geom::Point>(B, C));
 
282
    pts.push_back(std::make_pair<Geom::Point, Geom::Point>(C, D));
 
283
    pts.push_back(std::make_pair<Geom::Point, Geom::Point>(D, A));
 
284
 
 
285
    sp_guide_pt_pairs_to_guides(dt, pts);
 
286
 
 
287
    sp_document_done (doc, SP_VERB_NONE, _("Guides Around Page"));
 
288
}
 
289
 
 
290
void sp_guide_show(SPGuide *guide, SPCanvasGroup *group, GCallback handler)
 
291
{
 
292
    SPCanvasItem *item = sp_guideline_new(group, guide->point_on_line, guide->normal_to_line);
 
293
    sp_guideline_set_color(SP_GUIDELINE(item), guide->color);
 
294
 
 
295
    g_signal_connect(G_OBJECT(item), "event", G_CALLBACK(handler), guide);
 
296
 
 
297
    guide->views = g_slist_prepend(guide->views, item);
 
298
}
 
299
 
 
300
void sp_guide_hide(SPGuide *guide, SPCanvas *canvas)
 
301
{
 
302
    g_assert(guide != NULL);
 
303
    g_assert(SP_IS_GUIDE(guide));
 
304
    g_assert(canvas != NULL);
 
305
    g_assert(SP_IS_CANVAS(canvas));
 
306
 
 
307
    for (GSList *l = guide->views; l != NULL; l = l->next) {
 
308
        if (canvas == SP_CANVAS_ITEM(l->data)->canvas) {
 
309
            sp_guideline_delete(SP_GUIDELINE(l->data));
 
310
            guide->views = g_slist_remove(guide->views, l->data);
 
311
            return;
 
312
        }
 
313
    }
 
314
 
 
315
    g_assert_not_reached();
 
316
}
 
317
 
 
318
void sp_guide_sensitize(SPGuide *guide, SPCanvas *canvas, gboolean sensitive)
 
319
{
 
320
    g_assert(guide != NULL);
 
321
    g_assert(SP_IS_GUIDE(guide));
 
322
    g_assert(canvas != NULL);
 
323
    g_assert(SP_IS_CANVAS(canvas));
 
324
 
 
325
    for (GSList *l = guide->views; l != NULL; l = l->next) {
 
326
        if (canvas == SP_CANVAS_ITEM(l->data)->canvas) {
 
327
            sp_guideline_set_sensitive(SP_GUIDELINE(l->data), sensitive);
 
328
            return;
 
329
        }
 
330
    }
 
331
 
 
332
    g_assert_not_reached();
 
333
}
 
334
 
 
335
Geom::Point sp_guide_position_from_pt(SPGuide const *guide, Geom::Point const &pt)
 
336
{
 
337
    return -(pt - guide->point_on_line);
 
338
}
 
339
 
 
340
double sp_guide_distance_from_pt(SPGuide const *guide, Geom::Point const &pt)
 
341
{
 
342
    return Geom::dot(pt - guide->point_on_line, guide->normal_to_line);
 
343
}
 
344
 
 
345
/**
 
346
 * \arg commit False indicates temporary moveto in response to motion event while dragging,
 
347
 *      true indicates a "committing" version: in response to button release event after
 
348
 *      dragging a guideline, or clicking OK in guide editing dialog.
 
349
 */
 
350
void sp_guide_moveto(SPGuide const &guide, Geom::Point const point_on_line, bool const commit)
 
351
{
 
352
    g_assert(SP_IS_GUIDE(&guide));
 
353
 
 
354
    for (GSList *l = guide.views; l != NULL; l = l->next) {
 
355
        sp_guideline_set_position(SP_GUIDELINE(l->data), point_on_line);
 
356
    }
 
357
 
 
358
    /* Calling sp_repr_set_point must precede calling sp_item_notify_moveto in the commit
 
359
       case, so that the guide's new position is available for sp_item_rm_unsatisfied_cns. */
 
360
    if (commit) {
 
361
        sp_repr_set_point(SP_OBJECT(&guide)->repr, "position", point_on_line);
 
362
    }
 
363
 
 
364
/*  DISABLED CODE BECAUSE  SPGuideAttachment  IS NOT USE AT THE MOMENT (johan)
 
365
    for (vector<SPGuideAttachment>::const_iterator i(guide.attached_items.begin()),
 
366
             iEnd(guide.attached_items.end());
 
367
         i != iEnd; ++i)
 
368
    {
 
369
        SPGuideAttachment const &att = *i;
 
370
        sp_item_notify_moveto(*att.item, guide, att.snappoint_ix, position, commit);
 
371
    }
 
372
*/
 
373
}
 
374
 
 
375
/**
 
376
 * \arg commit False indicates temporary moveto in response to motion event while dragging,
 
377
 *      true indicates a "committing" version: in response to button release event after
 
378
 *      dragging a guideline, or clicking OK in guide editing dialog.
 
379
 */
 
380
void sp_guide_set_normal(SPGuide const &guide, Geom::Point const normal_to_line, bool const commit)
 
381
{
 
382
    g_assert(SP_IS_GUIDE(&guide));
 
383
 
 
384
    for (GSList *l = guide.views; l != NULL; l = l->next) {
 
385
        sp_guideline_set_normal(SP_GUIDELINE(l->data), normal_to_line);
 
386
    }
 
387
 
 
388
    /* Calling sp_repr_set_svg_point must precede calling sp_item_notify_moveto in the commit
 
389
       case, so that the guide's new position is available for sp_item_rm_unsatisfied_cns. */
 
390
    if (commit) {
 
391
        sp_repr_set_point(SP_OBJECT(&guide)->repr, "orientation", normal_to_line);
 
392
    }
 
393
 
 
394
/*  DISABLED CODE BECAUSE  SPGuideAttachment  IS NOT USE AT THE MOMENT (johan)
 
395
    for (vector<SPGuideAttachment>::const_iterator i(guide.attached_items.begin()),
 
396
             iEnd(guide.attached_items.end());
 
397
         i != iEnd; ++i)
 
398
    {
 
399
        SPGuideAttachment const &att = *i;
 
400
        sp_item_notify_moveto(*att.item, guide, att.snappoint_ix, position, commit);
 
401
    }
 
402
*/
 
403
}
 
404
 
 
405
/**
 
406
 * Returns a human-readable description of the guideline for use in dialog boxes and status bar.
 
407
 *
 
408
 * The caller is responsible for freeing the string.
 
409
 */
 
410
char *sp_guide_description(SPGuide const *guide)
 
411
{
 
412
    using Geom::X;
 
413
    using Geom::Y;
 
414
            
 
415
    GString *position_string_x = SP_PX_TO_METRIC_STRING(guide->point_on_line[X], SP_ACTIVE_DESKTOP->namedview->getDefaultMetric());
 
416
    GString *position_string_y = SP_PX_TO_METRIC_STRING(guide->point_on_line[Y], SP_ACTIVE_DESKTOP->namedview->getDefaultMetric());
 
417
 
 
418
    const gchar *shortcuts = _("<b>drag</b> to move, <b>Shift+drag</b> to rotate, <b>Ctrl</b>+click to delete");
 
419
 
 
420
    if ( are_near(guide->normal_to_line, component_vectors[X]) ||
 
421
         are_near(guide->normal_to_line, -component_vectors[X]) ) {
 
422
        return g_strdup_printf(_("vertical, at %s; %s"), position_string_x->str, shortcuts);
 
423
    } else if ( are_near(guide->normal_to_line, component_vectors[Y]) ||
 
424
                are_near(guide->normal_to_line, -component_vectors[Y]) ) {
 
425
        return g_strdup_printf(_("horizontal, at %s; %s"), position_string_y->str, shortcuts);
 
426
    } else {
 
427
        double const radians = guide->angle();
 
428
        double const degrees = Geom::rad_to_deg(radians);
 
429
        int const degrees_int = (int) round(degrees);
 
430
        return g_strdup_printf(_("at %d degrees, through (%s,%s); %s"), 
 
431
                               degrees_int, position_string_x->str, position_string_y->str, shortcuts);
 
432
    }
 
433
 
 
434
    g_string_free(position_string_x, TRUE);
 
435
    g_string_free(position_string_y, TRUE);
 
436
}
 
437
 
 
438
void sp_guide_remove(SPGuide *guide)
 
439
{
 
440
    g_assert(SP_IS_GUIDE(guide));
 
441
 
 
442
    for (vector<SPGuideAttachment>::const_iterator i(guide->attached_items.begin()),
 
443
             iEnd(guide->attached_items.end());
 
444
         i != iEnd; ++i)
 
445
    {
 
446
        SPGuideAttachment const &att = *i;
 
447
        remove_last(att.item->constraints, SPGuideConstraint(guide, att.snappoint_ix));
 
448
    }
 
449
    guide->attached_items.clear();
 
450
 
 
451
    sp_repr_unparent(SP_OBJECT(guide)->repr);
 
452
}
 
453
 
 
454
/*
 
455
  Local Variables:
 
456
  mode:c++
 
457
  c-file-style:"stroustrup"
 
458
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
459
  indent-tabs-mode:nil
 
460
  fill-column:99
 
461
  End:
 
462
*/
 
463
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :