2
2
* Connector creation tool
5
5
* Michael Wybrow <mjwybrow@users.sourceforge.net>
7
* Jon A. Cruz <jon@joncruz.org>
7
9
* Copyright (C) 2005-2008 Michael Wybrow
8
10
* Copyright (C) 2009 Monash University
11
* Copyright (C) 2010 authors
10
13
* Released under GNU GPL, read the file 'COPYING' for more information
188
192
#include "sp-flowtext.h"
189
193
#include "display/curve.h"
195
using Inkscape::DocumentUndo;
191
197
static void sp_connector_context_class_init(SPConnectorContextClass *klass);
192
198
static void sp_connector_context_init(SPConnectorContext *conn_context);
193
199
static void sp_connector_context_dispose(GObject *object);
791
796
// This is the first point, so just snap it to the grid
792
797
// as there's no other points to go off.
798
m.setup(cc->desktop);
793
799
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
795
802
spcc_connector_set_initial_point(cc, p);
802
809
case SP_CONNECTOR_CONTEXT_DRAGGING:
804
811
// This is the second click of a connector creation.
812
m.setup(cc->desktop);
805
813
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
807
816
spcc_connector_set_subsequent_point(cc, p);
808
817
spcc_connector_finish_segment(cc, p);
950
958
gobble_motion_events(mevent.state);
951
959
// This is movement during a connector creation.
952
960
if ( cc->npoints > 0 ) {
953
962
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
954
964
cc->selection->clear();
955
965
spcc_connector_set_subsequent_point(cc, p);
962
972
gobble_motion_events(GDK_BUTTON1_MASK);
963
973
g_assert( SP_IS_PATH(cc->clickeditem));
965
976
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
967
979
// Update the hidden path
968
Geom::Matrix i2d = sp_item_i2d_affine(cc->clickeditem);
969
Geom::Matrix d2i = i2d.inverse();
980
Geom::Affine i2d ( (cc->clickeditem)->i2dt_affine() );
981
Geom::Affine d2i = i2d.inverse();
970
982
SPPath *path = SP_PATH(cc->clickeditem);
971
983
SPCurve *curve = path->original_curve ? path->original_curve : path->curve;
972
984
if (cc->clickedhandle == cc->endpt_handle[0]) {
1040
1053
//case SP_CONNECTOR_CONTEXT_POINT:
1041
1054
case SP_CONNECTOR_CONTEXT_DRAGGING:
1043
1057
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
1045
1060
if (cc->within_tolerance)
1062
1077
case SP_CONNECTOR_CONTEXT_REROUTING:
1064
1080
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
1065
1082
cc_connector_rerouting_finish(cc, &p);
1067
sp_document_ensure_up_to_date(doc);
1084
doc->ensureUpToDate();
1068
1085
cc->state = SP_CONNECTOR_CONTEXT_IDLE;
1086
1103
if (!cc->within_tolerance)
1088
1106
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
1089
1108
sp_knot_set_position(cc->selected_handle, p, 0);
1090
1109
ConnectionPoint& cp = cc->connpthandles[cc->selected_handle];
1091
cp.pos = p * sp_item_dt2i_affine(cc->active_shape);
1110
cp.pos = p * (cc->active_shape)->dt2i_affine();
1092
1111
cc->active_shape->avoidRef->updateConnectionPoint(cp);
1100
1119
case SP_CONNECTOR_CONTEXT_NEWCONNPOINT:
1101
1121
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
1103
1124
sp_knot_set_position(cc->selected_handle, p, 0);
1105
1126
ConnectionPoint cp;
1106
1127
cp.type = ConnPointUserDefined;
1107
cp.pos = p * sp_item_dt2i_affine(cc->active_shape);
1128
cp.pos = p * (cc->active_shape)->dt2i_affine();
1108
1129
cp.dir = Avoid::ConnDirAll;
1109
1130
g_object_unref(cc->selected_handle);
1110
1131
cc->active_shape->avoidRef->addConnectionPoint(cp);
1111
sp_document_ensure_up_to_date(doc);
1132
doc->ensureUpToDate();
1112
1133
for (ConnectionPointMap::iterator it = cc->connpthandles.begin(); it != cc->connpthandles.end(); ++it)
1113
1134
if (it->second.type == ConnPointUserDefined && it->second.id == cp.id)
1182
1203
// Obtain original position
1183
1204
ConnectionPoint const& cp = cc->connpthandles[cc->selected_handle];
1184
1205
SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc);
1185
const Geom::Matrix& i2doc = sp_item_i2doc_affine(cc->active_shape);
1206
const Geom::Affine& i2doc = (cc->active_shape)->i2doc_affine();
1186
1207
sp_knot_set_position(cc->selected_handle, cp.pos * i2doc * desktop->doc2dt(), 0);
1187
1208
cc->state = SP_CONNECTOR_CONTEXT_IDLE;
1188
1209
desktop->messageStack()->flash( Inkscape::NORMAL_MESSAGE,
1194
1215
// Put connection point at current position
1196
SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc);
1197
SnapManager &m = desktop->namedview->snap_manager;
1199
1217
Geom::Point p = cc->selected_handle->pos;
1200
// SPEventContext* event_context = SP_EVENT_CONTEXT( cc );
1202
1219
if (!cc->within_tolerance)
1221
SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc);
1222
SnapManager &m = desktop->namedview->snap_manager;
1204
1224
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
1205
1226
sp_knot_set_position(cc->selected_handle, p, 0);
1206
1227
ConnectionPoint& cp = cc->connpthandles[cc->selected_handle];
1207
cp.pos = p * sp_item_dt2i_affine(cc->active_shape);
1228
cp.pos = p * (cc->active_shape)->dt2i_affine();
1208
1229
cc->active_shape->avoidRef->updateConnectionPoint(cp);
1228
1249
SnapManager &m = desktop->namedview->snap_manager;
1229
1250
m.setup(desktop);
1230
1251
Geom::Point p = cc->selected_handle->pos;
1232
1252
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
1234
1254
sp_knot_set_position(cc->selected_handle, p, 0);
1236
1256
ConnectionPoint cp;
1237
1257
cp.type = ConnPointUserDefined;
1238
cp.pos = p * sp_item_dt2i_affine(cc->active_shape);
1258
cp.pos = p * (cc->active_shape)->dt2i_affine();
1239
1259
cp.dir = Avoid::ConnDirAll;
1240
1260
g_object_unref(cc->selected_handle);
1241
1261
cc->active_shape->avoidRef->addConnectionPoint(cp);
1242
sp_document_ensure_up_to_date(doc);
1262
doc->ensureUpToDate();
1243
1263
for (ConnectionPointMap::iterator it = cc->connpthandles.begin(); it != cc->connpthandles.end(); ++it)
1244
1264
if (it->second.type == ConnPointUserDefined && it->second.id == cp.id)
1288
1308
if (cc->clickedhandle == cc->endpt_handle[0]) {
1289
sp_object_setAttribute(cc->clickeditem,
1290
"inkscape:connection-start", shape_label, false);
1291
sp_object_setAttribute(cc->clickeditem,
1292
"inkscape:connection-start-point", cpid, false);
1309
cc->clickeditem->setAttribute("inkscape:connection-start", shape_label, NULL);
1310
cc->clickeditem->setAttribute("inkscape:connection-start-point", cpid, NULL);
1295
sp_object_setAttribute(cc->clickeditem,
1296
"inkscape:connection-end", shape_label, false);
1297
sp_object_setAttribute(cc->clickeditem,
1298
"inkscape:connection-end-point", cpid, false);
1313
cc->clickeditem->setAttribute("inkscape:connection-end", shape_label, NULL);
1314
cc->clickeditem->setAttribute("inkscape:connection-end-point", cpid, NULL);
1300
1316
g_free(shape_label);
1303
1319
cc->clickeditem->setHidden(false);
1304
1320
sp_conn_reroute_path_immediate(SP_PATH(cc->clickeditem));
1305
1321
cc->clickeditem->updateRepr();
1306
sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
1322
DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR,
1307
1323
_("Reroute connector"));
1308
1324
cc_set_active_conn(cc, cc->clickeditem);
1416
1432
SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc);
1417
1433
SPDocument *doc = sp_desktop_document(desktop);
1418
Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
1434
Inkscape::XML::Document *xml_doc = doc->getReprDoc();
1420
1436
if ( c && !c->is_empty() ) {
1421
1437
/* We actually have something to write */
1432
1448
/* Attach repr */
1433
1449
cc->newconn = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr));
1434
cc->newconn->transform = sp_item_i2doc_affine(SP_ITEM(desktop->currentLayer())).inverse();
1450
cc->newconn->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
1436
1452
bool connection = false;
1437
sp_object_setAttribute(cc->newconn, "inkscape:connector-type",
1438
cc->isOrthogonal ? "orthogonal" : "polyline", false);
1439
sp_object_setAttribute(cc->newconn, "inkscape:connector-curvature",
1440
Glib::Ascii::dtostr(cc->curvature).c_str(), false);
1453
cc->newconn->setAttribute( "inkscape:connector-type",
1454
cc->isOrthogonal ? "orthogonal" : "polyline", NULL );
1455
cc->newconn->setAttribute( "inkscape:connector-curvature",
1456
Glib::Ascii::dtostr(cc->curvature).c_str(), NULL );
1443
sp_object_setAttribute(cc->newconn, "inkscape:connection-start",
1446
sp_object_setAttribute(cc->newconn, "inkscape:connection-start-point",
1459
cc->newconn->setAttribute( "inkscape:connection-start", cc->shref, NULL);
1461
cc->newconn->setAttribute( "inkscape:connection-start-point", cc->scpid, NULL);
1448
1463
connection = true;
1453
sp_object_setAttribute(cc->newconn, "inkscape:connection-end",
1456
sp_object_setAttribute(cc->newconn, "inkscape:connection-end-point",
1468
cc->newconn->setAttribute( "inkscape:connection-end", cc->ehref, NULL);
1470
cc->newconn->setAttribute( "inkscape:connection-end-point", cc->ecpid, NULL);
1458
1472
connection = true;
1460
1474
// Process pending updates.
1461
1475
cc->newconn->updateRepr();
1462
sp_document_ensure_up_to_date(doc);
1476
doc->ensureUpToDate();
1464
1478
if (connection) {
1465
1479
// Adjust endpoints to shape edge.
1594
1608
// Show the red path for dragging.
1595
1609
cc->red_curve = SP_PATH(cc->clickeditem)->original_curve ? SP_PATH(cc->clickeditem)->original_curve->copy() : SP_PATH(cc->clickeditem)->curve->copy();
1596
Geom::Matrix i2d = sp_item_i2d_affine(cc->clickeditem);
1610
Geom::Affine i2d = (cc->clickeditem)->i2dt_affine();
1597
1611
cc->red_curve->transform(i2d);
1598
1612
sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(cc->red_bpath), cc->red_curve);
1626
1640
knot->_event_handler_id);
1627
1641
knot->_event_handler_id = 0;
1629
gtk_signal_connect(GTK_OBJECT(knot->item), "event",
1630
GTK_SIGNAL_FUNC(cc_generic_knot_handler), knot);
1643
g_signal_connect(G_OBJECT(knot->item), "event",
1644
G_CALLBACK(cc_generic_knot_handler), knot);
1631
1645
sp_knot_set_position(knot, item->avoidRef->getConnectionPointPos(cp.type, cp.id) * desktop->doc2dt(), 0);
1632
1646
sp_knot_show(knot);
1633
1647
cphandles[knot] = cp;
1656
1670
// Listen in case the active shape changes
1657
cc->active_shape_repr = SP_OBJECT_REPR(item);
1671
cc->active_shape_repr = item->getRepr();
1658
1672
if (cc->active_shape_repr) {
1659
1673
Inkscape::GC::anchor(cc->active_shape_repr);
1660
1674
sp_repr_add_listener(cc->active_shape_repr, &shape_repr_events, cc);
1694
1708
// Ensure the item's connection_points map
1695
1709
// has been updated
1696
sp_document_ensure_up_to_date(SP_OBJECT_DOCUMENT(item));
1710
item->document->ensureUpToDate();
1698
1712
std::set<int> seen;
1699
1713
for ( ConnectionPointMap::iterator it = cc->connpthandles.begin(); it != cc->connpthandles.end() ;)
1752
1766
g_assert( SP_IS_PATH(item) );
1754
1768
SPCurve *curve = SP_PATH(item)->original_curve ? SP_PATH(item)->original_curve : SP_PATH(item)->curve;
1755
Geom::Matrix i2d = sp_item_i2d_affine(item);
1769
Geom::Affine i2dt = item->i2dt_affine();
1757
1771
if (cc->active_conn == item)
1759
// Just adjust handle positions.
1760
Geom::Point startpt = *(curve->first_point()) * i2d;
1761
sp_knot_set_position(cc->endpt_handle[0], startpt, 0);
1773
if (curve->is_empty())
1775
// Connector is invisible because it is clipped to the boundary of
1776
// two overlpapping shapes.
1777
sp_knot_hide(cc->endpt_handle[0]);
1778
sp_knot_hide(cc->endpt_handle[1]);
1782
// Just adjust handle positions.
1783
Geom::Point startpt = *(curve->first_point()) * i2dt;
1784
sp_knot_set_position(cc->endpt_handle[0], startpt, 0);
1763
Geom::Point endpt = *(curve->last_point()) * i2d;
1764
sp_knot_set_position(cc->endpt_handle[1], endpt, 0);
1786
Geom::Point endpt = *(curve->last_point()) * i2dt;
1787
sp_knot_set_position(cc->endpt_handle[1], endpt, 0);
1778
1802
// Listen in case the active conn changes
1779
cc->active_conn_repr = SP_OBJECT_REPR(item);
1803
cc->active_conn_repr = item->getRepr();
1780
1804
if (cc->active_conn_repr) {
1781
1805
Inkscape::GC::anchor(cc->active_conn_repr);
1782
1806
sp_repr_add_listener(cc->active_conn_repr, &shape_repr_events, cc);
1802
1826
knot->_event_handler_id);
1803
1827
knot->_event_handler_id = 0;
1805
gtk_signal_connect(GTK_OBJECT(knot->item), "event",
1806
GTK_SIGNAL_FUNC(cc_generic_knot_handler), knot);
1829
g_signal_connect(G_OBJECT(knot->item), "event",
1830
G_CALLBACK(cc_generic_knot_handler), knot);
1808
1832
cc->endpt_handle[i] = knot;
1824
1848
G_CALLBACK(endpt_handler), cc);
1827
Geom::Point startpt = *(curve->first_point()) * i2d;
1851
if (curve->is_empty())
1853
// Connector is invisible because it is clipped to the boundary
1854
// of two overlpapping shapes. So, it doesn't need endpoints.
1858
Geom::Point startpt = *(curve->first_point()) * i2dt;
1828
1859
sp_knot_set_position(cc->endpt_handle[0], startpt, 0);
1830
Geom::Point endpt = *(curve->last_point()) * i2d;
1861
Geom::Point endpt = *(curve->last_point()) * i2dt;
1831
1862
sp_knot_set_position(cc->endpt_handle[1], endpt, 0);
1833
1864
sp_knot_show(cc->endpt_handle[0]);
1887
1918
bool cc_item_is_connector(SPItem *item)
1889
1920
if (SP_IS_PATH(item)) {
1890
if (SP_PATH(item)->connEndPair.isAutoRoutingConn()) {
1891
g_assert( SP_PATH(item)->original_curve ? !(SP_PATH(item)->original_curve->is_closed()) : !(SP_PATH(item)->curve->is_closed()) );
1921
bool closed = SP_PATH(item)->original_curve ? SP_PATH(item)->original_curve->is_closed() : SP_PATH(item)->curve->is_closed();
1922
if (SP_PATH(item)->connEndPair.isAutoRoutingConn() && !closed) {
1923
// To be considered a connector, an object must be a non-closed
1924
// path that is marked with a "inkscape:connector-type" attribute.
1917
1950
char const *value = (set_avoid) ? "true" : NULL;
1919
1952
if (cc_item_is_shape(item)) {
1920
sp_object_setAttribute(item, "inkscape:connector-avoid",
1953
item->setAttribute("inkscape:connector-avoid", value, NULL);
1922
1954
item->avoidRef->handleSettingChange();
1935
1967
char *event_desc = (set_avoid) ?
1936
1968
_("Make connectors avoid selected objects") :
1937
1969
_("Make connectors ignore selected objects");
1938
sp_document_done(document, SP_VERB_CONTEXT_CONNECTOR, event_desc);
1970
DocumentUndo::done(document, SP_VERB_CONTEXT_CONNECTOR, event_desc);