19class ContainerBase :
public ComponentBase {
21 ContainerBase(
Components children,
int* selector)
22 : selector_(selector ? selector : &selected_) {
24 Add(std::move(child));
29 bool OnEvent(Event event)
override {
30 if (event.is_mouse()) {
31 return OnMouseEvent(event);
38 if (ActiveChild() && ActiveChild()->OnEvent(event)) {
42 return EventHandler(event);
54 for (
size_t i = 0; i <
children_.size(); ++i) {
55 if (children_[i].get() == child) {
56 *selector_ =
static_cast<int>(i);
64 virtual bool EventHandler(Event ) {
return false; }
66 virtual bool OnMouseEvent(Event event) {
71 int* selector_ =
nullptr;
73 void MoveSelector(
int dir) {
74 for (
int i = *selector_ + dir; i >= 0 && i < int(
children_.size());
83 void MoveSelectorWrap(
int dir) {
87 for (
size_t offset = 1; offset <
children_.size(); ++offset) {
98class VerticalContainer :
public ContainerBase {
100 using ContainerBase::ContainerBase;
105 for (
auto& it : children_) {
106 elements.push_back(it->Render());
108 if (elements.empty()) {
114 bool EventHandler(Event event)
override {
115 const int old_selected = *selector_;
123 for (
int i = 0; i < box_.y_max - box_.y_min; ++i) {
128 for (
int i = 0; i < box_.y_max - box_.y_min; ++i) {
133 for (
size_t i = 0; i < children_.size(); ++i) {
138 for (
size_t i = 0; i < children_.size(); ++i) {
143 MoveSelectorWrap(+1);
146 MoveSelectorWrap(-1);
149 *selector_ = std::max(0, std::min(
int(children_.size()) - 1, *selector_));
150 return old_selected != *selector_;
153 bool OnMouseEvent(Event event)
override {
154 if (ContainerBase::OnMouseEvent(event)) {
163 if (!box_.Contain(event.mouse().x, event.mouse().y)) {
173 *selector_ = std::max(0, std::min(
int(children_.size()) - 1, *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_;
206 MoveSelectorWrap(+1);
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()) {
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);
340 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));
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.
void SetActiveChild(Component child)
Make the |child| to be the "active" one.
virtual bool OnEvent(Event)
Called in response to an event.
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 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...
std::shared_ptr< Node > Element
std::shared_ptr< ComponentBase > Component
std::vector< Component > Components
Element hbox(Elements)
A container displaying elements horizontally one by one.
Element text(std::wstring text)
Display a piece of unicode text.
std::vector< Element > Elements
Element dbox(Elements)
Stack several element on top of each other.
Decorator reflect(Box &box)
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
Element vbox(Elements)
A container displaying elements vertically one by one.
static const Event TabReverse
static const Event PageUp
static Event Character(std::string)
An event corresponding to a given typed character.
static const Event ArrowUp
static const Event ArrowDown
static const Event PageDown
static const Event ArrowLeft
static const Event ArrowRight