27Element DefaultOptionTransform(
const EntryState& state) {
28 std::string label = (state.active ?
"> " :
" ") + state.label;
67class MenuBase :
public ComponentBase {
69 MenuBase(ConstStringListRef entries,
int* selected, Ref<MenuOption> option)
70 : entries_(entries), selected_(selected), option_(std::move(option)) {}
72 bool IsHorizontal() {
return ftxui::IsHorizontal(option_->direction); }
74 if (option_->on_change) {
80 if (option_->on_enter) {
86 boxes_.resize(size());
87 *selected_ =
util::clamp(*selected_, 0, size() - 1);
88 focused_entry() =
util::clamp(focused_entry(), 0, size() - 1);
91 void OnAnimation(animation::Params& params)
override {
94 for (
auto& animator : animator_background_) {
95 animator.OnAnimation(params);
97 for (
auto& animator : animator_foreground_) {
98 animator.OnAnimation(params);
104 UpdateAnimationTarget();
107 bool is_menu_focused =
Focused();
108 if (option_->elements_prefix) {
109 elements.push_back(option_->elements_prefix());
111 for (
int i = 0; i < size(); ++i) {
112 if (i != 0 && option_->elements_infix) {
113 elements.push_back(option_->elements_infix());
115 bool is_focused = (focused_entry() == i) && is_menu_focused;
116 bool is_selected = (*selected_ == i);
118 auto focus_management = !is_selected ?
nothing
119 : is_menu_focused ?
focus
129 (option_->entries.transform ? option_->entries.transform
130 : DefaultOptionTransform)
132 elements.push_back(element | AnimatedColorStyle(i) |
reflect(boxes_[i]) |
135 if (option_->elements_postfix) {
136 elements.push_back(option_->elements_postfix());
139 if (IsInverted(option_->direction)) {
140 std::reverse(elements.begin(), elements.end());
144 IsHorizontal() ?
hbox(std::move(elements)) :
vbox(std::move(elements));
146 if (!option_->underline.enabled) {
147 return bar | reflect(box_);
150 if (IsHorizontal()) {
154 option_->underline.color_active,
155 option_->underline.color_inactive),
161 option_->underline.color_active,
162 option_->underline.color_inactive),
170 switch (option_->direction) {
184 switch (option_->direction) {
198 switch (option_->direction) {
212 switch (option_->direction) {
226 bool OnEvent(Event event)
override {
232 if (event.is_mouse()) {
233 return OnMouseEvent(event);
237 int old_selected = *selected_;
260 (*selected_) = size() - 1;
263 *selected_ = (*selected_ + 1) % size();
266 *selected_ = (*selected_ + size() - 1) % size();
269 *selected_ =
util::clamp(*selected_, 0, size() - 1);
271 if (*selected_ != old_selected) {
272 focused_entry() = *selected_;
286 bool OnMouseEvent(Event event) {
289 return OnMouseWheel(event);
299 for (
int i = 0; i < size(); ++i) {
300 if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) {
308 if (*selected_ != i) {
318 bool OnMouseWheel(Event event) {
319 if (!box_.
Contain(event.mouse().x, event.mouse().y)) {
322 int old_selected = *selected_;
331 *selected_ =
util::clamp(*selected_, 0, size() - 1);
333 if (*selected_ != old_selected) {
339 void UpdateAnimationTarget() {
341 UpdateUnderlineTarget();
344 void UpdateColorTarget() {
345 if (size() != (
int)animation_background_.size()) {
346 animation_background_.resize(size());
347 animation_foreground_.resize(size());
348 animator_background_.clear();
349 animator_foreground_.clear();
351 for (
int i = 0; i < size(); ++i) {
352 animation_background_[i] = 0.F;
353 animation_foreground_[i] = 0.F;
354 animator_background_.emplace_back(&animation_background_[i], 0.F,
355 std::chrono::milliseconds(0),
357 animator_foreground_.emplace_back(&animation_foreground_[i], 0.F,
358 std::chrono::milliseconds(0),
363 bool is_menu_focused =
Focused();
364 for (
int i = 0; i < size(); ++i) {
365 bool is_focused = (focused_entry() == i) && is_menu_focused;
366 bool is_selected = (*selected_ == i);
367 float target = is_selected ? 1.F : is_focused ? 0.5F : 0.F;
368 if (animator_background_[i].to() != target) {
369 animator_background_[i] = animation::Animator(
370 &animation_background_[i], target,
371 option_->entries.animated_colors.background.duration,
372 option_->entries.animated_colors.background.function);
373 animator_foreground_[i] = animation::Animator(
374 &animation_foreground_[i], target,
375 option_->entries.animated_colors.foreground.duration,
376 option_->entries.animated_colors.foreground.function);
383 if (option_->entries.animated_colors.foreground.enabled) {
385 animation_foreground_[i],
386 option_->entries.animated_colors.foreground.inactive,
387 option_->entries.animated_colors.foreground.active));
390 if (option_->entries.animated_colors.background.enabled) {
392 animation_background_[i],
393 option_->entries.animated_colors.background.inactive,
394 option_->entries.animated_colors.background.active));
399 void UpdateUnderlineTarget() {
400 if (!option_->underline.enabled) {
404 if (FirstTarget() == animator_first_.
to() &&
405 SecondTarget() == animator_second_.
to()) {
409 if (FirstTarget() >= animator_first_.
to()) {
410 animator_first_ = animation::Animator(
411 &first_, FirstTarget(), option_->underline.follower_duration,
412 option_->underline.follower_function,
413 option_->underline.follower_delay);
415 animator_second_ = animation::Animator(
416 &second_, SecondTarget(), option_->underline.leader_duration,
417 option_->underline.leader_function, option_->underline.leader_delay);
419 animator_first_ = animation::Animator(
420 &first_, FirstTarget(), option_->underline.leader_duration,
421 option_->underline.leader_function, option_->underline.leader_delay);
423 animator_second_ = animation::Animator(
424 &second_, SecondTarget(), option_->underline.follower_duration,
425 option_->underline.follower_function,
426 option_->underline.follower_delay);
430 bool Focusable() const final {
return entries_.
size(); }
431 int& focused_entry() {
return option_->focused_entry(); }
432 int size()
const {
return int(entries_.
size()); }
433 float FirstTarget() {
434 if (boxes_.empty()) {
437 int value = IsHorizontal() ? boxes_[*selected_].x_min - box_.
x_min
438 : boxes_[*selected_].y_min - box_.
y_min;
441 float SecondTarget() {
442 if (boxes_.empty()) {
445 int value = IsHorizontal() ? boxes_[*selected_].x_max - box_.
x_min
446 : boxes_[*selected_].y_max - box_.
y_min;
451 ConstStringListRef entries_;
452 int* selected_ =
nullptr;
453 Ref<MenuOption> option_;
455 std::vector<Box> boxes_;
460 animation::Animator animator_first_ = animation::Animator(&first_, 0.F);
461 animation::Animator animator_second_ = animation::Animator(&second_, 0.F);
463 std::vector<animation::Animator> animator_background_;
464 std::vector<animation::Animator> animator_foreground_;
465 std::vector<float> animation_background_;
466 std::vector<float> animation_foreground_;
541 : label_(std::move(label)), option_(std::move(option)) {}
545 bool focused = Focused();
546 UpdateAnimationTarget();
556 (option_->transform ? option_->transform : DefaultOptionTransform)
560 return element | AnimatedColorStyle() | focus_management |
reflect(box_);
563 void UpdateAnimationTarget() {
564 bool focused = Focused();
565 float target = focused ? 1.F : hovered_ ? 0.5F : 0.F;
566 if (target == animator_background_.to()) {
569 animator_background_ =
571 option_->animated_colors.background.duration,
572 option_->animated_colors.background.function);
573 animator_foreground_ =
575 option_->animated_colors.foreground.duration,
576 option_->animated_colors.foreground.function);
581 if (option_->animated_colors.foreground.enabled) {
582 style = style |
color(Color::Interpolate(
583 animation_foreground_,
584 option_->animated_colors.foreground.inactive,
585 option_->animated_colors.foreground.active));
588 if (option_->animated_colors.background.enabled) {
589 style = style |
bgcolor(Color::Interpolate(
590 animation_background_,
591 option_->animated_colors.background.inactive,
592 option_->animated_colors.background.active));
597 bool Focusable()
const override {
return true; }
598 bool OnEvent(
Event event)
override {
603 hovered_ = box_.Contain(event.
mouse().
x, event.
mouse().
y);
619 animator_background_.OnAnimation(params);
620 animator_foreground_.OnAnimation(params);
626 bool hovered_ =
false;
628 float animation_background_ = 0.F;
629 float animation_foreground_ = 0.F;
636 return Make<Impl>(std::move(label), std::move(option));
static Color Interpolate(float t, const Color &a, const Color &b)
It implement rendering itself as ftxui::Element. It implement keyboard navigation by responding to ft...
bool Focused() const
Returns if the elements if focused by the user. True when the ComponentBase is focused by the user....
CapturedMouse CaptureMouse(const Event &event)
Take the CapturedMouse if available. There is only one component of them. It represents a component t...
void TakeFocus()
Configure all the ancestors to give focus to this component.
An adapter. Reference a list of strings.
An adapter. Own or reference a constant string. For convenience, this class convert multiple immutabl...
An adapter. Own or reference an mutable object.
void OnAnimation(Params &)
constexpr const T & clamp(const T &v, const T &lo, const T &hi)
Decorator bgcolor(Color)
Decorate using a background color.
Element xflex(Element)
Expand/Minimize if possible/needed on the X axis.
std::function< Element(Element)> Decorator
Element separatorVSelector(float up, float down, Color unselected_color, Color selected_color)
Draw an vertical bar, with the area in between up/downcolored differently.
Element nothing(Element element)
A decoration doing absolutely nothing.
std::shared_ptr< T > Make(Args &&... args)
std::shared_ptr< Node > Element
Component Toggle(ConstStringListRef entries, int *selected)
An horizontal list of elements. The user can navigate through them.
Element bold(Element)
Use a bold font, for elements with more emphasis.
Element yflex(Element)
Expand/Minimize if possible/needed on the Y axis.
Component MenuEntry(ConstStringRef label, Ref< MenuEntryOption >={})
A specific menu entry. They can be put into a Container::Vertical to form a menu.
Element separatorHSelector(float left, float right, Color unselected_color, Color selected_color)
Draw an horizontal bar, with the area in between left/right colored differently.
Element hbox(Elements)
A container displaying elements horizontally one by one.
std::vector< Element > Elements
Element inverted(Element)
Add a filter that will invert the foreground and the background colors.
Element text(std::wstring text)
Display a piece of unicode text.
Component Menu(ConstStringListRef entries, int *selected_, Ref< MenuOption >=MenuOption::Vertical())
A list of text. The focused element is selected.
Decorator reflect(Box &box)
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
std::shared_ptr< ComponentBase > Component
Decorator color(Color)
Decorate using a foreground color.
Element vbox(Elements)
A container displaying elements vertically one by one.
arguments for |ButtonOption::transform|, |CheckboxOption::transform|, |Radiobox::transform|,...
bool Contain(int x, int y) const
Represent an event. It can be key press event, a terminal resize, or more ...
static const Event TabReverse
static const Event PageUp
static const Event ArrowUp
static const Event ArrowDown
static const Event PageDown
static const Event Return
static const Event ArrowLeft
static const Event ArrowRight