29Element DefaultOptionTransform(
const EntryState& state) {
30 std::string label = (state.active ?
"> " :
" ") + state.label;
69class MenuBase :
public ComponentBase,
public MenuOption {
71 explicit MenuBase(
const MenuOption& option) : MenuOption(option) {
72 focused_entry() = selected();
75 bool IsHorizontal() {
return ftxui::IsHorizontal(
direction); }
76 void OnChange() { App::PostEventOrExecute(on_change); }
78 void OnEnter() { App::PostEventOrExecute(on_enter); }
81 if (selected() != selected_previous_) {
84 boxes_.resize(size());
85 selected() =
util::clamp(selected(), 0, size() - 1);
86 selected_previous_ =
util::clamp(selected_previous_, 0, size() - 1);
87 selected_focus_ =
util::clamp(selected_focus_, 0, size() - 1);
88 focused_entry() =
util::clamp(focused_entry(), 0, size() - 1);
91 void OnAnimation(animation::Params& params)
override {
92 animator_first_.OnAnimation(params);
93 animator_second_.OnAnimation(params);
94 for (
auto& animator : animator_background_) {
95 animator.OnAnimation(params);
97 for (
auto& animator : animator_foreground_) {
98 animator.OnAnimation(params);
104 UpdateAnimationTarget();
107 const bool is_menu_focused = Focused();
108 if (elements_prefix) {
109 elements.push_back(elements_prefix());
111 elements.reserve(size());
112 for (
int i = 0; i < size(); ++i) {
113 if (i != 0 && elements_infix) {
114 elements.push_back(elements_infix());
116 const bool is_focused = (focused_entry() == i) && is_menu_focused;
117 const bool is_selected = (selected() == i);
119 const EntryState state = {
120 std::string(entries[i]),
false, is_selected, is_focused, i,
123 Element element = (entries_option.transform ? entries_option.transform
124 : DefaultOptionTransform)
126 if (selected_focus_ == i) {
129 element |= AnimatedColorStyle(i);
133 if (elements_postfix) {
134 elements.push_back(elements_postfix());
138 std::reverse(elements.begin(), elements.end());
142 IsHorizontal() ?
hbox(std::move(elements)) : vbox(std::move(elements));
144 if (!underline.enabled) {
145 return bar | reflect(box_);
148 if (IsHorizontal()) {
152 underline.color_active,
153 underline.color_inactive),
159 underline.color_active,
160 underline.color_inactive),
167 void SelectedTakeFocus() {
168 selected_previous_ = selected();
169 selected_focus_ = selected();
229 bool OnEvent(Event event)
override {
231 if (!CaptureMouse(event)) {
235 if (event.is_mouse()) {
236 return OnMouseEvent(event);
240 const int old_selected = selected();
241 if (event == Event::ArrowUp || event == Event::Character(
'k')) {
244 if (event == Event::ArrowDown || event == Event::Character(
'j')) {
247 if (event == Event::ArrowLeft || event == Event::Character(
'h')) {
250 if (event == Event::ArrowRight || event == Event::Character(
'l')) {
253 if (event == Event::PageUp) {
254 selected() -= box_.y_max - box_.y_min;
256 if (event == Event::PageDown) {
257 selected() += box_.y_max - box_.y_min;
259 if (event == Event::Home) {
262 if (event == Event::End) {
263 selected() = size() - 1;
265 if (event == Event::Tab && size()) {
266 selected() = (selected() + 1) % size();
268 if (event == Event::TabReverse && size()) {
269 selected() = (selected() + size() - 1) % size();
272 selected() =
util::clamp(selected(), 0, size() - 1);
274 if (selected() != old_selected) {
275 focused_entry() = selected();
282 if (event == Event::Return) {
290 bool OnMouseEvent(Event event) {
291 if (event.mouse().button == Mouse::WheelDown ||
292 event.mouse().button == Mouse::WheelUp) {
293 return OnMouseWheel(event);
296 if (event.mouse().button != Mouse::None &&
297 event.mouse().button != Mouse::Left) {
300 if (!CaptureMouse(event)) {
303 for (
int i = 0; i < size(); ++i) {
304 if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) {
311 if (event.mouse().button == Mouse::Left &&
312 event.mouse().motion == Mouse::Pressed) {
313 if (selected() != i) {
315 selected_previous_ = selected();
324 bool OnMouseWheel(Event event) {
325 if (!box_.Contain(event.mouse().x, event.mouse().y)) {
328 const int old_selected = selected();
330 if (event.mouse().button == Mouse::WheelUp) {
333 if (event.mouse().button == Mouse::WheelDown) {
337 selected() =
util::clamp(selected(), 0, size() - 1);
339 if (selected() != old_selected) {
346 void UpdateAnimationTarget() {
348 UpdateUnderlineTarget();
351 void UpdateColorTarget() {
352 if (size() !=
int(animation_background_.size())) {
353 animation_background_.resize(size());
354 animation_foreground_.resize(size());
355 animator_background_.clear();
356 animator_foreground_.clear();
358 const int len = size();
359 animator_background_.reserve(len);
360 animator_foreground_.reserve(len);
361 for (
int i = 0; i < len; ++i) {
362 animation_background_[i] = 0.F;
363 animation_foreground_[i] = 0.F;
364 animator_background_.emplace_back(&animation_background_[i], 0.F,
365 std::chrono::milliseconds(0),
367 animator_foreground_.emplace_back(&animation_foreground_[i], 0.F,
368 std::chrono::milliseconds(0),
373 const bool is_menu_focused = Focused();
374 for (
int i = 0; i < size(); ++i) {
375 const bool is_focused = (focused_entry() == i) && is_menu_focused;
376 const bool is_selected = (selected() == i);
377 float target = is_selected ? 1.F : is_focused ? 0.5F : 0.F;
378 if (animator_background_[i].to() != target) {
379 animator_background_[i] = animation::Animator(
380 &animation_background_[i], target,
381 entries_option.animated_colors.background.duration,
382 entries_option.animated_colors.background.function);
383 animator_foreground_[i] = animation::Animator(
384 &animation_foreground_[i], target,
385 entries_option.animated_colors.foreground.duration,
386 entries_option.animated_colors.foreground.function);
393 if (entries_option.animated_colors.foreground.enabled) {
394 style = style |
color(Color::Interpolate(
395 animation_foreground_[i],
396 entries_option.animated_colors.foreground.inactive,
397 entries_option.animated_colors.foreground.active));
400 if (entries_option.animated_colors.background.enabled) {
401 style = style |
bgcolor(Color::Interpolate(
402 animation_background_[i],
403 entries_option.animated_colors.background.inactive,
404 entries_option.animated_colors.background.active));
409 void UpdateUnderlineTarget() {
410 if (!underline.enabled) {
414 if (FirstTarget() == animator_first_.to() &&
415 SecondTarget() == animator_second_.to()) {
419 if (FirstTarget() >= animator_first_.to()) {
420 animator_first_ = animation::Animator(
421 &first_, FirstTarget(), underline.follower_duration,
422 underline.follower_function, underline.follower_delay);
424 animator_second_ = animation::Animator(
425 &second_, SecondTarget(), underline.leader_duration,
426 underline.leader_function, underline.leader_delay);
428 animator_first_ = animation::Animator(
429 &first_, FirstTarget(), underline.leader_duration,
430 underline.leader_function, underline.leader_delay);
432 animator_second_ = animation::Animator(
433 &second_, SecondTarget(), underline.follower_duration,
434 underline.follower_function, underline.follower_delay);
438 bool Focusable() const final {
return entries.size(); }
439 int size()
const {
return int(entries.size()); }
440 float FirstTarget() {
441 if (boxes_.empty()) {
444 const int value = IsHorizontal() ? boxes_[selected()].x_min - box_.x_min
445 : boxes_[selected()].y_min - box_.y_min;
448 float SecondTarget() {
449 if (boxes_.empty()) {
452 const int value = IsHorizontal() ? boxes_[selected()].x_max - box_.x_min
453 : boxes_[selected()].y_max - box_.y_min;
458 int selected_previous_ = selected();
459 int selected_focus_ = selected();
462 std::vector<Box> boxes_;
468 animation::Animator animator_first_ = animation::Animator(&first_, 0.F);
469 animation::Animator animator_second_ = animation::Animator(&second_, 0.F);
470 std::vector<animation::Animator> animator_background_;
471 std::vector<animation::Animator> animator_foreground_;
472 std::vector<float> animation_background_;
473 std::vector<float> animation_foreground_;
536Component Menu(ConstStringListRef entries,
int* selected, MenuOption option) {
537 option.entries = std::move(entries);
538 option.selected = selected;
548 return Menu(std::move(entries), selected, MenuOption::Toggle());
578 option.label = std::move(label);
608 class Impl :
public ComponentBase,
public MenuEntryOption {
610 explicit Impl(MenuEntryOption option)
611 : MenuEntryOption(std::move(option)) {}
615 const bool is_focused = Focused();
616 UpdateAnimationTarget();
618 const EntryState state{
619 std::string(label()),
false, hovered_, is_focused, Index(),
622 Element element = (transform ? transform : DefaultOptionTransform)
629 return element | AnimatedColorStyle() | reflect(box_);
632 void UpdateAnimationTarget() {
633 const bool focused = Focused();
634 float target = focused ? 1.F : hovered_ ? 0.5F : 0.F;
635 if (target == animator_background_.to()) {
638 animator_background_ = animation::Animator(
639 &animation_background_, target, animated_colors.background.duration,
640 animated_colors.background.function);
641 animator_foreground_ = animation::Animator(
642 &animation_foreground_, target, animated_colors.foreground.duration,
643 animated_colors.foreground.function);
648 if (animated_colors.foreground.enabled) {
650 color(Color::Interpolate(animation_foreground_,
651 animated_colors.foreground.inactive,
652 animated_colors.foreground.active));
655 if (animated_colors.background.enabled) {
657 bgcolor(Color::Interpolate(animation_background_,
658 animated_colors.background.inactive,
659 animated_colors.background.active));
664 bool Focusable()
const override {
return true; }
665 bool OnEvent(Event event)
override {
666 if (!event.is_mouse()) {
670 hovered_ = box_.Contain(event.mouse().x, event.mouse().y);
676 if (event.mouse().button == Mouse::Left &&
677 event.mouse().motion == Mouse::Pressed) {
685 void OnAnimation(animation::Params& params)
override {
686 animator_background_.OnAnimation(params);
687 animator_foreground_.OnAnimation(params);
691 bool hovered_ =
false;
693 float animation_background_ = 0.F;
694 float animation_foreground_ = 0.F;
695 animation::Animator animator_background_ =
696 animation::Animator(&animation_background_, 0.F);
697 animation::Animator animator_foreground_ =
698 animation::Animator(&animation_foreground_, 0.F);
Component Toggle(ConstStringListRef entries, int *selected)
Una lista horizontal de elementos. El usuario puede navegar a través de ellos.
Component Menu(ConstStringListRef entries, int *selected_, MenuOption options=MenuOption::Vertical())
Una lista de texto. El elemento enfocado está seleccionado.
Component MenuEntry(ConstStringRef label, MenuEntryOption options={})
Una entrada de menú específica. Se pueden colocar en un Container::Vertical para formar un menú.
Element text(std::string_view text)
Muestra un fragmento de texto Unicode codificado en UTF8.
Element xflex(Element)
Expandir/Minimizar si es posible/necesario en el eje X.
Element nothing(Element element)
Una decoración que no hace absolutamente nada.
Element bold(Element child)
Utiliza una fuente en negrita, para elementos con más énfasis.
Element yflex(Element)
Expandir/Minimizar si es posible/necesario en el eje Y.
Direction
Direction es una enumeración que representa las cuatro cardinales direcciones.
Element inverted(Element child)
Agrega un filtro que invertirá los colores de primer plano y de fondo. colores.
Element focus(Element child)
Establece que child sea el elemento enfocado entre sus hermanos.
Element bgcolor(Color color, Element child)
Establece el color de fondo de un elemento.
Element color(Color color, Element child)
Establece el color de primer plano de un elemento.
Element vbox(Elements children)
Un contenedor que muestra elementos verticalmente uno por uno.
float Linear(float p)
Modelado según la línea y = x.
constexpr const T & clamp(const T &v, const T &lo, const T &hi)
El espacio de nombres ftxui:: de FTXUI.
Element separatorVSelector(float up, float down, Color unselected_color, Color selected_color)
Dibuja una barra vertical, con el área entre arriba/abajo coloreada de forma diferente.
std::shared_ptr< T > Make(Args &&... args)
std::shared_ptr< Node > Element
FTXUI_EXPORT(DOM) Element separatorCharacter(std Element separatorHSelector(float left, float right, Color unselected_color, Color selected_color)
Dibuja una barra horizontal, con el área entre izquierda/derecha coloreada de forma diferente.
Element hbox(Elements children)
Un contenedor que muestra elementos horizontalmente uno por uno.
std::vector< Element > Elements
std::function< Element(Element)> Decorator
Decorator reflect(Box &box)
std::shared_ptr< ComponentBase > Component