Files
sloposk/tests/tst_keygeometry.cpp
T
ericek111andClaude Opus 5.5 ac0bfc2741 Keep blocks still when switching layers
- The main block reserves the width and rows of its biggest layer, so the
  numpad and function row no longer shift between letters and symbols
- Smaller layers stretch into the room: stretch keys widen, rows grow
  taller (rows above the layer, like the function row, keep their height)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:35:00 +02:00

104 lines
3.5 KiB
C++

#include "layout/KeyGeometry.h"
#include <QTest>
using namespace Qt::StringLiterals;
namespace {
KeyDef key(qreal width = 1.0, KeyType type = KeyType::Character)
{
KeyDef k;
k.type = type;
k.label = u"x"_s;
k.width = width;
return k;
}
} // namespace
class TestKeyGeometry : public QObject
{
Q_OBJECT
private Q_SLOTS:
void fillsWidthAndHeight()
{
const Layer layer{u"l"_s, {{key(), key()}, {key(2)}}};
const KeyboardMetrics metrics{.padding = 10, .gap = 10};
const auto rects = computeKeyRects(layer, {210, 110}, metrics);
QCOMPARE(rects.size(), 3);
QCOMPARE(rects[0], QRectF(10, 10, 90, 40));
QCOMPARE(rects[1], QRectF(110, 10, 90, 40));
QCOMPARE(rects[2], QRectF(10, 60, 190, 40)); // a 2-unit key spans the gap
}
void spacersShiftFollowingKeys()
{
const Layer layer{u"l"_s, {{key(), key(), key()}, {key(0.5, KeyType::Spacer), key(), key(1.5)}}};
const auto rects = computeKeyRects(layer, {300, 100}, {.padding = 0, .gap = 0});
QCOMPARE(rects[4].left(), 50.0);
QCOMPARE(rects[5].right(), 300.0);
}
void shorterRowsAreCentered()
{
const Layer layer{u"l"_s, {{key(), key(), key(), key()}, {key(), key()}}};
const auto rects = computeKeyRects(layer, {400, 100}, {.padding = 0, .gap = 0});
QCOMPARE(rects[4].left(), 100.0);
QCOMPARE(rects[5].right(), 300.0);
}
void stretchKeysFillTheRow()
{
KeyDef wide = key();
wide.stretch = true;
const Layer layer{u"l"_s, {{key(), key(), key(), key()}, {key(), wide}}};
const auto rects = computeKeyRects(layer, {400, 100}, {.padding = 0, .gap = 0});
QCOMPARE(rects[4].left(), 0.0);
QCOMPARE(rects[5].width(), 300.0);
}
void blocksShareUnitAndSitAtTheBottom()
{
const Block tall{{{key(), key()}, {key(), key()}}};
const Block shortBlock{{{key()}}};
const auto rects = computeKeyRects({tall, shortBlock}, {400, 100}, {.padding = 0, .gap = 0, .blockGap = 100});
// 3 units in 300 px: 100 each.
QCOMPARE(rects[1].right(), 200.0);
QCOMPARE(rects[4], QRectF(300, 50, 100, 50));
}
void fillingBlockSpansTheFullHeight()
{
const Block tall{{{key()}, {key()}, {key()}, {key()}}};
const Block filling{{{key()}, {key()}}, true};
const auto rects = computeKeyRects({tall, filling}, {200, 100}, {.padding = 0, .gap = 0, .blockGap = 0});
QCOMPARE(rects[0].height(), 25.0);
QCOMPARE(rects[4], QRectF(100, 0, 100, 50));
QCOMPARE(rects[5], QRectF(100, 50, 100, 50));
// A filling block taller than the rest doesn't shrink the shared rows.
QCOMPARE(totalRows({tall, filling}), 4);
QCOMPARE(totalRows({filling}), 2);
}
void reservedRoomStretchesTheRowsAfterTheFixedOnes()
{
Block reserved{{{key()}, {key()}, {key()}}};
reserved.minUnits = 2;
reserved.minRows = 5;
reserved.fixedRows = 1;
const Block side{{{key()}}};
const auto rects = computeKeyRects({reserved, side}, {300, 100}, {.padding = 0, .gap = 0, .blockGap = 0});
QCOMPARE(totalRows({reserved, side}), 5);
QCOMPARE(rects[0], QRectF(50, 0, 100, 20)); // fixed row keeps the shared height, centered in 2 units
QCOMPARE(rects[1], QRectF(50, 20, 100, 40));
QCOMPARE(rects[2], QRectF(50, 60, 100, 40));
QCOMPARE(rects[3], QRectF(200, 80, 100, 20)); // the side block doesn't move
}
};
QTEST_GUILESS_MAIN(TestKeyGeometry)
#include "tst_keygeometry.moc"