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)
Une liste de composants, dessinés un par un horizontalement et navigués horizontalement en utilisant ...
Component Vertical(Components children)
Une liste de composants, dessinés un par un verticalement et navigués verticalement en utilisant les ...
Component Stacked(Components children)
Une liste de composants à empiler les uns sur les autres. Les événements sont propagés au premier com...
Component Tab(Components children, int *selector)
Une liste de composants, où un seul est dessiné et interagit avec à la fois. Le |selector| donne l'in...
Element text(std::string_view text)
Affiche un morceau de texte unicode encodé en UTF8.
Decorator size(WidthOrHeight direction, Constraint constraint, int value)
Applique une contrainte sur la taille d'un élément.
Element dbox(Elements children_)
Empile plusieurs éléments les uns sur les autres.
Element vbox(Elements children)
Un conteneur affichant les éléments verticalement un par un.
L'espace de noms FTXUI ftxui::Container::
L'espace de noms FTXUI ftxui::
std::shared_ptr< Node > Element
std::vector< Component > Components
Element hbox(Elements children)
Un conteneur affichant les éléments horizontalement un par un.
std::vector< Element > Elements
Decorator reflect(Box &box)
std::shared_ptr< ComponentBase > Component