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