FTXUI  0.11.0
C++ functional terminal UI.
Loading...
Searching...
No Matches
container.cpp
Go to the documentation of this file.
1#include <stddef.h> // for size_t
2#include <algorithm> // for max, min
3#include <memory> // for make_shared, __shared_ptr_access, allocator, shared_ptr, allocator_traits<>::value_type
4#include <utility> // for move
5#include <vector> // for vector, __alloc_traits<>::value_type
6
7#include "ftxui/component/component.hpp" // for Horizontal, Vertical, Tab
8#include "ftxui/component/component_base.hpp" // for Components, Component, ComponentBase
9#include "ftxui/component/event.hpp" // for Event, Event::Tab, Event::TabReverse, Event::ArrowDown, Event::ArrowLeft, Event::ArrowRight, Event::ArrowUp
10#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::WheelDown, Mouse::WheelUp
11#include "ftxui/dom/elements.hpp" // for text, Elements, operator|, reflect, Element, hbox, vbox
12#include "ftxui/screen/box.hpp" // for Box
13
14namespace ftxui {
15
16class ContainerBase : public ComponentBase {
17 public:
18 ContainerBase(Components children, int* selector)
19 : selector_(selector ? selector : &selected_) {
20 for (Component& child : children)
21 Add(std::move(child));
22 }
23
24 // Component override.
25 bool OnEvent(Event event) override {
26 if (event.is_mouse())
27 return OnMouseEvent(event);
28
29 if (!Focused())
30 return false;
31
32 if (ActiveChild() && ActiveChild()->OnEvent(event))
33 return true;
34
35 return EventHandler(event);
36 }
37
38 Component ActiveChild() override {
39 if (children_.size() == 0)
40 return nullptr;
41
42 return children_[*selector_ % children_.size()];
43 }
44
45 void SetActiveChild(ComponentBase* child) override {
46 for (size_t i = 0; i < children_.size(); ++i) {
47 if (children_[i].get() == child) {
48 *selector_ = i;
49 return;
50 }
51 }
52 }
53
54 protected:
55 // Handlers
56 virtual bool EventHandler(Event) { return false; }
57
58 virtual bool OnMouseEvent(Event event) {
59 return ComponentBase::OnEvent(event);
60 }
61
62 int selected_ = 0;
63 int* selector_ = nullptr;
64
65 void MoveSelector(int dir) {
66 for (int i = *selector_ + dir; i >= 0 && i < (int)children_.size();
67 i += dir) {
68 if (children_[i]->Focusable()) {
69 *selector_ = i;
70 return;
71 }
72 }
73 }
74 void MoveSelectorWrap(int dir) {
75 for (size_t offset = 1; offset < children_.size(); ++offset) {
76 int i = (*selector_ + offset * dir + children_.size()) % children_.size();
77 if (children_[i]->Focusable()) {
78 *selector_ = i;
79 return;
80 }
81 }
82 }
83};
84
85class VerticalContainer : public ContainerBase {
86 public:
87 using ContainerBase::ContainerBase;
88
89 Element Render() override {
90 Elements elements;
91 for (auto& it : children_)
92 elements.push_back(it->Render());
93 if (elements.size() == 0)
94 return text("Empty container") | reflect(box_);
95 return vbox(std::move(elements)) | reflect(box_);
96 }
97
98 bool EventHandler(Event event) override {
99 int old_selected = *selector_;
100 if (event == Event::ArrowUp || event == Event::Character('k'))
101 MoveSelector(-1);
102 if (event == Event::ArrowDown || event == Event::Character('j'))
103 MoveSelector(+1);
104 if (event == Event::Tab && children_.size())
105 MoveSelectorWrap(+1);
106 if (event == Event::TabReverse && children_.size())
107 MoveSelectorWrap(-1);
108
109 *selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_));
110 return old_selected != *selector_;
111 }
112
113 bool OnMouseEvent(Event event) override {
114 if (ContainerBase::OnMouseEvent(event))
115 return true;
116
117 if (event.mouse().button != Mouse::WheelUp &&
118 event.mouse().button != Mouse::WheelDown) {
119 return false;
120 }
121
122 if (!box_.Contain(event.mouse().x, event.mouse().y))
123 return false;
124
125 if (event.mouse().button == Mouse::WheelUp)
126 MoveSelector(-1);
127 if (event.mouse().button == Mouse::WheelDown)
128 MoveSelector(+1);
129 *selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_));
130
131 return true;
132 }
133
134 Box box_;
135};
136
137class HorizontalContainer : public ContainerBase {
138 public:
139 using ContainerBase::ContainerBase;
140
141 Element Render() override {
142 Elements elements;
143 for (auto& it : children_)
144 elements.push_back(it->Render());
145 if (elements.size() == 0)
146 return text("Empty container");
147 return hbox(std::move(elements));
148 }
149
150 bool EventHandler(Event event) override {
151 int old_selected = *selector_;
152 if (event == Event::ArrowLeft || event == Event::Character('h'))
153 MoveSelector(-1);
154 if (event == Event::ArrowRight || event == Event::Character('l'))
155 MoveSelector(+1);
156 if (event == Event::Tab && children_.size())
157 MoveSelectorWrap(+1);
158 if (event == Event::TabReverse && children_.size())
159 MoveSelectorWrap(-1);
160
161 *selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_));
162 return old_selected != *selector_;
163 }
164};
165
166class TabContainer : public ContainerBase {
167 public:
168 using ContainerBase::ContainerBase;
169
170 Element Render() override {
171 Component active_child = ActiveChild();
172 if (active_child)
173 return active_child->Render();
174 return text("Empty container");
175 }
176
177 bool OnMouseEvent(Event event) override {
178 return ActiveChild()->OnEvent(event);
179 }
180};
181
182namespace Container {
183
184/// @brief A list of components, drawn one by one vertically and navigated
185/// vertically using up/down arrow key or 'j'/'k' keys.
186/// @param children the list of components.
187/// @ingroup component
188/// @see ContainerBase
189///
190/// ### Example
191///
192/// ```cpp
193/// auto container = Container::Vertical({
194/// children_1,
195/// children_2,
196/// children_3,
197/// children_4,
198/// });
199/// ```
201 return Vertical(std::move(children), nullptr);
202}
203
204/// @brief A list of components, drawn one by one vertically and navigated
205/// vertically using up/down arrow key or 'j'/'k' keys.
206/// This is useful for implementing a Menu for instance.
207/// @param children the list of components.
208/// @param selector A reference to the index of the selected children.
209/// @ingroup component
210/// @see ContainerBase
211///
212/// ### Example
213///
214/// ```cpp
215/// auto container = Container::Vertical({
216/// children_1,
217/// children_2,
218/// children_3,
219/// children_4,
220/// });
221/// ```
222Component Vertical(Components children, int* selector) {
223 return std::make_shared<VerticalContainer>(std::move(children), selector);
224}
225
226/// @brief A list of components, drawn one by one horizontally and navigated
227/// horizontally using left/right arrow key or 'h'/'l' keys.
228/// @param children the list of components.
229/// @ingroup component
230/// @see ContainerBase
231///
232/// ### Example
233///
234/// ```cpp
235/// int selected_children = 2;
236/// auto container = Container::Horizontal({
237/// children_1,
238/// children_2,
239/// children_3,
240/// children_4,
241/// }, &selected_children);
242/// ```
244 return Horizontal(std::move(children), nullptr);
245}
246
247/// @brief A list of components, drawn one by one horizontally and navigated
248/// horizontally using left/right arrow key or 'h'/'l' keys.
249/// @param children the list of components.
250/// @param selector A reference to the index of the selected children.
251/// @ingroup component
252/// @see ContainerBase
253///
254/// ### Example
255///
256/// ```cpp
257/// int selected_children = 2;
258/// auto container = Container::Horizontal({
259/// children_1,
260/// children_2,
261/// children_3,
262/// children_4,
263/// }, selected_children);
264/// ```
265Component Horizontal(Components children, int* selector) {
266 return std::make_shared<HorizontalContainer>(std::move(children), selector);
267}
268
269/// @brief A list of components, where only one is drawn and interacted with at
270/// a time. The |selector| gives the index of the selected component. This is
271/// useful to implement tabs.
272/// @param children The list of components.
273/// @param selector The index of the drawn children.
274/// @ingroup component
275/// @see ContainerBase
276///
277/// ### Example
278///
279/// ```cpp
280/// int tab_drawn = 0;
281/// auto container = Container::Tab({
282/// children_1,
283/// children_2,
284/// children_3,
285/// children_4,
286/// }, &tab_drawn);
287/// ```
288Component Tab(Components children, int* selector) {
289 return std::make_shared<TabContainer>(std::move(children), selector);
290}
291
292} // namespace Container
293
294} // namespace ftxui
295
296// Copyright 2020 Arthur Sonzogni. All rights reserved.
297// Use of this source code is governed by the MIT license that can be found in
298// the LICENSE file.
virtual bool Focusable() const
Return true when the component contains focusable elements. The non focusable Components will be skip...
bool Focused() const
Returns if the elements if focused by the user. True when the ComponentBase is focused by the user....
void Add(Component children)
Add a child. @param child The child to be attached.
Definition component.cpp:49
virtual bool OnEvent(Event)
Called in response to an event.
Definition component.cpp:95
Component Horizontal(Components children)
A list of components, drawn one by one horizontally and navigated horizontally using left/right arrow...
Component Vertical(Components children)
A list of components, drawn one by one vertically and navigated vertically using up/down arrow key or...
Component Tab(Components children, int *selector)
A list of components, where only one is drawn and interacted with at a time. The |selector| gives the...
std::shared_ptr< Node > Element
Definition elements.hpp:15
std::vector< Component > Components
Element hbox(Elements)
A container displaying elements horizontally one by one.
Definition hbox.cpp:76
std::vector< Element > Elements
Definition elements.hpp:16
Element text(std::wstring text)
Display a piece of unicode text.
Definition text.cpp:106
Decorator reflect(Box &box)
Definition reflect.cpp:39
std::shared_ptr< ComponentBase > Component
Element vbox(Elements)
A container displaying elements vertically one by one.
Definition vbox.cpp:77
bool Contain(int x, int y)
Definition box.cpp:20
static const Event TabReverse
Definition event.hpp:46
static const Event ArrowUp
Definition event.hpp:37
static const Event Tab
Definition event.hpp:45
static const Event ArrowDown
Definition event.hpp:38
static const Event ArrowLeft
Definition event.hpp:35
static const Event ArrowRight
Definition event.hpp:36