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