From dd92b8961116520b847aa620389d26c49a840200 Mon Sep 17 00:00:00 2001
From: Arthur Sonzogni <sonzogniarthur@gmail.com>
Date: Sat, 22 Sep 2018 09:49:43 +0200
Subject: [PATCH] Add gauge and frame.

---
 examples/CMakeLists.txt                   |  1 +
 examples/frame/CMakeLists.txt             |  4 ++
 examples/frame/main.cpp                   | 35 ++++++++++++++
 examples/gauge/main.cpp                   | 38 ++++++---------
 ftxui/CMakeLists.txt                      |  6 ++-
 ftxui/include/ftxui/core/dom/elements.hpp | 23 +++++----
 ftxui/src/ftxui/core/dom/frame.cpp        | 57 +++++++++++++++++++++++
 ftxui/src/ftxui/core/dom/gauge.cpp        | 15 ++++--
 ftxui/src/ftxui/core/dom/vbox.cpp         |  2 +-
 9 files changed, 141 insertions(+), 40 deletions(-)
 create mode 100644 examples/frame/CMakeLists.txt
 create mode 100644 examples/frame/main.cpp
 create mode 100644 ftxui/src/ftxui/core/dom/frame.cpp

diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 1e2e8486..ec4cb1b2 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 00000000..cef99a5d
--- /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 00000000..7b155cc2
--- /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 d1bdcd7e..ab45ec2b 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 2ff59703..46a91b58 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 a1b1116f..df2f7cc8 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 00000000..4b43f58a
--- /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 0c3f9f63..8b6756fc 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 386945c6..15566215 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;
-- 
GitLab