File indexing completed on 2024-05-19 04:29:30

0001 /*
0002  * SPDX-FileCopyrightText: 2020 Mathias Wein <lynx.mw+kde@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #include "KisVisualDiamondSelectorShape.h"
0008 
0009 #include <QPainter>
0010 #include <QRect>
0011 #include <QtMath>
0012 
0013 #include "kis_debug.h"
0014 #include "kis_global.h"
0015 
0016 KisVisualDiamondSelectorShape::KisVisualDiamondSelectorShape(KisVisualColorSelector *parent,
0017                                                                Dimensions dimension,
0018                                                                int channel1, int channel2,
0019                                                                int margin)
0020     : KisVisualColorSelectorShape(parent, dimension, channel1, channel2),
0021       m_margin(margin)
0022 {
0023 }
0024 
0025 KisVisualDiamondSelectorShape::~KisVisualDiamondSelectorShape()
0026 {
0027 }
0028 
0029 void KisVisualDiamondSelectorShape::setBorderWidth(int /*width*/)
0030 {
0031     // Diamond doesn't have a 1-dimensional mode
0032 }
0033 
0034 QRect KisVisualDiamondSelectorShape::getSpaceForSquare(QRect geom)
0035 {
0036     return geom;
0037 }
0038 
0039 QRect KisVisualDiamondSelectorShape::getSpaceForCircle(QRect geom)
0040 {
0041     return geom;
0042 }
0043 
0044 QRect KisVisualDiamondSelectorShape::getSpaceForTriangle(QRect geom)
0045 {
0046     return geom;
0047 }
0048 
0049 QPointF KisVisualDiamondSelectorShape::convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) const
0050 {
0051     // margin serves to render the cursor, and triangle is rendered 1px larger than its active area
0052     qreal offset = m_margin + 1.0;
0053 
0054     qreal y = ((1.0 - coordinate.y()) * (height() - 1 - 2 * offset)) + offset;
0055 
0056     qreal triWidth = width() - 1 - 2 * offset;
0057     qreal horizontalLineLength;
0058     if (coordinate.y() < 0.5) {
0059         horizontalLineLength = 2.0 * coordinate.y() * triWidth;
0060     } else {
0061         horizontalLineLength = 2.0 * (1.0 - coordinate.y()) * triWidth;
0062     }
0063     qreal horizontalLineStart = offset + 0.5 * (triWidth - horizontalLineLength);
0064 
0065     qreal x = coordinate.x() * horizontalLineLength + horizontalLineStart;
0066 
0067     return QPointF(x, y);
0068 }
0069 
0070 QPointF KisVisualDiamondSelectorShape::convertWidgetCoordinateToShapeCoordinate(QPointF coordinate) const
0071 {
0072     // margin serves to render the cursor, and triangle is rendered 1px larger than its active area
0073     qreal offset = m_margin + 1.0;
0074 
0075     qreal x = 0.5;
0076     qreal y = qBound(0.0, 1.0 - (coordinate.y() - offset)/(height() - 1 - 2 * offset), 1.0);
0077 
0078     qreal triWidth = width() - 1 - 2 * offset;
0079     qreal horizontalLineLength;
0080 
0081     if (y < 0.5) {
0082         horizontalLineLength = 2.0 * y * triWidth;
0083     } else {
0084         horizontalLineLength = 2.0 * (1.0 - y) * triWidth;
0085     }
0086 
0087     if (horizontalLineLength > 1e-4) {
0088         qreal horizontalLineStart = offset + 0.5 * (triWidth - horizontalLineLength);
0089         x = qBound(0.0, (coordinate.x() - horizontalLineStart) / horizontalLineLength, 1.0);
0090     }
0091 
0092     return QPointF(x, y);
0093 }
0094 
0095 QRegion KisVisualDiamondSelectorShape::getMaskMap()
0096 {
0097     const int cursorWidth = qMax(2 * m_margin, 2);
0098     QPolygon maskPoly;
0099     maskPoly << QPoint(qFloor(0.5 * (width() - cursorWidth)), 0)
0100              << QPoint(qCeil(0.5 * (width() + cursorWidth)), 0)
0101              << QPoint(width(), qFloor(0.5 * height() - cursorWidth))
0102              << QPoint(width(), qCeil(0.5 * height() + cursorWidth))
0103              << QPoint(qCeil(0.5 * (width() + cursorWidth)), height())
0104              << QPoint(qFloor(0.5 * (width() - cursorWidth)), height())
0105              << QPoint(0, qCeil(0.5 * height() + cursorWidth))
0106              << QPoint(0, qFloor(0.5 * height() - cursorWidth));
0107 
0108     return QRegion(maskPoly);
0109 }
0110 
0111 QImage KisVisualDiamondSelectorShape::renderAlphaMask() const
0112 {
0113     // Hi-DPI aware rendering requires that we determine the device pixel dimension;
0114     // actual widget size in device pixels is not accessible unfortunately, it might be 1px smaller...
0115     const int deviceWidth = qCeil(width() * devicePixelRatioF());
0116     const int deviceHeight = qCeil(height() * devicePixelRatioF());
0117 
0118     QImage alphaMask(deviceWidth, deviceHeight, QImage::Format_Alpha8);
0119     alphaMask.fill(0);
0120     alphaMask.setDevicePixelRatio(devicePixelRatioF());
0121     QPainter painter(&alphaMask);
0122     painter.setRenderHint(QPainter::Antialiasing);
0123     painter.setBrush(Qt::white);
0124     painter.setPen(Qt::NoPen);
0125     QPointF diamond[4] = {
0126         QPointF(0.5 * width(), m_margin),
0127         QPointF(m_margin, 0.5 * height()),
0128         QPointF(0.5 * width(), height() - m_margin),
0129         QPointF(width() - m_margin, 0.5 * height())
0130     };
0131     painter.drawConvexPolygon(diamond, 4);
0132 
0133     return alphaMask;
0134 }
0135 
0136 void KisVisualDiamondSelectorShape::drawCursor(QPainter &painter)
0137 {
0138     QPointF cursorPoint = convertShapeCoordinateToWidgetCoordinate(getCursorPosition());
0139     QColor col = getColorFromConverter(getCurrentColor());
0140     QBrush fill(Qt::SolidPattern);
0141 
0142     int cursorwidth = 5;
0143 
0144     painter.setPen(Qt::white);
0145     fill.setColor(Qt::white);
0146     painter.setBrush(fill);
0147     painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth);
0148     fill.setColor(col);
0149     painter.setPen(Qt::black);
0150     painter.setBrush(fill);
0151     painter.drawEllipse(cursorPoint, cursorwidth-1.0, cursorwidth-1.0);
0152 }