summaryrefslogtreecommitdiffstats
path: root/src/sp-conn-end-pair.cpp
diff options
context:
space:
mode:
authorMenTaLguY <mental@rydia.net>2006-01-16 02:36:01 +0000
committermental <mental@users.sourceforge.net>2006-01-16 02:36:01 +0000
commit179fa413b047bede6e32109e2ce82437c5fb8d34 (patch)
treea5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/sp-conn-end-pair.cpp
downloadinkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz
inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/sp-conn-end-pair.cpp')
-rw-r--r--src/sp-conn-end-pair.cpp275
1 files changed, 275 insertions, 0 deletions
diff --git a/src/sp-conn-end-pair.cpp b/src/sp-conn-end-pair.cpp
new file mode 100644
index 000000000..ff1005a16
--- /dev/null
+++ b/src/sp-conn-end-pair.cpp
@@ -0,0 +1,275 @@
+/*
+ * A class for handling connector endpoint movement and libavoid interaction.
+ *
+ * Authors:
+ * Peter Moulder <pmoulder@mail.csse.monash.edu.au>
+ * Michael Wybrow <mjwybrow@users.sourceforge.net>
+ *
+ * * Copyright (C) 2004-2005 Monash University
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "attributes.h"
+#include "sp-conn-end.h"
+#include "uri.h"
+#include "display/curve.h"
+#include "xml/repr.h"
+#include "sp-path.h"
+#include "libavoid/vertices.h"
+
+
+SPConnEndPair::SPConnEndPair(SPPath *const owner)
+ : _invalid_path_connection()
+ , _path(owner)
+ , _connRef(NULL)
+ , _connType(SP_CONNECTOR_NOAVOID)
+ , _transformed_connection()
+{
+ for (unsigned handle_ix = 0; handle_ix <= 1; ++handle_ix) {
+ this->_connEnd[handle_ix] = new SPConnEnd(SP_OBJECT(owner));
+ this->_connEnd[handle_ix]->_changed_connection
+ = this->_connEnd[handle_ix]->ref.changedSignal()
+ .connect(sigc::bind(sigc::ptr_fun(sp_conn_end_href_changed),
+ this->_connEnd[handle_ix], owner, handle_ix));
+ }
+}
+
+SPConnEndPair::~SPConnEndPair()
+{
+ for (unsigned handle_ix = 0; handle_ix < 2; ++handle_ix) {
+ delete this->_connEnd[handle_ix];
+ this->_connEnd[handle_ix] = NULL;
+ }
+ if (_connRef) {
+ _connRef->removeFromGraph();
+ delete _connRef;
+ _connRef = NULL;
+ }
+
+ _invalid_path_connection.disconnect();
+ _transformed_connection.disconnect();
+}
+
+void
+SPConnEndPair::release()
+{
+ for (unsigned handle_ix = 0; handle_ix < 2; ++handle_ix) {
+ this->_connEnd[handle_ix]->_changed_connection.disconnect();
+ this->_connEnd[handle_ix]->_delete_connection.disconnect();
+ this->_connEnd[handle_ix]->_transformed_connection.disconnect();
+ g_free(this->_connEnd[handle_ix]->href);
+ this->_connEnd[handle_ix]->href = NULL;
+ this->_connEnd[handle_ix]->ref.detach();
+ }
+}
+
+void
+sp_conn_end_pair_build(SPObject *object)
+{
+ sp_object_read_attr(object, "inkscape:connector-type");
+ sp_object_read_attr(object, "inkscape:connection-start");
+ sp_object_read_attr(object, "inkscape:connection-end");
+}
+
+
+static void
+avoid_conn_move(NR::Matrix const *mp, SPItem *moved_item)
+{
+ // Detach from objects if attached.
+ sp_conn_end_detach(moved_item, 0);
+ sp_conn_end_detach(moved_item, 1);
+ // Reroute connector
+ SPPath *path = SP_PATH(moved_item);
+ path->connEndPair.makePathInvalid();
+ sp_conn_adjust_invalid_path(path);
+}
+
+
+void
+SPConnEndPair::setAttr(unsigned const key, gchar const *const value)
+{
+ if (key == SP_ATTR_CONNECTOR_TYPE) {
+ if (value && (strcmp(value, "polyline") == 0)) {
+ _connType = SP_CONNECTOR_POLYLINE;
+
+ GQuark itemID = g_quark_from_string(SP_OBJECT(_path)->id);
+ _connRef = new Avoid::ConnRef(itemID);
+ _invalid_path_connection = connectInvalidPath(
+ sigc::ptr_fun(&sp_conn_adjust_invalid_path));
+ _transformed_connection = _path->connectTransformed(
+ sigc::ptr_fun(&avoid_conn_move));
+ }
+ else {
+ _connType = SP_CONNECTOR_NOAVOID;
+
+ if (_connRef) {
+ _connRef->removeFromGraph();
+ delete _connRef;
+ _connRef = NULL;
+ _invalid_path_connection.disconnect();
+ _transformed_connection.disconnect();
+ }
+ }
+ return;
+
+ }
+
+ unsigned const handle_ix = key - SP_ATTR_CONNECTION_START;
+ g_assert( handle_ix <= 1 );
+ this->_connEnd[handle_ix]->setAttacherHref(value);
+}
+
+void
+SPConnEndPair::writeRepr(Inkscape::XML::Node *const repr) const
+{
+ for (unsigned handle_ix = 0; handle_ix < 2; ++handle_ix) {
+ if (this->_connEnd[handle_ix]->ref.getURI()) {
+ char const * const attr_strs[] = {"inkscape:connection-start",
+ "inkscape:connection-end"};
+ gchar *uri_string = this->_connEnd[handle_ix]->ref.getURI()->toString();
+ repr->setAttribute(attr_strs[handle_ix], uri_string);
+ g_free(uri_string);
+ }
+ }
+}
+
+void
+SPConnEndPair::getAttachedItems(SPItem *h2attItem[2]) const {
+ for (unsigned h = 0; h < 2; ++h) {
+ h2attItem[h] = this->_connEnd[h]->ref.getObject();
+ }
+}
+
+void
+SPConnEndPair::getEndpoints(NR::Point endPts[]) const {
+ SPCurve *curve = _path->curve;
+ SPItem *h2attItem[2];
+ getAttachedItems(h2attItem);
+
+ for (unsigned h = 0; h < 2; ++h) {
+ if ( h2attItem[h] ) {
+ NR::Rect const bbox = h2attItem[h]->invokeBbox(sp_item_i2doc_affine(h2attItem[h]));
+ endPts[h] = bbox.midpoint();
+ }
+ else
+ {
+ if (h == 0) {
+ endPts[h] = sp_curve_first_point(curve);
+ }
+ else {
+ endPts[h] = sp_curve_last_point(curve);
+ }
+ }
+ }
+}
+
+sigc::connection
+SPConnEndPair::connectInvalidPath(sigc::slot<void, SPPath *> slot)
+{
+ return _invalid_path_signal.connect(slot);
+}
+
+static void emitPathInvalidationNotification(void *ptr)
+{
+ // We emit a signal here rather than just calling the reroute function
+ // since this allows all the movement action computation to happen,
+ // then all connectors (that require it) will be rerouted. Otherwise,
+ // one connector could get rerouted several times as a result of
+ // dragging a couple of shapes.
+
+ SPPath *path = SP_PATH(ptr);
+ path->connEndPair._invalid_path_signal.emit(path);
+}
+
+void
+SPConnEndPair::rerouteFromManipulation(void)
+{
+ _connRef->makePathInvalid();
+ sp_conn_adjust_path(_path);
+}
+
+void
+SPConnEndPair::reroute(void)
+{
+ sp_conn_adjust_path(_path);
+}
+
+// Called from sp_path_update to initialise the endpoints.
+void
+SPConnEndPair::update(void)
+{
+ if (_connType != SP_CONNECTOR_NOAVOID) {
+ g_assert(_connRef != NULL);
+ if (!(_connRef->isInitialised())) {
+ NR::Point endPt[2];
+ getEndpoints(endPt);
+
+ Avoid::Point src = { endPt[0][NR::X], endPt[0][NR::Y] };
+ Avoid::Point dst = { endPt[1][NR::X], endPt[1][NR::Y] };
+
+ _connRef->lateSetup(src, dst);
+ _connRef->setCallback(&emitPathInvalidationNotification, _path);
+ }
+ }
+}
+
+
+bool
+SPConnEndPair::isAutoRoutingConn(void)
+{
+ if (_connType != SP_CONNECTOR_NOAVOID) {
+ return true;
+ }
+ return false;
+}
+
+void
+SPConnEndPair::makePathInvalid(void)
+{
+ _connRef->makePathInvalid();
+}
+
+void
+SPConnEndPair::reroutePath(void)
+{
+ if (!isAutoRoutingConn()) {
+ // Do nothing
+ return;
+ }
+
+ SPCurve *curve = _path->curve;
+
+ NR::Point endPt[2];
+ getEndpoints(endPt);
+
+ Avoid::Point src = { endPt[0][NR::X], endPt[0][NR::Y] };
+ Avoid::Point dst = { endPt[1][NR::X], endPt[1][NR::Y] };
+
+ _connRef->updateEndPoint(Avoid::VertID::src, src);
+ _connRef->updateEndPoint(Avoid::VertID::tar, dst);
+
+ _connRef->generatePath(src, dst);
+
+ Avoid::PolyLine route = _connRef->route();
+ _connRef->calcRouteDist();
+
+ sp_curve_reset(curve);
+ sp_curve_moveto(curve, endPt[0]);
+
+ for (int i = 1; i < route.pn; ++i) {
+ NR::Point p(route.ps[i].x, route.ps[i].y);
+ sp_curve_lineto(curve, p);
+ }
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :