aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-05-22 23:13:29 +0200
committerHampusM <hampus@hampusmat.com>2022-06-13 17:56:59 +0200
commitb74611d2b20fc071b8a699f2ce25e61f60118d6e (patch)
tree55d4dbf727724f7f527f2acebea83abd34317329 /src
parentb1183c712d94d38f75068bd62df006f73bd3550f (diff)
refactor: improve input handling & remove commands
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/bootstrap.cpp6
-rw-r--r--src/commands/insert_cell.cpp24
-rw-r--r--src/commands/insert_cell.hpp21
-rw-r--r--src/commands/move_cursor.cpp27
-rw-r--r--src/commands/move_cursor.hpp25
-rw-r--r--src/commands/quit.cpp8
-rw-r--r--src/commands/quit.hpp9
-rw-r--r--src/commands/toggle_pause.cpp21
-rw-r--r--src/commands/toggle_pause.hpp21
-rw-r--r--src/engine/engine.cpp24
-rw-r--r--src/engine/engine.hpp11
-rw-r--r--src/engine/graphics/scene.cpp34
-rw-r--r--src/engine/graphics/scene.hpp6
-rw-r--r--src/engine/user/input.cpp68
-rw-r--r--src/engine/user/input.hpp37
-rw-r--r--src/game/game.cpp98
-rw-r--r--src/game/game.hpp8
-rw-r--r--src/game/status_manager.cpp1
-rw-r--r--src/interfaces/game.hpp8
-rw-r--r--src/interfaces/input.hpp20
-rw-r--r--src/interfaces/statusline.hpp3
22 files changed, 167 insertions, 317 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6fd044f..0b40358 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -27,10 +27,6 @@ file(GLOB SOURCES
engine/user/cursor.cpp
randomization/generator.cpp
randomization/seed_generator.cpp
- commands/insert_cell.cpp
- commands/move_cursor.cpp
- commands/quit.cpp
- commands/toggle_pause.cpp
DI/container.cpp
DI/object_type.cpp)
diff --git a/src/bootstrap.cpp b/src/bootstrap.cpp
index 14aa922..6d42263 100644
--- a/src/bootstrap.cpp
+++ b/src/bootstrap.cpp
@@ -44,7 +44,7 @@ auto bootstrap() noexcept -> yacppdic::Container
auto container = yacppdic::Container();
container.bind<IArgumentParser>().to<ArgumentParser>();
- container.bind<IInputHandler>().to<InputHandler>();
+ container.bind<IUserInputObserver>().to<UserInputObserver>();
container.bind<ICursorController>().to<CursorController>();
container.bind<ICLIGameEngine>().to<CLIGameEngine>();
container.bind<ISeedGenerator>().to<SeedGenerator>();
@@ -52,7 +52,8 @@ auto bootstrap() noexcept -> yacppdic::Container
container.bind<IGameFactory>().to_factory(
[&container](
const std::shared_ptr<IScene> &scene,
- const std::shared_ptr<ICursorController> &cursor_controller)
+ const std::shared_ptr<ICursorController> &cursor_controller,
+ const std::shared_ptr<IUserInputObserver> user_input_observer)
{
std::shared_ptr<IStatusLine> statusline =
container.get<IStatusLineFactory>()(cursor_controller, scene);
@@ -71,6 +72,7 @@ auto bootstrap() noexcept -> yacppdic::Container
cursor_controller,
generation_tracker,
status_manager,
+ user_input_observer,
vector2_statusline_subscriber_adapter_factory);
});
diff --git a/src/commands/insert_cell.cpp b/src/commands/insert_cell.cpp
deleted file mode 100644
index 86a5a52..0000000
--- a/src/commands/insert_cell.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "insert_cell.hpp"
-
-#include <iostream>
-
-InsertCellCommand::InsertCellCommand(
- const std::shared_ptr<ICursorController> &cursor_controller,
- const std::shared_ptr<IScene> &scene) noexcept
- : _cursor_controller(cursor_controller), _scene(scene)
-{
-}
-
-void InsertCellCommand::execute() noexcept
-{
- const auto position = _cursor_controller->where();
-
- std::cout.put('x');
- std::cout.flush();
-
- _cursor_controller->move_to(position);
-
- auto matrix = _scene->get_matrix();
-
- matrix->set(position - Vector2({.x = 0U, .y = 1U}), "#");
-}
diff --git a/src/commands/insert_cell.hpp b/src/commands/insert_cell.hpp
deleted file mode 100644
index 9d54736..0000000
--- a/src/commands/insert_cell.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma once
-
-#include "interfaces/command.hpp"
-#include "interfaces/cursor.hpp"
-#include "interfaces/scene.hpp"
-
-#include <memory>
-
-class InsertCellCommand : public ICommand
-{
-public:
- InsertCellCommand(
- const std::shared_ptr<ICursorController> &cursor_controller,
- const std::shared_ptr<IScene> &scene) noexcept;
-
- void execute() noexcept override;
-
-private:
- const std::shared_ptr<ICursorController> &_cursor_controller;
- const std::shared_ptr<IScene> &_scene;
-};
diff --git a/src/commands/move_cursor.cpp b/src/commands/move_cursor.cpp
deleted file mode 100644
index 6bd8eda..0000000
--- a/src/commands/move_cursor.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#include "move_cursor.hpp"
-
-MoveCursorCommand::MoveCursorCommand(
- const Vector2 &direction,
- const std::shared_ptr<ICursorController> &cursor_controller,
- const std::shared_ptr<IScene> &scene) noexcept
- : _direction(direction), _cursor_controller(cursor_controller), _scene(scene)
-
-{
-}
-
-void MoveCursorCommand::execute() noexcept
-{
- constexpr int32_t amount = 1;
-
- const auto new_position =
- _cursor_controller->where().to_direction(_direction, amount);
-
- const auto scene_size = _scene->size();
-
- if (scene_size.validate_coords(new_position) != CoordsValidation::VALID)
- {
- return;
- }
-
- _cursor_controller->move_to(new_position);
-}
diff --git a/src/commands/move_cursor.hpp b/src/commands/move_cursor.hpp
deleted file mode 100644
index dc08c64..0000000
--- a/src/commands/move_cursor.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-
-#include "interfaces/command.hpp"
-#include "interfaces/cursor.hpp"
-#include "interfaces/scene.hpp"
-
-#include "engine/data/vector2.hpp"
-
-#include <memory>
-
-class MoveCursorCommand : public ICommand
-{
-public:
- MoveCursorCommand(
- const Vector2 &direction,
- const std::shared_ptr<ICursorController> &cursor_controller,
- const std::shared_ptr<IScene> &scene) noexcept;
-
- void execute() noexcept override;
-
-private:
- Vector2 _direction;
- const std::shared_ptr<ICursorController> &_cursor_controller;
- const std::shared_ptr<IScene> &_scene;
-};
diff --git a/src/commands/quit.cpp b/src/commands/quit.cpp
deleted file mode 100644
index c2a68e7..0000000
--- a/src/commands/quit.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "quit.hpp"
-
-#include <cstdlib>
-
-void QuitCommand::execute() noexcept
-{
- exit(EXIT_SUCCESS);
-}
diff --git a/src/commands/quit.hpp b/src/commands/quit.hpp
deleted file mode 100644
index cb1aefd..0000000
--- a/src/commands/quit.hpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#include "interfaces/command.hpp"
-
-class QuitCommand : public ICommand
-{
-public:
- void execute() noexcept override;
-};
diff --git a/src/commands/toggle_pause.cpp b/src/commands/toggle_pause.cpp
deleted file mode 100644
index 852e093..0000000
--- a/src/commands/toggle_pause.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "toggle_pause.hpp"
-
-#include <fmt/core.h>
-#include <utility>
-
-TogglePauseCommand::TogglePauseCommand(
- std::shared_ptr<IGenerationTracker> generation_tracker,
- std::shared_ptr<IStatusManager> status_manager) noexcept
- : _generation_tracker(std::move(generation_tracker)),
- _status_manager(std::move(status_manager))
-{
-}
-
-void TogglePauseCommand::execute() noexcept
-{
- auto onoff = !_generation_tracker->get_is_paused();
-
- _generation_tracker->set_is_paused(onoff);
-
- _status_manager->set_section_body(StatusLineSection::D, onoff ? "yes" : "no");
-}
diff --git a/src/commands/toggle_pause.hpp b/src/commands/toggle_pause.hpp
deleted file mode 100644
index 41427cc..0000000
--- a/src/commands/toggle_pause.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma once
-
-#include "interfaces/command.hpp"
-#include "interfaces/generation_tracker.hpp"
-#include "interfaces/status_manager.hpp"
-
-#include <memory>
-
-class TogglePauseCommand : public ICommand
-{
-public:
- explicit TogglePauseCommand(
- std::shared_ptr<IGenerationTracker> generation_tracker,
- std::shared_ptr<IStatusManager> status_manager) noexcept;
-
- void execute() noexcept override;
-
-private:
- std::shared_ptr<IGenerationTracker> _generation_tracker;
- std::shared_ptr<IStatusManager> _status_manager;
-};
diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp
index 774220a..c7605b5 100644
--- a/src/engine/engine.cpp
+++ b/src/engine/engine.cpp
@@ -9,11 +9,11 @@
CLIGameEngine::CLIGameEngine(
IGameFactory game_factory,
ISceneFactory scene_factory,
- std::shared_ptr<IInputHandler> input_handler,
+ std::shared_ptr<IUserInputObserver> user_input_observer,
std::shared_ptr<ICursorController> cursor_controller) noexcept
: _game_factory(std::move(game_factory)),
_scene_factory(std::move(scene_factory)),
- _input_handler(std::move(input_handler)),
+ _user_input_observer(std::move(user_input_observer)),
_cursor_controller(std::move(cursor_controller))
{
}
@@ -23,9 +23,8 @@ void CLIGameEngine::start() noexcept
std::shared_ptr<IScene> scene = _scene_factory(_cursor_controller);
scene->enter();
- _input_handler->enter_raw_mode();
- auto game = _game_factory(scene, _cursor_controller);
+ auto game = _game_factory(scene, _cursor_controller, _user_input_observer);
game->on_start();
@@ -33,17 +32,14 @@ void CLIGameEngine::start() noexcept
[this, scene, &game]()
{
scene->leave();
- _input_handler->leave_raw_mode();
game->on_exit();
}));
- _configure_input(game->get_input_config());
-
auto listen_input_thread = std::thread(normalize_lambda(
[this]()
{
- _input_handler->listen();
+ _user_input_observer->listen();
}));
auto last_update_time = std::chrono::system_clock::now();
@@ -68,17 +64,7 @@ void CLIGameEngine::start() noexcept
game->on_update();
last_update_time = std::chrono::system_clock::now();
- }
-}
-
-void CLIGameEngine::_configure_input(
- const std::unordered_map<char, std::shared_ptr<ICommand>> &input_config) noexcept
-{
- for (const auto &config_pair : input_config)
- {
- auto key = config_pair.first;
- auto command = config_pair.second;
- _input_handler->subscribe(key, command);
+ _user_input_observer->clear_currently_pressed();
}
}
diff --git a/src/engine/engine.hpp b/src/engine/engine.hpp
index 1e8a217..b34ea2b 100644
--- a/src/engine/engine.hpp
+++ b/src/engine/engine.hpp
@@ -12,7 +12,7 @@
#include <memory>
#include <unordered_map>
-constexpr auto MIN_TIME_SINCE_LAST_UPDATE_MILLIS = 100;
+constexpr auto MIN_TIME_SINCE_LAST_UPDATE_MILLIS = 40;
class CLIGameEngine : public ICLIGameEngine,
public yacppdic::AutoWirable<
@@ -20,14 +20,14 @@ class CLIGameEngine : public ICLIGameEngine,
CLIGameEngine,
IGameFactory,
ISceneFactory,
- IInputHandler,
+ IUserInputObserver,
ICursorController>
{
public:
CLIGameEngine(
IGameFactory game_factory,
ISceneFactory scene_factory,
- std::shared_ptr<IInputHandler> input_handler,
+ std::shared_ptr<IUserInputObserver> user_input_observer,
std::shared_ptr<ICursorController> cursor_controller) noexcept;
void start() noexcept override;
@@ -36,9 +36,6 @@ private:
IGameFactory _game_factory;
ISceneFactory _scene_factory;
- std::shared_ptr<IInputHandler> _input_handler;
+ std::shared_ptr<IUserInputObserver> _user_input_observer;
std::shared_ptr<ICursorController> _cursor_controller;
-
- void _configure_input(
- const std::unordered_map<char, std::shared_ptr<ICommand>> &input_config) noexcept;
};
diff --git a/src/engine/graphics/scene.cpp b/src/engine/graphics/scene.cpp
index 52613d8..b0d77b8 100644
--- a/src/engine/graphics/scene.cpp
+++ b/src/engine/graphics/scene.cpp
@@ -13,36 +13,60 @@
Scene::Scene(
IMatrixFactory<std::string_view> matrix_factory,
std::shared_ptr<ICursorController> cursor_controller) noexcept
- : _is_shown(false),
- _matrix(matrix_factory(size() - Bounds({.width = 0U, .height = 1U}))),
- _cursor_controller(std::move(cursor_controller))
+ : _matrix(matrix_factory(size() - Bounds({.width = 0U, .height = 1U}))),
+ _cursor_controller(std::move(cursor_controller)),
+ _is_shown(false)
{
_matrix->fill(" ");
}
void Scene::enter() noexcept
{
- if (_is_shown)
+ if (_is_shown || _original_termios != nullptr)
{
return;
}
+ // Enable alternative buffer
fmt::print(ENABLE_ALT_BUFFER, fmt::arg("esc", ESC));
std::cout.flush();
+ // Create a backup of the current terminal state
+ _original_termios = std::make_shared<termios>();
+ tcgetattr(STDIN_FILENO, _original_termios.get());
+
+ auto new_termios = termios(*_original_termios);
+
+ // Set the local mode flags of the new termios structure
+ //
+ // The following flags are disabled:
+ // ECHO - Echoing input characters
+ // ICANON - Canonical mode (line by line input)
+ // ISIG - Generate the corresponding signals for the characters
+ // INTR, QUIT, SUSP and DSUSP
+ new_termios.c_lflag &= static_cast<uint32_t>(~(ECHO | ICANON | ISIG));
+
+ // Set a new terminal state
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_termios);
+
_is_shown = true;
}
void Scene::leave() noexcept
{
- if (!_is_shown)
+ if (!_is_shown || _original_termios == nullptr)
{
return;
}
+ // Disable alternative buffer
fmt::print(DISABLE_ALT_BUFFER, fmt::arg("esc", ESC));
std::cout.flush();
+ // Restore the original terminal state
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, _original_termios.get());
+
+ _original_termios = nullptr;
_is_shown = false;
}
diff --git a/src/engine/graphics/scene.hpp b/src/engine/graphics/scene.hpp
index 268f8dc..e57e1f8 100644
--- a/src/engine/graphics/scene.hpp
+++ b/src/engine/graphics/scene.hpp
@@ -8,6 +8,7 @@
#include <memory>
#include <string_view>
+#include <termios.h>
constexpr fmt::string_view ENABLE_ALT_BUFFER = "{esc}[?1049h";
constexpr fmt::string_view DISABLE_ALT_BUFFER = "{esc}[?1049l";
@@ -29,8 +30,9 @@ public:
-> const std::shared_ptr<IMatrix<std::string_view>> & override;
private:
- bool _is_shown;
-
std::shared_ptr<IMatrix<std::string_view>> _matrix;
std::shared_ptr<ICursorController> _cursor_controller;
+
+ bool _is_shown;
+ std::shared_ptr<termios> _original_termios = nullptr;
};
diff --git a/src/engine/user/input.cpp b/src/engine/user/input.cpp
index 7e9fe22..ac6d660 100644
--- a/src/engine/user/input.cpp
+++ b/src/engine/user/input.cpp
@@ -3,66 +3,46 @@
#include <iostream>
#include <unistd.h>
-void InputHandler::listen() const noexcept
-{
- char character = 0;
+#include <iostream>
- while (!std::cin.read(&character, 1).fail())
+void UserInputObserver::listen() noexcept
+{
+ while (true)
{
- notify_subscribers(character, nullptr);
- }
-}
+ char character = 0;
-void InputHandler::subscribe(
- const Event &event,
- const std::shared_ptr<ISubscriber<Context>> &subscriber) noexcept
-{
- auto event_index = _event_as_index(event);
+ if (std::cin.read(&character, 1).fail())
+ {
+ continue;
+ }
- _subscribers.at(event_index).push_back(subscriber);
-}
+ _currently_pressed_mutex.lock();
-void InputHandler::notify_subscribers(const Event &event, const Context &context)
- const noexcept
-{
- auto event_index = _event_as_index(event);
+ if (character != _currently_pressed)
+ {
+ _currently_pressed = character;
+ }
- for (const auto &subscriber : _subscribers.at(event_index))
- {
- subscriber->update(context);
+ _currently_pressed_mutex.unlock();
}
}
-void InputHandler::enter_raw_mode() noexcept
+bool UserInputObserver::is_key_pressed(Key key) noexcept
{
- if (_original_termios == nullptr)
- {
- _original_termios = std::make_shared<termios>();
- }
+ _currently_pressed_mutex.lock();
- tcgetattr(STDIN_FILENO, _original_termios.get());
+ const auto is_key_pressed = key == _currently_pressed;
- auto raw_termios = termios(*_original_termios);
+ _currently_pressed_mutex.unlock();
- raw_termios.c_lflag &= static_cast<uint32_t>(~(ECHO | ICANON | ISIG));
-
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw_termios);
+ return is_key_pressed;
}
-void InputHandler::leave_raw_mode() noexcept
+void UserInputObserver::clear_currently_pressed() noexcept
{
- if (_original_termios == nullptr)
- {
- return;
- }
-
- tcsetattr(STDIN_FILENO, TCSAFLUSH, _original_termios.get());
+ _currently_pressed_mutex.lock();
- _original_termios = nullptr;
-}
+ _currently_pressed = 0;
-auto InputHandler::_event_as_index(const Event &event) noexcept
- -> InputHandler::SubscribersSizeType
-{
- return static_cast<SubscribersSizeType>(static_cast<uint8_t>(event));
+ _currently_pressed_mutex.unlock();
}
diff --git a/src/engine/user/input.hpp b/src/engine/user/input.hpp
index f17472b..2fb97ac 100644
--- a/src/engine/user/input.hpp
+++ b/src/engine/user/input.hpp
@@ -5,40 +5,23 @@
#include <yacppdic/auto_wirable.hpp>
-#include <array>
-#include <climits>
#include <memory>
-#include <termios.h>
-#include <vector>
+#include <mutex>
-class InputHandler : public IInputHandler,
- public yacppdic::AutoWirable<IInputHandler, InputHandler>
+class UserInputObserver
+ : public IUserInputObserver,
+ public yacppdic::AutoWirable<IUserInputObserver, UserInputObserver>
{
public:
- InputHandler() noexcept = default;
+ UserInputObserver() noexcept = default;
- void listen() const noexcept override;
+ void listen() noexcept override;
- void subscribe(
- const Event &event,
- const std::shared_ptr<ISubscriber<Context>> &subscriber) noexcept override;
+ bool is_key_pressed(Key key) noexcept override;
- void notify_subscribers(const Event &event, const Context &context)
- const noexcept override;
-
- void enter_raw_mode() noexcept override;
-
- void leave_raw_mode() noexcept override;
+ void clear_currently_pressed() noexcept override;
private:
- std::array<
- std::vector<std::shared_ptr<ISubscriber<Context>>>,
- static_cast<std::size_t>(CHAR_MAX * 2U)>
- _subscribers;
-
- std::shared_ptr<termios> _original_termios = nullptr;
-
- using SubscribersSizeType = decltype(_subscribers)::size_type;
-
- static auto _event_as_index(const Event &event) noexcept -> SubscribersSizeType;
+ Key _currently_pressed;
+ std::mutex _currently_pressed_mutex;
};
diff --git a/src/game/game.cpp b/src/game/game.cpp
index b9f5e3a..5606e71 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -1,13 +1,9 @@
#include "game.hpp"
-#include "commands/insert_cell.hpp"
-#include "commands/move_cursor.hpp"
-#include "commands/quit.hpp"
-#include "commands/toggle_pause.hpp"
-
#include <fmt/core.h>
#include <chrono>
+#include <cstdlib>
#include <iostream>
#include <utility>
@@ -16,12 +12,14 @@ Game::Game(
std::shared_ptr<ICursorController> cursor_controller,
std::shared_ptr<IGenerationTracker> generation_tracker,
std::shared_ptr<IStatusManager> status_manager,
+ std::shared_ptr<IUserInputObserver> user_input_observer,
IStatusLineSubscriberAdapterFactory<Vector2>
vector2_statusline_subscriber_adapter_factory) noexcept
: _scene(std::move(scene)),
_cursor_controller(std::move(cursor_controller)),
_generation_tracker(std::move(generation_tracker)),
_status_manager(std::move(status_manager)),
+ _user_input_observer(std::move(user_input_observer)),
_vector2_statusline_subscriber_adapter_factory(
vector2_statusline_subscriber_adapter_factory)
{
@@ -71,11 +69,63 @@ void Game::on_start() noexcept
_status_manager->set_section_body(StatusLineSection::F, "0");
+ _status_manager->set_section_body(StatusLineSection::G, "lol");
+
_last_update_time = std::chrono::system_clock::now();
}
void Game::on_update() noexcept
{
+ if (_user_input_observer->is_key_pressed('q'))
+ {
+ std::exit(EXIT_SUCCESS);
+ }
+
+ if (_user_input_observer->is_key_pressed('i'))
+ {
+ const auto position = _cursor_controller->where();
+
+ std::cout.put('x');
+ std::cout.flush();
+
+ _cursor_controller->move_to(position);
+
+ auto matrix = _scene->get_matrix();
+
+ const auto pos_offset = Vector2({.x = 0U, .y = 1U});
+
+ matrix->set(position - pos_offset, "#");
+ }
+
+ if (_user_input_observer->is_key_pressed('h'))
+ {
+ _move_cursor(Vector2::left());
+ }
+
+ if (_user_input_observer->is_key_pressed('j'))
+ {
+ _move_cursor(Vector2::down());
+ }
+
+ if (_user_input_observer->is_key_pressed('k'))
+ {
+ _move_cursor(Vector2::up());
+ }
+
+ if (_user_input_observer->is_key_pressed('l'))
+ {
+ _move_cursor(Vector2::right());
+ }
+
+ if (_user_input_observer->is_key_pressed('p'))
+ {
+ auto onoff = !_generation_tracker->get_is_paused();
+
+ _generation_tracker->set_is_paused(onoff);
+
+ _status_manager->set_section_body(StatusLineSection::D, onoff ? "yes" : "no");
+ }
+
const auto time_since_last_update =
std::chrono::system_clock::now() - _last_update_time;
@@ -84,6 +134,10 @@ void Game::on_update() noexcept
fmt::format("{} nanoseconds", time_since_last_update.count()));
_last_update_time = std::chrono::system_clock::now();
+
+ _status_manager->set_section_body(
+ StatusLineSection::G,
+ fmt::format("{}", _user_input_observer->is_key_pressed('v')));
}
void Game::on_exit() const noexcept
@@ -101,28 +155,16 @@ void Game::on_exit() const noexcept
std::cout.flush();
}
-auto Game::get_input_config() const noexcept
- -> std::unordered_map<char, std::shared_ptr<ICommand>>
+void Game::_move_cursor(const Vector2 &direction) noexcept
{
- return {
- {'q', std::make_shared<QuitCommand>()},
- {'i', std::make_shared<InsertCellCommand>(_cursor_controller, _scene)},
- {'p', std::make_shared<TogglePauseCommand>(_generation_tracker, _status_manager)},
- {'k',
- std::make_shared<MoveCursorCommand>(Vector2::up(), _cursor_controller, _scene)},
- {'j',
- std::make_shared<MoveCursorCommand>(
- Vector2::down(),
- _cursor_controller,
- _scene)},
- {'h',
- std::make_shared<MoveCursorCommand>(
- Vector2::left(),
- _cursor_controller,
- _scene)},
- {'l',
- std::make_shared<MoveCursorCommand>(
- Vector2::right(),
- _cursor_controller,
- _scene)}};
+ const auto new_position = _cursor_controller->where().to_direction(direction, 1);
+
+ const auto scene_size = _scene->size();
+
+ if (scene_size.validate_coords(new_position) != CoordsValidation::VALID)
+ {
+ return;
+ }
+
+ _cursor_controller->move_to(new_position);
}
diff --git a/src/game/game.hpp b/src/game/game.hpp
index fb2ad63..fb6a5ed 100644
--- a/src/game/game.hpp
+++ b/src/game/game.hpp
@@ -3,6 +3,7 @@
#include "interfaces/cursor.hpp"
#include "interfaces/game.hpp"
#include "interfaces/generation_tracker.hpp"
+#include "interfaces/input.hpp"
#include "interfaces/scene.hpp"
#include "interfaces/status_manager.hpp"
#include "interfaces/statusline_subscriber_adapter.hpp"
@@ -18,6 +19,7 @@ public:
std::shared_ptr<ICursorController> cursor_controller,
std::shared_ptr<IGenerationTracker> generation_tracker,
std::shared_ptr<IStatusManager> status_manager,
+ std::shared_ptr<IUserInputObserver> user_input_observer,
IStatusLineSubscriberAdapterFactory<Vector2>
vector2_statusline_subscriber_adapter_factory) noexcept;
@@ -27,16 +29,16 @@ public:
void on_exit() const noexcept override;
- [[nodiscard]] auto get_input_config() const noexcept
- -> std::unordered_map<char, std::shared_ptr<ICommand>> override;
-
private:
std::shared_ptr<IScene> _scene;
std::shared_ptr<ICursorController> _cursor_controller;
std::shared_ptr<IGenerationTracker> _generation_tracker;
std::shared_ptr<IStatusManager> _status_manager;
+ std::shared_ptr<IUserInputObserver> _user_input_observer;
IStatusLineSubscriberAdapterFactory<Vector2>
_vector2_statusline_subscriber_adapter_factory;
std::chrono::system_clock::time_point _last_update_time;
+
+ void _move_cursor(const Vector2 &direction) noexcept;
};
diff --git a/src/game/status_manager.cpp b/src/game/status_manager.cpp
index 33174d1..9bd4f37 100644
--- a/src/game/status_manager.cpp
+++ b/src/game/status_manager.cpp
@@ -18,6 +18,7 @@ void StatusManager::initialize() noexcept
_statusline->set_section_length(StatusLineSection::D, 20U);
_statusline->set_section_length(StatusLineSection::E, 25U);
_statusline->set_section_length(StatusLineSection::F, 50U);
+ _statusline->set_section_length(StatusLineSection::G, 25U);
_statusline->initialize_background();
}
diff --git a/src/interfaces/game.hpp b/src/interfaces/game.hpp
index a54782a..3aac6a9 100644
--- a/src/interfaces/game.hpp
+++ b/src/interfaces/game.hpp
@@ -2,12 +2,12 @@
#include "interfaces/command.hpp"
#include "interfaces/cursor.hpp"
+#include "interfaces/input.hpp"
#include "interfaces/scene.hpp"
#include <yacppdic/factory.hpp>
#include <memory>
-#include <unordered_map>
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
class IGame
@@ -20,11 +20,9 @@ public:
virtual void on_update() noexcept = 0;
virtual void on_exit() const noexcept = 0;
-
- [[nodiscard]] virtual auto get_input_config() const noexcept
- -> std::unordered_map<char, std::shared_ptr<ICommand>> = 0;
};
using IGameFactory = yacppdic::Factory<std::unique_ptr<IGame>(
const std::shared_ptr<IScene> &scene,
- const std::shared_ptr<ICursorController> &cursor_controller)>;
+ const std::shared_ptr<ICursorController> &cursor_controller,
+ const std::shared_ptr<IUserInputObserver> user_input_observer)>;
diff --git a/src/interfaces/input.hpp b/src/interfaces/input.hpp
index f93a8e2..8239e48 100644
--- a/src/interfaces/input.hpp
+++ b/src/interfaces/input.hpp
@@ -7,24 +7,16 @@
#include <memory>
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
-class IInputHandler : public IPublisher<char, std::nullptr_t>
+class IUserInputObserver
{
public:
- using Event = char;
- using Context = std::nullptr_t;
+ using Key = char;
- ~IInputHandler() noexcept override = default;
+ virtual ~IUserInputObserver() noexcept = default;
- virtual void listen() const noexcept = 0;
+ virtual void listen() noexcept = 0;
- void subscribe(
- const Event &event,
- const std::shared_ptr<ISubscriber<Context>> &subscriber) noexcept override = 0;
+ virtual bool is_key_pressed(Key key) noexcept = 0;
- void notify_subscribers(const Event &event, const Context &context)
- const noexcept override = 0;
-
- virtual void enter_raw_mode() noexcept = 0;
-
- virtual void leave_raw_mode() noexcept = 0;
+ virtual void clear_currently_pressed() noexcept = 0;
};
diff --git a/src/interfaces/statusline.hpp b/src/interfaces/statusline.hpp
index 2e97ed6..c66a2d3 100644
--- a/src/interfaces/statusline.hpp
+++ b/src/interfaces/statusline.hpp
@@ -14,7 +14,8 @@ enum StatusLineSection
C = 2,
D = 3,
E = 4,
- F = 5
+ F = 5,
+ G = 6
};
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)