FTXUI 6.1.9
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 Compute how much space an element needs.
21void Node::ComputeRequirement() {
22 if (children_.empty()) {
23 return;
24 }
25 for (auto& child : children_) {
26 child->ComputeRequirement();
27 }
28
29 // By default, the requirement is the one of the first child.
30 requirement_ = children_[0]->requirement();
31
32 // Propagate the focused requirement.
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 Assign a position and a dimension to an element for drawing.
41void Node::SetBox(Box box) {
42 box_ = box;
43}
44
45/// @brief Compute the selection of an element.
46void Node::Select(Selection& selection) {
47 // If this Node box_ doesn't intersect with the selection, then no selection.
48 if (Box::Intersection(selection.GetBox(), box_).IsEmpty()) {
49 return;
50 }
51
52 // By default we defer the selection to the children.
53 for (auto& child : children_) {
54 child->Select(selection);
55 }
56}
57
58/// @brief Display an element on a 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 Display an element on a 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 Display an element on a 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 // Step 1: Find what dimension this elements wants to be.
117 node->ComputeRequirement();
118
119 // Step 2: Assign a dimension to the element.
120 node->SetBox(box);
121
122 // Check if the element needs another iteration of the layout algorithm.
123 status.need_iteration = false;
124 status.iteration++;
125 node->Check(&status);
126 }
127
128 // Step 3: Selection
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 // Setting the cursor to the right position allow folks using CJK (China,
138 // Japanese, Korean, ...) characters to see their [input method editor]
139 // displayed at the right location. See [issue].
140 //
141 // [input method editor]:
142 // https://en.wikipedia.org/wiki/Input_method
143 //
144 // [issue]:
145 // https://github.com/ArthurSonzogni/FTXUI/issues/2#issuecomment-505282355
146 //
147 // Unfortunately, Microsoft terminal do not handle properly hiding the
148 // cursor. Instead the character under the cursor is hidden, which is a
149 // big problem. As a result, we can't enable setting cursor to the right
150 // location. It will be displayed at the bottom right corner.
151 // See:
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 // Step 4: Draw the element.
172 screen.stencil = box;
173 node->Render(screen);
174
175 // Step 5: Apply shaders
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 // Step 1: Find what dimension this elements wants to be.
193 node->ComputeRequirement();
194
195 // Step 2: Assign a dimension to the element.
196 node->SetBox(box);
197
198 // Check if the element needs another iteration of the layout algorithm.
199 status.need_iteration = false;
200 status.iteration++;
201 node->Check(&status);
202 }
203
204 // Step 3: Selection
205 node->Select(selection);
206
207 // Step 4: get the selected content.
208 return node->GetSelectedContent(selection);
209}
210
211} // namespace ftxui
The FTXUI ftxui:: namespace.
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:24
std::vector< Element > Elements
Definition elements.hpp:25
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