FTXUI  5.0.0
C++ functional terminal UI.
button.cpp
Go to the documentation of this file.
1// Copyright 2020 Arthur Sonzogni. All rights reserved.
2// Use of this source code is governed by the MIT license that can be found in
3// the LICENSE file.
4
5#include <functional> // for function
6#include <memory> // for shared_ptr
7#include <utility> // for move
8
9#include "ftxui/component/animation.hpp" // for Animator, Params (ptr only)
10#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
11#include "ftxui/component/component.hpp" // for Make, Button
12#include "ftxui/component/component_base.hpp" // for ComponentBase
13#include "ftxui/component/component_options.hpp" // for ButtonOption, AnimatedColorOption, AnimatedColorsOption, EntryState
14#include "ftxui/component/event.hpp" // for Event, Event::Return
15#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed
16#include "ftxui/component/screen_interactive.hpp" // for Component
17#include "ftxui/dom/elements.hpp" // for operator|, Decorator, Element, operator|=, bgcolor, color, reflect, text, bold, border, inverted, nothing
18#include "ftxui/screen/box.hpp" // for Box
19#include "ftxui/screen/color.hpp" // for Color
20#include "ftxui/util/ref.hpp" // for Ref, ConstStringRef
21
22namespace ftxui {
23
24namespace {
25
26Element DefaultTransform(EntryState params) { // NOLINT
27 auto element = text(params.label) | border;
28 if (params.active) {
29 element |= bold;
30 }
31 if (params.focused) {
32 element |= inverted;
33 }
34 return element;
35}
36
37class ButtonBase : public ComponentBase, public ButtonOption {
38 public:
39 explicit ButtonBase(ButtonOption option) : ButtonOption(std::move(option)) {}
40
41 // Component implementation:
42 Element Render() override {
43 const bool active = Active();
44 const bool focused = Focused();
45 const bool focused_or_hover = focused || mouse_hover_;
46
47 float target = focused_or_hover ? 1.f : 0.f; // NOLINT
48 if (target != animator_background_.to()) {
49 SetAnimationTarget(target);
50 }
51
52 auto focus_management = focused ? focus : active ? select : nothing;
53 const EntryState state = {
54 *label,
55 false,
56 active,
57 focused_or_hover,
58 };
59
60 auto element = (transform ? transform : DefaultTransform) //
61 (state);
62 return element | AnimatedColorStyle() | focus_management | reflect(box_);
63 }
64
65 Decorator AnimatedColorStyle() {
66 Decorator style = nothing;
67 if (animated_colors.background.enabled) {
68 style = style |
69 bgcolor(Color::Interpolate(animation_foreground_, //
70 animated_colors.background.inactive,
71 animated_colors.background.active));
72 }
73 if (animated_colors.foreground.enabled) {
74 style =
75 style | color(Color::Interpolate(animation_foreground_, //
76 animated_colors.foreground.inactive,
77 animated_colors.foreground.active));
78 }
79 return style;
80 }
81
82 void SetAnimationTarget(float target) {
83 if (animated_colors.foreground.enabled) {
84 animator_foreground_ = animation::Animator(
85 &animation_foreground_, target, animated_colors.foreground.duration,
86 animated_colors.foreground.function);
87 }
88 if (animated_colors.background.enabled) {
89 animator_background_ = animation::Animator(
90 &animation_background_, target, animated_colors.background.duration,
91 animated_colors.background.function);
92 }
93 }
94
95 void OnAnimation(animation::Params& p) override {
96 animator_background_.OnAnimation(p);
97 animator_foreground_.OnAnimation(p);
98 }
99
100 void OnClick() {
101 on_click();
102 animation_background_ = 0.5F; // NOLINT
103 animation_foreground_ = 0.5F; // NOLINT
104 SetAnimationTarget(1.F); // NOLINT
105 }
106
107 bool OnEvent(Event event) override {
108 if (event.is_mouse()) {
109 return OnMouseEvent(event);
110 }
111
112 if (event == Event::Return) {
113 OnClick();
114 return true;
115 }
116 return false;
117 }
118
119 bool OnMouseEvent(Event event) {
120 mouse_hover_ =
121 box_.Contain(event.mouse().x, event.mouse().y) && CaptureMouse(event);
122
123 if (!mouse_hover_) {
124 return false;
125 }
126
127 if (event.mouse().IsPressed()) {
128 TakeFocus();
129 OnClick();
130 return true;
131 }
132
133 return false;
134 }
135
136 bool Focusable() const final { return true; }
137
138 private:
139 bool mouse_hover_ = false;
140 Box box_;
141 ButtonOption option_;
142 float animation_background_ = 0;
143 float animation_foreground_ = 0;
144 animation::Animator animator_background_ =
145 animation::Animator(&animation_background_);
146 animation::Animator animator_foreground_ =
147 animation::Animator(&animation_foreground_);
148};
149
150} // namespace
151
152/// @brief Draw a button. Execute a function when clicked.
153/// @param option Additional optional parameters.
154/// @ingroup component
155/// @see ButtonBase
156///
157/// ### Example
158///
159/// ```cpp
160/// auto screen = ScreenInteractive::FitComponent();
161/// Component button = Button({
162/// .label = "Click to quit",
163/// .on_click = screen.ExitLoopClosure(),
164/// });
165/// screen.Loop(button)
166/// ```
167///
168/// ### Output
169///
170/// ```bash
171/// ┌─────────────┐
172/// │Click to quit│
173/// └─────────────┘
174/// ```
176 return Make<ButtonBase>(std::move(option));
177}
178
179/// @brief Draw a button. Execute a function when clicked.
180/// @param label The label of the button.
181/// @param on_click The action to execute when clicked.
182/// @param option Additional optional parameters.
183/// @ingroup component
184/// @see ButtonBase
185///
186/// ### Example
187///
188/// ```cpp
189/// auto screen = ScreenInteractive::FitComponent();
190/// std::string label = "Click to quit";
191/// Component button = Button(&label, screen.ExitLoopClosure());
192/// screen.Loop(button)
193/// ```
194///
195/// ### Output
196///
197/// ```bash
198/// ┌─────────────┐
199/// │Click to quit│
200/// └─────────────┘
201/// ```
202// NOLINTNEXTLINE
204 std::function<void()> on_click,
205 ButtonOption option) {
206 option.label = label;
207 option.on_click = std::move(on_click);
208 return Make<ButtonBase>(std::move(option));
209}
210
211} // namespace ftxui
static Color Interpolate(float t, const Color &a, const Color &b)
Definition: color.cpp:217
An adapter. Own or reference a constant string. For convenience, this class convert multiple immutabl...
Definition: ref.hpp:86
Decorator bgcolor(Color)
Decorate using a background color.
Definition: color.cpp:124
std::function< Element(Element)> Decorator
Definition: elements.hpp:25
Element nothing(Element element)
A decoration doing absolutely nothing.
Definition: util.cpp:30
std::shared_ptr< Node > Element
Definition: elements.hpp:23
std::shared_ptr< ComponentBase > Component
Element bold(Element)
Use a bold font, for elements with more emphasis.
Definition: bold.cpp:33
Component Button(ButtonOption options)
Draw a button. Execute a function when clicked.
Definition: button.cpp:175
Element inverted(Element)
Add a filter that will invert the foreground and the background colors.
Definition: inverted.cpp:34
Element text(std::wstring text)
Display a piece of unicode text.
Definition: text.cpp:120
Element select(Element)
Set the child to be the one selected among its siblings.
Definition: frame.cpp:150
Element focus(Element)
Set the child to be the one in focus globally.
Definition: frame.cpp:157
Decorator reflect(Box &box)
Definition: reflect.cpp:44
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
Definition: node.cpp:47
Element border(Element)
Draw a border around the element.
Definition: border.cpp:227
Decorator color(Color)
Decorate using a foreground color.
Definition: color.cpp:110
Option for the AnimatedButton component.
std::function< void()> on_click
static const Event Return
Definition: event.hpp:53