18class ContainerBase :
public ComponentBase {
20 ContainerBase(
Components children,
int* selector)
23 Add(std::move(child));
28 bool OnEvent(Event event)
override {
29 if (event.is_mouse()) {
30 return OnMouseEvent(event);
37 if (ActiveChild() && ActiveChild()->OnEvent(event)) {
41 return EventHandler(event);
45 if (children().empty()) {
49 return children()[
static_cast<size_t>(*selector_) % children().size()];
52 void SetActiveChild(ComponentBase* child)
override {
53 for (
size_t i = 0; i < children().size(); ++i) {
54 if (children()[i].get() == child) {
55 *selector_ =
static_cast<int>(i);
63 virtual bool EventHandler(Event ) {
return false; }
65 virtual bool OnMouseEvent(Event event) {
66 return ComponentBase::OnEvent(std::move(event));
70 int* selector_ =
nullptr;
72 void EnsureFocusableSelection() {
73 if (!children().empty() && !ActiveChild()->Focusable()) {
78 void MoveSelector(
int dir) {
79 for (
int i = *selector_ + dir; i >= 0 && i < int(children().
size());
81 if (children()[i]->Focusable()) {
88 void MoveSelectorWrap(
int dir) {
89 if (children().empty()) {
92 for (
size_t offset = 1; offset < children().size(); ++offset) {
94 (*selector_ + offset * dir + children().size()) % children().size();
95 if (children()[i]->Focusable()) {
103class VerticalContainer :
public ContainerBase {
105 VerticalContainer(
Components children,
int* selector)
106 : ContainerBase(std::move(children),
selector) {
107 EnsureFocusableSelection();
111 EnsureFocusableSelection();
113 elements.reserve(children().
size());
114 for (
auto& it : children()) {
115 elements.push_back(it->Render());
117 if (elements.empty()) {
123 bool EventHandler(Event event)
override {
124 const int old_selected = *selector_;
125 if (event == Event::ArrowUp || event == Event::Character(
'k')) {
128 if (event == Event::ArrowDown || event == Event::Character(
'j')) {
131 if (event == Event::PageUp) {
132 for (
int i = 0; i < box_.y_max - box_.y_min; ++i) {
136 if (event == Event::PageDown) {
137 for (
int i = 0; i < box_.y_max - box_.y_min; ++i) {
141 if (event == Event::Home) {
142 for (
size_t i = 0; i < children().size(); ++i) {
146 if (event == Event::End) {
147 for (
size_t i = 0; i < children().size(); ++i) {
151 if (event == Event::Tab) {
152 MoveSelectorWrap(+1);
154 if (event == Event::TabReverse) {
155 MoveSelectorWrap(-1);
158 *selector_ = std::max(0, std::min(
int(children().
size()) - 1, *selector_));
159 return old_selected != *selector_;
162 bool OnMouseEvent(Event event)
override {
163 if (ContainerBase::OnMouseEvent(event)) {
167 if (event.mouse().button != Mouse::WheelUp &&
168 event.mouse().button != Mouse::WheelDown) {
172 if (!box_.Contain(event.mouse().x, event.mouse().y)) {
176 const int old_selected = *selector_;
177 if (event.mouse().button == Mouse::WheelUp) {
180 if (event.mouse().button == Mouse::WheelDown) {
183 *selector_ = std::max(0, std::min(
int(children().
size()) - 1, *selector_));
185 return old_selected != *selector_;
191class HorizontalContainer :
public ContainerBase {
193 HorizontalContainer(
Components children,
int* selector)
194 : ContainerBase(std::move(children),
selector) {
195 EnsureFocusableSelection();
199 EnsureFocusableSelection();
201 elements.reserve(children().
size());
202 for (
auto& it : children()) {
203 elements.push_back(it->Render());
205 if (elements.empty()) {
206 return text(
"Empty container");
208 return hbox(std::move(elements));
211 bool EventHandler(Event event)
override {
212 const int old_selected = *selector_;
213 if (event == Event::ArrowLeft || event == Event::Character(
'h')) {
216 if (event == Event::ArrowRight || event == Event::Character(
'l')) {
219 if (event == Event::Tab) {
220 MoveSelectorWrap(+1);
222 if (event == Event::TabReverse) {
223 MoveSelectorWrap(-1);
226 *selector_ = std::max(0, std::min(
int(children().
size()) - 1, *selector_));
227 return old_selected != *selector_;
231class TabContainer :
public ContainerBase {
233 using ContainerBase::ContainerBase;
236 const Component active_child = ActiveChild();
238 return active_child->Render();
240 return text(
"Empty container");
243 bool Focusable()
const override {
244 if (children().empty()) {
247 return children()[size_t(*selector_) % children().size()]->Focusable();
250 bool OnMouseEvent(Event event)
override {
251 return ActiveChild() && ActiveChild()->OnEvent(event);
255class StackedContainer :
public ContainerBase {
257 explicit StackedContainer(
Components children)
258 : ContainerBase(std::move(children), nullptr) {}
263 for (
auto& child : children()) {
264 elements.push_back(child->Render());
267 std::reverse(elements.begin(), elements.end());
268 return dbox(std::move(elements));
271 bool Focusable() const final {
272 for (
const auto& child : children()) {
273 if (child->Focusable()) {
281 if (children().empty()) {
284 return children()[0];
287 void SetActiveChild(ComponentBase* child)
final {
288 if (children().empty()) {
295 std::find_if(children().begin(), children().end(),
296 [child](
const Component& c) {
return c.get() == child; });
297 if (it == children().end()) {
300 std::rotate(children().begin(), it, it + 1);
303 bool OnEvent(Event event)
final {
304 for (
auto& child : children()) {
305 if (child->OnEvent(event)) {
332 return Vertical(std::move(children),
nullptr);
355 return std::make_shared<VerticalContainer>(std::move(children),
selector);
375 return Horizontal(std::move(children),
nullptr);
397 return std::make_shared<HorizontalContainer>(std::move(children),
selector);
420 return std::make_shared<TabContainer>(std::move(children),
selector);
447 return std::make_shared<StackedContainer>(std::move(children));
Component Horizontal(Components children, int *selector)
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 Stacked(Components children)
A list of components to be stacked on top of each other. Events are propagated to the first component...
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...
Element text(std::string_view text)
Display a piece of UTF8 encoded unicode text.
Decorator size(WidthOrHeight direction, Constraint constraint, int value)
Apply a constraint on the size of an element.
Element dbox(Elements children_)
Stack several element on top of each other.
Element vbox(Elements children)
A container displaying elements vertically one by one.
The FTXUI ftxui::Container:: namespace.
The FTXUI ftxui:: namespace.
std::shared_ptr< Node > Element
std::vector< Component > Components
Element hbox(Elements children)
A container displaying elements horizontally one by one.
std::vector< Element > Elements
Decorator reflect(Box &box)
std::shared_ptr< ComponentBase > Component