#include // for CapturedMouse #include // for function #include // for move #include "ftxui/component/component.hpp" // for ComponentDecorator, Hoverable, Make #include "ftxui/component/component_base.hpp" // for ComponentBase #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 #include "ftxui/screen/box.hpp" // for Box namespace ftxui { namespace { void Post(std::function f) { if (auto* screen = ScreenInteractive::Active()) { screen->Post(std::move(f)); return; } f(); } } // namespace /// @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); /// ``` // NOLINTNEXTLINE Component Hoverable(Component component, bool* hover) { class Impl : public ComponentBase { public: Impl(Component component, bool* hover) : component_(std::move(component)), hover_(hover) { 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(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 on_enter, std::function on_leave) { class Impl : public ComponentBase { public: Impl(Component component, std::function on_enter, std::function 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()) { const bool hover = box_.Contain(event.mouse().x, event.mouse().y) && CaptureMouse(event); if (hover != hover_) { Post(hover ? on_enter_ : on_leave_); } hover_ = hover; } return ComponentBase::OnEvent(event); } Component component_; Box box_; bool hover_ = false; std::function on_enter_; std::function on_leave_; }; return Make(std::move(component), std::move(on_enter), std::move(on_leave)); } /// @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) { return [hover](Component component) { return Hoverable(std::move(component), hover); }; } /// @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( /// [&]{ on_enter_cnt++; }, /// [&]{ on_leave_cnt++; } // ); /// ``` // NOLINTNEXTLINE ComponentDecorator Hoverable(std::function on_enter, // NOLINTNEXTLINE std::function on_leave) { return [on_enter, on_leave](Component component) { return Hoverable(std::move(component), on_enter, on_leave); }; } /// @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;}); /// ``` // NOLINTNEXTLINE Component Hoverable(Component component, std::function on_change) { return Hoverable( std::move(component), // [on_change] { on_change(true); }, // [on_change] { on_change(false); } // ); } /// @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;}); /// ``` // NOLINTNEXTLINE ComponentDecorator Hoverable(std::function on_change) { return [on_change](Component component) { return Hoverable(std::move(component), on_change); }; } } // 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.