~centralelyon2010/inkscape/imagelinks2

« back to all changes in this revision

Viewing changes to src/sp-conn-end-pair.cpp

  • Committer: mental
  • Date: 2006-01-16 02:36:01 UTC
  • Revision ID: mental@users.sourceforge.net-20060116023601-wkr0h7edl5veyudq
moving trunk for module inkscape

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * A class for handling connector endpoint movement and libavoid interaction.
 
3
 *
 
4
 * Authors:
 
5
 *   Peter Moulder <pmoulder@mail.csse.monash.edu.au>
 
6
 *   Michael Wybrow <mjwybrow@users.sourceforge.net>
 
7
 *
 
8
 *    * Copyright (C) 2004-2005 Monash University
 
9
 *
 
10
 * Released under GNU GPL, read the file 'COPYING' for more information
 
11
 */
 
12
 
 
13
#include "attributes.h"
 
14
#include "sp-conn-end.h"
 
15
#include "uri.h"
 
16
#include "display/curve.h"
 
17
#include "xml/repr.h"
 
18
#include "sp-path.h"
 
19
#include "libavoid/vertices.h"
 
20
 
 
21
 
 
22
SPConnEndPair::SPConnEndPair(SPPath *const owner)
 
23
    : _invalid_path_connection()
 
24
    , _path(owner)
 
25
    , _connRef(NULL)
 
26
    , _connType(SP_CONNECTOR_NOAVOID)
 
27
    , _transformed_connection()
 
28
{
 
29
    for (unsigned handle_ix = 0; handle_ix <= 1; ++handle_ix) {
 
30
        this->_connEnd[handle_ix] = new SPConnEnd(SP_OBJECT(owner));
 
31
        this->_connEnd[handle_ix]->_changed_connection
 
32
            = this->_connEnd[handle_ix]->ref.changedSignal()
 
33
            .connect(sigc::bind(sigc::ptr_fun(sp_conn_end_href_changed),
 
34
                                this->_connEnd[handle_ix], owner, handle_ix));
 
35
    }
 
36
}
 
37
 
 
38
SPConnEndPair::~SPConnEndPair()
 
39
{
 
40
    for (unsigned handle_ix = 0; handle_ix < 2; ++handle_ix) {
 
41
        delete this->_connEnd[handle_ix];
 
42
        this->_connEnd[handle_ix] = NULL;
 
43
    }
 
44
    if (_connRef) {
 
45
        _connRef->removeFromGraph();
 
46
        delete _connRef;
 
47
        _connRef = NULL;
 
48
    }
 
49
    
 
50
    _invalid_path_connection.disconnect();
 
51
    _transformed_connection.disconnect();
 
52
}
 
53
 
 
54
void
 
55
SPConnEndPair::release()
 
56
{
 
57
    for (unsigned handle_ix = 0; handle_ix < 2; ++handle_ix) {
 
58
        this->_connEnd[handle_ix]->_changed_connection.disconnect();
 
59
        this->_connEnd[handle_ix]->_delete_connection.disconnect();
 
60
        this->_connEnd[handle_ix]->_transformed_connection.disconnect();
 
61
        g_free(this->_connEnd[handle_ix]->href);
 
62
        this->_connEnd[handle_ix]->href = NULL;
 
63
        this->_connEnd[handle_ix]->ref.detach();
 
64
    }
 
65
}
 
66
 
 
67
void
 
68
sp_conn_end_pair_build(SPObject *object)
 
69
{
 
70
    sp_object_read_attr(object, "inkscape:connector-type");
 
71
    sp_object_read_attr(object, "inkscape:connection-start");
 
72
    sp_object_read_attr(object, "inkscape:connection-end");
 
73
}
 
74
 
 
75
 
 
76
static void 
 
77
avoid_conn_move(NR::Matrix const *mp, SPItem *moved_item)
 
78
{
 
79
    // Detach from objects if attached.
 
80
    sp_conn_end_detach(moved_item, 0);
 
81
    sp_conn_end_detach(moved_item, 1);
 
82
    // Reroute connector
 
83
    SPPath *path = SP_PATH(moved_item);
 
84
    path->connEndPair.makePathInvalid();
 
85
    sp_conn_adjust_invalid_path(path);
 
86
}
 
87
 
 
88
 
 
89
void
 
90
SPConnEndPair::setAttr(unsigned const key, gchar const *const value)
 
91
{
 
92
    if (key == SP_ATTR_CONNECTOR_TYPE) {
 
93
        if (value && (strcmp(value, "polyline") == 0)) {
 
94
            _connType = SP_CONNECTOR_POLYLINE;
 
95
            
 
96
            GQuark itemID = g_quark_from_string(SP_OBJECT(_path)->id);
 
97
            _connRef = new Avoid::ConnRef(itemID);
 
98
            _invalid_path_connection = connectInvalidPath(
 
99
                    sigc::ptr_fun(&sp_conn_adjust_invalid_path));
 
100
            _transformed_connection = _path->connectTransformed(
 
101
                    sigc::ptr_fun(&avoid_conn_move));
 
102
        }
 
103
        else {
 
104
            _connType = SP_CONNECTOR_NOAVOID;
 
105
            
 
106
            if (_connRef) {
 
107
                _connRef->removeFromGraph();
 
108
                delete _connRef;
 
109
                _connRef = NULL;
 
110
                _invalid_path_connection.disconnect();
 
111
                _transformed_connection.disconnect();
 
112
            }
 
113
        }
 
114
        return;
 
115
 
 
116
    }
 
117
    
 
118
    unsigned const handle_ix = key - SP_ATTR_CONNECTION_START;
 
119
    g_assert( handle_ix <= 1 );
 
120
    this->_connEnd[handle_ix]->setAttacherHref(value);
 
121
}
 
122
 
 
123
void
 
124
SPConnEndPair::writeRepr(Inkscape::XML::Node *const repr) const
 
125
{
 
126
    for (unsigned handle_ix = 0; handle_ix < 2; ++handle_ix) {
 
127
        if (this->_connEnd[handle_ix]->ref.getURI()) {
 
128
            char const * const attr_strs[] = {"inkscape:connection-start",
 
129
                                              "inkscape:connection-end"};
 
130
            gchar *uri_string = this->_connEnd[handle_ix]->ref.getURI()->toString();
 
131
            repr->setAttribute(attr_strs[handle_ix], uri_string);
 
132
            g_free(uri_string);
 
133
        }
 
134
    }
 
135
}
 
136
 
 
137
void
 
138
SPConnEndPair::getAttachedItems(SPItem *h2attItem[2]) const {
 
139
    for (unsigned h = 0; h < 2; ++h) {
 
140
        h2attItem[h] = this->_connEnd[h]->ref.getObject();
 
141
    }
 
142
}
 
143
 
 
144
void
 
145
SPConnEndPair::getEndpoints(NR::Point endPts[]) const {
 
146
    SPCurve *curve = _path->curve;
 
147
    SPItem *h2attItem[2];
 
148
    getAttachedItems(h2attItem);
 
149
    
 
150
    for (unsigned h = 0; h < 2; ++h) {
 
151
        if ( h2attItem[h] ) {
 
152
            NR::Rect const bbox = h2attItem[h]->invokeBbox(sp_item_i2doc_affine(h2attItem[h]));
 
153
            endPts[h] = bbox.midpoint();
 
154
        }
 
155
        else 
 
156
        {
 
157
            if (h == 0) {
 
158
                endPts[h] = sp_curve_first_point(curve);
 
159
            }
 
160
            else {
 
161
                endPts[h] = sp_curve_last_point(curve);
 
162
            }
 
163
        }
 
164
    }
 
165
}
 
166
 
 
167
sigc::connection
 
168
SPConnEndPair::connectInvalidPath(sigc::slot<void, SPPath *> slot)
 
169
{
 
170
    return _invalid_path_signal.connect(slot);
 
171
}
 
172
 
 
173
static void emitPathInvalidationNotification(void *ptr)
 
174
{
 
175
    // We emit a signal here rather than just calling the reroute function
 
176
    // since this allows all the movement action computation to happen,
 
177
    // then all connectors (that require it) will be rerouted.  Otherwise,
 
178
    // one connector could get rerouted several times as a result of
 
179
    // dragging a couple of shapes.
 
180
   
 
181
    SPPath *path = SP_PATH(ptr);
 
182
    path->connEndPair._invalid_path_signal.emit(path);
 
183
}
 
184
 
 
185
void
 
186
SPConnEndPair::rerouteFromManipulation(void)
 
187
{
 
188
    _connRef->makePathInvalid();
 
189
    sp_conn_adjust_path(_path);
 
190
}
 
191
 
 
192
void
 
193
SPConnEndPair::reroute(void)
 
194
{
 
195
    sp_conn_adjust_path(_path);
 
196
}
 
197
 
 
198
// Called from sp_path_update to initialise the endpoints.
 
199
void
 
200
SPConnEndPair::update(void)
 
201
{
 
202
    if (_connType != SP_CONNECTOR_NOAVOID) {
 
203
        g_assert(_connRef != NULL);
 
204
        if (!(_connRef->isInitialised())) {
 
205
            NR::Point endPt[2];
 
206
            getEndpoints(endPt);
 
207
 
 
208
            Avoid::Point src = { endPt[0][NR::X], endPt[0][NR::Y] };
 
209
            Avoid::Point dst = { endPt[1][NR::X], endPt[1][NR::Y] };
 
210
 
 
211
            _connRef->lateSetup(src, dst);
 
212
            _connRef->setCallback(&emitPathInvalidationNotification, _path);
 
213
        }
 
214
    }
 
215
}
 
216
    
 
217
 
 
218
bool
 
219
SPConnEndPair::isAutoRoutingConn(void)
 
220
{
 
221
    if (_connType != SP_CONNECTOR_NOAVOID) {
 
222
        return true;
 
223
    }
 
224
    return false;
 
225
}
 
226
    
 
227
void
 
228
SPConnEndPair::makePathInvalid(void)
 
229
{
 
230
    _connRef->makePathInvalid();
 
231
}
 
232
 
 
233
void
 
234
SPConnEndPair::reroutePath(void)
 
235
{
 
236
    if (!isAutoRoutingConn()) {
 
237
        // Do nothing
 
238
        return;
 
239
    }
 
240
 
 
241
    SPCurve *curve = _path->curve;
 
242
 
 
243
    NR::Point endPt[2];
 
244
    getEndpoints(endPt);
 
245
 
 
246
    Avoid::Point src = { endPt[0][NR::X], endPt[0][NR::Y] };
 
247
    Avoid::Point dst = { endPt[1][NR::X], endPt[1][NR::Y] };
 
248
    
 
249
    _connRef->updateEndPoint(Avoid::VertID::src, src);
 
250
    _connRef->updateEndPoint(Avoid::VertID::tar, dst);
 
251
 
 
252
    _connRef->generatePath(src, dst);
 
253
 
 
254
    Avoid::PolyLine route = _connRef->route();
 
255
    _connRef->calcRouteDist();
 
256
    
 
257
    sp_curve_reset(curve);
 
258
    sp_curve_moveto(curve, endPt[0]);
 
259
 
 
260
    for (int i = 1; i < route.pn; ++i) {
 
261
        NR::Point p(route.ps[i].x, route.ps[i].y);
 
262
        sp_curve_lineto(curve, p);
 
263
    }
 
264
}
 
265
 
 
266
/*
 
267
  Local Variables:
 
268
  mode:c++
 
269
  c-file-style:"stroustrup"
 
270
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
271
  indent-tabs-mode:nil
 
272
  fill-column:99
 
273
  End:
 
274
*/
 
275
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :