mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2024-11-23 11:17:06 +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({
|
hbox({
|
||||||
text(L"left") | border,
|
text(L"left") | border,
|
||||||
text(L"middle") | border | flex,
|
text(L"middle") | border | flex,
|
||||||
text(L"right") | border
|
text(L"right") | border,
|
||||||
}),
|
}),
|
||||||
gauge(0.5) | border
|
gauge(0.5) | border,
|
||||||
})
|
});
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
~~~bash
|
~~~bash
|
||||||
|
@ -118,7 +118,7 @@ class CompilerComponent : public Component {
|
|||||||
L"gcc",
|
L"gcc",
|
||||||
L"clang",
|
L"clang",
|
||||||
L"emcc",
|
L"emcc",
|
||||||
L"game_maker"
|
L"game_maker",
|
||||||
L"Ada compilers",
|
L"Ada compilers",
|
||||||
L"ALGOL 60 compilers",
|
L"ALGOL 60 compilers",
|
||||||
L"ALGOL 68 compilers",
|
L"ALGOL 68 compilers",
|
||||||
@ -212,9 +212,9 @@ class CompilerComponent : public Component {
|
|||||||
}),
|
}),
|
||||||
filler(),
|
filler(),
|
||||||
}),
|
}),
|
||||||
hflow(RenderCommandLine()),
|
hflow(RenderCommandLine()) | flex_grow,
|
||||||
}) |
|
}) |
|
||||||
border;
|
flex_grow | border;
|
||||||
}
|
}
|
||||||
|
|
||||||
Elements RenderCommandLine() {
|
Elements RenderCommandLine() {
|
||||||
|
@ -49,7 +49,7 @@ class MyComponent : public Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OnEvent(Event event) {
|
bool OnEvent(Event event) override {
|
||||||
if (event == Event::Return) {
|
if (event == Event::Return) {
|
||||||
on_enter();
|
on_enter();
|
||||||
return true;
|
return true;
|
||||||
|
@ -21,6 +21,7 @@ using GraphFunction = std::function<std::vector<int>(int, int)>;
|
|||||||
|
|
||||||
// --- Widget ---
|
// --- Widget ---
|
||||||
Element text(std::wstring text);
|
Element text(std::wstring text);
|
||||||
|
Element vtext(std::wstring text);
|
||||||
Element separator(void);
|
Element separator(void);
|
||||||
Element separator(Pixel);
|
Element separator(Pixel);
|
||||||
Element gauge(float ratio);
|
Element gauge(float ratio);
|
||||||
@ -52,9 +53,11 @@ Element hflow(Elements);
|
|||||||
// -- Flexibility ---
|
// -- Flexibility ---
|
||||||
// Define how to share the remaining space when not all of it is used inside a
|
// Define how to share the remaining space when not all of it is used inside a
|
||||||
// container.
|
// container.
|
||||||
Element filler();
|
Element flex(Element); // Expand/Minimize if possible/needed.
|
||||||
Element flex(Element);
|
Element flex_grow(Element); // Expand element if possible.
|
||||||
Element notflex(Element);
|
Element flex_shrink(Element); // Minimize element if needed.
|
||||||
|
Element notflex(Element); // Reset the flex attribute.
|
||||||
|
Element filler(); // A blank expandable element.
|
||||||
|
|
||||||
// -- Size override;
|
// -- Size override;
|
||||||
enum Direction { WIDTH, HEIGHT };
|
enum Direction { WIDTH, HEIGHT };
|
||||||
|
@ -15,8 +15,10 @@ struct Requirement {
|
|||||||
int min_y = 0;
|
int min_y = 0;
|
||||||
|
|
||||||
// How much flexibility is given to the component.
|
// How much flexibility is given to the component.
|
||||||
int flex_x = 0;
|
int flex_grow_x = 0;
|
||||||
int flex_y = 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.
|
// Focus management to support the frame/focus/select element.
|
||||||
enum Selection {
|
enum Selection {
|
||||||
|
@ -8,19 +8,19 @@
|
|||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
|
|
||||||
Element hcenter(Element child) {
|
Element hcenter(Element child) {
|
||||||
return hbox(filler(), std::move(child), filler());
|
return hbox(filler(), std::move(child), filler()) | flex_grow;
|
||||||
}
|
}
|
||||||
|
|
||||||
Element vcenter(Element child) {
|
Element vcenter(Element child) {
|
||||||
return vbox(filler(), std::move(child), filler());
|
return vbox(filler(), std::move(child), filler()) | flex_grow;
|
||||||
}
|
}
|
||||||
|
|
||||||
Element center(Element child) {
|
Element center(Element child) {
|
||||||
return hcenter(vcenter(std::move(child)));
|
return hcenter(vcenter(std::move(child))) | flex_grow;
|
||||||
}
|
}
|
||||||
|
|
||||||
Element align_right(Element child) {
|
Element align_right(Element child) {
|
||||||
return hbox(filler(), std::move(child));
|
return hbox(filler(), std::move(child)) | flex_grow;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
@ -17,8 +17,10 @@ class DBox : public Node {
|
|||||||
void ComputeRequirement() override {
|
void ComputeRequirement() override {
|
||||||
requirement_.min_x = 0;
|
requirement_.min_x = 0;
|
||||||
requirement_.min_y = 0;
|
requirement_.min_y = 0;
|
||||||
requirement_.flex_x = 1;
|
requirement_.flex_grow_x = 0;
|
||||||
requirement_.flex_y = 0;
|
requirement_.flex_grow_y = 0;
|
||||||
|
requirement_.flex_shrink_x = 0;
|
||||||
|
requirement_.flex_shrink_y = 0;
|
||||||
for (auto& child : children) {
|
for (auto& child : children) {
|
||||||
child->ComputeRequirement();
|
child->ComputeRequirement();
|
||||||
requirement_.min_x =
|
requirement_.min_x =
|
||||||
|
@ -7,10 +7,36 @@
|
|||||||
|
|
||||||
namespace ftxui {
|
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 {
|
class Flex : public Node {
|
||||||
public:
|
public:
|
||||||
Flex() {}
|
Flex(FlexFunction f) { f_ = f; }
|
||||||
Flex(Element child) : Node(unpack(std::move(child))) {}
|
Flex(FlexFunction f, Element child) : Node(unpack(std::move(child))), f_(f) {}
|
||||||
~Flex() override {}
|
~Flex() override {}
|
||||||
void ComputeRequirement() override {
|
void ComputeRequirement() override {
|
||||||
requirement_.min_x = 0;
|
requirement_.min_x = 0;
|
||||||
@ -19,8 +45,7 @@ class Flex : public Node {
|
|||||||
children[0]->ComputeRequirement();
|
children[0]->ComputeRequirement();
|
||||||
requirement_ = children[0]->requirement();
|
requirement_ = children[0]->requirement();
|
||||||
}
|
}
|
||||||
requirement_.flex_x = 1;
|
f_(requirement_);
|
||||||
requirement_.flex_y = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetBox(Box box) override {
|
void SetBox(Box box) override {
|
||||||
@ -28,35 +53,28 @@ class Flex : public Node {
|
|||||||
return;
|
return;
|
||||||
children[0]->SetBox(box);
|
children[0]->SetBox(box);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
class NotFlex : public Flex {
|
FlexFunction f_;
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Element filler() {
|
Element filler() {
|
||||||
return std::make_shared<Flex>();
|
return std::make_shared<Flex>(function_flex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Element flex(Element child) {
|
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) {
|
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
|
} // namespace ftxui
|
||||||
|
@ -15,7 +15,11 @@ class Gauge : public Node {
|
|||||||
~Gauge() override {}
|
~Gauge() override {}
|
||||||
|
|
||||||
void ComputeRequirement() 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;
|
requirement_.min_y = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,10 +14,12 @@ class Graph : public Node {
|
|||||||
~Graph() override {}
|
~Graph() override {}
|
||||||
|
|
||||||
void ComputeRequirement() override {
|
void ComputeRequirement() override {
|
||||||
requirement_.flex_x = 1;
|
requirement_.flex_grow_x = 1;
|
||||||
requirement_.flex_y = 1;
|
requirement_.flex_grow_y = 1;
|
||||||
requirement_.min_x = 1;
|
requirement_.flex_shrink_x = 1;
|
||||||
requirement_.min_y = 1;
|
requirement_.flex_shrink_y = 1;
|
||||||
|
requirement_.min_x = 3;
|
||||||
|
requirement_.min_y = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Render(Screen& screen) override {
|
void Render(Screen& screen) override {
|
||||||
|
@ -17,8 +17,10 @@ class HBox : public Node {
|
|||||||
void ComputeRequirement() override {
|
void ComputeRequirement() override {
|
||||||
requirement_.min_x = 0;
|
requirement_.min_x = 0;
|
||||||
requirement_.min_y = 0;
|
requirement_.min_y = 0;
|
||||||
requirement_.flex_x = 1;
|
requirement_.flex_grow_x = 0;
|
||||||
requirement_.flex_y = 0;
|
requirement_.flex_grow_y = 0;
|
||||||
|
requirement_.flex_shrink_x = 0;
|
||||||
|
requirement_.flex_shrink_y = 0;
|
||||||
for (auto& child : children) {
|
for (auto& child : children) {
|
||||||
child->ComputeRequirement();
|
child->ComputeRequirement();
|
||||||
if (requirement_.selection < child->requirement().selection) {
|
if (requirement_.selection < child->requirement().selection) {
|
||||||
@ -36,31 +38,89 @@ class HBox : public Node {
|
|||||||
void SetBox(Box box) override {
|
void SetBox(Box box) override {
|
||||||
Node::SetBox(box);
|
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 space = box.x_max - box.x_min + 1;
|
||||||
int extra_space = space - requirement_.min_x;
|
int extra_space = space - requirement_.min_x;
|
||||||
|
|
||||||
int remaining_flex = flex_sum;
|
int size = 0;
|
||||||
int remaining_extra_space = extra_space;
|
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;
|
int x = box.x_min;
|
||||||
for (auto& child : children) {
|
for (auto& child : children) {
|
||||||
Box child_box = box;
|
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_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) {
|
void SetBoxShrinkEasy(Box box, int extra_space, int flex_shrink_sum) {
|
||||||
int added_space = remaining_extra_space * child->requirement().flex_x /
|
int x = box.x_min;
|
||||||
remaining_flex;
|
for (auto& child : children) {
|
||||||
remaining_extra_space -= added_space;
|
Box child_box = box;
|
||||||
remaining_flex -= child->requirement().flex_x;
|
const Requirement& r = child->requirement();
|
||||||
child_box.x_max += added_space;
|
|
||||||
|
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);
|
child->SetBox(child_box);
|
||||||
x = child_box.x_max + 1;
|
x = child_box.x_max + 1;
|
||||||
|
@ -9,81 +9,347 @@
|
|||||||
using namespace ftxui;
|
using namespace ftxui;
|
||||||
using namespace ftxui;
|
using namespace ftxui;
|
||||||
|
|
||||||
TEST(HBoxTest, ScreenSmaller1) {
|
TEST(HBoxTest, NoFlex_NoFlex_NoFlex) {
|
||||||
auto root = hbox(text(L"text_1"), text(L"text_2"));
|
auto root = hbox({
|
||||||
Screen screen(11, 1);
|
text(L"012"),
|
||||||
Render(screen, root);
|
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) {
|
TEST(HBoxTest, FlexGrow_NoFlex_NoFlex) {
|
||||||
auto root = hbox(text(L"text_1"), text(L"text_2"));
|
auto root = hbox({
|
||||||
Screen screen(10, 1);
|
text(L"012") | flex_grow,
|
||||||
Render(screen, root);
|
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) {
|
TEST(HBoxTest, NoFlex_FlexGrow_NoFlex) {
|
||||||
auto root = hbox(text(L"text_1"), text(L"text_2"));
|
auto root = hbox({
|
||||||
Screen screen(12, 1);
|
text(L"012"),
|
||||||
Render(screen, root);
|
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) {
|
TEST(HBoxTest, NoFlex_NoFlex_FlexGrow) {
|
||||||
auto root = hbox(text(L"text_1"), text(L"text_2"));
|
auto root = hbox({
|
||||||
Screen screen(13, 1);
|
text(L"012"),
|
||||||
Render(screen, root);
|
text(L"abc"),
|
||||||
|
text(L"ABC") | flex_grow,
|
||||||
|
});
|
||||||
|
|
||||||
EXPECT_EQ("text_1text_2 ", screen.ToString());
|
std::vector<std::string> expectations = {
|
||||||
}
|
"", //
|
||||||
TEST(HBoxTest, ScreenBigger2) {
|
"0", //
|
||||||
auto root = hbox(text(L"text_1"), text(L"text_2"));
|
"0a", //
|
||||||
Screen screen(14, 1);
|
"0aA", //
|
||||||
Render(screen, root);
|
"01aA", //
|
||||||
|
"01abA", //
|
||||||
EXPECT_EQ("text_1text_2 ", screen.ToString());
|
"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) {
|
TEST(HBoxTest, FlexGrow_NoFlex_FlexGrow) {
|
||||||
auto root = hbox(text(L"text_1"), filler(), text(L"text_2"));
|
auto root = hbox({
|
||||||
Screen screen(11, 1);
|
text(L"012") | flex_grow,
|
||||||
Render(screen, root);
|
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) {
|
TEST(HBoxTest, FlexGrow_FlexGrow_FlexGrow) {
|
||||||
auto root = hbox(text(L"text_1"), filler(), text(L"text_2"));
|
auto root = hbox({
|
||||||
Screen screen(10, 1);
|
text(L"012") | flex_grow,
|
||||||
Render(screen, root);
|
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) {
|
TEST(HBoxTest, NoFlex_FlexShrink_NoFlex) {
|
||||||
auto root = hbox(text(L"text_1"), filler(), text(L"text_2"));
|
auto root = hbox({
|
||||||
Screen screen(13, 1);
|
text(L"012"),
|
||||||
Render(screen, root);
|
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) {
|
TEST(HBoxTest, NoFlex_NoFlex_FlexShrink) {
|
||||||
auto root = hbox(text(L"text_1"), filler(), text(L"text_2"));
|
auto root = hbox({
|
||||||
Screen screen(14, 1);
|
text(L"012"),
|
||||||
Render(screen, root);
|
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() {}
|
~HFlow() {}
|
||||||
|
|
||||||
void ComputeRequirement() override {
|
void ComputeRequirement() override {
|
||||||
requirement_.min_x = 0;
|
requirement_.min_x = 1;
|
||||||
requirement_.min_y = 0;
|
requirement_.min_y = 1;
|
||||||
requirement_.flex_x = 1;
|
requirement_.flex_grow_x = 1;
|
||||||
requirement_.flex_y = 1;
|
requirement_.flex_grow_y = 1;
|
||||||
|
requirement_.flex_shrink_x = 0;
|
||||||
|
requirement_.flex_shrink_y = 0;
|
||||||
for (auto& child : children)
|
for (auto& child : children)
|
||||||
child->ComputeRequirement();
|
child->ComputeRequirement();
|
||||||
}
|
}
|
||||||
|
@ -37,10 +37,13 @@ class Size : public Node {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (direction_ == WIDTH)
|
if (direction_ == WIDTH) {
|
||||||
requirement_.flex_x = 0;
|
requirement_.flex_grow_x = 0;
|
||||||
else
|
requirement_.flex_shrink_x = 0;
|
||||||
requirement_.flex_y = 0;
|
} else {
|
||||||
|
requirement_.flex_grow_y = 0;
|
||||||
|
requirement_.flex_shrink_y = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetBox(Box box) override {
|
void SetBox(Box box) override {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "ftxui/dom/node.hpp"
|
#include "ftxui/dom/node.hpp"
|
||||||
#include "ftxui/screen/string.hpp"
|
#include "ftxui/screen/string.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
|
|
||||||
@ -36,8 +37,43 @@ class Text : public Node {
|
|||||||
std::wstring text_;
|
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) {
|
Element text(std::wstring text) {
|
||||||
return std::make_shared<Text>(text);
|
return std::make_shared<Text>(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Element vtext(std::wstring text) {
|
||||||
|
return std::make_shared<VText>(text);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
@ -15,11 +15,13 @@ class VBox : public Node {
|
|||||||
VBox(Elements children) : Node(std::move(children)) {}
|
VBox(Elements children) : Node(std::move(children)) {}
|
||||||
~VBox() {}
|
~VBox() {}
|
||||||
|
|
||||||
void ComputeRequirement() {
|
void ComputeRequirement() override {
|
||||||
requirement_.min_x = 0;
|
requirement_.min_x = 0;
|
||||||
requirement_.min_y = 0;
|
requirement_.min_y = 0;
|
||||||
requirement_.flex_x = 0;
|
requirement_.flex_grow_x = 0;
|
||||||
requirement_.flex_y = 1;
|
requirement_.flex_grow_y = 0;
|
||||||
|
requirement_.flex_shrink_x = 0;
|
||||||
|
requirement_.flex_shrink_y = 0;
|
||||||
for (auto& child : children) {
|
for (auto& child : children) {
|
||||||
child->ComputeRequirement();
|
child->ComputeRequirement();
|
||||||
if (requirement_.selection < child->requirement().selection) {
|
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);
|
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 space = box.y_max - box.y_min + 1;
|
||||||
int extra_space = space - requirement_.min_y;
|
int extra_space = space - requirement_.min_y;
|
||||||
|
|
||||||
int remaining_flex = flex_sum;
|
int size = 0;
|
||||||
int remaining_extra_space = extra_space;
|
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;
|
int y = box.y_min;
|
||||||
for (auto& child : children) {
|
for (auto& child : children) {
|
||||||
Box child_box = box;
|
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_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) {
|
void SetBoxShrinkEasy(Box box, int extra_space, int flex_shrink_sum) {
|
||||||
int added_space = remaining_extra_space * child->requirement().flex_y /
|
int y = box.y_min;
|
||||||
remaining_flex;
|
for (auto& child : children) {
|
||||||
remaining_extra_space -= added_space;
|
Box child_box = box;
|
||||||
remaining_flex -= child->requirement().flex_y;
|
const Requirement& r = child->requirement();
|
||||||
child_box.y_max += added_space;
|
|
||||||
|
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);
|
child->SetBox(child_box);
|
||||||
y = child_box.y_max + 1;
|
y = child_box.y_max + 1;
|
||||||
|
@ -9,70 +9,352 @@
|
|||||||
using namespace ftxui;
|
using namespace ftxui;
|
||||||
using namespace ftxui;
|
using namespace ftxui;
|
||||||
|
|
||||||
TEST(VBoxTest, ScreenSmaller1) {
|
std::string rotate(std::string str) {
|
||||||
auto root = vbox(text(L"text_1"), text(L"text_2"));
|
str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
|
||||||
Screen screen(6, 1);
|
return str;
|
||||||
Render(screen, root);
|
|
||||||
|
|
||||||
EXPECT_EQ("text_1", screen.ToString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(VBoxTest, ScreenFit) {
|
TEST(VBoxText, NoFlex_NoFlex_NoFlex) {
|
||||||
auto root = vbox(text(L"text_1"), text(L"text_2"));
|
auto root = vbox({
|
||||||
Screen screen(6, 2);
|
vtext(L"012"),
|
||||||
Render(screen, root);
|
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) {
|
TEST(VBoxText, FlexGrow_NoFlex_NoFlex) {
|
||||||
auto root = vbox(text(L"text_1"), text(L"text_2"));
|
auto root = vbox({
|
||||||
Screen screen(6, 3);
|
vtext(L"012") | flex_grow,
|
||||||
Render(screen, root);
|
vtext(L"abc"),
|
||||||
|
vtext(L"ABC"),
|
||||||
|
});
|
||||||
|
|
||||||
EXPECT_EQ("text_1\ntext_2\n ", screen.ToString());
|
std::vector<std::string> expectations = {
|
||||||
}
|
"", //
|
||||||
TEST(VBoxTest, ScreenBigger2) {
|
"0", //
|
||||||
auto root = vbox(text(L"text_1"), text(L"text_2"));
|
"0a", //
|
||||||
Screen screen(6, 4);
|
"0aA", //
|
||||||
Render(screen, root);
|
"01aA", //
|
||||||
|
"01abA", //
|
||||||
EXPECT_EQ("text_1\ntext_2\n \n ", screen.ToString());
|
"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) {
|
TEST(VBoxText, NoFlex_FlexGrow_NoFlex) {
|
||||||
auto root = vbox(text(L"text_1"), filler(), text(L"text_2"));
|
auto root = vbox({
|
||||||
Screen screen(6, 1);
|
vtext(L"012"),
|
||||||
Render(screen, root);
|
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) {
|
TEST(VBoxText, NoFlex_NoFlex_FlexGrow) {
|
||||||
auto root = vbox(text(L"text_1"), filler(), text(L"text_2"));
|
auto root = vbox({
|
||||||
Screen screen(7, 5);
|
vtext(L"012"),
|
||||||
Render(screen, root);
|
vtext(L"abc"),
|
||||||
|
vtext(L"ABC") | flex_grow,
|
||||||
|
});
|
||||||
|
|
||||||
EXPECT_EQ(
|
std::vector<std::string> expectations = {
|
||||||
"text_1 \n"
|
"", //
|
||||||
" \n"
|
"0", //
|
||||||
" \n"
|
"0a", //
|
||||||
" \n"
|
"0aA", //
|
||||||
"text_2 ",
|
"01aA", //
|
||||||
screen.ToString());
|
"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) {
|
TEST(VBoxText, FlexGrow_NoFlex_FlexGrow) {
|
||||||
auto root = vbox(text(L"text_1"), filler(), text(L"text_2"));
|
auto root = vbox({
|
||||||
Screen screen(6, 3);
|
vtext(L"012") | flex_grow,
|
||||||
Render(screen, root);
|
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