diff --git a/Gui/ColorSelectorWidget.cpp b/Gui/ColorSelectorWidget.cpp index e72ce11f15..b92142a2b9 100644 --- a/Gui/ColorSelectorWidget.cpp +++ b/Gui/ColorSelectorWidget.cpp @@ -24,14 +24,150 @@ CLANG_DIAG_OFF(uninitialized) #include #include #include +#include +#include +#include +#include +#include CLANG_DIAG_ON(deprecated) CLANG_DIAG_ON(uninitialized) -#include "Gui/Label.h" #include "Engine/Lut.h" +#include "Gui/Label.h" + +#define COLOR_SELECTOR_BUTTON_PROPERTY "ColorButtonType" +#define COLOR_SELECTOR_BUTTON_RGB 0 +#define COLOR_SELECTOR_BUTTON_HSV 1 NATRON_NAMESPACE_ENTER +ColorSelectorPaletteButton::ColorSelectorPaletteButton(QWidget *parent) + : Button(parent) + , _r(COLOR_SELECTOR_PALETTE_DEFAULT_COLOR) + , _g(COLOR_SELECTOR_PALETTE_DEFAULT_COLOR) + , _b(COLOR_SELECTOR_PALETTE_DEFAULT_COLOR) + , _a(1.0) + , _modified(false) +{ + initButton(); +} + +ColorSelectorPaletteButton::ColorSelectorPaletteButton(float r, + float g, + float b, + float a, + QWidget *parent) + : Button(parent) + , _r(r) + , _g(g) + , _b(b) + , _a(a) + , _modified(true) +{ + initButton(); +} + +bool +ColorSelectorPaletteButton::isModified() +{ + return _modified; +} + +void +ColorSelectorPaletteButton::clearModified() +{ + _modified = false; +} + +void +ColorSelectorPaletteButton::getColor(float *r, + float *g, + float *b, + float *a) +{ + *r = _r; + *g = _g; + *b = _b; + *a = _a; +} + +void +ColorSelectorPaletteButton::clearColor() +{ + _r = COLOR_SELECTOR_PALETTE_DEFAULT_COLOR; + _g = COLOR_SELECTOR_PALETTE_DEFAULT_COLOR; + _b = COLOR_SELECTOR_PALETTE_DEFAULT_COLOR; + _a = 1.0; + _modified = false; + updateColor(false); +} + +void +ColorSelectorPaletteButton::setColor(float r, + float g, + float b, + float a) +{ + _r = r; + _g = g; + _b = b; + _a = a; + _modified = true; + updateColor(); +} + +void +ColorSelectorPaletteButton::updateColor(bool signal) +{ + QColor color; + color.setRgbF(Color::to_func_srgb(_r), + Color::to_func_srgb(_g), + Color::to_func_srgb(_b), + _a); + QPixmap pixColor(COLOR_SELECTOR_PALETTE_ICON_SIZE, + COLOR_SELECTOR_PALETTE_ICON_SIZE); + pixColor.fill(color); + setIcon( QIcon(pixColor) ); + setToolTip( QString::fromUtf8("R: %1\nG: %2\nB: %3\nA: %4\n\n%5") + .arg(_r) + .arg(_g) + .arg(_b) + .arg(_a) + .arg( tr("Clear color with right-click.") ) ); + + if (signal) { + Q_EMIT colorChanged(_r, _g, _b, _a); + } +} + +void +ColorSelectorPaletteButton::initButton() +{ + setIconSize( QSize(COLOR_SELECTOR_PALETTE_ICON_SIZE, + COLOR_SELECTOR_PALETTE_ICON_SIZE) ); + setStyleSheet( QString::fromUtf8("QPushButton { border: 0; background-color: transparent; }") ); + + QObject::connect( this, SIGNAL( clicked() ), + this, SLOT( buttonClicked() ) ); + + updateColor(false); +} + +void +ColorSelectorPaletteButton::buttonClicked() +{ + Q_EMIT colorPicked(_r, _g, _b, _a); +} + +void +ColorSelectorPaletteButton::mouseReleaseEvent(QMouseEvent *e) +{ + if (e->button() == Qt::RightButton) { + clearColor(); + } + Button::mouseReleaseEvent(e); +} + ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) : QWidget(parent) , _spinR(0) @@ -50,7 +186,7 @@ ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) , _slideA(0) , _triangle(0) , _hex(0) - , _button(0) + , _buttonColorGroup(0) , _stack(0) { QVBoxLayout *mainLayout = new QVBoxLayout(this); @@ -130,14 +266,14 @@ ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) _slideA->setMinimumAndMaximum(0., 1.); } - _slideR->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - _slideG->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - _slideB->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - _slideH->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - _slideS->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - _slideV->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + _slideR->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + _slideG->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + _slideB->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + _slideH->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + _slideS->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + _slideV->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); if (_slideA) { - _slideA->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + _slideA->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); } // set line color to match channel (R/G/B/A) @@ -217,10 +353,36 @@ ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) // hex _hex = new LineEdit(this); + _hex->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + // color buttons + _buttonColorGroup = new QButtonGroup(this); + + Button *buttonRGB = new Button(QString::fromUtf8("RGB"), this); + Button *buttonHSV = new Button(QString::fromUtf8("HSV"), this); + + buttonRGB->setProperty(COLOR_SELECTOR_BUTTON_PROPERTY, COLOR_SELECTOR_BUTTON_RGB); + buttonHSV->setProperty(COLOR_SELECTOR_BUTTON_PROPERTY, COLOR_SELECTOR_BUTTON_HSV); - // button - _button = new Button(QString::fromUtf8("RGB"), this); - _button->setCheckable(true); + buttonRGB->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + buttonHSV->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + buttonRGB->setCheckable(true); + buttonRGB->setChecked(true); + + buttonHSV->setCheckable(true); + buttonHSV->setChecked(false); + + _buttonColorGroup->setExclusive(true); + _buttonColorGroup->addButton(buttonRGB); + _buttonColorGroup->addButton(buttonHSV); + + // palette + Button *paletteAddColorButton = new Button(QObject::tr("Add"), this); + Button *paletteClearButton = new Button(QObject::tr("Clear"), this); + + QShortcut *addPaletteColorShortcut = new QShortcut(QKeySequence( QObject::tr("Shift+A") ), this); + QShortcut *clearPaletteColorsShortcut = new QShortcut(QKeySequence( QObject::tr("Shift+C") ), this); // set triangle size setTriangleSize(); @@ -236,7 +398,6 @@ ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) _spinS->setObjectName( QString::fromUtf8("ColorSelectorSat") ); _spinV->setObjectName( QString::fromUtf8("ColorSelectorVal") ); _hex->setObjectName( QString::fromUtf8("ColorSelectorHex") ); - _button->setObjectName( QString::fromUtf8("ColorSelectorSwitch") ); // labels Label *labelR = new Label(QString::fromUtf8("R"), this); @@ -261,6 +422,16 @@ ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) labelS->setMinimumWidth(10); labelV->setMinimumWidth(10); + labelR->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + labelG->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + labelB->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + if (_slideA) { + labelA->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + } + labelH->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + labelS->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + labelV->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + // tooltips _spinR->setToolTip( QObject::tr("Red color value") ); _spinG->setToolTip( QObject::tr("Green color value") ); @@ -272,7 +443,8 @@ ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) _spinS->setToolTip( QObject::tr("Saturation value") ); _spinV->setToolTip( QObject::tr("Brightness/Intensity value") ); _hex->setToolTip( QObject::tr("A HTML hexadecimal color is specified with: #RRGGBB, where the RR (red), GG (green) and BB (blue) hexadecimal integers specify the components of the color.") ); - _button->setToolTip( QObject::tr("Switch to HSV") ); + paletteAddColorButton->setToolTip( QObject::tr("Add current color to palette (Shift+A)") ); + paletteClearButton->setToolTip( QObject::tr("Clear colors in palette (Shift+C)") ); // layout _stack = new QStackedWidget(this); @@ -323,12 +495,21 @@ ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) QWidget *bottomWidget = new QWidget(this); QHBoxLayout *bottomLayout = new QHBoxLayout(bottomWidget); + QWidget *paletteWidget = new QWidget(this); + QHBoxLayout *paletteLayout = new QHBoxLayout(paletteWidget); + + QWidget *paletteButtonsWidget = new QWidget(this); + + QWidget *paletteOptionsWidget = new QWidget(this); + QVBoxLayout *paletteOptionsLayout = new QVBoxLayout(paletteOptionsWidget); + _stack->setContentsMargins(0, 0, 0, 0); hexWidget->setContentsMargins(0, 0, 0, 0); topWidget->setContentsMargins(0, 0, 0, 0); leftWidget->setContentsMargins(0, 0, 0, 0); rightWidget->setContentsMargins(0, 0, 0, 0); - bottomWidget->setContentsMargins(0, 0, 10, 0); + bottomWidget->setContentsMargins(10, 5, 10, 0); + paletteOptionsWidget->setContentsMargins(0, 0, 0, 0); _stack->layout()->setContentsMargins(0, 0, 0, 0); mainLayout->setContentsMargins(5, 5, 5, 5); @@ -343,6 +524,8 @@ ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) leftLayout->setContentsMargins(0, 0, 0, 0); rightLayout->setContentsMargins(0, 0, 0, 0); bottomLayout->setContentsMargins(0, 0, 0, 0); + paletteLayout->setContentsMargins(0, 5, 10, 0); + paletteOptionsLayout->setContentsMargins(0, 0, 0, 0); if (_slideA) { QMargins aMargin = hsvLayout->contentsMargins(); @@ -355,6 +538,7 @@ ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) topLayout->setSpacing(0); leftLayout->setSpacing(0); rightLayout->setSpacing(0); + paletteOptionsLayout->setSpacing(2); rLayout->addWidget(labelR); rLayout->addWidget(_spinR); @@ -393,6 +577,13 @@ ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) hsvLayout->addWidget(sWidget); hsvLayout->addWidget(vWidget); + paletteLayout->addWidget(paletteOptionsWidget); + paletteLayout->addWidget(paletteButtonsWidget); + + paletteOptionsLayout->addWidget(paletteAddColorButton); + paletteOptionsLayout->addStretch(); + paletteOptionsLayout->addWidget(paletteClearButton); + leftLayout->addWidget(_triangle); _stack->addWidget(rgbaWidget); @@ -406,12 +597,13 @@ ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) topLayout->addWidget(leftWidget); topLayout->addWidget(rightWidget); - bottomLayout->addWidget(_button); - bottomLayout->addStretch(); + bottomLayout->addWidget(buttonRGB); + bottomLayout->addWidget(buttonHSV); bottomLayout->addWidget(hexWidget); mainLayout->addWidget(topWidget); - mainLayout->addWidget(bottomWidget); + mainLayout->addWidget(paletteWidget); + rightLayout->addWidget(bottomWidget); // connect the widgets QObject::connect( _triangle, SIGNAL( colorChanged(QColor) ), @@ -454,8 +646,20 @@ ColorSelectorWidget::ColorSelectorWidget(bool withAlpha, QWidget *parent) this, SLOT( handleSliderAMoved(double) ) ); } - QObject::connect( _button, SIGNAL( clicked(bool) ), - this, SLOT( handleButtonClicked(bool) ) ); + QObject::connect( _buttonColorGroup, SIGNAL( buttonClicked(int) ), + this, SLOT( handleButtonColorClicked(int) ) ); + + QObject::connect( paletteAddColorButton, SIGNAL( clicked(bool) ), + this, SLOT( setPaletteButtonColor(bool) ) ); + QObject::connect( paletteClearButton, SIGNAL( clicked(bool) ), + this, SLOT( clearPaletteButtons(bool) ) ); + QObject::connect( addPaletteColorShortcut, SIGNAL( activated() ), + this, SLOT( setPaletteButtonColor() ) ); + QObject::connect( clearPaletteColorsShortcut, SIGNAL( activated() ), + this, SLOT( clearPaletteButtons() ) ); + + // setup palette + initPaletteButtons(paletteButtonsWidget); } void @@ -492,6 +696,16 @@ ColorSelectorWidget::setColor(float r, setHex( _triangle->color() ); } +void +ColorSelectorWidget::setColorFromPalette(float r, + float g, + float b, + float a) +{ + setColor(r, g, b, a); + announceColorChange(); +} + void ColorSelectorWidget::setRedChannel(float value) { @@ -633,7 +847,7 @@ ColorSelectorWidget::announceColorChange() void ColorSelectorWidget::setTriangleSize() { - int triangleSize = 4; + int triangleSize = _spinA ? 5 : 4; int padding = 10; triangleSize = (_spinR->size().height() * triangleSize) + (triangleSize * padding); @@ -642,6 +856,101 @@ ColorSelectorWidget::setTriangleSize() _triangle->setMaximumSize(triangleSize, triangleSize); } +void +ColorSelectorWidget::initPaletteButtons(QWidget *widget, + int rows, + int cols) +{ + if (!widget) { + return; + } + + _paletteButtons.clear(); + QVBoxLayout *widgetLayout = new QVBoxLayout(widget); + widget->setContentsMargins(0, 0, 0, 0); + widgetLayout->setContentsMargins(0, 0, 0, 0); + widgetLayout->setSpacing(0); + + for (int x = 0; x < rows; ++x) { + QWidget *colWidget = new QWidget(widget); + colWidget->setContentsMargins(0, 0, 0, 0); + QHBoxLayout *colLayout = new QHBoxLayout(colWidget); + colLayout->setContentsMargins(0, 0, 0, 0); + colLayout->setSpacing(0); + widgetLayout->addWidget(colWidget); + for (int y = 0; y < cols; ++y) { + ColorSelectorPaletteButton *button = new ColorSelectorPaletteButton(colWidget); + QObject::connect( button, SIGNAL( colorPicked(float,float,float,float) ), + this, SLOT( setColorFromPalette(float,float,float,float) ) ); + colLayout->addWidget(button); + _paletteButtons << button; + } + } +} + +void +ColorSelectorWidget::updatePaletteButtons() +{ + QSettings settings( QString::fromUtf8(NATRON_ORGANIZATION_NAME), + QString::fromUtf8(NATRON_APPLICATION_NAME) ); + settings.beginGroup( QString::fromUtf8(COLOR_SELECTOR_PALETTE_SETTINGS) ); + + for (int i = 0; i < _paletteButtons.size(); ++i) { + if ( !settings.value( QString::number(i) ).isValid() ) { + continue; + } + QStringList colorValues = settings.value( QString::number(i) ).toStringList(); + if (colorValues.size() > 3) { + _paletteButtons.at(i)->setColor( colorValues.at(0).toFloat(), + colorValues.at(1).toFloat(), + colorValues.at(2).toFloat(), + colorValues.at(3).toFloat() ); + } + } + + settings.endGroup(); +} + +void +ColorSelectorWidget::savePaletteButton(int id) +{ + if (_paletteButtons.size() < 1 || id >= _paletteButtons.size() || id < 0) { + return; + } + + QSettings settings( QString::fromUtf8(NATRON_ORGANIZATION_NAME), + QString::fromUtf8(NATRON_APPLICATION_NAME) ); + settings.beginGroup( QString::fromUtf8(COLOR_SELECTOR_PALETTE_SETTINGS) ); + + QStringList colorValues; + float r, g, b, a; + _paletteButtons.at(id)->getColor(&r, &g, &b, &a); + colorValues << QString::number(r) << QString::number(g); + colorValues << QString::number(b) << QString::number(a); + settings.setValue(QString::number(id), colorValues); + + settings.endGroup(); +} + +void +ColorSelectorWidget::savePaletteButtons() +{ + QSettings settings( QString::fromUtf8(NATRON_ORGANIZATION_NAME), + QString::fromUtf8(NATRON_APPLICATION_NAME) ); + settings.beginGroup( QString::fromUtf8(COLOR_SELECTOR_PALETTE_SETTINGS) ); + + for (int i = 0; i < _paletteButtons.size(); ++i) { + QStringList colorValues; + float r, g, b, a; + _paletteButtons.at(i)->getColor(&r, &g, &b, &a); + colorValues << QString::number(r) << QString::number(g); + colorValues << QString::number(b) << QString::number(a); + settings.setValue(QString::number(i), colorValues); + } + + settings.endGroup(); +} + void ColorSelectorWidget::handleTriangleColorChanged(const QColor &color, bool announce) @@ -914,17 +1223,56 @@ ColorSelectorWidget::setSliderVColor() } void -ColorSelectorWidget::handleButtonClicked(bool checked) +ColorSelectorWidget::handleButtonColorClicked(int /*id*/) +{ + QVariant var = _buttonColorGroup->checkedButton()->property(COLOR_SELECTOR_BUTTON_PROPERTY); + if ( var.isValid() ) { + _stack->setCurrentIndex( var.toInt() ); + } +} + +void +ColorSelectorWidget::setPaletteButtonColor(bool /*clicked*/) +{ + if (_paletteButtons.size() < 1) { + return; + } + + int buttonID = 0; + bool resetModified = false; + for (int i = 0; i < _paletteButtons.size(); ++i) { + if ( _paletteButtons.at(i)->isModified() ) { + if (i == (_paletteButtons.size() - 1) ) { + resetModified = true; + } + continue; + } + buttonID = i; + break; + } + + if (resetModified) { + for (int i = 0; i < _paletteButtons.size(); ++i) { + _paletteButtons.at(i)->clearModified(); + } + } + + if ( buttonID < _paletteButtons.size() ) { + _paletteButtons.at(buttonID)->setColor( _spinR->value(), + _spinG->value(), + _spinB->value(), + _spinA ? _spinA->value() : 1.0 ); + savePaletteButton(buttonID); + } +} + +void +ColorSelectorWidget::clearPaletteButtons(bool /*clicked*/) { - if (checked) { - _button->setText( QString::fromUtf8("HSV") ); - _button->setToolTip( QObject::tr("Switch to RGB") ); - _stack->setCurrentIndex(1); - } else { - _button->setText( QString::fromUtf8("RGB") ); - _button->setToolTip( QObject::tr("Switch to HSV") ); - _stack->setCurrentIndex(0); + for (int i = 0; i < _paletteButtons.size(); ++i) { + _paletteButtons.at(i)->clearColor(); } + savePaletteButtons(); } NATRON_NAMESPACE_EXIT diff --git a/Gui/ColorSelectorWidget.h b/Gui/ColorSelectorWidget.h index e7a4cdb304..f51f7064e4 100644 --- a/Gui/ColorSelectorWidget.h +++ b/Gui/ColorSelectorWidget.h @@ -30,6 +30,7 @@ CLANG_DIAG_OFF(uninitialized) #include #include #include +#include CLANG_DIAG_ON(deprecated) CLANG_DIAG_ON(uninitialized) @@ -38,8 +39,61 @@ CLANG_DIAG_ON(uninitialized) #include "Gui/LineEdit.h" #include "Gui/Button.h" +#define COLOR_SELECTOR_PALETTE_DEFAULT_COLOR 0.0 +#define COLOR_SELECTOR_PALETTE_SETTINGS "ColorSelectorPalette" +#define COLOR_SELECTOR_PALETTE_ROWS 2 +#define COLOR_SELECTOR_PALETTE_COLS 12 +#define COLOR_SELECTOR_PALETTE_ICON_SIZE 18 + NATRON_NAMESPACE_ENTER +class ColorSelectorPaletteButton : public Button +{ + Q_OBJECT + +public: + + explicit ColorSelectorPaletteButton(QWidget *parent = NULL); + explicit ColorSelectorPaletteButton(float r = COLOR_SELECTOR_PALETTE_DEFAULT_COLOR, + float g = COLOR_SELECTOR_PALETTE_DEFAULT_COLOR, + float b = COLOR_SELECTOR_PALETTE_DEFAULT_COLOR, + float a = 1.0, + QWidget *parent = NULL); + + bool isModified(); + void clearModified(); + + void getColor(float *r, float *g, float *b, float *a); + +Q_SIGNALS: + + void colorChanged(float r, float g, float b, float a); + void colorPicked(float r, float g, float b, float a); + +public Q_SLOTS: + + void clearColor(); + void setColor(float r, float g, float b, float a); + +private: + + float _r; + float _g; + float _b; + float _a; + bool _modified; + + void updateColor(bool signal = true); + + void initButton(); + +private Q_SLOTS: + + void buttonClicked(); + + void mouseReleaseEvent(QMouseEvent *e) override; +}; + class ColorSelectorWidget : public QWidget { Q_OBJECT @@ -57,6 +111,7 @@ class ColorSelectorWidget : public QWidget public Q_SLOTS: void setColor(float r, float g, float b, float a); + void setColorFromPalette(float r, float g, float b, float a); private: @@ -80,10 +135,12 @@ public Q_SLOTS: LineEdit *_hex; - Button *_button; + QButtonGroup *_buttonColorGroup; QStackedWidget *_stack; + QVector _paletteButtons; + void setRedChannel(float value); void setGreenChannel(float value); void setBlueChannel(float value); @@ -98,6 +155,13 @@ public Q_SLOTS: void setTriangleSize(); + void initPaletteButtons(QWidget *widget = NULL, + int rows = COLOR_SELECTOR_PALETTE_ROWS, + int cols = COLOR_SELECTOR_PALETTE_COLS); + void updatePaletteButtons(); + void savePaletteButton(int id); + void savePaletteButtons(); + private Q_SLOTS: void handleTriangleColorChanged(const QColor &color, bool announce = true); @@ -128,7 +192,10 @@ private Q_SLOTS: void setSliderSColor(); void setSliderVColor(); - void handleButtonClicked(bool checked); + void handleButtonColorClicked(int id); + + void setPaletteButtonColor(bool clicked = true); + void clearPaletteButtons(bool clicked = true); // workaround for QToolButton+QWidgetAction // triggered signal(s) are never emitted!? @@ -136,6 +203,7 @@ private Q_SLOTS: { if (e->type() == QEvent::Show) { Q_EMIT updateColor(); + updatePaletteButtons(); } return QWidget::event(e); }