~ubuntu-branches/ubuntu/utopic/inkscape/utopic-proposed

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/box3d-side.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 __BOX3D_SIDE_C__
 
2
 
 
3
/*
 
4
 * 3D box face implementation
 
5
 *
 
6
 * Authors:
 
7
 *   Maximilian Albert <Anhalter42@gmx.de>
 
8
 *
 
9
 * Copyright (C) 2007  Authors
 
10
 *
 
11
 * Released under GNU GPL, read the file 'COPYING' for more information
 
12
 */
 
13
 
 
14
#include "box3d-side.h"
 
15
#include "document.h"
 
16
#include "xml/document.h"
 
17
#include "xml/repr.h"
 
18
#include "display/curve.h"
 
19
#include "svg/svg.h"
 
20
#include "attributes.h"
 
21
#include "inkscape.h"
 
22
#include "persp3d.h"
 
23
#include "box3d-context.h"
 
24
#include "preferences.h"
 
25
#include "desktop-style.h"
 
26
#include "box3d.h"
 
27
 
 
28
static void box3d_side_class_init (Box3DSideClass *klass);
 
29
static void box3d_side_init (Box3DSide *side);
 
30
 
 
31
static void box3d_side_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
 
32
static Inkscape::XML::Node *box3d_side_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
 
33
static void box3d_side_set (SPObject *object, unsigned int key, const gchar *value);
 
34
static void box3d_side_update (SPObject *object, SPCtx *ctx, guint flags);
 
35
 
 
36
static void box3d_side_set_shape (SPShape *shape);
 
37
 
 
38
static void box3d_side_compute_corner_ids(Box3DSide *side, unsigned int corners[4]);
 
39
 
 
40
static SPShapeClass *parent_class;
 
41
 
 
42
GType
 
43
box3d_side_get_type (void)
 
44
{
 
45
    static GType type = 0;
 
46
 
 
47
    if (!type) {
 
48
        GTypeInfo info = {
 
49
            sizeof (Box3DSideClass),
 
50
            NULL, NULL,
 
51
            (GClassInitFunc) box3d_side_class_init,
 
52
            NULL, NULL,
 
53
            sizeof (Box3DSide),
 
54
            16,
 
55
            (GInstanceInitFunc) box3d_side_init,
 
56
            NULL,       /* value_table */
 
57
        };
 
58
        type = g_type_register_static (SP_TYPE_SHAPE, "Box3DSide", &info, (GTypeFlags)0);
 
59
    }
 
60
    return type;
 
61
}
 
62
 
 
63
static void
 
64
box3d_side_class_init (Box3DSideClass *klass)
 
65
{
 
66
    GObjectClass * gobject_class;
 
67
    SPObjectClass * sp_object_class;
 
68
    SPItemClass * item_class;
 
69
    SPPathClass * path_class;
 
70
    SPShapeClass * shape_class;
 
71
 
 
72
    gobject_class = (GObjectClass *) klass;
 
73
    sp_object_class = (SPObjectClass *) klass;
 
74
    item_class = (SPItemClass *) klass;
 
75
    path_class = (SPPathClass *) klass;
 
76
    shape_class = (SPShapeClass *) klass;
 
77
 
 
78
    parent_class = (SPShapeClass *)g_type_class_ref (SP_TYPE_SHAPE);
 
79
 
 
80
    sp_object_class->build = box3d_side_build;
 
81
    sp_object_class->write = box3d_side_write;
 
82
    sp_object_class->set = box3d_side_set;
 
83
    sp_object_class->update = box3d_side_update;
 
84
 
 
85
    shape_class->set_shape = box3d_side_set_shape;
 
86
}
 
87
 
 
88
static void
 
89
box3d_side_init (Box3DSide * side)
 
90
{
 
91
    side->dir1 = Box3D::NONE;
 
92
    side->dir2 = Box3D::NONE;
 
93
    side->front_or_rear = Box3D::FRONT;
 
94
}
 
95
 
 
96
static void
 
97
box3d_side_build (SPObject * object, SPDocument * document, Inkscape::XML::Node * repr)
 
98
{
 
99
    if (((SPObjectClass *) parent_class)->build)
 
100
        ((SPObjectClass *) parent_class)->build (object, document, repr);
 
101
 
 
102
    sp_object_read_attr(object, "inkscape:box3dsidetype");
 
103
}
 
104
 
 
105
static Inkscape::XML::Node *
 
106
box3d_side_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
 
107
{
 
108
    Box3DSide *side = SP_BOX3D_SIDE (object);
 
109
 
 
110
    if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
 
111
        // this is where we end up when saving as plain SVG (also in other circumstances?)
 
112
        // thus we don' set "sodipodi:type" so that the box is only saved as an ordinary svg:path
 
113
        repr = xml_doc->createElement("svg:path");
 
114
    }
 
115
 
 
116
    if (flags & SP_OBJECT_WRITE_EXT) {
 
117
        sp_repr_set_int(repr, "inkscape:box3dsidetype", side->dir1 ^ side->dir2 ^ side->front_or_rear);
 
118
    }
 
119
 
 
120
    sp_shape_set_shape ((SPShape *) object);
 
121
 
 
122
    /* Duplicate the path */
 
123
    SPCurve const *curve = ((SPShape *) object)->curve;
 
124
    //Nulls might be possible if this called iteratively
 
125
    if ( !curve ) {
 
126
        return NULL;
 
127
    }
 
128
    char *d = sp_svg_write_path ( curve->get_pathvector() );
 
129
    repr->setAttribute("d", d);
 
130
    g_free (d);
 
131
 
 
132
    if (((SPObjectClass *) (parent_class))->write)
 
133
        ((SPObjectClass *) (parent_class))->write (object, xml_doc, repr, flags);
 
134
 
 
135
    return repr;
 
136
}
 
137
 
 
138
static void
 
139
box3d_side_set (SPObject *object, unsigned int key, const gchar *value)
 
140
{
 
141
    Box3DSide *side = SP_BOX3D_SIDE (object);
 
142
 
 
143
    // TODO: In case the box was recreated (by undo, e.g.) we need to recreate the path
 
144
    //       (along with other info?) from the parent box.
 
145
 
 
146
    /* fixme: we should really collect updates */
 
147
    switch (key) {
 
148
        case SP_ATTR_INKSCAPE_BOX3D_SIDE_TYPE:
 
149
            if (value) {
 
150
                guint desc = atoi (value);
 
151
 
 
152
                if (!Box3D::is_face_id(desc)) {
 
153
                    g_print ("desc is not a face id: =%s=\n", value);
 
154
                }
 
155
                g_return_if_fail (Box3D::is_face_id (desc));
 
156
                Box3D::Axis plane = (Box3D::Axis) (desc & 0x7);
 
157
                plane = (Box3D::is_plane(plane) ? plane : Box3D::orth_plane_or_axis(plane));
 
158
                side->dir1 = Box3D::extract_first_axis_direction(plane);
 
159
                side->dir2 = Box3D::extract_second_axis_direction(plane);
 
160
                side->front_or_rear = (Box3D::FrontOrRear) (desc & 0x8);
 
161
 
 
162
                object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
163
            }
 
164
            break;
 
165
    default:
 
166
        if (((SPObjectClass *) parent_class)->set)
 
167
            ((SPObjectClass *) parent_class)->set (object, key, value);
 
168
        break;
 
169
    }
 
170
}
 
171
 
 
172
static void
 
173
box3d_side_update (SPObject *object, SPCtx *ctx, guint flags)
 
174
{
 
175
    if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
 
176
        flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore
 
177
    }
 
178
 
 
179
    if (flags & (SP_OBJECT_MODIFIED_FLAG |
 
180
                 SP_OBJECT_STYLE_MODIFIED_FLAG |
 
181
                 SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
 
182
        sp_shape_set_shape ((SPShape *) object);
 
183
    }
 
184
 
 
185
    if (((SPObjectClass *) parent_class)->update)
 
186
        ((SPObjectClass *) parent_class)->update (object, ctx, flags);
 
187
}
 
188
 
 
189
void
 
190
box3d_side_position_set (Box3DSide *side) {
 
191
    box3d_side_set_shape (SP_SHAPE (side));
 
192
 
 
193
    /* This call is responsible for live update of the sides during the initial drag */
 
194
    SP_OBJECT(side)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
195
}
 
196
 
 
197
void
 
198
box3d_side_set_shape (SPShape *shape)
 
199
{
 
200
    Box3DSide *side = SP_BOX3D_SIDE (shape);
 
201
    if (!SP_OBJECT_DOCUMENT(side)->root) {
 
202
        // avoid a warning caused by sp_document_height() (which is called from sp_item_i2d_affine() below)
 
203
        // when reading a file containing 3D boxes
 
204
        return;
 
205
    }
 
206
 
 
207
    SPObject *parent = SP_OBJECT(side)->parent;
 
208
    if (!SP_IS_BOX3D(parent)) {
 
209
        g_warning ("Parent of 3D box side is not a 3D box.\n");
 
210
        return;
 
211
    }
 
212
    SPBox3D *box = SP_BOX3D(parent);
 
213
 
 
214
    Persp3D *persp = box3d_side_perspective(side);
 
215
    if (!persp) {
 
216
        return;
 
217
    }
 
218
 
 
219
    // TODO: Draw the correct quadrangle here
 
220
    //       To do this, determine the perspective of the box, the orientation of the side (e.g., XY-FRONT)
 
221
    //       compute the coordinates of the corners in P^3, project them onto the canvas, and draw the
 
222
    //       resulting path.
 
223
 
 
224
    unsigned int corners[4];
 
225
    box3d_side_compute_corner_ids(side, corners);
 
226
 
 
227
    SPCurve *c = new SPCurve();
 
228
    c->moveto(box3d_get_corner_screen(box, corners[0]));
 
229
    c->lineto(box3d_get_corner_screen(box, corners[1]));
 
230
    c->lineto(box3d_get_corner_screen(box, corners[2]));
 
231
    c->lineto(box3d_get_corner_screen(box, corners[3]));
 
232
    c->closepath();
 
233
 
 
234
    /* Reset the shape'scurve to the "original_curve"
 
235
     * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/
 
236
    sp_shape_set_curve_insync (shape, c, TRUE);
 
237
    if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) {
 
238
        SPCurve *c_lpe = c->copy();
 
239
        bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe);
 
240
        if (success) {
 
241
            sp_shape_set_curve_insync (shape, c_lpe, TRUE);
 
242
        }
 
243
        c_lpe->unref();
 
244
    }
 
245
    c->unref();
 
246
}
 
247
 
 
248
void
 
249
box3d_side_apply_style (Box3DSide *side) {
 
250
    Inkscape::XML::Node *repr_face = SP_OBJECT_REPR(SP_OBJECT(side));
 
251
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
252
 
 
253
    Glib::ustring descr = "/desktop/";
 
254
    descr += box3d_side_axes_string(side);
 
255
    descr += "/style";
 
256
    Glib::ustring cur_style = prefs->getString(descr);    
 
257
    
 
258
    SPDesktop *desktop = inkscape_active_desktop();
 
259
    bool use_current = prefs->getBool("/tools/shapes/3dbox/usecurrent", false);
 
260
    if (use_current && !cur_style.empty()) {
 
261
        /* use last used style */
 
262
        repr_face->setAttribute("style", cur_style.data());
 
263
    } else {
 
264
        /* use default style */
 
265
        GString *pstring = g_string_new("");
 
266
        g_string_printf (pstring, "/tools/shapes/3dbox/%s", box3d_side_axes_string(side));
 
267
        sp_desktop_apply_style_tool (desktop, repr_face, pstring->str, false);
 
268
    }
 
269
}
 
270
 
 
271
gchar *
 
272
box3d_side_axes_string(Box3DSide *side)
 
273
{
 
274
    GString *pstring = g_string_new("");
 
275
    g_string_printf (pstring, "%s", Box3D::string_from_axes ((Box3D::Axis) (side->dir1 ^ side->dir2)));
 
276
    switch ((Box3D::Axis) (side->dir1 ^ side->dir2)) {
 
277
        case Box3D::XY:
 
278
            g_string_append_printf (pstring, (side->front_or_rear == Box3D::FRONT) ? "front" : "rear");
 
279
            break;
 
280
        case Box3D::XZ:
 
281
            g_string_append_printf (pstring, (side->front_or_rear == Box3D::FRONT) ? "top" : "bottom");
 
282
            break;
 
283
        case Box3D::YZ:
 
284
            g_string_append_printf (pstring, (side->front_or_rear == Box3D::FRONT) ? "right" : "left");
 
285
            break;
 
286
        default:
 
287
            break;
 
288
    }
 
289
    return pstring->str;
 
290
}
 
291
 
 
292
static void
 
293
box3d_side_compute_corner_ids(Box3DSide *side, unsigned int corners[4]) {
 
294
    Box3D::Axis orth = Box3D::third_axis_direction (side->dir1, side->dir2);
 
295
 
 
296
    corners[0] = (side->front_or_rear ? orth : 0);
 
297
    corners[1] = corners[0] ^ side->dir1;
 
298
    corners[2] = corners[0] ^ side->dir1 ^ side->dir2;
 
299
    corners[3] = corners[0] ^ side->dir2;
 
300
}
 
301
 
 
302
Persp3D *
 
303
box3d_side_perspective(Box3DSide *side) {
 
304
    return SP_BOX3D(SP_OBJECT(side)->parent)->persp_ref->getObject();
 
305
}
 
306
 
 
307
Inkscape::XML::Node *
 
308
box3d_side_convert_to_path(Box3DSide *side) {
 
309
    // TODO: Copy over all important attributes (see sp_selected_item_to_curved_repr() for an example)
 
310
    SPDocument *doc = SP_OBJECT_DOCUMENT(side);
 
311
    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
 
312
 
 
313
    Inkscape::XML::Node *repr = xml_doc->createElement("svg:path");
 
314
    repr->setAttribute("d", SP_OBJECT_REPR(side)->attribute("d"));
 
315
    repr->setAttribute("style", SP_OBJECT_REPR(side)->attribute("style"));
 
316
 
 
317
    return repr;
 
318
}
 
319
 
 
320
/*
 
321
  Local Variables:
 
322
  mode:c++
 
323
  c-file-style:"stroustrup"
 
324
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
325
  indent-tabs-mode:nil
 
326
  fill-column:99
 
327
  End:
 
328
*/
 
329
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :