diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f0ca2d76e129d11d5f6a0ec6eea18a6670706484..1e2e8486509fac0331d0834780da4d0c972b69e6 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1 +1,3 @@ -add_subdirectory(text) +add_subdirectory(gauge) +add_subdirectory(separator) +add_subdirectory(vbox_hbox) diff --git a/examples/gauge/CMakeLists.txt b/examples/gauge/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ea0a96440d30bea5868faaa5f4baaf6b62642d55 --- /dev/null +++ b/examples/gauge/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(gauge_example + main.cpp +) +target_link_libraries(gauge_example PRIVATE ftxui) diff --git a/examples/gauge/main.cpp b/examples/gauge/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1bdcd7e3e50f96a577f97c00f2d4bfcb01f09e9 --- /dev/null +++ b/examples/gauge/main.cpp @@ -0,0 +1,30 @@ +#include "ftxui/core/screen.hpp" +#include "ftxui/core/dom/elements.hpp" +#include <iostream> + +int main(int argc, const char *argv[]) +{ + using namespace ftxui::dom; + auto document = + hbox( + flex(vbox( + gauge(0.1), + gauge(0.2), + gauge(0.3) + )), + flex(vbox( + gauge(0.1), + gauge(0.8), + gauge(0.3) + )) + ); + //auto screen = ftxui::Screen::WholeTerminal(); + auto screen = ftxui::Screen::TerminalOutput(document); + Render(screen, document.get()); + + std::cout << screen.ToString(); + + getchar(); + + return 0; +} diff --git a/examples/separator/CMakeLists.txt b/examples/separator/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f2922117c333dbc1907088fd292f36639acab8ae --- /dev/null +++ b/examples/separator/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(separator_example + main.cpp +) +target_link_libraries(separator_example PRIVATE ftxui) diff --git a/examples/separator/main.cpp b/examples/separator/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c23f32611b402721692777cba35b63882d318fd --- /dev/null +++ b/examples/separator/main.cpp @@ -0,0 +1,26 @@ +#include "ftxui/core/screen.hpp" +#include "ftxui/core/dom/elements.hpp" +#include <iostream> + +int main(int argc, const char *argv[]) +{ + using namespace ftxui::dom; + auto document = + hbox( + text(L"left-column"), + separator(), + flex(vbox( + flex(center(text(L"right-column"))), + separator(), + center(text(L"bottom-column")) + )) + ); + auto screen = ftxui::Screen::WholeTerminal(); + Render(screen, document.get()); + + std::cout << screen.ToString(); + + getchar(); + + return 0; +} diff --git a/examples/text/CMakeLists.txt b/examples/text/CMakeLists.txt deleted file mode 100644 index bd709466d7f782260fa93273efb5f9d750fffcc2..0000000000000000000000000000000000000000 --- a/examples/text/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_executable(main - main.cpp -) -target_link_libraries(main PRIVATE ftxui) diff --git a/examples/vbox_hbox/CMakeLists.txt b/examples/vbox_hbox/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4db6ff6e55f7b39d7f389eebd9b84a847e8cb59a --- /dev/null +++ b/examples/vbox_hbox/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(vbox_hbox_example + main.cpp +) +target_link_libraries(vbox_hbox_example PRIVATE ftxui) diff --git a/examples/text/main.cpp b/examples/vbox_hbox/main.cpp similarity index 92% rename from examples/text/main.cpp rename to examples/vbox_hbox/main.cpp index 59b1e7fb34bd99239f5806ad26204c40b870f640..bae809019d846152e621e285d1f94df86f31997e 100644 --- a/examples/text/main.cpp +++ b/examples/vbox_hbox/main.cpp @@ -5,7 +5,7 @@ int main(int argc, const char *argv[]) { using namespace ftxui::dom; - auto root = + auto document = vbox( hbox( text(L"north-west"), @@ -28,7 +28,7 @@ int main(int argc, const char *argv[]) ) ); auto screen = ftxui::Screen::WholeTerminal(); - Render(screen, root.get()); + Render(screen, document.get()); std::cout << screen.ToString(); diff --git a/ftxui/CMakeLists.txt b/ftxui/CMakeLists.txt index 18e128adacf792c8e15685ecba2f21e556e0df78..2ff597035fa2a601a866fc0238469258e390a0ee 100644 --- a/ftxui/CMakeLists.txt +++ b/ftxui/CMakeLists.txt @@ -6,8 +6,11 @@ add_library(ftxui src/ftxui/core/dom/flex.cpp src/ftxui/core/dom/hbox.cpp src/ftxui/core/dom/node.cpp + src/ftxui/core/dom/separator.cpp src/ftxui/core/dom/text.cpp + src/ftxui/core/dom/centered.cpp src/ftxui/core/dom/vbox.cpp + src/ftxui/core/dom/gauge.cpp src/ftxui/core/screen.cpp src/ftxui/core/terminal.cpp src/ftxui/util/string.cpp diff --git a/ftxui/include/ftxui/core/dom/elements.hpp b/ftxui/include/ftxui/core/dom/elements.hpp index 2c2e5dd51222c5a4c9dc7ea026af8d99e89d5b69..a1b1116f9b168b72acad60b3a45dbb8af5618124 100644 --- a/ftxui/include/ftxui/core/dom/elements.hpp +++ b/ftxui/include/ftxui/core/dom/elements.hpp @@ -7,17 +7,29 @@ namespace ftxui { namespace dom { -using Child = std::unique_ptr<Node>; +using Element = std::unique_ptr<Node>; using Children = std::vector<std::unique_ptr<Node>>; + +// --- Layout ---- std::unique_ptr<Node> vbox(Children); std::unique_ptr<Node> hbox(Children); -std::unique_ptr<Node> text(std::wstring text); std::unique_ptr<Node> flex(); +std::unique_ptr<Node> flex(Element); + +// --- Widget -- +std::unique_ptr<Node> text(std::wstring text); +std::unique_ptr<Node> separator(); +std::unique_ptr<Node> gauge(float ratio); + +// --- Decorator --- +std::unique_ptr<Node> hcenter(Element); +std::unique_ptr<Node> vcenter(Element); +std::unique_ptr<Node> center(Element); template <class... Args> -std::vector<Child> unpack(Args... args) { - std::vector<Child> vec; +std::vector<Element> unpack(Args... args) { + std::vector<Element> vec; (vec.push_back(std::forward<Args>(args)), ...); return vec; } diff --git a/ftxui/include/ftxui/core/screen.hpp b/ftxui/include/ftxui/core/screen.hpp index c02e1d8e337147089bcda429beb64671b4eb3711..9d676010d4d00511b55713836dedc5b0193b9789 100644 --- a/ftxui/include/ftxui/core/screen.hpp +++ b/ftxui/include/ftxui/core/screen.hpp @@ -3,8 +3,12 @@ #include <string> #include <vector> +#include <memory> namespace ftxui { +namespace dom { + class Node; +} class Screen { public: @@ -16,6 +20,7 @@ class Screen { size_t dimy() { return dimy_;} static Screen WholeTerminal(); + static Screen TerminalOutput(std::unique_ptr<dom::Node>& element); private: size_t dimx_; diff --git a/ftxui/src/ftxui/core/dom/centered.cpp b/ftxui/src/ftxui/core/dom/centered.cpp new file mode 100644 index 0000000000000000000000000000000000000000..254c573896fe1bbe9e0d50345177b043924b3636 --- /dev/null +++ b/ftxui/src/ftxui/core/dom/centered.cpp @@ -0,0 +1,20 @@ +#include "ftxui/core/dom/node.hpp" +#include "ftxui/core/dom/elements.hpp" + +namespace ftxui { +namespace dom { + +std::unique_ptr<Node> hcenter(Element child) { + return hbox(flex(), std::move(child), flex()); +} + +std::unique_ptr<Node> vcenter(Element child) { + return vbox(flex(), std::move(child), flex()); +} + +std::unique_ptr<Node> center(Element child) { + return hcenter(vcenter(std::move(child))); +} + +} // namespace dom +} // namespace ftxui diff --git a/ftxui/src/ftxui/core/dom/flex.cpp b/ftxui/src/ftxui/core/dom/flex.cpp index 1643ccd497551ae9f111de5b387f9c0ed45265e7..99afa61098c526cb27f550cfad8adf3bb09a9e4f 100644 --- a/ftxui/src/ftxui/core/dom/flex.cpp +++ b/ftxui/src/ftxui/core/dom/flex.cpp @@ -1,4 +1,5 @@ #include "ftxui/core/dom/node.hpp" +#include "ftxui/core/dom/elements.hpp" namespace ftxui { namespace dom { @@ -6,18 +7,33 @@ namespace dom { class Flex : public Node { public: Flex() {} + Flex(Element child) : Node(unpack(std::move(child))) {} ~Flex() override {} void ComputeRequirement() { requirement_.min.x = 0; requirement_.min.y = 0; + if (!children.empty()) { + children[0]->ComputeRequirement(); + requirement_ = children[0]->requirement(); + } requirement_.flex.x = 1; requirement_.flex.y = 1; } + + void SetBox(Box box) override { + if (children.empty()) + return; + children[0]->SetBox(box); + } }; std::unique_ptr<Node> flex() { return std::make_unique<Flex>(); } +std::unique_ptr<Node> flex(Element child) { + return std::make_unique<Flex>(std::move(child)); +} + }; // namespace dom }; // namespace ftxui diff --git a/ftxui/src/ftxui/core/dom/gauge.cpp b/ftxui/src/ftxui/core/dom/gauge.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c3f9f638fa8b8230fabc9df58de07b552c720c9 --- /dev/null +++ b/ftxui/src/ftxui/core/dom/gauge.cpp @@ -0,0 +1,32 @@ +#include "ftxui/core/dom/node.hpp" +#include "ftxui/core/dom/elements.hpp" + +namespace ftxui { +namespace dom { + +class Gauge : public Node { + public: + Gauge(float progress) : progress_(progress) {} + ~Gauge() {} + + void ComputeRequirement() override { + requirement_.flex.x = 1; + requirement_.min.y = 1; + } + + void Render(Screen& screen) override { + float y = box_.top; + int limit = box_.left + progress_ * (box_.right - box_.left); + for(int i = box_.left; i<=limit; ++i) + screen.at(i, y) = 'X'; + } + private: + float progress_; +}; + +std::unique_ptr<Node> gauge(float progress) { + return std::make_unique<Gauge>(progress); +} + +}; // namespace dom +}; // namespace ftxui diff --git a/ftxui/src/ftxui/core/dom/separator.cpp b/ftxui/src/ftxui/core/dom/separator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf9a15821b5d6a45c2ac8c7b2ee0e5c056344331 --- /dev/null +++ b/ftxui/src/ftxui/core/dom/separator.cpp @@ -0,0 +1,38 @@ +#include "ftxui/core/dom/node.hpp" + +namespace ftxui { +namespace dom { + +class Separator : public Node { + public: + Separator() {} + ~Separator() override {} + void ComputeRequirement() override { + requirement_.min.x = 1; + requirement_.min.y = 1; + } + + void Render(Screen& screen) override { + bool is_column = (box_.right == box_.left); + bool is_line = (box_.top == box_.bottom); + + wchar_t c = U'+'; + if (is_line && !is_column) + c = U'─'; + else if (!is_line && is_column) + c = U'│'; + + for (int y = box_.top; y <= box_.bottom; ++y) { + for (int x = box_.left; x <= box_.right; ++x) { + screen.at(x, y) = c; + } + } + } +}; + +std::unique_ptr<Node> separator() { + return std::make_unique<Separator>(); +} + +}; // namespace dom +}; // namespace ftxui diff --git a/ftxui/src/ftxui/core/dom/vbox.cpp b/ftxui/src/ftxui/core/dom/vbox.cpp index a2bd4d7255e87794100b55930de12031b4c3f96b..386945c6ba3f608bf8551450d1a5a12d4d25c663 100644 --- a/ftxui/src/ftxui/core/dom/vbox.cpp +++ b/ftxui/src/ftxui/core/dom/vbox.cpp @@ -35,7 +35,7 @@ class VBox : public Node { int remaining_flex = flex_sum; int remaining_extra_space = extra_space; - int y = box.left; + int y = box.top; for (auto& child : children) { if (y > box.right) break; diff --git a/ftxui/src/ftxui/core/screen.cpp b/ftxui/src/ftxui/core/screen.cpp index 0411e6b68436c0acd156518240e65d6e3473e261..768e17e8155ba21b1b2a3e66fd1fefdde67e6284 100644 --- a/ftxui/src/ftxui/core/screen.cpp +++ b/ftxui/src/ftxui/core/screen.cpp @@ -1,6 +1,7 @@ #include "ftxui/core/screen.hpp" #include "ftxui/core/terminal.hpp" #include "ftxui/util/string.hpp" +#include "ftxui/core/dom/node.hpp" #include <sstream> @@ -28,4 +29,10 @@ Screen Screen::WholeTerminal() { return Screen(size.dimx, size.dimy); } +Screen Screen::TerminalOutput(std::unique_ptr<dom::Node>& element) { + element->ComputeRequirement(); + Terminal::Dimensions size = Terminal::Size(); + return Screen(size.dimx, element->requirement().min.y); +} + }; // namespace ftxui