FTXUI  5.0.0
C++ functional terminal UI.
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 <utility> // for move
9 #include <vector> // for vector, __alloc_traits<>::value_type
10 
11 #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface
13 #include "ftxui/component/component_base.hpp" // for ComponentBase, Components
14 #include "ftxui/component/event.hpp" // for Event
15 #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
16 #include "ftxui/dom/elements.hpp" // for text, Element
17 
18 namespace ftxui::animation {
19 class Params;
20 } // namespace ftxui::animation
21 
22 namespace ftxui {
23 
24 namespace {
25 class CaptureMouseImpl : public CapturedMouseInterface {};
26 } // namespace
27 
30 }
31 
32 /// @brief Return the parent ComponentBase, or nul if any.
33 /// @see Detach
34 /// @see Parent
35 /// @ingroup component
37  return parent_;
38 }
39 
40 /// @brief Access the child at index `i`.
41 /// @ingroup component
43  assert(i < ChildCount()); // NOLINT
44  return children_[i];
45 }
46 
47 /// @brief Returns the number of children.
48 /// @ingroup component
49 size_t ComponentBase::ChildCount() const {
50  return children_.size();
51 }
52 
53 /// @brief Add a child.
54 /// @@param child The child to be attached.
55 /// @ingroup component
57  child->Detach();
58  child->parent_ = this;
59  children_.push_back(std::move(child));
60 }
61 
62 /// @brief Detach this child from its parent.
63 /// @see Detach
64 /// @see Parent
65 /// @ingroup component
67  if (parent_ == nullptr) {
68  return;
69  }
70  auto it = std::find_if(std::begin(parent_->children_), //
71  std::end(parent_->children_), //
72  [this](const Component& that) { //
73  return this == that.get();
74  });
75  ComponentBase* parent = parent_;
76  parent_ = nullptr;
77  parent->children_.erase(it); // Might delete |this|.
78 }
79 
80 /// @brief Remove all children.
81 /// @ingroup component
83  while (!children_.empty()) {
84  children_[0]->Detach();
85  }
86 }
87 
88 /// @brief Draw the component.
89 /// Build a ftxui::Element to be drawn on the ftxi::Screen representing this
90 /// ftxui::ComponentBase.
91 /// @ingroup component
93  if (children_.size() == 1) {
94  return children_.front()->Render();
95  }
96 
97  return text("Not implemented component");
98 }
99 
100 /// @brief Called in response to an event.
101 /// @param event The event.
102 /// @return True when the event has been handled.
103 /// The default implementation called OnEvent on every child until one return
104 /// true. If none returns true, return false.
105 /// @ingroup component
106 bool ComponentBase::OnEvent(Event event) { // NOLINT
107  for (Component& child : children_) { // NOLINT
108  if (child->OnEvent(event)) {
109  return true;
110  }
111  }
112  return false;
113 }
114 
115 /// @brief Called in response to an animation event.
116 /// @param params the parameters of the animation
117 /// The default implementation dispatch the event to every child.
118 /// @ingroup component
120  for (const Component& child : children_) {
121  child->OnAnimation(params);
122  }
123 }
124 
125 /// @brief Return the currently Active child.
126 /// @return the currently Active child.
127 /// @ingroup component
129  for (auto& child : children_) {
130  if (child->Focusable()) {
131  return child;
132  }
133  }
134  return nullptr;
135 }
136 
137 /// @brief Return true when the component contains focusable elements.
138 /// The non focusable Components will be skipped when navigating using the
139 /// keyboard.
140 /// @ingroup component
142  for (const Component& child : children_) { // NOLINT
143  if (child->Focusable()) {
144  return true;
145  }
146  }
147  return false;
148 }
149 
150 /// @brief Returns if the element if the currently active child of its parent.
151 /// @ingroup component
152 bool ComponentBase::Active() const {
153  return parent_ == nullptr || parent_->ActiveChild().get() == this;
154 }
155 
156 /// @brief Returns if the elements if focused by the user.
157 /// True when the ComponentBase is focused by the user. An element is Focused
158 /// when it is with all its ancestors the ActiveChild() of their parents, and it
159 /// Focusable().
160 /// @ingroup component
162  const auto* current = this;
163  while (current && current->Active()) {
164  current = current->parent_;
165  }
166  return !current && Focusable();
167 }
168 
169 /// @brief Make the |child| to be the "active" one.
170 /// @param child the child to become active.
171 /// @ingroup component
172 void ComponentBase::SetActiveChild([[maybe_unused]] ComponentBase* child) {}
173 
174 /// @brief Make the |child| to be the "active" one.
175 /// @param child the child to become active.
176 /// @ingroup component
178  SetActiveChild(child.get());
179 }
180 
181 /// @brief Configure all the ancestors to give focus to this component.
182 /// @ingroup component
184  ComponentBase* child = this;
185  while (ComponentBase* parent = child->parent_) {
186  parent->SetActiveChild(child);
187  child = parent;
188  }
189 }
190 
191 /// @brief Take the CapturedMouse if available. There is only one component of
192 /// them. It represents a component taking priority over others.
193 /// @param event The event
194 /// @ingroup component
196  if (event.screen_) {
197  return event.screen_->CaptureMouse();
198  }
199  return std::make_unique<CaptureMouseImpl>();
200 }
201 
202 } // namespace ftxui
It implement rendering itself as ftxui::Element. It implement keyboard navigation by responding to ft...
virtual bool Focusable() const
Return true when the component contains focusable elements. The non focusable Components will be skip...
Definition: component.cpp:141
bool Focused() const
Returns if the elements if focused by the user. True when the ComponentBase is focused by the user....
Definition: component.cpp:161
CapturedMouse CaptureMouse(const Event &event)
Take the CapturedMouse if available. There is only one component of them. It represents a component t...
Definition: component.cpp:195
void Add(Component children)
Add a child. @param child The child to be attached.
Definition: component.cpp:56
virtual Element Render()
Draw the component. Build a ftxui::Element to be drawn on the ftxi::Screen representing this ftxui::C...
Definition: component.cpp:92
void TakeFocus()
Configure all the ancestors to give focus to this component.
Definition: component.cpp:183
bool Active() const
Returns if the element if the currently active child of its parent.
Definition: component.cpp:152
virtual Component ActiveChild()
Return the currently Active child.
Definition: component.cpp:128
void DetachAllChildren()
Remove all children.
Definition: component.cpp:82
size_t ChildCount() const
Returns the number of children.
Definition: component.cpp:49
ComponentBase * Parent() const
Return the parent ComponentBase, or nul if any.
Definition: component.cpp:36
virtual void SetActiveChild(ComponentBase *child)
virtual bool OnEvent(Event)
Called in response to an event.
Definition: component.cpp:106
void Detach()
Detach this child from its parent.
Definition: component.cpp:66
Component & ChildAt(size_t i)
Access the child at index i.
Definition: component.cpp:42
virtual ~ComponentBase()
Definition: component.cpp:28
virtual void OnAnimation(animation::Params &params)
Called in response to an animation event.
Definition: component.cpp:119
std::unique_ptr< CapturedMouseInterface > CapturedMouse
std::shared_ptr< Node > Element
Definition: elements.hpp:23
std::shared_ptr< ComponentBase > Component
Element text(std::wstring text)
Display a piece of unicode text.
Definition: text.cpp:120
Represent an event. It can be key press event, a terminal resize, or more ...
Definition: event.hpp:29
ScreenInteractive * screen_
Definition: event.hpp:124