mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-09-18 00:48:09 +08:00
25
src/ftxui/dom/blink.cpp
Normal file
25
src/ftxui/dom/blink.cpp
Normal 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
25
src/ftxui/dom/bold.cpp
Normal 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
118
src/ftxui/dom/border.cpp
Normal 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
61
src/ftxui/dom/color.cpp
Normal 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
|
22
src/ftxui/dom/composite_decorator.cpp
Normal file
22
src/ftxui/dom/composite_decorator.cpp
Normal 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
40
src/ftxui/dom/dbox.cpp
Normal 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
27
src/ftxui/dom/dim.cpp
Normal 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
58
src/ftxui/dom/flex.cpp
Normal 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
121
src/ftxui/dom/frame.cpp
Normal 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
39
src/ftxui/dom/gauge.cpp
Normal 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
45
src/ftxui/dom/graph.cpp
Normal 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
72
src/ftxui/dom/hbox.cpp
Normal 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
59
src/ftxui/dom/hflow.cpp
Normal 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
|
27
src/ftxui/dom/inverted.cpp
Normal file
27
src/ftxui/dom/inverted.cpp
Normal 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
47
src/ftxui/dom/node.cpp
Normal 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
|
15
src/ftxui/dom/node_decorator.cpp
Normal file
15
src/ftxui/dom/node_decorator.cpp
Normal 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
|
20
src/ftxui/dom/node_decorator.hpp
Normal file
20
src/ftxui/dom/node_decorator.hpp
Normal 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_ */
|
16
src/ftxui/dom/paragraph.cpp
Normal file
16
src/ftxui/dom/paragraph.cpp
Normal 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
|
56
src/ftxui/dom/separator.cpp
Normal file
56
src/ftxui/dom/separator.cpp
Normal 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
77
src/ftxui/dom/size.cpp
Normal 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
279
src/ftxui/dom/spinner.cpp
Normal 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
37
src/ftxui/dom/text.cpp
Normal 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
|
27
src/ftxui/dom/underlined.cpp
Normal file
27
src/ftxui/dom/underlined.cpp
Normal 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
33
src/ftxui/dom/util.cpp
Normal 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
72
src/ftxui/dom/vbox.cpp
Normal 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
|
Reference in New Issue
Block a user