2022-03-14 01:51:46 +08:00
|
|
|
#include "ftxui/component/component_options.hpp"
|
|
|
|
|
2023-05-02 19:32:37 +08:00
|
|
|
#include <ftxui/dom/linear_gradient.hpp> // for LinearGradient
|
|
|
|
#include <ftxui/screen/color.hpp> // for Color, Color::White, Color::Black, Color::GrayDark, Color::Blue, Color::GrayLight, Color::Red
|
|
|
|
#include <memory> // for shared_ptr
|
|
|
|
#include <utility> // for move
|
2022-03-14 01:51:46 +08:00
|
|
|
|
|
|
|
#include "ftxui/component/animation.hpp" // for Function, Duration
|
2023-05-02 19:32:37 +08:00
|
|
|
#include "ftxui/dom/elements.hpp" // for operator|=, Element, text, bgcolor, inverted, bold, dim, operator|, color, borderEmpty, hbox, automerge, border, borderLight
|
2022-03-14 01:51:46 +08:00
|
|
|
|
|
|
|
namespace ftxui {
|
|
|
|
|
|
|
|
void AnimatedColorOption::Set(Color a_inactive,
|
|
|
|
Color a_active,
|
|
|
|
animation::Duration a_duration,
|
|
|
|
animation::easing::Function a_function) {
|
|
|
|
enabled = true;
|
|
|
|
inactive = a_inactive;
|
|
|
|
active = a_active;
|
|
|
|
duration = a_duration;
|
2022-03-31 08:17:43 +08:00
|
|
|
function = std::move(a_function);
|
2022-03-14 01:51:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UnderlineOption::SetAnimation(animation::Duration d,
|
|
|
|
animation::easing::Function f) {
|
|
|
|
SetAnimationDuration(d);
|
2022-03-31 08:17:43 +08:00
|
|
|
SetAnimationFunction(std::move(f));
|
2022-03-14 01:51:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UnderlineOption::SetAnimationDuration(animation::Duration d) {
|
|
|
|
leader_duration = d;
|
|
|
|
follower_duration = d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnderlineOption::SetAnimationFunction(animation::easing::Function f) {
|
|
|
|
leader_function = f;
|
2022-03-31 08:17:43 +08:00
|
|
|
follower_function = std::move(f);
|
2022-03-14 01:51:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UnderlineOption::SetAnimationFunction(
|
|
|
|
animation::easing::Function f_leader,
|
|
|
|
animation::easing::Function f_follower) {
|
2022-03-31 08:17:43 +08:00
|
|
|
leader_function = std::move(f_leader);
|
|
|
|
follower_function = std::move(f_follower);
|
2022-03-14 01:51:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
MenuOption MenuOption::Horizontal() {
|
|
|
|
MenuOption option;
|
|
|
|
option.direction = Direction::Right;
|
2023-06-25 23:22:05 +08:00
|
|
|
option.entries_option.transform = [](const EntryState& state) {
|
2022-03-14 01:51:46 +08:00
|
|
|
Element e = text(state.label);
|
2022-03-31 08:17:43 +08:00
|
|
|
if (state.focused) {
|
2022-03-14 01:51:46 +08:00
|
|
|
e |= inverted;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
|
|
|
if (state.active) {
|
2022-03-14 01:51:46 +08:00
|
|
|
e |= bold;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
|
|
|
if (!state.focused && !state.active) {
|
2022-03-14 01:51:46 +08:00
|
|
|
e |= dim;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
2022-03-14 01:51:46 +08:00
|
|
|
return e;
|
|
|
|
};
|
|
|
|
option.elements_infix = [] { return text(" "); };
|
|
|
|
|
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
MenuOption MenuOption::HorizontalAnimated() {
|
|
|
|
auto option = Horizontal();
|
|
|
|
option.underline.enabled = true;
|
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
MenuOption MenuOption::Vertical() {
|
|
|
|
MenuOption option;
|
2023-06-25 23:22:05 +08:00
|
|
|
option.entries_option.transform = [](const EntryState& state) {
|
2022-03-31 08:17:43 +08:00
|
|
|
Element e = text((state.active ? "> " : " ") + state.label); // NOLINT
|
|
|
|
if (state.focused) {
|
2022-03-14 01:51:46 +08:00
|
|
|
e |= inverted;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
|
|
|
if (state.active) {
|
2022-03-14 01:51:46 +08:00
|
|
|
e |= bold;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
|
|
|
if (!state.focused && !state.active) {
|
2022-03-14 01:51:46 +08:00
|
|
|
e |= dim;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
2022-03-14 01:51:46 +08:00
|
|
|
return e;
|
|
|
|
};
|
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
MenuOption MenuOption::VerticalAnimated() {
|
|
|
|
auto option = MenuOption::Vertical();
|
2023-06-25 23:22:05 +08:00
|
|
|
option.entries_option.transform = [](const EntryState& state) {
|
2022-03-14 01:51:46 +08:00
|
|
|
Element e = text(state.label);
|
2022-03-31 08:17:43 +08:00
|
|
|
if (state.focused) {
|
2022-03-14 01:51:46 +08:00
|
|
|
e |= inverted;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
|
|
|
if (state.active) {
|
2022-03-14 01:51:46 +08:00
|
|
|
e |= bold;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
|
|
|
if (!state.focused && !state.active) {
|
2022-03-14 01:51:46 +08:00
|
|
|
e |= dim;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
2022-03-14 01:51:46 +08:00
|
|
|
return e;
|
|
|
|
};
|
|
|
|
option.underline.enabled = true;
|
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
MenuOption MenuOption::Toggle() {
|
|
|
|
auto option = MenuOption::Horizontal();
|
|
|
|
option.elements_infix = [] { return text("│") | automerge; };
|
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Create a ButtonOption, highlighted using [] characters.
|
|
|
|
// static
|
|
|
|
ButtonOption ButtonOption::Ascii() {
|
|
|
|
ButtonOption option;
|
2022-03-31 08:17:43 +08:00
|
|
|
option.transform = [](const EntryState& s) {
|
2023-06-25 23:22:05 +08:00
|
|
|
const std::string t = s.focused ? "[" + s.label + "]" //
|
|
|
|
: " " + s.label + " ";
|
|
|
|
return text(t);
|
2022-03-14 01:51:46 +08:00
|
|
|
};
|
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Create a ButtonOption, inverted when focused.
|
|
|
|
// static
|
|
|
|
ButtonOption ButtonOption::Simple() {
|
|
|
|
ButtonOption option;
|
2022-03-31 08:17:43 +08:00
|
|
|
option.transform = [](const EntryState& s) {
|
2022-03-14 01:51:46 +08:00
|
|
|
auto element = text(s.label) | borderLight;
|
2022-03-31 08:17:43 +08:00
|
|
|
if (s.focused) {
|
2022-03-14 01:51:46 +08:00
|
|
|
element |= inverted;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
2022-03-14 01:51:46 +08:00
|
|
|
return element;
|
|
|
|
};
|
|
|
|
return option;
|
2022-08-31 01:03:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Create a ButtonOption. The button is shown using a border, inverted
|
|
|
|
/// when focused. This is the current default.
|
|
|
|
ButtonOption ButtonOption::Border() {
|
|
|
|
ButtonOption option;
|
|
|
|
option.transform = [](const EntryState& s) {
|
|
|
|
auto element = text(s.label) | border;
|
|
|
|
if (s.active) {
|
|
|
|
element |= bold;
|
|
|
|
}
|
|
|
|
if (s.focused) {
|
|
|
|
element |= inverted;
|
|
|
|
}
|
|
|
|
return element;
|
|
|
|
};
|
|
|
|
return option;
|
2022-03-14 01:51:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Create a ButtonOption, using animated colors.
|
|
|
|
// static
|
|
|
|
ButtonOption ButtonOption::Animated() {
|
|
|
|
return Animated(Color::Black, Color::GrayLight, //
|
|
|
|
Color::GrayDark, Color::White);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Create a ButtonOption, using animated colors.
|
|
|
|
// static
|
|
|
|
ButtonOption ButtonOption::Animated(Color color) {
|
2022-03-31 08:17:43 +08:00
|
|
|
return ButtonOption::Animated(
|
|
|
|
Color::Interpolate(0.85F, color, Color::Black), // NOLINT
|
|
|
|
Color::Interpolate(0.10F, color, Color::White), // NOLINT
|
|
|
|
Color::Interpolate(0.10F, color, Color::Black), // NOLINT
|
|
|
|
Color::Interpolate(0.85F, color, Color::White)); // NOLINT
|
2022-03-14 01:51:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Create a ButtonOption, using animated colors.
|
|
|
|
// static
|
|
|
|
ButtonOption ButtonOption::Animated(Color background, Color foreground) {
|
2022-09-06 02:56:41 +08:00
|
|
|
// NOLINTBEGIN
|
2022-08-29 03:30:01 +08:00
|
|
|
return ButtonOption::Animated(
|
|
|
|
/*bakground=*/background,
|
|
|
|
/*foreground=*/foreground,
|
|
|
|
/*background_active=*/foreground,
|
|
|
|
/*foreground_active=*/background);
|
2022-09-06 02:56:41 +08:00
|
|
|
// NOLINTEND
|
2022-03-14 01:51:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Create a ButtonOption, using animated colors.
|
|
|
|
// static
|
|
|
|
ButtonOption ButtonOption::Animated(Color background,
|
|
|
|
Color foreground,
|
2022-03-31 08:17:43 +08:00
|
|
|
Color background_active,
|
|
|
|
Color foreground_active) {
|
2022-03-14 01:51:46 +08:00
|
|
|
ButtonOption option;
|
2022-03-31 08:17:43 +08:00
|
|
|
option.transform = [](const EntryState& s) {
|
2022-03-14 01:51:46 +08:00
|
|
|
auto element = text(s.label) | borderEmpty;
|
2022-03-31 08:17:43 +08:00
|
|
|
if (s.focused) {
|
2022-03-14 01:51:46 +08:00
|
|
|
element |= bold;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
2022-03-14 01:51:46 +08:00
|
|
|
return element;
|
|
|
|
};
|
2022-03-31 08:17:43 +08:00
|
|
|
option.animated_colors.foreground.Set(foreground, foreground_active);
|
|
|
|
option.animated_colors.background.Set(background, background_active);
|
2022-03-14 01:51:46 +08:00
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Option for standard Checkbox.
|
|
|
|
// static
|
|
|
|
CheckboxOption CheckboxOption::Simple() {
|
|
|
|
auto option = CheckboxOption();
|
2022-03-31 08:17:43 +08:00
|
|
|
option.transform = [](const EntryState& s) {
|
2022-03-14 01:51:46 +08:00
|
|
|
#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
|
|
|
|
// Microsoft terminal do not use fonts able to render properly the default
|
|
|
|
// radiobox glyph.
|
2022-03-31 08:17:43 +08:00
|
|
|
auto prefix = text(s.state ? "[X] " : "[ ] "); // NOLINT
|
2022-03-14 01:51:46 +08:00
|
|
|
#else
|
2022-03-31 08:17:43 +08:00
|
|
|
auto prefix = text(s.state ? "▣ " : "☐ "); // NOLINT
|
2022-03-14 01:51:46 +08:00
|
|
|
#endif
|
|
|
|
auto t = text(s.label);
|
2022-03-31 08:17:43 +08:00
|
|
|
if (s.active) {
|
2022-03-14 01:51:46 +08:00
|
|
|
t |= bold;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
|
|
|
if (s.focused) {
|
2022-03-14 01:51:46 +08:00
|
|
|
t |= inverted;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
2022-03-14 01:51:46 +08:00
|
|
|
return hbox({prefix, t});
|
|
|
|
};
|
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Option for standard Radiobox
|
|
|
|
// static
|
|
|
|
RadioboxOption RadioboxOption::Simple() {
|
|
|
|
auto option = RadioboxOption();
|
2022-03-31 08:17:43 +08:00
|
|
|
option.transform = [](const EntryState& s) {
|
2022-03-14 01:51:46 +08:00
|
|
|
#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
|
|
|
|
// Microsoft terminal do not use fonts able to render properly the default
|
|
|
|
// radiobox glyph.
|
2022-03-31 08:17:43 +08:00
|
|
|
auto prefix = text(s.state ? "(*) " : "( ) "); // NOLINT
|
2022-03-14 01:51:46 +08:00
|
|
|
#else
|
2022-03-31 08:17:43 +08:00
|
|
|
auto prefix = text(s.state ? "◉ " : "○ "); // NOLINT
|
2022-03-14 01:51:46 +08:00
|
|
|
#endif
|
|
|
|
auto t = text(s.label);
|
2022-03-31 08:17:43 +08:00
|
|
|
if (s.active) {
|
2022-03-14 01:51:46 +08:00
|
|
|
t |= bold;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
|
|
|
if (s.focused) {
|
2022-03-14 01:51:46 +08:00
|
|
|
t |= inverted;
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
2022-03-14 01:51:46 +08:00
|
|
|
return hbox({prefix, t});
|
|
|
|
};
|
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
2023-05-02 19:32:37 +08:00
|
|
|
// static
|
|
|
|
InputOption InputOption::Default() {
|
|
|
|
InputOption option;
|
|
|
|
option.transform = [](InputState state) {
|
|
|
|
state.element |= color(Color::White);
|
|
|
|
|
|
|
|
if (state.is_placeholder) {
|
|
|
|
state.element |= dim;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state.focused) {
|
|
|
|
state.element |= inverted;
|
|
|
|
} else if (state.hovered) {
|
|
|
|
state.element |= bgcolor(Color::GrayDark);
|
|
|
|
}
|
|
|
|
|
|
|
|
return state.element;
|
|
|
|
};
|
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
InputOption InputOption::Spacious() {
|
|
|
|
InputOption option;
|
|
|
|
option.transform = [](InputState state) {
|
|
|
|
state.element |= borderEmpty;
|
|
|
|
state.element |= color(Color::White);
|
|
|
|
|
|
|
|
if (state.is_placeholder) {
|
|
|
|
state.element |= dim;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state.focused) {
|
|
|
|
state.element |= bgcolor(Color::Black);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state.hovered) {
|
|
|
|
state.element |= bgcolor(Color::GrayDark);
|
|
|
|
}
|
|
|
|
|
|
|
|
return state.element;
|
|
|
|
};
|
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
2022-03-14 01:51:46 +08:00
|
|
|
} // namespace ftxui
|
|
|
|
|
|
|
|
// Copyright 2022 Arthur Sonzogni. All rights reserved.
|
|
|
|
// Use of this source code is governed by the MIT license that can be found in
|
|
|
|
// the LICENSE file.
|