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