| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include <QWidget> |
|
|
| #include "lc_flexlayout.h" |
|
|
| LC_FlexLayout::LC_FlexLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) |
| :QLayout(parent), m_hSpacing(hSpacing), m_vSpacing(vSpacing){ |
| setContentsMargins(margin, margin, margin, margin); |
| } |
|
|
| LC_FlexLayout::LC_FlexLayout(int margin, int hSpacing, int vSpacing, int widthOfFirstColumn) |
| :m_hSpacing(hSpacing), m_vSpacing(vSpacing), m_firstColumnWidth(widthOfFirstColumn){ |
| setContentsMargins(margin, margin, margin, margin); |
| } |
|
|
| LC_FlexLayout::~LC_FlexLayout(){ |
| QLayoutItem *item; |
| while ((item = takeAt(0))) { |
| delete item; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| void LC_FlexLayout::fillFromLayout(QLayout* source){ |
| QLayoutItem* pItem = source->itemAt(0); |
| while (pItem != nullptr) { |
| QWidget* widget = pItem->widget(); |
| if (widget != nullptr){ |
| this->addWidget(widget); |
| } |
| source->removeItem(pItem); |
| pItem = source->itemAt(0); |
| } |
| } |
| bool LC_FlexLayout::hasHeightForWidth() const{ |
| return true; |
| } |
|
|
| int LC_FlexLayout::heightForWidth(int width) const{ |
| int height = performLayout(QRect(0, 0, width, 0), true); |
| return height; |
| } |
|
|
| void LC_FlexLayout::setGeometry(const QRect &rect){ |
| QLayout::setGeometry(rect); |
| performLayout(rect, false); |
| } |
|
|
| QSize LC_FlexLayout::sizeHint() const{ |
| return minimumSize(); |
| } |
|
|
| int LC_FlexLayout::performLayout(const QRect &rect, bool geometryCheck) const{ |
| int left, top, right, bottom; |
| getContentsMargins(&left, &top, &right, &bottom); |
| QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); |
| int columnX = effectiveRect.x(); |
| int rowY = effectiveRect.y(); |
| int effectiveRight = effectiveRect.right(); |
| int lineHeight = 0; |
|
|
| int size = m_items.size(); |
|
|
| std::vector<int> linesHeight; |
|
|
| int nextY = rowY; |
|
|
| |
|
|
| for (int i = 0; i < size; i++) { |
| QLayoutItem *item = std::as_const(m_items.at(i)); |
| const QWidget *wid = item->widget(); |
| QLayoutItem *itemNext = nullptr; |
| bool checkForNextBreak = false; |
| int nextIndex = i + 1; |
| if (nextIndex < size){ |
| if (m_softBreakItems.find(i) != m_softBreakItems.end()){ |
| itemNext = m_items.at(nextIndex); |
| checkForNextBreak = true; |
| } |
| } |
| int spaceX = getSpaceX(wid); |
| int spaceY = getSpaceY(wid); |
| QSize itemSizeHint = item->sizeHint(); |
| int itemHeight = itemSizeHint.height(); |
| int itemWidth = itemSizeHint.width(); |
| int nextX = columnX + itemWidth + spaceX; |
|
|
| bool doBreak = false; |
| if (checkForNextBreak){ |
| int nextWidgetNextX = nextX + itemNext->sizeHint().width(); |
| doBreak = nextWidgetNextX > effectiveRight; |
| } |
| int widgetEndX = nextX - spaceX; |
|
|
| if ((widgetEndX > effectiveRight && lineHeight > 0) || doBreak){ |
| columnX = effectiveRect.x(); |
| rowY = rowY + lineHeight + spaceY; |
| nextY = rowY; |
| if (m_fullWidthItems.find(i) != m_fullWidthItems.end()){ |
| linesHeight.emplace_back(lineHeight); |
| nextY = rowY + itemHeight + spaceY; |
| nextX = columnX; |
| } |
| else { |
| if (m_firstColumnWidth > 0){ |
| itemWidth = m_firstColumnWidth; |
| } |
| nextX = columnX + itemWidth + spaceX; |
| } |
| linesHeight.emplace_back(qMax(lineHeight, itemHeight)); |
| lineHeight = 0; |
| } |
| lineHeight = qMax(lineHeight, itemHeight); |
| rowY = nextY; |
| columnX = nextX; |
| } |
| linesHeight.emplace_back(lineHeight); |
|
|
| int result = rowY + lineHeight - rect.y() + bottom; |
|
|
| |
| |
| if (!geometryCheck){ |
| columnX = effectiveRect.x(); |
| rowY = effectiveRect.y(); |
| nextY = rowY; |
| int lineIndex = 0; |
| int currentLineHeight; |
| |
| for (int i = 0; i < size; i++) { |
| QLayoutItem *item = std::as_const(m_items.at(i)); |
| const QWidget *wid = item->widget(); |
| QLayoutItem *itemNext = nullptr; |
| bool checkForNextBreak = false; |
| int nextIndex = i + 1; |
| if (nextIndex < size){ |
| if (m_softBreakItems.find(i) != m_softBreakItems.end()){ |
| itemNext = m_items.at(nextIndex); |
| checkForNextBreak = true; |
| } |
| } |
| int spaceX = getSpaceX(wid); |
| int spaceY = getSpaceY(wid); |
| QSize itemSizeHint = item->sizeHint(); |
| currentLineHeight = linesHeight.at(lineIndex); |
| int itemWidth = itemSizeHint.width(); |
| int nextX = columnX + itemWidth + spaceX; |
|
|
| bool doBreak = false; |
| if (checkForNextBreak){ |
| int nextWidgetNextX = nextX + itemNext->sizeHint().width(); |
| doBreak = nextWidgetNextX > effectiveRight; |
| } |
| int widgetEndX = nextX - spaceX; |
|
|
| if ((widgetEndX > effectiveRight) || doBreak){ |
| columnX = effectiveRect.x(); |
| rowY = rowY + currentLineHeight + spaceY; |
| nextY = rowY; |
| if (m_fullWidthItems.find(i) != m_fullWidthItems.end()){ |
| itemWidth = effectiveRect.width(); |
| nextY = rowY + currentLineHeight + spaceY; |
| nextX = columnX; |
| } else { |
| if (m_firstColumnWidth > 0){ |
| itemWidth = m_firstColumnWidth; |
| } |
| nextX = columnX + itemWidth + spaceX; |
| } |
| lineIndex++; |
| } |
|
|
| itemSizeHint = QSize(itemWidth, currentLineHeight); |
| item->setGeometry(QRect(QPoint(columnX, rowY), itemSizeHint)); |
| rowY = nextY; |
| columnX = nextX; |
| } |
| } |
| return result; |
| } |
|
|
| int LC_FlexLayout::getSpaceY(const QWidget *wid) const{ |
| int spacingX = verticalSpacing(); |
| if (spacingX == -1) |
| spacingX = wid->style()->layoutSpacing( |
| QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); |
| return spacingX; |
| } |
|
|
| int LC_FlexLayout::getSpaceX(const QWidget *wid) const{ |
| int spacingY = horizontalSpacing(); |
| if (spacingY == -1) |
| spacingY = wid->style()->layoutSpacing( |
| QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); |
| return spacingY; |
| } |
|
|
| int LC_FlexLayout::defaultSpacing(QStyle::PixelMetric pm) const{ |
| QObject *parent = this->parent(); |
| if (!parent) { |
| return -1; |
| } else if (parent->isWidgetType()) { |
| auto *pw = dynamic_cast<QWidget *>(parent); |
| return pw->style()->pixelMetric(pm, nullptr, pw); |
| } else { |
| return dynamic_cast<QLayout *>(parent)->spacing(); |
| } |
| } |
| int LC_FlexLayout::horizontalSpacing() const{ |
| if (m_hSpacing >= 0) { |
| return m_hSpacing; |
| } else { |
| return defaultSpacing(QStyle::PM_LayoutHorizontalSpacing); |
| } |
| } |
|
|
| int LC_FlexLayout::verticalSpacing() const{ |
| if (m_vSpacing >= 0) { |
| return m_vSpacing; |
| } else { |
| return defaultSpacing(QStyle::PM_LayoutVerticalSpacing); |
| } |
| } |
| QLayoutItem*LC_FlexLayout::takeAt(int index){ |
| QLayoutItem* result = nullptr; |
| if (index >= 0 && index < m_items.size()){ |
| result = m_items.takeAt(index); |
| } |
| return result; |
| } |
|
|
| Qt::Orientations LC_FlexLayout::expandingDirections() const{ |
| return {}; |
| } |
|
|
|
|
| QSize LC_FlexLayout::minimumSize() const{ |
| QSize size; |
| for (const QLayoutItem *item : std::as_const(m_items)) |
| size = size.expandedTo(item->minimumSize()); |
|
|
| const QMargins margins = contentsMargins(); |
| size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); |
| return size; |
| } |
|
|
| void LC_FlexLayout::addItem(QLayoutItem *item){ |
| m_items.append(item); |
| } |
|
|
|
|
| int LC_FlexLayout::count() const{ |
| return m_items.size(); |
| } |
|
|
| QLayoutItem *LC_FlexLayout::itemAt(int index) const{ |
| return m_items.value(index); |
| } |
|
|