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 要素が必要とするスペースを計算します。
21void Node::ComputeRequirement() {
22 if (children_.empty()) {
23 return;
24 }
25 for (auto& child : children_) {
26 child->ComputeRequirement();
27 }
28
29 // デフォルトでは、要件は最初の子のものである。
30 requirement_ = children_[0]->requirement();
31
32 // フォーカス要求を伝播する。
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 描画のために要素に位置と次元を割り当てます。
41void Node::SetBox(Box box) {
42 box_ = box;
43}
44
45/// @brief 要素の選択を計算します。
46void Node::Select(Selection& selection) {
47 // このノードのbox_が選択範囲と交差しない場合、選択は行われません。
48 if (Box::Intersection(selection.GetBox(), box_).IsEmpty()) {
49 return;
50 }
51
52 // デフォルトでは選択を子に委ねる。
53 for (auto& child : children_) {
54 child->Select(selection);
55 }
56}
57
58/// @brief 要素を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 要素を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 要素を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 // ステップ1: この要素がどの寸法になりたいかを見つける。
117 node->ComputeRequirement();
118
119 // ステップ2: 要素に寸法を割り当てる。
120 node->SetBox(box);
121
122 // 要素がレイアウトアルゴリズムのもう一回の反復を必要とするか確認する。
123 status.need_iteration = false;
124 status.iteration++;
125 node->Check(&status);
126 }
127
128 // ステップ3: 選択
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 // カーソルを正しい位置に設定することで、CJK(中国語、日本語、韓国語など)
138 // の文字を使う人々が自分の[input method editor]が正しい位置に表示される
139 // のを見られるようにする。[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 // 残念ながら、Microsoftターミナルはカーソルを隠す処理を適切に扱わない。
148 // 代わりにカーソルの下の文字が隠されてしまい、これは大きな問題である。
149 // その結果、カーソルを正しい位置に設定することはできない。右下隅に
150 // 表示される。
151 // 参照:
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 // ステップ4: 要素を描画する。
172 screen.stencil = box;
173 node->Render(screen);
174
175 // ステップ5: シェーダーを適用する
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 // ステップ1: この要素がどの寸法になりたいかを見つける。
193 node->ComputeRequirement();
194
195 // ステップ2: 要素に寸法を割り当てる。
196 node->SetBox(box);
197
198 // 要素がレイアウトアルゴリズムのもう一回の反復を必要とするか確認する。
199 status.need_iteration = false;
200 status.iteration++;
201 node->Check(&status);
202 }
203
204 // ステップ3: 選択
205 node->Select(selection);
206
207 // ステップ4: 選択されたコンテンツを取得する。
208 return node->GetSelectedContent(selection);
209}
210
211} // namespace ftxui
FTXUI 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:94
void Render(Screen &screen, Node *node, Selection &selection)
Definition node.cpp:105
Node * node
Definition node.hpp:95