Long live QHVContainer!

Various places in Qt use arrays indexed by some function of
Qt::Orientation input. None document their dependence on the numerical
values of the Qt::Orientation enum, some waste space, none is
type-safe.

QHVContainer is a private container of two values, one for
Qt::Horizontal and one for Qt::Vertical. Its salient API is the
indexing operator, taking Qt::Orientation, thus making the class
type-safe.

Use it to port QGridLayoutItem and QAbstractScrollAreaPrivate.

Change-Id: I0d9f17431a5eb141bfb0763c83155710bb82a537
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
This commit is contained in:
Marc Mutz 2020-05-04 18:21:29 +02:00
parent 8ad1643895
commit 46a1cf9150
3 changed files with 59 additions and 30 deletions

View File

@ -507,24 +507,21 @@ void QGridLayoutRowData::dump(int indent) const
QGridLayoutItem::QGridLayoutItem(int row, int column, int rowSpan, int columnSpan,
Qt::Alignment alignment)
: q_alignment(alignment)
: q_firstRows{column, row},
q_rowSpans{columnSpan, rowSpan},
q_stretches{-1, -1},
q_alignment(alignment)
{
q_firstRows[Hor] = column;
q_firstRows[Ver] = row;
q_rowSpans[Hor] = columnSpan;
q_rowSpans[Ver] = rowSpan;
q_stretches[Hor] = -1;
q_stretches[Ver] = -1;
}
int QGridLayoutItem::firstRow(Qt::Orientation orientation) const
{
return q_firstRows[orientation == Qt::Vertical];
return q_firstRows[orientation];
}
int QGridLayoutItem::firstColumn(Qt::Orientation orientation) const
{
return q_firstRows[orientation == Qt::Horizontal];
return q_firstRows.transposed()[orientation];
}
int QGridLayoutItem::lastRow(Qt::Orientation orientation) const
@ -539,27 +536,27 @@ int QGridLayoutItem::lastColumn(Qt::Orientation orientation) const
int QGridLayoutItem::rowSpan(Qt::Orientation orientation) const
{
return q_rowSpans[orientation == Qt::Vertical];
return q_rowSpans[orientation];
}
int QGridLayoutItem::columnSpan(Qt::Orientation orientation) const
{
return q_rowSpans[orientation == Qt::Horizontal];
return q_rowSpans.transposed()[orientation];
}
void QGridLayoutItem::setFirstRow(int row, Qt::Orientation orientation)
{
q_firstRows[orientation == Qt::Vertical] = row;
q_firstRows[orientation] = row;
}
void QGridLayoutItem::setRowSpan(int rowSpan, Qt::Orientation orientation)
{
q_rowSpans[orientation == Qt::Vertical] = rowSpan;
q_rowSpans[orientation] = rowSpan;
}
int QGridLayoutItem::stretchFactor(Qt::Orientation orientation) const
{
int stretch = q_stretches[orientation == Qt::Vertical];
int stretch = q_stretches[orientation];
if (stretch >= 0)
return stretch;
@ -577,7 +574,7 @@ int QGridLayoutItem::stretchFactor(Qt::Orientation orientation) const
void QGridLayoutItem::setStretchFactor(int stretch, Qt::Orientation orientation)
{
Q_ASSERT(stretch >= 0); // ### deal with too big stretches
q_stretches[orientation == Qt::Vertical] = stretch;
q_stretches[orientation] = stretch;
}
QLayoutPolicy::ControlTypes QGridLayoutItem::controlTypes(LayoutSide /*side*/) const
@ -695,9 +692,9 @@ QRectF QGridLayoutItem::geometryWithin(qreal x, qreal y, qreal width, qreal heig
void QGridLayoutItem::transpose()
{
qSwap(q_firstRows[Hor], q_firstRows[Ver]);
qSwap(q_rowSpans[Hor], q_rowSpans[Ver]);
qSwap(q_stretches[Hor], q_stretches[Ver]);
q_firstRows.transpose();
q_rowSpans.transpose();
q_stretches.transpose();
}
void QGridLayoutItem::insertOrRemoveRows(int row, int delta, Qt::Orientation orientation)
@ -746,10 +743,10 @@ void QGridLayoutItem::dump(int indent) const
qDebug("%*s (%d, %d) %d x %d", indent, "", firstRow(), firstColumn(), //###
rowSpan(), columnSpan());
if (q_stretches[Hor] >= 0)
qDebug("%*s Horizontal stretch: %d", indent, "", q_stretches[Hor]);
if (q_stretches[Ver] >= 0)
qDebug("%*s Vertical stretch: %d", indent, "", q_stretches[Ver]);
if (q_stretches[Qt::Horizontal] >= 0)
qDebug("%*s Horizontal stretch: %d", indent, "", q_stretches[Qt::Horizontal]);
if (q_stretches[Qt::Vertical] >= 0)
qDebug("%*s Vertical stretch: %d", indent, "", q_stretches[Qt::Vertical]);
if (q_alignment != 0)
qDebug("%*s Alignment: %x", indent, "", uint(q_alignment));
qDebug("%*s Horizontal size policy: %x Vertical size policy: %x",

View File

@ -102,6 +102,37 @@ enum {
UnfeasibleConstraint // not feasible, it be has some items with Vertical and others with Horizontal constraints
};
/*
Minimal container to store Qt::Orientation-discriminated values.
The salient feature is the indexing operator, which takes
Qt::Orientation (and assumes it's passed only Qt::Horizonal or Qt::Vertical).
*/
template <typename T>
class QHVContainer {
T m_data[2];
Q_STATIC_ASSERT(Qt::Horizontal == 0x1);
Q_STATIC_ASSERT(Qt::Vertical == 0x2);
static constexpr int map(Qt::Orientation o) noexcept
{
return int(o) - 1;
}
public:
constexpr QHVContainer(const T &h, const T &v)
noexcept(std::is_nothrow_copy_constructible_v<T>)
: m_data{h, v} {}
QHVContainer() = default;
constexpr T &operator[](Qt::Orientation o) noexcept { return m_data[map(o)]; }
constexpr const T &operator[](Qt::Orientation o) const noexcept { return m_data[map(o)]; }
constexpr void transpose() noexcept { qSwap(m_data[0], m_data[1]); }
constexpr QHVContainer transposed() const
noexcept(std::is_nothrow_copy_constructible_v<T>)
{ return {m_data[1], m_data[0]}; }
};
template <typename T>
class QLayoutParameter
{
@ -279,10 +310,10 @@ public:
Qt::Alignment alignment = { });
virtual ~QGridLayoutItem() {}
inline int firstRow() const { return q_firstRows[Ver]; }
inline int firstColumn() const { return q_firstRows[Hor]; }
inline int rowSpan() const { return q_rowSpans[Ver]; }
inline int columnSpan() const { return q_rowSpans[Hor]; }
inline int firstRow() const { return q_firstRows[Qt::Vertical]; }
inline int firstColumn() const { return q_firstRows[Qt::Horizontal]; }
inline int rowSpan() const { return q_rowSpans[Qt::Vertical]; }
inline int columnSpan() const { return q_rowSpans[Qt::Horizontal]; }
inline int lastRow() const { return firstRow() + rowSpan() - 1; }
inline int lastColumn() const { return firstColumn() + columnSpan() - 1; }
@ -329,9 +360,9 @@ public:
#endif
private:
int q_firstRows[NOrientations];
int q_rowSpans[NOrientations];
int q_stretches[NOrientations];
QHVContainer<int> q_firstRows;
QHVContainer<int> q_rowSpans;
QHVContainer<int> q_stretches;
Qt::Alignment q_alignment;
};

View File

@ -54,6 +54,7 @@
#include <QtWidgets/private/qtwidgetsglobal_p.h>
#include "private/qframe_p.h"
#include "qabstractscrollarea.h"
#include <QtGui/private/qgridlayoutengine_p.h>
QT_BEGIN_NAMESPACE
@ -73,7 +74,7 @@ public:
void replaceScrollBar(QScrollBar *scrollBar, Qt::Orientation orientation);
QAbstractScrollAreaScrollBarContainer *scrollBarContainers[int(Qt::Vertical) + 1];
QHVContainer<QAbstractScrollAreaScrollBarContainer *> scrollBarContainers;
QScrollBar *hbar, *vbar;
Qt::ScrollBarPolicy vbarpolicy, hbarpolicy;