Add support for nxxm.

[nxxm](https://nxxm.github.io)
This commit is contained in:
ArthurSonzogni
2019-02-02 01:59:48 +01:00
parent 2eddd0fa17
commit ef0de8d873
72 changed files with 309 additions and 165 deletions

25
src/ftxui/dom/blink.cpp Normal file
View File

@@ -0,0 +1,25 @@
#include "ftxui/dom/node_decorator.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
class Blink : public NodeDecorator {
public:
Blink(Elements children) : NodeDecorator(std::move(children)) {}
~Blink() override {}
void Render(Screen& screen) override {
Node::Render(screen);
for (int y = box_.y_min; y <= box_.y_max; ++y) {
for (int x = box_.x_min; x <= box_.x_max; ++x) {
screen.PixelAt(x, y).blink = true;
}
}
}
};
std::unique_ptr<Node> blink(Element child) {
return std::make_unique<Blink>(unpack(std::move(child)));
}
}; // namespace ftxui

25
src/ftxui/dom/bold.cpp Normal file
View File

@@ -0,0 +1,25 @@
#include "ftxui/dom/node_decorator.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
class Bold : public NodeDecorator {
public:
Bold(Elements children) : NodeDecorator(std::move(children)) {}
~Bold() override {}
void Render(Screen& screen) override {
for (int y = box_.y_min; y <= box_.y_max; ++y) {
for (int x = box_.x_min; x <= box_.x_max; ++x) {
screen.PixelAt(x,y).bold = true;
}
}
Node::Render(screen);
}
};
std::unique_ptr<Node> bold(Element child) {
return std::make_unique<Bold>(unpack(std::move(child)));
}
}; // namespace ftxui

118
src/ftxui/dom/border.cpp Normal file
View File

@@ -0,0 +1,118 @@
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
using namespace ftxui;
static wchar_t simple_border_charset[] = L"┌┐└┘─│┬┴┤├";
class Border : public Node {
public:
Border(Elements children)
: Node(std::move(children)),
charset(std::begin(simple_border_charset),
std::end(simple_border_charset)) {}
Border(Elements children, Pixel pixel)
: Node(std::move(children)), charset_pixel(10, pixel) {}
~Border() override {}
std::vector<Pixel> charset_pixel;
std::vector<wchar_t> charset;
void ComputeRequirement() override {
Node::ComputeRequirement();
requirement_ = children[0]->requirement();
requirement_.min.x += 2;
requirement_.min.y += 2;
if (children.size() == 2) {
requirement_.min.x =
std::max(requirement_.min.x, children[1]->requirement().min.x + 2);
}
requirement_.selected_box.x_min++;
requirement_.selected_box.x_max++;
requirement_.selected_box.y_min++;
requirement_.selected_box.y_max++;
}
void SetBox(Box box) override {
Node::SetBox(box);
if (children.size() == 2) {
Box title_box;
title_box.x_min = box.x_min + 1;
title_box.x_max = box.x_max - 1;
title_box.y_min = box.y_min;
title_box.y_max = box.y_min;
children[1]->SetBox(title_box);
}
box.x_min++;
box.x_max--;
box.y_min++;
box.y_max--;
children[0]->SetBox(box);
}
void Render(Screen& screen) override {
// Draw content.
children[0]->Render(screen);
// Draw the border.
if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max)
return;
if (!charset.empty())
RenderPixel(screen);
else
RenderChar(screen);
}
void RenderPixel(Screen& screen) {
screen.at(box_.x_min, box_.y_min) = charset[0];
screen.at(box_.x_max, box_.y_min) = charset[1];
screen.at(box_.x_min, box_.y_max) = charset[2];
screen.at(box_.x_max, box_.y_max) = charset[3];
for(float x = box_.x_min + 1; x<box_.x_max; ++x) {
screen.at(x, box_.y_min) = charset[4];
screen.at(x, box_.y_max) = charset[4];
}
for(float y = box_.y_min + 1; y<box_.y_max; ++y) {
screen.at(box_.x_min, y) = charset[5];
screen.at(box_.x_max,y) = charset[5];
}
// Draw title.
if (children.size() == 2)
children[1]->Render(screen);
}
void RenderChar(Screen& screen) {
screen.PixelAt(box_.x_min, box_.y_min) = charset_pixel[0];
screen.PixelAt(box_.x_max, box_.y_min) = charset_pixel[1];
screen.PixelAt(box_.x_min, box_.y_max) = charset_pixel[2];
screen.PixelAt(box_.x_max, box_.y_max) = charset_pixel[3];
for(float x = box_.x_min + 1; x<box_.x_max; ++x) {
screen.PixelAt(x, box_.y_min) = charset_pixel[4];
screen.PixelAt(x, box_.y_max) = charset_pixel[4];
}
for(float y = box_.y_min + 1; y<box_.y_max; ++y) {
screen.PixelAt(box_.x_min, y) = charset_pixel[5];
screen.PixelAt(box_.x_max,y) = charset_pixel[5];
}
}
};
std::unique_ptr<Node> border(Element child) {
return std::make_unique<Border>(unpack(std::move(child)));
}
std::unique_ptr<Node> window(Element title, Element content) {
return std::make_unique<Border>(unpack(std::move(content), std::move(title)));
}
Decorator borderWith(Pixel pixel) {
return [pixel](Element child) {
return std::make_unique<Border>(unpack(std::move(child)), pixel);
};
}
}; // namespace ftxui

61
src/ftxui/dom/color.cpp Normal file
View File

@@ -0,0 +1,61 @@
#include "ftxui/dom/node_decorator.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
class BgColor : public NodeDecorator {
public:
BgColor(Elements children, Color color)
: NodeDecorator(std::move(children)), color_(color) {}
void Render(Screen& screen) override {
for (int y = box_.y_min; y <= box_.y_max; ++y) {
for (int x = box_.x_min; x <= box_.x_max; ++x) {
screen.PixelAt(x, y).background_color = color_;
}
}
NodeDecorator::Render(screen);
}
Color color_;
};
class FgColor : public NodeDecorator {
public:
FgColor(Elements children, Color color)
: NodeDecorator(std::move(children)), color_(color) {}
~FgColor() override {}
void Render(Screen& screen) override {
for (int y = box_.y_min; y <= box_.y_max; ++y) {
for (int x = box_.x_min; x <= box_.x_max; ++x) {
screen.PixelAt(x, y).foreground_color = color_;
}
}
NodeDecorator::Render(screen);
}
Color color_;
};
std::unique_ptr<Node> color(Color c, Element child) {
return std::make_unique<FgColor>(unpack(std::move(child)), c);
}
std::unique_ptr<Node> bgcolor(Color c, Element child) {
return std::make_unique<BgColor>(unpack(std::move(child)), c);
}
Decorator color(Color c) {
return [c](Element child) {
return color(c, std::move(child));
};
}
Decorator bgcolor(Color c) {
return [c](Element child) {
return bgcolor(c, std::move(child));
};
}
}; // namespace ftxui

View File

@@ -0,0 +1,22 @@
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
std::unique_ptr<Node> hcenter(Element child) {
return hbox(filler(), std::move(child), filler());
}
std::unique_ptr<Node> vcenter(Element child) {
return vbox(filler(), std::move(child), filler());
}
std::unique_ptr<Node> center(Element child) {
return hcenter(vcenter(std::move(child)));
}
std::unique_ptr<Node> align_right(Element child) {
return hbox(filler(), std::move(child));
}
} // namespace ftxui

40
src/ftxui/dom/dbox.cpp Normal file
View File

@@ -0,0 +1,40 @@
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
class DBox : public Node {
public:
DBox(Elements children) : Node(std::move(children)) {}
~DBox() {}
void ComputeRequirement() override {
requirement_.min.x = 0;
requirement_.min.y = 0;
requirement_.flex.x = 1;
requirement_.flex.y = 0;
for (auto& child : children) {
child->ComputeRequirement();
requirement_.min.x = std::max(requirement_.min.x, child->requirement().min.x);
requirement_.min.y = std::max(requirement_.min.y, child->requirement().min.y);
if (requirement_.selection < child->requirement().selection) {
requirement_.selection = child->requirement().selection;
requirement_.selected_box = child->requirement().selected_box;
}
}
}
void SetBox(Box box) override {
Node::SetBox(box);
for (auto& child : children)
child->SetBox(box);
}
};
std::unique_ptr<Node> dbox(Elements children) {
return std::make_unique<DBox>(std::move(children));
}
}; // namespace ftxui

27
src/ftxui/dom/dim.cpp Normal file
View File

@@ -0,0 +1,27 @@
#include "ftxui/dom/node_decorator.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
using ftxui::Screen;
class Dim : public NodeDecorator {
public:
Dim(Elements children) : NodeDecorator(std::move(children)) {}
~Dim() override {}
void Render(Screen& screen) override {
Node::Render(screen);
for (int y = box_.y_min; y <= box_.y_max; ++y) {
for (int x = box_.x_min; x <= box_.x_max; ++x) {
screen.PixelAt(x,y).dim = true;
}
}
}
};
std::unique_ptr<Node> dim(Element child) {
return std::make_unique<Dim>(unpack(std::move(child)));
}
}; // namespace ftxui

58
src/ftxui/dom/flex.cpp Normal file
View File

@@ -0,0 +1,58 @@
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
class Flex : public Node {
public:
Flex() {}
Flex(Element child) : Node(unpack(std::move(child))) {}
~Flex() override {}
void ComputeRequirement() override {
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);
}
};
class NotFlex : public Flex {
public:
NotFlex() {}
NotFlex(Element child) : Flex(std::move(child)) {}
~NotFlex() override {}
void ComputeRequirement() override {
requirement_.min.x = 0;
requirement_.min.y = 0;
if (!children.empty()) {
children[0]->ComputeRequirement();
requirement_ = children[0]->requirement();
}
requirement_.flex.x = 0;
requirement_.flex.y = 0;
}
};
std::unique_ptr<Node> filler() {
return std::make_unique<Flex>();
}
std::unique_ptr<Node> flex(Element child) {
return std::make_unique<Flex>(std::move(child));
}
std::unique_ptr<Node> notflex(Element child) {
return std::make_unique<NotFlex>(std::move(child));
}
}; // namespace ftxui

121
src/ftxui/dom/frame.cpp Normal file
View File

@@ -0,0 +1,121 @@
#include "ftxui/dom/elements.hpp"
#include "ftxui/dom/node.hpp"
#include "ftxui/util/autoreset.hpp"
namespace ftxui {
using namespace ftxui;
// -----------------------------------------------------------------------------
class Select : public Node {
public:
Select(std::vector<std::unique_ptr<Node>> children)
: Node(std::move(children)) {}
void ComputeRequirement() override {
Node::ComputeRequirement();
requirement_ = children[0]->requirement();
auto& selected_box = requirement_.selected_box;
selected_box.x_min = 0;
selected_box.y_min = 0;
selected_box.x_max = requirement_.min.x;
selected_box.y_max = requirement_.min.y;
requirement_.selection = Requirement::SELECTED;
};
void SetBox(Box box) override {
box_ = box;
children[0]->SetBox(box);
}
};
std::unique_ptr<Node> select(Element child) {
return std::make_unique<Select>(unpack(std::move(child)));
}
// -----------------------------------------------------------------------------
class Focus : public Select {
public:
Focus(std::vector<std::unique_ptr<Node>> children)
: Select(std::move(children)) {}
void ComputeRequirement() override {
Select::ComputeRequirement();
requirement_.selection = Requirement::FOCUSED;
};
};
std::unique_ptr<Node> focus(Element child) {
return std::make_unique<Focus>(unpack(std::move(child)));
}
// -----------------------------------------------------------------------------
class Frame : public Node {
public:
Frame(std::vector<std::unique_ptr<Node>> children)
: Node(std::move(children)) {}
void ComputeRequirement() override {
Node::ComputeRequirement();
requirement_ = children[0]->requirement();
}
void SetBox(Box box) override {
Node::SetBox(box);
int external_dimx = box.x_max - box.x_min;
int external_dimy = box.y_max - box.y_min;
int internal_dimx = std::max(requirement_.min.x, external_dimx);
int internal_dimy = std::max(requirement_.min.y, external_dimy);
auto& selected_box = requirement_.selected_box;
int focused_dimx = selected_box.x_max - selected_box.x_min;
int focused_dimy = selected_box.y_max - selected_box.y_min;
int dx = selected_box.x_min - external_dimx / 2 + focused_dimx / 2;
int dy = selected_box.y_min - external_dimy / 2 + focused_dimy / 2;
dx = std::max(0, std::min(internal_dimx - external_dimx - 1, dx));
dy = std::max(0, std::min(internal_dimy - external_dimy - 1, dy));
Box children_box = box;
children_box.x_min = box.x_min - dx;
children_box.y_min = box.y_min - dy;
children_box.x_max = box.x_min + internal_dimx - dx;
children_box.y_max = box.y_min + internal_dimy - dy;
children[0]->SetBox(children_box);
// int dx = box.x_max - box.x_min;
// int dy = box.y_max - box.y_min;
// int cdx = std::min(children[0].requirement().min.x
// Box children_box;
// children_box.x_min =
// if (box.x_max - box.x_min >= children[0].requirement().min.x && //
// box.y_max - box.y_min >= children[0].requirement().min.y) {
// children_[0]->SetBox(box);
// dx = 0;
// dy = 0;
// return;
//}
// Box children_box;
// children_box.x_min = box.x_min;
// children_box.y_min = box.x_min;
}
void Render(Screen& screen) override {
AutoReset<Box> stencil(&screen.stencil,
Box::Intersection(box_, screen.stencil));
children[0]->Render(screen);
}
};
std::unique_ptr<Node> frame(Element child) {
return std::make_unique<Frame>(unpack(std::move(child)));
}
}; // namespace ftxui

39
src/ftxui/dom/gauge.cpp Normal file
View File

@@ -0,0 +1,39 @@
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
using namespace ftxui;
static wchar_t charset[] = L" ▏▎▍▌▋▊▉█";
class Gauge : public Node {
public:
Gauge(float progress) : progress_(progress) {}
~Gauge() override {}
void ComputeRequirement() override {
requirement_.flex.x = 1;
requirement_.min.y = 1;
}
void Render(Screen& screen) override {
float y = box_.y_min;
float limit = box_.x_min + progress_ * (box_.x_max - box_.x_min + 1);
int limit_int = limit;
int x = box_.x_min;
while (x < limit_int)
screen.at(x++, y) = charset[9];
screen.at(x++, y) = charset[int(9*(limit-limit_int))];
while (x <= box_.x_max)
screen.at(x++, y) = charset[0];
}
private:
float progress_;
};
std::unique_ptr<Node> gauge(float progress) {
return std::make_unique<Gauge>(progress);
}
}; // namespace ftxui

45
src/ftxui/dom/graph.cpp Normal file
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

72
src/ftxui/dom/hbox.cpp Normal file
View File

@@ -0,0 +1,72 @@
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
class HBox : public Node {
public:
HBox(Elements children) : Node(std::move(children)) {}
~HBox() {}
void ComputeRequirement() override {
requirement_.min.x = 0;
requirement_.min.y = 0;
requirement_.flex.x = 1;
requirement_.flex.y = 0;
for (auto& child : children) {
child->ComputeRequirement();
if (requirement_.selection < child->requirement().selection) {
requirement_.selection = child->requirement().selection;
requirement_.selected_box = child->requirement().selected_box;
requirement_.selected_box.x_min += requirement_.min.x;
requirement_.selected_box.x_max += requirement_.min.x;
}
requirement_.min.x += child->requirement().min.x;
requirement_.min.y =
std::max(requirement_.min.y, child->requirement().min.y);
}
}
void SetBox(Box box) override {
Node::SetBox(box);
int flex_sum = 0;
for (auto& child : children)
flex_sum += child->requirement().flex.x;
int space = box.x_max - box.x_min + 1;
int extra_space = space - requirement_.min.x;
int remaining_flex = flex_sum;
int remaining_extra_space = extra_space;
int x = box.x_min;
for (auto& child : children) {
if (x > box.x_max)
break;
Box child_box = box;
child_box.x_min = x;
child_box.x_max = x + child->requirement().min.x - 1;
if (child->requirement().flex.x && remaining_extra_space > 0) {
int added_space = remaining_extra_space * child->requirement().flex.x /
remaining_flex;
remaining_extra_space -= added_space;
remaining_flex -= child->requirement().flex.x;
child_box.x_max += added_space;
}
child_box.x_max = std::min(child_box.x_max, box.x_max);
child->SetBox(child_box);
x = child_box.x_max + 1;
}
}
};
std::unique_ptr<Node> hbox(Elements children) {
return std::make_unique<HBox>(std::move(children));
}
}; // namespace ftxui

59
src/ftxui/dom/hflow.cpp Normal file
View File

@@ -0,0 +1,59 @@
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
class HFlow : public Node {
public:
HFlow(Elements children) : Node(std::move(children)) {}
~HFlow() {}
void ComputeRequirement() override {
requirement_.min.x = 0;
requirement_.min.y = 0;
requirement_.flex.x = 1;
requirement_.flex.y = 1;
for(auto& child : children)
child->ComputeRequirement();
}
void SetBox(Box box) override {
Node::SetBox(box);
// The position of the first component.
int x = box.x_min;
int y = box.y_min;
int y_next = y; // The position of next row of elements.
for (auto& child : children) {
Requirement requirement = child->requirement();
// Does it fit the end of the row?
if (x + requirement.min.x > box.x_max) {
// No? Use the next row.
x = box.x_min;
y = y_next;
}
// Does the current row big enough to contain the element?
if (y + requirement.min.y > box.y_max + 1)
break; // No? Ignore the element.
Box children_box;
children_box.x_min = x;
children_box.x_max = x + requirement.min.x - 1;
children_box.y_min = y;
children_box.y_max = y + requirement.min.y - 1;
child->SetBox(children_box);
x = x + requirement.min.x;
y_next = std::max(y_next, y + requirement.min.y);
}
}
};
std::unique_ptr<Node> hflow(Elements children) {
return std::make_unique<HFlow>(std::move(children));
}
}; // namespace ftxui

View File

@@ -0,0 +1,27 @@
#include "ftxui/dom/node_decorator.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
using ftxui::Screen;
class Inverted : public NodeDecorator {
public:
Inverted(Elements children) : NodeDecorator(std::move(children)) {}
~Inverted() override {}
void Render(Screen& screen) override {
Node::Render(screen);
for (int y = box_.y_min; y <= box_.y_max; ++y) {
for (int x = box_.x_min; x <= box_.x_max; ++x) {
screen.PixelAt(x,y).inverted = true;
}
}
}
};
std::unique_ptr<Node> inverted(Element child) {
return std::make_unique<Inverted>(unpack(std::move(child)));
}
}; // namespace ftxui

47
src/ftxui/dom/node.cpp Normal file
View File

@@ -0,0 +1,47 @@
#include "ftxui/dom/node.hpp"
namespace ftxui {
using ftxui::Screen;
Node::Node() {}
Node::Node(std::vector<std::unique_ptr<Node>> children)
: children(std::move(children)) {}
Node::~Node() {}
void Node::ComputeRequirement() {
for(auto& child : children)
child->ComputeRequirement();
}
void Node::SetBox(Box box) {
box_ = box;
}
void Node::Render(Screen& screen) {
for(auto& child : children)
child->Render(screen);
}
void Render(Screen& screen, Node* node) {
// Step 1: Find what dimension this elements wants to be.
node->ComputeRequirement();
Box box;
box.x_min = 0;
box.y_min = 0;
box.x_max = screen.dimx() - 1;
box.y_max = screen.dimy() - 1;
// Step 2: Assign a dimension to the element.
node->SetBox(box);
screen.stencil = box;
// Step 3: Draw the element.
node->Render(screen);
// Step 4: Apply shaders
screen.ApplyShader();
}
}; // namespace ftxui

View File

@@ -0,0 +1,15 @@
#include "ftxui/dom/node_decorator.hpp"
namespace ftxui {
void NodeDecorator::ComputeRequirement() {
Node::ComputeRequirement();
requirement_ = children[0]->requirement();
}
void NodeDecorator::SetBox(Box box) {
Node::SetBox(box);
children[0]->SetBox(box);
}
}; // namespace ftxui

View File

@@ -0,0 +1,20 @@
#ifndef FTXUI_DOM_NODE_DECORATOR_H_
#define FTXUI_DOM_NODE_DECORATOR_H_
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
// Helper class.
class NodeDecorator : public Node {
public:
NodeDecorator(Elements children) : Node(std::move(children)) {}
~NodeDecorator() override {}
void ComputeRequirement() override;
void SetBox(Box box) override;
};
}; // namespace ftxui
#endif /* end of include guard: FTXUI_DOM_NODE_DECORATOR_H_ */

View File

@@ -0,0 +1,16 @@
#include <sstream>
#include "ftxui/dom/elements.hpp"
namespace ftxui {
Elements paragraph(std::wstring the_text) {
Elements output;
std::wstringstream ss(the_text);
std::wstring word;
while (std::getline(ss, word, L' ')) {
output.push_back(text(word + L' '));
}
return output;
}
} // namespace ftxui

View File

@@ -0,0 +1,56 @@
#include "ftxui/dom/node.hpp"
namespace ftxui {
using ftxui::Screen;
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_.x_max == box_.x_min);
bool is_line = (box_.y_min == box_.y_max);
wchar_t c = U'+';
if (is_line && !is_column)
c = U'';
else
c = U'';
Pixel p;
p.character = c;
RenderWithPixel(screen, p);
}
void RenderWithPixel(Screen& screen, Pixel pixel) {
for (int y = box_.y_min; y <= box_.y_max; ++y) {
for (int x = box_.x_min; x <= box_.x_max; ++x) {
screen.PixelAt(x, y) = pixel;
}
}
}
};
class SeparatorWithPixel : public Separator {
public:
SeparatorWithPixel(Pixel p) : p(p) {}
~SeparatorWithPixel() override {}
void Render(Screen& screen) override { RenderWithPixel(screen, p); }
Pixel p;
};
std::unique_ptr<Node> separator() {
return std::make_unique<Separator>();
}
std::unique_ptr<Node> separator(Pixel pixel) {
return std::make_unique<SeparatorWithPixel>(pixel);
}
}; // namespace ftxui

77
src/ftxui/dom/size.cpp Normal file
View File

@@ -0,0 +1,77 @@
#include "ftxui/dom/elements.hpp"
#include "ftxui/dom/node.hpp"
namespace ftxui {
class Size : public Node {
public:
Size(Element child, Direction direction, Constraint constraint, size_t value)
: Node(unpack(std::move(child))),
direction_(direction),
constraint_(constraint),
value_(value) {}
~Size() override {}
void ComputeRequirement() override {
Node::ComputeRequirement();
requirement_ = children[0]->requirement();
auto& value = direction_ == WIDTH ? requirement_.min.x : requirement_.min.y;
switch (constraint_) {
case LESS_THAN:
value = std::min(value, value_);
break;
case EQUAL:
value = value_;
break;
case GREATER_THAN:
value = std::max(value, value_);
break;
}
if (direction_ == WIDTH)
requirement_.flex.x = 0;
else
requirement_.flex.y = 0;
}
void SetBox(Box box) override {
Node::SetBox(box);
if (direction_ == WIDTH) {
switch(constraint_) {
case LESS_THAN:
case EQUAL:
box.x_max = std::min(box.x_min + value_ + 1, box.x_max);
break;
case GREATER_THAN:
break;
}
} else {
switch(constraint_) {
case LESS_THAN:
case EQUAL:
box.y_max = std::min(box.y_min + value_ + 1, box.y_max);
break;
case GREATER_THAN:
break;
}
}
children[0]->SetBox(box);
}
private:
Direction direction_;
Constraint constraint_;
int value_;
};
Decorator size(Direction direction, Constraint constraint, int value) {
return [=](Element e) {
return std::make_unique<Size>(std::move(e), direction, constraint, value);
};
}
}; // namespace ftxui

279
src/ftxui/dom/spinner.cpp Normal file
View File

@@ -0,0 +1,279 @@
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
using namespace ftxui;
static const std::vector<std::vector<std::vector<std::wstring>>> elements = {
{
{L"Replaced by the gauge"},
},
{
{L". "},
{L".. "},
{L"..."},
},
{
{L"|"},
{L"/"},
{L"-"},
{L"\\"},
},
{
{L"+"},
{L"x"},
},
{
{L"| "},
{L"|| "},
{L"|||"},
},
{
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
},
{
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
},
{
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
},
{
{L""},
{L""},
{L""},
{L""},
},
{
{L""},
{L""},
{L""},
{L""},
},
{
{L""},
{L""},
{L""},
{L""},
},
{
{L""},
{L""},
{L""},
{L""},
},
{
{L""},
{L""},
{L""},
{L""},
},
{
{L""},
{L""},
{L""},
},
{
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
},
{
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
{L""},
},
{
{L"(*----------)"},
{L"(-*---------)"},
{L"(--*--------)"},
{L"(---*-------)"},
{L"(----*------)"},
{L"(-----*-----)"},
{L"(------*----)"},
{L"(-------*---)"},
{L"(--------*--)"},
{L"(---------*-)"},
{L"(----------*)"},
{L"(---------*-)"},
{L"(--------*--)"},
{L"(-------*---)"},
{L"(------*----)"},
{L"(-----*-----)"},
{L"(----*------)"},
{L"(---*-------)"},
{L"(--*--------)"},
{L"(-*---------)"},
},
{
{L"[ ]"},
{L"[= ]"},
{L"[== ]"},
{L"[=== ]"},
{L"[==== ]"},
{L"[===== ]"},
{L"[======]"},
{L"[===== ]"},
{L"[==== ]"},
{L"[=== ]"},
{L"[== ]"},
{L"[= ]"},
},
{
{L"[ ]"},
{L"[= ]"},
{L"[== ]"},
{L"[=== ]"},
{L"[==== ]"},
{L"[===== ]"},
{L"[======]"},
{L"[ =====]"},
{L"[ ====]"},
{L"[ ===]"},
{L"[ ==]"},
{L"[ =]"},
},
{
{L"[== ]"},
{L"[== ]"},
{L"[== ]"},
{L"[== ]"},
{L"[== ]"},
{L" [== ]"},
{L"[ == ]"},
{L"[ == ]"},
{L"[ ==]"},
{L"[ ==]"},
{L"[ ==]"},
{L"[ ==]"},
{L"[ ==]"},
{L"[ ==] "},
{L"[ == ]"},
{L"[ == ]"},
},
{
{
L" ─╮",
L"",
L" ",
},
{
L"",
L"",
L"",
},
{
L" ",
L"",
L" ─╯",
},
{
L" ",
L" ",
L"╰─╯",
},
{
L" ",
L"",
L"╰─ ",
},
{
L"",
L"",
L"",
},
{
L"╭─ ",
L"",
L" ",
},
{
L"╭─╮",
L" ",
L" ",
}
},
{
{
L" /\\O ",
L" /\\/ ",
L" /\\ ",
L" / \\ ",
L"LOL LOL",
},
{
L" _O ",
L" //|_ ",
L" | ",
L" /| ",
L" LLOL ",
},
{
L" O ",
L" /_ ",
L" |\\ ",
L" / | ",
L" LOLLOL ",
}
}
};
std::unique_ptr<Node> spinner(int c, size_t index) {
if (c == 0) {
index %= 40;
if (index > 20)
index = 40-index;
return gauge(index * 0.05);
}
c %= elements.size();
index %= elements[c].size();
std::vector<Element> lines;
for(const auto& it : elements[c][index])
lines.push_back(text(it));
return vbox(std::move(lines));
}
}; // namespace ftxui

37
src/ftxui/dom/text.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include "ftxui/dom/node.hpp"
namespace ftxui {
using ftxui::Screen;
class Text : public Node {
public:
Text(std::wstring text) : Node(), text_(text) {}
~Text() {}
void ComputeRequirement() override {
requirement_.min.x = text_.size();
requirement_.min.y = 1;
}
void Render(Screen& screen) override {
int x = box_.x_min;
int y = box_.y_min;
if (y > box_.y_max)
return;
for (wchar_t c : text_) {
if (x > box_.x_max)
return;
screen.at(x++, y) = c;
}
}
private:
std::wstring text_;
};
std::unique_ptr<Node> text(std::wstring text) {
return std::make_unique<Text>(text);
}
}; // namespace ftxui

View File

@@ -0,0 +1,27 @@
#include "ftxui/dom/node_decorator.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
using ftxui::Screen;
class Underlined : public NodeDecorator {
public:
Underlined(Elements children) : NodeDecorator(std::move(children)) {}
~Underlined() override {}
void Render(Screen& screen) override {
Node::Render(screen);
for (int y = box_.y_min; y <= box_.y_max; ++y) {
for (int x = box_.x_min; x <= box_.x_max; ++x) {
screen.PixelAt(x, y).underlined = true;
}
}
}
};
std::unique_ptr<Node> underlined(Element child) {
return std::make_unique<Underlined>(unpack(std::move(child)));
}
}; // namespace ftxui

33
src/ftxui/dom/util.cpp Normal file
View File

@@ -0,0 +1,33 @@
#include "ftxui/dom/elements.hpp"
namespace ftxui {
Element nothing(Element element) {
return element;
}
Decorator compose(Decorator a, Decorator b) {
return [
a = std::move(a),
b = std::move(b)
](Element element) {
return b(a(std::move(element)));
};
}
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));
}
} // namespace ftxui

72
src/ftxui/dom/vbox.cpp Normal file
View File

@@ -0,0 +1,72 @@
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
class VBox : public Node {
public:
VBox(Elements children) : Node(std::move(children)) {}
~VBox() {}
void ComputeRequirement() {
requirement_.min.x = 0;
requirement_.min.y = 0;
requirement_.flex.x = 0;
requirement_.flex.y = 1;
for (auto& child : children) {
child->ComputeRequirement();
if (requirement_.selection < child->requirement().selection) {
requirement_.selection = child->requirement().selection;
requirement_.selected_box = child->requirement().selected_box;
requirement_.selected_box.y_min += requirement_.min.y;
requirement_.selected_box.y_max += requirement_.min.y;
}
requirement_.min.y += child->requirement().min.y;
requirement_.min.x =
std::max(requirement_.min.x, child->requirement().min.x);
}
}
void SetBox(Box box) {
Node::SetBox(box);
int flex_sum = 0;
for (auto& child : children)
flex_sum += child->requirement().flex.y;
int space = box.y_max - box.y_min + 1;
int extra_space = space - requirement_.min.y;
int remaining_flex = flex_sum;
int remaining_extra_space = extra_space;
int y = box.y_min;
for (auto& child : children) {
if (y > box.y_max)
break;
Box child_box = box;
child_box.y_min = y;
child_box.y_max = y + child->requirement().min.y - 1;
if (child->requirement().flex.y && remaining_extra_space > 0) {
int added_space = remaining_extra_space * child->requirement().flex.y /
remaining_flex;
remaining_extra_space -= added_space;
remaining_flex -= child->requirement().flex.y;
child_box.y_max += added_space;
}
child_box.y_max = std::min(child_box.y_max, box.y_max);
child->SetBox(child_box);
y = child_box.y_max + 1;
}
}
};
std::unique_ptr<Node> vbox(Elements children) {
return std::make_unique<VBox>(std::move(children));
}
}; // namespace ftxui