Project tabs drag to reorder; tabs that don't fit gather in a menu (13.14)
This commit is contained in:
1 parent
0616f9b006
commit
3f2b99f045
15 files changed
+957
-138
No files matched your search
@@ -0,0 +1,152 @@
|
||||
#include "UI/ProjectTabLayout.h"
|
||||
#include <QtTest>
|
||||
|
||||
// projectTabOverflow is geometry: made-up ids and widths.
|
||||
namespace {
|
||||
const QUuid a = QUuid::createUuid(), b = QUuid::createUuid(), c = QUuid::createUuid(), d = QUuid::createUuid(), e = QUuid::createUuid();
|
||||
|
||||
// Every tab 100 wide.
|
||||
std::map<QUuid, double> widths(const std::vector<QUuid> &ids)
|
||||
{
|
||||
std::map<QUuid, double> result;
|
||||
for (const QUuid &id : ids)
|
||||
result.insert({id, 100});
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::function<double(int)> pill = [](int) { return 80.0; };
|
||||
|
||||
std::vector<QUuid> ids(const ProjectTabOverflow &layout)
|
||||
{
|
||||
std::vector<QUuid> result;
|
||||
for (const ProjectTabSlot &slot : layout.visible)
|
||||
result.push_back(slot.id);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<double> xs(const ProjectTabOverflow &layout)
|
||||
{
|
||||
std::vector<double> result;
|
||||
for (const ProjectTabSlot &slot : layout.visible)
|
||||
result.push_back(slot.x);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class ProjectTabLayoutTests : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void everythingFitsShowsAllTabsWithNoPill();
|
||||
void overflowHidesTheLeftmostTabsAndPillsThem();
|
||||
void selectedTabInTheHiddenSetIsPinnedRightOfThePill();
|
||||
void overflowLabelIsSingularForOneTab();
|
||||
void unmeasuredWidthShowsEverythingRatherThanGuessing();
|
||||
void aWiderSelectedTabStillFits();
|
||||
void thePillsWidthFollowsTheHiddenCount();
|
||||
};
|
||||
|
||||
void ProjectTabLayoutTests::everythingFitsShowsAllTabsWithNoPill()
|
||||
{
|
||||
const std::vector<QUuid> order{a, b, c};
|
||||
const ProjectTabOverflow result = projectTabOverflow(order, widths(order), c, 400, pill);
|
||||
QVERIFY(result.hiddenIDs.empty());
|
||||
QVERIFY(!result.pill);
|
||||
QVERIFY(ids(result) == order);
|
||||
QVERIFY((xs(result) == std::vector<double>{0, 106, 212}));
|
||||
QCOMPARE(result.contentWidth(), 312.0);
|
||||
// Exactly the room it needs still fits.
|
||||
QVERIFY(!projectTabOverflow(order, widths(order), c, 312, pill).pill);
|
||||
QVERIFY(projectTabOverflow(order, widths(order), c, 311.5, pill).pill);
|
||||
QVERIFY(projectTabOverflow({}, {}, c, 400, pill) == ProjectTabOverflow());
|
||||
QCOMPARE(ProjectTabOverflow().contentWidth(), 0.0);
|
||||
}
|
||||
|
||||
void ProjectTabLayoutTests::overflowHidesTheLeftmostTabsAndPillsThem()
|
||||
{
|
||||
const std::vector<QUuid> order{a, b, c, d, e};
|
||||
// The pill and two tabs: 292; a third needs 398.
|
||||
const ProjectTabOverflow result = projectTabOverflow(order, widths(order), e, 300, pill);
|
||||
QVERIFY((result.hiddenIDs == std::vector<QUuid>{a, b, c}));
|
||||
QVERIFY((ids(result) == std::vector<QUuid>{d, e}));
|
||||
QVERIFY((result.pill.value() == ProjectTabPillSlot{0, 80}));
|
||||
QCOMPARE(result.visible.front().x, 86.0);
|
||||
QCOMPARE(result.visible.front().width, 100.0);
|
||||
QCOMPARE(result.contentWidth(), 292.0);
|
||||
// 292 exactly still holds two; a third at 398.
|
||||
QCOMPARE(projectTabOverflow(order, widths(order), e, 292, pill).visible.size(), size_t(2));
|
||||
QCOMPARE(projectTabOverflow(order, widths(order), e, 398, pill).visible.size(), size_t(3));
|
||||
// Too narrow for even one: one tab stays.
|
||||
QVERIFY((ids(projectTabOverflow(order, widths(order), e, 50, pill)) == std::vector<QUuid>{e}));
|
||||
}
|
||||
|
||||
void ProjectTabLayoutTests::selectedTabInTheHiddenSetIsPinnedRightOfThePill()
|
||||
{
|
||||
const std::vector<QUuid> order{a, b, c, d, e};
|
||||
// a takes the first slot; d, bumped, hides in order.
|
||||
const ProjectTabOverflow result = projectTabOverflow(order, widths(order), a, 300, pill);
|
||||
QVERIFY((ids(result) == std::vector<QUuid>{a, e}));
|
||||
QVERIFY((result.hiddenIDs == std::vector<QUuid>{b, c, d}));
|
||||
QCOMPARE(result.pill.value().width, 80.0);
|
||||
QVERIFY((xs(result) == std::vector<double>{86, 192}));
|
||||
}
|
||||
|
||||
void ProjectTabLayoutTests::overflowLabelIsSingularForOneTab()
|
||||
{
|
||||
QCOMPARE(projectTabOverflowLabel(1), QString("1 more tab"));
|
||||
QCOMPARE(projectTabOverflowLabel(2), QString("2 more tabs"));
|
||||
QCOMPARE(projectTabOverflowLabel(11), QString("11 more tabs"));
|
||||
}
|
||||
|
||||
void ProjectTabLayoutTests::unmeasuredWidthShowsEverythingRatherThanGuessing()
|
||||
{
|
||||
const std::vector<QUuid> order{a, b, c, d, e};
|
||||
const ProjectTabOverflow result = projectTabOverflow(order, widths(order), a, 0, pill);
|
||||
QVERIFY(result.hiddenIDs.empty());
|
||||
QVERIFY(!result.pill);
|
||||
QCOMPARE(result.visible.size(), size_t(5));
|
||||
}
|
||||
|
||||
// A long-titled hidden tab still leaves a row that fits.
|
||||
void ProjectTabLayoutTests::aWiderSelectedTabStillFits()
|
||||
{
|
||||
std::vector<QUuid> order;
|
||||
std::map<QUuid, double> sizes;
|
||||
for (int index = 0; index < 8; ++index) {
|
||||
order.push_back(QUuid::createUuid());
|
||||
sizes.insert({order.back(), 80});
|
||||
}
|
||||
sizes[order[0]] = 190;
|
||||
const ProjectTabOverflow layout = projectTabOverflow(order, sizes, order[0], 500, [](int) { return 90.0; });
|
||||
QVERIFY2(layout.contentWidth() <= 500, qPrintable(QString::number(layout.contentWidth())));
|
||||
QCOMPARE(layout.visible.front().id, order[0]);
|
||||
// Pill 90, 190, two of 80; three would make 522.
|
||||
QVERIFY((ids(layout) == std::vector<QUuid>{order[0], order[6], order[7]}));
|
||||
QVERIFY((layout.hiddenIDs == std::vector<QUuid>{order[1], order[2], order[3], order[4], order[5]}));
|
||||
QCOMPARE(layout.contentWidth(), 90 + 6 + 190 + 6 + 80 + 6 + 80.0);
|
||||
// Wide enough, it stands alone after the pill.
|
||||
const std::vector<QUuid> five{a, b, c, d, e};
|
||||
std::map<QUuid, double> wide = widths(five);
|
||||
wide[a] = 290;
|
||||
const ProjectTabOverflow alone = projectTabOverflow(five, wide, a, 400, pill);
|
||||
QVERIFY((ids(alone) == std::vector<QUuid>{a}));
|
||||
QVERIFY((alone.hiddenIDs == std::vector<QUuid>{b, c, d, e}));
|
||||
}
|
||||
|
||||
// The pill's width is asked by its hidden count.
|
||||
void ProjectTabLayoutTests::thePillsWidthFollowsTheHiddenCount()
|
||||
{
|
||||
const std::vector<QUuid> order{a, b, c, d, e};
|
||||
std::vector<int> asked;
|
||||
const ProjectTabOverflow result = projectTabOverflow(order, widths(order), e, 300, [&](int hidden) {
|
||||
asked.push_back(hidden);
|
||||
return 50.0 + hidden;
|
||||
});
|
||||
// Three hidden fits (265); the last ask places it.
|
||||
QVERIFY((asked == std::vector<int>{0, 1, 2, 3, 3}));
|
||||
QVERIFY((ids(result) == std::vector<QUuid>{d, e}));
|
||||
QCOMPARE(result.pill.value().width, 53.0);
|
||||
QCOMPARE(result.visible.front().x, 59.0);
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(ProjectTabLayoutTests)
|
||||
#include "ProjectTabLayoutTests.moc"
|
||||
Reference in new issue
Block a user