From 1a4b2c98b2b08710baf815aea5b24cba37e6dd1f Mon Sep 17 00:00:00 2001
From: Arthur Sonzogni <sonzogniarthur@gmail.com>
Date: Fri, 12 Oct 2018 09:23:37 +0200
Subject: [PATCH] Add colors.

+ example.
---
 .clang-format                            |  4 --
 examples/CMakeLists.txt                  |  3 +-
 examples/color/CMakeLists.txt            |  4 ++
 examples/color/main.cpp                  | 60 ++++++++++++++++++++++++
 ftxui/CMakeLists.txt                     | 10 ++--
 ftxui/include/ftxui/color.hpp            | 40 ++++++++++++++++
 ftxui/include/ftxui/dom/elements.hpp     |  3 ++
 ftxui/include/ftxui/screen.hpp           |  4 ++
 ftxui/src/ftxui/dom/bold.cpp             | 16 ++-----
 ftxui/src/ftxui/dom/color.cpp            | 51 ++++++++++++++++++++
 ftxui/src/ftxui/dom/dim.cpp              | 16 ++-----
 ftxui/src/ftxui/dom/inverted.cpp         | 16 ++-----
 ftxui/src/ftxui/dom/node_decorator.cpp   | 17 +++++++
 ftxui/src/ftxui/dom/node_decorator.hpp   | 22 +++++++++
 ftxui/src/ftxui/dom/underlined.cpp       | 18 ++-----
 ftxui/src/ftxui/screen.cpp               | 14 +++++-
 tutorials/dom_elements.md => tutorial.md |  0
 17 files changed, 234 insertions(+), 64 deletions(-)
 create mode 100644 examples/color/CMakeLists.txt
 create mode 100644 examples/color/main.cpp
 create mode 100644 ftxui/include/ftxui/color.hpp
 create mode 100644 ftxui/src/ftxui/dom/color.cpp
 create mode 100644 ftxui/src/ftxui/dom/node_decorator.cpp
 create mode 100644 ftxui/src/ftxui/dom/node_decorator.hpp
 rename tutorials/dom_elements.md => tutorial.md (100%)

diff --git a/.clang-format b/.clang-format
index 6fdf1dc8..0f21d0bb 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,8 +1,4 @@
 # Defines the Chromium style for automatic reformatting.
 # http://clang.llvm.org/docs/ClangFormatStyleOptions.html
 BasedOnStyle: Chromium
-# This defaults to 'Auto'. Explicitly set it for a while, so that
-# 'vector<vector<int> >' in existing files gets formatted to
-# 'vector<vector<int>>'. ('Auto' means that clang-format will only use
-# 'int>>' if the file already contains at least one such instance.)
 Standard: Cpp11
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 7637c65e..53382c7d 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,8 +1,9 @@
+add_subdirectory(color)
 add_subdirectory(frame)
 add_subdirectory(gauge)
 add_subdirectory(menu)
 add_subdirectory(menu2)
 add_subdirectory(print_key_press)
 add_subdirectory(separator)
-add_subdirectory(vbox_hbox)
 add_subdirectory(toggle)
+add_subdirectory(vbox_hbox)
diff --git a/examples/color/CMakeLists.txt b/examples/color/CMakeLists.txt
new file mode 100644
index 00000000..78183556
--- /dev/null
+++ b/examples/color/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_executable(color_main
+  main.cpp
+)
+target_link_libraries(color_main PRIVATE ftxui)
diff --git a/examples/color/main.cpp b/examples/color/main.cpp
new file mode 100644
index 00000000..337da032
--- /dev/null
+++ b/examples/color/main.cpp
@@ -0,0 +1,60 @@
+#include "ftxui/screen.hpp"
+#include "ftxui/dom/elements.hpp"
+#include <iostream>
+
+int main(int argc, const char *argv[])
+{
+  using namespace ftxui;
+  using namespace ftxui::dom;
+  auto document =
+    hbox(
+      vbox(
+        color(Color::Default, text(L"Default")),
+        color(Color::Black, text(L"Black")),
+        color(Color::GrayDark, text(L"GrayDark")),
+        color(Color::GrayLight, text(L"GrayLight")),
+        color(Color::White, text(L"White")),
+        color(Color::Blue, text(L"Blue")),
+        color(Color::BlueLight, text(L"BlueLight")),
+        color(Color::Cyan, text(L"Cyan")),
+        color(Color::CyanLight, text(L"CyanLight")),
+        color(Color::Green, text(L"Green")),
+        color(Color::GreenLight, text(L"GreenLight")),
+        color(Color::Magenta, text(L"Magenta")),
+        color(Color::MagentaLight, text(L"MagentaLight")),
+        color(Color::Red, text(L"Red")),
+        color(Color::RedLight, text(L"RedLight")),
+        color(Color::Yellow, text(L"Yellow")),
+        color(Color::YellowLight, text(L"YellowLight"))
+      ),
+      vbox(
+        bgcolor(Color::Default, text(L"Default")),
+        bgcolor(Color::Black, text(L"Black")),
+        bgcolor(Color::GrayDark, text(L"GrayDark")),
+        bgcolor(Color::GrayLight, text(L"GrayLight")),
+        bgcolor(Color::White, text(L"White")),
+        bgcolor(Color::Blue, text(L"Blue")),
+        bgcolor(Color::BlueLight, text(L"BlueLight")),
+        bgcolor(Color::Cyan, text(L"Cyan")),
+        bgcolor(Color::CyanLight, text(L"CyanLight")),
+        bgcolor(Color::Green, text(L"Green")),
+        bgcolor(Color::GreenLight, text(L"GreenLight")),
+        bgcolor(Color::Magenta, text(L"Magenta")),
+        bgcolor(Color::MagentaLight, text(L"MagentaLight")),
+        bgcolor(Color::Red, text(L"Red")),
+        bgcolor(Color::RedLight, text(L"RedLight")),
+        bgcolor(Color::Yellow, text(L"Yellow")),
+        bgcolor(Color::YellowLight, text(L"YellowLight"))
+      ),
+      flex()
+    );
+
+  auto screen = ftxui::Screen::TerminalOutput(document);
+  Render(screen, document.get());
+
+  std::cout << screen.ToString();
+
+  getchar();
+
+  return 0;
+}
diff --git a/ftxui/CMakeLists.txt b/ftxui/CMakeLists.txt
index dc5d1fff..7128aac9 100644
--- a/ftxui/CMakeLists.txt
+++ b/ftxui/CMakeLists.txt
@@ -6,21 +6,23 @@ add_library(ftxui
   src/ftxui/component/component_direction.cpp
   src/ftxui/component/component_horizontal.cpp
   src/ftxui/component/component_vertical.cpp
-  src/ftxui/component/toggle.cpp
   src/ftxui/component/menu.cpp
+  src/ftxui/component/toggle.cpp
   src/ftxui/dom/bold.cpp
-  src/ftxui/dom/dim.cpp
-  src/ftxui/dom/underlined.cpp
-  src/ftxui/dom/inverted.cpp
+  src/ftxui/dom/color.cpp
   src/ftxui/dom/composite_decorator.cpp
+  src/ftxui/dom/dim.cpp
   src/ftxui/dom/flex.cpp
   src/ftxui/dom/frame.cpp
   src/ftxui/dom/frame.cpp
   src/ftxui/dom/gauge.cpp
   src/ftxui/dom/hbox.cpp
+  src/ftxui/dom/inverted.cpp
   src/ftxui/dom/node.cpp
+  src/ftxui/dom/node_decorator.cpp
   src/ftxui/dom/separator.cpp
   src/ftxui/dom/text.cpp
+  src/ftxui/dom/underlined.cpp
   src/ftxui/dom/vbox.cpp
   src/ftxui/screen.cpp
   src/ftxui/screen_interactive.cpp
diff --git a/ftxui/include/ftxui/color.hpp b/ftxui/include/ftxui/color.hpp
new file mode 100644
index 00000000..4853c5cb
--- /dev/null
+++ b/ftxui/include/ftxui/color.hpp
@@ -0,0 +1,40 @@
+#ifndef FTXUI_COLOR_H_
+#define FTXUI_COLOR_H_
+
+#include <cstdint>
+
+namespace ftxui {
+
+enum class Color : uint8_t {
+  // --- Transparent -----
+  Default = 39,
+
+  // --- Grayscale -----
+  Black = 30,
+  GrayDark = 90,
+  GrayLight = 37,
+  White = 97,
+
+  // --- Hue -----
+  Blue = 34,
+  BlueLight = 94,
+
+  Cyan = 36,
+  CyanLight = 96,
+
+  Green = 32,
+  GreenLight = 92,
+
+  Magenta = 35,
+  MagentaLight = 95,
+
+  Red = 31,
+  RedLight = 91,
+
+  Yellow = 33,
+  YellowLight = 93,
+};
+
+};  // namespace ftxui
+
+#endif /* end of include guard: FTXUI_COLOR_H_ */
diff --git a/ftxui/include/ftxui/dom/elements.hpp b/ftxui/include/ftxui/dom/elements.hpp
index 40c2dfe2..37f2d302 100644
--- a/ftxui/include/ftxui/dom/elements.hpp
+++ b/ftxui/include/ftxui/dom/elements.hpp
@@ -1,6 +1,7 @@
 #ifndef FTXUI_DOM_ELEMENTS_HPP
 #define FTXUI_DOM_ELEMENTS_HPP
 
+#include "ftxui/color.hpp"
 #include "ftxui/dom/node.hpp"
 
 namespace ftxui {
@@ -27,6 +28,8 @@ Element bold(Element);
 Element dim(Element);
 Element inverted(Element);
 Element underlined(Element);
+Element color(Color, Element);
+Element bgcolor(Color, Element);
 
 // --- Decorator ---
 Element hcenter(Element);
diff --git a/ftxui/include/ftxui/screen.hpp b/ftxui/include/ftxui/screen.hpp
index 2782271a..3f6fcabd 100644
--- a/ftxui/include/ftxui/screen.hpp
+++ b/ftxui/include/ftxui/screen.hpp
@@ -5,6 +5,8 @@
 #include <vector>
 #include <memory>
 
+#include <ftxui/color.hpp>
+
 namespace ftxui {
 namespace dom {
   class Node;
@@ -16,6 +18,8 @@ struct Pixel {
   bool inverted = false;
   bool underlined = false;
   bool dim = false;
+  Color background_color = Color::Default;
+  Color foreground_color = Color::Default;
 };
 
 class Screen {
diff --git a/ftxui/src/ftxui/dom/bold.cpp b/ftxui/src/ftxui/dom/bold.cpp
index cee8d972..90250201 100644
--- a/ftxui/src/ftxui/dom/bold.cpp
+++ b/ftxui/src/ftxui/dom/bold.cpp
@@ -1,24 +1,14 @@
-#include "ftxui/dom/node.hpp"
+#include "ftxui/dom/node_decorator.hpp"
 #include "ftxui/dom/elements.hpp"
 
 namespace ftxui {
 namespace dom {
 
-class Bold : public Node {
+class Bold : public NodeDecorator {
  public:
-  Bold(Children children) : Node(std::move(children)) {}
+  Bold(Children children) : NodeDecorator(std::move(children)) {}
   ~Bold() override {}
 
-  void ComputeRequirement() override {
-    Node::ComputeRequirement();
-    requirement_ = children[0]->requirement();
-  }
-
-  void SetBox(Box box) override {
-    Node::SetBox(box);
-    children[0]->SetBox(box);
-  }
-
   void Render(Screen& screen) override {
     Node::Render(screen);
     for (int y = box_.top; y <= box_.bottom; ++y) {
diff --git a/ftxui/src/ftxui/dom/color.cpp b/ftxui/src/ftxui/dom/color.cpp
new file mode 100644
index 00000000..e0c44c9c
--- /dev/null
+++ b/ftxui/src/ftxui/dom/color.cpp
@@ -0,0 +1,51 @@
+#include "ftxui/dom/node_decorator.hpp"
+#include "ftxui/dom/elements.hpp"
+
+namespace ftxui {
+namespace dom {
+
+class BgColor : public NodeDecorator {
+ public:
+  BgColor(Children children, Color color)
+      : NodeDecorator(std::move(children)), color_(color) {}
+
+  void Render(Screen& screen) override {
+    NodeDecorator::Render(screen);
+    for (int y = box_.top; y <= box_.bottom; ++y) {
+      for (int x = box_.left; x <= box_.right; ++x) {
+        screen.PixelAt(x, y).background_color = color_;
+      }
+    }
+  }
+
+  Color color_;
+};
+
+class FgColor : public NodeDecorator {
+ public:
+  FgColor(Children children, Color color)
+      : NodeDecorator(std::move(children)), color_(color) {}
+  ~FgColor() override {}
+
+  void Render(Screen& screen) override {
+    NodeDecorator::Render(screen);
+    for (int y = box_.top; y <= box_.bottom; ++y) {
+      for (int x = box_.left; x <= box_.right; ++x) {
+        screen.PixelAt(x, y).foreground_color = color_;
+      }
+    }
+  }
+
+  Color color_;
+};
+
+std::unique_ptr<Node> color(Color c, Child child) {
+  return std::make_unique<FgColor>(unpack(std::move(child)), c);
+}
+
+std::unique_ptr<Node> bgcolor(Color c, Child child) {
+  return std::make_unique<BgColor>(unpack(std::move(child)), c);
+}
+
+};  // namespace dom
+};  // namespace ftxui
diff --git a/ftxui/src/ftxui/dom/dim.cpp b/ftxui/src/ftxui/dom/dim.cpp
index 08283f96..ef7cdb96 100644
--- a/ftxui/src/ftxui/dom/dim.cpp
+++ b/ftxui/src/ftxui/dom/dim.cpp
@@ -1,24 +1,14 @@
-#include "ftxui/dom/node.hpp"
+#include "ftxui/dom/node_decorator.hpp"
 #include "ftxui/dom/elements.hpp"
 
 namespace ftxui {
 namespace dom {
 
-class Dim : public Node {
+class Dim : public NodeDecorator {
  public:
-  Dim(Children children) : Node(std::move(children)) {}
+  Dim(Children children) : NodeDecorator(std::move(children)) {}
   ~Dim() override {}
 
-  void ComputeRequirement() override {
-    Node::ComputeRequirement();
-    requirement_ = children[0]->requirement();
-  }
-
-  void SetBox(Box box) override {
-    Node::SetBox(box);
-    children[0]->SetBox(box);
-  }
-
   void Render(Screen& screen) override {
     Node::Render(screen);
     for (int y = box_.top; y <= box_.bottom; ++y) {
diff --git a/ftxui/src/ftxui/dom/inverted.cpp b/ftxui/src/ftxui/dom/inverted.cpp
index 2f4afdb8..2e231ee8 100644
--- a/ftxui/src/ftxui/dom/inverted.cpp
+++ b/ftxui/src/ftxui/dom/inverted.cpp
@@ -1,24 +1,14 @@
-#include "ftxui/dom/node.hpp"
+#include "ftxui/dom/node_decorator.hpp"
 #include "ftxui/dom/elements.hpp"
 
 namespace ftxui {
 namespace dom {
 
-class Inverted : public Node {
+class Inverted : public NodeDecorator {
  public:
-  Inverted(Children children) : Node(std::move(children)) {}
+  Inverted(Children children) : NodeDecorator(std::move(children)) {}
   ~Inverted() override {}
 
-  void ComputeRequirement() override {
-    Node::ComputeRequirement();
-    requirement_ = children[0]->requirement();
-  }
-
-  void SetBox(Box box) override {
-    Node::SetBox(box);
-    children[0]->SetBox(box);
-  }
-
   void Render(Screen& screen) override {
     Node::Render(screen);
     for (int y = box_.top; y <= box_.bottom; ++y) {
diff --git a/ftxui/src/ftxui/dom/node_decorator.cpp b/ftxui/src/ftxui/dom/node_decorator.cpp
new file mode 100644
index 00000000..8ba35a92
--- /dev/null
+++ b/ftxui/src/ftxui/dom/node_decorator.cpp
@@ -0,0 +1,17 @@
+#include "ftxui/dom/node_decorator.hpp"
+
+namespace ftxui {
+namespace dom {
+
+void NodeDecorator::ComputeRequirement() {
+  Node::ComputeRequirement();
+  requirement_ = children[0]->requirement();
+}
+
+void NodeDecorator::SetBox(Box box) {
+  Node::SetBox(box);
+  children[0]->SetBox(box);
+}
+
+};  // namespace dom
+};  // namespace ftxui
diff --git a/ftxui/src/ftxui/dom/node_decorator.hpp b/ftxui/src/ftxui/dom/node_decorator.hpp
new file mode 100644
index 00000000..cc53ef31
--- /dev/null
+++ b/ftxui/src/ftxui/dom/node_decorator.hpp
@@ -0,0 +1,22 @@
+#ifndef FTXUI_DOM_NODE_DECORATOR_H_
+#define FTXUI_DOM_NODE_DECORATOR_H_
+
+#include "ftxui/dom/node.hpp"
+#include "ftxui/dom/elements.hpp"
+
+namespace ftxui {
+namespace dom {
+
+// Helper class.
+class NodeDecorator : public Node {
+ public:
+  NodeDecorator(Children children) : Node(std::move(children)) {}
+  ~NodeDecorator() override {}
+  void ComputeRequirement() override;
+  void SetBox(Box box) override;
+};
+
+};  // namespace dom
+};  // namespace ftxui
+
+#endif /* end of include guard: FTXUI_DOM_NODE_DECORATOR_H_ */
diff --git a/ftxui/src/ftxui/dom/underlined.cpp b/ftxui/src/ftxui/dom/underlined.cpp
index 07f714fc..b2cd7f9d 100644
--- a/ftxui/src/ftxui/dom/underlined.cpp
+++ b/ftxui/src/ftxui/dom/underlined.cpp
@@ -1,29 +1,19 @@
-#include "ftxui/dom/node.hpp"
+#include "ftxui/dom/node_decorator.hpp"
 #include "ftxui/dom/elements.hpp"
 
 namespace ftxui {
 namespace dom {
 
-class Underlined : public Node {
+class Underlined : public NodeDecorator {
  public:
-  Underlined(Children children) : Node(std::move(children)) {}
+  Underlined(Children children) : NodeDecorator(std::move(children)) {}
   ~Underlined() override {}
 
-  void ComputeRequirement() override {
-    Node::ComputeRequirement();
-    requirement_ = children[0]->requirement();
-  }
-
-  void SetBox(Box box) override {
-    Node::SetBox(box);
-    children[0]->SetBox(box);
-  }
-
   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).underlined = true; 
+        screen.PixelAt(x, y).underlined = true;
       }
     }
   }
diff --git a/ftxui/src/ftxui/screen.cpp b/ftxui/src/ftxui/screen.cpp
index cbb54975..a3adeefe 100644
--- a/ftxui/src/ftxui/screen.cpp
+++ b/ftxui/src/ftxui/screen.cpp
@@ -12,7 +12,7 @@ Screen::Screen(size_t dimx, size_t dimy)
 
 std::string Screen::ToString() {
   std::wstringstream ss;
-  
+
   Pixel previous_pixel;
 
   for (size_t y = 0; y < dimy_; ++y) {
@@ -45,6 +45,16 @@ std::string Screen::ToString() {
           ss << L"\e[22m";
         }
       }
+      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";
+      }
       ss << pixels_[y][x].character;
       previous_pixel = pixels_[y][x];
     }
@@ -77,7 +87,7 @@ Screen Screen::TerminalOutput(std::unique_ptr<dom::Node>& element) {
 
 std::string Screen::ResetPosition() {
   std::stringstream ss;
-  for(size_t y = 1; y<dimy_; ++y) {
+  for (size_t y = 1; y < dimy_; ++y) {
     ss << "\e[2K\r\e[1A";
   }
   return ss.str();
diff --git a/tutorials/dom_elements.md b/tutorial.md
similarity index 100%
rename from tutorials/dom_elements.md
rename to tutorial.md
-- 
GitLab