mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2024-11-26 04:31:34 +08:00
Add flex_grow and flex_shrink.
Two new elements: - flex_grow : Expand the element to occupy free space. - flex_shrink: Minimize the element leave away missing space. flex = flex_grow | flex_shrink. Other changes: - hbox and vbox are now non flexible by default. - the vtext element has been added to help writting tests. - Many new tests.
This commit is contained in:
parent
7f7775ba62
commit
08ee49f3e6
@ -41,10 +41,10 @@ A simple C++ library for terminal based user interface.
|
||||
hbox({
|
||||
text(L"left") | border,
|
||||
text(L"middle") | border | flex,
|
||||
text(L"right") | border
|
||||
text(L"right") | border,
|
||||
}),
|
||||
gauge(0.5) | border
|
||||
})
|
||||
gauge(0.5) | border,
|
||||
});
|
||||
~~~
|
||||
|
||||
~~~bash
|
||||
|
@ -118,7 +118,7 @@ class CompilerComponent : public Component {
|
||||
L"gcc",
|
||||
L"clang",
|
||||
L"emcc",
|
||||
L"game_maker"
|
||||
L"game_maker",
|
||||
L"Ada compilers",
|
||||
L"ALGOL 60 compilers",
|
||||
L"ALGOL 68 compilers",
|
||||
@ -212,9 +212,9 @@ class CompilerComponent : public Component {
|
||||
}),
|
||||
filler(),
|
||||
}),
|
||||
hflow(RenderCommandLine()),
|
||||
hflow(RenderCommandLine()) | flex_grow,
|
||||
}) |
|
||||
border;
|
||||
flex_grow | border;
|
||||
}
|
||||
|
||||
Elements RenderCommandLine() {
|
||||
|
@ -49,7 +49,7 @@ class MyComponent : public Component {
|
||||
});
|
||||
}
|
||||
|
||||
bool OnEvent(Event event) {
|
||||
bool OnEvent(Event event) override {
|
||||
if (event == Event::Return) {
|
||||
on_enter();
|
||||
return true;
|
||||
|
@ -21,6 +21,7 @@ using GraphFunction = std::function<std::vector<int>(int, int)>;
|
||||
|
||||
// --- Widget ---
|
||||
Element text(std::wstring text);
|
||||
Element vtext(std::wstring text);
|
||||
Element separator(void);
|
||||
Element separator(Pixel);
|
||||
Element gauge(float ratio);
|
||||
@ -52,9 +53,11 @@ Element hflow(Elements);
|
||||
// -- Flexibility ---
|
||||
// Define how to share the remaining space when not all of it is used inside a
|
||||
// container.
|
||||
Element filler();
|
||||
Element flex(Element);
|
||||
Element notflex(Element);
|
||||
Element flex(Element); // Expand/Minimize if possible/needed.
|
||||
Element flex_grow(Element); // Expand element if possible.
|
||||
Element flex_shrink(Element); // Minimize element if needed.
|
||||
Element notflex(Element); // Reset the flex attribute.
|
||||
Element filler(); // A blank expandable element.
|
||||
|
||||
// -- Size override;
|
||||
enum Direction { WIDTH, HEIGHT };
|
||||
|
@ -15,8 +15,10 @@ struct Requirement {
|
||||
int min_y = 0;
|
||||
|
||||
// How much flexibility is given to the component.
|
||||
int flex_x = 0;
|
||||
int flex_y = 0;
|
||||
int flex_grow_x = 0;
|
||||
int flex_grow_y = 0;
|
||||
int flex_shrink_x = 0;
|
||||
int flex_shrink_y = 0;
|
||||
|
||||
// Focus management to support the frame/focus/select element.
|
||||
enum Selection {
|
||||
|
@ -8,19 +8,19 @@
|
||||
namespace ftxui {
|
||||
|
||||
Element hcenter(Element child) {
|
||||
return hbox(filler(), std::move(child), filler());
|
||||
return hbox(filler(), std::move(child), filler()) | flex_grow;
|
||||
}
|
||||
|
||||
Element vcenter(Element child) {
|
||||
return vbox(filler(), std::move(child), filler());
|
||||
return vbox(filler(), std::move(child), filler()) | flex_grow;
|
||||
}
|
||||
|
||||
Element center(Element child) {
|
||||
return hcenter(vcenter(std::move(child)));
|
||||
return hcenter(vcenter(std::move(child))) | flex_grow;
|
||||
}
|
||||
|
||||
Element align_right(Element child) {
|
||||
return hbox(filler(), std::move(child));
|
||||
return hbox(filler(), std::move(child)) | flex_grow;
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@ -17,8 +17,10 @@ class DBox : public Node {
|
||||
void ComputeRequirement() override {
|
||||
requirement_.min_x = 0;
|
||||
requirement_.min_y = 0;
|
||||
requirement_.flex_x = 1;
|
||||
requirement_.flex_y = 0;
|
||||
requirement_.flex_grow_x = 0;
|
||||
requirement_.flex_grow_y = 0;
|
||||
requirement_.flex_shrink_x = 0;
|
||||
requirement_.flex_shrink_y = 0;
|
||||
for (auto& child : children) {
|
||||
child->ComputeRequirement();
|
||||
requirement_.min_x =
|
||||
|
@ -7,10 +7,36 @@
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
using FlexFunction = void (*)(Requirement&);
|
||||
|
||||
void function_flex_grow(Requirement& r) {
|
||||
r.flex_grow_x = 1;
|
||||
r.flex_grow_y = 1;
|
||||
}
|
||||
|
||||
void function_flex_shrink(Requirement& r) {
|
||||
r.flex_shrink_x = 1;
|
||||
r.flex_shrink_y = 1;
|
||||
}
|
||||
|
||||
void function_flex(Requirement& r) {
|
||||
r.flex_grow_x = 1;
|
||||
r.flex_grow_y = 1;
|
||||
r.flex_shrink_x = 1;
|
||||
r.flex_shrink_y = 1;
|
||||
}
|
||||
|
||||
void function_not_flex(Requirement& r) {
|
||||
r.flex_grow_x = 0;
|
||||
r.flex_grow_y = 0;
|
||||
r.flex_shrink_x = 0;
|
||||
r.flex_shrink_y = 0;
|
||||
}
|
||||
|
||||
class Flex : public Node {
|
||||
public:
|
||||
Flex() {}
|
||||
Flex(Element child) : Node(unpack(std::move(child))) {}
|
||||
Flex(FlexFunction f) { f_ = f; }
|
||||
Flex(FlexFunction f, Element child) : Node(unpack(std::move(child))), f_(f) {}
|
||||
~Flex() override {}
|
||||
void ComputeRequirement() override {
|
||||
requirement_.min_x = 0;
|
||||
@ -19,8 +45,7 @@ class Flex : public Node {
|
||||
children[0]->ComputeRequirement();
|
||||
requirement_ = children[0]->requirement();
|
||||
}
|
||||
requirement_.flex_x = 1;
|
||||
requirement_.flex_y = 1;
|
||||
f_(requirement_);
|
||||
}
|
||||
|
||||
void SetBox(Box box) override {
|
||||
@ -28,35 +53,28 @@ class Flex : public Node {
|
||||
return;
|
||||
children[0]->SetBox(box);
|
||||
}
|
||||
};
|
||||
|
||||
class NotFlex : public Flex {
|
||||
public:
|
||||
NotFlex() {}
|
||||
NotFlex(Element child) : Flex(std::move(child)) {}
|
||||
~NotFlex() override {}
|
||||
void ComputeRequirement() override {
|
||||
requirement_.min_x = 0;
|
||||
requirement_.min_y = 0;
|
||||
if (!children.empty()) {
|
||||
children[0]->ComputeRequirement();
|
||||
requirement_ = children[0]->requirement();
|
||||
}
|
||||
requirement_.flex_x = 0;
|
||||
requirement_.flex_y = 0;
|
||||
}
|
||||
FlexFunction f_;
|
||||
};
|
||||
|
||||
Element filler() {
|
||||
return std::make_shared<Flex>();
|
||||
return std::make_shared<Flex>(function_flex);
|
||||
}
|
||||
|
||||
Element flex(Element child) {
|
||||
return std::make_shared<Flex>(std::move(child));
|
||||
return std::make_shared<Flex>(function_flex, std::move(child));
|
||||
}
|
||||
|
||||
Element flex_grow(Element child) {
|
||||
return std::make_shared<Flex>(function_flex_grow, std::move(child));
|
||||
}
|
||||
|
||||
Element flex_shrink(Element child) {
|
||||
return std::make_shared<Flex>(function_flex_shrink, std::move(child));
|
||||
}
|
||||
|
||||
Element notflex(Element child) {
|
||||
return std::make_shared<NotFlex>(std::move(child));
|
||||
return std::make_shared<Flex>(function_not_flex, std::move(child));
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@ -15,7 +15,11 @@ class Gauge : public Node {
|
||||
~Gauge() override {}
|
||||
|
||||
void ComputeRequirement() override {
|
||||
requirement_.flex_x = 1;
|
||||
requirement_.flex_grow_x = 1;
|
||||
requirement_.flex_grow_y = 0;
|
||||
requirement_.flex_shrink_x = 1;
|
||||
requirement_.flex_shrink_y = 0;
|
||||
requirement_.min_x = 1;
|
||||
requirement_.min_y = 1;
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,12 @@ class Graph : public Node {
|
||||
~Graph() override {}
|
||||
|
||||
void ComputeRequirement() override {
|
||||
requirement_.flex_x = 1;
|
||||
requirement_.flex_y = 1;
|
||||
requirement_.min_x = 1;
|
||||
requirement_.min_y = 1;
|
||||
requirement_.flex_grow_x = 1;
|
||||
requirement_.flex_grow_y = 1;
|
||||
requirement_.flex_shrink_x = 1;
|
||||
requirement_.flex_shrink_y = 1;
|
||||
requirement_.min_x = 3;
|
||||
requirement_.min_y = 3;
|
||||
}
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
|
@ -17,8 +17,10 @@ class HBox : public Node {
|
||||
void ComputeRequirement() override {
|
||||
requirement_.min_x = 0;
|
||||
requirement_.min_y = 0;
|
||||
requirement_.flex_x = 1;
|
||||
requirement_.flex_y = 0;
|
||||
requirement_.flex_grow_x = 0;
|
||||
requirement_.flex_grow_y = 0;
|
||||
requirement_.flex_shrink_x = 0;
|
||||
requirement_.flex_shrink_y = 0;
|
||||
for (auto& child : children) {
|
||||
child->ComputeRequirement();
|
||||
if (requirement_.selection < child->requirement().selection) {
|
||||
@ -36,31 +38,89 @@ class HBox : public Node {
|
||||
void SetBox(Box box) override {
|
||||
Node::SetBox(box);
|
||||
|
||||
int flex_sum = 0;
|
||||
for (auto& child : children)
|
||||
flex_sum += child->requirement().flex_x;
|
||||
|
||||
int space = box.x_max - box.x_min + 1;
|
||||
int extra_space = space - requirement_.min_x;
|
||||
|
||||
int remaining_flex = flex_sum;
|
||||
int remaining_extra_space = extra_space;
|
||||
int size = 0;
|
||||
int flex_grow_sum = 0;
|
||||
int flex_shrink_sum = 0;
|
||||
int flex_shrink_size = 0;
|
||||
for (auto& child : children) {
|
||||
const Requirement& r = child->requirement();
|
||||
flex_grow_sum += r.flex_grow_x;
|
||||
flex_shrink_sum += r.min_x * r.flex_shrink_x;
|
||||
if (r.flex_shrink_x) {
|
||||
flex_shrink_size += r.min_x;
|
||||
}
|
||||
size += r.min_x;
|
||||
}
|
||||
|
||||
if (extra_space >= 0)
|
||||
SetBoxGrow(box, extra_space, flex_grow_sum);
|
||||
else if (flex_shrink_size + extra_space >= 0)
|
||||
SetBoxShrinkEasy(box, extra_space, flex_shrink_sum);
|
||||
else
|
||||
SetBoxShrinkHard(box, extra_space + flex_shrink_size,
|
||||
size - flex_shrink_size);
|
||||
}
|
||||
|
||||
void SetBoxGrow(Box box, int extra_space, int flex_grow_sum) {
|
||||
int x = box.x_min;
|
||||
for (auto& child : children) {
|
||||
Box child_box = box;
|
||||
const Requirement& r = child->requirement();
|
||||
|
||||
int added_space =
|
||||
extra_space * r.flex_grow_x / std::max(flex_grow_sum, 1);
|
||||
extra_space -= added_space;
|
||||
flex_grow_sum -= r.flex_grow_x;
|
||||
|
||||
child_box.x_min = x;
|
||||
child_box.x_max = x + r.min_x + added_space - 1;
|
||||
|
||||
child_box.x_max = x + child->requirement().min_x - 1;
|
||||
child->SetBox(child_box);
|
||||
x = child_box.x_max + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (child->requirement().flex_x) {
|
||||
int added_space = remaining_extra_space * child->requirement().flex_x /
|
||||
remaining_flex;
|
||||
remaining_extra_space -= added_space;
|
||||
remaining_flex -= child->requirement().flex_x;
|
||||
child_box.x_max += added_space;
|
||||
void SetBoxShrinkEasy(Box box, int extra_space, int flex_shrink_sum) {
|
||||
int x = box.x_min;
|
||||
for (auto& child : children) {
|
||||
Box child_box = box;
|
||||
const Requirement& r = child->requirement();
|
||||
|
||||
int added_space = extra_space * r.min_x * r.flex_shrink_x /
|
||||
std::max(flex_shrink_sum, 1);
|
||||
extra_space -= added_space;
|
||||
flex_shrink_sum -= r.flex_shrink_x * r.min_x;
|
||||
|
||||
child_box.x_min = x;
|
||||
child_box.x_max = x + r.min_x + added_space - 1;
|
||||
|
||||
child->SetBox(child_box);
|
||||
x = child_box.x_max + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void SetBoxShrinkHard(Box box, int extra_space, int size) {
|
||||
int x = box.x_min;
|
||||
for (auto& child : children) {
|
||||
Box child_box = box;
|
||||
const Requirement& r = child->requirement();
|
||||
|
||||
if (r.flex_shrink_x) {
|
||||
child_box.x_min = x;
|
||||
child_box.x_max = x - 1;
|
||||
child->SetBox(child_box);
|
||||
continue;
|
||||
}
|
||||
child_box.x_max = std::min(child_box.x_max, box.x_max);
|
||||
|
||||
int added_space = extra_space * r.min_x / std::max(1, size);
|
||||
extra_space -= added_space;
|
||||
size -= r.min_x;
|
||||
|
||||
child_box.x_min = x;
|
||||
child_box.x_max = x + r.min_x + added_space - 1;
|
||||
|
||||
child->SetBox(child_box);
|
||||
x = child_box.x_max + 1;
|
||||
|
@ -9,81 +9,347 @@
|
||||
using namespace ftxui;
|
||||
using namespace ftxui;
|
||||
|
||||
TEST(HBoxTest, ScreenSmaller1) {
|
||||
auto root = hbox(text(L"text_1"), text(L"text_2"));
|
||||
Screen screen(11, 1);
|
||||
Render(screen, root);
|
||||
TEST(HBoxTest, NoFlex_NoFlex_NoFlex) {
|
||||
auto root = hbox({
|
||||
text(L"012"),
|
||||
text(L"abc"),
|
||||
text(L"ABC"),
|
||||
});
|
||||
|
||||
EXPECT_EQ("text_1text_", screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(i, 1);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], screen.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HBoxTest, ScreenSmaller2) {
|
||||
auto root = hbox(text(L"text_1"), text(L"text_2"));
|
||||
Screen screen(10, 1);
|
||||
Render(screen, root);
|
||||
TEST(HBoxTest, FlexGrow_NoFlex_NoFlex) {
|
||||
auto root = hbox({
|
||||
text(L"012") | flex_grow,
|
||||
text(L"abc"),
|
||||
text(L"ABC"),
|
||||
});
|
||||
|
||||
EXPECT_EQ("text_1text", screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012 abcABC", //
|
||||
"012 abcABC", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(i, 1);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], screen.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HBoxTest, ScreenFit) {
|
||||
auto root = hbox(text(L"text_1"), text(L"text_2"));
|
||||
Screen screen(12, 1);
|
||||
Render(screen, root);
|
||||
TEST(HBoxTest, NoFlex_FlexGrow_NoFlex) {
|
||||
auto root = hbox({
|
||||
text(L"012"),
|
||||
text(L"abc") | flex_grow,
|
||||
text(L"ABC"),
|
||||
});
|
||||
|
||||
EXPECT_EQ("text_1text_2", screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abc ABC", //
|
||||
"012abc ABC", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(i, 1);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], screen.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HBoxTest, ScreenBigger1) {
|
||||
auto root = hbox(text(L"text_1"), text(L"text_2"));
|
||||
Screen screen(13, 1);
|
||||
Render(screen, root);
|
||||
TEST(HBoxTest, NoFlex_NoFlex_FlexGrow) {
|
||||
auto root = hbox({
|
||||
text(L"012"),
|
||||
text(L"abc"),
|
||||
text(L"ABC") | flex_grow,
|
||||
});
|
||||
|
||||
EXPECT_EQ("text_1text_2 ", screen.ToString());
|
||||
}
|
||||
TEST(HBoxTest, ScreenBigger2) {
|
||||
auto root = hbox(text(L"text_1"), text(L"text_2"));
|
||||
Screen screen(14, 1);
|
||||
Render(screen, root);
|
||||
|
||||
EXPECT_EQ("text_1text_2 ", screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(i, 1);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], screen.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HBoxTest, ScreenSmaller1Flex) {
|
||||
auto root = hbox(text(L"text_1"), filler(), text(L"text_2"));
|
||||
Screen screen(11, 1);
|
||||
Render(screen, root);
|
||||
TEST(HBoxTest, FlexGrow_NoFlex_FlexGrow) {
|
||||
auto root = hbox({
|
||||
text(L"012") | flex_grow,
|
||||
text(L"abc"),
|
||||
text(L"ABC") | flex_grow,
|
||||
});
|
||||
|
||||
EXPECT_EQ("text_text_2", screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012 abcABC ", //
|
||||
"012 abcABC ", //
|
||||
"012 abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(i, 1);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], screen.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HBoxTest, ScreenSmaller2Flex) {
|
||||
auto root = hbox(text(L"text_1"), filler(), text(L"text_2"));
|
||||
Screen screen(10, 1);
|
||||
Render(screen, root);
|
||||
TEST(HBoxTest, FlexGrow_FlexGrow_FlexGrow) {
|
||||
auto root = hbox({
|
||||
text(L"012") | flex_grow,
|
||||
text(L"abc") | flex_grow,
|
||||
text(L"ABC") | flex_grow,
|
||||
});
|
||||
|
||||
EXPECT_EQ("texttext_2", screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abc ABC ", //
|
||||
"012 abc ABC ", //
|
||||
"012 abc ABC ", //
|
||||
"012 abc ABC ", //
|
||||
"012 abc ABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(i, 1);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], screen.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HBoxTest, ScreenFitFlex) {
|
||||
auto root = hbox(text(L"text_1"), filler(), text(L"text_2"));
|
||||
Screen screen(12, 1);
|
||||
Render(screen, root);
|
||||
// ------
|
||||
|
||||
EXPECT_EQ("text_1text_2", screen.ToString());
|
||||
TEST(HBoxTest, FlexShrink_NoFlex_NoFlex) {
|
||||
auto root = hbox({
|
||||
text(L"012") | flex_shrink,
|
||||
text(L"abc"),
|
||||
text(L"ABC"),
|
||||
});
|
||||
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"a", //
|
||||
"aA", //
|
||||
"abA", //
|
||||
"abAB", //
|
||||
"abcAB", //
|
||||
"abcABC", //
|
||||
"0abcABC", //
|
||||
"01abcABC", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(i, 1);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], screen.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HBoxTest, ScreenBigger1Flex) {
|
||||
auto root = hbox(text(L"text_1"), filler(), text(L"text_2"));
|
||||
Screen screen(13, 1);
|
||||
Render(screen, root);
|
||||
TEST(HBoxTest, NoFlex_FlexShrink_NoFlex) {
|
||||
auto root = hbox({
|
||||
text(L"012"),
|
||||
text(L"abc") | flex_shrink,
|
||||
text(L"ABC"),
|
||||
});
|
||||
|
||||
EXPECT_EQ("text_1 text_2", screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0A", //
|
||||
"01A", //
|
||||
"01AB", //
|
||||
"012AB", //
|
||||
"012ABC", //
|
||||
"012aABC", //
|
||||
"012abABC", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(i, 1);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], screen.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HBoxTest, ScreenBigger2Flex) {
|
||||
auto root = hbox(text(L"text_1"), filler(), text(L"text_2"));
|
||||
Screen screen(14, 1);
|
||||
Render(screen, root);
|
||||
TEST(HBoxTest, NoFlex_NoFlex_FlexShrink) {
|
||||
auto root = hbox({
|
||||
text(L"012"),
|
||||
text(L"abc"),
|
||||
text(L"ABC") | flex_shrink,
|
||||
});
|
||||
|
||||
EXPECT_EQ("text_1 text_2", screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"01a", //
|
||||
"01ab", //
|
||||
"012ab", //
|
||||
"012abc", //
|
||||
"012abcA", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(i, 1);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], screen.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HBoxTest, FlexShrink_NoFlex_FlexShrink) {
|
||||
auto root = hbox({
|
||||
text(L"012") | flex_shrink,
|
||||
text(L"abc"),
|
||||
text(L"ABC") | flex_shrink,
|
||||
});
|
||||
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"a", //
|
||||
"ab", //
|
||||
"abc", //
|
||||
"0abc", //
|
||||
"0abcA", //
|
||||
"01abcA", //
|
||||
"01abcAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(i, 1);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], screen.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HBoxTest, FlexShrink_FlexShrink_FlexShrink) {
|
||||
auto root = hbox({
|
||||
text(L"012") | flex_shrink,
|
||||
text(L"abc") | flex_shrink,
|
||||
text(L"ABC") | flex_shrink,
|
||||
});
|
||||
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(i, 1);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], screen.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HBoxTest, FlexGrow_NoFlex_FlewShrink) {
|
||||
auto root = hbox({
|
||||
text(L"012") | flex_grow,
|
||||
text(L"abc"),
|
||||
text(L"ABC") | flex_shrink,
|
||||
});
|
||||
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"01a", //
|
||||
"01ab", //
|
||||
"012ab", //
|
||||
"012abc", //
|
||||
"012abcA", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012 abcABC", //
|
||||
"012 abcABC", //
|
||||
"012 abcABC", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(i, 1);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], screen.ToString());
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,12 @@ class HFlow : public Node {
|
||||
~HFlow() {}
|
||||
|
||||
void ComputeRequirement() override {
|
||||
requirement_.min_x = 0;
|
||||
requirement_.min_y = 0;
|
||||
requirement_.flex_x = 1;
|
||||
requirement_.flex_y = 1;
|
||||
requirement_.min_x = 1;
|
||||
requirement_.min_y = 1;
|
||||
requirement_.flex_grow_x = 1;
|
||||
requirement_.flex_grow_y = 1;
|
||||
requirement_.flex_shrink_x = 0;
|
||||
requirement_.flex_shrink_y = 0;
|
||||
for (auto& child : children)
|
||||
child->ComputeRequirement();
|
||||
}
|
||||
|
@ -37,10 +37,13 @@ class Size : public Node {
|
||||
break;
|
||||
}
|
||||
|
||||
if (direction_ == WIDTH)
|
||||
requirement_.flex_x = 0;
|
||||
else
|
||||
requirement_.flex_y = 0;
|
||||
if (direction_ == WIDTH) {
|
||||
requirement_.flex_grow_x = 0;
|
||||
requirement_.flex_shrink_x = 0;
|
||||
} else {
|
||||
requirement_.flex_grow_y = 0;
|
||||
requirement_.flex_shrink_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SetBox(Box box) override {
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "ftxui/dom/node.hpp"
|
||||
#include "ftxui/screen/string.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
@ -36,8 +37,43 @@ class Text : public Node {
|
||||
std::wstring text_;
|
||||
};
|
||||
|
||||
class VText : public Node {
|
||||
public:
|
||||
VText(std::wstring text) : Node(), text_(text) {
|
||||
for (auto& c : text_)
|
||||
width_ = std::max(width_, wchar_width(c));
|
||||
}
|
||||
~VText() {}
|
||||
|
||||
void ComputeRequirement() override {
|
||||
requirement_.min_x = width_;
|
||||
requirement_.min_y = text_.size();
|
||||
}
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
int x = box_.x_min;
|
||||
int y = box_.y_min;
|
||||
if (x + width_ - 1 > box_.x_max)
|
||||
return;
|
||||
for (wchar_t c : text_) {
|
||||
if (y > box_.y_max)
|
||||
return;
|
||||
screen.at(x, y) = c;
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::wstring text_;
|
||||
int width_ = 1;
|
||||
};
|
||||
|
||||
Element text(std::wstring text) {
|
||||
return std::make_shared<Text>(text);
|
||||
}
|
||||
|
||||
Element vtext(std::wstring text) {
|
||||
return std::make_shared<VText>(text);
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@ -15,11 +15,13 @@ class VBox : public Node {
|
||||
VBox(Elements children) : Node(std::move(children)) {}
|
||||
~VBox() {}
|
||||
|
||||
void ComputeRequirement() {
|
||||
void ComputeRequirement() override {
|
||||
requirement_.min_x = 0;
|
||||
requirement_.min_y = 0;
|
||||
requirement_.flex_x = 0;
|
||||
requirement_.flex_y = 1;
|
||||
requirement_.flex_grow_x = 0;
|
||||
requirement_.flex_grow_y = 0;
|
||||
requirement_.flex_shrink_x = 0;
|
||||
requirement_.flex_shrink_y = 0;
|
||||
for (auto& child : children) {
|
||||
child->ComputeRequirement();
|
||||
if (requirement_.selection < child->requirement().selection) {
|
||||
@ -34,34 +36,92 @@ class VBox : public Node {
|
||||
}
|
||||
}
|
||||
|
||||
void SetBox(Box box) {
|
||||
void SetBox(Box box) override {
|
||||
Node::SetBox(box);
|
||||
|
||||
int flex_sum = 0;
|
||||
for (auto& child : children)
|
||||
flex_sum += child->requirement().flex_y;
|
||||
|
||||
int space = box.y_max - box.y_min + 1;
|
||||
int extra_space = space - requirement_.min_y;
|
||||
|
||||
int remaining_flex = flex_sum;
|
||||
int remaining_extra_space = extra_space;
|
||||
int size = 0;
|
||||
int flex_grow_sum = 0;
|
||||
int flex_shrink_sum = 0;
|
||||
int flex_shrink_size = 0;
|
||||
for (auto& child : children) {
|
||||
const Requirement& r = child->requirement();
|
||||
flex_grow_sum += r.flex_grow_y;
|
||||
flex_shrink_sum += r.min_y * r.flex_shrink_y;
|
||||
if (r.flex_shrink_y) {
|
||||
flex_shrink_size += r.min_y;
|
||||
}
|
||||
size += r.min_y;
|
||||
}
|
||||
|
||||
if (extra_space >= 0)
|
||||
SetBoxGrow(box, extra_space, flex_grow_sum);
|
||||
else if (flex_shrink_size + extra_space >= 0)
|
||||
SetBoxShrinkEasy(box, extra_space, flex_shrink_sum);
|
||||
else
|
||||
SetBoxShrinkHard(box, extra_space + flex_shrink_size,
|
||||
size - flex_shrink_size);
|
||||
}
|
||||
|
||||
void SetBoxGrow(Box box, int extra_space, int flex_grow_sum) {
|
||||
int y = box.y_min;
|
||||
for (auto& child : children) {
|
||||
Box child_box = box;
|
||||
const Requirement& r = child->requirement();
|
||||
|
||||
int added_space =
|
||||
extra_space * r.flex_grow_y / std::max(flex_grow_sum, 1);
|
||||
extra_space -= added_space;
|
||||
flex_grow_sum -= r.flex_grow_y;
|
||||
|
||||
child_box.y_min = y;
|
||||
child_box.y_max = y + r.min_y + added_space - 1;
|
||||
|
||||
child_box.y_max = y + child->requirement().min_y - 1;
|
||||
child->SetBox(child_box);
|
||||
y = child_box.y_max + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (child->requirement().flex_y) {
|
||||
int added_space = remaining_extra_space * child->requirement().flex_y /
|
||||
remaining_flex;
|
||||
remaining_extra_space -= added_space;
|
||||
remaining_flex -= child->requirement().flex_y;
|
||||
child_box.y_max += added_space;
|
||||
void SetBoxShrinkEasy(Box box, int extra_space, int flex_shrink_sum) {
|
||||
int y = box.y_min;
|
||||
for (auto& child : children) {
|
||||
Box child_box = box;
|
||||
const Requirement& r = child->requirement();
|
||||
|
||||
int added_space = extra_space * r.min_y * r.flex_shrink_y /
|
||||
std::max(flex_shrink_sum, 1);
|
||||
extra_space -= added_space;
|
||||
flex_shrink_sum -= r.flex_shrink_y * r.min_y;
|
||||
|
||||
child_box.y_min = y;
|
||||
child_box.y_max = y + r.min_y + added_space - 1;
|
||||
|
||||
child->SetBox(child_box);
|
||||
y = child_box.y_max + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void SetBoxShrinkHard(Box box, int extra_space, int size) {
|
||||
int y = box.y_min;
|
||||
for (auto& child : children) {
|
||||
Box child_box = box;
|
||||
const Requirement& r = child->requirement();
|
||||
|
||||
if (r.flex_shrink_y) {
|
||||
child_box.y_min = y;
|
||||
child_box.y_max = y - 1;
|
||||
child->SetBox(child_box);
|
||||
continue;
|
||||
}
|
||||
child_box.y_max = std::min(child_box.y_max, box.y_max);
|
||||
|
||||
int added_space = extra_space * r.min_y / std::max(1, size);
|
||||
extra_space -= added_space;
|
||||
size -= r.min_y;
|
||||
|
||||
child_box.y_min = y;
|
||||
child_box.y_max = y + r.min_y + added_space - 1;
|
||||
|
||||
child->SetBox(child_box);
|
||||
y = child_box.y_max + 1;
|
||||
|
@ -9,70 +9,352 @@
|
||||
using namespace ftxui;
|
||||
using namespace ftxui;
|
||||
|
||||
TEST(VBoxTest, ScreenSmaller1) {
|
||||
auto root = vbox(text(L"text_1"), text(L"text_2"));
|
||||
Screen screen(6, 1);
|
||||
Render(screen, root);
|
||||
|
||||
EXPECT_EQ("text_1", screen.ToString());
|
||||
std::string rotate(std::string str) {
|
||||
str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
|
||||
return str;
|
||||
}
|
||||
|
||||
TEST(VBoxTest, ScreenFit) {
|
||||
auto root = vbox(text(L"text_1"), text(L"text_2"));
|
||||
Screen screen(6, 2);
|
||||
Render(screen, root);
|
||||
TEST(VBoxText, NoFlex_NoFlex_NoFlex) {
|
||||
auto root = vbox({
|
||||
vtext(L"012"),
|
||||
vtext(L"abc"),
|
||||
vtext(L"ABC"),
|
||||
});
|
||||
|
||||
EXPECT_EQ("text_1\ntext_2", screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(1, i);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], rotate(screen.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VBoxTest, ScreenBigger1) {
|
||||
auto root = vbox(text(L"text_1"), text(L"text_2"));
|
||||
Screen screen(6, 3);
|
||||
Render(screen, root);
|
||||
TEST(VBoxText, FlexGrow_NoFlex_NoFlex) {
|
||||
auto root = vbox({
|
||||
vtext(L"012") | flex_grow,
|
||||
vtext(L"abc"),
|
||||
vtext(L"ABC"),
|
||||
});
|
||||
|
||||
EXPECT_EQ("text_1\ntext_2\n ", screen.ToString());
|
||||
}
|
||||
TEST(VBoxTest, ScreenBigger2) {
|
||||
auto root = vbox(text(L"text_1"), text(L"text_2"));
|
||||
Screen screen(6, 4);
|
||||
Render(screen, root);
|
||||
|
||||
EXPECT_EQ("text_1\ntext_2\n \n ", screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012 abcABC", //
|
||||
"012 abcABC", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(1, i);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], rotate(screen.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VBoxTest, ScreenSmaller1Flex) {
|
||||
auto root = vbox(text(L"text_1"), filler(), text(L"text_2"));
|
||||
Screen screen(6, 1);
|
||||
Render(screen, root);
|
||||
TEST(VBoxText, NoFlex_FlexGrow_NoFlex) {
|
||||
auto root = vbox({
|
||||
vtext(L"012"),
|
||||
vtext(L"abc") | flex_grow,
|
||||
vtext(L"ABC"),
|
||||
});
|
||||
|
||||
EXPECT_EQ("text_2", screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abc ABC", //
|
||||
"012abc ABC", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(1, i);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], rotate(screen.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VBoxTest, ScreenFitFlex) {
|
||||
auto root = vbox(text(L"text_1"), filler(), text(L"text_2"));
|
||||
Screen screen(7, 5);
|
||||
Render(screen, root);
|
||||
TEST(VBoxText, NoFlex_NoFlex_FlexGrow) {
|
||||
auto root = vbox({
|
||||
vtext(L"012"),
|
||||
vtext(L"abc"),
|
||||
vtext(L"ABC") | flex_grow,
|
||||
});
|
||||
|
||||
EXPECT_EQ(
|
||||
"text_1 \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
"text_2 ",
|
||||
screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(1, i);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], rotate(screen.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VBoxTest, ScreenBigger1Flex) {
|
||||
auto root = vbox(text(L"text_1"), filler(), text(L"text_2"));
|
||||
Screen screen(6, 3);
|
||||
Render(screen, root);
|
||||
TEST(VBoxText, FlexGrow_NoFlex_FlexGrow) {
|
||||
auto root = vbox({
|
||||
vtext(L"012") | flex_grow,
|
||||
vtext(L"abc"),
|
||||
vtext(L"ABC") | flex_grow,
|
||||
});
|
||||
|
||||
EXPECT_EQ("text_1\n \ntext_2", screen.ToString());
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012 abcABC ", //
|
||||
"012 abcABC ", //
|
||||
"012 abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(1, i);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], rotate(screen.ToString()));
|
||||
}
|
||||
}
|
||||
TEST(VBoxTest, ScreenBigger2Flex) {
|
||||
auto root = vbox(text(L"text_1"), filler(), text(L"text_2"));
|
||||
Screen screen(6, 4);
|
||||
Render(screen, root);
|
||||
|
||||
EXPECT_EQ("text_1\n \n \ntext_2", screen.ToString());
|
||||
TEST(VBoxText, FlexGrow_FlexGrow_FlexGrow) {
|
||||
auto root = vbox({
|
||||
vtext(L"012") | flex_grow,
|
||||
vtext(L"abc") | flex_grow,
|
||||
vtext(L"ABC") | flex_grow,
|
||||
});
|
||||
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abc ABC ", //
|
||||
"012 abc ABC ", //
|
||||
"012 abc ABC ", //
|
||||
"012 abc ABC ", //
|
||||
"012 abc ABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(1, i);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], rotate(screen.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
// ------
|
||||
|
||||
TEST(VBoxText, FlexShrink_NoFlex_NoFlex) {
|
||||
auto root = vbox({
|
||||
vtext(L"012") | flex_shrink,
|
||||
vtext(L"abc"),
|
||||
vtext(L"ABC"),
|
||||
});
|
||||
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"a", //
|
||||
"aA", //
|
||||
"abA", //
|
||||
"abAB", //
|
||||
"abcAB", //
|
||||
"abcABC", //
|
||||
"0abcABC", //
|
||||
"01abcABC", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(1, i);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], rotate(screen.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VBoxText, NoFlex_FlexShrink_NoFlex) {
|
||||
auto root = vbox({
|
||||
vtext(L"012"),
|
||||
vtext(L"abc") | flex_shrink,
|
||||
vtext(L"ABC"),
|
||||
});
|
||||
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0A", //
|
||||
"01A", //
|
||||
"01AB", //
|
||||
"012AB", //
|
||||
"012ABC", //
|
||||
"012aABC", //
|
||||
"012abABC", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(1, i);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], rotate(screen.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VBoxText, NoFlex_NoFlex_FlexShrink) {
|
||||
auto root = vbox({
|
||||
vtext(L"012"),
|
||||
vtext(L"abc"),
|
||||
vtext(L"ABC") | flex_shrink,
|
||||
});
|
||||
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"01a", //
|
||||
"01ab", //
|
||||
"012ab", //
|
||||
"012abc", //
|
||||
"012abcA", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(1, i);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], rotate(screen.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VBoxText, FlexShrink_NoFlex_FlexShrink) {
|
||||
auto root = vbox({
|
||||
vtext(L"012") | flex_shrink,
|
||||
vtext(L"abc"),
|
||||
vtext(L"ABC") | flex_shrink,
|
||||
});
|
||||
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"a", //
|
||||
"ab", //
|
||||
"abc", //
|
||||
"0abc", //
|
||||
"0abcA", //
|
||||
"01abcA", //
|
||||
"01abcAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(1, i);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], rotate(screen.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VBoxText, FlexShrink_FlexShrink_FlexShrink) {
|
||||
auto root = vbox({
|
||||
vtext(L"012") | flex_shrink,
|
||||
vtext(L"abc") | flex_shrink,
|
||||
vtext(L"ABC") | flex_shrink,
|
||||
});
|
||||
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"0aA", //
|
||||
"01aA", //
|
||||
"01abA", //
|
||||
"01abAB", //
|
||||
"012abAB", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
"012abcABC ", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(1, i);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], rotate(screen.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VBoxText, FlexGrow_NoFlex_FlewShrink) {
|
||||
auto root = vbox({
|
||||
vtext(L"012") | flex_grow,
|
||||
vtext(L"abc"),
|
||||
vtext(L"ABC") | flex_shrink,
|
||||
});
|
||||
|
||||
std::vector<std::string> expectations = {
|
||||
"", //
|
||||
"0", //
|
||||
"0a", //
|
||||
"01a", //
|
||||
"01ab", //
|
||||
"012ab", //
|
||||
"012abc", //
|
||||
"012abcA", //
|
||||
"012abcAB", //
|
||||
"012abcABC", //
|
||||
"012 abcABC", //
|
||||
"012 abcABC", //
|
||||
"012 abcABC", //
|
||||
};
|
||||
for (int i = 0; i < expectations.size(); ++i) {
|
||||
Screen screen(1, i);
|
||||
Render(screen, root);
|
||||
EXPECT_EQ(expectations[i], rotate(screen.ToString()));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user