┌   ┐
54
└   ┘

summaryrefslogtreecommitdiff
path: root/src/search/barsecondrowflowlayout.cpp
blob: 29e3513e896ff24d32ccadcf5237de76c77b4e12 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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;
}