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 
16 namespace ftxui {
17 
18 namespace {
19 
20 void 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
44 Component 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
166 ComponentDecorator 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
189 Component 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
210 ComponentDecorator 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