FTXUI 6.1.9
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 Return the parent ComponentBase, or nul if any.
57/// @see Detach
58/// @see Parent
59ComponentBase* ComponentBase::Parent() const {
60 return impl_->parent;
61}
62
63/// @brief Access the child at index `i`.
64Component& ComponentBase::ChildAt(size_t i) {
65 assert(i < ChildCount()); // NOLINT
66 return impl_->children[i];
67}
68
69/// @brief Returns the number of children.
70size_t ComponentBase::ChildCount() const {
71 return impl_->children.size();
72}
73
74/// @brief Return index of the component in its parent. -1 if no parent.
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; // Not reached.
87}
88
89/// @brief Add a child.
90/// @param child The child to be attached.
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 Detach this child from its parent.
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); // Might delete |this|.
112}
113
114/// @brief Remove all children.
115void ComponentBase::DetachAllChildren() {
116 while (!impl_->children.empty()) {
117 impl_->children[0]->Detach();
118 }
119}
120
121/// @brief Draw the component.
122/// Build a ftxui::Element to be drawn on the ftxui::Screen representing this
123/// ftxui::ComponentBase. Please override OnRender() to modify the rendering.
124Element ComponentBase::Render() {
125 // Some users might call `ComponentBase::Render()` from
126 // `T::OnRender()`. To avoid infinite recursion, we use a flag.
127 if (impl_->in_render) {
128 return ComponentBase::OnRender();
129 }
130
131 impl_->in_render = true;
132 Element element = OnRender();
133 impl_->in_render = false;
134
135 class Wrapper : public Node {
136 public:
137 bool active_ = false;
138 bool focused_ = false;
139
140 Wrapper(Element child, bool active, bool focused)
141 : Node({std::move(child)}), active_(active), focused_(focused) {}
142
143 void SetBox(Box box) override {
144 Node::SetBox(box);
145 children_[0]->SetBox(box);
146 }
147
148 void ComputeRequirement() override {
149 Node::ComputeRequirement();
150 requirement_.focused.component_active = active_;
151 requirement_.focused.component_focused = focused_;
152 }
153 };
154
155 return std::make_shared<Wrapper>(std::move(element), Active(), Focused());
156}
157
158/// @brief Draw the component.
159/// Build a ftxui::Element to be drawn on the ftxi::Screen representing this
160/// ftxui::ComponentBase. This function is means to be overridden.
161Element ComponentBase::OnRender() {
162 if (impl_->children.size() == 1) {
163 return impl_->children.front()->Render();
164 }
165
166 return text("Not implemented component");
167}
168
169/// @brief Called in response to an event.
170/// @param event The event.
171/// @return True when the event has been handled.
172/// The default implementation called OnEvent on every child until one return
173/// true. If none returns true, return false.
174bool ComponentBase::OnEvent(Event event) { // NOLINT
175 for (Component& child : impl_->children) { // NOLINT
176 if (child->OnEvent(event)) {
177 return true;
178 }
179 }
180 return false;
181}
182
183/// @brief Called in response to an animation event.
184/// @param params the parameters of the animation
185/// The default implementation dispatch the event to every child.
186void ComponentBase::OnAnimation(animation::Params& params) {
187 for (const Component& child : impl_->children) {
188 child->OnAnimation(params);
189 }
190}
191
192/// @brief Return the currently Active child.
193/// @return the currently Active child.
194Component ComponentBase::ActiveChild() {
195 for (auto& child : impl_->children) {
196 if (child->Focusable()) {
197 return child;
198 }
199 }
200 return nullptr;
201}
202
203/// @brief Return true when the component contains focusable elements.
204/// The non focusable Components will be skipped when navigating using the
205/// keyboard.
206bool ComponentBase::Focusable() const {
207 for (const Component& child : impl_->children) { // NOLINT
208 if (child->Focusable()) {
209 return true;
210 }
211 }
212 return false;
213}
214
215/// @brief Returns if the element if the currently active child of its parent.
216bool ComponentBase::Active() const {
217 return impl_->parent == nullptr || impl_->parent->ActiveChild().get() == this;
218}
219
220/// @brief Returns if the elements if focused by the user.
221/// True when the ComponentBase is focused by the user. An element is Focused
222/// when it is with all its ancestors the ActiveChild() of their parents, and it
223/// Focusable().
224bool ComponentBase::Focused() const {
225 const auto* current = this;
226 while (current && current->Active()) {
227 current = current->impl_->parent;
228 }
229 return !current && Focusable();
230}
231
232/// @brief Make the |child| to be the "active" one.
233/// @param child the child to become active.
234void ComponentBase::SetActiveChild([[maybe_unused]] ComponentBase* child) {}
235
236/// @brief Make the |child| to be the "active" one.
237/// @param child the child to become active.
238void ComponentBase::SetActiveChild(Component child) { // NOLINT
239 SetActiveChild(child.get());
240}
241
242/// @brief Configure all the ancestors to give focus to this component.
243void ComponentBase::TakeFocus() {
244 ComponentBase* child = this;
245 while (ComponentBase* parent = child->impl_->parent) {
246 parent->SetActiveChild(child);
247 child = parent;
248 }
249}
250
251/// @brief Take the CapturedMouse if available. There is only one component of
252/// them. It represents a component taking priority over others.
253/// @param event The event
254CapturedMouse ComponentBase::CaptureMouse(const Event& event) { // NOLINT
255 if (event.screen_) {
256 return event.screen_->CaptureMouse();
257 }
258 return std::make_unique<CaptureMouseImpl>();
259}
260
261} // namespace ftxui
The FTXUI ftxui:: namespace.
Definition animation.hpp:11
std::unique_ptr< CapturedMouseInterface > CapturedMouse
std::shared_ptr< Node > Element
Definition elements.hpp:24
std::vector< Component > Components
const Element & element
Definition node.hpp:95
std::shared_ptr< ComponentBase > Component
Definition app.hpp:23