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