View Issue Details

IDProjectCategoryView StatusLast Update
0017277ScribusUser Interfacepublic2024-09-24 22:31
Reporternitramr Assigned Tonitramr  
PrioritynormalSeverityminorReproducibilityN/A
Status resolvedResolutionfixed 
PlatformDesktop PCOSUbuntuOS Version24.04 64-bit
Product Version1.7.0.svn 
Target Version1.7.0Fixed in Version1.7.0.svn 
Summary0017277: ColorButton preview is not highres
DescriptionThe rendered preview of the color button is pixelated in screens with devicePixelRatio > 1.

I add a fix in util_gui to scale up the image size by devicePixelRatio before rendering.
TagsNo tags attached.
PatchYes

Activities

nitramr

2024-09-21 19:44

developer  

utilgui_2024-09-21_01.patch (10,394 bytes)   
Index: scribus/util_gui.h
===================================================================
--- scribus/util_gui.h	(Revision 26308)
+++ scribus/util_gui.h	(Arbeitskopie)
@@ -16,6 +16,7 @@
 void SCRIBUS_API drawNodeHandle(QPainter *painter, QPointF point, QPen pen, qreal scaleFactor, bool isActive = false);
 void SCRIBUS_API drawNodeControl(QPainter *painter, QPointF point, QPen pen, qreal scaleFactor, bool isActive = false);
 void SCRIBUS_API drawWeldMarker(QPainter *painter, QPointF point, QColor color, qreal scaleFactor);
+void SCRIBUS_API drawColorBox(QPainter * painter, QRect rect, QColor color, bool isEnabled = true);
 QPixmap SCRIBUS_API renderEmptyPattern(QSize size);
 QPixmap SCRIBUS_API renderColor(QSize size, QColor color, QColor colorShade, double alpha = 1.0);
 QPixmap SCRIBUS_API renderGradientLinear(QSize size, const VGradient& gradient);
@@ -27,6 +28,8 @@
 QPixmap SCRIBUS_API renderGradientPatchMesh(QSize size);
 QPixmap SCRIBUS_API renderHatch(QSize size, int type, double distance, double angle, bool hasBackground, QColor backgroundColor, QColor foregroundColor);
 QPixmap SCRIBUS_API renderPattern(QSize size, const ScPattern& pattern);
+QPixmap SCRIBUS_API combinePixmaps(const QPixmap& background, const QPixmap& foreground, bool tintForeground, bool isDarkColor);
+bool SCRIBUS_API isDarkColor(QColor color);
 
 // Helper
 VColorStop SCRIBUS_API computeInBetweenStop(const VColorStop* last, const VColorStop* actual, double t);
Index: scribus/util_gui.cpp
===================================================================
--- scribus/util_gui.cpp	(Revision 26308)
+++ scribus/util_gui.cpp	(Arbeitskopie)
@@ -28,6 +28,15 @@
 	painter->setPen(QPen(ScQApp->palette().color(isEnabled ? QPalette::Active : QPalette::Disabled, QPalette::WindowText), 1));
 	painter->drawEllipse(center, radius, radius);
 
+	painter->restore();
+}
+
+void drawColorBox(QPainter *painter, QRect rect, QColor color, bool isEnabled)
+{
+	painter->save();
+	painter->setBrush(color);
+	painter->setPen(QPen(ScQApp->palette().color(isEnabled ? QPalette::Active : QPalette::Disabled, QPalette::WindowText), 1));
+	painter->drawRect(rect.adjusted(0, 0, -1, -1));
 	painter->restore();
 }
 
@@ -150,6 +159,7 @@
 {
 	alpha = qBound(0., alpha, 1.);
 
+	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 	double mid = 0.5;
@@ -174,7 +184,8 @@
 		shadeAlpha = shadeSolid;
 	}
 
-	QPixmap pixmap(w, h);
+	QPixmap pixmap(w * scale, h * scale);
+	pixmap.setDevicePixelRatio(scale);
 	pixmap.fill(Qt::transparent);
 
 	QPainter p(&pixmap);
@@ -194,13 +205,18 @@
 
 QPixmap renderEmptyPattern(QSize size)
 {
-	QPixmap pixmap(size.width(), size.height());
+	double scale = qApp->devicePixelRatio();
+	int w = size.width();
+	int h = size.height();
+
+	QPixmap pixmap(w * scale, h * scale);
+	pixmap.setDevicePixelRatio(scale);
 	pixmap.fill(Qt::white);
 
 	QPainter p(&pixmap);
 	p.setRenderHint(QPainter::Antialiasing, true);
 	p.setPen(QPen(QBrush(Qt::red), 2));
-	p.drawLine(QPoint(0, size.height()), QPoint(size.width(), 0));
+	p.drawLine(QPoint(0, h), QPoint(w, 0));
 	p.end();
 
 	return pixmap;
@@ -208,13 +224,15 @@
 
 QPixmap renderGradientLinear(QSize size, const VGradient& gradient)
 {
-	int w = size.width();
-	int h = size.height();
-
-	QImage pixm(w, h, QImage::Format_ARGB32_Premultiplied);
-	pixm.fill(Qt::transparent);
-
-	ScPainter *p = new ScPainter(&pixm, w, h);
+	double scale = qApp->devicePixelRatio();
+	int w = size.width();
+	int h = size.height();
+
+	QImage pixm(w * scale, h * scale, QImage::Format_ARGB32_Premultiplied);
+	pixm.setDevicePixelRatio(scale);
+	pixm.fill(Qt::transparent);
+
+	ScPainter *p = new ScPainter(&pixm, w * scale, h * scale);
 	p->setPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
 	p->setFillMode(ScPainter::Gradient);
 	p->fill_gradient = gradient;
@@ -228,15 +246,17 @@
 
 QPixmap renderGradientRadial(QSize size, const VGradient& gradient)
 {
+	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 	qreal wHalf = w / 2;
 	qreal hHalf = h / 2;
 
-	QImage pixm(w, h, QImage::Format_ARGB32_Premultiplied);
-	pixm.fill(Qt::transparent);
-
-	ScPainter *p = new ScPainter(&pixm, w, h);
+	QImage pixm(w * scale, h * scale, QImage::Format_ARGB32_Premultiplied);
+	pixm.setDevicePixelRatio(scale);
+	pixm.fill(Qt::transparent);
+
+	ScPainter *p = new ScPainter(&pixm, w * scale, h * scale);
 	p->setPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
 	p->setFillMode(ScPainter::Gradient);
 	p->fill_gradient = gradient;
@@ -250,6 +270,7 @@
 
 QPixmap renderGradientConical(QSize size, const VGradient& gradient)
 {
+	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 	qreal wHalf = w / 2;
@@ -258,7 +279,8 @@
 	QConicalGradient grad(wHalf, hHalf, 0);
 	grad.setStops(gradient.toQGradientStops());
 
-	QImage pixm(w, h, QImage::Format_ARGB32_Premultiplied);
+	QImage pixm(w * scale, h * scale, QImage::Format_ARGB32_Premultiplied);
+	pixm.setDevicePixelRatio(scale);
 	pixm.fill(Qt::transparent);
 
 	QPainter p(&pixm);
@@ -274,13 +296,15 @@
 
 QPixmap renderGradient4Colors(QSize size, QColor col1, QColor col2, QColor col3, QColor col4)
 {
-	int w = size.width();
-	int h = size.height();
-
-	QImage pixm(w, h, QImage::Format_ARGB32_Premultiplied);
-	pixm.fill(Qt::transparent);
-
-	ScPainter *p = new ScPainter(&pixm, w, h);
+	double scale = qApp->devicePixelRatio();
+	int w = size.width();
+	int h = size.height();
+
+	QImage pixm(w * scale, h * scale, QImage::Format_ARGB32_Premultiplied);
+	pixm.setDevicePixelRatio(scale);
+	pixm.fill(Qt::transparent);
+
+	ScPainter *p = new ScPainter(&pixm, w * scale, h * scale);
 	p->setPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
 	p->setFillMode(ScPainter::Gradient);
 	p->fill_gradient = VGradient();
@@ -295,13 +319,15 @@
 
 QPixmap renderGradientDiamond(QSize size, const VGradient& gradient)
 {
-	int w = size.width();
-	int h = size.height();
-
-	QImage pixm(w, h, QImage::Format_ARGB32_Premultiplied);
-	pixm.fill(Qt::transparent);
-
-	ScPainter *p = new ScPainter(&pixm, w, h);
+	double scale = qApp->devicePixelRatio();
+	int w = size.width();
+	int h = size.height();
+
+	QImage pixm(w * scale, h * scale, QImage::Format_ARGB32_Premultiplied);
+	pixm.setDevicePixelRatio(scale);
+	pixm.fill(Qt::transparent);
+
+	ScPainter *p = new ScPainter(&pixm, w * scale, h * scale);
 	p->setPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
 	p->setFillMode(ScPainter::Gradient);
 	p->fill_gradient = gradient;
@@ -315,6 +341,7 @@
 
 QPixmap renderGradientMesh(QSize size)
 {
+	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int w25 = w * .25;
 	int w50 = w * .5;
@@ -324,7 +351,8 @@
 	int h50 = h * .5;
 	int h75 = h * .75;
 
-	QImage pixm(w, h, QImage::Format_ARGB32_Premultiplied);
+	QImage pixm(w * scale, h * scale, QImage::Format_ARGB32_Premultiplied);
+	pixm.setDevicePixelRatio(scale);
 	pixm.fill(Qt::transparent);
 
 	QPainter p(&pixm);
@@ -352,13 +380,15 @@
 
 QPixmap renderHatch(QSize size, int type, double distance, double angle, bool hasBackground, QColor backgroundColor, QColor foregroundColor)
 {
-	int w = size.width();
-	int h = size.height();
-
-	QImage pixm(w, h, QImage::Format_ARGB32_Premultiplied);
-	pixm.fill(Qt::transparent);
-
-	ScPainter *p = new ScPainter(&pixm, w, h);
+	double scale = qApp->devicePixelRatio();
+	int w = size.width();
+	int h = size.height();
+
+	QImage pixm(w * scale, h * scale, QImage::Format_ARGB32_Premultiplied);
+	pixm.setDevicePixelRatio(scale);
+	pixm.fill(Qt::transparent);
+
+	ScPainter *p = new ScPainter(&pixm, w * scale, h * scale);
 	p->setPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
 	p->setFillMode(ScPainter::Hatch);
 	p->setHatchParameters(type, distance, angle, hasBackground, backgroundColor, foregroundColor, w, h);
@@ -371,12 +401,14 @@
 
 QPixmap renderPattern(QSize size, const ScPattern& pattern)
 {
+	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 	int pW = pattern.getPattern().width();
 	int pH = pattern.getPattern().height();
 
-	QImage pixm(w, h, QImage::Format_ARGB32_Premultiplied);
+	QImage pixm(w * scale, h * scale, QImage::Format_ARGB32_Premultiplied);
+	pixm.setDevicePixelRatio(scale);
 	pixm.fill(Qt::transparent);
 
 	Qt::TransformationMode tm = Qt::FastTransformation;
@@ -391,11 +423,43 @@
 	else
 		img = pattern.getPattern().scaledToHeight(h, tm);
 
-	QPainter *qp = new QPainter(&pixm);
-	qp->setPen(Qt::NoPen);
-	qp->drawImage(w / 2 - img.width() / 2, h / 2 - img.height() / 2, img);
-	qp->end();
-	delete qp;
+	QPainter qp(&pixm);
+	qp.setPen(Qt::NoPen);
+	qp.drawImage(w / 2 - img.width() / 2, h / 2 - img.height() / 2, img);
+	qp.end();
+
+	return QPixmap::fromImage(pixm);
+}
+
+QPixmap combinePixmaps(const QPixmap &background, const QPixmap &foreground, bool tintForeground, bool isDarkColor)
+{
+	double scale = qApp->devicePixelRatio();
+	int w = qMax(background.deviceIndependentSize().width(), foreground.deviceIndependentSize().width());
+	int h = qMax(background.deviceIndependentSize().height(), foreground.deviceIndependentSize().height());
+
+	QImage pixm(w * scale, h * scale, QImage::Format_ARGB32_Premultiplied);
+	pixm.setDevicePixelRatio(scale);
+	pixm.fill(Qt::transparent);
+
+	QRect frame(0, 0, w, h);
+
+	QRect rB(0, 0, background.deviceIndependentSize().width(), background.deviceIndependentSize().height());
+	rB.moveCenter(frame.center());
+
+	QRect rF(0, 0, foreground.deviceIndependentSize().width(), foreground.deviceIndependentSize().height());
+	rF.moveCenter(frame.center());
+
+	QPainter p;
+	p.begin(&pixm);
+	p.drawPixmap(rF, foreground);
+	p.setCompositionMode( tintForeground ? QPainter::CompositionMode_SourceIn : QPainter::CompositionMode_SourceOut);
+	p.drawPixmap(rB, background);
+	p.end();
+
+	p.begin(&pixm);
+	p.setCompositionMode(QPainter::CompositionMode_DestinationAtop);
+	p.fillRect(frame, isDarkColor? Qt::white : Qt::black);
+	p.end();
 
 	return QPixmap::fromImage(pixm);
 }
@@ -445,3 +509,9 @@
 
 	return blendColor(opacity, fg, bg);
 }
+
+bool isDarkColor(QColor color) {
+	// sRGB luminance(Y) values
+	double lum = 0.2126 * color.redF() + 0.7152 * color.greenF() + 0.0722 * color.blueF();
+	return color.alphaF() > 0 && lum <= 0.65; // It is a dark color if the luminance is below 65%
+}
utilgui_2024-09-21_01.patch (10,394 bytes)   

jghali

2024-09-21 20:15

administrator   ~0051379

Your are still making the assumption of single screen configuration in that patch. The device pixel ratio should ideally be obtained directly from the base QWidget/QPaintDevice, qApp returns the highest screen device pixel ratio found on the system in case of multiple screens configuration according to Qt doc.

nitramr

2024-09-21 20:56

developer   ~0051380

Thanks for the hint. I can make a change, but unfortunately I can't test with different device pixel ratio of multiple screens on the same computer.

BN_Dev

2024-09-22 11:15

reporter   ~0051381

I would be happy to test this and provide some screenshots

nitramr

2024-09-22 14:36

developer   ~0051383

Ok, I set the scale factor as a parameter in util_gui.

Now, the color button passes the widget's scale factor to the render functions. Because of this, some other places had to be updated as well.
At the moment, I have no idea if the scale factor of a widget needs to be updated on the screenChanged() event. Currently, I haven't used this event anywhere.

What is the patch supposed to change? The image resolution of each color button is equal to the screen scale factor of the screen the color button is on. There is probably little difference between "normal" scale factors, like 100%, 200%, however the color button should look good even at 150% and other fractal scales.

BTW: Some other changes to the color button are also included in this patch. It was difficult for me to exclude them. The color button now supports icons and has an extended tooltip.
colorbutton_2024-09-22_01.patch (34,726 bytes)   
Index: scribus/iconmanager.cpp
===================================================================
--- scribus/iconmanager.cpp	(Revision 26310)
+++ scribus/iconmanager.cpp	(Arbeitskopie)
@@ -433,13 +433,8 @@
 
 		QSvgRenderer svgRenderer(document.toByteArray());
 
-		QSize size = svgRenderer.defaultSize();
+		QSize size = (width > -1) ? QSize(width, width) : svgRenderer.defaultSize();
 		QPixmap *iconPixmap = new QPixmap(size * m_devicePixelRatio);
-		if (width > -1)
-		{
-			iconPixmap = new QPixmap(iconPixmap->scaledToWidth(width * m_devicePixelRatio, Qt::SmoothTransformation));
-			size = iconPixmap->size() / m_devicePixelRatio;
-		}
 		iconPixmap->setDevicePixelRatio(m_devicePixelRatio);
 		iconPixmap->fill(Qt::transparent);
 
Index: scribus/ui/colorpicker/colorpicker_color.cpp
===================================================================
--- scribus/ui/colorpicker/colorpicker_color.cpp	(Revision 26310)
+++ scribus/ui/colorpicker/colorpicker_color.cpp	(Arbeitskopie)
@@ -119,10 +128,50 @@
 	if (isMask)
 		return QString( tr("Opacity: %1 %").arg(op) );
 
-	QString name = m_color.Name.isEmpty() ? CommonStrings::tr_None : m_color.Name;
-	QString shade = sh < 100 ? QString(", Shade: %1 %").arg(sh) : "";
-	QString opacity = op < 100 ? QString(", Opacity: %1 %").arg(op) : "";
-	return QString( tr("Color: %1%2%3").arg(name).arg(shade).arg(opacity) );
+	QString name = CommonStrings::tr_None;
+	QString shade = sh < 100 ? QString( tr("<br> Shade: %1 %")).arg(sh) : "";
+	QString opacity = op < 100 ? QString( tr("<br> Opacity: %1 %")).arg(op) : "";
+
+	if (!m_color.Name.isEmpty())
+	{
+		QString colorValues = "";
+
+		if (m_doc->PageColors.contains(m_color.Name))
+		{
+			ScColor color = m_doc->PageColors.value(m_color.Name);
+
+			switch (color.getColorModel())
+			{
+			case colorModelRGB:
+			{
+				int r, g, b;
+				color.getRawRGBColor(&r, &g, &b);
+				colorValues = tr("R: %1 G: %2 B: %3").arg(r).arg(g).arg(b);
+			}
+				break;
+			case colorModelCMYK:
+			{
+				double c, m, y, k;
+				color.getCMYK(&c, &m, &y, &k);
+				colorValues = tr("C: %1% M: %2% Y: %3% K: %4%").arg(c * 100, 0, 'f', 2).arg(m * 100, 0, 'f', 2).arg(y * 100, 0, 'f', 2).arg(k * 100, 0, 'f', 2);
+			}
+				break;
+			case colorModelLab:
+			{
+				double L, a, b;
+				color.getLab(&L, &a, &b);
+				colorValues = tr("L: %1 a: %2 b: %3").arg(L, 0, 'f', 2).arg(a, 0, 'f', 2).arg(b, 0, 'f', 2);
+			}
+				break;
+			}
+		}
+		else
+			colorValues = CommonStrings::tr_None;
+
+		name = QString( tr("Color: %1 (%2)")).arg(m_color.Name, colorValues);
+	}
+
+	return QString("%1%2%3").arg(name, shade, opacity);
 }
 
 /* ********************************************************************************* *
Index: scribus/ui/colorpicker/colorpicker_gradient.cpp
===================================================================
--- scribus/ui/colorpicker/colorpicker_gradient.cpp	(Revision 26310)
+++ scribus/ui/colorpicker/colorpicker_gradient.cpp	(Arbeitskopie)
@@ -487,13 +487,13 @@
 	m_gradient.Color4Shade = numberColor4Shade->value();
 
 	// render color buttons
-	buttonColor1->setBackground(colorBrush(buttonColor1->backgroundDotSize(), m_gradient.Color1Name, m_gradient.Color1Shade, m_gradient.Color1Alpha));
+	buttonColor1->setBrush(colorBrush(buttonColor1->circleSize(), m_gradient.Color1Name, m_gradient.Color1Shade, m_gradient.Color1Alpha));
 	buttonColor1->setToolTip(m_gradient.Color1Name);
-	buttonColor2->setBackground(colorBrush(buttonColor2->backgroundDotSize(), m_gradient.Color2Name, m_gradient.Color2Shade, m_gradient.Color2Alpha));
+	buttonColor2->setBrush(colorBrush(buttonColor2->circleSize(), m_gradient.Color2Name, m_gradient.Color2Shade, m_gradient.Color2Alpha));
 	buttonColor2->setToolTip(m_gradient.Color2Name);
-	buttonColor3->setBackground(colorBrush(buttonColor3->backgroundDotSize(), m_gradient.Color3Name, m_gradient.Color3Shade, m_gradient.Color3Alpha));
+	buttonColor3->setBrush(colorBrush(buttonColor3->circleSize(), m_gradient.Color3Name, m_gradient.Color3Shade, m_gradient.Color3Alpha));
 	buttonColor3->setToolTip(m_gradient.Color3Name);
-	buttonColor4->setBackground(colorBrush(buttonColor4->backgroundDotSize(), m_gradient.Color4Name, m_gradient.Color4Shade, m_gradient.Color4Alpha));
+	buttonColor4->setBrush(colorBrush(buttonColor4->circleSize(), m_gradient.Color4Name, m_gradient.Color4Shade, m_gradient.Color4Alpha));
 	buttonColor4->setToolTip(m_gradient.Color4Name);
 
 	updateGradient();
@@ -510,7 +510,7 @@
 	m_gradientMesh.Opacity = numberColorMeshAlpha->value() / 100.0;
 
 	// render color button
-	buttonColorMesh->setBackground(colorBrush(buttonColorMesh->backgroundDotSize(), m_gradientMesh.Name, m_gradientMesh.Shade, m_gradientMesh.Opacity));
+	buttonColorMesh->setBrush(colorBrush(buttonColorMesh->circleSize(), m_gradientMesh.Name, m_gradientMesh.Shade, m_gradientMesh.Opacity));
 	buttonColorMesh->setToolTip(m_gradientMesh.Name);
 
 	if (gradientEditPropertiesEnabled() && (type() == Gradient_PatchMesh || type() == Gradient_Mesh))
@@ -678,13 +678,13 @@
 	QSignalBlocker sigButtonColor2(buttonColor2);
 	QSignalBlocker sigButtonColor3(buttonColor3);
 	QSignalBlocker sigButtonColor4(buttonColor4);
-	buttonColor1->setBackground(colorBrush(buttonColor1->backgroundDotSize(), color1, m_gradient.Color1Shade, m_gradient.Color1Alpha));
+	buttonColor1->setBrush(colorBrush(buttonColor1->circleSize(), color1, m_gradient.Color1Shade, m_gradient.Color1Alpha));
 	buttonColor1->setToolTip(color1);
-	buttonColor2->setBackground(colorBrush(buttonColor2->backgroundDotSize(), color2, m_gradient.Color2Shade, m_gradient.Color2Alpha));
+	buttonColor2->setBrush(colorBrush(buttonColor2->circleSize(), color2, m_gradient.Color2Shade, m_gradient.Color2Alpha));
 	buttonColor2->setToolTip(color2);
-	buttonColor3->setBackground(colorBrush(buttonColor3->backgroundDotSize(), color3, m_gradient.Color3Shade, m_gradient.Color3Alpha));
+	buttonColor3->setBrush(colorBrush(buttonColor3->circleSize(), color3, m_gradient.Color3Shade, m_gradient.Color3Alpha));
 	buttonColor3->setToolTip(color3);
-	buttonColor4->setBackground(colorBrush(buttonColor4->backgroundDotSize(), color4, m_gradient.Color4Shade, m_gradient.Color4Alpha));
+	buttonColor4->setBrush(colorBrush(buttonColor4->circleSize(), color4, m_gradient.Color4Shade, m_gradient.Color4Alpha));
 	buttonColor4->setToolTip(color4);
 
 }
@@ -705,7 +705,7 @@
 	m_gradientMesh.Opacity = alpha;
 
 	QSignalBlocker sigMeshColor(buttonColorMesh);
-	buttonColorMesh->setBackground(colorBrush(buttonColorMesh->backgroundDotSize(), m_gradientMesh.Name, m_gradientMesh.Shade, m_gradientMesh.Opacity));
+	buttonColorMesh->setBrush(colorBrush(buttonColorMesh->circleSize(), m_gradientMesh.Name, m_gradientMesh.Shade, m_gradientMesh.Opacity));
 	buttonColorMesh->setToolTip(m_gradientMesh.Name);
 }
 
@@ -717,7 +717,7 @@
 QBrush ColorPickerGradient::colorBrush(QSize size, QString colorName, double shade, double opacity) const
 {
 	if (!m_doc || colorName == CommonStrings::tr_NoneColor || colorName == CommonStrings::None)
-		return renderEmptyPattern(size);
+		return renderEmptyPattern(size, devicePixelRatio());
 
 	ScColor sColor(0, 0, 0);
 
@@ -730,7 +730,7 @@
 	QColor qColorShade = ScColorEngine::getDisplayColor(sColor, m_doc, shade);
 	QColor qColor = ScColorEngine::getDisplayColor(sColor, m_doc, 100.0);
 
-	return renderColor(size, qColor, qColorShade, opacity);
+	return renderColor(size, devicePixelRatio(), qColor, qColorShade, opacity);
 }
 
 void ColorPickerGradient::updateGradient()
Index: scribus/ui/colorpicker/colorpicker_hatch.cpp
===================================================================
--- scribus/ui/colorpicker/colorpicker_hatch.cpp	(Revision 26310)
+++ scribus/ui/colorpicker/colorpicker_hatch.cpp	(Arbeitskopie)
@@ -107,9 +107,9 @@
 	else
 		listBackgroundSwatches->setCurrentColor(CommonStrings::None);
 
-	buttonLineColor->setBackground( colorBrush(buttonLineColor->backgroundDotSize(), m_hatch.ColorForeground) );
+	buttonLineColor->setBrush( colorBrush(buttonLineColor->circleSize(), m_hatch.ColorForeground) );
 	buttonLineColor->setToolTip(m_hatch.ColorForeground);
-	buttonBackgroundColor->setBackground( colorBrush(buttonBackgroundColor->backgroundDotSize(), m_hatch.ColorBackground) );
+	buttonBackgroundColor->setBrush( colorBrush(buttonBackgroundColor->circleSize(), m_hatch.ColorBackground) );
 	buttonBackgroundColor->setToolTip(m_hatch.ColorBackground);
 
 	connectSlots();
@@ -172,9 +172,9 @@
 	m_hatch.Distance = hatchDist->value() / unitGetRatioFromIndex(currentUnit);
 	m_hatch.Type = hatchType->currentIndex();
 
-	buttonLineColor->setBackground( colorBrush(buttonLineColor->backgroundDotSize(), m_hatch.ColorForeground) );
+	buttonLineColor->setBrush( colorBrush(buttonLineColor->circleSize(), m_hatch.ColorForeground) );
 	buttonLineColor->setToolTip(m_hatch.ColorForeground);
-	buttonBackgroundColor->setBackground( colorBrush(buttonBackgroundColor->backgroundDotSize(), m_hatch.ColorBackground) );
+	buttonBackgroundColor->setBrush( colorBrush(buttonBackgroundColor->circleSize(), m_hatch.ColorBackground) );
 	buttonBackgroundColor->setToolTip(m_hatch.ColorBackground);
 
 	emit hatchChanged();
@@ -197,9 +197,9 @@
 QBrush ColorPickerHatch::colorBrush(QSize size, QString colorName, double shade, double opacity) const
 {
 	if (!m_doc || colorName == CommonStrings::tr_NoneColor || colorName == CommonStrings::None)
-		return renderEmptyPattern(size);
+		return renderEmptyPattern(size, devicePixelRatio());
 
-	return renderColor(size, colorFromName(colorName, 100.0), colorFromName(colorName, shade), opacity);
+	return renderColor(size, devicePixelRatio(), colorFromName(colorName, 100.0), colorFromName(colorName, shade), opacity);
 }
 
 
Index: scribus/ui/colorpicker/colorpicker_pattern.cpp
===================================================================
--- scribus/ui/colorpicker/colorpicker_pattern.cpp	(Revision 26310)
+++ scribus/ui/colorpicker/colorpicker_pattern.cpp	(Arbeitskopie)
@@ -115,7 +115,7 @@
 	for (int a = 0; a < patK.count(); a++)
 	{
 		ScPattern sp = docPatterns->value(patK[a]);
-		QListWidgetItem *item = new QListWidgetItem(renderPattern(listPattern->iconSize(), sp), patK[a], listPattern);
+		QListWidgetItem *item = new QListWidgetItem(renderPattern(listPattern->iconSize(), devicePixelRatio(), sp), patK[a], listPattern);
 		item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
 	}
 	listPattern->clearSelection();
Index: scribus/ui/gradienteditor.cpp
===================================================================
--- scribus/ui/gradienteditor.cpp	(Revision 26310)
+++ scribus/ui/gradienteditor.cpp	(Arbeitskopie)
@@ -197,7 +197,7 @@
 	QBrush brush;
 
 	if (colorName == CommonStrings::tr_NoneColor || colorName == CommonStrings::None)
-		brush = renderEmptyPattern(buttonColor->backgroundDotSize());
+		brush = renderEmptyPattern(buttonColor->circleSize(), devicePixelRatio());
 	else
 	{
 		const ScColor& color = m_colorList[colorName];
@@ -205,10 +205,10 @@
 		QColor qColorShade = ScColorEngine::getDisplayColor(color, m_colorList.document(), stopShade->value());
 		QColor qColor = ScColorEngine::getDisplayColor(color, m_colorList.document(), 100.0);
 
-		brush = QBrush(renderColor(buttonColor->backgroundDotSize(), qColor, qColorShade, stopOpacity->value() / 100.0));
+		brush = QBrush(renderColor(buttonColor->circleSize(), devicePixelRatio(), qColor, qColorShade, stopOpacity->value() / 100.0));
 	}
 
-	buttonColor->setBackground(brush);
+	buttonColor->setBrush(brush);
 }
 
 void GradientEditor::initExtend()
Index: scribus/ui/linestyleselector.cpp
===================================================================
--- scribus/ui/linestyleselector.cpp	(Revision 26310)
+++ scribus/ui/linestyleselector.cpp	(Arbeitskopie)
@@ -84,7 +84,7 @@
 
 		lineStyles->sortItems();
 		lineStyles->insertItem( 0, tr("No Style"));
-		lineStyles->item(0)->setIcon(QIcon(renderEmptyPattern(m_size)));
+		lineStyles->item(0)->setIcon(QIcon(renderEmptyPattern(m_size, devicePixelRatio())));
 
 		if (lineStyles->currentItem())
 			lineStyles->currentItem()->setSelected(false);
Index: scribus/ui/propertiespalette_fill.cpp
===================================================================
--- scribus/ui/propertiespalette_fill.cpp	(Revision 26310)
+++ scribus/ui/propertiespalette_fill.cpp	(Arbeitskopie)
@@ -729,10 +729,8 @@
 	evenOdd->setIcon(im.loadIcon("fill-rule-even-odd.png"));
 	nonZero->setIcon(im.loadIcon("fill-rule-nonzero.png"));
 
-	if (labelFillMask->labelVisibility())
-		buttonFillMask->setIcon(QIcon());
-	else
-		buttonFillMask->setIcon(im.loadIcon("mask", 8));
+	buttonFillMask->setDotIcon(im.loadIcon("mask", 8));
+
 }
 
 void PropertiesPalette_Fill::languageChange()
@@ -753,8 +751,8 @@
 	labelFillMask->setLabelVisibility(v);
 	labelFillRule->setLabelVisibility(v);
 	labelBlendmode->setLabelVisibility(v);
+	buttonFillMask->setHasDot(!v);
 
-	iconSetChange();
 }
 
 
Index: scribus/ui/propertiespalette_line.cpp
===================================================================
--- scribus/ui/propertiespalette_line.cpp	(Revision 26310)
+++ scribus/ui/propertiespalette_line.cpp	(Arbeitskopie)
@@ -840,12 +840,8 @@
 	buttonCapSquare->setIcon(im.loadIcon("16/stroke-cap-square.png"));
 
 	buttonSwapMarker->setIcon(im.loadIcon("swap"));
+	buttonLineMask->setDotIcon(im.loadIcon("mask", 8));
 
-	if (lineMaskLabel->labelVisibility())
-		buttonLineMask->setIcon(QIcon());
-	else
-		buttonLineMask->setIcon(im.loadIcon("mask", 8));
-
 }
 
 void PropertiesPalette_Line::languageChange()
@@ -927,6 +923,5 @@
 	lineMarkerLabel->setLabelVisibility(v);
 	lineMaskLabel->setLabelVisibility(v);
 	lineBlendmodeLabel->setLabelVisibility(v);
-
-	iconSetChange();
+	buttonLineMask->setHasDot(!v);
 }
Index: scribus/ui/widgets/color_button.cpp
===================================================================
--- scribus/ui/widgets/color_button.cpp	(Revision 26310)
+++ scribus/ui/widgets/color_button.cpp	(Arbeitskopie)
@@ -39,7 +39,7 @@
 	return m_hasDot;
 }
 
-QSize ColorButton::backgroundDotSize() const
+QSize ColorButton::circleSize() const
 {
 	int smallestSize = qMin(height(), width());
 
@@ -46,7 +46,7 @@
 	return QSize(smallestSize, smallestSize);
 }
 
-QSize ColorButton::foregroundDotSize() const
+QSize ColorButton::dotSize() const
 {
 	int smallestSize = 12;
 
@@ -93,32 +93,32 @@
 		return nullptr;
 }
 
-void ColorButton::setBackground(QBrush background)
+void ColorButton::setBrush(QBrush brush)
 {
-	m_background = background;
+	m_brush = brush;
 	update();
 }
 
-QBrush ColorButton::background() const
+QBrush ColorButton::brush() const
 {
 	if (isEnabled())
-		return m_background;
+		return m_brush;
 	else
 		return QBrush(palette().color(QPalette::Window));
 }
 
 
-void ColorButton::setForeground(QBrush foreground)
+void ColorButton::setDotBrush(QBrush brush)
 {
-	m_foreground = foreground;
+	m_dotBrush = brush;
 	if (m_hasDot)
 		update();
 }
 
-QBrush ColorButton::foreground() const
+QBrush ColorButton::dotBrush() const
 {
 	if (isEnabled())
-		return m_foreground;
+		return m_dotBrush;
 	else
 		return QBrush(palette().color(QPalette::Window));
 }
@@ -344,14 +344,6 @@
 	return ScColorEngine::getDisplayColor(sColor, m_doc, shade);
 }
 
-QBrush ColorButton::colorBrush(QSize size, QString colorName, double shade, double opacity) const
-{
-	if (!m_doc || colorName == CommonStrings::tr_NoneColor || colorName == CommonStrings::None)
-		return renderEmptyPattern(size);
-
-	return renderColor(size, colorFromName(colorName, 100.0), colorFromName(colorName, shade), opacity);
-}
-
 Context ColorButton::context() const
 {
 	return m_context;
@@ -392,7 +384,12 @@
 QBrush ColorButton::brushSolid() const
 {
 	if (!m_doc || m_colorData.Name == CommonStrings::tr_NoneColor || m_colorData.Name == CommonStrings::None)
-		return renderEmptyPattern(this->size());
+	{
+		if (icon().isNull())
+			return renderEmptyPattern(this->size(), devicePixelRatio());
+		else
+			return combinePixmaps(renderEmptyPattern(this->size(), devicePixelRatio()), icon().pixmap(iconSize()), devicePixelRatio(), m_onIcon, false);
+	}
 
 	ScColor sColor(0, 0, 0);
 
@@ -399,18 +396,23 @@
 	if (m_doc->PageColors.contains(m_colorData.Name))
 		sColor = m_doc->PageColors.value(m_colorData.Name);
 
+	QColor qColorShade = ScColorEngine::getDisplayColor(sColor, m_doc, m_colorData.Shade);
+	QColor qColor = ScColorEngine::getDisplayColor(sColor, m_doc, 100.0);
+	QPixmap pBackground(renderColor(this->size(), devicePixelRatio(), qColor, qColorShade, 1 - m_colorData.Opacity));
+
 	// simulate grey tone for mask color
 	if (isMask())
 	{
-		QColor qColor = ScColorEngine::getDisplayColor(sColor, m_doc, m_colorData.Opacity * 100.0);
-		return renderColor(this->size(), qColor, qColor, 1);
+		qColor = ScColorEngine::getDisplayColor(sColor, m_doc, m_colorData.Opacity * 100.0);
+		qColorShade = qColor;
+		pBackground = renderColor(this->size(), devicePixelRatio(), qColor, qColor, 1);
 	}
+
+	if (icon().isNull())
+		return pBackground;
 	else
-	{
-		QColor qColorShade = ScColorEngine::getDisplayColor(sColor, m_doc, m_colorData.Shade);
-		QColor qColor = ScColorEngine::getDisplayColor(sColor, m_doc, 100.0);
-		return renderColor(this->size(), qColor, qColorShade, 1 - m_colorData.Opacity);
-	}
+		return combinePixmaps(pBackground, icon().pixmap(iconSize()), devicePixelRatio(), m_onIcon, isDarkColor(qColor));
+
 }
 
 QBrush ColorButton::brushGradient() const
@@ -422,11 +424,11 @@
 		default:
 		case GradMask_Linear:
 		case GradMask_LinearLumAlpha:
-			return QBrush(renderGradientLinear(this->size(), gradientData().Gradient));
+			return QBrush(renderGradientLinear(this->size(), devicePixelRatio(), gradientData().Gradient));
 			break;
 		case GradMask_Radial:
 		case GradMask_RadialLumAlpha:
-			return QBrush(renderGradientRadial(this->size(), gradientData().Gradient));
+			return QBrush(renderGradientRadial(this->size(), devicePixelRatio(), gradientData().Gradient));
 			break;
 		}
 	}
@@ -435,16 +437,16 @@
 		switch(type())
 		{
 		case Gradient_Linear:
-			return QBrush(renderGradientLinear(this->size(), gradientData().Gradient));
+			return QBrush(renderGradientLinear(this->size(), devicePixelRatio(), gradientData().Gradient));
 			break;
 		case Gradient_Radial:
-			return QBrush(renderGradientRadial(this->size(), gradientData().Gradient));
+			return QBrush(renderGradientRadial(this->size(), devicePixelRatio(), gradientData().Gradient));
 			break;
 		case Gradient_Diamond:
-			return QBrush(renderGradientDiamond(this->size(), gradientData().Gradient));
+			return QBrush(renderGradientDiamond(this->size(), devicePixelRatio(), gradientData().Gradient));
 			break;
 		case Gradient_Conical:
-			return QBrush(renderGradientConical(this->size(), gradientData().Gradient));
+			return QBrush(renderGradientConical(this->size(), devicePixelRatio(), gradientData().Gradient));
 			break;
 		case Gradient_4Colors:
 		{
@@ -489,14 +491,14 @@
 				}
 			}
 
-			return QBrush(renderGradient4Colors(this->size(), color1, color2, color3, color4));
+			return QBrush(renderGradient4Colors(this->size(), devicePixelRatio(), color1, color2, color3, color4));
 		}
 			break;
 		case Gradient_Mesh:
-			return QBrush(renderGradientMesh(this->size()));
+			return QBrush(renderGradientMesh(this->size(), devicePixelRatio()));
 			break;
 		case Gradient_PatchMesh:
-			return QBrush(renderGradientPatchMesh(this->size()));
+			return QBrush(renderGradientPatchMesh(this->size(), devicePixelRatio()));
 			break;
 		}
 	}
@@ -518,7 +520,7 @@
 	if (m_hatchData.ColorBackground != CommonStrings::None)
 		bg = colorFromName(m_hatchData.ColorBackground, 100.0);
 
-	return renderHatch(this->size(),
+	return renderHatch(this->size(), devicePixelRatio(),
 					   m_hatchData.Type,
 					   m_hatchData.Distance,
 					   m_hatchData.Angle,
@@ -536,7 +538,10 @@
 	if (!m_doc->docPatterns.contains(m_patternData.Name))
 		return QBrush();
 
-	return QBrush(pattern().getPattern());
+	QImage img = pattern().getPattern();
+	img.setDevicePixelRatio(qApp->devicePixelRatio());
+
+	return QBrush(img);
 }
 
 void ColorButton::setType(int type)
@@ -545,6 +550,30 @@
 	setModeByType(type);
 }
 
+void ColorButton::setPersistentToolTip(const QString &tooltip)
+{
+	m_persistenToolTip = tooltip;
+	buildToolTip();
+}
+
+void ColorButton::setIcon(const QIcon &icon)
+{
+	QToolButton::setIcon(icon);
+	updatePreview();
+}
+
+void ColorButton::setDotIcon(const QIcon &icon)
+{
+	m_dotIcon = icon;
+	update();
+}
+
+void ColorButton::setApplyColorOnIcon(bool onIcon)
+{
+	m_onIcon = onIcon;
+	updatePreview();
+}
+
 void ColorButton::setDoc(ScribusDoc *doc)
 {
 	m_doc = doc;
@@ -558,7 +587,7 @@
 
 void ColorButton::updatePreview()
 {
-	setBackground(renderBrush());
+	setBrush(renderBrush());
 }
 
 void ColorButton::updateFloatingContext()
@@ -614,7 +643,8 @@
 			setType(colorPicker->type());
 			setGeneralData(colorPicker->generalData());
 			setColorData(colorPicker->colorData());
-			setToolTip(colorPicker->toolTipText());
+			m_dynamicToolTip = colorPicker->toolTipText();
+			buildToolTip();
 			updatePreview();
 			emit changed();
 			emit colorChanged();
@@ -631,7 +661,8 @@
 			setType(colorPicker->type());
 			setGeneralData(colorPicker->generalData());
 			setGradientData(colorPicker->gradientData());
-			setToolTip(colorPicker->toolTipText());
+			m_dynamicToolTip = colorPicker->toolTipText();
+			buildToolTip();
 			updatePreview();
 			emit changed();
 			emit gradientChanged();
@@ -674,7 +705,8 @@
 			setType(colorPicker->type());
 			setGeneralData(colorPicker->generalData());
 			setHatchData(colorPicker->hatchData());
-			setToolTip(colorPicker->toolTipText());
+			m_dynamicToolTip = colorPicker->toolTipText();
+			buildToolTip();
 			updatePreview();
 			emit changed();
 			emit hatchChanged();
@@ -691,7 +723,8 @@
 			setType(colorPicker->type());
 			setGeneralData(colorPicker->generalData());
 			setPatternData(colorPicker->patternData());
-			setToolTip(colorPicker->toolTipText());
+			m_dynamicToolTip = colorPicker->toolTipText();
+			buildToolTip();
 			updatePreview();
 			emit changed();
 			emit patternChanged();
@@ -717,6 +750,12 @@
 
 }
 
+void ColorButton::buildToolTip()
+{
+	QString sb = (m_persistenToolTip.isEmpty() || m_dynamicToolTip.isEmpty()) ? "" : "<br/>";
+	QString tt = "<html><head/><body><p>" + m_persistenToolTip + sb + m_dynamicToolTip + "</p></body></html>";
+	setToolTip(tt);
+}
 
 /* ********************************************************************************* *
  *
@@ -731,8 +770,8 @@
 	QPainter painter(this);
 	painter.setRenderHint(QPainter::Antialiasing, true);
 
-	QSize bSize = backgroundDotSize();
-	QSize fSize = foregroundDotSize();
+	QSize bSize = circleSize();
+	QSize fSize = dotSize();
 	QPainterPath mask;
 
 	int inset = 1;
@@ -744,10 +783,10 @@
 	renderCheckerPattern(&painter, mask.boundingRect());
 	painter.setClipping(false);
 
-	drawCircularHandle(&painter, bDot.center(), bSize.width() - inset, background(), isEnabled());
+	drawCircularHandle(&painter, bDot.center(), bSize.width() - inset, brush(), isEnabled());
 
 	// Draw Foreground Dot
-	if (m_hasDot && icon().isNull())
+	if (m_hasDot && dotIcon().isNull())
 	{
 		mask.clear();
 		QRectF fDot(rect().right() - fSize.width() + 0.5, rect().bottom() - fSize.height() + 0.5, fSize.width(), fSize.height()); // bottom right corner
@@ -756,17 +795,17 @@
 		renderCheckerPattern(&painter, mask.boundingRect());
 		painter.setClipping(false);
 
-		drawCircularHandle(&painter, fDot.center(), fDot.width(), foreground(), isEnabled());
+		drawCircularHandle(&painter, fDot.center(), fDot.width(), dotBrush(), isEnabled());
 	}
 
 	// Draw Icon
-	if (!icon().isNull())
+	if (m_hasDot && !dotIcon().isNull())
 	{
 		QIcon::Mode iMode = isEnabled() ? QIcon::Normal : QIcon::Disabled;
 
 		int w = 8;
 		int h = 8;
-		QPixmap pix = icon().pixmap(QSize(w, h), iMode);
+		QPixmap pix = dotIcon().pixmap(QSize(w, h), iMode);
 		QRectF fDot(rect().right() - fSize.width() + 0.5, rect().bottom() - fSize.height() + 0.5, fSize.width(), fSize.height()); // bottom right corner
 		painter.setPen(QPen(palette().color(QPalette::WindowText)));
 		painter.setBrush(palette().color(QPalette::Base));
@@ -776,3 +815,4 @@
 
 	painter.end();
 }
+
Index: scribus/ui/widgets/color_button.h
===================================================================
--- scribus/ui/widgets/color_button.h	(Revision 26310)
+++ scribus/ui/widgets/color_button.h	(Arbeitskopie)
@@ -38,8 +38,8 @@
 	void setHasDot(bool enabled);
 	bool hasDot() const;
 
-	QSize backgroundDotSize() const;
-	QSize foregroundDotSize() const;
+	QSize circleSize() const;
+	QSize dotSize() const;
 
 	/*!
 	 * \brief Set type of context to show on click event, e.g. floating or list.
@@ -105,6 +105,17 @@
 	void setType(int type);
 	int type() const { return m_type; };
 
+	void setPersistentToolTip(const QString& tooltip);
+	QString persistentToolTip() const { return m_persistenToolTip; };
+
+	void setIcon(const QIcon &icon);
+
+	void setDotIcon(const QIcon &icon);
+	QIcon dotIcon() const { return m_dotIcon; };
+
+	void setApplyColorOnIcon(bool onIcon);
+	bool applyColorOnIcon() { return m_onIcon; };
+
 	void updatePreview();
 	void unsetDoc();
 
@@ -118,8 +129,8 @@
 public slots:
 	void setDoc(ScribusDoc *doc);
 
-	void setBackground(QBrush background);
-	void setForeground(QBrush foreground);
+	void setBrush(QBrush brush);
+	void setDotBrush(QBrush brush);
 
 	void toggleFloatingContext();
 	void updateFloatingContext();
@@ -134,8 +145,8 @@
 	void updateColorPicker(ColorPicker *colorPicker);
 
 private:
-	QBrush m_background {Qt::NoBrush};
-	QBrush m_foreground {Qt::NoBrush};
+	QBrush m_brush {Qt::NoBrush};
+	QBrush m_dotBrush {Qt::NoBrush};
 	bool m_hasDot {false};
 	QWidget *stickyWidget {nullptr};
 	FloatingWindow *floatingWidget {nullptr};
@@ -154,14 +165,17 @@
 	bool m_isMask {false};
 	int m_type {0};
 	bool m_ignoreItemType {true};
+	bool m_onIcon {false};
+	QString m_persistenToolTip {QString()};
+	QString m_dynamicToolTip {QString()};
+	QIcon m_dotIcon {QIcon()};
 
-	QBrush background() const;
-	QBrush foreground() const;
+	QBrush brush() const;
+	QBrush dotBrush() const;
 	QBrush renderBrush() const;
 	bool isMask() const;
 	void setModeByType(int type);
 	QColor colorFromName(QString colorName, double shade) const;
-	QBrush colorBrush(QSize size, QString colorName, double shade = 100.0, double opacity = 1.0) const;
 
 	QBrush brushSolid() const;
 	QBrush brushGradient() const;
@@ -171,6 +185,7 @@
 protected:
 
 	void paintEvent(QPaintEvent *e);
+	void buildToolTip();
 
 signals:
 	void changed();
Index: scribus/ui/widgets/combo_linestyle.cpp
===================================================================
--- scribus/ui/widgets/combo_linestyle.cpp	(Revision 26310)
+++ scribus/ui/widgets/combo_linestyle.cpp	(Arbeitskopie)
@@ -73,7 +73,7 @@
 
 	m_list->sortItems();
 	m_list->insertItem( 0, tr("No Style"));
-	m_list->item(0)->setIcon(QIcon(renderEmptyPattern(m_size)));
+	m_list->item(0)->setIcon(QIcon(renderEmptyPattern(m_size, devicePixelRatio())));
 
 	index = (m_list->count() >= 0 && index < m_list->count()) ? index : 0;
 	this->setCurrentIndex(index);
Index: scribus/util_gui.cpp
===================================================================
--- scribus/util_gui.cpp	(Revision 26310)
+++ scribus/util_gui.cpp	(Arbeitskopie)
@@ -67,9 +67,9 @@
 
 	// Draw color
 	if(isEmpty)
-		painter->drawPixmap(rect, renderEmptyPattern(rect.size()) );
+		painter->drawPixmap(rect, renderEmptyPattern(rect.size(), painter->device()->devicePixelRatio()) );
 	else
-		painter->drawPixmap(rect, renderColor(rect.size(), background, background, 1) );
+		painter->drawPixmap(rect, renderColor(rect.size(), painter->device()->devicePixelRatio(), background, background, 1) );
 
 	// Draw light border
 	painter->setBrush(Qt::NoBrush);
@@ -155,11 +155,10 @@
 	painter->drawImage(rect, pattern);
 }
 
-QPixmap renderColor(QSize size, QColor color, QColor colorShade, double alpha)
+QPixmap renderColor(QSize size, double scale, QColor color, QColor colorShade, double alpha)
 {
 	alpha = qBound(0., alpha, 1.);
 
-	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 	double mid = 0.5;
@@ -203,9 +202,8 @@
 	return pixmap;
 }
 
-QPixmap renderEmptyPattern(QSize size)
+QPixmap renderEmptyPattern(QSize size, double scale)
 {
-	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 
@@ -222,9 +220,8 @@
 	return pixmap;
 }
 
-QPixmap renderGradientLinear(QSize size, const VGradient& gradient)
+QPixmap renderGradientLinear(QSize size, double scale, const VGradient& gradient)
 {
-	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 
@@ -244,9 +241,8 @@
 	return QPixmap::fromImage(pixm);
 }
 
-QPixmap renderGradientRadial(QSize size, const VGradient& gradient)
+QPixmap renderGradientRadial(QSize size, double scale, const VGradient& gradient)
 {
-	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 	qreal wHalf = w / 2;
@@ -268,9 +264,8 @@
 	return QPixmap::fromImage(pixm);
 }
 
-QPixmap renderGradientConical(QSize size, const VGradient& gradient)
+QPixmap renderGradientConical(QSize size, double scale, const VGradient& gradient)
 {
-	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 	qreal wHalf = w / 2;
@@ -294,9 +289,8 @@
 	return QPixmap::fromImage(pixm);
 }
 
-QPixmap renderGradient4Colors(QSize size, QColor col1, QColor col2, QColor col3, QColor col4)
+QPixmap renderGradient4Colors(QSize size, double scale, QColor col1, QColor col2, QColor col3, QColor col4)
 {
-	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 
@@ -317,9 +311,8 @@
 	return QPixmap::fromImage(pixm);
 }
 
-QPixmap renderGradientDiamond(QSize size, const VGradient& gradient)
+QPixmap renderGradientDiamond(QSize size, double scale, const VGradient& gradient)
 {
-	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 
@@ -339,9 +332,8 @@
 	return QPixmap::fromImage(pixm);
 }
 
-QPixmap renderGradientMesh(QSize size)
+QPixmap renderGradientMesh(QSize size, double scale)
 {
-	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int w25 = w * .25;
 	int w50 = w * .5;
@@ -373,14 +365,13 @@
 	return QPixmap::fromImage(pixm);
 }
 
-QPixmap renderGradientPatchMesh(QSize size)
+QPixmap renderGradientPatchMesh(QSize size, double scale)
 {
-	return renderGradientMesh(size);
+	return renderGradientMesh(size, scale);
 }
 
-QPixmap renderHatch(QSize size, int type, double distance, double angle, bool hasBackground, QColor backgroundColor, QColor foregroundColor)
+QPixmap renderHatch(QSize size, double scale, int type, double distance, double angle, bool hasBackground, QColor backgroundColor, QColor foregroundColor)
 {
-	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 
@@ -399,9 +390,8 @@
 	return QPixmap::fromImage(pixm);
 }
 
-QPixmap renderPattern(QSize size, const ScPattern& pattern)
+QPixmap renderPattern(QSize size, double scale, const ScPattern& pattern)
 {
-	double scale = qApp->devicePixelRatio();
 	int w = size.width();
 	int h = size.height();
 	int pW = pattern.getPattern().width();
@@ -431,9 +421,8 @@
 	return QPixmap::fromImage(pixm);
 }
 
-QPixmap combinePixmaps(const QPixmap &background, const QPixmap &foreground, bool tintForeground, bool isDarkColor)
+QPixmap combinePixmaps(const QPixmap &background, const QPixmap &foreground, double scale, bool tintForeground, bool isDarkColor)
 {
-	double scale = qApp->devicePixelRatio();
 	int w = qMax(background.deviceIndependentSize().width(), foreground.deviceIndependentSize().width());
 	int h = qMax(background.deviceIndependentSize().height(), foreground.deviceIndependentSize().height());
 
Index: scribus/util_gui.h
===================================================================
--- scribus/util_gui.h	(Revision 26310)
+++ scribus/util_gui.h	(Arbeitskopie)
@@ -17,18 +17,18 @@
 void SCRIBUS_API drawNodeControl(QPainter *painter, QPointF point, QPen pen, qreal scaleFactor, bool isActive = false);
 void SCRIBUS_API drawWeldMarker(QPainter *painter, QPointF point, QColor color, qreal scaleFactor);
 void SCRIBUS_API drawColorBox(QPainter * painter, QRect rect, QColor color, bool isEnabled = true);
-QPixmap SCRIBUS_API renderEmptyPattern(QSize size);
-QPixmap SCRIBUS_API renderColor(QSize size, QColor color, QColor colorShade, double alpha = 1.0);
-QPixmap SCRIBUS_API renderGradientLinear(QSize size, const VGradient& gradient);
-QPixmap SCRIBUS_API renderGradientRadial(QSize size, const VGradient& gradient);
-QPixmap SCRIBUS_API renderGradientConical(QSize size, const VGradient& gradient);
-QPixmap SCRIBUS_API renderGradient4Colors(QSize size, QColor col1, QColor col2, QColor col3, QColor col4);
-QPixmap SCRIBUS_API renderGradientDiamond(QSize size, const VGradient& gradient);
-QPixmap SCRIBUS_API renderGradientMesh(QSize size);
-QPixmap SCRIBUS_API renderGradientPatchMesh(QSize size);
-QPixmap SCRIBUS_API renderHatch(QSize size, int type, double distance, double angle, bool hasBackground, QColor backgroundColor, QColor foregroundColor);
-QPixmap SCRIBUS_API renderPattern(QSize size, const ScPattern& pattern);
-QPixmap SCRIBUS_API combinePixmaps(const QPixmap& background, const QPixmap& foreground, bool tintForeground, bool isDarkColor);
+QPixmap SCRIBUS_API renderEmptyPattern(QSize size, double scale);
+QPixmap SCRIBUS_API renderColor(QSize size, double scale, QColor color, QColor colorShade, double alpha = 1.0);
+QPixmap SCRIBUS_API renderGradientLinear(QSize size, double scale, const VGradient& gradient);
+QPixmap SCRIBUS_API renderGradientRadial(QSize size, double scale, const VGradient& gradient);
+QPixmap SCRIBUS_API renderGradientConical(QSize size, double scale, const VGradient& gradient);
+QPixmap SCRIBUS_API renderGradient4Colors(QSize size, double scale, QColor col1, QColor col2, QColor col3, QColor col4);
+QPixmap SCRIBUS_API renderGradientDiamond(QSize size, double scale, const VGradient& gradient);
+QPixmap SCRIBUS_API renderGradientMesh(QSize size, double scale);
+QPixmap SCRIBUS_API renderGradientPatchMesh(QSize size, double scale);
+QPixmap SCRIBUS_API renderHatch(QSize size, double scale, int type, double distance, double angle, bool hasBackground, QColor backgroundColor, QColor foregroundColor);
+QPixmap SCRIBUS_API renderPattern(QSize size, double scale, const ScPattern& pattern);
+QPixmap SCRIBUS_API combinePixmaps(const QPixmap& background, const QPixmap& foreground, double scale, bool tintForeground, bool isDarkColor);
 bool SCRIBUS_API isDarkColor(QColor color);
 
 // Helper
colorbutton_2024-09-22_01.patch (34,726 bytes)   

BN_Dev

2024-09-22 16:00

reporter   ~0051384

OK I am getting setup with your patch now. For context, my laptop is running a modern Plasma on Wayland. It has 2 built-in 4K touchscreens; and I have used the Plasma settings to scale the bottom screen to 200%. I generally launch Scribus with the env-var of QT_SCALE_FACTOR=2 but I have set this to be =1 for these tests. I will upload the actual screenshots next.
laptop.jpg (75,590 bytes)   
laptop.jpg (75,590 bytes)   
plasmasettings.png (63,279 bytes)   
plasmasettings.png (63,279 bytes)   

BN_Dev

2024-09-22 16:16

reporter   ~0051385

I hope these are what you wanted to see. If not please clarify and I'll try again. Many thanks
100pc.png (471,354 bytes)   
100pc.png (471,354 bytes)   
200pc.png (419,739 bytes)   
200pc.png (419,739 bytes)   

nitramr

2024-09-22 16:25

developer   ~0051386

Thanks for the test and sharing the results.

By color button, I mean this thing. Sorry if it wasn't clear.

BN_Dev

2024-09-22 16:56

reporter   ~0051387

Apologies, here they are

nitramr

2024-09-22 17:03

developer   ~0051388

Thanks, looks like the scale factor is not correct on 200%. At 200% you should see clearly the stripes.

BN_Dev

2024-09-22 17:08

reporter   ~0051389

No it is working, it was my crappy screenshot settings. Sorry! Fresh ones below, and looking fine at 100% and 200%.
100pc-3.png (43,101 bytes)   
100pc-3.png (43,101 bytes)   
200pc-3.png (43,484 bytes)   
200pc-3.png (43,484 bytes)   

nitramr

2024-09-22 17:22

developer   ~0051390

Great, I can't see any blurriness in the pattern.

BN_Dev

2024-09-22 17:37

reporter   ~0051391

Looks crisp on the actual display. Is there anything you want me to check?

nitramr

2024-09-22 17:45

developer   ~0051392

No, thanks.

jghali

2024-09-24 22:31

administrator   ~0051395

The updated patch has been applied with a few minor corrections. Thanks nitramr!

Issue History

Date Modified Username Field Change
2024-09-21 19:44 nitramr New Issue
2024-09-21 19:44 nitramr File Added: utilgui_2024-09-21_01.patch
2024-09-21 20:00 cbradney Assigned To => nitramr
2024-09-21 20:00 cbradney Status new => resolved
2024-09-21 20:00 cbradney Resolution open => fixed
2024-09-21 20:00 cbradney Fixed in Version => 1.7.0.svn
2024-09-21 20:15 jghali Note Added: 0051379
2024-09-21 20:56 nitramr Note Added: 0051380
2024-09-22 11:15 BN_Dev Note Added: 0051381
2024-09-22 14:36 nitramr Note Added: 0051383
2024-09-22 14:36 nitramr File Added: colorbutton_2024-09-22_01.patch
2024-09-22 16:00 BN_Dev Note Added: 0051384
2024-09-22 16:00 BN_Dev File Added: laptop.jpg
2024-09-22 16:00 BN_Dev File Added: plasmasettings.png
2024-09-22 16:16 BN_Dev Note Added: 0051385
2024-09-22 16:16 BN_Dev File Added: 100pc.png
2024-09-22 16:16 BN_Dev File Added: 200pc.png
2024-09-22 16:25 nitramr Note Added: 0051386
2024-09-22 16:25 nitramr File Added: Bildschirmfoto vom 2024-09-22 18-22-01.png
2024-09-22 16:56 BN_Dev Note Added: 0051387
2024-09-22 16:56 BN_Dev File Added: 100pc-2.png
2024-09-22 16:56 BN_Dev File Added: 200pc-2.png
2024-09-22 17:03 nitramr Note Added: 0051388
2024-09-22 17:08 BN_Dev Note Added: 0051389
2024-09-22 17:08 BN_Dev File Added: 100pc-3.png
2024-09-22 17:08 BN_Dev File Added: 200pc-3.png
2024-09-22 17:11 BN_Dev File Deleted: 200pc-2.png
2024-09-22 17:11 BN_Dev File Deleted: 100pc-2.png
2024-09-22 17:22 nitramr Note Added: 0051390
2024-09-22 17:37 BN_Dev Note Added: 0051391
2024-09-22 17:45 nitramr Note Added: 0051392
2024-09-24 22:31 jghali Note Added: 0051395