File indexing completed on 2024-05-12 05:38:57

0001 /* SPDX-FileCopyrightText: 2020 Noah Davis <noahadvs@gmail.com>
0002  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0003  */
0004 
0005 #include "paintedsymbolitem.h"
0006 #include "paintedsymbolitem_p.h"
0007 #include <QGuiApplication>
0008 #include <QPainter>
0009 
0010 PaintedSymbolItem::PaintedSymbolItem(QQuickItem *parent)
0011     : QQuickPaintedItem(parent)
0012     , d_ptr(new PaintedSymbolItemPrivate(this))
0013 {
0014     Q_D(PaintedSymbolItem);
0015     connect(qGuiApp, &QGuiApplication::fontChanged, this, [this, d]() {
0016         d->fontMetrics = QFontMetricsF(QGuiApplication::font());
0017         update();
0018     });
0019     d->targetSymbolSize = d->fontMetrics.height() + std::fmod(d->fontMetrics.height(), 2.0);
0020     d->targetSymbolSize -= std::fmod(d->targetSymbolSize, 6.0);
0021     d->targetSymbolSize -= d->targetSymbolSize / 3.0;
0022     setImplicitSize(d->targetSymbolSize, d->fontMetrics.height());
0023     setBaselineOffset(d->fontMetrics.ascent());
0024 }
0025 
0026 PaintedSymbolItem::~PaintedSymbolItem() noexcept
0027 {
0028 }
0029 
0030 void PaintedSymbolItem::paint(QPainter *painter)
0031 {
0032     Q_D(PaintedSymbolItem);
0033     // Do I need to save() and restore() if I change the painter in the switch blocks?
0034     switch (d->symbolType) {
0035     case SymbolType::Checkmark: {
0036         setPenWidth(2);
0037         qreal penOffset = d->penWidth / 2;
0038 
0039         // Prevent the sides from being cut off. Remember to add extra width and height externally.
0040         qreal width = this->width() - d->penWidth * 2;
0041         qreal height = this->height() - d->penWidth * 2;
0042 
0043         // No point in trying to draw if it's too small
0044         if (std::min(width, height) <= 0) {
0045             return;
0046         }
0047 
0048         painter->translate(d->penWidth, d->penWidth);
0049 
0050         painter->setBrush(Qt::NoBrush);
0051         painter->setPen(d->pen);
0052         painter->setRenderHint(QPainter::Antialiasing);
0053 
0054         QList<QPointF> points = {
0055             QPointF(0 + penOffset, height / 2.0 + penOffset),
0056             QPointF(width / 3.0, height / 1.2), // height * (5/6)
0057             QPointF(width - penOffset, height / 6.0 + penOffset),
0058         };
0059         painter->drawPolyline(points);
0060 
0061     } break;
0062     case SymbolType::LeftArrow: {
0063         setPenWidth(1);
0064         qreal penOffset = d->penWidth / 2;
0065 
0066         // Prevent the sides from being cut off. Remember to add extra width and height externally.
0067         qreal width = this->width() - d->penWidth * 2;
0068         qreal height = this->height() - d->penWidth * 2;
0069 
0070         // No point in trying to draw if it's too small
0071         if (std::min(width, height) <= 0) {
0072             return;
0073         }
0074 
0075         painter->translate(d->penWidth, d->penWidth);
0076 
0077         painter->setBrush(Qt::NoBrush);
0078         painter->setPen(d->pen);
0079         painter->setRenderHint(QPainter::Antialiasing);
0080 
0081         QList<QPointF> points = {
0082             QPointF(width / 1.5 - penOffset, 0 + penOffset),
0083             QPointF(width / 4.0, height / 2),
0084             QPointF(width / 1.5 - penOffset, height - penOffset),
0085         };
0086         painter->drawPolyline(points);
0087 
0088     } break;
0089     case SymbolType::RightArrow: {
0090         setPenWidth(1);
0091         // qreal penOffset = d->penWidth / 2;
0092 
0093         // Prevent the sides from being cut off. Remember to add extra width and height externally.
0094         qreal width = this->width() - d->penWidth * 2;
0095         qreal height = this->height() - d->penWidth * 2;
0096 
0097         // No point in trying to draw if it's too small
0098         if (std::min(width, height) <= 0) {
0099             return;
0100         }
0101 
0102         painter->translate(d->penWidth, d->penWidth);
0103 
0104         painter->setBrush(Qt::NoBrush);
0105         painter->setPen(d->pen);
0106         painter->setRenderHint(QPainter::Antialiasing);
0107 
0108         QList<QPointF> points = {
0109             QPointF(width / 3 /* + penOffset*/, 0 /* + penOffset*/),
0110             QPointF(width * 0.75, height / 2),
0111             QPointF(width / 3 /* + penOffset*/, height /* - penOffset*/),
0112         };
0113         painter->drawPolyline(points);
0114 
0115     } break;
0116     case SymbolType::UpArrow: {
0117         setPenWidth(1);
0118         qreal penOffset = d->penWidth / 2;
0119 
0120         // Prevent the sides from being cut off. Remember to add extra width and height externally.
0121         qreal width = this->width() - d->penWidth * 2;
0122         qreal height = this->height() - d->penWidth * 2;
0123 
0124         // No point in trying to draw if it's too small
0125         if (std::min(width, height) <= 0) {
0126             return;
0127         }
0128 
0129         painter->translate(d->penWidth, d->penWidth + penOffset);
0130 
0131         painter->setBrush(Qt::NoBrush);
0132         painter->setPen(d->pen);
0133         painter->setRenderHint(QPainter::Antialiasing);
0134 
0135         QList<QPointF> points = {
0136             QPointF(0 - penOffset, height * 0.75),
0137             QPointF(width / 2.0, height / 4 - penOffset),
0138             QPointF(width + penOffset, height * 0.75),
0139         };
0140         painter->drawPolyline(points);
0141 
0142     } break;
0143     case SymbolType::DownArrow: {
0144         setPenWidth(1);
0145         qreal penOffset = d->penWidth / 2;
0146 
0147         // Prevent the sides from being cut off. Remember to add extra width and height externally.
0148         qreal width = this->width() - d->penWidth * 2;
0149         qreal height = this->height() - d->penWidth * 2;
0150 
0151         // No point in trying to draw if it's too small
0152         if (std::min(width, height) <= 0) {
0153             return;
0154         }
0155 
0156         painter->translate(d->penWidth, d->penWidth + penOffset);
0157 
0158         painter->setBrush(Qt::NoBrush);
0159         painter->setPen(d->pen);
0160         painter->setRenderHint(QPainter::Antialiasing);
0161 
0162         QList<QPointF> points = {
0163             QPointF(0 - penOffset, height / 4),
0164             QPointF(width / 2.0, height * 0.75 + penOffset),
0165             QPointF(width + penOffset, height / 4),
0166         };
0167         painter->drawPolyline(points);
0168 
0169     } break;
0170     default:
0171         break;
0172     }
0173 }
0174 
0175 // color
0176 QColor PaintedSymbolItem::color() const
0177 {
0178     Q_D(const PaintedSymbolItem);
0179     return d->color;
0180 }
0181 
0182 void PaintedSymbolItem::setColor(const QColor &color)
0183 {
0184     Q_D(PaintedSymbolItem);
0185     if (color == d->color) {
0186         return;
0187     }
0188 
0189     d->color = color;
0190     d->pen.setColor(d->color);
0191     update();
0192     Q_EMIT colorChanged();
0193 }
0194 
0195 // penWidth
0196 qreal PaintedSymbolItem::penWidth() const
0197 {
0198     Q_D(const PaintedSymbolItem);
0199     return d->penWidth;
0200 }
0201 
0202 void PaintedSymbolItem::setPenWidth(const qreal penWidth)
0203 {
0204     Q_D(PaintedSymbolItem);
0205     if (penWidth == d->penWidth || (d->penWidth == 1.001 && penWidth == 1)) {
0206         return;
0207     }
0208 
0209     d->penWidth = penWidth == 1 ? 1.001 : penWidth;
0210     d->pen.setWidthF(d->penWidth);
0211     Q_EMIT penWidthChanged();
0212 }
0213 
0214 // symbolType
0215 PaintedSymbolItem::SymbolType PaintedSymbolItem::symbolType() const
0216 {
0217     Q_D(const PaintedSymbolItem);
0218     return d->symbolType;
0219 }
0220 
0221 void PaintedSymbolItem::setSymbolType(const SymbolType symbolType)
0222 {
0223     Q_D(PaintedSymbolItem);
0224     if (symbolType == d->symbolType) {
0225         return;
0226     }
0227 
0228     d->symbolType = symbolType;
0229     update();
0230     Q_EMIT symbolTypeChanged();
0231 }
0232 
0233 #include "moc_paintedsymbolitem.cpp"