mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-09-28 16:29:34 +08:00
Remove Ref<XxxOption> and add new interfaces. (#686)
1. Stop taking Ref<XxxOption> in Component constructors. Instead, use the XxxOption directly. Passing by copy avoid problems developers had where one was shared in between multiple component, causing issues. 2. Add variants of most component constructors taking a struct only. This replaces: https://github.com/ArthurSonzogni/FTXUI/pull/670 This fixes: https://github.com/ArthurSonzogni/FTXUI/issues/426
This commit is contained in:
@@ -30,7 +30,148 @@ Element DefaultTransform(EntryState params) { // NOLINT
|
||||
return element;
|
||||
}
|
||||
|
||||
class ButtonBase : public ComponentBase, public ButtonOption {
|
||||
public:
|
||||
explicit ButtonBase(ButtonOption option) : ButtonOption(std::move(option)) {}
|
||||
|
||||
// Component implementation:
|
||||
Element Render() override {
|
||||
const bool active = Active();
|
||||
const bool focused = Focused();
|
||||
const bool focused_or_hover = focused || mouse_hover_;
|
||||
|
||||
float target = focused_or_hover ? 1.f : 0.f; // NOLINT
|
||||
if (target != animator_background_.to()) {
|
||||
SetAnimationTarget(target);
|
||||
}
|
||||
|
||||
auto focus_management = focused ? focus : active ? select : nothing;
|
||||
const EntryState state = {
|
||||
*label,
|
||||
false,
|
||||
active,
|
||||
focused_or_hover,
|
||||
};
|
||||
|
||||
auto element = (transform ? transform : DefaultTransform) //
|
||||
(state);
|
||||
return element | AnimatedColorStyle() | focus_management | reflect(box_);
|
||||
}
|
||||
|
||||
Decorator AnimatedColorStyle() {
|
||||
Decorator style = nothing;
|
||||
if (animated_colors.background.enabled) {
|
||||
style = style |
|
||||
bgcolor(Color::Interpolate(animation_foreground_, //
|
||||
animated_colors.background.inactive,
|
||||
animated_colors.background.active));
|
||||
}
|
||||
if (animated_colors.foreground.enabled) {
|
||||
style =
|
||||
style | color(Color::Interpolate(animation_foreground_, //
|
||||
animated_colors.foreground.inactive,
|
||||
animated_colors.foreground.active));
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
void SetAnimationTarget(float target) {
|
||||
if (animated_colors.foreground.enabled) {
|
||||
animator_foreground_ = animation::Animator(
|
||||
&animation_foreground_, target, animated_colors.foreground.duration,
|
||||
animated_colors.foreground.function);
|
||||
}
|
||||
if (animated_colors.background.enabled) {
|
||||
animator_background_ = animation::Animator(
|
||||
&animation_background_, target, animated_colors.background.duration,
|
||||
animated_colors.background.function);
|
||||
}
|
||||
}
|
||||
|
||||
void OnAnimation(animation::Params& p) override {
|
||||
animator_background_.OnAnimation(p);
|
||||
animator_foreground_.OnAnimation(p);
|
||||
}
|
||||
|
||||
void OnClick() {
|
||||
on_click();
|
||||
animation_background_ = 0.5F; // NOLINT
|
||||
animation_foreground_ = 0.5F; // NOLINT
|
||||
SetAnimationTarget(1.F); // NOLINT
|
||||
}
|
||||
|
||||
bool OnEvent(Event event) override {
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(event);
|
||||
}
|
||||
|
||||
if (event == Event::Return) {
|
||||
OnClick();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OnMouseEvent(Event event) {
|
||||
mouse_hover_ =
|
||||
box_.Contain(event.mouse().x, event.mouse().y) && CaptureMouse(event);
|
||||
|
||||
if (!mouse_hover_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.mouse().button == Mouse::Left &&
|
||||
event.mouse().motion == Mouse::Pressed) {
|
||||
TakeFocus();
|
||||
OnClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Focusable() const final { return true; }
|
||||
|
||||
private:
|
||||
bool mouse_hover_ = false;
|
||||
Box box_;
|
||||
ButtonOption option_;
|
||||
float animation_background_ = 0;
|
||||
float animation_foreground_ = 0;
|
||||
animation::Animator animator_background_ =
|
||||
animation::Animator(&animation_background_);
|
||||
animation::Animator animator_foreground_ =
|
||||
animation::Animator(&animation_foreground_);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
//
|
||||
/// @brief Draw a button. Execute a function when clicked.
|
||||
/// @param option Additional optional parameters.
|
||||
/// @ingroup component
|
||||
/// @see ButtonBase
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```cpp
|
||||
/// auto screen = ScreenInteractive::FitComponent();
|
||||
/// Component button = Button({
|
||||
/// .label = "Click to quit",
|
||||
/// .on_click = screen.ExitLoopClosure(),
|
||||
/// });
|
||||
/// screen.Loop(button)
|
||||
/// ```
|
||||
///
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
/// ┌─────────────┐
|
||||
/// │Click to quit│
|
||||
/// └─────────────┘
|
||||
/// ```
|
||||
Component Button(ButtonOption option) {
|
||||
return Make<ButtonBase>(std::move(option));
|
||||
}
|
||||
|
||||
/// @brief Draw a button. Execute a function when clicked.
|
||||
/// @param label The label of the button.
|
||||
@@ -55,135 +196,13 @@ Element DefaultTransform(EntryState params) { // NOLINT
|
||||
/// │Click to quit│
|
||||
/// └─────────────┘
|
||||
/// ```
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
// NOLINTNEXTLINE
|
||||
Component Button(ConstStringRef label,
|
||||
std::function<void()> on_click,
|
||||
Ref<ButtonOption> option) {
|
||||
class Impl : public ComponentBase {
|
||||
public:
|
||||
Impl(ConstStringRef label,
|
||||
std::function<void()> on_click,
|
||||
Ref<ButtonOption> option)
|
||||
: label_(std::move(label)),
|
||||
on_click_(std::move(on_click)),
|
||||
option_(std::move(option)) {}
|
||||
|
||||
// Component implementation:
|
||||
Element Render() override {
|
||||
const bool active = Active();
|
||||
const bool focused = Focused();
|
||||
const bool focused_or_hover = focused || mouse_hover_;
|
||||
|
||||
float target = focused_or_hover ? 1.f : 0.f; // NOLINT
|
||||
if (target != animator_background_.to()) {
|
||||
SetAnimationTarget(target);
|
||||
}
|
||||
|
||||
auto focus_management = focused ? focus : active ? select : nothing;
|
||||
const EntryState state = {
|
||||
*label_,
|
||||
false,
|
||||
active,
|
||||
focused_or_hover,
|
||||
};
|
||||
|
||||
auto element =
|
||||
(option_->transform ? option_->transform : DefaultTransform) //
|
||||
(state);
|
||||
return element | AnimatedColorStyle() | focus_management | reflect(box_);
|
||||
}
|
||||
|
||||
Decorator AnimatedColorStyle() {
|
||||
Decorator style = nothing;
|
||||
if (option_->animated_colors.background.enabled) {
|
||||
style = style | bgcolor(Color::Interpolate(
|
||||
animation_foreground_, //
|
||||
option_->animated_colors.background.inactive,
|
||||
option_->animated_colors.background.active));
|
||||
}
|
||||
if (option_->animated_colors.foreground.enabled) {
|
||||
style = style | color(Color::Interpolate(
|
||||
animation_foreground_, //
|
||||
option_->animated_colors.foreground.inactive,
|
||||
option_->animated_colors.foreground.active));
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
void SetAnimationTarget(float target) {
|
||||
if (option_->animated_colors.foreground.enabled) {
|
||||
animator_foreground_ =
|
||||
animation::Animator(&animation_foreground_, target,
|
||||
option_->animated_colors.foreground.duration,
|
||||
option_->animated_colors.foreground.function);
|
||||
}
|
||||
if (option_->animated_colors.background.enabled) {
|
||||
animator_background_ =
|
||||
animation::Animator(&animation_background_, target,
|
||||
option_->animated_colors.background.duration,
|
||||
option_->animated_colors.background.function);
|
||||
}
|
||||
}
|
||||
|
||||
void OnAnimation(animation::Params& p) override {
|
||||
animator_background_.OnAnimation(p);
|
||||
animator_foreground_.OnAnimation(p);
|
||||
}
|
||||
|
||||
void OnClick() {
|
||||
on_click_();
|
||||
animation_background_ = 0.5F; // NOLINT
|
||||
animation_foreground_ = 0.5F; // NOLINT
|
||||
SetAnimationTarget(1.F); // NOLINT
|
||||
}
|
||||
|
||||
bool OnEvent(Event event) override {
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(event);
|
||||
}
|
||||
|
||||
if (event == Event::Return) {
|
||||
OnClick();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OnMouseEvent(Event event) {
|
||||
mouse_hover_ =
|
||||
box_.Contain(event.mouse().x, event.mouse().y) && CaptureMouse(event);
|
||||
|
||||
if (!mouse_hover_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.mouse().button == Mouse::Left &&
|
||||
event.mouse().motion == Mouse::Pressed) {
|
||||
TakeFocus();
|
||||
OnClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Focusable() const final { return true; }
|
||||
|
||||
private:
|
||||
ConstStringRef label_;
|
||||
std::function<void()> on_click_;
|
||||
bool mouse_hover_ = false;
|
||||
Box box_;
|
||||
Ref<ButtonOption> option_;
|
||||
float animation_background_ = 0;
|
||||
float animation_foreground_ = 0;
|
||||
animation::Animator animator_background_ =
|
||||
animation::Animator(&animation_background_);
|
||||
animation::Animator animator_foreground_ =
|
||||
animation::Animator(&animation_foreground_);
|
||||
};
|
||||
|
||||
return Make<Impl>(std::move(label), std::move(on_click), std::move(option));
|
||||
ButtonOption option) {
|
||||
option.label = label;
|
||||
option.on_click = std::move(on_click);
|
||||
return Make<ButtonBase>(std::move(option));
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
Reference in New Issue
Block a user