void ConnectionTool::repaintDecorations() { const qreal radius = handleRadius(); QRectF repaintRect; if (m_currentShape) { repaintRect = m_currentShape->boundingRect(); canvas()->updateCanvas(repaintRect.adjusted(-radius, -radius, radius, radius)); KoConnectionShape * connectionShape = dynamic_cast<KoConnectionShape*>(m_currentShape); if (!m_resetPaint && m_currentShape->isVisible(true) && !connectionShape) { // only paint connection points of textShapes not inside a tos container and other shapes if ( !(m_currentShape->shapeId() == TextShape_SHAPEID && dynamic_cast<KoTosContainer*>(m_currentShape->parent())) ) { KoConnectionPoints connectionPoints = m_currentShape->connectionPoints(); KoConnectionPoints::const_iterator cp = connectionPoints.constBegin(); KoConnectionPoints::const_iterator lastCp = connectionPoints.constEnd(); for(; cp != lastCp; ++cp) { repaintRect = handleGrabRect(m_currentShape->shapeToDocument(cp.value().position)); canvas()->updateCanvas(repaintRect.adjusted(-radius, -radius, radius, radius)); } } } if (m_editMode == EditConnection) { if (connectionShape) { QPointF handlePos = connectionShape->handlePosition(m_activeHandle); handlePos = connectionShape->shapeToDocument(handlePos); repaintRect = handlePaintRect(handlePos); canvas()->updateCanvas(repaintRect.adjusted(-radius, -radius, radius, radius)); } } } if (m_resetPaint) { QList<KoShape*> shapes = canvas()->shapeManager()->shapes(); for (QList<KoShape*>::const_iterator end = shapes.constBegin(); end != shapes.constEnd(); ++end) { KoShape* shape = *end; if (!dynamic_cast<KoConnectionShape*>(shape)) { // only paint connection points of textShapes not inside a tos container and other shapes if (shape->shapeId() == TextShape_SHAPEID && dynamic_cast<KoTosContainer*>(shape->parent())) continue; KoConnectionPoints connectionPoints = shape->connectionPoints(); KoConnectionPoints::const_iterator cp = connectionPoints.constBegin(); KoConnectionPoints::const_iterator lastCp = connectionPoints.constEnd(); for(; cp != lastCp; ++cp) { repaintRect = handleGrabRect(shape->shapeToDocument(cp.value().position)); canvas()->updateCanvas(repaintRect.adjusted(-radius, -radius, radius, radius)); } } } } m_resetPaint = false; }
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; } }
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; } }
KoShape * ConnectionTool::findNonConnectionShapeAtPosition(const QPointF &position) const { QList<KoShape*> shapes = canvas()->shapeManager()->shapesAt(handleGrabRect(position)); if (!shapes.isEmpty()) { qSort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex); for (QList<KoShape*>::const_iterator end = shapes.constEnd()-1; end >= shapes.constBegin(); --end) { KoShape* shape = *end; if (!dynamic_cast<KoConnectionShape*>(shape) && shape->shapeId() != TextShape_SHAPEID) { return shape; } } } return 0; }
void KoCreatePathTool::mouseMoveEvent(KoPointerEvent *event) { Q_D(KoCreatePathTool); KoPathPoint *endPoint = d->endPointAtPosition(event->point); if (d->hoveredPoint != endPoint) { if (d->hoveredPoint) { QPointF nodePos = d->hoveredPoint->parent()->shapeToDocument(d->hoveredPoint->point()); canvas()->updateCanvas(handlePaintRect(nodePos)); } d->hoveredPoint = endPoint; if (d->hoveredPoint) { QPointF nodePos = d->hoveredPoint->parent()->shapeToDocument(d->hoveredPoint->point()); canvas()->updateCanvas(handlePaintRect(nodePos)); } } if (!pathStarted()) { canvas()->updateCanvas(canvas()->snapGuide()->boundingRect()); canvas()->snapGuide()->snap(event->point, event->modifiers()); canvas()->updateCanvas(canvas()->snapGuide()->boundingRect()); d->mouseOverFirstPoint = false; return; } d->mouseOverFirstPoint = handleGrabRect(d->firstPoint->point()).contains(event->point); canvas()->updateCanvas(d->shape->boundingRect()); canvas()->updateCanvas(canvas()->snapGuide()->boundingRect()); QPointF snappedPosition = canvas()->snapGuide()->snap(event->point, event->modifiers()); d->repaintActivePoint(); if (event->buttons() & Qt::LeftButton) { d->pointIsDragged = true; QPointF offset = snappedPosition - d->activePoint->point(); d->activePoint->setControlPoint2(d->activePoint->point() + offset); // pressing <alt> stops controls points moving symmetrically if ((event->modifiers() & Qt::AltModifier) == 0) d->activePoint->setControlPoint1(d->activePoint->point() - offset); d->repaintActivePoint(); } else { d->activePoint->setPoint(snappedPosition); } canvas()->updateCanvas(d->shape->boundingRect()); canvas()->updateCanvas(canvas()->snapGuide()->boundingRect()); }
KoShape * ConnectionTool::findShapeAtPosition(const QPointF &position) const { QList<KoShape*> shapes = canvas()->shapeManager()->shapesAt(handleGrabRect(position)); if (!shapes.isEmpty()) { qSort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex); // we want to priorize connection shape handles, even if the connection shape // is not at the top of the shape stack at the mouse position KoConnectionShape *connectionShape = nearestConnectionShape(shapes, position); // use best connection shape or first shape from stack (last in the list) if not found if (connectionShape) { return connectionShape; } else { for (QList<KoShape*>::const_iterator end = shapes.constEnd()-1; end >= shapes.constBegin(); --end) { KoShape* shape = *end; if (!dynamic_cast<KoConnectionShape*>(shape) && shape->shapeId() != TextShape_SHAPEID) { return shape; } } } } return 0; }
void KoCreatePathTool::mousePressEvent(KoPointerEvent *event) { Q_D(KoCreatePathTool); //Right click removes last point if (event->button() == Qt::RightButton) { removeLastPoint(); return; } const bool isOverFirstPoint = d->shape && handleGrabRect(d->firstPoint->point()).contains(event->point); bool haveCloseModifier = (listeningToModifiers() && (event->modifiers() & Qt::ShiftModifier)); if ((event->button() == Qt::LeftButton) && haveCloseModifier && !isOverFirstPoint) { endPathWithoutLastPoint(); return; } d->finishAfterThisPoint = false; if (pathStarted()) { if (isOverFirstPoint) { d->activePoint->setPoint(d->firstPoint->point()); canvas()->updateCanvas(d->shape->boundingRect()); canvas()->updateCanvas(canvas()->snapGuide()->boundingRect()); if (haveCloseModifier) { d->shape->closeMerge(); // we are closing the path, so reset the existing start path point d->existingStartPoint = 0; // finish path endPath(); } else { // the path shape will get closed when the user releases // the mouse button d->finishAfterThisPoint = true; } } else { canvas()->updateCanvas(canvas()->snapGuide()->boundingRect()); QPointF point = canvas()->snapGuide()->snap(event->point, event->modifiers()); // check whether we hit an start/end node of an existing path d->existingEndPoint = d->endPointAtPosition(point); if (d->existingEndPoint.isValid() && d->existingEndPoint != d->existingStartPoint) { point = d->existingEndPoint.path->shapeToDocument(d->existingEndPoint.point->point()); d->activePoint->setPoint(point); // finish path endPath(); } else { d->activePoint->setPoint(point); canvas()->updateCanvas(d->shape->boundingRect()); canvas()->updateCanvas(canvas()->snapGuide()->boundingRect()); } } } else { KoPathShape *pathShape = new KoPathShape(); d->shape=pathShape; pathShape->setShapeId(KoPathShapeId); KoShapeStroke *stroke = new KoShapeStroke(canvas()->resourceManager()->activeStroke()); stroke->setColor(canvas()->resourceManager()->foregroundColor().toQColor()); pathShape->setStroke(stroke); canvas()->updateCanvas(canvas()->snapGuide()->boundingRect()); QPointF point = canvas()->snapGuide()->snap(event->point, event->modifiers()); // check whether we hit an start/end node of an existing path d->existingStartPoint = d->endPointAtPosition(point); if (d->existingStartPoint.isValid()) { point = d->existingStartPoint.path->shapeToDocument(d->existingStartPoint.point->point()); } d->activePoint = pathShape->moveTo(point); d->firstPoint = d->activePoint; canvas()->updateCanvas(handlePaintRect(point)); canvas()->updateCanvas(canvas()->snapGuide()->boundingRect()); canvas()->snapGuide()->setEditedShape(pathShape); d->angleSnapStrategy = new AngleSnapStrategy(d->angleSnappingDelta, d->angleSnapStatus); canvas()->snapGuide()->addCustomSnapStrategy(d->angleSnapStrategy); } if (d->angleSnapStrategy) d->angleSnapStrategy->setStartPoint(d->activePoint->point()); }