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)
Une liste horizontale d'éléments. L'utilisateur peut naviguer à travers eux.
Component Menu(ConstStringListRef entries, int *selected_, MenuOption options=MenuOption::Vertical())
Une liste de texte. L'élément focalisé est sélectionné.
Component MenuEntry(ConstStringRef label, MenuEntryOption options={})
Une entrée de menu spécifique. Elles peuvent être placées dans un Container::Vertical pour former un ...
Element text(std::string_view text)
Affiche un morceau de texte unicode encodé en UTF8.
Element xflex(Element)
Développer/Réduire si possible/nécessaire sur l'axe X.
Element nothing(Element element)
Une décoration qui ne fait absolument rien.
Element bold(Element child)
Utilise une police en gras, pour les éléments avec plus d'emphase.
Element yflex(Element)
Développer/Réduire si possible/nécessaire sur l'axe Y.
Direction
Direction est une énumération qui représente les quatre directions cardinales.
Element inverted(Element child)
Ajoute un filtre qui inversera les couleurs de premier plan et d'arrière-plan.
Element focus(Element child)
Définit l'élément child comme étant celui qui est focalisé parmi ses frères.
Element bgcolor(Color color, Element child)
Définit la couleur d'arrière-plan d'un élément.
Element color(Color color, Element child)
Définit la couleur de premier plan d'un élément.
Element vbox(Elements children)
Un conteneur affichant les éléments verticalement un par un.
float Linear(float p)
Modélisé d'après la ligne y = x.
constexpr const T & clamp(const T &v, const T &lo, const T &hi)
L'espace de noms FTXUI ftxui::
Element separatorVSelector(float up, float down, Color unselected_color, Color selected_color)
Dessine une barre verticale, avec la zone entre le haut et le bas colorée différemment.
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)
Dessine une barre horizontale, avec la zone entre la gauche et la droite colorée différemment.
Element hbox(Elements children)
Un conteneur affichant les éléments horizontalement un par un.
std::vector< Element > Elements
std::function< Element(Element)> Decorator
Decorator reflect(Box &box)
std::shared_ptr< ComponentBase > Component