index 294e129b3f4e40bdda229aeedd30fd44d9bbb9f8..f4b202451156cc5e83133d55d3fe5dfda76075b1 100644 (file)
-/*
+/**
* Connector creation tool
*
* Authors:
* Michael Wybrow <mjwybrow@users.sourceforge.net>
+ * Abhishek Sharma
+ * Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2005-2008 Michael Wybrow
* Copyright (C) 2009 Monash University
+ * Copyright (C) 2010 authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*
#include "inkscape.h"
#include "preferences.h"
#include "sp-path.h"
+#include "display/sp-canvas.h"
#include "display/canvas-bpath.h"
#include "display/sodipodi-ctrl.h"
#include <glibmm/i18n.h>
#include "sp-flowtext.h"
#include "display/curve.h"
+using Inkscape::DocumentUndo;
+
static void sp_connector_context_class_init(SPConnectorContextClass *klass);
static void sp_connector_context_init(SPConnectorContext *conn_context);
static void sp_connector_context_dispose(GObject *object);
static void cc_clear_active_shape(SPConnectorContext *cc);
static void cc_set_active_conn(SPConnectorContext *cc, SPItem *item);
static void cc_clear_active_conn(SPConnectorContext *cc);
-static gchar *conn_pt_handle_test(SPConnectorContext *cc, Geom::Point& w);
+static bool conn_pt_handle_test(SPConnectorContext *cc, Geom::Point& p, gchar **href, gchar **cpid);
static void cc_select_handle(SPKnot* knot);
static void cc_deselect_handle(SPKnot* knot);
static bool cc_item_is_shape(SPItem *item);
@@ -233,6 +239,9 @@ static void shape_event_attr_changed(Inkscape::XML::Node *repr, gchar const *nam
gpointer data);
+static char* cc_knot_tips[] = { _("<b>Connection point</b>: click or drag to create a new connector"),
+ _("<b>Connection point</b>: click to select, drag to move") };
+
/*static Geom::Point connector_drag_origin_w(0, 0);
static bool connector_within_tolerance = false;*/
static SPEventContextClass *parent_class;
cc->endpt_handle[i] = NULL;
cc->endpt_handler_id[i] = 0;
}
- cc->sid = NULL;
- cc->eid = NULL;
+ cc->shref = NULL;
+ cc->scpid = NULL;
+ cc->ehref = NULL;
+ cc->ecpid = NULL;
cc->npoints = 0;
cc->state = SP_CONNECTOR_CONTEXT_IDLE;
}
cc->endpt_handle[i] = NULL;
}
}
- if (cc->sid) {
- g_free(cc->sid);
- cc->sid = NULL;
+ if (cc->shref) {
+ g_free(cc->shref);
+ cc->shref = NULL;
}
- if (cc->eid) {
- g_free(cc->eid);
- cc->eid = NULL;
+ if (cc->scpid) {
+ g_free(cc->scpid);
+ cc->scpid = NULL;
+ }
+ if (cc->ehref) {
+ g_free(cc->shref);
+ cc->shref = NULL;
+ }
+ if (cc->ecpid) {
+ g_free(cc->scpid);
+ cc->scpid = NULL;
}
g_assert( cc->newConnRef == NULL );
}
-static gchar *
-conn_pt_handle_test(SPConnectorContext *cc, Geom::Point& p)
+static bool
+conn_pt_handle_test(SPConnectorContext *cc, Geom::Point& p, gchar **href, gchar **cpid)
{
// TODO: this will need to change when there are more connection
// points available for each shape.
{
p = cc->active_handle->pos;
const ConnectionPoint& cp = cc->connpthandles[cc->active_handle];
- return g_strdup_printf("#%s_%c_%d", SP_OBJECT_ID(cc->active_shape),
- cp.type == ConnPointDefault ? 'd' : 'u' , cp.id);
+ *href = g_strdup_printf("#%s", cc->active_shape->getId());
+ *cpid = g_strdup_printf("%c%d", cp.type == ConnPointDefault ? 'd' : 'u' , cp.id);
+ return true;
}
- return NULL;
+ *href = NULL;
+ *cpid = NULL;
+ return false;
}
static void
@@ -752,7 +774,6 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const
Geom::Point const event_dt = cc->desktop->w2d(event_w);
SnapManager &m = cc->desktop->namedview->snap_manager;
- m.setup(cc->desktop);
switch (cc->state) {
case SP_CONNECTOR_CONTEXT_STOP:
@@ -769,12 +790,14 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const
Geom::Point p = event_dt;
// Test whether we clicked on a connection point
- cc->sid = conn_pt_handle_test(cc, p);
+ bool found = conn_pt_handle_test(cc, p, &cc->shref, &cc->scpid);
- if (!cc->sid) {
+ if (!found) {
// This is the first point, so just snap it to the grid
// as there's no other points to go off.
+ m.setup(cc->desktop);
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ m.unSetup();
}
spcc_connector_set_initial_point(cc, p);
@@ -786,12 +809,14 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const
case SP_CONNECTOR_CONTEXT_DRAGGING:
{
// This is the second click of a connector creation.
+ m.setup(cc->desktop);
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ m.unSetup();
spcc_connector_set_subsequent_point(cc, p);
spcc_connector_finish_segment(cc, p);
// Test whether we clicked on a connection point
- cc->eid = conn_pt_handle_test(cc, p);
+ /*bool found = */conn_pt_handle_test(cc, p, &cc->ehref, &cc->ecpid);
if (cc->npoints != 0) {
spcc_connector_finish(cc);
}
@@ -926,7 +951,6 @@ connector_handle_motion_notify(SPConnectorContext *const cc, GdkEventMotion cons
if ( cc->mode == SP_CONNECTOR_CONTEXT_DRAWING_MODE )
{
SnapManager &m = dt->namedview->snap_manager;
- m.setup(dt);
switch (cc->state) {
case SP_CONNECTOR_CONTEXT_DRAGGING:
@@ -934,7 +958,9 @@ connector_handle_motion_notify(SPConnectorContext *const cc, GdkEventMotion cons
gobble_motion_events(mevent.state);
// This is movement during a connector creation.
if ( cc->npoints > 0 ) {
+ m.setup(dt);
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ m.unSetup();
cc->selection->clear();
spcc_connector_set_subsequent_point(cc, p);
ret = TRUE;
@@ -946,10 +972,12 @@ connector_handle_motion_notify(SPConnectorContext *const cc, GdkEventMotion cons
gobble_motion_events(GDK_BUTTON1_MASK);
g_assert( SP_IS_PATH(cc->clickeditem));
+ m.setup(dt);
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ m.unSetup();
// Update the hidden path
- Geom::Matrix i2d = sp_item_i2d_affine(cc->clickeditem);
+ Geom::Matrix i2d = (cc->clickeditem)->i2d_affine();
Geom::Matrix d2i = i2d.inverse();
SPPath *path = SP_PATH(cc->clickeditem);
SPCurve *curve = path->original_curve ? path->original_curve : path->curve;
@@ -976,8 +1004,10 @@ connector_handle_motion_notify(SPConnectorContext *const cc, GdkEventMotion cons
/* This is perfectly valid */
break;
default:
- if (sp_event_context_knot_mouseover(cc)) {
+ if (!sp_event_context_knot_mouseover(cc)) {
+ m.setup(dt);
m.preSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_OTHER_HANDLE));
+ m.unSetup();
}
break;
}
@@ -1012,7 +1042,6 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con
SPDocument *doc = sp_desktop_document(desktop);
SnapManager &m = desktop->namedview->snap_manager;
- m.setup(desktop);
Geom::Point const event_w(revent.x, revent.y);
@@ -1024,7 +1053,9 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con
//case SP_CONNECTOR_CONTEXT_POINT:
case SP_CONNECTOR_CONTEXT_DRAGGING:
{
+ m.setup(desktop);
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ m.unSetup();
if (cc->within_tolerance)
{
@@ -1035,7 +1066,7 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con
spcc_connector_set_subsequent_point(cc, p);
spcc_connector_finish_segment(cc, p);
// Test whether we clicked on a connection point
- cc->eid = conn_pt_handle_test(cc, p);
+ /*bool found = */conn_pt_handle_test(cc, p, &cc->ehref, &cc->ecpid);
if (cc->npoints != 0) {
spcc_connector_finish(cc);
}
@@ -1045,10 +1076,12 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con
}
case SP_CONNECTOR_CONTEXT_REROUTING:
{
+ m.setup(desktop);
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ m.unSetup();
cc_connector_rerouting_finish(cc, &p);
- sp_document_ensure_up_to_date(doc);
+ doc->ensureUpToDate();
cc->state = SP_CONNECTOR_CONTEXT_IDLE;
return TRUE;
break;
@@ -1069,10 +1102,12 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con
if (!cc->within_tolerance)
{
+ m.setup(desktop);
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ m.unSetup();
sp_knot_set_position(cc->selected_handle, p, 0);
ConnectionPoint& cp = cc->connpthandles[cc->selected_handle];
- cp.pos = p * sp_item_dt2i_affine(cc->active_shape);
+ cp.pos = p * (cc->active_shape)->dt2i_affine();
cc->active_shape->avoidRef->updateConnectionPoint(cp);
}
@@ -1082,17 +1117,19 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con
case SP_CONNECTOR_CONTEXT_NEWCONNPOINT:
+ m.setup(desktop);
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ m.unSetup();
sp_knot_set_position(cc->selected_handle, p, 0);
ConnectionPoint cp;
cp.type = ConnPointUserDefined;
- cp.pos = p * sp_item_dt2i_affine(cc->active_shape);
+ cp.pos = p * (cc->active_shape)->dt2i_affine();
cp.dir = Avoid::ConnDirAll;
g_object_unref(cc->selected_handle);
cc->active_shape->avoidRef->addConnectionPoint(cp);
- sp_document_ensure_up_to_date(doc);
+ doc->ensureUpToDate();
for (ConnectionPointMap::iterator it = cc->connpthandles.begin(); it != cc->connpthandles.end(); ++it)
if (it->second.type == ConnPointUserDefined && it->second.id == cp.id)
{
cc_connector_rerouting_finish(cc, NULL);
- sp_document_undo(doc);
+ DocumentUndo::undo(doc);
cc->state = SP_CONNECTOR_CONTEXT_IDLE;
desktop->messageStack()->flash( Inkscape::NORMAL_MESSAGE,
// Obtain original position
ConnectionPoint const& cp = cc->connpthandles[cc->selected_handle];
SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc);
- const Geom::Matrix& i2doc = sp_item_i2doc_affine(cc->active_shape);
+ const Geom::Matrix& i2doc = (cc->active_shape)->i2doc_affine();
sp_knot_set_position(cc->selected_handle, cp.pos * i2doc * desktop->doc2dt(), 0);
cc->state = SP_CONNECTOR_CONTEXT_IDLE;
desktop->messageStack()->flash( Inkscape::NORMAL_MESSAGE,
@@ -1177,18 +1214,18 @@ connector_handle_key_press(SPConnectorContext *const cc, guint const keyval)
{
// Put connection point at current position
- SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc);
- SnapManager &m = desktop->namedview->snap_manager;
- m.setup(desktop);
Geom::Point p = cc->selected_handle->pos;
-// SPEventContext* event_context = SP_EVENT_CONTEXT( cc );
if (!cc->within_tolerance)
{
+ SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc);
+ SnapManager &m = desktop->namedview->snap_manager;
+ m.setup(desktop);
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ m.unSetup();
sp_knot_set_position(cc->selected_handle, p, 0);
ConnectionPoint& cp = cc->connpthandles[cc->selected_handle];
- cp.pos = p * sp_item_dt2i_affine(cc->active_shape);
+ cp.pos = p * (cc->active_shape)->dt2i_affine();
cc->active_shape->avoidRef->updateConnectionPoint(cp);
}
@@ -1212,18 +1249,17 @@ connector_handle_key_press(SPConnectorContext *const cc, guint const keyval)
SnapManager &m = desktop->namedview->snap_manager;
m.setup(desktop);
Geom::Point p = cc->selected_handle->pos;
-
m.freeSnapReturnByRef(p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
-
+ m.unSetup();
sp_knot_set_position(cc->selected_handle, p, 0);
ConnectionPoint cp;
cp.type = ConnPointUserDefined;
- cp.pos = p * sp_item_dt2i_affine(cc->active_shape);
+ cp.pos = p * (cc->active_shape)->dt2i_affine();
cp.dir = Avoid::ConnDirAll;
g_object_unref(cc->selected_handle);
cc->active_shape->avoidRef->addConnectionPoint(cp);
- sp_document_ensure_up_to_date(doc);
+ doc->ensureUpToDate();
for (ConnectionPointMap::iterator it = cc->connpthandles.begin(); it != cc->connpthandles.end(); ++it)
if (it->second.type == ConnPointUserDefined && it->second.id == cp.id)
{
@@ -1265,16 +1301,17 @@ cc_connector_rerouting_finish(SPConnectorContext *const cc, Geom::Point *const p
if (p != NULL)
{
// Test whether we clicked on a connection point
- gchar *shape_label = conn_pt_handle_test(cc, *p);
+ gchar *shape_label, *cpid;
+ bool found = conn_pt_handle_test(cc, *p, &shape_label, &cpid);
- if (shape_label) {
+ if (found) {
if (cc->clickedhandle == cc->endpt_handle[0]) {
- sp_object_setAttribute(cc->clickeditem,
- "inkscape:connection-start",shape_label, false);
+ cc->clickeditem->setAttribute("inkscape:connection-start", shape_label, false);
+ cc->clickeditem->setAttribute("inkscape:connection-start-point", cpid, false);
}
else {
- sp_object_setAttribute(cc->clickeditem,
- "inkscape:connection-end",shape_label, false);
+ cc->clickeditem->setAttribute("inkscape:connection-end", shape_label, false);
+ cc->clickeditem->setAttribute("inkscape:connection-end-point", cpid, false);
}
g_free(shape_label);
}
@@ -1282,7 +1319,7 @@ cc_connector_rerouting_finish(SPConnectorContext *const cc, Geom::Point *const p
cc->clickeditem->setHidden(false);
sp_conn_reroute_path_immediate(SP_PATH(cc->clickeditem));
cc->clickeditem->updateRepr();
- sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
+ DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR,
_("Reroute connector"));
cc_set_active_conn(cc, cc->clickeditem);
}
SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc);
SPDocument *doc = sp_desktop_document(desktop);
- Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
+ Inkscape::XML::Document *xml_doc = doc->getReprDoc();
if ( c && !c->is_empty() ) {
/* We actually have something to write */
/* Attach repr */
cc->newconn = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr));
- cc->newconn->transform = sp_item_i2doc_affine(SP_ITEM(desktop->currentLayer())).inverse();
+ cc->newconn->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
bool connection = false;
- sp_object_setAttribute(cc->newconn, "inkscape:connector-type",
- cc->isOrthogonal ? "orthogonal" : "polyline", false);
- sp_object_setAttribute(cc->newconn, "inkscape:connector-curvature",
- Glib::Ascii::dtostr(cc->curvature).c_str(), false);
- if (cc->sid)
+ cc->newconn->setAttribute( "inkscape:connector-type",
+ cc->isOrthogonal ? "orthogonal" : "polyline", false );
+ cc->newconn->setAttribute( "inkscape:connector-curvature",
+ Glib::Ascii::dtostr(cc->curvature).c_str(), false );
+ if (cc->shref)
{
- sp_object_setAttribute(cc->newconn, "inkscape:connection-start",
- cc->sid, false);
+ cc->newconn->setAttribute( "inkscape:connection-start", cc->shref, false);
+ if (cc->scpid) {
+ cc->newconn->setAttribute( "inkscape:connection-start-point", cc->scpid, false);
+ }
connection = true;
}
- if (cc->eid)
+ if (cc->ehref)
{
- sp_object_setAttribute(cc->newconn, "inkscape:connection-end",
- cc->eid, false);
+ cc->newconn->setAttribute( "inkscape:connection-end", cc->ehref, false);
+ if (cc->ecpid) {
+ cc->newconn->setAttribute( "inkscape:connection-end-point", cc->ecpid, false);
+ }
connection = true;
}
// Process pending updates.
cc->newconn->updateRepr();
- sp_document_ensure_up_to_date(doc);
+ doc->ensureUpToDate();
if (connection) {
// Adjust endpoints to shape edge.
c->unref();
- sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR, _("Create connector"));
+ DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, _("Create connector"));
}
// Show the red path for dragging.
cc->red_curve = SP_PATH(cc->clickeditem)->original_curve ? SP_PATH(cc->clickeditem)->original_curve->copy() : SP_PATH(cc->clickeditem)->curve->copy();
- Geom::Matrix i2d = sp_item_i2d_affine(cc->clickeditem);
+ Geom::Matrix i2d = (cc->clickeditem)->i2d_affine();
cc->red_curve->transform(i2d);
sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(cc->red_bpath), cc->red_curve);
// Ensure the item's connection_points map
// has been updated
- sp_document_ensure_up_to_date(SP_OBJECT_DOCUMENT(item));
+ item->document->ensureUpToDate();
std::set<int> seen;
for ( ConnectionPointMap::iterator it = cc->connpthandles.begin(); it != cc->connpthandles.end() ;)
g_assert( SP_IS_PATH(item) );
SPCurve *curve = SP_PATH(item)->original_curve ? SP_PATH(item)->original_curve : SP_PATH(item)->curve;
- Geom::Matrix i2d = sp_item_i2d_affine(item);
+ Geom::Matrix i2d = item->i2d_affine();
if (cc->active_conn == item)
{
- // Just adjust handle positions.
- Geom::Point startpt = *(curve->first_point()) * i2d;
- sp_knot_set_position(cc->endpt_handle[0], startpt, 0);
+ if (curve->is_empty())
+ {
+ // Connector is invisible because it is clipped to the boundary of
+ // two overlpapping shapes.
+ sp_knot_hide(cc->endpt_handle[0]);
+ sp_knot_hide(cc->endpt_handle[1]);
+ }
+ else
+ {
+ // Just adjust handle positions.
+ Geom::Point startpt = *(curve->first_point()) * i2d;
+ sp_knot_set_position(cc->endpt_handle[0], startpt, 0);
- Geom::Point endpt = *(curve->last_point()) * i2d;
- sp_knot_set_position(cc->endpt_handle[1], endpt, 0);
+ Geom::Point endpt = *(curve->last_point()) * i2d;
+ sp_knot_set_position(cc->endpt_handle[1], endpt, 0);
+ }
return;
}
G_CALLBACK(endpt_handler), cc);
}
+ if (curve->is_empty())
+ {
+ // Connector is invisible because it is clipped to the boundary
+ // of two overlpapping shapes. So, it doesn't need endpoints.
+ return;
+ }
+
Geom::Point startpt = *(curve->first_point()) * i2d;
sp_knot_set_position(cc->endpt_handle[0], startpt, 0);
bool cc_item_is_connector(SPItem *item)
{
if (SP_IS_PATH(item)) {
- if (SP_PATH(item)->connEndPair.isAutoRoutingConn()) {
- g_assert( SP_PATH(item)->original_curve ? !(SP_PATH(item)->original_curve->is_closed()) : !(SP_PATH(item)->curve->is_closed()) );
+ bool closed = SP_PATH(item)->original_curve ? SP_PATH(item)->original_curve->is_closed() : SP_PATH(item)->curve->is_closed();
+ if (SP_PATH(item)->connEndPair.isAutoRoutingConn() && !closed) {
+ // To be considered a connector, an object must be a non-closed
+ // path that is marked with a "inkscape:connector-type" attribute.
return true;
}
}
char const *value = (set_avoid) ? "true" : NULL;
if (cc_item_is_shape(item)) {
- sp_object_setAttribute(item, "inkscape:connector-avoid",
- value, false);
+ item->setAttribute("inkscape:connector-avoid", value, false);
item->avoidRef->handleSettingChange();
changes++;
}
char *event_desc = (set_avoid) ?
_("Make connectors avoid selected objects") :
_("Make connectors ignore selected objects");
- sp_document_done(document, SP_VERB_CONTEXT_CONNECTOR, event_desc);
+ DocumentUndo::done(document, SP_VERB_CONTEXT_CONNECTOR, event_desc);
}
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :