fix: blobs now allow to be drawn in device pixels to stay sharp
C++ / fmt (pull_request) Failing after 5s
C++ / build (pull_request) Failing after 10s
C++ / clang-tidy (pull_request) Failing after 10s
JS/TS / fmt (pull_request) Successful in 9s
JS/TS / lint (pull_request) Successful in 25s
Python / static (pull_request) Successful in 34s
Rust / build (pull_request) Successful in 51s
Python / verify (pull_request) Failing after 1m25s
Rust / fmt (pull_request) Successful in 39s
Rust / clippy (pull_request) Successful in 59s
C++ / fmt (pull_request) Failing after 5s
C++ / build (pull_request) Failing after 10s
C++ / clang-tidy (pull_request) Failing after 10s
JS/TS / fmt (pull_request) Successful in 9s
JS/TS / lint (pull_request) Successful in 25s
Python / static (pull_request) Successful in 34s
Rust / build (pull_request) Successful in 51s
Python / verify (pull_request) Failing after 1m25s
Rust / fmt (pull_request) Successful in 39s
Rust / clippy (pull_request) Successful in 59s
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <QQuickWindow>
|
||||
#include <QScopeGuard>
|
||||
#include <QtGui/private/qfont_p.h>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
Q_LOGGING_CATEGORY(lcQuickLayouts, "qt.quick.layouts")
|
||||
@@ -54,49 +55,13 @@ SnapGridLayoutItem::SnapGridLayoutItem(
|
||||
int column,
|
||||
int rowSpan,
|
||||
int columnSpan,
|
||||
Qt::Alignment alignment,
|
||||
SnapLayout* layout)
|
||||
: QQuickGridLayoutItem(item, row, column, rowSpan, columnSpan, alignment)
|
||||
, m_layout(layout) {}
|
||||
Qt::Alignment alignment)
|
||||
: QQuickGridLayoutItem(item, row, column, rowSpan, columnSpan, alignment) {}
|
||||
|
||||
void SnapGridLayoutItem::setGeometry(const QRectF& rect) {
|
||||
QQuickLayoutAttached* info = attachedLayoutObject(m_item, false);
|
||||
QRectF placed = info ? rect.marginsRemoved(info->effectiveQMargins())
|
||||
: rect;
|
||||
|
||||
const QQuickWindow* win = m_item->window();
|
||||
const qreal dpr = win ? win->effectiveDevicePixelRatio() : 1.0;
|
||||
|
||||
if (dpr > 0.0) {
|
||||
const QPointF origin = absoluteOrigin(m_layout);
|
||||
const qreal left = (origin.x() + placed.x()) * dpr;
|
||||
const qreal top = (origin.y() + placed.y()) * dpr;
|
||||
const qreal right = (origin.x() + placed.right()) * dpr;
|
||||
const qreal bottom = (origin.y() + placed.bottom()) * dpr;
|
||||
|
||||
const qint64 nearX = std::llround(left);
|
||||
const qint64 nearY = std::llround(top);
|
||||
const qint64 farX = std::llround(right);
|
||||
const qint64 farY = std::llround(bottom);
|
||||
|
||||
placed = QRectF(
|
||||
qreal(nearX) / dpr - origin.x(),
|
||||
qreal(nearY) / dpr - origin.y(),
|
||||
qreal(farX - nearX) / dpr,
|
||||
qreal(farY - nearY) / dpr);
|
||||
}
|
||||
|
||||
const QSizeF oldSize(m_item->width(), m_item->height());
|
||||
const QSizeF newSize = placed.size();
|
||||
|
||||
m_item->setPosition(placed.topLeft());
|
||||
if (newSize == oldSize) {
|
||||
if (QQuickLayout* lay = qobject_cast<QQuickLayout*>(m_item)) {
|
||||
if (lay->invalidatedArrangement()) lay->rearrange(newSize);
|
||||
}
|
||||
} else {
|
||||
m_item->setSize(newSize);
|
||||
}
|
||||
engineRect = info ? rect.marginsRemoved(info->effectiveQMargins()) : rect;
|
||||
placed = true;
|
||||
}
|
||||
|
||||
void SnapLayoutPrivate::mirrorChange() {
|
||||
@@ -119,6 +84,7 @@ SnapLayout::~SnapLayout() {
|
||||
void SnapLayout::componentComplete() {
|
||||
QQuickLayout::componentComplete();
|
||||
|
||||
applySpacing();
|
||||
invalidate();
|
||||
ensureLayoutItemsUpdated(QQuickLayout::ApplySizeHints);
|
||||
|
||||
@@ -128,8 +94,12 @@ void SnapLayout::componentComplete() {
|
||||
|
||||
void SnapLayout::itemChange(ItemChange change, const ItemChangeData& value) {
|
||||
QQuickLayout::itemChange(change, value);
|
||||
if (change == ItemDevicePixelRatioHasChanged || change == ItemSceneChange)
|
||||
if (change == ItemChildRemovedChange && value.item)
|
||||
d_func()->childSizes.remove(value.item);
|
||||
if (change == ItemDevicePixelRatioHasChanged || change == ItemSceneChange) {
|
||||
applySpacing();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
QSizeF SnapLayout::sizeHint(Qt::SizeHint whichSizeHint) const {
|
||||
@@ -169,16 +139,33 @@ Qt::LayoutDirection SnapLayout::effectiveLayoutDirection() const {
|
||||
|
||||
qreal SnapLayout::spacing() const {
|
||||
Q_D(const SnapLayout);
|
||||
return d->engine.spacing(d->orientation, d->styleInfo);
|
||||
if (!std::isnan(d->spacingRequest)) return d->spacingRequest;
|
||||
return d->styleInfo->spacing(d->orientation);
|
||||
}
|
||||
|
||||
void SnapLayout::applySpacing() {
|
||||
Q_D(SnapLayout);
|
||||
if (!isReady()) return;
|
||||
|
||||
const QQuickWindow* win = window();
|
||||
const qreal dpr = win ? win->effectiveDevicePixelRatio() : 1.0;
|
||||
|
||||
qreal space = d->spacingRequest;
|
||||
if (std::isnan(space)) space = d->styleInfo->spacing(d->orientation);
|
||||
|
||||
if (dpr > 0.0) space = qreal(std::llround(space * dpr)) / dpr;
|
||||
|
||||
d->engine.setSpacing(space, Qt::Horizontal | Qt::Vertical);
|
||||
}
|
||||
|
||||
void SnapLayout::setSpacing(qreal space) {
|
||||
Q_D(SnapLayout);
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
if (std::isnan(space) || spacing() == space) return;
|
||||
if (std::isnan(space) || d->spacingRequest == space) return;
|
||||
#pragma GCC diagnostic pop
|
||||
d->engine.setSpacing(space, Qt::Horizontal | Qt::Vertical);
|
||||
d->spacingRequest = space;
|
||||
applySpacing();
|
||||
invalidate();
|
||||
emit spacingChanged();
|
||||
}
|
||||
@@ -242,6 +229,14 @@ void SnapLayout::updateLayoutItems() {
|
||||
Q_D(SnapLayout);
|
||||
if (!isReady()) return;
|
||||
|
||||
const auto items = childItems();
|
||||
for (auto entry = d->childSizes.begin(); entry != d->childSizes.end();) {
|
||||
if (items.contains(entry.key()))
|
||||
++entry;
|
||||
else
|
||||
entry = d->childSizes.erase(entry);
|
||||
}
|
||||
|
||||
d->engine.deleteItems();
|
||||
insertLayoutItems();
|
||||
}
|
||||
@@ -286,8 +281,8 @@ void SnapLayout::insertLayoutItems() {
|
||||
int gridRow = 0;
|
||||
int gridColumn = index;
|
||||
if (d->orientation == Qt::Vertical) qSwap(gridRow, gridColumn);
|
||||
QGridLayoutItem* layoutItem = new SnapGridLayoutItem(
|
||||
child, gridRow, gridColumn, 1, 1, alignment, this);
|
||||
QGridLayoutItem* layoutItem =
|
||||
new SnapGridLayoutItem(child, gridRow, gridColumn, 1, 1, alignment);
|
||||
|
||||
if (hStretch >= 0) {
|
||||
if (!fillWidth)
|
||||
@@ -315,6 +310,7 @@ void SnapLayout::removeGridItem(QGridLayoutItem* gridItem) {
|
||||
void SnapLayout::itemDestroyed(QQuickItem* item) {
|
||||
if (!isReady()) return;
|
||||
Q_D(SnapLayout);
|
||||
d->childSizes.remove(item);
|
||||
if (QQuickGridLayoutItem* gridItem = d->engine.findLayoutItem(item)) {
|
||||
removeGridItem(gridItem);
|
||||
delete gridItem;
|
||||
@@ -381,6 +377,98 @@ void SnapLayout::clearAncestorListeners() {
|
||||
d->ancestorListeners.clear();
|
||||
}
|
||||
|
||||
void SnapLayout::arrangeChildren() {
|
||||
Q_D(SnapLayout);
|
||||
const QQuickWindow* win = window();
|
||||
const qreal dpr = win ? win->effectiveDevicePixelRatio() : 1.0;
|
||||
if (dpr <= 0.0) return;
|
||||
|
||||
const bool horiz = d->orientation == Qt::Horizontal;
|
||||
const QPointF origin = absoluteOrigin(this);
|
||||
const qint64 originXDev = std::llround(origin.x() * dpr);
|
||||
const qint64 originYDev = std::llround(origin.y() * dpr);
|
||||
|
||||
qreal prevEndExact = 0.0;
|
||||
qint64 prevNearDev = 0;
|
||||
qint64 prevSizeDev = 0;
|
||||
bool started = false;
|
||||
|
||||
for (int i = 0; i < d->engine.itemCount(); ++i) {
|
||||
SnapGridLayoutItem* gridItem =
|
||||
static_cast<SnapGridLayoutItem*>(d->engine.itemAt(i));
|
||||
if (!gridItem->placed) continue;
|
||||
QQuickItem* child = gridItem->layoutItem();
|
||||
const QRectF& cell = gridItem->engineRect;
|
||||
|
||||
const qreal mainExact = (horiz ? cell.x() : cell.y()) * dpr;
|
||||
const qreal mainSizeExact =
|
||||
(horiz ? cell.width() : cell.height()) * dpr;
|
||||
const qreal crossExact = (horiz ? cell.y() : cell.x()) * dpr;
|
||||
const qint64 mainSizeDev = std::llround(mainSizeExact);
|
||||
const qint64 crossSizeDev =
|
||||
std::llround((horiz ? cell.height() : cell.width()) * dpr);
|
||||
const qint64 engineWidth = horiz ? mainSizeDev : crossSizeDev;
|
||||
const qint64 engineHeight = horiz ? crossSizeDev : mainSizeDev;
|
||||
|
||||
qint64 mainNear = 0;
|
||||
if (!started) {
|
||||
mainNear = std::llround(mainExact);
|
||||
started = true;
|
||||
} else {
|
||||
mainNear = prevNearDev + prevSizeDev +
|
||||
std::llround(mainExact - prevEndExact);
|
||||
}
|
||||
|
||||
const qint64 mainFarDev = std::llround(mainExact + mainSizeExact);
|
||||
|
||||
const auto stored = d->childSizes.constFind(child);
|
||||
qint64 width = engineWidth;
|
||||
qint64 height = engineHeight;
|
||||
if (horiz)
|
||||
width = std::max(mainFarDev - mainNear, qint64(0));
|
||||
else
|
||||
height = std::max(mainFarDev - mainNear, qint64(0));
|
||||
|
||||
if (stored != d->childSizes.constEnd() &&
|
||||
stored.value().engineWidth == engineWidth &&
|
||||
stored.value().engineHeight == engineHeight &&
|
||||
std::llround(child->width() * dpr) == stored.value().width &&
|
||||
std::llround(child->height() * dpr) == stored.value().height) {
|
||||
width = stored.value().width;
|
||||
height = stored.value().height;
|
||||
} else {
|
||||
d->childSizes[child] = SnapLayoutPrivate::ChildSize{
|
||||
engineWidth, engineHeight, width, height};
|
||||
}
|
||||
|
||||
prevEndExact = mainExact + mainSizeExact;
|
||||
prevNearDev = mainNear;
|
||||
prevSizeDev = horiz ? width : height;
|
||||
|
||||
const qint64 crossNear = std::llround(crossExact);
|
||||
const qint64 nearX = originXDev + (horiz ? mainNear : crossNear);
|
||||
const qint64 nearY = originYDev + (horiz ? crossNear : mainNear);
|
||||
|
||||
const QRectF snapped(
|
||||
qreal(nearX) / dpr - origin.x(),
|
||||
qreal(nearY) / dpr - origin.y(),
|
||||
qreal(width) / dpr,
|
||||
qreal(height) / dpr);
|
||||
|
||||
const QSizeF oldSize(child->width(), child->height());
|
||||
const QSizeF newSize = snapped.size();
|
||||
|
||||
child->setPosition(snapped.topLeft());
|
||||
if (newSize == oldSize) {
|
||||
if (QQuickLayout* lay = qobject_cast<QQuickLayout*>(child)) {
|
||||
if (lay->invalidatedArrangement()) lay->rearrange(newSize);
|
||||
}
|
||||
} else {
|
||||
child->setSize(newSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SnapLayout::rearrange(const QSizeF& size) {
|
||||
Q_D(SnapLayout);
|
||||
if (!isReady() || !size.isValid()) return;
|
||||
@@ -408,7 +496,11 @@ void SnapLayout::rearrange(const QSizeF& size) {
|
||||
}
|
||||
|
||||
QQuickLayout::rearrange(size);
|
||||
|
||||
for (int i = 0; i < d->engine.itemCount(); ++i)
|
||||
static_cast<SnapGridLayoutItem*>(d->engine.itemAt(i))->placed = false;
|
||||
d->engine.setGeometries(QRectF(QPointF(0, 0), size), d->styleInfo);
|
||||
arrangeChildren();
|
||||
d->rearranging = false;
|
||||
|
||||
for (auto childItem : std::as_const(d->invalidateAfterRearrange))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <QHash>
|
||||
#include <QPointer>
|
||||
#include <QtMath>
|
||||
#include <QtGui/private/qabstractlayoutstyleinfo_p.h>
|
||||
#include <QtGui/private/qgridlayoutengine_p.h>
|
||||
#include <QtQuickLayouts/private/qquickgridlayoutengine_p.h>
|
||||
@@ -20,6 +22,20 @@ class SnapLayoutStyleInfo : public QAbstractLayoutStyleInfo {
|
||||
bool hasChangedCore() const override;
|
||||
};
|
||||
|
||||
class SnapGridLayoutEngine : public QGridLayoutEngine {
|
||||
public:
|
||||
SnapGridLayoutEngine() : QGridLayoutEngine(Qt::AlignVCenter, false) {}
|
||||
|
||||
QQuickGridLayoutItem* findLayoutItem(QQuickItem* item) const {
|
||||
for (int i = int(q_items.size()) - 1; i >= 0; --i) {
|
||||
QQuickGridLayoutItem* layoutItem =
|
||||
static_cast<QQuickGridLayoutItem*>(q_items.at(i));
|
||||
if (layoutItem->layoutItem() == item) return layoutItem;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
class SnapGridLayoutItem : public QQuickGridLayoutItem {
|
||||
public:
|
||||
SnapGridLayoutItem(
|
||||
@@ -28,13 +44,12 @@ class SnapGridLayoutItem : public QQuickGridLayoutItem {
|
||||
int column,
|
||||
int rowSpan,
|
||||
int columnSpan,
|
||||
Qt::Alignment alignment,
|
||||
SnapLayout* layout);
|
||||
Qt::Alignment alignment);
|
||||
|
||||
void setGeometry(const QRectF& rect) override;
|
||||
|
||||
private:
|
||||
SnapLayout* m_layout;
|
||||
QRectF engineRect;
|
||||
bool placed = false;
|
||||
};
|
||||
|
||||
class SnapLayout : public QQuickLayout {
|
||||
@@ -101,6 +116,10 @@ class SnapLayout : public QQuickLayout {
|
||||
void insertLayoutItems();
|
||||
void removeGridItem(QGridLayoutItem* gridItem);
|
||||
|
||||
void arrangeChildren();
|
||||
|
||||
void applySpacing();
|
||||
|
||||
void updateAncestorListeners();
|
||||
void clearAncestorListeners();
|
||||
};
|
||||
@@ -113,10 +132,11 @@ class SnapLayoutPrivate : public QQuickLayoutPrivate {
|
||||
|
||||
void mirrorChange() override;
|
||||
|
||||
QQuickGridLayoutEngine engine;
|
||||
SnapGridLayoutEngine engine;
|
||||
SnapLayoutStyleInfo* styleInfo = nullptr;
|
||||
Qt::Orientation orientation = Qt::Horizontal;
|
||||
Qt::LayoutDirection layoutDirection = Qt::LeftToRight;
|
||||
qreal spacingRequest = qQNaN();
|
||||
bool rearranging = false;
|
||||
int recurRearrangeCounter = 0;
|
||||
QList<QQuickItem*> invalidateAfterRearrange;
|
||||
@@ -124,6 +144,14 @@ class SnapLayoutPrivate : public QQuickLayoutPrivate {
|
||||
QVector<QPointer<QQuickItem>> ancestorListeners;
|
||||
qint64 originResidualX = -1;
|
||||
qint64 originResidualY = -1;
|
||||
|
||||
struct ChildSize {
|
||||
qint64 engineWidth = 0;
|
||||
qint64 engineHeight = 0;
|
||||
qint64 width = 0;
|
||||
qint64 height = 0;
|
||||
};
|
||||
QHash<QQuickItem*, ChildSize> childSizes;
|
||||
};
|
||||
|
||||
} // namespace ZShell::components
|
||||
|
||||
Reference in New Issue
Block a user