From c34416a478345736c5b79b512b128fe18bc28172 Mon Sep 17 00:00:00 2001
From: itsmattkc <34096995+itsmattkc@users.noreply.github.com>
Date: Sun, 25 Sep 2022 14:27:15 -0700
Subject: [PATCH] colordialog: add support for swatches
---
app/dialog/color/colordialog.cpp | 50 ++++-
app/dialog/color/colordialog.h | 6 +
app/widget/colorbutton/colorbutton.cpp | 6 +-
app/widget/colorbutton/colorbutton.h | 6 +-
app/widget/colorwheel/CMakeLists.txt | 2 +
app/widget/colorwheel/colorswatchchooser.cpp | 223 +++++++++++++++++++
app/widget/colorwheel/colorswatchchooser.h | 73 ++++++
app/widget/colorwheel/colorvalueswidget.cpp | 81 ++++++-
8 files changed, 424 insertions(+), 23 deletions(-)
create mode 100644 app/widget/colorwheel/colorswatchchooser.cpp
create mode 100644 app/widget/colorwheel/colorswatchchooser.h
diff --git a/app/dialog/color/colordialog.cpp b/app/dialog/color/colordialog.cpp
index e15e8d209..360a8445d 100644
--- a/app/dialog/color/colordialog.cpp
+++ b/app/dialog/color/colordialog.cpp
@@ -40,9 +40,13 @@ ColorDialog::ColorDialog(ColorManager* color_manager, const ManagedColor& start,
splitter->setChildrenCollapsible(false);
layout->addWidget(splitter);
- QWidget* wheel_area = new QWidget();
- QHBoxLayout* wheel_layout = new QHBoxLayout(wheel_area);
- splitter->addWidget(wheel_area);
+ QWidget* graphics_area = new QWidget();
+ splitter->addWidget(graphics_area);
+
+ QVBoxLayout *graphics_layout = new QVBoxLayout(graphics_area);
+
+ QHBoxLayout* wheel_layout = new QHBoxLayout();
+ graphics_layout->addLayout(wheel_layout);
color_wheel_ = new ColorWheelWidget();
wheel_layout->addWidget(color_wheel_);
@@ -51,6 +55,17 @@ ColorDialog::ColorDialog(ColorManager* color_manager, const ManagedColor& start,
hsv_value_gradient_->setFixedWidth(QtUtils::QFontMetricsWidth(fontMetrics(), QStringLiteral("HHH")));
wheel_layout->addWidget(hsv_value_gradient_);
+ QHBoxLayout *swatch_layout = new QHBoxLayout();
+ graphics_layout->addLayout(swatch_layout);
+
+ swatch_layout->addStretch();
+
+ swatch_ = new ColorSwatchChooser(color_manager_);
+ swatch_->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+ swatch_layout->addWidget(swatch_);
+
+ swatch_layout->addStretch();
+
QWidget* value_area = new QWidget();
QVBoxLayout* value_layout = new QVBoxLayout(value_area);
value_layout->setSpacing(0);
@@ -61,8 +76,6 @@ ColorDialog::ColorDialog(ColorManager* color_manager, const ManagedColor& start,
value_layout->addWidget(color_values_widget_);
chooser_ = new ColorSpaceChooser(color_manager_);
- chooser_->set_input(start.color_input());
- chooser_->set_output(start.color_output());
value_layout->addWidget(chooser_);
@@ -71,10 +84,16 @@ ColorDialog::ColorDialog(ColorManager* color_manager, const ManagedColor& start,
connect(color_wheel_, &ColorWheelWidget::SelectedColorChanged, color_values_widget_, &ColorValuesWidget::SetColor);
connect(color_wheel_, &ColorWheelWidget::SelectedColorChanged, hsv_value_gradient_, &ColorGradientWidget::SetSelectedColor);
+ connect(color_wheel_, &ColorWheelWidget::SelectedColorChanged, swatch_, &ColorSwatchChooser::SetCurrentColor);
connect(hsv_value_gradient_, &ColorGradientWidget::SelectedColorChanged, color_values_widget_, &ColorValuesWidget::SetColor);
connect(hsv_value_gradient_, &ColorGradientWidget::SelectedColorChanged, color_wheel_, &ColorWheelWidget::SetSelectedColor);
+ connect(hsv_value_gradient_, &ColorGradientWidget::SelectedColorChanged, swatch_, &ColorSwatchChooser::SetCurrentColor);
connect(color_values_widget_, &ColorValuesWidget::ColorChanged, hsv_value_gradient_, &ColorGradientWidget::SetSelectedColor);
connect(color_values_widget_, &ColorValuesWidget::ColorChanged, color_wheel_, &ColorWheelWidget::SetSelectedColor);
+ connect(color_values_widget_, &ColorValuesWidget::ColorChanged, swatch_, &ColorSwatchChooser::SetCurrentColor);
+ connect(swatch_, &ColorSwatchChooser::ColorClicked, hsv_value_gradient_, &ColorGradientWidget::SetSelectedColor);
+ connect(swatch_, &ColorSwatchChooser::ColorClicked, color_wheel_, &ColorWheelWidget::SetSelectedColor);
+ connect(swatch_, &ColorSwatchChooser::ColorClicked, color_values_widget_, &ColorValuesWidget::SetColor);
connect(color_wheel_, &ColorWheelWidget::DiameterChanged, hsv_value_gradient_, &ColorGradientWidget::setFixedHeight);
@@ -83,6 +102,20 @@ ColorDialog::ColorDialog(ColorManager* color_manager, const ManagedColor& start,
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
layout->addWidget(buttons);
+ SetColor(start);
+
+ connect(chooser_, &ColorSpaceChooser::ColorSpaceChanged, this, &ColorDialog::ColorSpaceChanged);
+ ColorSpaceChanged(chooser_->input(), chooser_->output());
+
+ // Set default size ratio to 2:1
+ resize(sizeHint().height() * 2, sizeHint().height());
+}
+
+void ColorDialog::SetColor(const ManagedColor &start)
+{
+ chooser_->set_input(start.color_input());
+ chooser_->set_output(start.color_output());
+
Color managed_start;
if (start.color_input().isEmpty()) {
@@ -103,12 +136,7 @@ ColorDialog::ColorDialog(ColorManager* color_manager, const ManagedColor& start,
color_wheel_->SetSelectedColor(managed_start);
hsv_value_gradient_->SetSelectedColor(managed_start);
color_values_widget_->SetColor(managed_start);
-
- connect(chooser_, &ColorSpaceChooser::ColorSpaceChanged, this, &ColorDialog::ColorSpaceChanged);
- ColorSpaceChanged(chooser_->input(), chooser_->output());
-
- // Set default size ratio to 2:1
- resize(sizeHint().height() * 2, sizeHint().height());
+ swatch_->SetCurrentColor(managed_start);
}
ManagedColor ColorDialog::GetSelectedColor() const
diff --git a/app/dialog/color/colordialog.h b/app/dialog/color/colordialog.h
index 837feee95..bdd517e50 100644
--- a/app/dialog/color/colordialog.h
+++ b/app/dialog/color/colordialog.h
@@ -28,6 +28,7 @@
#include "render/managedcolor.h"
#include "widget/colorwheel/colorgradientwidget.h"
#include "widget/colorwheel/colorspacechooser.h"
+#include "widget/colorwheel/colorswatchchooser.h"
#include "widget/colorwheel/colorvalueswidget.h"
#include "widget/colorwheel/colorwheelwidget.h"
@@ -69,6 +70,9 @@ public:
ColorTransform GetColorSpaceOutput() const;
+public slots:
+ void SetColor(const ManagedColor &c);
+
private:
ColorManager* color_manager_;
@@ -82,6 +86,8 @@ private:
ColorSpaceChooser* chooser_;
+ ColorSwatchChooser *swatch_;
+
private slots:
void ColorSpaceChanged(const QString& input, const ColorTransform &output);
diff --git a/app/widget/colorbutton/colorbutton.cpp b/app/widget/colorbutton/colorbutton.cpp
index 4abf33a30..0e1a9cf14 100644
--- a/app/widget/colorbutton/colorbutton.cpp
+++ b/app/widget/colorbutton/colorbutton.cpp
@@ -24,14 +24,16 @@
namespace olive {
-ColorButton::ColorButton(ColorManager* color_manager, QWidget *parent) :
+ColorButton::ColorButton(ColorManager* color_manager, bool show_dialog_on_click, QWidget *parent) :
QPushButton(parent),
color_manager_(color_manager),
color_processor_(nullptr)
{
setAutoFillBackground(true);
- connect(this, &ColorButton::clicked, this, &ColorButton::ShowColorDialog);
+ if (show_dialog_on_click) {
+ connect(this, &ColorButton::clicked, this, &ColorButton::ShowColorDialog);
+ }
SetColor(Color(1.0f, 1.0f, 1.0f));
}
diff --git a/app/widget/colorbutton/colorbutton.h b/app/widget/colorbutton/colorbutton.h
index 31ce5dfaa..c325fc8bd 100644
--- a/app/widget/colorbutton/colorbutton.h
+++ b/app/widget/colorbutton/colorbutton.h
@@ -32,7 +32,11 @@ class ColorButton : public QPushButton
{
Q_OBJECT
public:
- ColorButton(ColorManager* color_manager, QWidget* parent = nullptr);
+ ColorButton(ColorManager* color_manager, bool show_dialog_on_click, QWidget* parent = nullptr);
+ ColorButton(ColorManager* color_manager, QWidget* parent = nullptr) :
+ ColorButton(color_manager, true, parent)
+ {
+ }
const ManagedColor& GetColor() const;
diff --git a/app/widget/colorwheel/CMakeLists.txt b/app/widget/colorwheel/CMakeLists.txt
index c5a8407f3..fb1f43082 100644
--- a/app/widget/colorwheel/CMakeLists.txt
+++ b/app/widget/colorwheel/CMakeLists.txt
@@ -22,6 +22,8 @@ set(OLIVE_SOURCES
widget/colorwheel/colorpreviewbox.cpp
widget/colorwheel/colorspacechooser.h
widget/colorwheel/colorspacechooser.cpp
+ widget/colorwheel/colorswatchchooser.h
+ widget/colorwheel/colorswatchchooser.cpp
widget/colorwheel/colorswatchwidget.h
widget/colorwheel/colorswatchwidget.cpp
widget/colorwheel/colorvalueswidget.h
diff --git a/app/widget/colorwheel/colorswatchchooser.cpp b/app/widget/colorwheel/colorswatchchooser.cpp
new file mode 100644
index 000000000..18214f707
--- /dev/null
+++ b/app/widget/colorwheel/colorswatchchooser.cpp
@@ -0,0 +1,223 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2022 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#include "colorswatchchooser.h"
+
+#include
+
+#include "common/filefunctions.h"
+#include "widget/menu/menu.h"
+
+namespace olive {
+
+const int kDefaultColorCount = 16;
+const Color kDefaultColors[kDefaultColorCount] = {
+ Color(1.0, 1.0, 1.0),
+ Color(1.0, 1.0, 0.0),
+ Color(1.0, 0.5, 0.0),
+ Color(1.0, 0.0, 0.0),
+ Color(1.0, 0.0, 1.0),
+ Color(0.5, 0.0, 1.0),
+ Color(0.0, 0.0, 1.0),
+ Color(0.0, 0.5, 1.0),
+ Color(0.0, 1.0, 0.0),
+ Color(0.0, 0.5, 0.0),
+ Color(0.5, 0.25, 0.0),
+ Color(0.75, 0.5, 0.25),
+ Color(0.75, 0.75, 0.75),
+ Color(0.5, 0.5, 0.5),
+ Color(0.25, 0.25, 0.25),
+ Color(0.0, 0.0, 0.0)
+};
+
+ColorSwatchChooser::ColorSwatchChooser(ColorManager *manager, QWidget *parent) :
+ QWidget(parent)
+{
+ auto layout = new QGridLayout(this);
+
+ for (int x=0; xsetFixedWidth(b->sizeHint().height()/2*3);
+ b->setContextMenuPolicy(Qt::CustomContextMenu);
+ layout->addWidget(b, y, x);
+
+ // Save button in buttons array
+ int btn_index = x + kColCount*y;
+ buttons_[btn_index] = b;
+
+ // Set default color
+ SetDefaultColor(btn_index);
+
+ // Connect clicks
+ connect(b, &ColorButton::clicked, this, &ColorSwatchChooser::HandleButtonClick);
+ connect(b, &ColorButton::customContextMenuRequested, this, &ColorSwatchChooser::HandleContextMenu);
+ }
+ }
+
+ LoadSwatches();
+}
+
+void ColorSwatchChooser::SetDefaultColor(int index)
+{
+ if (index < kDefaultColorCount) {
+ buttons_[index]->SetColor(kDefaultColors[index]);
+ } else {
+ buttons_[index]->SetColor(Color(1.0, 1.0, 1.0));
+ }
+}
+
+void ColorSwatchChooser::HandleButtonClick()
+{
+ auto b = static_cast(sender());
+
+ emit ColorClicked(b->GetColor());
+ SetCurrentColor(b->GetColor());
+}
+
+void ColorSwatchChooser::HandleContextMenu()
+{
+ Menu m(this);
+
+ auto save_action = m.addAction(tr("Save Color Here"));
+ connect(save_action, &QAction::triggered, this, &ColorSwatchChooser::SaveCurrentColor);
+
+ m.addSeparator();
+
+ auto reset_action = m.addAction(tr("Reset To Default"));
+ connect(reset_action, &QAction::triggered, this, &ColorSwatchChooser::ResetMenuButton);
+
+ menu_btn_ = static_cast(sender());
+
+ m.exec(QCursor::pos());
+}
+
+void ColorSwatchChooser::SaveCurrentColor()
+{
+ menu_btn_->SetColor(current_);
+
+ SaveSwatches();
+}
+
+void ColorSwatchChooser::ResetMenuButton()
+{
+ for (int i=0; i> version;
+
+ if (version == 1) {
+ int index = 0;
+ while (index < kBtnCount && !d.atEnd()) {
+ Color::DataType r;
+ QString s;
+ ManagedColor c;
+ ColorTransform t;
+ bool is_display;
+
+ c.set_alpha(1.0);
+
+ d >> r;
+ c.set_red(r);
+
+ d >> r;
+ c.set_green(r);
+
+ d >> r;
+ c.set_blue(r);
+
+ d >> s;
+ c.set_color_input(s);
+
+ d >> is_display;
+ if (is_display) {
+ QString display, view, look;
+ d >> display;
+ d >> view;
+ d >> look;
+ c.set_color_output(ColorTransform(display, view, look));
+ } else {
+ d >> s;
+ c.set_color_output(ColorTransform(s));
+ }
+
+ buttons_[index]->SetColor(c);
+
+ index++;
+ }
+ }
+
+ f.close();
+ }
+}
+
+void ColorSwatchChooser::SaveSwatches()
+{
+ QString fn = GetSwatchFilename();
+ QFile f(fn);
+
+ if (f.open(QFile::WriteOnly)) {
+ QDataStream d(&f);
+
+ const uint version = 1;
+ d << version;
+
+ for (int i=0; iGetColor();
+ d << c.red();
+ d << c.green();
+ d << c.blue();
+ d << c.color_input();
+ d << c.color_output().is_display();
+
+ if (c.color_output().is_display()) {
+ d << c.color_output().display();
+ d << c.color_output().view();
+ d << c.color_output().look();
+ } else {
+ d << c.color_output().output();
+ }
+ }
+
+ f.close();
+ } else {
+ qCritical() << "Failed to open swatch file" << fn << "for writing";
+ }
+}
+
+}
diff --git a/app/widget/colorwheel/colorswatchchooser.h b/app/widget/colorwheel/colorswatchchooser.h
new file mode 100644
index 000000000..a2b4c571d
--- /dev/null
+++ b/app/widget/colorwheel/colorswatchchooser.h
@@ -0,0 +1,73 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2022 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#ifndef COLORSWATCHCHOOSER_H
+#define COLORSWATCHCHOOSER_H
+
+#include "node/color/colormanager/colormanager.h"
+#include "widget/colorbutton/colorbutton.h"
+
+namespace olive {
+
+class ColorSwatchChooser : public QWidget
+{
+ Q_OBJECT
+public:
+ ColorSwatchChooser(ColorManager *manager, QWidget *parent = nullptr);
+
+public slots:
+ void SetCurrentColor(const ManagedColor &c)
+ {
+ current_ = c;
+ }
+
+signals:
+ void ColorClicked(const ManagedColor &c);
+
+private:
+ void SetDefaultColor(int index);
+
+ static QString GetSwatchFilename();
+
+ void LoadSwatches();
+ void SaveSwatches();
+
+ static const int kRowCount = 4;
+ static const int kColCount = 8;
+ static const int kBtnCount = kRowCount*kColCount;
+ ColorButton *buttons_[kBtnCount];
+
+ ManagedColor current_;
+ ColorButton *menu_btn_;
+
+private slots:
+ void HandleButtonClick();
+
+ void HandleContextMenu();
+
+ void SaveCurrentColor();
+
+ void ResetMenuButton();
+
+};
+
+}
+
+#endif // COLORSWATCHCHOOSER_H
diff --git a/app/widget/colorwheel/colorvalueswidget.cpp b/app/widget/colorwheel/colorvalueswidget.cpp
index 85ac6fb62..e125decd5 100644
--- a/app/widget/colorwheel/colorvalueswidget.cpp
+++ b/app/widget/colorwheel/colorvalueswidget.cpp
@@ -270,14 +270,16 @@ ColorValuesTab::ColorValuesTab(bool with_legacy_option, QWidget *parent) :
row++;
- hex_lbl_ = new QLabel(tr("Hex"));
+ hex_lbl_ = new QLabel(tr("Web"));
layout->addWidget(hex_lbl_, row, 0);
hex_slider_ = new StringSlider();
connect(hex_slider_, &StringSlider::ValueChanged, this, &ColorValuesTab::HexChanged);
layout->addWidget(hex_slider_, row, 1);
- LegacyChanged(AreSlidersLegacyValues());
+ if (legacy_box_) {
+ LegacyChanged(AreSlidersLegacyValues());
+ }
}
Color ColorValuesTab::GetColor() const
@@ -371,11 +373,20 @@ void ColorValuesTab::LegacyChanged(bool legacy)
s->SetDragMultiplier(drag_multiplier);
}
- hex_lbl_->setVisible(legacy);
- hex_slider_->setVisible(legacy);
UpdateHex();
}
+QString RGBValToString(double d)
+{
+ QString s = QString::number(d);
+
+ if (!s.contains('.')) {
+ s.append(QStringLiteral(".0"));
+ }
+
+ return s;
+}
+
void ColorValuesTab::UpdateHex()
{
if (AreSlidersLegacyValues()) {
@@ -390,9 +401,39 @@ void ColorValuesTab::UpdateHex()
hex_slider_->SetValue(QStringLiteral("%1").arg(rgb, 6, 16, QLatin1Char('0')).toUpper());
}
+ } else {
+ hex_slider_->SetValue(QStringLiteral("rgb(%1, %2, %3)").arg(RGBValToString(red_slider_->GetValue()), RGBValToString(green_slider_->GetValue()), RGBValToString(blue_slider_->GetValue())));
}
}
+bool ParseRGBString(QString s, double *r, double *g, double *b)
+{
+ // Trim whitespace
+ s = s.trimmed();
+
+ s.remove(QStringLiteral("rgba"), Qt::CaseInsensitive);
+ s.remove(QStringLiteral("rgb"), Qt::CaseInsensitive);
+ s.remove('(');
+ s.remove(')');
+
+ QStringList vals = s.split(',');
+ if (vals.size() < 3) {
+ return false;
+ }
+
+ bool ok;
+ *r = vals.at(0).toDouble(&ok);
+ if (!ok) return false;
+
+ *g = vals.at(1).toDouble(&ok);
+ if (!ok) return false;
+
+ *b = vals.at(2).toDouble(&ok);
+ if (!ok) return false;
+
+ return true;
+}
+
void ColorValuesTab::HexChanged(const QString &s)
{
bool ok;
@@ -403,15 +444,37 @@ void ColorValuesTab::HexChanged(const QString &s)
uint32_t g = (hex & 0x00FF00) >> 8;
uint32_t b = (hex & 0x0000FF);
- red_slider_->SetValue(r);
- green_slider_->SetValue(g);
- blue_slider_->SetValue(b);
+ if (AreSlidersLegacyValues()) {
+ red_slider_->SetValue(r);
+ green_slider_->SetValue(g);
+ blue_slider_->SetValue(b);
+ } else {
+ red_slider_->SetValue(double(r)/kLegacyMultiplier);
+ green_slider_->SetValue(double(g)/kLegacyMultiplier);
+ blue_slider_->SetValue(double(b)/kLegacyMultiplier);
+ }
emit ColorChanged(GetColor());
} else {
- // Return to original value
- UpdateHex();
+ // Attempt to parse rgb/rgba
+ double r, g, b;
+ if (ParseRGBString(s, &r, &g, &b)) {
+ if (AreSlidersLegacyValues()) {
+ red_slider_->SetValue(r*kLegacyMultiplier);
+ green_slider_->SetValue(g*kLegacyMultiplier);
+ blue_slider_->SetValue(b*kLegacyMultiplier);
+ } else {
+ red_slider_->SetValue(r);
+ green_slider_->SetValue(g);
+ blue_slider_->SetValue(b);
+ }
+
+ emit ColorChanged(GetColor());
+ }
}
+
+ // Conform string to our formatting
+ UpdateHex();
}
bool ColorValuesTab::AreSlidersLegacyValues() const