summaryrefslogtreecommitdiffstats
path: root/src/gui/util/qgridlayoutengine.cpp
diff options
context:
space:
mode:
authorJan Arve Saether <jan-arve.saether@theqtcompany.com>2014-11-25 12:15:37 +0100
committerJan Arve Sæther <jan-arve.saether@theqtcompany.com>2015-02-09 12:06:34 +0000
commit68293395ed6c513703a206389734201d3202c30c (patch)
tree3dfcc1f6d5d4b702b905579344f48a3d58dba32a /src/gui/util/qgridlayoutengine.cpp
parent18aae36a90c0753f1b1e615ba8437d8ebd1bd2fb (diff)
Add support for snapping to pixel grid
This enables us to do more intelligent distribution than simply doing the rounding on each individual items geometry (which often leads to larger spacings than specified). Instead of doing the rounding on the output geometries, we now do the snapping inside the layout engine. This allows us to do more intelligent distribution of items, and spacings should always be respected. There are some cases where items with fractional size hints might overlap with less than a pixel. This was also the case before this patch. Those cases are impossible to fix properly, since fractional size hints conflicts with the snapping in some cases. (Fractional size hints is normal for Text items.) Task-number: QTBUG-41216 Change-Id: I01a8bc3529f0b8b028d6eb0a530c751b67ac6f4e Reviewed-by: Paul Olav Tvete <paul.tvete@theqtcompany.com>
Diffstat (limited to 'src/gui/util/qgridlayoutengine.cpp')
-rw-r--r--src/gui/util/qgridlayoutengine.cpp59
1 files changed, 41 insertions, 18 deletions
diff --git a/src/gui/util/qgridlayoutengine.cpp b/src/gui/util/qgridlayoutengine.cpp
index 861b713efd..572dce9675 100644
--- a/src/gui/util/qgridlayoutengine.cpp
+++ b/src/gui/util/qgridlayoutengine.cpp
@@ -154,7 +154,7 @@ void QGridLayoutRowData::reset(int count)
hasIgnoreFlag = false;
}
-void QGridLayoutRowData::distributeMultiCells(const QGridLayoutRowInfo &rowInfo)
+void QGridLayoutRowData::distributeMultiCells(const QGridLayoutRowInfo &rowInfo, bool snapToPixelGrid)
{
MultiCellMap::const_iterator i = multiCellMap.constBegin();
for (; i != multiCellMap.constEnd(); ++i) {
@@ -173,7 +173,7 @@ void QGridLayoutRowData::distributeMultiCells(const QGridLayoutRowInfo &rowInfo)
qreal extra = compare(box, totalBox, j);
if (extra > 0.0) {
calculateGeometries(start, end, box.q_sizes(j), dummy.data(), newSizes.data(),
- 0, totalBox, rowInfo);
+ 0, totalBox, rowInfo, snapToPixelGrid);
for (int k = 0; k < span; ++k)
extras[k].q_sizes(j) = newSizes[k];
@@ -188,11 +188,19 @@ void QGridLayoutRowData::distributeMultiCells(const QGridLayoutRowInfo &rowInfo)
}
multiCellMap.clear();
}
+namespace {
+// does not return int
+static inline qreal qround(qreal f)
+{
+ return floor(f + 0.5);
+}
+
+}
void QGridLayoutRowData::calculateGeometries(int start, int end, qreal targetSize, qreal *positions,
qreal *sizes, qreal *descents,
const QGridLayoutBox &totalBox,
- const QGridLayoutRowInfo &rowInfo)
+ const QGridLayoutRowInfo &rowInfo, bool snapToPixelGrid)
{
Q_ASSERT(end > start);
@@ -335,17 +343,19 @@ void QGridLayoutRowData::calculateGeometries(int start, int end, qreal targetSiz
bool keepGoing = somethingHasAMaximumSize;
while (keepGoing) {
+ //sumCurrentAvailable is so large that something *might* reach its maximum size
keepGoing = false;
for (int i = 0; i < n; ++i) {
if (newSizes[i] >= 0.0)
continue;
- qreal maxBoxSize;
- if (isLargerThanMaximum)
- maxBoxSize = rowInfo.boxes.value(start + i).q_maximumSize;
- else
- maxBoxSize = boxes.at(start + i).q_maximumSize;
+ const QVector<QGridLayoutBox> &rBoxes = isLargerThanMaximum ? rowInfo.boxes : boxes;
+ const QGridLayoutBox &box = rBoxes.value(start + i);
+ qreal maxBoxSize = box.q_maximumSize;
+
+ if (snapToPixelGrid)
+ maxBoxSize = qMax(box.q_minimumSize, floor(maxBoxSize));
qreal avail = sumCurrentAvailable * factors[i] / sumFactors;
if (sizes[i] + avail >= maxBoxSize) {
@@ -358,7 +368,6 @@ void QGridLayoutRowData::calculateGeometries(int start, int end, qreal targetSiz
}
}
}
-
for (int i = 0; i < n; ++i) {
if (newSizes[i] < 0.0) {
qreal delta = (sumFactors == 0.0) ? 0.0
@@ -402,6 +411,10 @@ void QGridLayoutRowData::calculateGeometries(int start, int end, qreal targetSiz
Q_ASSERT(surplus == 0);
#endif
}
+ if (snapToPixelGrid) {
+ for (int i = 0; i < n; ++i)
+ positions[i] = qround(positions[i]);
+ }
if (descents) {
for (int i = 0; i < n; ++i) {
@@ -753,10 +766,11 @@ void QGridLayoutRowInfo::dump(int indent) const
}
#endif
-QGridLayoutEngine::QGridLayoutEngine(Qt::Alignment defaultAlignment)
+QGridLayoutEngine::QGridLayoutEngine(Qt::Alignment defaultAlignment, bool snapToPixelGrid)
{
m_visualDirection = Qt::LeftToRight;
m_defaultAlignment = defaultAlignment;
+ m_snapToPixelGrid = snapToPixelGrid;
invalidate();
}
@@ -1007,8 +1021,17 @@ void QGridLayoutEngine::setGeometries(const QRectF &contentsGeometry, const QAbs
if (item->rowSpan() != 1)
height += q_yy[item->lastRow()] - y;
+ const Qt::Alignment align = effectiveAlignment(item);
QRectF geom = item->geometryWithin(contentsGeometry.x() + x, contentsGeometry.y() + y,
- width, height, q_descents[item->lastRow()], effectiveAlignment(item));
+ width, height, q_descents[item->lastRow()], align);
+ if (m_snapToPixelGrid) {
+ // x and y should already be rounded, but the call to geometryWithin() above might
+ // result in a geom with x,y at half-pixels (due to centering within the cell)
+ geom.setX(qround(geom.x()));
+ // Do not snap baseline aligned items, since that might cause the baselines to not be aligned.
+ if (align != Qt::AlignBaseline)
+ geom.setY(qround(geom.y()));
+ }
visualRect(&geom, visualDirection(), contentsGeometry);
item->setGeometry(geom);
}
@@ -1061,7 +1084,7 @@ QSizeF QGridLayoutEngine::sizeHint(Qt::SizeHint which, const QSizeF &constraint,
//Calculate column widths and positions, and put results in q_xx.data() and q_widths.data() so that we can use this information as
//constraints to find the row heights
q_columnData.calculateGeometries(0, columnCount(), width, sizehint_xx.data(), sizehint_widths.data(),
- 0, sizehint_totalBoxes[Hor], q_infos[Hor]);
+ 0, sizehint_totalBoxes[Hor], q_infos[Hor], m_snapToPixelGrid);
ensureColumnAndRowData(&q_rowData, &sizehint_totalBoxes[Ver], sizehint_xx.data(), sizehint_widths.data(), Qt::Vertical, styleInfo);
sizeHintCalculated = true;
}
@@ -1078,7 +1101,7 @@ QSizeF QGridLayoutEngine::sizeHint(Qt::SizeHint which, const QSizeF &constraint,
//Calculate row heights and positions, and put results in q_yy.data() and q_heights.data() so that we can use this information as
//constraints to find the column widths
q_rowData.calculateGeometries(0, rowCount(), height, sizehint_yy.data(), sizehint_heights.data(),
- 0, sizehint_totalBoxes[Ver], q_infos[Ver]);
+ 0, sizehint_totalBoxes[Ver], q_infos[Ver], m_snapToPixelGrid);
ensureColumnAndRowData(&q_columnData, &sizehint_totalBoxes[Hor], sizehint_yy.data(), sizehint_heights.data(), Qt::Horizontal, styleInfo);
sizeHintCalculated = true;
}
@@ -1533,7 +1556,7 @@ void QGridLayoutEngine::ensureColumnAndRowData(QGridLayoutRowData *rowData, QGri
rowData->reset(rowCount(orientation));
fillRowData(rowData, colPositions, colSizes, orientation, styleInfo);
const QGridLayoutRowInfo &rowInfo = q_infos[orientation == Qt::Vertical];
- rowData->distributeMultiCells(rowInfo);
+ rowData->distributeMultiCells(rowInfo, m_snapToPixelGrid);
*totalBox = rowData->totalBox(0, rowCount(orientation));
if (totalBox != &q_totalBoxes[o])
@@ -1605,22 +1628,22 @@ void QGridLayoutEngine::ensureGeometries(const QSizeF &size,
//Calculate column widths and positions, and put results in q_xx.data() and q_widths.data() so that we can use this information as
//constraints to find the row heights
q_columnData.calculateGeometries(0, columnCount(), size.width(), q_xx.data(), q_widths.data(),
- 0, q_totalBoxes[Hor], q_infos[Hor] );
+ 0, q_totalBoxes[Hor], q_infos[Hor], m_snapToPixelGrid);
ensureColumnAndRowData(&q_rowData, &q_totalBoxes[Ver], q_xx.data(), q_widths.data(), Qt::Vertical, styleInfo);
//Calculate row heights and positions, and put results in q_yy.data() and q_heights.data()
q_rowData.calculateGeometries(0, rowCount(), size.height(), q_yy.data(), q_heights.data(),
- q_descents.data(), q_totalBoxes[Ver], q_infos[Ver]);
+ q_descents.data(), q_totalBoxes[Ver], q_infos[Ver], m_snapToPixelGrid);
} else {
//We have items whose width depends on their height (WFH)
ensureColumnAndRowData(&q_rowData, &q_totalBoxes[Ver], NULL, NULL, Qt::Vertical, styleInfo);
//Calculate row heights and positions, and put results in q_yy.data() and q_heights.data() so that we can use this information as
//constraints to find the column widths
q_rowData.calculateGeometries(0, rowCount(), size.height(), q_yy.data(), q_heights.data(),
- q_descents.data(), q_totalBoxes[Ver], q_infos[Ver]);
+ q_descents.data(), q_totalBoxes[Ver], q_infos[Ver], m_snapToPixelGrid);
ensureColumnAndRowData(&q_columnData, &q_totalBoxes[Hor], q_yy.data(), q_heights.data(), Qt::Horizontal, styleInfo);
//Calculate row heights and positions, and put results in q_yy.data() and q_heights.data()
q_columnData.calculateGeometries(0, columnCount(), size.width(), q_xx.data(), q_widths.data(),
- 0, q_totalBoxes[Hor], q_infos[Hor]);
+ 0, q_totalBoxes[Hor], q_infos[Hor], m_snapToPixelGrid);
}
}