123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- #include "pch.h"
- #include <QLayout>
- #include <QDoubleValidator>
- #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);});
- colorButton = new ColorButton(this, QColor(0,0,0));
-
- connect(colorButton, &ColorButton::colorChanged, this, [this](QColor color) {
- if (selected != nullptr) setColorPointColor(*selected, color);
- });
- QVBoxLayout* vBoxLayout = new QVBoxLayout(this);
- vBoxLayout->setContentsMargins(0,0,0,0);
- QGridLayout* layoutTop = new QGridLayout();
- vBoxLayout->addLayout(layoutTop);
- layoutTop->setContentsMargins(0, 0, 0, 0);
- layoutTop->setAlignment(Qt::AlignTop);
- spacerH = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
- layoutTop->addWidget(new QLabel("ObjectiveFunction-Gradient:", this), 0, 0);
- layoutTop->addItem(spacerH, 0, 1);
- layoutTop->addWidget(modeCombobox, 0, 6);
- layoutTop->addWidget(interpolationCombobox, 0, 7);
- QGridLayout* layoutBottom = new QGridLayout();
- vBoxLayout->addLayout(layoutBottom);
- layoutBottom->setContentsMargins(0, 0, 0, 0);
- layoutBottom->setAlignment(Qt::AlignBottom);
- layoutBottom->addItem(new QSpacerItem(10, 20, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 0);
- colorLabel = new QLabel("Color:");
- layoutBottom->addWidget(colorLabel, 0, 1);
- layoutBottom->addWidget(colorButton, 0, 2);
- alphaLabel = new QLabel("Alpha:");
- layoutBottom->addWidget(alphaLabel, 0, 3);
-
-
- layoutTop->addWidget(new QLabel("ValueRange:"), 0, 2);
- minEdit = new QLineEdit();
- minEdit->setMaximumWidth(80);
- layoutTop->addWidget(minEdit, 0, 3);
- layoutTop->addWidget(new QLabel(":"), 0, 4);
- maxEdit = new QLineEdit();
- maxEdit->setMaximumWidth(80);
- layoutTop->addWidget(maxEdit, 0, 5);
- valueLabel = new QLabel("Value:");
- layoutBottom->addWidget(valueLabel, 0,5);
- QRegExp rxMinMax("[+-]?[0-9]*(\\.[0-9]{0,6})?");
- QRegExpValidator* validatorMinMax = new QRegExpValidator(rxMinMax, 0);
- minEdit->setValidator(validatorMinMax);
- maxEdit->setValidator(validatorMinMax);
- minEdit->setText(QString::number(minValue));
- maxEdit->setText(QString::number(maxValue));
- connect(minEdit, &QLineEdit::editingFinished, this, &ColorGradient::minEditChangeEvent);
- connect(maxEdit, &QLineEdit::editingFinished, this, &ColorGradient::maxEditChangeEvent);
- alphaLineEdit = new QLineEdit(this);
- alphaLineEdit->setMaximumWidth(80);
- layoutBottom->addWidget(alphaLineEdit, 0, 4);
- valueEdit = new QLineEdit();
- valueEdit->setMaximumWidth(80);
- valueEdit->setValidator(validatorMinMax);
- connect(valueEdit, &QLineEdit::editingFinished, this, &ColorGradient::setValueOfSelected);
- layoutBottom->addWidget(valueEdit, 0, 6);
- QRegExp rx("0(\\.[0-9]{0,6})?|1(\\.0*)?");
- QRegExpValidator* v = new QRegExpValidator(rx, 0);
- alphaLineEdit->setValidator(v);
- connect(alphaLineEdit, &QLineEdit::editingFinished, this, &ColorGradient::setAlphaOfSelected);
- layoutBottom->addItem(new QSpacerItem(10, 20, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 7);
- //this->setMinimumHeight(150);
- this->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
-
- this->setMinimumHeight(150);
- //Dummy Data
- //TODO(ColorGradient #1) get gradient from last time or save project
- pointList.push_back(ColorPoint(0.0, QColor(0, 100, 200)));
- pointList.push_back(ColorPoint(0.5, QColor(0, 100, 50)));
- pointList.push_back(ColorPoint(1.0, QColor(200, 10, 10)));
- //select first
- selectColorPoint(&pointList.front());
- }
- ColorGradient::~ColorGradient()
- {
- }
- QColor ColorGradient::getColorFromAlpha(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);
- }
- }
-
- }
- QColor ColorGradient::getColorFromValue(double value)
- {
- double alpha = util::inverseLinearInterpolation(minValue, maxValue, value);
- return getColorFromAlpha(alpha);
- }
- void ColorGradient::addColorPoint(double alpha)
- {
- auto iter = pointList.begin();
- for (; iter != pointList.end(); iter++) {
- if (iter->alpha >= alpha) {
- break;
- }
- }
- selectColorPoint(&*pointList.insert(iter, ColorPoint(alpha, getColorFromAlpha(alpha))));
- emit gradientChanged();
- }
- void ColorGradient::removeColorPoint(ColorPoint& pointToRemove)
- {
- pointList.erase(std::remove_if(pointList.begin(), pointList.end(),
- [&pointToRemove](ColorPoint& point) {return &point == &pointToRemove; }));
- //colorButton->setVisible(false);
- selected = nullptr;
- hideSelectionEdit(true);
- emit gradientChanged();
- }
- void ColorGradient::setColorPointAlpha(ColorPoint& point, double alpha)
- {
- alpha = std::clamp(alpha, 0.0, 1.0);
- if (alpha == point.alpha) return;
- point.alpha = alpha;
- pointList.sort([](ColorPoint& a, ColorPoint& b) {
- return a.alpha < b.alpha;
- });
- if (&point == selected) {
- alphaLineEdit->setText(QString::number(alpha));
- valueEdit->setText(QString::number(util::linearInterpolate(minValue, maxValue, alpha)));
- }
- emit gradientChanged();
- update();
- }
- void ColorGradient::setColorPointColor(ColorPoint& point, QColor newColor)
- {
- if (newColor == point.color) return;
- point.color = newColor;
- emit gradientChanged();
- update();
- }
- 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::setMinValue(double value)
- {
- if (value > maxValue) {
- minValue = maxValue;
- maxValue = value;
- minEdit->setText(QString::number(minValue));
- maxEdit->setText(QString::number(maxValue));
- }
- else {
- minValue = value;
- minEdit->setText(QString::number(minValue));
- }
- if (selected != nullptr) {
- valueEdit->setText(QString::number(util::linearInterpolate(minValue, maxValue, selected->alpha)));
- }
- emit gradientChanged();
- }
- void ColorGradient::setMaxValue(double value)
- {
- if (value < minValue) {
- maxValue = minValue;
- minValue = value;
- minEdit->setText(QString::number(minValue));
- maxEdit->setText(QString::number(maxValue));
- }
- else {
- maxValue = value;
- maxEdit->setText(QString::number(maxValue));
- }
- if (selected != nullptr) {
- valueEdit->setText(QString::number(util::linearInterpolate(minValue, maxValue, selected->alpha)));
- }
- emit gradientChanged();
- }
- void ColorGradient::hideSelectionEdit(bool value)
- {
- colorButton->setHidden(value);
- alphaLineEdit->setHidden(value);
- alphaLabel->setHidden(value);
- colorLabel->setHidden(value);
- valueEdit->setHidden(value);
- valueLabel->setHidden(value);
- }
- void ColorGradient::setAlphaOfSelected()
- {
- if (selected == nullptr) return;
- bool success = false;
- double alpha = alphaLineEdit->text().toDouble(&success);
- if (success) {
- setColorPointAlpha(*selected, alpha);
- }
- }
- void ColorGradient::setValueOfSelected()
- {
- if (selected == nullptr) return;
- bool success = false;
- double value = valueEdit->text().toDouble(&success);
-
- if (success) {
- if (value < minValue) {
- value = minValue;
- }
- else if (value > maxValue) {
- value = maxValue;
- }
- setColorPointAlpha(*selected, util::inverseLinearInterpolation(minValue, maxValue, value));
- }
- }
- void ColorGradient::selectColorPoint(ColorPoint* point)
- {
- selected = point;
- colorButton->setColor(selected->color);
- alphaLineEdit->setText(QString::number(selected->alpha));
- valueEdit->setText(QString::number(util::linearInterpolate(minValue, maxValue, selected->alpha)));
- hideSelectionEdit(false);
- }
- 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);
- //drawSliders
- 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 = getColorFromAlpha(alpha);
- painter.setPen(color);
- painter.drawLine(pixelX, colorExampleRect.top() + 1, pixelX, colorExampleRect.bottom());
- }
-
- }
- void ColorGradient::mousePressEvent(QMouseEvent* event)
- {
- if (childAt(event->pos()) != nullptr) {
- return;
- }
- QPoint mousePos = event->pos();
- QRect area(QPoint(rect().left() + LeftRightGap, ColorExmapleHeight), QPoint(rect().right() - LeftRightGap, ColorExmapleHeight+SliderBody+SliderPeak));
- QRect responisveArea(QPoint(area.left() - SliderPeak * 2, area.top()), QPoint(area.right() + SliderPeak * 2, area.bottom()));
- if (responisveArea.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) {
- selectColorPoint(&point);
- }
- else if(event->buttons() & Qt::RightButton){
- removeColorPoint(point);
-
- }
- update();
- return;
- }
- }
-
- // Insert new Color Point
- if (event->buttons() & Qt::LeftButton) {
- double alpha = util::inverseLinearInterpolation(area.left(), area.right() + 1, mousePos.x());
- addColorPoint(alpha);
- update();
- }
- }
- }
- void ColorGradient::mouseMoveEvent(QMouseEvent* event)
- {
- if (selected == nullptr) return;
- if (childAt(event->pos()) != 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());
- this->setColorPointAlpha(*selected, alpha);
- }
- void ColorGradient::minEditChangeEvent()
- {
- bool success = false;
- double value = minEdit->text().toDouble(&success);
- if (success) {
- this->setMinValue(value);
- }
- }
- void ColorGradient::maxEditChangeEvent()
- {
- bool success = false;
- double value = maxEdit->text().toDouble(&success);
- if (success) {
- this->setMaxValue(value);
- }
- }
|