FTXUI 7.0.3
C++ functional terminal UI.
Loading...
Searching...
No Matches
component.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 find_if
5#include <cassert> // for assert
6#include <cstddef> // for size_t
7#include <iterator> // for begin, end
8#include <memory> // for unique_ptr, make_unique
9#include <utility> // for move
10#include <vector> // for vector, __alloc_traits<>::value_type
11
12#include "ftxui/component/app.hpp" // for Component, App
13#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface
15#include "ftxui/component/component_base.hpp" // for ComponentBase, Components
16#include "ftxui/component/event.hpp" // for Event
17#include "ftxui/dom/elements.hpp" // for text, Element
18#include "ftxui/dom/node.hpp" // for Node, Elements
19#include "ftxui/screen/box.hpp" // for Box
20
21namespace ftxui::animation {
22class Params;
23} // namespace ftxui::animation
24
25namespace ftxui {
26
27namespace {
28class CaptureMouseImpl : public CapturedMouseInterface {};
29} // namespace
30
31struct ComponentBase::Impl {
32 Components children;
33 ComponentBase* parent = nullptr;
34 bool in_render = false;
35};
36
37ComponentBase::ComponentBase() : impl_(std::make_unique<Impl>()) {}
38
39ComponentBase::ComponentBase(Components children)
40 : impl_(std::make_unique<Impl>()) {
41 impl_->children = std::move(children);
42}
43
44ComponentBase::~ComponentBase() {
45 DetachAllChildren();
46}
47
48Components& ComponentBase::children() {
49 return impl_->children;
50}
51
52const Components& ComponentBase::children() const {
53 return impl_->children;
54}
55
56/// @brief 親のComponentBaseを返します。存在しない場合はnullを返します。
57/// @see Detach
58/// @see Parent
59ComponentBase* ComponentBase::Parent() const {
60 return impl_->parent;
61}
62
63/// @brief インデックス`i`の子にアクセスします。
64Component& ComponentBase::ChildAt(size_t i) {
65 assert(i < ChildCount()); // NOLINT
66 return impl_->children[i];
67}
68
69/// @brief 子の数を返します。
70size_t ComponentBase::ChildCount() const {
71 return impl_->children.size();
72}
73
74/// @brief 親におけるコンポーネントのインデックスを返します。親がない場合は-1を返します。
75int ComponentBase::Index() const {
76 if (impl_->parent == nullptr) {
77 return -1;
78 }
79 int index = 0;
80 for (const Component& child : impl_->parent->impl_->children) {
81 if (child.get() == this) {
82 return index;
83 }
84 index++;
85 }
86 return -1; // ここには到達しません。
87}
88
89/// @brief 子を追加します。
90/// @param child アタッチする子。
91void ComponentBase::Add(Component child) {
92 child->Detach();
93 child->impl_->parent = this;
94 impl_->children.push_back(std::move(child));
95}
96
97/// @brief この子を親からデタッチします。
98/// @see Detach
99/// @see Parent
100void ComponentBase::Detach() {
101 if (impl_->parent == nullptr) {
102 return;
103 }
104 auto it = std::find_if(std::begin(impl_->parent->impl_->children), // NOLINT
105 std::end(impl_->parent->impl_->children), //
106 [this](const Component& that) { //
107 return this == that.get();
108 });
109 ComponentBase* parent = impl_->parent;
110 impl_->parent = nullptr;
111 parent->impl_->children.erase(it); // |this| を削除する可能性があります。
112}
113
114/// @brief すべての子を削除します。
115void ComponentBase::DetachAllChildren() {
116 while (!impl_->children.empty()) {
117 impl_->children[0]->Detach();
118 }
119}
120
121/// @brief コンポーネントを描画します。
122/// このftxui::ComponentBaseを表すftxui::Screen上に描画されるftxui::Elementを構築します。レンダリングを変更するにはOnRender()をオーバーライドしてください。
123Element ComponentBase::Render() {
124 // `T::OnRender()` から `ComponentBase::Render()` を呼び出す
125 // ユーザーがいるかもしれません。無限再帰を避けるため、フラグを使用します。
126 if (impl_->in_render) {
127 return ComponentBase::OnRender();
128 }
129
130 impl_->in_render = true;
131 Element element = OnRender();
132 impl_->in_render = false;
133
134 class Wrapper : public Node {
135 public:
136 bool active_ = false;
137 bool focused_ = false;
138
139 Wrapper(Element child, bool active, bool focused)
140 : Node({std::move(child)}), active_(active), focused_(focused) {}
141
142 void SetBox(Box box) override {
143 Node::SetBox(box);
144 children_[0]->SetBox(box);
145 }
146
147 void ComputeRequirement() override {
148 Node::ComputeRequirement();
149 requirement_.focused.component_active = active_;
150 requirement_.focused.component_focused = focused_;
151 }
152 };
153
154 return std::make_shared<Wrapper>(std::move(element), Active(), Focused());
155}
156
157/// @brief コンポーネントを描画します。
158/// このftxui::ComponentBaseを表すftxui::Screen上に描画されるftxui::Elementを構築します。この関数はオーバーライドされることを意図しています。
159Element ComponentBase::OnRender() {
160 if (impl_->children.size() == 1) {
161 return impl_->children.front()->Render();
162 }
163
164 return text("Not implemented component");
165}
166
167/// @brief イベントに応じて呼び出されます。
168/// @param event イベント。
169/// @return イベントが処理された場合はtrue。
170/// デフォルトの実装では、いずれかの子がtrueを返すまで、すべての子でOnEventを呼び出します。どれもtrueを返さない場合は、falseを返します。
171bool ComponentBase::OnEvent(Event event) { // NOLINT
172 for (Component& child : impl_->children) { // NOLINT
173 if (child->OnEvent(event)) {
174 return true;
175 }
176 }
177 return false;
178}
179
180/// @brief アニメーションイベントに応じて呼び出されます。
181/// @param params アニメーションのパラメータ
182/// デフォルトの実装では、イベントをすべての子にディスパッチします。
183void ComponentBase::OnAnimation(animation::Params& params) {
184 for (const Component& child : impl_->children) {
185 child->OnAnimation(params);
186 }
187}
188
189/// @brief 現在アクティブな子を返します。
190/// @return 現在アクティブな子。
191Component ComponentBase::ActiveChild() {
192 for (auto& child : impl_->children) {
193 if (child->Focusable()) {
194 return child;
195 }
196 }
197 return nullptr;
198}
199
200/// @brief コンポーネントがフォーカス可能な要素を含んでいる場合にtrueを返します。
201/// フォーカス不可能なコンポーネントは、キーボードでナビゲートする際にスキップされます。
202bool ComponentBase::Focusable() const {
203 for (const Component& child : impl_->children) { // NOLINT
204 if (child->Focusable()) {
205 return true;
206 }
207 }
208 return false;
209}
210
211/// @brief 要素が現在親のアクティブな子であるかどうかを返します。
212bool ComponentBase::Active() const {
213 return impl_->parent == nullptr || impl_->parent->ActiveChild().get() == this;
214}
215
216/// @brief 要素がユーザーによってフォーカスされているかどうかを返します。
217/// ComponentBaseがユーザーによってフォーカスされている場合にtrueを返します。要素は、そのすべての子孫が親のActiveChild()であり、かつFocusable()である場合にフォーカスされます。
218bool ComponentBase::Focused() const {
219 const auto* current = this;
220 while (current && current->Active()) {
221 current = current->impl_->parent;
222 }
223 return !current && Focusable();
224}
225
226/// @brief |child|を「アクティブ」にします。
227/// @param child アクティブにする子。
228void ComponentBase::SetActiveChild([[maybe_unused]] ComponentBase* child) {}
229
230/// @brief |child|を「アクティブ」にします。
231/// @param child アクティブにする子。
232void ComponentBase::SetActiveChild(Component child) { // NOLINT
233 SetActiveChild(child.get());
234}
235
236/// @brief このコンポーネントにフォーカスを与えるように、すべての祖先を設定します。
237void ComponentBase::TakeFocus() {
238 ComponentBase* child = this;
239 while (ComponentBase* parent = child->impl_->parent) {
240 parent->SetActiveChild(child);
241 child = parent;
242 }
243}
244
245/// @brief 利用可能であればCapturedMouseを取得します。コンポーネントは1つしかありません。これは他のコンポーネントよりも優先されるコンポーネントを表します。
246/// @param event イベント
247CapturedMouse ComponentBase::CaptureMouse(const Event& event) { // NOLINT
248 if (event.screen_) {
249 return event.screen_->CaptureMouse();
250 }
251 return std::make_unique<CaptureMouseImpl>();
252}
253
254void ComponentBase::Reserved1() {}
255void ComponentBase::Reserved2() {}
256void ComponentBase::Reserved3() {}
257void ComponentBase::Reserved4() {}
258void ComponentBase::Reserved5() {}
259void ComponentBase::Reserved6() {}
260void ComponentBase::Reserved7() {}
261void ComponentBase::Reserved8() {}
262
263} // namespace ftxui
FTXUI ftxui::名前空間
Definition animation.hpp:11
std::unique_ptr< CapturedMouseInterface > CapturedMouse
std::shared_ptr< Node > Element
Definition elements.hpp:25
std::vector< Component > Components
const Element & element
Definition node.hpp:94
std::shared_ptr< ComponentBase > Component
Definition app.hpp:23