|
@@ -0,0 +1,238 @@
|
|
|
|
+#include "pch.h"
|
|
|
|
+#include <QLayout>
|
|
|
|
+#include "ColorGradient.h"
|
|
|
|
+#include "util.h"
|
|
|
|
+
|
|
|
|
+#define LeftRightGap 10
|
|
|
|
+#define ColorExampleStart 30
|
|
|
|
+#define ColorExmapleHeight 80
|
|
|
|
+#define SliderBeginHeight 83
|
|
|
|
+#define SliderBody 14
|
|
|
|
+#define SliderPeak 6
|
|
|
|
+#define SelectedPreview 20
|
|
|
|
+#define SelectedHeight 115
|
|
|
|
+ColorGradient::ColorGradient(QWidget *parent)
|
|
|
|
+ : QWidget(parent)
|
|
|
|
+{
|
|
|
|
+ interpolationCombobox = new QComboBox(this);
|
|
|
|
+ interpolationCombobox->addItem("RGB");
|
|
|
|
+ interpolationCombobox->addItem("HLS");
|
|
|
|
+ connect(interpolationCombobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
|
|
|
+ this, [this](int index) {this->setInterpolationMode((ColorGradient::ColorInterpolationMode)index); });
|
|
|
|
+ modeCombobox = new QComboBox(this);
|
|
|
|
+ modeCombobox->addItem("Interpolate");
|
|
|
|
+ modeCombobox->addItem("Discrete");
|
|
|
|
+ connect(modeCombobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
|
|
|
+ this, [this](int index) {this->setMode((ColorGradient::ColorMode)index);});
|
|
|
|
+ label = new QLabel("Gradient", this);
|
|
|
|
+ colorbutton = new ColorButton(this, QColor(0,0,0));
|
|
|
|
+ connect(colorbutton, &ColorButton::colorChanged, this, [this](QColor color) {
|
|
|
|
+ if (selected != nullptr) selected->color = color;
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ QGridLayout* layout = new QGridLayout(this);
|
|
|
|
+ layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
+ layout->setAlignment(Qt::AlignTop);
|
|
|
|
+ spacerH = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
|
|
|
+ layout->addWidget(label, 0, 0);
|
|
|
|
+ layout->addItem(spacerH, 0, 1);
|
|
|
|
+ layout->addWidget(colorbutton, 0, 2);
|
|
|
|
+ layout->addWidget(modeCombobox, 0, 3);
|
|
|
|
+ layout->addWidget(interpolationCombobox, 0, 4);
|
|
|
|
+ //layout->(spacer);
|
|
|
|
+
|
|
|
|
+ this->setLayout(layout);
|
|
|
|
+ pointList.push_back(ColorPoint(0.0, QColor(0, 100, 200)));
|
|
|
|
+ pointList.push_back(ColorPoint(0.5, QColor(0, 100, 50)));
|
|
|
|
+ pointList.push_back(ColorPoint(0.7, QColor(200, 10, 10)));
|
|
|
|
+ this->setMinimumHeight(150);
|
|
|
|
+ //this->setMinimumHeight(150);
|
|
|
|
+ this->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+ColorGradient::~ColorGradient()
|
|
|
|
+{
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+QColor ColorGradient::getColor(double alpha)
|
|
|
|
+{
|
|
|
|
+ alpha = std::clamp(alpha, 0.0, 1.0);
|
|
|
|
+ switch(mode) {
|
|
|
|
+ case ColorMode::Discrete: {
|
|
|
|
+ QColor result(255,255,255);
|
|
|
|
+ for (ColorPoint& point : pointList) {
|
|
|
|
+ if (point.alpha >= alpha) {
|
|
|
|
+ result = point.color;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+ case ColorMode::Interpolate: {
|
|
|
|
+ ColorPoint before(0.0, QColor(255, 255, 255));
|
|
|
|
+ ColorPoint last(1.0, QColor(255, 255, 255));
|
|
|
|
+ ColorPoint* first = &before;
|
|
|
|
+ ColorPoint* second = &last;
|
|
|
|
+ for (ColorPoint& point : pointList) {
|
|
|
|
+ if (point.alpha >= alpha) {
|
|
|
|
+ second = &point;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ first = &point;
|
|
|
|
+ }
|
|
|
|
+ double alphaBetween = util::inverseLinearInterpolation(first->alpha, second->alpha, alpha);
|
|
|
|
+ switch (interpolationMode) {
|
|
|
|
+ case ColorInterpolationMode::HSL:
|
|
|
|
+ return util::interpolateHSL(first->color, second->color, alphaBetween);
|
|
|
|
+ case ColorInterpolationMode::RGB:
|
|
|
|
+ default:
|
|
|
|
+ return util::interpolateRGB(first->color, second->color, alphaBetween);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ default: {
|
|
|
|
+ return QColor(0, 0, 0);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void ColorGradient::addColorPoint(double alpha)
|
|
|
|
+{
|
|
|
|
+ auto iter = pointList.begin();
|
|
|
|
+ for (; iter != pointList.end(); iter++) {
|
|
|
|
+ if (iter->alpha >= alpha) {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ selected = &*pointList.insert(iter, ColorPoint(alpha, getColor(alpha)));
|
|
|
|
+ colorbutton->setVisible(true);
|
|
|
|
+ colorbutton->setColor(selected->color);
|
|
|
|
+ emit gradientChanged();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void ColorGradient::removeColorPoint(ColorPoint& pointToRemove)
|
|
|
|
+{
|
|
|
|
+ pointList.erase(std::remove_if(pointList.begin(), pointList.end(),
|
|
|
|
+ [&pointToRemove](ColorPoint& point) {return &point == &pointToRemove; }));
|
|
|
|
+ selected = nullptr;
|
|
|
|
+ emit gradientChanged();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void ColorGradient::setMode(ColorMode mode)
|
|
|
|
+{
|
|
|
|
+ this->mode = mode;
|
|
|
|
+ update();
|
|
|
|
+ emit gradientChanged();
|
|
|
|
+ interpolationCombobox->setEnabled(mode != ColorGradient::ColorMode::Discrete);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void ColorGradient::setInterpolationMode(ColorInterpolationMode mode)
|
|
|
|
+{
|
|
|
|
+ this->interpolationMode = mode;
|
|
|
|
+ update();
|
|
|
|
+ emit gradientChanged();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void ColorGradient::paintEvent(QPaintEvent* event)
|
|
|
|
+{
|
|
|
|
+ QPainter painter(this);
|
|
|
|
+ painter.setRenderHint(QPainter::RenderHint::HighQualityAntialiasing);
|
|
|
|
+ QRect colorExampleRect(QPoint(rect().left() + LeftRightGap, ColorExampleStart), QPoint(rect().right() - LeftRightGap, ColorExmapleHeight));
|
|
|
|
+ painter.drawRect(colorExampleRect);
|
|
|
|
+ //painter.drawRect()
|
|
|
|
+ //drawSlider
|
|
|
|
+ QPen sliderPen;
|
|
|
|
+ sliderPen.setWidth(2);
|
|
|
|
+ painter.setPen(Qt::NoPen);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ for (ColorPoint& point : pointList) {
|
|
|
|
+ QPainterPath slider;
|
|
|
|
+ if (&point == selected) {
|
|
|
|
+ sliderPen.setColor(QColor(0, 0, 0));
|
|
|
|
+ painter.setPen(sliderPen);
|
|
|
|
+ }
|
|
|
|
+ painter.setBrush(point.color);
|
|
|
|
+ int middlePosition = util::linearInterpolate(colorExampleRect.left(), colorExampleRect.right(), point.alpha);
|
|
|
|
+ slider.moveTo(middlePosition, SliderBeginHeight);
|
|
|
|
+ slider.lineTo(middlePosition - SliderPeak, SliderBeginHeight + SliderPeak);
|
|
|
|
+ slider.lineTo(middlePosition - SliderPeak, SliderBeginHeight + SliderPeak + SliderBody);
|
|
|
|
+ slider.lineTo(middlePosition + SliderPeak, SliderBeginHeight + SliderPeak + SliderBody);
|
|
|
|
+ slider.lineTo(middlePosition + SliderPeak, SliderBeginHeight + SliderPeak);
|
|
|
|
+ slider.closeSubpath();
|
|
|
|
+ painter.drawPath(slider);
|
|
|
|
+ if (&point == selected) {
|
|
|
|
+ painter.setPen(Qt::NoPen);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ for (int pixelX = colorExampleRect.left() + 1; pixelX < colorExampleRect.right()+1; pixelX++) {
|
|
|
|
+ double alpha = util::inverseLinearInterpolation(colorExampleRect.left(), colorExampleRect.right()+1, pixelX);
|
|
|
|
+ QColor color = getColor(alpha);
|
|
|
|
+ painter.setPen(color);
|
|
|
|
+ painter.drawLine(pixelX, colorExampleRect.top() + 1, pixelX, colorExampleRect.bottom());
|
|
|
|
+ }
|
|
|
|
+ if (selected != nullptr) {
|
|
|
|
+ QRect currentSelected(QPoint(rect().right()/2 , SelectedHeight), QPoint(rect().right() / 2 + SelectedPreview, SelectedHeight + SelectedPreview));
|
|
|
|
+ painter.fillRect(currentSelected, selected->color);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void ColorGradient::mousePressEvent(QMouseEvent* event)
|
|
|
|
+{
|
|
|
|
+ QPoint mousePos = event->pos();
|
|
|
|
+ QRect area(QPoint(rect().left() + LeftRightGap, ColorExmapleHeight), QPoint(rect().right() - LeftRightGap, ColorExmapleHeight+SliderBody+SliderPeak));
|
|
|
|
+ if (area.contains(mousePos)) {
|
|
|
|
+
|
|
|
|
+ // Check for existing color point
|
|
|
|
+ // Select with left mouse Button
|
|
|
|
+ // Remove Point with right mouse Button
|
|
|
|
+ for (ColorPoint& point : pointList) {
|
|
|
|
+ double posX = util::linearInterpolate(area.left(), area.right() + 1, point.alpha);
|
|
|
|
+ if (posX - SliderPeak * 2 < mousePos.x() && mousePos.x() < posX + SliderPeak * 2) {
|
|
|
|
+ if (event->buttons() & Qt::LeftButton) {
|
|
|
|
+ selected = &point;
|
|
|
|
+ colorbutton->setVisible(true);
|
|
|
|
+ colorbutton->setColor(selected->color);
|
|
|
|
+ }
|
|
|
|
+ else if(event->buttons() & Qt::RightButton){
|
|
|
|
+ removeColorPoint(point);
|
|
|
|
+ colorbutton->setVisible(false);
|
|
|
|
+ }
|
|
|
|
+ update();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // Insert new Color Point
|
|
|
|
+ double alpha = util::inverseLinearInterpolation(area.left(), area.right() + 1, mousePos.x());
|
|
|
|
+ addColorPoint(alpha);
|
|
|
|
+ update();
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void ColorGradient::mouseMoveEvent(QMouseEvent* event)
|
|
|
|
+{
|
|
|
|
+ if (selected == nullptr) return;
|
|
|
|
+ //TODO(Bug #1) when mouse press button mouse move gets emitted and move the selected
|
|
|
|
+ //currently a workarround to not move the selected colorpoint when selecting a button
|
|
|
|
+ if (event->pos().y() < ColorExmapleHeight) return;
|
|
|
|
+ QPoint mousePos = event->pos();
|
|
|
|
+ QRect area(QPoint(rect().left() + LeftRightGap, ColorExmapleHeight), QPoint(rect().right() - LeftRightGap, ColorExmapleHeight + SliderBody + SliderPeak));
|
|
|
|
+ double alpha = util::inverseLinearInterpolation(area.left(), area.right() + 1, mousePos.x());
|
|
|
|
+ selected->alpha = std::clamp(alpha, 0.0, 1.0);
|
|
|
|
+
|
|
|
|
+ pointList.sort([](ColorPoint& a, ColorPoint& b) {
|
|
|
|
+ return a.alpha < b.alpha;
|
|
|
|
+ });
|
|
|
|
+ emit gradientChanged();
|
|
|
|
+ update();
|
|
|
|
+}
|