diff --git a/libs/flake/KoFlake.h b/libs/flake/KoFlake.h index fe4eeb2be080f31379727f99d474bbf679a2e9c2..ffc5c2c2dd6eb1ee53072f9bf9070384628c60a9 100644 --- a/libs/flake/KoFlake.h +++ b/libs/flake/KoFlake.h @@ -81,6 +81,15 @@ namespace KoFlake Foreground ///< the foreground / border style is active }; + /// Default connection point ids + enum ConnectionPointId { + TopConnectionPoint = 0, + RightConnectionPoint = 1, + BottomConnectionPoint = 2, + LeftConnectionPoint = 3, + FirstCustomConnectionPoint = 4 + }; + /// clones the given gradient FLAKE_EXPORT QGradient *cloneGradient(const QGradient *gradient); diff --git a/libs/flake/KoShape.cpp b/libs/flake/KoShape.cpp index 4da0c24007976ad925b59216b8a96efb7280009c..3e6277735f665fd4dd629bc00ff3a7b7aabc5807 100644 --- a/libs/flake/KoShape.cpp +++ b/libs/flake/KoShape.cpp @@ -105,10 +105,10 @@ KoShapePrivate::KoShapePrivate(KoShape *shape) textRunAroundSide(KoShape::BiggestRunAroundSide), textRunAroundDistance(1.0) { - connectors.append(QPointF(0.5, 0.0)); - connectors.append(QPointF(1.0, 0.5)); - connectors.append(QPointF(0.5, 1.0)); - connectors.append(QPointF(0.0, 0.5)); + connectors[KoFlake::TopConnectionPoint] = defaultConnectionPoint(KoFlake::TopConnectionPoint); + connectors[KoFlake::RightConnectionPoint] = defaultConnectionPoint(KoFlake::RightConnectionPoint); + connectors[KoFlake::BottomConnectionPoint] = defaultConnectionPoint(KoFlake::BottomConnectionPoint); + connectors[KoFlake::LeftConnectionPoint] = defaultConnectionPoint(KoFlake::LeftConnectionPoint); } KoShapePrivate::~KoShapePrivate() @@ -203,7 +203,22 @@ void KoShapePrivate::removeShapeCache() } } - +QPointF KoShapePrivate::defaultConnectionPoint(KoFlake::ConnectionPointId connectionPointId) +{ + switch(connectionPointId) + { + case KoFlake::TopConnectionPoint: + return QPointF(0.5, 0.0); + case KoFlake::RightConnectionPoint: + return QPointF(1.0, 0.5); + case KoFlake::BottomConnectionPoint: + return QPointF(0.5, 1.0); + case KoFlake::LeftConnectionPoint: + return QPointF(0.0, 0.5); + default: + return QPointF(); + } +} // static QString KoShapePrivate::getStyleProperty(const char *property, KoShapeLoadingContext &context) { @@ -728,12 +743,46 @@ QPointF KoShape::position() const return d->localMatrix.map(center) - center; } -void KoShape::addConnectionPoint(const QPointF &point) +int KoShape::addConnectionPoint(const QPointF &point) { Q_D(KoShape); QSizeF s = size(); // convert glue point from shape coordinates to factors of size - d->connectors.append(QPointF(point.x() / s.width(), point.y() / s.height())); + QPointF connectionPoint(point.x() / s.width(), point.y() / s.height()); + // get next glue point id + int nextConnectionPointId = KoFlake::FirstCustomConnectionPoint; + if(d->connectors.size()) + nextConnectionPointId = qMax(nextConnectionPointId, (--d->connectors.end()).key()+1); + + // allow adding default connection point + if(connectionPoint == d->defaultConnectionPoint(KoFlake::TopConnectionPoint)) + nextConnectionPointId = KoFlake::TopConnectionPoint; + else if(connectionPoint == d->defaultConnectionPoint(KoFlake::RightConnectionPoint)) + nextConnectionPointId = KoFlake::RightConnectionPoint; + else if(connectionPoint == d->defaultConnectionPoint(KoFlake::BottomConnectionPoint)) + nextConnectionPointId = KoFlake::BottomConnectionPoint; + else if(connectionPoint == d->defaultConnectionPoint(KoFlake::LeftConnectionPoint)) + nextConnectionPointId = KoFlake::LeftConnectionPoint; + + d->connectors[nextConnectionPointId] = connectionPoint; + + return nextConnectionPointId; +} + +bool KoShape::hasConnectionPoint(int connectionPointId) const +{ + Q_D(const KoShape); + return d->connectors.contains(connectionPointId); +} + +QPointF KoShape::connectionPoint(int connectionPointId) const +{ + Q_D(const KoShape); + QSizeF s = size(); + QPointF p = d->connectors.value(connectionPointId, QPointF()); + p.rx() *= s.width(); + p.ry() *= s.height(); + return p; } QList KoShape::connectionPoints() const @@ -748,6 +797,18 @@ QList KoShape::connectionPoints() const return points; } +void KoShape::removeConnectionPoint(int connectionPointId) +{ + Q_D(KoShape); + d->connectors.remove(connectionPointId); +} + +void KoShape::clearConnectionPoints() +{ + Q_D(KoShape); + d->connectors.clear(); +} + void KoShape::addEventAction(KoEventAction *action) { Q_D(KoShape); @@ -1012,13 +1073,6 @@ QTransform KoShape::transform() const return d->localMatrix; } -void KoShape::removeConnectionPoint(int index) -{ - Q_D(KoShape); - if (index < d->connectors.count()) - d->connectors.remove(index); -} - QString KoShape::name() const { Q_D(const KoShape); @@ -1282,6 +1336,47 @@ bool KoShape::loadOdfAttributes(const KoXmlElement &element, KoShapeLoadingConte d->eventActions = KoEventActionRegistry::instance()->createEventActionsFromOdf(eventActionsElement, context); } // load glue points (connection points) + KoXmlElement child; + forEachElement(child, element) { + if (child.namespaceURI() != KoXmlNS::draw) + continue; + if (child.localName() == "glue-point") { + const QString id = child.attributeNS(KoXmlNS::draw, "id", QString()); + const int index = id.toInt(); + if(id.isEmpty() || index < 4) { + kWarning(30006) << "glue-point with no or invalid id"; + continue; + } + QString xStr = child.attributeNS(KoXmlNS::svg, "x", QString()).simplified(); + QString yStr = child.attributeNS(KoXmlNS::svg, "y", QString()).simplified(); + if(xStr.isEmpty() || yStr.isEmpty()) { + kWarning(30006) << "glue-point with invald position"; + continue; + } + QPointF connectorPos; + const QRectF bbox = boundingRect(); + if(child.hasAttributeNS(KoXmlNS::draw, "align")) { + // absolute distances to the edge specified by align + connectorPos.setX(KoUnit::parseValue(xStr)); + connectorPos.setY(KoUnit::parseValue(yStr)); + // TODO: convert position to percentage values taking align attribute into account + } else { + // x and y are relative to drawing object center + if(xStr.endsWith('%')) + connectorPos.setX(xStr.remove('%').toDouble()/100.0); + else + connectorPos.setX(KoUnit::parseValue(xStr) / bbox.width()); + if(yStr.endsWith('%')) + connectorPos.setY(yStr.remove('%').toDouble()/100.0); + else + connectorPos.setY(KoUnit::parseValue(yStr) / bbox.height()); + // convert position to be relative to top-left corner + connectorPos += QPointF(0.5, 0.5); + } + d->connectors[index] = connectorPos; + kDebug(30006) << "loaded glue-point" << index << "at position" << connectorPos; + } + } } return true; diff --git a/libs/flake/KoShape.h b/libs/flake/KoShape.h index 99c4a8dbda8d72a8ec440adf6e71e07d02a2c8fd..eeafdacd74e5277d722bf73656363dfbac24d255 100644 --- a/libs/flake/KoShape.h +++ b/libs/flake/KoShape.h @@ -318,8 +318,15 @@ public: * are based around the zero-pos which is the top-left of the shape * The point does not have to be inside the boundings rectangle. The point is in pt, * just like the rest of the KoShape class uses. + * @return the id of the new connection point */ - void addConnectionPoint(const QPointF &point); + int addConnectionPoint(const QPointF &point); + + /// Checks if a connection point with the specified id exists + bool hasConnectionPoint(int connectionPointId) const; + + /// Returns connection point with specified connection point id + QPointF connectionPoint(int connectionPointId) const; /** * Return a list of the connection points that have been added to this shape. @@ -328,6 +335,12 @@ public: */ QList connectionPoints() const; + /// Removes connection point with specified id + void removeConnectionPoint(int connectionPointId); + + /// Removes all connection points + void clearConnectionPoints(); + /** * Add a event action */ @@ -819,9 +832,6 @@ public: /// checks recursively if the shape or one of its parents is not visible or locked bool isEditable() const; - /// Removes connection point with given index - void removeConnectionPoint(int index); - /** * Adds a shape which depends on this shape. * Making a shape dependent on this one means it will get shapeChanged() called diff --git a/libs/flake/KoShape_p.h b/libs/flake/KoShape_p.h index f52ba8ce3f4e79ee4da5071ebc3be94ff88c038d..d0bb68dcc6bba1b17c83bfef09bb6860f54ca851 100644 --- a/libs/flake/KoShape_p.h +++ b/libs/flake/KoShape_p.h @@ -89,7 +89,7 @@ public: QTransform localMatrix; ///< the shapes local transformation matrix - QVector connectors; ///< glue points in percent of size [0..1] + QMap connectors; ///< glue point id and position in percent of size [0..1] KoShapeContainer *parent; QSet shapeManagers; @@ -142,6 +142,9 @@ public: */ void removeShapeCache(); + /// Returns the specified default connection point + QPointF defaultConnectionPoint(KoFlake::ConnectionPointId connectionPointId); + Q_DECLARE_PUBLIC(KoShape) };