int ConnectionTool::handleAtPoint(KoShape *shape, const QPointF &mousePoint) const { if (!shape) return -1; const QPointF shapePoint = shape->documentToShape(mousePoint); KoConnectionShape * connectionShape = dynamic_cast<KoConnectionShape*>(shape); if (connectionShape) { // check connection shape handles return connectionShape->handleIdAt(handleGrabRect(shapePoint)); } else { // check connection points int grabDistance = grabSensitivity(); qreal minDistance = HUGE_VAL; int handleId = -1; KoConnectionPoints connectionPoints = shape->connectionPoints(); KoConnectionPoints::const_iterator cp = connectionPoints.constBegin(); KoConnectionPoints::const_iterator lastCp = connectionPoints.constEnd(); for(; cp != lastCp; ++cp) { qreal d = squareDistance(shapePoint, cp.value().position); if (d <= grabDistance && d < minDistance) { handleId = cp.key(); minDistance = d; } } return handleId; } }
KoConnectionShape * ConnectionTool::nearestConnectionShape(const QList<KoShape*> &shapes, const QPointF &mousePos) const { int grabDistance = grabSensitivity(); KoConnectionShape * nearestConnectionShape = 0; qreal minSquaredDistance = HUGE_VAL; const qreal maxSquaredDistance = grabDistance*grabDistance; foreach(KoShape *shape, shapes) { KoConnectionShape * connectionShape = dynamic_cast<KoConnectionShape*>(shape); if (!connectionShape || !connectionShape->isParametricShape()) continue; // convert document point to shape coordinates QPointF p = connectionShape->documentToShape(mousePos); // our region of interest, i.e. a region around our mouse position QRectF roi = handleGrabRect(p); // check all segments of this shape which intersect the region of interest QList<KoPathSegment> segments = connectionShape->segmentsAt(roi); foreach (const KoPathSegment &s, segments) { qreal nearestPointParam = s.nearestPoint(p); QPointF nearestPoint = s.pointAt(nearestPointParam); QPointF diff = p - nearestPoint; qreal squaredDistance = diff.x()*diff.x() + diff.y()*diff.y(); // are we within the allowed distance ? if (squaredDistance > maxSquaredDistance) continue; // are we closer to the last closest point ? if (squaredDistance < minSquaredDistance) { nearestConnectionShape = connectionShape; minSquaredDistance = squaredDistance; } }
QRectF KoToolBase::handleGrabRect(const QPointF &position) const { Q_D(const KoToolBase); const KoViewConverter * converter = d->canvas->viewConverter(); uint handleSize = 2*grabSensitivity(); QRectF r = converter->viewToDocument(QRectF(0, 0, handleSize, handleSize)); r.moveCenter(position); return r; }
void ConnectionTool::mouseReleaseEvent(KoPointerEvent *event) { if (m_currentStrategy) { if (m_editMode == CreateConnection) { // check if connection handles have a minimal distance KoConnectionShape * connectionShape = dynamic_cast<KoConnectionShape*>(m_currentShape); Q_ASSERT(connectionShape); // get both handle positions in document coordinates QPointF p1 = connectionShape->shapeToDocument(connectionShape->handlePosition(0)); QPointF p2 = connectionShape->shapeToDocument(connectionShape->handlePosition(1)); int grabDistance = grabSensitivity(); // use grabbing sensitivity as minimal distance threshold if (squareDistance(p1, p2) < grabDistance*grabDistance) { // minimal distance was not reached, so we have to undo the started work: // - cleanup and delete the strategy // - remove connection shape from shape manager and delete it // - reset edit mode to last state delete m_currentStrategy; m_currentStrategy = 0; repaintDecorations(); canvas()->shapeManager()->remove(m_currentShape); setEditMode(m_editMode, connectionShape->firstShape(), connectionShape->firstConnectionId()); repaintDecorations(); delete connectionShape; return; } else { // finalize adding the new connection shape with an undo command KUndo2Command * cmd = canvas()->shapeController()->addShape(m_currentShape); canvas()->addCommand(cmd); setEditMode(EditConnection, m_currentShape, KoConnectionShape::StartHandle); } } m_currentStrategy->finishInteraction(event->modifiers()); // TODO: Add parent command to KoInteractionStrategy::createCommand // so that we can have a single command to undo for the user KUndo2Command *command = m_currentStrategy->createCommand(); if (command) canvas()->addCommand(command); delete m_currentStrategy; m_currentStrategy = 0; } updateStatusText(); }