diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 1e2e8486509fac0331d0834780da4d0c972b69e6..ec4cb1b2a9973512ce7d80717d6b19128d15c3a3 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(frame) add_subdirectory(gauge) add_subdirectory(separator) add_subdirectory(vbox_hbox) diff --git a/examples/frame/CMakeLists.txt b/examples/frame/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..cef99a5daa21433044fcf788c22568dce4acd893 --- /dev/null +++ b/examples/frame/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(frame_example + main.cpp +) +target_link_libraries(frame_example PRIVATE ftxui) diff --git a/examples/frame/main.cpp b/examples/frame/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b155cc205aa7bf5db9439a8d511d00befd74625 --- /dev/null +++ b/examples/frame/main.cpp @@ -0,0 +1,35 @@ +#include <chrono> +#include <iostream> +#include <thread> + +#include "ftxui/core/screen.hpp" +#include "ftxui/core/dom/elements.hpp" + +int main(int argc, const char *argv[]) +{ + using namespace ftxui::dom; + auto document = + hbox( + frame( + vbox( + text(L"Line 1"), + text(L"Line 2"), + text(L"Line 3"), + frame( + vbox( + text(L"Line 4"), + text(L"Line 5"), + text(L"Line 6") + ) + ), + text(L"Line 7"), + text(L"Line 8"), + text(L"Line 9") + ) + ), + flex() + ); + auto screen = ftxui::Screen::TerminalOutput(document); + Render(screen, document.get()); + std::cout << screen.ToString() << std::endl; +} diff --git a/examples/gauge/main.cpp b/examples/gauge/main.cpp index d1bdcd7e3e50f96a577f97c00f2d4bfcb01f09e9..ab45ec2b0bb2ef80154d2689d51111f447499413 100644 --- a/examples/gauge/main.cpp +++ b/examples/gauge/main.cpp @@ -1,30 +1,22 @@ +#include <chrono> +#include <iostream> +#include <thread> + #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(); + for(float percentage = 0; percentage <= 1.0; percentage+=0.001) { + using namespace ftxui::dom; + auto document = + hbox(text(L"gauge = -"), flex(gauge(percentage)), text(L"-")); + auto screen = ftxui::Screen(100, 1); + Render(screen, document.get()); + std::cout << '\r' << screen.ToString() << std::flush; - return 0; + using namespace std::chrono_literals; + std::this_thread::sleep_for(0.01s); + } + std::cout << std::endl; } diff --git a/ftxui/CMakeLists.txt b/ftxui/CMakeLists.txt index 2ff597035fa2a601a866fc0238469258e390a0ee..46a91b581e14a162731f5a5ac67766b6ec44aef0 100644 --- a/ftxui/CMakeLists.txt +++ b/ftxui/CMakeLists.txt @@ -3,14 +3,16 @@ project(ftxui) add_library(ftxui src/ftxui/core/component.cpp + src/ftxui/core/dom/frame.cpp + src/ftxui/core/dom/centered.cpp src/ftxui/core/dom/flex.cpp + src/ftxui/core/dom/frame.cpp + src/ftxui/core/dom/gauge.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 a1b1116f9b168b72acad60b3a45dbb8af5618124..df2f7cc890c6bc607105421092feeb5b15e6bbcb 100644 --- a/ftxui/include/ftxui/core/dom/elements.hpp +++ b/ftxui/include/ftxui/core/dom/elements.hpp @@ -8,24 +8,27 @@ namespace ftxui { namespace dom { using Element = std::unique_ptr<Node>; +using Child = 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> flex(); -std::unique_ptr<Node> flex(Element); +Element vbox(Children); +Element hbox(Children); +Element flex(); // --- Widget -- -std::unique_ptr<Node> text(std::wstring text); -std::unique_ptr<Node> separator(); -std::unique_ptr<Node> gauge(float ratio); +Element text(std::wstring text); +Element separator(); +Element gauge(float ratio); +Element frame(Child); +Element frame(std::wstring title, Child); // --- Decorator --- -std::unique_ptr<Node> hcenter(Element); -std::unique_ptr<Node> vcenter(Element); -std::unique_ptr<Node> center(Element); +Element hcenter(Element); +Element vcenter(Element); +Element center(Element); +Element flex(Element); template <class... Args> std::vector<Element> unpack(Args... args) { diff --git a/ftxui/src/ftxui/core/dom/frame.cpp b/ftxui/src/ftxui/core/dom/frame.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4b43f58ad586ef21ef67667c26e35126538e5232 --- /dev/null +++ b/ftxui/src/ftxui/core/dom/frame.cpp @@ -0,0 +1,57 @@ +#include "ftxui/core/dom/node.hpp" +#include "ftxui/core/dom/elements.hpp" + +namespace ftxui { +namespace dom { + +static wchar_t charset[] = L"┌┐└┘─│"; + +class Frame : public Node { + public: + Frame(Child child) : Node(unpack(std::move(child))) {} + ~Frame() override {} + + void ComputeRequirement() override { + children[0]->ComputeRequirement(); + requirement_ = children[0]->requirement(); + requirement_.min.x += 2; + requirement_.min.y += 2; + } + + void SetBox(Box box) override { + Node::SetBox(box); + box.left++; + box.right--; + box.top++; + box.bottom--; + children[0]->SetBox(box); + } + + void Render(Screen& screen) override { + if (box_.left >= box_.right || box_.top >= box_.bottom) + return; + + screen.at(box_.left, box_.top) = charset[0]; + screen.at(box_.right, box_.top) = charset[1]; + screen.at(box_.left, box_.bottom) = charset[2]; + screen.at(box_.right, box_.bottom) = charset[3]; + for(float x = box_.left + 1; x<box_.right; ++x) { + screen.at(x, box_.top) = charset[4]; + screen.at(x, box_.bottom) = charset[4]; + } + for(float y = box_.top + 1; y<box_.bottom; ++y) { + screen.at(box_.left, y) = charset[5]; + screen.at(box_.right,y) = charset[5]; + } + children[0]->Render(screen); + } + private: + float progress_; +}; + +std::unique_ptr<Node> frame(Child child) { + return std::make_unique<Frame>(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 index 0c3f9f638fa8b8230fabc9df58de07b552c720c9..8b6756fc5e065bb96af3f6299c47188e84a662fd 100644 --- a/ftxui/src/ftxui/core/dom/gauge.cpp +++ b/ftxui/src/ftxui/core/dom/gauge.cpp @@ -4,10 +4,12 @@ namespace ftxui { namespace dom { +static wchar_t charset[] = L" ▏▎▍▌▋▊▉█"; + class Gauge : public Node { public: Gauge(float progress) : progress_(progress) {} - ~Gauge() {} + ~Gauge() override {} void ComputeRequirement() override { requirement_.flex.x = 1; @@ -16,9 +18,14 @@ class Gauge : public Node { 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'; + float limit = box_.left + progress_ * (box_.right - box_.left + 1); + int limit_int = limit; + int x = box_.left; + while (x < limit_int) + screen.at(x++, y) = charset[9]; + screen.at(x++, y) = charset[int(9*(limit-limit_int))]; + while (x <= box_.right) + screen.at(x++, y) = charset[0]; } private: float progress_; diff --git a/ftxui/src/ftxui/core/dom/vbox.cpp b/ftxui/src/ftxui/core/dom/vbox.cpp index 386945c6ba3f608bf8551450d1a5a12d4d25c663..15566215c5793d5c6561d0762cc5fc724b9bc959 100644 --- a/ftxui/src/ftxui/core/dom/vbox.cpp +++ b/ftxui/src/ftxui/core/dom/vbox.cpp @@ -37,7 +37,7 @@ class VBox : public Node { int y = box.top; for (auto& child : children) { - if (y > box.right) + if (y > box.bottom) break; Box child_box = box;