Skip to content

Commit

Permalink
tidy up color picker widgets
Browse files Browse the repository at this point in the history
- add gradient class and start widget
  • Loading branch information
njbrown committed Oct 1, 2024
1 parent b60b874 commit 692a26d
Show file tree
Hide file tree
Showing 8 changed files with 385 additions and 239 deletions.
6 changes: 6 additions & 0 deletions src/colorpicker/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(SRCS
colorpicker.cpp
gradient.cpp
gradientpicker.cpp
widgets.cpp
)
set(HEADERS
colorpicker.h
gradient.h
gradientpicker.h
widgets.h
)

# library
Expand Down
243 changes: 4 additions & 239 deletions src/colorpicker/colorpicker.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "colorpicker.h"
#include "./widgets.h"
#include <QEvent>
#include <QGridLayout>
#include <QHBoxLayout>
Expand All @@ -7,255 +8,19 @@
#include <QVBoxLayout>
#include <QWidget>

// https://github.com/yjg30737/pyqt-color-picker/blob/main/pyqt_color_picker/colorSquareWidget.py
class SVBox : public QWidget {
QColor color;

QWidget* colorWidget;
// black overlay
QWidget* blackWidget;

QWidget* selector;
int selectorDiameter = 10;
bool dragging = false;

float h, s, v;

public:
SVBox()
{
this->setFixedSize(400, 300);

auto layout = new QGridLayout(this);
colorWidget = new QWidget();

blackWidget = new QWidget();
// https://github.com/yjg30737/pyqt-color-picker/blob/main/pyqt_color_picker/style/black_overlay.css
QString blackStyle =
"background-color: qlineargradient(spread:pad, x1:0, "
"y1:0, x2:0, y2:1, stop:0 rgba(0, 0, 0, 0),"
"stop:1 rgba(0, 0, 0, 255));"
"width:100%;"
"border-radius: 5px;";
blackWidget->setStyleSheet(blackStyle);

blackWidget->installEventFilter(this);
blackWidget->setMouseTracking(true);

selector = new QWidget(blackWidget);
selector->setGeometry(qFloor(selectorDiameter / 2) * -1,
qFloor(selectorDiameter / 2) * -1,
selectorDiameter, selectorDiameter);

selector->setStyleSheet("background-color: none;"
"border: 2px solid white;"
"border-radius: 5px;");

// connect(blackWidget, &QWidget::mouseMoveEvent, []() {

// });

// you can stack widgets on top of each other in a grid

layout->addWidget(colorWidget, 0, 0, 1, 1);
layout->addWidget(blackWidget, 0, 0, 1, 1);
layout->setContentsMargins(0, 0, 0, 0);
this->setLayout(layout);

this->setColor(QColor(255, 0, 0));
}

void setColor(const QColor& color)
{
h = color.hueF();
s = color.saturationF();
v = color.valueF();

auto hue = color.hueF() * 100;
QString style = "background-color: qlineargradient(x1:1, x2:0, "
"stop:0 hsl(%1%,100%,50%),"
"stop:1 #fff);"
"border-radius: 5px;";
auto formatted = style.arg(hue);

// qDebug() << formatted;
this->setStyleSheet(formatted);
}

bool eventFilter(QObject* object, QEvent* event)
{

if (object == this->blackWidget) {
auto mouseEvent = (QMouseEvent*)event;
// handle appropriate event
switch (event->type()) {
case QEvent::MouseButtonPress: {
if (mouseEvent->button() == Qt::LeftButton) {
dragging = true;
moveSelector(mouseEvent);
}
} break;
case QEvent::MouseButtonRelease: {
if (mouseEvent->button() == Qt::LeftButton) {
dragging = false;
}
} break;
case QEvent::MouseMove: {
if (dragging) {
//
moveSelector(mouseEvent);
}
} break;
}
}

// false means it should be send to target also. as in , we dont remove
// it. if you return true , you will take the event and widget never
// sees it so be carefull with that.
return false;
}

void moveSelector(QMouseEvent* evt)
{
auto pos = evt->pos();

pos.setX(std::clamp(pos.x(), 0, this->width()));
pos.setY(std::clamp(pos.y(), 0, this->height()));

this->selector->move(
pos - QPoint(selectorDiameter / 2, selectorDiameter / 2));

// calculate hsl
s = (this->selector->pos().x() + (selectorDiameter / 2.0f)) /
this->width();

v = std::abs(((this->selector->pos().y() + (selectorDiameter / 2.0f)) /
this->height()) -
1.0f);

// qDebug() << s << " " << v << "\n";
}

signals:
void onSVChanged(float saturation, float value);
};

// https://github.com/mortalis13/Qt-Color-Picker-Qt/blob/master/Widgets/ColorWidgets/hselector.cpp
class HueSlider : public QWidget {
float hue;
bool selectorDrawn;
QColor color;
QPixmap selectorPixmap;

public:
HueSlider()
{
selectorDrawn = false;
hue = 0;
// this->setFixedSize(400, 20);
setFixedHeight(20);

this->setStyleSheet("border-radius: 5px;");
}
void setHue(float hue)
{
this->hue = hue;
update();
}
void setColor(const QColor& color)
{
this->color = color;
this->hue = color.hueF();
update();
}

protected:
void paintEvent(QPaintEvent* event) override
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);

float barHeight = height();
float barWidth = width();

if (!selectorDrawn) {
// if (true) {
selectorPixmap = QPixmap(barWidth, barHeight);
QPainter huePainter(&selectorPixmap);

QPointF p1(0, 0);
QPointF p2(width(), 0);
// QPointF p1(0, 0);
// QPointF p2(100, 100);
QLinearGradient grad(p1, p2);
// QLinearGradient grad(p1, p2);

float ratio = 1.0 / 360.0f;

QColor gradientColor;
for (qreal hs = 0; hs < 1.0; hs += ratio) {
gradientColor.setHsvF(hs, 1.0f, 1.0f);
grad.setColorAt(hs, gradientColor);
}

// grad.setColorAt(0.0, Qt::red);
// grad.setColorAt(0.5, Qt::green);
// grad.setColorAt(1.0, Qt::blue);

huePainter.setPen(Qt::NoPen);
huePainter.setBrush(QBrush(grad));
huePainter.drawRect(0, 0, barWidth, barHeight);

selectorDrawn = true;
}

// selectorPixmap.save("./selector.png");
painter.drawPixmap(0, 0, selectorPixmap);

// draw selector
painter.setPen(QPen(Qt::black, 2));
painter.setBrush(Qt::white);
painter.drawEllipse(QPointF(hue * width(), height() / 2), 5, 5);
}

void resizeEvent(QResizeEvent* event) override { selectorDrawn = false; }

void mousePressEvent(QMouseEvent* event) override
{
hue = event->pos().x() / (float)width();
update();
// emit onHueChanged(hue);
}

void mouseMoveEvent(QMouseEvent* event) override
{
hue = event->pos().x() / (float)width();
hue = std::clamp(hue, 0.0f, 1.0f);
update();
}
signals:
void onHueChanged(float hue);
};

class AlphaSlider : public QWidget {
public:
AlphaSlider() {}
void setColor(const QColor& color) {}
};

ColorPicker::ColorPicker()
{
svBox = new SVBox();
hueSlider = new HueSlider();
alphaSlider = new AlphaSlider();
// alphaSlider = new AlphaSlider();

svBox->setColor(QColor(255, 150, 0, 255));

// add layout
auto vlayout = new QVBoxLayout(this);
vlayout->addWidget(svBox);
vlayout->addWidget(hueSlider);
vlayout->addWidget(alphaSlider);
// vlayout->addWidget(alphaSlider);

this->setLayout(vlayout);

Expand All @@ -267,5 +32,5 @@ void ColorPicker::setColor(const QColor& color)
{
svBox->setColor(color);
hueSlider->setColor(color);
alphaSlider->setColor(color);
// alphaSlider->setColor(color);
}
17 changes: 17 additions & 0 deletions src/colorpicker/gradient.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "gradient.h"

void Gradient::sort()
{
std::sort(points.begin(), points.end(),
[](const GradientPoint& a, const GradientPoint& b) {
return a.position < b.position;
});
}

Gradient Gradient::defaultGradient()
{
Gradient gradient;
gradient.addPoint(GradientPoint(0.0, QColor(0, 0, 0)));
gradient.addPoint(GradientPoint(1.0, QColor(255, 255, 255)));
return gradient;
}
29 changes: 29 additions & 0 deletions src/colorpicker/gradient.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include <QColor>
#include <QVector>

class GradientPoint {
public:
float position;
QColor color;

GradientPoint(float position, const QColor& color)
: position(position), color(color)
{
}
};

class Gradient {
public:
QVector<GradientPoint> points;

Gradient() {}
Gradient(const QVector<GradientPoint>& points) : points(points) {}
Gradient(const Gradient& other) : points(other.points) {}

void addPoint(GradientPoint point) { points.append(point); }
void sort();

static Gradient defaultGradient();
};
29 changes: 29 additions & 0 deletions src/colorpicker/gradientpicker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include "gradientpicker.h"
#include "gradient.h"

GradientSlider::GradientSlider() { this->initUI(); }

void GradientSlider::setGradient(const Gradient& gradient)
{
this->gradient = gradient;
this->update();
}

void GradientSlider::initUI() { this->setFixedSize(400, 100); }

GradientPickerDialog::GradientPickerDialog() { this->initUI(); }

void GradientPickerDialog::setGradient(const Gradient& gradient)
{
// this->gradient = gradient;
this->gradientSlider->setGradient(gradient);

// update ui
// this->update();
}

void GradientPickerDialog::initUI()
{
// create ui
// this->setFixedSize(400, 100);
}
Loading

0 comments on commit 692a26d

Please sign in to comment.