diff options
Diffstat (limited to 'src/search/barsecondrowflowlayout.cpp')
| -rw-r--r-- | src/search/barsecondrowflowlayout.cpp | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/src/search/barsecondrowflowlayout.cpp b/src/search/barsecondrowflowlayout.cpp new file mode 100644 index 000000000..29e3513e8 --- /dev/null +++ b/src/search/barsecondrowflowlayout.cpp @@ -0,0 +1,150 @@ +/* + SPDX-FileCopyrightText: 2025 Felix Ernst <[email protected]> + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#include "barsecondrowflowlayout.h" + +#include <QWidget> + +#include <vector> + +using namespace Search; + +namespace +{ +constexpr int searchLocationButtonsCount = 2; +} + +BarSecondRowFlowLayout::BarSecondRowFlowLayout(QWidget *parent) + : QLayout{parent} +{ + setContentsMargins(0, 0, 0, 0); +} + +BarSecondRowFlowLayout::~BarSecondRowFlowLayout() +{ + QLayoutItem *item; + while ((item = takeAt(0))) + delete item; +} + +void BarSecondRowFlowLayout::addItem(QLayoutItem *item) +{ + itemList.append(item); +} + +Qt::Orientations BarSecondRowFlowLayout::expandingDirections() const +{ + return {}; +} + +bool BarSecondRowFlowLayout::hasHeightForWidth() const +{ + return false; +} + +int BarSecondRowFlowLayout::count() const +{ + return itemList.size(); +} + +QLayoutItem *BarSecondRowFlowLayout::itemAt(int index) const +{ + return itemList.value(index); +} + +QSize BarSecondRowFlowLayout::sizeHint() const +{ + const QRect rect = geometry(); + QSize size; + for (const QLayoutItem *item : std::as_const(itemList)) { + size = size.expandedTo(QSize{item->geometry().right() - rect.x(), item->geometry().bottom() - rect.y()}); + } + return size; +} + +void BarSecondRowFlowLayout::setGeometry(const QRect &rect) +{ + const int oldHeightHint = sizeHint().height(); + QLayout::setGeometry(rect); + const bool isLeftToRight = itemAt(0)->widget()->layoutDirection() == Qt::LeftToRight; + int x = rect.left(); + int y = rect.top(); + + /// The search location buttons are treated differently. They are meant to be in the same row and aligned the other way. + int totalLocationButtonWidth = 0; + for (int i = 0; i < searchLocationButtonsCount; i++) { + totalLocationButtonWidth += itemAt(i)->widget()->sizeHint().width(); + } + if (totalLocationButtonWidth > rect.width()) { + /// There is not enough space so we will smush all the location buttons into the first row. + for (int i = 0; i < searchLocationButtonsCount; i++) { + QWidget *widget = itemAt(i)->widget(); + const int targetWidth = qMin(widget->sizeHint().width(), rect.width() / searchLocationButtonsCount); + widget->setGeometry(isLeftToRight ? x : rect.right() - x - targetWidth, y, targetWidth, widget->sizeHint().height()); + x += widget->width(); + } + } else { + for (int i = 0; i < searchLocationButtonsCount; i++) { + QWidget *widget = itemAt(i)->widget(); + QSize preferredSize = widget->sizeHint(); + widget->setGeometry(isLeftToRight ? x : rect.right() - x - preferredSize.width(), y, preferredSize.width(), preferredSize.height()); + x += widget->width() + spacing(); + } + } + + // We want to align all further widgets the other way. We do this by first filling up the row like usual and then moving all widgets of the current row by + // the remaining space. + std::vector<QWidget *> currentRowWidgets; + for (int i = searchLocationButtonsCount; i < count(); i++) { + QWidget *widget = itemAt(i)->widget(); + const int remainingSpace = rect.right() - x + spacing(); + if (widget->sizeHint().width() < remainingSpace) { + QSize preferredSize = widget->sizeHint(); + widget->setGeometry(isLeftToRight ? x : rect.right() - x - preferredSize.width(), y, preferredSize.width(), preferredSize.height()); + x += widget->width() + spacing(); + currentRowWidgets.push_back(widget); + continue; + } + + // There is not enough space for the next widget. We need to open up a new row. + // Right align all the widgets of the previous row. + for (QWidget *widget : std::as_const(currentRowWidgets)) { + widget->setGeometry(widget->geometry().translated(isLeftToRight ? remainingSpace : -remainingSpace, 0)); + } + currentRowWidgets.clear(); + + x = 0; + y += itemAt(i - 1)->widget()->height() + spacing(); + + QSize preferredSize = widget->sizeHint(); + const int targetWidth = qMin(preferredSize.width(), rect.width()); + widget->setGeometry(isLeftToRight ? x : rect.right() - x - targetWidth, y, targetWidth, preferredSize.height()); + x += widget->width() + spacing(); + currentRowWidgets.push_back(widget); + } + + // Right align all the widgets of the previous row. + int remainingSpace = rect.right() - x + spacing(); + for (QWidget *widget : std::as_const(currentRowWidgets)) { + widget->setGeometry(widget->geometry().translated(isLeftToRight ? remainingSpace : -remainingSpace, 0)); + } + + if (sizeHint().height() != oldHeightHint) { + Q_EMIT heightHintChanged(); + } +} + +QSize BarSecondRowFlowLayout::minimumSize() const +{ + return QSize{0, sizeHint().height()}; +} + +QLayoutItem *BarSecondRowFlowLayout::takeAt(int index) +{ + if (index >= 0 && index < itemList.size()) + return itemList.takeAt(index); + return nullptr; +} |
