2
* A class for handling connector endpoint movement and libavoid interaction.
5
* Peter Moulder <pmoulder@mail.csse.monash.edu.au>
6
* Michael Wybrow <mjwybrow@users.sourceforge.net>
8
* * Copyright (C) 2004-2005 Monash University
10
* Released under GNU GPL, read the file 'COPYING' for more information
13
#include "attributes.h"
14
#include "sp-conn-end.h"
16
#include "display/curve.h"
19
#include "libavoid/vertices.h"
22
SPConnEndPair::SPConnEndPair(SPPath *const owner)
23
: _invalid_path_connection()
26
, _connType(SP_CONNECTOR_NOAVOID)
27
, _transformed_connection()
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));
38
SPConnEndPair::~SPConnEndPair()
40
for (unsigned handle_ix = 0; handle_ix < 2; ++handle_ix) {
41
delete this->_connEnd[handle_ix];
42
this->_connEnd[handle_ix] = NULL;
45
_connRef->removeFromGraph();
50
_invalid_path_connection.disconnect();
51
_transformed_connection.disconnect();
55
SPConnEndPair::release()
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();
68
sp_conn_end_pair_build(SPObject *object)
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");
77
avoid_conn_move(NR::Matrix const *mp, SPItem *moved_item)
79
// Detach from objects if attached.
80
sp_conn_end_detach(moved_item, 0);
81
sp_conn_end_detach(moved_item, 1);
83
SPPath *path = SP_PATH(moved_item);
84
path->connEndPair.makePathInvalid();
85
sp_conn_adjust_invalid_path(path);
90
SPConnEndPair::setAttr(unsigned const key, gchar const *const value)
92
if (key == SP_ATTR_CONNECTOR_TYPE) {
93
if (value && (strcmp(value, "polyline") == 0)) {
94
_connType = SP_CONNECTOR_POLYLINE;
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));
104
_connType = SP_CONNECTOR_NOAVOID;
107
_connRef->removeFromGraph();
110
_invalid_path_connection.disconnect();
111
_transformed_connection.disconnect();
118
unsigned const handle_ix = key - SP_ATTR_CONNECTION_START;
119
g_assert( handle_ix <= 1 );
120
this->_connEnd[handle_ix]->setAttacherHref(value);
124
SPConnEndPair::writeRepr(Inkscape::XML::Node *const repr) const
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);
138
SPConnEndPair::getAttachedItems(SPItem *h2attItem[2]) const {
139
for (unsigned h = 0; h < 2; ++h) {
140
h2attItem[h] = this->_connEnd[h]->ref.getObject();
145
SPConnEndPair::getEndpoints(NR::Point endPts[]) const {
146
SPCurve *curve = _path->curve;
147
SPItem *h2attItem[2];
148
getAttachedItems(h2attItem);
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();
158
endPts[h] = sp_curve_first_point(curve);
161
endPts[h] = sp_curve_last_point(curve);
168
SPConnEndPair::connectInvalidPath(sigc::slot<void, SPPath *> slot)
170
return _invalid_path_signal.connect(slot);
173
static void emitPathInvalidationNotification(void *ptr)
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.
181
SPPath *path = SP_PATH(ptr);
182
path->connEndPair._invalid_path_signal.emit(path);
186
SPConnEndPair::rerouteFromManipulation(void)
188
_connRef->makePathInvalid();
189
sp_conn_adjust_path(_path);
193
SPConnEndPair::reroute(void)
195
sp_conn_adjust_path(_path);
198
// Called from sp_path_update to initialise the endpoints.
200
SPConnEndPair::update(void)
202
if (_connType != SP_CONNECTOR_NOAVOID) {
203
g_assert(_connRef != NULL);
204
if (!(_connRef->isInitialised())) {
208
Avoid::Point src = { endPt[0][NR::X], endPt[0][NR::Y] };
209
Avoid::Point dst = { endPt[1][NR::X], endPt[1][NR::Y] };
211
_connRef->lateSetup(src, dst);
212
_connRef->setCallback(&emitPathInvalidationNotification, _path);
219
SPConnEndPair::isAutoRoutingConn(void)
221
if (_connType != SP_CONNECTOR_NOAVOID) {
228
SPConnEndPair::makePathInvalid(void)
230
_connRef->makePathInvalid();
234
SPConnEndPair::reroutePath(void)
236
if (!isAutoRoutingConn()) {
241
SPCurve *curve = _path->curve;
246
Avoid::Point src = { endPt[0][NR::X], endPt[0][NR::Y] };
247
Avoid::Point dst = { endPt[1][NR::X], endPt[1][NR::Y] };
249
_connRef->updateEndPoint(Avoid::VertID::src, src);
250
_connRef->updateEndPoint(Avoid::VertID::tar, dst);
252
_connRef->generatePath(src, dst);
254
Avoid::PolyLine route = _connRef->route();
255
_connRef->calcRouteDist();
257
sp_curve_reset(curve);
258
sp_curve_moveto(curve, endPt[0]);
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);
269
c-file-style:"stroustrup"
270
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
275
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :