diff --git a/scribus/CMakeLists_Sources.txt b/scribus/CMakeLists_Sources.txt
index 8a71d0a99..afb5817be 100644
--- a/scribus/CMakeLists_Sources.txt
+++ b/scribus/CMakeLists_Sources.txt
@@ -567,6 +567,7 @@ set(SCRIBUS_SOURCES
 	ui/docks/dock_panelbase.cpp
 	ui/factories/scribusproxystyle.cpp
 	ui/widgets/color_button.cpp
+	ui/widgets/color_slider.cpp
 	ui/widgets/combo_blendmode.cpp
 	ui/widgets/combo_linestyle.cpp
 	ui/widgets/dropdown_button.cpp
diff --git a/scribus/ui/colorpicker/colorpicker_color.cpp b/scribus/ui/colorpicker/colorpicker_color.cpp
index 8e4d5c709..ac0907a1c 100644
--- a/scribus/ui/colorpicker/colorpicker_color.cpp
+++ b/scribus/ui/colorpicker/colorpicker_color.cpp
@@ -26,6 +26,9 @@ ColorPickerColor::ColorPickerColor(QWidget *parent) : QWidget(parent)
 
 	languageChange();
 
+	sliderAlpha->setMode(ColorSlider::Opacity);
+	sliderShade->setMode(ColorSlider::Shade);
+
 	connectSlots();
 	connect(sectionSwatches,    &SectionContainer::sizeChanged,				this, &ColorPickerColor::updateSize);
 }
@@ -34,14 +37,18 @@ void ColorPickerColor::connectSlots()
 {
 	connect(swatches,			&ColorPickerColorSwatches::colorChanged,	this, &ColorPickerColor::updateColorFromSwatches);	
 	connect(numberShade,		&ScrSpinBox::valueChanged,					this, &ColorPickerColor::updateColorShade);
+	connect(sliderShade,		&ColorSlider::valueChanged,					this, &ColorPickerColor::updateColorShade);
 	connect(numberAlpha,		&ScrSpinBox::valueChanged,					this, &ColorPickerColor::updateColorAlpha);
+	connect(sliderAlpha,		&ColorSlider::valueChanged,					this, &ColorPickerColor::updateColorAlpha);
 }
 
 void ColorPickerColor::disconnectSlots()
 {
 	disconnect(swatches,		&ColorPickerColorSwatches::colorChanged,	this, &ColorPickerColor::updateColorFromSwatches);
 	disconnect(numberShade,		&ScrSpinBox::valueChanged,					this, &ColorPickerColor::updateColorShade);
+	disconnect(sliderShade,		&ColorSlider::valueChanged,					this, &ColorPickerColor::updateColorShade);
 	disconnect(numberAlpha,		&ScrSpinBox::valueChanged,					this, &ColorPickerColor::updateColorAlpha);
+	disconnect(sliderAlpha,		&ColorSlider::valueChanged,					this, &ColorPickerColor::updateColorAlpha);
 }
 
 /* ********************************************************************************* *
@@ -73,8 +80,10 @@ void ColorPickerColor::setContext(Context config)
 		sectionSwatches->setVisible(true);
 		numberShade->setVisible(false);
 		labelShade->setVisible(false);
+		sliderShade->setVisible(false);
 		numberAlpha->setVisible(false);
 		labelAlpha->setVisible(false);
+		sliderAlpha->setVisible(false);
 		break;
 	case Context::Text:
 	case Context::TextBackground:
@@ -82,38 +91,48 @@ void ColorPickerColor::setContext(Context config)
 		sectionSwatches->setVisible(true);
 		numberShade->setVisible(true);
 		labelShade->setVisible(true);
+		sliderShade->setVisible(true);
 		numberAlpha->setVisible(false);
 		labelAlpha->setVisible(false);
+		sliderAlpha->setVisible(false);
 		break;
 	case Context::Fill:
 		sectionSwatches->setVisible(true);
 		numberShade->setVisible(true);
 		labelShade->setVisible(true);
+		sliderShade->setVisible(true);
 		numberAlpha->setVisible(false);
 		labelAlpha->setVisible(false);
+		sliderAlpha->setVisible(false);
 		break;
 	case Context::Line:
 		sectionSwatches->setVisible(true);
 		numberShade->setVisible(true);
 		labelShade->setVisible(true);
+		sliderShade->setVisible(true);
 		numberAlpha->setVisible(false);
 		labelAlpha->setVisible(false);
+		sliderAlpha->setVisible(false);
 		break;
 	case Context::FillMask:
 	case Context::LineMask:
 		sectionSwatches->setVisible(false);
 		numberShade->setVisible(false);
 		labelShade->setVisible(false);
+		sliderShade->setVisible(false);
 		numberAlpha->setVisible(true);
 		labelAlpha->setVisible(true);
+		sliderAlpha->setVisible(true);
 		isMask = true;
 		break;
 	case Context::DropShadow:
 		sectionSwatches->setVisible(true);
 		numberShade->setVisible(true);
 		labelShade->setVisible(true);
+		sliderShade->setVisible(true);
 		numberAlpha->setVisible(false);
 		labelAlpha->setVisible(false);
+		sliderAlpha->setVisible(false);
 		break;
 	}
 
@@ -183,23 +202,38 @@ QString ColorPickerColor::toolTipText() const
 void ColorPickerColor::setDoc(ScribusDoc *doc)
 {
 	m_doc = doc;
+	sliderAlpha->setDoc(m_doc);
+	sliderShade->setDoc(m_doc);
 }
 
 void ColorPickerColor::setColorData(const CPColorData& color)
 {
+	if (!m_doc)
+		return;
+
 	m_color = color;
 
+	bool hasColor = m_color.Name != CommonStrings::tr_NoneColor;
+
 	// update UI + controls
 	QSignalBlocker sigSwatches(swatches);
 	swatches->setCurrentColor(m_color.Name);
 
 	QSignalBlocker sigShade(numberShade);
 	numberShade->setValue(m_color.Shade);
-	numberShade->setEnabled(m_color.Name != CommonStrings::tr_NoneColor);
+	numberShade->setEnabled(hasColor);
 
 	QSignalBlocker sigAlpha(numberAlpha);
 	numberAlpha->setValue(qRound(100 - (m_color.Opacity * 100)));
-	numberAlpha->setEnabled(m_color.Name != CommonStrings::tr_NoneColor);
+	numberAlpha->setEnabled(hasColor);
+
+	QSignalBlocker sigAlphaSlider(sliderAlpha);
+	sliderAlpha->setEnabled(hasColor);
+	sliderAlpha->setValues(m_color.Name, numberAlpha->value(), numberShade->value());
+
+	QSignalBlocker sigShadeSlider(sliderShade);
+	sliderShade->setEnabled(hasColor);
+	sliderShade->setValues(m_color.Name, numberAlpha->value(), numberShade->value());
 
 }
 
@@ -211,20 +245,50 @@ void ColorPickerColor::languageChange()
 void ColorPickerColor::updateColorFromSwatches()
 {
 	m_color.Name = swatches->currentColor();
-	numberShade->setEnabled(m_color.Name != CommonStrings::tr_NoneColor);
-	numberAlpha->setEnabled(m_color.Name != CommonStrings::tr_NoneColor);
+	bool hasColor = m_color.Name != CommonStrings::tr_NoneColor;
+
+	numberShade->setEnabled(hasColor);
+	sliderShade->setEnabled(hasColor);
+	sliderShade->setValues(m_color.Name, numberAlpha->value(), numberShade->value());
+	numberAlpha->setEnabled(hasColor);
+	sliderAlpha->setEnabled(hasColor);
+	sliderAlpha->setValues(m_color.Name, numberAlpha->value(), numberShade->value());
 
 	updateColor();
 }
 
 void ColorPickerColor::updateColorShade()
 {
+	QObject* obj = sender();
+	if( obj == sliderShade )
+	{
+		QSignalBlocker sigBlocker(numberShade);
+		numberShade->setValue(sliderShade->value());
+	}
+	else if( obj == numberShade )
+	{
+		QSignalBlocker sigBlocker(sliderShade);
+		sliderShade->setValue(numberShade->value());
+	}
+
 	m_color.Shade = numberShade->value();
 	updateColor();
 }
 
 void ColorPickerColor::updateColorAlpha()
 {
+	QObject* obj = sender();
+	if( obj == sliderAlpha )
+	{
+		QSignalBlocker sigBlocker(numberAlpha);
+		numberAlpha->setValue(sliderAlpha->value());
+	}
+	else if( obj == numberAlpha )
+	{
+		QSignalBlocker sigBlocker(sliderAlpha);
+		sliderAlpha->setValue(numberAlpha->value());
+	}
+
 	m_color.Opacity = (100 - numberAlpha->value()) / 100.0;
 	updateColor();
 }
diff --git a/scribus/ui/colorpicker/colorpicker_color.ui b/scribus/ui/colorpicker/colorpicker_color.ui
index 4ee50c4ed..96550bf2f 100644
--- a/scribus/ui/colorpicker/colorpicker_color.ui
+++ b/scribus/ui/colorpicker/colorpicker_color.ui
@@ -59,51 +59,58 @@
        </property>
       </widget>
      </item>
-     <item row="1" column="1">
-      <widget class="QLabel" name="labelAlpha">
-       <property name="text">
-        <string>Opacity:</string>
+     <item row="0" column="2">
+      <widget class="ScrSpinBox" name="numberShade">
+       <property name="suffix">
+        <string> %</string>
        </property>
-       <property name="alignment">
-        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       <property name="maximum">
+        <double>100.000000000000000</double>
+       </property>
+       <property name="singleStep">
+        <double>10.000000000000000</double>
        </property>
       </widget>
      </item>
-     <item row="0" column="1">
+     <item row="0" column="0">
       <widget class="QLabel" name="labelShade">
        <property name="text">
         <string>Shade:</string>
        </property>
        <property name="alignment">
-        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
        </property>
       </widget>
      </item>
-     <item row="0" column="2">
-      <widget class="ScrSpinBox" name="numberShade">
-       <property name="suffix">
-        <string> %</string>
-       </property>
-       <property name="maximum">
-        <double>100.000000000000000</double>
+     <item row="0" column="1">
+      <widget class="ColorSlider" name="sliderShade">
+       <property name="orientation">
+        <enum>Qt::Orientation::Horizontal</enum>
        </property>
-       <property name="singleStep">
-        <double>10.000000000000000</double>
+       <property name="tickPosition">
+        <enum>QSlider::TickPosition::TicksAbove</enum>
        </property>
       </widget>
      </item>
      <item row="1" column="0">
-      <spacer name="horizontalSpacer">
+      <widget class="QLabel" name="labelAlpha">
+       <property name="text">
+        <string>Opacity:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="ColorSlider" name="sliderAlpha">
        <property name="orientation">
-        <enum>Qt::Horizontal</enum>
+        <enum>Qt::Orientation::Horizontal</enum>
        </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>0</width>
-         <height>0</height>
-        </size>
+       <property name="tickPosition">
+        <enum>QSlider::TickPosition::TicksAbove</enum>
        </property>
-      </spacer>
+      </widget>
      </item>
     </layout>
    </item>
@@ -136,6 +143,11 @@
    <header>ui/colorpicker/colorpicker_color_swatches.h</header>
    <container>1</container>
   </customwidget>
+  <customwidget>
+   <class>ColorSlider</class>
+   <extends>QSlider</extends>
+   <header>ui/widgets/color_slider.h</header>
+  </customwidget>
  </customwidgets>
  <tabstops>
   <tabstop>numberShade</tabstop>
diff --git a/scribus/ui/dasheditor.cpp b/scribus/ui/dasheditor.cpp
index c0cfbf77b..6d6d3d358 100644
--- a/scribus/ui/dasheditor.cpp
+++ b/scribus/ui/dasheditor.cpp
@@ -55,7 +55,6 @@ for which a new license (GPL+exception) is in place.
  *
  * ********************************************************************************* */
 
-const int RADIUS = 6;
 const double HAIRLINE = 0.001;
 
 DashPreview::DashPreview(QWidget *pa) : QFrame(pa)
diff --git a/scribus/ui/factories/scribusproxystyle.cpp b/scribus/ui/factories/scribusproxystyle.cpp
index 5295b27a4..94ce7dbde 100644
--- a/scribus/ui/factories/scribusproxystyle.cpp
+++ b/scribus/ui/factories/scribusproxystyle.cpp
@@ -18,6 +18,8 @@
 
 #include "prefsmanager.h"
 #include "scribus.h"
+#include "ui/widgets/color_slider.h"
+#include "util_gui.h"
 
 // https://doc.qt.io/qt-6/qstyle.html#standardPalette
 QPalette createLightPalette()
@@ -64,6 +66,167 @@ ScribusProxyStyle* ScribusProxyStyle::instance()
 	return static_cast<ScribusProxyStyle*>(qApp->style());
 }
 
+QRect ScribusProxyStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *option, SubControl sc, const QWidget *widget) const
+{
+	QRect rect = QProxyStyle::subControlRect(cc, option, sc, widget);
+
+	switch (cc)
+	{
+	case QStyle::ComplexControl::CC_Slider:
+	{
+		const QStyleOptionSlider *soSlider = qstyleoption_cast<const QStyleOptionSlider *>(option);
+
+		if (soSlider && widget->inherits("ColorSlider") )
+		{
+			QRect ret;
+			bool horizontal = soSlider->orientation == Qt::Horizontal;
+			int thickness = RADIUS * 2;
+			int center = (horizontal) ? (soSlider->rect.height() - thickness) / 2 : (soSlider->rect.width() - thickness) / 2;
+			int sliderOffset = (soSlider->tickPosition != QSlider::NoTicks) ? thickness : center;
+
+			switch (sc)
+			{
+			case SC_SliderHandle:
+			{
+				int len = thickness + 2; //proxy()->pixelMetric(PM_SliderLength, styleOption, widget);
+				int sliderPos = sliderPositionFromValue(soSlider->minimum, soSlider->maximum, soSlider->sliderPosition, (horizontal ? soSlider->rect.width() : soSlider->rect.height()) - len, soSlider->upsideDown);
+
+				if (horizontal)
+					ret.setRect(soSlider->rect.x() + sliderPos, soSlider->rect.y() + sliderOffset, len, thickness);
+				else
+					ret.setRect(soSlider->rect.x() + 1, soSlider->rect.y() + sliderPos, thickness, len);
+
+				break;
+			}
+			case SC_SliderGroove:
+				if (horizontal)
+					ret.setRect(soSlider->rect.x(), soSlider->rect.y() + sliderOffset + 1, soSlider->rect.width(), thickness - 3);
+				else
+					ret.setRect(soSlider->rect.x() + 2, soSlider->rect.y(), thickness - 3, soSlider->rect.height());
+
+				break;
+			case SC_SliderTickmarks:
+			{
+				int tickOffset = (soSlider->tickPosition != QSlider::NoTicks) ? thickness : 0;
+
+				if (soSlider->tickPosition != QSlider::NoTicks)
+				{
+					if (horizontal)
+						ret.setRect(soSlider->rect.x() + 1, soSlider->rect.y(), soSlider->rect.width() - 3, thickness);
+					else
+						ret.setRect(soSlider->rect.x() + tickOffset, soSlider->rect.y() + 1, thickness, soSlider->rect.height() - 3);
+				}
+				break;
+			}
+			default:
+				break;
+			}
+
+			return visualRect(soSlider->direction, soSlider->rect, ret);
+		}
+	}
+	break;
+	default:
+		break;
+	}
+
+	return rect;
+}
+
+void ScribusProxyStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *painter, const QWidget *widget) const
+{
+	switch (cc)
+	{
+	case QStyle::ComplexControl::CC_Slider:
+	{
+		const ColorSlider *wdg = qobject_cast<const ColorSlider *>(widget);
+		const QStyleOptionSlider *soSlider = qstyleoption_cast<const QStyleOptionSlider *>(opt);
+
+		if (soSlider && wdg)
+		{
+			painter->save();
+			painter->setRenderHint(QPainter::Antialiasing, true);
+
+			QRect groove = subControlRect(CC_Slider, soSlider, SC_SliderGroove, widget);
+			QRect handle = subControlRect(CC_Slider, soSlider, SC_SliderHandle, widget);
+			QRect tickmarks = subControlRect(CC_Slider, soSlider, SC_SliderTickmarks, widget);
+
+			// Draw Slider
+			if ((soSlider->subControls & SC_SliderGroove) && groove.isValid())
+			{
+				double radius = (soSlider->orientation == Qt::Horizontal) ? groove.height() / 2 + 0.5 : groove.width() / 2 + 0.5;
+
+				QPainterPath border;
+				border.addRoundedRect(groove.toRectF().adjusted(0.5, 0.5, -0.5, -0.5), radius, radius);
+
+				// Draw Slider Gradients
+				painter->setClipPath(border);
+				if (wdg->m_background.isNull() || !widget->isEnabled())
+					painter->fillRect(groove, widget->palette().color(QPalette::Window));
+				else
+				{
+					renderCheckerPattern(painter, groove);
+					painter->drawImage(groove, wdg->m_background);
+				}
+				painter->setClipping(false);
+
+				// Draw Slider Border
+				painter->setPen(widget->palette().color(QPalette::Mid));
+				painter->setBrush(Qt::NoBrush);
+				painter->drawPath(border);
+				painter->setPen(Qt::NoPen);
+			}
+
+			// Draw Handle
+			if ((soSlider->subControls & SC_SliderHandle) && handle.isValid())
+				drawCircularHandle(painter, handle.center() + QPointF(0.5, 0.5), RADIUS * 2, Qt::NoBrush, widget->isEnabled());
+
+			// Draw Tickmarks
+			if ((soSlider->subControls & SC_SliderTickmarks) && tickmarks.isValid() && soSlider->tickInterval > 0)
+			{
+				QFont font = widget->font();
+				font.setPixelSize(8);
+				painter->setFont(font);
+
+				if (soSlider->orientation == Qt::Horizontal)
+				{
+					double ratio = double(tickmarks.width() - (2 * RADIUS)) / double(soSlider->tickInterval);
+
+					for (int x = 0; x <= soSlider->tickInterval; x++)
+					{
+						QRect tick(double(x) * ratio + RADIUS + 1, tickmarks.bottom() - 3, 1, 2);
+						QString label = QString::number((x * soSlider->maximum / soSlider->tickInterval) - abs(soSlider->minimum));
+						int offset = QFontMetrics(painter->font()).size(Qt::TextSingleLine, label).width() / 2;
+
+						painter->setPen(widget->palette().color(QPalette::WindowText));
+						painter->drawText(qBound(0, tick.left() - offset, tickmarks.width()), tickmarks.bottom() - 4, label);
+						painter->fillRect(tick, widget->palette().color(QPalette::WindowText));
+					}
+				}
+				else
+				{
+					double ratio = double(tickmarks.height() - (2 * RADIUS)) / double(soSlider->tickInterval);
+
+					for (int y = 0; y <= soSlider->tickInterval; y++)
+					{
+						QRect tick(tickmarks.left() + 2, double(y) * ratio + RADIUS + 1, 2, 1);
+						painter->fillRect(tick, widget->palette().color(QPalette::WindowText));
+					}
+				}
+			}
+
+			painter->restore();
+			return;
+		}
+	}
+		break;
+	default:
+		break;
+	}
+
+	QProxyStyle::drawComplexControl(cc, opt, painter, widget);
+}
+
 bool ScribusProxyStyle::eventFilter(QObject *object, QEvent *event)
 {
 	if(object == qApp && event->type() == QEvent::ThemeChange)
diff --git a/scribus/ui/factories/scribusproxystyle.h b/scribus/ui/factories/scribusproxystyle.h
index 6924af8d2..308d8594b 100644
--- a/scribus/ui/factories/scribusproxystyle.h
+++ b/scribus/ui/factories/scribusproxystyle.h
@@ -20,6 +20,9 @@ public:
 
 	static ScribusProxyStyle* instance();
 
+	QRect subControlRect(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, QStyle::SubControl sc, const QWidget *widget = nullptr) const override;
+	void drawComplexControl(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, QPainter *painter, const QWidget *widget) const override;
+
 protected:
 	bool eventFilter(QObject *object, QEvent *event) override;
 
diff --git a/scribus/ui/gradientpreview.cpp b/scribus/ui/gradientpreview.cpp
index b3684304c..191276a2d 100644
--- a/scribus/ui/gradientpreview.cpp
+++ b/scribus/ui/gradientpreview.cpp
@@ -29,7 +29,6 @@ for which a new license (GPL+exception) is in place.
 #include "gradientpreview.h"
 #include "util_gui.h"
 
-const int RADIUS = 6;
 const int GRADIENT_HEIGHT = 20;
 
 /* ********************************************************************************* *
diff --git a/scribus/ui/widgets/color_slider.cpp b/scribus/ui/widgets/color_slider.cpp
new file mode 100644
index 000000000..2d45d1bd7
--- /dev/null
+++ b/scribus/ui/widgets/color_slider.cpp
@@ -0,0 +1,721 @@
+#include "color_slider.h"
+
+#include <QPaintEvent>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPalette>
+#include <QStyle>
+#include <QStyleOption>
+#include <QWidget>
+
+#include "sccolorengine.h"
+#include "scribusdoc.h"
+#include "util_gui.h"
+
+/* ********************************************************************************* *
+ *
+ * Constructor + Setup
+ *
+ * ********************************************************************************* */
+
+ColorSlider::ColorSlider(QWidget *parent): ColorSlider(Mode::RGBRed, parent) {}
+
+ColorSlider::ColorSlider(Mode mode, QWidget *parent): QSlider(parent)
+{
+	m_mode = mode;
+	m_color = ScColor(255, 0, 0);
+
+	setMinimumSize(24, 24);
+	setOrientation(Qt::Horizontal);
+	setup();
+	updateValues();
+}
+
+void ColorSlider::setDoc(ScribusDoc *doc)
+{
+	m_doc = doc;
+}
+
+/* ********************************************************************************* *
+ *
+ * Slots
+ *
+ * ********************************************************************************* */
+
+void ColorSlider::setMode(Mode mode)
+{
+	m_mode = mode;
+	setup();
+	updateValues();
+	renderMap();
+	update();
+}
+
+void ColorSlider::setColor(const QString &colorName)
+{
+	if (!m_doc)
+		return;
+
+	if (colorName == CommonStrings::tr_NoneColor || colorName == CommonStrings::None)
+	{
+		m_background = QImage(width(), height(), QImage::Format_ARGB32); // if there is no image we draw the window color
+		m_background.fill(Qt::transparent);
+	}
+	else if (colorName.isEmpty())
+		setColor(m_doc->PageColors.value("White"));
+	else
+		setColor(m_doc->PageColors.value(colorName));
+}
+
+void ColorSlider::setColor(ScColor color)
+{
+	m_color = color;
+	updateValues();
+	renderMap();
+	update();
+}
+
+void ColorSlider::setShade(double shade)
+{
+	m_shade = shade;
+	updateValues();
+	update();
+}
+
+void ColorSlider::setOpacity(double opacity)
+{
+	m_opacity = opacity;
+	updateValues();
+	update();
+}
+
+void ColorSlider::setIsDynamic(double dynamic)
+{
+	m_dynamicColor = dynamic;
+	renderMap();
+	update();
+}
+
+void ColorSlider::setValues(const QString &colorName, double opacity, double shade)
+{
+	if (!m_doc)
+		return;
+
+	if (colorName == CommonStrings::tr_NoneColor || colorName == CommonStrings::None)
+	{
+		m_background = QImage(width(), height(), QImage::Format_ARGB32); // if there is no image we draw the window color
+		m_background.fill(Qt::transparent);
+	}
+	else if (!colorName.isEmpty() || m_doc->PageColors.contains(colorName))
+		setValues(m_doc->PageColors.value(colorName), opacity, shade);
+	else
+		setValues(m_doc->PageColors.value("White"), opacity, shade);
+}
+
+void ColorSlider::setValues(ScColor color, double opacity, double shade)
+{
+	m_color = color;
+	m_shade = shade;
+	m_opacity = opacity;
+	updateValues();
+	renderMap();
+	update();
+}
+
+/* ********************************************************************************* *
+ *
+ * Functions
+ *
+ * ********************************************************************************* */
+
+void ColorSlider::updateColor()
+{
+	if (!m_doc)
+		return;
+
+	double v1, v2, v3, v4;
+
+	switch (m_mode)
+	{
+	case Mode::Opacity:
+		m_opacity = value();
+		break;
+	case Mode::Shade:
+		m_shade = value();
+		break;
+	case Mode::CMYKCyan:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelCMYK);
+		m_color.getCMYK(&v1, &v2, &v3, &v4);
+		m_color.setCmykColorF(value() / (double) maximum(), v2, v3, v4);
+		break;
+	case Mode::CMYKMagenta:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelCMYK);
+		m_color.getCMYK(&v1, &v2, &v3, &v4);
+		m_color.setCmykColorF(v1, value() / (double) maximum(), v3, v4);
+		break;
+	case Mode::CMYKYellow:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelCMYK);
+		m_color.getCMYK(&v1, &v2, &v3, &v4);
+		m_color.setCmykColorF(v1, v2, value() / (double) maximum(), v4);
+		break;
+	case Mode::CMYKKey:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelCMYK);
+		m_color.getCMYK(&v1, &v2, &v3, &v4);
+		m_color.setCmykColorF(v1, v2, v3, value() / (double) maximum());
+		break;
+	case Mode::HSVHue:
+	{
+		QColor color = ScColorEngine::getRGBColor(m_color, m_doc);
+		color.setHslF(value() / (double) maximum(), color.saturationF(), color.valueF());
+		m_color.fromQColor(color);
+		break;
+	}
+	case Mode::HSVSaturation:
+	{
+		QColor color = ScColorEngine::getRGBColor(m_color, m_doc);
+		color.setHslF(color.hslHueF(), value() / (double) maximum(), color.valueF());
+		m_color.fromQColor(color);
+		break;
+	}
+	case Mode::HSVValue:
+	{
+		QColor color = ScColorEngine::getRGBColor(m_color, m_doc);
+		color.setHslF(color.hslHueF(), color.saturationF(), value() / (double) maximum());
+		m_color.fromQColor(color);
+		break;
+	}
+	case Mode::HLCHue:
+	{
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelLab);
+		m_color.getLab(&v1, &v2, &v3);
+		QLineF lin(QPointF(0.0, 0.0), QPointF(v2, v3));
+		lin = QLineF::fromPolar(lin.length(), 360 - value());
+		m_color.setLabColor(v1, lin.p2().x(), lin.p2().y());
+		break;
+	}
+	case Mode::HLCChroma:
+	{
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelLab);
+		m_color.getLab(&v1, &v2, &v3);
+		QLineF lin(QPointF(0.0, 0.0), QPointF(v2, v3));
+		lin = QLineF::fromPolar(value(), lin.angle());
+		m_color.setLabColor(v1, lin.p2().x(), lin.p2().y());
+		break;
+	}
+	case Mode::HLCLightness:
+	case Mode::LabLightness:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelLab);
+		m_color.getLab(&v1, &v2, &v3);
+		m_color.setLabColor(value(), v2, v3);
+		break;
+	case Mode::LabA:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelLab);
+		m_color.getLab(&v1, &v2, &v3);
+		m_color.setLabColor(v1, value(), v3);
+		break;
+	case Mode::LabB:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelLab);
+		m_color.getLab(&v1, &v2, &v3);
+		m_color.setLabColor(v1, v2, value());
+		break;
+	case Mode::RGBRed:
+	case Mode::RGBWebRed:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelRGB);
+		m_color.getRGB(&v1, &v2, &v3);
+		m_color.setRgbColorF(QSlider::value() / (double) maximum(), v2, v3);
+		break;
+	case Mode::RGBGreen:
+	case Mode::RGBWebGreen:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelRGB);
+		m_color.getRGB(&v1, &v2, &v3);
+		m_color.setRgbColorF(v1, QSlider::value() / (double) maximum(), v3);
+		break;
+	case Mode::RGBBlue:
+	case Mode::RGBWebBlue:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelRGB);
+		m_color.getRGB(&v1, &v2, &v3);
+		m_color.setRgbColorF(v1, v2, QSlider::value() / (double) maximum());
+		break;
+	}
+
+	emit colorChanged(m_color);
+}
+
+void ColorSlider::setup()
+{
+	disconnectSlots();
+
+	switch (m_mode)
+	{
+	default:
+	case Mode::Opacity:
+	case Mode::CMYKCyan:
+	case Mode::CMYKMagenta:
+	case Mode::CMYKYellow:
+	case Mode::CMYKKey:
+	case Mode::HSVSaturation:
+	case Mode::HSVValue:
+	case Mode::HLCLightness:
+	case Mode::LabLightness:
+	case Mode::Shade:
+		setMinimum(0);
+		setMaximum(100);
+		setTickInterval(4);
+		m_colorSteps = 100;
+		break;
+	case Mode::HSVHue:
+	case Mode::HLCHue:
+		setMinimum(0);
+		setMaximum(359);
+		setTickInterval(6);
+		m_colorSteps = 359;
+		break;
+	case Mode::LabA:
+	case Mode::LabB:
+		setMinimum(-128);
+		setMaximum(128);
+		setTickInterval(4);
+		m_colorSteps = 256;
+		break;
+	case Mode::HLCChroma:
+		setMinimum(0);
+		setMaximum(128);
+		setTickInterval(4);
+		m_colorSteps = 128;
+		break;
+	case Mode::RGBRed:
+	case Mode::RGBGreen:
+	case Mode::RGBBlue:
+		setMinimum(0);
+		setMaximum(255);
+		setTickInterval(2);
+		m_colorSteps = 255;
+		break;
+	case Mode::RGBWebRed:
+	case Mode::RGBWebGreen:
+	case Mode::RGBWebBlue:
+		setMinimum(0);
+		setMaximum(255);
+		setTickInterval(5);
+		m_colorSteps = 5;
+		break;
+	}
+
+	setSingleStep(maximum() / m_colorSteps);
+	setPageStep(maximum() / m_colorSteps);
+
+	connectSlots();
+}
+
+void ColorSlider::connectSlots()
+{
+	connect(this, &QSlider::valueChanged, this, &ColorSlider::updateColor);
+}
+
+void ColorSlider::disconnectSlots()
+{
+	disconnect(this, &QSlider::valueChanged, this, &ColorSlider::updateColor);
+}
+
+void ColorSlider::renderMap()
+{
+	if (!m_doc || !isVisible())
+		return;
+
+	QRect rect;
+	QPoint pEnd;
+	QColor color = ScColorEngine::getDisplayColor(m_color, m_doc);
+
+	if (orientation() == Qt::Horizontal)
+	{
+		rect = QRect(0, 0, width(), 1);
+		pEnd = rect.topRight();
+	}
+	else
+	{
+		rect = QRect(0, 0, 1, height());
+		pEnd = rect.bottomLeft();
+	}
+
+	m_background = QImage(rect.width(), rect.height(), QImage::Format_ARGB32);
+	m_background.fill(Qt::transparent);
+
+	QPainter p(&m_background);
+	p.setPen(Qt::NoPen);
+
+	// For opacity and shade we can use simple linear gradients
+	if (m_mode == Mode::Opacity || m_mode == Mode::Shade)
+	{
+		QLinearGradient grad = QLinearGradient(QPoint(0, 0), pEnd);
+
+		switch (m_mode)
+		{
+		case Mode::Opacity:
+		{
+			QColor colorA = color;
+			colorA.setAlphaF(0);
+			grad.setColorAt(0, colorA);
+			grad.setColorAt(1, color);
+			p.setBrush(grad);
+			p.drawRect(m_background.rect());
+			break;
+		}
+		default:
+		case Mode::Shade:
+		{
+			grad.setColorAt(0, Qt::white);
+			grad.setColorAt(1, color);
+			p.setBrush(grad);
+			p.drawRect(m_background.rect());
+			break;
+		}
+		}
+	}
+	else
+	{
+		double l, a, b;
+		int c, m, y, k, red, green, blue;
+		int length = qMax(rect.width(), rect.height());
+		int step = qMax(1, (length - RADIUS * 2) / m_colorSteps); // it must be at leat 1 (px)
+
+		// CMYK
+		CMYKColor cmyk;
+		ScColorEngine::getCMYKValues(m_color, m_doc, cmyk);
+		cmyk.getValues(c, m, y, k);
+
+		// RGB
+		RGBColor rgb;
+		ScColorEngine::getRGBValues(m_color, m_doc, rgb);
+		rgb.getValues(red, green, blue);
+
+		// Lab / HLC
+		ScColor sColor = ScColorEngine::convertToModel(m_color, m_doc, colorModelLab);
+		sColor.getLab(&l, &a, &b);
+		QLineF lin(QPointF(0.0, 0.0), QPointF(a, b));
+		double H = lin.angle();
+		double C = lin.length();
+
+		for (int x = 0; x <= length; x += step)
+		{
+			switch (m_mode)
+			{
+			default:
+			case Mode::CMYKCyan:
+			{
+				int val = qRound(((orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length) * 255);
+				if (isDynamic())
+					color = ScColorEngine::getDisplayColorGC(ScColor(val, m, y, k), m_doc);
+				else
+					color = ScColorEngine::getDisplayColorGC(ScColor(val, 0, 0, 0), m_doc);
+			}
+			break;
+			case Mode::CMYKMagenta:
+			{
+				int val = qRound(((orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length) * 255);
+				if (isDynamic())
+					color = ScColorEngine::getDisplayColorGC(ScColor(c, val, y, k), m_doc);
+				else
+					color = ScColorEngine::getDisplayColorGC(ScColor(0, val, 0, 0), m_doc);
+			}
+			break;
+			case Mode::CMYKYellow:
+			{
+				int val = qRound(((orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length) * 255);
+				if (isDynamic())
+					color = ScColorEngine::getDisplayColorGC(ScColor(c, m, val, k), m_doc);
+				else
+					color = ScColorEngine::getDisplayColorGC(ScColor(0, 0, val, 0), m_doc);
+			}
+			break;
+			case Mode::CMYKKey:
+			{
+				int val = qRound(((orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length) * 255);
+				if (isDynamic())
+					color = ScColorEngine::getDisplayColorGC(ScColor(c, m, y, val), m_doc);
+				else
+					color = ScColorEngine::getDisplayColorGC(ScColor(0, 0, 0, val), m_doc);
+			}
+			break;
+			case Mode::HLCHue:
+			{
+				qreal val = (orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length;
+				lin = QLineF::fromPolar(C, -360 * val);
+				if (isDynamic())
+					color = ScColorEngine::getDisplayColorGC(ScColor(l, lin.p2().x(), lin.p2().y()), m_doc);
+				else
+					color = ScColorEngine::getDisplayColorGC(ScColor(100.0, lin.p2().x(), lin.p2().y()), m_doc);
+			}
+			break;
+			case Mode::HLCChroma:
+			{
+				qreal val = (orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length;
+				lin = QLineF::fromPolar(128 * val, H);
+				if (isDynamic())
+					color = ScColorEngine::getDisplayColorGC(ScColor(l, lin.p2().x(), lin.p2().y()), m_doc);
+				else
+					color = ScColorEngine::getDisplayColorGC(ScColor(100.0, lin.p2().x(), lin.p2().y()), m_doc);
+			}
+			break;
+			case Mode::HLCLightness:
+			case Mode::LabLightness:
+			{
+				qreal val = ((orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length) * 100.0;
+				if (isDynamic())
+					color = ScColorEngine::getDisplayColorGC(ScColor(val, a, b), m_doc);
+				else
+					color = ScColorEngine::getDisplayColorGC(ScColor(val, 0.0, 0.0), m_doc);
+			}
+			break;
+			case Mode::LabA:
+			{
+				qreal val = ((orientation() == Qt::Horizontal) ? -(0.5 - qreal(x) / length) : (0.5 - qreal(x) / length)) * 255.;
+				if (isDynamic())
+					color = ScColorEngine::getDisplayColorGC(ScColor(l, val, b), m_doc);
+				else
+					color = ScColorEngine::getDisplayColorGC(ScColor(0.0, val, 0.0), m_doc);
+			}
+			break;
+			case Mode::LabB:
+			{
+				qreal val = ((orientation() == Qt::Horizontal) ? -(0.5 - qreal(x) / length) : (0.5 - qreal(x) / length)) * 255.;
+				if (isDynamic())
+					color = ScColorEngine::getDisplayColorGC(ScColor(l, a, val), m_doc);
+				else
+					color = ScColorEngine::getDisplayColorGC(ScColor(0.0, 0.0, val), m_doc);
+			}
+			break;
+			case Mode::RGBRed:
+			case Mode::RGBWebRed:
+			{
+				int val = qRound(((orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length) * 255);
+				if (isDynamic())
+					color = ScColorEngine::getDisplayColorGC(ScColor(val, green, blue), m_doc);
+				else
+					color = ScColorEngine::getDisplayColorGC(ScColor(val, 0, 0), m_doc);
+			}
+			break;
+			case Mode::RGBGreen:
+			case Mode::RGBWebGreen:
+			{
+				int val = qRound(((orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length) * 255);
+				if (isDynamic())
+					color = ScColorEngine::getDisplayColorGC(ScColor(red, val, blue), m_doc);
+				else
+					color = ScColorEngine::getDisplayColorGC(ScColor(0, val, 0), m_doc);
+			}
+			break;
+			case Mode::RGBBlue:
+			case Mode::RGBWebBlue:
+			{
+				int val = qRound(((orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length) * 255);
+				if (isDynamic())
+					color = ScColorEngine::getDisplayColorGC(ScColor(red, green, val), m_doc);
+				else
+					color = ScColorEngine::getDisplayColorGC(ScColor(0, 0, val), m_doc);
+			}
+			break;
+			case Mode::HSVHue:
+			{
+				qreal val = (orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length;
+				if (isDynamic())
+					color.setHsvF(val, color.saturationF(), color.valueF());
+				else
+					color.setHsvF(val, 1.0, 0.5);
+			}
+			break;
+			case Mode::HSVSaturation:
+			{
+				qreal val = (orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length;
+				if (isDynamic())
+					color.setHsvF(color.hueF(), val, color.valueF());
+				else
+					color.setHsvF(0.0, val, 0.5);
+			}
+			break;
+			case Mode::HSVValue:
+			{
+				qreal val = (orientation() == Qt::Horizontal) ? qreal(x) / length : 1. - qreal(x) / length;
+				if (isDynamic())
+					color.setHsvF(color.hueF(), color.saturationF(), val);
+				else
+					color.setHsvF(0.0, 1.0, val);
+			}
+			break;
+			}
+
+			int w = (x == 0) ? step + RADIUS : step;
+			int o = (x == 0) ? 0 : RADIUS;
+
+			p.setBrush(color);
+			p.drawRect((orientation() == Qt::Horizontal) ? QRect(o + x - step / 2, 0, w, 1) : QRect(0, o + x - step / 2, 1, w));
+		}
+	}
+	p.end();
+
+}
+
+void ColorSlider::updateValues()
+{
+	if (!m_doc)
+		return;
+
+	disconnectSlots();
+
+	QSignalBlocker blocker(this);
+
+	double v1, v2, v3, v4;
+
+	switch (m_mode)
+	{
+	case Mode::Opacity:
+		setValue(m_opacity);
+		break;
+	case Mode::Shade:
+		setValue(m_shade);
+		break;
+	case Mode::CMYKCyan:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelCMYK);
+		m_color.getCMYK(&v1, &v2, &v3, &v4);
+		setValue(v1 * maximum());
+		break;
+	case Mode::CMYKMagenta:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelCMYK);
+		m_color.getCMYK(&v1, &v2, &v3, &v4);
+		setValue(v2 * maximum());
+		break;
+	case Mode::CMYKYellow:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelCMYK);
+		m_color.getCMYK(&v1, &v2, &v3, &v4);
+		setValue(v3 * maximum());
+		break;
+	case Mode::CMYKKey:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelCMYK);
+		m_color.getCMYK(&v1, &v2, &v3, &v4);
+		setValue(v4 * maximum());
+		break;
+	case Mode::HSVHue:
+		setValue(ScColorEngine::getRGBColor(m_color, m_doc).hueF() * maximum());
+		break;
+	case Mode::HSVSaturation:
+		setValue(ScColorEngine::getRGBColor(m_color, m_doc).saturationF() * maximum());
+		break;
+	case Mode::HSVValue:
+		setValue(ScColorEngine::getRGBColor(m_color, m_doc).valueF() * maximum());
+		break;
+	case Mode::HLCHue:
+	{
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelLab);
+		m_color.getLab(&v1, &v2, &v3);
+		QLineF lin(QPointF(0.0, 0.0), QPointF(v2, v3));
+		setValue(360 - lin.angle());
+		break;
+	}
+	case Mode::HLCChroma:
+	{
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelLab);
+		m_color.getLab(&v1, &v2, &v3);
+		QLineF lin(QPointF(0.0, 0.0), QPointF(v2, v3));
+		setValue(lin.length());
+		break;
+	}
+	case Mode::HLCLightness:
+	case Mode::LabLightness:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelLab);
+		m_color.getLab(&v1, &v2, &v3);
+		setValue(v1);
+		break;
+	case Mode::LabA:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelLab);
+		m_color.getLab(&v1, &v2, &v3);
+		setValue(v2);
+		break;
+	case Mode::LabB:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelLab);
+		m_color.getLab(&v1, &v2, &v3);
+		setValue(v3);
+		break;
+	case Mode::RGBWebRed:
+	case Mode::RGBRed:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelRGB);
+		m_color.getRGB(&v1, &v2, &v3);
+		setValue(v1 * maximum());
+		break;
+	case Mode::RGBWebGreen:
+	case Mode::RGBGreen:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelRGB);
+		m_color.getRGB(&v1, &v2, &v3);
+		setValue(v2 * maximum());
+		break;
+	case Mode::RGBWebBlue:
+	case Mode::RGBBlue:
+		m_color = ScColorEngine::convertToModel(m_color, m_doc, colorModelRGB);
+		m_color.getRGB(&v1, &v2, &v3);
+		setValue(v3 * maximum());
+		break;
+	}
+
+	connectSlots();
+}
+
+/* ********************************************************************************* *
+ *
+ * Events
+ *
+ * ********************************************************************************* */
+
+void ColorSlider::resizeEvent(QResizeEvent *e)
+{
+	QWidget::resizeEvent(e);
+
+	if (e->oldSize() != e->size())
+		renderMap();
+}
+
+void ColorSlider::showEvent(QShowEvent *e)
+{
+	QWidget::showEvent(e);
+	renderMap();
+}
+
+void ColorSlider::mouseMoveEvent(QMouseEvent *e)
+{
+	if (e->buttons() & Qt::LeftButton)
+	{
+		switch (m_mode)
+		{
+		// Override slider movement for custom steps
+		case Mode::RGBWebBlue:
+		case Mode::RGBWebGreen:
+		case Mode::RGBWebRed:
+			setSliderPosition(pixelPosToRangeValue(e->pos()));
+			break;
+		default:
+			QSlider::mouseMoveEvent(e);
+			break;
+		}
+
+		return;
+	}
+
+	QSlider::mouseMoveEvent(e);
+}
+
+int ColorSlider::pixelPosToRangeValue(QPoint pt) const
+{
+	int pos, sliderMin, sliderMax;
+	if (orientation() == Qt::Horizontal)
+	{
+		pos = pt.x();
+		sliderMin = rect().x();
+		sliderMax = rect().right() - RADIUS * 2 + 1;
+	}
+	else
+	{
+		pos = pt.y();
+		sliderMin = rect().y();
+		sliderMax = rect().bottom() - RADIUS * 2 + 1;
+	}
+
+	return roundToStep(QStyle::sliderValueFromPosition(minimum(), maximum(), pos - sliderMin, sliderMax - sliderMin));
+}
+
diff --git a/scribus/ui/widgets/color_slider.h b/scribus/ui/widgets/color_slider.h
new file mode 100644
index 000000000..b497f18bd
--- /dev/null
+++ b/scribus/ui/widgets/color_slider.h
@@ -0,0 +1,115 @@
+/***************************************************************************
+ *                                                                         *
+ *   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) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+/*
+For general Scribus copyright and licensing information please refer
+to the COPYING file provided with the program.
+*/
+#ifndef COLOR_SLIDER_H
+#define COLOR_SLIDER_H
+
+#include <QPointer>
+#include <QSlider>
+#include "sccolor.h"
+#include "scribusapi.h"
+
+class QPaintEvent;
+class QWidget;
+class ScribusDoc;
+
+class SCRIBUS_API ColorSlider : public QSlider
+{
+    Q_OBJECT
+
+friend class ScribusProxyStyle;
+
+public:
+	enum Mode
+	{
+		RGBRed = 0,
+		RGBGreen,
+		RGBBlue,
+		RGBWebRed,
+		RGBWebGreen,
+		RGBWebBlue,
+		LabLightness,
+		LabA,
+		LabB,
+		CMYKCyan,
+		CMYKMagenta,
+		CMYKYellow,
+		CMYKKey,
+		HLCHue,
+		HLCLightness,
+		HLCChroma,
+		HSVHue,
+		HSVSaturation,
+		HSVValue,
+		Shade,
+		Opacity
+	};
+
+	ColorSlider(QWidget* parent = nullptr);
+	ColorSlider(Mode mode, QWidget* parent = nullptr);
+
+	ScColor color() { return m_color; }
+	double opacity() { return m_opacity; } // 0.0 - 100.0
+	double shade() { return m_shade; } // 0.0 - 100.0
+	Mode mode() { return m_mode; }
+	bool isDynamic() { return m_dynamicColor; }
+
+public slots:
+	void setDoc(ScribusDoc *doc);
+    void setMode(ColorSlider::Mode mode);
+	void setValues(const QString &colorName, double opacity, double shade);
+	void setValues(ScColor color, double opacity, double shade);
+	void setColor(const QString &colorName);
+	void setColor(ScColor color);
+	void setShade(double shade);
+	void setOpacity(double opacity);
+	void setIsDynamic(double dynamic);
+
+private slots:
+	void updateColor();
+
+protected:
+    void resizeEvent(QResizeEvent* e);
+	void showEvent(QShowEvent *e);
+	void mouseMoveEvent(QMouseEvent *e);
+
+private:
+	QPointer<ScribusDoc> m_doc;
+    QGradientStops m_stops;
+    ScColor m_color;
+	double m_opacity {100.0}; // full opacity
+	double m_shade {100.0}; // no shade
+	int m_colorSteps {100};
+	bool m_dynamicColor {true};
+	Mode m_mode {RGBRed};
+    QImage m_background;
+
+	int pixelPosToRangeValue(QPoint pos) const;
+	int roundToStep(int value) const
+	{
+		int mod = maximum() / m_colorSteps;
+		return (value / mod) * mod;
+	}
+
+    void setup();
+    void connectSlots();
+    void disconnectSlots();
+
+    void renderMap();
+    void updateValues();
+
+signals:
+    void colorChanged(ScColor);
+
+};
+
+#endif // COLOR_SLIDER_H
diff --git a/scribus/util_gui.h b/scribus/util_gui.h
index 4ed63b819..9ec661438 100644
--- a/scribus/util_gui.h
+++ b/scribus/util_gui.h
@@ -9,6 +9,8 @@ class VGradient;
 class VColorStop;
 class ScPattern;
 
+const int RADIUS = 6;
+
 void SCRIBUS_API drawCircularHandle(QPainter * painter, QPointF center, qreal width, QBrush background, bool isEnabled = true);
 void SCRIBUS_API drawPointerHandle(QPainter * painter, QPointF pointer, qreal width, QColor background, bool isEnabled = true, bool isEmpty = false);
 void SCRIBUS_API renderCheckerPattern(QPainter *painter, QRectF rect);
