From 610b86183bd878f93879cb4179f9ef1ea6d5b2a7 Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Tue, 22 Jan 2019 23:42:57 +0100 Subject: [PATCH] Add hflow. --- examples/component/gallery.cpp | 2 +- examples/dom/CMakeLists.txt | 2 + examples/dom/hflow.cpp | 51 +++++++++++++++++++++++ examples/dom/size.cpp | 30 ++++++++++++++ ftxui/CMakeLists.txt | 1 + ftxui/include/ftxui/dom/elements.hpp | 4 +- ftxui/include/ftxui/screen/screen.hpp | 1 + ftxui/src/ftxui/dom/hflow.cpp | 59 +++++++++++++++++++++++++++ ftxui/src/ftxui/dom/size.cpp | 2 + ftxui/src/ftxui/screen/screen.cpp | 11 +++++ 10 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 examples/dom/hflow.cpp create mode 100644 examples/dom/size.cpp create mode 100644 ftxui/src/ftxui/dom/hflow.cpp diff --git a/examples/component/gallery.cpp b/examples/component/gallery.cpp index 1278423a..37f1264f 100644 --- a/examples/component/gallery.cpp +++ b/examples/component/gallery.cpp @@ -73,7 +73,7 @@ class MyComponent : public Component { separator(), Render(L"radiobox", radiobox), separator(), - Render(L"input", input) + Render(L"input", input) | size(WIDTH, EQUAL, 20) ) | border; } }; diff --git a/examples/dom/CMakeLists.txt b/examples/dom/CMakeLists.txt index 81493f46..ee5e7343 100644 --- a/examples/dom/CMakeLists.txt +++ b/examples/dom/CMakeLists.txt @@ -16,4 +16,6 @@ example(style_dim) example(style_gallery) example(style_inverted) example(style_underlined) +example(size) example(vbox_hbox) +example(hflow) diff --git a/examples/dom/hflow.cpp b/examples/dom/hflow.cpp new file mode 100644 index 00000000..ae0e6b58 --- /dev/null +++ b/examples/dom/hflow.cpp @@ -0,0 +1,51 @@ +#include "ftxui/screen/screen.hpp" +#include "ftxui/screen/string.hpp" +#include "ftxui/dom/elements.hpp" +#include + +int main(int argc, const char *argv[]) +{ + using namespace ftxui; + auto make_box = [](size_t dimx, size_t dimy) { + std::wstring title = to_wstring(dimx) + L"x" + to_wstring(dimy); + return + window( + text(title) | hcenter | bold, + text(L"content") | hcenter | dim + ) | size(WIDTH, EQUAL, dimx) + | size(HEIGHT, EQUAL, dimy) + ; + }; + + auto document = + hflow( + make_box(7,7), + make_box(7,5), + make_box(5,7), + make_box(10,4), + make_box(10,4), + make_box(10,4), + make_box(10,4), + make_box(11,4), + make_box(11,4), + make_box(11,4), + make_box(11,4), + make_box(12,4), + make_box(12,5), + make_box(12,4), + make_box(13,4), + make_box(13,3), + make_box(13,3), + make_box(10,3) + ) | size(WIDTH, GREATER_THAN, 20) + | border + | size(HEIGHT, GREATER_THAN, 30) + | size(WIDTH, LESS_THAN, 50) + ; + + auto screen = Screen::TerminalOutput(document); + Render(screen, document.get()); + std::cout << screen.ToString() << std::endl; + + return 0; +} diff --git a/examples/dom/size.cpp b/examples/dom/size.cpp new file mode 100644 index 00000000..6d910913 --- /dev/null +++ b/examples/dom/size.cpp @@ -0,0 +1,30 @@ +#include "ftxui/screen/screen.hpp" +#include "ftxui/screen/string.hpp" +#include "ftxui/dom/elements.hpp" +#include + +int main(int argc, const char *argv[]) +{ + using namespace ftxui; + auto make_box = [](const std::wstring title) { + return + window( + text(title) | hcenter | bold, + text(L"content") | hcenter | dim + ); + }; + + Elements content; + for(int x = 3; x<30; ++x) { + content.push_back( + make_box(to_wstring(x)) + | size(WIDTH, EQUAL, x) + ); + } + auto document = hbox(std::move(content)); + auto screen = Screen::FitDocument(document); + Render(screen, document.get()); + std::cout << screen.ToString() << std::endl; + + return 0; +} diff --git a/ftxui/CMakeLists.txt b/ftxui/CMakeLists.txt index 6001d8b5..d3c75dcc 100644 --- a/ftxui/CMakeLists.txt +++ b/ftxui/CMakeLists.txt @@ -19,6 +19,7 @@ add_library(dom src/ftxui/dom/frame.cpp src/ftxui/dom/gauge.cpp src/ftxui/dom/hbox.cpp + src/ftxui/dom/hflow.cpp src/ftxui/dom/inverted.cpp src/ftxui/dom/node.cpp src/ftxui/dom/node_decorator.cpp diff --git a/ftxui/include/ftxui/dom/elements.hpp b/ftxui/include/ftxui/dom/elements.hpp index d130edfe..d4b56c02 100644 --- a/ftxui/include/ftxui/dom/elements.hpp +++ b/ftxui/include/ftxui/dom/elements.hpp @@ -33,9 +33,10 @@ Element bgcolor(Color, Element); // --- Layout --- // Horizontal, Vertical or stacked set of elements. -Element vbox(Elements); Element hbox(Elements); +Element vbox(Elements); Element dbox(Elements); +Element hflow(Elements); // -- Flexibility --- // Define how to share the remaining space when not all of it is used inside a @@ -73,6 +74,7 @@ Decorator operator|(Decorator, Decorator); TAKE_ANY_ARGS(vbox) TAKE_ANY_ARGS(hbox) TAKE_ANY_ARGS(dbox) +TAKE_ANY_ARGS(hflow) }; // namespace ftxui diff --git a/ftxui/include/ftxui/screen/screen.hpp b/ftxui/include/ftxui/screen/screen.hpp index 4a89fb53..04953199 100644 --- a/ftxui/include/ftxui/screen/screen.hpp +++ b/ftxui/include/ftxui/screen/screen.hpp @@ -33,6 +33,7 @@ class Screen { // Constructor using the terminal. static Screen TerminalFullscreen(); static Screen TerminalOutput(std::unique_ptr& element); + static Screen FitDocument(std::unique_ptr& element); // Node write into the screen using Screen::at. wchar_t& at(size_t x, size_t y); diff --git a/ftxui/src/ftxui/dom/hflow.cpp b/ftxui/src/ftxui/dom/hflow.cpp new file mode 100644 index 00000000..2463709d --- /dev/null +++ b/ftxui/src/ftxui/dom/hflow.cpp @@ -0,0 +1,59 @@ +#include "ftxui/dom/node.hpp" +#include "ftxui/dom/elements.hpp" + +namespace ftxui { + +class HFlow : public Node { + public: + HFlow(Elements children) : Node(std::move(children)) {} + ~HFlow() {} + + void ComputeRequirement() override { + requirement_.min.x = 0; + requirement_.min.y = 0; + requirement_.flex.x = 1; + requirement_.flex.y = 0; + for(auto& child : children) + child->ComputeRequirement(); + } + + void SetBox(Box box) override { + Node::SetBox(box); + + // The position of the first component. + int x = box.x_min; + int y = box.y_min; + int y_next = y; // The position of next row of elements. + + for (auto& child : children) { + Requirement requirement = child->requirement(); + + // Does it fit the end of the row? + if (x + requirement.min.x > box.x_max) { + // No? Use the next row. + x = box.x_min; + y = y_next; + } + + // Does the current row big enough to contain the element? + if (y + requirement.min.y > box.y_max) + break; // No? Ignore the element. + + Box children_box; + children_box.x_min = x; + children_box.x_max = x + requirement.min.x; + children_box.y_min = y; + children_box.y_max = y + requirement.min.y; + child->SetBox(children_box); + + x = x + requirement.min.x + 1; + y_next = std::max(y_next, y + requirement.min.y + 1); + } + } +}; + +std::unique_ptr hflow(Elements children) { + return std::make_unique(std::move(children)); +} + +}; // namespace ftxui diff --git a/ftxui/src/ftxui/dom/size.cpp b/ftxui/src/ftxui/dom/size.cpp index 51633a93..26d93a0c 100644 --- a/ftxui/src/ftxui/dom/size.cpp +++ b/ftxui/src/ftxui/dom/size.cpp @@ -39,6 +39,8 @@ class Size : public Node { void SetBox(Box box) override { Node::SetBox(box); + if (constraint_ == LESS_THAN) + box.x_max = std::min(box.x_min + value_ + 1, box.x_max); children[0]->SetBox(box); } diff --git a/ftxui/src/ftxui/screen/screen.cpp b/ftxui/src/ftxui/screen/screen.cpp index 3e98814c..0306a6b9 100644 --- a/ftxui/src/ftxui/screen/screen.cpp +++ b/ftxui/src/ftxui/screen/screen.cpp @@ -109,6 +109,17 @@ Screen Screen::TerminalOutput(std::unique_ptr& element) { return Screen(size.dimx, element->requirement().min.y); } +// static +Screen Screen::FitDocument(std::unique_ptr& element) { + element->ComputeRequirement(); + Terminal::Dimensions size = Terminal::Size(); + return + Screen( + std::min(size.dimx, element->requirement().min.x), + std::min(size.dimy, element->requirement().min.y) + ); +} + std::string Screen::ResetPosition() { std::stringstream ss; ss << MOVE_LEFT << CLEAR_LINE;