aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--softwarecontext/rectanglenode.cpp152
-rw-r--r--softwarecontext/rectanglenode.h4
2 files changed, 143 insertions, 13 deletions
diff --git a/softwarecontext/rectanglenode.cpp b/softwarecontext/rectanglenode.cpp
index 8e3548cf23..054ffd3ecf 100644
--- a/softwarecontext/rectanglenode.cpp
+++ b/softwarecontext/rectanglenode.cpp
@@ -18,10 +18,15 @@
**
****************************************************************************/
#include "rectanglenode.h"
+#include <qmath.h>
+
+#include <QtGui/QPainter>
+
RectangleNode::RectangleNode()
: m_penWidth(0)
, m_radius(0)
+ , m_cornerPixmapIsDirty(true)
{
setMaterial((QSGMaterial*)1);
setGeometry((QSGGeometry*)1);
@@ -29,32 +34,47 @@ RectangleNode::RectangleNode()
void RectangleNode::setRect(const QRectF &rect)
{
- m_rect = rect;
+ if (m_rect != rect) {
+ m_rect = rect;
+ }
}
void RectangleNode::setColor(const QColor &color)
{
- m_color = color;
+ if (m_color != color) {
+ m_color = color;
+ m_cornerPixmapIsDirty = true;
+ }
}
void RectangleNode::setPenColor(const QColor &color)
{
- m_penColor = color;
+ if (m_penColor != color) {
+ m_penColor = color;
+ m_cornerPixmapIsDirty = true;
+ }
}
void RectangleNode::setPenWidth(qreal width)
{
- m_penWidth = width;
+ if (m_penWidth != width) {
+ m_penWidth = width;
+ m_cornerPixmapIsDirty = true;
+ }
}
void RectangleNode::setGradientStops(const QGradientStops &stops)
{
m_stops = stops;
+ m_cornerPixmapIsDirty = true;
}
void RectangleNode::setRadius(qreal radius)
{
- m_radius = radius;
+ if (m_radius != radius) {
+ m_radius = radius;
+ m_cornerPixmapIsDirty = true;
+ }
}
void RectangleNode::setAligned(bool /*aligned*/)
@@ -78,16 +98,122 @@ void RectangleNode::update()
} else {
m_brush = QBrush(m_color);
}
+
+ if (m_cornerPixmapIsDirty) {
+ //Generate new corner Pixmap
+ int radius = qRound(qMin(qMin(m_rect.width(), m_rect.height()) * 0.5f, m_radius));
+
+ m_cornerPixmap = QPixmap(radius * 2, radius * 2);
+ m_cornerPixmap.fill(Qt::transparent);
+
+ if (radius > 0) {
+ QPainter cornerPainter(&m_cornerPixmap);
+ cornerPainter.setRenderHint(QPainter::Antialiasing);
+ cornerPainter.setCompositionMode(QPainter::CompositionMode_Source);
+
+ //Paint outer cicle
+ if (m_penWidth > 0) {
+ cornerPainter.setPen(Qt::NoPen);
+ cornerPainter.setBrush(m_penColor);
+ cornerPainter.drawRoundedRect(QRectF(0, 0, radius * 2, radius *2), radius, radius);
+ }
+
+ //Paint inner circle
+ if (radius > m_penWidth) {
+ cornerPainter.setPen(Qt::NoPen);
+ if (m_stops.isEmpty())
+ cornerPainter.setBrush(m_brush);
+ else
+ cornerPainter.setBrush(Qt::transparent);
+
+ QMarginsF adjustmentMargins(m_penWidth, m_penWidth, m_penWidth, m_penWidth);
+ QRectF cornerCircleRect = QRectF(0, 0, radius * 2, radius * 2).marginsRemoved(adjustmentMargins);
+ cornerPainter.drawRoundedRect(cornerCircleRect, radius, radius);
+ }
+ cornerPainter.end();
+ }
+ m_cornerPixmapIsDirty = false;
+ }
}
void RectangleNode::paint(QPainter *painter)
{
- painter->setPen(m_pen);
- painter->setBrush(m_brush);
- if (m_radius)
- painter->drawRoundedRect(m_rect, m_radius, m_radius);
- else if (m_pen.style() == Qt::NoPen && m_stops.isEmpty())
- painter->fillRect(m_rect, m_color);
- else
- painter->drawRect(m_rect);
+ //Radius should never exceeds half of the width or half of the height
+ int radius = qRound(qMin(qMin(m_rect.width(), m_rect.height()) * 0.5, m_radius));
+
+ QPainter::RenderHints previousRenderHints = painter->renderHints();
+ painter->setRenderHint(QPainter::Antialiasing, false);
+
+ if (m_penWidth > 0) {
+ //Borders can not be more than half the height/width of a rect
+ double borderWidth = qMin(m_penWidth, m_rect.width() * 0.5);
+ double borderHeight = qMin(m_penWidth, m_rect.height() * 0.5);
+
+ //Fill 4 border Rects
+ QRectF borderTop(QPointF(m_rect.x() + radius, m_rect.y()),
+ QPointF(m_rect.x() + m_rect.width() - radius, m_rect.y() + borderHeight));
+ painter->fillRect(borderTop, m_penColor);
+ QRectF borderBottom(QPointF(m_rect.x() + radius, m_rect.y() + m_rect.height() - borderHeight),
+ QPointF(m_rect.x() + m_rect.width() - radius, m_rect.y() + m_rect.height()));
+ painter->fillRect(borderBottom, m_penColor);
+ QRectF borderLeft(QPointF(m_rect.x(), m_rect.y() + radius),
+ QPointF(m_rect.x() + borderWidth, m_rect.y() + m_rect.height() - radius));
+ painter->fillRect(borderLeft, m_penColor);
+ QRectF borderRight(QPointF(m_rect.x() + m_rect.width() - borderWidth, m_rect.y() + radius),
+ QPointF(m_rect.x() + m_rect.width(), m_rect.y() + m_rect.height() - radius));
+ painter->fillRect(borderRight, m_penColor);
+ }
+
+ if (radius > 0) {
+ //blit 4 corners to border
+ QRectF topLeftCorner(QPointF(m_rect.x(), m_rect.y()),
+ QPointF(m_rect.x() + radius, m_rect.y() + radius));
+ painter->drawPixmap(topLeftCorner, m_cornerPixmap, QRectF(0, 0, radius, radius));
+ QRectF topRightCorner(QPointF(m_rect.x() + m_rect.width() - radius, m_rect.y()),
+ QPointF(m_rect.x() + m_rect.width(), m_rect.y() + radius));
+ painter->drawPixmap(topRightCorner, m_cornerPixmap, QRectF(radius, 0, radius, radius));
+ QRectF bottomLeftCorner(QPointF(m_rect.x(), m_rect.y() + m_rect.height() - radius),
+ QPointF(m_rect.x() + radius, m_rect.y() + m_rect.height()));
+ painter->drawPixmap(bottomLeftCorner, m_cornerPixmap, QRectF(0, radius, radius, radius));
+ QRectF bottomRightCorner(QPointF(m_rect.x() + m_rect.width() - radius, m_rect.y() + m_rect.height() - radius),
+ QPointF(m_rect.x() + m_rect.width(), m_rect.y() + m_rect.height()));
+ painter->drawPixmap(bottomRightCorner, m_cornerPixmap, QRectF(radius, radius, radius, radius));
+
+ }
+
+ QRectF brushRect = m_rect.marginsRemoved(QMarginsF(m_penWidth, m_penWidth, m_penWidth, m_penWidth));
+ if (brushRect.width() < 0)
+ brushRect.setWidth(0);
+ if (brushRect.height() < 0)
+ brushRect.setHeight(0);
+ double innerRectRadius = qMax(0.0, radius - m_penWidth);
+
+ //If not completely transparent or has a gradient
+ if (m_color.alpha() > 0 || !m_stops.empty()) {
+ if (innerRectRadius > 0) {
+ //Rounded Rect
+ if (m_stops.empty()) {
+ //Rounded Rects without gradient need 3 blits
+ QRectF centerRect(QPointF(brushRect.x() + innerRectRadius, brushRect.y()),
+ QPointF(brushRect.x() + brushRect.width() - innerRectRadius, brushRect.y() + brushRect.height()));
+ painter->fillRect(centerRect, m_color);
+ QRectF leftRect(QPointF(brushRect.x(), brushRect.y() + innerRectRadius),
+ QPointF(brushRect.x() + innerRectRadius, brushRect.y() + brushRect.height() - innerRectRadius));
+ painter->fillRect(leftRect, m_color);
+ QRectF rightRect(QPointF(brushRect.x() + brushRect.width() - innerRectRadius, brushRect.y() + innerRectRadius),
+ QPointF(brushRect.x() + brushRect.width(), brushRect.y() + brushRect.height() - innerRectRadius));
+ painter->fillRect(rightRect, m_color);
+ } else {
+ //Rounded Rect with gradient (slow)
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(m_brush);
+ painter->drawRoundedRect(brushRect, innerRectRadius, innerRectRadius);
+ }
+ } else {
+ //non-rounded rects only need 1 blit
+ painter->fillRect(brushRect, m_brush);
+ }
+ }
+
+ painter->setRenderHints(previousRenderHints);
}
diff --git a/softwarecontext/rectanglenode.h b/softwarecontext/rectanglenode.h
index df906d718a..74c0971c82 100644
--- a/softwarecontext/rectanglenode.h
+++ b/softwarecontext/rectanglenode.h
@@ -24,6 +24,7 @@
#include <QPen>
#include <QBrush>
+#include <QPixmap>
class RectangleNode : public QSGRectangleNode
{
@@ -52,6 +53,9 @@ private:
double m_radius;
QPen m_pen;
QBrush m_brush;
+
+ bool m_cornerPixmapIsDirty;
+ QPixmap m_cornerPixmap;
};
#endif // RECTANGLENODE_H