From 13e04176a40932760bfbf34119caafb34eca36a5 Mon Sep 17 00:00:00 2001
From: Arthur Sonzogni <sonzogniarthur@gmail.com>
Date: Wed, 2 Jan 2019 22:33:59 +0100
Subject: [PATCH] Add Blink. Refactor examples.

---
 examples/CMakeLists.txt                       | 18 ++---
 examples/color/CMakeLists.txt                 |  4 -
 examples/component/CMakeLists.txt             |  6 ++
 .../{color/main.cpp => component/color.cpp}   |  2 -
 .../{gauge/main.cpp => component/gauge.cpp}   |  0
 .../{input/main.cpp => component/input.cpp}   |  3 +-
 .../{menu/main.cpp => component/menu.cpp}     |  0
 .../{menu2/main.cpp => component/menu2.cpp}   |  2 +
 .../{toggle/main.cpp => component/toggle.cpp} |  0
 examples/dom/CMakeLists.txt                   |  3 +
 examples/{frame/main.cpp => dom/frame.cpp}    |  0
 .../{separator/main.cpp => dom/separator.cpp} |  1 -
 .../{vbox_hbox/main.cpp => dom/vbox_hbox.cpp} |  2 -
 examples/frame/CMakeLists.txt                 |  4 -
 examples/gauge/CMakeLists.txt                 |  4 -
 examples/input/CMakeLists.txt                 |  4 -
 examples/menu/CMakeLists.txt                  |  4 -
 examples/menu2/CMakeLists.txt                 |  4 -
 .../main.cpp => print_key_press.cpp}          |  0
 examples/print_key_press/CMakeLists.txt       |  4 -
 examples/separator/CMakeLists.txt             |  4 -
 examples/toggle/CMakeLists.txt                |  4 -
 examples/vbox_hbox/CMakeLists.txt             |  4 -
 .../ftxui/component/component_direction.hpp   |  1 +
 ftxui/include/ftxui/dom/elements.hpp          |  6 +-
 ftxui/include/ftxui/dom/node.hpp              |  8 +-
 ftxui/src/ftxui/component/input.cpp           |  3 +
 ftxui/src/ftxui/dom/blink.cpp                 | 27 +++++++
 ftxui/src/ftxui/dom/util.cpp                  | 11 +++
 ftxui/src/ftxui/screen.cpp                    | 79 ++++++++-----------
 ftxui/src/ftxui/screen_interactive.cpp        |  6 ++
 tutorial.md                                   | 20 +++--
 32 files changed, 122 insertions(+), 116 deletions(-)
 delete mode 100644 examples/color/CMakeLists.txt
 create mode 100644 examples/component/CMakeLists.txt
 rename examples/{color/main.cpp => component/color.cpp} (99%)
 rename examples/{gauge/main.cpp => component/gauge.cpp} (100%)
 rename examples/{input/main.cpp => component/input.cpp} (94%)
 rename examples/{menu/main.cpp => component/menu.cpp} (100%)
 rename examples/{menu2/main.cpp => component/menu2.cpp} (97%)
 rename examples/{toggle/main.cpp => component/toggle.cpp} (100%)
 create mode 100644 examples/dom/CMakeLists.txt
 rename examples/{frame/main.cpp => dom/frame.cpp} (100%)
 rename examples/{separator/main.cpp => dom/separator.cpp} (99%)
 rename examples/{vbox_hbox/main.cpp => dom/vbox_hbox.cpp} (97%)
 delete mode 100644 examples/frame/CMakeLists.txt
 delete mode 100644 examples/gauge/CMakeLists.txt
 delete mode 100644 examples/input/CMakeLists.txt
 delete mode 100644 examples/menu/CMakeLists.txt
 delete mode 100644 examples/menu2/CMakeLists.txt
 rename examples/{print_key_press/main.cpp => print_key_press.cpp} (100%)
 delete mode 100644 examples/print_key_press/CMakeLists.txt
 delete mode 100644 examples/separator/CMakeLists.txt
 delete mode 100644 examples/toggle/CMakeLists.txt
 delete mode 100644 examples/vbox_hbox/CMakeLists.txt
 create mode 100644 ftxui/src/ftxui/dom/blink.cpp
 create mode 100644 ftxui/src/ftxui/dom/util.cpp

diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 9ffb08ec..c733e2d5 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,10 +1,8 @@
-add_subdirectory(color)
-add_subdirectory(frame)
-add_subdirectory(gauge)
-add_subdirectory(input)
-add_subdirectory(menu)
-add_subdirectory(menu2)
-add_subdirectory(print_key_press)
-add_subdirectory(separator)
-add_subdirectory(toggle)
-add_subdirectory(vbox_hbox)
+function(example name)
+  add_executable(${name} ${name}.cpp)
+  target_link_libraries(${name} PUBLIC ftxui)
+endfunction(example)
+
+add_subdirectory(component)
+add_subdirectory(dom)
+example(print_key_press)
diff --git a/examples/color/CMakeLists.txt b/examples/color/CMakeLists.txt
deleted file mode 100644
index 78183556..00000000
--- a/examples/color/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-add_executable(color_main
-  main.cpp
-)
-target_link_libraries(color_main PRIVATE ftxui)
diff --git a/examples/component/CMakeLists.txt b/examples/component/CMakeLists.txt
new file mode 100644
index 00000000..b6b9615a
--- /dev/null
+++ b/examples/component/CMakeLists.txt
@@ -0,0 +1,6 @@
+example(color)
+example(gauge)
+example(input)
+example(menu)
+example(menu2)
+example(toggle)
diff --git a/examples/color/main.cpp b/examples/component/color.cpp
similarity index 99%
rename from examples/color/main.cpp
rename to examples/component/color.cpp
index 337da032..5eb429ca 100644
--- a/examples/color/main.cpp
+++ b/examples/component/color.cpp
@@ -54,7 +54,5 @@ int main(int argc, const char *argv[])
 
   std::cout << screen.ToString();
 
-  getchar();
-
   return 0;
 }
diff --git a/examples/gauge/main.cpp b/examples/component/gauge.cpp
similarity index 100%
rename from examples/gauge/main.cpp
rename to examples/component/gauge.cpp
diff --git a/examples/input/main.cpp b/examples/component/input.cpp
similarity index 94%
rename from examples/input/main.cpp
rename to examples/component/input.cpp
index d4688c83..72ea012d 100644
--- a/examples/input/main.cpp
+++ b/examples/component/input.cpp
@@ -9,6 +9,7 @@
 
 using namespace ftxui::component;
 using namespace ftxui::dom;
+using namespace ftxui;
 
 class MyComponent : ComponentVertical {
  public:
@@ -44,7 +45,7 @@ class MyComponent : ComponentVertical {
 };
 
 int main(int argc, const char* argv[]) {
-  ftxui::ScreenInteractive screen(60, 17);
+  ftxui::ScreenInteractive screen(60, 5);
   MyComponent component(screen.delegate());
   component.on_enter = screen.ExitLoopClosure();
   screen.Loop();
diff --git a/examples/menu/main.cpp b/examples/component/menu.cpp
similarity index 100%
rename from examples/menu/main.cpp
rename to examples/component/menu.cpp
diff --git a/examples/menu2/main.cpp b/examples/component/menu2.cpp
similarity index 97%
rename from examples/menu2/main.cpp
rename to examples/component/menu2.cpp
index 80accafc..f2244af4 100644
--- a/examples/menu2/main.cpp
+++ b/examples/component/menu2.cpp
@@ -43,6 +43,7 @@ class MyComponent : ComponentHorizontal {
              flex(
                vbox(
                  hcenter(bold(text(L"Percentage by 10%"))),
+                 separator(),
                  left_menu.Render()
                )
              ),
@@ -50,6 +51,7 @@ class MyComponent : ComponentHorizontal {
              flex(
                vbox(
                  hcenter(bold(text(L"Percentage by 1%"))),
+                 separator(),
                  right_menu.Render()
                )
              ),
diff --git a/examples/toggle/main.cpp b/examples/component/toggle.cpp
similarity index 100%
rename from examples/toggle/main.cpp
rename to examples/component/toggle.cpp
diff --git a/examples/dom/CMakeLists.txt b/examples/dom/CMakeLists.txt
new file mode 100644
index 00000000..6aeb8a51
--- /dev/null
+++ b/examples/dom/CMakeLists.txt
@@ -0,0 +1,3 @@
+example(frame)
+example(separator)
+example(vbox_hbox)
diff --git a/examples/frame/main.cpp b/examples/dom/frame.cpp
similarity index 100%
rename from examples/frame/main.cpp
rename to examples/dom/frame.cpp
diff --git a/examples/separator/main.cpp b/examples/dom/separator.cpp
similarity index 99%
rename from examples/separator/main.cpp
rename to examples/dom/separator.cpp
index e3426d88..79f1f9af 100644
--- a/examples/separator/main.cpp
+++ b/examples/dom/separator.cpp
@@ -19,7 +19,6 @@ int main(int argc, const char *argv[])
   Render(screen, document.get());
 
   std::cout << screen.ToString();
-
   getchar();
 
   return 0;
diff --git a/examples/vbox_hbox/main.cpp b/examples/dom/vbox_hbox.cpp
similarity index 97%
rename from examples/vbox_hbox/main.cpp
rename to examples/dom/vbox_hbox.cpp
index f4efb41e..77bdc358 100644
--- a/examples/vbox_hbox/main.cpp
+++ b/examples/dom/vbox_hbox.cpp
@@ -32,7 +32,5 @@ int main(int argc, const char *argv[])
 
   std::cout << screen.ToString();
 
-  getchar();
-
   return 0;
 }
diff --git a/examples/frame/CMakeLists.txt b/examples/frame/CMakeLists.txt
deleted file mode 100644
index cef99a5d..00000000
--- a/examples/frame/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-add_executable(frame_example
-  main.cpp
-)
-target_link_libraries(frame_example PRIVATE ftxui)
diff --git a/examples/gauge/CMakeLists.txt b/examples/gauge/CMakeLists.txt
deleted file mode 100644
index ea0a9644..00000000
--- a/examples/gauge/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-add_executable(gauge_example
-  main.cpp
-)
-target_link_libraries(gauge_example PRIVATE ftxui)
diff --git a/examples/input/CMakeLists.txt b/examples/input/CMakeLists.txt
deleted file mode 100644
index 1e37595c..00000000
--- a/examples/input/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-add_executable(input_main
-  main.cpp
-)
-target_link_libraries(input_main PRIVATE ftxui)
diff --git a/examples/menu/CMakeLists.txt b/examples/menu/CMakeLists.txt
deleted file mode 100644
index 3b5e4200..00000000
--- a/examples/menu/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-add_executable(menu_main
-  main.cpp
-)
-target_link_libraries(menu_main PRIVATE ftxui)
diff --git a/examples/menu2/CMakeLists.txt b/examples/menu2/CMakeLists.txt
deleted file mode 100644
index 719d9bc2..00000000
--- a/examples/menu2/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-add_executable(menu2_main
-  main.cpp
-)
-target_link_libraries(menu2_main PRIVATE ftxui)
diff --git a/examples/print_key_press/main.cpp b/examples/print_key_press.cpp
similarity index 100%
rename from examples/print_key_press/main.cpp
rename to examples/print_key_press.cpp
diff --git a/examples/print_key_press/CMakeLists.txt b/examples/print_key_press/CMakeLists.txt
deleted file mode 100644
index 8245f948..00000000
--- a/examples/print_key_press/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-add_executable(print_key_press
-  main.cpp
-)
-target_link_libraries(print_key_press PRIVATE ftxui)
diff --git a/examples/separator/CMakeLists.txt b/examples/separator/CMakeLists.txt
deleted file mode 100644
index f2922117..00000000
--- a/examples/separator/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-add_executable(separator_example
-  main.cpp
-)
-target_link_libraries(separator_example PRIVATE ftxui)
diff --git a/examples/toggle/CMakeLists.txt b/examples/toggle/CMakeLists.txt
deleted file mode 100644
index a1784e26..00000000
--- a/examples/toggle/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-add_executable(toogle_main
-  main.cpp
-)
-target_link_libraries(toogle_main PRIVATE ftxui)
diff --git a/examples/vbox_hbox/CMakeLists.txt b/examples/vbox_hbox/CMakeLists.txt
deleted file mode 100644
index 4db6ff6e..00000000
--- a/examples/vbox_hbox/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-add_executable(vbox_hbox_example
-  main.cpp
-)
-target_link_libraries(vbox_hbox_example PRIVATE ftxui)
diff --git a/ftxui/include/ftxui/component/component_direction.hpp b/ftxui/include/ftxui/component/component_direction.hpp
index 55b99ef8..1b7c6a25 100644
--- a/ftxui/include/ftxui/component/component_direction.hpp
+++ b/ftxui/include/ftxui/component/component_direction.hpp
@@ -7,6 +7,7 @@ namespace ftxui {
 namespace component {
 
 // A component where focus and events are automatically handled for you.
+// Please use ComponentVertical or ComponentHorizontal.
 class ComponentDirection : public Component {
  public:
   ComponentDirection(Delegate* delegate);
diff --git a/ftxui/include/ftxui/dom/elements.hpp b/ftxui/include/ftxui/dom/elements.hpp
index c24a1f6d..c2a7c73b 100644
--- a/ftxui/include/ftxui/dom/elements.hpp
+++ b/ftxui/include/ftxui/dom/elements.hpp
@@ -15,6 +15,7 @@ using Children = std::vector<Child>;
 Element vbox(Children);
 Element hbox(Children);
 Element flex();
+Element flex(Element);
 
 // --- Widget --
 Element text(std::wstring text);
@@ -23,7 +24,7 @@ Element gauge(float ratio);
 Element frame(Child);
 Element frame(Child title, Child content);
 
-// -- Decorator (Style) ---
+// -- Style ---
 Element bold(Element);
 Element dim(Element);
 Element inverted(Element);
@@ -32,11 +33,10 @@ Element blink(Element);
 Element color(Color, Element);
 Element bgcolor(Color, Element);
 
-// --- Decorator ---
+// --- Util ---
 Element hcenter(Element);
 Element vcenter(Element);
 Element center(Element);
-Element flex(Element);
 
 // --- Util ---
 Element nothing(Element element);
diff --git a/ftxui/include/ftxui/dom/node.hpp b/ftxui/include/ftxui/dom/node.hpp
index 6a5f7beb..7f92be7f 100644
--- a/ftxui/include/ftxui/dom/node.hpp
+++ b/ftxui/include/ftxui/dom/node.hpp
@@ -17,14 +17,14 @@ class Node {
   Node(std::vector<std::unique_ptr<Node>> children);
   virtual ~Node();
 
-  // Step 1: Direction parent <= children.
-  //         Compute layout requirement. Tell parent what dimensions this
+  // Step 1: Compute layout requirement. Tell parent what dimensions this
   //         element wants to be.
+  //         Propagated from Children to Parents.
   virtual void ComputeRequirement();
   Requirement requirement() { return requirement_; }
 
-  // Step 2: Direction parent => children.
-  //         Assign this element its final dimensions.
+  // Step 2: Assign this element its final dimensions.
+  //         Propagated from Parents to Children.
   virtual void SetBox(Box box);
 
   // Step 3: Draw this element.
diff --git a/ftxui/src/ftxui/component/input.cpp b/ftxui/src/ftxui/component/input.cpp
index 77e53d66..3da91e42 100644
--- a/ftxui/src/ftxui/component/input.cpp
+++ b/ftxui/src/ftxui/component/input.cpp
@@ -24,6 +24,9 @@ dom::Element Input::Render() {
   if (!is_focused)
     return flex(text(content));
 
+  std::wstring sub_content = content;
+  size_t sub_cursor_position = cursor_position;
+
   std::wstring part_before_cursor = content.substr(0,cursor_position);
   std::wstring part_at_cursor = cursor_position < (int)content.size()
                                     ? content.substr(cursor_position, 1)
diff --git a/ftxui/src/ftxui/dom/blink.cpp b/ftxui/src/ftxui/dom/blink.cpp
new file mode 100644
index 00000000..a24f20a2
--- /dev/null
+++ b/ftxui/src/ftxui/dom/blink.cpp
@@ -0,0 +1,27 @@
+#include "ftxui/dom/node_decorator.hpp"
+#include "ftxui/dom/elements.hpp"
+
+namespace ftxui {
+namespace dom {
+
+class Blink : public NodeDecorator {
+ public:
+  Blink(Children children) : NodeDecorator(std::move(children)) {}
+  ~Blink() override {}
+
+  void Render(Screen& screen) override {
+    Node::Render(screen);
+    for (int y = box_.top; y <= box_.bottom; ++y) {
+      for (int x = box_.left; x <= box_.right; ++x) {
+        screen.PixelAt(x, y).blink = true;
+      }
+    }
+  }
+};
+
+std::unique_ptr<Node> blink(Child child) {
+  return std::make_unique<Blink>(unpack(std::move(child)));
+}
+
+};  // namespace dom
+};  // namespace ftxui
diff --git a/ftxui/src/ftxui/dom/util.cpp b/ftxui/src/ftxui/dom/util.cpp
new file mode 100644
index 00000000..b4dc76f1
--- /dev/null
+++ b/ftxui/src/ftxui/dom/util.cpp
@@ -0,0 +1,11 @@
+#include "ftxui/dom/elements.hpp"
+
+namespace ftxui {
+namespace dom {
+
+Element nothing(Element element) {
+  return std::move(element);
+}
+
+};  // namespace dom
+};  // namespace ftxui
diff --git a/ftxui/src/ftxui/screen.cpp b/ftxui/src/ftxui/screen.cpp
index 79cc866a..c2e05166 100644
--- a/ftxui/src/ftxui/screen.cpp
+++ b/ftxui/src/ftxui/screen.cpp
@@ -1,5 +1,5 @@
-#include "ftxui/dom/node.hpp"
 #include "ftxui/screen.hpp"
+#include "ftxui/dom/node.hpp"
 #include "ftxui/terminal.hpp"
 #include "ftxui/util/string.hpp"
 
@@ -10,6 +10,35 @@ namespace ftxui {
 Screen::Screen(size_t dimx, size_t dimy)
     : dimx_(dimx), dimy_(dimy), pixels_(dimy, std::vector<Pixel>(dimx)) {}
 
+void UpdatePixelStyle(std::wstringstream& ss, Pixel& previous, Pixel& next) {
+  if (next.bold != previous.bold)
+    ss << (next.bold ? L"\e[1m" : L"\e[0m");
+
+  if (next.inverted != previous.inverted)
+    ss << (next.inverted ? L"\e[7m" : L"\e[27m");
+
+  if (next.underlined != previous.underlined)
+    ss << (next.underlined ? L"\e[4m" : L"\e[24m");
+
+  if (next.dim != previous.dim)
+    ss << (next.dim ? L"\e[2m" : L"\e[22m");
+
+  if (next.blink != previous.blink)
+    ss << (next.blink ? L"\e[5m" : L"\e[25m");
+
+  if (next.foreground_color != previous.foreground_color) {
+    ss << L"\e[" + to_wstring(std::to_string((uint8_t)next.foreground_color)) +
+              L"m";
+  }
+  if (next.background_color != previous.background_color) {
+    ss << L"\e[" +
+              to_wstring(std::to_string(10 + (uint8_t)next.background_color)) +
+              L"m";
+  }
+
+  previous = next;
+}
+
 std::string Screen::ToString() {
   std::wstringstream ss;
 
@@ -17,57 +46,13 @@ std::string Screen::ToString() {
 
   for (size_t y = 0; y < dimy_; ++y) {
     for (size_t x = 0; x < dimx_; ++x) {
-      if (pixels_[y][x].bold != previous_pixel.bold) {
-        if (pixels_[y][x].bold) {
-          ss << L"\e[1m";
-        } else {
-          ss << L"\e[0m";
-        }
-      }
-      if (pixels_[y][x].inverted != previous_pixel.inverted) {
-        if (pixels_[y][x].inverted) {
-          ss << L"\e[7m";
-        } else {
-          ss << L"\e[27m";
-        }
-      }
-      if (pixels_[y][x].underlined != previous_pixel.underlined) {
-        if (pixels_[y][x].underlined) {
-          ss << L"\e[4m";
-        } else {
-          ss << L"\e[24m";
-        }
-      }
-      if (pixels_[y][x].dim != previous_pixel.dim) {
-        if (pixels_[y][x].dim) {
-          ss << L"\e[2m";
-        } else {
-          ss << L"\e[22m";
-        }
-      }
-      if (pixels_[y][x].blink != previous_pixel.blink) {
-        if (pixels_[y][x].blink) {
-          ss << L"\e[5m";
-        } else {
-          ss << L"\e[25m";
-        }
-      }
-      if (pixels_[y][x].foreground_color != previous_pixel.foreground_color) {
-        ss << L"\e[" + to_wstring(std::to_string(
-                           (uint8_t)pixels_[y][x].foreground_color)) +
-                  L"m";
-      }
-      if (pixels_[y][x].background_color != previous_pixel.background_color) {
-        ss << L"\e[" + to_wstring(std::to_string(
-                           10 + (uint8_t)pixels_[y][x].background_color)) +
-                  L"m";
-      }
+      UpdatePixelStyle(ss, previous_pixel, pixels_[y][x]);
       ss << pixels_[y][x].character;
-      previous_pixel = pixels_[y][x];
     }
     if (y + 1 < dimy_)
       ss << '\n';
   }
+
   return to_string(ss.str());
 }
 
diff --git a/ftxui/src/ftxui/screen_interactive.cpp b/ftxui/src/ftxui/screen_interactive.cpp
index 7e157e35..0ffd1fd5 100644
--- a/ftxui/src/ftxui/screen_interactive.cpp
+++ b/ftxui/src/ftxui/screen_interactive.cpp
@@ -11,6 +11,7 @@ namespace ftxui {
 namespace {
   constexpr int ESC = 27;
   constexpr int WAT = 195;
+  constexpr int WAT2 = 194;
   constexpr int WATWAIT = 91;
 
   Event GetEvent() {
@@ -32,6 +33,11 @@ namespace {
       return Event{v1, v2};
     }
 
+    if (v1 == WAT2) {
+      int v2 = getchar();
+      return Event{v1, v2};
+    }
+
     return Event{v1};
   };
 };
diff --git a/tutorial.md b/tutorial.md
index f3920948..955c6baf 100644
--- a/tutorial.md
+++ b/tutorial.md
@@ -25,6 +25,7 @@ It declares the following set of elements:
 Element vbox(Children);
 Element hbox(Children);
 Element flex();
+Element flex(Element);
 
 // --- Widget --
 Element text(std::wstring text);
@@ -33,24 +34,28 @@ Element gauge(float ratio);
 Element frame(Child);
 Element frame(Child title, Child content);
 
-// -- Decorator (Style) ---
+// -- Style ---
 Element bold(Element);
 Element dim(Element);
 Element inverted(Element);
 Element underlined(Element);
-Element color(Color,Element);
-Element bgcolor(Element);
+Element blink(Element);
+Element color(Color, Element);
+Element bgcolor(Color, Element);
 
-// --- Decorator ---
+// --- Util ---
 Element hcenter(Element);
 Element vcenter(Element);
 Element center(Element);
-Element flex(Element);
+
+// --- Util ---
+Element nothing(Element element);
 ~~~
 
 ### Style
 A terminal console can usually display colored text and colored background.
-The text can also have different effects: bold, dim, underlined, inverted.
+The text can also have different effects: bold, dim, underlined, inverted,
+blink.
 
 ~~~cpp
 Element bold(Element);
@@ -164,5 +169,8 @@ frame(gauge(0.5))
 ## Components.
 
 ### Input
+  TODO(arthursonzogni): Add Video
 ### Menu
+  TODO(arthursonzogni): Add Video
 ### Toggle.
+  TODO(arthursonzogni): Add video
-- 
GitLab