aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2020-06-05 09:28:00 +0200
committerRichard Moe Gustavsen <richard.gustavsen@qt.io>2020-06-08 09:06:43 +0000
commit62fa08d89eadfcd79cd4a51b997223eb6ec24d5e (patch)
tree5838ee3777cd5ac03db9a369afab175e8600e0d8 /src
parent2275a0896c7b7e648641f4c6977a02006a581577 (diff)
Native style: make it possible to set nine patch margins from the style
Up till now, all images have been scaled using nine patch images with margins set to be at the center. This was doomed to be too simplistic at some point, at that point is now (when working on comboboxes). So instead, calculate the nine patch margins from the style. This will let the different styles set pixel perfect margins per control that matches the image they draw. If left unspecified by a style, the default implementation in QCommonStyle will return the old logic of using the center. We also add support for specifying if an image can be scaled horizontally or vertically by setting the right or bottom nine patch margin to -1 respectively. E.g on macOS, an NSButton cannot be scaled vertically, so the image we draw will not look native if we do. Change-Id: Icaf232748b8d15f06f9b289e164b5c8fb86a6c7b Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/imports/nativestyle/items/qquickstyleitem.cpp49
-rw-r--r--src/imports/nativestyle/items/qquickstyleitem.h1
-rw-r--r--src/imports/nativestyle/items/qquickstyleitembutton.cpp1
-rw-r--r--src/imports/nativestyle/items/qquickstyleitemcheckbox.cpp1
-rw-r--r--src/imports/nativestyle/items/qquickstyleitemframe.cpp4
-rw-r--r--src/imports/nativestyle/items/qquickstyleitemgroupbox.cpp1
-rw-r--r--src/imports/nativestyle/items/qquickstyleitemradiobutton.cpp1
-rw-r--r--src/imports/nativestyle/items/qquickstyleitemslider.cpp1
-rw-r--r--src/imports/nativestyle/items/qquickstyleitemspinbox.cpp1
-rw-r--r--src/imports/nativestyle/items/qquickstyleitemtextarea.cpp1
-rw-r--r--src/imports/nativestyle/items/qquickstyleitemtextfield.cpp1
-rw-r--r--src/imports/nativestyle/qstyle/qquickcommonstyle.cpp16
-rw-r--r--src/imports/nativestyle/qstyle/qquickcommonstyle.h2
-rw-r--r--src/imports/nativestyle/qstyle/qquickstyle.h2
14 files changed, 69 insertions, 13 deletions
diff --git a/src/imports/nativestyle/items/qquickstyleitem.cpp b/src/imports/nativestyle/items/qquickstyleitem.cpp
index be1e9316..1034459d 100644
--- a/src/imports/nativestyle/items/qquickstyleitem.cpp
+++ b/src/imports/nativestyle/items/qquickstyleitem.cpp
@@ -114,27 +114,44 @@ QSGNode *QQuickStyleItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePa
if (!node)
node = window()->createNinePatchNode();
- QRectF bounds = boundingRect();
auto texture = window()->createTextureFromImage(m_paintedImage, QQuickWindow::TextureCanUseAtlas);
- QSize padding = m_useNinePatchImage ? m_styleItemGeometry.minimumSize / 2 : QSize(0, 0);
- if (boundingRect().width() < m_styleItemGeometry.minimumSize.width())
- padding.setWidth(0);
- if (boundingRect().height() < m_styleItemGeometry.minimumSize.height())
- padding.setHeight(0);
+ QRectF bounds = boundingRect();
+ const qreal scale = window()->devicePixelRatio();
+ const QSizeF ninePatchImageSize = m_paintedImage.rect().size() / scale;
#ifdef QT_DEBUG
if (m_debugFlags.testFlag(ShowUnscaled)) {
- const qreal scale = window()->devicePixelRatio();
- const QSizeF ninePatchImageSize = m_paintedImage.rect().size() / scale;
bounds = QRectF(QPointF(), ninePatchImageSize);
qqc2Debug() << "Setting paint node bounds to size of image:" << bounds;
}
#endif
+ QMargins padding = m_useNinePatchImage ? m_styleItemGeometry.ninePatchMargins : QMargins(0, 0, 0, 0);
+ if (padding.right() == -1) {
+ // Special case: a right padding of -1 means that
+ // the image should not scale horizontally.
+ bounds.setWidth(ninePatchImageSize.width());
+ padding.setLeft(0);
+ padding.setRight(0);
+ } else if (boundingRect().width() < m_styleItemGeometry.minimumSize.width()) {
+ // If the item size is smaller that the image, using nine-patch scaling
+ // ends up wrapping it. In that case we scale the whole image instead.
+ padding.setLeft(0);
+ padding.setRight(0);
+ }
+ if (padding.bottom() == -1) {
+ bounds.setHeight(ninePatchImageSize.height());
+ padding.setTop(0);
+ padding.setBottom(0);
+ } else if (boundingRect().height() < m_styleItemGeometry.minimumSize.height()) {
+ padding.setTop(0);
+ padding.setBottom(0);
+ }
+
node->setBounds(bounds);
node->setTexture(texture);
node->setDevicePixelRatio(window()->devicePixelRatio());
- node->setPadding(padding.width(), padding.height(), padding.width(), padding.height());
+ node->setPadding(padding.left(), padding.top(), padding.right(), padding.bottom());
node->update();
return node;
@@ -259,9 +276,17 @@ void QQuickStyleItem::paintControlToImage()
painter.drawLine(p.x() - offset, p.y() - offset, p.x() - offset, p.y() + m_contentSize.height());
}
if (m_debugFlags.testFlag(ShowUnscaled)) {
- const QPoint center = m_paintedImage.rect().center() / scale;
- painter.drawLine(center.x(), 0, center.x(), m_paintedImage.rect().height());
- painter.drawLine(0, center.y(), m_paintedImage.rect().width(), center.y());
+ const QMargins m = m_styleItemGeometry.ninePatchMargins;
+ const int w = int(m_paintedImage.rect().width() / scale);
+ const int h = int(m_paintedImage.rect().height() / scale);
+ if (m.right() != -1) {
+ painter.drawLine(m.left(), 0, m.left(), h);
+ painter.drawLine(w - m.right(), 0, w - m.right(), h);
+ }
+ if (m.bottom() != -1) {
+ painter.drawLine(0, m.top(), w, m.top());
+ painter.drawLine(0, h - m.bottom(), w, h - m.bottom());
+ }
}
}
#endif
diff --git a/src/imports/nativestyle/items/qquickstyleitem.h b/src/imports/nativestyle/items/qquickstyleitem.h
index bab038ce..47247e15 100644
--- a/src/imports/nativestyle/items/qquickstyleitem.h
+++ b/src/imports/nativestyle/items/qquickstyleitem.h
@@ -144,6 +144,7 @@ struct StyleItemGeometry
QSize implicitSize;
QRect contentRect;
QRect layoutRect;
+ QMargins ninePatchMargins;
};
QDebug operator<<(QDebug debug, const StyleItemGeometry &cg);
diff --git a/src/imports/nativestyle/items/qquickstyleitembutton.cpp b/src/imports/nativestyle/items/qquickstyleitembutton.cpp
index 4d5d32e0..6f3fbfec 100644
--- a/src/imports/nativestyle/items/qquickstyleitembutton.cpp
+++ b/src/imports/nativestyle/items/qquickstyleitembutton.cpp
@@ -59,6 +59,7 @@ StyleItemGeometry QQuickStyleItemButton::calculateGeometry()
styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
geometry.contentRect = style()->subElementRect(QStyle::SE_PushButtonContents, &styleOption);
geometry.layoutRect = style()->subElementRect(QStyle::SE_PushButtonLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CE_PushButtonBevel, &styleOption, geometry.minimumSize);
return geometry;
}
diff --git a/src/imports/nativestyle/items/qquickstyleitemcheckbox.cpp b/src/imports/nativestyle/items/qquickstyleitemcheckbox.cpp
index e97f7d94..e5ee9133 100644
--- a/src/imports/nativestyle/items/qquickstyleitemcheckbox.cpp
+++ b/src/imports/nativestyle/items/qquickstyleitemcheckbox.cpp
@@ -60,6 +60,7 @@ StyleItemGeometry QQuickStyleItemCheckBox::calculateGeometry()
styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
geometry.contentRect = style()->subElementRect(QStyle::SE_CheckBoxContents, &styleOption);
geometry.layoutRect = style()->subElementRect(QStyle::SE_CheckBoxLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CE_CheckBox, &styleOption, geometry.minimumSize);
// Spacing seems to already be baked into SE_CheckBoxContents, so ignore until needed
//const int space = style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing, &styleOption);
diff --git a/src/imports/nativestyle/items/qquickstyleitemframe.cpp b/src/imports/nativestyle/items/qquickstyleitemframe.cpp
index fe5d1370..42a6c231 100644
--- a/src/imports/nativestyle/items/qquickstyleitemframe.cpp
+++ b/src/imports/nativestyle/items/qquickstyleitemframe.cpp
@@ -40,12 +40,14 @@ StyleItemGeometry QQuickStyleItemFrame::calculateGeometry()
{
QStyleOptionFrame styleOption;
initStyleOption(styleOption);
-
StyleItemGeometry geometry;
+
geometry.minimumSize = style()->sizeFromContents(QStyle::CT_Frame, &styleOption, QSize(0, 0));
geometry.implicitSize = contentSize();
styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
geometry.contentRect = style()->subElementRect(QStyle::SE_FrameContents, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CE_ShapedFrame, &styleOption, geometry.minimumSize);
+
return geometry;
}
diff --git a/src/imports/nativestyle/items/qquickstyleitemgroupbox.cpp b/src/imports/nativestyle/items/qquickstyleitemgroupbox.cpp
index fab8fb3a..2b4154d2 100644
--- a/src/imports/nativestyle/items/qquickstyleitemgroupbox.cpp
+++ b/src/imports/nativestyle/items/qquickstyleitemgroupbox.cpp
@@ -60,6 +60,7 @@ StyleItemGeometry QQuickStyleItemGroupBox::calculateGeometry()
styleOption.rect.setSize(geometry.implicitSize);
geometry.contentRect = style()->subControlRect(QStyle::CC_GroupBox, &styleOption, QStyle::SC_GroupBoxContents);
geometry.layoutRect = style()->subElementRect(QStyle::SE_GroupBoxLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CC_GroupBox, &styleOption, geometry.minimumSize);
const QQuickStyleMargins oldGroupBoxPadding = m_groupBoxPadding;
const QRect frame = style()->subControlRect(QStyle::CC_GroupBox, &styleOption, QStyle::SC_GroupBoxFrame);
diff --git a/src/imports/nativestyle/items/qquickstyleitemradiobutton.cpp b/src/imports/nativestyle/items/qquickstyleitemradiobutton.cpp
index 5561184c..c8bb251f 100644
--- a/src/imports/nativestyle/items/qquickstyleitemradiobutton.cpp
+++ b/src/imports/nativestyle/items/qquickstyleitemradiobutton.cpp
@@ -60,6 +60,7 @@ StyleItemGeometry QQuickStyleItemRadioButton::calculateGeometry()
styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
geometry.contentRect = style()->subElementRect(QStyle::SE_RadioButtonContents, &styleOption);
geometry.layoutRect = style()->subElementRect(QStyle::SE_RadioButtonLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CE_RadioButton, &styleOption, geometry.minimumSize);
return geometry;
}
diff --git a/src/imports/nativestyle/items/qquickstyleitemslider.cpp b/src/imports/nativestyle/items/qquickstyleitemslider.cpp
index 99b0e312..5ca282cc 100644
--- a/src/imports/nativestyle/items/qquickstyleitemslider.cpp
+++ b/src/imports/nativestyle/items/qquickstyleitemslider.cpp
@@ -63,6 +63,7 @@ StyleItemGeometry QQuickStyleItemSlider::calculateGeometry()
geometry.minimumSize = style()->sizeFromContents(QStyle::CT_Slider, &styleOption, QSize(0, 0));
geometry.implicitSize = geometry.minimumSize;
geometry.layoutRect = style()->subElementRect(QStyle::SE_SliderLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CC_Slider, &styleOption, geometry.minimumSize);
return geometry;
}
diff --git a/src/imports/nativestyle/items/qquickstyleitemspinbox.cpp b/src/imports/nativestyle/items/qquickstyleitemspinbox.cpp
index 9ebc62b1..a2c4f1d1 100644
--- a/src/imports/nativestyle/items/qquickstyleitemspinbox.cpp
+++ b/src/imports/nativestyle/items/qquickstyleitemspinbox.cpp
@@ -62,6 +62,7 @@ StyleItemGeometry QQuickStyleItemSpinBox::calculateGeometry()
styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
geometry.contentRect = style()->subControlRect(QStyle::CC_SpinBox, &styleOption, QStyle::SC_SpinBoxEditField);
geometry.layoutRect = style()->subElementRect(QStyle::SE_SpinBoxLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CC_SpinBox, &styleOption, geometry.minimumSize);
} else {
geometry.implicitSize = geometry.minimumSize;
}
diff --git a/src/imports/nativestyle/items/qquickstyleitemtextarea.cpp b/src/imports/nativestyle/items/qquickstyleitemtextarea.cpp
index 88dbf065..c149444b 100644
--- a/src/imports/nativestyle/items/qquickstyleitemtextarea.cpp
+++ b/src/imports/nativestyle/items/qquickstyleitemtextarea.cpp
@@ -60,6 +60,7 @@ StyleItemGeometry QQuickStyleItemTextArea::calculateGeometry()
geometry.implicitSize = style()->sizeFromContents(QStyle::CT_LineEdit, &styleOption, contentSize());
styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
geometry.contentRect = style()->subElementRect(QStyle::SE_LineEditContents, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CE_ShapedFrame, &styleOption, geometry.minimumSize);
return geometry;
}
diff --git a/src/imports/nativestyle/items/qquickstyleitemtextfield.cpp b/src/imports/nativestyle/items/qquickstyleitemtextfield.cpp
index ed8aaf46..1a262033 100644
--- a/src/imports/nativestyle/items/qquickstyleitemtextfield.cpp
+++ b/src/imports/nativestyle/items/qquickstyleitemtextfield.cpp
@@ -59,6 +59,7 @@ StyleItemGeometry QQuickStyleItemTextField::calculateGeometry()
geometry.implicitSize = style()->sizeFromContents(QStyle::CT_LineEdit, &styleOption, contentSize());
styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
geometry.contentRect = style()->subElementRect(QStyle::SE_LineEditContents, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CE_ShapedFrame, &styleOption, geometry.minimumSize);
return geometry;
}
diff --git a/src/imports/nativestyle/qstyle/qquickcommonstyle.cpp b/src/imports/nativestyle/qstyle/qquickcommonstyle.cpp
index 0cb8e848..e8dadb9e 100644
--- a/src/imports/nativestyle/qstyle/qquickcommonstyle.cpp
+++ b/src/imports/nativestyle/qstyle/qquickcommonstyle.cpp
@@ -4694,6 +4694,22 @@ QFont QCommonStyle::font(QStyle::ControlElement element, const QStyle::State sta
return QGuiApplication::font();
}
+QMargins QCommonStyle::ninePatchMargins(QStyle::ControlElement ce, const QStyleOption *opt, const QSize &imageSize) const
+{
+ // By default, we just divide the image at the center
+ int w = imageSize.width() / 2;
+ int h = imageSize.height() / 2;
+ return QMargins(w, h, w, h);
+}
+
+QMargins QCommonStyle::ninePatchMargins(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, const QSize &imageSize) const
+{
+ // By default, we just divide the image at the center
+ int w = imageSize.width() / 2;
+ int h = imageSize.height() / 2;
+ return QMargins(w, h, w, h);
+}
+
int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, QStyleHintReturn *hret) const
{
int ret = 0;
diff --git a/src/imports/nativestyle/qstyle/qquickcommonstyle.h b/src/imports/nativestyle/qstyle/qquickcommonstyle.h
index 77626843..894194a0 100644
--- a/src/imports/nativestyle/qstyle/qquickcommonstyle.h
+++ b/src/imports/nativestyle/qstyle/qquickcommonstyle.h
@@ -62,6 +62,8 @@ public:
QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize) const override;
QFont font(ControlElement element, const QStyle::State state) const override;
+ QMargins ninePatchMargins(ControlElement ce, const QStyleOption *opt, const QSize &imageSize) const override;
+ QMargins ninePatchMargins(ComplexControl cc, const QStyleOptionComplex *opt, const QSize &imageSize) const override;
int pixelMetric(PixelMetric m, const QStyleOption *opt = nullptr) const override;
int styleHint(StyleHint sh, const QStyleOption *opt = nullptr, QStyleHintReturn *shret = nullptr) const override;
diff --git a/src/imports/nativestyle/qstyle/qquickstyle.h b/src/imports/nativestyle/qstyle/qquickstyle.h
index 91e09f4b..bc0cccf7 100644
--- a/src/imports/nativestyle/qstyle/qquickstyle.h
+++ b/src/imports/nativestyle/qstyle/qquickstyle.h
@@ -782,6 +782,8 @@ public:
virtual QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize) const = 0;
virtual QFont font(ControlElement element, const QStyle::State state) const = 0;
+ virtual QMargins ninePatchMargins(ControlElement ce, const QStyleOption *opt, const QSize &imageSize) const = 0;
+ virtual QMargins ninePatchMargins(ComplexControl cc, const QStyleOptionComplex *opt, const QSize &imageSize) const = 0;
virtual SubControl hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt) const = 0;