QPainterPath CPcbCircle::path() { QPainterPath ppath; QPoint topLeft(-radius(),-radius()); QPoint bottomRight(radius(),radius()); ppath.addEllipse(QRectF(topLeft,bottomRight)); return ppath.simplified(); }
void BalloonTip::paintEvent(QPaintEvent * /*ev*/) { QPainter painter(this); painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); painter.setBrush(Qt::white); painter.setPen(QColor(0, 0, 0, 130)); painter.setFont(this->font()); QRect popupRect = relativePopupRect(); QRect textRect = relativeTextRect(); QPainterPath path; QPolygon arrowTriangle; switch (my_arrowPos) { case BottomLeft: arrowTriangle << QPoint(30, popupRect.height() + 60) << QPoint(60, popupRect.height() + 30) << QPoint(90, popupRect.height() + 30); break; case TopLeft: arrowTriangle << QPoint(30, 0) << QPoint(60, 15) << QPoint(90, 15); break; case BottomRight: arrowTriangle << QPoint(popupRect.width() - 30, popupRect.height() + 60) << QPoint(popupRect.width() - 60, popupRect.height() + 30) << QPoint(popupRect.width() - 90, popupRect.height() + 30); break; case TopRight: arrowTriangle << QPoint(popupRect.width() - 30, 0) << QPoint(popupRect.width() - 60, 30) << QPoint(popupRect.width() - 90, 30); break; case LeftTop: arrowTriangle << QPoint(popupRect.left() - 10, popupRect.height() * 0.6) << QPoint(popupRect.left(), popupRect.height() * 0.6 + 5) << QPoint(popupRect.left(), popupRect.height() * 0.6 - 5); break; } path.addPolygon(arrowTriangle); path.addRoundedRect(popupRect, 1, 1); path = path.simplified(); painter.drawPath(path); painter.setPen(QColor(20, 20, 20)); painter.drawText(textRect, my_text); QFont font = this->font(); font.setBold(true); font.setPixelSize(12); painter.setFont(font); painter.setPen(QColor(48, 159, 220)); if (!my_icon.isNull()) { painter.drawText(textRect.topLeft() + QPoint(20, -10), my_title); painter.drawPixmap(textRect.topLeft() + QPoint(0, -22), my_icon); } else { painter.drawText(textRect.topLeft() + QPoint(5, -10), my_title); } }
void KisGradientPainterTest::testSplitDisjointPaths() { QPainterPath path; // small bug: the smaller rect is also merged path.addRect(QRectF(323, 123, 4, 4)); path.addRect(QRectF(300, 100, 50, 50)); path.addRect(QRectF(320, 120, 10, 10)); path.addRect(QRectF(200, 100, 50, 50)); path.addRect(QRectF(240, 120, 70, 10)); path.addRect(QRectF(100, 100, 50, 50)); path.addRect(QRectF(120, 120, 10, 10)); path = path.simplified(); { QImage srcImage(450, 250, QImage::Format_ARGB32); srcImage.fill(0); QPainter gc(&srcImage); gc.fillPath(path, Qt::red); //srcImage.save("src_disjoint_paths.png"); } QList<QPainterPath> result = KritaUtils::splitDisjointPaths(path); { QImage dstImage(450, 250, QImage::Format_ARGB32); dstImage.fill(0); QPainter gc(&dstImage); QVector<QBrush> brushes; brushes << Qt::red; brushes << Qt::green; brushes << Qt::blue; brushes << Qt::cyan; brushes << Qt::magenta; brushes << Qt::yellow; brushes << Qt::black; brushes << Qt::white; int index = 0; Q_FOREACH (const QPainterPath &p, result) { gc.fillPath(p, brushes[index]); index = (index + 1) % brushes.size(); } TestUtil::checkQImageExternal(dstImage, "shaped_gradient", "test", "disjoint_paths"); }
void Callout::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* w) { Q_UNUSED(option); Q_UNUSED(w); QPainterPath path; path.addRoundedRect(rect, 5, 5); auto anchor = mapFromParent(chart->mapToPosition(this->anchor)); if (!rect.contains(anchor)) { QPointF point1, point2; // establish the position of the anchor point in relation to rect auto above = anchor.y() <= rect.top(); auto aboveCenter = anchor.y() > rect.top() && anchor.y() <= rect.center().y(); auto belowCenter = anchor.y() > rect.center().y() && anchor.y() <= rect.bottom(); auto below = anchor.y() > rect.bottom(); auto onLeft = anchor.x() <= rect.left(); auto leftOfCenter = anchor.x() > rect.left() && anchor.x() <= rect.center().x(); auto rightOfCenter = anchor.x() > rect.center().x() && anchor.x() <= rect.right(); auto onRight = anchor.x() > rect.right(); // get the nearest rect corner. auto x = (onRight + rightOfCenter) * rect.width(); auto y = (below + belowCenter) * rect.height(); auto cornerCase = (above && onLeft) || (above && onRight) || (below && onLeft) || (below && onRight); auto vertical = qAbs(anchor.x() - x) > qAbs(anchor.y() - y); auto x1 = x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCase * !vertical * (onLeft * 10 - onRight * 20); auto y1 = y + aboveCenter * 10 - belowCenter * 20 + cornerCase * vertical * (above * 10 - below * 20);; point1.setX(x1); point1.setY(y1); auto x2 = x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCase * !vertical * (onLeft * 20 - onRight * 10);; auto y2 = y + aboveCenter * 20 - belowCenter * 10 + cornerCase * vertical * (above * 20 - below * 10);; point2.setX(x2); point2.setY(y2); path.moveTo(point1); path.lineTo(anchor); path.lineTo(point2); path = path.simplified(); } painter->setBrush(QColor(255, 255, 255)); painter->drawPath(path); painter->drawText(textRect, text); }
void TitleBar::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setBrush(_background); painter.setPen(Qt::NoPen); painter.setRenderHint(QPainter::Antialiasing); QPainterPath path; path.setFillRule(Qt::WindingFill); path.addRoundedRect(QRect(0, 0, width(), height()), _radius, _radius); //bottomRight path.addRect(QRect(width() - _radius, height() - _radius, _radius, _radius)); //bottomLeft path.addRect(QRect(0, height() - _radius, _radius, _radius)); painter.drawPath(path.simplified()); }
void Window::paintEvent(QPaintEvent *) { QPainter painter(this); if (_hasShadow) { drawShadow(painter, _borderWidth, _radius, QColor(120, 120, 120, 32), QColor(255, 255, 255, 0), 0.0, 1.0, 0.6, width(), height()); } else { painter.setBrush(QColor("#FFFFFF")); painter.setPen(Qt::NoPen); painter.setRenderHint(QPainter::Antialiasing); QPainterPath path; path.setFillRule(Qt::WindingFill); path.addRoundedRect(QRect(0, 0, width(), height()), _radius, _radius); painter.drawPath(path.simplified()); } }
QPainterPath XYTempWindows::getPainterPath(const QRect &rect, XYTempWindows::DIRECTION direction) { QPainterPath path; int arrow_h = 5; switch (direction) { case TOP: arrow_h = rect.height() * 0.1; textRect = QRect(rect.x() + 1, rect.y() + arrow_h + 1, rect.width() - 2, rect.height() - arrow_h - 2); path.addRoundedRect(textRect, 4, 4); path.moveTo(rect.x() + rect.width() / 2 - arrow_h / 2, rect.y() + arrow_h + 1); path.lineTo(rect.x() + rect.width() / 2, rect.y()); path.lineTo(rect.x() + rect.width() / 2 + arrow_h / 2, rect.y() + arrow_h + 1); break; case BOTTOM: arrow_h = rect.height() * 0.1; textRect = QRect(rect.x() + 1, rect.y() + 1, rect.width() - 2, rect.height() - arrow_h - 1); path.addRoundedRect(textRect, 4, 4); path.moveTo(rect.x() + rect.width() / 2 - arrow_h / 2, rect.y() + rect.height() - arrow_h); path.lineTo(rect.x() + rect.width() / 2, rect.y() + rect.height()); path.lineTo(rect.x() + rect.width() / 2 + arrow_h / 2, rect.y() + rect.height() - arrow_h); break; case LEFT: arrow_h = rect.height() * 0.1; textRect = QRect(rect.x() + arrow_h, rect.y() + 1, rect.width() - arrow_h - 2, rect.height() - 2); path.addRoundedRect(textRect, 4, 4); path.moveTo(rect.x() + arrow_h, rect.y() + rect.height() / 2 - arrow_h / 2); path.lineTo(rect.x() - 2, rect.y() + rect.height() / 2); path.lineTo(rect.x() + arrow_h, rect.y() + rect.height() / 2 + arrow_h / 2); break; case RIGHT: arrow_h = rect.height() * 0.1; textRect = QRect(rect.x() + 1, rect.y() + 1, rect.width() - arrow_h - 2, rect.height() - 2); path.addRoundedRect(textRect, 4, 4); path.moveTo(rect.x() - 1 + rect.width() - arrow_h, rect.y() + rect.height() / 2 - arrow_h / 2); path.lineTo(rect.x() - 1 + rect.width(), rect.y() + rect.height() / 2); path.lineTo(rect.x() - 1 + rect.width() - arrow_h, rect.y() + rect.height() / 2 + arrow_h / 2); break; default: break; } return path.simplified(); }
QPainterPath EvButton::textPath() const { QPainterPath path; path.setFillRule( Qt::WindingFill); QRect rect = textRect(); if(m_rounded){ float roundness = this->roundness(); path.addRoundRect( rect, roundness ); path.addRect( QRect(rect.x(),0, roundness,roundness ) ); path.addRect( QRect( rect.x(),rect.y() , roundness,roundness ) ); } else{ path.addRect(rect); } return path.simplified(); }
QPolygonF Carton::outline() const { #if QT_VERSION >= 0x040400 QPainterPath painterPath; if (isFaceVisibleFromFront(Top)) painterPath.addPolygon(face2d(Top)); if (isFaceVisibleFromFront(Left)) painterPath.addPolygon(face2d(Left)); else if (isFaceVisibleFromFront(Right)) painterPath.addPolygon(face2d(Right)); if (isFaceVisibleFromFront(Front)) painterPath.addPolygon(face2d(Front)); else if (isFaceVisibleFromFront(Back)) painterPath.addPolygon(face2d(Back)); return painterPath.simplified().toFillPolygon(); #else return QPolygonF(); #endif }
/*! \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(); }
static QPainterPath qwtCombinePathList( const QRectF &rect, const QList<QPainterPath> &pathList ) { if ( pathList.isEmpty() ) return QPainterPath(); QPainterPath ordered[8]; // starting top left for ( int i = 0; i < pathList.size(); i++ ) { int index = -1; QPainterPath subPath = pathList[i]; const QRectF br = pathList[i].controlPointRect(); if ( br.center().x() < rect.center().x() ) { if ( br.center().y() < rect.center().y() ) { if ( qAbs( br.top() - rect.top() ) < qAbs( br.left() - rect.left() ) ) { index = 1; } else { index = 0; } } else { if ( qAbs( br.bottom() - rect.bottom() ) < qAbs( br.left() - rect.left() ) ) { index = 6; } else { index = 7; } } if ( subPath.currentPosition().y() > br.center().y() ) qwtRevertPath( subPath ); } else { if ( br.center().y() < rect.center().y() ) { if ( qAbs( br.top() - rect.top() ) < qAbs( br.right() - rect.right() ) ) { index = 2; } else { index = 3; } } else { if ( qAbs( br.bottom() - rect.bottom() ) < qAbs( br.right() - rect.right() ) ) { index = 5; } else { index = 4; } } if ( subPath.currentPosition().y() < br.center().y() ) qwtRevertPath( subPath ); } ordered[index] = subPath; } for ( int i = 0; i < 4; i++ ) { if ( ordered[ 2 * i].isEmpty() != ordered[2 * i + 1].isEmpty() ) { // we don't accept incomplete rounded borders return QPainterPath(); } } const QPolygonF corners( rect ); QPainterPath path; //path.moveTo( rect.topLeft() ); for ( int i = 0; i < 4; i++ ) { if ( ordered[2 * i].isEmpty() ) { path.lineTo( corners[i] ); } else { path.connectPath( ordered[2 * i] ); path.connectPath( ordered[2 * i + 1] ); } } path.closeSubpath(); #if 0 return path.simplified(); #else return path; #endif }
void QWaylandMaterialDecoration::paint(QPaintDevice *device) { QRect surfaceRect(QPoint(), window()->frameGeometry().size()); QRect top(QPoint(), QSize(window()->frameGeometry().width(), margins().top())); QPainter p(device); p.setRenderHint(QPainter::Antialiasing); // Title bar int radius = waylandWindow()->isMaximized() ? 0 : dp(3); QPainterPath roundedRect; roundedRect.addRoundedRect(0, 0, window()->frameGeometry().width(), margins().top() * 1.5, radius, radius); p.fillPath(roundedRect.simplified(), m_backgroundColor); // Window icon QIcon icon = waylandWindow()->windowIcon(); if (!icon.isNull()) { QPixmap pixmap = icon.pixmap(QSize(128, 128)); QPixmap scaled = pixmap.scaled(22, 22, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); QRectF iconRect(0, 0, 22, 22); p.drawPixmap(iconRect.adjusted(margins().left() + BUTTON_SPACING, 4, margins().left() + BUTTON_SPACING, 4), scaled, iconRect); } // Window title QString windowTitleText = window()->title(); if (!windowTitleText.isEmpty()) { if (m_windowTitle.text() != windowTitleText) { m_windowTitle.setText(windowTitleText); m_windowTitle.prepare(); } QRect titleBar = top; titleBar.setLeft(margins().left() + BUTTON_SPACING + (icon.isNull() ? 0 : 22 + BUTTON_SPACING)); titleBar.setRight(minimizeButtonRect().left() - BUTTON_SPACING); p.save(); p.setClipRect(titleBar); p.setPen(m_textColor); QSizeF size = m_windowTitle.size(); int dx = (top.width() - size.width()) / 2; int dy = (top.height() - size.height()) / 2; QFont font = p.font(); font.setBold(true); font.setFamily("Roboto"); p.setFont(font); QPoint windowTitlePoint(top.topLeft().x() + dx, top.topLeft().y() + dy); p.drawStaticText(windowTitlePoint, m_windowTitle); p.restore(); } p.save(); p.setPen(m_iconColor); // Close button QBitmap closeIcon = buttonIcon("window-close"); p.drawPixmap(closeButtonRect(), closeIcon, closeIcon.rect()); // Maximize button QBitmap maximizeIcon = buttonIcon(waylandWindow()->isMaximized() ? "window-restore" : "window-maximize"); p.drawPixmap(maximizeButtonRect(), maximizeIcon, maximizeIcon.rect()); // Minimize button QBitmap minimizeIcon = buttonIcon("window-minimize"); p.drawPixmap(minimizeButtonRect(), minimizeIcon, minimizeIcon.rect()); p.restore(); }
void QRibbonComboBoxStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const { QProxyStyle::drawComplexControl(control, option, painter, widget); int rightButtonWidth = 18; int x = option->rect.x(); int y = option->rect.y(); int cbWidth = option->rect.width(); int cbHeight = option->rect.height(); float arrowX = cbWidth - arrowWidth - (rightButtonWidth - arrowWidth) / 2.0; float arrowY = (cbHeight - arrowHeight) / 2.0; QPainterPath* painterPath = new QPainterPath(); // Erase the old border QRect* borderErased = new QRect(1, 1, cbWidth - 2, cbHeight - 2); painterPath->addRoundedRect(*borderErased, 0, 0); painter->strokePath(painterPath->simplified(), QPen(Qt::white, 2)); QDELETE(borderErased); QDELETE(painterPath); // Erase the right button part QRect* rightPartErased = new QRect(0, 0, rightButtonWidth, cbHeight); rightPartErased->moveLeft(cbWidth - rightButtonWidth); painter->fillRect(*rightPartErased, Qt::white); QDELETE(rightPartErased); // Paint the border of button painterPath = new QPainterPath(); QRect* border = new QRect(0, 0, cbWidth - 1, cbHeight - 1); painterPath->addRoundedRect(*border, 0, 0); bool isHovered = option->state & State_MouseOver; bool isOpened = option->state & (State_On | State_Sunken); if (isOpened == true) { painter->strokePath(painterPath->simplified(), QPen(QColor("#0078d7"), 1)); } else { painter->strokePath(painterPath->simplified(), QPen(QColor("#5c5c5c"), 1)); } QDELETE(border); QDELETE(painterPath); QPoint globalCursorPos = QCursor::pos(); QPoint widgetPos = widget->mapFromGlobal(globalCursorPos); // Paint the right part of combobox if ((isHovered == true || isOpened == true) && widgetPos.x() >= (cbWidth - rightButtonWidth) && widgetPos.x() <= cbWidth) { QColor hoveredColor(Qt::green); QRect* hoverRightPart = new QRect(0, 0, rightButtonWidth, cbHeight); hoverRightPart->moveLeft(cbWidth - rightButtonWidth); painter->fillRect(*hoverRightPart, hoveredColor); QDELETE(hoverRightPart); // Draw right button border painterPath = new QPainterPath(); QRect* rightButtonBorder = new QRect(cbWidth - rightButtonWidth, 0, rightButtonWidth - 1, cbHeight - 1); painterPath->addRoundedRect(*rightButtonBorder, 0, 0); painter->strokePath(painterPath->simplified(), QPen(QColor("#0078d7"), 1)); QDELETE(rightButtonBorder); QDELETE(painterPath); } // Draw the down arrow painter->setPen(QPen(QColor("#5c5c5c"), 2)); QLineF arrowDown(QPointF(arrowX, arrowY), QPointF(arrowX + arrowHeight, arrowY + arrowHeight)); painter->drawLine(arrowDown); arrowDown.setLine(arrowX + arrowHeight, arrowY + arrowHeight, arrowX + arrowWidth, arrowY); painter->drawLine(arrowDown); }
void TextLayer::recreateTexture(VidgfxContext *gfx) { if(!m_isTexDirty) return; // Don't waste any time if it hasn't changed m_isTexDirty = false; // Delete existing texture if one exists if(m_texture != NULL) vidgfx_context_destroy_tex(gfx, m_texture); m_texture = NULL; // Determine texture size. We need to keep in mind that the text in the // document might extend outside of the layer's bounds. m_document.setTextWidth(m_rect.width()); QSize size( (int)ceilf(m_document.size().width()), (int)ceilf(m_document.size().height())); if(m_document.isEmpty() || size.isEmpty()) { // Nothing to display return; } // Create temporary canvas. We need to be careful here as text is rendered // differently on premultiplied vs non-premultiplied pixel formats. On a // premultiplied format text is rendered with subpixel rendering enabled // while on a non-premultiplied format it is not. As we don't want subpixel // rendering we use the standard ARGB32 format. QSize imgSize( size.width() + m_strokeSize * 2, size.height() + m_strokeSize * 2); QImage img(imgSize, QImage::Format_ARGB32); img.fill(Qt::transparent); QPainter p(&img); p.setRenderHint(QPainter::Antialiasing, true); // Render text //m_document.drawContents(&p); // Render stroke if(m_strokeSize > 0) { #define STROKE_TECHNIQUE 0 #if STROKE_TECHNIQUE == 0 // Technique 0: Use QTextDocument's built-in text outliner //quint64 timeStart = App->getUsecSinceExec(); QTextDocument *outlineDoc = m_document.clone(this); QTextCharFormat format; QPen pen(m_strokeColor, (double)(m_strokeSize * 2)); pen.setJoinStyle(Qt::RoundJoin); format.setTextOutline(pen); QTextCursor cursor(outlineDoc); cursor.select(QTextCursor::Document); cursor.mergeCharFormat(format); // Take into account the stroke offset p.translate(m_strokeSize, m_strokeSize); //quint64 timePath = App->getUsecSinceExec(); outlineDoc->drawContents(&p); delete outlineDoc; //quint64 timeEnd = App->getUsecSinceExec(); //appLog() << "Path time = " << (timePath - timeStart) << " usec"; //appLog() << "Render time = " << (timeEnd - timePath) << " usec"; //appLog() << "Full time = " << (timeEnd - timeStart) << " usec"; #elif STROKE_TECHNIQUE == 1 // Technique 1: Create a text QPainterPath and stroke it quint64 timeStart = App->getUsecSinceExec(); // Create the path for the text's stroke QPainterPath path; QTextBlock &block = m_document.firstBlock(); int numBlocks = m_document.blockCount(); for(int i = 0; i < numBlocks; i++) { QTextLayout *layout = block.layout(); for(int j = 0; j < layout->lineCount(); j++) { QTextLine &line = layout->lineAt(j); const QString text = block.text().mid( line.textStart(), line.textLength()); QPointF pos = layout->position() + line.position(); pos.ry() += line.ascent(); //appLog() << pos << ": " << text; path.addText(pos, block.charFormat().font(), text); } block = block.next(); } quint64 timePath = App->getUsecSinceExec(); path = path.simplified(); // Fixes gaps with large stroke sizes quint64 timeSimplify = App->getUsecSinceExec(); // Render the path //p.strokePath(path, QPen(m_strokeColor, m_strokeSize)); // Convert it to a stroke QPainterPathStroker stroker; stroker.setWidth(m_strokeSize); //stroker.setCurveThreshold(2.0); stroker.setJoinStyle(Qt::RoundJoin); path = stroker.createStroke(path); // Render the path p.fillPath(path, m_strokeColor); quint64 timeEnd = App->getUsecSinceExec(); appLog() << "Path time = " << (timePath - timeStart) << " usec"; appLog() << "Simplify time = " << (timeSimplify - timePath) << " usec"; appLog() << "Render time = " << (timeEnd - timeSimplify) << " usec"; appLog() << "Full time = " << (timeEnd - timeStart) << " usec"; #elif STROKE_TECHNIQUE == 2 // Technique 2: Similar to technique 1 but do each block separately quint64 timeStart = App->getUsecSinceExec(); quint64 timeTotalSimplify = 0; quint64 timeTotalRender = 0; // Create the path for the text's stroke QTextBlock &block = m_document.firstBlock(); int numBlocks = m_document.blockCount(); for(int i = 0; i < numBlocks; i++) { // Convert this block to a painter path QPainterPath path; QTextLayout *layout = block.layout(); for(int j = 0; j < layout->lineCount(); j++) { QTextLine &line = layout->lineAt(j); const QString text = block.text().mid( line.textStart(), line.textLength()); QPointF pos = layout->position() + line.position() + QPointF(m_strokeSize, m_strokeSize); pos.ry() += line.ascent(); //appLog() << pos << ": " << text; path.addText(pos, block.charFormat().font(), text); } // Prevent gaps appearing at larger stroke sizes quint64 timeA = App->getUsecSinceExec(); path = path.simplified(); quint64 timeB = App->getUsecSinceExec(); timeTotalSimplify += timeB - timeA; // Render the path QPen pen(m_strokeColor, m_strokeSize * 2); pen.setJoinStyle(Qt::RoundJoin); p.strokePath(path, pen); timeA = App->getUsecSinceExec(); timeTotalRender += timeA - timeB; // Iterate block = block.next(); } // Make the final draw take into account the stroke offset p.translate(m_strokeSize, m_strokeSize); quint64 timeEnd = App->getUsecSinceExec(); appLog() << "Simplify time = " << timeTotalSimplify << " usec"; appLog() << "Render time = " << timeTotalRender << " usec"; appLog() << "Full time = " << (timeEnd - timeStart) << " usec"; #elif STROKE_TECHNIQUE == 3 // Technique 3: Raster brute-force where for each destination pixel // we measure the distance to the closest opaque source pixel quint64 timeStart = App->getUsecSinceExec(); // Get bounding region based on text line bounding rects QRegion region; QTextBlock &block = m_document.firstBlock(); int numBlocks = m_document.blockCount(); for(int i = 0; i < numBlocks; i++) { QTextLayout *layout = block.layout(); for(int j = 0; j < layout->lineCount(); j++) { QTextLine &line = layout->lineAt(j); const QString text = block.text().mid( line.textStart(), line.textLength()); QRect rect = line.naturalTextRect() .translated(layout->position()).toAlignedRect(); if(rect.isEmpty()) continue; // Don't add empty rectangles rect.adjust(0, 0, 1, 0); // QTextLine is incorrect? rect.adjust( -m_strokeSize, -m_strokeSize, m_strokeSize, m_strokeSize); //appLog() << rect; region += rect; } // Iterate block = block.next(); } quint64 timeRegion = App->getUsecSinceExec(); #if 0 // Debug bounding region QPainterPath regionPath; regionPath.addRegion(region); regionPath.setFillRule(Qt::WindingFill); p.fillPath(regionPath, QColor(255, 0, 0, 128)); #endif // 0 // We cannot read and write to the same image at the same time so // create a second one. Note that this is not premultiplied. QImage imgOut(size, QImage::Format_ARGB32); imgOut.fill(Qt::transparent); // Do distance calculation. We assume that non-fully transparent // pixels are always next to a fully opaque one so if the closest // "covered" pixel is not fully opaque then we can use that pixel's // opacity to determine the distance to the shape's edge. for(int y = 0; y < img.height(); y++) { for(int x = 0; x < img.width(); x++) { if(!region.contains(QPoint(x, y))) continue; float dist = getDistance(img, x, y, m_strokeSize); // We fake antialiasing by blurring the edge by 1px float outEdge = (float)m_strokeSize; if(dist >= outEdge) continue; // Outside stroke completely float opacity = qMin(1.0f, outEdge - dist); QColor col = m_strokeColor; col.setAlphaF(col.alphaF() * opacity); // Blend the stroke so that it appears under the existing // pixel data QRgb origRgb = img.pixel(x, y); QColor origCol(origRgb); origCol.setAlpha(qAlpha(origRgb)); col = blendColors(col, origCol, 1.0f); imgOut.setPixel(x, y, col.rgba()); } } quint64 timeRender = App->getUsecSinceExec(); // Swap image data p.end(); img = imgOut; p.begin(&img); quint64 timeEnd = App->getUsecSinceExec(); appLog() << "Region time = " << (timeRegion - timeStart) << " usec"; appLog() << "Render time = " << (timeRender - timeRegion) << " usec"; appLog() << "Swap time = " << (timeEnd - timeRender) << " usec"; appLog() << "Full time = " << (timeEnd - timeStart) << " usec"; #endif // STROKE_TECHNIQUE } // Render text m_document.drawContents(&p); // Convert the image to a GPU texture m_texture = vidgfx_context_new_tex(gfx, img); // Preview texture for debugging //img.save(App->getDataDirectory().filePath("Preview.png")); }
// This function generates puzzle piece shapes. // ---------- // unit - the size of the rectangular base of the puzzle piece // status - flags of TabStatus values that describe the shape of this puzzle piece // tabFull - the full size of tabs including stroke, offset, tolerance // tabSize - size of tabs // tabOffset - offset of tabs (meaning: how far away they are from the edge of the piece) // tabTolerance - extra size to the tabs (so that merging works flawlessly, without visual artifacts) // blankSize - size of blanks // blankOffset - offset of blanks (meaning: how far away they are from the edge of the piece) // ---------- static QPainterPath createPuzzleShape(QSize unit, int status, qreal tabFull, qreal tabSize, qreal tabOffset, qreal tabTolerance, qreal blankSize, qreal blankOffset) { QPainterPath rectClip; rectClip.addRect(tabFull - 1, tabFull - 1, unit.width() + 1, unit.height() + 1); QPainterPath clip = rectClip; // Left if (status & Puzzle::Creation::LeftBlank) { QPainterPath leftBlank; leftBlank.addEllipse(QPointF(tabFull + blankOffset, tabFull + unit.height() / 2.0), blankSize, blankSize); clip = clip.subtracted(leftBlank); } else if (status & Puzzle::Creation::LeftTab) { QPainterPath leftTab; leftTab.addEllipse(QPointF(tabSize + tabTolerance, tabFull + unit.height() / 2.0), tabSize + tabTolerance, tabSize + tabTolerance); clip = clip.united(leftTab); } // Top if (status & Puzzle::Creation::TopBlank) { QPainterPath topBlank; topBlank.addEllipse(QPointF(tabFull + unit.width() / 2.0, tabFull + blankOffset), blankSize, blankSize); clip = clip.subtracted(topBlank); } else if (status & Puzzle::Creation::TopTab) { QPainterPath topTab; topTab.addEllipse(QPointF(tabFull + unit.width() / 2.0, tabSize + tabTolerance), tabSize + tabTolerance, tabSize + tabTolerance); clip = clip.united(topTab); } // Right if (status & Puzzle::Creation::RightTab) { QPainterPath rightTab; rightTab.addEllipse(QPointF(tabFull + unit.width() + tabOffset, tabFull + unit.height() / 2.0), tabSize + tabTolerance, tabSize + tabTolerance); clip = clip.united(rightTab); } else if (status & Puzzle::Creation::RightBlank) { QPainterPath rightBlank; rightBlank.addEllipse(QPointF(tabFull + unit.width() - blankOffset, tabFull + unit.height() / 2.0), blankSize, blankSize); clip = clip.subtracted(rightBlank); } // Bottom if (status & Puzzle::Creation::BottomTab) { QPainterPath bottomTab; bottomTab.addEllipse(QPointF(tabFull + unit.width() / 2.0, tabFull + unit.height() + tabOffset), tabSize + tabTolerance, tabSize + tabTolerance); clip = clip.united(bottomTab); } else if (status & Puzzle::Creation::BottomBlank) { QPainterPath bottomBlank; bottomBlank.addEllipse(QPointF(tabFull + unit.width() / 2.0, tabFull + unit.height() - blankOffset), blankSize, blankSize); clip = clip.subtracted(bottomBlank); } clip = clip.simplified(); return clip; }
void GraphicsItemNode::paint(QPainter * painter, const QStyleOptionGraphicsItem *, QWidget *) { QPainterPath outlinePath = shape(); //Fill the node's colour QBrush brush(m_colour); painter->fillPath(outlinePath, brush); //If the node contains a BLAST hit, draw that on top. if (g_settings->nodeColourScheme == BLAST_HITS_COLOUR) { std::vector<BlastHitPart> parts; if (g_settings->doubleMode) { if (m_deBruijnNode->thisNodeHasBlastHits()) parts = m_deBruijnNode->getBlastHitPartsForThisNode(); } else { if (m_deBruijnNode->thisNodeOrReverseComplementHasBlastHits()) parts = m_deBruijnNode->getBlastHitPartsForThisNodeOrReverseComplement(); } if (parts.size() > 0) { QPen partPen; partPen.setWidthF(m_width); partPen.setCapStyle(Qt::FlatCap); partPen.setJoinStyle(Qt::BevelJoin); for (size_t i = 0; i < parts.size(); ++i) { partPen.setColor(parts[i].m_colour); painter->setPen(partPen); painter->drawPath(makePartialPath(parts[i].m_nodeFractionStart, parts[i].m_nodeFractionEnd)); } } } //Draw the node outline QColor outlineColour = g_settings->outlineColour; double outlineThickness = g_settings->outlineThickness; if (isSelected()) { outlineColour = g_settings->selectionColour; outlineThickness = g_settings->selectionThickness; } if (outlineThickness > 0.0) { outlinePath = outlinePath.simplified(); QPen outlinePen(QBrush(outlineColour), outlineThickness, Qt::SolidLine, Qt::FlatCap, Qt::RoundJoin); painter->setPen(outlinePen); painter->drawPath(outlinePath); } //Draw text if there is any to display. if (g_settings->anyNodeDisplayText()) { //The text should always be displayed upright, so //counter the view's rotation here. painter->setRenderHint(QPainter::TextAntialiasing, true); painter->setFont(g_settings->labelFont); QString displayText = getNodeText(); QSize textSize = getNodeTextSize(displayText); double textWidth = textSize.width(); double textHeight = textSize.height(); //The text outline is made by drawing the text first in white at a slight offset //at many angles. The larger the text outline, the more angles are needed to //make the outline look nice. if (g_settings->textOutline) { int offsetSteps = 8; if (g_settings->textOutlineThickness > 0.5) offsetSteps = 16; if (g_settings->textOutlineThickness > 1.0) offsetSteps = 32; double offsetDistance = g_settings->textOutlineThickness; painter->translate(getCentre()); painter->rotate(-g_graphicsView->m_rotation); for (int i = 0; i < offsetSteps; ++i) { double offsetAngle = 6.2832 * (double(i) / offsetSteps); double xOffset = offsetDistance * cos(offsetAngle); double yOffset = offsetDistance * sin(offsetAngle); QRectF shadowTextRectangle(-textWidth / 2.0 + xOffset, -textHeight / 2.0 + yOffset, textWidth, textHeight); painter->setPen(Qt::white); painter->drawText(shadowTextRectangle, Qt::AlignCenter, displayText); } painter->rotate(g_graphicsView->m_rotation); painter->translate(-1.0 * getCentre()); } QRectF textRectangle(-textWidth / 2.0, -textHeight / 2.0, textWidth, textHeight); painter->setPen(g_settings->textColour); painter->translate(getCentre()); painter->rotate(-g_graphicsView->m_rotation); painter->drawText(textRectangle, Qt::AlignCenter, displayText); painter->rotate(g_graphicsView->m_rotation); painter->translate(-1.0 * getCentre()); } }
void QWaylandMaterialDecoration::paint(QPaintDevice *device) { const QRect frameGeometry = window()->frameGeometry(); QRect top(QPoint(WINDOW_BORDER, WINDOW_BORDER), QSize(frameGeometry.width(), margins().top())); QPainter p(device); p.setRenderHint(QPainter::Antialiasing); // Title bar int radius = waylandWindow()->isMaximized() ? 0 : dp(3); QPainterPath roundedRect; roundedRect.addRoundedRect(0, 0, frameGeometry.width(), margins().top() * 1.5, radius, radius); p.fillPath(roundedRect.simplified(), m_backgroundColor); // Borders QPainterPath borderPath; borderPath.addRect(0, margins().top(), margins().left(), frameGeometry.height() - margins().top()); borderPath.addRect(0, frameGeometry.height() - margins().bottom(), frameGeometry.width(), margins().bottom()); borderPath.addRect(frameGeometry.width() - margins().right(), margins().top(), margins().right(), frameGeometry.height() - margins().bottom()); p.fillPath(borderPath, m_backgroundColor); // Window title QString windowTitleText = window()->title(); if (!windowTitleText.isEmpty()) { if (m_windowTitle.text() != windowTitleText) { m_windowTitle.setText(windowTitleText); m_windowTitle.prepare(); } QRect titleBar = top; titleBar.setLeft(margins().left() + BUTTON_SPACING); titleBar.setRight(minimizeButtonRect().left() - BUTTON_SPACING); p.save(); p.setClipRect(titleBar); p.setPen(m_textColor); QSizeF size = m_windowTitle.size(); int dx = (top.width() - size.width()) / 2; int dy = (top.height() - size.height()) / 2; QFont font = p.font(); font.setBold(true); font.setFamily("Roboto"); p.setFont(font); QPoint windowTitlePoint(top.topLeft().x() + dx, top.topLeft().y() + dy); p.drawStaticText(windowTitlePoint, m_windowTitle); p.restore(); } p.save(); p.setPen(m_iconColor); // Close button QBitmap closeIcon = buttonIcon("window-close"); p.drawPixmap(closeButtonRect(), closeIcon, closeIcon.rect()); // Maximize button if (window()->flags() & Qt::WindowMaximizeButtonHint) { QBitmap maximizeIcon = buttonIcon(waylandWindow()->isMaximized() ? "window-restore" : "window-maximize"); p.drawPixmap(maximizeButtonRect(), maximizeIcon, maximizeIcon.rect()); } // Minimize button if (window()->flags() & Qt::WindowMinimizeButtonHint) { QBitmap minimizeIcon = buttonIcon("window-minimize"); p.drawPixmap(minimizeButtonRect(), minimizeIcon, minimizeIcon.rect()); } p.restore(); }