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

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/sp-rect.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
/*
 
2
 * SVG <rect> implementation
 
3
 *
 
4
 * Authors:
 
5
 *   Lauris Kaplinski <lauris@kaplinski.com>
 
6
 *   bulia byak <buliabyak@users.sf.net>
 
7
 *
 
8
 * Copyright (C) 1999-2002 Lauris Kaplinski
 
9
 * Copyright (C) 2000-2001 Ximian, Inc.
 
10
 *
 
11
 * Released under GNU GPL, read the file 'COPYING' for more information
 
12
 */
 
13
 
 
14
#ifdef HAVE_CONFIG_H
 
15
# include "config.h"
 
16
#endif
 
17
 
 
18
 
 
19
#include <display/curve.h>
 
20
#include <libnr/nr-matrix-ops.h>
 
21
#include <libnr/nr-matrix-fns.h>
 
22
#include <2geom/rect.h>
 
23
 
 
24
#include "inkscape.h"
 
25
#include "document.h"
 
26
#include "attributes.h"
 
27
#include "style.h"
 
28
#include "sp-rect.h"
 
29
#include <glibmm/i18n.h>
 
30
#include "xml/repr.h"
 
31
#include "sp-guide.h"
 
32
#include "preferences.h"
 
33
 
 
34
#define noRECT_VERBOSE
 
35
 
 
36
static void sp_rect_class_init(SPRectClass *klass);
 
37
static void sp_rect_init(SPRect *rect);
 
38
 
 
39
static void sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
 
40
static void sp_rect_set(SPObject *object, unsigned key, gchar const *value);
 
41
static void sp_rect_update(SPObject *object, SPCtx *ctx, guint flags);
 
42
static Inkscape::XML::Node *sp_rect_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
 
43
 
 
44
static gchar *sp_rect_description(SPItem *item);
 
45
static Geom::Matrix sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform);
 
46
static void sp_rect_convert_to_guides(SPItem *item);
 
47
 
 
48
static void sp_rect_set_shape(SPShape *shape);
 
49
static void sp_rect_snappoints(SPItem const *item, bool const target, SnapPointsWithType &p, Inkscape::SnapPreferences const *snapprefs);
 
50
 
 
51
static SPShapeClass *parent_class;
 
52
 
 
53
GType
 
54
sp_rect_get_type(void)
 
55
{
 
56
    static GType type = 0;
 
57
 
 
58
    if (!type) {
 
59
        GTypeInfo info = {
 
60
            sizeof(SPRectClass),
 
61
            NULL,   /* base_init */
 
62
            NULL,   /* base_finalize */
 
63
            (GClassInitFunc) sp_rect_class_init,
 
64
            NULL,   /* class_finalize */
 
65
            NULL,   /* class_data */
 
66
            sizeof(SPRect),
 
67
            16,     /* n_preallocs */
 
68
            (GInstanceInitFunc) sp_rect_init,
 
69
            NULL,   /* value_table */
 
70
        };
 
71
        type = g_type_register_static(SP_TYPE_SHAPE, "SPRect", &info, (GTypeFlags)0);
 
72
    }
 
73
    return type;
 
74
}
 
75
 
 
76
static void
 
77
sp_rect_class_init(SPRectClass *klass)
 
78
{
 
79
    SPObjectClass *sp_object_class = (SPObjectClass *) klass;
 
80
    SPItemClass *item_class = (SPItemClass *) klass;
 
81
    SPShapeClass *shape_class = (SPShapeClass *) klass;
 
82
 
 
83
    parent_class = (SPShapeClass *)g_type_class_ref(SP_TYPE_SHAPE);
 
84
 
 
85
    sp_object_class->build = sp_rect_build;
 
86
    sp_object_class->write = sp_rect_write;
 
87
    sp_object_class->set = sp_rect_set;
 
88
    sp_object_class->update = sp_rect_update;
 
89
 
 
90
    item_class->description = sp_rect_description;
 
91
    item_class->set_transform = sp_rect_set_transform;
 
92
    item_class->convert_to_guides = sp_rect_convert_to_guides;
 
93
    item_class->snappoints = sp_rect_snappoints; //override the default sp_shape_snappoints; see sp_rect_snappoints for details
 
94
 
 
95
    shape_class->set_shape = sp_rect_set_shape;
 
96
}
 
97
 
 
98
static void
 
99
sp_rect_init(SPRect */*rect*/)
 
100
{
 
101
    /* Initializing to zero is automatic */
 
102
    /* sp_svg_length_unset(&rect->x, SP_SVG_UNIT_NONE, 0.0, 0.0); */
 
103
    /* sp_svg_length_unset(&rect->y, SP_SVG_UNIT_NONE, 0.0, 0.0); */
 
104
    /* sp_svg_length_unset(&rect->width, SP_SVG_UNIT_NONE, 0.0, 0.0); */
 
105
    /* sp_svg_length_unset(&rect->height, SP_SVG_UNIT_NONE, 0.0, 0.0); */
 
106
    /* sp_svg_length_unset(&rect->rx, SP_SVG_UNIT_NONE, 0.0, 0.0); */
 
107
    /* sp_svg_length_unset(&rect->ry, SP_SVG_UNIT_NONE, 0.0, 0.0); */
 
108
}
 
109
 
 
110
static void
 
111
sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
 
112
{
 
113
    if (((SPObjectClass *) parent_class)->build)
 
114
        ((SPObjectClass *) parent_class)->build(object, document, repr);
 
115
 
 
116
    sp_object_read_attr(object, "x");
 
117
    sp_object_read_attr(object, "y");
 
118
    sp_object_read_attr(object, "width");
 
119
    sp_object_read_attr(object, "height");
 
120
    sp_object_read_attr(object, "rx");
 
121
    sp_object_read_attr(object, "ry");
 
122
}
 
123
 
 
124
static void
 
125
sp_rect_set(SPObject *object, unsigned key, gchar const *value)
 
126
{
 
127
    SPRect *rect = SP_RECT(object);
 
128
 
 
129
    /* fixme: We need real error processing some time */
 
130
 
 
131
    switch (key) {
 
132
        case SP_ATTR_X:
 
133
            rect->x.readOrUnset(value);
 
134
            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
135
            break;
 
136
        case SP_ATTR_Y:
 
137
            rect->y.readOrUnset(value);
 
138
            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
139
            break;
 
140
        case SP_ATTR_WIDTH:
 
141
            if (!rect->width.read(value) || rect->width.value < 0.0) {
 
142
                rect->width.unset();
 
143
            }
 
144
            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
145
            break;
 
146
        case SP_ATTR_HEIGHT:
 
147
            if (!rect->height.read(value) || rect->height.value < 0.0) {
 
148
                rect->height.unset();
 
149
            }
 
150
            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
151
            break;
 
152
        case SP_ATTR_RX:
 
153
            if (!rect->rx.read(value) || rect->rx.value < 0.0) {
 
154
                rect->rx.unset();
 
155
            }
 
156
            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
157
            break;
 
158
        case SP_ATTR_RY:
 
159
            if (!rect->ry.read(value) || rect->ry.value < 0.0) {
 
160
                rect->ry.unset();
 
161
            }
 
162
            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
163
            break;
 
164
        default:
 
165
            if (((SPObjectClass *) parent_class)->set)
 
166
                ((SPObjectClass *) parent_class)->set(object, key, value);
 
167
            break;
 
168
    }
 
169
}
 
170
 
 
171
static void
 
172
sp_rect_update(SPObject *object, SPCtx *ctx, guint flags)
 
173
{
 
174
    if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
 
175
        SPRect *rect = (SPRect *) object;
 
176
        SPStyle *style = object->style;
 
177
        SPItemCtx const *ictx = (SPItemCtx const *) ctx;
 
178
        double const w = (ictx->vp.x1 - ictx->vp.x0);
 
179
        double const h = (ictx->vp.y1 - ictx->vp.y0);
 
180
        double const em = style->font_size.computed;
 
181
        double const ex = 0.5 * em;  // fixme: get x height from pango or libnrtype.
 
182
        rect->x.update(em, ex, w);
 
183
        rect->y.update(em, ex, h);
 
184
        rect->width.update(em, ex, w);
 
185
        rect->height.update(em, ex, h);
 
186
        rect->rx.update(em, ex, w);
 
187
        rect->ry.update(em, ex, h);
 
188
        sp_shape_set_shape((SPShape *) object);
 
189
        flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore
 
190
    }
 
191
 
 
192
    if (((SPObjectClass *) parent_class)->update)
 
193
        ((SPObjectClass *) parent_class)->update(object, ctx, flags);
 
194
}
 
195
 
 
196
static Inkscape::XML::Node *
 
197
sp_rect_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
 
198
{
 
199
    SPRect *rect = SP_RECT(object);
 
200
 
 
201
    if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
 
202
        repr = xml_doc->createElement("svg:rect");
 
203
    }
 
204
 
 
205
    sp_repr_set_svg_double(repr, "width", rect->width.computed);
 
206
    sp_repr_set_svg_double(repr, "height", rect->height.computed);
 
207
    if (rect->rx._set) sp_repr_set_svg_double(repr, "rx", rect->rx.computed);
 
208
    if (rect->ry._set) sp_repr_set_svg_double(repr, "ry", rect->ry.computed);
 
209
    sp_repr_set_svg_double(repr, "x", rect->x.computed);
 
210
    sp_repr_set_svg_double(repr, "y", rect->y.computed);
 
211
 
 
212
    if (((SPObjectClass *) parent_class)->write)
 
213
        ((SPObjectClass *) parent_class)->write(object, xml_doc, repr, flags);
 
214
 
 
215
    return repr;
 
216
}
 
217
 
 
218
static gchar *
 
219
sp_rect_description(SPItem *item)
 
220
{
 
221
    g_return_val_if_fail(SP_IS_RECT(item), NULL);
 
222
 
 
223
    return g_strdup(_("<b>Rectangle</b>"));
 
224
}
 
225
 
 
226
#define C1 0.554
 
227
 
 
228
static void
 
229
sp_rect_set_shape(SPShape *shape)
 
230
{
 
231
    SPRect *rect = (SPRect *) shape;
 
232
 
 
233
    if ((rect->height.computed < 1e-18) || (rect->width.computed < 1e-18)) {
 
234
        sp_shape_set_curve_insync(SP_SHAPE(rect), NULL, TRUE);
 
235
        return;
 
236
    }
 
237
 
 
238
    SPCurve *c = new SPCurve();
 
239
 
 
240
    double const x = rect->x.computed;
 
241
    double const y = rect->y.computed;
 
242
    double const w = rect->width.computed;
 
243
    double const h = rect->height.computed;
 
244
    double const w2 = w / 2;
 
245
    double const h2 = h / 2;
 
246
    double const rx = std::min(( rect->rx._set
 
247
                                 ? rect->rx.computed
 
248
                                 : ( rect->ry._set
 
249
                                     ? rect->ry.computed
 
250
                                     : 0.0 ) ),
 
251
                               .5 * rect->width.computed);
 
252
    double const ry = std::min(( rect->ry._set
 
253
                                 ? rect->ry.computed
 
254
                                 : ( rect->rx._set
 
255
                                     ? rect->rx.computed
 
256
                                     : 0.0 ) ),
 
257
                               .5 * rect->height.computed);
 
258
    /* TODO: Handle negative rx or ry as per
 
259
     * http://www.w3.org/TR/SVG11/shapes.html#RectElementRXAttribute once Inkscape has proper error
 
260
     * handling (see http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing).
 
261
     */
 
262
 
 
263
    /* We don't use proper circular/elliptical arcs, but bezier curves can approximate a 90-degree
 
264
     * arc fairly well.
 
265
     */
 
266
    if ((rx > 1e-18) && (ry > 1e-18)) {
 
267
        c->moveto(x + rx, y);
 
268
        if (rx < w2) c->lineto(x + w - rx, y);
 
269
        c->curveto(x + w - rx * (1 - C1), y,     x + w, y + ry * (1 - C1),       x + w, y + ry);
 
270
        if (ry < h2) c->lineto(x + w, y + h - ry);
 
271
        c->curveto(x + w, y + h - ry * (1 - C1),     x + w - rx * (1 - C1), y + h,       x + w - rx, y + h);
 
272
        if (rx < w2) c->lineto(x + rx, y + h);
 
273
        c->curveto(x + rx * (1 - C1), y + h,     x, y + h - ry * (1 - C1),       x, y + h - ry);
 
274
        if (ry < h2) c->lineto(x, y + ry);
 
275
        c->curveto(x, y + ry * (1 - C1),     x + rx * (1 - C1), y,       x + rx, y);
 
276
    } else {
 
277
        c->moveto(x + 0.0, y + 0.0);
 
278
        c->lineto(x + w, y + 0.0);
 
279
        c->lineto(x + w, y + h);
 
280
        c->lineto(x + 0.0, y + h);
 
281
        c->lineto(x + 0.0, y + 0.0);
 
282
    }
 
283
 
 
284
    c->closepath_current();
 
285
    sp_shape_set_curve_insync(SP_SHAPE(rect), c, TRUE);
 
286
    c->unref();
 
287
}
 
288
 
 
289
/* fixme: Think (Lauris) */
 
290
 
 
291
void
 
292
sp_rect_position_set(SPRect *rect, gdouble x, gdouble y, gdouble width, gdouble height)
 
293
{
 
294
    g_return_if_fail(rect != NULL);
 
295
    g_return_if_fail(SP_IS_RECT(rect));
 
296
 
 
297
    rect->x.computed = x;
 
298
    rect->y.computed = y;
 
299
    rect->width.computed = width;
 
300
    rect->height.computed = height;
 
301
 
 
302
    SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
303
}
 
304
 
 
305
void
 
306
sp_rect_set_rx(SPRect *rect, gboolean set, gdouble value)
 
307
{
 
308
    g_return_if_fail(rect != NULL);
 
309
    g_return_if_fail(SP_IS_RECT(rect));
 
310
 
 
311
    rect->rx._set = set;
 
312
    if (set) rect->rx.computed = value;
 
313
 
 
314
    SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
315
}
 
316
 
 
317
void
 
318
sp_rect_set_ry(SPRect *rect, gboolean set, gdouble value)
 
319
{
 
320
    g_return_if_fail(rect != NULL);
 
321
    g_return_if_fail(SP_IS_RECT(rect));
 
322
 
 
323
    rect->ry._set = set;
 
324
    if (set) rect->ry.computed = value;
 
325
 
 
326
    SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
327
}
 
328
 
 
329
/*
 
330
 * Initially we'll do:
 
331
 * Transform x, y, set x, y, clear translation
 
332
 */
 
333
 
 
334
/* fixme: Use preferred units somehow (Lauris) */
 
335
/* fixme: Alternately preserve whatever units there are (lauris) */
 
336
 
 
337
static Geom::Matrix
 
338
sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform)
 
339
{
 
340
    SPRect *rect = SP_RECT(item);
 
341
 
 
342
    /* Calculate rect start in parent coords. */
 
343
    Geom::Point pos( Geom::Point(rect->x.computed, rect->y.computed) * xform );
 
344
 
 
345
    /* This function takes care of translation and scaling, we return whatever parts we can't
 
346
       handle. */
 
347
    Geom::Matrix ret(Geom::Matrix(xform).without_translation());
 
348
    gdouble const sw = hypot(ret[0], ret[1]);
 
349
    gdouble const sh = hypot(ret[2], ret[3]);
 
350
    if (sw > 1e-9) {
 
351
        ret[0] /= sw;
 
352
        ret[1] /= sw;
 
353
    } else {
 
354
        ret[0] = 1.0;
 
355
        ret[1] = 0.0;
 
356
    }
 
357
    if (sh > 1e-9) {
 
358
        ret[2] /= sh;
 
359
        ret[3] /= sh;
 
360
    } else {
 
361
        ret[2] = 0.0;
 
362
        ret[3] = 1.0;
 
363
    }
 
364
 
 
365
    /* fixme: Would be nice to preserve units here */
 
366
    rect->width = rect->width.computed * sw;
 
367
    rect->height = rect->height.computed * sh;
 
368
    if (rect->rx._set) {
 
369
        rect->rx = rect->rx.computed * sw;
 
370
    }
 
371
    if (rect->ry._set) {
 
372
        rect->ry = rect->ry.computed * sh;
 
373
    }
 
374
 
 
375
    /* Find start in item coords */
 
376
    pos = pos * ret.inverse();
 
377
    rect->x = pos[Geom::X];
 
378
    rect->y = pos[Geom::Y];
 
379
 
 
380
    sp_rect_set_shape(rect);
 
381
 
 
382
    // Adjust stroke width
 
383
    sp_item_adjust_stroke(item, sqrt(fabs(sw * sh)));
 
384
 
 
385
    // Adjust pattern fill
 
386
    sp_item_adjust_pattern(item, xform * ret.inverse());
 
387
 
 
388
    // Adjust gradient fill
 
389
    sp_item_adjust_gradient(item, xform * ret.inverse());
 
390
 
 
391
    item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
 
392
 
 
393
    return ret;
 
394
}
 
395
 
 
396
 
 
397
/**
 
398
Returns the ratio in which the vector from p0 to p1 is stretched by transform
 
399
 */
 
400
static gdouble
 
401
vector_stretch(Geom::Point p0, Geom::Point p1, Geom::Matrix xform)
 
402
{
 
403
    if (p0 == p1)
 
404
        return 0;
 
405
    return (Geom::distance(p0 * xform, p1 * xform) / Geom::distance(p0, p1));
 
406
}
 
407
 
 
408
void
 
409
sp_rect_set_visible_rx(SPRect *rect, gdouble rx)
 
410
{
 
411
    if (rx == 0) {
 
412
        rect->rx.computed = 0;
 
413
        rect->rx._set = false;
 
414
    } else {
 
415
        rect->rx.computed = rx / vector_stretch(
 
416
            Geom::Point(rect->x.computed + 1, rect->y.computed),
 
417
            Geom::Point(rect->x.computed, rect->y.computed),
 
418
            SP_ITEM(rect)->transform);
 
419
        rect->rx._set = true;
 
420
    }
 
421
    SP_OBJECT(rect)->updateRepr();
 
422
}
 
423
 
 
424
void
 
425
sp_rect_set_visible_ry(SPRect *rect, gdouble ry)
 
426
{
 
427
    if (ry == 0) {
 
428
        rect->ry.computed = 0;
 
429
        rect->ry._set = false;
 
430
    } else {
 
431
        rect->ry.computed = ry / vector_stretch(
 
432
            Geom::Point(rect->x.computed, rect->y.computed + 1),
 
433
            Geom::Point(rect->x.computed, rect->y.computed),
 
434
            SP_ITEM(rect)->transform);
 
435
        rect->ry._set = true;
 
436
    }
 
437
    SP_OBJECT(rect)->updateRepr();
 
438
}
 
439
 
 
440
gdouble
 
441
sp_rect_get_visible_rx(SPRect *rect)
 
442
{
 
443
    if (!rect->rx._set)
 
444
        return 0;
 
445
    return rect->rx.computed * vector_stretch(
 
446
        Geom::Point(rect->x.computed + 1, rect->y.computed),
 
447
        Geom::Point(rect->x.computed, rect->y.computed),
 
448
        SP_ITEM(rect)->transform);
 
449
}
 
450
 
 
451
gdouble
 
452
sp_rect_get_visible_ry(SPRect *rect)
 
453
{
 
454
    if (!rect->ry._set)
 
455
        return 0;
 
456
    return rect->ry.computed * vector_stretch(
 
457
        Geom::Point(rect->x.computed, rect->y.computed + 1),
 
458
        Geom::Point(rect->x.computed, rect->y.computed),
 
459
        SP_ITEM(rect)->transform);
 
460
}
 
461
 
 
462
Geom::Rect
 
463
sp_rect_get_rect (SPRect *rect)
 
464
{
 
465
    Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed);
 
466
    Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed);
 
467
    return Geom::Rect(p0, p2);
 
468
}
 
469
 
 
470
void
 
471
sp_rect_compensate_rxry(SPRect *rect, Geom::Matrix xform)
 
472
{
 
473
    if (rect->rx.computed == 0 && rect->ry.computed == 0)
 
474
        return; // nothing to compensate
 
475
 
 
476
    // test unit vectors to find out compensation:
 
477
    Geom::Point c(rect->x.computed, rect->y.computed);
 
478
    Geom::Point cx = c + Geom::Point(1, 0);
 
479
    Geom::Point cy = c + Geom::Point(0, 1);
 
480
 
 
481
    // apply previous transform if any
 
482
    c *= SP_ITEM(rect)->transform;
 
483
    cx *= SP_ITEM(rect)->transform;
 
484
    cy *= SP_ITEM(rect)->transform;
 
485
 
 
486
    // find out stretches that we need to compensate
 
487
    gdouble eX = vector_stretch(cx, c, xform);
 
488
    gdouble eY = vector_stretch(cy, c, xform);
 
489
 
 
490
    // If only one of the radii is set, set both radii so they have the same visible length
 
491
    // This is needed because if we just set them the same length in SVG, they might end up unequal because of transform
 
492
    if ((rect->rx._set && !rect->ry._set) || (rect->ry._set && !rect->rx._set)) {
 
493
        gdouble r = MAX(rect->rx.computed, rect->ry.computed);
 
494
        rect->rx.computed = r / eX;
 
495
        rect->ry.computed = r / eY;
 
496
    } else {
 
497
        rect->rx.computed = rect->rx.computed / eX;
 
498
        rect->ry.computed = rect->ry.computed / eY;
 
499
    }
 
500
 
 
501
    // Note that a radius may end up larger than half-side if the rect is scaled down;
 
502
    // that's ok because this preserves the intended radii in case the rect is enlarged again,
 
503
    // and set_shape will take care of trimming too large radii when generating d=
 
504
 
 
505
    rect->rx._set = rect->ry._set = true;
 
506
}
 
507
 
 
508
void
 
509
sp_rect_set_visible_width(SPRect *rect, gdouble width)
 
510
{
 
511
    rect->width.computed = width / vector_stretch(
 
512
        Geom::Point(rect->x.computed + 1, rect->y.computed),
 
513
        Geom::Point(rect->x.computed, rect->y.computed),
 
514
        SP_ITEM(rect)->transform);
 
515
    rect->width._set = true;
 
516
    SP_OBJECT(rect)->updateRepr();
 
517
}
 
518
 
 
519
void
 
520
sp_rect_set_visible_height(SPRect *rect, gdouble height)
 
521
{
 
522
    rect->height.computed = height / vector_stretch(
 
523
        Geom::Point(rect->x.computed, rect->y.computed + 1),
 
524
        Geom::Point(rect->x.computed, rect->y.computed),
 
525
        SP_ITEM(rect)->transform);
 
526
    rect->height._set = true;
 
527
    SP_OBJECT(rect)->updateRepr();
 
528
}
 
529
 
 
530
gdouble
 
531
sp_rect_get_visible_width(SPRect *rect)
 
532
{
 
533
    if (!rect->width._set)
 
534
        return 0;
 
535
    return rect->width.computed * vector_stretch(
 
536
        Geom::Point(rect->x.computed + 1, rect->y.computed),
 
537
        Geom::Point(rect->x.computed, rect->y.computed),
 
538
        SP_ITEM(rect)->transform);
 
539
}
 
540
 
 
541
gdouble
 
542
sp_rect_get_visible_height(SPRect *rect)
 
543
{
 
544
    if (!rect->height._set)
 
545
        return 0;
 
546
    return rect->height.computed * vector_stretch(
 
547
        Geom::Point(rect->x.computed, rect->y.computed + 1),
 
548
        Geom::Point(rect->x.computed, rect->y.computed),
 
549
        SP_ITEM(rect)->transform);
 
550
}
 
551
 
 
552
/**
 
553
 * Sets the snappoint p to the unrounded corners of the rectangle
 
554
 */
 
555
static void sp_rect_snappoints(SPItem const *item, bool const target, SnapPointsWithType &p, Inkscape::SnapPreferences const *snapprefs)
 
556
{
 
557
    /* This method overrides sp_shape_snappoints, which is the default for any shape. The default method
 
558
    returns all eight points along the path of a rounded rectangle, but not the real corners. Snapping
 
559
    the startpoint and endpoint of each rounded corner is not very useful and really confusing. Instead
 
560
    we could snap either the real corners, or not snap at all. Bulia Byak opted to snap the real corners,
 
561
    but it should be noted that this might be confusing in some cases with relatively large radii. With
 
562
    small radii though the user will easily understand which point is snapping. */
 
563
 
 
564
    g_assert(item != NULL);
 
565
    g_assert(SP_IS_RECT(item));
 
566
 
 
567
    // Help enforcing strict snapping, i.e. only return nodes when we're snapping nodes to nodes or a guide to nodes
 
568
        if (!(snapprefs->getSnapModeNode() || snapprefs->getSnapModeGuide())) {
 
569
                return;
 
570
        }
 
571
 
 
572
    SPRect *rect = SP_RECT(item);
 
573
 
 
574
    Geom::Matrix const i2d (sp_item_i2d_affine (item));
 
575
 
 
576
    Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed) * i2d;
 
577
    Geom::Point p1 = Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d;
 
578
    Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d;
 
579
    Geom::Point p3 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d;
 
580
 
 
581
    int type;
 
582
 
 
583
    if (snapprefs->getSnapToItemNode()) {
 
584
        type = target ? int(Inkscape::SNAPTARGET_CORNER) : int(Inkscape::SNAPSOURCE_CORNER);
 
585
        p.push_back(std::make_pair(p0, type));
 
586
        p.push_back(std::make_pair(p1, type));
 
587
        p.push_back(std::make_pair(p2, type));
 
588
        p.push_back(std::make_pair(p3, type));
 
589
    }
 
590
 
 
591
        if (snapprefs->getSnapLineMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping)
 
592
                type = target ? int(Inkscape::SNAPTARGET_LINE_MIDPOINT) : int(Inkscape::SNAPSOURCE_LINE_MIDPOINT);
 
593
                p.push_back(std::make_pair((p0 + p1)/2, type));
 
594
                p.push_back(std::make_pair((p1 + p2)/2, type));
 
595
                p.push_back(std::make_pair((p2 + p3)/2, type));
 
596
                p.push_back(std::make_pair((p3 + p0)/2, type));
 
597
        }
 
598
 
 
599
        if (snapprefs->getSnapObjectMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping)
 
600
                type = target ? int(Inkscape::SNAPTARGET_OBJECT_MIDPOINT) : int(Inkscape::SNAPSOURCE_OBJECT_MIDPOINT);
 
601
                p.push_back(std::make_pair((p0 + p2)/2, type));
 
602
        }
 
603
 
 
604
}
 
605
 
 
606
void
 
607
sp_rect_convert_to_guides(SPItem *item) {
 
608
    SPRect *rect = SP_RECT(item);
 
609
 
 
610
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
611
    if (!prefs->getBool("/tools/shapes/rect/convertguides", true)) {
 
612
        sp_item_convert_to_guides(SP_ITEM(rect));
 
613
        return;
 
614
    }
 
615
 
 
616
    std::list<std::pair<Geom::Point, Geom::Point> > pts;
 
617
 
 
618
    Geom::Matrix const i2d (sp_item_i2d_affine(SP_ITEM(rect)));
 
619
 
 
620
    Geom::Point A1(Geom::Point(rect->x.computed, rect->y.computed) * i2d);
 
621
    Geom::Point A2(Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d);
 
622
    Geom::Point A3(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d);
 
623
    Geom::Point A4(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d);
 
624
 
 
625
    pts.push_back(std::make_pair(A1, A2));
 
626
    pts.push_back(std::make_pair(A2, A3));
 
627
    pts.push_back(std::make_pair(A3, A4));
 
628
    pts.push_back(std::make_pair(A4, A1));
 
629
 
 
630
    sp_guide_pt_pairs_to_guides(inkscape_active_desktop(), pts);
 
631
}
 
632
 
 
633
/*
 
634
  Local Variables:
 
635
  mode:c++
 
636
  c-file-style:"stroustrup"
 
637
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
638
  indent-tabs-mode:nil
 
639
  fill-column:99
 
640
  End:
 
641
*/
 
642
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :