Implemented coarse color picker
This commit is contained in:
@@ -38,8 +38,10 @@ HEADERS += \
|
||||
src/editor/editorguiutils.h \
|
||||
src/editor/roomscene.h \
|
||||
src/editor/widgets/actiondragwidget.h \
|
||||
src/editor/widgets/coarsecolorwidget.h \
|
||||
src/editor/widgets/colorwidget.h \
|
||||
src/editor/widgets/draggabletreeview.h \
|
||||
src/editor/widgets/finecolorwidget.h \
|
||||
src/editor/widgets/objectparentselectorwidget.h \
|
||||
src/editor/widgets/objectselectorwidget.h \
|
||||
src/editor/widgets/qlineeditwithmenu.h \
|
||||
@@ -109,8 +111,10 @@ SOURCES += \
|
||||
src/editor/editorguiutils.cpp \
|
||||
src/editor/roomscene.cpp \
|
||||
src/editor/widgets/actiondragwidget.cpp \
|
||||
src/editor/widgets/coarsecolorwidget.cpp \
|
||||
src/editor/widgets/colorwidget.cpp \
|
||||
src/editor/widgets/draggabletreeview.cpp \
|
||||
src/editor/widgets/finecolorwidget.cpp \
|
||||
src/editor/widgets/objectparentselectorwidget.cpp \
|
||||
src/editor/widgets/objectselectorwidget.cpp \
|
||||
src/editor/widgets/qlineeditwithmenu.cpp \
|
||||
|
||||
@@ -94,7 +94,7 @@ void EditSpriteDialog::newSprite()
|
||||
m_model->beginResetModel();
|
||||
m_pixmaps = std::vector<QPixmap> { std::move(pixmap) };
|
||||
m_model->endResetModel();
|
||||
qDebug() << m_model->rowCount({});
|
||||
|
||||
changed();
|
||||
}
|
||||
}
|
||||
@@ -110,11 +110,9 @@ void EditSpriteDialog::doubleClicked(const QModelIndex &index)
|
||||
ImageEditorDialog dialog{m_model->pixmap(index), tr("Image Editor: %0").arg(m_spriteName), this};
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
qDebug() << "apply pixmap?!";
|
||||
emit m_model->beginResetModel();
|
||||
m_pixmaps[index.row()] = dialog.pixmap();
|
||||
emit m_model->endResetModel();
|
||||
//emit m_model->dataChanged(index, index, {Qt::DecorationRole});
|
||||
emit m_model->dataChanged(index, index, {Qt::DecorationRole});
|
||||
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,16 @@ ImageEditorDialog::ImageEditorDialog(const QPixmap &pixmap, const QString &title
|
||||
connect(m_ui->pushButtonRightButtonColor, &QAbstractButton::pressed,
|
||||
this, &ImageEditorDialog::selectRightButtonColor);
|
||||
|
||||
connect(m_ui->frameColorCoarse, &ColorWidget::colorLeftClicked,
|
||||
m_ui->canvas, &DrawingCanvasWidget::setLeftButtonColor);
|
||||
connect(m_ui->frameColorCoarse, &ColorWidget::colorRightClicked,
|
||||
m_ui->canvas, &DrawingCanvasWidget::setRightButtonColor);
|
||||
|
||||
connect(m_ui->frameColorFine, &ColorWidget::colorLeftClicked,
|
||||
m_ui->canvas, &DrawingCanvasWidget::setLeftButtonColor);
|
||||
connect(m_ui->frameColorFine, &ColorWidget::colorRightClicked,
|
||||
m_ui->canvas, &DrawingCanvasWidget::setRightButtonColor);
|
||||
|
||||
connect(m_ui->canvas, &DrawingCanvasWidget::changed,
|
||||
this, &ImageEditorDialog::changed);
|
||||
connect(m_ui->canvas, &DrawingCanvasWidget::leftButtonColorChanged,
|
||||
|
||||
@@ -725,12 +725,20 @@
|
||||
<string>Colors</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelLeft">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Left</string>
|
||||
</property>
|
||||
@@ -752,6 +760,11 @@
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelRight">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Right</string>
|
||||
</property>
|
||||
@@ -772,34 +785,34 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ColorWidget" name="frameColorCoarse">
|
||||
<widget class="CoarseColorWidget" name="frameColorCoarse">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>75</width>
|
||||
<height>100</height>
|
||||
<width>0</width>
|
||||
<height>125</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
<enum>QFrame::Shadow::Sunken</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ColorWidget" name="frameColorFine">
|
||||
<widget class="FineColorWidget" name="frameColorFine">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>75</width>
|
||||
<height>100</height>
|
||||
<width>0</width>
|
||||
<height>125</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
<enum>QFrame::Shadow::Sunken</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -1112,9 +1125,15 @@
|
||||
<header>widgets/drawingcanvaswidget.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ColorWidget</class>
|
||||
<class>CoarseColorWidget</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>widgets/colorwidget.h</header>
|
||||
<header>widgets/coarsecolorwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>FineColorWidget</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>widgets/finecolorwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
#include "projectserialization.h"
|
||||
#include "stdserialization.h"
|
||||
|
||||
ActionDragWidget::ActionDragWidget(QWidget *parent) :
|
||||
QToolButton{parent}
|
||||
{
|
||||
}
|
||||
|
||||
void ActionDragWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
QToolButton::mousePressEvent(event);
|
||||
|
||||
@@ -10,7 +10,7 @@ class ActionDragWidget : public QToolButton
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ActionDragWidget(QWidget *parent = nullptr);
|
||||
using QToolButton::QToolButton;
|
||||
|
||||
const Action &action() const { return m_action; }
|
||||
void setAction(Action &&action) { m_action = std::move(action); }
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "coarsecolorwidget.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
void CoarseColorWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
ColorWidget::resizeEvent(event);
|
||||
|
||||
int w = width() - frameWidth() * 2;
|
||||
int h = height() - frameWidth() * 2;
|
||||
|
||||
// dynamic columns
|
||||
constexpr int MIN_COL_WIDTH = 16;
|
||||
constexpr int MAX_COL_WIDTH = 32;
|
||||
|
||||
int minCols = std::max(1, w / MAX_COL_WIDTH);
|
||||
int maxCols = std::max(1, w / MIN_COL_WIDTH);
|
||||
int columns = std::clamp(maxCols, minCols, maxCols);
|
||||
|
||||
// dynamic rows
|
||||
constexpr int MIN_ROW_HEIGHT = 16;
|
||||
constexpr int MAX_ROW_HEIGHT = 32;
|
||||
|
||||
int minRows = std::max(1, h / MAX_ROW_HEIGHT);
|
||||
int maxRows = std::max(1, h / MIN_ROW_HEIGHT);
|
||||
int rows = std::clamp(maxRows, minRows, maxRows);
|
||||
|
||||
m_image = QImage(w, h, QImage::Format_RGB32);
|
||||
|
||||
{
|
||||
QPainter p(&m_image);
|
||||
p.setPen(Qt::NoPen);
|
||||
|
||||
for (int r = 0; r < rows; ++r)
|
||||
for (int c = 0; c < columns; ++c)
|
||||
{
|
||||
// fractional geometry (smooth scaling)
|
||||
int x0 = (c * w) / columns;
|
||||
int x1 = ((c+1) * w) / columns;
|
||||
int y0 = (r * h) / rows;
|
||||
int y1 = ((r+1) * h) / rows;
|
||||
|
||||
int cw = x1 - x0;
|
||||
int rh = y1 - y0;
|
||||
|
||||
// color logic
|
||||
QColor color;
|
||||
float hue = float(c) * 360.f / float(columns);
|
||||
|
||||
// bottom row = grayscale, but now rows are dynamic
|
||||
if (r == rows - 1)
|
||||
{
|
||||
int v = int(c * 255.f / std::max(1, columns - 1));
|
||||
color = QColor(v, v, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
// spread the "classic5 rows" over whatever number of rows we have
|
||||
// We interpolate S and V vertically.
|
||||
float t = float(r) / float(rows - 1); // 0..1, except grayscale row
|
||||
|
||||
// Windows-like palette interpolation:
|
||||
// r=0 (top): S=255 V=140
|
||||
// r=1: S=255 V=200
|
||||
// r=2: S=255 V=255
|
||||
// r=3: S=100 V=255
|
||||
// r=4: S= 40 V=255
|
||||
// r=5 bottom: grayscale row (handled above)
|
||||
|
||||
// Predefined control points
|
||||
constexpr struct { int s, v; } ctrl[] = {
|
||||
{255, 140},
|
||||
{255, 200},
|
||||
{255, 255},
|
||||
{100, 255},
|
||||
{ 40, 255}
|
||||
};
|
||||
|
||||
int ctrlRows = 5;
|
||||
|
||||
float pos = t * (ctrlRows - 1);
|
||||
int i = int(pos);
|
||||
float f = pos - i;
|
||||
|
||||
if (i >= ctrlRows - 1) {
|
||||
i = ctrlRows - 2;
|
||||
f = 1.f;
|
||||
}
|
||||
|
||||
int S = int(ctrl[i].s * (1.f - f) + ctrl[i + 1].s * f);
|
||||
int V = int(ctrl[i].v * (1.f - f) + ctrl[i + 1].v * f);
|
||||
|
||||
color.setHsv(int(hue), S, V);
|
||||
}
|
||||
|
||||
p.setBrush(color);
|
||||
p.drawRect(x0, y0, cw, rh);
|
||||
}
|
||||
}
|
||||
|
||||
m_pixmap = QPixmap::fromImage(m_image);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "colorwidget.h"
|
||||
|
||||
class CoarseColorWidget : public ColorWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using ColorWidget::ColorWidget;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
};
|
||||
@@ -2,33 +2,17 @@
|
||||
|
||||
#include <QPaintEvent>
|
||||
#include <QResizeEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
|
||||
ColorWidget::ColorWidget(QWidget *parent)
|
||||
: QFrame{parent}
|
||||
ColorWidget::ColorWidget(QWidget *parent) :
|
||||
QFrame{parent}
|
||||
{
|
||||
setCol(150, 255);
|
||||
setAttribute(Qt::WA_NoSystemBackground);
|
||||
setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) );
|
||||
}
|
||||
|
||||
ColorWidget::~ColorWidget() = default;
|
||||
|
||||
void ColorWidget::setCol(int h, int s)
|
||||
{
|
||||
int nhue = qMin(qMax(0,h), 359);
|
||||
int nsat = qMin(qMax(0,s), 255);
|
||||
if (nhue == m_hue && nsat == m_sat)
|
||||
return;
|
||||
QRect r(colPt(), QSize(20,20));
|
||||
m_hue = nhue;
|
||||
m_sat = nsat;
|
||||
r = r.united(QRect(colPt(), QSize(20,20)));
|
||||
r.translate(contentsRect().x()-9, contentsRect().y()-9);
|
||||
// update(r);
|
||||
repaint(r);
|
||||
}
|
||||
|
||||
void ColorWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
@@ -39,50 +23,61 @@ void ColorWidget::paintEvent(QPaintEvent *event)
|
||||
p.drawPixmap(r.topLeft(), m_pixmap);
|
||||
}
|
||||
|
||||
void ColorWidget::resizeEvent(QResizeEvent *event)
|
||||
void ColorWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
QFrame::mousePressEvent(event);
|
||||
|
||||
int w = width() - frameWidth() * 2;
|
||||
int h = height() - frameWidth() * 2;
|
||||
QImage img(w, h, QImage::Format_RGB32);
|
||||
int x, y;
|
||||
uint *pixel = (uint *) img.scanLine(0);
|
||||
for (y = 0; y < h; y++)
|
||||
switch (event->button())
|
||||
{
|
||||
const uint *end = pixel + w;
|
||||
x = 0;
|
||||
while (pixel < end) {
|
||||
QPoint p(x, y);
|
||||
QColor c;
|
||||
c.setHsv(huePt(p), satPt(p), 200);
|
||||
*pixel = c.rgb();
|
||||
++pixel;
|
||||
++x;
|
||||
}
|
||||
case Qt::LeftButton:
|
||||
case Qt::RightButton:
|
||||
{
|
||||
m_currentlyPicking = event->button() == Qt::LeftButton;
|
||||
|
||||
setMouseTracking(true);
|
||||
|
||||
pickPixel(event->pos(), event->button() == Qt::LeftButton);
|
||||
|
||||
break;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
m_pixmap = QPixmap::fromImage(img);
|
||||
}
|
||||
|
||||
QPoint ColorWidget::colPt()
|
||||
void ColorWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
QRect r = contentsRect();
|
||||
return QPoint((360 - m_hue) * (r.width() - 1) / 360, (255 - m_sat) * (r.height() - 1) / 255);
|
||||
QFrame::mouseReleaseEvent(event);
|
||||
|
||||
switch (event->button())
|
||||
{
|
||||
case Qt::LeftButton:
|
||||
case Qt::RightButton:
|
||||
{
|
||||
m_currentlyPicking = std::nullopt;
|
||||
|
||||
setMouseTracking(false);
|
||||
|
||||
break;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
int ColorWidget::huePt(const QPoint &pt)
|
||||
void ColorWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
QRect r = contentsRect();
|
||||
return 360 - pt.x() * 360 / (r.width() - 1);
|
||||
QFrame::mouseMoveEvent(event);
|
||||
|
||||
if (m_currentlyPicking)
|
||||
pickPixel(event->pos(), *m_currentlyPicking);
|
||||
}
|
||||
|
||||
int ColorWidget::satPt(const QPoint &pt)
|
||||
void ColorWidget::pickPixel(const QPoint &pos, bool left)
|
||||
{
|
||||
QRect r = contentsRect();
|
||||
return 255 - pt.y() * 255 / (r.height() - 1);
|
||||
}
|
||||
if (!m_image.rect().contains(pos))
|
||||
return;
|
||||
|
||||
void ColorWidget::setCol(const QPoint &pt)
|
||||
{
|
||||
setCol(huePt(pt), satPt(pt));
|
||||
if (left)
|
||||
emit colorLeftClicked(m_image.pixelColor(pos));
|
||||
else
|
||||
emit colorRightClicked(m_image.pixelColor(pos));
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
|
||||
#include <optional>
|
||||
|
||||
class ColorWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -11,21 +14,22 @@ public:
|
||||
explicit ColorWidget(QWidget *parent = nullptr);
|
||||
~ColorWidget() override;
|
||||
|
||||
public slots:
|
||||
void setCol(int h, int s);
|
||||
signals:
|
||||
void colorLeftClicked(const QColor &color);
|
||||
void colorRightClicked(const QColor &color);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
|
||||
QImage m_image;
|
||||
QPixmap m_pixmap;
|
||||
|
||||
private:
|
||||
QPoint colPt();
|
||||
int huePt(const QPoint &pt);
|
||||
int satPt(const QPoint &pt);
|
||||
void setCol(const QPoint &pt);
|
||||
void pickPixel(const QPoint &pos, bool left);
|
||||
|
||||
int m_hue{};
|
||||
int m_sat{};
|
||||
|
||||
QPixmap m_pixmap;
|
||||
std::optional<bool> m_currentlyPicking;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
#include "draggabletreeview.h"
|
||||
|
||||
DraggableTreeView::DraggableTreeView(QWidget *parent) :
|
||||
QTreeView{parent}
|
||||
{
|
||||
}
|
||||
|
||||
void DraggableTreeView::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
setDropIndicatorShown(true);
|
||||
|
||||
@@ -7,7 +7,7 @@ class DraggableTreeView : public QTreeView
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DraggableTreeView(QWidget *parent = nullptr);
|
||||
using QTreeView::QTreeView;
|
||||
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
|
||||
@@ -4,11 +4,6 @@
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
|
||||
DrawingCanvasWidget::DrawingCanvasWidget(QWidget *parent) :
|
||||
QWidget{parent}
|
||||
{
|
||||
}
|
||||
|
||||
void DrawingCanvasWidget::setPixmap(QPixmap &pixmap)
|
||||
{
|
||||
m_pixmap = &pixmap;
|
||||
|
||||
@@ -14,7 +14,7 @@ class DrawingCanvasWidget : public QWidget
|
||||
Q_PROPERTY(QColor rightButtonColor READ rightButtonColor WRITE setRightButtonColor NOTIFY rightButtonColorChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit DrawingCanvasWidget(QWidget *parent = nullptr);
|
||||
using QWidget::QWidget;
|
||||
|
||||
QPixmap *pixmap() { return m_pixmap; }
|
||||
const QPixmap *pixmap() const { return m_pixmap; }
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "finecolorwidget.h"
|
||||
|
||||
void FineColorWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
ColorWidget::resizeEvent(event);
|
||||
|
||||
int w = width() - frameWidth() * 2;
|
||||
int h = height() - frameWidth() * 2;
|
||||
|
||||
m_image = QImage{w, h, QImage::Format_RGB32};
|
||||
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
uint *pixel = (uint *)m_image.scanLine(y);
|
||||
float hue = float(360 - y * 360 / (h - 1));
|
||||
|
||||
QColor pure;
|
||||
pure.setHsv(hue, 255, 255);
|
||||
|
||||
for (int x = 0; x < w; x++, pixel++)
|
||||
{
|
||||
float t = float(x) / float(w - 1); // 0..1 across width
|
||||
QColor c;
|
||||
|
||||
if (t < 0.5f)
|
||||
{
|
||||
float k = t / 0.5f; // 0..1 across halve
|
||||
c.setRgb(
|
||||
pure.red() * k,
|
||||
pure.green() * k,
|
||||
pure.blue() * k
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
float k = (t - 0.5f) / 0.5f; // 0..1 across halve
|
||||
c.setRgb(
|
||||
pure.red() + (255 - pure.red()) * k,
|
||||
pure.green() + (255 - pure.green()) * k,
|
||||
pure.blue() + (255 - pure.blue()) * k
|
||||
);
|
||||
}
|
||||
|
||||
*pixel = c.rgb();
|
||||
}
|
||||
}
|
||||
|
||||
m_pixmap = QPixmap::fromImage(m_image);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "colorwidget.h"
|
||||
|
||||
class FineColorWidget : public ColorWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using ColorWidget::ColorWidget;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
};
|
||||
Reference in New Issue
Block a user