18 class ContainerBase :
public ComponentBase {
20 ContainerBase(
Components children,
int* selector)
21 : selector_(selector ? selector : &selected_) {
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);
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) {
70 int* selector_ =
nullptr;
72 void MoveSelector(
int dir) {
73 for (
int i = *selector_ + dir; i >= 0 && i < int(
children_.size());
82 void MoveSelectorWrap(
int dir) {
86 for (
size_t offset = 1; offset <
children_.size(); ++offset) {
97 class VerticalContainer :
public ContainerBase {
99 using ContainerBase::ContainerBase;
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_;
122 for (
int i = 0; i < box_.y_max - box_.y_min; ++i) {
127 for (
int i = 0; i < box_.y_max - box_.y_min; ++i) {
132 for (
size_t i = 0; i < children_.size(); ++i) {
137 for (
size_t i = 0; i < children_.size(); ++i) {
142 MoveSelectorWrap(+1);
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)) {
162 if (!box_.Contain(event.mouse().x, event.mouse().y)) {
172 *selector_ = std::max(0, std::min(
int(children_.size()) - 1, *selector_));
180 class HorizontalContainer :
public ContainerBase {
182 using ContainerBase::ContainerBase;
186 elements.reserve(children_.size());
187 for (
auto& it : children_) {
188 elements.push_back(it->Render());
190 if (elements.empty()) {
191 return text(
"Empty container");
193 return hbox(std::move(elements));
196 bool EventHandler(Event event)
override {
197 const int old_selected = *selector_;
205 MoveSelectorWrap(+1);
208 MoveSelectorWrap(-1);
211 *selector_ = std::max(0, std::min(
int(children_.size()) - 1, *selector_));
212 return old_selected != *selector_;
216 class TabContainer :
public ContainerBase {
218 using ContainerBase::ContainerBase;
221 const Component active_child = ActiveChild();
223 return active_child->Render();
225 return text(
"Empty container");
228 bool Focusable()
const override {
229 if (children_.empty()) {
232 return children_[size_t(*selector_) % children_.size()]->Focusable();
235 bool OnMouseEvent(Event event)
override {
236 return ActiveChild() && ActiveChild()->OnEvent(event);
240 class StackedContainer :
public ContainerBase {
242 explicit StackedContainer(
Components children)
243 : ContainerBase(std::move(children), nullptr) {}
248 for (
auto& child : children_) {
249 elements.push_back(child->Render());
252 std::reverse(elements.begin(), elements.end());
253 return dbox(std::move(elements));
256 bool Focusable() const final {
257 for (
const auto& child : children_) {
258 if (child->Focusable()) {
266 if (children_.empty()) {
273 if (children_.empty()) {
280 std::find_if(children_.begin(), children_.end(),
281 [child](
const Component& c) { return c.get() == child; });
282 if (it == children_.end()) {
285 std::rotate(children_.begin(), it, it + 1);
288 bool OnEvent(Event event)
final {
289 for (
auto& child : children_) {
290 if (child->OnEvent(event)) {
298 namespace Container {
317 return Vertical(std::move(children),
nullptr);
339 return std::make_shared<VerticalContainer>(std::move(children), selector);
360 return Horizontal(std::move(children),
nullptr);
382 return std::make_shared<HorizontalContainer>(std::move(children), selector);
405 return std::make_shared<TabContainer>(std::move(children), selector);
432 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