FTXUI 7.0.3
C++ functional terminal UI.
Loading...
Searching...
No Matches
node.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 <ftxui/screen/box.hpp> // for Box
5#include <string>
6#include <utility> // for move
7
8#include <cstddef>
9#include "ftxui/dom/node.hpp"
10#include "ftxui/dom/selection.hpp" // for Selection
11#include "ftxui/screen/screen.hpp" // for Screen
12#include "ftxui/screen/terminal.hpp" // for GetQuirks
13
14namespace ftxui {
15
16Node::Node() = default;
17Node::Node(Elements children) : children_(std::move(children)) {}
18Node::~Node() = default;
19
20/// @brief Calcula cuánto espacio necesita un elemento.
21void Node::ComputeRequirement() {
22 if (children_.empty()) {
23 return;
24 }
25 for (auto& child : children_) {
26 child->ComputeRequirement();
27 }
28
29 // Por defecto, el requisito es el del primer hijo.
30 requirement_ = children_[0]->requirement();
31
32 // Propagar el requisito de enfoque.
33 for (size_t i = 1; i < children_.size(); ++i) {
34 if (requirement_.focused.Prefer(children_[i]->requirement().focused)) {
35 requirement_.focused = children_[i]->requirement().focused;
36 }
37 }
38}
39
40/// @brief Asigna una posición y una dimensión a un elemento para dibujarlo.
41void Node::SetBox(Box box) {
42 box_ = box;
43}
44
45/// @brief Calcula la selección de un elemento.
46void Node::Select(Selection& selection) {
47 // Si el cuadro de este Nodo no se interseca con la selección, entonces no hay selección.
48 if (Box::Intersection(selection.GetBox(), box_).IsEmpty()) {
49 return;
50 }
51
52 // Por defecto, diferimos la selección a los hijos.
53 for (auto& child : children_) {
54 child->Select(selection);
55 }
56}
57
58/// @brief Muestra un elemento en un ftxui::Screen.
59void Node::Render(Screen& screen) {
60 for (auto& child : children_) {
61 child->Render(screen);
62 }
63}
64
65void Node::Check(Status* status) {
66 for (auto& child : children_) {
67 child->Check(status);
68 }
69 status->need_iteration |= (status->iteration == 0);
70}
71
72std::string Node::GetSelectedContent(Selection& selection) {
73 std::string content;
74
75 for (auto& child : children_) {
76 content += child->GetSelectedContent(selection);
77 }
78
79 return content;
80}
81
82void Node::Reserved1() {}
83void Node::Reserved2() {}
84void Node::Reserved3() {}
85void Node::Reserved4() {}
86void Node::Reserved5() {}
87void Node::Reserved6() {}
88void Node::Reserved7() {}
89void Node::Reserved8() {}
90
91/// @brief Muestra un elemento en un ftxui::Screen.
92/// @ingroup dom
93void Render(Screen& screen, const Element& element) {
94 Selection selection;
95 Render(screen, element.get(), selection);
96}
97
98/// @brief Muestra un elemento en un ftxui::Screen.
99/// @ingroup dom
100void Render(Screen& screen, Node* node) {
101 Selection selection;
102 Render(screen, node, selection);
103}
104
105void Render(Screen& screen, Node* node, Selection& selection) {
106 Box box;
107 box.x_min = 0;
108 box.y_min = 0;
109 box.x_max = screen.dimx() - 1;
110 box.y_max = screen.dimy() - 1;
111
112 Node::Status status;
113 node->Check(&status);
114 const int max_iterations = 20;
115 while (status.need_iteration && status.iteration < max_iterations) {
116 // Paso 1: Encontrar qué dimensión quiere tener este elemento.
117 node->ComputeRequirement();
118
119 // Paso 2: Asignar una dimensión al elemento.
120 node->SetBox(box);
121
122 // Comprobar si el elemento necesita otra iteración del algoritmo de diseño.
123 status.need_iteration = false;
124 status.iteration++;
125 node->Check(&status);
126 }
127
128 // Paso 3: Selección
129 if (!selection.IsEmpty()) {
130 node->Select(selection);
131 }
132
133 bool use_cursor = node->requirement().focused.enabled;
134 if (!Terminal::GetQuirks().CursorHiding() &&
135 node->requirement().focused.cursor_shape ==
136 Screen::Cursor::Shape::Hidden) {
137 // Establecer el cursor en la posición correcta permite que las personas que usan caracteres CJK
138 // (chino, japonés, coreano, ...) vean su [editor de método de entrada]
139 // mostrado en la ubicación correcta. Ver [issue].
140 //
141 // [editor de método de entrada]:
142 // https://en.wikipedia.org/wiki/Input_method
143 //
144 // [issue]:
145 // https://github.com/ArthurSonzogni/FTXUI/issues/2#issuecomment-505282355
146 //
147 // Desafortunadamente, la terminal de Microsoft no maneja bien la ocultación
148 // del cursor. En su lugar, el carácter bajo el cursor se oculta, lo cual es un
149 // gran problema. Como resultado, no podemos habilitar la colocación del cursor
150 // en la ubicación correcta. Se mostrará en la esquina inferior derecha.
151 // Ver:
152 // https://github.com/microsoft/terminal/issues/1203
153 // https://github.com/microsoft/terminal/issues/3093
154 use_cursor = false;
155 }
156
157 if (use_cursor) {
158 screen.SetCursor(Screen::Cursor{
159 node->requirement().focused.node->box_.x_min,
160 node->requirement().focused.node->box_.y_min,
161 node->requirement().focused.cursor_shape,
162 });
163 } else {
164 screen.SetCursor(Screen::Cursor{
165 screen.dimx() - 1,
166 screen.dimy() - 1,
167 Screen::Cursor::Shape::Hidden,
168 });
169 }
170
171 // Paso 4: Dibujar el elemento.
172 screen.stencil = box;
173 node->Render(screen);
174
175 // Paso 5: Aplicar sombreadores
176 screen.ApplyShader();
177}
178
179std::string GetNodeSelectedContent(Screen& screen,
180 Node* node,
181 Selection& selection) {
182 Box box;
183 box.x_min = 0;
184 box.y_min = 0;
185 box.x_max = screen.dimx() - 1;
186 box.y_max = screen.dimy() - 1;
187
188 Node::Status status;
189 node->Check(&status);
190 const int max_iterations = 20;
191 while (status.need_iteration && status.iteration < max_iterations) {
192 // Paso 1: Encontrar qué dimensión quiere tener este elemento.
193 node->ComputeRequirement();
194
195 // Paso 2: Asignar una dimensión al elemento.
196 node->SetBox(box);
197
198 // Comprobar si el elemento necesita otra iteración del algoritmo de diseño.
199 status.need_iteration = false;
200 status.iteration++;
201 node->Check(&status);
202 }
203
204 // Paso 3: Selección
205 node->Select(selection);
206
207 // Paso 4: obtener el contenido seleccionado.
208 return node->GetSelectedContent(selection);
209}
210
211} // namespace ftxui
El espacio de nombres ftxui:: de FTXUI.
Definition animation.hpp:11
std::string GetNodeSelectedContent(Screen &screen, Node *node, Selection &selection)
Definition node.cpp:179
std::shared_ptr< Node > Element
Definition elements.hpp:25
std::vector< Element > Elements
Definition elements.hpp:26
const Element & element
Definition node.hpp:95
void Render(Screen &screen, Node *node, Selection &selection)
Definition node.cpp:105
Node * node
Definition node.hpp:96