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 MoveSelector(
int dir) {
73 for (
int i = *selector_ + dir; i >= 0 && i < int(children().
size());
75 if (children()[i]->Focusable()) {
82 void MoveSelectorWrap(
int dir) {
83 if (children().empty()) {
86 for (
size_t offset = 1; offset < children().size(); ++offset) {
88 (*selector_ + offset * dir + children().size()) % children().size();
89 if (children()[i]->Focusable()) {
97class VerticalContainer :
public ContainerBase {
99 using ContainerBase::ContainerBase;
103 elements.reserve(children().
size());
104 for (
auto& it : children()) {
105 elements.push_back(it->Render());
107 if (elements.empty()) {
113 bool EventHandler(Event event)
override {
114 const int old_selected = *selector_;
115 if (event == Event::ArrowUp || event == Event::Character(
'k')) {
118 if (event == Event::ArrowDown || event == Event::Character(
'j')) {
121 if (event == Event::PageUp) {
122 for (
int i = 0; i < box_.y_max - box_.y_min; ++i) {
126 if (event == Event::PageDown) {
127 for (
int i = 0; i < box_.y_max - box_.y_min; ++i) {
131 if (event == Event::Home) {
132 for (
size_t i = 0; i < children().size(); ++i) {
136 if (event == Event::End) {
137 for (
size_t i = 0; i < children().size(); ++i) {
141 if (event == Event::Tab) {
142 MoveSelectorWrap(+1);
144 if (event == Event::TabReverse) {
145 MoveSelectorWrap(-1);
148 *selector_ = std::max(0, std::min(
int(children().
size()) - 1, *selector_));
149 return old_selected != *selector_;
152 bool OnMouseEvent(Event event)
override {
153 if (ContainerBase::OnMouseEvent(event)) {
157 if (event.mouse().button != Mouse::WheelUp &&
158 event.mouse().button != Mouse::WheelDown) {
162 if (!box_.Contain(event.mouse().x, event.mouse().y)) {
166 const int old_selected = *selector_;
167 if (event.mouse().button == Mouse::WheelUp) {
170 if (event.mouse().button == Mouse::WheelDown) {
173 *selector_ = std::max(0, std::min(
int(children().
size()) - 1, *selector_));
175 return old_selected != *selector_;
181class HorizontalContainer :
public ContainerBase {
183 using ContainerBase::ContainerBase;
187 elements.reserve(children().
size());
188 for (
auto& it : children()) {
189 elements.push_back(it->Render());
191 if (elements.empty()) {
192 return text(
"Empty container");
194 return hbox(std::move(elements));
197 bool EventHandler(Event event)
override {
198 const int old_selected = *selector_;
199 if (event == Event::ArrowLeft || event == Event::Character(
'h')) {
202 if (event == Event::ArrowRight || event == Event::Character(
'l')) {
205 if (event == Event::Tab) {
206 MoveSelectorWrap(+1);
208 if (event == Event::TabReverse) {
209 MoveSelectorWrap(-1);
212 *selector_ = std::max(0, std::min(
int(children().
size()) - 1, *selector_));
213 return old_selected != *selector_;
217class TabContainer :
public ContainerBase {
219 using ContainerBase::ContainerBase;
222 const Component active_child = ActiveChild();
224 return active_child->Render();
226 return text(
"Empty container");
229 bool Focusable()
const override {
230 if (children().empty()) {
233 return children()[size_t(*selector_) % children().size()]->Focusable();
236 bool OnMouseEvent(Event event)
override {
237 return ActiveChild() && ActiveChild()->OnEvent(event);
241class StackedContainer :
public ContainerBase {
243 explicit StackedContainer(
Components children)
244 : ContainerBase(std::move(children), nullptr) {}
249 for (
auto& child : children()) {
250 elements.push_back(child->Render());
253 std::reverse(elements.begin(), elements.end());
254 return dbox(std::move(elements));
257 bool Focusable() const final {
258 for (
const auto& child : children()) {
259 if (child->Focusable()) {
267 if (children().empty()) {
270 return children()[0];
273 void SetActiveChild(ComponentBase* child)
final {
274 if (children().empty()) {
281 std::find_if(children().begin(), children().end(),
282 [child](
const Component& c) {
return c.get() == child; });
283 if (it == children().end()) {
286 std::rotate(children().begin(), it, it + 1);
289 bool OnEvent(Event event)
final {
290 for (
auto& child : children()) {
291 if (child->OnEvent(event)) {
318 return Vertical(std::move(children),
nullptr);
341 return std::make_shared<VerticalContainer>(std::move(children),
selector);
361 return Horizontal(std::move(children),
nullptr);
383 return std::make_shared<HorizontalContainer>(std::move(children),
selector);
406 return std::make_shared<TabContainer>(std::move(children),
selector);
433 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