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