File indexing completed on 2024-05-19 04:29:30
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 #ifndef KIS_VISUAL_COLOR_SELECTOR_SHAPE_H 0007 #define KIS_VISUAL_COLOR_SELECTOR_SHAPE_H 0008 0009 #include <QWidget> 0010 #include <QScopedPointer> 0011 #include <QPixmap> 0012 #include <QRegion> 0013 #include <QMouseEvent> 0014 0015 #include <KoColor.h> 0016 #include "KoColorDisplayRendererInterface.h" 0017 0018 #include "KisVisualColorSelector.h" 0019 #include "KisColorSelectorConfiguration.h" 0020 0021 /** 0022 * @brief The KisVisualColorSelectorShape class 0023 * A 2d widget can represent at maximum 2 coordinates. 0024 * So first decide how many coordinates you need. (onedimensional, or twodimensional) 0025 * Then, select the channels you wish to be affected. This uses the model, so for cmyk 0026 * the channel is c=0, m=1, y=2, k=3, but for hsv, hue=0, sat=1, and val=2 0027 * Then finally, connect the displayrenderer, you can also do this with 'setdisplayrenderer' 0028 * 0029 * Either way, this class is made to be subclassed, with a few virtuals so that the geometry 0030 * can be calculated properly. 0031 */ 0032 0033 class KisVisualColorSelectorShape : public QWidget 0034 { 0035 Q_OBJECT 0036 public: 0037 /** 0038 * @brief The Dimensions enum 0039 * Whether or not the shape is single or two dimensional. 0040 **/ 0041 enum Dimensions{onedimensional, twodimensional}; 0042 explicit KisVisualColorSelectorShape(KisVisualColorSelector *parent, 0043 KisVisualColorSelectorShape::Dimensions dimension, 0044 int channel1, int channel2); 0045 ~KisVisualColorSelectorShape() override; 0046 0047 /** 0048 * @brief getCursorPosition 0049 * @return current cursor position in shape-coordinates. 0050 */ 0051 QPointF getCursorPosition() const; 0052 /** 0053 * @brief getDimensions 0054 * @return whether this is a single or twodimensional widget. 0055 */ 0056 Dimensions getDimensions() const; 0057 /** 0058 * @brief getImageMap returns the updated base image 0059 * @return the final image of the shape content, before the handle gets drawn. 0060 * the pixmap will not change until a redraw is required, which depends on 0061 * whether the shape is static or changes depending on other color channels. 0062 */ 0063 const QImage& getImageMap(); 0064 /** 0065 * @brief getCurrentColor 0066 * @return the current kocolor 0067 */ 0068 KoColor getCurrentColor(); 0069 /** 0070 * @brief getColorFromConverter 0071 * @param c a koColor. 0072 * @return get the qcolor from the given kocolorusing this widget's display renderer. 0073 */ 0074 QColor getColorFromConverter(KoColor c); 0075 0076 /** 0077 * @brief getSpaceForSquare 0078 * @param geom the full widget rectangle 0079 * @return rectangle with enough space for second widget 0080 */ 0081 virtual QRect getSpaceForSquare(QRect geom) = 0; 0082 virtual QRect getSpaceForCircle(QRect geom) = 0; 0083 virtual QRect getSpaceForTriangle(QRect geom) = 0; 0084 0085 bool isHueControl() const; 0086 virtual bool supportsGamutMask() const; 0087 0088 /** 0089 * @brief forceImageUpdate 0090 * force the image to recache. 0091 */ 0092 void forceImageUpdate(); 0093 0094 /** 0095 * @brief Notify shape that the gamut mask changed 0096 * 0097 * The gamut mask shall be updated and the widget repainted if necessary. 0098 * This includes removal of gamut masks 0099 */ 0100 virtual void updateGamutMask(); 0101 0102 /** 0103 * @brief setBorderWidth 0104 * set the border of the single dimensional selector. 0105 * @param width 0106 */ 0107 virtual void setBorderWidth(int width) = 0; 0108 0109 /** 0110 * @brief channel 0111 * Get the channel index associated with a selector shape dimension 0112 * @param dimension A shape dimension that can be controlled by the cursor 0113 * @return 0114 */ 0115 int channel(int dimension) const; 0116 0117 quint32 channelMask() const; 0118 0119 /** 0120 * @brief setCursorPosition 0121 * Set the cursor to normalized shape coordinates. This will only repaint the cursor. 0122 * @param position normalized shape coordinates ([0,1] range, not yet transformed to actual channel values!) 0123 * @param signal if true, emit a sigCursorMoved signal 0124 */ 0125 void setCursorPosition(QPointF position, bool signal = false); 0126 0127 /** 0128 * @brief setChannelValues 0129 * Set the current channel values; 0130 * Note that channel values controlled by the shape itself have no effect unless setCursor is true. 0131 * This will trigger a full widget repaint. 0132 * @param position normalized shape coordinates ([0,1] range) 0133 * these are not yet transformed to color space specific ranges! 0134 * @param setCursor if true, sets the cursor too, otherwise the shape-controlled channels are not set 0135 */ 0136 void setChannelValues(QVector4D channelValues, quint32 channelFlags); 0137 0138 void setAcceptTabletEvents(bool on); 0139 0140 Q_SIGNALS: 0141 void sigCursorMoved(QPointF pos); 0142 0143 protected: 0144 KisVisualColorSelector* colorSelector() const; 0145 KisVisualColorModel* selectorModel() const; 0146 /** 0147 * @brief convertImageMap 0148 * convert image data containing raw KoColor data into a QImage 0149 * @param data must point to memory of size width()*height()*pixelSize 0150 * @param size the number of bytes to read from data, must match aforementioned criteria 0151 * @return the converted QImage guaranteed to match the widget size (black content on failure) 0152 */ 0153 QImage convertImageMap(const quint8 *rawColor, quint32 bufferSize, QSize imgSize) const; 0154 /** 0155 * @brief renderBackground 0156 * Render the widget background visible inside the widget's mask in current color space 0157 * Rendering shall be done with the conversion functions of KisVisualColorSelector 0158 * @param data points to zero-initialized memory of size width()*height()*pixelSize 0159 * @param pixelSize the data size to transfer from KoColor::data() to data per pixel 0160 * in the current color space 0161 * @param channelValues the normalized channel values of the currently selected color 0162 */ 0163 virtual QImage renderBackground(const QVector4D &channelValues, const QImage &alpha) const; 0164 virtual QImage compositeBackground() const; 0165 /** 0166 * @brief render the alpha mask for the widget background 0167 * the returned image is expected to be QImage::Format_Alpha8 0168 */ 0169 virtual QImage renderAlphaMask() const; 0170 virtual QImage renderStaticAlphaMask() const; 0171 /** 0172 * @brief default implementation just calls convertWidgetCoordinateToShapeCoordinate(pos) 0173 */ 0174 virtual QPointF mousePositionToShapeCoordinate(const QPointF &pos, const QPointF &dragStart) const; 0175 0176 void mousePressEvent(QMouseEvent *e) override; 0177 void mouseMoveEvent(QMouseEvent *e) override; 0178 void mouseReleaseEvent(QMouseEvent *e) override; 0179 void tabletEvent(QTabletEvent* event) override; 0180 void paintEvent(QPaintEvent*) override; 0181 void resizeEvent(QResizeEvent *) override; 0182 0183 private: 0184 struct Private; 0185 const QScopedPointer<Private> m_d; 0186 0187 /** 0188 * @brief convertShapeCoordinateToWidgetCoordinate 0189 * @return take the position in the shape and convert it to screen coordinates. 0190 */ 0191 virtual QPointF convertShapeCoordinateToWidgetCoordinate(QPointF) const = 0; 0192 0193 /** 0194 * @brief convertWidgetCoordinateToShapeCoordinate 0195 * Convert a coordinate in the widget's height/width to a shape coordinate. 0196 * @param coordinate the position your wish to have the shape coordinates of. 0197 */ 0198 virtual QPointF convertWidgetCoordinateToShapeCoordinate(QPointF coordinate) const = 0; 0199 0200 /** 0201 * @brief getPixmap 0202 * @return the pixmap of this shape. 0203 */ 0204 virtual QRegion getMaskMap() = 0; 0205 virtual void drawCursor(QPainter &painter) = 0; 0206 virtual void drawGamutMask(QPainter &painter); 0207 }; 0208 0209 #endif