FTXUI  5.0.0
C++ functional terminal UI.
hoverable.cpp
Go to the documentation of this file.
1// Copyright 2022 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#include <ftxui/component/captured_mouse.hpp> // for CapturedMouse
5#include <functional> // for function
6#include <utility> // for move
7
8#include "ftxui/component/component.hpp" // for ComponentDecorator, Hoverable, Make
9#include "ftxui/component/component_base.hpp" // for ComponentBase
10#include "ftxui/component/event.hpp" // for Event
11#include "ftxui/component/mouse.hpp" // for Mouse
12#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
13#include "ftxui/dom/elements.hpp" // for operator|, reflect, Element
14#include "ftxui/screen/box.hpp" // for Box
15
16namespace ftxui {
17
18namespace {
19
20void Post(std::function<void()> f) {
21 if (auto* screen = ScreenInteractive::Active()) {
22 screen->Post(std::move(f));
23 return;
24 }
25 f();
26}
27
28} // namespace
29
30/// @brief Wrap a component. Gives the ability to know if it is hovered by the
31/// mouse.
32/// @param component The wrapped component.
33/// @param hover The value to reflect whether the component is hovered or not.
34/// @ingroup component
35///
36/// ### Example
37///
38/// ```cpp
39/// auto button = Button("exit", screen.ExitLoopClosure());
40/// bool hover = false;
41/// auto button_hover = Hoverable(button, &hover);
42/// ```
43// NOLINTNEXTLINE
44Component Hoverable(Component component, bool* hover) {
45 class Impl : public ComponentBase {
46 public:
47 Impl(Component component, bool* hover)
48 : component_(std::move(component)), hover_(hover) {
49 Add(component_);
50 }
51
52 private:
53 Element Render() override {
54 return ComponentBase::Render() | reflect(box_);
55 }
56
57 bool OnEvent(Event event) override {
58 if (event.is_mouse()) {
59 *hover_ = box_.Contain(event.mouse().x, event.mouse().y) &&
60 CaptureMouse(event);
61 }
62
63 return ComponentBase::OnEvent(event);
64 }
65
66 Component component_;
67 bool* hover_;
68 Box box_;
69 };
70
71 return Make<Impl>(component, hover);
72}
73
74/// @brief Wrap a component. Uses callbacks.
75/// @param component The wrapped component.
76/// @param on_enter Callback OnEnter
77/// @param on_leave Callback OnLeave
78/// @ingroup component
79///
80/// ### Example
81///
82/// ```cpp
83/// auto button = Button("exit", screen.ExitLoopClosure());
84/// bool hover = false;
85/// auto button_hover = Hoverable(button, &hover);
86/// ```
88 std::function<void()> on_enter,
89 std::function<void()> on_leave) {
90 class Impl : public ComponentBase {
91 public:
92 Impl(Component component,
93 std::function<void()> on_enter,
94 std::function<void()> on_leave)
95 : component_(std::move(component)),
96 on_enter_(std::move(on_enter)),
97 on_leave_(std::move(on_leave)) {
98 Add(component_);
99 }
100
101 private:
102 Element Render() override {
103 return ComponentBase::Render() | reflect(box_);
104 }
105
106 bool OnEvent(Event event) override {
107 if (event.is_mouse()) {
108 const bool hover = box_.Contain(event.mouse().x, event.mouse().y) &&
109 CaptureMouse(event);
110 if (hover != hover_) {
111 Post(hover ? on_enter_ : on_leave_);
112 }
113 hover_ = hover;
114 }
115
116 return ComponentBase::OnEvent(event);
117 }
118
119 Component component_;
120 Box box_;
121 bool hover_ = false;
122 std::function<void()> on_enter_;
123 std::function<void()> on_leave_;
124 };
125
126 return Make<Impl>(std::move(component), std::move(on_enter),
127 std::move(on_leave));
128}
129
130/// @brief Wrap a component. Gives the ability to know if it is hovered by the
131/// mouse.
132/// @param hover The value to reflect whether the component is hovered or not.
133/// @ingroup component
134///
135/// ### Example
136///
137/// ```cpp
138/// bool hover = false;
139/// auto button = Button("exit", screen.ExitLoopClosure());
140/// button |= Hoverable(&hover);
141/// ```
143 return [hover](Component component) {
144 return Hoverable(std::move(component), hover);
145 };
146}
147
148/// @brief Wrap a component. Gives the ability to know if it is hovered by the
149/// mouse.
150/// @param on_enter is called when the mouse hover the component.
151/// @param on_leave is called when the mouse leave the component.
152/// @ingroup component
153///
154/// ### Example
155///
156/// ```cpp
157/// auto button = Button("exit", screen.ExitLoopClosure());
158/// int on_enter_cnt = 0;
159/// int on_leave_cnt = 0;
160/// button |= Hoverable(
161/// [&]{ on_enter_cnt++; },
162/// [&]{ on_leave_cnt++; }
163// );
164/// ```
165// NOLINTNEXTLINE
166ComponentDecorator Hoverable(std::function<void()> on_enter,
167 // NOLINTNEXTLINE
168 std::function<void()> on_leave) {
169 return [on_enter, on_leave](Component component) {
170 return Hoverable(std::move(component), on_enter, on_leave);
171 };
172}
173
174/// @brief Wrap a component. Gives the ability to know if it is hovered by the
175/// mouse.
176/// @param component the wrapped component.
177/// @param on_change is called when the mouse enter or leave the component.
178/// @ingroup component
179///
180/// ### Example
181///
182/// ```cpp
183/// auto button = Button("exit", screen.ExitLoopClosure());
184/// bool hovered = false;
185/// auto button_hoverable = Hoverable(button,
186// [&](bool hover) { hovered = hover;});
187/// ```
188// NOLINTNEXTLINE
189Component Hoverable(Component component, std::function<void(bool)> on_change) {
190 return Hoverable(
191 std::move(component), //
192 [on_change] { on_change(true); }, //
193 [on_change] { on_change(false); } //
194 );
195}
196
197/// @brief Wrap a component. Gives the ability to know if it is hovered by the
198/// mouse.
199/// @param on_change is called when the mouse enter or leave the component.
200/// @ingroup component
201///
202/// ### Example
203///
204/// ```cpp
205/// auto button = Button("exit", screen.ExitLoopClosure());
206/// bool hovered = false;
207/// button |= Hoverable([&](bool hover) { hovered = hover;});
208/// ```
209// NOLINTNEXTLINE
210ComponentDecorator Hoverable(std::function<void(bool)> on_change) {
211 return [on_change](Component component) {
212 return Hoverable(std::move(component), on_change);
213 };
214}
215
216} // namespace ftxui
It implement rendering itself as ftxui::Element. It implement keyboard navigation by responding to ft...
virtual Element Render()
Draw the component. Build a ftxui::Element to be drawn on the ftxi::Screen representing this ftxui::C...
Definition: component.cpp:92
virtual bool OnEvent(Event)
Called in response to an event.
Definition: component.cpp:106
static ScreenInteractive * Active()
Return the currently active screen, or null if none.
std::shared_ptr< Node > Element
Definition: elements.hpp:23
std::shared_ptr< ComponentBase > Component
Component Hoverable(Component component, bool *hover)
Wrap a component. Gives the ability to know if it is hovered by the mouse.
Definition: hoverable.cpp:44
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
std::function< Component(Component)> ComponentDecorator
Definition: component.hpp:33
Represent an event. It can be key press event, a terminal resize, or more ...
Definition: event.hpp:29
bool is_mouse() const
Definition: event.hpp:78
struct Mouse & mouse()
Definition: event.hpp:79