26class Text :
public Node {
28 explicit Text(std::string_view text) : glyphs_(Utf8ToGlyphs(text)) {
30 int current_width = 0;
32 lines_offsets_.push_back(0);
34 for (
size_t i = 0; i < glyphs_.size(); ++i) {
35 if (glyphs_[i] ==
"\n") {
36 max_width = std::max(max_width, current_width);
39 lines_offsets_.push_back((
int)i + 1);
44 max_width = std::max(max_width, current_width);
45 lines_offsets_.push_back((
int)glyphs_.size() + 1);
47 requirement_.min_x = max_width;
48 requirement_.min_y = lines_count;
51 void ComputeRequirement()
override {
55 selection_rows_.clear();
58 void Select(Selection& selection)
override {
59 const Box selection_box = Box::Intersection(selection.GetBox(), box_);
60 if (selection_box.IsEmpty()) {
66 const size_t lines_count = lines_offsets_.size() - 1;
67 const size_t first = selection_box.y_min - box_.y_min;
69 std::min<size_t>(selection_box.y_max - box_.y_min + 1, lines_count);
73 selection_first_line_ = first;
74 selection_rows_.assign(last - first, {-1, -1});
76 for (
size_t i = first; i < last; ++i) {
77 const int y = box_.y_min + (int)i;
78 const Box row_box{box_.x_min, box_.x_max,
y,
y};
79 const Selection row_sel = selection.SaturateHorizontal(row_box);
80 const int sel_start = row_sel.GetBox().x_min;
81 const int sel_end = row_sel.GetBox().x_max;
82 selection_rows_[i - first] = {sel_start, sel_end};
86 const int start = lines_offsets_[i];
87 const int end = lines_offsets_[i + 1] - 1;
88 for (
int j = start; j < end; ++j) {
89 if (sel_start <= x && x <= sel_end) {
94 selection.AddPart(std::move(part),
y, sel_start, sel_end);
98 void Render(Screen& screen)
override {
99 const auto visible_box = Box::Intersection(screen.stencil, box_);
100 if (visible_box.IsEmpty()) {
104 int y = visible_box.y_min;
106 const size_t first_line = visible_box.y_min - box_.y_min;
107 const size_t last_line = std::min<size_t>(
108 visible_box.y_max - box_.y_min + 1, lines_offsets_.size() - 1);
110 for (
size_t line = first_line; line < last_line; ++line, ++
y) {
113 for (
auto glyph = glyphs_.begin() + lines_offsets_[line];
114 glyph != glyphs_.end() && *glyph !=
"\n"; ++glyph, ++x) {
115 if (x > box_.x_max) {
119 auto& cell = screen.CellAt(x,
y);
120 cell.character = *glyph;
122 const size_t sel_index = line - selection_first_line_;
123 if (sel_index < selection_rows_.size()) {
124 const auto& [sel_start, sel_end] = selection_rows_[sel_index];
125 if (sel_start != -1 && x >= sel_start && x <= sel_end) {
126 screen.GetSelectionStyle()(cell);
134 std::vector<std::string> glyphs_;
135 std::vector<int> lines_offsets_;
138 size_t selection_first_line_ = 0;
139 std::vector<std::pair<int, int>> selection_rows_;
142class VText :
public Node {
144 explicit VText(std::string_view text) : glyphs_(Utf8ToGlyphs(text)) {
145 for (
const auto& g : glyphs_) {
153 void ComputeRequirement()
override {
155 int current_height = 0;
158 for (
const auto& cell : glyphs_) {
160 max_height = std::max(max_height, current_height);
167 max_height = std::max(max_height, current_height);
169 requirement_.min_x = width_ * columns;
170 requirement_.min_y = max_height;
173 void Render(Screen& screen)
override {
176 if (x + width_ - 1 > box_.x_max) {
179 for (
const auto& it : glyphs_) {
183 if (x + width_ - 1 > box_.x_max) {
188 if (
y > box_.y_max) {
191 screen.CellAt(x,
y).character = it;
197 std::vector<std::string> glyphs_;
219 return std::make_shared<Text>(std::string(text));
268 return std::make_shared<VText>(text);
Element text(std::string_view text)
Display a piece of UTF8 encoded unicode text.
Element vtext(std::string_view text)
Display a piece of unicode text vertically.
The FTXUI ftxui:: namespace.
std::shared_ptr< Node > Element
std::string to_string(std::wstring_view s)
Convert a std::wstring into a UTF8 std::string.
void Render(Screen &screen, Node *node, Selection &selection)