diff --git a/forms/colorinputwidget.ui b/forms/colorinputwidget.ui new file mode 100644 index 00000000..eebd7955 --- /dev/null +++ b/forms/colorinputwidget.ui @@ -0,0 +1,313 @@ + + + ColorInputWidget + + + + 0 + 0 + 221 + 212 + + + + Color + + + + + + QFrame::Shape::NoFrame + + + QFrame::Shadow::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::Shape::NoFrame + + + QFrame::Shadow::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::Shape::NoFrame + + + QFrame::Shadow::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Orientation::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Orientation::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Orientation::Horizontal + + + + + + + + + + QFrame::Shape::NoFrame + + + QFrame::Shadow::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::Shadow::Raised + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + QFrame::Shape::NoFrame + + + QFrame::Shadow::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::Shape::NoFrame + + + QFrame::Shadow::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + diff --git a/forms/gridsettingsdialog.ui b/forms/gridsettingsdialog.ui index c5aa299d..73411742 100644 --- a/forms/gridsettingsdialog.ui +++ b/forms/gridsettingsdialog.ui @@ -6,8 +6,8 @@ 0 0 - 423 - 375 + 331 + 467 @@ -24,39 +24,23 @@ 0 0 - 397 - 309 + 305 + 401 - - - - Offset (in pixels) + + + + Qt::Orientation::Vertical - - - - - X - - - - - - - Y - - - - - - - - - - - + + + 20 + 40 + + + @@ -71,6 +55,19 @@ + + + + false + + + QComboBox::SizeAdjustPolicy::AdjustToContentsOnFirstShow + + + 0 + + + @@ -121,31 +118,41 @@ - - - - false - - - QComboBox::SizeAdjustPolicy::AdjustToContentsOnFirstShow - - - 0 + + + + Offset (in pixels) + + + + + X + + + + + + + Y + + + + + + + + + + - - - - Qt::Orientation::Vertical + + + + - - - 20 - 40 - - - + @@ -174,6 +181,12 @@ QComboBox
noscrollcombobox.h
+ + ColorInputWidget + QGroupBox +
colorinputwidget.h
+ 1 +
diff --git a/include/ui/colorinputwidget.h b/include/ui/colorinputwidget.h new file mode 100644 index 00000000..5b414776 --- /dev/null +++ b/include/ui/colorinputwidget.h @@ -0,0 +1,45 @@ +#ifndef COLORINPUTWIDGET_H +#define COLORINPUTWIDGET_H + +#include +#include + +namespace Ui { +class ColorInputWidget; +} + + +class ColorInputWidget : public QGroupBox { + Q_OBJECT +public: + explicit ColorInputWidget(QWidget *parent = nullptr); + explicit ColorInputWidget(const QString &title, QWidget *parent = nullptr); + ~ColorInputWidget(); + + void setColor(QRgb color); + QRgb color() const { return m_color; } + + bool setBitDepth(int bits); + int bitDepth() const { return m_bitDepth; } + +signals: + void colorChanged(QRgb color); + void bitDepthChanged(int bits); + +private: + Ui::ColorInputWidget *ui; + + QRgb m_color = 0; + int m_bitDepth = 0; + + void init(); + void updateColorUi(); + void pickColor(); + void blockEditSignals(bool block); + + void setRgbFromSliders(); + void setRgbFromSpinners(); + void setRgbFromHexString(const QString &); +}; + +#endif // COLORINPUTWIDGET_H diff --git a/include/ui/gridsettingsdialog.h b/include/ui/gridsettingsdialog.h index 957edb43..9c64f29d 100644 --- a/include/ui/gridsettingsdialog.h +++ b/include/ui/gridsettingsdialog.h @@ -34,6 +34,7 @@ private slots: void on_spinBox_X_valueChanged(int value); void on_spinBox_Y_valueChanged(int value); void on_comboBox_Style_currentIndexChanged(int index); + void onColorChanged(QRgb color); }; inline bool operator==(const struct GridSettings &a, const struct GridSettings &b) { diff --git a/porymap.pro b/porymap.pro index ae49c4aa..182ea11a 100644 --- a/porymap.pro +++ b/porymap.pro @@ -51,6 +51,7 @@ SOURCES += src/core/block.cpp \ src/scriptapi/apiutility.cpp \ src/scriptapi/scripting.cpp \ src/ui/aboutporymap.cpp \ + src/ui/colorinputwidget.cpp \ src/ui/connectionslistitem.cpp \ src/ui/customscriptseditor.cpp \ src/ui/customscriptslistitem.cpp \ @@ -175,6 +176,7 @@ HEADERS += include/core/block.h \ include/ui/prefabcreationdialog.h \ include/ui/regionmappixmapitem.h \ include/ui/citymappixmapitem.h \ + include/ui/colorinputwidget.h \ include/ui/mapsceneeventfilter.h \ include/ui/metatilelayersitem.h \ include/ui/metatileselector.h \ @@ -220,6 +222,7 @@ HEADERS += include/core/block.h \ include/ui/wildmonchart.h FORMS += forms/mainwindow.ui \ + forms/colorinputwidget.ui \ forms/connectionslistitem.ui \ forms/gridsettingsdialog.ui \ forms/newmapconnectiondialog.ui \ diff --git a/src/ui/colorinputwidget.cpp b/src/ui/colorinputwidget.cpp new file mode 100644 index 00000000..200567af --- /dev/null +++ b/src/ui/colorinputwidget.cpp @@ -0,0 +1,216 @@ +#include "colorinputwidget.h" +#include "ui_colorinputwidget.h" +#include "colorpicker.h" + +#include + +// TODO: Refactor palette editor to make use of this class + +class HexCodeValidator : public QValidator { + virtual QValidator::State validate(QString &input, int &) const override { + input = input.toUpper(); + return QValidator::Acceptable; + } +}; + +static inline int rgb5(int rgb) { return round(static_cast(rgb * 31) / 255.0); } +static inline int rgb8(int rgb) { return round(rgb * 255. / 31.); } +static inline int gbaRed(int rgb) { return rgb & 0x1f; } +static inline int gbaGreen(int rgb) { return (rgb >> 5) & 0x1f; } +static inline int gbaBlue(int rgb) { return (rgb >> 10) & 0x1f; } + +ColorInputWidget::ColorInputWidget(QWidget *parent) : + QGroupBox(parent), + ui(new Ui::ColorInputWidget) +{ + init(); +} + +ColorInputWidget::ColorInputWidget(const QString &title, QWidget *parent) : + QGroupBox(title, parent), + ui(new Ui::ColorInputWidget) +{ + init(); +} + +void ColorInputWidget::init() { + ui->setupUi(this); + + connect(ui->slider_Red, &QSlider::valueChanged, this, &ColorInputWidget::setRgbFromSliders); + connect(ui->slider_Green, &QSlider::valueChanged, this, &ColorInputWidget::setRgbFromSliders); + connect(ui->slider_Blue, &QSlider::valueChanged, this, &ColorInputWidget::setRgbFromSliders); + + connect(ui->spinBox_Red, QOverload::of(&QSpinBox::valueChanged), this, &ColorInputWidget::setRgbFromSpinners); + connect(ui->spinBox_Green, QOverload::of(&QSpinBox::valueChanged), this, &ColorInputWidget::setRgbFromSpinners); + connect(ui->spinBox_Blue, QOverload::of(&QSpinBox::valueChanged), this, &ColorInputWidget::setRgbFromSpinners); + + static const HexCodeValidator hexValidator; + ui->lineEdit_Hex->setValidator(&hexValidator); + connect(ui->lineEdit_Hex, &QLineEdit::textEdited, this, &ColorInputWidget::setRgbFromHexString); + + connect(ui->button_Eyedrop, &QToolButton::clicked, this, &ColorInputWidget::pickColor); + + setBitDepth(24); +} + +ColorInputWidget::~ColorInputWidget() { + delete ui; +} + +void ColorInputWidget::updateColorUi() { + blockEditSignals(true); + + int red = qRed(m_color); + int green = qGreen(m_color); + int blue = qBlue(m_color); + + if (m_bitDepth == 15) { + // Sliders + ui->slider_Red->setValue(rgb5(red)); + ui->slider_Green->setValue(rgb5(green)); + ui->slider_Blue->setValue(rgb5(blue)); + + // Hex + int hex15 = (rgb5(blue) << 10) | (rgb5(green) << 5) | rgb5(red); + ui->lineEdit_Hex->setText(QString("%1").arg(hex15, 4, 16, QLatin1Char('0')).toUpper()); + + // Spinners + ui->spinBox_Red->setValue(rgb5(red)); + ui->spinBox_Green->setValue(rgb5(green)); + ui->spinBox_Blue->setValue(rgb5(blue)); + } else { + // Sliders + ui->slider_Red->setValue(red); + ui->slider_Green->setValue(green); + ui->slider_Blue->setValue(blue); + + // Hex + QColor color(red, green, blue); + ui->lineEdit_Hex->setText(color.name().remove(0, 1).toUpper()); + + // Spinners + ui->spinBox_Red->setValue(red); + ui->spinBox_Green->setValue(green); + ui->spinBox_Blue->setValue(blue); + } + + ui->frame_ColorDisplay->setStyleSheet(QString("background-color: rgb(%1, %2, %3);").arg(red).arg(green).arg(blue)); + + blockEditSignals(false); +} + +void ColorInputWidget::blockEditSignals(bool block) { + ui->slider_Red->blockSignals(block); + ui->slider_Green->blockSignals(block); + ui->slider_Blue->blockSignals(block); + + ui->spinBox_Red->blockSignals(block); + ui->spinBox_Green->blockSignals(block); + ui->spinBox_Blue->blockSignals(block); + + ui->lineEdit_Hex->blockSignals(block); +} + +bool ColorInputWidget::setBitDepth(int bits) { + if (m_bitDepth == bits) + return true; + + int singleStep, pageStep, maximum; + QString hexInputMask; + if (bits == 15) { + singleStep = 1; + pageStep = 4; + maximum = 31; + hexInputMask = "HHHH"; + } else if (bits == 24) { + singleStep = 8; + pageStep = 24; + maximum = 255; + hexInputMask = "HHHHHH"; + } else { + // Unsupported bit depth + return false; + } + m_bitDepth = bits; + + blockEditSignals(true); + ui->slider_Red->setSingleStep(singleStep); + ui->slider_Green->setSingleStep(singleStep); + ui->slider_Blue->setSingleStep(singleStep); + ui->slider_Red->setPageStep(pageStep); + ui->slider_Green->setPageStep(pageStep); + ui->slider_Blue->setPageStep(pageStep); + ui->slider_Red->setMaximum(maximum); + ui->slider_Green->setMaximum(maximum); + ui->slider_Blue->setMaximum(maximum); + + ui->spinBox_Red->setSingleStep(singleStep); + ui->spinBox_Green->setSingleStep(singleStep); + ui->spinBox_Blue->setSingleStep(singleStep); + ui->spinBox_Red->setMaximum(maximum); + ui->spinBox_Green->setMaximum(maximum); + ui->spinBox_Blue->setMaximum(maximum); + + ui->lineEdit_Hex->setInputMask(hexInputMask); + ui->lineEdit_Hex->setMaxLength(hexInputMask.length()); + + updateColorUi(); + blockEditSignals(false); + emit bitDepthChanged(m_bitDepth); + return true; +} + +void ColorInputWidget::setColor(QRgb rgb) { + if (m_color == rgb) + return; + m_color = rgb; + updateColorUi(); + emit colorChanged(m_color); +} + +void ColorInputWidget::setRgbFromSliders() { + if (m_bitDepth == 15) { + setColor(qRgb(rgb8(ui->slider_Red->value()), + rgb8(ui->slider_Green->value()), + rgb8(ui->slider_Blue->value()))); + } else { + setColor(qRgb(ui->slider_Red->value(), + ui->slider_Green->value(), + ui->slider_Blue->value())); + } +} + +void ColorInputWidget::setRgbFromSpinners() { + if (m_bitDepth == 15) { + setColor(qRgb(rgb8(ui->spinBox_Red->value()), rgb8(ui->spinBox_Green->value()), rgb8(ui->spinBox_Blue->value()))); + } else { + setColor(qRgb(ui->spinBox_Red->value(), ui->spinBox_Green->value(), ui->spinBox_Blue->value())); + } +} + +void ColorInputWidget::setRgbFromHexString(const QString &text) { + if ((m_bitDepth == 24 && text.length() != 6) + || (m_bitDepth == 15 && text.length() != 4)) + return; + + bool ok = false; + int rgb = text.toInt(&ok, 16); + if (!ok) rgb = 0xFFFFFFFF; + + if (m_bitDepth == 15) { + int rc = gbaRed(rgb); + int gc = gbaGreen(rgb); + int bc = gbaBlue(rgb); + setColor(qRgb(rgb8(rc), rgb8(gc), rgb8(bc))); + } else { + setColor(qRgb(qRed(rgb), qGreen(rgb), qBlue(rgb))); + } +} + +void ColorInputWidget::pickColor() { + ColorPicker picker(this); + if (picker.exec() == QDialog::Accepted) { + QColor c = picker.getColor(); + setColor(c.rgb()); + } +} diff --git a/src/ui/gridsettingsdialog.cpp b/src/ui/gridsettingsdialog.cpp index 10934196..bfc814bc 100644 --- a/src/ui/gridsettingsdialog.cpp +++ b/src/ui/gridsettingsdialog.cpp @@ -1,7 +1,6 @@ #include "ui_gridsettingsdialog.h" #include "gridsettingsdialog.h" -// TODO: Add color picker // TODO: Add linking chain button to width/height // TODO: Add "snap to metatile" check box? // TODO: Save settings in config @@ -39,9 +38,7 @@ GridSettingsDialog::GridSettingsDialog(GridSettings *settings, QWidget *parent) reset(true); connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &GridSettingsDialog::dialogButtonClicked); - - // TODO: Connect color picker - // connect(ui->, &, this, &GridSettingsDialog::changedGridSettings); + connect(ui->colorInput, &ColorInputWidget::colorChanged, this, &GridSettingsDialog::onColorChanged); } GridSettingsDialog::~GridSettingsDialog() { @@ -59,11 +56,13 @@ void GridSettingsDialog::reset(bool force) { const QSignalBlocker b_X(ui->spinBox_X); const QSignalBlocker b_Y(ui->spinBox_Y); const QSignalBlocker b_Style(ui->comboBox_Style); + const QSignalBlocker b_Color(ui->colorInput); ui->spinBox_Width->setValue(this->settings->width); ui->spinBox_Height->setValue(this->settings->height); ui->spinBox_X->setValue(this->settings->offsetX); ui->spinBox_Y->setValue(this->settings->offsetY); + ui->colorInput->setColor(this->settings->color.rgb()); // TODO: Debug //ui->comboBox_Style->setCurrentIndex(ui->comboBox_Style->findData(static_cast(this->settings->style))); @@ -73,7 +72,6 @@ void GridSettingsDialog::reset(bool force) { break; } } - // TODO: Initialize color with settings-color emit changedGridSettings(); } @@ -106,6 +104,11 @@ void GridSettingsDialog::on_comboBox_Style_currentIndexChanged(int index) { emit changedGridSettings(); } +void GridSettingsDialog::onColorChanged(QRgb color) { + this->settings->color = QColor::fromRgb(color); + emit changedGridSettings(); +} + void GridSettingsDialog::dialogButtonClicked(QAbstractButton *button) { auto role = ui->buttonBox->buttonRole(button); if (role == QDialogButtonBox::AcceptRole) { @@ -114,6 +117,6 @@ void GridSettingsDialog::dialogButtonClicked(QAbstractButton *button) { reset(); close(); } else if (role == QDialogButtonBox::ResetRole) { - reset(); + reset(); // TODO: We should restore to original defaults, not to the values when the window was opened. } }