FTXUI 6.1.9
C++ functional terminal UI.
Loading...
Searching...
No Matches
src/ftxui/dom/text.cpp
Go to the documentation of this file.
1// Copyright 2020 Arthur Sonzogni. All rights reserved.
2// Use of this source code is governed by the MIT license that can be found in
3// the LICENSE file.
4#include <algorithm> // for min, max
5#include <memory> // for make_shared
6#include <string> // for string, wstring
7#include <string_view> // for string_view
8#include <utility> // for move
9#include <vector> // for vector
10
11#include "ftxui/dom/deprecated.hpp" // for text, vtext
12#include "ftxui/dom/elements.hpp" // for Element, text, vtext
13#include "ftxui/dom/node.hpp" // for Node
14#include "ftxui/dom/requirement.hpp" // for Requirement
15#include "ftxui/dom/selection.hpp" // for Selection
16#include "ftxui/screen/box.hpp" // for Box
17#include "ftxui/screen/screen.hpp" // for Cell, Screen
18#include "ftxui/screen/string.hpp" // for string_width, Utf8ToGlyphs, to_string
19
20namespace ftxui {
21
22namespace {
23using ftxui::Screen;
24
25class Text : public Node {
26 public:
27 explicit Text(std::string text) : glyphs_(Utf8ToGlyphs(text)) {}
28 explicit Text(std::string_view sv) : Text(std::string(sv)) {}
29
30 void ComputeRequirement() override {
31 int max_width = 0;
32 int current_width = 0;
33 int lines_count = 1;
34 has_selection_ = false;
35 selection_rows_.clear();
36 lines_offsets_.clear();
37 lines_offsets_.push_back(0);
38
39 for (size_t i = 0; i < glyphs_.size(); ++i) {
40 if (glyphs_[i] == "\n") {
41 max_width = std::max(max_width, current_width);
42 current_width = 0;
43 lines_count++;
44 lines_offsets_.push_back((int)i + 1);
45 } else {
46 current_width++;
47 }
48 }
49 max_width = std::max(max_width, current_width);
50 lines_offsets_.push_back((int)glyphs_.size() + 1);
51
52 requirement_.min_x = max_width;
53 requirement_.min_y = lines_count;
54 }
55
56 void Select(Selection& selection) override {
57 if (Box::Intersection(selection.GetBox(), box_).IsEmpty()) {
58 return;
59 }
60
61 has_selection_ = true;
62 selection_rows_.assign(lines_offsets_.size() - 1, {-1, -1});
63
64 for (size_t i = 0; i < lines_offsets_.size() - 1; ++i) {
65 const int y = box_.y_min + (int)i;
66 if (y > box_.y_max) {
67 break;
68 }
69
70 const Box row_box{box_.x_min, box_.x_max, y, y};
71 if (Box::Intersection(selection.GetBox(), row_box).IsEmpty()) {
72 continue;
73 }
74
75 const Selection row_sel = selection.SaturateHorizontal(row_box);
76 const int sel_start = row_sel.GetBox().x_min;
77 const int sel_end = row_sel.GetBox().x_max;
78 selection_rows_[i] = {sel_start, sel_end};
79
80 std::string part;
81 int x = box_.x_min;
82 const int start = lines_offsets_[i];
83 const int end = lines_offsets_[i + 1] - 1;
84 for (int j = start; j < end; ++j) {
85 if (sel_start <= x && x <= sel_end) {
86 part += glyphs_[j];
87 }
88 x++;
89 }
90 selection.AddPart(std::move(part), y, sel_start, sel_end);
91 }
92 }
93
94 void Render(Screen& screen) override {
95 int x = box_.x_min;
96 int y = box_.y_min;
97 size_t line = 0;
98
99 if (y > box_.y_max) {
100 return;
101 }
102
103 for (const auto& cell : glyphs_) {
104 if (cell == "\n") {
105 y++;
106 x = box_.x_min;
107 line++;
108 if (y > box_.y_max) {
109 return;
110 }
111 continue;
112 }
113
114 if (x <= box_.x_max) {
115 screen.CellAt(x, y).character = cell;
116
117 if (has_selection_ && line < selection_rows_.size()) {
118 const auto& [sel_start, sel_end] = selection_rows_[line];
119 if (sel_start != -1 && x >= sel_start && x <= sel_end) {
120 screen.GetSelectionStyle()(screen.CellAt(x, y));
121 }
122 }
123 }
124 x++;
125 }
126 }
127
128 private:
129 std::vector<std::string> glyphs_;
130 std::vector<int> lines_offsets_;
131 bool has_selection_ = false;
132 std::vector<std::pair<int, int>> selection_rows_;
133};
134
135class VText : public Node {
136 public:
137 explicit VText(std::string text) : glyphs_(Utf8ToGlyphs(text)) {
138 for (const auto& g : glyphs_) {
139 if (g != "\n") {
140 width_ = 1;
141 break;
142 }
143 }
144 }
145 explicit VText(std::string_view sv) : VText(std::string(sv)) {}
146
147 void ComputeRequirement() override {
148 int max_height = 0;
149 int current_height = 0;
150 int columns = 1;
151
152 for (const auto& cell : glyphs_) {
153 if (cell == "\n") {
154 max_height = std::max(max_height, current_height);
155 current_height = 0;
156 columns++;
157 } else {
158 current_height++;
159 }
160 }
161 max_height = std::max(max_height, current_height);
162
163 requirement_.min_x = width_ * columns;
164 requirement_.min_y = max_height;
165 }
166
167 void Render(Screen& screen) override {
168 int x = box_.x_min;
169 int y = box_.y_min;
170 if (x + width_ - 1 > box_.x_max) {
171 return;
172 }
173 for (const auto& it : glyphs_) {
174 if (it == "\n") {
175 x += width_;
176 y = box_.y_min;
177 if (x + width_ - 1 > box_.x_max) {
178 return;
179 }
180 continue;
181 }
182 if (y > box_.y_max) {
183 continue;
184 }
185 screen.CellAt(x, y).character = it;
186 y += 1;
187 }
188 }
189
190 private:
191 std::vector<std::string> glyphs_;
192 int width_ = 0;
193};
194
195} // namespace
196
197/// @brief Display a piece of UTF8 encoded unicode text.
198/// @ingroup dom
199/// @see ftxui::to_wstring
200///
201/// ### Example
202///
203/// ```cpp
204/// Element document = text("Hello world!");
205/// ```
206///
207/// ### Output
208///
209/// ```bash
210/// Hello world!
211/// ```
212Element text(std::string_view text) {
213 return std::make_shared<Text>(std::string(text));
214}
215
216/// @brief Display a piece of unicode text.
217/// @ingroup dom
218/// @see ftxui::to_wstring
219///
220/// ### Example
221///
222/// ```cpp
223/// Element document = text(L"Hello world!");
224/// ```
225///
226/// ### Output
227///
228/// ```bash
229/// Hello world!
230/// ```
231Element text(std::wstring_view sv) {
232 return text(to_string(sv));
233}
234
235/// @brief Display a piece of unicode text vertically.
236/// @ingroup dom
237/// @see ftxui::to_wstring
238///
239/// ### Example
240///
241/// ```cpp
242/// Element document = vtext("Hello world!");
243/// ```
244///
245/// ### Output
246///
247/// ```bash
248/// H
249/// e
250/// l
251/// l
252/// o
253///
254/// w
255/// o
256/// r
257/// l
258/// d
259/// !
260/// ```
261Element vtext(std::string_view text) {
262 return std::make_shared<VText>(std::string(text));
263}
264
265/// @brief Display a piece unicode text vertically.
266/// @ingroup dom
267/// @see ftxui::to_wstring
268///
269/// ### Example
270///
271/// ```cpp
272/// Element document = vtext(L"Hello world!");
273/// ```
274///
275/// ### Output
276///
277/// ```bash
278/// H
279/// e
280/// l
281/// l
282/// o
283///
284/// w
285/// o
286/// r
287/// l
288/// d
289/// !
290/// ```
291Element vtext(std::wstring_view text) { // NOLINT
292 return vtext(to_string(text));
293}
294
295} // namespace ftxui
Element vtext(std::wstring_view text)
Display a piece unicode text vertically.
Element text(std::wstring_view text)
Display a piece of unicode text.
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
Definition node.cpp:83
static auto Intersection(Box a, Box b) -> Box
Definition box.cpp:11
A rectangular grid of Cell.
Definition screen.hpp:26
The FTXUI ftxui:: namespace.
Definition animation.hpp:10
std::shared_ptr< Node > Element
Definition elements.hpp:23
std::string to_string(std::wstring_view s)
Convert a std::wstring into a UTF8 std::string.
Definition string.cpp:1593