| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #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); |
| | } |
| |
|