aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Mardelle <[email protected]>2016-06-22 02:24:36 +0200
committerJean-Baptiste Mardelle <[email protected]>2016-06-22 02:24:36 +0200
commit5238614252a40b664ac49bdea8666bd90443b297 (patch)
treefa586a586d377f0df2fa48ce113180a4a212f27b
parent3e4c0cfb7f8c8379a598dc86998e1a50ef147b28 (diff)
New color correction effect based on avfilter selective color (CMYK adjustments)
-rw-r--r--data/blacklisted_effects.txt1
-rw-r--r--data/effects/avfilter/CMakeLists.txt2
-rw-r--r--data/effects/avfilter/selectivecolor.xml38
-rw-r--r--data/kdenliveeffectscategory.rc2
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/effectstack/CMakeLists.txt1
-rw-r--r--src/effectstack/effectstackview2.cpp1
-rw-r--r--src/effectstack/parametercontainer.cpp12
-rw-r--r--src/effectstack/widgets/choosecolorwidget.h2
-rw-r--r--src/effectstack/widgets/lumaliftgain.cpp8
-rw-r--r--src/effectstack/widgets/selectivecolor.cpp149
-rw-r--r--src/effectstack/widgets/selectivecolor.h62
-rw-r--r--src/ui/selectivecolor_ui.ui351
13 files changed, 622 insertions, 8 deletions
diff --git a/data/blacklisted_effects.txt b/data/blacklisted_effects.txt
index d1b0407..a86c899 100644
--- a/data/blacklisted_effects.txt
+++ b/data/blacklisted_effects.txt
@@ -139,4 +139,5 @@ avfilter.ass
avfilter.acompressor
avfilter.aecho
avfilter.agate
+avfilter.selectivecolor
diff --git a/data/effects/avfilter/CMakeLists.txt b/data/effects/avfilter/CMakeLists.txt
index 61c4179..2260572 100644
--- a/data/effects/avfilter/CMakeLists.txt
+++ b/data/effects/avfilter/CMakeLists.txt
@@ -3,5 +3,5 @@ INSTALL (FILES
acompressor.xml
aecho.xml
agate.xml
-
+selectivecolor.xml
DESTINATION ${DATA_INSTALL_DIR}/kdenlive/effects)
diff --git a/data/effects/avfilter/selectivecolor.xml b/data/effects/avfilter/selectivecolor.xml
new file mode 100644
index 0000000..2e6d65c
--- /dev/null
+++ b/data/effects/avfilter/selectivecolor.xml
@@ -0,0 +1,38 @@
+<!DOCTYPE kpartgui>
+<effect tag="avfilter.selectivecolor" id="avfilter.selectivecolor">
+ <name>CMYK adjust (avfilter)</name>
+ <description>Apply CMYK correction to specific color ranges</description>
+ <author>libavfilter</author>
+ <parameter type="cmyk" name="av.reds" default="">
+ <name>Reds</name>
+ </parameter>
+ <parameter type="cmyk" name="av.yellows" default="">
+ <name>Yellows</name>
+ </parameter>
+ <parameter type="cmyk" name="av.greens" default="">
+ <name>Greens</name>
+ </parameter>
+ <parameter type="cmyk" name="av.cyans" default="">
+ <name>Cyans</name>
+ </parameter>
+ <parameter type="cmyk" name="av.blues" default="">
+ <name>Blues</name>
+ </parameter>
+ <parameter type="cmyk" name="av.magentas" default="">
+ <name>Magentas</name>
+ </parameter>
+ <parameter type="cmyk" name="av.whites" default="">
+ <name>Whites</name>
+ </parameter>
+ <parameter type="cmyk" name="av.neutrals" default="">
+ <name>Neutrals</name>
+ </parameter>
+ <parameter type="cmyk" name="av.blacks" default="">
+ <name>Blacks</name>
+ </parameter>
+ <parameter type="list" name="av.correction_method" default="0" paramlist="0;1">
+ <paramlistdisplay>Absolute,Relative</paramlistdisplay>
+ <name>Correction Method</name>
+ </parameter>
+</effect>
+
diff --git a/data/kdenliveeffectscategory.rc b/data/kdenliveeffectscategory.rc
index f15828f..352bc3b 100644
--- a/data/kdenliveeffectscategory.rc
+++ b/data/kdenliveeffectscategory.rc
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
<data name="effects" version="0">
- <group list="lift_gamma_gain,brightness,gamma,frei0r.colgate,frei0r.balanc0r,frei0r.brightness,frei0r.levels,frei0r.three_point_balance,frei0r.curves,frei0r.coloradj_RGB,frei0r.sopsat,frei0r.bezier_curves">
+ <group list="lift_gamma_gain,brightness,gamma,frei0r.colgate,frei0r.balanc0r,frei0r.brightness,frei0r.levels,frei0r.three_point_balance,frei0r.curves,frei0r.coloradj_RGB,frei0r.sopsat,frei0r.bezier_curves,avfilter.selectivecolor">
<text>Colour correction</text>
</group>
<group list="invert,sepia,tcolor,greyscale,frei0r.B,frei0r.G,frei0r.R,frei0r.contrast0r,frei0r.saturat0r,frei0r.tint0r,frei0r.primaries,chroma_hold,frei0r.colorize,frei0r.equaliz0r,frei0r.hueshift0r,frei0r.luminance,lumaliftgaingamma">
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a987830..d3236fe 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -204,6 +204,7 @@ ki18n_wrap_ui(kdenlive_UIS
ui/cutjobdialog_ui.ui
ui/scenecutdialog_ui.ui
ui/gradientedit_ui.ui
+ ui/selectivecolor_ui.ui
)
if(BUILD_JogShuttle)
diff --git a/src/effectstack/CMakeLists.txt b/src/effectstack/CMakeLists.txt
index 28725f6..80ae0d6 100644
--- a/src/effectstack/CMakeLists.txt
+++ b/src/effectstack/CMakeLists.txt
@@ -25,5 +25,6 @@ set(kdenlive_SRCS
effectstack/widgets/colorwheel.cpp
effectstack/widgets/lumaliftgain.cpp
effectstack/widgets/keyframeimport.cpp
+ effectstack/widgets/selectivecolor.cpp
PARENT_SCOPE)
diff --git a/src/effectstack/effectstackview2.cpp b/src/effectstack/effectstackview2.cpp
index 701b11d..3cac1df 100644
--- a/src/effectstack/effectstackview2.cpp
+++ b/src/effectstack/effectstackview2.cpp
@@ -789,7 +789,6 @@ void EffectStackView2::setActiveKeyframe(int frame)
void EffectStackView2::slotDeleteGroup(QDomDocument doc)
{
-
ClipItem * clip = NULL;
int ix = -1;
if (m_status == MASTER_CLIP) {
diff --git a/src/effectstack/parametercontainer.cpp b/src/effectstack/parametercontainer.cpp
index 27bd36b..e3e8526 100644
--- a/src/effectstack/parametercontainer.cpp
+++ b/src/effectstack/parametercontainer.cpp
@@ -31,6 +31,7 @@
#include "widgets/bezier/beziersplinewidget.h"
#include "effectstack/widgets/lumaliftgain.h"
#include "effectstack/widgets/animationwidget.h"
+#include "effectstack/widgets/selectivecolor.h"
#include "kdenlivesettings.h"
#include "mainwindow.h"
@@ -195,6 +196,11 @@ ParameterContainer::ParameterContainer(const QDomElement &effect, const ItemInfo
m_vbox->addWidget(gainWidget);
m_valueItems[effect.attribute(QStringLiteral("id"))] = gainWidget;
connect(gainWidget, SIGNAL(valueChanged()), this, SLOT(slotCollectAllParameters()));
+ } else if (effect.attribute(QStringLiteral("id")) == QLatin1String("avfilter.selectivecolor")) {
+ SelectiveColor *cmykAdjust = new SelectiveColor(effect);
+ connect(cmykAdjust, SIGNAL(valueChanged()), this, SLOT(slotCollectAllParameters()));
+ m_vbox->addWidget(cmykAdjust);
+ m_valueItems[effect.attribute(QStringLiteral("id"))] = cmykAdjust;
}
else for (int i = 0; i < namenode.count() ; ++i) {
QDomElement pa = namenode.item(i).toElement();
@@ -927,6 +933,12 @@ void ParameterContainer::slotCollectAllParameters()
emit parameterChanged(oldparam, m_effect, m_effect.attribute(QStringLiteral("kdenlive_ix")).toInt());
return;
}
+ if (m_effect.attribute(QStringLiteral("tag")) == QLatin1String("avfilter.selectivecolor")) {
+ SelectiveColor *cmykAdjust = static_cast<SelectiveColor*>(m_valueItems.value(m_effect.attribute(QStringLiteral("id"))));
+ cmykAdjust->updateEffect(m_effect);
+ emit parameterChanged(oldparam, m_effect, m_effect.attribute(QStringLiteral("kdenlive_ix")).toInt());
+ return;
+ }
QDomNodeList namenode = m_effect.elementsByTagName(QStringLiteral("parameter"));
diff --git a/src/effectstack/widgets/choosecolorwidget.h b/src/effectstack/widgets/choosecolorwidget.h
index 2d892a6..736bdf7 100644
--- a/src/effectstack/widgets/choosecolorwidget.h
+++ b/src/effectstack/widgets/choosecolorwidget.h
@@ -49,7 +49,7 @@ private:
public slots:
void slotColorModified(const QColor &color);
-
+
private slots:
/** @brief Updates the different color choosing options to have all selected @param color. */
void setColor(const QColor &color);
diff --git a/src/effectstack/widgets/lumaliftgain.cpp b/src/effectstack/widgets/lumaliftgain.cpp
index 8c29ad1..c8d1991 100644
--- a/src/effectstack/widgets/lumaliftgain.cpp
+++ b/src/effectstack/widgets/lumaliftgain.cpp
@@ -88,15 +88,15 @@ void LumaLiftGain::updateEffect(QDomElement &effect)
values.insert(QStringLiteral("lift_r"), lift.redF());
values.insert(QStringLiteral("lift_g"), lift.greenF());
values.insert(QStringLiteral("lift_b"), lift.blueF());
-
+
values.insert(QStringLiteral("gamma_r"), gamma.redF() * GAMMA_FACTOR);
values.insert(QStringLiteral("gamma_g"), gamma.greenF() * GAMMA_FACTOR);
values.insert(QStringLiteral("gamma_b"), gamma.blueF() * GAMMA_FACTOR);
-
+
values.insert(QStringLiteral("gain_r"), gain.redF() * GAIN_FACTOR);
values.insert(QStringLiteral("gain_g"), gain.greenF() * GAIN_FACTOR);
values.insert(QStringLiteral("gain_b"), gain.blueF() * GAIN_FACTOR);
-
+
QDomNodeList namenode = effect.childNodes();
for (int i = 0; i < namenode.count() ; ++i) {
QDomElement pa = namenode.item(i).toElement();
@@ -104,6 +104,6 @@ void LumaLiftGain::updateEffect(QDomElement &effect)
if (values.contains(pa.attribute(QStringLiteral("name")))) {
pa.setAttribute(QStringLiteral("value"), (int) (values.value(pa.attribute(QStringLiteral("name"))) * m_locale.toDouble(pa.attribute(QStringLiteral("factor"), QStringLiteral("1")))));
}
- }
+ }
}
diff --git a/src/effectstack/widgets/selectivecolor.cpp b/src/effectstack/widgets/selectivecolor.cpp
new file mode 100644
index 0000000..49a640b
--- /dev/null
+++ b/src/effectstack/widgets/selectivecolor.cpp
@@ -0,0 +1,149 @@
+/*
+Copyright (C) 2016 Jean-Baptiste Mardelle <[email protected]>
+This file is part of Kdenlive. See www.kdenlive.org.
+
+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 2 of
+the License or (at your option) version 3 or any later version
+accepted by the membership of KDE e.V. (or its successor approved
+by the membership of KDE e.V.), which shall act as a proxy
+defined in Section 14 of version 3 of the license.
+
+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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "effectstack/widgets/selectivecolor.h"
+#include "utils/KoIconUtils.h"
+
+#include <QLabel>
+#include <QComboBox>
+#include <QDebug>
+#include <KLocalizedString>
+
+SelectiveColor::SelectiveColor(const QDomElement effect, QWidget* parent) :
+ QWidget(parent)
+{
+ setupUi(this);
+ QDomNodeList namenode = effect.elementsByTagName(QStringLiteral("parameter"));
+ for (int i = 0; i < namenode.count() ; ++i) {
+ QDomElement pa = namenode.item(i).toElement();
+ QDomElement na = pa.firstChildElement(QStringLiteral("name"));
+ QString type = pa.attribute(QStringLiteral("type"));
+ QString paramName = na.isNull() ? pa.attribute(QStringLiteral("name")) : i18n(na.text().toUtf8().data());
+ if (type == QLatin1String("cmyk"))
+ addParam(pa, paramName);
+ else if (pa.attribute(QStringLiteral("name")) == QLatin1String("av.correction_method")) {
+ if (pa.attribute(QStringLiteral("value")).toInt() == 1)
+ relative->setChecked(true);
+ else
+ absolute->setChecked(true);
+ }
+ }
+ connect(range, SIGNAL(currentIndexChanged(int)), this, SLOT(updateValues()));
+ connect(slider_black, SIGNAL(valueChanged(int)), this, SLOT(effectChanged()));
+ connect(slider_yell, SIGNAL(valueChanged(int)), this, SLOT(effectChanged()));
+ connect(slider_mag, SIGNAL(valueChanged(int)), this, SLOT(effectChanged()));
+ connect(slider_cyan, SIGNAL(valueChanged(int)), this, SLOT(effectChanged()));
+ connect(relative, SIGNAL(toggled(bool)), this, SLOT(effectChanged()));
+ updateValues();
+}
+
+void SelectiveColor::addParam(QDomElement &effect, QString name)
+{
+ QString tag = effect.attribute(QStringLiteral("name"));
+ if (name.isEmpty()) {
+ name = tag;
+ }
+ QString value = effect.attribute(QStringLiteral("value"));
+ if (value.isEmpty())
+ value = effect.attribute(QStringLiteral("default"));
+ QIcon icon;
+ if (!value.isEmpty())
+ icon = KoIconUtils::themedIcon(QStringLiteral("dialog-ok-apply"));
+ range->addItem(icon, name, QStringList() << effect.attribute(QStringLiteral("name")) << value);
+}
+
+void SelectiveColor::updateValues()
+{
+ QStringList values = range->currentData().toStringList();
+ if (values.count() < 2) {
+ // Something is wrong, abort
+ return;
+ }
+ blockSignals(true);
+ spin_black->setValue(0);
+ spin_yell->setValue(0);
+ spin_mag->setValue(0);
+ spin_cyan->setValue(0);
+ QStringList vals = values.at(1).split(QStringLiteral(" "));
+ switch (vals.count()) {
+ case 4 :
+ spin_black->setValue(vals.at(3).toDouble() * 100);
+ case 3:
+ spin_yell->setValue(vals.at(2).toDouble() * 100);
+ case 2:
+ spin_mag->setValue(vals.at(1).toDouble() * 100);
+ case 1:
+ spin_cyan->setValue(vals.at(0).toDouble() * 100);
+ break;
+ default:
+ break;
+ }
+ blockSignals(false);
+}
+
+void SelectiveColor::effectChanged()
+{
+ int vBlack = spin_black->value();
+ int vYell = spin_yell->value();
+ int vMag = spin_mag->value();
+ int vCyan = spin_cyan->value();
+ QString result;
+ if (vBlack == 0 && vYell == 0 && vMag == 0 && vCyan == 0) {
+ // default empty val
+ } else {
+ result = QString("%1 %2 %3 %4").arg(vCyan / 100.0).arg(vMag / 100.0).arg(vYell / 100.0).arg(vBlack / 100.0);
+ }
+ QStringList values = range->currentData().toStringList();
+ if (values.isEmpty()) {
+ // Something is wrong, abort
+ return;
+ }
+ if (values.at(1).isEmpty() && !result.isEmpty()) {
+ range->setItemIcon(range->currentIndex(), KoIconUtils::themedIcon(QStringLiteral("dialog-ok-apply")));
+ } else if (!values.at(1).isEmpty() && result.isEmpty()) {
+ range->setItemIcon(range->currentIndex(), QIcon());
+ }
+ QStringList newData = QStringList() << values.at(0) << result;
+ range->setItemData(range->currentIndex(), newData);
+ emit valueChanged();
+}
+
+void SelectiveColor::updateEffect(QDomElement &effect)
+{
+ QMap <QString, QString> values;
+ for (int i = 0; i < range->count(); i++) {
+ QStringList vals = range->itemData(i).toStringList();
+ values.insert(vals.at(0), vals.at(1));
+ }
+ QDomNodeList namenode = effect.childNodes();
+ for (int i = 0; i < namenode.count() ; ++i) {
+ QDomElement pa = namenode.item(i).toElement();
+ if (pa.tagName() != QLatin1String("parameter")) continue;
+ QString paramName = pa.attribute(QStringLiteral("name"));
+ if (values.contains(paramName)) {
+ pa.setAttribute(QStringLiteral("value"), values.value(paramName));
+ } else if (paramName == QLatin1String("av.correction_method")) {
+ pa.setAttribute(QStringLiteral("value"), relative->isChecked() ? QStringLiteral("1") : QStringLiteral("0"));
+ }
+ }
+}
+
+
diff --git a/src/effectstack/widgets/selectivecolor.h b/src/effectstack/widgets/selectivecolor.h
new file mode 100644
index 0000000..118c5f9
--- /dev/null
+++ b/src/effectstack/widgets/selectivecolor.h
@@ -0,0 +1,62 @@
+/*
+Copyright (C) 2016 Jean-Baptiste Mardelle <[email protected]>
+This file is part of Kdenlive. See www.kdenlive.org.
+
+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 2 of
+the License or (at your option) version 3 or any later version
+accepted by the membership of KDE e.V. (or its successor approved
+by the membership of KDE e.V.), which shall act as a proxy
+defined in Section 14 of version 3 of the license.
+
+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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SELECTIVECOLORWIDGET_H
+#define SELECTIVECOLORWIDGET_H
+
+#include "ui_selectivecolor_ui.h"
+
+#include <QWidget>
+#include <QDomNodeList>
+#include <QLocale>
+
+
+/**
+ * @class SelectiveColor
+ * @brief Provides options to adjust CMYK factor of a color range.
+ * @author Jean-Baptiste Mardelle
+ */
+
+class SelectiveColor : public QWidget, public Ui::SelectiveColor
+{
+ Q_OBJECT
+public:
+ /** @brief Sets up the widget.
+ * @param text (optional) What the color will be used for
+ * @param color (optional) initial color
+ * @param alphaEnabled (optional) Should transparent colors be enabled */
+ explicit SelectiveColor(const QDomElement effect, QWidget* parent = 0);
+ void addParam(QDomElement &effect, QString name);
+ void updateEffect(QDomElement &effect);
+
+private:
+ QLocale m_locale;
+
+private slots:
+ void updateValues();
+ void effectChanged();
+
+signals:
+ /** @brief Emitted whenever a different color was choosen. */
+ void valueChanged();
+};
+
+#endif
diff --git a/src/ui/selectivecolor_ui.ui b/src/ui/selectivecolor_ui.ui
new file mode 100644
index 0000000..92c446b
--- /dev/null
+++ b/src/ui/selectivecolor_ui.ui
@@ -0,0 +1,351 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SelectiveColor</class>
+ <widget class="QWidget" name="SelectiveColor">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>413</width>
+ <height>455</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Preset</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QComboBox" name="preset"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="add_preset">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="remove_preset">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Color range</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2">
+ <widget class="QComboBox" name="range"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Cyan</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QSlider" name="slider_cyan">
+ <property name="minimum">
+ <number>-100</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QSpinBox" name="spin_cyan">
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="minimum">
+ <number>-100</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Magenta</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QSlider" name="slider_mag">
+ <property name="minimum">
+ <number>-100</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="2">
+ <widget class="QSpinBox" name="spin_mag">
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="minimum">
+ <number>-100</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Yellow</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QSlider" name="slider_yell">
+ <property name="minimum">
+ <number>-100</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="2">
+ <widget class="QSpinBox" name="spin_yell">
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="minimum">
+ <number>-100</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Black</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QSlider" name="slider_black">
+ <property name="minimum">
+ <number>-100</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="2">
+ <widget class="QSpinBox" name="spin_black">
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="minimum">
+ <number>-100</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0" colspan="3">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QRadioButton" name="absolute">
+ <property name="text">
+ <string>Absol&amp;ute</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="relative">
+ <property name="text">
+ <string>Re&amp;lative</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="7" column="1">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>122</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>slider_cyan</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>spin_cyan</receiver>
+ <slot>setValue(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>212</x>
+ <y>121</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>360</x>
+ <y>121</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>spin_cyan</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>slider_cyan</receiver>
+ <slot>setValue(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>360</x>
+ <y>121</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>212</x>
+ <y>121</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>slider_mag</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>spin_mag</receiver>
+ <slot>setValue(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>212</x>
+ <y>167</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>360</x>
+ <y>167</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>spin_mag</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>slider_mag</receiver>
+ <slot>setValue(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>360</x>
+ <y>167</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>212</x>
+ <y>167</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>slider_yell</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>spin_yell</receiver>
+ <slot>setValue(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>212</x>
+ <y>213</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>360</x>
+ <y>213</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>spin_yell</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>slider_yell</receiver>
+ <slot>setValue(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>360</x>
+ <y>213</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>212</x>
+ <y>213</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>slider_black</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>spin_black</receiver>
+ <slot>setValue(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>212</x>
+ <y>259</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>360</x>
+ <y>259</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>spin_black</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>slider_black</receiver>
+ <slot>setValue(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>360</x>
+ <y>259</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>212</x>
+ <y>259</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>