Subversion Repositories Scribus

Rev

Rev 24661 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/


#include "colorwheelwidget.h"

#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
#define _USE_MATH_DEFINES
#endif
#include <cmath>
#include <QPainter>

#include "sccolor.h"
#include "sccolorengine.h"


ColorWheel::ColorWheel(QWidget * parent, const char * name) : QLabel(parent)
{
        setObjectName(name);
        pointList.clear();
        currentDoc = nullptr;
        currentColorSpace = colorModelRGB;
        baseAngle = 0;
        angleShift = 270;
        widthH = heightH = 150;
        // create color map
        colorMap.clear();
        // fit the colorMap 1st value with matrix beginning
        int mapIndex = angleShift;
        for (int i = 0; i < 360; ++i)
        {
                QColor c;
                c.setHsv(i, 255, 255);
                ScColor col;
                col.fromQColor(c);
                colorMap[mapIndex++] = col;
                if (mapIndex > 359)
                        mapIndex = 0;
        }
        actualColor = colorMap[0];
        trBaseColor = tr("Base Color");
}

void ColorWheel::mousePressEvent(QMouseEvent *e)
{
        mouseReleaseEvent(e);
}

void ColorWheel::mouseMoveEvent(QMouseEvent *e)
{
        mouseReleaseEvent(e);
}

void ColorWheel::mouseReleaseEvent(QMouseEvent *e)
{
        baseAngle = valueFromPoint(e->pos());
        actualColor = colorMap[baseAngle];
        actualColor = ScColorEngine::convertToModel(actualColor, currentDoc, currentColorSpace);
        emit clicked(e->button(), e->pos());
        update();
}

void ColorWheel::paintEvent(QPaintEvent *)
{
        paintWheel();
        paintCenterSample();
        makeColors();
        // clear marks
        for (int i = 0; i < 360; ++i)
                drawBorderPoint(i, false, true);
        for (auto it = pointList.constBegin(); it != pointList.constEnd(); ++it)
                drawBorderPoint(it->angle, it->base);
}

void ColorWheel::makeColors()
{
        if (currentType == Monochromatic)
                makeMonochromatic();
        if (currentType == Analogous)
                makeAnalogous();
        if (currentType == Complementary)
                makeComplementary();
        if (currentType == Split)
                makeSplit();
        if (currentType == Triadic)
                makeTriadic();
        if (currentType == Tetradic)
                makeTetradic();
}

void ColorWheel::paintCenterSample()
{
        QPainter p;
        p.begin(this);
        p.setRenderHint(QPainter::Antialiasing, true);
        p.setPen(QPen(Qt::black, 2));
        p.setBrush(ScColorEngine::getDisplayColor(actualColor, currentDoc ));
        p.drawEllipse(widthH - 20, heightH - 20, 40, 40);
        p.end();
}

void ColorWheel::paintWheel()
{
        int h, s, v;
        QColor col(ScColorEngine::getDisplayColor(actualColor, currentDoc ));
        col.getHsv(&h, &s, &v);
        int width = this->width();
        int height = this->height();
        QPainter p;
        p.begin(this);
        p.setWindow( 0, 0, width, height);
        p.fillRect(0, 0, width, height, palette().color(QPalette::Base));
        p.setPen(Qt::black);
        p.drawRect(0, 0, width, height);
        // Half sizes
        heightH = height / 2;
        widthH = width / 2;
        for (int i = 0; i < 360; ++i)
        {
                QTransform matrix;
                matrix.translate(widthH, heightH);
                matrix.rotate((float) i);
                p.setWorldTransform(matrix);
                QColor c;
                c.setHsv(i, 255, 255);
                p.setPen(QPen(c, 7));
                p.setBrush(c);
                p.drawLine(0, 0, 130, 0);
        }
}

QString ColorWheel::getTypeDescription(MethodType aType)
{
        switch (aType)
        {
                case Monochromatic: return tr("Monochromatic");
                case Analogous: return tr("Analogous");
                case Complementary: return tr("Complementary");
                case Split: return tr("Split Complementary");
                case Triadic: return tr("Triadic");
                case Tetradic: return tr("Tetradic (Double Complementary)");
        }
        return "n/a";
}

ScColor ColorWheel::colorByAngle(int angle)
{
        while (angle > 359)
                angle -= 359;
        while (angle < 0)
                angle += 359;
        return colorSpaceColor(colorMap[angle]);
}

ScColor ColorWheel::sampleByAngle(int angle)
{
        while (angle > 359)
                angle -= 359;
        while (angle < 0)
                angle += 359;
        //drawBorderPoint(angle);
        PaintPoint p;
        p.angle = angle;
        p.base = false;
        pointList.append(p);
        return colorSpaceColor(colorMap[angle]);
}

ScColor ColorWheel::colorSpaceColor(ScColor col)
{
        QColor newcol;
        ScColor ret;
        int h, s, v;

        ScColorEngine::getRGBColor(col, currentDoc).getHsv(&h, &s, &v);
        newcol.setHsv(h, s, v);
        ret.fromQColor(newcol);
        ret = ScColorEngine::convertToModel(ret, currentDoc, currentColorSpace);
        return ret;
}

void ColorWheel::baseColor()
{
        //clearBorder();
        pointList.clear();
        //drawBorderPoint(baseAngle, true);
        PaintPoint p;
        p.angle = baseAngle;
        p.base = true;
        pointList.append(p);
        //paintCenterSample();
        colorList.clear();
        colorList[trBaseColor] = colorSpaceColor(actualColor);
}

void ColorWheel::makeMonochromatic()
{
        baseColor();
        QColor col(ScColorEngine::getRGBColor(actualColor, currentDoc));
        ScColor l;
        l.fromQColor(col.lighter());
        l = ScColorEngine::convertToModel(l, currentDoc, currentColorSpace);
        colorList[tr("Monochromatic Light")] = l;
        l.fromQColor(col.darker());
        l = ScColorEngine::convertToModel(l, currentDoc, currentColorSpace);
        colorList[tr("Monochromatic Dark")] = l;
        currentType = Monochromatic;
}

void ColorWheel::makeAnalogous()
{
        baseColor();
        colorList[tr("1st. Analogous")] = sampleByAngle(baseAngle + angle);
        colorList[tr("2nd. Analogous")] = sampleByAngle(baseAngle - angle);
        currentType = Analogous;
}

void ColorWheel::makeComplementary()
{
        baseColor();
        colorList[tr("Complementary")] = sampleByAngle(baseAngle + 180);
        currentType = Complementary;
}

void ColorWheel::makeSplit()
{
        baseColor();
        colorList[tr("1st. Split")] = sampleByAngle(baseAngle + angle);
        colorList[tr("2nd. Split")] = sampleByAngle(baseAngle - angle);
        colorList[tr("3rd. Split")] = sampleByAngle(baseAngle + 180 + angle);
        colorList[tr("4th. Split")] = sampleByAngle(baseAngle + 180 - angle);
        currentType = Split;
}

void ColorWheel::makeTriadic()
{
        baseColor();
        colorList[tr("1st. Triadic")] = sampleByAngle(baseAngle + 120);
        colorList[tr("2nd. Triadic")] = sampleByAngle(baseAngle - 120);
        currentType = Triadic;
}

void ColorWheel::makeTetradic()
{
        baseColor();
        colorList[tr("1st. Tetradic (base opposite)")] = sampleByAngle(baseAngle + 180);
        colorList[tr("2nd. Tetradic (angle)")] = sampleByAngle(baseAngle + angle);
        colorList[tr("3rd. Tetradic (angle opposite)")] = sampleByAngle(baseAngle + angle + 180);
        currentType = Tetradic;
}

// void ColorWheel::clearBorder()
// {
//      for (int i = 0; i < 360; ++i)
//              drawBorderPoint(i, false, true);
// }

void ColorWheel::drawBorderPoint(int angle, bool base, bool clear)
{
        double r = 137.0;
        angle -= angleShift;
        double radang = M_PI * (double)angle/180.0;
        int x = (int)(r * cos(radang)) + widthH;
        int y = (int)(r * sin(radang)) + heightH;
        // draw border mark
        QPainter p;
        p.begin(this);
        p.setRenderHint(QPainter::Antialiasing, true);
        if (clear)
        {
                QColor baseColor = palette().color(QPalette::Base);
                p.setPen(QPen(baseColor, 1));
                p.setBrush(baseColor);
        }
        else
        {
                QColor textColor = palette().color(QPalette::WindowText);
                p.setPen(QPen(textColor, 1));
                if (base)
                        p.setBrush(Qt::red);
                else
                        p.setBrush(Qt::SolidPattern);
        }
        p.drawEllipse(x - 4, y - 4, 8, 8);
        p.end();
}

int ColorWheel::valueFromPoint(const QPoint & p) const
{
        double yy = (double)heightH - (double)p.y();
        double xx = (double)p.x() - (double)widthH;
        double a = (xx || yy) ? atan2(yy, xx) : 0.0;

        if ( a < M_PI/-2 )
                a = a + M_PI * 2;

        int minv = 0, maxv = 359;
        int r = maxv - minv;
        int val;

        val = (int)(0.5 + minv + r * (M_PI * 3/2 -a) / (2 * M_PI));

        return val;
}

bool ColorWheel::recomputeColor(ScColor col)
{
        int origh, origs, origv;
        ColorMap::iterator it;
        QColor c(ScColorEngine::getRGBColor(col, currentDoc));
        QColor act(ScColorEngine::getRGBColor(actualColor, currentDoc));

        c.getHsv(&origh, &origs, &origv);
        angle = origh + angleShift;
        if (angle > 359)
                angle -= 360;
        if (colorMap.contains(angle))
        {
                int tmph, tmps, tmpv;
                QColor col(ScColorEngine::getRGBColor(colorMap[angle], currentDoc));
                col.getHsv(&tmph, &tmps, &tmpv);
                act.setHsv(tmph , origs, origv);
                actualColor.fromQColor(act);
                actualColor = ScColorEngine::convertToModel(actualColor, currentDoc, currentColorSpace);
                baseAngle = angle;
                return true;
        }
        return false;
}