Unbreak binary compatibility in QStyleOptionHeader

4d94384612 introduced a new data member to
QStyleOptionHeader, and reduced the size of the orientation member.
This changed the binary layout of class instances, and breaks ABI.

180c662b07 added another member within
the new bitfield.

Introduce a new QStyleOptionHeaderV2 class instead with the new members,
and use that in QHeaderView, and the styles using the new members.

Fixes: QTBUG-91224
Pick-to: 6.1
Change-Id: I47e6841e6652e4b67f247b7b4514e90be5609156
Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
Volker Hilsheimer 2021-02-19 08:14:31 +01:00
parent 6172f3101e
commit 4c6579eacd
6 changed files with 63 additions and 19 deletions

View File

@ -3565,8 +3565,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
textr.translate(pixmap.width() / pixmap.devicePixelRatio() + 2, 0); textr.translate(pixmap.width() / pixmap.devicePixelRatio() + 2, 0);
} }
QString text = header->text; QString text = header->text;
if (header->textElideMode != Qt::ElideNone) if (const QStyleOptionHeaderV2 *headerV2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(header)) {
text = header->fontMetrics.elidedText(text, header->textElideMode, textr.width()); if (headerV2->textElideMode != Qt::ElideNone)
text = header->fontMetrics.elidedText(text, headerV2->textElideMode, textr.width());
}
proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette, proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
header->state.testFlag(State_Enabled), text, QPalette::ButtonText); header->state.testFlag(State_Enabled), text, QPalette::ButtonText);

View File

@ -2910,6 +2910,7 @@ void QHeaderView::initStyleOptionForIndex(QStyleOptionHeader *option, int logica
if (!option) if (!option)
return; return;
QStyleOptionHeader &opt = *option; QStyleOptionHeader &opt = *option;
QStyleOptionHeaderV2 *optV2 = qstyleoption_cast<QStyleOptionHeaderV2*>(option);
QStyle::State state = QStyle::State_None; QStyle::State state = QStyle::State_None;
if (window()->isActiveWindow()) if (window()->isActiveWindow())
@ -2953,7 +2954,8 @@ void QHeaderView::initStyleOptionForIndex(QStyleOptionHeader *option, int logica
Qt::FontRole); Qt::FontRole);
if (var.isValid() && var.canConvert<QFont>()) if (var.isValid() && var.canConvert<QFont>())
opt.fontMetrics = QFontMetrics(qvariant_cast<QFont>(var)); opt.fontMetrics = QFontMetrics(qvariant_cast<QFont>(var));
opt.textElideMode = d->textElideMode; if (optV2)
optV2->textElideMode = d->textElideMode;
QVariant foregroundBrush = d->model->headerData(logicalIndex, d->orientation, QVariant foregroundBrush = d->model->headerData(logicalIndex, d->orientation,
Qt::ForegroundRole); Qt::ForegroundRole);
@ -2992,7 +2994,8 @@ void QHeaderView::initStyleOptionForIndex(QStyleOptionHeader *option, int logica
opt.selectedPosition = QStyleOptionHeader::NextIsSelected; opt.selectedPosition = QStyleOptionHeader::NextIsSelected;
else else
opt.selectedPosition = QStyleOptionHeader::NotAdjacent; opt.selectedPosition = QStyleOptionHeader::NotAdjacent;
opt.isSectionDragTarget = d->target == logicalIndex; if (optV2)
optV2->isSectionDragTarget = d->target == logicalIndex;
} }
/*! /*!
@ -3007,7 +3010,7 @@ void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logical
if (!rect.isValid()) if (!rect.isValid())
return; return;
QStyleOptionHeader opt; QStyleOptionHeaderV2 opt;
QPointF oldBO = painter->brushOrigin(); QPointF oldBO = painter->brushOrigin();
initStyleOption(&opt); initStyleOption(&opt);
@ -3052,7 +3055,7 @@ QSize QHeaderView::sectionSizeFromContents(int logicalIndex) const
return qvariant_cast<QSize>(variant); return qvariant_cast<QSize>(variant);
// otherwise use the contents // otherwise use the contents
QStyleOptionHeader opt; QStyleOptionHeaderV2 opt;
initStyleOption(&opt); initStyleOption(&opt);
opt.section = logicalIndex; opt.section = logicalIndex;
QVariant var = d->model->headerData(logicalIndex, d->orientation, QVariant var = d->model->headerData(logicalIndex, d->orientation,

View File

@ -1682,11 +1682,11 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
p->setFont(fnt); p->setFont(fnt);
fm = QFontMetrics((p->font())); fm = QFontMetrics((p->font()));
} }
QString text; QString text = header->text;
if (header->textElideMode != Qt::ElideNone) if (const QStyleOptionHeaderV2 *headerV2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(header)) {
text = fm.elidedText(header->text, header->textElideMode, rect.width()); if (headerV2->textElideMode != Qt::ElideNone)
else text = fm.elidedText(header->text, headerV2->textElideMode, rect.width());
text = header->text; }
proxy()->drawItemText(p, rect, header->textAlignment, header->palette, proxy()->drawItemText(p, rect, header->textAlignment, header->palette,
header->state.testFlag(State_Enabled), text, QPalette::ButtonText); header->state.testFlag(State_Enabled), text, QPalette::ButtonText);
} }

View File

@ -1280,10 +1280,12 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
painter->save(); painter->save();
// Draws the header in tables. // Draws the header in tables.
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
const QStyleOptionHeaderV2 *headerV2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(option);
QString pixmapName = QStyleHelper::uniqueName(QLatin1String("headersection"), option, option->rect.size()); QString pixmapName = QStyleHelper::uniqueName(QLatin1String("headersection"), option, option->rect.size());
pixmapName += QString::number(- int(header->position)); pixmapName += QString::number(- int(header->position));
pixmapName += QString::number(- int(header->orientation)); pixmapName += QString::number(- int(header->orientation));
pixmapName += QString::number(- int(header->isSectionDragTarget)); if (headerV2)
pixmapName += QString::number(- int(headerV2->isSectionDragTarget));
QPixmap cache; QPixmap cache;
if (!QPixmapCache::find(pixmapName, &cache)) { if (!QPixmapCache::find(pixmapName, &cache)) {
@ -1294,7 +1296,7 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
QColor buttonColor = d->buttonColor(option->palette); QColor buttonColor = d->buttonColor(option->palette);
QColor gradientStartColor = buttonColor.lighter(104); QColor gradientStartColor = buttonColor.lighter(104);
QColor gradientStopColor = buttonColor.darker(102); QColor gradientStopColor = buttonColor.darker(102);
if (header->isSectionDragTarget) { if (headerV2 && headerV2->isSectionDragTarget) {
gradientStopColor = gradientStartColor.darker(130); gradientStopColor = gradientStartColor.darker(130);
gradientStartColor = gradientStartColor.darker(130); gradientStartColor = gradientStartColor.darker(130);
} }

View File

@ -748,10 +748,32 @@ QStyleOptionHeader::QStyleOptionHeader(int version)
section(0), textAlignment(Qt::AlignLeft), iconAlignment(Qt::AlignLeft), section(0), textAlignment(Qt::AlignLeft), iconAlignment(Qt::AlignLeft),
position(QStyleOptionHeader::Beginning), position(QStyleOptionHeader::Beginning),
selectedPosition(QStyleOptionHeader::NotAdjacent), sortIndicator(None), selectedPosition(QStyleOptionHeader::NotAdjacent), sortIndicator(None),
orientation(Qt::Horizontal), textElideMode(Qt::ElideNone), isSectionDragTarget(false), unused(0) orientation(Qt::Horizontal)
{ {
} }
/*!
\class QStyleOptionHeaderV2
\brief The QStyleOptionHeaderV2 class is used to describe the
parameters for drawing a header.
*/
/*!
Constructs a QStyleOptionHeaderV2, initializing the members
variables to their default values.
*/
QStyleOptionHeaderV2::QStyleOptionHeaderV2()
: QStyleOptionHeaderV2(QStyleOptionHeader::Version)
{
}
/*!
\internal
*/
QStyleOptionHeaderV2::QStyleOptionHeaderV2(int version)
: QStyleOptionHeader(version), textElideMode(Qt::ElideNone), isSectionDragTarget(false), unused(0)
{}
/*! /*!
\variable QStyleOptionHeader::orientation \variable QStyleOptionHeader::orientation
\brief the header's orientation (horizontal or vertical) \brief the header's orientation (horizontal or vertical)
@ -892,7 +914,7 @@ QStyleOptionHeader::QStyleOptionHeader(int version)
*/ */
/*! /*!
\variable QStyleOptionHeader::textElideMode \variable QStyleOptionHeaderV2::textElideMode
\brief where ellipsis should be added for text that is too long to fit \brief where ellipsis should be added for text that is too long to fit
into an item into an item

View File

@ -219,10 +219,7 @@ public:
SectionPosition position; SectionPosition position;
SelectedPosition selectedPosition; SelectedPosition selectedPosition;
SortIndicator sortIndicator; SortIndicator sortIndicator;
Qt::Orientation orientation:2; Qt::Orientation orientation;
Qt::TextElideMode textElideMode:2;
bool isSectionDragTarget:1;
int unused:27;
QStyleOptionHeader(); QStyleOptionHeader();
QStyleOptionHeader(const QStyleOptionHeader &other) : QStyleOption(Version, Type) { *this = other; } QStyleOptionHeader(const QStyleOptionHeader &other) : QStyleOption(Version, Type) { *this = other; }
@ -232,6 +229,24 @@ protected:
QStyleOptionHeader(int version); QStyleOptionHeader(int version);
}; };
class Q_WIDGETS_EXPORT QStyleOptionHeaderV2 : public QStyleOptionHeader
{
public:
enum StyleOptionType { Type = SO_Header };
enum StyleOptionVersion { Version = 2 };
QStyleOptionHeaderV2();
QStyleOptionHeaderV2(const QStyleOptionHeaderV2 &other) : QStyleOptionHeader(Version) { *this = other; }
QStyleOptionHeaderV2 &operator=(const QStyleOptionHeaderV2 &) = default;
Qt::TextElideMode textElideMode:2;
bool isSectionDragTarget:1;
int unused:29;
protected:
QStyleOptionHeaderV2(int version);
};
class Q_WIDGETS_EXPORT QStyleOptionButton : public QStyleOption class Q_WIDGETS_EXPORT QStyleOptionButton : public QStyleOption
{ {
public: public: