void ArcItem::updateTextPath() { QPainterPath path; if((_endItem && _startItem->collidesWithItem(_endItem)) || (!_endItem && _startItem->contains(_end))) return; QPointF start(0,0), point = _end - pos(); //The arrow line and reverse liune QLineF line(start, point); QLineF revline(point, start); //Make some text if(this->weight() != 1){ QFont font; font.setPointSizeF(6); path.addText(QPointF(0,0), font, QString::number(this->weight())); //Move it into some reasonable position path.translate(-path.boundingRect().width()/2, -3); QTransform rotation; qreal angle = line.angle(); if(angle > 90 && angle < 270) angle = 180 - angle; else angle = 360 - angle; rotation.rotate(angle); path = rotation.map(path); path.translate(point/2); } _cachedTextPath = path; }
void ChordLine::draw(QPainter* painter) const { qreal _spatium = spatium(); if (this->isStraight()) { painter->scale(_spatium, _spatium); painter->setPen(QPen(curColor(), .15, Qt::SolidLine)); painter->setBrush(Qt::NoBrush); QPainterPath pathOffset = path; float offset = 0.5; if (_chordLineType == ChordLineType::FALL) pathOffset.translate(offset, -offset); else if (_chordLineType == ChordLineType::DOIT) pathOffset.translate(offset, offset); else if (_chordLineType == ChordLineType::SCOOP) pathOffset.translate(-offset, offset); else if (_chordLineType == ChordLineType::PLOP) pathOffset.translate(-offset, -offset); painter->drawPath(pathOffset); painter->scale(1.0/_spatium, 1.0/_spatium); } else { painter->scale(_spatium, _spatium); painter->setPen(QPen(curColor(), .15, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter->setBrush(Qt::NoBrush); painter->drawPath(path); painter->scale(1.0/_spatium, 1.0/_spatium); } }
PlainTextItem(QString text, QFont font, double width, double height, QBrush brush, QColor outlineColor, double outline, int align, int lineSpacing) { m_boundingRect = QRectF(0, 0, width, height); m_brush = brush; m_outline = outline; m_pen = QPen(outlineColor); m_pen.setWidthF(outline); QFontMetrics metrics(font); lineSpacing += metrics.lineSpacing(); // Calculate line width QStringList lines = text.split('\n'); double linePos = metrics.ascent(); foreach(const QString &line, lines) { QPainterPath linePath; linePath.addText(0, linePos, font, line); linePos += lineSpacing; if ( align == Qt::AlignHCenter ) { double offset = (width - metrics.width(line)) / 2; linePath.translate(offset, 0); } else if ( align == Qt::AlignRight ) { double offset = (width - metrics.width(line)); linePath.translate(offset, 0); } m_path = m_path.united(linePath); }
void EditorArea::paintMeshElToBeHigh(QPainter &painter) { qreal radius = size2screen(8); float fontSize = size2screen(12); qreal width = radius * 2; qreal height = radius * 2; QPainterPath path; QPainterPath text; QPainterPath circle; path.arcTo(QRectF(-radius, -radius, width, height), 0, 360); text.addText(-radius / 2.0, radius / 2.0, QFont("Arial", fontSize), meshElsType.value(meshElToBeHigh)); circle.arcTo(QRectF(-radius * 3 / 2, -radius * 3 / 2, width * 3 / 2, height * 3 / 2), 0, 360); path.translate(meshElsPos.value(meshElToBeHigh)); text.translate(meshElsPos.value(meshElToBeHigh)); circle.translate(meshElsPos.value(meshElToBeHigh)); painter.setPen(Qt::NoPen); painter.setBrush(Qt::magenta); painter.drawPath(circle); painter.setBrush(Qt::darkCyan); painter.drawPath(path); painter.setPen(Qt::yellow); painter.setBrush(Qt::yellow); painter.drawPath(text); }
void MyTextItem::updateShadow() { QString text = toPlainText(); if (text.isEmpty()) { m_shadow = QImage(); return; } QFontMetrics metrics(font()); //ADJUST TO CURRENT SETTING int lineSpacing = data(TitleDocument::LineSpacing).toInt() + metrics.lineSpacing(); QPainterPath path; // Calculate line width QStringList lines = text.split('\n'); double linePos = metrics.ascent(); QRectF bounding = boundingRect(); foreach(const QString &line, lines) { QPainterPath linePath; linePath.addText(0, linePos, font(), line); linePos += lineSpacing; if ( m_alignment == Qt::AlignHCenter ) { double offset = (bounding.width() - metrics.width(line)) / 2; linePath.translate(offset, 0); } else if ( m_alignment == Qt::AlignRight ) { double offset = (bounding.width() - metrics.width(line)); linePath.translate(offset, 0); } path.addPath(linePath); }
QPainterPath LineBand::path() { //move the path so it accounts for the position of the selectionband QPainterPath temppath = mIntersectionPath; temppath.translate(getTopLeft()); return temppath; }
void MapView::drawArrow(QPainter &painter, const QPoint &p) { QPainterPath path; path.moveTo(0, 0); path.lineTo(1, 0); path.lineTo(7, 15); path.lineTo(0, 10); path.lineTo(-7, 15); path.lineTo(0, 0); path.translate(p); path.translate(0, 2); painter.fillPath(path, QBrush(Qt::yellow)); }
static QPainterPath createArrow() { const qreal arrowHeadPos = 10; const qreal arrowHeadLength = 4; const qreal arrowHeadWidth = 4; const qreal arcWidth = 2; const qreal outerArcSize = arrowHeadPos + arcWidth - arrowHeadLength; const qreal innerArcSize = arrowHeadPos - arcWidth - arrowHeadLength; QPainterPath path; path.moveTo(arrowHeadPos, 0); path.lineTo(arrowHeadPos + arrowHeadWidth, arrowHeadLength); path.lineTo(arrowHeadPos + arcWidth, arrowHeadLength); path.arcTo(QRectF(arrowHeadLength - outerArcSize, arrowHeadLength - outerArcSize, outerArcSize * 2, outerArcSize * 2), 0, -90); path.lineTo(arrowHeadLength, arrowHeadPos + arrowHeadWidth); path.lineTo(0, arrowHeadPos); path.lineTo(arrowHeadLength, arrowHeadPos - arrowHeadWidth); path.lineTo(arrowHeadLength, arrowHeadPos - arcWidth); path.arcTo(QRectF(arrowHeadLength - innerArcSize, arrowHeadLength - innerArcSize, innerArcSize * 2, innerArcSize * 2), -90, 90); path.lineTo(arrowHeadPos - arrowHeadWidth, arrowHeadLength); path.closeSubpath(); path.translate(-3, -3); return path; }
void TopologyNode::updateShapeCache() { QPainterPath shapePath; QString imagePath; #ifdef PLUGIN_TARGET if(mNodeFlags & NF_ISCENTRALROUTER) { Q_ASSERT (m_paintStrategy); imagePath = m_paintStrategy->getImageName(); } else #endif { #ifdef POWERLINE_REVISION if(m_isPowerLine) { imagePath = GENIE2_RES("map/devices/PowerLineNormal.png"); } else #endif { imagePath = getDeviceTypeImagePath(m_deviceType,DTIR_NORMAL); } } QPixmap pixDetecter(imagePath); shapePath.addRegion(QRegion(pixDetecter.mask())); shapePath.translate(-pixDetecter.width() / 2,-pixDetecter.height() / 2); m_shapePath = shapePath; }
/** * @brief RefreshCurve refresh curve on scene. * @param curve curve. * @param curveId curve id. */ void VToolCutSpline::RefreshCurve(VSimpleCurve *curve, quint32 curveId, SimpleCurvePoint curvePosition, PathDirection direction) { const QSharedPointer<VSpline> spl = VAbstractTool::data.GeometricObject<VSpline>(curveId); QPainterPath path; path.addPath(spl->GetPath(direction)); path.setFillRule( Qt::WindingFill ); if (curvePosition == SimpleCurvePoint::FirstPoint) { path.translate(-spl->GetP1().toQPointF().x(), -spl->GetP1().toQPointF().y()); } else { path.translate(-spl->GetP4().toQPointF().x(), -spl->GetP4().toQPointF().y()); } curve->setPath(path); }
void ToolButton::paintEvent(QPaintEvent *) { QPainter p(this); p.setRenderHint(QPainter::Antialiasing); p.setPen(Qt::black); p.setBrush(_flashBackground != Qt::lightGray ? _flashBackground : _mousePressPoint.isNull() ? (_mouseCurrentlyOver ? Qt::darkGray : Qt::lightGray) : Qt::white); p.drawRoundedRect(rect(), 20, 20, Qt::RelativeSize); if (_tool) { p.drawPixmap(2, 2, _tool->icon() .pixmap(iconSize(), _currentlyTriggerable ? QIcon::Normal : QIcon::Disabled)); } if (!_keyLabel.isNull()) { QPainterPath pp; QFont font = this->font(); //QFont font("Sans"); //font.setPointSize(10); pp.addText(QPointF(0, 0), font, _keyLabel); pp.translate(width()-2-pp.boundingRect().width()-pp.boundingRect().x(), height()-2-pp.boundingRect().height()-pp.boundingRect().y()); p.setRenderHint(QPainter::Antialiasing); // LATER parametrize outline and main letter colors p.setBrush(Qt::white); p.setPen(Qt::white); p.drawPath(pp); p.setBrush(Qt::darkBlue); p.setPen(Qt::transparent); p.drawPath(pp); } // LATER use icon rather than text as target indicator QString targetIndicator("?"); switch (_targetType) { case TargetManager::PrimaryTarget: targetIndicator = QString(); break; case TargetManager::PreviousPrimaryTarget: targetIndicator = "p"; break; case TargetManager::MouseOverTarget: targetIndicator = "o"; break; } if (!targetIndicator.isEmpty()) { QFont font = this->font(); //font.setPointSize(10); p.setFont(font); p.setPen(Qt::black); QFontMetrics fm(font); p.drawText(QRectF(2, height()-2-fm.height(), width()-4, fm.maxWidth()), Qt::AlignLeft, targetIndicator); } p.end(); }
void EditorArea::paintNodes(QPainter &painter) { bool firstTime = true; qreal radius = size2screen(6); qreal width = radius * 2; qreal height = radius * 2; QVector<int> nodesIds = workspace->getNodesIds(); for (int i=0; i < nodesIds.size(); i++) { QPointF screenXY = graph2screen(workspace->getNodePosition(nodesIds[i])); if (workspace->getNodeMov(nodesIds[i])) { painter.setPen(Qt::NoPen); } else { painter.setPen(QPen(Qt::darkRed, size2screen(3), Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); } QPainterPath path; path.arcTo(QRectF(-radius, -radius, width, height), 0, 360); path.translate(screenXY); painter.drawPath(path); QPainterPath mousePath; mousePath.arcTo(QRectF(-5, -5, 10, 10), 0, 360); mousePath.translate(mouseCurrentPos); if (path.intersects(mousePath)) { if (firstTime) { firstTime = false; hitElements.clear(); } QPoint temp(1, nodesIds[i]); hitElements.append(temp); } } }
QPainterPath KisChalkPaintOpSettings::brushOutline(const QPointF& pos, KisPaintOpSettings::OutlineMode mode, qreal scale, qreal rotation) const { Q_UNUSED(scale); Q_UNUSED(rotation); QPainterPath path; if (mode == CursorIsOutline){ qreal size = getInt(CHALK_RADIUS) * 2 + 1; QRectF rc(0, 0, size, size); rc.translate(-rc.center()); path.addEllipse(rc); path.translate(pos); } return path; }
void tst_QPainterPath::translate() { QPainterPath path; // Path with no elements. QCOMPARE(path.currentPosition(), QPointF()); path.translate(50.5, 50.5); QCOMPARE(path.currentPosition(), QPointF()); QCOMPARE(path.translated(50.5, 50.5).currentPosition(), QPointF()); // path.isEmpty(), but we have one MoveTo element that should be translated. path.moveTo(50, 50); QCOMPARE(path.currentPosition(), QPointF(50, 50)); path.translate(99.9, 99.9); QCOMPARE(path.currentPosition(), QPointF(149.9, 149.9)); path.translate(-99.9, -99.9); QCOMPARE(path.currentPosition(), QPointF(50, 50)); QCOMPARE(path.translated(-50, -50).currentPosition(), QPointF(0, 0)); // Complex path. QRegion shape(100, 100, 300, 200, QRegion::Ellipse); shape -= QRect(225, 175, 50, 50); QPainterPath complexPath; complexPath.addRegion(shape); QVector<QPointF> untranslatedElements; for (int i = 0; i < complexPath.elementCount(); ++i) untranslatedElements.append(QPointF(complexPath.elementAt(i))); const QPainterPath untranslatedComplexPath(complexPath); const QPointF offset(100, 100); complexPath.translate(offset); for (int i = 0; i < complexPath.elementCount(); ++i) QCOMPARE(QPointF(complexPath.elementAt(i)) - offset, untranslatedElements.at(i)); QCOMPARE(complexPath.translated(-offset), untranslatedComplexPath); }
QPainterPath MapObjectItem::shape() const { QPainterPath path = mMapDocument->renderer()->shape(mObject); #if QT_VERSION >= 0x040600 path.translate(-pos()); #else const QPointF p = pos(); const int elementCount = path.elementCount(); for (int i = 0; i < elementCount; i++) { const QPainterPath::Element &element = path.elementAt(i); path.setElementPositionAt(i, element.x - p.x(), element.y - p.y()); } #endif return path; }
static bool intersect_rect(const QGraphicsItem *item, const QRectF &exposeRect, Qt::ItemSelectionMode mode, const QTransform &deviceTransform, const void *intersectData) { const QRectF sceneRect = *static_cast<const QRectF *>(intersectData); QRectF brect = item->boundingRect(); _q_adjustRect(&brect); // ### Add test for this (without making things slower?) Q_UNUSED(exposeRect); bool keep = true; const QGraphicsItemPrivate *itemd = QGraphicsItemPrivate::get(item); if (itemd->itemIsUntransformable()) { // Untransformable items; map the scene rect to item coordinates. const QTransform transform = item->deviceTransform(deviceTransform); QRectF itemRect = (deviceTransform * transform.inverted()).mapRect(sceneRect); if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect) keep = itemRect.contains(brect) && itemRect != brect; else keep = itemRect.intersects(brect); if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) { QPainterPath itemPath; itemPath.addRect(itemRect); keep = QGraphicsSceneIndexPrivate::itemCollidesWithPath(item, itemPath, mode); } } else { Q_ASSERT(!itemd->dirtySceneTransform); const QRectF itemSceneBoundingRect = itemd->sceneTransformTranslateOnly ? brect.translated(itemd->sceneTransform.dx(), itemd->sceneTransform.dy()) : itemd->sceneTransform.mapRect(brect); if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect) keep = sceneRect != brect && sceneRect.contains(itemSceneBoundingRect); else keep = sceneRect.intersects(itemSceneBoundingRect); if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) { QPainterPath rectPath; rectPath.addRect(sceneRect); if (itemd->sceneTransformTranslateOnly) rectPath.translate(-itemd->sceneTransform.dx(), -itemd->sceneTransform.dy()); else rectPath = itemd->sceneTransform.inverted().map(rectPath); keep = QGraphicsSceneIndexPrivate::itemCollidesWithPath(item, rectPath, mode); } } return keep; }
QPainterPath KisPaintOpSettings::brushOutline(const QPointF& pos, OutlineMode mode, qreal scale, qreal rotation) const { QPainterPath path; if (mode == CursorIsOutline){ QRectF rc(-5,-5, 10, 10); path.moveTo(rc.topLeft()); path.lineTo(rc.bottomRight()); path.moveTo(rc.topRight()); path.lineTo(rc.bottomLeft()); QTransform m; m.reset(); m.scale(scale,scale); m.rotateRadians(rotation); path = m.map(path); path.translate(pos); } return path; }
QPainterPath BallItem::path() const { QPainterPath path; QPolygonF collidingPlgn = collidingPolygon(); QMatrix m; m.rotate(rotation()); QPointF firstP = collidingPlgn.at(0); collidingPlgn.translate(-firstP.x(), -firstP.y()); path.addEllipse(collidingPlgn.boundingRect()); path = m.map(path); path.translate(firstP.x(), firstP.y()); return path; }
QPainterPath KisExperimentPaintOpSettings::brushOutline(const KisPaintInformation &info, KisPaintOpSettings::OutlineMode mode) const { QPainterPath path; if (mode == CursorIsOutline) { QRectF ellipse(0, 0, 3, 3); ellipse.translate(-ellipse.center()); path.addEllipse(ellipse); ellipse.setRect(0,0, 12, 12); ellipse.translate(-ellipse.center()); path.addEllipse(ellipse); path.translate(info.pos()); } return path; }
QPainterPath KisGridPaintOpSettings::brushOutline(const QPointF& pos, KisPaintOpSettings::OutlineMode mode, qreal scale, qreal rotation) const { QPainterPath path; if (mode == CursorIsOutline) { qreal sizex = getInt(GRID_WIDTH) * getDouble(GRID_SCALE) * scale; qreal sizey = getInt(GRID_HEIGHT) * getDouble(GRID_SCALE) * scale; QRectF rc(0, 0, sizex, sizey); rc.translate(-rc.center()); QTransform m; m.reset(); m.rotate(rotation); path = m.map(path); path.addRect(rc); path.translate(pos); } return path; }
/*! * Initializes the path */ QPainterPath * createVehiclePath(OpenScenario::oscObjectBase *vehicle) { QPainterPath *path = new QPainterPath(); double width = 10; double height = 10; oscIntValue *iv = dynamic_cast<oscIntValue *>(vehicle->getMember("category")->getOrCreateValue()); if (iv) { switch (iv->getValue()) { case oscVehicle::car: { QPolygonF polygon; polygon << QPointF(0,0) << QPointF(0,2) << QPointF(0,2) << QPointF(3.7,4) << QPointF(6.3,4) << QPointF(7.7,2) << QPointF(9.2,2) << QPointF(9.8,1.2) << QPointF(10,0); path->addPolygon(polygon); path->closeSubpath(); path->addEllipse(QPointF(2,-0.1), 0.8, 0.8); path->addEllipse(QPointF(8,-0.1), 0.8, 0.8); height = 4; break; } default: { path->addRect(0, 0, 10, 10); } /* truck, trailer, bus, motorbike, bicycle, train, tram,*/ } } path->translate(-width/2, -height/2); return path; }
QDomElement PolaroidBorderDrawer::toSvg(QDomDocument & document) const { QDomElement result = document.createElement("g"); QDomElement path = document.createElement("path"); result.appendChild(path); path.setAttribute("d", pathToSvg(m_path)); path.setAttribute("fill", "#ffffff"); path.setAttribute("fill-rule", "evenodd"); QPainterPath p; p.addText(0, 0, m_font, m_text); p.translate(m_text_rect.center() - p.boundingRect().center()); QDomElement text = document.createElement("path"); result.appendChild(text); text.setAttribute("d", pathToSvg(p)); text.setAttribute("fill", m_color.name()); return result; }
static QPainterPath createResizeArrow(bool straight) { const qreal arrowLength = straight ? 14 : 16; const qreal arrowHeadLength = 4.5; const qreal arrowHeadWidth = 5; const qreal bodyWidth = 1.5; QPainterPath path; path.lineTo(arrowHeadWidth, arrowHeadLength); path.lineTo(0 + bodyWidth, arrowHeadLength); path.lineTo(0 + bodyWidth, arrowLength - arrowHeadLength); path.lineTo(arrowHeadWidth, arrowLength - arrowHeadLength); path.lineTo(0, arrowLength); path.lineTo(-arrowHeadWidth, arrowLength - arrowHeadLength); path.lineTo(0 - bodyWidth, arrowLength - arrowHeadLength); path.lineTo(0 - bodyWidth, arrowHeadLength); path.lineTo(-arrowHeadWidth, arrowHeadLength); path.closeSubpath(); path.translate(0, straight ? 2 : 3); return path; }
QPainterPath PieChart3D::itemExternalPart( qreal angle, qreal delta, bool splitted ) const { QPainterPath ell; ell.addEllipse( myRect ); qreal a = angle / 360.0; if ( a > 1 ) { a -= int(a); } QPointF p1 = ell.pointAtPercent( a ); QPointF offset = QPointF( 0, myHeight ); QPainterPath outside; outside.setFillRule( Qt::WindingFill ); outside.moveTo( p1 ); outside.arcTo( myRect, -angle, -delta ); outside.lineTo( outside.currentPosition() + offset ); outside.arcTo( myRect.translated( 0, myHeight ), -angle - delta, delta ); outside.lineTo( p1 ); if ( splitted == true ) { QPointF p = splittedOffset( angle, delta ); outside.translate( p.x(), p.y() ); } return outside; }
/*! \fn QPainterPath NmHsWidget::shape() Called by home screen fw to check widget boundaries, needed to draw outside widget boundingRect. /return QPainterPath path describing actual boundaries of widget including child items */ QPainterPath NmHsWidget::shape() const { NM_FUNCTION; QPainterPath path; path.setFillRule(Qt::WindingFill); if (mWidgetContainer){ //add mWidgetContainer using geometry to get //correct point for top-left-corner QRectF widgetRect = mWidgetContainer->geometry(); path.addRect(widgetRect); //then fetch shape from title row QPainterPath titlepath; titlepath.addPath(mTitleRow->shape()); //translate it's location to be inside mWidgetContainer titlepath.translate(widgetRect.topLeft()); //and finally add it to path path.addPath(titlepath); } //simplified path, i.e. only outlines return path.simplified(); }
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPainterPath path; //移动当前点到点(50, 250) path.moveTo(50, 250); //从当前点即(50, 250)绘制一条直线到点(50, 230),完成后当前点更改为(50, 230) path.lineTo(50, 230); //从当前点和点(120, 60)之间绘制一条三次贝塞尔曲线 path.cubicTo(QPointF(105, 40), QPointF(115, 80), QPointF(120, 60)); path.lineTo(130, 130); //向路径中添加一个椭圆 path.addEllipse(QPoint(130, 130), 30, 30); painter.setPen(Qt::darkYellow); //绘制路径 painter.drawPath(path); //平移坐标系统后重新绘制路径 path.translate(200,0); painter.setPen(Qt::darkBlue); painter.drawPath(path); }
QPainterPath MapObjectItem::shape() const { QPainterPath path = mMapDocument->renderer()->shape(mObject); path.translate(-pos()); return path; }
void TextEditorOverlay::paintSelection(QPainter *painter, const OverlaySelection &selection) { QTextCursor begin = selection.m_cursor_begin; const QTextCursor &end= selection.m_cursor_end; const QColor &fg = selection.m_fg; const QColor &bg = selection.m_bg; if (begin.isNull() || end.isNull() || begin.position() > end.position()) return; QPainterPath path = createSelectionPath(begin, end, m_editor->viewport()->rect()); painter->save(); QColor penColor = fg; if (m_alpha) penColor.setAlpha(220); QPen pen(penColor, m_borderWidth); painter->translate(-.5, -.5); QRectF pathRect = path.controlPointRect(); if (bg.isValid()) { if (!m_alpha || begin.blockNumber() != end.blockNumber()) { // gradients are too slow for larger selections :( QColor col = bg; if (m_alpha) col.setAlpha(50); painter->setBrush(col); } else { QLinearGradient linearGrad(pathRect.topLeft(), pathRect.bottomLeft()); QColor col1 = fg.lighter(150); col1.setAlpha(20); QColor col2 = fg; col2.setAlpha(80); linearGrad.setColorAt(0, col1); linearGrad.setColorAt(1, col2); painter->setBrush(QBrush(linearGrad)); } } else { painter->setBrush(QBrush()); } painter->setRenderHint(QPainter::Antialiasing); if (selection.m_dropShadow) { painter->save(); QPainterPath shadow = path; shadow.translate(m_dropShadowWidth, m_dropShadowWidth); QPainterPath clip; clip.addRect(m_editor->viewport()->rect()); painter->setClipPath(clip - path); painter->fillPath(shadow, QColor(0, 0, 0, 100)); painter->restore(); } pen.setJoinStyle(Qt::RoundJoin); painter->setPen(pen); painter->drawPath(path); painter->restore(); }
QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, const QTextCursor &end, const QRect &clip) { if (begin.isNull() || end.isNull() || begin.position() > end.position()) return QPainterPath(); QPointF offset = m_editor->contentOffset(); QRect viewportRect = rect(); QTextDocument *document = m_editor->document(); if (m_editor->blockBoundingGeometry(begin.block()).translated(offset).top() > clip.bottom() + 10 || m_editor->blockBoundingGeometry(end.block()).translated(offset).bottom() < clip.top() - 10 ) return QPainterPath(); // nothing of the selection is visible QTextBlock block = begin.block(); if (block.blockNumber() < m_editor->firstVisibleBlock().blockNumber() - 4) block = m_editor->document()->findBlockByNumber(m_editor->firstVisibleBlock().blockNumber() - 4); bool inSelection = false; QVector<QRectF> selection; if (begin.position() == end.position()) { // special case empty selections const QRectF blockGeometry = m_editor->blockBoundingGeometry(block); QTextLayout *blockLayout = block.layout(); int pos = begin.position() - begin.block().position(); QTextLine line = blockLayout->lineForTextPosition(pos); QRectF lineRect = line.naturalTextRect(); int x = line.cursorToX(pos); lineRect.setLeft(x - m_borderWidth); lineRect.setRight(x + m_borderWidth); selection += lineRect.translated(blockGeometry.topLeft()); } else { for (; block.isValid() && block.blockNumber() <= end.blockNumber(); block = block.next()) { if (! block.isVisible()) continue; const QRectF blockGeometry = m_editor->blockBoundingGeometry(block); QTextLayout *blockLayout = block.layout(); QTextLine line = blockLayout->lineAt(0); bool firstOrLastBlock = false; int beginChar = 0; if (!inSelection) { if (block == begin.block()) { beginChar = begin.positionInBlock(); line = blockLayout->lineForTextPosition(beginChar); firstOrLastBlock = true; } inSelection = true; } else { // while (beginChar < block.length() && document->characterAt(block.position() + beginChar).isSpace()) // ++beginChar; // if (beginChar == block.length()) // beginChar = 0; } int lastLine = blockLayout->lineCount()-1; int endChar = -1; if (block == end.block()) { endChar = end.positionInBlock(); lastLine = blockLayout->lineForTextPosition(endChar).lineNumber(); inSelection = false; firstOrLastBlock = true; } else { endChar = block.length(); while (endChar > beginChar && document->characterAt(block.position() + endChar - 1).isSpace()) --endChar; } QRectF lineRect = line.naturalTextRect(); if (beginChar < endChar) { lineRect.setLeft(line.cursorToX(beginChar)); if (line.lineNumber() == lastLine) lineRect.setRight(line.cursorToX(endChar)); selection += lineRect.translated(blockGeometry.topLeft()); for (int lineIndex = line.lineNumber()+1; lineIndex <= lastLine; ++lineIndex) { line = blockLayout->lineAt(lineIndex); lineRect = line.naturalTextRect(); if (lineIndex == lastLine) lineRect.setRight(line.cursorToX(endChar)); selection += lineRect.translated(blockGeometry.topLeft()); } } else { // empty lines const int emptyLineSelectionSize = 16; if (!firstOrLastBlock && !selection.isEmpty()) { // middle lineRect.setLeft(selection.last().left()); } else if (inSelection) { // first line lineRect.setLeft(line.cursorToX(beginChar)); } else { // last line if (endChar == 0) break; lineRect.setLeft(line.cursorToX(endChar) - emptyLineSelectionSize); } lineRect.setRight(lineRect.left() + emptyLineSelectionSize); selection += lineRect.translated(blockGeometry.topLeft()); } if (!inSelection) break; if (blockGeometry.translated(offset).y() > 2*viewportRect.height()) break; } } if (selection.isEmpty()) return QPainterPath(); QVector<QPointF> points; const int margin = m_borderWidth/2; const int extra = 0; const QRectF &firstSelection = selection.at(0); points += (firstSelection.topLeft() + firstSelection.topRight()) / 2 + QPointF(0, -margin); points += firstSelection.topRight() + QPointF(margin+1, -margin); points += firstSelection.bottomRight() + QPointF(margin+1, 0); const int count = selection.count(); for (int i = 1; i < count-1; ++i) { #define MAX3(a,b,c) qMax(a, qMax(b,c)) qreal x = MAX3(selection.at(i-1).right(), selection.at(i).right(), selection.at(i+1).right()) + margin; points += QPointF(x+1, selection.at(i).top()); points += QPointF(x+1, selection.at(i).bottom()); } const QRectF &lastSelection = selection.at(count-1); points += lastSelection.topRight() + QPointF(margin+1, 0); points += lastSelection.bottomRight() + QPointF(margin+1, margin+extra); points += lastSelection.bottomLeft() + QPointF(-margin, margin+extra); points += lastSelection.topLeft() + QPointF(-margin, 0); for (int i = count-2; i > 0; --i) { #define MIN3(a,b,c) qMin(a, qMin(b,c)) qreal x = MIN3(selection.at(i-1).left(), selection.at(i).left(), selection.at(i+1).left()) - margin; points += QPointF(x, selection.at(i).bottom()+extra); points += QPointF(x, selection.at(i).top()); } points += firstSelection.bottomLeft() + QPointF(-margin, extra); points += firstSelection.topLeft() + QPointF(-margin, -margin); QPainterPath path; const int corner = 4; path.moveTo(points.at(0)); points += points.at(0); QPointF previous = points.at(0); for (int i = 1; i < points.size(); ++i) { QPointF point = points.at(i); if (point.y() == previous.y() && qAbs(point.x() - previous.x()) > 2*corner) { QPointF tmp = QPointF(previous.x() + corner * ((point.x() > previous.x())?1:-1), previous.y()); path.quadTo(previous, tmp); previous = tmp; i--; continue; } else if (point.x() == previous.x() && qAbs(point.y() - previous.y()) > 2*corner) { QPointF tmp = QPointF(previous.x(), previous.y() + corner * ((point.y() > previous.y())?1:-1)); path.quadTo(previous, tmp); previous = tmp; i--; continue; } QPointF target = (previous + point) / 2; path.quadTo(previous, target); previous = points.at(i); } path.closeSubpath(); path.translate(offset); return path; }
void MythPainter::DrawTextPriv(MythImage *im, const QString &msg, int flags, const QRect &r, const MythFontProperties &font) { if (!im) return; QColor outlineColor; int outlineSize = 0; int outlineAlpha; if (font.hasOutline()) font.GetOutline(outlineColor, outlineSize, outlineAlpha); QPoint shadowOffset(0, 0); QColor shadowColor; int shadowAlpha; if (font.hasShadow()) font.GetShadow(shadowOffset, shadowColor, shadowAlpha); QFontMetrics fm(font.face()); int totalHeight = fm.height() + outlineSize + std::max(outlineSize, std::abs(shadowOffset.y())); // initialPaddingX is the number of pixels from the left of the // input QRect to the left of the actual text. It is always 0 // because we don't add padding to the text rectangle. int initialPaddingX = 0; // initialPaddingY is the number of pixels from the top of the // input QRect to the top of the actual text. It may be nonzero // because of extra vertical padding. int initialPaddingY = (r.height() - totalHeight) / 2; // Hack. Normally we vertically center the text due to some // (solvable) issues in the SubtitleScreen code - the text rect // and the background rect are both created with PAD_WIDTH extra // padding, and to honor Qt::AlignTop, the text rect needs to be // without padding. This doesn't work for Qt::TextWordWrap, since // the first line will be vertically centered with subsequence // lines below. So if Qt::TextWordWrap is set, we do top // alignment. if (flags & Qt::TextWordWrap) initialPaddingY = 0; // textOffsetX is the number of pixels from r.left() to the left // edge of the core text. This assumes that flags contains // Qt::AlignLeft. int textOffsetX = initialPaddingX + std::max(outlineSize, -shadowOffset.x()); // textOffsetY is the number of pixels from r.top() to the top // edge of the core text. This assumes that flags contains // Qt::AlignTop. int textOffsetY = initialPaddingY + std::max(outlineSize, -shadowOffset.y()); QImage pm(r.size(), QImage::Format_ARGB32); QColor fillcolor = font.color(); if (font.hasOutline()) fillcolor = outlineColor; fillcolor.setAlpha(0); pm.fill(fillcolor.rgba()); QPainter tmp(&pm); QFont tmpfont = font.face(); tmpfont.setStyleStrategy(QFont::OpenGLCompatible); tmp.setFont(tmpfont); QPainterPath path; if (font.hasOutline()) path.addText(0, 0, tmpfont, msg); if (font.hasShadow()) { QRect a = QRect(0, 0, r.width(), r.height()); a.translate(shadowOffset.x() + textOffsetX, shadowOffset.y() + textOffsetY); shadowColor.setAlpha(shadowAlpha); tmp.setPen(shadowColor); tmp.drawText(a, flags, msg); } if (font.hasOutline()) { // QPainter::drawText() treats the Y coordinate as the top of // the text (when Qt::AlignTop is used). However, // QPainterPath::addText() treats the Y coordinate as the base // line of the text. To translate from the top to the base // line, we need to add QFontMetrics::ascent(). int adjX = 0; int adjY = fm.ascent(); outlineColor.setAlpha(outlineAlpha); tmp.setPen(outlineColor); path.translate(adjX + textOffsetX, adjY + textOffsetY); QPen pen = tmp.pen(); pen.setWidth(outlineSize * 2 + 1); pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); tmp.setPen(pen); tmp.drawPath(path); path.translate(outlineSize, outlineSize); } tmp.setPen(QPen(font.GetBrush(), 0)); tmp.setBrush(font.GetBrush()); tmp.drawText(textOffsetX, textOffsetY, r.width(), r.height(), flags, msg); tmp.end(); im->Assign(pm); }