connector-context.cpp revision e77e2e02d8ab186389f86e48b1834d95f51cf68d
360aad676ba92ca443083da298b766628f6a3bfbmental * Connector creation tool
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * Michael Wybrow <mjwybrow@users.sourceforge.net>
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * Copyright (C) 2005 Michael Wybrow
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * Released under GNU GPL, read the file 'COPYING' for more information
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * o Have shapes avoid convex hulls of objects, rather than their
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * bounding box. Possibly implement the unfinished ConvexHull
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * class in libnr.
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * (HOWEVER, using the convex hull C of a shape S does the wrong thing if a
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * connector starts outside of S but inside C, or if the best route around
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * an object involves going inside C but without entering S.)
360aad676ba92ca443083da298b766628f6a3bfbmental * o Draw connectors to shape edges rather than bounding box.
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * o Show a visual indicator for objects with the 'avoid' property set.
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * o Allow user to change a object between a path and connector through
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * the interface.
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * o Create an interface for setting markers (arrow heads).
360aad676ba92ca443083da298b766628f6a3bfbmental * o Better distinguish between paths and connectors to prevent problems
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * in the node tool and paths accidently being turned into connectors
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * in the connector tool. Perhaps have a way to convert between.
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * o Only call libavoid's updateEndPoint as required. Currently we do it
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * for both endpoints, even if only one is moving.
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * o Allow user-placeable connection points.
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * o Deal sanely with connectors with both endpoints attached to the
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * same connection point, and drawing of connectors attaching
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * overlaping shapes (currently tries to adjust connector to be
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * outside both bounding boxes).
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * o Fix many special cases related to connectors updating,
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * e.g., copying a couple of shapes and a connector that are
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * attached to each other.
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * e.g., detach connector when it is moved or transformed in
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * one of the other contexts.
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * o Cope with shapes whose ids change when they have attached
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * connectors.
e7cd2ec3e1687a262ebe95e5ac7a47f8ab147ce2mental * o gobble_motion_events(GDK_BUTTON1_MASK)?;
#include <string>
#include <cstring>
#include "connector-context.h"
#include "pixmaps/cursor-connector.xpm"
#include "xml/node-event-vector.h"
#include "desktop.h"
#include "desktop-style.h"
#include "desktop-affine.h"
#include "desktop-handles.h"
#include "document.h"
#include "message-context.h"
#include "message-stack.h"
#include "selection.h"
#include "inkscape.h"
#include "prefs-utils.h"
#include "sp-path.h"
#include "display/canvas-bpath.h"
#include "display/sodipodi-ctrl.h"
#include "snap.h"
#include "knot.h"
#include "sp-conn-end.h"
#include "conn-avoid-ref.h"
#include "libavoid/vertices.h"
#include "context-fns.h"
#include "sp-namedview.h"
#include "sp-text.h"
#include "sp-flowtext.h"
static gint sp_connector_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event);
static gint connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const &bevent);
static gint connector_handle_motion_notify(SPConnectorContext *const cc, GdkEventMotion const &mevent);
static gint connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton const &revent);
static bool connector_within_tolerance = false;
if (!type) {
sizeof(SPConnectorContextClass),
sizeof(SPConnectorContext),
return type;
static gchar *
return NULL;
static gint
case GDK_BUTTON_RELEASE:
case GDK_ENTER_NOTIFY:
return ret;
case GDK_BUTTON_PRESS:
case GDK_MOTION_NOTIFY:
case GDK_BUTTON_RELEASE:
case GDK_KEY_PRESS:
if (!ret) {
if (parent_root_handler) {
return ret;
static gint
return TRUE;
bevent.y);
connector_within_tolerance = true;
SP_EVENT_CONTEXT_DESKTOP(cc)->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Creating new connector"));
p = event_dt;
return ret;
static gint
if (event_context->space_panning || mevent.state & GDK_BUTTON2_MASK || mevent.state & GDK_BUTTON3_MASK) {
return FALSE;
if (connector_within_tolerance) {
connector_within_tolerance = false;
return ret;
static gint
return TRUE;
return TRUE;
return ret;
static gint
switch (keyval) {
case GDK_Return:
case GDK_KP_Enter:
case GDK_Escape:
return ret;
if (p != NULL)
if (shape_label) {
cc->p[0] = p;
if (c->is_empty()) {
c->unref();
c->unref();
SPCurve *c;
if (gc) {
c = gc;
c->ref();
if ( c && !c->is_empty() ) {
bool connection = false;
connection = true;
connection = true;
if (connection) {
c->unref();
static gboolean
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
return consumed;
static gboolean
case GDK_BUTTON_PRESS:
return consumed;
if (bbox) {
int changes = 0;
value, false);
changes++;
l = l->next;
if (changes == 0) {