2022-12-20 01:51:25 +08:00
|
|
|
|
#include <ftxui/component/captured_mouse.hpp> // for CapturedMouse
|
|
|
|
|
#include <functional> // for function
|
|
|
|
|
#include <utility> // for move
|
2022-12-04 18:54:49 +08:00
|
|
|
|
|
2022-12-20 01:51:25 +08:00
|
|
|
|
#include "ftxui/component/component.hpp" // for ComponentDecorator, Hoverable, Make
|
2022-12-04 18:54:49 +08:00
|
|
|
|
#include "ftxui/component/component_base.hpp" // for ComponentBase
|
2022-12-20 01:51:25 +08:00
|
|
|
|
#include "ftxui/component/event.hpp" // for Event
|
|
|
|
|
#include "ftxui/component/mouse.hpp" // for Mouse
|
|
|
|
|
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
|
|
|
|
|
#include "ftxui/dom/elements.hpp" // for operator|, reflect, Element
|
2022-12-04 18:54:49 +08:00
|
|
|
|
#include "ftxui/screen/box.hpp" // for Box
|
|
|
|
|
|
|
|
|
|
namespace ftxui {
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
void Post(std::function<void()> f) {
|
|
|
|
|
if (auto* screen = ScreenInteractive::Active()) {
|
|
|
|
|
screen->Post(std::move(f));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
f();
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-20 01:51:25 +08:00
|
|
|
|
} // namespace
|
2022-12-04 18:54:49 +08:00
|
|
|
|
|
|
|
|
|
/// @brief Wrap a component. Gives the ability to know if it is hovered by the
|
|
|
|
|
/// mouse.
|
|
|
|
|
/// @param component: The wrapped component.
|
|
|
|
|
/// @param hover: The value to reflect whether the component is hovered or not.
|
|
|
|
|
/// @ingroup component
|
|
|
|
|
///
|
|
|
|
|
/// ### Example
|
|
|
|
|
///
|
|
|
|
|
/// ```cpp
|
|
|
|
|
/// auto button = Button("exit", screen.ExitLoopClosure());
|
|
|
|
|
/// bool hover = false;
|
|
|
|
|
/// auto button_hover = Hoverable(button, &hover);
|
|
|
|
|
/// ```
|
2022-12-20 01:51:25 +08:00
|
|
|
|
// NOLINTNEXTLINE
|
2022-12-04 18:54:49 +08:00
|
|
|
|
Component Hoverable(Component component, bool* hover) {
|
|
|
|
|
class Impl : public ComponentBase {
|
|
|
|
|
public:
|
|
|
|
|
Impl(Component component, bool* hover)
|
2022-12-20 01:51:25 +08:00
|
|
|
|
: component_(std::move(component)), hover_(hover) {
|
2022-12-04 18:54:49 +08:00
|
|
|
|
Add(component_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Element Render() override {
|
|
|
|
|
return ComponentBase::Render() | reflect(box_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool OnEvent(Event event) override {
|
|
|
|
|
if (event.is_mouse()) {
|
|
|
|
|
*hover_ = box_.Contain(event.mouse().x, event.mouse().y) &&
|
|
|
|
|
CaptureMouse(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ComponentBase::OnEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Component component_;
|
|
|
|
|
bool* hover_;
|
|
|
|
|
Box box_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return Make<Impl>(component, hover);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @brief Wrap a component. Gives the ability to know if it is hovered by the
|
|
|
|
|
/// mouse.
|
|
|
|
|
/// @param component: The wrapped component.
|
|
|
|
|
/// @param hover: The value to reflect whether the component is hovered or not.
|
|
|
|
|
/// @ingroup component
|
|
|
|
|
///
|
|
|
|
|
/// ### Example
|
|
|
|
|
///
|
|
|
|
|
/// ```cpp
|
|
|
|
|
/// auto button = Button("exit", screen.ExitLoopClosure());
|
|
|
|
|
/// bool hover = false;
|
|
|
|
|
/// auto button_hover = Hoverable(button, &hover);
|
|
|
|
|
/// ```
|
|
|
|
|
Component Hoverable(Component component,
|
|
|
|
|
std::function<void()> on_enter,
|
|
|
|
|
std::function<void()> on_leave) {
|
|
|
|
|
class Impl : public ComponentBase {
|
|
|
|
|
public:
|
|
|
|
|
Impl(Component component,
|
|
|
|
|
std::function<void()> on_enter,
|
|
|
|
|
std::function<void()> on_leave)
|
|
|
|
|
: component_(std::move(component)),
|
|
|
|
|
on_enter_(std::move(on_enter)),
|
|
|
|
|
on_leave_(std::move(on_leave)) {
|
|
|
|
|
Add(component_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Element Render() override {
|
|
|
|
|
return ComponentBase::Render() | reflect(box_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool OnEvent(Event event) override {
|
|
|
|
|
if (event.is_mouse()) {
|
2022-12-20 01:51:25 +08:00
|
|
|
|
const bool hover = box_.Contain(event.mouse().x, event.mouse().y) &&
|
|
|
|
|
CaptureMouse(event);
|
2022-12-04 18:54:49 +08:00
|
|
|
|
if (hover != hover_) {
|
|
|
|
|
Post(hover ? on_enter_ : on_leave_);
|
|
|
|
|
}
|
|
|
|
|
hover_ = hover;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ComponentBase::OnEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Component component_;
|
|
|
|
|
Box box_;
|
|
|
|
|
bool hover_ = false;
|
|
|
|
|
std::function<void()> on_enter_;
|
|
|
|
|
std::function<void()> on_leave_;
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-20 01:51:25 +08:00
|
|
|
|
return Make<Impl>(std::move(component), std::move(on_enter),
|
|
|
|
|
std::move(on_leave));
|
2022-12-04 18:54:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @brief Wrap a component. Gives the ability to know if it is hovered by the
|
|
|
|
|
/// mouse.
|
|
|
|
|
/// @param hover: The value to reflect whether the component is hovered or not.
|
|
|
|
|
/// @ingroup component
|
|
|
|
|
///
|
|
|
|
|
/// ### Example
|
|
|
|
|
///
|
|
|
|
|
/// ```cpp
|
|
|
|
|
/// bool hover = false;
|
|
|
|
|
/// auto button = Button("exit", screen.ExitLoopClosure());
|
|
|
|
|
/// button |= Hoverable(&hover);
|
|
|
|
|
/// ```
|
|
|
|
|
ComponentDecorator Hoverable(bool* hover) {
|
2022-12-20 01:51:25 +08:00
|
|
|
|
return [hover](Component component) {
|
|
|
|
|
return Hoverable(std::move(component), hover);
|
|
|
|
|
};
|
2022-12-04 18:54:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 18:59:56 +08:00
|
|
|
|
/// @brief Wrap a component. Gives the ability to know if it is hovered by the
|
|
|
|
|
/// mouse.
|
|
|
|
|
/// @param on_enter is called when the mouse hover the component.
|
|
|
|
|
/// @param on_leave is called when the mouse leave the component.
|
|
|
|
|
/// @ingroup component
|
|
|
|
|
///
|
|
|
|
|
/// ### Example
|
|
|
|
|
///
|
|
|
|
|
/// ```cpp
|
|
|
|
|
/// auto button = Button("exit", screen.ExitLoopClosure());
|
|
|
|
|
/// int on_enter_cnt = 0;
|
|
|
|
|
/// int on_leave_cnt = 0;
|
|
|
|
|
/// button |= Hoverable(
|
2022-12-20 01:51:25 +08:00
|
|
|
|
/// [&]{ on_enter_cnt++; },
|
2022-12-04 18:59:56 +08:00
|
|
|
|
/// [&]{ on_leave_cnt++; }
|
|
|
|
|
// );
|
|
|
|
|
/// ```
|
2022-12-20 01:51:25 +08:00
|
|
|
|
// NOLINTNEXTLINE
|
2022-12-04 18:54:49 +08:00
|
|
|
|
ComponentDecorator Hoverable(std::function<void()> on_enter,
|
2022-12-20 01:51:25 +08:00
|
|
|
|
// NOLINTNEXTLINE
|
2022-12-04 18:54:49 +08:00
|
|
|
|
std::function<void()> on_leave) {
|
|
|
|
|
return [on_enter, on_leave](Component component) {
|
2022-12-20 01:51:25 +08:00
|
|
|
|
return Hoverable(std::move(component), on_enter, on_leave);
|
2022-12-04 18:54:49 +08:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 18:59:56 +08:00
|
|
|
|
/// @brief Wrap a component. Gives the ability to know if it is hovered by the
|
|
|
|
|
/// mouse.
|
|
|
|
|
/// @param component the wrapped component.
|
|
|
|
|
/// @param on_change is called when the mouse enter or leave the component.
|
|
|
|
|
/// @ingroup component
|
|
|
|
|
///
|
|
|
|
|
/// ### Example
|
|
|
|
|
///
|
|
|
|
|
/// ```cpp
|
|
|
|
|
/// auto button = Button("exit", screen.ExitLoopClosure());
|
|
|
|
|
/// bool hovered = false;
|
|
|
|
|
/// auto button_hoverable = Hoverable(button,
|
|
|
|
|
// [&](bool hover) { hovered = hover;});
|
|
|
|
|
/// ```
|
2022-12-20 01:51:25 +08:00
|
|
|
|
// NOLINTNEXTLINE
|
2022-12-04 18:54:49 +08:00
|
|
|
|
Component Hoverable(Component component, std::function<void(bool)> on_change) {
|
|
|
|
|
return Hoverable(
|
2022-12-20 01:51:25 +08:00
|
|
|
|
std::move(component), //
|
2022-12-04 18:54:49 +08:00
|
|
|
|
[on_change] { on_change(true); }, //
|
|
|
|
|
[on_change] { on_change(false); } //
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 18:59:56 +08:00
|
|
|
|
/// @brief Wrap a component. Gives the ability to know if it is hovered by the
|
|
|
|
|
/// mouse.
|
|
|
|
|
/// @param on_change is called when the mouse enter or leave the component.
|
|
|
|
|
/// @ingroup component
|
|
|
|
|
///
|
|
|
|
|
/// ### Example
|
|
|
|
|
///
|
|
|
|
|
/// ```cpp
|
|
|
|
|
/// auto button = Button("exit", screen.ExitLoopClosure());
|
|
|
|
|
/// bool hovered = false;
|
|
|
|
|
/// button |= Hoverable([&](bool hover) { hovered = hover;});
|
|
|
|
|
/// ```
|
2022-12-20 01:51:25 +08:00
|
|
|
|
// NOLINTNEXTLINE
|
2022-12-04 18:54:49 +08:00
|
|
|
|
ComponentDecorator Hoverable(std::function<void(bool)> on_change) {
|
|
|
|
|
return [on_change](Component component) {
|
2022-12-20 01:51:25 +08:00
|
|
|
|
return Hoverable(std::move(component), on_change);
|
2022-12-04 18:54:49 +08:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace ftxui
|
|
|
|
|
|
|
|
|
|
// Copyright 2022 Arthur Sonzogni. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by the MIT license that can be found in
|
|
|
|
|
// the LICENSE file.
|