#pragma once #include "DI/auto_wirable.hpp" #include "interfaces/cursor.hpp" #include "engine/data/vector2.hpp" #include <array> #include <fmt/core.h> #include <memory> #include <string_view> #include <unordered_map> constexpr std::string_view MOVE_CURSOR_UP = "{esc}[{amount}A"; constexpr std::string_view MOVE_CURSOR_DOWN = "{esc}[{amount}B"; constexpr std::string_view MOVE_CURSOR_LEFT = "{esc}[{amount}D"; constexpr std::string_view MOVE_CURSOR_RIGHT = "{esc}[{amount}C"; constexpr fmt::string_view MOVE_CURSOR_TO = "{esc}[{row};{column}H"; constexpr fmt::string_view REQUEST_CURSOR_POSITION = "{esc}[6n"; constexpr fmt::string_view CURSOR_VISIBLE = "{esc}[?25h"; constexpr fmt::string_view CURSOR_INVISIBLE = "{esc}[?25l"; const std::unordered_map<Vector2, std::string_view, Vector2Hasher> direction_format_map = {{Vector2::up(), MOVE_CURSOR_UP}, {Vector2::down(), MOVE_CURSOR_DOWN}, {Vector2::left(), MOVE_CURSOR_LEFT}, {Vector2::right(), MOVE_CURSOR_RIGHT}}; class CursorController : public ICursorController, public AutoWirable<ICursorController, CursorController> { public: CursorController() noexcept; void move(const Vector2 &direction, const uint32_t &amount) noexcept override; void move_to(const Vector2 &position, bool silent) noexcept override; [[nodiscard]] Vector2 where() const noexcept override; void ensure_position() noexcept override; void hide() noexcept override; void show() noexcept override; void subscribe(const Event &event, const Subscriber &subscriber) noexcept override; void notify_subscribers(const Event &event, const Context &context) const noexcept override; private: Vector2 _position; std::unordered_map<CursorEvent, std::vector<Subscriber>> _subscribers; };