Skip to content

Instantly share code, notes, and snippets.

@HookedBehemoth
Last active June 7, 2023 00:09
Show Gist options
  • Save HookedBehemoth/f77eb4826af96ad66ddf82c076d465eb to your computer and use it in GitHub Desktop.
Save HookedBehemoth/f77eb4826af96ad66ddf82c076d465eb to your computer and use it in GitHub Desktop.
#include "qquick_masonry.h"
MasonryLayout::MasonryLayout() : QQuickItem() {
connect(this, &QQuickItem::widthChanged, this, &MasonryLayout::handleWidthChanged);
}
void MasonryLayout::setSpacing(int32_t spacing) {
if (m_spacing == spacing) {
return;
}
m_spacing = spacing;
doPositioningAll();
}
void MasonryLayout::setElements(uint elements) {
if (m_elements == elements) {
return;
}
m_elements = elements;
doPositioningAll();
}
void MasonryLayout::itemChange(QQuickItem::ItemChange change, QQuickItem::ItemChangeData const& value) {
if (change == QQuickItem::ItemChange::ItemChildAddedChange) {
doPositioningSingle(value.item);
}
QQuickItem::itemChange(change, value);
}
void MasonryLayout::handleWidthChanged() {
doPositioningAll();
}
void MasonryLayout::doPositioningAll() {
/* We're not done layouting. */
/* TODO: find better way. */
if (width() == 0.0) {
return;
}
/* Calculate element width */
m_width = width() / m_elements - 2 * m_spacing;
/* Reset masonry row progress */
m_progress.resize(m_elements);
std::fill(
m_progress.begin(),
m_progress.end(),
m_spacing
);
setHeight(0.0);
for (auto item : childItems()) {
doPositioningSingle(item);
}
}
void MasonryLayout::doPositioningSingle(QQuickItem *item) {
if (m_progress.empty()) return;
auto it = std::min_element(m_progress.begin(), m_progress.end());
auto idx = it - m_progress.begin();
auto aspect_ratio = item->height() / item->width();
item->setWidth(m_width);
item->setHeight(aspect_ratio * m_width);
/**
* || ||| ||| ||
* ^ ^ ^
* Spacing | Start
* Double Spacing
*/
item->setX(m_spacing + (m_width + 2 * m_spacing) * idx);
item->setY(*it);
*it += item->height() + 2 * m_spacing;
if (*it > height()) {
setHeight(*it);
}
}
#pragma once
#include <QQuickItem>
class MasonryLayout : public QQuickItem {
Q_OBJECT
Q_PROPERTY(int32_t spacing READ spacing WRITE setSpacing)
Q_PROPERTY(uint elements READ elements WRITE setElements)
QML_ELEMENT
public:
MasonryLayout();
int32_t spacing() const { return m_spacing; }
void setSpacing(int32_t spacing);
uint elements() const { return m_elements; }
void setElements(uint elements);
private:
void itemChange(QQuickItem::ItemChange change, QQuickItem::ItemChangeData const& value);
void handleWidthChanged();
void doPositioningAll();
void doPositioningSingle(QQuickItem *item);
int32_t m_spacing = 0;
uint m_elements = 1;
qreal m_width;
std::vector<qreal> m_progress;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment