File indexing completed on 2024-05-12 16:02:06
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Wolthera van Hovell tot Westerflier <griffinvalley@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 #include "KisVisualEllipticalSelectorShape.h" 0007 0008 #include <QColor> 0009 #include <QPainter> 0010 #include <QRect> 0011 #include <QLineF> 0012 #include <QtMath> 0013 0014 #include "kis_debug.h" 0015 #include "kis_global.h" 0016 0017 KisVisualEllipticalSelectorShape::KisVisualEllipticalSelectorShape(QWidget *parent, 0018 Dimensions dimension, 0019 const KoColorSpace *cs, 0020 int channel1, int channel2, 0021 const KoColorDisplayRendererInterface *displayRenderer, 0022 int barWidth, 0023 singelDTypes d) 0024 : KisVisualColorSelectorShape(parent, dimension, cs, channel1, channel2, displayRenderer) 0025 { 0026 //qDebug() << "creating KisVisualEllipticalSelectorShape" << this; 0027 m_type = d; 0028 m_barWidth = barWidth; 0029 } 0030 0031 KisVisualEllipticalSelectorShape::~KisVisualEllipticalSelectorShape() 0032 { 0033 //qDebug() << "deleting KisVisualEllipticalSelectorShape" << this; 0034 } 0035 0036 QSize KisVisualEllipticalSelectorShape::sizeHint() const 0037 { 0038 return QSize(180,180); 0039 } 0040 0041 void KisVisualEllipticalSelectorShape::setBorderWidth(int width) 0042 { 0043 m_barWidth = width; 0044 forceImageUpdate(); 0045 update(); 0046 } 0047 0048 QRect KisVisualEllipticalSelectorShape::getSpaceForSquare(QRect geom) 0049 { 0050 int sizeValue = qMin(width(),height()); 0051 QRect b(geom.left(), geom.top(), sizeValue, sizeValue); 0052 QLineF radius(b.center(), QPointF(b.left()+m_barWidth, b.center().y()) ); 0053 radius.setAngle(135); 0054 QPointF tl = radius.p2(); 0055 radius.setAngle(315); 0056 QPointF br = radius.p2(); 0057 QRect r(tl.toPoint(), br.toPoint()); 0058 return r; 0059 } 0060 0061 QRect KisVisualEllipticalSelectorShape::getSpaceForCircle(QRect geom) 0062 { 0063 int sizeValue = qMin(width(),height()); 0064 QRect b(geom.left(), geom.top(), sizeValue, sizeValue); 0065 QPointF tl = QPointF (b.topLeft().x()+m_barWidth, b.topLeft().y()+m_barWidth); 0066 QPointF br = QPointF (b.bottomRight().x()-m_barWidth, b.bottomRight().y()-m_barWidth); 0067 QRect r(tl.toPoint(), br.toPoint()); 0068 return r; 0069 } 0070 0071 QRect KisVisualEllipticalSelectorShape::getSpaceForTriangle(QRect geom) 0072 { 0073 int sizeValue = qMin(width(),height()); 0074 QPointF center(0.5 * width(), 0.5 * height()); 0075 qreal radius = 0.5 * sizeValue - (m_barWidth + 4); 0076 QLineF rLine(center, QPointF(center.x() + radius, center.y())); 0077 rLine.setAngle(330); 0078 QPoint br(rLine.p2().toPoint()); 0079 //QPoint br(qCeil(rLine.p2().x()), qCeil(rLine.p2().y())); 0080 QPoint tl(width() - br.x(), m_barWidth + 4); 0081 QRect bound(tl, br); 0082 // adjust with triangle default margin for cursor rendering 0083 // it's not +5 because above calculation is for pixel center and ignores 0084 // the fact that dimensions are then effectively 1px smaller... 0085 bound.adjust(-5, -5, 4, 4); 0086 return bound.intersected(geom); 0087 } 0088 0089 QPointF KisVisualEllipticalSelectorShape::convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) const 0090 { 0091 qreal offset = 7.0; 0092 qreal a = (qreal)width()*0.5; 0093 QPointF center(a, a); 0094 QLineF line(center, QPoint((m_barWidth*0.5),a)); 0095 qreal angle = coordinate.x()*360.0; 0096 angle = 360.0 - fmod(angle+180.0, 360.0); 0097 if (m_type==KisVisualEllipticalSelectorShape::borderMirrored) { 0098 angle = (coordinate.x()/2)*360.0; 0099 angle = fmod((angle+270.0), 360.0); 0100 } 0101 line.setAngle(angle); 0102 if (getDimensions()!=KisVisualColorSelectorShape::onedimensional) { 0103 line.setLength(qMin(coordinate.y()*(a-offset), a-offset)); 0104 } 0105 return line.p2(); 0106 } 0107 0108 QPointF KisVisualEllipticalSelectorShape::convertWidgetCoordinateToShapeCoordinate(QPointF coordinate) const 0109 { 0110 //default implementation: 0111 qreal x = 0.5; 0112 qreal y = 1.0; 0113 qreal offset = 7.0; 0114 QPointF center = QRectF(QPointF(0.0, 0.0), this->size()).center(); 0115 qreal a = (qreal(this->width()) / qreal(2)); 0116 qreal xRel = center.x()-coordinate.x(); 0117 qreal yRel = center.y()-coordinate.y(); 0118 qreal radius = sqrt(xRel*xRel+yRel*yRel); 0119 0120 if (m_type!=KisVisualEllipticalSelectorShape::borderMirrored){ 0121 qreal angle = atan2(yRel, xRel); 0122 angle = kisRadiansToDegrees(angle); 0123 angle = fmod(angle+360, 360.0); 0124 x = angle/360.0; 0125 if (getDimensions()==KisVisualColorSelectorShape::twodimensional) { 0126 y = qBound(0.0,radius/(a-offset), 1.0); 0127 } 0128 0129 } else { 0130 qreal angle = atan2(xRel, yRel); 0131 angle = kisRadiansToDegrees(angle); 0132 angle = fmod(angle+180, 360.0); 0133 if (angle>180.0) { 0134 angle = 360.0-angle; 0135 } 0136 x = (angle/360.0)*2; 0137 if (getDimensions()==KisVisualColorSelectorShape::twodimensional) { 0138 y = qBound(0.0,(radius+offset)/a, 1.0); 0139 } 0140 } 0141 0142 return QPointF(x, y); 0143 } 0144 0145 QPointF KisVisualEllipticalSelectorShape::mousePositionToShapeCoordinate(const QPointF &pos, const QPointF &dragStart) const 0146 { 0147 QPointF pos2(pos); 0148 if (m_type == KisVisualEllipticalSelectorShape::borderMirrored) { 0149 qreal h_center = width()/2.0; 0150 bool start_left = dragStart.x() < h_center; 0151 bool cursor_left = pos.x() < h_center; 0152 if (start_left != cursor_left) { 0153 pos2.setX(h_center); 0154 } 0155 } 0156 return convertWidgetCoordinateToShapeCoordinate(pos2); 0157 } 0158 0159 QRegion KisVisualEllipticalSelectorShape::getMaskMap() 0160 { 0161 QRegion mask = QRegion(0,0,width(),height(), QRegion::Ellipse); 0162 if (getDimensions()==KisVisualColorSelectorShape::onedimensional) { 0163 mask = mask.subtracted(QRegion(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2), QRegion::Ellipse)); 0164 } 0165 return mask; 0166 } 0167 0168 QImage KisVisualEllipticalSelectorShape::renderAlphaMask() const 0169 { 0170 // Hi-DPI aware rendering requires that we determine the device pixel dimension; 0171 // actual widget size in device pixels is not accessible unfortunately, it might be 1px smaller... 0172 const int deviceWidth = qCeil(width() * devicePixelRatioF()); 0173 const int deviceHeight = qCeil(height() * devicePixelRatioF()); 0174 0175 QImage alphaMask(deviceWidth, deviceHeight, QImage::Format_Alpha8); 0176 alphaMask.fill(0); 0177 alphaMask.setDevicePixelRatio(devicePixelRatioF()); 0178 QPainter painter(&alphaMask); 0179 painter.setRenderHint(QPainter::Antialiasing); 0180 painter.setBrush(Qt::white); 0181 painter.setPen(Qt::NoPen); 0182 painter.drawEllipse(2, 2, width() - 4, height() - 4); 0183 //painter.setBrush(Qt::black); 0184 if (getDimensions() == KisVisualColorSelectorShape::onedimensional) { 0185 painter.setCompositionMode(QPainter::CompositionMode_Clear); 0186 painter.drawEllipse(m_barWidth - 2, m_barWidth - 2, width() - 2*(m_barWidth-2), height() - 2*(m_barWidth-2)); 0187 } 0188 return alphaMask; 0189 } 0190 0191 void KisVisualEllipticalSelectorShape::drawCursor() 0192 { 0193 //qDebug() << this << "KisVisualEllipticalSelectorShape::drawCursor: image needs update" << imagesNeedUpdate(); 0194 QPointF cursorPoint = convertShapeCoordinateToWidgetCoordinate(getCursorPosition()); 0195 QImage fullSelector = getImageMap(); 0196 QColor col = getColorFromConverter(getCurrentColor()); 0197 QPainter painter; 0198 painter.begin(&fullSelector); 0199 painter.setRenderHint(QPainter::Antialiasing); 0200 QBrush fill; 0201 fill.setStyle(Qt::SolidPattern); 0202 0203 int cursorwidth = 5; 0204 0205 if (m_type==KisVisualEllipticalSelectorShape::borderMirrored) { 0206 painter.setPen(Qt::white); 0207 fill.setColor(Qt::white); 0208 painter.setBrush(fill); 0209 painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth); 0210 QPointF mirror(width() - cursorPoint.x(), cursorPoint.y()); 0211 painter.drawEllipse(mirror, cursorwidth, cursorwidth); 0212 fill.setColor(col); 0213 painter.setPen(Qt::black); 0214 painter.setBrush(fill); 0215 painter.drawEllipse(cursorPoint, cursorwidth-1, cursorwidth-1); 0216 painter.drawEllipse(mirror, cursorwidth-1, cursorwidth-1); 0217 0218 } else { 0219 painter.setPen(Qt::white); 0220 fill.setColor(Qt::white); 0221 painter.setBrush(fill); 0222 painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth); 0223 fill.setColor(col); 0224 painter.setPen(Qt::black); 0225 painter.setBrush(fill); 0226 painter.drawEllipse(cursorPoint, cursorwidth-1.0, cursorwidth-1.0); 0227 } 0228 painter.end(); 0229 setFullImage(fullSelector); 0230 }