From e577d67f2a7cfe97fcdbf8c30f1137faa61ca475 Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Wed, 19 Sep 2018 21:52:25 +0200 Subject: [PATCH] Start the gauge widget. --- examples/CMakeLists.txt | 4 ++- examples/gauge/CMakeLists.txt | 4 +++ examples/gauge/main.cpp | 30 ++++++++++++++++++ examples/separator/CMakeLists.txt | 4 +++ examples/separator/main.cpp | 26 ++++++++++++++++ examples/text/CMakeLists.txt | 4 --- examples/vbox_hbox/CMakeLists.txt | 4 +++ examples/{text => vbox_hbox}/main.cpp | 4 +-- ftxui/CMakeLists.txt | 3 ++ ftxui/include/ftxui/core/dom/elements.hpp | 20 +++++++++--- ftxui/include/ftxui/core/screen.hpp | 5 +++ ftxui/src/ftxui/core/dom/centered.cpp | 20 ++++++++++++ ftxui/src/ftxui/core/dom/flex.cpp | 16 ++++++++++ ftxui/src/ftxui/core/dom/gauge.cpp | 32 +++++++++++++++++++ ftxui/src/ftxui/core/dom/separator.cpp | 38 +++++++++++++++++++++++ ftxui/src/ftxui/core/dom/vbox.cpp | 2 +- ftxui/src/ftxui/core/screen.cpp | 7 +++++ 17 files changed, 211 insertions(+), 12 deletions(-) create mode 100644 examples/gauge/CMakeLists.txt create mode 100644 examples/gauge/main.cpp create mode 100644 examples/separator/CMakeLists.txt create mode 100644 examples/separator/main.cpp delete mode 100644 examples/text/CMakeLists.txt create mode 100644 examples/vbox_hbox/CMakeLists.txt rename examples/{text => vbox_hbox}/main.cpp (92%) create mode 100644 ftxui/src/ftxui/core/dom/centered.cpp create mode 100644 ftxui/src/ftxui/core/dom/gauge.cpp create mode 100644 ftxui/src/ftxui/core/dom/separator.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f0ca2d7..1e2e848 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 0000000..ea0a964 --- /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 0000000..d1bdcd7 --- /dev/null +++ b/examples/gauge/main.cpp @@ -0,0 +1,30 @@ +#include "ftxui/core/screen.hpp" +#include "ftxui/core/dom/elements.hpp" +#include + +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 0000000..f292211 --- /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 0000000..0c23f32 --- /dev/null +++ b/examples/separator/main.cpp @@ -0,0 +1,26 @@ +#include "ftxui/core/screen.hpp" +#include "ftxui/core/dom/elements.hpp" +#include + +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 bd70946..0000000 --- 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 0000000..4db6ff6 --- /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 59b1e7f..bae8090 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 18e128a..2ff5970 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 2c2e5dd..a1b1116 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; +using Element = std::unique_ptr; using Children = std::vector>; + +// --- Layout ---- std::unique_ptr vbox(Children); std::unique_ptr hbox(Children); -std::unique_ptr text(std::wstring text); std::unique_ptr flex(); +std::unique_ptr flex(Element); + +// --- Widget -- +std::unique_ptr text(std::wstring text); +std::unique_ptr separator(); +std::unique_ptr gauge(float ratio); + +// --- Decorator --- +std::unique_ptr hcenter(Element); +std::unique_ptr vcenter(Element); +std::unique_ptr center(Element); template -std::vector unpack(Args... args) { - std::vector vec; +std::vector unpack(Args... args) { + std::vector vec; (vec.push_back(std::forward(args)), ...); return vec; } diff --git a/ftxui/include/ftxui/core/screen.hpp b/ftxui/include/ftxui/core/screen.hpp index c02e1d8..9d67601 100644 --- a/ftxui/include/ftxui/core/screen.hpp +++ b/ftxui/include/ftxui/core/screen.hpp @@ -3,8 +3,12 @@ #include #include +#include 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& 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 0000000..254c573 --- /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 hcenter(Element child) { + return hbox(flex(), std::move(child), flex()); +} + +std::unique_ptr vcenter(Element child) { + return vbox(flex(), std::move(child), flex()); +} + +std::unique_ptr 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 1643ccd..99afa61 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 flex() { return std::make_unique(); } +std::unique_ptr flex(Element child) { + return std::make_unique(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 0000000..0c3f9f6 --- /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 gauge(float progress) { + return std::make_unique(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 0000000..cf9a158 --- /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 separator() { + return std::make_unique(); +} + +}; // namespace dom +}; // namespace ftxui diff --git a/ftxui/src/ftxui/core/dom/vbox.cpp b/ftxui/src/ftxui/core/dom/vbox.cpp index a2bd4d7..386945c 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 0411e6b..768e17e 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 @@ -28,4 +29,10 @@ Screen Screen::WholeTerminal() { return Screen(size.dimx, size.dimy); } +Screen Screen::TerminalOutput(std::unique_ptr& element) { + element->ComputeRequirement(); + Terminal::Dimensions size = Terminal::Size(); + return Screen(size.dimx, element->requirement().min.y); +} + }; // namespace ftxui