7#include <QtGui/QPainter>
11QSGSoftwareInternalRectangleNode::QSGSoftwareInternalRectangleNode()
16 , m_bottomLeftRadius(0)
17 , m_bottomRightRadius(0)
18 , m_devicePixelRatio(1)
20 , m_cornerPixmapIsDirty(
true)
21 , m_isTopLeftRadiusSet(
false)
22 , m_isTopRightRadiusSet(
false)
23 , m_isBottomLeftRadiusSet(
false)
24 , m_isBottomRightRadiusSet(
false)
26 m_pen.setJoinStyle(Qt::MiterJoin);
27 m_pen.setMiterLimit(0);
28 setMaterial((QSGMaterial*)1);
29 setGeometry((QSGGeometry*)1);
34 QRect alignedRect = rect.toAlignedRect();
35 if (m_rect != alignedRect) {
37 markDirty(DirtyMaterial);
43 if (m_color != color) {
45 m_cornerPixmapIsDirty =
true;
46 markDirty(DirtyMaterial);
52 if (m_penColor != color) {
54 m_cornerPixmapIsDirty =
true;
55 markDirty(DirtyMaterial);
61 if (m_penWidth != width) {
63 m_cornerPixmapIsDirty =
true;
64 markDirty(DirtyMaterial);
71 double distance = secondStop.first - firstStop.first;
72 double distanceDelta = newPos - firstStop.first;
73 double modifierValue = distanceDelta / distance;
74 const auto firstStopRgbColor = firstStop.second.toRgb();
75 const auto secondStopRgbColor = secondStop.second.toRgb();
76 int redDelta = (secondStopRgbColor.red() - firstStopRgbColor.red()) * modifierValue;
77 int greenDelta = (secondStopRgbColor.green() - firstStopRgbColor.green()) * modifierValue;
78 int blueDelta = (secondStopRgbColor.blue() - firstStopRgbColor.blue()) * modifierValue;
79 int alphaDelta = (secondStopRgbColor.alpha() - firstStopRgbColor.alpha()) * modifierValue;
81 QGradientStop newStop;
82 newStop.first = newPos;
83 newStop.second = QColor(firstStopRgbColor.red() + redDelta,
84 firstStopRgbColor.green() + greenDelta,
85 firstStopRgbColor.blue() + blueDelta,
86 firstStopRgbColor.alpha() + alphaDelta);
94 bool needsNormalization =
false;
95 for (
const QGradientStop &stop : std::as_const(stops)) {
96 if (stop.first < 0.0 || stop.first > 1.0) {
97 needsNormalization =
true;
102 if (needsNormalization) {
103 QGradientStops normalizedStops;
104 if (stops.size() == 1) {
107 QGradientStop stop = stops.at(0);
109 normalizedStops.append(stop);
114 QVector<
int> between;
115 for (
int i = 0; i < stops.size(); ++i) {
116 if (stops.at(i).first < 0.0) {
118 }
else if (stops.at(i).first > 1.0) {
129 if (below + 1 < stops.size()) {
130 normalizedStops.append(interpolateStop(stops.at(below), stops.at(below + 1), 0.0));
132 QGradientStop singleStop;
133 singleStop.first = 0.0;
134 singleStop.second = stops.at(below).second;
135 normalizedStops.append(singleStop);
139 for (
int i = 0; i < between.size(); ++i)
140 normalizedStops.append(stops.at(between.at(i)));
145 normalizedStops.append(interpolateStop(stops.at(above), stops.at(above - 1), 1.0));
147 QGradientStop singleStop;
148 singleStop.first = 1.0;
149 singleStop.second = stops.at(above).second;
150 normalizedStops.append(singleStop);
155 m_stops = normalizedStops;
160 m_cornerPixmapIsDirty =
true;
161 markDirty(DirtyMaterial);
166 if (m_vertical != vertical) {
167 m_vertical = vertical;
168 m_cornerPixmapIsDirty =
true;
169 markDirty(DirtyMaterial);
175 if (m_radius == radius)
178 m_cornerPixmapIsDirty =
true;
179 markDirty(DirtyMaterial);
184 if (m_isTopLeftRadiusSet && m_topLeftRadius == radius)
186 m_isTopLeftRadiusSet =
true;
187 m_topLeftRadius = radius;
188 m_cornerPixmapIsDirty =
true;
189 markDirty(DirtyMaterial);
194 if (m_isTopRightRadiusSet && m_topRightRadius == radius)
196 m_isTopRightRadiusSet =
true;
197 m_topRightRadius = radius;
198 m_cornerPixmapIsDirty =
true;
199 markDirty(DirtyMaterial);
204 if (m_isBottomLeftRadiusSet && m_bottomLeftRadius == radius)
206 m_isBottomLeftRadiusSet =
true;
207 m_bottomLeftRadius = radius;
208 m_cornerPixmapIsDirty =
true;
209 markDirty(DirtyMaterial);
214 if (m_isBottomRightRadiusSet && m_bottomRightRadius == radius)
216 m_isBottomRightRadiusSet =
true;
217 m_bottomRightRadius = radius;
218 m_cornerPixmapIsDirty =
true;
219 markDirty(DirtyMaterial);
224 if (!m_isTopLeftRadiusSet)
226 m_isTopLeftRadiusSet =
false;
227 m_cornerPixmapIsDirty =
true;
228 markDirty(DirtyMaterial);
233 if (!m_isTopRightRadiusSet)
235 m_isTopRightRadiusSet =
false;
236 m_cornerPixmapIsDirty =
true;
237 markDirty(DirtyMaterial);
242 if (!m_isBottomLeftRadiusSet)
244 m_isBottomLeftRadiusSet =
false;
245 m_cornerPixmapIsDirty =
true;
246 markDirty(DirtyMaterial);
251 if (!m_isBottomRightRadiusSet)
253 m_isBottomRightRadiusSet =
false;
254 m_cornerPixmapIsDirty =
true;
255 markDirty(DirtyMaterial);
264 if (!m_penWidth || m_penColor == Qt::transparent) {
267 m_pen = QPen(m_penColor);
268 m_pen.setWidthF(m_penWidth);
271 if (!m_stops.isEmpty()) {
272 QLinearGradient gradient(QPoint(0,0), QPoint(m_vertical ? 0 : m_rect.width(), m_vertical ? m_rect.height() : 0));
273 gradient.setStops(m_stops);
274 m_brush = QBrush(gradient);
276 m_brush = QBrush(m_color);
279 if (m_cornerPixmapIsDirty) {
280 generateCornerPixmap();
281 m_cornerPixmapIsDirty =
false;
289 if (!qFuzzyCompare(painter->device()->devicePixelRatio(), m_devicePixelRatio)) {
290 m_devicePixelRatio = painter->device()->devicePixelRatio();
291 generateCornerPixmap();
294 if (painter->transform().isRotating()) {
300 && !m_isTopLeftRadiusSet
301 && !m_isTopRightRadiusSet
302 && !m_isBottomLeftRadiusSet
303 && !m_isBottomRightRadiusSet) {
306 painter->setPen(Qt::NoPen);
307 painter->setBrush(m_brush);
308 painter->drawRect(m_rect);
309 }
else if (!m_isTopLeftRadiusSet
310 && !m_isTopRightRadiusSet
311 && !m_isBottomLeftRadiusSet
312 && !m_isBottomRightRadiusSet) {
315 QPixmap pixmap = QPixmap(qRound(m_rect.width() * m_devicePixelRatio), qRound(m_rect.height() * m_devicePixelRatio));
316 pixmap.fill(Qt::transparent);
317 pixmap.setDevicePixelRatio(m_devicePixelRatio);
318 QPainter pixmapPainter(&pixmap);
319 paintRectangle(&pixmapPainter, QRect(0, 0, m_rect.width(), m_rect.height()));
321 QPainter::RenderHints previousRenderHints = painter->renderHints();
322 painter->setRenderHint(QPainter::SmoothPixmapTransform,
true);
323 painter->drawPixmap(m_rect, pixmap);
324 painter->setRenderHints(previousRenderHints);
328 QPixmap pixmap = QPixmap(qRound(m_rect.width() * m_devicePixelRatio), qRound(m_rect.height() * m_devicePixelRatio));
329 pixmap.fill(Qt::transparent);
330 pixmap.setDevicePixelRatio(m_devicePixelRatio);
331 QPainter pixmapPainter(&pixmap);
333 paintRectangleIndividualCorners(&pixmapPainter, QRect(0, 0, m_rect.width(), m_rect.height()));
335 QPainter::RenderHints previousRenderHints = painter->renderHints();
336 painter->setRenderHint(QPainter::SmoothPixmapTransform,
true);
337 painter->drawPixmap(m_rect, pixmap);
338 painter->setRenderHints(previousRenderHints);
345 if (!m_isTopLeftRadiusSet
346 && !m_isTopRightRadiusSet
347 && !m_isBottomLeftRadiusSet
348 && !m_isBottomRightRadiusSet) {
349 paintRectangle(painter, m_rect);
351 paintRectangleIndividualCorners(painter, m_rect);
359 || m_topLeftRadius > 0.0f
360 || m_topRightRadius > 0.0f
361 || m_bottomRightRadius > 0.0f
362 || m_bottomLeftRadius > 0.0f)
364 if (m_color.alpha() < 255)
366 if (m_penWidth > 0.0f && m_penColor.alpha() < 255)
368 if (m_stops.size() > 0) {
369 for (
const QGradientStop &stop : std::as_const(m_stops)) {
370 if (stop.second.alpha() < 255)
387 int radius = qFloor(qMin(qMin(rect.width(), rect.height()) * 0.5, m_radius));
388 QPainter::RenderHints previousRenderHints = painter->renderHints();
389 painter->setRenderHint(QPainter::Antialiasing,
false);
391 if (m_penWidth > 0) {
395 double borderWidth = qMin(m_penWidth, rect.width() * 0.5);
396 double borderHeight = qMin(m_penWidth, rect.height() * 0.5);
400 if (borderWidth > radius) {
402 QRectF borderTopOutside(QPointF(rect.x() + radius, rect.y()),
403 QPointF(rect.x() + rect.width() - radius, rect.y() + radius));
404 QRectF borderTopInside(QPointF(rect.x() + borderWidth, rect.y() + radius),
405 QPointF(rect.x() + rect.width() - borderWidth, rect.y() + borderHeight));
406 QRectF borderBottomOutside(QPointF(rect.x() + radius, rect.y() + rect.height() - radius),
407 QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height()));
408 QRectF borderBottomInside(QPointF(rect.x() + borderWidth, rect.y() + rect.height() - borderHeight),
409 QPointF(rect.x() + rect.width() - borderWidth, rect.y() + rect.height() - radius));
411 if (borderTopOutside.isValid())
412 painter->fillRect(borderTopOutside, m_penColor);
413 if (borderTopInside.isValid())
414 painter->fillRect(borderTopInside, m_penColor);
415 if (borderBottomOutside.isValid())
416 painter->fillRect(borderBottomOutside, m_penColor);
417 if (borderBottomInside.isValid())
418 painter->fillRect(borderBottomInside, m_penColor);
422 QRectF borderTop(QPointF(rect.x() + radius, rect.y()),
423 QPointF(rect.x() + rect.width() - radius, rect.y() + borderHeight));
424 QRectF borderBottom(QPointF(rect.x() + radius, rect.y() + rect.height() - borderHeight),
425 QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height()));
426 if (borderTop.isValid())
427 painter->fillRect(borderTop, m_penColor);
428 if (borderBottom.isValid())
429 painter->fillRect(borderBottom, m_penColor);
431 QRectF borderLeft(QPointF(rect.x(), rect.y() + radius),
432 QPointF(rect.x() + borderWidth, rect.y() + rect.height() - radius));
433 QRectF borderRight(QPointF(rect.x() + rect.width() - borderWidth, rect.y() + radius),
434 QPointF(rect.x() + rect.width(), rect.y() + rect.height() - radius));
435 if (borderLeft.isValid())
436 painter->fillRect(borderLeft, m_penColor);
437 if (borderRight.isValid())
438 painter->fillRect(borderRight, m_penColor);
444 if (radius * 2 >= rect.width() && radius * 2 >= rect.height()) {
446 painter->drawPixmap(rect, m_cornerPixmap, m_cornerPixmap.rect());
450 int scaledRadius = qRound(radius * m_devicePixelRatio);
451 QRectF topLeftCorner(QPointF(rect.x(), rect.y()),
452 QPointF(rect.x() + radius, rect.y() + radius));
453 painter->drawPixmap(topLeftCorner, m_cornerPixmap, QRectF(0, 0, scaledRadius, scaledRadius));
454 QRectF topRightCorner(QPointF(rect.x() + rect.width() - radius, rect.y()),
455 QPointF(rect.x() + rect.width(), rect.y() + radius));
456 painter->drawPixmap(topRightCorner, m_cornerPixmap, QRectF(scaledRadius, 0, scaledRadius, scaledRadius));
457 QRectF bottomLeftCorner(QPointF(rect.x(), rect.y() + rect.height() - radius),
458 QPointF(rect.x() + radius, rect.y() + rect.height()));
459 painter->drawPixmap(bottomLeftCorner, m_cornerPixmap, QRectF(0, scaledRadius, scaledRadius, scaledRadius));
460 QRectF bottomRightCorner(QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height() - radius),
461 QPointF(rect.x() + rect.width(), rect.y() + rect.height()));
462 painter->drawPixmap(bottomRightCorner, m_cornerPixmap, QRectF(scaledRadius, scaledRadius, scaledRadius, scaledRadius));
468 QRectF brushRect = QRectF(rect).marginsRemoved(QMarginsF(m_penWidth, m_penWidth, m_penWidth, m_penWidth));
469 if (brushRect.width() < 0)
470 brushRect.setWidth(0);
471 if (brushRect.height() < 0)
472 brushRect.setHeight(0);
473 double innerRectRadius = qMax(0.0, radius - m_penWidth);
476 if (m_color.alpha() > 0 || !m_stops.empty()) {
477 if (innerRectRadius > 0) {
479 if (m_stops.empty()) {
481 QRectF centerRect(QPointF(brushRect.x() + innerRectRadius, brushRect.y()),
482 QPointF(brushRect.x() + brushRect.width() - innerRectRadius, brushRect.y() + brushRect.height()));
483 painter->fillRect(centerRect, m_color);
484 QRectF leftRect(QPointF(brushRect.x(), brushRect.y() + innerRectRadius),
485 QPointF(brushRect.x() + innerRectRadius, brushRect.y() + brushRect.height() - innerRectRadius));
486 painter->fillRect(leftRect, m_color);
487 QRectF rightRect(QPointF(brushRect.x() + brushRect.width() - innerRectRadius, brushRect.y() + innerRectRadius),
488 QPointF(brushRect.x() + brushRect.width(), brushRect.y() + brushRect.height() - innerRectRadius));
489 painter->fillRect(rightRect, m_color);
492 painter->setPen(Qt::NoPen);
493 painter->setBrush(m_brush);
494 painter->drawRoundedRect(brushRect, innerRectRadius, innerRectRadius);
498 painter->fillRect(brushRect, m_brush);
502 painter->setRenderHints(previousRenderHints);
509 const float w = m_penWidth;
512 const float radiusTL = qMin(qMin(rect.width(), rect.height()) * 0.5f,
513 m_isTopLeftRadiusSet ? m_topLeftRadius : m_radius);
514 const float radiusTR = qMin(qMin(rect.width(), rect.height()) * 0.5f,
515 m_isTopRightRadiusSet ? m_topRightRadius : m_radius);
516 const float radiusBL = qMin(qMin(rect.width(), rect.height()) * 0.5f,
517 m_isBottomLeftRadiusSet ? m_bottomLeftRadius : m_radius);
518 const float radiusBR = qMin(qMin(rect.width(), rect.height()) * 0.5f,
519 m_isBottomRightRadiusSet ? m_bottomRightRadius : m_radius);
521 const float innerRadiusTL = qMin(qMin(rect.width(), rect.height()) * 0.5f, radiusTL - w);
522 const float innerRadiusTR = qMin(qMin(rect.width(), rect.height()) * 0.5f, radiusTR - w);
523 const float innerRadiusBL = qMin(qMin(rect.width(), rect.height()) * 0.5f, radiusBL - w);
524 const float innerRadiusBR = qMin(qMin(rect.width(), rect.height()) * 0.5f, radiusBR - w);
526 QRect rect2 = rect.adjusted(0, 0, 1, 1);
528 path.moveTo(rect2.topRight() - QPointF(radiusTR, -w));
529 if (innerRadiusTR > 0.)
530 path.arcTo(QRectF(rect2.topRight() - QPointF(radiusTR + innerRadiusTR, -w), 2. * QSizeF(innerRadiusTR, innerRadiusTR)), 90, -90);
532 path.lineTo(rect2.topRight() - QPointF(w, -w));
534 if (innerRadiusBR > 0.)
535 path.arcTo(QRectF(rect2.bottomRight() - QPointF(radiusBR + innerRadiusBR, radiusBR + innerRadiusBR), 2. * QSizeF(innerRadiusBR, innerRadiusBR)), 0, -90);
537 path.lineTo(rect2.bottomRight() - QPointF(w, w));
539 if (innerRadiusBL > 0.)
540 path.arcTo(QRectF(rect2.bottomLeft() - QPointF(-w, radiusBL + innerRadiusBL), 2. * QSizeF(innerRadiusBL, innerRadiusBL)), -90, -90);
542 path.lineTo(rect2.bottomLeft() - QPointF(-w, w));
543 if (innerRadiusTL > 0.)
544 path.arcTo(QRectF(rect2.topLeft() + QPointF(w, w), 2. * QSizeF(innerRadiusTL, innerRadiusTL)), -180, -90);
546 path.lineTo(rect2.topLeft() + QPointF(w, w));
549 painter->setPen(Qt::NoPen);
550 painter->setBrush(m_brush);
551 painter->drawPath(path);
554 path.moveTo(rect2.topRight() - QPointF(radiusTR, 0.));
556 path.arcTo(QRectF(rect2.topRight() - 2. * QPointF(radiusTR, 0.), 2. * QSizeF(radiusTR, radiusTR)), 90, -90);
558 path.lineTo(rect2.topRight());
560 path.arcTo(QRectF(rect2.bottomRight() - 2. * QPointF(radiusBR, radiusBR), 2. * QSizeF(radiusBR, radiusBR)), 0, -90);
562 path.lineTo(rect2.bottomRight());
564 path.arcTo(QRectF(rect2.bottomLeft() - 2. * QPointF(0., radiusBL), 2. * QSizeF(radiusBL, radiusBL)), -90, -90);
566 path.lineTo(rect2.bottomLeft());
568 path.arcTo(QRectF(rect2.topLeft() - 2. * QPointF(0., 0.), 2. * QSizeF(radiusTL, radiusTL)), -180, -90);
570 path.lineTo(rect2.topLeft());
573 painter->setBrush(m_penColor);
574 painter->drawPath(path);
581 int radius = qFloor(qMin(qMin(m_rect.width(), m_rect.height()) * 0.5, m_radius));
582 const auto width = qRound(radius * 2 * m_devicePixelRatio);
584 if (m_cornerPixmap.width() != width)
585 m_cornerPixmap = QPixmap(width, width);
587 m_cornerPixmap.setDevicePixelRatio(m_devicePixelRatio);
588 m_cornerPixmap.fill(Qt::transparent);
591 QPainter cornerPainter(&m_cornerPixmap);
592 cornerPainter.setRenderHint(QPainter::Antialiasing);
593 cornerPainter.setCompositionMode(QPainter::CompositionMode_Source);
596 if (m_penWidth > 0) {
597 cornerPainter.setPen(Qt::NoPen);
598 cornerPainter.setBrush(m_penColor);
599 cornerPainter.drawRoundedRect(QRectF(0, 0, radius * 2, radius *2), radius, radius);
603 if (radius > m_penWidth) {
604 cornerPainter.setPen(Qt::NoPen);
605 if (m_stops.isEmpty())
606 cornerPainter.setBrush(m_brush);
608 cornerPainter.setBrush(Qt::transparent);
610 QMarginsF adjustmentMargins(m_penWidth, m_penWidth, m_penWidth, m_penWidth);
611 QRectF cornerCircleRect = QRectF(0, 0, radius * 2, radius * 2).marginsRemoved(adjustmentMargins);
612 cornerPainter.drawRoundedRect(cornerCircleRect, radius, radius);
void setBottomRightRadius(qreal radius) override
void setRect(const QRectF &rect) override
void setRadius(qreal radius) override
void setGradientVertical(bool vertical) override
void resetBottomRightRadius() override
void setTopLeftRadius(qreal radius) override
void setTopRightRadius(qreal radius) override
void setBottomLeftRadius(qreal radius) override
void setColor(const QColor &color) override
void setGradientStops(const QGradientStops &stops) override
void setPenWidth(qreal width) override
void resetBottomLeftRadius() override
void setPenColor(const QColor &color) override
void setAligned(bool aligned) override
void resetTopLeftRadius() override
void resetTopRightRadius() override
static QGradientStop interpolateStop(const QGradientStop &firstStop, const QGradientStop &secondStop, double newPos)