Add Graph.

This commit is contained in:
ArthurSonzogni 2019-01-26 21:52:55 +01:00
parent 1e92db7ec0
commit 9117166541
31 changed files with 226 additions and 80 deletions

View File

@ -73,7 +73,7 @@ class MyComponent : public Component {
separator(),
Render(L"radiobox", radiobox),
separator(),
Render(L"input", input) | size(WIDTH, EQUAL, 20)
Render(L"input", input) | size(WIDTH, LESS_THAN, 30)
) | border;
}
};

View File

@ -8,6 +8,7 @@ example(border)
example(gauge)
example(package_manager)
example(separator)
example(graph)
example(spinner)
example(style_blink)
example(style_bold)

View File

@ -41,7 +41,7 @@ int main(int argc, const char *argv[])
),
filler()
);
auto screen = Screen::TerminalOutput(document);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString() << std::endl;
}

View File

@ -16,7 +16,7 @@ int main(int argc, const char *argv[])
) | border,
text(L"overlay") | border | center
);
auto screen = Screen::TerminalOutput(document);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString();

65
examples/dom/graph.cpp Normal file
View File

@ -0,0 +1,65 @@
#include "ftxui/dom/elements.hpp"
#include "ftxui/dom/graph.hpp"
#include "ftxui/screen/screen.hpp"
#include "ftxui/screen/string.hpp"
#include <chrono>
#include <cmath>
#include <iostream>
#include <thread>
class Graph : public ftxui::GraphFunction {
public:
std::vector<int> operator()(int width, int height) {
std::vector<int> output(width);
for (int i = 0; i < width; ++i) {
float v = 0;
v += 0.1 * sin((i + shift) * 0.1);
v += 0.2 * sin((i + shift+10) * 0.15);
v += 0.1 * sin((i + shift) * 0.03);
// v += 0.2*sin((i+shift)*0.3);
// v += 0.1*sin((i+shift)*0.9);
v *= height;
v += 0.5 * height;
output[i] = v;
}
return output;
}
int shift = 0;
};
int main(int argc, const char* argv[]) {
using namespace ftxui;
using namespace std::chrono_literals;
Graph my_graph;
std::string reset_position;
for (int i = 0;; ++i) {
auto document =
window(text(L"Your graphs"),
hbox(
vbox(
graph(my_graph), separator(),
graph(my_graph) | inverted
) | flex,
separator(),
vbox(
graph(my_graph) | color(Color::BlueLight), separator(),
graph(my_graph) | color(Color::RedLight), separator(),
graph(my_graph) | color(Color::YellowLight)
) | flex
)
) | size(HEIGHT, GREATER_THAN, 40);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << reset_position << screen.ToString() << std::flush;
reset_position = screen.ResetPosition();
std::this_thread::sleep_for(0.03s);
my_graph.shift++;
}
return 0;
}

View File

@ -43,7 +43,7 @@ int main(int argc, const char *argv[])
| size(WIDTH, LESS_THAN, 50)
;
auto screen = Screen::TerminalOutput(document);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString() << std::endl;

View File

@ -39,7 +39,7 @@ int main(int argc, const char* argv[]) {
paragraph(L" A spinner "), spinner(6, i / 10)) |
border;
auto screen = Screen::TerminalFullscreen();
auto screen = Screen::Create(Dimension::Full());
Render(screen, document.get());
std::cout << reset_position << screen.ToString() << std::flush;

View File

@ -115,7 +115,7 @@ int main(int argc, const char *argv[])
// Draw.
auto document = render();
auto screen = Screen::TerminalOutput(document);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << reset_position << screen.ToString() << std::flush;
reset_position = screen.ResetPosition();

View File

@ -24,7 +24,7 @@ int main(int argc, const char *argv[])
) | flex
);
auto screen = Screen::TerminalFullscreen();
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString();
getchar();

View File

@ -9,17 +9,18 @@ int main(int argc, const char *argv[])
hbox(
text(L"left-column"),
separator(),
flex(vbox(
center(text(L"right-column")) | flex,
vbox(
center(text(L"right-top")) | flex,
separator(),
center(text(L"bottom-column"))
))
);
auto screen = Screen::TerminalFullscreen();
center(text(L"bottom-bottom"))
) | flex,
separator(),
text(L"right-column")
) | border;
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString();
getchar();
std::cout << screen.ToString() << std::endl;
return 0;
}

View File

@ -22,7 +22,7 @@ int main(int argc, const char *argv[])
);
}
auto document = hbox(std::move(content));
auto screen = Screen::FitDocument(document);
auto screen = Screen::Create(Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString() << std::endl;

View File

@ -26,7 +26,7 @@ int main(int argc, const char *argv[])
);
}
auto document = hbox(vbox(std::move(entries)) | border, filler());
auto screen = Screen::TerminalOutput(document);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << reset_position << screen.ToString() << std::flush;
reset_position = screen.ResetPosition();

View File

@ -11,7 +11,7 @@ int main(int argc, const char *argv[])
text(L"blink") | blink,
text(L". Do you like it?")
);
auto screen = Screen::TerminalOutput(document);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString();

View File

@ -11,7 +11,7 @@ int main(int argc, const char *argv[])
text(L"bold") | bold,
text(L". Do you like it?")
);
auto screen = Screen::TerminalOutput(document);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString();

View File

@ -48,7 +48,7 @@ int main(int argc, const char *argv[])
filler()
);
auto screen = Screen::TerminalOutput(document);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString();

View File

@ -11,7 +11,7 @@ int main(int argc, const char *argv[])
text(L"dim") | dim,
text(L". Do you like it?")
);
auto screen = Screen::TerminalOutput(document);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString();

View File

@ -16,7 +16,7 @@ int main(int argc, const char *argv[])
text(L"color") | color(Color::Blue) , text(L" ") ,
text(L"bgcolor") | bgcolor(Color::Blue)
);
auto screen = Screen::TerminalOutput(document);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString();

View File

@ -11,7 +11,7 @@ int main(int argc, const char *argv[])
text(L"inverted") | inverted,
text(L". Do you like it?")
);
auto screen = Screen::TerminalOutput(document);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString();

View File

@ -11,7 +11,7 @@ int main(int argc, const char *argv[])
text(L"underlined") | underlined,
text(L". Do you like it?")
);
auto screen = Screen::TerminalOutput(document);
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << screen.ToString();

View File

@ -28,7 +28,7 @@ int main(int argc, const char *argv[])
text(L"south-east")
)
);
auto screen = Screen::TerminalFullscreen();
auto screen = Screen::Create(Dimension::Full());
Render(screen, document.get());
std::cout << screen.ToString();

View File

@ -18,6 +18,7 @@ add_library(dom
src/ftxui/dom/flex.cpp
src/ftxui/dom/frame.cpp
src/ftxui/dom/gauge.cpp
src/ftxui/dom/graph.cpp
src/ftxui/dom/hbox.cpp
src/ftxui/dom/hflow.cpp
src/ftxui/dom/inverted.cpp

View File

@ -17,7 +17,7 @@ class CheckBox : public Component {
//std::wstring checked = L"[X] ";
//std::wstring unchecked = L"[ ] ";
std::wstring checked = L" ";
std::wstring checked = L" ";
std::wstring unchecked = L"";
Decorator focused_style = inverted;

View File

@ -10,7 +10,7 @@ class Component;
class ScreenInteractive : public Screen {
public:
static ScreenInteractive FixedSize(size_t dimx, size_t dimy);
static ScreenInteractive FixedSize(int dimx, int dimy);
static ScreenInteractive Fullscreen();
static ScreenInteractive FitComponent();
static ScreenInteractive TerminalOutput();
@ -30,7 +30,7 @@ class ScreenInteractive : public Screen {
TerminalOutput,
};
Dimension dimension_ = Dimension::Fixed;
ScreenInteractive(size_t dimx, size_t dimy, Dimension dimension);
ScreenInteractive(int dimx, int dimy, Dimension dimension);
};
} // namespace ftxui

View File

@ -3,6 +3,7 @@
#include <functional>
#include "ftxui/dom/graph.hpp"
#include "ftxui/dom/node.hpp"
#include "ftxui/screen/color.hpp"
@ -20,6 +21,7 @@ Element border(Element);
Element window(Element title, Element content);
Element spinner(int charset_index, size_t image_index);
Elements paragraph(std::wstring text); // Use inside hflow(). Split by space.
Element graph(GraphFunction&); // See graph.hpp
// -- Decorator ---
Element bold(Element);
@ -68,6 +70,7 @@ Element nothing(Element element);
// Pipe elements into decorator togethers.
// Examples: text("ftxui") | bold | underlined;
Element operator|(Element, Decorator);
Elements operator|(Elements, Decorator);
Decorator operator|(Decorator, Decorator);
// Make container able to take any number of children as input.

View File

@ -0,0 +1,15 @@
#ifndef FTXUI_DOM_GRAPH_HPP
#define FTXUI_DOM_GRAPH_HPP
#include "ftxui/dom/elements.hpp"
namespace ftxui {
class GraphFunction {
public:
virtual std::vector<int> operator()(int width, int height) = 0;
};
} // namespace ftxui
#endif /* end of include guard: FTXUI_DOM_GRAPH_HPP */

View File

@ -25,26 +25,32 @@ struct Pixel {
Color foreground_color = Color::Default;
};
struct Dimension {
static Dimension Fixed(int);
static Dimension Fit(std::unique_ptr<Node>&);
static Dimension Full();
int dimx;
int dimy;
};
class Screen {
public:
// Constructor.
Screen(size_t dimx, size_t dimy);
// Constructor using the terminal.
static Screen TerminalFullscreen();
static Screen TerminalOutput(std::unique_ptr<Node>& element);
static Screen FitDocument(std::unique_ptr<Node>& element);
Screen(int dimx, int dimy);
static Screen Create(Dimension dimension);
static Screen Create(Dimension width, Dimension height);
// Node write into the screen using Screen::at.
wchar_t& at(size_t x, size_t y);
Pixel& PixelAt(size_t x, size_t y);
wchar_t& at(int x, int y);
Pixel& PixelAt(int x, int y);
// Convert the screen into a printable string in the terminal.
std::string ToString();
// Get screen dimensions.
size_t dimx() { return dimx_;}
size_t dimy() { return dimy_;}
int dimx() { return dimx_;}
int dimy() { return dimy_;}
// Move the terminal cursor n-lines up with n = dimy().
std::string ResetPosition();
@ -56,8 +62,8 @@ class Screen {
Box stencil;
protected:
size_t dimx_;
size_t dimy_;
int dimx_;
int dimy_;
std::vector<std::vector<Pixel>> pixels_;
};

View File

@ -44,14 +44,14 @@ Event GetEvent() {
}; // namespace
ScreenInteractive::ScreenInteractive(size_t dimx,
size_t dimy,
ScreenInteractive::ScreenInteractive(int dimx,
int dimy,
Dimension dimension)
: Screen(dimx, dimy), dimension_(dimension) {}
ScreenInteractive::~ScreenInteractive() {}
// static
ScreenInteractive ScreenInteractive::FixedSize(size_t dimx, size_t dimy) {
ScreenInteractive ScreenInteractive::FixedSize(int dimx, int dimy) {
return ScreenInteractive(dimx, dimy, Dimension::Fixed);
}
@ -106,8 +106,8 @@ void ScreenInteractive::Loop(Component* component) {
void ScreenInteractive::Draw(Component* component) {
auto document = component->Render();
size_t dimx;
size_t dimy;
int dimx;
int dimy;
switch (dimension_) {
case Dimension::Fixed:
dimx = dimx_;

View File

@ -0,0 +1,45 @@
#include "ftxui/dom/elements.hpp"
namespace ftxui {
const wchar_t charset[] = L" ▗▐▖▄▟▌▙█";
class Graph : public Node {
public:
Graph(GraphFunction& graph_function) : graph_function_(graph_function) {}
~Graph() override {}
void ComputeRequirement() override {
requirement_.flex.x = 1;
requirement_.flex.y = 1;
requirement_.min.x = 1;
requirement_.min.y = 1;
}
void Render(Screen& screen) override {
int width = (box_.x_max - box_.x_min + 1) * 2;
int height = (box_.y_max - box_.y_min + 1) * 2;
auto data = graph_function_(width, height);
int i = 0;
for (int x = box_.x_min; x <= box_.x_max; ++x) {
int height_1 = 2 * box_.y_max - data[i++];
int height_2 = 2 * box_.y_max - data[i++];
for (int y = box_.y_min; y <= box_.y_max; ++y) {
int yy = 2 * y;
int i_1 = yy < height_1 ? 0 : yy == height_1 ? 3 : 6;
int i_2 = yy < height_2 ? 0 : yy == height_2 ? 1 : 2;
wchar_t pix = charset[i_1 + i_2];
screen.at(x, y) = pix;
}
}
}
private:
GraphFunction& graph_function_;
};
std::unique_ptr<Node> graph(GraphFunction& graph_function) {
return std::make_unique<Graph>(graph_function);
}
}; // namespace ftxui

View File

@ -12,7 +12,7 @@ class HFlow : public Node {
requirement_.min.x = 0;
requirement_.min.y = 0;
requirement_.flex.x = 1;
requirement_.flex.y = 0;
requirement_.flex.y = 1;
for(auto& child : children)
child->ComputeRequirement();
}

View File

@ -19,6 +19,13 @@ Decorator operator|(Decorator a, Decorator b) {
return compose(a, b);
}
Elements operator|(Elements es, Decorator d) {
Elements output;
for (auto& it : es)
output.push_back(std::move(it) | d);
return output;
}
Element operator|(Element e, Decorator d) {
return d(std::move(e));
}

View File

@ -1,5 +1,5 @@
#include "ftxui/dom/node.hpp"
#include "ftxui/screen/screen.hpp"
#include "ftxui/dom/node.hpp"
#include "ftxui/screen/string.hpp"
#include "ftxui/screen/terminal.hpp"
@ -36,8 +36,34 @@ Pixel dev_null_pixel;
} // namespace
Screen::Screen(size_t dimx, size_t dimy)
: stencil({0, int(dimx) - 1, 0, int(dimy) - 1}),
Dimension Dimension::Fixed(int v) {
return Dimension{v, v};
}
Dimension Dimension::Fit(std::unique_ptr<Node>& e) {
e->ComputeRequirement();
Terminal::Dimensions size = Terminal::Size();
return Dimension{std::min(e->requirement().min.x, size.dimx),
std::min(e->requirement().min.y, size.dimy)};
}
Dimension Dimension::Full() {
Terminal::Dimensions size = Terminal::Size();
return Dimension{size.dimx, size.dimy};
}
// static
Screen Screen::Create(Dimension width, Dimension height) {
return Screen(width.dimx, height.dimy);
}
// static
Screen Screen::Create(Dimension dimension) {
return Screen(dimension.dimx, dimension.dimy);
}
Screen::Screen(int dimx, int dimy)
: stencil({0, dimx - 1, 0, dimy - 1}),
dimx_(dimx),
dimy_(dimy),
pixels_(dimy, std::vector<Pixel>(dimx)) {}
@ -72,10 +98,10 @@ std::string Screen::ToString() {
Pixel previous_pixel;
for (size_t y = 0; y < dimy_; ++y) {
for (int y = 0; y < dimy_; ++y) {
if (y != 0)
ss << '\n';
for (size_t x = 0; x < dimx_; ++x) {
for (int x = 0; x < dimx_; ++x) {
UpdatePixelStyle(ss, previous_pixel, pixels_[y][x]);
ss << pixels_[y][x].character;
}
@ -88,42 +114,18 @@ std::string Screen::ToString() {
return to_string(ss.str());
}
wchar_t& Screen::at(size_t x, size_t y) {
wchar_t& Screen::at(int x, int y) {
return PixelAt(x,y).character;
}
Pixel& Screen::PixelAt(size_t x, size_t y) {
Pixel& Screen::PixelAt(int x, int y) {
return In(stencil, x, y) ? pixels_[y][x] : dev_null_pixel;
}
// static
Screen Screen::TerminalFullscreen() {
Terminal::Dimensions size = Terminal::Size();
return Screen(size.dimx, size.dimy);
}
// static
Screen Screen::TerminalOutput(std::unique_ptr<Node>& element) {
element->ComputeRequirement();
Terminal::Dimensions size = Terminal::Size();
return Screen(size.dimx, element->requirement().min.y);
}
// static
Screen Screen::FitDocument(std::unique_ptr<Node>& element) {
element->ComputeRequirement();
Terminal::Dimensions size = Terminal::Size();
return
Screen(
std::min(size.dimx, element->requirement().min.x),
std::min(size.dimy, element->requirement().min.y)
);
}
std::string Screen::ResetPosition() {
std::stringstream ss;
ss << MOVE_LEFT << CLEAR_LINE;
for (size_t y = 1; y < dimy_; ++y) {
for (int y = 1; y < dimy_; ++y) {
ss << MOVE_UP << CLEAR_LINE;
}
return ss.str();
@ -137,8 +139,8 @@ void Screen::Clear() {
void Screen::ApplyShader() {
// Merge box characters togethers.
for(size_t y = 1; y<dimy_; ++y) {
for(size_t x = 1; x<dimx_; ++x) {
for(int y = 1; y<dimy_; ++y) {
for(int x = 1; x<dimx_; ++x) {
wchar_t& left = at(x - 1, y);
wchar_t& top = at(x, y - 1);
wchar_t& cur = at(x, y);