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; } }
void ConnectionTool::paint(QPainter &painter, const KoViewConverter &converter) { // get the correctly sized rect for painting handles QRectF handleRect = handlePaintRect(QPointF()); painter.setRenderHint(QPainter::Antialiasing, true); if (m_currentStrategy) { painter.save(); m_currentStrategy->paint(painter, converter); painter.restore(); } 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; painter.save(); painter.setPen(Qt::black); QTransform transform = shape->absoluteTransformation(0); KoShape::applyConversion(painter, converter); // Draw all the connection points of the shape KoConnectionPoints connectionPoints = shape->connectionPoints(); KoConnectionPoints::const_iterator cp = connectionPoints.constBegin(); KoConnectionPoints::const_iterator lastCp = connectionPoints.constEnd(); for(; cp != lastCp; ++cp) { if (shape == findNonConnectionShapeAtPosition(transform.map(cp.value().position)) ) { handleRect.moveCenter(transform.map(cp.value().position)); painter.setBrush(cp.key() == m_activeHandle && shape == m_currentShape ? Qt::red : Qt::white); painter.drawRect(handleRect); } } painter.restore(); } } // paint connection points or connection handles depending // on the shape the mouse is currently if (m_currentShape && m_editMode == EditConnection) { KoConnectionShape *connectionShape = dynamic_cast<KoConnectionShape*>(m_currentShape); if (connectionShape) { int radius = handleRadius()+1; int handleCount = connectionShape->handleCount(); for(int i = 0; i < handleCount; ++i) { painter.save(); painter.setPen(Qt::blue); painter.setBrush(i == m_activeHandle ? Qt::red : Qt::white); painter.setTransform(connectionShape->absoluteTransformation(&converter) * painter.transform()); connectionShape->paintHandle(painter, converter, i, radius); painter.restore(); } } } }
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; }
void KoPathConnectionPointStrategy::handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) { Q_D(KoPathConnectionPointStrategy); const qreal MAX_DISTANCE = 20.0; // TODO make user definable const qreal MAX_DISTANCE_SQR = MAX_DISTANCE * MAX_DISTANCE; d->newConnectionShape = 0; d->newConnectionId = InvalidConnectionPointId; QRectF roi(mouseLocation - QPointF(MAX_DISTANCE, MAX_DISTANCE), QSizeF(2*MAX_DISTANCE, 2*MAX_DISTANCE)); QList<KoShape*> shapes = d->tool->canvas()->shapeManager()->shapesAt(roi, true); if (shapes.count() < 2) { // we are not near any other shape, so remove the corresponding connection if (d->handleId == 0) d->connectionShape->connectFirst(0, InvalidConnectionPointId); else d->connectionShape->connectSecond(0, InvalidConnectionPointId); KoParameterChangeStrategy::handleMouseMove(mouseLocation, modifiers); } else { qreal minimalDistance = DBL_MAX; QPointF nearestPoint; KoShape *nearestShape = 0; int nearestPointId = InvalidConnectionPointId; Q_FOREACH (KoShape* shape, shapes) { // we do not want to connect to ourself if (shape == d->connectionShape) continue; KoConnectionPoints connectionPoints = shape->connectionPoints(); if (! connectionPoints.count()) { QSizeF size = shape->size(); connectionPoints[-1] = QPointF(0.0, 0.0); connectionPoints[-2] = QPointF(size.width(), 0.0); connectionPoints[-3] = QPointF(size.width(), size.height()); connectionPoints[-4] = QPointF(0.0, size.height()); connectionPoints[-5] = 0.5 * (connectionPoints[-1].position + connectionPoints[-2].position); connectionPoints[-6] = 0.5 * (connectionPoints[-2].position + connectionPoints[-3].position); connectionPoints[-7] = 0.5 * (connectionPoints[-3].position + connectionPoints[-4].position); connectionPoints[-8] = 0.5 * (connectionPoints[-4].position + connectionPoints[-1].position); } QPointF localMousePosition = shape->absoluteTransformation(0).inverted().map(mouseLocation); KoConnectionPoints::const_iterator cp = connectionPoints.constBegin(); KoConnectionPoints::const_iterator lastCp = connectionPoints.constEnd(); for(; cp != lastCp; ++cp) { QPointF difference = localMousePosition - cp.value().position; qreal distance = difference.x() * difference.x() + difference.y() * difference.y(); if (distance > MAX_DISTANCE_SQR) continue; if (distance < minimalDistance) { nearestShape = shape; nearestPoint = cp.value().position; nearestPointId = cp.key(); minimalDistance = distance; } } } if (nearestShape) { nearestPoint = nearestShape->absoluteTransformation(0).map(nearestPoint); } else { nearestPoint = mouseLocation; } d->newConnectionShape = nearestShape; d->newConnectionId = nearestPointId; if (d->handleId == 0) d->connectionShape->connectFirst(nearestShape, nearestPointId); else d->connectionShape->connectSecond(nearestShape, nearestPointId); KoParameterChangeStrategy::handleMouseMove(nearestPoint, modifiers); } }