KisVisualColorSelectorShape.h 8.03 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Copyright (C) Wolthera van Hovell tot Westerflier <griffinvalley@gmail.com>, (C) 2016
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
18 19
#ifndef KIS_VISUAL_COLOR_SELECTOR_SHAPE_H
#define KIS_VISUAL_COLOR_SELECTOR_SHAPE_H
20 21 22 23 24 25 26 27 28 29 30

#include <QWidget>
#include <QScopedPointer>
#include <QPixmap>
#include <QRegion>
#include <QMouseEvent>

#include <KoColor.h>
#include <KoColorSpace.h>
#include "KoColorDisplayRendererInterface.h"

31 32
#include "KisVisualColorSelector.h"
#include "KisColorSelectorConfiguration.h"
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

/**
 * @brief The KisVisualColorSelectorShape class
 * A 2d widget can represent at maximum 2 coordinates.
 * So first decide howmany coordinates you need. (onedimensional, or twodimensional)
 * Then the model, (Channel, HSV, HSL, HSI, YUV). Channel is the raw color channels.
 * When it finds a non-implemented feature it'll return to Channel.
 * Then, select the channels you wish to be affected. This uses the model, so for cmyk
 * the channel is c=0, m=1, y=2, k=3, but for hsv, hue=0, sat=1, and val=2
 * These can also be set with 'slotsetactive channels'.
 * Then finally, connect the displayrenderer, you can also do this with 'setdisplayrenderer'
 *
 * Either way, this class is made to be subclassed, with a few virtuals so that the geometry
 * can be calculated properly.
 */

class KisVisualColorSelectorShape : public QWidget
{
    Q_OBJECT
public:
    /**
     * @brief The Dimensions enum
luz paz's avatar
luz paz committed
55
     * Whether or not the shape is single or two dimensional.
56 57 58 59 60 61 62 63
     **/
    enum Dimensions{onedimensional, twodimensional};
    enum ColorModel{Channel, HSV, HSL, HSI, HSY, YUV};
    explicit KisVisualColorSelectorShape(QWidget *parent,
                                         KisVisualColorSelectorShape::Dimensions dimension,
                                         const KoColorSpace *cs,
                                         int channel1, int channel2,
                                         const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance());
64
    ~KisVisualColorSelectorShape() override;
65 66 67 68 69 70 71 72 73 74

    /**
     * @brief getCursorPosition
     * @return current cursor position in shape-coordinates.
     */
    QPointF getCursorPosition();
    /**
     * @brief getDimensions
     * @return whether this is a single or twodimensional widget.
     */
75
    Dimensions getDimensions() const;
76 77 78 79 80 81
    /**
     * @brief getPixmap
     * @return the pixmap of the gradient, for drawing on with a subclass.
     * the pixmap will not change unless 'm_d->setPixmap=true' which is toggled by
     * refresh and update functions.
     */
82
    bool imagesNeedUpdate() const;
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
    QImage getImageMap();
    /**
     * @brief setFullImage
     * Set the full widget image to be painted.
     * @param full this should be the full image.
     */
    void setFullImage(QImage full);
    /**
     * @brief getCurrentColor
     * @return the current kocolor
     */
    KoColor getCurrentColor();
    /**
     * @brief setDisplayRenderer
     * disconnect the old display renderer if needed and connect the new one.
     * @param displayRenderer
     */
    void setDisplayRenderer (const KoColorDisplayRendererInterface *displayRenderer);
    /**
     * @brief getColorFromConverter
     * @param c a koColor.
     * @return get the qcolor from the given kocolorusing this widget's display renderer.
     */
    QColor getColorFromConverter(KoColor c);

    /**
     * @brief getSpaceForSquare
     * @param geom the full widget rectangle
     * @return rectangle with enough space for second widget
     */
    virtual QRect getSpaceForSquare(QRect geom) = 0;
    virtual QRect getSpaceForCircle(QRect geom) = 0;
    virtual QRect getSpaceForTriangle(QRect geom) = 0;

    /**
     * @brief forceImageUpdate
     * force the image to recache.
     */
    void forceImageUpdate();

    /**
     * @brief setBorderWidth
     * set the border of the single dimensional selector.
     * @param width
     */
    virtual void setBorderWidth(int width) = 0;

    /**
     * @brief getChannels
     * get used channels
     * @return
     */
135
    QVector <int> getChannels() const;
136

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
    /**
      * @brief setCursorPosition
      * Set the cursor to normalized shape coordinates. This will only repaint the cursor.
      * @param position normalized shape coordinates ([0,1] range, not yet transformed to actual channel values!)
      * @param signal if true, emit a sigCursorMoved signal
      */
    void setCursorPosition(QPointF position, bool signal = false);

    /**
      * @brief setChannelValues
      * Set the current channel values;
      * Note that channel values controlled by the shape itself have no effect unless setCursor is true.
      * This will trigger a full widget repaint.
      * @param position normalized shape coordinates ([0,1] range)
      * these are not yet transformed to color space specific ranges!
      * @param setCursor if true, sets the cursor too, otherwise the shape-controlled channels are not set
      */
    void setChannelValues(QVector4D channelValues, bool setCursor);

156 157

Q_SIGNALS:
158
    void sigCursorMoved(QPointF pos);
159 160 161 162 163 164 165 166 167

public Q_SLOTS:
    /**
     * @brief slotSetActiveChannels
     * Change the active channels if necessary.
     * @param channel1 used by single and twodimensional widgets.
     * @param channel2 only used by twodimensional widgets.
     */
    void slotSetActiveChannels(int channel1, int channel2);
168

169
protected:
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
    /**
     * @brief convertImageMap
     * convert image data containing raw KoColor data into a QImage
     * @param data must point to memory of size width()*height()*pixelSize
     * @param size the number of bytes to read from data, must match aforementioned cirteria
     * @return the converted QImage guaranteed to match the widget size (black content on failure)
     */
    QImage convertImageMap(const quint8 *rawColor, quint32 size) const;
    /**
     * @brief renderBackground
     * Render the widget background visible inside the widget's mask in current color space
     * Rendering shall be done with the conversion functions of KisVisualColorSelector
     * @param data points to zero-initialized memory of size width()*height()*pixelSize
     * @param pixelSize the data size to transfer from KoColor::data() to data per pixel
     * in the current color space
     * @param channelValues the normalized channel values of the currently picked color
     */
    virtual QImage renderBackground(const QVector4D &channelValues, quint32 pixelSize) const;
188

189 190 191 192
    void mousePressEvent(QMouseEvent *e) override;
    void mouseMoveEvent(QMouseEvent *e) override;
    void mouseReleaseEvent(QMouseEvent *e) override;
    void paintEvent(QPaintEvent*) override;
193
    void resizeEvent(QResizeEvent *) override;
194

195 196 197 198 199 200 201 202
private:
    struct Private;
    const QScopedPointer<Private> m_d;

    /**
     * @brief convertShapeCoordinateToWidgetCoordinate
     * @return take the position in the shape and convert it to screen coordinates.
     */
203
    virtual QPointF convertShapeCoordinateToWidgetCoordinate(QPointF) const = 0;
204 205 206 207 208 209

    /**
     * @brief convertWidgetCoordinateToShapeCoordinate
     * Convert a coordinate in the widget's height/width to a shape coordinate.
     * @param coordinate the position your wish to have the shape coordinates of.
     */
210
    virtual QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) const = 0;
211 212 213 214 215 216 217 218 219

    /**
     * @brief getPixmap
     * @return the pixmap of this shape.
     */
    virtual QRegion getMaskMap() = 0;
    virtual void drawCursor() = 0;
};

220
#endif