From f3f39c24f1d2c6310556545a56170b0c897e106d Mon Sep 17 00:00:00 2001 From: Totto16 Date: Sun, 5 May 2024 00:41:17 +0200 Subject: [PATCH 01/76] HUGE input refactoring (WIP): - remove capabilities functions and make new input manager / input handlers, that hide cross platform stuff - name mouse / touch inputs pointer events - add navigation events - add menu commands (toggleable) - add SDL_key + SDL_Keymod wrapper - handle special inputs correctly - add joystick wrappers, that work on every platform - refactor some major logic in the input handling for the game / navigation - refactor settings - require git to always have git information --- settings.json | 53 +- src/application.cpp | 71 +-- src/application.hpp | 40 +- src/game/game.cpp | 25 +- src/game/game.hpp | 13 +- src/game/grid.cpp | 2 +- src/game/grid.hpp | 2 +- src/game/meson.build | 2 - src/game/tetrion.cpp | 38 +- src/game/tetrion.hpp | 7 +- src/graphics/point.hpp | 2 + src/graphics/sdl_context.cpp | 11 - src/helper/color_literals.hpp | 1 - src/helper/git_helper.hpp | 5 +- src/helper/meson.build | 28 +- src/helper/platform.hpp | 45 ++ src/helper/utils.hpp | 23 + src/{platform => input}/console_buttons.hpp | 0 .../input.cpp => input/game_input.cpp} | 34 +- src/input/game_input.hpp | 87 +++ src/input/input.cpp | 136 ++++ src/input/input.hpp | 109 ++++ src/{game => input}/input_creator.cpp | 36 +- src/{game => input}/input_creator.hpp | 5 +- src/input/joystick_input.cpp | 471 ++++++++++++++ src/input/joystick_input.hpp | 184 ++++++ src/input/keyboard_input.cpp | 133 ++++ src/input/keyboard_input.hpp | 151 +++++ src/input/meson.build | 19 + src/input/mouse_input.cpp | 81 +++ src/input/mouse_input.hpp | 25 + src/{platform => input}/replay_input.cpp | 18 +- src/input/replay_input.hpp | 30 + .../touch_input.cpp} | 72 ++- src/input/touch_input.hpp | 189 ++++++ src/main.cpp | 6 +- src/manager/controls.hpp | 48 -- src/manager/event_dispatcher.hpp | 31 +- src/manager/event_listener.hpp | 5 +- src/manager/key_codes.hpp | 589 ------------------ src/manager/meson.build | 7 +- src/manager/music_manager.cpp | 22 +- src/manager/music_manager.hpp | 3 +- src/manager/sdl_key.cpp | 239 +++++++ src/manager/sdl_key.hpp | 112 ++++ src/manager/service_provider.hpp | 23 +- src/manager/settings.hpp | 91 --- src/manager/settings_manager.cpp | 21 + src/manager/settings_manager.hpp | 68 ++ src/meson.build | 3 +- src/platform/android_input.hpp | 41 -- src/platform/capabilities.cpp | 426 ------------- src/platform/capabilities.hpp | 150 ----- src/platform/console_input.cpp | 131 ---- src/platform/console_input.hpp | 34 - src/platform/input.hpp | 78 --- src/platform/keyboard_input.cpp | 81 --- src/platform/keyboard_input.hpp | 23 - src/platform/meson.build | 31 - src/platform/platform.hpp | 34 - src/platform/replay_input.hpp | 21 - src/scenes/about_page/about_page.cpp | 26 +- src/scenes/about_page/about_page.hpp | 2 +- src/scenes/game_over/game_over.cpp | 18 +- src/scenes/game_over/game_over.hpp | 2 +- src/scenes/main_menu/main_menu.cpp | 33 +- src/scenes/main_menu/main_menu.hpp | 2 +- src/scenes/meson.build | 1 - .../multiplayer_menu/multiplayer_menu.cpp | 35 +- .../multiplayer_menu/multiplayer_menu.hpp | 2 +- src/scenes/online_lobby/online_lobby.cpp | 35 +- src/scenes/online_lobby/online_lobby.hpp | 2 +- src/scenes/pause/meson.build | 4 - src/scenes/pause/pause.cpp | 59 -- src/scenes/pause/pause.hpp | 21 - .../play_select_menu/play_select_menu.cpp | 40 +- .../play_select_menu/play_select_menu.hpp | 2 +- .../recording_selector/recording_chooser.cpp | 16 +- .../recording_selector/recording_chooser.hpp | 2 +- .../recording_component.cpp | 31 +- .../recording_component.hpp | 2 +- .../recording_selector/recording_selector.cpp | 40 +- .../recording_selector/recording_selector.hpp | 2 +- src/scenes/replay_game/replay_game.cpp | 34 +- src/scenes/replay_game/replay_game.hpp | 2 +- src/scenes/scene.cpp | 3 - src/scenes/scene.hpp | 4 +- src/scenes/scene_id.hpp | 1 - .../settings_menu/color_setting_row.cpp | 51 +- .../settings_menu/color_setting_row.hpp | 6 +- src/scenes/settings_menu/settings_menu.cpp | 53 +- src/scenes/settings_menu/settings_menu.hpp | 14 +- src/scenes/single_player_game/meson.build | 2 + src/scenes/single_player_game/pause.cpp | 65 ++ src/scenes/single_player_game/pause.hpp | 27 + .../single_player_game/single_player_game.cpp | 39 +- .../single_player_game/single_player_game.hpp | 3 +- src/ui/components/abstract_slider.hpp | 39 +- src/ui/components/button.hpp | 31 +- src/ui/components/color_picker.cpp | 71 +-- src/ui/components/color_picker.hpp | 4 +- src/ui/components/image_view.cpp | 2 +- src/ui/components/image_view.hpp | 2 +- src/ui/components/label.cpp | 2 +- src/ui/components/label.hpp | 3 +- src/ui/components/link_label.cpp | 5 +- src/ui/components/link_label.hpp | 3 +- src/ui/components/textinput.cpp | 10 +- src/ui/components/textinput.hpp | 2 +- src/ui/focusable.hpp | 1 + src/ui/hoverable.hpp | 36 +- src/ui/layouts/focus_layout.cpp | 33 +- src/ui/layouts/focus_layout.hpp | 23 +- src/ui/layouts/grid_layout.cpp | 42 +- src/ui/layouts/grid_layout.hpp | 3 +- src/ui/layouts/scroll_layout.cpp | 149 +++-- src/ui/layouts/scroll_layout.hpp | 3 +- src/ui/layouts/tile_layout.cpp | 43 +- src/ui/layouts/tile_layout.hpp | 2 +- src/ui/widget.cpp | 15 +- src/ui/widget.hpp | 2 +- tests/graphics/meson.build | 3 + tests/graphics/sdl_key.cpp | 314 ++++++++++ tests/meson.build | 26 +- 124 files changed, 3444 insertions(+), 2572 deletions(-) create mode 100644 src/helper/platform.hpp rename src/{platform => input}/console_buttons.hpp (100%) rename src/{platform/input.cpp => input/game_input.cpp} (70%) create mode 100644 src/input/game_input.hpp create mode 100644 src/input/input.cpp create mode 100644 src/input/input.hpp rename src/{game => input}/input_creator.cpp (78%) rename src/{game => input}/input_creator.hpp (91%) create mode 100644 src/input/joystick_input.cpp create mode 100644 src/input/joystick_input.hpp create mode 100644 src/input/keyboard_input.cpp create mode 100644 src/input/keyboard_input.hpp create mode 100644 src/input/meson.build create mode 100644 src/input/mouse_input.cpp create mode 100644 src/input/mouse_input.hpp rename src/{platform => input}/replay_input.cpp (78%) create mode 100644 src/input/replay_input.hpp rename src/{platform/android_input.cpp => input/touch_input.cpp} (57%) create mode 100644 src/input/touch_input.hpp delete mode 100644 src/manager/controls.hpp delete mode 100644 src/manager/key_codes.hpp create mode 100644 src/manager/sdl_key.cpp create mode 100644 src/manager/sdl_key.hpp delete mode 100644 src/manager/settings.hpp create mode 100644 src/manager/settings_manager.cpp create mode 100644 src/manager/settings_manager.hpp delete mode 100644 src/platform/android_input.hpp delete mode 100644 src/platform/capabilities.cpp delete mode 100644 src/platform/capabilities.hpp delete mode 100644 src/platform/console_input.cpp delete mode 100644 src/platform/console_input.hpp delete mode 100644 src/platform/input.hpp delete mode 100644 src/platform/keyboard_input.cpp delete mode 100644 src/platform/keyboard_input.hpp delete mode 100644 src/platform/meson.build delete mode 100644 src/platform/platform.hpp delete mode 100644 src/platform/replay_input.hpp delete mode 100644 src/scenes/pause/meson.build delete mode 100644 src/scenes/pause/pause.cpp delete mode 100644 src/scenes/pause/pause.hpp create mode 100644 src/scenes/single_player_game/pause.cpp create mode 100644 src/scenes/single_player_game/pause.hpp create mode 100644 tests/graphics/meson.build create mode 100644 tests/graphics/sdl_key.cpp diff --git a/settings.json b/settings.json index 772b03e4..1afd1dc0 100644 --- a/settings.json +++ b/settings.json @@ -1,15 +1,46 @@ { - "platform": "pc", - "controls": { - "type": "keyboard", - "drop": "W", - "hold": "E", - "move_down": "S", - "move_left": "A", - "move_right": "D", - "rotate_left": "Left", - "rotate_right": "Right" - }, + "controls": [ + { + "type": "keyboard", + "drop": "W", + "hold": "E", + "move_down": "S", + "move_left": "A", + "move_right": "D", + "rotate_left": "Left", + "rotate_right": "Right", + "menu": { + "pause": "Esc", + "open_settings": "E" + } + }, + { + "type": "joystick", + "identification": { + "guid": "GUID1" + }, + "drop": "W", + "hold": "E", + "move_down": "S", + "move_left": "A", + "move_right": "D", + "rotate_left": "Y", + "rotate_right": "X" + }, + { + "type": "joystick", + "identification": { + "guid": "GUID2" + }, + "drop": "W", + "hold": "E", + "move_down": "S", + "move_left": "A", + "move_right": "D", + "rotate_left": "Y", + "rotate_right": "X" + } + ], "volume": 0.2, "discord": false } diff --git a/src/application.cpp b/src/application.cpp index dd36bce3..3741f663 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -2,10 +2,11 @@ #include "helper/errors.hpp" #include "helper/message_box.hpp" #include "helper/sleep.hpp" -#include "platform/capabilities.hpp" +#include "input/input.hpp" #include "scenes/scene.hpp" #include +#include #include #include @@ -13,6 +14,10 @@ #include "helper/console_helpers.hpp" #endif +#ifdef DEBUG_BUILD +#include "graphics/text.hpp" +#endif + namespace { [[nodiscard]] helper::MessageBox::Type get_notification_level(helper::error::Severity severity) { @@ -24,14 +29,15 @@ namespace { } // namespace -Application::Application(std::unique_ptr&& window, const std::vector& arguments) try +Application::Application(std::shared_ptr&& window, const std::vector& arguments) try : m_command_line_arguments{ arguments }, m_window{ std::move(window) }, m_renderer{ *m_window, m_command_line_arguments.target_fps.has_value() ? Renderer::VSync::Disabled : Renderer::VSync::Enabled }, m_music_manager{ this, num_audio_channels }, - m_target_framerate{ m_command_line_arguments.target_fps }, - m_event_dispatcher{ m_window.get() } { + m_input_manager{ std::make_shared(m_window) }, + m_settings_manager{ this }, + m_target_framerate{ m_command_line_arguments.target_fps } { initialize(); } catch (const helper::GeneralError& general_error) { const auto severity = general_error.severity(); @@ -103,7 +109,7 @@ void Application::run() { } } -void Application::handle_event(const SDL_Event& event, const Window* window) { +void Application::handle_event(const SDL_Event& event) { if (event.type == SDL_QUIT) { m_is_running = false; } @@ -111,7 +117,7 @@ void Application::handle_event(const SDL_Event& event, const Window* window) { auto handled = false; for (const auto& scene : std::ranges::views::reverse(m_scene_stack)) { - if (not handled and scene->handle_event(event, window)) { + if (not handled and scene->handle_event(m_input_manager, event)) { handled = true; } @@ -122,8 +128,8 @@ void Application::handle_event(const SDL_Event& event, const Window* window) { } // if the scene is not covering the whole screen, it should give scenes in the background mouse events, but keyboard events are still only captured by the scene in focus, we also detect unhovers for whole scenes here - if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any)) { - if (not utils::is_event_in(window, event, scene->get_layout().get_rect())) { + if (const auto result = m_input_manager->get_pointer_event(event); result.has_value()) { + if (not result->is_in(scene->get_layout().get_rect())) { scene->on_unhover(); } } @@ -134,29 +140,22 @@ void Application::handle_event(const SDL_Event& event, const Window* window) { } // handle some special events + const auto is_special_event = m_input_manager->process_special_inputs(event); + if (is_special_event) { - switch (event.type) { - case SDL_WINDOWEVENT: - switch (event.window.event) { - case SDL_WINDOWEVENT_HIDDEN: - case SDL_WINDOWEVENT_MINIMIZED: - case SDL_WINDOWEVENT_LEAVE: { - for (const auto& scene : m_scene_stack) { - scene->on_unhover(); - } - break; + if (const auto special_event = is_special_event.get_additional(); special_event.has_value()) { + if (special_event.value() == input::SpecialRequest::WindowFocusLost) { + for (const auto& scene : m_scene_stack) { + scene->on_unhover(); } - default: - break; } - break; - default: - break; + } } - // this global event handlers (atm only one) are special cases, they receive all inputs if they are not handled by the scenes explicably - if (m_music_manager.handle_event(event)) { + // this global event handlers (atm only one) are special cases, they receive all inputs if they are not handled by the scenes explicitly + + if (m_music_manager.handle_event(m_input_manager, event)) { return; } } @@ -246,20 +245,20 @@ void Application::render() const { void Application::initialize() { - try_load_settings(); load_resources(); push_scene(scenes::create_scene(*this, SceneId::MainMenu, ui::FullScreenLayout{ *m_window })); #ifdef DEBUG_BUILD m_fps_text = std::make_unique( - this, "FPS: ?", fonts().get(FontId::Default), Color::white(), std::pair{ 0.95, 0.95 }, + this, "FPS: ?", font_manager().get(FontId::Default), Color::white(), + std::pair{ 0.95, 0.95 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }, ui::RelativeLayout{ window(), 0.0, 0.0, 0.1, 0.05 }, false ); #endif #if defined(_HAVE_DISCORD_SDK) - if (m_settings.discord) { + if (m_settings_manager.discord()) { auto discord_instance = DiscordInstance::initialize(); if (not discord_instance.has_value()) { spdlog::warn( @@ -274,22 +273,6 @@ void Application::initialize() { #endif } -void Application::try_load_settings() { - const std::filesystem::path settings_file = utils::get_root_folder() / settings_filename; - - const auto result = json::try_parse_json_file(settings_file); - - if (result.has_value()) { - m_settings = result.value(); - } else { - spdlog::error("unable to load settings from \"{}\": {}", settings_filename, result.error()); - spdlog::warn("applying default settings"); - } - - // apply settings - m_music_manager.set_volume(m_settings.volume); -} - void Application::load_resources() { constexpr auto fonts_size = 128; const std::vector> fonts{ diff --git a/src/application.hpp b/src/application.hpp index 32eb5d58..31b1df79 100644 --- a/src/application.hpp +++ b/src/application.hpp @@ -1,22 +1,19 @@ #pragma once #include "graphics/renderer.hpp" -#include "graphics/sdl_context.hpp" #include "graphics/window.hpp" #include "helper/command_line_arguments.hpp" #include "helper/types.hpp" +#include "input/input.hpp" #include "manager/event_dispatcher.hpp" #include "manager/event_listener.hpp" #include "manager/music_manager.hpp" #include "manager/resource_manager.hpp" #include "manager/service_provider.hpp" +#include "manager/settings_manager.hpp" #include "scenes/scene.hpp" #include "ui/components/label.hpp" -#ifdef DEBUG_BUILD -#include "graphics/text.hpp" -#endif - #include #include @@ -25,12 +22,12 @@ struct Application final : public EventListener, public ServiceProvider { static constexpr auto num_audio_channels = u8{ 2 }; CommandLineArguments m_command_line_arguments; - std::unique_ptr m_window; + std::shared_ptr m_window; Renderer m_renderer; bool m_is_running{ true }; MusicManager m_music_manager; - static constexpr auto settings_filename = "settings.json"; - Settings m_settings; + std::shared_ptr m_input_manager; + SettingsManager m_settings_manager; FontManager m_font_manager; helper::optional m_target_framerate; @@ -50,17 +47,19 @@ struct Application final : public EventListener, public ServiceProvider { std::vector> m_scene_stack; public: - Application(std::unique_ptr&& window, const std::vector& arguments); + Application(std::shared_ptr&& window, const std::vector& arguments); Application(const Application&) = delete; Application& operator=(const Application&) = delete; void run(); - void handle_event(const SDL_Event& event, const Window* window) override; + void handle_event(const SDL_Event& event) override; virtual void update(); virtual void render() const; + //TODO: move those functions bodies to the cpp + void push_scene(std::unique_ptr scene) { m_scene_stack.push_back(std::move(scene)); } @@ -74,10 +73,10 @@ struct Application final : public EventListener, public ServiceProvider { return m_event_dispatcher; } - FontManager& fonts() override { + FontManager& font_manager() override { return m_font_manager; } - const FontManager& fonts() const override { + const FontManager& font_manager() const override { return m_font_manager; } @@ -87,11 +86,11 @@ struct Application final : public EventListener, public ServiceProvider { const CommandLineArguments& command_line_arguments() const override { return m_command_line_arguments; } - Settings& settings() override { - return m_settings; + SettingsManager& settings_manager() override { + return m_settings_manager; } - const Settings& settings() const override { - return m_settings; + const SettingsManager& settings_manager() const override { + return m_settings_manager; } MusicManager& music_manager() override { return m_music_manager; @@ -112,6 +111,14 @@ struct Application final : public EventListener, public ServiceProvider { return *m_window; } + [[nodiscard]] input::InputManager& input_manager() override { + return *m_input_manager; + } + + [[nodiscard]] const input::InputManager& input_manager() const override { + return *m_input_manager; + } + #if defined(_HAVE_DISCORD_SDK) @@ -124,6 +131,5 @@ struct Application final : public EventListener, public ServiceProvider { private: void initialize(); - void try_load_settings(); void load_resources(); }; diff --git a/src/game/game.cpp b/src/game/game.cpp index a7a96c25..81ca264c 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -1,10 +1,12 @@ #include "game.hpp" -#include "platform/replay_input.hpp" +#include "helper/magic_enum_wrapper.hpp" +#include "helper/utils.hpp" +#include "input/replay_input.hpp" Game::Game( ServiceProvider* const service_provider, - std::unique_ptr&& input, + const std::shared_ptr& input, const tetrion::StartingParameters& starting_parameters, const ui::Layout& layout, bool is_top_level @@ -60,7 +62,7 @@ void Game::render(const ServiceProvider& service_provider) const { } [[nodiscard]] helper::BoolWrapper> -Game::handle_event(const SDL_Event&, const Window*) { +Game::handle_event(const std::shared_ptr&, const SDL_Event&) { return false; } @@ -74,10 +76,10 @@ void Game::set_paused(bool paused) { m_clock_source->resume(); } - auto* listener = dynamic_cast(m_input.get()); + auto listener = utils::is_child_class(m_input); - if (listener != nullptr) { - listener->set_paused(paused); + if (listener.has_value()) { + listener.value()->set_paused(paused); } } @@ -91,10 +93,15 @@ void Game::set_paused(bool paused) { return true; }; - auto* const input_as_replay = dynamic_cast(m_input.get()); - if (input_as_replay != nullptr) { - return input_as_replay->is_end_of_recording(); + const auto input_as_replay = utils::is_child_class(m_input); + if (input_as_replay.has_value()) { + return input_as_replay.value()->is_end_of_recording(); } return false; } + + +[[nodiscard]] const std::shared_ptr& Game::game_input() const { + return m_input; +} diff --git a/src/game/game.hpp b/src/game/game.hpp index 4bc7253f..f6633326 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -1,7 +1,7 @@ #pragma once #include "helper/clock_source.hpp" -#include "input_creator.hpp" +#include "input/input_creator.hpp" #include "recordings/recording.hpp" #include "tetrion.hpp" #include "ui/widget.hpp" @@ -13,24 +13,29 @@ struct Game : public ui::Widget { std::unique_ptr m_clock_source; SimulationStep m_simulation_step_index{ 0 }; std::unique_ptr m_tetrion; - std::unique_ptr m_input; + std::shared_ptr m_input; bool m_is_paused{ false }; public: explicit Game( ServiceProvider* service_provider, - std::unique_ptr&& input, + const std::shared_ptr& input, const tetrion::StartingParameters& starting_parameters, const ui::Layout& layout, bool is_top_level ); void update() override; + void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const SDL_Event& event, const Window* window) override; + [[nodiscard]] Widget::EventHandleResult + + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; void set_paused(bool paused); [[nodiscard]] bool is_paused() const; [[nodiscard]] bool is_game_finished() const; + + [[nodiscard]] const std::shared_ptr& game_input() const; }; diff --git a/src/game/grid.cpp b/src/game/grid.cpp index 6fe73485..18cff92c 100644 --- a/src/game/grid.cpp +++ b/src/game/grid.cpp @@ -42,7 +42,7 @@ void Grid::render(const ServiceProvider& service_provider) const { } [[nodiscard]] helper::BoolWrapper> -Grid::handle_event(const SDL_Event&, const Window*) { +Grid::handle_event(const std::shared_ptr&, const SDL_Event&) { return false; } diff --git a/src/game/grid.hpp b/src/game/grid.hpp index 98169b57..44a59da8 100644 --- a/src/game/grid.hpp +++ b/src/game/grid.hpp @@ -29,7 +29,7 @@ struct Grid final : public ui::Widget { [[nodiscard]] shapes::UPoint to_screen_coords(GridPoint grid_coords) const; void render(const ServiceProvider& service_provider) const override; [[nodiscard]] helper::BoolWrapper> - handle_event(const SDL_Event& event, const Window* window) override; + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; private: void draw_preview_background(const ServiceProvider& service_provider) const; diff --git a/src/game/meson.build b/src/game/meson.build index 78149184..5e360af8 100644 --- a/src/game/meson.build +++ b/src/game/meson.build @@ -15,8 +15,6 @@ graphics_src_files += files( 'grid.cpp', 'grid.hpp', 'grid_properties.hpp', - 'input_creator.cpp', - 'input_creator.hpp', 'rotation.cpp', 'rotation.hpp', 'tetrion.cpp', diff --git a/src/game/tetrion.cpp b/src/game/tetrion.cpp index ac4e775b..7b3efb70 100644 --- a/src/game/tetrion.cpp +++ b/src/game/tetrion.cpp @@ -1,7 +1,9 @@ #include "tetrion.hpp" #include "helper/constants.hpp" #include "helper/graphic_utils.hpp" +#include "helper/magic_enum_wrapper.hpp" #include "helper/music_utils.hpp" +#include "helper/platform.hpp" #include "helper/utils.hpp" #include "manager/music_manager.hpp" #include "manager/resource_manager.hpp" @@ -49,24 +51,24 @@ Tetrion::Tetrion( auto* text_layout = get_text_layout(); - constexpr auto text_size = utils::device_orientation() == utils::Orientation::Landscape + constexpr auto text_size = utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.2, 0.8 } : std::pair{ 0.6, 0.8 }; text_layout->add( - service_provider, "score: 0", service_provider->fonts().get(FontId::Default), Color::white(), text_size, - ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } + service_provider, "score: 0", service_provider->font_manager().get(FontId::Default), Color::white(), + text_size, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); text_layout->add( - service_provider, "lines: 0", service_provider->fonts().get(FontId::Default), Color::white(), text_size, - ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } + service_provider, "lines: 0", service_provider->font_manager().get(FontId::Default), Color::white(), + text_size, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); text_layout->add( - service_provider, "lines: 0", service_provider->fonts().get(FontId::Default), Color::white(), text_size, - ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } + service_provider, "lines: 0", service_provider->font_manager().get(FontId::Default), Color::white(), + text_size, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); refresh_texts(); @@ -146,37 +148,37 @@ void Tetrion::render(const ServiceProvider& service_provider) const { } [[nodiscard]] helper::BoolWrapper> -Tetrion::handle_event(const SDL_Event&, const Window*) { +Tetrion::handle_event(const std::shared_ptr&, const SDL_Event&) { return false; } -bool Tetrion::handle_input_command(const InputCommand command, const SimulationStep simulation_step_index) { +bool Tetrion::handle_input_command(const input::GameInputCommand command, const SimulationStep simulation_step_index) { switch (command) { - case InputCommand::RotateLeft: + case input::GameInputCommand::RotateLeft: if (rotate_tetromino_left()) { reset_lock_delay(simulation_step_index); return true; } return false; - case InputCommand::RotateRight: + case input::GameInputCommand::RotateRight: if (rotate_tetromino_right()) { reset_lock_delay(simulation_step_index); return true; } return false; - case InputCommand::MoveLeft: + case input::GameInputCommand::MoveLeft: if (move_tetromino_left()) { reset_lock_delay(simulation_step_index); return true; } return false; - case InputCommand::MoveRight: + case input::GameInputCommand::MoveRight: if (move_tetromino_right()) { reset_lock_delay(simulation_step_index); return true; } return false; - case InputCommand::MoveDown: + case input::GameInputCommand::MoveDown: //TODO: use input_type() != InputType:Touch #if not defined(__ANDROID__) m_down_key_pressed = true; @@ -188,14 +190,14 @@ bool Tetrion::handle_input_command(const InputCommand command, const SimulationS return true; } return false; - case InputCommand::Drop: + case input::GameInputCommand::Drop: m_lock_delay_step_index = simulation_step_index; // lock instantly return drop_tetromino(simulation_step_index); - case InputCommand::ReleaseMoveDown: { + case input::GameInputCommand::ReleaseMoveDown: { m_down_key_pressed = false; return false; } - case InputCommand::Hold: + case input::GameInputCommand::Hold: if (m_allowed_to_hold) { hold_tetromino(simulation_step_index); reset_lock_delay(simulation_step_index); @@ -204,7 +206,7 @@ bool Tetrion::handle_input_command(const InputCommand command, const SimulationS } return false; default: - assert(false and "unknown event"); + assert(false and "unknown GameInput"); return false; } } diff --git a/src/game/tetrion.hpp b/src/game/tetrion.hpp index 85dd7e38..f6588599 100644 --- a/src/game/tetrion.hpp +++ b/src/game/tetrion.hpp @@ -5,9 +5,9 @@ #include "helper/optional.hpp" #include "helper/random.hpp" #include "helper/types.hpp" +#include "input/game_input.hpp" #include "manager/service_provider.hpp" #include "mino_stack.hpp" -#include "platform/input.hpp" #include "recordings/tetrion_core_information.hpp" #include "tetromino.hpp" #include "ui/layout.hpp" @@ -89,10 +89,11 @@ struct Tetrion final : public ui::Widget { bool is_top_level); void update_step(SimulationStep simulation_step_index); void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const SDL_Event& event, const Window* window) override; + [[nodiscard]] Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; // returns if the input event lead to a movement - bool handle_input_command(InputCommand command, SimulationStep simulation_step_index); + bool handle_input_command(input::GameInputCommand command, SimulationStep simulation_step_index); void spawn_next_tetromino(SimulationStep simulation_step_index); void spawn_next_tetromino(helper::TetrominoType type, SimulationStep simulation_step_index); bool rotate_tetromino_right(); diff --git a/src/graphics/point.hpp b/src/graphics/point.hpp index c083a96f..b0849901 100644 --- a/src/graphics/point.hpp +++ b/src/graphics/point.hpp @@ -9,6 +9,8 @@ namespace shapes { template struct AbstractPoint final { + using Type = T; + T x; T y; diff --git a/src/graphics/sdl_context.cpp b/src/graphics/sdl_context.cpp index e86ab4dc..24ed8b03 100644 --- a/src/graphics/sdl_context.cpp +++ b/src/graphics/sdl_context.cpp @@ -26,17 +26,6 @@ SdlContext::SdlContext() { #if defined(__CONSOLE__) console::platform_init(); - - //TODO: factor out - - // init joystick and other nintendo switch / 3ds specific things - SDL_InitSubSystem(SDL_INIT_JOYSTICK); - SDL_JoystickEventState(SDL_ENABLE); - // only use the first joystick! - - //TODO, since local multiplayer on a switch / 3ds is possible, test here if there are more then one joysticks available (e.g. left and right controller) then ask the user if he wants to play local multiplayer, implement that in JoystickInput (in the SDL event the joystick index is present) - SDL_JoystickOpen(0); - #endif #if defined(_HAVE_FILE_DIALOGS) diff --git a/src/helper/color_literals.hpp b/src/helper/color_literals.hpp index ac728f9c..1dfd5fcf 100644 --- a/src/helper/color_literals.hpp +++ b/src/helper/color_literals.hpp @@ -4,7 +4,6 @@ #include "helper/types.hpp" #include "helper/utils.hpp" -#include "manager/service_provider.hpp" #include #include diff --git a/src/helper/git_helper.hpp b/src/helper/git_helper.hpp index 5b2b1836..7a580b43 100644 --- a/src/helper/git_helper.hpp +++ b/src/helper/git_helper.hpp @@ -6,12 +6,9 @@ namespace utils { [[nodiscard]] inline std::string git_commit() { -#if defined(_HAS_GIT_COMMIT_INFORMATION) #include "git_version.hpp" + return GIT_VERSION; -#else - return "Unknown"; -#endif } } // namespace utils diff --git a/src/helper/meson.build b/src/helper/meson.build index 9cff7832..2b9135c8 100644 --- a/src/helper/meson.build +++ b/src/helper/meson.build @@ -15,6 +15,7 @@ core_src_files += files( 'optional.hpp', 'parse_json.cpp', 'parse_json.hpp', + 'platform.hpp', 'random.cpp', 'random.hpp', 'sleep.cpp', @@ -23,7 +24,6 @@ core_src_files += files( 'timer.hpp', 'types.hpp', 'utils.hpp', - ) graphics_src_files += files( @@ -42,23 +42,13 @@ if have_file_dialogs graphics_src_files += files('nfd.cpp', 'nfd_include.hpp') endif -git = find_program('git', required: false) - -if git.found() - - vcs_dep = vcs_tag( - command: ['git', 'describe', '--tags', '--always', '--abbrev=12'], - input: 'git_version.hpp.in', - output: 'git_version.hpp', - replace_string: '@GIT_VERSION@', - ) +git = find_program('git') - graphics_src_files += vcs_dep - graphics_lib += { - 'compile_args': [ - graphics_lib.get('compile_args'), - '-D_HAS_GIT_COMMIT_INFORMATION', - ], - } -endif +vcs_dep = vcs_tag( + command: ['git', 'describe', '--tags', '--always', '--abbrev=12'], + input: 'git_version.hpp.in', + output: 'git_version.hpp', + replace_string: '@GIT_VERSION@', +) +graphics_src_files += vcs_dep diff --git a/src/helper/platform.hpp b/src/helper/platform.hpp new file mode 100644 index 00000000..42e7249f --- /dev/null +++ b/src/helper/platform.hpp @@ -0,0 +1,45 @@ + + +#pragma once + +#include "helper/types.hpp" + +#include + +enum class Platform : u8 { PC, Android, Console }; + + +namespace utils { + + constexpr Platform get_platform() { + +#if defined(__ANDROID__) + return Platform::Android; +#elif defined(__CONSOLE__) + return Platform::Console; +#else + return Platform::PC; +#endif + }; + + + enum class Orientation : u8 { + Portrait, // 9x16, e.g. smartphone + Landscape // 16x9 + }; + + + constexpr Orientation get_orientation() { +#if defined(__ANDROID__) + return Orientation::Portrait; +#else + return Orientation::Landscape; +#endif + } + + + [[nodiscard]] std::string built_for_platform(); + + [[nodiscard]] bool open_url(const std::string& url); + +} // namespace utils diff --git a/src/helper/utils.hpp b/src/helper/utils.hpp index 814ce024..1b1a3cec 100644 --- a/src/helper/utils.hpp +++ b/src/helper/utils.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +85,28 @@ namespace utils { } + template + constexpr helper::optional is_child_class(S* parent) { + auto* result = dynamic_cast(parent); + + if (result == nullptr) { + return helper::nullopt; + } + + return result; + } + + template + constexpr helper::optional is_child_class(const std::unique_ptr& parent) { + return is_child_class(parent.get()); + } + + template + constexpr helper::optional is_child_class(const std::shared_ptr& parent) { + return is_child_class(parent.get()); + } + + } // namespace utils diff --git a/src/platform/console_buttons.hpp b/src/input/console_buttons.hpp similarity index 100% rename from src/platform/console_buttons.hpp rename to src/input/console_buttons.hpp diff --git a/src/platform/input.cpp b/src/input/game_input.cpp similarity index 70% rename from src/platform/input.cpp rename to src/input/game_input.cpp index 5085e28e..18e87ad2 100644 --- a/src/platform/input.cpp +++ b/src/input/game_input.cpp @@ -1,53 +1,54 @@ -#include "input.hpp" #include "game/tetrion.hpp" +#include "input.hpp" #include "manager/event_dispatcher.hpp" -#include "manager/key_codes.hpp" #include -void Input::handle_event(const InputEvent event, const SimulationStep simulation_step_index) { +void input::GameInput::handle_event(const InputEvent event, const SimulationStep simulation_step_index) { if (m_on_event_callback) { m_on_event_callback(event, simulation_step_index); } switch (event) { case InputEvent::RotateLeftPressed: - m_target_tetrion->handle_input_command(InputCommand::RotateLeft, simulation_step_index); + m_target_tetrion->handle_input_command(GameInputCommand::RotateLeft, simulation_step_index); break; case InputEvent::RotateRightPressed: - m_target_tetrion->handle_input_command(InputCommand::RotateRight, simulation_step_index); + m_target_tetrion->handle_input_command(GameInputCommand::RotateRight, simulation_step_index); break; case InputEvent::MoveLeftPressed: if (not supports_das()) { - m_target_tetrion->handle_input_command(InputCommand::MoveLeft, simulation_step_index); + m_target_tetrion->handle_input_command(GameInputCommand::MoveLeft, simulation_step_index); } else { m_keys_hold[HoldableKey::Left] = simulation_step_index + delayed_auto_shift_frames; if (not m_keys_hold.contains(HoldableKey::Right) - and not m_target_tetrion->handle_input_command(InputCommand::MoveLeft, simulation_step_index)) { + and not m_target_tetrion->handle_input_command(GameInputCommand::MoveLeft, simulation_step_index)) { m_keys_hold[HoldableKey::Left] = simulation_step_index; } } break; case InputEvent::MoveRightPressed: if (not supports_das()) { - m_target_tetrion->handle_input_command(InputCommand::MoveRight, simulation_step_index); + m_target_tetrion->handle_input_command(GameInputCommand::MoveRight, simulation_step_index); } else { m_keys_hold[HoldableKey::Right] = simulation_step_index + delayed_auto_shift_frames; if (not m_keys_hold.contains(HoldableKey::Left) - and not m_target_tetrion->handle_input_command(InputCommand::MoveRight, simulation_step_index)) { + and not m_target_tetrion->handle_input_command( + GameInputCommand::MoveRight, simulation_step_index + )) { m_keys_hold[HoldableKey::Right] = simulation_step_index; } } break; case InputEvent::MoveDownPressed: - m_target_tetrion->handle_input_command(InputCommand::MoveDown, simulation_step_index); + m_target_tetrion->handle_input_command(GameInputCommand::MoveDown, simulation_step_index); break; case InputEvent::DropPressed: - m_target_tetrion->handle_input_command(InputCommand::Drop, simulation_step_index); + m_target_tetrion->handle_input_command(GameInputCommand::Drop, simulation_step_index); break; case InputEvent::HoldPressed: - m_target_tetrion->handle_input_command(InputCommand::Hold, simulation_step_index); + m_target_tetrion->handle_input_command(GameInputCommand::Hold, simulation_step_index); break; case InputEvent::MoveLeftReleased: if (supports_das()) { @@ -60,7 +61,7 @@ void Input::handle_event(const InputEvent event, const SimulationStep simulation } break; case InputEvent::MoveDownReleased: - m_target_tetrion->handle_input_command(InputCommand::ReleaseMoveDown, simulation_step_index); + m_target_tetrion->handle_input_command(GameInputCommand::ReleaseMoveDown, simulation_step_index); break; case InputEvent::RotateLeftReleased: case InputEvent::RotateRightReleased: @@ -72,7 +73,7 @@ void Input::handle_event(const InputEvent event, const SimulationStep simulation } } -void Input::update(const SimulationStep simulation_step_index) { +void input::GameInput::update(const SimulationStep simulation_step_index) { const auto current_simulation_step_index = simulation_step_index; const auto is_left_key_down = m_keys_hold.contains(HoldableKey::Left); @@ -87,9 +88,10 @@ void Input::update(const SimulationStep simulation_step_index) { target_simulation_step_index += auto_repeat_rate_frames; } if ((key == HoldableKey::Left - and not m_target_tetrion->handle_input_command(InputCommand::MoveLeft, simulation_step_index)) + and not m_target_tetrion->handle_input_command(GameInputCommand::MoveLeft, simulation_step_index)) or (key == HoldableKey::Right - and not m_target_tetrion->handle_input_command(InputCommand::MoveRight, simulation_step_index))) { + and not m_target_tetrion->handle_input_command(GameInputCommand::MoveRight, simulation_step_index) + )) { target_simulation_step_index = current_simulation_step_index + delayed_auto_shift_frames; } } diff --git a/src/input/game_input.hpp b/src/input/game_input.hpp new file mode 100644 index 00000000..086cebe6 --- /dev/null +++ b/src/input/game_input.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include "helper/clock_source.hpp" +#include "helper/optional.hpp" +#include "helper/random.hpp" +#include "helper/types.hpp" +#include "manager/event_listener.hpp" +#include "manager/input_event.hpp" + +#include +#include + +struct Tetrion; + +namespace input { + + enum class GameInputCommand : u8 { + MoveLeft, + MoveRight, + MoveDown, + RotateLeft, + RotateRight, + Drop, + Hold, + ReleaseMoveDown, + }; + + enum class GameInputType : u8 { Touch, Keyboard, Controller, Recording }; + + enum class MenuEvent : u8 { OPEN_SETTINGS, PAUSE }; + + + struct GameInput { + public: + using OnEventCallback = std::function; + + private: + enum class HoldableKey : u8 { + Left, + Right, + }; + + static constexpr u64 delayed_auto_shift_frames = 10; + static constexpr u64 auto_repeat_rate_frames = 2; + + std::unordered_map m_keys_hold; + GameInputType m_input_type; + + protected: + Tetrion* m_target_tetrion{}; + OnEventCallback m_on_event_callback{}; + + GameInput(GameInputType input_type) : m_input_type{ input_type } { } + + void handle_event(InputEvent event, SimulationStep simulation_step_index); + + public: + virtual void update(SimulationStep simulation_step_index); + virtual void late_update(SimulationStep){}; + + [[nodiscard]] virtual helper::optional get_menu_event(const SDL_Event& event) const = 0; + + [[nodiscard]] virtual std::string describe_menu_event(MenuEvent event) const = 0; + + [[nodiscard]] GameInputType input_type() const { + return m_input_type; + } + + [[nodiscard]] bool supports_das() const { + // todo support das with hold in touch mode + return m_input_type != GameInputType::Touch; + } + + void set_target_tetrion(Tetrion* target_tetrion) { + m_target_tetrion = target_tetrion; + } + + void set_event_callback(OnEventCallback on_event_callback) { + m_on_event_callback = std::move(on_event_callback); + } + + GameInput(const GameInput&) = delete; + GameInput& operator=(const GameInput&) = delete; + + virtual ~GameInput() = default; + }; +} // namespace input diff --git a/src/input/input.cpp b/src/input/input.cpp new file mode 100644 index 00000000..b456056c --- /dev/null +++ b/src/input/input.cpp @@ -0,0 +1,136 @@ +#include "input.hpp" +#include "helper/utils.hpp" +#include "joystick_input.hpp" +#include "keyboard_input.hpp" +#include "manager/settings_manager.hpp" +#include "mouse_input.hpp" +#include "touch_input.hpp" + +#include +#include +#include + + +[[nodiscard]] bool input::PointerEventHelper::is_in(const shapes::URect& rect) const { + using Type = decltype(m_pos)::Type; + + assert(rect.top_left.x <= std::numeric_limits::max()); + assert(rect.top_left.y <= std::numeric_limits::max()); + assert(rect.bottom_right.x <= std::numeric_limits::max()); + assert(rect.bottom_right.y <= std::numeric_limits::max()); + + return is_in(rect.cast()); +} + +[[nodiscard]] bool input::PointerEventHelper::is_in(const shapes::IRect& rect) const { + const auto rect_start_x = rect.top_left.x; + const auto rect_start_y = rect.top_left.y; + const auto rect_end_x = rect.bottom_right.x; + const auto rect_end_y = rect.bottom_right.y; + + + const bool is_in = + (m_pos.x >= rect_start_x and m_pos.x <= rect_end_x and m_pos.y >= rect_start_y and m_pos.y <= rect_end_y); + + return is_in; +} + + +input::InputManager::InputManager(const std::shared_ptr& window) { + + //initialize mouse input + m_inputs.push_back(std::make_unique()); + + //initialize keyboard input + m_inputs.push_back(std::make_unique()); + + //initialize touch input (needs window) + m_inputs.push_back(std::make_unique(window)); + + //initialize joystick input manager + m_joystick_manager = std::make_unique(); +} + +input::InputManager::~InputManager() = default; + + +[[nodiscard]] const std::vector>& input::InputManager::inputs() const { + return m_inputs; +} + + +[[nodiscard]] helper::optional input::InputManager::get_navigation_event(const SDL_Event& event +) const { + for (const auto& input : m_inputs) { + + if (const auto navigation_event = input->get_navigation_event(event); navigation_event.has_value()) { + return navigation_event; + } + } + + return helper::nullopt; +} + +[[nodiscard]] helper::optional input::InputManager::get_pointer_event(const SDL_Event& event +) const { + for (const auto& input : m_inputs) { + if (const auto pointer_input = utils::is_child_class(input); pointer_input.has_value()) { + if (const auto pointer_event = pointer_input.value()->get_pointer_event(event); pointer_event.has_value()) { + return pointer_event; + } + } + } + + return helper::nullopt; +} + + +[[nodiscard]] helper::BoolWrapper input::InputManager::process_special_inputs( + const SDL_Event& event +) { + switch (event.type) { + case SDL_WINDOWEVENT: + switch (event.window.event) { + case SDL_WINDOWEVENT_HIDDEN: + case SDL_WINDOWEVENT_MINIMIZED: + case SDL_WINDOWEVENT_LEAVE: { + return { true, SpecialRequest::WindowFocusLost }; + } + default: + break; + } + break; + default: + break; + } + + + const auto is_joystick_special_input = m_joystick_manager->process_special_inputs(event); + + if (is_joystick_special_input) { + return { true, SpecialRequest::InputsChanged }; + } + + return false; +} + +//TODO: improve this API, to correctly use settings to determine the input to use. +[[nodiscard]] std::unique_ptr input::InputManager::get_game_input(ServiceProvider* service_provider) { + return std::visit( + helper::overloaded{ + [service_provider]([[maybe_unused]] const input::KeyboardSettings& keyboard_settings + ) mutable -> std::unique_ptr { + auto* const event_dispatcher = &(service_provider->event_dispatcher()); +#if defined(__ANDROID__) + auto input = std::make_unique(event_dispatcher); +#elif defined(__CONSOLE__) + auto input = std::make_unique(event_dispatcher); +#else + auto input = std::make_unique(keyboard_settings, event_dispatcher); +#endif + return input; + }, + }, + service_provider->settings_manager().controls() + ); +} diff --git a/src/input/input.hpp b/src/input/input.hpp new file mode 100644 index 00000000..2427250c --- /dev/null +++ b/src/input/input.hpp @@ -0,0 +1,109 @@ + + +#pragma once + + +#include "SDL_events.h" +#include "game_input.hpp" +#include "graphics/point.hpp" +#include "graphics/rect.hpp" +#include "graphics/window.hpp" +#include "helper/bool_wrapper.hpp" +#include "helper/expected.hpp" +#include "helper/optional.hpp" +#include "manager/service_provider.hpp" + + +#include +#include + +namespace input { + + enum class InputType : u8 { Keyboard, Pointer, JoyStick }; + + enum class NavigationEvent : u8 { OK, DOWN, UP, LEFT, RIGHT, BACK, TAB }; + + enum class SpecialRequest : u8 { WindowFocusLost, InputsChanged }; + + + struct Input { + private: + std::string m_name; + InputType m_type; + + public: + Input(const std::string& name, InputType type); + virtual ~Input(); + + [[nodiscard]] const std::string& name() const; + [[nodiscard]] InputType type(); + + [[nodiscard]] virtual helper::optional get_navigation_event(const SDL_Event& event) const = 0; + + [[nodiscard]] virtual std::string describe_navigation_event(NavigationEvent event) const = 0; + }; + + enum class PointerEvent : u8 { Motion, PointerDown, PointerUp }; + + struct PointerEventHelper { + private: + shapes::IPoint m_pos; + PointerEvent m_event; + + public: + PointerEventHelper(shapes::IPoint pos, PointerEvent event); + + [[nodiscard]] PointerEvent event() const; + + [[nodiscard]] shapes::IPoint position() const; + + [[nodiscard]] bool is_in(const shapes::URect& rect) const; + + [[nodiscard]] bool is_in(const shapes::IRect& rect) const; + + [[nodiscard]] SDL_Event offset_raw(const SDL_Event& event, const shapes::IPoint& rect) const; + + [[nodiscard]] bool operator==(PointerEvent event) const; + }; + + + struct PointerInput : Input { + PointerInput(const std::string& name); + + [[nodiscard]] virtual helper::optional get_pointer_event(const SDL_Event& event) const = 0; + }; + + //forward declaration + struct JoyStickInputManager; + + struct InputManager { + private: + std::unique_ptr m_joystick_manager; + + std::vector> m_inputs{}; + + public: + explicit InputManager(const std::shared_ptr& window); + ~InputManager(); + + [[nodiscard]] const std::vector>& inputs() const; + + [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const; + + [[nodiscard]] helper::optional get_pointer_event(const SDL_Event& event) const; + + [[nodiscard]] helper::BoolWrapper process_special_inputs(const SDL_Event& event); + + [[nodiscard]] std::unique_ptr get_game_input(ServiceProvider* service_provider); + + [[nodiscard]] const std::unique_ptr& get_primary_input(); + }; + + + struct InputSettings { + + [[nodiscard]] virtual helper::expected validate() const; + }; + + +} // namespace input diff --git a/src/game/input_creator.cpp b/src/input/input_creator.cpp similarity index 78% rename from src/game/input_creator.cpp rename to src/input/input_creator.cpp index b3192a4b..059b232c 100644 --- a/src/game/input_creator.cpp +++ b/src/input/input_creator.cpp @@ -4,41 +4,15 @@ #include "helper/command_line_arguments.hpp" #include "helper/date.hpp" #include "helper/errors.hpp" -#include "platform/replay_input.hpp" -#include - +#include "input.hpp" +#include "input/replay_input.hpp" -#if defined(__ANDROID__) -#include "platform/android_input.hpp" -#elif defined(__CONSOLE__) -#include "platform/console_input.hpp" -#else -#include "platform/keyboard_input.hpp" -#endif #include +#include namespace { - [[nodiscard]] std::unique_ptr create_input(ServiceProvider* service_provider) { - return std::visit( - helper::overloaded{ - [service_provider]([[maybe_unused]] KeyboardControls& keyboard_controls - ) mutable -> std::unique_ptr { - auto* const event_dispatcher = &(service_provider->event_dispatcher()); -#if defined(__ANDROID__) - auto input = std::make_unique(event_dispatcher); -#elif defined(__CONSOLE__) - auto input = std::make_unique(event_dispatcher); -#else - auto input = std::make_unique(keyboard_controls, event_dispatcher); -#endif - return input; - }, - }, - service_provider->settings().controls - ); - } [[nodiscard]] recorder::TetrionHeader create_tetrion_headers_for_one(const input::AdditionalInfo& info) { const auto& needed_info = std::get<1>(info); @@ -96,7 +70,7 @@ namespace { for (u8 tetrion_index = 0; tetrion_index < static_cast(tetrion_headers.size()); ++tetrion_index) { - auto input = std::make_unique(recording_reader); + auto input = std::make_unique(recording_reader); const auto& header = tetrion_headers.at(tetrion_index); @@ -120,7 +94,7 @@ namespace { const date::ISO8601Date& date ) { - auto input = create_input(service_provider); + auto input = service_provider->input_manager().get_game_input(service_provider); const auto starting_level = service_provider->command_line_arguments().starting_level; diff --git a/src/game/input_creator.hpp b/src/input/input_creator.hpp similarity index 91% rename from src/game/input_creator.hpp rename to src/input/input_creator.hpp index 10251833..940b7d90 100644 --- a/src/game/input_creator.hpp +++ b/src/input/input_creator.hpp @@ -3,12 +3,11 @@ #include "helper/date.hpp" #include "helper/optional.hpp" +#include "input/game_input.hpp" #include "manager/service_provider.hpp" -#include "platform/input.hpp" #include "recordings/recording_writer.hpp" #include -#include namespace tetrion { struct StartingParameters { @@ -35,7 +34,7 @@ namespace tetrion { namespace input { - using AdditionalInfo = std::tuple, tetrion::StartingParameters>; + using AdditionalInfo = std::tuple, tetrion::StartingParameters>; [[nodiscard]] std::vector get_game_parameters_for_replay(ServiceProvider* service_provider, const std::filesystem::path& recording_path); diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp new file mode 100644 index 00000000..b0a11806 --- /dev/null +++ b/src/input/joystick_input.cpp @@ -0,0 +1,471 @@ + + +#include "joystick_input.hpp" +#include "SDL_stdinc.h" +#include "helper/expected.hpp" +#include "helper/optional.hpp" +#include "input/input.hpp" + +#include +#include +#include + + +joystick::GUID::GUID() : m_guid{} { } +joystick::GUID::GUID(const SDL_GUID& data) : m_guid{} { + std::copy(std::begin(data.data), std::end(data.data), std::begin(m_guid)); +} + +[[nodiscard]] bool joystick::GUID::operator==(const GUID& other) const { + return this->m_guid == other.m_guid; +} + +[[nodiscard]] joystick::GUID::operator std::string() const { + return fmt::format("{}", fmt::join(m_guid, ":")); +} + + +input::JoystickInput::JoystickInput(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name) + : input::Input{ name, input::InputType::JoyStick }, + m_joystick{ joystick }, + m_instance_id{ instance_id } { } + + +input::JoystickInput::~JoystickInput() { + SDL_JoystickClose(m_joystick); +} + + +[[nodiscard]] helper::optional> input::JoystickInput::get_joystick_by_guid( + const joystick::GUID& guid, + SDL_Joystick* joystick, + SDL_JoystickID instance_id +) { +#if defined(__CONSOLE__) +#if defined(__SWITCH__) + if (guid == SwitchJoystickInput_Type1::guid) { + return std::make_unique(joystick, instance_id); + } +#elif defined(__3DS__) + if (guid == _3DSJoystickInput_Type1::guid) { + return std::make_unique<_3DSJoystickInput_Type1>(joystick, instance_id); + } + +#endif +#endif + + UNUSED(guid); + UNUSED(joystick); + UNUSED(instance_id); + + return helper::nullopt; +} + + +[[nodiscard]] helper::expected, std::string> +input::JoystickInput::get_by_device_index(int device_index) { + + + auto* joystick = SDL_JoystickOpen(device_index); + + if (joystick == nullptr) { + return helper::unexpected{ + fmt::format("Failed to get joystick at device index {}: {}", device_index, SDL_GetError()) + }; + } + + //TODO: add support for gamecontrollers (SDL_IsGameController) + + const auto instance_id = SDL_JoystickInstanceID(joystick); + + if (instance_id < 0) { + return helper::unexpected{ fmt::format("Failed to get joystick instance id: {}", SDL_GetError()) }; + } + + std::string name = "unknown name"; + const auto* char_name = SDL_JoystickName(joystick); + + if (char_name != nullptr) { + name = char_name; + } + + + const auto guid = joystick::GUID{ SDL_JoystickGetGUID(joystick) }; + + if (guid == joystick::GUID{}) { + return helper::unexpected{ fmt::format("Failed to get joystick GUID: {}", SDL_GetError()) }; + } + + auto joystick_input = JoystickInput::get_joystick_by_guid(guid, joystick, instance_id); + + if (joystick_input.has_value()) { + return std::move(joystick_input.value()); + } + + return helper::unexpected{ + fmt::format("Failed to get joystick model by GUID {} We don't support this joystick yet", guid) + }; +} + + +input::JoyStickInputManager::JoyStickInputManager() { + + + //initialize joystick input, this needs to call some sdl things + + const auto result = SDL_InitSubSystem(SDL_INIT_JOYSTICK); + + if (result != 0) { + spdlog::warn("Failed to initialize the joystick system: {}", SDL_GetError()); + return; + } + + + const auto enable_result = SDL_JoystickEventState(SDL_ENABLE); + + if (enable_result != 1) { + const auto* const error = enable_result == 0 ? "it was disabled" : SDL_GetError(); + spdlog::warn("Failed to set JoystickEventState (automatic polling by SDL): {}", error); + + return; + } + + + const auto allow_background_events_result = SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); + + if (allow_background_events_result != SDL_TRUE) { + spdlog::warn("Failed to set the JOYSTICK_ALLOW_BACKGROUND_EVENTS hint: {}", SDL_GetError()); + + return; + } + + + const auto num_of_joysticks = SDL_NumJoysticks(); + + if (num_of_joysticks < 0) { + spdlog::warn("Failed to get number of joysticks: {}", SDL_GetError()); + return; + } + + for (auto i = 0; i < num_of_joysticks; ++i) { + + auto joystick = JoystickInput::get_by_device_index(i); + if (joystick.has_value()) { + m_inputs.push_back(std::move(joystick.value())); + } else { + spdlog::warn("Failed to configure joystick: {}", joystick.error()); + } + } +} + + +[[nodiscard]] const std::vector>& input::JoyStickInputManager::inputs() const { + return m_inputs; +} + + +[[nodiscard]] helper::optional input::JoyStickInputManager::get_navigation_event( + const SDL_Event& event +) const { + for (const auto& input : m_inputs) { + + if (const auto navigation_event = input->get_navigation_event(event); navigation_event.has_value()) { + return navigation_event; + } + } + + return helper::nullopt; +} + +[[nodiscard]] helper::optional input::JoyStickInputManager::get_pointer_event( + const SDL_Event& event +) const { + for (const auto& input : m_inputs) { + if (const auto pointer_input = utils::is_child_class(input); pointer_input.has_value()) { + if (const auto pointer_event = pointer_input.value()->get_pointer_event(event); pointer_event.has_value()) { + return pointer_event; + } + } + } + + return helper::nullopt; +} + +[[nodiscard]] bool input::JoyStickInputManager::process_special_inputs(const SDL_Event& event) { + + switch (event.type) { + case SDL_JOYDEVICEADDED: { + const auto device_id = event.jdevice.which; + auto joystick = JoystickInput::get_by_device_index(device_id); + if (joystick.has_value()) { + m_inputs.push_back(std::move(joystick.value())); + } else { + spdlog::warn("Failed to add newly added joystick: {}", joystick.error()); + } + return true; + } + case SDL_JOYDEVICEREMOVED: { + const auto instance_id = event.jdevice.which; + for (auto it = m_inputs.cbegin(); it != m_inputs.end(); it++) { + + if ((*it)->instance_id() == instance_id) { + m_inputs.erase(it); + return true; + } + } + + spdlog::warn("Failed to remove removed joystick from internal joystick vector"); + + return true; + } + default: + return false; + } + //TODO +} + + +#if defined(__CONSOLE__) +#include "console_input.hpp" + +#if defined(__SWITCH__) + +input::SwitchJoystickInput_Type1::SwitchJoystickInput_Type1( + SDL_Joystick* joystick, + SDL_JoystickID instance_id, + const std::string& name +) + : JoystickInput{ joystick, instance_id, name } { } + + +[[nodiscard]] helper::optional input::SwitchJoystickInput_Type1::get_navigation_event( + const SDL_Event& event +) const { + + //TODO handle SDL_JOYAXISMOTION + + + if (event.type == SDL_JOYBUTTONDOWN) { + + if (event.jbutton.which != m_id) { + return helper::nullopt; + } + + + switch (event.jbutton.button) { + case JOYCON_A: + return NavigationEvent::OK; + case JOYCON_DPAD_DOWN: + case JOYCON_LDPAD_DOWN: + case JOYCON_RDPAD_DOWN: + return NavigationEvent::DOWN; + case JOYCON_DPAD_UP: + case JOYCON_LDPAD_UP: + case JOYCON_RDPAD_UP: + return NavigationEvent::UP; + case JOYCON_DPAD_LEFT: + case JOYCON_LDPAD_LEFT: + case JOYCON_RDPAD_LEFT: + return NavigationEvent::LEFT; + case JOYCON_DPAD_RIGHT: + case JOYCON_LDPAD_RIGHT: + case JOYCON_RDPAD_RIGHT: + return NavigationEvent::RIGHT; + case JOYCON_MINUS: + return NavigationEvent::BACK; + + + //note, that NavigationEvent::TAB is not supported + } + } + + //TODO: handle SDL_JOYAXISMOTION + + + return helper::nullopt; +} + +#elif defined(__3DS__) + +input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( + SDL_Joystick* joystick, + SDL_JoystickID instance_id, + const std::string& name +) + : JoystickInput{ joystick, instance_id, name } { } + + +[[nodiscard]] helper::optional input::_3DSJoystickInput_Type1::get_navigation_event( + const SDL_Event& event +) const { + + + if (event.type == SDL_JOYBUTTONDOWN) { + + if (event.jbutton.which != m_id) { + return helper::nullopt; + } + + + switch (event.jbutton.button) { + case JOYCON_A: + return NavigationEvent::OK; + case JOYCON_DPAD_DOWN: + case JOYCON_CSTICK_DOWN: + case JOYCON_CPAD_DOWN: + return NavigationEvent::DOWN; + case JOYCON_DPAD_UP: + case JOYCON_CSTICK_UP: + case JOYCON_CPAD_UP: + return NavigationEvent::UP; + case JOYCON_DPAD_LEFT: + case JOYCON_CSTICK_LEFT: + case JOYCON_CPAD_LEFT: + return NavigationEvent::LEFT; + case JOYCON_DPAD_RIGHT: + case JOYCON_CSTICK_RIGHT: + case JOYCON_CPAD_RIGHT: + return NavigationEvent::RIGHT; + case JOYCON_X: + return NavigationEvent::BACK; + + //note, that NavigationEvent::TAB is not supported + } + } + + //TODO: handle SDL_JOYAXISMOTION + + + return helper::nullopt; +} + +#endif + +void JoystickGameInput::handle_event(const SDL_Event& event, const Window*) { + m_event_buffer.push_back(event); +} + +void JoystickGameInput::update(SimulationStep simulation_step_index) { + for (const auto& event : m_event_buffer) { + const auto input_event = sdl_event_to_input_event(event); + if (input_event.has_value()) { + Input::handle_event(*input_event, simulation_step_index); + } + } + m_event_buffer.clear(); + + Input::update(simulation_step_index); +} + +#if defined(__SWITCH__) + +// game_input uses Input to handle events, but stores teh config settings for teh specific button + +helper::optional JoystickSwitchGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event) const { + if (event.type == SDL_JOYBUTTONDOWN) { + //TODO: use switch case + const auto button = event.jbutton.button; + if (button == JOYCON_DPAD_LEFT) { + return InputEvent::RotateLeftPressed; + } + if (button == JOYCON_DPAD_RIGHT) { + return InputEvent::RotateRightPressed; + } + if (button == JOYCON_LDPAD_DOWN or button == JOYCON_RDPAD_DOWN) { + return InputEvent::MoveDownPressed; + } + if (button == JOYCON_LDPAD_LEFT or button == JOYCON_RDPAD_LEFT) { + return InputEvent::MoveLeftPressed; + } + if (button == JOYCON_LDPAD_RIGHT or button == JOYCON_RDPAD_RIGHT) { + return InputEvent::MoveRightPressed; + } + if (button == JOYCON_X) { + return InputEvent::DropPressed; + } + if (button == JOYCON_B) { + return InputEvent::HoldPressed; + } + } else if (event.type == SDL_JOYBUTTONUP) { + const auto button = event.jbutton.button; + if (button == JOYCON_DPAD_LEFT) { + return InputEvent::RotateLeftReleased; + } + if (button == JOYCON_DPAD_RIGHT) { + return InputEvent::RotateRightReleased; + } + if (button == JOYCON_LDPAD_DOWN or button == JOYCON_RDPAD_DOWN) { + return InputEvent::MoveDownReleased; + } + if (button == JOYCON_LDPAD_LEFT or button == JOYCON_RDPAD_LEFT) { + return InputEvent::MoveLeftReleased; + } + if (button == JOYCON_LDPAD_RIGHT or button == JOYCON_RDPAD_RIGHT) { + return InputEvent::MoveRightReleased; + } + if (button == JOYCON_X) { + return InputEvent::DropReleased; + } + if (button == JOYCON_B) { + return InputEvent::HoldReleased; + } + } + return helper::nullopt; +} +#elif defined(__3DS__) + + +helper::optional JoystickInput::sdl_event_to_input_event(const SDL_Event& event) const { + if (event.type == SDL_JOYBUTTONDOWN) { + const auto button = event.jbutton.button; + if (button == JOYCON_L) { + return InputEvent::RotateLeftPressed; + } + if (button == JOYCON_R) { + return InputEvent::RotateRightPressed; + } + if (button == JOYCON_DPAD_DOWN or button == JOYCON_CSTICK_DOWN) { + return InputEvent::MoveDownPressed; + } + if (button == JOYCON_DPAD_LEFT or button == JOYCON_CSTICK_LEFT) { + return InputEvent::MoveLeftPressed; + } + if (button == JOYCON_DPAD_RIGHT or button == JOYCON_CSTICK_RIGHT) { + return InputEvent::MoveRightPressed; + } + if (button == JOYCON_A) { + return InputEvent::DropPressed; + } + if (button == JOYCON_B) { + return InputEvent::HoldPressed; + } + } else if (event.type == SDL_JOYBUTTONUP) { + const auto button = event.jbutton.button; + if (button == JOYCON_L) { + return InputEvent::RotateLeftReleased; + } + if (button == JOYCON_R) { + return InputEvent::RotateRightReleased; + } + if (button == JOYCON_DPAD_DOWN or button == JOYCON_CSTICK_DOWN) { + return InputEvent::MoveDownReleased; + } + if (button == JOYCON_DPAD_LEFT or button == JOYCON_CSTICK_LEFT) { + return InputEvent::MoveLeftReleased; + } + if (button == JOYCON_DPAD_RIGHT or button == JOYCON_CSTICK_RIGHT) { + return InputEvent::MoveRightReleased; + } + if (button == JOYCON_A) { + return InputEvent::DropReleased; + } + if (button == JOYCON_B) { + return InputEvent::HoldReleased; + } + } + return helper::nullopt; +} +#endif + + +#endif diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp new file mode 100644 index 00000000..da1ca1c6 --- /dev/null +++ b/src/input/joystick_input.hpp @@ -0,0 +1,184 @@ +#pragma once + + +#include "SDL_joystick.h" +#include "helper/expected.hpp" +#include "input.hpp" +#include "input/game_input.hpp" +#include "manager/event_dispatcher.hpp" + +#include + +namespace joystick { + struct GUID { + private: + std::array m_guid; + + public: + GUID(); + GUID(const SDL_GUID& data); + + [[nodiscard]] bool operator==(const GUID& other) const; + + [[nodiscard]] operator std::string() const; + }; +} // namespace joystick + + +template<> +struct fmt::formatter : formatter { + auto format(const joystick::GUID& guid, format_context& ctx) { + return formatter::format(std::string{ guid }, ctx); + } +}; + +namespace input { + + struct JoystickInput : Input { + private: + SDL_Joystick* m_joystick; + SDL_JoystickID m_instance_id; + + [[nodiscard]] static helper::optional> + get_joystick_by_guid(const joystick::GUID& guid, SDL_Joystick* joystick, SDL_JoystickID instance_id); + + public: + JoystickInput(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); + virtual ~JoystickInput(); + + [[nodiscard]] static helper::expected, std::string> get_by_device_index( + int device_index + ); + [[nodiscard]] SDL_JoystickID instance_id() const; + }; + + + //TODO: also support gamecontroller API + // see: https://github.com/mdqinc/SDL_GameControllerDB?tab=readme-ov-file + + struct JoyStickInputManager { + private: + std::vector> m_inputs{}; + + public: + explicit JoyStickInputManager(); + [[nodiscard]] const std::vector>& inputs() const; + + [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const; + + [[nodiscard]] helper::optional get_pointer_event(const SDL_Event& event) const; + + [[nodiscard]] bool process_special_inputs(const SDL_Event& event); + }; + + + //TODO: differntiate different controllers and modes, e.g the switch can have pro controller, the included ones, each of them seperate etc. + +#if defined(__CONSOLE__) +#if defined(__SWITCH__) + struct SwitchJoystickInput_Type1 : JoystickInput { + + //TODO + static joystick::GUID guid{}; + + public: + SwitchJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); + + [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; + }; + + +#elif defined(__3DS__) + + struct _3DSJoystickInput_Type1 : JoystickInput { + + //TODO + static joystick::GUID guid{}; + + public: + _3DSJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); + + [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; + }; + + +#endif + +#endif + + struct JoystickGameInput : public GameInput, public EventListener { + private: + std::vector m_event_buffer; + EventDispatcher* m_event_dispatcher; + + public: + JoystickGameInput(EventDispatcher* event_dispatcher) + : GameInput{ GameInputType::Controller }, + m_event_dispatcher{ event_dispatcher } { + m_event_dispatcher->register_listener(this); + } + + ~JoystickGameInput() override { + m_event_dispatcher->unregister_listener(this); + } + + void handle_event(const SDL_Event& event) override; + + void update(SimulationStep simulation_step_index) override; + + private: + [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event) const; + }; + +} // namespace input + + +//TODO: +/* +#elif defined(__SWITCH__) + switch (action) { + case CrossPlatformAction::OK: + return "A"; + case CrossPlatformAction::PAUSE: + case CrossPlatformAction::UNPAUSE: + return "PLUS"; + case CrossPlatformAction::CLOSE: + case CrossPlatformAction::EXIT: + return "MINUS"; + case CrossPlatformAction::DOWN: + return "Down"; + case CrossPlatformAction::UP: + return "Up"; + case CrossPlatformAction::LEFT: + return "Left"; + case CrossPlatformAction::RIGHT: + return "Right"; + case CrossPlatformAction::OPEN_SETTINGS: + return "Y"; + default: + utils::unreachable(); + } + +#elif defined(__3DS__) + switch (action) { + case CrossPlatformAction::OK: + return "A"; + case CrossPlatformAction::PAUSE: + case CrossPlatformAction::UNPAUSE: + return "Y"; + case CrossPlatformAction::CLOSE: + case CrossPlatformAction::EXIT: + return "X"; + case CrossPlatformAction::DOWN: + return "Down"; + case CrossPlatformAction::UP: + return "Up"; + case CrossPlatformAction::LEFT: + return "Left"; + case CrossPlatformAction::RIGHT: + return "Right"; + case CrossPlatformAction::OPEN_SETTINGS: + return "Select"; + default: + utils::unreachable(); + } */ diff --git a/src/input/keyboard_input.cpp b/src/input/keyboard_input.cpp new file mode 100644 index 00000000..4e6faedb --- /dev/null +++ b/src/input/keyboard_input.cpp @@ -0,0 +1,133 @@ +#include "keyboard_input.hpp" +#include "SDL_keycode.h" + + +input::KeyboardInput::KeyboardInput() : input::Input{ "keyboard", InputType::Keyboard } { } + + +[[nodiscard]] helper::optional input::KeyboardInput::get_navigation_event(const SDL_Event& event +) const { + + + if (event.type == SDL_KEYDOWN) { + + const auto key = SDL::Key{ event.key.keysym }; + + if (key == SDL::Key{ SDLK_RETURN } or key == SDL::Key{ SDLK_SPACE }) { + return NavigationEvent::OK; + } + + if (key == SDL::Key{ SDLK_DOWN } or key == SDL::Key{ SDLK_s }) { + return NavigationEvent::DOWN; + } + + + if (key == SDL::Key{ SDLK_UP } or key == SDL::Key{ SDLK_w }) { + return NavigationEvent::UP; + } + + + if (key == SDL::Key{ SDLK_LEFT } or key == SDL::Key{ SDLK_a }) { + return NavigationEvent::LEFT; + } + + + if (key == SDL::Key{ SDLK_RIGHT } or key == SDL::Key{ SDLK_d }) { + return NavigationEvent::RIGHT; + } + + + if (key == SDL::Key{ SDLK_ESCAPE } or key == SDL::Key{ SDLK_BACKSPACE }) { + return NavigationEvent::BACK; + } + + + if (key == SDL::Key{ SDLK_TAB }) { + return NavigationEvent::TAB; + } + } + + return helper::nullopt; +} + + +void input::KeyboardGameInput::handle_event(const SDL_Event& event) { + m_event_buffer.push_back(event); +} + +void input::KeyboardGameInput::update(SimulationStep simulation_step_index) { + for (const auto& event : m_event_buffer) { + const auto input_event = sdl_event_to_input_event(event); + if (input_event.has_value()) { + GameInput::handle_event(*input_event, simulation_step_index); + } + } + m_event_buffer.clear(); + + GameInput::update(simulation_step_index); +} + +helper::optional +input::KeyboardGameInput::sdl_event_to_input_event( // NOLINT(readability-function-cognitive-complexity) + const SDL_Event& event +) const { + if (event.type == SDL_KEYDOWN and event.key.repeat == 0) { + const auto key = SDL::Key{ event.key.keysym }; + if (key == m_settings.rotate_left) { + return InputEvent::RotateLeftPressed; + } + if (key == m_settings.rotate_right) { + return InputEvent::RotateRightPressed; + } + if (key == m_settings.move_down) { + return InputEvent::MoveDownPressed; + } + if (key == m_settings.move_left) { + return InputEvent::MoveLeftPressed; + } + if (key == m_settings.move_right) { + return InputEvent::MoveRightPressed; + } + if (key == m_settings.drop) { + return InputEvent::DropPressed; + } + if (key == m_settings.hold) { + return InputEvent::HoldPressed; + } + } else if (event.type == SDL_KEYUP) { + const auto key = SDL::Key{ event.key.keysym }; + if (key == m_settings.rotate_left) { + return InputEvent::RotateLeftReleased; + } + if (key == m_settings.rotate_right) { + return InputEvent::RotateRightReleased; + } + if (key == m_settings.move_down) { + return InputEvent::MoveDownReleased; + } + if (key == m_settings.move_left) { + return InputEvent::MoveLeftReleased; + } + if (key == m_settings.move_right) { + return InputEvent::MoveRightReleased; + } + if (key == m_settings.drop) { + return InputEvent::DropReleased; + } + if (key == m_settings.hold) { + return InputEvent::HoldReleased; + } + } + return helper::nullopt; +} + +input::KeyboardGameInput::KeyboardGameInput(KeyboardSettings settings, EventDispatcher* event_dispatcher) + : GameInput{ GameInputType::Keyboard }, + m_settings{ settings }, + m_event_dispatcher{ event_dispatcher } { + m_event_dispatcher->register_listener(this); +} + +input::KeyboardGameInput::~KeyboardGameInput() { + m_event_dispatcher->unregister_listener(this); +} diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp new file mode 100644 index 00000000..46bb4aec --- /dev/null +++ b/src/input/keyboard_input.hpp @@ -0,0 +1,151 @@ +#pragma once + +#include "SDL_keycode.h" +#include "game_input.hpp" +#include "helper/expected.hpp" +#include "helper/parse_json.hpp" +#include "input.hpp" +#include "manager/event_dispatcher.hpp" +#include "manager/sdl_key.hpp" + +#include +#include + + +namespace input { + + + struct KeyboardInput : Input { + + public: + KeyboardInput(); + virtual ~KeyboardInput(); + + + [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; + + [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; + }; + + + struct KeyboardSettings : InputSettings { + SDL::Key rotate_left = SDL::Key{ SDLK_LEFT }; + SDL::Key rotate_right = SDL::Key{ SDLK_RIGHT }; + SDL::Key move_left = SDL::Key{ SDLK_a }; + SDL::Key move_right = SDL::Key{ SDLK_d }; + SDL::Key move_down = SDL::Key{ SDLK_a }; + SDL::Key drop = SDL::Key{ SDLK_s }; + SDL::Key hold = SDL::Key{ SDLK_TAB }; + + SDL::Key pause = SDL::Key{ SDLK_ESCAPE }; + SDL::Key open_settings = SDL::Key{ SDLK_e }; + + //TODO: move into cpp + [[nodiscard]] helper::expected validate() const override { + std::vector already_bound_keys{}; + + const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, + drop, hold, pause, open_settings }; + + + for (const auto key_to_use : to_use) { + + if (std::find(already_bound_keys.cbegin(), already_bound_keys.cend(), key_to_use) + != already_bound_keys.cend()) { + return helper::unexpected{ + fmt::format("KeyCode already bound: '{}'", key_to_use.name()) + }; + } + + already_bound_keys.push_back(key_to_use); + } + + return true; + } + }; + + + struct KeyboardGameInput : public GameInput, public EventListener { + private: + KeyboardSettings m_settings; + std::vector m_event_buffer; + EventDispatcher* m_event_dispatcher; + + public: + KeyboardGameInput(KeyboardSettings settings, EventDispatcher* event_dispatcher); + + ~KeyboardGameInput() override; + + void handle_event(const SDL_Event& event) override; + + void update(SimulationStep simulation_step_index) override; + + [[nodiscard]] helper::optional get_menu_event(const SDL_Event& event) const override; + + [[nodiscard]] std::string describe_menu_event(MenuEvent event) const override; + + + private: + [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event) const; + }; +} // namespace input + + +//TODO port to input_type and let them have Settings that are serialiazable ! + +inline void to_json(nlohmann::json& j, const input::KeyboardSettings& settings) { + j = nlohmann::json{ + { "rotate_left", settings.rotate_left.name() }, + { "rotate_right", settings.rotate_right.name() }, + { "move_left", settings.move_left.name() }, + { "move_right", settings.move_right.name() }, + { "move_down", settings.move_down.name() }, + { "drop", settings.drop.name() }, + { "hold", settings.hold.name() }, + { "pause", settings.pause.name() }, + { "open_settings", settings.open_settings.name() }, + }; +} + + +inline SDL::Key get_key(const nlohmann::json& j, const std::string& name) { + + auto context = j.at(name); + + std::string input; + context.get_to(input); + + //TODO + const auto& value = SDL::Key::from_string(input); + + if (not value.has_value()) { + throw nlohmann::json::type_error::create( + 302, fmt::format("Expected a valid Key from string '{}', but got '{}'", name, input), &context + ); + } + return value.value(); +} + +inline void from_json(const nlohmann::json& j, input::KeyboardSettings& settings) { + + json::check_for_no_additional_keys( + j, { "type", "rotate_left", "rotate_right", "move_left", "move_right", "move_down", "drop", "hold", "pause", + "open_settings" } + ); + + settings.rotate_left = get_key(j, "rotate_left"); + settings.rotate_right = get_key(j, "rotate_right"); + settings.move_left = get_key(j, "move_left"); + settings.move_right = get_key(j, "move_right"); + settings.move_down = get_key(j, "move_down"); + settings.drop = get_key(j, "drop"); + settings.hold = get_key(j, "hold"); + + settings.pause = get_key(j, "pause"); + settings.open_settings = get_key(j, "open_settings"); + + const auto is_valid = settings.validate(); + if (not is_valid.has_value()) { + throw std::runtime_error(is_valid.error()); + } +} diff --git a/src/input/meson.build b/src/input/meson.build new file mode 100644 index 00000000..0c9951bd --- /dev/null +++ b/src/input/meson.build @@ -0,0 +1,19 @@ +graphics_src_files += files( + 'console_buttons.hpp', + 'game_input.cpp', + 'game_input.hpp', + 'input.cpp', + 'input.hpp', + 'input_creator.cpp', + 'input_creator.hpp', + 'joystick_input.cpp', + 'joystick_input.hpp', + 'keyboard_input.cpp', + 'keyboard_input.hpp', + 'mouse_input.cpp', + 'mouse_input.hpp', + 'replay_input.cpp', + 'replay_input.hpp', + 'touch_input.cpp', + 'touch_input.hpp', +) diff --git a/src/input/mouse_input.cpp b/src/input/mouse_input.cpp new file mode 100644 index 00000000..d3a01039 --- /dev/null +++ b/src/input/mouse_input.cpp @@ -0,0 +1,81 @@ + + +#include "mouse_input.hpp" + + +//TODO: +/* +[[nodiscard]] bool utils::event_is_click_event(const SDL_Event& event, CrossPlatformClickEvent click_type) { + + + decltype(event.type) desired_type{}; + switch (click_type) { + case CrossPlatformClickEvent::Motion: + desired_type = SDL_MOUSEMOTION; + break; + case CrossPlatformClickEvent::ButtonDown: + desired_type = SDL_MOUSEBUTTONDOWN; + break; + case CrossPlatformClickEvent::ButtonUp: + desired_type = SDL_MOUSEBUTTONUP; + break; + case CrossPlatformClickEvent::Any: + return event.type == SDL_MOUSEMOTION + || ((event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) + && event.button.button == SDL_BUTTON_LEFT); + default: + utils::unreachable(); + } + + + return event.type == desired_type && event.button.button == SDL_BUTTON_LEFT; + */ + + +/** + + +[[nodiscard]] std::pair utils::get_raw_coordinates(const Window* window, const SDL_Event& event) { + + assert(utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any) && "expected a click event"); + +#if defined(__ANDROID__) + // These are doubles, from 0-1 (or if using virtual layouts > 0) in percent, the have to be casted to absolut x coordinates! + const double x_percent = event.tfinger.x; + const double y_percent = event.tfinger.y; + const auto window_size = window->size(); + const auto x = static_cast(std::round(x_percent * window_size.x)); + const auto y = static_cast(std::round(y_percent * window_size.y)); + + +#elif defined(__SWITCH__) + UNUSED(window); + UNUSED(event); + throw std::runtime_error("Not supported on the Nintendo switch"); + int x{}; + int y{}; +#else + UNUSED(window); + + Sint32 x{}; + Sint32 y{}; + switch (event.type) { + case SDL_MOUSEMOTION: + x = event.motion.x; + y = event.motion.y; + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + x = event.button.x; + y = event.button.y; + break; + default: + utils::unreachable(); + } +#endif + + + return { static_cast(x), static_cast(y) }; +} + + */ diff --git a/src/input/mouse_input.hpp b/src/input/mouse_input.hpp new file mode 100644 index 00000000..961b8731 --- /dev/null +++ b/src/input/mouse_input.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "input.hpp" +#include "recordings/recording_reader.hpp" + +#include + +namespace input { + + struct MouseInput : public PointerInput { + public: + MouseInput(); + virtual ~MouseInput(); + + [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; + + [[nodiscard]] helper::optional get_pointer_event(const SDL_Event& event) const override; + + [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; + }; + + +} // namespace input + + diff --git a/src/platform/replay_input.cpp b/src/input/replay_input.cpp similarity index 78% rename from src/platform/replay_input.cpp rename to src/input/replay_input.cpp index 99ab1b1c..6e0a99a3 100644 --- a/src/platform/replay_input.cpp +++ b/src/input/replay_input.cpp @@ -1,12 +1,12 @@ #include "replay_input.hpp" #include "game/tetrion.hpp" +#include "helper/magic_enum_wrapper.hpp" - -ReplayInput::ReplayInput(std::shared_ptr recording_reader) - : Input{ InputType::Recording }, +input::ReplayGameInput::ReplayGameInput(std::shared_ptr recording_reader) + : GameInput{ GameInputType::Recording }, m_recording_reader{ std::move(recording_reader) } { } -void ReplayInput::update(const SimulationStep simulation_step_index) { +void input::ReplayGameInput::update(const SimulationStep simulation_step_index) { while (true) { if (is_end_of_recording()) { break; @@ -28,16 +28,16 @@ void ReplayInput::update(const SimulationStep simulation_step_index) { spdlog::debug("replaying event {} at step {}", magic_enum::enum_name(record.event), simulation_step_index); - Input::handle_event(record.event, simulation_step_index); + GameInput::handle_event(record.event, simulation_step_index); ++m_next_record_index; } - Input::update(simulation_step_index); + GameInput::update(simulation_step_index); } -void ReplayInput::late_update(const SimulationStep simulation_step_index) { - Input::late_update(simulation_step_index); +void input::ReplayGameInput::late_update(const SimulationStep simulation_step_index) { + GameInput::late_update(simulation_step_index); while (true) { if (m_next_snapshot_index >= m_recording_reader->snapshots().size()) { @@ -75,6 +75,6 @@ void ReplayInput::late_update(const SimulationStep simulation_step_index) { } } -[[nodiscard]] bool ReplayInput::is_end_of_recording() const { +[[nodiscard]] bool input::ReplayGameInput::is_end_of_recording() const { return m_next_record_index >= m_recording_reader->num_records(); } diff --git a/src/input/replay_input.hpp b/src/input/replay_input.hpp new file mode 100644 index 00000000..ec37fa9b --- /dev/null +++ b/src/input/replay_input.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "game_input.hpp" +#include "recordings/recording_reader.hpp" + +#include + +namespace input { + + + struct ReplayGameInput : public GameInput { + private: + std::shared_ptr m_recording_reader; + usize m_next_record_index{ 0 }; + usize m_next_snapshot_index{ 0 }; + + public: + ReplayGameInput(std::shared_ptr recording_reader); + + void update(SimulationStep simulation_step_index) override; + void late_update(SimulationStep simulation_step_index) override; + + [[nodiscard]] helper::optional get_menu_event(const SDL_Event& event) const override; + + [[nodiscard]] std::string describe_menu_event(MenuEvent event) const override; + + [[nodiscard]] bool is_end_of_recording() const; + }; + +} // namespace input diff --git a/src/platform/android_input.cpp b/src/input/touch_input.cpp similarity index 57% rename from src/platform/android_input.cpp rename to src/input/touch_input.cpp index 76229f4f..c2729cea 100644 --- a/src/platform/android_input.cpp +++ b/src/input/touch_input.cpp @@ -1,31 +1,28 @@ -#if defined(__ANDROID__) - -#include "android_input.hpp" +#include "touch_input.hpp" #include -#include - -void TouchInput::handle_event(const SDL_Event& event, const Window*) { +void input::TouchGameInput::handle_event(const SDL_Event& event) { m_event_buffer.push_back(event); } -void TouchInput::update(SimulationStep simulation_step_index) { +void input::TouchGameInput::update(SimulationStep simulation_step_index) { for (const auto& event : m_event_buffer) { const auto input_event = sdl_event_to_input_event(event); if (input_event.has_value()) { - Input::handle_event(*input_event, simulation_step_index); + GameInput::handle_event(*input_event, simulation_step_index); } } m_event_buffer.clear(); - Input::update(simulation_step_index); + GameInput::update(simulation_step_index); } -helper::optional TouchInput::sdl_event_to_input_event( // NOLINT(readability-function-cognitive-complexity) +helper::optional +input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function-cognitive-complexity) const SDL_Event& event ) { //TODO to handle those things better, holding has to be supported @@ -50,7 +47,7 @@ helper::optional TouchInput::sdl_event_to_input_event( // NOLINT(rea m_finger_state.insert_or_assign( finger_id, helper::optional{ - PressedState{timestamp, x, y} + PressedState{ timestamp, x, y } } ); } @@ -126,5 +123,56 @@ helper::optional TouchInput::sdl_event_to_input_event( // NOLINT(rea return helper::nullopt; } +//TODO: +/* +[[nodiscard]] bool utils::event_is_action(const SDL_Event& event, const CrossPlatformAction action) { + switch (action) { + case CrossPlatformAction::OK: + case CrossPlatformAction::DOWN: + case CrossPlatformAction::UP: + case CrossPlatformAction::LEFT: + case CrossPlatformAction::RIGHT: + case CrossPlatformAction::OPEN_SETTINGS: + case CrossPlatformAction::TAB: + // this can't be checked here, it has to be checked via collision on buttons etc. event_is_action(..., ...::DOWN, UP ...) can only be used inside device_supports_keys() clauses! + throw std::runtime_error("Not supported on android 'event_is_action'"); + case CrossPlatformAction::PAUSE: + return (event.type == SDL_KEYDOWN and event.key.keysym.sym == SDLK_AC_BACK); + + case CrossPlatformAction::UNPAUSE: + return event.type == SDL_FINGERDOWN; + + case CrossPlatformAction::EXIT: + case CrossPlatformAction::CLOSE: + return (event.type == SDL_KEYDOWN and event.key.keysym.sym == SDLK_AC_BACK); + + default: + utils::unreachable(); + } + -#endif + [[nodiscard]] std::string utils::action_description(CrossPlatformAction action) { + + + switch (action) { + case CrossPlatformAction::OK: + case CrossPlatformAction::DOWN: + case CrossPlatformAction::UP: + case CrossPlatformAction::LEFT: + case CrossPlatformAction::RIGHT: + case CrossPlatformAction::OPEN_SETTINGS: + case CrossPlatformAction::TAB: + // this can't be checked here, it has to be checked via collision on buttons etc. event_is_action(..., ...::DOWN, UP ...) can only be used inside device_supports_keys() clauses! + throw std::runtime_error("Not supported on android 'action_description'"); + case CrossPlatformAction::UNPAUSE: + return "Tap anywhere"; + case CrossPlatformAction::PAUSE: + case CrossPlatformAction::EXIT: + case CrossPlatformAction::CLOSE: + return "Back"; + + default: + utils::unreachable(); + } + } + */ diff --git a/src/input/touch_input.hpp b/src/input/touch_input.hpp new file mode 100644 index 00000000..229c6093 --- /dev/null +++ b/src/input/touch_input.hpp @@ -0,0 +1,189 @@ +#pragma once + + +#include "input.hpp" +#include "input/game_input.hpp" +#include "manager/event_dispatcher.hpp" + + +namespace input { + + struct TouchInput : PointerInput { + std::shared_ptr m_window; + + public: + TouchInput(const std::shared_ptr& window); + virtual ~TouchInput(); + + + [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; + + [[nodiscard]] helper::optional get_pointer_event(const SDL_Event& event) const override; + + [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; + }; + + struct TouchGameInput final : public GameInput, public EventListener { + private: + struct PressedState { + Uint32 timestamp; + float x; + float y; + explicit PressedState(Uint32 timestamp, float x, float y) : timestamp{ timestamp }, x{ x }, y{ y } { } + }; + + std::unordered_map> m_finger_state; + std::vector m_event_buffer; + EventDispatcher* m_event_dispatcher; + + public: + explicit TouchGameInput(EventDispatcher* event_dispatcher) + : GameInput{ GameInputType::Touch }, + m_event_dispatcher{ event_dispatcher } { + m_event_dispatcher->register_listener(this); + } + + ~TouchGameInput() override { + m_event_dispatcher->unregister_listener(this); + } + + void handle_event(const SDL_Event& event) override; + void update(SimulationStep simulation_step_index) override; + + [[nodiscard]] helper::optional get_menu_event(const SDL_Event& event) const override; + + [[nodiscard]] std::string describe_menu_event(MenuEvent event) const override; + + private: + [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event); + }; + +} // namespace input + + +//TODO: +/* + + + decltype(event.type) desired_type{}; + switch (click_type) { + case CrossPlatformClickEvent::Motion: + desired_type = SDL_FINGERMOTION; + break; + case CrossPlatformClickEvent::ButtonDown: + desired_type = SDL_FINGERDOWN; + break; + case CrossPlatformClickEvent::ButtonUp: + desired_type = SDL_FINGERUP; + break; + case CrossPlatformClickEvent::Any: + return event.type == SDL_FINGERMOTION || event.type == SDL_FINGERDOWN || event.type == SDL_FINGERUP; + default: + utils::unreachable(); + } + + return event.type == desired_type; + */ + + +/** + + + +[[nodiscard]] std::pair utils::get_raw_coordinates(const Window* window, const SDL_Event& event) { + + assert(utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any) && "expected a click event"); + +#if defined(__ANDROID__) + // These are doubles, from 0-1 (or if using virtual layouts > 0) in percent, the have to be casted to absolut x coordinates! + const double x_percent = event.tfinger.x; + const double y_percent = event.tfinger.y; + const auto window_size = window->size(); + const auto x = static_cast(std::round(x_percent * window_size.x)); + const auto y = static_cast(std::round(y_percent * window_size.y)); + + +#elif defined(__SWITCH__) + UNUSED(window); + UNUSED(event); + throw std::runtime_error("Not supported on the Nintendo switch"); + int x{}; + int y{}; +#else + UNUSED(window); + + Sint32 x{}; + Sint32 y{}; + switch (event.type) { + case SDL_MOUSEMOTION: + x = event.motion.x; + y = event.motion.y; + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + x = event.button.x; + y = event.button.y; + break; + default: + utils::unreachable(); + } +#endif + + + return { static_cast(x), static_cast(y) }; +} + + + * + */ + + +/* + +[[nodiscard]] SDL_Event utils::offset_event(const Window* window, const SDL_Event& event, const shapes::IPoint& point) { + + + assert(utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any) && "expected a click event"); + + + auto new_event = event; + +#if defined(__ANDROID__) + // These are doubles in percent, the have to be modified by using the windows sizes + + + const double x_percent = event.tfinger.x; + const double y_percent = event.tfinger.y; + const auto window_size = window->size(); + new_event.tfinger.x = x_percent + static_cast(point.x) / static_cast(window_size.x); + new_event.tfinger.y = y_percent + static_cast(point.y) / static_cast(window_size.y); + + +#elif defined(__SWITCH__) + UNUSED(window); + UNUSED(event); + UNUSED(point); + UNUSED(new_event); + throw std::runtime_error("Not supported on the Nintendo switch"); +#else + UNUSED(window); + + switch (event.type) { + case SDL_MOUSEMOTION: + new_event.motion.x = event.motion.x + point.x; + new_event.motion.y = event.motion.y + point.y; + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + new_event.button.x = event.button.x + point.x; + new_event.button.y = event.button.y + point.y; + break; + default: + utils::unreachable(); + } +#endif + + + return new_event; +} + */ diff --git a/src/main.cpp b/src/main.cpp index 948de8e2..d23a52a4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -59,16 +59,16 @@ int main(int argc, char** argv) { constexpr auto window_name = constants::program_name.c_str(); - std::unique_ptr window{ nullptr }; + std::shared_ptr window{ nullptr }; try { #if defined(__ANDROID__) or defined(__CONSOLE__) - window = std::make_unique(window_name, WindowPosition::Centered); + window = std::make_shared(window_name, WindowPosition::Centered); #else static constexpr int width = 1280; static constexpr int height = 720; - window = std::make_unique(window_name, WindowPosition::Centered, width, height); + window = std::make_shared(window_name, WindowPosition::Centered, width, height); #endif } catch (const helper::GeneralError& general_error) { spdlog::error("{}", general_error.message()); diff --git a/src/manager/controls.hpp b/src/manager/controls.hpp deleted file mode 100644 index 0f672482..00000000 --- a/src/manager/controls.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "helper/magic_enum_wrapper.hpp" -#include "key_codes.hpp" -#include "platform/capabilities.hpp" - -struct KeyboardControls final { - KeyCode rotate_left = KeyCode::Left; - KeyCode rotate_right = KeyCode::Right; - KeyCode move_left = KeyCode::A; - KeyCode move_right = KeyCode::D; - KeyCode move_down = KeyCode::S; - KeyCode drop = KeyCode::W; - KeyCode hold = KeyCode::Tab; - - void validate() const { - std::vector already_bound_keycodes{}; - if (utils::device_supports_keys()) { - for (const auto& key : utils::get_bound_keys({ utils::CrossPlatformAction::PAUSE, - utils::CrossPlatformAction::OPEN_SETTINGS })) { - const auto key_code = from_sdl_keycode(static_cast(key)); - if (key_code == KeyCode::Unknown) { - throw std::runtime_error("Couldn't map bound key '" + std::to_string(key) + "'"); - } - - already_bound_keycodes.push_back(key_code); - } - } - - - const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, drop, hold }; - - - for (const auto key_to_use : to_use) { - - if (std::find(already_bound_keycodes.cbegin(), already_bound_keycodes.cend(), key_to_use) - != already_bound_keycodes.cend()) { - std::string error_code = "KeyCode already bound: '"; - error_code += magic_enum::enum_name(key_to_use); - error_code += "'"; - - throw std::runtime_error(error_code); - } - - already_bound_keycodes.push_back(key_to_use); - } - } -}; diff --git a/src/manager/event_dispatcher.hpp b/src/manager/event_dispatcher.hpp index 9e3683a1..5d546a19 100644 --- a/src/manager/event_dispatcher.hpp +++ b/src/manager/event_dispatcher.hpp @@ -3,8 +3,8 @@ #include "graphics/rect.hpp" #include "helper/optional.hpp" #include "manager/event_listener.hpp" +#include "sdl_key.hpp" -#include #include #include #include @@ -12,14 +12,26 @@ struct EventDispatcher final { private: std::vector m_listeners; - Window* m_window; bool m_input_activated{ false }; bool m_enabled{ true }; - std::vector allowed_input_keys{ SDLK_RETURN, SDLK_BACKSPACE, SDLK_DOWN, SDLK_UP, - SDLK_LEFT, SDLK_RIGHT, SDLK_ESCAPE, SDLK_TAB }; + + //TODO: factor out to some other place! + std::vector allowed_input_keys{ + SDL::Key{ SDLK_RETURN }, + SDL::Key{ SDLK_BACKSPACE }, + SDL::Key{ SDLK_BACKSPACE, { SDL::Modifier::CTRL } }, + SDL::Key{ SDLK_DOWN }, + SDL::Key{ SDLK_UP }, + SDL::Key{ SDLK_LEFT }, + SDL::Key{ SDLK_RIGHT }, + SDL::Key{ SDLK_ESCAPE }, + SDL::Key{ SDLK_TAB }, + SDL::Key{ SDLK_c, { SDL::Modifier::CTRL } }, + SDL::Key{ SDLK_v, { SDL::Modifier::CTRL } } + }; public: - EventDispatcher(Window* window) : m_window{ window } {}; + explicit EventDispatcher() = default; void register_listener(EventListener* listener) { m_listeners.push_back(listener); @@ -42,10 +54,9 @@ struct EventDispatcher final { switch (event.type) { case SDL_KEYDOWN: case SDL_KEYUP: { - if (event.key.keysym.sym == SDLK_v and (event.key.keysym.mod & KMOD_CTRL) != 0) { - break; - } - if (std::find(allowed_input_keys.cbegin(), allowed_input_keys.cend(), event.key.keysym.sym) + if (std::find( + allowed_input_keys.cbegin(), allowed_input_keys.cend(), SDL::Key{ event.key.keysym } + ) == allowed_input_keys.cend()) { return; } @@ -62,7 +73,7 @@ struct EventDispatcher final { continue; } - listener->handle_event(event, m_window); + listener->handle_event(event); } } } diff --git a/src/manager/event_listener.hpp b/src/manager/event_listener.hpp index 05db635f..59415071 100644 --- a/src/manager/event_listener.hpp +++ b/src/manager/event_listener.hpp @@ -1,15 +1,14 @@ #pragma once #include - -#include "graphics/window.hpp" +#include struct EventListener { bool m_is_paused{ false }; virtual ~EventListener() = default; - virtual void handle_event(const SDL_Event& event, const Window* window) = 0; + virtual void handle_event(const SDL_Event& event) = 0; [[nodiscard]] bool is_paused() const { return m_is_paused; diff --git a/src/manager/key_codes.hpp b/src/manager/key_codes.hpp deleted file mode 100644 index 8203415a..00000000 --- a/src/manager/key_codes.hpp +++ /dev/null @@ -1,589 +0,0 @@ -#pragma once - -#include - -//TODO: remove this, SDL has it's own conversion function: -// https://wiki.libsdl.org/SDL2/SDL_GetKeyFromName -// https://wiki.libsdl.org/SDL2/SDL_GetKeyName - -enum class KeyCode { - Unknown, - Return, - Escape, - Backspace, - Tab, - Space, - ExclamationMark, - QuoteDouble, - Hash, - Percent, - Dollar, - Ampersand, - Quote, - LeftParenthesis, - RightParenthesis, - Asterisk, - Plus, - Comma, - Minus, - Period, - Slash, - Key0, - Key1, - Key2, - Key3, - Key4, - Key5, - Key6, - Key7, - Key8, - Key9, - Colon, - Semicolon, - Less, - Equals, - Greater, - QuestionMark, - At, - LeftBracket, - Backslash, - RightBracket, - Caret, - Underscore, - Backquote, - A, - B, - C, - D, - E, - F, - G, - H, - I, - J, - K, - L, - M, - N, - O, - P, - Q, - R, - S, - T, - U, - V, - W, - X, - Y, - Z, - CapsLock, - F1, - F2, - F3, - F4, - F5, - F6, - F7, - F8, - F9, - F10, - F11, - F12, - PrintScreen, - ScrollLock, - Pause, - Insert, - Home, - PageUp, - Delete, - End, - PageDown, - Right, - Left, - Down, - Up, - NumLockClear, - NumPadDivide, - NumPadMultiply, - NumPadMinus, - NumPadPlus, - NumPadEnter, - NumPad1, - NumPad2, - NumPad3, - NumPad4, - NumPad5, - NumPad6, - NumPad7, - NumPad8, - NumPad9, - NumPad0, - NumPadPeriod, -}; - -inline SDL_KeyCode to_sdl_keycode(KeyCode code) { - switch (code) { - case KeyCode::Unknown: - return SDLK_UNKNOWN; - case KeyCode::Return: - return SDLK_RETURN; - case KeyCode::Escape: - return SDLK_ESCAPE; - case KeyCode::Backspace: - return SDLK_BACKSPACE; - case KeyCode::Tab: - return SDLK_TAB; - case KeyCode::Space: - return SDLK_SPACE; - case KeyCode::ExclamationMark: - return SDLK_EXCLAIM; - case KeyCode::QuoteDouble: - return SDLK_QUOTEDBL; - case KeyCode::Hash: - return SDLK_HASH; - case KeyCode::Percent: - return SDLK_PERCENT; - case KeyCode::Dollar: - return SDLK_DOLLAR; - case KeyCode::Ampersand: - return SDLK_AMPERSAND; - case KeyCode::Quote: - return SDLK_QUOTE; - case KeyCode::LeftParenthesis: - return SDLK_LEFTPAREN; - case KeyCode::RightParenthesis: - return SDLK_RIGHTPAREN; - case KeyCode::Asterisk: - return SDLK_ASTERISK; - case KeyCode::Plus: - return SDLK_PLUS; - case KeyCode::Comma: - return SDLK_COMMA; - case KeyCode::Minus: - return SDLK_MINUS; - case KeyCode::Period: - return SDLK_PERIOD; - case KeyCode::Slash: - return SDLK_SLASH; - case KeyCode::Key0: - return SDLK_0; - case KeyCode::Key1: - return SDLK_1; - case KeyCode::Key2: - return SDLK_2; - case KeyCode::Key3: - return SDLK_3; - case KeyCode::Key4: - return SDLK_4; - case KeyCode::Key5: - return SDLK_5; - case KeyCode::Key6: - return SDLK_6; - case KeyCode::Key7: - return SDLK_7; - case KeyCode::Key8: - return SDLK_8; - case KeyCode::Key9: - return SDLK_9; - case KeyCode::Colon: - return SDLK_COLON; - case KeyCode::Semicolon: - return SDLK_SEMICOLON; - case KeyCode::Less: - return SDLK_LESS; - case KeyCode::Equals: - return SDLK_EQUALS; - case KeyCode::Greater: - return SDLK_GREATER; - case KeyCode::QuestionMark: - return SDLK_QUESTION; - case KeyCode::At: - return SDLK_AT; - case KeyCode::LeftBracket: - return SDLK_LEFTBRACKET; - case KeyCode::Backslash: - return SDLK_BACKSLASH; - case KeyCode::RightBracket: - return SDLK_RIGHTBRACKET; - case KeyCode::Caret: - return SDLK_CARET; - case KeyCode::Underscore: - return SDLK_UNDERSCORE; - case KeyCode::Backquote: - return SDLK_BACKQUOTE; - case KeyCode::A: - return SDLK_a; - case KeyCode::B: - return SDLK_b; - case KeyCode::C: - return SDLK_c; - case KeyCode::D: - return SDLK_d; - case KeyCode::E: - return SDLK_e; - case KeyCode::F: - return SDLK_f; - case KeyCode::G: - return SDLK_g; - case KeyCode::H: - return SDLK_h; - case KeyCode::I: - return SDLK_i; - case KeyCode::J: - return SDLK_j; - case KeyCode::K: - return SDLK_k; - case KeyCode::L: - return SDLK_l; - case KeyCode::M: - return SDLK_m; - case KeyCode::N: - return SDLK_n; - case KeyCode::O: - return SDLK_o; - case KeyCode::P: - return SDLK_p; - case KeyCode::Q: - return SDLK_q; - case KeyCode::R: - return SDLK_r; - case KeyCode::S: - return SDLK_s; - case KeyCode::T: - return SDLK_t; - case KeyCode::U: - return SDLK_u; - case KeyCode::V: - return SDLK_v; - case KeyCode::W: - return SDLK_w; - case KeyCode::X: - return SDLK_x; - case KeyCode::Y: - return SDLK_y; - case KeyCode::Z: - return SDLK_z; - case KeyCode::CapsLock: - return SDLK_CAPSLOCK; - case KeyCode::F1: - return SDLK_F1; - case KeyCode::F2: - return SDLK_F2; - case KeyCode::F3: - return SDLK_F3; - case KeyCode::F4: - return SDLK_F4; - case KeyCode::F5: - return SDLK_F5; - case KeyCode::F6: - return SDLK_F6; - case KeyCode::F7: - return SDLK_F7; - case KeyCode::F8: - return SDLK_F8; - case KeyCode::F9: - return SDLK_F9; - case KeyCode::F10: - return SDLK_F10; - case KeyCode::F11: - return SDLK_F11; - case KeyCode::F12: - return SDLK_F12; - case KeyCode::PrintScreen: - return SDLK_PRINTSCREEN; - case KeyCode::ScrollLock: - return SDLK_SCROLLLOCK; - case KeyCode::Pause: - return SDLK_PAUSE; - case KeyCode::Insert: - return SDLK_INSERT; - case KeyCode::Home: - return SDLK_HOME; - case KeyCode::PageUp: - return SDLK_PAGEUP; - case KeyCode::Delete: - return SDLK_DELETE; - case KeyCode::End: - return SDLK_END; - case KeyCode::PageDown: - return SDLK_PAGEDOWN; - case KeyCode::Right: - return SDLK_RIGHT; - case KeyCode::Left: - return SDLK_LEFT; - case KeyCode::Down: - return SDLK_DOWN; - case KeyCode::Up: - return SDLK_UP; - case KeyCode::NumLockClear: - return SDLK_NUMLOCKCLEAR; - case KeyCode::NumPadDivide: - return SDLK_KP_DIVIDE; - case KeyCode::NumPadMultiply: - return SDLK_KP_MULTIPLY; - case KeyCode::NumPadMinus: - return SDLK_KP_MINUS; - case KeyCode::NumPadPlus: - return SDLK_KP_PLUS; - case KeyCode::NumPadEnter: - return SDLK_KP_ENTER; - case KeyCode::NumPad1: - return SDLK_KP_1; - case KeyCode::NumPad2: - return SDLK_KP_2; - case KeyCode::NumPad3: - return SDLK_KP_3; - case KeyCode::NumPad4: - return SDLK_KP_4; - case KeyCode::NumPad5: - return SDLK_KP_5; - case KeyCode::NumPad6: - return SDLK_KP_6; - case KeyCode::NumPad7: - return SDLK_KP_7; - case KeyCode::NumPad8: - return SDLK_KP_8; - case KeyCode::NumPad9: - return SDLK_KP_9; - case KeyCode::NumPad0: - return SDLK_KP_0; - case KeyCode::NumPadPeriod: - return SDLK_KP_PERIOD; - default: - return SDLK_UNKNOWN; - } -} - -inline KeyCode from_sdl_keycode(SDL_KeyCode code) { - switch (code) { - case SDLK_UNKNOWN: - return KeyCode::Unknown; - case SDLK_RETURN: - return KeyCode::Return; - case SDLK_ESCAPE: - return KeyCode::Escape; - case SDLK_BACKSPACE: - return KeyCode::Backspace; - case SDLK_TAB: - return KeyCode::Tab; - case SDLK_SPACE: - return KeyCode::Space; - case SDLK_EXCLAIM: - return KeyCode::ExclamationMark; - case SDLK_QUOTEDBL: - return KeyCode::QuoteDouble; - case SDLK_HASH: - return KeyCode::Hash; - case SDLK_PERCENT: - return KeyCode::Percent; - case SDLK_DOLLAR: - return KeyCode::Dollar; - case SDLK_AMPERSAND: - return KeyCode::Ampersand; - case SDLK_QUOTE: - return KeyCode::Quote; - case SDLK_LEFTPAREN: - return KeyCode::LeftParenthesis; - case SDLK_RIGHTPAREN: - return KeyCode::RightParenthesis; - case SDLK_ASTERISK: - return KeyCode::Asterisk; - case SDLK_PLUS: - return KeyCode::Plus; - case SDLK_COMMA: - return KeyCode::Comma; - case SDLK_MINUS: - return KeyCode::Minus; - case SDLK_PERIOD: - return KeyCode::Period; - case SDLK_SLASH: - return KeyCode::Slash; - case SDLK_0: - return KeyCode::Key0; - case SDLK_1: - return KeyCode::Key1; - case SDLK_2: - return KeyCode::Key2; - case SDLK_3: - return KeyCode::Key3; - case SDLK_4: - return KeyCode::Key4; - case SDLK_5: - return KeyCode::Key5; - case SDLK_6: - return KeyCode::Key6; - case SDLK_7: - return KeyCode::Key7; - case SDLK_8: - return KeyCode::Key8; - case SDLK_9: - return KeyCode::Key9; - case SDLK_COLON: - return KeyCode::Colon; - case SDLK_SEMICOLON: - return KeyCode::Semicolon; - case SDLK_LESS: - return KeyCode::Less; - case SDLK_EQUALS: - return KeyCode::Equals; - case SDLK_GREATER: - return KeyCode::Greater; - case SDLK_QUESTION: - return KeyCode::QuestionMark; - case SDLK_AT: - return KeyCode::At; - case SDLK_LEFTBRACKET: - return KeyCode::LeftBracket; - case SDLK_BACKSLASH: - return KeyCode::Backslash; - case SDLK_RIGHTBRACKET: - return KeyCode::RightBracket; - case SDLK_CARET: - return KeyCode::Caret; - case SDLK_UNDERSCORE: - return KeyCode::Underscore; - case SDLK_BACKQUOTE: - return KeyCode::Backquote; - case SDLK_a: - return KeyCode::A; - case SDLK_b: - return KeyCode::B; - case SDLK_c: - return KeyCode::C; - case SDLK_d: - return KeyCode::D; - case SDLK_e: - return KeyCode::E; - case SDLK_f: - return KeyCode::F; - case SDLK_g: - return KeyCode::G; - case SDLK_h: - return KeyCode::H; - case SDLK_i: - return KeyCode::I; - case SDLK_j: - return KeyCode::J; - case SDLK_k: - return KeyCode::K; - case SDLK_l: - return KeyCode::L; - case SDLK_m: - return KeyCode::M; - case SDLK_n: - return KeyCode::N; - case SDLK_o: - return KeyCode::O; - case SDLK_p: - return KeyCode::P; - case SDLK_q: - return KeyCode::Q; - case SDLK_r: - return KeyCode::R; - case SDLK_s: - return KeyCode::S; - case SDLK_t: - return KeyCode::T; - case SDLK_u: - return KeyCode::U; - case SDLK_v: - return KeyCode::V; - case SDLK_w: - return KeyCode::W; - case SDLK_x: - return KeyCode::X; - case SDLK_y: - return KeyCode::Y; - case SDLK_z: - return KeyCode::Z; - case SDLK_CAPSLOCK: - return KeyCode::CapsLock; - case SDLK_F1: - return KeyCode::F1; - case SDLK_F2: - return KeyCode::F2; - case SDLK_F3: - return KeyCode::F3; - case SDLK_F4: - return KeyCode::F4; - case SDLK_F5: - return KeyCode::F5; - case SDLK_F6: - return KeyCode::F6; - case SDLK_F7: - return KeyCode::F7; - case SDLK_F8: - return KeyCode::F8; - case SDLK_F9: - return KeyCode::F9; - case SDLK_F10: - return KeyCode::F10; - case SDLK_F11: - return KeyCode::F11; - case SDLK_F12: - return KeyCode::F12; - case SDLK_PRINTSCREEN: - return KeyCode::PrintScreen; - case SDLK_SCROLLLOCK: - return KeyCode::ScrollLock; - case SDLK_PAUSE: - return KeyCode::Pause; - case SDLK_INSERT: - return KeyCode::Insert; - case SDLK_HOME: - return KeyCode::Home; - case SDLK_PAGEUP: - return KeyCode::PageUp; - case SDLK_DELETE: - return KeyCode::Delete; - case SDLK_END: - return KeyCode::End; - case SDLK_PAGEDOWN: - return KeyCode::PageDown; - case SDLK_RIGHT: - return KeyCode::Right; - case SDLK_LEFT: - return KeyCode::Left; - case SDLK_DOWN: - return KeyCode::Down; - case SDLK_UP: - return KeyCode::Up; - case SDLK_NUMLOCKCLEAR: - return KeyCode::NumLockClear; - case SDLK_KP_DIVIDE: - return KeyCode::NumPadDivide; - case SDLK_KP_MULTIPLY: - return KeyCode::NumPadMultiply; - case SDLK_KP_MINUS: - return KeyCode::NumPadMinus; - case SDLK_KP_PLUS: - return KeyCode::NumPadPlus; - case SDLK_KP_ENTER: - return KeyCode::NumPadEnter; - case SDLK_KP_1: - return KeyCode::NumPad1; - case SDLK_KP_2: - return KeyCode::NumPad2; - case SDLK_KP_3: - return KeyCode::NumPad3; - case SDLK_KP_4: - return KeyCode::NumPad4; - case SDLK_KP_5: - return KeyCode::NumPad5; - case SDLK_KP_6: - return KeyCode::NumPad6; - case SDLK_KP_7: - return KeyCode::NumPad7; - case SDLK_KP_8: - return KeyCode::NumPad8; - case SDLK_KP_9: - return KeyCode::NumPad9; - case SDLK_KP_0: - return KeyCode::NumPad0; - case SDLK_KP_PERIOD: - return KeyCode::NumPadPeriod; - default: - return KeyCode::Unknown; - } -} diff --git a/src/manager/meson.build b/src/manager/meson.build index b9179d95..886fdb90 100644 --- a/src/manager/meson.build +++ b/src/manager/meson.build @@ -1,12 +1,13 @@ graphics_src_files += files( - 'controls.hpp', 'event_dispatcher.hpp', 'event_listener.hpp', 'font.cpp', 'font.hpp', 'input_event.hpp', - 'key_codes.hpp', 'music_manager.cpp', 'music_manager.hpp', - 'settings.hpp', + 'sdl_key.cpp', + 'sdl_key.hpp', + 'settings_manager.cpp', + 'settings_manager.hpp', ) diff --git a/src/manager/music_manager.cpp b/src/manager/music_manager.cpp index 0d7f2dae..3a6c1c42 100644 --- a/src/manager/music_manager.cpp +++ b/src/manager/music_manager.cpp @@ -4,7 +4,7 @@ #include "helper/errors.hpp" #include "helper/optional.hpp" #include "helper/types.hpp" -#include "platform/capabilities.hpp" +#include "manager/sdl_key.hpp" #include #include @@ -352,18 +352,26 @@ helper::optional MusicManager::change_volume(const std::int8_t steps) { return new_volume; } -bool MusicManager::handle_event(const SDL_Event& event) { +bool MusicManager::handle_event(const std::shared_ptr&, const SDL_Event& event) { + if (event.type == SDL_KEYDOWN) { + const auto key = SDL::Key{ event.key.keysym }; - if (utils::device_supports_keys() && event.type == SDL_KEYDOWN) { - if (event.key.keysym.sym == SDLK_PLUS or event.key.keysym.sym == SDLK_KP_PLUS) { - change_volume(1); + if (key.is_key(SDL::Key{ SDLK_PLUS }) or key.is_key(SDL::Key{ SDLK_KP_PLUS })) { + const i8 steps = key.has_modifier(SDL::Modifier::CTRL) ? 100 + : key.has_modifier(SDL::Modifier::SHIFT) ? 10 + : 1; + + change_volume(steps); return true; } - if (event.key.keysym.sym == SDLK_MINUS or event.key.keysym.sym == SDLK_KP_MINUS) { - change_volume(-1); + if (key.is_key(SDL::Key{ SDLK_MINUS }) or key.is_key(SDL::Key{ SDLK_KP_MINUS })) { + const i8 steps = key.has_modifier(SDL::Modifier::CTRL) ? -100 + : key.has_modifier(SDL::Modifier::SHIFT) ? -10 + : -1; + change_volume(steps); return true; } } diff --git a/src/manager/music_manager.hpp b/src/manager/music_manager.hpp index 702be644..68dfb692 100644 --- a/src/manager/music_manager.hpp +++ b/src/manager/music_manager.hpp @@ -3,6 +3,7 @@ #include "helper/optional.hpp" #include "helper/types.hpp" #include "manager/service_provider.hpp" +#include "input/input.hpp" #include #include @@ -52,7 +53,7 @@ struct MusicManager final { // no nodiscard, since the return value is only a side effect, that is maybe useful helper::optional change_volume(std::int8_t steps); - bool handle_event(const SDL_Event& event); + bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event); bool add_volume_listener(const std::string& name, VolumeChangeFunction change_function) { diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp new file mode 100644 index 00000000..3d2a678f --- /dev/null +++ b/src/manager/sdl_key.cpp @@ -0,0 +1,239 @@ + +#include "sdl_key.hpp" +#include "helper/utils.hpp" + +#include +#include +#include + + +SDL::Key::Key(SDL_KeyCode keycode, ModifierType modifiers) : m_keycode{ keycode }, m_modifiers{ modifiers } { } + +SDL::Key::Key(SDL_KeyCode keycode, const std::vector& modifiers) + : Key{ keycode, SDL::Key::sdl_modifier_from_modifiers(modifiers) } { } + +SDL::Key::Key(const SDL_Keysym& keysym) : Key{ static_cast(keysym.sym), keysym.mod } { } + +helper::expected +SDL::Key::from_string(const std::string& value, const std::vector& modifiers) { + + const auto keycode = SDL::Key::sdl_keycode_from_string(value); + if (not keycode.has_value()) { + return helper::unexpected{ keycode.error() }; + } + + const auto raw_modifiers = SDL::Key::sdl_modifier_from_modifiers(modifiers); + return SDL::Key{ keycode.value(), raw_modifiers }; +} + + +[[nodiscard]] bool SDL::Key::is_key(const SDL::Key& other) const { + return m_keycode == other.m_keycode; +} + +namespace { + SDL_Keymod to_sdl_modifier(SDL::Modifier modifier) { + switch (modifier) { + case SDL::Modifier::LSHIFT: + return KMOD_LSHIFT; + case SDL::Modifier::RSHIFT: + return KMOD_RSHIFT; + + case SDL::Modifier::LCTRL: + return KMOD_LCTRL; + case SDL::Modifier::RCTRL: + return KMOD_RCTRL; + + case SDL::Modifier::LALT: + return KMOD_LALT; + case SDL::Modifier::RALT: + return KMOD_RALT; + + case SDL::Modifier::LGUI: + return KMOD_LGUI; + case SDL::Modifier::RGUI: + return KMOD_RGUI; + + case SDL::Modifier::NUM: + return KMOD_NUM; + case SDL::Modifier::CAPS: + return KMOD_CAPS; + case SDL::Modifier::MODE: + return KMOD_MODE; + case SDL::Modifier::SCROLL: + return KMOD_SCROLL; + + case SDL::Modifier::CTRL: + return KMOD_CTRL; + case SDL::Modifier::SHIFT: + return KMOD_SHIFT; + case SDL::Modifier::ALT: + return KMOD_ALT; + case SDL::Modifier::GUI: + return KMOD_GUI; + default: + utils::unreachable(); + } + } + + SDL::Modifier from_sdl_modifier(SDL_Keymod modifier) { + switch (modifier) { + case KMOD_LSHIFT: + return SDL::Modifier::LSHIFT; + case KMOD_RSHIFT: + return SDL::Modifier::RSHIFT; + + case KMOD_LCTRL: + return SDL::Modifier::LCTRL; + case KMOD_RCTRL: + return SDL::Modifier::RCTRL; + + case KMOD_LALT: + return SDL::Modifier::LALT; + case KMOD_RALT: + return SDL::Modifier::RALT; + + case KMOD_LGUI: + return SDL::Modifier::LGUI; + case KMOD_RGUI: + return SDL::Modifier::RGUI; + + case KMOD_NUM: + return SDL::Modifier::NUM; + case KMOD_CAPS: + return SDL::Modifier::CAPS; + case KMOD_MODE: + return SDL::Modifier::MODE; + case KMOD_SCROLL: + return SDL::Modifier::SCROLL; + + case KMOD_CTRL: + return SDL::Modifier::CTRL; + case KMOD_SHIFT: + return SDL::Modifier::SHIFT; + case KMOD_ALT: + return SDL::Modifier::ALT; + case KMOD_GUI: + return SDL::Modifier::GUI; + default: + utils::unreachable(); + } + } +} // namespace + +[[nodiscard]] bool SDL::Key::has_modifier(const Modifier& modifier) const { + const auto sdl_modifier = to_sdl_modifier(modifier); + return (m_modifiers & sdl_modifier) != KMOD_NONE; +} + +[[nodiscard]] bool SDL::Key::operator==(const Key& other) const { + if (not is_key(other)) { + return false; + } + + + // fast path, if the second one has no modifiers + if (other.m_modifiers == KMOD_NONE) { + return m_modifiers == KMOD_NONE; + } + + //TODO: use a feaster method, this takes a long time! + const auto it = detail::ModifierIterator(other.m_modifiers); + + for (const auto& [present, modifier] : it) { + if (present != not has_modifier(modifier)) { + return false; + } + } + + return true; +} + +[[nodiscard]] std::string SDL::Key::name() const { + const auto* name = SDL_GetKeyName(m_keycode); + if (std::strlen(name) == 0) { + throw std::runtime_error(fmt::format( + "No name for the sdl key {}: {}", static_cast>(m_keycode), + SDL_GetError() + )); + } + return std::string{ name }; +} + + +[[nodiscard]] helper::expected SDL::Key::sdl_keycode_from_string(const std::string& value) { + const auto key = SDL_GetKeyFromName(value.c_str()); + if (key == SDLK_UNKNOWN) { + return helper::unexpected{ + fmt::format("No sdl key for the name '{}': {}", value, SDL_GetError()) + }; + } + + return static_cast(key); +} + +[[nodiscard]] SDL::Key::ModifierType SDL::Key::sdl_modifier_from_modifiers(const std::vector& modifiers) { + ModifierType result = KMOD_NONE; + for (const auto& modifier : modifiers) { + result |= to_sdl_modifier(modifier); + } + + return result; +} + + +detail::ModifierIterator::ModifierIterator(SDL::Key::ModifierType modifiers) { + + const std::vector> triples{ + { KMOD_LSHIFT, KMOD_RSHIFT, KMOD_SHIFT }, + { KMOD_LCTRL, KMOD_RCTRL, KMOD_CTRL }, + { KMOD_LALT, KMOD_RALT, KMOD_ALT }, + { KMOD_LGUI, KMOD_RGUI, KMOD_GUI }, + }; + + + const std::vector normal_mods{ + KMOD_NUM, + KMOD_CAPS, + KMOD_MODE, + KMOD_SCROLL, + }; + + for (const auto& [left_mod, right_mod, both_mod] : triples) { + + std::tuple result = { false, false, false }; + + if ((modifiers & both_mod) == both_mod) { + result = { true, true, true }; + } else if ((modifiers & left_mod) == left_mod) { + result = { true, false, true }; + } else if ((modifiers & right_mod) == right_mod) { + result = { false, true, true }; + } + + m_underlying_container.emplace_back(std::get<0>(result), from_sdl_modifier(left_mod)); + m_underlying_container.emplace_back(std::get<1>(result), from_sdl_modifier(right_mod)); + m_underlying_container.emplace_back(std::get<2>(result), from_sdl_modifier(both_mod)); + } + + for (const auto& mod : normal_mods) { + m_underlying_container.emplace_back((modifiers & mod) != KMOD_NONE, from_sdl_modifier(mod)); + } +} + + +[[nodiscard]] detail::ModifierIterator::const_iterator detail::ModifierIterator::begin() const { + return m_underlying_container.begin(); +} + +[[nodiscard]] detail::ModifierIterator::iterator detail::ModifierIterator::begin() { + return m_underlying_container.begin(); +} + +[[nodiscard]] detail::ModifierIterator::const_iterator detail::ModifierIterator::end() const { + return m_underlying_container.end(); +} + +[[nodiscard]] detail::ModifierIterator::iterator detail::ModifierIterator::end() { + return m_underlying_container.end(); +} diff --git a/src/manager/sdl_key.hpp b/src/manager/sdl_key.hpp new file mode 100644 index 00000000..0c1d3cd1 --- /dev/null +++ b/src/manager/sdl_key.hpp @@ -0,0 +1,112 @@ +#pragma once + +#include "helper/expected.hpp" + +#include "helper/types.hpp" + +#include +#include +#include +#include + +namespace SDL { + + enum class Modifier : u8 { + LSHIFT, + RSHIFT, + + LCTRL, + RCTRL, + + LALT, + RALT, + + LGUI, + RGUI, + + NUM, + CAPS, + MODE, + SCROLL, + + CTRL, + SHIFT, + ALT, + GUI, + }; + + struct Key { + // the difference between SDL_Keymod and ModifierType type is, that ModifierType is SDL_Keymod or-ed together, and supports arithmetic expressions out of teh box (like & and |) + using ModifierType = std::underlying_type_t; + + private: + SDL_KeyCode m_keycode; + ModifierType m_modifiers; + + public: + explicit Key(SDL_KeyCode keycode, ModifierType modifiers); + explicit Key(SDL_KeyCode keycode, const std::vector& modifiers = {}); + explicit Key(const SDL_Keysym& keysym); + + static helper::expected + from_string(const std::string& value, const std::vector& modifiers = {}); + + + [[nodiscard]] bool is_key(const Key& other) const; + + [[nodiscard]] bool has_modifier(const Modifier& modifier) const; + + [[nodiscard]] bool operator==(const Key& other) const; + + [[nodiscard]] std::string name() const; + + private: + [[nodiscard]] static helper::expected sdl_keycode_from_string(const std::string& value + ); + + [[nodiscard]] static ModifierType sdl_modifier_from_modifiers(const std::vector& modifiers); + }; + + +} // namespace SDL + + +namespace detail { + + struct ModifierIterator { + public: + using ContentType = std::pair; + using Container = std::vector; + using iterator = Container::iterator; + using const_iterator = Container::const_iterator; + + private: + std::vector m_underlying_container{}; + + public: + ModifierIterator(SDL::Key::ModifierType modifiers); + + [[nodiscard]] const_iterator begin() const; + [[nodiscard]] iterator begin(); + + [[nodiscard]] const_iterator end() const; + [[nodiscard]] iterator end(); + }; +} // namespace detail + + +//TODO: add input manager and rename curretn inputmanager to game_input manager or similar + +// each devices can have multiple input devices, like keyboard, joycon etc. you can select mulltiple ones for navigation, some keys are ficed, like ctrl+c ctrl+v or arrow keys enter, esc tab,, some like wasd and similar can be chnaged by the inpout controller, support both click only and keyboard only, joyocn only, joyncon(s) + keyboard configurations + + +// each devices has a name, e.g. keabord 1, keabyord 2, SDL_NumJoysticks + +// SDL_JoystickNameForIndex +//SDL_JoystickName + +//SDL_JoystickInstanceID + +// if a type is disconnected, recognize that, and potentially pause the game !, show warning! + +//SDL_JoystickCurrentPowerLevel diff --git a/src/manager/service_provider.hpp b/src/manager/service_provider.hpp index 9d42bb79..44160039 100644 --- a/src/manager/service_provider.hpp +++ b/src/manager/service_provider.hpp @@ -1,5 +1,8 @@ #pragma once +#include "manager/event_dispatcher.hpp" + + #if defined(_HAVE_DISCORD_SDK) && !defined(_OOPETRIS_RECORDING_UTILITY) #include "discord/core.hpp" @@ -8,14 +11,19 @@ #endif +//forward declarations struct CommandLineArguments; -struct Settings; +struct SettingsManager; struct MusicManager; +struct EventDispatcher; struct Renderer; struct FontManager; -struct EventDispatcher; struct Window; +namespace input { + struct InputManager; +} + namespace scenes { struct Scene; } @@ -30,18 +38,21 @@ struct ServiceProvider { [[nodiscard]] virtual CommandLineArguments& command_line_arguments() = 0; [[nodiscard]] virtual const CommandLineArguments& command_line_arguments() const = 0; - [[nodiscard]] virtual Settings& settings() = 0; - [[nodiscard]] virtual const Settings& settings() const = 0; + [[nodiscard]] virtual SettingsManager& settings_manager() = 0; + [[nodiscard]] virtual const SettingsManager& settings_manager() const = 0; [[nodiscard]] virtual MusicManager& music_manager() = 0; [[nodiscard]] virtual const MusicManager& music_manager() const = 0; [[nodiscard]] virtual const Renderer& renderer() const = 0; - [[nodiscard]] virtual FontManager& fonts() = 0; - [[nodiscard]] virtual const FontManager& fonts() const = 0; + [[nodiscard]] virtual FontManager& font_manager() = 0; + [[nodiscard]] virtual const FontManager& font_manager() const = 0; [[nodiscard]] virtual EventDispatcher& event_dispatcher() = 0; [[nodiscard]] virtual const EventDispatcher& event_dispatcher() const = 0; [[nodiscard]] virtual const Window& window() const = 0; [[nodiscard]] virtual Window& window() = 0; + [[nodiscard]] virtual input::InputManager& input_manager() = 0; + [[nodiscard]] virtual const input::InputManager& input_manager() const = 0; + #if defined(_HAVE_DISCORD_SDK) && !defined(_OOPETRIS_RECORDING_UTILITY) [[nodiscard]] virtual helper::optional& discord_instance() = 0; diff --git a/src/manager/settings.hpp b/src/manager/settings.hpp deleted file mode 100644 index 87863cd4..00000000 --- a/src/manager/settings.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#pragma once - -#include "helper/magic_enum_wrapper.hpp" -#include "helper/parse_json.hpp" -#include "manager/controls.hpp" -#include "platform/platform.hpp" - -#include -#include -#include -#include - -inline void to_json(nlohmann::json& j, const KeyboardControls& controls) { - j = nlohmann::json{ - { "rotate_left", magic_enum::enum_name(controls.rotate_left) }, - { "rotate_right", magic_enum::enum_name(controls.rotate_right) }, - { "move_left", magic_enum::enum_name(controls.move_left) }, - { "move_right", magic_enum::enum_name(controls.move_right) }, - { "move_down", magic_enum::enum_name(controls.move_down) }, - { "drop", magic_enum::enum_name(controls.drop) }, - { "hold", magic_enum::enum_name(controls.hold) }, - }; -} - - -inline KeyCode get_key_code_safe(const nlohmann::json& j, const std::string& name) { - - auto context = j.at(name); - - std::string input; - context.get_to(input); - - const auto& value = magic_enum::enum_cast(input); - if (not value.has_value()) { - throw nlohmann::json::type_error::create( - 302, fmt::format("Expected a valid KeyCode in key '{}', but got '{}'", name, input), &context - ); - } - return value.value(); -} - -inline void from_json(const nlohmann::json& j, KeyboardControls& controls) { - - json::check_for_no_additional_keys( - j, { "type", "rotate_left", "rotate_right", "move_left", "move_right", "move_down", "drop", "hold" } - ); - - controls.rotate_left = get_key_code_safe(j, "rotate_left"); - controls.rotate_right = get_key_code_safe(j, "rotate_right"); - controls.move_left = get_key_code_safe(j, "move_left"); - controls.move_right = get_key_code_safe(j, "move_right"); - controls.move_down = get_key_code_safe(j, "move_down"); - controls.drop = get_key_code_safe(j, "drop"); - controls.hold = get_key_code_safe(j, "hold"); - controls.validate(); -} - -using Controls = std::variant; - -inline void to_json(nlohmann::json& j, const Controls& controls) { - std::visit( - helper::overloaded{ - [&](const KeyboardControls& keyboard_controls) { - to_json(j, keyboard_controls); - j["type"] = "keyboard"; - }, - }, - controls - ); -} - -inline void from_json(const nlohmann::json& j, Controls& controls) { - const auto& type = j.at("type"); - - if (type == "keyboard") { - KeyboardControls keyboard_controls; - from_json(j, keyboard_controls); - controls = keyboard_controls; - } else { - throw std::runtime_error{ fmt::format("unsupported control type '{}'", to_string(type)) }; - } -} - -struct Settings { - Platform platform{}; - Controls controls; - float volume{ 0.2f }; - bool discord{ false }; //changing this requires a restart -}; - -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Settings, platform, controls, volume, discord) diff --git a/src/manager/settings_manager.cpp b/src/manager/settings_manager.cpp new file mode 100644 index 00000000..d9835b69 --- /dev/null +++ b/src/manager/settings_manager.cpp @@ -0,0 +1,21 @@ +#include "settings_manager.hpp" +#include "helper/graphic_utils.hpp" + + +#include + +SettingsManager::SettingsManager(ServiceProvider* service_provider) : m_service_provider{ service_provider } { + const std::filesystem::path settings_file = utils::get_root_folder() / detail::settings_filename; + + const auto result = json::try_parse_json_file(settings_file); + + if (result.has_value()) { + m_current_settings = result.value(); + } else { + spdlog::error("unable to load settings from \"{}\": {}", detail::settings_filename, result.error()); + spdlog::warn("applying default settings"); + + //TODO: better default settings + m_current_settings = detail::Settings{ input::KeyboardSettings{}, 1.0 }; + } +} diff --git a/src/manager/settings_manager.hpp b/src/manager/settings_manager.hpp new file mode 100644 index 00000000..ed2c1bf3 --- /dev/null +++ b/src/manager/settings_manager.hpp @@ -0,0 +1,68 @@ +#pragma once + + +#include "helper/magic_enum_wrapper.hpp" +#include "helper/parse_json.hpp" +#include "helper/platform.hpp" +#include "input/keyboard_input.hpp" +#include "manager/service_provider.hpp" + +#include +#include +#include + + +using Controls = std::variant; + +inline void to_json(nlohmann::json& j, const Controls& controls) { + std::visit( + helper::overloaded{ + [&](const input::KeyboardSettings& keyboard_controls) { + to_json(j, keyboard_controls); + j["type"] = "keyboard"; + }, + }, + controls + ); +} + +inline void from_json(const nlohmann::json& j, Controls& controls) { + const auto& type = j.at("type"); + + if (type == "keyboard") { + input::KeyboardSettings keyboard_controls{}; + from_json(j, keyboard_controls); + controls = keyboard_controls; + } else { + throw std::runtime_error{ fmt::format("unsupported control type '{}'", to_string(type)) }; + } +} + + +namespace detail { + + static constexpr auto settings_filename = "settings.json"; + + + struct Settings { + Controls controls; + float volume{ 0.2f }; + bool discord{ false }; //changing this requires a restart + }; + + + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Settings, volume, discord) + +} // namespace detail + + +struct SettingsManager { +private: + ServiceProvider* m_service_provider; + detail::Settings m_current_settings; + +public: + explicit SettingsManager(ServiceProvider* service_provider); + + [[nodiscard]] const detail::Settings& settings() const; +}; diff --git a/src/meson.build b/src/meson.build index b57a8dab..9152205c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -14,14 +14,13 @@ main_files = files( subdir('game') subdir('graphics') subdir('helper') +subdir('input') subdir('manager') -subdir('platform') subdir('recordings') subdir('scenes') subdir('thirdparty') subdir('ui') - if online_multiplayer_supported subdir('lobby') endif diff --git a/src/platform/android_input.hpp b/src/platform/android_input.hpp deleted file mode 100644 index 71ea3439..00000000 --- a/src/platform/android_input.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#if defined(__ANDROID__) - - -#include "input.hpp" -#include "manager/event_dispatcher.hpp" - - -struct TouchInput final : public Input, public EventListener { -private: - struct PressedState { - Uint32 timestamp; - float x; - float y; - explicit PressedState(Uint32 timestamp, float x, float y) : timestamp{ timestamp }, x{ x }, y{ y } { } - }; - - std::unordered_map> m_finger_state; - std::vector m_event_buffer; - EventDispatcher* m_event_dispatcher; - -public: - explicit TouchInput(EventDispatcher* event_dispatcher) - : Input{ InputType::Touch }, - m_event_dispatcher{ event_dispatcher } { - m_event_dispatcher->register_listener(this); - } - - ~TouchInput() override { - m_event_dispatcher->unregister_listener(this); - } - - void handle_event(const SDL_Event& event, const Window* window) override; - void update(SimulationStep simulation_step_index) override; - -private: - [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event); -}; - -#endif diff --git a/src/platform/capabilities.cpp b/src/platform/capabilities.cpp deleted file mode 100644 index 9bde5b1a..00000000 --- a/src/platform/capabilities.cpp +++ /dev/null @@ -1,426 +0,0 @@ - -#include -#include - -#include "helper/utils.hpp" -#include "platform/capabilities.hpp" - -#if defined(__CONSOLE__) -#include "helper/console_helpers.hpp" -#include "platform/console_buttons.hpp" -#endif - - -namespace { - - inline std::string get_error_from_errno() { - -#if defined(_MSC_VER) - char buffer[256] = { 0 }; - const auto result = strerror_s<256>(buffer, errno); - - if (result == 0) { - return std::string{ buffer }; - - } else { - return std::string{ "Error while getting error!" }; - } - -#else - return std::string{ std::strerror(errno) }; - -#endif - } - - -} // namespace - - -[[nodiscard]] std::string utils::built_for_platform() { -#if defined(__ANDROID__) - return "Android"; -#elif defined(__SWITCH__) - return "Nintendo Switch"; -#elif defined(__3DS__) - return "Nintendo 3DS"; -#elif defined(FLATPAK_BUILD) - return "Linux (Flatpak)"; -#elif defined(__linux__) - return "Linux"; -#elif defined(_WIN32) - return "Windows"; -#elif defined(__APPLE__) - return "MacOS"; -#else -#error "Unsupported platform" -#endif -} - -// partially from: https://stackoverflow.com/questions/17347950/how-do-i-open-a-url-from-c -[[nodiscard]] bool utils::open_url(const std::string& url) { -#if defined(__ANDROID__) - const auto result = SDL_OpenURL(url.c_str()); - if (result < 0) { - spdlog::error("Error in opening url in android: {}", SDL_GetError()); - return false; - } - - return true; - -#elif defined(__CONSOLE__) - auto result = console::open_url(url); - spdlog::info("Returned string from url open was: {}", result); - return true; -#else - //TODO: this is dangerous, if we supply user input, so use SDL_OpenURL preferably - -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) - const std::string shell_command = "start " + url; -#elif defined(__APPLE__) - const std::string shell_command = "open " + url; -#elif defined(__linux__) - const std::string shell_command = "xdg-open " + url; -#else -#error "Unsupported platform" -#endif - - const auto result = system(shell_command.c_str()); - if (result < 0) { - spdlog::error("Error in opening url: {}", get_error_from_errno()); - return false; - } - - - return true; - - -#endif -} - - -[[nodiscard]] bool utils::event_is_action(const SDL_Event& event, const CrossPlatformAction action) { -#if defined(__ANDROID__) - switch (action) { - case CrossPlatformAction::OK: - case CrossPlatformAction::DOWN: - case CrossPlatformAction::UP: - case CrossPlatformAction::LEFT: - case CrossPlatformAction::RIGHT: - case CrossPlatformAction::OPEN_SETTINGS: - case CrossPlatformAction::TAB: - // this can't be checked here, it has to be checked via collision on buttons etc. event_is_action(..., ...::DOWN, UP ...) can only be used inside device_supports_keys() clauses! - throw std::runtime_error("Not supported on android 'event_is_action'"); - case CrossPlatformAction::PAUSE: - return (event.type == SDL_KEYDOWN and event.key.keysym.sym == SDLK_AC_BACK); - - case CrossPlatformAction::UNPAUSE: - return event.type == SDL_FINGERDOWN; - - case CrossPlatformAction::EXIT: - case CrossPlatformAction::CLOSE: - return (event.type == SDL_KEYDOWN and event.key.keysym.sym == SDLK_AC_BACK); - - default: - utils::unreachable(); - } -#else - - const std::vector needed_events = utils::key_map.at(static_cast(action)); - for (const auto& needed_event : needed_events) { // NOLINT(readability-use-anyofallof) -#if defined(__SWITCH__) or defined(__3DS__) - //TODO: some events use the SDL_JOYAXISMOTION event, but that needs to be done in the next reiteration of these helpers! - if (event.type == SDL_JOYBUTTONDOWN and event.jbutton.button == needed_event) { - return true; - } -#else - if (event.type == SDL_KEYDOWN and event.key.keysym.sym == needed_event) { - return true; - } -#endif - } - return false; -#endif -} - - -[[nodiscard]] std::vector utils::get_bound_keys() { - std::vector bound_keys{}; - for (const auto& [_, keys] : utils::key_map) { - for (const auto key : keys) { - bound_keys.push_back(key); - } - } - return bound_keys; -} - - -[[nodiscard]] std::vector utils::get_bound_keys(const std::vector& actions) { - std::vector bound_keys{}; - for (const auto& [value, keys] : utils::key_map) { - if (std::find(actions.cbegin(), actions.cend(), static_cast(value)) - == actions.cend()) { - continue; - } - for (const auto key : keys) { - bound_keys.push_back(key); - } - } - return bound_keys; -} - -[[nodiscard]] std::string utils::action_description(CrossPlatformAction action) { -#if defined(__ANDROID__) - - switch (action) { - case CrossPlatformAction::OK: - case CrossPlatformAction::DOWN: - case CrossPlatformAction::UP: - case CrossPlatformAction::LEFT: - case CrossPlatformAction::RIGHT: - case CrossPlatformAction::OPEN_SETTINGS: - case CrossPlatformAction::TAB: - // this can't be checked here, it has to be checked via collision on buttons etc. event_is_action(..., ...::DOWN, UP ...) can only be used inside device_supports_keys() clauses! - throw std::runtime_error("Not supported on android 'action_description'"); - case CrossPlatformAction::UNPAUSE: - return "Tap anywhere"; - case CrossPlatformAction::PAUSE: - case CrossPlatformAction::EXIT: - case CrossPlatformAction::CLOSE: - return "Back"; - - default: - utils::unreachable(); - } -#elif defined(__SWITCH__) - switch (action) { - case CrossPlatformAction::OK: - return "A"; - case CrossPlatformAction::PAUSE: - case CrossPlatformAction::UNPAUSE: - return "PLUS"; - case CrossPlatformAction::CLOSE: - case CrossPlatformAction::EXIT: - return "MINUS"; - case CrossPlatformAction::DOWN: - return "Down"; - case CrossPlatformAction::UP: - return "Up"; - case CrossPlatformAction::LEFT: - return "Left"; - case CrossPlatformAction::RIGHT: - return "Right"; - case CrossPlatformAction::OPEN_SETTINGS: - return "Y"; - default: - utils::unreachable(); - } -#elif defined(__3DS__) - switch (action) { - case CrossPlatformAction::OK: - return "A"; - case CrossPlatformAction::PAUSE: - case CrossPlatformAction::UNPAUSE: - return "Y"; - case CrossPlatformAction::CLOSE: - case CrossPlatformAction::EXIT: - return "X"; - case CrossPlatformAction::DOWN: - return "Down"; - case CrossPlatformAction::UP: - return "Up"; - case CrossPlatformAction::LEFT: - return "Left"; - case CrossPlatformAction::RIGHT: - return "Right"; - case CrossPlatformAction::OPEN_SETTINGS: - return "Select"; - default: - utils::unreachable(); - } -#else - switch (action) { - case CrossPlatformAction::OK: - return "Enter"; - case CrossPlatformAction::PAUSE: - case CrossPlatformAction::UNPAUSE: - case CrossPlatformAction::CLOSE: - return "Esc"; - case CrossPlatformAction::EXIT: - return "Enter"; - case CrossPlatformAction::DOWN: - return "Down"; - case CrossPlatformAction::UP: - return "Up"; - case CrossPlatformAction::LEFT: - return "Left"; - case CrossPlatformAction::RIGHT: - return "Right"; - case CrossPlatformAction::OPEN_SETTINGS: - return "E"; - default: - utils::unreachable(); - } -#endif -} - - -//TODO: not correctly supported ButtonUp, since it only can be triggered, when a ButtonDown event is fired first and the target is not left (unhovered) - -[[nodiscard]] bool utils::event_is_click_event(const SDL_Event& event, CrossPlatformClickEvent click_type) { - -#if defined(__ANDROID__) - decltype(event.type) desired_type{}; - switch (click_type) { - case CrossPlatformClickEvent::Motion: - desired_type = SDL_FINGERMOTION; - break; - case CrossPlatformClickEvent::ButtonDown: - desired_type = SDL_FINGERDOWN; - break; - case CrossPlatformClickEvent::ButtonUp: - desired_type = SDL_FINGERUP; - break; - case CrossPlatformClickEvent::Any: - return event.type == SDL_FINGERMOTION || event.type == SDL_FINGERDOWN || event.type == SDL_FINGERUP; - default: - utils::unreachable(); - } - - return event.type == desired_type; - -#elif defined(__SWITCH__) - UNUSED(event); - UNUSED(click_type); - throw std::runtime_error("Not supported on the Nintendo switch"); -#else - decltype(event.type) desired_type{}; - switch (click_type) { - case CrossPlatformClickEvent::Motion: - desired_type = SDL_MOUSEMOTION; - break; - case CrossPlatformClickEvent::ButtonDown: - desired_type = SDL_MOUSEBUTTONDOWN; - break; - case CrossPlatformClickEvent::ButtonUp: - desired_type = SDL_MOUSEBUTTONUP; - break; - case CrossPlatformClickEvent::Any: - return event.type == SDL_MOUSEMOTION - || ((event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) - && event.button.button == SDL_BUTTON_LEFT); - default: - utils::unreachable(); - } - - - return event.type == desired_type && event.button.button == SDL_BUTTON_LEFT; -#endif -} - -[[nodiscard]] std::pair utils::get_raw_coordinates(const Window* window, const SDL_Event& event) { - - assert(utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any) && "expected a click event"); - -#if defined(__ANDROID__) - // These are doubles, from 0-1 (or if using virtual layouts > 0) in percent, the have to be casted to absolut x coordinates! - const double x_percent = event.tfinger.x; - const double y_percent = event.tfinger.y; - const auto window_size = window->size(); - const auto x = static_cast(std::round(x_percent * window_size.x)); - const auto y = static_cast(std::round(y_percent * window_size.y)); - - -#elif defined(__SWITCH__) - UNUSED(window); - UNUSED(event); - throw std::runtime_error("Not supported on the Nintendo switch"); - int x{}; - int y{}; -#else - UNUSED(window); - - Sint32 x{}; - Sint32 y{}; - switch (event.type) { - case SDL_MOUSEMOTION: - x = event.motion.x; - y = event.motion.y; - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - x = event.button.x; - y = event.button.y; - break; - default: - utils::unreachable(); - } -#endif - - - return { static_cast(x), static_cast(y) }; -} - - -[[nodiscard]] bool utils::is_event_in(const Window* window, const SDL_Event& event, const shapes::URect& rect) { - - const auto& [x, y] = get_raw_coordinates(window, event); - const auto casted_rect = rect.cast(); - - const auto rect_start_x = casted_rect.top_left.x; - const auto rect_start_y = casted_rect.top_left.y; - const auto rect_end_x = casted_rect.bottom_right.x; - const auto rect_end_y = casted_rect.bottom_right.y; - - - const bool button_clicked = (x >= rect_start_x and x <= rect_end_x and y >= rect_start_y and y <= rect_end_y); - - return button_clicked; -} - - -[[nodiscard]] SDL_Event utils::offset_event(const Window* window, const SDL_Event& event, const shapes::IPoint& point) { - - - assert(utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any) && "expected a click event"); - - - auto new_event = event; - -#if defined(__ANDROID__) - // These are doubles in percent, the have to be modified by using the windows sizes - - - const double x_percent = event.tfinger.x; - const double y_percent = event.tfinger.y; - const auto window_size = window->size(); - new_event.tfinger.x = x_percent + static_cast(point.x) / static_cast(window_size.x); - new_event.tfinger.y = y_percent + static_cast(point.y) / static_cast(window_size.y); - - -#elif defined(__SWITCH__) - UNUSED(window); - UNUSED(event); - UNUSED(point); - UNUSED(new_event); - throw std::runtime_error("Not supported on the Nintendo switch"); -#else - UNUSED(window); - - switch (event.type) { - case SDL_MOUSEMOTION: - new_event.motion.x = event.motion.x + point.x; - new_event.motion.y = event.motion.y + point.y; - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - new_event.button.x = event.button.x + point.x; - new_event.button.y = event.button.y + point.y; - break; - default: - utils::unreachable(); - } -#endif - - - return new_event; -} diff --git a/src/platform/capabilities.hpp b/src/platform/capabilities.hpp deleted file mode 100644 index 31bf07a8..00000000 --- a/src/platform/capabilities.hpp +++ /dev/null @@ -1,150 +0,0 @@ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "graphics/window.hpp" -#include "helper/types.hpp" -#include "helper/utils.hpp" - -#if defined(__CONSOLE__) -#include "platform/console_buttons.hpp" -#endif - -//TODO factor this file into mulitple ones, according to logic distribution of what the functions are doing, remove and refacator the input helper functions - -namespace utils { - - enum class Orientation : u8 { - Portrait, // 9x16, e.g. smartphone - Landscape // 16x9 - }; - - struct Capabilities { - bool supports_keys; - bool supports_clicks; - Orientation orientation; - }; - - // the PAUSE and UNPAUSE might be different (e.g on android, even if androids map is stub, - // it checks in the usage of these for the CrossPlatformAction!), so don't remove the duplication here! - enum class CrossPlatformAction : u8 { OK, PAUSE, UNPAUSE, EXIT, DOWN, UP, LEFT, RIGHT, CLOSE, OPEN_SETTINGS, TAB }; - - static std::unordered_map> - key_map = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -#if defined(__ANDROID__) - { - { static_cast(CrossPlatformAction::OK), { 0 }}, - { static_cast(CrossPlatformAction::PAUSE), { 0 }}, - { static_cast(CrossPlatformAction::UNPAUSE), { 0 }}, - { static_cast(CrossPlatformAction::EXIT), { 0 }}, - { static_cast(CrossPlatformAction::DOWN), { 0 }}, - { static_cast(CrossPlatformAction::UP), { 0 }}, - { static_cast(CrossPlatformAction::LEFT), { 0 }}, - { static_cast(CrossPlatformAction::RIGHT), { 0 }}, - { static_cast(CrossPlatformAction::CLOSE), { 0 }}, - {static_cast(CrossPlatformAction::OPEN_SETTINGS), { 0 }}, - { static_cast(CrossPlatformAction::TAB), { 0 }} - }; -#elif defined(__SWITCH__) - { - { static_cast(CrossPlatformAction::OK),{ JOYCON_A } }, - { static_cast(CrossPlatformAction::PAUSE), { JOYCON_PLUS }}, - { static_cast(CrossPlatformAction::UNPAUSE), { JOYCON_PLUS }}, - { static_cast(CrossPlatformAction::EXIT), { JOYCON_MINUS }}, - { static_cast(CrossPlatformAction::DOWN), - { JOYCON_DPAD_DOWN, JOYCON_LDPAD_DOWN, JOYCON_RDPAD_DOWN } }, - { static_cast(CrossPlatformAction::UP), { JOYCON_DPAD_UP, JOYCON_LDPAD_UP, JOYCON_RDPAD_UP }}, - { static_cast(CrossPlatformAction::LEFT), - { JOYCON_DPAD_LEFT, JOYCON_LDPAD_LEFT, JOYCON_RDPAD_LEFT } }, - { static_cast(CrossPlatformAction::RIGHT), - { JOYCON_DPAD_RIGHT, JOYCON_LDPAD_RIGHT, JOYCON_RDPAD_RIGHT } }, - { static_cast(CrossPlatformAction::CLOSE), { JOYCON_MINUS }}, - {static_cast(CrossPlatformAction::OPEN_SETTINGS), { JOYCON_Y }}, - { static_cast(CrossPlatformAction::TAB), {}}, // no tab support -}; -#elif defined(__3DS__) - { - { static_cast(CrossPlatformAction::OK),{ JOYCON_A } }, - { static_cast(CrossPlatformAction::PAUSE), { JOYCON_Y }}, - { static_cast(CrossPlatformAction::UNPAUSE), { JOYCON_Y }}, - { static_cast(CrossPlatformAction::EXIT), { JOYCON_X }}, - { static_cast(CrossPlatformAction::DOWN), - { JOYCON_DPAD_DOWN, JOYCON_CSTICK_DOWN, JOYCON_CPAD_DOWN } }, - { static_cast(CrossPlatformAction::UP), { JOYCON_DPAD_UP, JOYCON_CSTICK_UP, JOYCON_CPAD_UP }}, - { static_cast(CrossPlatformAction::LEFT), - { JOYCON_DPAD_LEFT, JOYCON_CSTICK_LEFT, JOYCON_CPAD_LEFT } }, - { static_cast(CrossPlatformAction::RIGHT), - { JOYCON_DPAD_RIGHT, JOYCON_CSTICK_RIGHT, JOYCON_CPAD_RIGHT } }, - { static_cast(CrossPlatformAction::CLOSE), { JOYCON_X }}, - {static_cast(CrossPlatformAction::OPEN_SETTINGS), { JOYCON_SELECT }}, - { static_cast(CrossPlatformAction::TAB), {}}, // no tab support -}; -#else - { - { static_cast(CrossPlatformAction::OK), { SDLK_RETURN, SDLK_SPACE }}, - { static_cast(CrossPlatformAction::PAUSE), { SDLK_ESCAPE }}, - { static_cast(CrossPlatformAction::UNPAUSE), { SDLK_ESCAPE }}, - { static_cast(CrossPlatformAction::EXIT), { SDLK_RETURN }}, - { static_cast(CrossPlatformAction::DOWN), { SDLK_DOWN, SDLK_s }}, - { static_cast(CrossPlatformAction::UP), { SDLK_UP, SDLK_w }}, - { static_cast(CrossPlatformAction::LEFT), { SDLK_LEFT, SDLK_a }}, - { static_cast(CrossPlatformAction::RIGHT), { SDLK_RIGHT, SDLK_d }}, - { static_cast(CrossPlatformAction::CLOSE), { SDLK_ESCAPE }}, - {static_cast(CrossPlatformAction::OPEN_SETTINGS), { SDLK_p }}, - { static_cast(CrossPlatformAction::TAB), { SDLK_TAB }}, -}; -#endif - - //TODO: refactor - [[nodiscard]] constexpr Capabilities get_capabilities() { -#if defined(__ANDROID__) - return Capabilities{ false, true, Orientation::Portrait }; -#elif defined(__SWITCH__) or defined(__3DS__) - return Capabilities{ true, false, Orientation::Landscape }; -#else - return Capabilities{ true, true, Orientation::Landscape }; -#endif - } - - [[nodiscard]] constexpr bool device_supports_keys() { - return get_capabilities().supports_keys; - } - - [[nodiscard]] constexpr bool device_supports_clicks() { - return get_capabilities().supports_clicks; - } - - [[nodiscard]] constexpr Orientation device_orientation() { - return get_capabilities().orientation; - } - - [[nodiscard]] std::string built_for_platform(); - - [[nodiscard]] bool open_url(const std::string& url); - - [[nodiscard]] bool event_is_action(const SDL_Event& event, CrossPlatformAction action); - - [[nodiscard]] std::vector get_bound_keys(); - [[nodiscard]] std::vector get_bound_keys(const std::vector& actions); - - [[nodiscard]] std::string action_description(CrossPlatformAction action); - - enum class CrossPlatformClickEvent : u8 { Motion, ButtonDown, ButtonUp, Any }; - - [[nodiscard]] bool event_is_click_event(const SDL_Event& event, CrossPlatformClickEvent click_type); - - [[nodiscard]] std::pair get_raw_coordinates(const Window* window, const SDL_Event& event); - - [[nodiscard]] bool is_event_in(const Window* window, const SDL_Event& event, const shapes::URect& rect); - - [[nodiscard]] SDL_Event offset_event(const Window* window, const SDL_Event& event, const shapes::IPoint& point); - -} // namespace utils diff --git a/src/platform/console_input.cpp b/src/platform/console_input.cpp deleted file mode 100644 index 76947d93..00000000 --- a/src/platform/console_input.cpp +++ /dev/null @@ -1,131 +0,0 @@ - -#if defined(__CONSOLE__) -#include "console_input.hpp" - - -void JoystickInput::handle_event(const SDL_Event& event, const Window*) { - m_event_buffer.push_back(event); -} - -void JoystickInput::update(SimulationStep simulation_step_index) { - for (const auto& event : m_event_buffer) { - const auto input_event = sdl_event_to_input_event(event); - if (input_event.has_value()) { - Input::handle_event(*input_event, simulation_step_index); - } - } - m_event_buffer.clear(); - - Input::update(simulation_step_index); -} - -#if defined(__SWITCH__) - - -helper::optional JoystickInput::sdl_event_to_input_event(const SDL_Event& event) const { - if (event.type == SDL_JOYBUTTONDOWN) { - const auto button = event.jbutton.button; - if (button == JOYCON_DPAD_LEFT) { - return InputEvent::RotateLeftPressed; - } - if (button == JOYCON_DPAD_RIGHT) { - return InputEvent::RotateRightPressed; - } - if (button == JOYCON_LDPAD_DOWN or button == JOYCON_RDPAD_DOWN) { - return InputEvent::MoveDownPressed; - } - if (button == JOYCON_LDPAD_LEFT or button == JOYCON_RDPAD_LEFT) { - return InputEvent::MoveLeftPressed; - } - if (button == JOYCON_LDPAD_RIGHT or button == JOYCON_RDPAD_RIGHT) { - return InputEvent::MoveRightPressed; - } - if (button == JOYCON_X) { - return InputEvent::DropPressed; - } - if (button == JOYCON_B) { - return InputEvent::HoldPressed; - } - } else if (event.type == SDL_JOYBUTTONUP) { - const auto button = event.jbutton.button; - if (button == JOYCON_DPAD_LEFT) { - return InputEvent::RotateLeftReleased; - } - if (button == JOYCON_DPAD_RIGHT) { - return InputEvent::RotateRightReleased; - } - if (button == JOYCON_LDPAD_DOWN or button == JOYCON_RDPAD_DOWN) { - return InputEvent::MoveDownReleased; - } - if (button == JOYCON_LDPAD_LEFT or button == JOYCON_RDPAD_LEFT) { - return InputEvent::MoveLeftReleased; - } - if (button == JOYCON_LDPAD_RIGHT or button == JOYCON_RDPAD_RIGHT) { - return InputEvent::MoveRightReleased; - } - if (button == JOYCON_X) { - return InputEvent::DropReleased; - } - if (button == JOYCON_B) { - return InputEvent::HoldReleased; - } - } - return helper::nullopt; -} -#elif defined(__3DS__) - - -helper::optional JoystickInput::sdl_event_to_input_event(const SDL_Event& event) const { - if (event.type == SDL_JOYBUTTONDOWN) { - const auto button = event.jbutton.button; - if (button == JOYCON_L) { - return InputEvent::RotateLeftPressed; - } - if (button == JOYCON_R) { - return InputEvent::RotateRightPressed; - } - if (button == JOYCON_DPAD_DOWN or button == JOYCON_CSTICK_DOWN) { - return InputEvent::MoveDownPressed; - } - if (button == JOYCON_DPAD_LEFT or button == JOYCON_CSTICK_LEFT) { - return InputEvent::MoveLeftPressed; - } - if (button == JOYCON_DPAD_RIGHT or button == JOYCON_CSTICK_RIGHT) { - return InputEvent::MoveRightPressed; - } - if (button == JOYCON_A) { - return InputEvent::DropPressed; - } - if (button == JOYCON_B) { - return InputEvent::HoldPressed; - } - } else if (event.type == SDL_JOYBUTTONUP) { - const auto button = event.jbutton.button; - if (button == JOYCON_L) { - return InputEvent::RotateLeftReleased; - } - if (button == JOYCON_R) { - return InputEvent::RotateRightReleased; - } - if (button == JOYCON_DPAD_DOWN or button == JOYCON_CSTICK_DOWN) { - return InputEvent::MoveDownReleased; - } - if (button == JOYCON_DPAD_LEFT or button == JOYCON_CSTICK_LEFT) { - return InputEvent::MoveLeftReleased; - } - if (button == JOYCON_DPAD_RIGHT or button == JOYCON_CSTICK_RIGHT) { - return InputEvent::MoveRightReleased; - } - if (button == JOYCON_A) { - return InputEvent::DropReleased; - } - if (button == JOYCON_B) { - return InputEvent::HoldReleased; - } - } - return helper::nullopt; -} -#endif - - -#endif diff --git a/src/platform/console_input.hpp b/src/platform/console_input.hpp deleted file mode 100644 index 82fb2e7a..00000000 --- a/src/platform/console_input.hpp +++ /dev/null @@ -1,34 +0,0 @@ - - -#pragma once - -#if defined(__CONSOLE__) - -#include "console_buttons.hpp" -#include "input.hpp" -#include "manager/event_dispatcher.hpp" - -struct JoystickInput : public Input, public EventListener { -private: - std::vector m_event_buffer; - EventDispatcher* m_event_dispatcher; - -public: - JoystickInput(EventDispatcher* event_dispatcher) - : Input{ InputType::Controller }, - m_event_dispatcher{ event_dispatcher } { - m_event_dispatcher->register_listener(this); - } - - ~JoystickInput() override { - m_event_dispatcher->unregister_listener(this); - } - - void handle_event(const SDL_Event& event, const Window* window) override; - - void update(SimulationStep simulation_step_index) override; - -private: - [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event) const; -}; -#endif diff --git a/src/platform/input.hpp b/src/platform/input.hpp deleted file mode 100644 index bb2918db..00000000 --- a/src/platform/input.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include "helper/clock_source.hpp" -#include "helper/optional.hpp" -#include "helper/random.hpp" -#include "helper/types.hpp" -#include "manager/controls.hpp" -#include "manager/event_listener.hpp" -#include "manager/input_event.hpp" -#include "manager/settings.hpp" - -#include -#include - -struct Tetrion; - -enum class InputCommand : u8 { - MoveLeft, - MoveRight, - MoveDown, - RotateLeft, - RotateRight, - Drop, - Hold, - ReleaseMoveDown, -}; - -enum class InputType : u8 { Touch, Keyboard, Controller, Recording }; - -struct Input { -public: - using OnEventCallback = std::function; - -private: - enum class HoldableKey : u8 { - Left, - Right, - }; - - static constexpr u64 delayed_auto_shift_frames = 10; - static constexpr u64 auto_repeat_rate_frames = 2; - - std::unordered_map m_keys_hold; - InputType m_input_type; - -protected: - Tetrion* m_target_tetrion{}; - OnEventCallback m_on_event_callback{}; - - Input(InputType input_type) : m_input_type{ input_type } { } - - void handle_event(InputEvent event, SimulationStep simulation_step_index); - -public: - virtual void update(SimulationStep simulation_step_index); - virtual void late_update(SimulationStep){}; - - [[nodiscard]] InputType input_type() const { - return m_input_type; - } - - [[nodiscard]] bool supports_das() const { - return m_input_type != InputType::Touch; - } - - void set_target_tetrion(Tetrion* target_tetrion) { - m_target_tetrion = target_tetrion; - } - - void set_event_callback(OnEventCallback on_event_callback) { - m_on_event_callback = std::move(on_event_callback); - } - - Input(const Input&) = delete; - Input& operator=(const Input&) = delete; - - virtual ~Input() = default; -}; diff --git a/src/platform/keyboard_input.cpp b/src/platform/keyboard_input.cpp deleted file mode 100644 index 1500346c..00000000 --- a/src/platform/keyboard_input.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "keyboard_input.hpp" - -void KeyboardInput::handle_event(const SDL_Event& event, const Window*) { - m_event_buffer.push_back(event); -} - -void KeyboardInput::update(SimulationStep simulation_step_index) { - for (const auto& event : m_event_buffer) { - const auto input_event = sdl_event_to_input_event(event); - if (input_event.has_value()) { - Input::handle_event(*input_event, simulation_step_index); - } - } - m_event_buffer.clear(); - - Input::update(simulation_step_index); -} - -helper::optional -KeyboardInput::sdl_event_to_input_event( // NOLINT(readability-function-cognitive-complexity) - const SDL_Event& event -) const { - if (event.type == SDL_KEYDOWN and event.key.repeat == 0) { - const auto key = event.key.keysym.sym; - if (key == to_sdl_keycode(m_controls.rotate_left)) { - return InputEvent::RotateLeftPressed; - } - if (key == to_sdl_keycode(m_controls.rotate_right)) { - return InputEvent::RotateRightPressed; - } - if (key == to_sdl_keycode(m_controls.move_down)) { - return InputEvent::MoveDownPressed; - } - if (key == to_sdl_keycode(m_controls.move_left)) { - return InputEvent::MoveLeftPressed; - } - if (key == to_sdl_keycode(m_controls.move_right)) { - return InputEvent::MoveRightPressed; - } - if (key == to_sdl_keycode(m_controls.drop)) { - return InputEvent::DropPressed; - } - if (key == to_sdl_keycode(m_controls.hold)) { - return InputEvent::HoldPressed; - } - } else if (event.type == SDL_KEYUP) { - const auto key = event.key.keysym.sym; - if (key == to_sdl_keycode(m_controls.rotate_left)) { - return InputEvent::RotateLeftReleased; - } - if (key == to_sdl_keycode(m_controls.rotate_right)) { - return InputEvent::RotateRightReleased; - } - if (key == to_sdl_keycode(m_controls.move_down)) { - return InputEvent::MoveDownReleased; - } - if (key == to_sdl_keycode(m_controls.move_left)) { - return InputEvent::MoveLeftReleased; - } - if (key == to_sdl_keycode(m_controls.move_right)) { - return InputEvent::MoveRightReleased; - } - if (key == to_sdl_keycode(m_controls.drop)) { - return InputEvent::DropReleased; - } - if (key == to_sdl_keycode(m_controls.hold)) { - return InputEvent::HoldReleased; - } - } - return helper::nullopt; -} -KeyboardInput::KeyboardInput(KeyboardControls controls, EventDispatcher* event_dispatcher) - : Input{ InputType::Keyboard }, - m_controls{ controls }, - m_event_dispatcher{ event_dispatcher } { - m_event_dispatcher->register_listener(this); -} - -KeyboardInput::~KeyboardInput() { - m_event_dispatcher->unregister_listener(this); -} diff --git a/src/platform/keyboard_input.hpp b/src/platform/keyboard_input.hpp deleted file mode 100644 index 780f6303..00000000 --- a/src/platform/keyboard_input.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "input.hpp" -#include "manager/event_dispatcher.hpp" - -struct KeyboardInput : public Input, public EventListener { -private: - KeyboardControls m_controls; - std::vector m_event_buffer; - EventDispatcher* m_event_dispatcher; - -public: - KeyboardInput(KeyboardControls controls, EventDispatcher* event_dispatcher); - - ~KeyboardInput() override; - - void handle_event(const SDL_Event& event, const Window* window) override; - - void update(SimulationStep simulation_step_index) override; - -private: - [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event) const; -}; diff --git a/src/platform/meson.build b/src/platform/meson.build deleted file mode 100644 index f7d92f2f..00000000 --- a/src/platform/meson.build +++ /dev/null @@ -1,31 +0,0 @@ -graphics_src_files += files( - 'capabilities.cpp', - 'capabilities.hpp', - 'input.cpp', - 'input.hpp', - 'platform.hpp', - 'replay_input.cpp', - 'replay_input.hpp', -) - -if meson.is_cross_build() and host_machine.system() == 'android' - graphics_src_files += files( - 'android_input.cpp', - 'android_input.hpp', - ) -elif ( - meson.is_cross_build() - and (host_machine.system() == 'switch' - or host_machine.system() == '3ds') -) - graphics_src_files += files( - 'console_buttons.hpp', - 'console_input.cpp', - 'console_input.hpp', - ) -else - graphics_src_files += files( - 'keyboard_input.cpp', - 'keyboard_input.hpp', - ) -endif diff --git a/src/platform/platform.hpp b/src/platform/platform.hpp deleted file mode 100644 index ad53796a..00000000 --- a/src/platform/platform.hpp +++ /dev/null @@ -1,34 +0,0 @@ - - -#pragma once - -#include "helper/parse_json.hpp" -#include "helper/types.hpp" - -enum class Platform : u8 { PC, Android, Console }; - - -NLOHMANN_JSON_SERIALIZE_ENUM( // NOLINT(modernize-type-traits,cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays) - Platform, - { - { Platform::PC, "pc"}, - {Platform::Android, "android"}, - {Platform::Console, "console"} -} -) - - -namespace utils { - - constexpr std::string get_platform() { - -#if defined(__ANDROID__) - return "android"; -#elif defined(__CONSOLE__) - return "console"; -#else - return "pc"; -#endif - }; - -} // namespace utils diff --git a/src/platform/replay_input.hpp b/src/platform/replay_input.hpp deleted file mode 100644 index 08964342..00000000 --- a/src/platform/replay_input.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "input.hpp" -#include "recordings/recording_reader.hpp" - -#include - -struct ReplayInput : public Input { -private: - std::shared_ptr m_recording_reader; - usize m_next_record_index{ 0 }; - usize m_next_snapshot_index{ 0 }; - -public: - ReplayInput(std::shared_ptr recording_reader); - - void update(SimulationStep simulation_step_index) override; - void late_update(SimulationStep simulation_step_index) override; - - [[nodiscard]] bool is_end_of_recording() const; -}; diff --git a/src/scenes/about_page/about_page.cpp b/src/scenes/about_page/about_page.cpp index e044e06d..a8fb3ecb 100644 --- a/src/scenes/about_page/about_page.cpp +++ b/src/scenes/about_page/about_page.cpp @@ -2,9 +2,9 @@ #include "graphics/window.hpp" #include "helper/constants.hpp" #include "helper/git_helper.hpp" +#include "helper/platform.hpp" #include "helper/utils.hpp" #include "manager/resource_manager.hpp" -#include "platform/capabilities.hpp" #include "ui/components/image_view.hpp" #include "ui/components/link_label.hpp" #include "ui/layouts/tile_layout.hpp" @@ -28,30 +28,34 @@ namespace scenes { #ifdef DEBUG_BUILD m_main_grid.add( service_provider, fmt::format("Git Commit: {}", utils::git_commit()), - service_provider->fonts().get(FontId::Default), Color::white(), std::pair{ 0.3, 0.5 }, + service_provider->font_manager().get(FontId::Default), Color::white(), + std::pair{ 0.3, 0.5 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); #else m_main_grid.add( service_provider, fmt::format("Version: {}", constants::version.c_str()), - service_provider->fonts().get(FontId::Default), Color::white(), std::pair{ 0.3, 0.5 }, + service_provider->font_manager().get(FontId::Default), Color::white(), + std::pair{ 0.3, 0.5 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); #endif m_main_grid.add( service_provider, fmt::format("Build for: {}", utils::built_for_platform()), - service_provider->fonts().get(FontId::Default), Color::white(), std::pair{ 0.3, 0.5 }, + service_provider->font_manager().get(FontId::Default), Color::white(), + std::pair{ 0.3, 0.5 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); m_main_grid.add( service_provider, fmt::format("Features: {}", fmt::join(utils::supported_features(), ", ")), - service_provider->fonts().get(FontId::Default), Color::white(), std::pair{ 0.95, 0.5 }, + service_provider->font_manager().get(FontId::Default), Color::white(), + std::pair{ 0.95, 0.5 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); m_main_grid.add( - service_provider, "Authors:", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Authors:", service_provider->font_manager().get(FontId::Default), Color::white(), std::pair{ 0.2, 0.4 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Bottom } ); @@ -67,7 +71,7 @@ namespace scenes { auto* tile_layout = m_main_grid.get(tile_layout_index); tile_layout->add( - service_provider, name, link, service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, name, link, service_provider->font_manager().get(FontId::Default), Color::white(), Color{ 0xA1, 0x9F, 0x9F }, std::pair{ 0.9, 0.8 }, ui::Alignment{ ui::AlignmentHorizontal::Right, ui::AlignmentVertical::Center } ); @@ -98,12 +102,14 @@ namespace scenes { m_main_grid.render(service_provider); } - bool AboutPage::handle_event(const SDL_Event& event, const Window* window) { - if (m_main_grid.handle_event(event, window)) { + bool AboutPage::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { + if (m_main_grid.handle_event(input_manager, event)) { return true; } - if (utils::event_is_action(event, utils::CrossPlatformAction::CLOSE)) { + const auto navigation_event = input_manager->get_navigation_event(event); + + if (navigation_event == input::NavigationEvent::BACK) { m_should_exit = true; return true; } diff --git a/src/scenes/about_page/about_page.hpp b/src/scenes/about_page/about_page.hpp index e6b0df70..c7cb7e87 100644 --- a/src/scenes/about_page/about_page.hpp +++ b/src/scenes/about_page/about_page.hpp @@ -24,7 +24,7 @@ namespace scenes { [[nodiscard]] UpdateResult update() override; void render(const ServiceProvider& service_provider) override; - bool handle_event(const SDL_Event& event, const Window* window) override; + bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; }; } // namespace scenes diff --git a/src/scenes/game_over/game_over.cpp b/src/scenes/game_over/game_over.cpp index 1da19b80..808aee65 100644 --- a/src/scenes/game_over/game_over.cpp +++ b/src/scenes/game_over/game_over.cpp @@ -1,9 +1,10 @@ #include "game_over.hpp" #include "graphics/renderer.hpp" #include "helper/music_utils.hpp" +#include "helper/platform.hpp" +#include "input/input.hpp" #include "manager/music_manager.hpp" #include "manager/resource_manager.hpp" -#include "platform/capabilities.hpp" #include @@ -15,11 +16,11 @@ namespace scenes { service_provider, fmt::format( "Game Over, Press {} to continue", - utils::action_description(utils::CrossPlatformAction::EXIT) + service_provider->input_manager().get_primary_input()->describe_navigation_event(input::NavigationEvent::BACK) ), - service_provider->fonts().get(FontId::Default), + service_provider->font_manager().get(FontId::Default), Color::white(), - utils::device_orientation() == utils::Orientation::Landscape + utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.7, 0.07 } : std::pair{ 0.95, 0.07 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }, @@ -37,7 +38,7 @@ namespace scenes { if (m_should_exit) { return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Switch{SceneId::MainMenu, ui::FullScreenLayout{ m_service_provider->window() }} + Scene::Switch{ SceneId::MainMenu, ui::FullScreenLayout{ m_service_provider->window() } } }; } return UpdateResult{ SceneUpdate::StopUpdating, helper::nullopt }; @@ -48,8 +49,11 @@ namespace scenes { m_text.render(service_provider); } - bool GameOver::handle_event(const SDL_Event& event, const Window*) { - if (utils::event_is_action(event, utils::CrossPlatformAction::EXIT)) { + bool GameOver::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { + + const auto navigation_event = input_manager->get_navigation_event(event); + + if (navigation_event == input::NavigationEvent::BACK) { m_should_exit = true; return true; } diff --git a/src/scenes/game_over/game_over.hpp b/src/scenes/game_over/game_over.hpp index 2a7f6552..df90b705 100644 --- a/src/scenes/game_over/game_over.hpp +++ b/src/scenes/game_over/game_over.hpp @@ -17,7 +17,7 @@ namespace scenes { void render(const ServiceProvider& service_provider) override; - bool handle_event(const SDL_Event& event, const Window* window) override; + bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; }; } // namespace scenes diff --git a/src/scenes/main_menu/main_menu.cpp b/src/scenes/main_menu/main_menu.cpp index 68e158fd..92505a89 100644 --- a/src/scenes/main_menu/main_menu.cpp +++ b/src/scenes/main_menu/main_menu.cpp @@ -2,6 +2,7 @@ #include "graphics/window.hpp" #include "helper/constants.hpp" #include "helper/music_utils.hpp" +#include "helper/platform.hpp" #include "manager/music_manager.hpp" #include "manager/resource_manager.hpp" #include "ui/layout.hpp" @@ -16,23 +17,23 @@ namespace scenes { auto focus_helper = ui::FocusHelper{ 1 }; m_main_grid.add( - service_provider, constants::program_name, service_provider->fonts().get(FontId::Default), + service_provider, constants::program_name, service_provider->font_manager().get(FontId::Default), Color::white(), std::pair{ 0.3, 1.0 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); - constexpr auto button_size = utils::device_orientation() == utils::Orientation::Landscape + constexpr auto button_size = utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.15, 0.85 } : std::pair{ 0.5, 0.85 }; constexpr auto button_alignment = ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }; - constexpr auto button_margins = utils::device_orientation() == utils::Orientation::Landscape + constexpr auto button_margins = utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.1, 0.1 } : std::pair{ 0.2, 0.2 }; m_main_grid.add( - service_provider, "Play", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Play", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::OpenPlaySelection; @@ -42,7 +43,7 @@ namespace scenes { ); m_main_grid.add( - service_provider, "Settings", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Settings", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::OpenSettingsMenu; @@ -52,7 +53,7 @@ namespace scenes { ); m_main_grid.add( - service_provider, "About", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "About", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::OpenAboutPage; @@ -62,7 +63,7 @@ namespace scenes { ); m_main_grid.add( - service_provider, "Achievements", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Achievements", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::OpenAchievements; @@ -73,7 +74,7 @@ namespace scenes { m_main_grid.get(4)->disable(); m_main_grid.add( - service_provider, "Exit", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Exit", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::Exit; @@ -113,28 +114,28 @@ namespace scenes { m_next_command = helper::nullopt; return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Push{SceneId::PlaySelectMenu, ui::FullScreenLayout{ m_service_provider->window() }} + Scene::Push{ SceneId::PlaySelectMenu, ui::FullScreenLayout{ m_service_provider->window() } } }; case Command::OpenAboutPage: // perform a push and reset the command, so that the music keeps playing the entire time m_next_command = helper::nullopt; return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Push{SceneId::AboutPage, ui::FullScreenLayout{ m_service_provider->window() }} + Scene::Push{ SceneId::AboutPage, ui::FullScreenLayout{ m_service_provider->window() } } }; case Command::OpenSettingsMenu: // perform a push and reset the command, so that the music keeps playing the entire time m_next_command = helper::nullopt; return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Push{SceneId::SettingsMenu, ui::FullScreenLayout{ m_service_provider->window() }} + Scene::Push{ SceneId::SettingsMenu, ui::FullScreenLayout{ m_service_provider->window() } } }; case Command::OpenAchievements: // perform a push and reset the command, so that the music keeps playing the entire time m_next_command = helper::nullopt; return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Push{SceneId::AchievementsPage, ui::FullScreenLayout{ m_service_provider->window() }} + Scene::Push{ SceneId::AchievementsPage, ui::FullScreenLayout{ m_service_provider->window() } } }; case Command::Exit: return UpdateResult{ SceneUpdate::StopUpdating, Scene::Exit{} }; @@ -149,12 +150,14 @@ namespace scenes { m_main_grid.render(service_provider); } - bool MainMenu::handle_event(const SDL_Event& event, const Window* window) { - if (m_main_grid.handle_event(event, window)) { + bool MainMenu::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { + if (m_main_grid.handle_event(input_manager, event)) { return true; } - if (utils::event_is_action(event, utils::CrossPlatformAction::CLOSE)) { + const auto navigation_event = input_manager->get_navigation_event(event); + + if (navigation_event == input::NavigationEvent::BACK) { m_next_command = Command::Exit; return true; } diff --git a/src/scenes/main_menu/main_menu.hpp b/src/scenes/main_menu/main_menu.hpp index 28935559..c513ab10 100644 --- a/src/scenes/main_menu/main_menu.hpp +++ b/src/scenes/main_menu/main_menu.hpp @@ -25,7 +25,7 @@ namespace scenes { [[nodiscard]] UpdateResult update() override; void render(const ServiceProvider& service_provider) override; - bool handle_event(const SDL_Event& event, const Window* window) override; + bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; }; } // namespace scenes diff --git a/src/scenes/meson.build b/src/scenes/meson.build index 02625d9b..ac638a46 100644 --- a/src/scenes/meson.build +++ b/src/scenes/meson.build @@ -4,7 +4,6 @@ subdir('about_page') subdir('game_over') subdir('main_menu') subdir('multiplayer_menu') -subdir('pause') subdir('play_select_menu') subdir('recording_selector') subdir('replay_game') diff --git a/src/scenes/multiplayer_menu/multiplayer_menu.cpp b/src/scenes/multiplayer_menu/multiplayer_menu.cpp index 4277e2c8..83785541 100644 --- a/src/scenes/multiplayer_menu/multiplayer_menu.cpp +++ b/src/scenes/multiplayer_menu/multiplayer_menu.cpp @@ -1,6 +1,8 @@ #include "multiplayer_menu.hpp" #include "graphics/window.hpp" #include "helper/constants.hpp" +#include "helper/platform.hpp" +#include "input/input.hpp" #include "manager/music_manager.hpp" #include "manager/resource_manager.hpp" #include "ui/layout.hpp" @@ -15,23 +17,23 @@ namespace scenes { auto focus_helper = ui::FocusHelper{ 1 }; m_main_grid.add( - service_provider, "Select MultiPlayer Mode", service_provider->fonts().get(FontId::Default), + service_provider, "Select MultiPlayer Mode", service_provider->font_manager().get(FontId::Default), Color::white(), std::pair{ 0.3, 1.0 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); - constexpr auto button_size = utils::device_orientation() == utils::Orientation::Landscape + constexpr auto button_size = utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.15, 0.85 } : std::pair{ 0.5, 0.85 }; constexpr auto button_alignment = ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }; - constexpr auto button_margins = utils::device_orientation() == utils::Orientation::Landscape + constexpr auto button_margins = utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.1, 0.1 } : std::pair{ 0.2, 0.2 }; const auto local_button_id = m_main_grid.add( - service_provider, "Local", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Local", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::LocalMultiPlayer; @@ -42,7 +44,7 @@ namespace scenes { m_main_grid.get(local_button_id)->disable(); const auto online_button_id = m_main_grid.add( - service_provider, "Online", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Online", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::OnlineMultiPlayer; @@ -57,7 +59,7 @@ namespace scenes { #endif const auto ai_button_id = m_main_grid.add( - service_provider, "vs AI", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "vs AI", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::AIMultiPlayer; @@ -68,7 +70,7 @@ namespace scenes { m_main_grid.get(ai_button_id)->disable(); m_main_grid.add( - service_provider, "Return", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Return", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::Return; @@ -85,20 +87,20 @@ namespace scenes { switch (m_next_command.value()) { case Command::LocalMultiPlayer: return UpdateResult{ - SceneUpdate::StopUpdating, Scene::Switch{SceneId::LocalMultiPlayerGame, - ui::FullScreenLayout{ m_service_provider->window() }} + SceneUpdate::StopUpdating, Scene::Switch{ SceneId::LocalMultiPlayerGame, + ui::FullScreenLayout{ m_service_provider->window() } } }; case Command::OnlineMultiPlayer: // perform a push and reset the command, so that the music keeps playing the entire time m_next_command = helper::nullopt; return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Push{SceneId::OnlineLobby, ui::FullScreenLayout{ m_service_provider->window() }} + Scene::Push{ SceneId::OnlineLobby, ui::FullScreenLayout{ m_service_provider->window() } } }; case Command::AIMultiPlayer: return UpdateResult{ - SceneUpdate::StopUpdating, Scene::Switch{SceneId::AIMultiPlayerGame, - ui::FullScreenLayout{ m_service_provider->window() }} + SceneUpdate::StopUpdating, Scene::Switch{ SceneId::AIMultiPlayerGame, + ui::FullScreenLayout{ m_service_provider->window() } } }; case Command::Return: return UpdateResult{ SceneUpdate::StopUpdating, Scene::Pop{} }; @@ -116,12 +118,15 @@ namespace scenes { m_main_grid.render(service_provider); } - bool MultiPlayerMenu::handle_event(const SDL_Event& event, const Window* window) { - if (m_main_grid.handle_event(event, window)) { + bool + MultiPlayerMenu::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { + if (m_main_grid.handle_event(input_manager, event)) { return true; } - if (utils::event_is_action(event, utils::CrossPlatformAction::CLOSE)) { + const auto navigation_event = input_manager->get_navigation_event(event); + + if (navigation_event == input::NavigationEvent::BACK) { m_next_command = Command::Return; return true; } diff --git a/src/scenes/multiplayer_menu/multiplayer_menu.hpp b/src/scenes/multiplayer_menu/multiplayer_menu.hpp index c7d5e02d..b498b418 100644 --- a/src/scenes/multiplayer_menu/multiplayer_menu.hpp +++ b/src/scenes/multiplayer_menu/multiplayer_menu.hpp @@ -19,7 +19,7 @@ namespace scenes { [[nodiscard]] UpdateResult update() override; void render(const ServiceProvider& service_provider) override; - bool handle_event(const SDL_Event& event, const Window* window) override; + bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; }; } // namespace scenes diff --git a/src/scenes/online_lobby/online_lobby.cpp b/src/scenes/online_lobby/online_lobby.cpp index 14cd710a..fda25b62 100644 --- a/src/scenes/online_lobby/online_lobby.cpp +++ b/src/scenes/online_lobby/online_lobby.cpp @@ -2,6 +2,9 @@ #include "graphics/window.hpp" #include "helper/constants.hpp" #include "helper/errors.hpp" +#include "helper/magic_enum_wrapper.hpp" +#include "helper/platform.hpp" +#include "helper/utils.hpp" #include "manager/music_manager.hpp" #include "manager/resource_manager.hpp" #include "ui/components/textinput.hpp" @@ -33,7 +36,7 @@ namespace scenes { auto focus_helper = ui::FocusHelper{ 1 }; m_main_layout.add( - service_provider, "Select Lobby to play in", service_provider->fonts().get(FontId::Default), + service_provider, "Select Lobby to play in", service_provider->font_manager().get(FontId::Default), Color::white(), std::pair{ 0.5, 1.0 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); @@ -49,7 +52,7 @@ namespace scenes { if (i == 2) { scroll_layout->add( ui::RelativeItemSize{ scroll_layout->layout(), 0.2 }, service_provider, - service_provider->fonts().get(FontId::Symbola), Color::white(), focus_helper.focus_id(), + service_provider->font_manager().get(FontId::Symbola), Color::white(), focus_helper.focus_id(), std::pair{ 0.9, 0.9 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }, ui::TextInputMode::Scroll @@ -57,7 +60,7 @@ namespace scenes { } else { scroll_layout->add( ui::RelativeItemSize{ scroll_layout->layout(), 0.2 }, service_provider, - fmt::format("Button Nr.: {}", i), service_provider->fonts().get(FontId::Default), + fmt::format("Button Nr.: {}", i), service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [i](const ui::TextButton&) -> bool { spdlog::info("Pressed button: {}", i); @@ -70,17 +73,17 @@ namespace scenes { } } - constexpr auto button_size = utils::device_orientation() == utils::Orientation::Landscape + constexpr auto button_size = utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.15, 0.85 } : std::pair{ 0.5, 0.85 }; constexpr auto button_alignment = ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }; - constexpr auto button_margins = utils::device_orientation() == utils::Orientation::Landscape + constexpr auto button_margins = utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.1, 0.1 } : std::pair{ 0.2, 0.2 }; m_main_layout.add( - service_provider, "Return", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Return", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::Return; @@ -97,8 +100,8 @@ namespace scenes { switch (m_next_command.value()) { case Command::Play: return UpdateResult{ - SceneUpdate::StopUpdating, Scene::Switch{SceneId::OnlineMultiplayerGame, - ui::FullScreenLayout{ m_service_provider->window() }} + SceneUpdate::StopUpdating, Scene::Switch{ SceneId::OnlineMultiplayerGame, + ui::FullScreenLayout{ m_service_provider->window() } } }; case Command::Return: return UpdateResult{ SceneUpdate::StopUpdating, Scene::Pop{} }; @@ -115,11 +118,11 @@ namespace scenes { m_main_layout.render(service_provider); } - bool OnlineLobby::handle_event(const SDL_Event& event, const Window* window) { + bool OnlineLobby::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { // description of intentional behaviour of this scene, even if it seems off: // the return button or the scroll layout can have the focus, if the scroll_layout has the focus, it can be scrolled by the scroll wheel and you can move around the focused item of the scroll_layout with up and down, but not with TAB, with tab you can change the focus to the return button, where you can't use the scroll wheel or up / down to change the scroll items, but you still can use click events, they are not affected by focus - if (const auto event_result = m_main_layout.handle_event(event, window)) { + if (const auto event_result = m_main_layout.handle_event(input_manager, event)) { if (const auto additional = event_result.get_additional(); additional.has_value()) { const auto value = additional.value(); @@ -127,11 +130,11 @@ namespace scenes { if (value.first == ui::EventHandleType::RequestAction) { - if (auto* text_input = dynamic_cast(value.second); text_input != nullptr) { - spdlog::info("Pressed Enter on TextInput {}", text_input->get_text()); + if (auto text_input = utils::is_child_class(value.second); text_input.has_value()) { + spdlog::info("Pressed Enter on TextInput {}", text_input.value()->get_text()); - if (text_input->has_focus()) { - text_input->unfocus(); + if (text_input.value()->has_focus()) { + text_input.value()->unfocus(); } return true; } @@ -148,7 +151,9 @@ namespace scenes { return true; } - if (utils::event_is_action(event, utils::CrossPlatformAction::CLOSE)) { + const auto navigation_event = input_manager->get_navigation_event(event); + + if (navigation_event == input::NavigationEvent::BACK) { m_next_command = Command::Return; return true; } diff --git a/src/scenes/online_lobby/online_lobby.hpp b/src/scenes/online_lobby/online_lobby.hpp index 6a3b52c8..e391bc3a 100644 --- a/src/scenes/online_lobby/online_lobby.hpp +++ b/src/scenes/online_lobby/online_lobby.hpp @@ -23,7 +23,7 @@ namespace scenes { [[nodiscard]] UpdateResult update() override; void render(const ServiceProvider& service_provider) override; - bool handle_event(const SDL_Event& event, const Window* window) override; + bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; }; } // namespace scenes diff --git a/src/scenes/pause/meson.build b/src/scenes/pause/meson.build deleted file mode 100644 index 879e64fa..00000000 --- a/src/scenes/pause/meson.build +++ /dev/null @@ -1,4 +0,0 @@ -graphics_src_files += files( - 'pause.cpp', - 'pause.hpp', -) diff --git a/src/scenes/pause/pause.cpp b/src/scenes/pause/pause.cpp deleted file mode 100644 index f98828d4..00000000 --- a/src/scenes/pause/pause.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "pause.hpp" -#include "graphics/renderer.hpp" -#include "manager/resource_manager.hpp" -#include "platform/capabilities.hpp" -#include - -namespace scenes { - - Pause::Pause(ServiceProvider* service_provider, const ui::Layout& layout) : Scene{ service_provider, layout }, m_heading { - service_provider, - fmt::format( - "Pause ({}: continue, {}: quit)", - utils::action_description(utils::CrossPlatformAction::UNPAUSE), - utils::action_description(utils::CrossPlatformAction::EXIT) - ), - service_provider->fonts().get(FontId::Default), - Color::white(),utils::device_orientation() == utils::Orientation::Landscape - ? std::pair{ 0.7, 0.07 } - : std::pair{ 0.95, 0.07 }, - ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }, - layout, - true - } - { } - - [[nodiscard]] Scene::UpdateResult scenes::Pause::update() { - if (m_should_unpause) { - return UpdateResult{ SceneUpdate::StopUpdating, Scene::Pop{} }; - } - if (m_should_exit) { - return UpdateResult{ - SceneUpdate::StopUpdating, - Scene::Switch{SceneId::MainMenu, ui::FullScreenLayout{ m_service_provider->window() }} - }; - } - return UpdateResult{ SceneUpdate::StopUpdating, helper::nullopt }; - } - - void Pause::render(const ServiceProvider& service_provider) { - service_provider.renderer().draw_rect_filled(get_layout().get_rect(), Color::black(180)); - m_heading.render(service_provider); - } - - [[nodiscard]] bool Pause::handle_event(const SDL_Event& event, const Window*) { - - if (utils::event_is_action(event, utils::CrossPlatformAction::UNPAUSE)) { - m_should_unpause = true; - return true; - } - - if (utils::event_is_action(event, utils::CrossPlatformAction::EXIT)) { - m_should_exit = true; - return true; - } - - return false; - } - -} // namespace scenes diff --git a/src/scenes/pause/pause.hpp b/src/scenes/pause/pause.hpp deleted file mode 100644 index bc830666..00000000 --- a/src/scenes/pause/pause.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "manager/event_listener.hpp" -#include "scenes/scene.hpp" -#include "ui/components/label.hpp" - -namespace scenes { - struct Pause : public scenes::Scene { - private: - ui::Label m_heading; - bool m_should_unpause{ false }; - bool m_should_exit{ false }; - - public: - explicit Pause(ServiceProvider* service_provider, const ui::Layout& layout); - - [[nodiscard]] UpdateResult update() override; - void render(const ServiceProvider& service_provider) override; - [[nodiscard]] bool handle_event(const SDL_Event& event, const Window* window) override; - }; -} // namespace scenes diff --git a/src/scenes/play_select_menu/play_select_menu.cpp b/src/scenes/play_select_menu/play_select_menu.cpp index 5d5481ae..cb06178b 100644 --- a/src/scenes/play_select_menu/play_select_menu.cpp +++ b/src/scenes/play_select_menu/play_select_menu.cpp @@ -1,6 +1,7 @@ #include "play_select_menu.hpp" #include "graphics/window.hpp" #include "helper/constants.hpp" +#include "helper/platform.hpp" #include "manager/music_manager.hpp" #include "manager/resource_manager.hpp" #include "ui/layout.hpp" @@ -15,24 +16,24 @@ namespace scenes { auto focus_helper = ui::FocusHelper{ 1 }; m_main_grid.add( - service_provider, "Select Play Mode", service_provider->fonts().get(FontId::Default), Color::white(), - std::pair{ 0.3, 1.0 }, + service_provider, "Select Play Mode", service_provider->font_manager().get(FontId::Default), + Color::white(), std::pair{ 0.3, 1.0 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); - constexpr auto button_size = utils::device_orientation() == utils::Orientation::Landscape + constexpr auto button_size = utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.15, 0.85 } : std::pair{ 0.5, 0.85 }; constexpr auto button_alignment = ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }; - constexpr auto button_margins = utils::device_orientation() == utils::Orientation::Landscape + constexpr auto button_margins = utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.1, 0.1 } : std::pair{ 0.2, 0.2 }; m_main_grid.add( - service_provider, "Single Player", service_provider->fonts().get(FontId::Default), Color::white(), - focus_helper.focus_id(), + service_provider, "Single Player", service_provider->font_manager().get(FontId::Default), + Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::SinglePlayer; return false; @@ -41,7 +42,7 @@ namespace scenes { ); m_main_grid.add( - service_provider, "Multi Player", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Multi Player", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::MultiPlayer; @@ -51,8 +52,8 @@ namespace scenes { ); m_main_grid.add( - service_provider, "Replay Recordings", service_provider->fonts().get(FontId::Default), Color::white(), - focus_helper.focus_id(), + service_provider, "Replay Recordings", service_provider->font_manager().get(FontId::Default), + Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::RecordingSelector; return false; @@ -61,7 +62,7 @@ namespace scenes { ); m_main_grid.add( - service_provider, "Return", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Return", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command::Return; @@ -79,21 +80,21 @@ namespace scenes { case Command::SinglePlayer: return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Switch{SceneId::SinglePlayerGame, ui::FullScreenLayout{ m_service_provider->window() }} + Scene::Switch{ SceneId::SinglePlayerGame, ui::FullScreenLayout{ m_service_provider->window() } } }; case Command::MultiPlayer: // perform a push and reset the command, so that the music keeps playing the entire time m_next_command = helper::nullopt; return UpdateResult{ - SceneUpdate::StopUpdating, Scene::Push{SceneId::MultiPlayerModeSelectMenu, - ui::FullScreenLayout{ m_service_provider->window() }} + SceneUpdate::StopUpdating, Scene::Push{ SceneId::MultiPlayerModeSelectMenu, + ui::FullScreenLayout{ m_service_provider->window() } } }; case Command::RecordingSelector: // perform a push and reset the command, so that the music keeps playing the entire time m_next_command = helper::nullopt; return UpdateResult{ - SceneUpdate::StopUpdating, Scene::Push{SceneId::RecordingSelectorMenu, - ui::FullScreenLayout{ m_service_provider->window() }} + SceneUpdate::StopUpdating, Scene::Push{ SceneId::RecordingSelectorMenu, + ui::FullScreenLayout{ m_service_provider->window() } } }; case Command::Return: return UpdateResult{ SceneUpdate::StopUpdating, Scene::Pop{} }; @@ -111,12 +112,15 @@ namespace scenes { m_main_grid.render(service_provider); } - bool PlaySelectMenu::handle_event(const SDL_Event& event, const Window* window) { - if (m_main_grid.handle_event(event, window)) { + bool + PlaySelectMenu::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { + if (m_main_grid.handle_event(input_manager, event)) { return true; } - if (utils::event_is_action(event, utils::CrossPlatformAction::CLOSE)) { + const auto navigation_event = input_manager->get_navigation_event(event); + + if (navigation_event == input::NavigationEvent::BACK) { m_next_command = Command::Return; return true; } diff --git a/src/scenes/play_select_menu/play_select_menu.hpp b/src/scenes/play_select_menu/play_select_menu.hpp index 1a6b0036..b362dd52 100644 --- a/src/scenes/play_select_menu/play_select_menu.hpp +++ b/src/scenes/play_select_menu/play_select_menu.hpp @@ -19,7 +19,7 @@ namespace scenes { [[nodiscard]] UpdateResult update() override; void render(const ServiceProvider& service_provider) override; - bool handle_event(const SDL_Event& event, const Window* window) override; + bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; }; } // namespace scenes diff --git a/src/scenes/recording_selector/recording_chooser.cpp b/src/scenes/recording_selector/recording_chooser.cpp index 057aa3fe..32d962f7 100644 --- a/src/scenes/recording_selector/recording_chooser.cpp +++ b/src/scenes/recording_selector/recording_chooser.cpp @@ -27,13 +27,13 @@ custom_ui::RecordingFileChooser::RecordingFileChooser( m_main_grid.add( - service_provider, "Select Recording", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Select Recording", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [service_provider, this](const ui::TextButton&) -> bool { this->prepare_dialog(service_provider); const auto result = helper::openMultipleFilesDialog({ - {"OOPetris Recording", { constants::recording::extension }} + { "OOPetris Recording", { constants::recording::extension } } }); if (result.has_value()) { @@ -54,7 +54,7 @@ custom_ui::RecordingFileChooser::RecordingFileChooser( m_main_grid.add( - service_provider, "Select Recording Folder", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Select Recording Folder", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this, service_provider](const ui::TextButton&) -> bool { this->prepare_dialog(service_provider); @@ -96,16 +96,18 @@ void custom_ui::RecordingFileChooser::render(const ServiceProvider& service_prov m_main_grid.render(service_provider); } -helper::BoolWrapper> -custom_ui::RecordingFileChooser::handle_event(const SDL_Event& event, const Window* window) { +helper::BoolWrapper> custom_ui::RecordingFileChooser::handle_event( + const std::shared_ptr& input_manager, + const SDL_Event& event +) { //TODO: this double nested component can't correctly detect focus changes (since the checking for a focus change only occurs at one level deep) //TODO: allow horizontal RIGHT <-> LEFT focus change on horizontal focus_layouts - if (const auto handled = m_main_grid.handle_event(event, window); handled) { + if (const auto handled = m_main_grid.handle_event(input_manager, event); handled) { return handled; } - if (detect_hover(event, window)) { + if (detect_hover(input_manager, event)) { return true; } diff --git a/src/scenes/recording_selector/recording_chooser.hpp b/src/scenes/recording_selector/recording_chooser.hpp index cba875ac..1d430a7c 100644 --- a/src/scenes/recording_selector/recording_chooser.hpp +++ b/src/scenes/recording_selector/recording_chooser.hpp @@ -27,7 +27,7 @@ namespace custom_ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const SDL_Event& event, const Window* window) override; + [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; [[nodiscard]] const std::vector& get_currently_chosen_files() const; diff --git a/src/scenes/recording_selector/recording_component.cpp b/src/scenes/recording_selector/recording_component.cpp index 1f8e0e31..97d50ff0 100644 --- a/src/scenes/recording_selector/recording_component.cpp +++ b/src/scenes/recording_selector/recording_component.cpp @@ -2,6 +2,7 @@ #include "recording_component.hpp" #include "helper/date.hpp" #include "helper/magic_enum_wrapper.hpp" +#include "input/input.hpp" #include "manager/font.hpp" #include "manager/resource_manager.hpp" #include "ui/widget.hpp" @@ -25,7 +26,7 @@ custom_ui::RecordingComponent::RecordingComponent( },m_metadata{std::move(metadata)}{ m_main_layout.add( - service_provider, "name: ?", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "name: ?", service_provider->font_manager().get(FontId::Default), Color::white(), std::pair{ 0.5, 0.5 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); @@ -39,19 +40,19 @@ custom_ui::RecordingComponent::RecordingComponent( information_layout->add( - service_provider, "source: ?", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "source: ?", service_provider->font_manager().get(FontId::Default), Color::white(), std::pair{ 0.9, 0.9 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); information_layout->add( - service_provider, "date: ?", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "date: ?", service_provider->font_manager().get(FontId::Default), Color::white(), std::pair{ 0.9, 0.9 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); information_layout->add( - service_provider, "playmode: ?", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "playmode: ?", service_provider->font_manager().get(FontId::Default), Color::white(), std::pair{ 0.9, 0.9 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); @@ -70,24 +71,24 @@ void custom_ui::RecordingComponent::render(const ServiceProvider& service_provid m_main_layout.render(service_provider); } -helper::BoolWrapper> -custom_ui::RecordingComponent::handle_event(const SDL_Event& event, const Window* window) { +helper::BoolWrapper> custom_ui::RecordingComponent::handle_event( + const std::shared_ptr& input_manager, + const SDL_Event& event +) { - if (utils::device_supports_keys()) { - if (has_focus() and utils::event_is_action(event, utils::CrossPlatformAction::OK)) { - return { - true, - {ui::EventHandleType::RequestAction, this} - }; - } + if (has_focus() and input_manager->get_navigation_event(event) == input::NavigationEvent::OK) { + return { + true, + { ui::EventHandleType::RequestAction, this } + }; } - if (const auto hover_result = detect_hover(event, window); hover_result) { + if (const auto hover_result = detect_hover(input_manager, event); hover_result) { if (hover_result.is(ui::ActionType::Clicked)) { return { true, - {has_focus() ? ui::EventHandleType::RequestAction : ui::EventHandleType::RequestFocus, this} + { has_focus() ? ui::EventHandleType::RequestAction : ui::EventHandleType::RequestFocus, this } }; } return true; diff --git a/src/scenes/recording_selector/recording_component.hpp b/src/scenes/recording_selector/recording_component.hpp index 289ea170..a6440fc9 100644 --- a/src/scenes/recording_selector/recording_component.hpp +++ b/src/scenes/recording_selector/recording_component.hpp @@ -46,7 +46,7 @@ namespace custom_ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const SDL_Event& event, const Window* window) override; + [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; [[nodiscard]] data::RecordingMetadata metadata() const; diff --git a/src/scenes/recording_selector/recording_selector.cpp b/src/scenes/recording_selector/recording_selector.cpp index 2f9b6eaa..17c63795 100644 --- a/src/scenes/recording_selector/recording_selector.cpp +++ b/src/scenes/recording_selector/recording_selector.cpp @@ -1,3 +1,7 @@ +#include "helper/platform.hpp" +#include "helper/utils.hpp" + + #if defined(_HAVE_FILE_DIALOGS) #include "recording_chooser.hpp" #endif @@ -37,7 +41,7 @@ namespace scenes { auto focus_helper = ui::FocusHelper{ 1 }; m_main_layout.add( - service_provider, "Select Recording to replay", service_provider->fonts().get(FontId::Default), + service_provider, "Select Recording to replay", service_provider->font_manager().get(FontId::Default), Color::white(), std::pair{ 0.5, 1.0 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); @@ -49,17 +53,17 @@ namespace scenes { add_all_recordings(); - constexpr auto button_size = utils::device_orientation() == utils::Orientation::Landscape + constexpr auto button_size = utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.15, 0.85 } : std::pair{ 0.5, 0.85 }; constexpr auto button_alignment = ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }; - constexpr auto button_margins = utils::device_orientation() == utils::Orientation::Landscape + constexpr auto button_margins = utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.1, 0.1 } : std::pair{ 0.2, 0.2 }; m_main_layout.add( - service_provider, "Return", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Return", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command{ Return{} }; @@ -77,11 +81,10 @@ namespace scenes { helper::overloaded{ [](const Return&) { return UpdateResult{ SceneUpdate::StopUpdating, Scene::Pop{} }; }, [this](const Action& action) { - if (auto* recording_component = - dynamic_cast(action.widget); - recording_component != nullptr) { - - const auto recording_path = recording_component->metadata().path; + if (auto recording_component = + utils::is_child_class(action.widget); + recording_component.has_value()) { + const auto recording_path = recording_component.value()->metadata().path; // action is a reference to a structure inside m_next_command, so resetting it means, we need to copy everything out of it m_next_command = helper::nullopt; @@ -97,11 +100,11 @@ namespace scenes { } #if defined(_HAVE_FILE_DIALOGS) - if (auto* recording_file_chooser = - dynamic_cast(action.widget); - recording_file_chooser != nullptr) { - - for (const auto& path : recording_file_chooser->get_currently_chosen_files()) { + if (auto recording_file_chooser = + utils::is_child_class(action.widget); + recording_file_chooser.has_value()) { + for (const auto& path : + recording_file_chooser.value()->get_currently_chosen_files()) { m_chosen_paths.push_back(path); } @@ -130,10 +133,11 @@ namespace scenes { m_main_layout.render(service_provider); } - bool RecordingSelector::handle_event(const SDL_Event& event, const Window* window) { + bool + RecordingSelector::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { - if (const auto event_result = m_main_layout.handle_event(event, window); event_result) { + if (const auto event_result = m_main_layout.handle_event(input_manager, event); event_result) { if (const auto additional = event_result.get_additional(); additional.has_value() and additional.value().first == ui::EventHandleType::RequestAction) { m_next_command = Command{ Action(additional.value().second) }; @@ -142,7 +146,9 @@ namespace scenes { return true; } - if (utils::event_is_action(event, utils::CrossPlatformAction::CLOSE)) { + const auto navigation_event = input_manager->get_navigation_event(event); + + if (navigation_event == input::NavigationEvent::BACK) { m_next_command = Command{ Return{} }; return true; } diff --git a/src/scenes/recording_selector/recording_selector.hpp b/src/scenes/recording_selector/recording_selector.hpp index 2f0cb7ef..dcdd40c6 100644 --- a/src/scenes/recording_selector/recording_selector.hpp +++ b/src/scenes/recording_selector/recording_selector.hpp @@ -41,7 +41,7 @@ namespace scenes { [[nodiscard]] UpdateResult update() override; void render(const ServiceProvider& service_provider) override; - bool handle_event(const SDL_Event& event, const Window* window) override; + bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; private: void add_all_recordings(); diff --git a/src/scenes/replay_game/replay_game.cpp b/src/scenes/replay_game/replay_game.cpp index 233901ea..c4515649 100644 --- a/src/scenes/replay_game/replay_game.cpp +++ b/src/scenes/replay_game/replay_game.cpp @@ -77,7 +77,7 @@ namespace scenes { if (all_games_finished) { return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Push{SceneId::GameOver, ui::FullScreenLayout{ m_service_provider->window() }} + Scene::Push{ SceneId::GameOver, ui::FullScreenLayout{ m_service_provider->window() } } }; } @@ -89,16 +89,16 @@ namespace scenes { } switch (next_scene) { - case NextScene::Pause: + /* case NextScene::Pause: return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Push{SceneId::Pause, ui::FullScreenLayout{ m_service_provider->window() }} - }; + Scene::Push{ SceneId::Pause, ui::FullScreenLayout{ m_service_provider->window() } } + }; */ case NextScene::Settings: return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Push{SceneId::SettingsMenu, - ui::RelativeLayout{ m_service_provider->window(), 0.15, 0.15, 0.7, 0.7 }} + Scene::Push{ SceneId::SettingsMenu, + ui::RelativeLayout{ m_service_provider->window(), 0.15, 0.15, 0.7, 0.7 } } }; default: utils::unreachable(); @@ -113,9 +113,14 @@ namespace scenes { } } - [[nodiscard]] bool ReplayGame::handle_event(const SDL_Event& event, const Window*) { + [[nodiscard]] bool + ReplayGame::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { - if (utils::event_is_action(event, utils::CrossPlatformAction::PAUSE)) { + //TODO: add gameInput to this function + //TODO: re-add pause scene + UNUSED(input_manager); + UNUSED(event); + /* if (utils::event_is_action(event, utils::CrossPlatformAction::PAUSE)) { for (auto& game : m_games) { if (game->is_game_finished()) { @@ -128,12 +133,13 @@ namespace scenes { return true; } - if (utils::device_supports_keys()) { - if (utils::event_is_action(event, utils::CrossPlatformAction::OPEN_SETTINGS)) { - m_next_scene = NextScene::Settings; - return true; - } - } + + if (utils::event_is_action(event, utils::CrossPlatformAction::OPEN_SETTINGS)) { + m_next_scene = NextScene::Settings; + return true; + } */ + + return false; } diff --git a/src/scenes/replay_game/replay_game.hpp b/src/scenes/replay_game/replay_game.hpp index 55327d78..c918d82e 100644 --- a/src/scenes/replay_game/replay_game.hpp +++ b/src/scenes/replay_game/replay_game.hpp @@ -22,7 +22,7 @@ namespace scenes { [[nodiscard]] UpdateResult update() override; void render(const ServiceProvider& service_provider) override; - [[nodiscard]] bool handle_event(const SDL_Event& event, const Window* window) override; + [[nodiscard]] bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; }; diff --git a/src/scenes/scene.cpp b/src/scenes/scene.cpp index 3d367443..46b22a39 100644 --- a/src/scenes/scene.cpp +++ b/src/scenes/scene.cpp @@ -3,7 +3,6 @@ #include "game_over/game_over.hpp" #include "main_menu/main_menu.hpp" #include "multiplayer_menu/multiplayer_menu.hpp" -#include "pause/pause.hpp" #include "play_select_menu/play_select_menu.hpp" #include "recording_selector/recording_selector.hpp" #include "replay_game/replay_game.hpp" @@ -25,8 +24,6 @@ namespace scenes { switch (identifier) { case SceneId::MainMenu: return std::make_unique(&service_provider, layout); - case SceneId::Pause: - return std::make_unique(&service_provider, layout); case SceneId::SinglePlayerGame: return std::make_unique(&service_provider, layout); case SceneId::GameOver: diff --git a/src/scenes/scene.hpp b/src/scenes/scene.hpp index 7fc7a8e4..48aa71b7 100644 --- a/src/scenes/scene.hpp +++ b/src/scenes/scene.hpp @@ -1,9 +1,9 @@ #pragma once #include "helper/command_line_arguments.hpp" +#include "input/input.hpp" #include "manager/event_listener.hpp" #include "manager/service_provider.hpp" -#include "manager/settings.hpp" #include "scene_id.hpp" #include "ui/layout.hpp" @@ -75,7 +75,7 @@ namespace scenes { [[nodiscard]] virtual UpdateResult update() = 0; virtual void render(const ServiceProvider& service_provider) = 0; - virtual bool handle_event(const SDL_Event& event, const Window* window) = 0; + virtual bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) = 0; // override this, if you (the scene) could potentially be displayed in non fullscreen! virtual void on_unhover(); [[nodiscard]] const ui::Layout& get_layout() const; diff --git a/src/scenes/scene_id.hpp b/src/scenes/scene_id.hpp index f6174b34..6971e43c 100644 --- a/src/scenes/scene_id.hpp +++ b/src/scenes/scene_id.hpp @@ -12,7 +12,6 @@ enum class SceneId : u8 { MultiPlayerModeSelectMenu, OnlineLobby, OnlineMultiplayerGame, - Pause, PlaySelectMenu, SettingsMenu, SinglePlayerGame, diff --git a/src/scenes/settings_menu/color_setting_row.cpp b/src/scenes/settings_menu/color_setting_row.cpp index fdb5fbfb..bad82373 100644 --- a/src/scenes/settings_menu/color_setting_row.cpp +++ b/src/scenes/settings_menu/color_setting_row.cpp @@ -1,7 +1,9 @@ #include "color_setting_row.hpp" #include "helper/errors.hpp" +#include "helper/magic_enum_wrapper.hpp" #include "helper/utils.hpp" +#include "input/input.hpp" #include "ui/components/label.hpp" #include "ui/focusable.hpp" #include "ui/hoverable.hpp" @@ -51,22 +53,26 @@ void detail::ColorSettingRectangle::render(const ServiceProvider& service_provid //TODO: maybe use a dynamic color, to have some contrast? service_provider.renderer().draw_rect_outline(m_fill_rect, Color::white()); } -helper::BoolWrapper> -detail::ColorSettingRectangle::handle_event(const SDL_Event& event, const Window* window) { - if (utils::device_supports_keys()) { - if (has_focus() and utils::event_is_action(event, utils::CrossPlatformAction::OK)) { - return { - true, - {ui::EventHandleType::RequestAction, this} - }; - } +helper::BoolWrapper> detail::ColorSettingRectangle::handle_event( + const std::shared_ptr& input_manager, + const SDL_Event& event +) { + + const auto navigation_event = input_manager->get_navigation_event(event); + + if (has_focus() and navigation_event == input::NavigationEvent::OK) { + return { + true, + { ui::EventHandleType::RequestAction, this } + }; } - if (const auto hover_result = detect_hover(event, window); hover_result) { + + if (const auto hover_result = detect_hover(input_manager, event); hover_result) { if (hover_result.is(ui::ActionType::Clicked)) { return { true, - {ui::EventHandleType::RequestAction, this} + { ui::EventHandleType::RequestAction, this } }; } return true; @@ -102,14 +108,19 @@ void detail::ColorPickerScene::render(const ServiceProvider& service_provider) { m_color_picker.render(service_provider); } -bool detail::ColorPickerScene::handle_event(const SDL_Event& event, const Window* window) { +bool detail::ColorPickerScene::handle_event( + const std::shared_ptr& input_manager, + const SDL_Event& event +) { + + const auto navigation_event = input_manager->get_navigation_event(event); - if (utils::event_is_action(event, utils::CrossPlatformAction::CLOSE)) { + if (navigation_event == input::NavigationEvent::BACK) { m_should_exit = true; return true; } - const auto result = m_color_picker.handle_event(event, window); + const auto result = m_color_picker.handle_event(input_manager, event); if (result) { return result; } @@ -144,7 +155,7 @@ custom_ui::ColorSettingRow::ColorSettingRow( m_main_layout.add( - service_provider, std::move(name), service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, std::move(name), service_provider->font_manager().get(FontId::Default), Color::white(), std::pair{ 0.5, 0.5 }, ui::Alignment{ ui::AlignmentHorizontal::Left, ui::AlignmentVertical::Center } ); @@ -160,14 +171,16 @@ void custom_ui::ColorSettingRow::render(const ServiceProvider& service_provider) m_main_layout.render(service_provider); } -helper::BoolWrapper> -custom_ui::ColorSettingRow::handle_event(const SDL_Event& event, const Window* window) { - const auto result = m_main_layout.handle_event(event, window); +helper::BoolWrapper> custom_ui::ColorSettingRow::handle_event( + const std::shared_ptr& input_manager, + const SDL_Event& event +) { + const auto result = m_main_layout.handle_event(input_manager, event); if (const auto additional = result.get_additional(); additional.has_value()) { if (additional->first == ui::EventHandleType::RequestAction) { return { result, - {ui::EventHandleType::RequestAction, this} + { ui::EventHandleType::RequestAction, this } }; } diff --git a/src/scenes/settings_menu/color_setting_row.hpp b/src/scenes/settings_menu/color_setting_row.hpp index bda2c5f0..a54f907a 100644 --- a/src/scenes/settings_menu/color_setting_row.hpp +++ b/src/scenes/settings_menu/color_setting_row.hpp @@ -36,7 +36,7 @@ namespace detail { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const SDL_Event& event, const Window* window) override; + [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; }; @@ -59,7 +59,7 @@ namespace detail { void render(const ServiceProvider& service_provider) override; - bool handle_event(const SDL_Event& event, const Window* window) override; + bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; }; @@ -92,7 +92,7 @@ namespace custom_ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const SDL_Event& event, const Window* window) override; + [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; [[nodiscard]] scenes::Scene::Change get_details_scene() override; diff --git a/src/scenes/settings_menu/settings_menu.cpp b/src/scenes/settings_menu/settings_menu.cpp index 29977d61..9300d83b 100644 --- a/src/scenes/settings_menu/settings_menu.cpp +++ b/src/scenes/settings_menu/settings_menu.cpp @@ -1,7 +1,8 @@ #include "settings_menu.hpp" #include "color_setting_row.hpp" -#include "graphics/window.hpp" #include "helper/color_literals.hpp" +#include "helper/optional.hpp" +#include "helper/utils.hpp" #include "manager/music_manager.hpp" #include "manager/resource_manager.hpp" #include "settings_details.hpp" @@ -16,7 +17,18 @@ namespace scenes { using namespace details::settings::menu; - SettingsMenu::SettingsMenu(ServiceProvider* service_provider, const ui::Layout& layout) : Scene{service_provider, layout} + SettingsMenu::SettingsMenu(ServiceProvider* service_provider, const ui::Layout& layout) + : SettingsMenu{ service_provider, layout, helper::nullopt } { } + + SettingsMenu::SettingsMenu( + ServiceProvider* service_provider, + const ui::Layout& layout, + const std::shared_ptr& game_input + ) + : SettingsMenu{ service_provider, layout, helper::optional>{ game_input } } { + } + + SettingsMenu::SettingsMenu(ServiceProvider* service_provider, const ui::Layout& layout, const helper::optional>& game_input) : Scene{service_provider, layout} , m_main_layout{ utils::size_t_identity<3>(), 0, ui::Direction::Vertical, @@ -25,12 +37,12 @@ namespace scenes { std::pair{ 0.05, 0.03 }, layout }, - m_colors{COLOR_LITERAL("#FF33FF"), COLOR_LITERAL("hsv(281.71, 0.70085, 0.45882)"), COLOR_LITERAL("rgb(246, 255, 61)"),COLOR_LITERAL("hsv(103.12, 0.39024, 0.32157)")} + m_colors{COLOR_LITERAL("#FF33FF"), COLOR_LITERAL("hsv(281.71, 0.70085, 0.45882)"), COLOR_LITERAL("rgb(246, 255, 61)"),COLOR_LITERAL("hsv(103.12, 0.39024, 0.32157)")},m_game_input{game_input} { auto focus_helper = ui::FocusHelper{ 1 }; m_main_layout.add( - service_provider, "Settings", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Settings", service_provider->font_manager().get(FontId::Default), Color::white(), std::pair{ 0.3, 0.6 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } ); @@ -45,7 +57,8 @@ namespace scenes { scroll_layout->add( ui::RelativeItemSize{ scroll_layout->layout(), 0.2 }, service_provider, "Volume", - service_provider->fonts().get(FontId::Default), Color::white(), std::pair{ 0.1, 0.3 }, + service_provider->font_manager().get(FontId::Default), Color::white(), + std::pair{ 0.1, 0.3 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Bottom } ); @@ -74,7 +87,8 @@ namespace scenes { scroll_layout->add( ui::RelativeItemSize{ scroll_layout->layout(), 0.2 }, service_provider, "Colors", - service_provider->fonts().get(FontId::Default), Color::white(), std::pair{ 0.1, 0.3 }, + service_provider->font_manager().get(FontId::Default), Color::white(), + std::pair{ 0.1, 0.3 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Bottom } ); @@ -92,7 +106,7 @@ namespace scenes { } m_main_layout.add( - service_provider, "Return", service_provider->fonts().get(FontId::Default), Color::white(), + service_provider, "Return", service_provider->font_manager().get(FontId::Default), Color::white(), focus_helper.focus_id(), [this](const ui::TextButton&) -> bool { m_next_command = Command{ Return{} }; @@ -115,10 +129,11 @@ namespace scenes { return UpdateResult{ SceneUpdate::StopUpdating, Scene::Pop{} }; }, [this](const Action& action) { - if (auto* settings_details = dynamic_cast(action.widget); - settings_details != nullptr) { + if (auto settings_details = + utils::is_child_class(action.widget); + settings_details.has_value()) { - auto change_scene = settings_details->get_details_scene(); + auto change_scene = settings_details.value()->get_details_scene(); // action is a reference to a structure inside m_next_command, so resetting it means, we need to copy everything out of it m_next_command = helper::nullopt; @@ -148,8 +163,8 @@ namespace scenes { m_main_layout.render(service_provider); } - bool SettingsMenu::handle_event(const SDL_Event& event, const Window* window) { - if (const auto event_result = m_main_layout.handle_event(event, window); event_result) { + bool SettingsMenu::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { + if (const auto event_result = m_main_layout.handle_event(input_manager, event); event_result) { if (const auto additional = event_result.get_additional(); additional.has_value() and additional.value().first == ui::EventHandleType::RequestAction) { m_next_command = Command{ Action{ additional.value().second } }; @@ -158,19 +173,21 @@ namespace scenes { return true; } - if (utils::event_is_action(event, utils::CrossPlatformAction::CLOSE)) { + const auto navigation_event = input_manager->get_navigation_event(event); + + if (navigation_event == input::NavigationEvent::BACK) { m_next_command = Command{ Return{} }; return true; } - if (utils::device_supports_keys()) { - if (utils::event_is_action(event, utils::CrossPlatformAction::OPEN_SETTINGS)) { - m_next_command = Command{ Return{} }; - return true; - } + if (m_game_input.has_value() + and m_game_input.value()->get_menu_event(event) == input::MenuEvent::OPEN_SETTINGS) { + m_next_command = Command{ Return{} }; + return true; } + return false; } diff --git a/src/scenes/settings_menu/settings_menu.hpp b/src/scenes/settings_menu/settings_menu.hpp index b359bc2d..80b52ed4 100644 --- a/src/scenes/settings_menu/settings_menu.hpp +++ b/src/scenes/settings_menu/settings_menu.hpp @@ -36,17 +36,29 @@ namespace scenes { ui::TileLayout m_main_layout; //todo migrate to settings state std::vector m_colors; + helper::optional> m_game_input; const std::string listener_name = "settings_menu"; + explicit SettingsMenu( + ServiceProvider* service_provider, + const ui::Layout& layout, + const helper::optional>& game_input + ); + public: explicit SettingsMenu(ServiceProvider* service_provider, const ui::Layout& layout); + explicit SettingsMenu( + ServiceProvider* service_provider, + const ui::Layout& layout, + const std::shared_ptr& game_input + ); [[nodiscard]] UpdateResult update() override; void render(const ServiceProvider& service_provider) override; - bool handle_event(const SDL_Event& event, const Window* window) override; + bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; void on_unhover() override; }; diff --git a/src/scenes/single_player_game/meson.build b/src/scenes/single_player_game/meson.build index 1da476f9..15096996 100644 --- a/src/scenes/single_player_game/meson.build +++ b/src/scenes/single_player_game/meson.build @@ -1,4 +1,6 @@ graphics_src_files += files( + 'pause.cpp', + 'pause.hpp', 'single_player_game.cpp', 'single_player_game.hpp', ) diff --git a/src/scenes/single_player_game/pause.cpp b/src/scenes/single_player_game/pause.cpp new file mode 100644 index 00000000..993edef5 --- /dev/null +++ b/src/scenes/single_player_game/pause.cpp @@ -0,0 +1,65 @@ +#include "pause.hpp" +#include "graphics/renderer.hpp" +#include "helper/platform.hpp" +#include "input/game_input.hpp" +#include "input/input.hpp" +#include "manager/resource_manager.hpp" +#include + +namespace scenes { + + SinglePlayerPause::SinglePlayerPause(ServiceProvider* service_provider, const ui::Layout& layout, const std::shared_ptr& game_input) : Scene{ service_provider, layout }, m_heading { + service_provider, + fmt::format( + "Pause ({}: continue, {}: quit)", + game_input->describe_menu_event(input::MenuEvent::PAUSE), + service_provider->input_manager().get_primary_input()->describe_navigation_event(input::NavigationEvent::BACK) + ), + service_provider->font_manager().get(FontId::Default), + Color::white(),utils::get_orientation() == utils::Orientation::Landscape + ? std::pair{ 0.7, 0.07 } + : std::pair{ 0.95, 0.07 }, + ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }, + layout, + true + },m_game_input{game_input} + { } + + [[nodiscard]] Scene::UpdateResult scenes::SinglePlayerPause::update() { + if (m_should_unpause) { + return UpdateResult{ SceneUpdate::StopUpdating, Scene::Pop{} }; + } + if (m_should_exit) { + return UpdateResult{ + SceneUpdate::StopUpdating, + Scene::Switch{ SceneId::MainMenu, ui::FullScreenLayout{ m_service_provider->window() } } + }; + } + return UpdateResult{ SceneUpdate::StopUpdating, helper::nullopt }; + } + + void SinglePlayerPause::render(const ServiceProvider& service_provider) { + service_provider.renderer().draw_rect_filled(get_layout().get_rect(), Color::black(180)); + m_heading.render(service_provider); + } + + [[nodiscard]] bool + SinglePlayerPause::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { + + const auto navigation_event = input_manager->get_navigation_event(event); + + + if (m_game_input->get_menu_event(event) == input::MenuEvent::OPEN_SETTINGS) { + m_should_unpause = true; + return true; + } + + if (navigation_event == input::NavigationEvent::BACK) { + m_should_exit = true; + return true; + } + + return false; + } + +} // namespace scenes diff --git a/src/scenes/single_player_game/pause.hpp b/src/scenes/single_player_game/pause.hpp new file mode 100644 index 00000000..a8394ba4 --- /dev/null +++ b/src/scenes/single_player_game/pause.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "manager/event_listener.hpp" +#include "scenes/scene.hpp" +#include "ui/components/label.hpp" + +namespace scenes { + struct SinglePlayerPause : public scenes::Scene { + private: + ui::Label m_heading; + bool m_should_unpause{ false }; + bool m_should_exit{ false }; + std::shared_ptr m_game_input; + + public: + explicit SinglePlayerPause( + ServiceProvider* service_provider, + const ui::Layout& layout, + const std::shared_ptr& game_input + ); + + [[nodiscard]] UpdateResult update() override; + void render(const ServiceProvider& service_provider) override; + [[nodiscard]] bool + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; + }; +} // namespace scenes diff --git a/src/scenes/single_player_game/single_player_game.cpp b/src/scenes/single_player_game/single_player_game.cpp index 550dcdf6..6872203d 100644 --- a/src/scenes/single_player_game/single_player_game.cpp +++ b/src/scenes/single_player_game/single_player_game.cpp @@ -1,8 +1,13 @@ #include "single_player_game.hpp" #include "helper/date.hpp" #include "helper/music_utils.hpp" +#include "helper/platform.hpp" +#include "input/game_input.hpp" +#include "magic_enum.hpp" #include "manager/music_manager.hpp" #include "scenes/scene.hpp" +#include "scenes/settings_menu/settings_menu.hpp" +#include "scenes/single_player_game/pause.hpp" namespace scenes { @@ -13,7 +18,7 @@ namespace scenes { recorder::AdditionalInformation additional_information{}; additional_information.add("mode", "single_player"); - additional_information.add("platform", utils::get_platform()); + additional_information.add("platform", std::string{ magic_enum::enum_name(utils::get_platform()) }); additional_information.add("date", date.value()); //TODO: add more information, if logged in @@ -48,7 +53,7 @@ namespace scenes { if (m_game->is_game_finished()) { return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Push{SceneId::GameOver, ui::FullScreenLayout{ m_service_provider->window() }} + Scene::Push{ SceneId::GameOver, ui::FullScreenLayout{ m_service_provider->window() } } }; } @@ -63,13 +68,21 @@ namespace scenes { case NextScene::Pause: return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Push{SceneId::Pause, ui::FullScreenLayout{ m_service_provider->window() }} + Scene::RawPush{ "Pause", std::make_unique( + m_service_provider, ui::FullScreenLayout{ m_service_provider->window() }, + m_game->game_input() + ) } }; case NextScene::Settings: return UpdateResult{ SceneUpdate::StopUpdating, - Scene::Push{SceneId::SettingsMenu, - ui::RelativeLayout{ m_service_provider->window(), 0.15, 0.15, 0.7, 0.7 }} + Scene::RawPush{ "SettingsMenu", std::make_unique( + m_service_provider, ui::RelativeLayout{ m_service_provider->window(), 0.15, + 0.15, 0.7, 0.7 }, + m_game->game_input() + ) + + } }; default: utils::unreachable(); @@ -82,20 +95,22 @@ namespace scenes { m_game->render(service_provider); } - [[nodiscard]] bool SinglePlayerGame::handle_event(const SDL_Event& event, const Window*) { + [[nodiscard]] bool + SinglePlayerGame::handle_event(const std::shared_ptr&, const SDL_Event& event) { + + const auto& game_input = m_game->game_input(); - if (utils::event_is_action(event, utils::CrossPlatformAction::PAUSE) and not m_game->is_game_finished()) { + if (game_input->get_menu_event(event) == input::MenuEvent::PAUSE and not m_game->is_game_finished()) { m_next_scene = NextScene::Pause; m_game->set_paused(true); return true; } - if (utils::device_supports_keys()) { - if (utils::event_is_action(event, utils::CrossPlatformAction::OPEN_SETTINGS)) { - m_next_scene = NextScene::Settings; - return true; - } + if (game_input->get_menu_event(event) == input::MenuEvent::OPEN_SETTINGS) { + m_next_scene = NextScene::Settings; + return true; } + return false; } diff --git a/src/scenes/single_player_game/single_player_game.hpp b/src/scenes/single_player_game/single_player_game.hpp index a63b978d..254205c3 100644 --- a/src/scenes/single_player_game/single_player_game.hpp +++ b/src/scenes/single_player_game/single_player_game.hpp @@ -19,7 +19,8 @@ namespace scenes { [[nodiscard]] UpdateResult update() override; void render(const ServiceProvider& service_provider) override; - [[nodiscard]] bool handle_event(const SDL_Event& event, const Window* window) override; + [[nodiscard]] bool + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; }; diff --git a/src/ui/components/abstract_slider.hpp b/src/ui/components/abstract_slider.hpp index 5ce553b0..25557daf 100644 --- a/src/ui/components/abstract_slider.hpp +++ b/src/ui/components/abstract_slider.hpp @@ -6,6 +6,7 @@ #include #include "graphics/rect.hpp" +#include "input/input.hpp" #include "ui/focusable.hpp" #include "ui/widget.hpp" @@ -90,20 +91,24 @@ namespace ui { } - Widget::EventHandleResult - handle_event(const SDL_Event& event, const Window* window) // NOLINT(readability-function-cognitive-complexity) + Widget::EventHandleResult handle_event( + const std::shared_ptr& input_manager, + const SDL_Event& event + ) // NOLINT(readability-function-cognitive-complexity) override { Widget::EventHandleResult handled = false; - if (utils::device_supports_keys() and has_focus()) { - if (utils::event_is_action(event, utils::CrossPlatformAction::RIGHT)) { + const auto navigation_event = input_manager->get_navigation_event(event); + + if (navigation_event.has_value() and has_focus()) { + if (navigation_event == input::NavigationEvent::RIGHT) { m_current_value = m_current_value + m_step; if (m_current_value >= m_range.second) { m_current_value = m_range.second; } handled = true; - } else if (utils::event_is_action(event, utils::CrossPlatformAction::LEFT)) { + } else if (navigation_event == input::NavigationEvent::LEFT) { m_current_value = m_current_value - m_step; if (m_current_value <= m_range.first) { m_current_value = m_range.first; @@ -113,12 +118,15 @@ namespace ui { } } - if (not handled and utils::device_supports_clicks()) { + const auto pointer_event = input_manager->get_pointer_event(event); + + + if (not handled and pointer_event.has_value()) { - const auto change_value_on_scroll = [&window, &event, this]() { + const auto change_value_on_scroll = [&pointer_event, this]() { const auto& [bar_rect, slider_rect] = this->get_rectangles(); - const auto& [x, _] = utils::get_raw_coordinates(window, event); + const auto& [x, _] = pointer_event->position(); if (x <= static_cast(bar_rect.top_left.x)) { m_current_value = m_range.first; @@ -133,41 +141,42 @@ namespace ui { }; - if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::ButtonDown)) { + if (pointer_event == input::PointerEvent::PointerDown) { - if (utils::is_event_in(window, event, m_bar_rect)) { + if (pointer_event->is_in(m_bar_rect)) { change_value_on_scroll(); m_is_dragging = true; SDL_CaptureMouse(SDL_TRUE); handled = { true, - {ui::EventHandleType::RequestFocus, this} + { ui::EventHandleType::RequestFocus, this } }; - } else if (utils::is_event_in(window, event, m_slider_rect)) { + } else if (pointer_event->is_in(m_slider_rect)) { m_is_dragging = true; SDL_CaptureMouse(SDL_TRUE); handled = { true, - {ui::EventHandleType::RequestFocus, this} + { ui::EventHandleType::RequestFocus, this } }; } - } else if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::ButtonUp)) { + } else if (pointer_event == input::PointerEvent::PointerUp) { // only handle this, if already dragging, otherwise it's a button down from previously or some other widget if (m_is_dragging) { m_is_dragging = false; SDL_CaptureMouse(SDL_FALSE); handled = true; } - } else if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Motion)) { + } else if (pointer_event == input::PointerEvent::Motion) { if (m_is_dragging) { change_value_on_scroll(); handled = true; } + //TODO: this is not working, since pointer_event.has_value() is wrong in this case } else if (event.type == SDL_MOUSEWHEEL && has_focus()) { // here we use a reverse scroll behaviour, since moving the mouse up is always considered increasing the volume, regardless of you OS setting about natural scrolling or not diff --git a/src/ui/components/button.hpp b/src/ui/components/button.hpp index 2e604d5c..944e3e12 100644 --- a/src/ui/components/button.hpp +++ b/src/ui/components/button.hpp @@ -7,7 +7,7 @@ #include "graphics/rect.hpp" #include "graphics/renderer.hpp" #include "helper/color_literals.hpp" -#include "platform/capabilities.hpp" +#include "input/input.hpp" #include "ui/focusable.hpp" #include "ui/hoverable.hpp" #include "ui/widget.hpp" @@ -82,30 +82,33 @@ namespace ui { m_content.render(service_provider); } - [[nodiscard]] Widget::EventHandleResult handle_event(const SDL_Event& event, const Window* window) override { + [[nodiscard]] Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override { if (not m_enabled) { return false; } - if (utils::device_supports_keys()) { - if (has_focus() and utils::event_is_action(event, utils::CrossPlatformAction::OK)) { - spdlog::info("Button pressed"); - if (on_clicked()) { - return { - true, - {ui::EventHandleType::RequestAction, this} - }; - } - return true; + + const auto navigation_event = input_manager->get_navigation_event(event); + + if (has_focus() and navigation_event == input::NavigationEvent::OK) { + spdlog::info("Button pressed"); + if (on_clicked()) { + return { + true, + { ui::EventHandleType::RequestAction, this } + }; } + return true; } - if (const auto hover_result = detect_hover(event, window); hover_result) { + + if (const auto hover_result = detect_hover(input_manager, event); hover_result) { if (hover_result.is(ActionType::Clicked)) { if (on_clicked()) { return { true, - {ui::EventHandleType::RequestAction, this} + { ui::EventHandleType::RequestAction, this } }; } } diff --git a/src/ui/components/color_picker.cpp b/src/ui/components/color_picker.cpp index 107e1238..91a28b2e 100644 --- a/src/ui/components/color_picker.cpp +++ b/src/ui/components/color_picker.cpp @@ -6,6 +6,7 @@ #include "helper/color.hpp" #include "helper/graphic_utils.hpp" #include "helper/utils.hpp" +#include "input/input.hpp" #include "manager/resource_manager.hpp" #include "ui/components/textinput.hpp" #include "ui/layout.hpp" @@ -81,8 +82,8 @@ detail::ColorSlider::ColorSlider( } const auto slider_rect = shapes::URect{ - shapes::UPoint{slider_start_x, layout_rect.top_left.y}, - shapes::UPoint{ slider_end_x, layout_rect.bottom_right.y} + shapes::UPoint{ slider_start_x, layout_rect.top_left.y }, + shapes::UPoint{ slider_end_x, layout_rect.bottom_right.y } }; return { layout_rect, slider_rect }; @@ -149,46 +150,46 @@ void detail::ColorCanvas::draw_pseudo_circle(const ServiceProvider& service_prov helper::BoolWrapper> detail::ColorCanvas::handle_event( //NOLINT(readability-function-cognitive-complexity) - const SDL_Event& event, - const Window* window + const std::shared_ptr& input_manager, + const SDL_Event& event ) { Widget::EventHandleResult handled = false; const auto fill_rect = layout().get_rect(); - if (utils::device_supports_clicks()) { - if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::ButtonDown)) { + const auto pointer_event = input_manager->get_pointer_event(event); - if (utils::is_event_in(window, event, fill_rect)) { + if (pointer_event.has_value() and pointer_event.value() == input::PointerEvent::PointerDown) { - m_is_dragging = true; - SDL_CaptureMouse(SDL_TRUE); - handled = { - true, - {ui::EventHandleType::RequestFocus, this} - }; - } - } else if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::ButtonUp)) { - // only handle this, if already dragging, otherwise it's a button down from previously or some other widget - if (m_is_dragging) { - m_is_dragging = false; - SDL_CaptureMouse(SDL_FALSE); - handled = true; - } - } else if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Motion)) { + if (pointer_event.value().is_in(fill_rect)) { - if (m_is_dragging) { - handled = true; - } + m_is_dragging = true; + SDL_CaptureMouse(SDL_TRUE); + handled = { + true, + { ui::EventHandleType::RequestFocus, this } + }; + } + } else if (pointer_event == input::PointerEvent::PointerUp) { + // only handle this, if already dragging, otherwise it's a button down from previously or some other widget + if (m_is_dragging) { + m_is_dragging = false; + SDL_CaptureMouse(SDL_FALSE); + handled = true; + } + } else if (pointer_event.value() == input::PointerEvent::Motion) { + + if (m_is_dragging) { + handled = true; } } - if (handled) { + if (handled and pointer_event.has_value()) { const auto previous_color = m_current_color; - const auto& [x, y] = utils::get_raw_coordinates(window, event); + const auto& [x, y] = pointer_event.value().position(); if (x <= static_cast(fill_rect.top_left.x)) { m_current_color.s = 0.0; @@ -407,7 +408,7 @@ ui::ColorPicker::ColorPicker( m_color_text = std::make_unique( - service_provider, service_provider->fonts().get(FontId::Default), Color::white(), focus_id_unused, + service_provider, service_provider->font_manager().get(FontId::Default), Color::white(), focus_id_unused, std::pair{ 0.9, 0.9 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }, ui::TextInputMode::Scale, textinput_layout, false @@ -459,17 +460,17 @@ void ui::ColorPicker::render(const ServiceProvider& service_provider) const { helper::BoolWrapper> ui::ColorPicker::handle_event( //NOLINT(readability-function-cognitive-complexity) - const SDL_Event& event, - const Window* window + const std::shared_ptr& input_manager, + const SDL_Event& event ) { - auto handled = m_color_slider->handle_event(event, window); + auto handled = m_color_slider->handle_event(input_manager, event); if (handled) { return handled; } - handled = m_color_canvas->handle_event(event, window); + handled = m_color_canvas->handle_event(input_manager, event); if (handled) { return handled; @@ -477,16 +478,16 @@ ui::ColorPicker::handle_event( //NOLINT(readability-function-cognitive-complexit if (m_mode == ColorMode::HSV) { - handled = m_hsv_button->handle_event(event, window); + handled = m_hsv_button->handle_event(input_manager, event); } else { - handled = m_rgb_button->handle_event(event, window); + handled = m_rgb_button->handle_event(input_manager, event); } if (handled) { return handled; } - handled = m_color_text->handle_event(event, window); + handled = m_color_text->handle_event(input_manager, event); if (handled) { if (const auto additional = handled.get_additional(); additional.has_value()) { diff --git a/src/ui/components/color_picker.hpp b/src/ui/components/color_picker.hpp index 9cb96e60..1f7bd04b 100644 --- a/src/ui/components/color_picker.hpp +++ b/src/ui/components/color_picker.hpp @@ -62,7 +62,7 @@ namespace detail { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const SDL_Event& event, const Window* window) override; + [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; void on_change(ColorChangeOrigin origin, const HSVColor& color); @@ -116,7 +116,7 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const SDL_Event& event, const Window* window) override; + [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; [[nodiscard]] Color get_color() const; diff --git a/src/ui/components/image_view.cpp b/src/ui/components/image_view.cpp index 51115e74..65102ea6 100644 --- a/src/ui/components/image_view.cpp +++ b/src/ui/components/image_view.cpp @@ -30,6 +30,6 @@ void ui::ImageView::render(const ServiceProvider& service_provider) const { } helper::BoolWrapper> -ui::ImageView::handle_event(const SDL_Event&, const Window*) { +ui::ImageView::handle_event(const std::shared_ptr&, const SDL_Event&) { return false; } diff --git a/src/ui/components/image_view.hpp b/src/ui/components/image_view.hpp index cf3b3251..1cf98ba1 100644 --- a/src/ui/components/image_view.hpp +++ b/src/ui/components/image_view.hpp @@ -27,6 +27,6 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const SDL_Event&, const Window*) override; + [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& even) override; }; } // namespace ui diff --git a/src/ui/components/label.cpp b/src/ui/components/label.cpp index 7d028677..c204e0e7 100644 --- a/src/ui/components/label.cpp +++ b/src/ui/components/label.cpp @@ -27,7 +27,7 @@ void ui::Label::render(const ServiceProvider& service_provider) const { } helper::BoolWrapper> -ui::Label::handle_event(const SDL_Event&, const Window*) { +ui::Label::handle_event(const std::shared_ptr&, const SDL_Event&) { return false; } diff --git a/src/ui/components/label.hpp b/src/ui/components/label.hpp index ae0aa374..6bf99e86 100644 --- a/src/ui/components/label.hpp +++ b/src/ui/components/label.hpp @@ -22,7 +22,8 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const SDL_Event&, const Window*) override; + [[nodiscard]] Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event&) override; void set_text(const ServiceProvider& service_provider, const std::string& text); }; diff --git a/src/ui/components/link_label.cpp b/src/ui/components/link_label.cpp index 33728918..0dff0ffd 100644 --- a/src/ui/components/link_label.cpp +++ b/src/ui/components/link_label.cpp @@ -1,5 +1,6 @@ #include "link_label.hpp" +#include "helper/platform.hpp" ui::LinkLabel::LinkLabel( @@ -56,8 +57,8 @@ void ui::LinkLabel::render(const ServiceProvider& service_provider) const { } helper::BoolWrapper> -ui::LinkLabel::handle_event(const SDL_Event& event, const Window* window) { - if (const auto hover_result = detect_hover(event, window); hover_result) { +ui::LinkLabel::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { + if (const auto hover_result = detect_hover(input_manager, event); hover_result) { if (hover_result.is(ActionType::Clicked)) { on_clicked(); } diff --git a/src/ui/components/link_label.hpp b/src/ui/components/link_label.hpp index 3267521c..92b0d341 100644 --- a/src/ui/components/link_label.hpp +++ b/src/ui/components/link_label.hpp @@ -1,7 +1,6 @@ #pragma once #include "graphics/text.hpp" -#include "platform/capabilities.hpp" #include "ui/hoverable.hpp" #include "ui/widget.hpp" @@ -44,7 +43,7 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const SDL_Event& event, const Window* window) override; + [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; void on_clicked(); diff --git a/src/ui/components/textinput.cpp b/src/ui/components/textinput.cpp index 197e25ec..34da52fa 100644 --- a/src/ui/components/textinput.cpp +++ b/src/ui/components/textinput.cpp @@ -103,16 +103,16 @@ void ui::TextInput::render(const ServiceProvider& service_provider) const { helper::BoolWrapper> ui::TextInput::handle_event( // NOLINT(readability-function-cognitive-complexity) - const SDL_Event& event, - const Window* window + const std::shared_ptr& input_manager, + const SDL_Event& event ) { //TODO: if already has focus, position cursor there, where we clicked - if (const auto hover_result = detect_hover(event, window); hover_result) { + if (const auto hover_result = detect_hover(input_manager, event); hover_result) { if (hover_result.is(ActionType::Clicked)) { return { true, - {EventHandleType::RequestFocus, this} + { EventHandleType::RequestFocus, this } }; } @@ -126,7 +126,7 @@ ui::TextInput::handle_event( // NOLINT(readability-function-cognitive-complexity on_unfocus(); return { true, - {EventHandleType::RequestAction, this} + { EventHandleType::RequestAction, this } }; } case SDLK_BACKSPACE: { diff --git a/src/ui/components/textinput.hpp b/src/ui/components/textinput.hpp index e76279b4..3750eb70 100644 --- a/src/ui/components/textinput.hpp +++ b/src/ui/components/textinput.hpp @@ -63,7 +63,7 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; Widget::EventHandleResult - handle_event(const SDL_Event& event, const Window* window) // NOLINT(readability-function-cognitive-complexity) + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) // NOLINT(readability-function-cognitive-complexity) override; void set_text(const std::string& text); diff --git a/src/ui/focusable.hpp b/src/ui/focusable.hpp index 9e49fa48..3f5a8201 100644 --- a/src/ui/focusable.hpp +++ b/src/ui/focusable.hpp @@ -1,4 +1,5 @@ #pragma once + #include "helper/types.hpp" #include diff --git a/src/ui/hoverable.hpp b/src/ui/hoverable.hpp index 0af8af08..0257528d 100644 --- a/src/ui/hoverable.hpp +++ b/src/ui/hoverable.hpp @@ -3,13 +3,12 @@ #include "graphics/rect.hpp" #include "helper/bool_wrapper.hpp" #include "helper/types.hpp" -#include "platform/capabilities.hpp" - -#include +#include "helper/utils.hpp" +#include "input/input.hpp" namespace ui { - enum class ActionType : u8 { Hover, Clicked }; + enum class ActionType : u8 { Hover, Clicked, Released }; struct Hoverable { @@ -37,27 +36,34 @@ namespace ui { } - [[nodiscard]] helper::BoolWrapper detect_hover(const SDL_Event& event, const Window* window) { + [[nodiscard]] helper::BoolWrapper + detect_hover(const std::shared_ptr& input_manager, const SDL_Event& event) { - if (utils::device_supports_clicks()) { - if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any)) { - if (utils::is_event_in(window, event, m_fill_rect)) { + if (const auto result = input_manager->get_pointer_event(event); result.has_value()) { + if (result->is_in(m_fill_rect)) { - on_hover(); + on_hover(); - if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::ButtonDown)) { + switch (result->event()) { + case input::PointerEvent::PointerDown: return { true, ActionType::Clicked }; - } + case input::PointerEvent::PointerUp: + return { true, ActionType::Released }; - return { true, ActionType::Hover }; - } + case input::PointerEvent::Motion: + return { true, ActionType::Hover }; - on_unhover(); - return false; + default: + utils::unreachable(); + } } + + on_unhover(); + return false; } + return false; } diff --git a/src/ui/layouts/focus_layout.cpp b/src/ui/layouts/focus_layout.cpp index 54c47205..65923a2f 100644 --- a/src/ui/layouts/focus_layout.cpp +++ b/src/ui/layouts/focus_layout.cpp @@ -1,6 +1,7 @@ #include "focus_layout.hpp" #include "helper/optional.hpp" +#include "input/input.hpp" #include "ui/widget.hpp" @@ -28,25 +29,31 @@ void ui::FocusLayout::update() { return static_cast(m_widgets.size()); } -ui::Widget::EventHandleResult ui::FocusLayout::handle_focus_change_button_events(const SDL_Event& event) { +ui::Widget::EventHandleResult ui::FocusLayout::handle_focus_change_button_events( + const std::shared_ptr& input_manager, + const SDL_Event& event +) { Widget::EventHandleResult handled = false; - if (utils::device_supports_keys()) { - if (utils::event_is_action(event, utils::CrossPlatformAction::DOWN) - or (m_options.allow_tab and utils::event_is_action(event, utils::CrossPlatformAction::TAB))) { - handled = try_set_next_focus(FocusChangeDirection::Forward); - } else if (utils::event_is_action(event, utils::CrossPlatformAction::UP)) { - handled = try_set_next_focus(FocusChangeDirection::Backward); - } + const auto navigation_action = input_manager->get_navigation_event(event); + + if (navigation_action == input::NavigationEvent::DOWN + or (m_options.allow_tab and navigation_action == input::NavigationEvent::TAB)) { + handled = try_set_next_focus(FocusChangeDirection::Forward); + } else if (navigation_action == input::NavigationEvent::UP) { + handled = try_set_next_focus(FocusChangeDirection::Backward); } + return handled; } -ui::Widget::EventHandleResult -ui::FocusLayout::handle_focus_change_events(const SDL_Event& event, const Window* window) { +ui::Widget::EventHandleResult ui::FocusLayout::handle_focus_change_events( + const std::shared_ptr& input_manager, + const SDL_Event& event +) { if (not has_focus()) { @@ -61,7 +68,7 @@ ui::FocusLayout::handle_focus_change_events(const SDL_Event& event, const Window if (widget->type() != WidgetType::Container) { - handled = handle_focus_change_button_events(event); + handled = handle_focus_change_button_events(input_manager, event); } @@ -69,13 +76,13 @@ ui::FocusLayout::handle_focus_change_events(const SDL_Event& event, const Window return handled; } - if (const auto event_result = widget->handle_event(event, window); event_result) { + if (const auto event_result = widget->handle_event(input_manager, event); event_result) { return { true, handle_event_result(event_result.get_additional(), widget.get()) }; } if (widget->type() == WidgetType::Container) { - handled = handle_focus_change_button_events(event); + handled = handle_focus_change_button_events(input_manager, event); } } diff --git a/src/ui/layouts/focus_layout.hpp b/src/ui/layouts/focus_layout.hpp index 5a4bba6d..487a4924 100644 --- a/src/ui/layouts/focus_layout.hpp +++ b/src/ui/layouts/focus_layout.hpp @@ -1,6 +1,7 @@ #pragma once +#include "helper/utils.hpp" #include "ui/focusable.hpp" #include "ui/widget.hpp" @@ -59,8 +60,8 @@ namespace ui { ) }; } - auto item = dynamic_cast(m_widgets.at(index).get()); - return item != nullptr; + auto item = utils::is_child_class(m_widgets.at(index)); + return item.has_value(); } @@ -73,12 +74,12 @@ namespace ui { ) }; } - auto item = dynamic_cast(m_widgets.at(index).get()); - if (item == nullptr) { + auto item = utils::is_child_class(m_widgets.at(index)); + if (not item.has_value()) { throw std::runtime_error("Invalid get of FocusLayout item!"); } - return item; + return item.value(); } template @@ -87,21 +88,25 @@ namespace ui { throw std::runtime_error("Invalid get of FocusLayout item: index out of bound!"); } - const auto item = dynamic_cast(m_widgets.at(index).get()); + const auto item = utils::is_child_class(m_widgets.at(index).get()); if (item == nullptr) { throw std::runtime_error("Invalid get of FocusLayout item!"); } - return item; + return item.value(); } private: - Widget::EventHandleResult handle_focus_change_button_events(const SDL_Event& event); + Widget::EventHandleResult handle_focus_change_button_events( + const std::shared_ptr& input_manager, + const SDL_Event& event + ); protected: [[nodiscard]] virtual Layout get_layout_for_index(u32 index) = 0; - Widget::EventHandleResult handle_focus_change_events(const SDL_Event& event, const Window* window); + Widget::EventHandleResult + handle_focus_change_events(const std::shared_ptr& input_manager, const SDL_Event& event); [[nodiscard]] helper::optional handle_event_result(const helper::optional& result, Widget* widget); diff --git a/src/ui/layouts/grid_layout.cpp b/src/ui/layouts/grid_layout.cpp index 0eddd1a6..f0060871 100644 --- a/src/ui/layouts/grid_layout.cpp +++ b/src/ui/layouts/grid_layout.cpp @@ -29,39 +29,35 @@ void ui::GridLayout::render(const ServiceProvider& service_provider) const { } } -ui::Widget::EventHandleResult ui::GridLayout::handle_event( - const SDL_Event& event, - const Window* window -) // NOLINT(readability-function-cognitive-complexity) -{ - Widget::EventHandleResult handled = handle_focus_change_events(event, window); +ui::Widget::EventHandleResult +ui::GridLayout::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { + Widget::EventHandleResult handled = handle_focus_change_events(input_manager, event); if (handled) { return handled; } - if (utils::device_supports_clicks()) { - - if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any)) { - - for (auto& widget : m_widgets) { - const auto layout = widget->layout(); - if (not handled and utils::is_event_in(window, event, layout.get_rect())) { - if (const auto event_result = widget->handle_event(event, window); event_result) { - handled = { true, handle_event_result(event_result.get_additional(), widget.get()) }; - continue; - } - } else { - const auto hoverable = as_hoverable(widget.get()); - if (hoverable.has_value()) { - hoverable.value()->on_unhover(); - } + + if (const auto point_event = input_manager->get_pointer_event(event); point_event.has_value()) { + + for (auto& widget : m_widgets) { + const auto layout = widget->layout(); + if (not handled and point_event->is_in(layout.get_rect())) { + if (const auto event_result = widget->handle_event(input_manager, event); event_result) { + handled = { true, handle_event_result(event_result.get_additional(), widget.get()) }; + continue; + } + } else { + const auto hoverable = as_hoverable(widget.get()); + if (hoverable.has_value()) { + hoverable.value()->on_unhover(); } } - return handled; } + return handled; } + return handled; } diff --git a/src/ui/layouts/grid_layout.hpp b/src/ui/layouts/grid_layout.hpp index e18463be..15aa41db 100644 --- a/src/ui/layouts/grid_layout.hpp +++ b/src/ui/layouts/grid_layout.hpp @@ -28,8 +28,7 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; Widget::EventHandleResult - handle_event(const SDL_Event& event, const Window* window) // NOLINT(readability-function-cognitive-complexity) - override; + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; private: diff --git a/src/ui/layouts/scroll_layout.cpp b/src/ui/layouts/scroll_layout.cpp index 2a91f2c8..c9b3c211 100644 --- a/src/ui/layouts/scroll_layout.cpp +++ b/src/ui/layouts/scroll_layout.cpp @@ -1,6 +1,7 @@ #include "scroll_layout.hpp" #include "helper/color_literals.hpp" +#include "input/input.hpp" ui::ItemSize::ItemSize(const u32 height, ItemSizeType type) : height{ height }, type{ type } { } @@ -107,118 +108,116 @@ void ui::ScrollLayout::render(const ServiceProvider& service_provider) const { } ui::Widget::EventHandleResult ui::ScrollLayout::handle_event( // NOLINT(readability-function-cognitive-complexity) - const SDL_Event& event, - const Window* window + const std::shared_ptr& input_manager, + const SDL_Event& event ) { - Widget::EventHandleResult handled = handle_focus_change_events(event, window); + Widget::EventHandleResult handled = handle_focus_change_events(input_manager, event); if (handled) { auto_move_after_focus_change(); return handled; } - if (utils::device_supports_clicks()) { - const u32 total_widgets_height = m_widgets.empty() ? 0 : m_widgets.back()->layout().get_rect().bottom_right.y; + const u32 total_widgets_height = m_widgets.empty() ? 0 : m_widgets.back()->layout().get_rect().bottom_right.y; - const auto change_value_on_scroll = [&window, &event, total_widgets_height, this]() { - const auto& [_, y] = utils::get_raw_coordinates(window, event); + const auto change_value_on_scroll = [total_widgets_height, this](const input::PointerEventHelper& pointer_event) { + const auto& [_, y] = pointer_event.position(); - auto desired_scroll_height = 0; + auto desired_scroll_height = 0; - if (y <= static_cast(scrollbar_rect.top_left.y)) { - desired_scroll_height = 0; - } else if (y >= static_cast(scrollbar_rect.bottom_right.y)) { - // this is to high, but recalculate_sizes reset it to the highest possible value! - desired_scroll_height = static_cast(total_widgets_height); - } else { - - const double percentage = static_cast(y - scrollbar_rect.top_left.y) - / static_cast(scrollbar_rect.height()); + if (y <= static_cast(scrollbar_rect.top_left.y)) { + desired_scroll_height = 0; + } else if (y >= static_cast(scrollbar_rect.bottom_right.y)) { + // this is to high, but recalculate_sizes reset it to the highest possible value! + desired_scroll_height = static_cast(total_widgets_height); + } else { - // we want the final point to be in the middle, but desired_scroll_height expects the top position. - desired_scroll_height = static_cast( - static_cast(percentage * total_widgets_height) - scrollbar_rect.height() / 2 - ); - is_dragging = true; - } + const double percentage = + static_cast(y - scrollbar_rect.top_left.y) / static_cast(scrollbar_rect.height()); + // we want the final point to be in the middle, but desired_scroll_height expects the top position. + desired_scroll_height = + static_cast(static_cast(percentage * total_widgets_height) - scrollbar_rect.height() / 2); + is_dragging = true; + } - recalculate_sizes(desired_scroll_height); - }; + recalculate_sizes(desired_scroll_height); + }; - if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::ButtonDown)) { - // note: this behaviour is intentional, namely, clicking into the scroll slider doesn't move it, it just "grabs" it for dragging - if (utils::is_event_in(window, event, scrollbar_mover_rect)) { - is_dragging = true; - handled = true; - } else if (utils::is_event_in(window, event, scrollbar_rect)) { + const auto pointer_event = input_manager->get_pointer_event(event); - change_value_on_scroll(); - handled = true; - } + if (pointer_event == input::PointerEvent::PointerDown) { + // note: this behaviour is intentional, namely, clicking into the scroll slider doesn't move it, it just "grabs" it for dragging + if (pointer_event->is_in(scrollbar_mover_rect)) { + is_dragging = true; + handled = true; + } else if (pointer_event->is_in(scrollbar_rect)) { - } else if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::ButtonUp)) { - is_dragging = false; + change_value_on_scroll(pointer_event.value()); handled = true; + } - } else if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Motion)) { + } else if (pointer_event == input::PointerEvent::PointerUp) { + is_dragging = false; + handled = true; - if (is_dragging) { + } else if (pointer_event == input::PointerEvent::Motion) { - change_value_on_scroll(); - handled = true; - } + if (is_dragging) { - //TODO: support touch screen scrolling too! - } else if (event.type == SDL_MOUSEWHEEL) { + change_value_on_scroll(pointer_event.value()); + handled = true; + } - // attention the mouse direction changes (it's called natural scrolling on macos/ windows / linux) are not detected by sdl until restart, and here we use the correct scroll behaviour, as the user configured the mouse in it's OS - const bool direction_is_down = - event.wheel.direction == SDL_MOUSEWHEEL_NORMAL ? event.wheel.y < 0 : event.wheel.y > 0; + //TODO: support touch screen scrolling too, factor this out into the input manager + } else if (event.type == SDL_MOUSEWHEEL) { + // attention the mouse direction changes (it's called natural scrolling on macos/ windows / linux) are not detected by sdl until restart, and here we use the correct scroll behaviour, as the user configured the mouse in it's OS + const bool direction_is_down = + event.wheel.direction == SDL_MOUSEWHEEL_NORMAL ? event.wheel.y < 0 : event.wheel.y > 0; - auto desired_scroll_height = 0; - if (direction_is_down) { - desired_scroll_height = static_cast(m_viewport.top_left.y + m_step_size); - } else { - desired_scroll_height = static_cast(m_viewport.top_left.y - m_step_size); - } + auto desired_scroll_height = 0; - recalculate_sizes(desired_scroll_height); - handled = true; + if (direction_is_down) { + desired_scroll_height = static_cast(m_viewport.top_left.y + m_step_size); + } else { + desired_scroll_height = static_cast(m_viewport.top_left.y - m_step_size); } - if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any)) { - - const auto offset_distance = main_rect.top_left.cast() - m_viewport.top_left.cast(); - for (auto& widget : m_widgets) { - const auto& layout_rect = widget->layout().get_rect(); - const auto& offset_rect = (layout_rect.cast()) >> offset_distance; - - if (not handled and utils::is_event_in(window, event, main_rect) - and utils::is_event_in(window, event, offset_rect.cast())) { - const auto offset_event = utils::offset_event(window, event, -offset_distance); - if (const auto event_result = widget->handle_event(offset_event, window); event_result) { - handled = { true, handle_event_result(event_result.get_additional(), widget.get()) }; - continue; - } - } else { - const auto hoverable = as_hoverable(widget.get()); - if (hoverable.has_value()) { - hoverable.value()->on_unhover(); - } + recalculate_sizes(desired_scroll_height); + handled = true; + } + + if (pointer_event.has_value()) { + + const auto offset_distance = main_rect.top_left.cast() - m_viewport.top_left.cast(); + for (auto& widget : m_widgets) { + const auto& layout_rect = widget->layout().get_rect(); + const auto& offset_rect = (layout_rect.cast()) >> offset_distance; + + if (not handled and pointer_event->is_in(main_rect) and pointer_event->is_in(offset_rect)) { + const auto offset_event = pointer_event.value().offset_raw(event, -offset_distance); + if (const auto event_result = widget->handle_event(input_manager, offset_event); event_result) { + handled = { true, handle_event_result(event_result.get_additional(), widget.get()) }; + continue; + } + } else { + const auto hoverable = as_hoverable(widget.get()); + if (hoverable.has_value()) { + hoverable.value()->on_unhover(); } } - - return handled; } + + return handled; } + return handled; } diff --git a/src/ui/layouts/scroll_layout.hpp b/src/ui/layouts/scroll_layout.hpp index 502e71fc..6e672461 100644 --- a/src/ui/layouts/scroll_layout.hpp +++ b/src/ui/layouts/scroll_layout.hpp @@ -66,8 +66,7 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; Widget::EventHandleResult - handle_event(const SDL_Event& event, const Window* window) // NOLINT(readability-function-cognitive-complexity) - override; + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; //TODO: with some template paramater and magic make this an option in the base class, so that only get_layout_for_new needs to be overwritten! template u32 add(ItemSize size, Args... args) { diff --git a/src/ui/layouts/tile_layout.cpp b/src/ui/layouts/tile_layout.cpp index d5ce6436..4b8c4ba3 100644 --- a/src/ui/layouts/tile_layout.cpp +++ b/src/ui/layouts/tile_layout.cpp @@ -9,39 +9,40 @@ void ui::TileLayout::render(const ServiceProvider& service_provider) const { } ui::Widget::EventHandleResult ui::TileLayout::handle_event( - const SDL_Event& event, - const Window* window + const std::shared_ptr& input_manager, + const SDL_Event& event ) // NOLINT(readability-function-cognitive-complexity) { - Widget::EventHandleResult handled = handle_focus_change_events(event, window); + Widget::EventHandleResult handled = handle_focus_change_events(input_manager, event); if (handled) { return handled; } - if (utils::device_supports_clicks()) { - - if (utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any)) { - - for (auto& widget : m_widgets) { - const auto layout = widget->layout(); - if (not handled and utils::is_event_in(window, event, layout.get_rect())) { - if (const auto event_result = widget->handle_event(event, window); event_result) { - handled = { true, handle_event_result(event_result.get_additional(), widget.get()) }; - continue; - } - } else { - const auto hoverable = ui::as_hoverable(widget.get()); - if (hoverable.has_value()) { - hoverable.value()->on_unhover(); - } + + const auto pointer_event = input_manager->get_pointer_event(event); + + if (pointer_event.has_value()) { + + for (auto& widget : m_widgets) { + const auto layout = widget->layout(); + if (not handled and pointer_event.value().is_in(layout.get_rect())) { + if (const auto event_result = widget->handle_event(input_manager, event); event_result) { + handled = { true, handle_event_result(event_result.get_additional(), widget.get()) }; + continue; + } + } else { + const auto hoverable = ui::as_hoverable(widget.get()); + if (hoverable.has_value()) { + hoverable.value()->on_unhover(); } } - - return handled; } + + return handled; } + return handled; } diff --git a/src/ui/layouts/tile_layout.hpp b/src/ui/layouts/tile_layout.hpp index e2e4eac0..05380665 100644 --- a/src/ui/layouts/tile_layout.hpp +++ b/src/ui/layouts/tile_layout.hpp @@ -52,7 +52,7 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; Widget::EventHandleResult - handle_event(const SDL_Event& event, const Window* window) // NOLINT(readability-function-cognitive-complexity) + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) // NOLINT(readability-function-cognitive-complexity) override; private: diff --git a/src/ui/widget.cpp b/src/ui/widget.cpp index 98d3d904..b3db6555 100644 --- a/src/ui/widget.cpp +++ b/src/ui/widget.cpp @@ -1,21 +1,12 @@ #include "widget.hpp" +#include "helper/utils.hpp" [[nodiscard]] helper::optional ui::as_focusable(ui::Widget* const widget) { - auto* const focusable = dynamic_cast(widget); - if (focusable == nullptr) { - return helper::nullopt; - } - - return focusable; + return utils::is_child_class(widget); } [[nodiscard]] helper::optional ui::as_hoverable(ui::Widget* const widget) { - auto* const hoverable = dynamic_cast(widget); - if (hoverable == nullptr) { - return helper::nullopt; - } - - return hoverable; + return utils::is_child_class(widget); } diff --git a/src/ui/widget.hpp b/src/ui/widget.hpp index 0052667d..40d9115f 100644 --- a/src/ui/widget.hpp +++ b/src/ui/widget.hpp @@ -55,7 +55,7 @@ namespace ui { // do nothing } virtual void render(const ServiceProvider& service_provider) const = 0; - [[nodiscard]] virtual EventHandleResult handle_event(const SDL_Event& event, const Window* window) = 0; + [[nodiscard]] virtual EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) = 0; }; [[nodiscard]] helper::optional as_focusable(Widget* widget); diff --git a/tests/graphics/meson.build b/tests/graphics/meson.build new file mode 100644 index 00000000..50a19049 --- /dev/null +++ b/tests/graphics/meson.build @@ -0,0 +1,3 @@ + + +graphics_test_src += files('sdl_key.cpp') diff --git a/tests/graphics/sdl_key.cpp b/tests/graphics/sdl_key.cpp new file mode 100644 index 00000000..ada3fce9 --- /dev/null +++ b/tests/graphics/sdl_key.cpp @@ -0,0 +1,314 @@ + +#include "helper/color.hpp" + +#include +#include +#include +#include + +namespace { + using ForeachCallback = std::function; + void foreach_loop(const ForeachCallback& callback) { + u8 r{ 0 }; + u8 g{ 0 }; + u8 b{ 0 }; + do { // NOLINT(cppcoreguidelines-avoid-do-while) + do { // NOLINT(cppcoreguidelines-avoid-do-while) + do { // NOLINT(cppcoreguidelines-avoid-do-while) + callback(r, g, b); + } while (r++ != 255); + } while (g++ != 255); + } while (b++ != 255); + } + +} // namespace + +// helper thought just for the tests +[[nodiscard]] constexpr bool operator==(const HSVColor& value1, const HSVColor& value2) { + return value1.to_rgb_color() == value2.to_rgb_color(); +} + + +// make colors printable +void PrintTo(const Color& color, std::ostream* os) { + *os << color.to_string(); +} + +void PrintTo(const HSVColor& color, std::ostream* os) { + *os << color.to_string(); +} + + +// make helper::expected printable +template +void PrintTo(const helper::expected& value, std::ostream* os) { + if (value.has_value()) { + *os << "Value: " << ::testing::PrintToString(value.value()); + } else { + *os << "Error: " << ::testing::PrintToString(value.error()); + } +} + + +MATCHER(ExpectedHasValue, "expected has value") { + return arg.has_value(); +} + +MATCHER(ExpectedHasError, "expected has error") { + return not arg.has_value(); +} + +TEST(Color, DefaultConstruction) { + const auto c1 = Color{}; + const auto c2 = Color{ 0, 0, 0, 0 }; + ASSERT_EQ(c1, c2); +} + +TEST(Color, ConstructorProperties) { + foreach_loop([](u8 r, u8 g, u8 b) { + const auto c1 = Color{ r, g, b }; + const auto c2 = Color{ r, g, b, 0xFF }; + ASSERT_EQ(c1, c2); + }); +} + +TEST(Color, FromStringValid) { + + const std::vector> valid_values{ + { "#FFAA33", { Color{ 0xFF, 0xAA, 0x33 }, color::SerializeMode::Hex, false }}, + { "#FF00FF00", { Color{ 0xFF, 0x00, 0xFF, 0x00 }, color::SerializeMode::Hex, true }}, + { "rgb(0,0,0)", { Color{ 0, 0, 0 }, color::SerializeMode::RGB, false }}, + { "rgba(0,0,0,0)", { Color{ 0, 0, 0, 0 }, color::SerializeMode::RGB, true }}, + { "hsv(0,0,0)", { HSVColor{ 0, 0, 0 }, color::SerializeMode::HSV, false }}, + { "hsva(340,0,0.5,0)", { HSVColor{ 340, 0, 0.5, 0 }, color::SerializeMode::HSV, true }}, + { "#ffaa33", { Color{ 0xff, 0xaa, 0x33 }, color::SerializeMode::Hex, false }}, + {"hsv(0, 0.00_000_000_1, 0)", { HSVColor{ 0, 0.000000001, 0 }, color::SerializeMode::HSV, false }}, + { "hsva(0, 0, 0, 0xFF)", { HSVColor{ 0, 0, 0, 0xFF }, color::SerializeMode::HSV, true }}, + { "rgba(0, 0xFF, 0, 255)", { Color{ 0, 0xFF, 0, 255 }, color::SerializeMode::RGB, true }}, + { "rgba(0, 0xFF, 0, 1_0_0)", { Color{ 0, 0xFF, 0, 100 }, color::SerializeMode::RGB, true }}, + }; + + for (const auto& [valid_string, expected_result] : valid_values) { + const auto result = Color::from_string_with_info(valid_string); + ASSERT_THAT(result, ExpectedHasValue()) << "Input was: " << valid_string; + ASSERT_EQ(result.value(), expected_result) << "Input was: " << valid_string; + + const auto color_string = std::get<0>(result.value()).to_string(color::SerializeMode::Hex); + + const auto converted_color = Color::from_string_with_info(color_string); + ASSERT_THAT(converted_color, ExpectedHasValue()) << "Input was: " << color_string; + ASSERT_EQ(result.value(), expected_result) << "Input was: " << color_string; + } +} + +TEST(Color, FromStringInvalid) { + + const std::vector> invalid_strings{ + { "", "not enough data to determine the literal type"}, + { "#44", "Unrecognized HEX literal"}, + { "#Z", "Unrecognized HEX literal"}, + { "#ZZFF", "Unrecognized HEX literal"}, + { "u", "Unrecognized color literal"}, + { "#IIFFFFFF", "the input must be a valid hex character"}, + { "#FFIIFFFF", "the input must be a valid hex character"}, + { "#FFFFIIFF", "the input must be a valid hex character"}, + { "#FFFFFFII", "the input must be a valid hex character"}, + { "#FFFF4T", "the input must be a valid hex character"}, + { "#0000001", "Unrecognized HEX literal"}, + { "hsl(0,0,0)", "Unrecognized HSV literal"}, + { "rgg(0,0,0)", "Unrecognized RGB literal"}, + { "hsva(9,9,9)", "s has to be in range 0.0 - 1.0"}, + { "hsva(9,9,9,10212)", "s has to be in range 0.0 - 1.0"}, + { "hsv(-1,0,0)", "the input must be a valid decimal character"}, + { "hsv(404040,0,0)", "h has to be in range 0.0 - 360.0"}, + { "hsv(0,1.4,0)", "s has to be in range 0.0 - 1.0"}, + { "hsv(0,0,1.7)", "v has to be in range 0.0 - 1.0"}, + { "hsva(1321.4,0,0,0)", "h has to be in range 0.0 - 360.0"}, + { "hsva(0,1.4,0,0)", "s has to be in range 0.0 - 1.0"}, + { "hsva(0,0,1.7,0)", "v has to be in range 0.0 - 1.0"}, + { "hsva(0, 0, 0, 256)", "a has to be in range 0 - 255"}, + { "hsv(0,0,1.7.8)", "only one comma allowed"}, + { "hsv(0", "input ended too early"}, + { "rgba(0, 0xFFF, 0, 255)", "g has to be in range 0 - 255"}, + { "rgba(0, 0xFF, 0)", "expected ','"}, + { "rgb(0, 0xFF, 0, 255)", "expected ')'"}, + { "rgba(0, 0xFF, 0, 256)", "a has to be in range 0 - 255"}, + { "rgba(0", "input ended too early"}, + { "rgba(0, 0xFF, 0, 4_294_967_296)", "overflow detected"}, + { "rgba(0, 0xFF, 0, 4_294_967_300)", "overflow detected"}, + {"rgba(0, 0xFF, 0, 121_123_124_294_967_300)", "overflow detected"}, + { "rgb(256,0,0)", "r has to be in range 0 - 255"}, + { "rgb(0)", "expected ','"}, + { "rgb(0,256,0)", "g has to be in range 0 - 255"}, + { "rgb(0,0)", "expected ','"}, + { "rgb(0,0,256)", "b has to be in range 0 - 255"}, + { "rgb(0,0,0,", "expected ')'"}, + { "rgb(0,0,255) ", "expected end of string"}, + { "rgba(256,0,0,0)", "r has to be in range 0 - 255"}, + { "rgba(0)", "expected ','"}, + { "rgba(0,256,0,0)", "g has to be in range 0 - 255"}, + { "rgba(0,0)", "expected ','"}, + { "rgba(0,0,256,0)", "b has to be in range 0 - 255"}, + { "rgba(0,0,0)", "expected ','"}, + { "rgba(0,0,0,256)", "a has to be in range 0 - 255"}, + { "rgba(0,0,0,0,", "expected ')'"}, + { "rgba(0,0,0,255) ", "expected end of string"}, + { "hsv(0)", "expected ','"}, + { "hsv(0,0)", "expected ','"}, + { "hsv(0,0,0,", "expected ')'"}, + { "hsv(0,0,0) ", "expected end of string"}, + { "hsva(0)", "expected ','"}, + { "hsva(0,0)", "expected ','"}, + { "hsva(0,0,0)", "expected ','"}, + { "hsva(0,0,0,0,", "expected ')'"}, + { "hsva(0,0,0,255) ", "expected end of string"}, + }; + + for (const auto& [invalid_string, error_message] : invalid_strings) { + const auto result = Color::from_string(invalid_string); + ASSERT_THAT(result, ExpectedHasError()) << "Input was: " << invalid_string; + ASSERT_EQ(result.error(), error_message) << "Input was: " << invalid_string; + } +} + + +TEST(HSVColor, DefaultConstruction) { + const auto c1 = HSVColor{}; + const auto c2 = HSVColor{ 0, 0, 0, 0 }; + ASSERT_EQ(c1, c2); +} + +TEST(HSVColor, ConstructorProperties) { + + const std::vector> values{ + { 0.0, 0.0, 0.0}, + {360.0, 0.0, 0.0}, + {360.0, 1.0, 0.0}, + {360.0, 1.0, 1.0}, + { 57.0, 0.6, 0.8} + }; + + for (const auto& [h, s, v] : values) { + const auto c1 = HSVColor{ h, s, v }; + const auto c2 = HSVColor{ h, s, v, 0xFF }; + ASSERT_EQ(c1, c2); + } +} + +TEST(HSVColor, InvalidConstructors) { + + const std::vector> invalid_values{ + { -1.0, 0.0, 0.0}, + {360.0, -1.0, 0.0}, + {360.0, 1.0, -1.0}, + {460.0, 1.0, 1.0}, + { 57.0, 2.6, 0.8}, + { 57.0, 1.6, 3.8} + }; + + for (const auto& [h, s, v] : invalid_values) { + + const auto construct = [h, s, v]() { HSVColor{ h, s, v }; }; //NOLINT(clang-analyzer-core.NullDereference) + + ASSERT_ANY_THROW(construct()); //NOLINT(*) + } +} + +#ifndef COLOR_TEST_MODE +#define COLOR_TEST_MODE 0 +#endif + + +TEST(ColorConversion, HSV_to_RGB_to_HSV) { //NOLINT(readability-function-cognitive-complexity) + +#if COLOR_TEST_MODE == 0 + const std::vector colors{ + HSVColor{ 2, 0.3, 0.6}, + HSVColor{ 82, 0.3, 0.6}, + HSVColor{142, 0.3, 0.6}, + HSVColor{192, 0.3, 0.6}, + HSVColor{252, 0.3, 0.6}, + HSVColor{312, 0.3, 0.6}, + }; + + for (const auto& original_color : colors) { + +#else +#if COLOR_TEST_MODE == 1 + constexpr const auto step_amount = 1000; // arbitrary number, to make it kinda exhaustive +#else + constexpr const auto step_amount = COLOR_TEST_MODE; +#endif + + for (double h = 0.0; h < 360.0; h += 360.0 / step_amount) { + for (double s = 0.0; s < 1.0; s += 1.0 / step_amount) { + for (double v = 0.0; v < 1.0; v += 1.0 / step_amount) { + const auto original_color = HSVColor{ h, s, v }; + + +#endif + const auto convert = [&original_color]() { + const auto converted_color = original_color.to_rgb_color(); + + const auto result_color = converted_color.to_hsv_color(); + + ASSERT_EQ(original_color, result_color) << "Intermediate step: " << converted_color.to_string(); + }; + + ASSERT_NO_THROW(convert()); //NOLINT(*) + +#if COLOR_TEST_MODE != 0 + } +} +#endif +} +} + + +TEST(ColorConversion, RGG_to_HSV_to_RGB) { //NOLINT(readability-function-cognitive-complexity) + +#if COLOR_TEST_MODE == 0 + const std::vector colors{ + Color{ 0, 0, 0}, + Color{180, 135, 223}, + Color{ 12, 34, 130}, + Color{ 79, 85, 20}, + Color{155, 174, 2}, + Color{243, 32, 34}, + }; + + for (const auto& original_color : colors) { + +#else + +#if COLOR_TEST_MODE == 1 + constexpr const u8 step_amount = 0xFF; // max u8 +#else + + constexpr const u8 step_amount = COLOR_TEST_MODE; +#endif + + constexpr const u8 u8_max = std::numeric_limits::max(); + constexpr const u8 step_size = u8_max / step_amount; + + + for (u8 r = 0.0; u8_max - r < step_amount; r += step_size) { + for (u8 g = 0.0; u8_max - g < step_amount; g += step_size) { + for (u8 b = 0.0; u8_max - b < step_amount; b += step_size) { + const auto original_color = Color{ r, g, b }; +#endif + const auto convert = [&original_color]() { + const auto converted_color = original_color.to_hsv_color(); + + const auto result_color = converted_color.to_rgb_color(); + + ASSERT_EQ(original_color, result_color) << "Intermediate step: " << converted_color.to_string(); + }; + + ASSERT_NO_THROW(convert()); //NOLINT(*) +#if COLOR_TEST_MODE != 0 + } +} +#endif +} +} diff --git a/tests/meson.build b/tests/meson.build index 91db1638..bba9d4a0 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -10,13 +10,14 @@ extra_src = files('entry.cpp') test_src = [] test_inc_dirs = [] core_test_src = [] +graphics_test_src = [] test_deps += dependency('gtest') test_deps += dependency('gmock') - subdir('core') +subdir('graphics') subdir('utils') test_inc_dirs += include_directories('.') @@ -43,3 +44,26 @@ test( protocol: 'gtest', workdir: meson.project_source_root() / 'tests' / 'files', ) + +graphics_tests = executable( + 'graphics_tests', + extra_src, + test_src, + graphics_test_src, + include_directories: test_inc_dirs, + dependencies: [test_deps, liboopetris_graphics_dep], + ## COLOR_TEST_MODE = 0 (SET_VALUE) | 1 (EXHAUSTIVE) | any other number : use that many steps from exhaustive, see code + cpp_args: ['-DCOLOR_TEST_MODE=0'], + override_options: { + 'warning_level': '3', + 'werror': true, + 'b_coverage': false, + }, +) + +test( + 'graphics_tests', + graphics_tests, + protocol: 'gtest', + workdir: meson.project_source_root() / 'tests' / 'files', +) From e2ca40b63e6736db374ad7eea445cb0b98e8b377 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Sun, 5 May 2024 00:44:02 +0200 Subject: [PATCH 02/76] readd clang tidy warnings fro special member functions (WIP, warnings will be fixed later) --- .clang-tidy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 2fd2120e..dc6c70d9 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,6 +1,6 @@ # taken from https://github.com/cpp-linter/cpp-linter-action/blob/main/demo/.clang-tidy --- -Checks: "clang-diagnostic-*,clang-analyzer-*,bugprone-*,misc-*,performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,-modernize-use-trailing-return-type,-readability-named-parameter,-readability-identifier-length,-misc-include-cleaner,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-misc-non-private-member-variables-in-classes,-cppcoreguidelines-non-private-member-variables-in-classes,-cppcoreguidelines-special-member-functions" +Checks: "clang-diagnostic-*,clang-analyzer-*,bugprone-*,misc-*,performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,-modernize-use-trailing-return-type,-readability-named-parameter,-readability-identifier-length,-misc-include-cleaner,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-misc-non-private-member-variables-in-classes,-cppcoreguidelines-non-private-member-variables-in-classes" WarningsAsErrors: "" HeaderFilterRegex: "oopetris/src/.*" AnalyzeTemporaryDtors: false From c66be9d04cee172bc7a3ffa3bcf65ff1c303a3ea Mon Sep 17 00:00:00 2001 From: Totto16 Date: Sun, 5 May 2024 02:18:10 +0200 Subject: [PATCH 03/76] add settings for all three input types: - serialize and deserialize them all - use the settings to make TouchGameInput dynamic --- settings.json | 19 ++++- src/application.cpp | 1 + src/input/input.cpp | 50 +++++++----- src/input/input.hpp | 22 ++++- src/input/input_creator.cpp | 2 +- src/input/input_creator.hpp | 2 +- src/input/joystick_input.cpp | 21 +++++ src/input/joystick_input.hpp | 133 ++++++++++++++++++++++++++++++- src/input/keyboard_input.cpp | 29 ++++++- src/input/keyboard_input.hpp | 93 ++++++++------------- src/input/touch_input.cpp | 34 +++++--- src/input/touch_input.hpp | 127 +++++++++++++++++++++++++++-- src/manager/sdl_key.hpp | 4 + src/manager/settings_manager.cpp | 49 +++++++++++- src/manager/settings_manager.hpp | 58 +++++++------- 15 files changed, 510 insertions(+), 134 deletions(-) diff --git a/settings.json b/settings.json index 1afd1dc0..acfa88fe 100644 --- a/settings.json +++ b/settings.json @@ -25,7 +25,11 @@ "move_left": "A", "move_right": "D", "rotate_left": "Y", - "rotate_right": "X" + "rotate_right": "X", + "menu": { + "pause": "Esc", + "open_settings": "E" + } }, { "type": "joystick", @@ -38,7 +42,18 @@ "move_left": "A", "move_right": "D", "rotate_left": "Y", - "rotate_right": "X" + "rotate_right": "X", + "menu": { + "pause": "Esc", + "open_settings": "E" + } + }, + { + "type": "touch", + "move_x_threshold": 0.07, + "move_y_threshold": 0.37, + "rotation_duration_threshold": 500, + "drop_duration_threshold": 200 } ], "volume": 0.2, diff --git a/src/application.cpp b/src/application.cpp index 3741f663..ed0513c8 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -1,5 +1,6 @@ #include "application.hpp" #include "helper/errors.hpp" +#include "helper/magic_enum_wrapper.hpp" #include "helper/message_box.hpp" #include "helper/sleep.hpp" #include "input/input.hpp" diff --git a/src/input/input.cpp b/src/input/input.cpp index b456056c..54a7c694 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -115,22 +115,36 @@ input::InputManager::~InputManager() = default; } //TODO: improve this API, to correctly use settings to determine the input to use. -[[nodiscard]] std::unique_ptr input::InputManager::get_game_input(ServiceProvider* service_provider) { - return std::visit( - helper::overloaded{ - [service_provider]([[maybe_unused]] const input::KeyboardSettings& keyboard_settings - ) mutable -> std::unique_ptr { - auto* const event_dispatcher = &(service_provider->event_dispatcher()); -#if defined(__ANDROID__) - auto input = std::make_unique(event_dispatcher); -#elif defined(__CONSOLE__) - auto input = std::make_unique(event_dispatcher); -#else - auto input = std::make_unique(keyboard_settings, event_dispatcher); -#endif - return input; - }, - }, - service_provider->settings_manager().controls() - ); +[[nodiscard]] std::shared_ptr input::InputManager::get_game_input(ServiceProvider* service_provider) { + + + //TODO: select the first suitable + for (const auto& control : service_provider->settings_manager().controls()) { + + return std::visit( + helper::overloaded{ + [service_provider](const input::KeyboardSettings& keyboard_settings + ) mutable -> std::shared_ptr { + auto* const event_dispatcher = &(service_provider->event_dispatcher()); + auto input = + std::make_shared(keyboard_settings, event_dispatcher); + return input; + }, + [service_provider](const input::JoystickSettings& joystick_settings + ) mutable -> std::shared_ptr { + auto* const event_dispatcher = &(service_provider->event_dispatcher()); + auto input = std::make_shared(joystick_settings, event_dispatcher); + return input; + }, + [service_provider](const input::TouchSettings& touch_settings + ) mutable -> std::shared_ptr { + auto* const event_dispatcher = &(service_provider->event_dispatcher()); + auto input = std::make_shared(touch_settings, event_dispatcher); + return input; + } }, + control.content() + ); + } + + return nullptr; } diff --git a/src/input/input.hpp b/src/input/input.hpp index 2427250c..cf4d20b7 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -14,6 +14,7 @@ #include "manager/service_provider.hpp" +#include #include #include @@ -94,7 +95,7 @@ namespace input { [[nodiscard]] helper::BoolWrapper process_special_inputs(const SDL_Event& event); - [[nodiscard]] std::unique_ptr get_game_input(ServiceProvider* service_provider); + [[nodiscard]] std::shared_ptr get_game_input(ServiceProvider* service_provider); [[nodiscard]] const std::unique_ptr& get_primary_input(); }; @@ -103,6 +104,25 @@ namespace input { struct InputSettings { [[nodiscard]] virtual helper::expected validate() const; + + template + [[nodiscard]] helper::expected has_unique_members(const std::vector& to_check) const { + std::vector already_bound{}; + + + for (const auto single_check : to_check) { + + if (std::find(already_bound.cbegin(), already_bound.cend(), single_check) != already_bound.cend()) { + return helper::unexpected{ + fmt::format("KeyCode already bound: '{}'", std::string{ single_check }) + }; + } + + already_bound.push_back(single_check); + } + + return true; + } }; diff --git a/src/input/input_creator.cpp b/src/input/input_creator.cpp index 059b232c..46e41396 100644 --- a/src/input/input_creator.cpp +++ b/src/input/input_creator.cpp @@ -104,7 +104,7 @@ namespace { const tetrion::StartingParameters starting_parameters = { target_fps, seed, starting_level, 0 }; - AdditionalInfo result{ std::move(input), starting_parameters }; + AdditionalInfo result{ input, starting_parameters }; auto tetrion_header = create_tetrion_headers_for_one(result); diff --git a/src/input/input_creator.hpp b/src/input/input_creator.hpp index 940b7d90..82256858 100644 --- a/src/input/input_creator.hpp +++ b/src/input/input_creator.hpp @@ -34,7 +34,7 @@ namespace tetrion { namespace input { - using AdditionalInfo = std::tuple, tetrion::StartingParameters>; + using AdditionalInfo = std::tuple, tetrion::StartingParameters>; [[nodiscard]] std::vector get_game_parameters_for_replay(ServiceProvider* service_provider, const std::filesystem::path& recording_path); diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index b0a11806..c48d487b 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -469,3 +469,24 @@ helper::optional JoystickInput::sdl_event_to_input_event(const SDL_E #endif + + +[[nodiscard]] helper::expected input::JoystickSettings::validate() const { + + const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, + drop, hold, pause, open_settings }; + + return has_unique_members(to_use); +} + + +std::string json_helper::get_key_from_object(const nlohmann::json& j, const std::string& name) { + + auto context = j.at(name); + + std::string input; + context.get_to(input); + + + return input; +} diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index da1ca1c6..cf0dd7ee 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -3,11 +3,13 @@ #include "SDL_joystick.h" #include "helper/expected.hpp" +#include "helper/parse_json.hpp" #include "input.hpp" #include "input/game_input.hpp" #include "manager/event_dispatcher.hpp" #include +#include namespace joystick { struct GUID { @@ -18,6 +20,8 @@ namespace joystick { GUID(); GUID(const SDL_GUID& data); + static helper::expected from_string(const std::string& value); + [[nodiscard]] bool operator==(const GUID& other) const; [[nodiscard]] operator std::string() const; @@ -72,6 +76,34 @@ namespace input { }; + // essentially a GUID + struct JoystickIdentification { + joystick::GUID guid; + + + static helper::expected from_string(const std::string& value); + }; + + //using std::string in here, since we only know, if these are valid joystick button names, after parsing the GUID and than seeing if we support that joystick and than using the string mappings for that specific joystick + struct JoystickSettings : InputSettings { + JoystickIdentification identification; + + std::string rotate_left{}; + std::string rotate_right{}; + std::string move_left{}; + std::string move_right{}; + std::string move_down{}; + std::string drop{}; + std::string hold{}; + + std::string pause{}; + std::string open_settings{}; + + + [[nodiscard]] helper::expected validate() const override; + }; + + //TODO: differntiate different controllers and modes, e.g the switch can have pro controller, the included ones, each of them seperate etc. #if defined(__CONSOLE__) @@ -108,12 +140,14 @@ namespace input { struct JoystickGameInput : public GameInput, public EventListener { private: + JoystickSettings m_settings; std::vector m_event_buffer; EventDispatcher* m_event_dispatcher; public: - JoystickGameInput(EventDispatcher* event_dispatcher) + JoystickGameInput(const JoystickSettings& settings, EventDispatcher* event_dispatcher) : GameInput{ GameInputType::Controller }, + m_settings{ settings }, m_event_dispatcher{ event_dispatcher } { m_event_dispatcher->register_listener(this); } @@ -126,6 +160,10 @@ namespace input { void update(SimulationStep simulation_step_index) override; + [[nodiscard]] helper::optional get_menu_event(const SDL_Event& event) const override; + + [[nodiscard]] std::string describe_menu_event(MenuEvent event) const override; + private: [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event) const; }; @@ -133,6 +171,99 @@ namespace input { } // namespace input +inline void to_json(nlohmann::json& j, const input::JoystickIdentification& identification) { + + j = nlohmann::json{ + { "guid", std::string{ identification.guid } }, + }; +} + + +inline void to_json(nlohmann::json& j, const input::JoystickSettings& settings) { + + auto identification = nlohmann::json{}; + to_json(identification, settings.identification); + + j = nlohmann::json{ + { "identification", identification }, + { "rotate_left", settings.rotate_left }, + { "rotate_right", settings.rotate_right }, + { "move_left", settings.move_left }, + { "move_right", settings.move_right }, + { "move_down", settings.move_down }, + { "drop", settings.drop }, + { "hold", settings.hold }, + { + "menu", nlohmann::json{ + { "pause", settings.pause }, + { "open_settings", settings.open_settings }, + }, } + }; +} + +namespace json_helper { + + + [[nodiscard]] std::string get_key_from_object(const nlohmann::json& j, const std::string& name); + +} // namespace json_helper + + +inline void from_json(const nlohmann::json& j, input::JoystickIdentification& identification) { + + json::check_for_no_additional_keys(j, { "guid" }); + + auto context = j.at("guid"); + + std::string input; + context.get_to(input); + + const auto& value = joystick::GUID::from_string(input); + + if (not value.has_value()) { + throw nlohmann::json::type_error::create( + 302, fmt::format("Expected a valid GUID but got '{}': {}", input, value.error()), &context + ); + } + + identification.guid = value.value(); +} + + +inline void from_json(const nlohmann::json& j, input::JoystickSettings& settings) { + + json::check_for_no_additional_keys( + j, { "type", "identification", "rotate_left", "rotate_right", "move_left", "move_right", "move_down", + "drop", "hold", "menu" } + ); + + input::JoystickIdentification identification{ joystick::GUID{} }; + + from_json(j.at("identification"), identification); + settings.identification = std::move(identification); + + settings.rotate_left = json_helper::get_key_from_object(j, "rotate_left"); + settings.rotate_right = json_helper::get_key_from_object(j, "rotate_right"); + settings.move_left = json_helper::get_key_from_object(j, "move_left"); + settings.move_right = json_helper::get_key_from_object(j, "move_right"); + settings.move_down = json_helper::get_key_from_object(j, "move_down"); + settings.drop = json_helper::get_key_from_object(j, "drop"); + settings.hold = json_helper::get_key_from_object(j, "hold"); + + const auto& menu = j.at("menu"); + + json::check_for_no_additional_keys(menu, { "pause", "open_settings" }); + + settings.pause = json_helper::get_key_from_object(menu, "pause"); + settings.open_settings = json_helper::get_key_from_object(menu, "open_settings"); + + const auto is_valid = settings.validate(); + if (not is_valid.has_value()) { + throw std::runtime_error(is_valid.error()); + } +} + + //TODO: /* #elif defined(__SWITCH__) diff --git a/src/input/keyboard_input.cpp b/src/input/keyboard_input.cpp index 4e6faedb..78f82c0d 100644 --- a/src/input/keyboard_input.cpp +++ b/src/input/keyboard_input.cpp @@ -121,7 +121,7 @@ input::KeyboardGameInput::sdl_event_to_input_event( // NOLINT(readability-functi return helper::nullopt; } -input::KeyboardGameInput::KeyboardGameInput(KeyboardSettings settings, EventDispatcher* event_dispatcher) +input::KeyboardGameInput::KeyboardGameInput(const KeyboardSettings& settings, EventDispatcher* event_dispatcher) : GameInput{ GameInputType::Keyboard }, m_settings{ settings }, m_event_dispatcher{ event_dispatcher } { @@ -131,3 +131,30 @@ input::KeyboardGameInput::KeyboardGameInput(KeyboardSettings settings, EventDisp input::KeyboardGameInput::~KeyboardGameInput() { m_event_dispatcher->unregister_listener(this); } + + +[[nodiscard]] helper::expected input::KeyboardSettings::validate() const { + + const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, + drop, hold, pause, open_settings }; + + return has_unique_members(to_use); +} + +SDL::Key json_helper::get_key(const nlohmann::json& j, const std::string& name) { + + auto context = j.at(name); + + std::string input; + context.get_to(input); + + const auto& value = SDL::Key::from_string(input); + + if (not value.has_value()) { + throw nlohmann::json::type_error::create( + 302, fmt::format("Expected a valid Key for key '{}', but got '{}': {}", name, input, value.error()), + &context + ); + } + return value.value(); +} diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index 46bb4aec..a3608b06 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -8,7 +8,7 @@ #include "manager/event_dispatcher.hpp" #include "manager/sdl_key.hpp" -#include + #include @@ -28,6 +28,7 @@ namespace input { }; + //TODO: don't default initialize all settings, but rather provide a static default setting, so that everything has to be set explicitly, or you can use the default explicitly struct KeyboardSettings : InputSettings { SDL::Key rotate_left = SDL::Key{ SDLK_LEFT }; SDL::Key rotate_right = SDL::Key{ SDLK_RIGHT }; @@ -40,28 +41,8 @@ namespace input { SDL::Key pause = SDL::Key{ SDLK_ESCAPE }; SDL::Key open_settings = SDL::Key{ SDLK_e }; - //TODO: move into cpp - [[nodiscard]] helper::expected validate() const override { - std::vector already_bound_keys{}; - - const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, - drop, hold, pause, open_settings }; - - - for (const auto key_to_use : to_use) { - if (std::find(already_bound_keys.cbegin(), already_bound_keys.cend(), key_to_use) - != already_bound_keys.cend()) { - return helper::unexpected{ - fmt::format("KeyCode already bound: '{}'", key_to_use.name()) - }; - } - - already_bound_keys.push_back(key_to_use); - } - - return true; - } + [[nodiscard]] helper::expected validate() const override; }; @@ -72,7 +53,7 @@ namespace input { EventDispatcher* m_event_dispatcher; public: - KeyboardGameInput(KeyboardSettings settings, EventDispatcher* event_dispatcher); + KeyboardGameInput(const KeyboardSettings& settings, EventDispatcher* event_dispatcher); ~KeyboardGameInput() override; @@ -91,58 +72,50 @@ namespace input { } // namespace input -//TODO port to input_type and let them have Settings that are serialiazable ! - inline void to_json(nlohmann::json& j, const input::KeyboardSettings& settings) { j = nlohmann::json{ - { "rotate_left", settings.rotate_left.name() }, - { "rotate_right", settings.rotate_right.name() }, - { "move_left", settings.move_left.name() }, - { "move_right", settings.move_right.name() }, - { "move_down", settings.move_down.name() }, - { "drop", settings.drop.name() }, - { "hold", settings.hold.name() }, - { "pause", settings.pause.name() }, - { "open_settings", settings.open_settings.name() }, + { "rotate_left", settings.rotate_left.name() }, + { "rotate_right", settings.rotate_right.name() }, + { "move_left", settings.move_left.name() }, + { "move_right", settings.move_right.name() }, + { "move_down", settings.move_down.name() }, + { "drop", settings.drop.name() }, + { "hold", settings.hold.name() }, + { + "menu", nlohmann::json{ + { "pause", settings.pause.name() }, + { "open_settings", settings.open_settings.name() }, + }, } }; } +namespace json_helper { -inline SDL::Key get_key(const nlohmann::json& j, const std::string& name) { - auto context = j.at(name); + [[nodiscard]] SDL::Key get_key(const nlohmann::json& j, const std::string& name); - std::string input; - context.get_to(input); - - //TODO - const auto& value = SDL::Key::from_string(input); - - if (not value.has_value()) { - throw nlohmann::json::type_error::create( - 302, fmt::format("Expected a valid Key from string '{}', but got '{}'", name, input), &context - ); - } - return value.value(); -} +} // namespace json_helper inline void from_json(const nlohmann::json& j, input::KeyboardSettings& settings) { json::check_for_no_additional_keys( - j, { "type", "rotate_left", "rotate_right", "move_left", "move_right", "move_down", "drop", "hold", "pause", - "open_settings" } + j, { "type", "rotate_left", "rotate_right", "move_left", "move_right", "move_down", "drop", "hold", "menu" } ); - settings.rotate_left = get_key(j, "rotate_left"); - settings.rotate_right = get_key(j, "rotate_right"); - settings.move_left = get_key(j, "move_left"); - settings.move_right = get_key(j, "move_right"); - settings.move_down = get_key(j, "move_down"); - settings.drop = get_key(j, "drop"); - settings.hold = get_key(j, "hold"); + settings.rotate_left = json_helper::get_key(j, "rotate_left"); + settings.rotate_right = json_helper::get_key(j, "rotate_right"); + settings.move_left = json_helper::get_key(j, "move_left"); + settings.move_right = json_helper::get_key(j, "move_right"); + settings.move_down = json_helper::get_key(j, "move_down"); + settings.drop = json_helper::get_key(j, "drop"); + settings.hold = json_helper::get_key(j, "hold"); + + const auto& menu = j.at("menu"); + + json::check_for_no_additional_keys(menu, { "pause", "open_settings" }); - settings.pause = get_key(j, "pause"); - settings.open_settings = get_key(j, "open_settings"); + settings.pause = json_helper::get_key(menu, "pause"); + settings.open_settings = json_helper::get_key(menu, "open_settings"); const auto is_valid = settings.validate(); if (not is_valid.has_value()) { diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index c2729cea..aaa54daf 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -4,6 +4,7 @@ #include "touch_input.hpp" #include +#include void input::TouchGameInput::handle_event(const SDL_Event& event) { m_event_buffer.push_back(event); @@ -30,9 +31,6 @@ input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function- // also take into accounts fingerId, since there may be multiple fingers, each finger has it's own saved state const SDL_FingerID finger_id = event.tfinger.fingerId; - // this is used, to get the percentage, since it' all constexpr it's mainly for the developer to not think about percentages but about a pixel range on a certain device, but then it works as expected everywhere - constexpr auto screen_h_reference = 2160.0; - constexpr auto screen_w_reference = 1080.0; if (event.type == SDL_FINGERDOWN) { if (m_finger_state.contains(finger_id) and m_finger_state.at(finger_id).has_value()) { @@ -65,10 +63,6 @@ input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function- const auto y = event.tfinger.y; const auto timestamp = event.tfinger.timestamp; - constexpr auto threshold_x = 150.0 / screen_w_reference; - constexpr auto threshold_y = 400.0 / screen_h_reference; - constexpr auto duration_threshold = 500.0; - constexpr auto duration_drop_threshold = 200.0; const auto dx = x - pressed_state.x; const auto dy = y - pressed_state.y; @@ -77,8 +71,11 @@ input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function- const auto dx_abs = std::fabs(dx); const auto dy_abs = std::fabs(dy); + const auto threshold_x = m_settings.move_x_threshold; + const auto threshold_y = m_settings.move_y_threshold; + m_finger_state.insert_or_assign(finger_id, helper::nullopt); - if (duration < duration_threshold) { + if (duration < m_settings.rotation_duration_threshold) { if (dx_abs < threshold_x and dy_abs < threshold_y) { // tap on the right side of the screen if (x > 0.5) { @@ -102,7 +99,7 @@ input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function- // swipe down if (dy > threshold_y and dx_abs < threshold_x) { // swipe down to drop - if (duration < duration_drop_threshold) { + if (duration < m_settings.drop_duration_threshold) { return InputEvent::DropPressed; } return InputEvent::MoveDownPressed; @@ -123,6 +120,25 @@ input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function- return helper::nullopt; } + +[[nodiscard]] helper::expected input::TouchSettings::validate() const { + + if (move_x_threshold > 1.0 || move_x_threshold < 0.0) { + return helper::unexpected{ + fmt::format("move_x_threshold has to be in range [0,1] but was {}", move_x_threshold) + }; + } + + if (move_y_threshold > 1.0 || move_y_threshold < 0.0) { + return helper::unexpected{ + fmt::format("move_y_threshold has to be in range [0,1] but was {}", move_y_threshold) + }; + } + + return true; +} + + //TODO: /* [[nodiscard]] bool utils::event_is_action(const SDL_Event& event, const CrossPlatformAction action) { diff --git a/src/input/touch_input.hpp b/src/input/touch_input.hpp index 229c6093..aebfb54d 100644 --- a/src/input/touch_input.hpp +++ b/src/input/touch_input.hpp @@ -1,10 +1,12 @@ #pragma once +#include "helper/expected.hpp" +#include "helper/parse_json.hpp" #include "input.hpp" #include "input/game_input.hpp" #include "manager/event_dispatcher.hpp" - +#include namespace input { @@ -23,22 +25,38 @@ namespace input { [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; }; + + struct TouchSettings : InputSettings { + double move_x_threshold{ 150.0 / 2160.0 }; + double move_y_threshold{ 400.0 / 1080.0 }; + + // in ms + u32 rotation_duration_threshold{ 500 }; + u32 drop_duration_threshold{ 200 }; + + [[nodiscard]] helper::expected validate() const override; + }; + + struct PressedState { + Uint32 timestamp; + float x; + float y; + explicit PressedState(Uint32 timestamp, float x, float y) : timestamp{ timestamp }, x{ x }, y{ y } { } + }; + struct TouchGameInput final : public GameInput, public EventListener { + private: - struct PressedState { - Uint32 timestamp; - float x; - float y; - explicit PressedState(Uint32 timestamp, float x, float y) : timestamp{ timestamp }, x{ x }, y{ y } { } - }; + TouchSettings m_settings; std::unordered_map> m_finger_state; std::vector m_event_buffer; EventDispatcher* m_event_dispatcher; public: - explicit TouchGameInput(EventDispatcher* event_dispatcher) + explicit TouchGameInput(const TouchSettings& settings, EventDispatcher* event_dispatcher) : GameInput{ GameInputType::Touch }, + m_settings{ settings }, m_event_dispatcher{ event_dispatcher } { m_event_dispatcher->register_listener(this); } @@ -61,6 +79,99 @@ namespace input { } // namespace input +inline void to_json(nlohmann::json& j, const input::TouchSettings& settings) { + j = nlohmann::json{ + { "move_x_threshold", settings.move_x_threshold }, + { "move_y_threshold", settings.move_y_threshold }, + { "rotation_duration_threshold", settings.rotation_duration_threshold }, + { "drop_duration_threshold", settings.drop_duration_threshold }, + }; +} + +namespace json_helper { + + template + concept IsNumeric = std::is_arithmetic_v; + + + template + [[nodiscard]] T get_number(const nlohmann::json& j, const std::string& name) { + + helper::expected error = true; + + auto context = j.at(name); + + + if (not context.is_number()) { + error = helper::unexpected{ fmt::format("Not a number but: {}", context.type_name()) }; + } + + if (error.has_value()) { + + + // integers are checked explicitly, floating points are just retrieved vai get_to, which may convert numbers, but converting from int to floating point is always fine + + if constexpr (std::numeric_limits::is_integer) { + + if (not context.is_number_integer()) { + error = helper::unexpected{ "Not an integer" }; + } else { + if constexpr (not std::numeric_limits::is_signed) { + if (not context.is_number_unsigned()) { + error = helper::unexpected{ "Not an unsigned integer" }; + } + } + } + } + } + + if (not error.has_value()) { + + throw nlohmann::json::type_error::create( + 302, + fmt::format( + "Expected a valid number of type '{}' for key '{}' but an error occurred: {}", + typeid(T).name(), name, error.error() + ), + &context + ); + } + + T input; + context.get_to(input); + + + return input; + } + +} // namespace json_helper + +inline void from_json(const nlohmann::json& j, input::TouchSettings& settings) { + + json::check_for_no_additional_keys( + j, + { + "type", + "move_x_threshold", + "move_y_threshold", + "rotation_duration_threshold", + "drop_duration_threshold", + } + ); + + settings.move_x_threshold = json_helper::get_number(j, "move_x_threshold"); + settings.move_y_threshold = json_helper::get_number(j, "move_y_threshold"); + settings.rotation_duration_threshold = json_helper::get_number(j, "rotation_duration_threshold"); + settings.drop_duration_threshold = json_helper::get_number(j, "drop_duration_threshold"); + + + const auto is_valid = settings.validate(); + if (not is_valid.has_value()) { + throw std::runtime_error(is_valid.error()); + } +} + + //TODO: /* diff --git a/src/manager/sdl_key.hpp b/src/manager/sdl_key.hpp index 0c1d3cd1..010b183a 100644 --- a/src/manager/sdl_key.hpp +++ b/src/manager/sdl_key.hpp @@ -48,6 +48,7 @@ namespace SDL { explicit Key(SDL_KeyCode keycode, const std::vector& modifiers = {}); explicit Key(const SDL_Keysym& keysym); + //TODO: also parse modifiers according to some format (E.g " + + ") static helper::expected from_string(const std::string& value, const std::vector& modifiers = {}); @@ -58,8 +59,11 @@ namespace SDL { [[nodiscard]] bool operator==(const Key& other) const; + //TODO: also add function, to serialize the modifiers too [[nodiscard]] std::string name() const; + [[nodiscard]] operator std::string() const; + private: [[nodiscard]] static helper::expected sdl_keycode_from_string(const std::string& value ); diff --git a/src/manager/settings_manager.cpp b/src/manager/settings_manager.cpp index d9835b69..4ea5f7ac 100644 --- a/src/manager/settings_manager.cpp +++ b/src/manager/settings_manager.cpp @@ -16,6 +16,53 @@ SettingsManager::SettingsManager(ServiceProvider* service_provider) : m_service_ spdlog::warn("applying default settings"); //TODO: better default settings - m_current_settings = detail::Settings{ input::KeyboardSettings{}, 1.0 }; + m_current_settings = { + detail::Settings{ { Controls{ input::KeyboardSettings{} } }, 1.0 } + }; + } +} + + +void to_json(nlohmann::json& j, const Controls& controls) { + std::visit( + helper::overloaded{ [&](const input::KeyboardSettings& keyboard_settings) { + to_json(j, keyboard_settings); + j["type"] = "keyboard"; + }, + [&](const input::JoystickSettings& joystick_settings) { + to_json(j, joystick_settings); + j["type"] = "joystick"; + }, + [&](const input::TouchSettings& touch_settings) { + to_json(j, touch_settings); + j["type"] = "touch"; + } }, + controls.content() + ); +} + + +void from_json(const nlohmann::json& j, Controls& controls) { + const auto& type = j.at("type"); + + if (type == "keyboard") { + input::KeyboardSettings keyboard_settings{}; + from_json(j, keyboard_settings); + controls = std::move(keyboard_settings); + } else if (type == "joystick") { + input::JoystickSettings joystick_settings{}; + from_json(j, joystick_settings); + controls = std::move(joystick_settings); + } else if (type == "touch") { + input::TouchSettings touch_settings{}; + from_json(j, touch_settings); + controls = std::move(touch_settings); + } else { + throw std::runtime_error{ fmt::format("unsupported control type '{}'", to_string(type)) }; + } + + // security check, since we allow an empty variant here, since its required by the json interface to be default constructible + if (controls.content().valueless_by_exception()) { + throw std::runtime_error{ "invalid variant state: valueless" }; } } diff --git a/src/manager/settings_manager.hpp b/src/manager/settings_manager.hpp index ed2c1bf3..761b3eab 100644 --- a/src/manager/settings_manager.hpp +++ b/src/manager/settings_manager.hpp @@ -1,43 +1,39 @@ #pragma once - -#include "helper/magic_enum_wrapper.hpp" -#include "helper/parse_json.hpp" -#include "helper/platform.hpp" +#include "input/joystick_input.hpp" #include "input/keyboard_input.hpp" +#include "input/touch_input.hpp" #include "manager/service_provider.hpp" #include -#include #include +struct Controls { +private: + using Type = std::variant; + Type m_content; + +public: + // default constructor is need for deserialization + Controls() : m_content{} { } + template + explicit Controls(T content) : m_content{ std::move(content) } { + // + } -using Controls = std::variant; - -inline void to_json(nlohmann::json& j, const Controls& controls) { - std::visit( - helper::overloaded{ - [&](const input::KeyboardSettings& keyboard_controls) { - to_json(j, keyboard_controls); - j["type"] = "keyboard"; - }, - }, - controls - ); -} - -inline void from_json(const nlohmann::json& j, Controls& controls) { - const auto& type = j.at("type"); - - if (type == "keyboard") { - input::KeyboardSettings keyboard_controls{}; - from_json(j, keyboard_controls); - controls = keyboard_controls; - } else { - throw std::runtime_error{ fmt::format("unsupported control type '{}'", to_string(type)) }; + template + Controls& operator=(T&& content) { + m_content = std::move(content); + return *this; } -} + [[nodiscard]] const Type& content() const; +}; + + +void to_json(nlohmann::json& j, const Controls& controls); + +void from_json(const nlohmann::json& j, Controls& controls); namespace detail { @@ -45,13 +41,13 @@ namespace detail { struct Settings { - Controls controls; + std::vector controls; float volume{ 0.2f }; bool discord{ false }; //changing this requires a restart }; - NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Settings, volume, discord) + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Settings, controls, volume, discord) } // namespace detail From bd8dfbbdb52af9af32feb47224a8401e526c2ffd Mon Sep 17 00:00:00 2001 From: Totto16 Date: Sun, 5 May 2024 16:56:15 +0200 Subject: [PATCH 04/76] make settings non default constructible, and move them around while serializing / deserializing them --- src/input/input.cpp | 2 +- src/input/input.hpp | 4 +- src/input/joystick_input.cpp | 14 ++- src/input/joystick_input.hpp | 194 +++++++++++++++++-------------- src/input/keyboard_input.cpp | 3 +- src/input/keyboard_input.hpp | 143 ++++++++++++++--------- src/input/touch_input.hpp | 91 +++++++++------ src/manager/settings_manager.cpp | 47 +------- src/manager/settings_manager.hpp | 63 ++++++---- 9 files changed, 305 insertions(+), 256 deletions(-) diff --git a/src/input/input.cpp b/src/input/input.cpp index 54a7c694..6fb6cd58 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -142,7 +142,7 @@ input::InputManager::~InputManager() = default; auto input = std::make_shared(touch_settings, event_dispatcher); return input; } }, - control.content() + control ); } diff --git a/src/input/input.hpp b/src/input/input.hpp index cf4d20b7..149f0c73 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -103,10 +103,8 @@ namespace input { struct InputSettings { - [[nodiscard]] virtual helper::expected validate() const; - template - [[nodiscard]] helper::expected has_unique_members(const std::vector& to_check) const { + [[nodiscard]] static helper::expected has_unique_members(const std::vector& to_check) { std::vector already_bound{}; diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index c48d487b..81747158 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -6,16 +6,24 @@ #include "helper/optional.hpp" #include "input/input.hpp" +#include #include #include #include -joystick::GUID::GUID() : m_guid{} { } joystick::GUID::GUID(const SDL_GUID& data) : m_guid{} { std::copy(std::begin(data.data), std::end(data.data), std::begin(m_guid)); } +joystick::GUID::GUID(const ArrayType& data) : m_guid{ data } { } + + +joystick::GUID joystick::GUID::zero() { + return joystick::GUID{ joystick::GUID::ArrayType{} }; +} + + [[nodiscard]] bool joystick::GUID::operator==(const GUID& other) const { return this->m_guid == other.m_guid; } @@ -92,7 +100,7 @@ input::JoystickInput::get_by_device_index(int device_index) { const auto guid = joystick::GUID{ SDL_JoystickGetGUID(joystick) }; - if (guid == joystick::GUID{}) { + if (guid == joystick::GUID::zero()) { return helper::unexpected{ fmt::format("Failed to get joystick GUID: {}", SDL_GetError()) }; } @@ -476,7 +484,7 @@ helper::optional JoystickInput::sdl_event_to_input_event(const SDL_E const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, drop, hold, pause, open_settings }; - return has_unique_members(to_use); + return input::InputSettings::has_unique_members(to_use); } diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index cf0dd7ee..2d362c8e 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -14,13 +14,16 @@ namespace joystick { struct GUID { private: - std::array m_guid; + using ArrayType = std::array; + ArrayType m_guid; public: - GUID(); GUID(const SDL_GUID& data); + GUID(const ArrayType& data); - static helper::expected from_string(const std::string& value); + [[nodiscard]] static GUID zero(); + + [[nodiscard]] static helper::expected from_string(const std::string& value); [[nodiscard]] bool operator==(const GUID& other) const; @@ -85,22 +88,22 @@ namespace input { }; //using std::string in here, since we only know, if these are valid joystick button names, after parsing the GUID and than seeing if we support that joystick and than using the string mappings for that specific joystick - struct JoystickSettings : InputSettings { + struct JoystickSettings { JoystickIdentification identification; - std::string rotate_left{}; - std::string rotate_right{}; - std::string move_left{}; - std::string move_right{}; - std::string move_down{}; - std::string drop{}; - std::string hold{}; + std::string rotate_left; + std::string rotate_right; + std::string move_left; + std::string move_right; + std::string move_down; + std::string drop; + std::string hold; - std::string pause{}; - std::string open_settings{}; + std::string pause; + std::string open_settings; - [[nodiscard]] helper::expected validate() const override; + [[nodiscard]] helper::expected validate() const; }; @@ -171,36 +174,6 @@ namespace input { } // namespace input -inline void to_json(nlohmann::json& j, const input::JoystickIdentification& identification) { - - j = nlohmann::json{ - { "guid", std::string{ identification.guid } }, - }; -} - - -inline void to_json(nlohmann::json& j, const input::JoystickSettings& settings) { - - auto identification = nlohmann::json{}; - to_json(identification, settings.identification); - - j = nlohmann::json{ - { "identification", identification }, - { "rotate_left", settings.rotate_left }, - { "rotate_right", settings.rotate_right }, - { "move_left", settings.move_left }, - { "move_right", settings.move_right }, - { "move_down", settings.move_down }, - { "drop", settings.drop }, - { "hold", settings.hold }, - { - "menu", nlohmann::json{ - { "pause", settings.pause }, - { "open_settings", settings.open_settings }, - }, } - }; -} - namespace json_helper { @@ -209,59 +182,106 @@ namespace json_helper { } // namespace json_helper -inline void from_json(const nlohmann::json& j, input::JoystickIdentification& identification) { - - json::check_for_no_additional_keys(j, { "guid" }); - - auto context = j.at("guid"); - - std::string input; - context.get_to(input); - - const auto& value = joystick::GUID::from_string(input); - - if (not value.has_value()) { - throw nlohmann::json::type_error::create( - 302, fmt::format("Expected a valid GUID but got '{}': {}", input, value.error()), &context - ); - } - - identification.guid = value.value(); -} +namespace nlohmann { + template<> + struct adl_serializer { + static input::JoystickIdentification from_json(const json& j) { -inline void from_json(const nlohmann::json& j, input::JoystickSettings& settings) { + ::json::check_for_no_additional_keys(j, { "guid" }); - json::check_for_no_additional_keys( - j, { "type", "identification", "rotate_left", "rotate_right", "move_left", "move_right", "move_down", - "drop", "hold", "menu" } - ); + auto context = j.at("guid"); - input::JoystickIdentification identification{ joystick::GUID{} }; + std::string input; + context.get_to(input); - from_json(j.at("identification"), identification); - settings.identification = std::move(identification); + const auto& value = joystick::GUID::from_string(input); - settings.rotate_left = json_helper::get_key_from_object(j, "rotate_left"); - settings.rotate_right = json_helper::get_key_from_object(j, "rotate_right"); - settings.move_left = json_helper::get_key_from_object(j, "move_left"); - settings.move_right = json_helper::get_key_from_object(j, "move_right"); - settings.move_down = json_helper::get_key_from_object(j, "move_down"); - settings.drop = json_helper::get_key_from_object(j, "drop"); - settings.hold = json_helper::get_key_from_object(j, "hold"); + if (not value.has_value()) { + throw nlohmann::json::type_error::create( + 302, fmt::format("Expected a valid GUID but got '{}': {}", input, value.error()), &context + ); + } - const auto& menu = j.at("menu"); + return input::JoystickIdentification{ .guid = value.value() }; + } - json::check_for_no_additional_keys(menu, { "pause", "open_settings" }); + static void to_json(json& j, const input::JoystickIdentification& identification) { + j = nlohmann::json{ + { "guid", std::string{ identification.guid } }, + }; + } + }; - settings.pause = json_helper::get_key_from_object(menu, "pause"); - settings.open_settings = json_helper::get_key_from_object(menu, "open_settings"); + template<> + struct adl_serializer { + static input::JoystickSettings from_json(const json& j) { + + ::json::check_for_no_additional_keys( + j, { "type", "identification", "rotate_left", "rotate_right", "move_left", "move_right", + "move_down", "drop", "hold", "menu" } + ); + + input::JoystickIdentification identification = + adl_serializer::from_json(j.at("identification")); + + const auto rotate_left = json_helper::get_key_from_object(j, "rotate_left"); + const auto rotate_right = json_helper::get_key_from_object(j, "rotate_right"); + const auto move_left = json_helper::get_key_from_object(j, "move_left"); + const auto move_right = json_helper::get_key_from_object(j, "move_right"); + const auto move_down = json_helper::get_key_from_object(j, "move_down"); + const auto drop = json_helper::get_key_from_object(j, "drop"); + const auto hold = json_helper::get_key_from_object(j, "hold"); + + const auto& menu = j.at("menu"); + + ::json::check_for_no_additional_keys(menu, { "pause", "open_settings" }); + + const auto pause = json_helper::get_key_from_object(menu, "pause"); + const auto open_settings = json_helper::get_key_from_object(menu, "open_settings"); + + auto settings = input::JoystickSettings{ .identification = identification, + .rotate_left = rotate_left, + .rotate_right = rotate_right, + .move_left = move_left, + .move_right = move_right, + .move_down = move_down, + .drop = drop, + .hold = hold, + .pause = pause, + .open_settings = open_settings }; + + const auto is_valid = settings.validate(); + if (not is_valid.has_value()) { + throw std::runtime_error(is_valid.error()); + } + + return settings; + } - const auto is_valid = settings.validate(); - if (not is_valid.has_value()) { - throw std::runtime_error(is_valid.error()); - } -} + static void to_json(json& j, const input::JoystickSettings& settings) { + + auto identification = nlohmann::json{}; + adl_serializer::to_json(identification, settings.identification); + + j = nlohmann::json{ + { "identification", identification }, + { "rotate_left", settings.rotate_left }, + { "rotate_right", settings.rotate_right }, + { "move_left", settings.move_left }, + { "move_right", settings.move_right }, + { "move_down", settings.move_down }, + { "drop", settings.drop }, + { "hold", settings.hold }, + { + "menu", nlohmann::json{ + { "pause", settings.pause }, + { "open_settings", settings.open_settings }, + }, } + }; + } + }; +} // namespace nlohmann //TODO: diff --git a/src/input/keyboard_input.cpp b/src/input/keyboard_input.cpp index 78f82c0d..64374cd6 100644 --- a/src/input/keyboard_input.cpp +++ b/src/input/keyboard_input.cpp @@ -1,5 +1,6 @@ #include "keyboard_input.hpp" #include "SDL_keycode.h" +#include "input/input.hpp" input::KeyboardInput::KeyboardInput() : input::Input{ "keyboard", InputType::Keyboard } { } @@ -138,7 +139,7 @@ input::KeyboardGameInput::~KeyboardGameInput() { const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, drop, hold, pause, open_settings }; - return has_unique_members(to_use); + return input::InputSettings::has_unique_members(to_use); } SDL::Key json_helper::get_key(const nlohmann::json& j, const std::string& name) { diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index a3608b06..4799486d 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -29,20 +29,32 @@ namespace input { //TODO: don't default initialize all settings, but rather provide a static default setting, so that everything has to be set explicitly, or you can use the default explicitly - struct KeyboardSettings : InputSettings { - SDL::Key rotate_left = SDL::Key{ SDLK_LEFT }; - SDL::Key rotate_right = SDL::Key{ SDLK_RIGHT }; - SDL::Key move_left = SDL::Key{ SDLK_a }; - SDL::Key move_right = SDL::Key{ SDLK_d }; - SDL::Key move_down = SDL::Key{ SDLK_a }; - SDL::Key drop = SDL::Key{ SDLK_s }; - SDL::Key hold = SDL::Key{ SDLK_TAB }; - - SDL::Key pause = SDL::Key{ SDLK_ESCAPE }; - SDL::Key open_settings = SDL::Key{ SDLK_e }; - - - [[nodiscard]] helper::expected validate() const override; + struct KeyboardSettings { + SDL::Key rotate_left; + SDL::Key rotate_right; + SDL::Key move_left; + SDL::Key move_right; + SDL::Key move_down; + SDL::Key drop; + SDL::Key hold; + + SDL::Key pause; + SDL::Key open_settings; + + + [[nodiscard]] helper::expected validate() const; + + [[nodiscard]] static KeyboardSettings default_settings() { + return KeyboardSettings{ .rotate_left = SDL::Key{ SDLK_LEFT }, + .rotate_right = SDL::Key{ SDLK_RIGHT }, + .move_left = SDL::Key{ SDLK_a }, + .move_right = SDL::Key{ SDLK_d }, + .move_down = SDL::Key{ SDLK_a }, + .drop = SDL::Key{ SDLK_s }, + .hold = SDL::Key{ SDLK_TAB }, + .pause = SDL::Key{ SDLK_ESCAPE }, + .open_settings = SDL::Key{ SDLK_e } }; + } }; @@ -72,23 +84,6 @@ namespace input { } // namespace input -inline void to_json(nlohmann::json& j, const input::KeyboardSettings& settings) { - j = nlohmann::json{ - { "rotate_left", settings.rotate_left.name() }, - { "rotate_right", settings.rotate_right.name() }, - { "move_left", settings.move_left.name() }, - { "move_right", settings.move_right.name() }, - { "move_down", settings.move_down.name() }, - { "drop", settings.drop.name() }, - { "hold", settings.hold.name() }, - { - "menu", nlohmann::json{ - { "pause", settings.pause.name() }, - { "open_settings", settings.open_settings.name() }, - }, } - }; -} - namespace json_helper { @@ -96,29 +91,65 @@ namespace json_helper { } // namespace json_helper -inline void from_json(const nlohmann::json& j, input::KeyboardSettings& settings) { - - json::check_for_no_additional_keys( - j, { "type", "rotate_left", "rotate_right", "move_left", "move_right", "move_down", "drop", "hold", "menu" } - ); - settings.rotate_left = json_helper::get_key(j, "rotate_left"); - settings.rotate_right = json_helper::get_key(j, "rotate_right"); - settings.move_left = json_helper::get_key(j, "move_left"); - settings.move_right = json_helper::get_key(j, "move_right"); - settings.move_down = json_helper::get_key(j, "move_down"); - settings.drop = json_helper::get_key(j, "drop"); - settings.hold = json_helper::get_key(j, "hold"); - - const auto& menu = j.at("menu"); - - json::check_for_no_additional_keys(menu, { "pause", "open_settings" }); - - settings.pause = json_helper::get_key(menu, "pause"); - settings.open_settings = json_helper::get_key(menu, "open_settings"); - - const auto is_valid = settings.validate(); - if (not is_valid.has_value()) { - throw std::runtime_error(is_valid.error()); - } -} +namespace nlohmann { + template<> + struct adl_serializer { + static input::KeyboardSettings from_json(const json& j) { + + ::json::check_for_no_additional_keys( + j, { "type", "rotate_left", "rotate_right", "move_left", "move_right", "move_down", "drop", "hold", + "menu" } + ); + + const auto rotate_left = json_helper::get_key(j, "rotate_left"); + const auto rotate_right = json_helper::get_key(j, "rotate_right"); + const auto move_left = json_helper::get_key(j, "move_left"); + const auto move_right = json_helper::get_key(j, "move_right"); + const auto move_down = json_helper::get_key(j, "move_down"); + const auto drop = json_helper::get_key(j, "drop"); + const auto hold = json_helper::get_key(j, "hold"); + + const auto& menu = j.at("menu"); + + ::json::check_for_no_additional_keys(menu, { "pause", "open_settings" }); + + const auto pause = json_helper::get_key(menu, "pause"); + const auto open_settings = json_helper::get_key(menu, "open_settings"); + + auto settings = input::KeyboardSettings{ .rotate_left = rotate_left, + .rotate_right = rotate_right, + .move_left = move_left, + .move_right = move_right, + .move_down = move_down, + .drop = drop, + .hold = hold, + .pause = pause, + .open_settings = open_settings }; + + const auto is_valid = settings.validate(); + if (not is_valid.has_value()) { + throw std::runtime_error(is_valid.error()); + } + + return settings; + } + + static void to_json(json& j, const input::KeyboardSettings& settings) { + j = nlohmann::json{ + { "rotate_left", settings.rotate_left.name() }, + { "rotate_right", settings.rotate_right.name() }, + { "move_left", settings.move_left.name() }, + { "move_right", settings.move_right.name() }, + { "move_down", settings.move_down.name() }, + { "drop", settings.drop.name() }, + { "hold", settings.hold.name() }, + { + "menu", nlohmann::json{ + { "pause", settings.pause.name() }, + { "open_settings", settings.open_settings.name() }, + }, } + }; + } + }; +} // namespace nlohmann diff --git a/src/input/touch_input.hpp b/src/input/touch_input.hpp index aebfb54d..9d39ecc3 100644 --- a/src/input/touch_input.hpp +++ b/src/input/touch_input.hpp @@ -26,15 +26,22 @@ namespace input { }; - struct TouchSettings : InputSettings { - double move_x_threshold{ 150.0 / 2160.0 }; - double move_y_threshold{ 400.0 / 1080.0 }; + struct TouchSettings { + double move_x_threshold; + double move_y_threshold; // in ms - u32 rotation_duration_threshold{ 500 }; - u32 drop_duration_threshold{ 200 }; + u32 rotation_duration_threshold; + u32 drop_duration_threshold; - [[nodiscard]] helper::expected validate() const override; + [[nodiscard]] helper::expected validate() const; + + [[nodiscard]] static TouchSettings default_settings() { + return TouchSettings{ .move_x_threshold = 150.0 / 2160.0, + .move_y_threshold = 400.0 / 1080.0, + .rotation_duration_threshold = 500, + .drop_duration_threshold = 200 }; + } }; struct PressedState { @@ -79,15 +86,6 @@ namespace input { } // namespace input -inline void to_json(nlohmann::json& j, const input::TouchSettings& settings) { - j = nlohmann::json{ - { "move_x_threshold", settings.move_x_threshold }, - { "move_y_threshold", settings.move_y_threshold }, - { "rotation_duration_threshold", settings.rotation_duration_threshold }, - { "drop_duration_threshold", settings.drop_duration_threshold }, - }; -} - namespace json_helper { template @@ -146,30 +144,55 @@ namespace json_helper { } // namespace json_helper -inline void from_json(const nlohmann::json& j, input::TouchSettings& settings) { - json::check_for_no_additional_keys( - j, - { - "type", - "move_x_threshold", - "move_y_threshold", - "rotation_duration_threshold", - "drop_duration_threshold", +namespace nlohmann { + template<> + struct adl_serializer { + static input::TouchSettings from_json(const json& j) { + + + ::json::check_for_no_additional_keys( + j, + { + "type", + "move_x_threshold", + "move_y_threshold", + "rotation_duration_threshold", + "drop_duration_threshold", + } + ); + + const auto move_x_threshold = json_helper::get_number(j, "move_x_threshold"); + const auto move_y_threshold = json_helper::get_number(j, "move_y_threshold"); + + const auto rotation_duration_threshold = json_helper::get_number(j, "rotation_duration_threshold"); + const auto drop_duration_threshold = json_helper::get_number(j, "drop_duration_threshold"); + + auto settings = input::TouchSettings{ .move_x_threshold = move_x_threshold, + .move_y_threshold = move_y_threshold, + .rotation_duration_threshold = rotation_duration_threshold, + .drop_duration_threshold = drop_duration_threshold }; + + + const auto is_valid = settings.validate(); + if (not is_valid.has_value()) { + throw std::runtime_error(is_valid.error()); } - ); - settings.move_x_threshold = json_helper::get_number(j, "move_x_threshold"); - settings.move_y_threshold = json_helper::get_number(j, "move_y_threshold"); - settings.rotation_duration_threshold = json_helper::get_number(j, "rotation_duration_threshold"); - settings.drop_duration_threshold = json_helper::get_number(j, "drop_duration_threshold"); + return settings; + } + static void to_json(json& j, const input::TouchSettings& settings) { - const auto is_valid = settings.validate(); - if (not is_valid.has_value()) { - throw std::runtime_error(is_valid.error()); - } -} + j = nlohmann::json{ + { "move_x_threshold", settings.move_x_threshold }, + { "move_y_threshold", settings.move_y_threshold }, + { "rotation_duration_threshold", settings.rotation_duration_threshold }, + { "drop_duration_threshold", settings.drop_duration_threshold }, + }; + } + }; +} // namespace nlohmann //TODO: diff --git a/src/manager/settings_manager.cpp b/src/manager/settings_manager.cpp index 4ea5f7ac..322f6553 100644 --- a/src/manager/settings_manager.cpp +++ b/src/manager/settings_manager.cpp @@ -17,52 +17,7 @@ SettingsManager::SettingsManager(ServiceProvider* service_provider) : m_service_ //TODO: better default settings m_current_settings = { - detail::Settings{ { Controls{ input::KeyboardSettings{} } }, 1.0 } + detail::Settings{ {}, 1.0 } }; } } - - -void to_json(nlohmann::json& j, const Controls& controls) { - std::visit( - helper::overloaded{ [&](const input::KeyboardSettings& keyboard_settings) { - to_json(j, keyboard_settings); - j["type"] = "keyboard"; - }, - [&](const input::JoystickSettings& joystick_settings) { - to_json(j, joystick_settings); - j["type"] = "joystick"; - }, - [&](const input::TouchSettings& touch_settings) { - to_json(j, touch_settings); - j["type"] = "touch"; - } }, - controls.content() - ); -} - - -void from_json(const nlohmann::json& j, Controls& controls) { - const auto& type = j.at("type"); - - if (type == "keyboard") { - input::KeyboardSettings keyboard_settings{}; - from_json(j, keyboard_settings); - controls = std::move(keyboard_settings); - } else if (type == "joystick") { - input::JoystickSettings joystick_settings{}; - from_json(j, joystick_settings); - controls = std::move(joystick_settings); - } else if (type == "touch") { - input::TouchSettings touch_settings{}; - from_json(j, touch_settings); - controls = std::move(touch_settings); - } else { - throw std::runtime_error{ fmt::format("unsupported control type '{}'", to_string(type)) }; - } - - // security check, since we allow an empty variant here, since its required by the json interface to be default constructible - if (controls.content().valueless_by_exception()) { - throw std::runtime_error{ "invalid variant state: valueless" }; - } -} diff --git a/src/manager/settings_manager.hpp b/src/manager/settings_manager.hpp index 761b3eab..2ec9f535 100644 --- a/src/manager/settings_manager.hpp +++ b/src/manager/settings_manager.hpp @@ -8,32 +8,45 @@ #include #include -struct Controls { -private: - using Type = std::variant; - Type m_content; - -public: - // default constructor is need for deserialization - Controls() : m_content{} { } - template - explicit Controls(T content) : m_content{ std::move(content) } { - // - } - - template - Controls& operator=(T&& content) { - m_content = std::move(content); - return *this; - } - - [[nodiscard]] const Type& content() const; -}; - - -void to_json(nlohmann::json& j, const Controls& controls); +using Controls = std::variant; + +namespace nlohmann { + template<> + struct adl_serializer { + static Controls from_json(const json& j) { + const auto& type = j.at("type"); + + if (type == "keyboard") { + return Controls{ nlohmann::adl_serializer::from_json(j) }; + } else if (type == "joystick") { + return Controls{ nlohmann::adl_serializer::from_json(j) }; + } else if (type == "touch") { + return Controls{ nlohmann::adl_serializer::from_json(j) }; + } else { + throw std::runtime_error{ fmt::format("unsupported control type '{}'", to_string(type)) }; + } + } + + static void to_json(json& j, Controls controls) { + std::visit( + helper::overloaded{ [&](const input::KeyboardSettings& keyboard_settings) { + to_json(j, keyboard_settings); + j["type"] = "keyboard"; + }, + [&](const input::JoystickSettings& joystick_settings) { + to_json(j, joystick_settings); + j["type"] = "joystick"; + }, + [&](const input::TouchSettings& touch_settings) { + to_json(j, touch_settings); + j["type"] = "touch"; + } }, + controls + ); + } + }; +} // namespace nlohmann -void from_json(const nlohmann::json& j, Controls& controls); namespace detail { From ad39a002026dae698b53deef39f7127e525b2f4e Mon Sep 17 00:00:00 2001 From: Totto16 Date: Sun, 5 May 2024 17:12:32 +0200 Subject: [PATCH 05/76] implement offset_pointer_event for pointer inputs --- src/input/input.cpp | 15 +++++++++ src/input/input.hpp | 13 ++++++-- src/input/mouse_input.cpp | 23 +++++++++++++ src/input/mouse_input.hpp | 7 ++-- src/input/touch_input.cpp | 23 +++++++++++++ src/input/touch_input.hpp | 55 ++------------------------------ src/ui/layouts/scroll_layout.cpp | 2 +- 7 files changed, 80 insertions(+), 58 deletions(-) diff --git a/src/input/input.cpp b/src/input/input.cpp index 6fb6cd58..c297a29e 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -9,6 +9,7 @@ #include #include #include +#include [[nodiscard]] bool input::PointerEventHelper::is_in(const shapes::URect& rect) const { @@ -85,6 +86,20 @@ input::InputManager::~InputManager() = default; } +[[nodiscard]] SDL_Event input::InputManager::offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) + const { + for (const auto& input : m_inputs) { + if (const auto pointer_input = utils::is_child_class(input); pointer_input.has_value()) { + if (const auto pointer_event = pointer_input.value()->get_pointer_event(event); pointer_event.has_value()) { + return pointer_input.value()->offset_pointer_event(event, point); + } + } + } + + throw std::runtime_error("Tried to offset event, that is no pointer event"); +} + + [[nodiscard]] helper::BoolWrapper input::InputManager::process_special_inputs( const SDL_Event& event ) { diff --git a/src/input/input.hpp b/src/input/input.hpp index 149f0c73..878a4e24 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -62,8 +62,6 @@ namespace input { [[nodiscard]] bool is_in(const shapes::IRect& rect) const; - [[nodiscard]] SDL_Event offset_raw(const SDL_Event& event, const shapes::IPoint& rect) const; - [[nodiscard]] bool operator==(PointerEvent event) const; }; @@ -72,6 +70,8 @@ namespace input { PointerInput(const std::string& name); [[nodiscard]] virtual helper::optional get_pointer_event(const SDL_Event& event) const = 0; + + [[nodiscard]] virtual SDL_Event offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) const = 0; }; //forward declaration @@ -93,6 +93,15 @@ namespace input { [[nodiscard]] helper::optional get_pointer_event(const SDL_Event& event) const; + /** + * @brief Offsets a pointer event, only safe to call, if get_pointer_event returns a non null optional + * + * @param event the original SDL Event + * @param point the point to offset it by + * @return SDL_Event which has the correct offset + */ + [[nodiscard]] SDL_Event offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) const; + [[nodiscard]] helper::BoolWrapper process_special_inputs(const SDL_Event& event); [[nodiscard]] std::shared_ptr get_game_input(ServiceProvider* service_provider); diff --git a/src/input/mouse_input.cpp b/src/input/mouse_input.cpp index d3a01039..24747ae6 100644 --- a/src/input/mouse_input.cpp +++ b/src/input/mouse_input.cpp @@ -3,6 +3,29 @@ #include "mouse_input.hpp" +[[nodiscard]] SDL_Event input::MouseInput::offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) + const { + + auto new_event = event; + + switch (event.type) { + case SDL_MOUSEMOTION: + new_event.motion.x = event.motion.x + point.x; + new_event.motion.y = event.motion.y + point.y; + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + new_event.button.x = event.button.x + point.x; + new_event.button.y = event.button.y + point.y; + break; + default: + throw std::runtime_error("Tried to offset event, that is no pointer event: in Mouse Input"); + } + + return new_event; +} + + //TODO: /* [[nodiscard]] bool utils::event_is_click_event(const SDL_Event& event, CrossPlatformClickEvent click_type) { diff --git a/src/input/mouse_input.hpp b/src/input/mouse_input.hpp index 961b8731..bc4baa36 100644 --- a/src/input/mouse_input.hpp +++ b/src/input/mouse_input.hpp @@ -14,12 +14,13 @@ namespace input { [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; + [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; + [[nodiscard]] helper::optional get_pointer_event(const SDL_Event& event) const override; - [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; + [[nodiscard]] SDL_Event offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) + const override; }; } // namespace input - - diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index aaa54daf..162c7663 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -139,6 +139,29 @@ input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function- } +[[nodiscard]] SDL_Event input::TouchInput::offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) + const { + + + auto new_event = event; + + if (event.type != SDL_FINGERMOTION and event.type != SDL_FINGERDOWN and event.type != SDL_FINGERUP) { + throw std::runtime_error("Tried to offset event, that is no pointer event: in Touch Input"); + } + + + const double x_percent = event.tfinger.x; + const double y_percent = event.tfinger.y; + + const auto window_size = m_window->size(); + + new_event.tfinger.x = x_percent + static_cast(point.x) / static_cast(window_size.x); + new_event.tfinger.y = y_percent + static_cast(point.y) / static_cast(window_size.y); + + return new_event; +} + + //TODO: /* [[nodiscard]] bool utils::event_is_action(const SDL_Event& event, const CrossPlatformAction action) { diff --git a/src/input/touch_input.hpp b/src/input/touch_input.hpp index 9d39ecc3..3c5c869b 100644 --- a/src/input/touch_input.hpp +++ b/src/input/touch_input.hpp @@ -20,9 +20,11 @@ namespace input { [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; + [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; + [[nodiscard]] helper::optional get_pointer_event(const SDL_Event& event) const override; - [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; + [[nodiscard]] SDL_Event offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) const override; }; @@ -270,54 +272,3 @@ namespace nlohmann { * */ - - -/* - -[[nodiscard]] SDL_Event utils::offset_event(const Window* window, const SDL_Event& event, const shapes::IPoint& point) { - - - assert(utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any) && "expected a click event"); - - - auto new_event = event; - -#if defined(__ANDROID__) - // These are doubles in percent, the have to be modified by using the windows sizes - - - const double x_percent = event.tfinger.x; - const double y_percent = event.tfinger.y; - const auto window_size = window->size(); - new_event.tfinger.x = x_percent + static_cast(point.x) / static_cast(window_size.x); - new_event.tfinger.y = y_percent + static_cast(point.y) / static_cast(window_size.y); - - -#elif defined(__SWITCH__) - UNUSED(window); - UNUSED(event); - UNUSED(point); - UNUSED(new_event); - throw std::runtime_error("Not supported on the Nintendo switch"); -#else - UNUSED(window); - - switch (event.type) { - case SDL_MOUSEMOTION: - new_event.motion.x = event.motion.x + point.x; - new_event.motion.y = event.motion.y + point.y; - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - new_event.button.x = event.button.x + point.x; - new_event.button.y = event.button.y + point.y; - break; - default: - utils::unreachable(); - } -#endif - - - return new_event; -} - */ diff --git a/src/ui/layouts/scroll_layout.cpp b/src/ui/layouts/scroll_layout.cpp index c9b3c211..5c5cfba7 100644 --- a/src/ui/layouts/scroll_layout.cpp +++ b/src/ui/layouts/scroll_layout.cpp @@ -201,7 +201,7 @@ ui::Widget::EventHandleResult ui::ScrollLayout::handle_event( // NOLINT(readabil const auto& offset_rect = (layout_rect.cast()) >> offset_distance; if (not handled and pointer_event->is_in(main_rect) and pointer_event->is_in(offset_rect)) { - const auto offset_event = pointer_event.value().offset_raw(event, -offset_distance); + const auto offset_event = input_manager->offset_pointer_event(event, -offset_distance); if (const auto event_result = widget->handle_event(input_manager, offset_event); event_result) { handled = { true, handle_event_result(event_result.get_additional(), widget.get()) }; continue; From 5e8f013e2594cb0a229587bf386b4a2fbcbfc64f Mon Sep 17 00:00:00 2001 From: Totto16 Date: Sun, 5 May 2024 17:28:09 +0200 Subject: [PATCH 06/76] refactor the way the joystick manager works, it now is only used by the input manager and called by static methods, that also have an argument of the input array, this is done to have this functionality in the joystick input file, but use it in this place --- src/input/input.cpp | 4 +-- src/input/input.hpp | 5 ---- src/input/joystick_input.cpp | 56 +++++++++++------------------------- src/input/joystick_input.hpp | 15 ++-------- 4 files changed, 21 insertions(+), 59 deletions(-) diff --git a/src/input/input.cpp b/src/input/input.cpp index c297a29e..ce3d08b7 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -49,7 +49,7 @@ input::InputManager::InputManager(const std::shared_ptr& window) { m_inputs.push_back(std::make_unique(window)); //initialize joystick input manager - m_joystick_manager = std::make_unique(); + input::JoyStickInputManager::discover_devices(m_inputs); } input::InputManager::~InputManager() = default; @@ -120,7 +120,7 @@ input::InputManager::~InputManager() = default; } - const auto is_joystick_special_input = m_joystick_manager->process_special_inputs(event); + const auto is_joystick_special_input = input::JoyStickInputManager::process_special_inputs(event, m_inputs); if (is_joystick_special_input) { return { true, SpecialRequest::InputsChanged }; diff --git a/src/input/input.hpp b/src/input/input.hpp index 878a4e24..8e968f3b 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -74,13 +74,8 @@ namespace input { [[nodiscard]] virtual SDL_Event offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) const = 0; }; - //forward declaration - struct JoyStickInputManager; - struct InputManager { private: - std::unique_ptr m_joystick_manager; - std::vector> m_inputs{}; public: diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 81747158..c1d25886 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -4,6 +4,7 @@ #include "SDL_stdinc.h" #include "helper/expected.hpp" #include "helper/optional.hpp" +#include "helper/utils.hpp" #include "input/input.hpp" #include @@ -116,7 +117,7 @@ input::JoystickInput::get_by_device_index(int device_index) { } -input::JoyStickInputManager::JoyStickInputManager() { +void input::JoyStickInputManager::discover_devices(std::vector>& inputs) { //initialize joystick input, this needs to call some sdl things @@ -159,7 +160,7 @@ input::JoyStickInputManager::JoyStickInputManager() { auto joystick = JoystickInput::get_by_device_index(i); if (joystick.has_value()) { - m_inputs.push_back(std::move(joystick.value())); + inputs.push_back(std::move(joystick.value())); } else { spdlog::warn("Failed to configure joystick: {}", joystick.error()); } @@ -167,46 +168,17 @@ input::JoyStickInputManager::JoyStickInputManager() { } -[[nodiscard]] const std::vector>& input::JoyStickInputManager::inputs() const { - return m_inputs; -} - - -[[nodiscard]] helper::optional input::JoyStickInputManager::get_navigation_event( - const SDL_Event& event -) const { - for (const auto& input : m_inputs) { - - if (const auto navigation_event = input->get_navigation_event(event); navigation_event.has_value()) { - return navigation_event; - } - } - - return helper::nullopt; -} - -[[nodiscard]] helper::optional input::JoyStickInputManager::get_pointer_event( - const SDL_Event& event -) const { - for (const auto& input : m_inputs) { - if (const auto pointer_input = utils::is_child_class(input); pointer_input.has_value()) { - if (const auto pointer_event = pointer_input.value()->get_pointer_event(event); pointer_event.has_value()) { - return pointer_event; - } - } - } - - return helper::nullopt; -} - -[[nodiscard]] bool input::JoyStickInputManager::process_special_inputs(const SDL_Event& event) { +[[nodiscard]] bool input::JoyStickInputManager::process_special_inputs( + const SDL_Event& event, + std::vector>& inputs +) { switch (event.type) { case SDL_JOYDEVICEADDED: { const auto device_id = event.jdevice.which; auto joystick = JoystickInput::get_by_device_index(device_id); if (joystick.has_value()) { - m_inputs.push_back(std::move(joystick.value())); + inputs.push_back(std::move(joystick.value())); } else { spdlog::warn("Failed to add newly added joystick: {}", joystick.error()); } @@ -214,11 +186,15 @@ input::JoyStickInputManager::JoyStickInputManager() { } case SDL_JOYDEVICEREMOVED: { const auto instance_id = event.jdevice.which; - for (auto it = m_inputs.cbegin(); it != m_inputs.end(); it++) { + for (auto it = inputs.cbegin(); it != inputs.end(); it++) { + + if (const auto joystick_input = utils::is_child_class(*it); + joystick_input.has_value()) { - if ((*it)->instance_id() == instance_id) { - m_inputs.erase(it); - return true; + if (joystick_input.value()->instance_id() == instance_id) { + inputs.erase(it); + return true; + } } } diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index 2d362c8e..66a0a82d 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -64,18 +64,9 @@ namespace input { // see: https://github.com/mdqinc/SDL_GameControllerDB?tab=readme-ov-file struct JoyStickInputManager { - private: - std::vector> m_inputs{}; - - public: - explicit JoyStickInputManager(); - [[nodiscard]] const std::vector>& inputs() const; - - [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const; - - [[nodiscard]] helper::optional get_pointer_event(const SDL_Event& event) const; - - [[nodiscard]] bool process_special_inputs(const SDL_Event& event); + static void discover_devices(std::vector>& inputs); + [[nodiscard]] static bool + process_special_inputs(const SDL_Event& event, std::vector>& inputs); }; From 06a6496430f8b0603649f16689aeeda5b9ea8621 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 6 May 2024 22:43:50 +0200 Subject: [PATCH 07/76] detect touch inputs dynamically, as sdl allows that --- src/input/input.cpp | 6 ++-- src/input/joystick_input.cpp | 6 ++-- src/input/joystick_input.hpp | 1 + src/input/touch_input.cpp | 57 ++++++++++++++++++++++++++++++++++++ src/input/touch_input.hpp | 15 ++++++++-- 5 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/input/input.cpp b/src/input/input.cpp index ce3d08b7..cc09a8a2 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -45,10 +45,10 @@ input::InputManager::InputManager(const std::shared_ptr& window) { //initialize keyboard input m_inputs.push_back(std::make_unique()); - //initialize touch input (needs window) - m_inputs.push_back(std::make_unique(window)); + //initialize touch inputs by using the manager(needs window) + input::TouchInputManager::discover_devices(m_inputs, window); - //initialize joystick input manager + //initialize joystick inputs by using the manager input::JoyStickInputManager::discover_devices(m_inputs); } diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index c1d25886..2095040e 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -111,9 +111,9 @@ input::JoystickInput::get_by_device_index(int device_index) { return std::move(joystick_input.value()); } - return helper::unexpected{ - fmt::format("Failed to get joystick model by GUID {} We don't support this joystick yet", guid) - }; + return helper::unexpected{ fmt::format( + "Failed to get joystick model by GUID {} We don't support this joystick yet: the name was {}", guid, name + ) }; } diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index 66a0a82d..6e423e3e 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -65,6 +65,7 @@ namespace input { struct JoyStickInputManager { static void discover_devices(std::vector>& inputs); + [[nodiscard]] static bool process_special_inputs(const SDL_Event& event, std::vector>& inputs); }; diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index 162c7663..f38d8181 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -4,6 +4,8 @@ #include "touch_input.hpp" #include +#include +#include #include void input::TouchGameInput::handle_event(const SDL_Event& event) { @@ -121,6 +123,36 @@ input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function- } +input::TouchInput::TouchInput(const std::shared_ptr& window, SDL_TouchID id, const std::string& name) + : PointerInput{ name }, + m_window{ window }, + m_id{ id } { } + + +[[nodiscard]] helper::expected, std::string> +input::TouchInput::get_by_device_index(const std::shared_ptr& window, int device_index) { + + + const auto touch_id = SDL_GetTouchDevice(device_index); + + if (touch_id <= 0) { + return helper::unexpected{ + fmt::format("Failed to get touch id at device index {}: {}", device_index, SDL_GetError()) + }; + } + + + std::string name = "unknown name"; + const auto* char_name = SDL_GetTouchName(device_index); + + if (char_name != nullptr) { + name = char_name; + } + + return std::make_unique(window, touch_id, name); +} + + [[nodiscard]] helper::expected input::TouchSettings::validate() const { if (move_x_threshold > 1.0 || move_x_threshold < 0.0) { @@ -162,6 +194,31 @@ input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function- } +void input::TouchInputManager::discover_devices( + std::vector>& inputs, + const std::shared_ptr& window +) { + + + const auto num_of_touch_devices = SDL_GetNumTouchDevices(); + + if (num_of_touch_devices < 0) { + spdlog::warn("Failed to get number of touch devices: {}", SDL_GetError()); + return; + } + + for (auto i = 0; i < num_of_touch_devices; ++i) { + + auto touch_input = TouchInput::get_by_device_index(window, i); + if (touch_input.has_value()) { + inputs.push_back(std::move(touch_input.value())); + } else { + spdlog::warn("Failed to get TouchInput: {}", touch_input.error()); + } + } +} + + //TODO: /* [[nodiscard]] bool utils::event_is_action(const SDL_Event& event, const CrossPlatformAction action) { diff --git a/src/input/touch_input.hpp b/src/input/touch_input.hpp index 3c5c869b..7dd6ec8c 100644 --- a/src/input/touch_input.hpp +++ b/src/input/touch_input.hpp @@ -12,11 +12,15 @@ namespace input { struct TouchInput : PointerInput { std::shared_ptr m_window; + SDL_TouchID m_id; public: - TouchInput(const std::shared_ptr& window); + TouchInput(const std::shared_ptr& window, SDL_TouchID id, const std::string& name); virtual ~TouchInput(); + [[nodiscard]] static helper::expected, std::string> + get_by_device_index(const std::shared_ptr& window, int device_index); + [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; @@ -24,7 +28,14 @@ namespace input { [[nodiscard]] helper::optional get_pointer_event(const SDL_Event& event) const override; - [[nodiscard]] SDL_Event offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) const override; + [[nodiscard]] SDL_Event offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) + const override; + }; + + + struct TouchInputManager { + static void + discover_devices(std::vector>& inputs, const std::shared_ptr& window); }; From 0eaceb63d04a701bcf46bfa43f07213f92890ea5 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 6 May 2024 22:45:21 +0200 Subject: [PATCH 08/76] clang format (18) everything --- src/game/grid.cpp | 6 +- src/game/tetromino.cpp | 8 +- src/graphics/renderer.cpp | 17 +- src/graphics/window.cpp | 14 +- src/helper/color_literals.hpp | 12 +- src/input/input.hpp | 3 +- src/lobby/api.hpp | 20 +- src/manager/music_manager.hpp | 2 +- src/recordings/helper.hpp | 8 +- src/recordings/recording_reader.cpp | 20 +- src/scenes/about_page/about_page.hpp | 4 +- .../recording_selector/recording_chooser.cpp | 4 +- .../recording_selector/recording_chooser.hpp | 3 +- .../recording_component.hpp | 3 +- src/scenes/replay_game/replay_game.hpp | 3 +- src/scenes/scene.hpp | 3 +- .../settings_menu/color_setting_row.hpp | 6 +- src/ui/components/color_picker.hpp | 6 +- src/ui/components/image_button.cpp | 2 +- src/ui/components/image_view.hpp | 3 +- src/ui/components/link_label.hpp | 3 +- src/ui/components/slider.cpp | 4 +- src/ui/components/text_button.cpp | 14 +- src/ui/components/textinput.hpp | 6 +- src/ui/focusable.hpp | 2 +- src/ui/layout.hpp | 2 +- src/ui/layouts/tile_layout.hpp | 6 +- src/ui/widget.hpp | 3 +- tests/core/color.cpp | 184 +++++++++--------- tests/graphics/sdl_key.cpp | 184 +++++++++--------- 30 files changed, 283 insertions(+), 272 deletions(-) diff --git a/src/game/grid.cpp b/src/game/grid.cpp index 18cff92c..aec7056f 100644 --- a/src/game/grid.cpp +++ b/src/game/grid.cpp @@ -51,7 +51,7 @@ void Grid::draw_preview_background(const ServiceProvider& service_provider) cons service_provider, GridRect{ grid::preview_background_position, - grid::preview_background_position + grid::preview_extends - GridPoint{1, 1}, + grid::preview_background_position + grid::preview_extends - GridPoint{ 1, 1 }, } ); } @@ -61,7 +61,7 @@ void Grid::draw_hold_background(const ServiceProvider& service_provider) const { service_provider, GridRect{ grid::hold_background_position, - grid::hold_background_position + grid::hold_background_extends - GridPoint{1, 1}, + grid::hold_background_position + grid::hold_background_extends - GridPoint{ 1, 1 }, } ); } @@ -71,7 +71,7 @@ void Grid::draw_playing_field_background(const ServiceProvider& service_provider service_provider, GridRect{ grid::grid_position, - grid::grid_position + shapes::UPoint{grid::width_in_tiles - 1, grid::height_in_tiles - 1}, + grid::grid_position + shapes::UPoint{ grid::width_in_tiles - 1, grid::height_in_tiles - 1 }, } ); } diff --git a/src/game/tetromino.cpp b/src/game/tetromino.cpp index ba137eec..ca978562 100644 --- a/src/game/tetromino.cpp +++ b/src/game/tetromino.cpp @@ -69,9 +69,9 @@ Tetromino::Pattern Tetromino::get_pattern(helper::TetrominoType type, Rotation r std::array Tetromino::create_minos(GridPoint position, Rotation rotation, helper::TetrominoType type) { return std::array{ - Mino{position + get_pattern(type, rotation).at(0), type}, - Mino{position + get_pattern(type, rotation).at(1), type}, - Mino{position + get_pattern(type, rotation).at(2), type}, - Mino{position + get_pattern(type, rotation).at(3), type}, + Mino{ position + get_pattern(type, rotation).at(0), type }, + Mino{ position + get_pattern(type, rotation).at(1), type }, + Mino{ position + get_pattern(type, rotation).at(2), type }, + Mino{ position + get_pattern(type, rotation).at(3), type }, }; } diff --git a/src/graphics/renderer.cpp b/src/graphics/renderer.cpp index fed3b9ae..c2eeda71 100644 --- a/src/graphics/renderer.cpp +++ b/src/graphics/renderer.cpp @@ -3,18 +3,17 @@ //TODO: assert return values of all sdl functions -Renderer::Renderer(const Window& window, const VSync v_sync) : m_renderer { - SDL_CreateRenderer( - window.get_sdl_window(), -1, - (v_sync == VSync::Enabled ? SDL_RENDERER_PRESENTVSYNC : 0) | SDL_RENDERER_TARGETTEXTURE +Renderer::Renderer(const Window& window, const VSync v_sync) + : m_renderer{ SDL_CreateRenderer( + window.get_sdl_window(), + -1, + (v_sync == VSync::Enabled ? SDL_RENDERER_PRESENTVSYNC : 0) | SDL_RENDERER_TARGETTEXTURE #if defined(__3DS__) - | SDL_RENDERER_SOFTWARE + | SDL_RENDERER_SOFTWARE #else - | SDL_RENDERER_ACCELERATED + | SDL_RENDERER_ACCELERATED #endif - ) -} -{ + ) } { if (m_renderer == nullptr) { throw helper::InitializationError{ fmt::format("Failed creating a SDL Renderer: {}", SDL_GetError()) }; diff --git a/src/graphics/window.cpp b/src/graphics/window.cpp index 4de48104..036875a2 100644 --- a/src/graphics/window.cpp +++ b/src/graphics/window.cpp @@ -8,13 +8,13 @@ Window::Window(const std::string& title, WindowPosition position, u32 width, u32 Window::Window(const std::string& title, u32 x, u32 y, u32 width, u32 height) : m_window{ SDL_CreateWindow( - title.c_str(), - static_cast(x), - static_cast(y), - static_cast(width), - static_cast(height), - 0 - ) } { } + title.c_str(), + static_cast(x), + static_cast(y), + static_cast(width), + static_cast(height), + 0 + ) } { } Window::Window(const std::string& title, WindowPosition position) : Window{ title, static_cast(position), static_cast(position) } { } diff --git a/src/helper/color_literals.hpp b/src/helper/color_literals.hpp index 1dfd5fcf..e519c711 100644 --- a/src/helper/color_literals.hpp +++ b/src/helper/color_literals.hpp @@ -254,7 +254,7 @@ namespace { PROPAGATE(b, ColorFromHexStringReturnType); return const_utils::expected::good_result({ - Color{r.value(), g.value(), b.value()}, + Color{ r.value(), g.value(), b.value() }, false }); } @@ -274,7 +274,7 @@ namespace { PROPAGATE(a, ColorFromHexStringReturnType); return const_utils::expected::good_result({ - Color{r.value(), g.value(), b.value(), a.value()}, + Color{ r.value(), g.value(), b.value(), a.value() }, true }); } @@ -347,7 +347,7 @@ namespace { return const_utils::expected::good_result({ - Color{static_cast(r), static_cast(g), static_cast(b)}, + Color{ static_cast(r), static_cast(g), static_cast(b) }, false }); } @@ -428,7 +428,7 @@ namespace { return const_utils::expected::good_result({ - Color{static_cast(r), static_cast(g), static_cast(b), static_cast(a)}, + Color{ static_cast(r), static_cast(g), static_cast(b), static_cast(a) }, true } ); @@ -503,7 +503,7 @@ namespace { return const_utils::expected::good_result({ - HSVColor{h, s, v}, + HSVColor{ h, s, v }, false }); } @@ -584,7 +584,7 @@ namespace { return const_utils::expected::good_result({ - HSVColor{h, s, v, static_cast(a)}, + HSVColor{ h, s, v, static_cast(a) }, true }); } diff --git a/src/input/input.hpp b/src/input/input.hpp index 8e968f3b..28236d57 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -71,7 +71,8 @@ namespace input { [[nodiscard]] virtual helper::optional get_pointer_event(const SDL_Event& event) const = 0; - [[nodiscard]] virtual SDL_Event offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) const = 0; + [[nodiscard]] virtual SDL_Event offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) + const = 0; }; struct InputManager { diff --git a/src/lobby/api.hpp b/src/lobby/api.hpp index 8a4ace1d..4b7a64bf 100644 --- a/src/lobby/api.hpp +++ b/src/lobby/api.hpp @@ -183,28 +183,24 @@ namespace lobby { explicit Client(const std::string& api_url) : m_client{ api_url } { - + // clang-format off m_client.set_default_headers({ #if defined(CPPHTTPLIB_ZLIB_SUPPORT) || defined(CPPHTTPLIB_BROTLI_SUPPORT) - { - "Accept-Encoding", + { "Accept-Encoding", #if defined(CPPHTTPLIB_ZLIB_SUPPORT) - "gzip, deflate" + "gzip, deflate" #endif #if defined(CPPHTTPLIB_ZLIB_SUPPORT) && defined(CPPHTTPLIB_BROTLI_SUPPORT) - ", " + ", " #endif #if defined(CPPHTTPLIB_BROTLI_SUPPORT) - "br" + "br" #endif - } - , + }, #endif - { - "Accept", constants::json_content_type - } - }); + // clang-format on + { "Accept", constants::json_content_type } }); #if defined(CPPHTTPLIB_ZLIB_SUPPORT) || defined(CPPHTTPLIB_BROTLI_SUPPORT) m_client.set_compress(true); diff --git a/src/manager/music_manager.hpp b/src/manager/music_manager.hpp index 68dfb692..4cc54adb 100644 --- a/src/manager/music_manager.hpp +++ b/src/manager/music_manager.hpp @@ -2,8 +2,8 @@ #include "helper/optional.hpp" #include "helper/types.hpp" -#include "manager/service_provider.hpp" #include "input/input.hpp" +#include "manager/service_provider.hpp" #include #include diff --git a/src/recordings/helper.hpp b/src/recordings/helper.hpp index 261ae1d2..8479b411 100644 --- a/src/recordings/helper.hpp +++ b/src/recordings/helper.hpp @@ -33,7 +33,7 @@ namespace helper { [[nodiscard]] ReadResult> read_integral_from_file(std::ifstream& file) { if (not file) { return helper::unexpected{ - {ReadErrorType::InvalidStream, "failed to read data from file (before reading)"} + { ReadErrorType::InvalidStream, "failed to read data from file (before reading)" } }; } @@ -45,7 +45,7 @@ namespace helper { if (not file) { return helper::unexpected{ - {ReadErrorType::Incomplete, "failed to read data from file (after reading)"} + { ReadErrorType::Incomplete, "failed to read data from file (after reading)" } }; } @@ -56,7 +56,7 @@ namespace helper { [[nodiscard]] ReadResult> read_array_from_file(std::ifstream& file) { if (not file) { return helper::unexpected{ - {ReadErrorType::InvalidStream, "failed to read data from file (before reading)"} + { ReadErrorType::InvalidStream, "failed to read data from file (before reading)" } }; } @@ -71,7 +71,7 @@ namespace helper { if (not file) { return helper::unexpected{ - {ReadErrorType::Incomplete, "failed to read data from file (after reading)"} + { ReadErrorType::Incomplete, "failed to read data from file (after reading)" } }; } diff --git a/src/recordings/recording_reader.cpp b/src/recordings/recording_reader.cpp index c99be804..052d0ead 100644 --- a/src/recordings/recording_reader.cpp +++ b/src/recordings/recording_reader.cpp @@ -206,7 +206,7 @@ recorder::RecordingReader::from_path( // NOLINT(readability-function-cognitive-c recorder::RecordingReader::read_tetrion_header_from_file(std::ifstream& file) { if (not file) { return helper::unexpected{ - {helper::reader::ReadErrorType::InvalidStream, "failed to read data from file"} + { helper::reader::ReadErrorType::InvalidStream, "failed to read data from file" } }; } @@ -214,14 +214,14 @@ recorder::RecordingReader::read_tetrion_header_from_file(std::ifstream& file) { if (not seed.has_value()) { return helper::unexpected{ - {helper::reader::ReadErrorType::Incomplete, "field 'seed' has no value"} + { helper::reader::ReadErrorType::Incomplete, "field 'seed' has no value" } }; } const auto starting_level = helper::reader::read_integral_from_file(file); if (not starting_level.has_value()) { return helper::unexpected{ - {helper::reader::ReadErrorType::Incomplete, "field 'starting_level' has no value"} + { helper::reader::ReadErrorType::Incomplete, "field 'starting_level' has no value" } }; } @@ -233,14 +233,14 @@ recorder::RecordingReader::read_tetrion_header_from_file(std::ifstream& file) { ) { if (not file) { return helper::unexpected{ - {helper::reader::ReadErrorType::InvalidStream, "invalid input file stream while trying to read record"} + { helper::reader::ReadErrorType::InvalidStream, "invalid input file stream while trying to read record" } }; } const auto tetrion_index = helper::reader::read_integral_from_file(file); if (not tetrion_index.has_value()) { return helper::unexpected{ - {helper::reader::ReadErrorType::EndOfFile, "the field 'tetrion_index' is missing"} + { helper::reader::ReadErrorType::EndOfFile, "the field 'tetrion_index' is missing" } }; } @@ -248,27 +248,27 @@ recorder::RecordingReader::read_tetrion_header_from_file(std::ifstream& file) { helper::reader::read_integral_from_file(file); if (not simulation_step_index.has_value()) { return helper::unexpected{ - {helper::reader::ReadErrorType::Incomplete, "the field 'simulation_step_index' is missing"} + { helper::reader::ReadErrorType::Incomplete, "the field 'simulation_step_index' is missing" } }; } const auto event = helper::reader::read_integral_from_file>(file); if (not event.has_value()) { return helper::unexpected{ - {helper::reader::ReadErrorType::Incomplete, "the field 'InputEvent' is missing"} + { helper::reader::ReadErrorType::Incomplete, "the field 'InputEvent' is missing" } }; } if (not file) { return helper::unexpected{ - {helper::reader::ReadErrorType::Incomplete, "failed to read data from file"} + { helper::reader::ReadErrorType::Incomplete, "failed to read data from file" } }; } const auto maybe_event = magic_enum::enum_cast(event.value()); if (not maybe_event.has_value()) { return helper::unexpected{ - {helper::reader::ReadErrorType::Incomplete, - fmt::format("got invalid enum value for InputEvent: {}", event.value())} + { helper::reader::ReadErrorType::Incomplete, + fmt::format("got invalid enum value for InputEvent: {}", event.value()) } }; } diff --git a/src/scenes/about_page/about_page.hpp b/src/scenes/about_page/about_page.hpp index c7cb7e87..72e2cd80 100644 --- a/src/scenes/about_page/about_page.hpp +++ b/src/scenes/about_page/about_page.hpp @@ -15,8 +15,8 @@ namespace scenes { static constexpr std::initializer_list> authors{ - {"mgerhold", "https://github.com/mgerhold", "mgerhold.jpg"}, - { "Totto16", "https://github.com/Totto16", "Totto16.png"} + { "mgerhold", "https://github.com/mgerhold", "mgerhold.jpg" }, + { "Totto16", "https://github.com/Totto16", "Totto16.png" } }; public: diff --git a/src/scenes/recording_selector/recording_chooser.cpp b/src/scenes/recording_selector/recording_chooser.cpp index 32d962f7..a36364e1 100644 --- a/src/scenes/recording_selector/recording_chooser.cpp +++ b/src/scenes/recording_selector/recording_chooser.cpp @@ -54,8 +54,8 @@ custom_ui::RecordingFileChooser::RecordingFileChooser( m_main_grid.add( - service_provider, "Select Recording Folder", service_provider->font_manager().get(FontId::Default), Color::white(), - focus_helper.focus_id(), + service_provider, "Select Recording Folder", service_provider->font_manager().get(FontId::Default), + Color::white(), focus_helper.focus_id(), [this, service_provider](const ui::TextButton&) -> bool { this->prepare_dialog(service_provider); diff --git a/src/scenes/recording_selector/recording_chooser.hpp b/src/scenes/recording_selector/recording_chooser.hpp index 1d430a7c..7b824c66 100644 --- a/src/scenes/recording_selector/recording_chooser.hpp +++ b/src/scenes/recording_selector/recording_chooser.hpp @@ -27,7 +27,8 @@ namespace custom_ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; + [[nodiscard]] Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; [[nodiscard]] const std::vector& get_currently_chosen_files() const; diff --git a/src/scenes/recording_selector/recording_component.hpp b/src/scenes/recording_selector/recording_component.hpp index a6440fc9..9ab066d6 100644 --- a/src/scenes/recording_selector/recording_component.hpp +++ b/src/scenes/recording_selector/recording_component.hpp @@ -46,7 +46,8 @@ namespace custom_ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; + [[nodiscard]] Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; [[nodiscard]] data::RecordingMetadata metadata() const; diff --git a/src/scenes/replay_game/replay_game.hpp b/src/scenes/replay_game/replay_game.hpp index c918d82e..0c6ad5cb 100644 --- a/src/scenes/replay_game/replay_game.hpp +++ b/src/scenes/replay_game/replay_game.hpp @@ -22,7 +22,8 @@ namespace scenes { [[nodiscard]] UpdateResult update() override; void render(const ServiceProvider& service_provider) override; - [[nodiscard]] bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; + [[nodiscard]] bool + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; }; diff --git a/src/scenes/scene.hpp b/src/scenes/scene.hpp index 48aa71b7..5f2b4ed4 100644 --- a/src/scenes/scene.hpp +++ b/src/scenes/scene.hpp @@ -75,7 +75,8 @@ namespace scenes { [[nodiscard]] virtual UpdateResult update() = 0; virtual void render(const ServiceProvider& service_provider) = 0; - virtual bool handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) = 0; + virtual bool + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) = 0; // override this, if you (the scene) could potentially be displayed in non fullscreen! virtual void on_unhover(); [[nodiscard]] const ui::Layout& get_layout() const; diff --git a/src/scenes/settings_menu/color_setting_row.hpp b/src/scenes/settings_menu/color_setting_row.hpp index a54f907a..b03d4fdf 100644 --- a/src/scenes/settings_menu/color_setting_row.hpp +++ b/src/scenes/settings_menu/color_setting_row.hpp @@ -36,7 +36,8 @@ namespace detail { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; + [[nodiscard]] Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; }; @@ -92,7 +93,8 @@ namespace custom_ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; + [[nodiscard]] Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; [[nodiscard]] scenes::Scene::Change get_details_scene() override; diff --git a/src/ui/components/color_picker.hpp b/src/ui/components/color_picker.hpp index 1f7bd04b..89b96775 100644 --- a/src/ui/components/color_picker.hpp +++ b/src/ui/components/color_picker.hpp @@ -62,7 +62,8 @@ namespace detail { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; + [[nodiscard]] Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; void on_change(ColorChangeOrigin origin, const HSVColor& color); @@ -116,7 +117,8 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; + [[nodiscard]] Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; [[nodiscard]] Color get_color() const; diff --git a/src/ui/components/image_button.cpp b/src/ui/components/image_button.cpp index 1f402587..1d2f439a 100644 --- a/src/ui/components/image_button.cpp +++ b/src/ui/components/image_button.cpp @@ -14,7 +14,7 @@ ui::ImageButton::ImageButton( bool is_top_level ) : Button{ - ImageView{service_provider, image_path, size, respect_ratio, alignment, layout, false}, + ImageView{ service_provider, image_path, size, respect_ratio, alignment, layout, false }, focus_id, std::move(callback), size, diff --git a/src/ui/components/image_view.hpp b/src/ui/components/image_view.hpp index 1cf98ba1..04077ba4 100644 --- a/src/ui/components/image_view.hpp +++ b/src/ui/components/image_view.hpp @@ -27,6 +27,7 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& even) override; + [[nodiscard]] Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& even) override; }; } // namespace ui diff --git a/src/ui/components/link_label.hpp b/src/ui/components/link_label.hpp index 92b0d341..e5c14c97 100644 --- a/src/ui/components/link_label.hpp +++ b/src/ui/components/link_label.hpp @@ -43,7 +43,8 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; - [[nodiscard]] Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; + [[nodiscard]] Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; void on_clicked(); diff --git a/src/ui/components/slider.cpp b/src/ui/components/slider.cpp index 7a42ff41..8f07cadf 100644 --- a/src/ui/components/slider.cpp +++ b/src/ui/components/slider.cpp @@ -56,8 +56,8 @@ ui::Slider::Slider( const auto slider_rect = shapes::URect{ - shapes::UPoint{slider_start_x, m_fill_rect.top_left.y}, - shapes::UPoint{ slider_end_x, m_fill_rect.bottom_right.y} + shapes::UPoint{ slider_start_x, m_fill_rect.top_left.y }, + shapes::UPoint{ slider_end_x, m_fill_rect.bottom_right.y } }; return { bar.get_rect(), slider_rect }; diff --git a/src/ui/components/text_button.cpp b/src/ui/components/text_button.cpp index 8f06914f..07583c42 100644 --- a/src/ui/components/text_button.cpp +++ b/src/ui/components/text_button.cpp @@ -15,12 +15,12 @@ ui::TextButton::TextButton( bool is_top_level ) : Button{ - Text{service_provider, + Text{ service_provider, text, font, text_color, { fill_rect.top_left.x + static_cast(margin.first), - fill_rect.top_left.y + static_cast(margin.second), - fill_rect.width() - 2 * static_cast(margin.first), - fill_rect.height() - 2 * static_cast(margin.second) }}, + fill_rect.top_left.y + static_cast(margin.second), + fill_rect.width() - 2 * static_cast(margin.first), + fill_rect.height() - 2 * static_cast(margin.second) } }, focus_id, std::move(callback), fill_rect, @@ -51,12 +51,12 @@ ui::TextButton::TextButton( text_color, ui::get_rectangle_aligned( layout, - { static_cast(size.first * layout.get_rect().width()), + { static_cast(size.first * layout.get_rect().width()), static_cast(size.second * layout.get_rect().height()) }, alignment ), - {static_cast(margin.first * size.first * layout.get_rect().width()), - static_cast(margin.second * size.second * layout.get_rect().height())}, + { static_cast(margin.first * size.first * layout.get_rect().width()), + static_cast(margin.second * size.second * layout.get_rect().height()) }, layout, is_top_level } { } diff --git a/src/ui/components/textinput.hpp b/src/ui/components/textinput.hpp index 3750eb70..850b6559 100644 --- a/src/ui/components/textinput.hpp +++ b/src/ui/components/textinput.hpp @@ -62,8 +62,10 @@ namespace ui { //TODO: how to handle text limits (since texture for texts on the gpu can't get unlimitedly big, maybe use software texture?) void render(const ServiceProvider& service_provider) const override; - Widget::EventHandleResult - handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) // NOLINT(readability-function-cognitive-complexity) + Widget::EventHandleResult handle_event( + const std::shared_ptr& input_manager, + const SDL_Event& event + ) // NOLINT(readability-function-cognitive-complexity) override; void set_text(const std::string& text); diff --git a/src/ui/focusable.hpp b/src/ui/focusable.hpp index 3f5a8201..a3274ccd 100644 --- a/src/ui/focusable.hpp +++ b/src/ui/focusable.hpp @@ -57,7 +57,7 @@ namespace ui { } private: - virtual void on_focus(){ + virtual void on_focus() { //do nothing }; virtual void on_unfocus() { diff --git a/src/ui/layout.hpp b/src/ui/layout.hpp index 612c5ccd..6bb75b45 100644 --- a/src/ui/layout.hpp +++ b/src/ui/layout.hpp @@ -35,7 +35,7 @@ namespace ui { struct AbsolutLayout : public Layout { AbsolutLayout(const u32 x, const u32 y, const u32 width, const u32 height) : Layout{ - shapes::URect{x, y, width, height}, + shapes::URect{ x, y, width, height }, LayoutType::Absolut } { } }; diff --git a/src/ui/layouts/tile_layout.hpp b/src/ui/layouts/tile_layout.hpp index 05380665..7d75c8c3 100644 --- a/src/ui/layouts/tile_layout.hpp +++ b/src/ui/layouts/tile_layout.hpp @@ -51,8 +51,10 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; - Widget::EventHandleResult - handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) // NOLINT(readability-function-cognitive-complexity) + Widget::EventHandleResult handle_event( + const std::shared_ptr& input_manager, + const SDL_Event& event + ) // NOLINT(readability-function-cognitive-complexity) override; private: diff --git a/src/ui/widget.hpp b/src/ui/widget.hpp index 40d9115f..92cd6a6a 100644 --- a/src/ui/widget.hpp +++ b/src/ui/widget.hpp @@ -55,7 +55,8 @@ namespace ui { // do nothing } virtual void render(const ServiceProvider& service_provider) const = 0; - [[nodiscard]] virtual EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) = 0; + [[nodiscard]] virtual EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) = 0; }; [[nodiscard]] helper::optional as_focusable(Widget* widget); diff --git a/tests/core/color.cpp b/tests/core/color.cpp index ada3fce9..f1b9b941 100644 --- a/tests/core/color.cpp +++ b/tests/core/color.cpp @@ -75,17 +75,17 @@ TEST(Color, ConstructorProperties) { TEST(Color, FromStringValid) { const std::vector> valid_values{ - { "#FFAA33", { Color{ 0xFF, 0xAA, 0x33 }, color::SerializeMode::Hex, false }}, - { "#FF00FF00", { Color{ 0xFF, 0x00, 0xFF, 0x00 }, color::SerializeMode::Hex, true }}, - { "rgb(0,0,0)", { Color{ 0, 0, 0 }, color::SerializeMode::RGB, false }}, - { "rgba(0,0,0,0)", { Color{ 0, 0, 0, 0 }, color::SerializeMode::RGB, true }}, - { "hsv(0,0,0)", { HSVColor{ 0, 0, 0 }, color::SerializeMode::HSV, false }}, - { "hsva(340,0,0.5,0)", { HSVColor{ 340, 0, 0.5, 0 }, color::SerializeMode::HSV, true }}, - { "#ffaa33", { Color{ 0xff, 0xaa, 0x33 }, color::SerializeMode::Hex, false }}, - {"hsv(0, 0.00_000_000_1, 0)", { HSVColor{ 0, 0.000000001, 0 }, color::SerializeMode::HSV, false }}, - { "hsva(0, 0, 0, 0xFF)", { HSVColor{ 0, 0, 0, 0xFF }, color::SerializeMode::HSV, true }}, - { "rgba(0, 0xFF, 0, 255)", { Color{ 0, 0xFF, 0, 255 }, color::SerializeMode::RGB, true }}, - { "rgba(0, 0xFF, 0, 1_0_0)", { Color{ 0, 0xFF, 0, 100 }, color::SerializeMode::RGB, true }}, + { "#FFAA33", { Color{ 0xFF, 0xAA, 0x33 }, color::SerializeMode::Hex, false } }, + { "#FF00FF00", { Color{ 0xFF, 0x00, 0xFF, 0x00 }, color::SerializeMode::Hex, true } }, + { "rgb(0,0,0)", { Color{ 0, 0, 0 }, color::SerializeMode::RGB, false } }, + { "rgba(0,0,0,0)", { Color{ 0, 0, 0, 0 }, color::SerializeMode::RGB, true } }, + { "hsv(0,0,0)", { HSVColor{ 0, 0, 0 }, color::SerializeMode::HSV, false } }, + { "hsva(340,0,0.5,0)", { HSVColor{ 340, 0, 0.5, 0 }, color::SerializeMode::HSV, true } }, + { "#ffaa33", { Color{ 0xff, 0xaa, 0x33 }, color::SerializeMode::Hex, false } }, + { "hsv(0, 0.00_000_000_1, 0)", { HSVColor{ 0, 0.000000001, 0 }, color::SerializeMode::HSV, false } }, + { "hsva(0, 0, 0, 0xFF)", { HSVColor{ 0, 0, 0, 0xFF }, color::SerializeMode::HSV, true } }, + { "rgba(0, 0xFF, 0, 255)", { Color{ 0, 0xFF, 0, 255 }, color::SerializeMode::RGB, true } }, + { "rgba(0, 0xFF, 0, 1_0_0)", { Color{ 0, 0xFF, 0, 100 }, color::SerializeMode::RGB, true } }, }; for (const auto& [valid_string, expected_result] : valid_values) { @@ -104,64 +104,64 @@ TEST(Color, FromStringValid) { TEST(Color, FromStringInvalid) { const std::vector> invalid_strings{ - { "", "not enough data to determine the literal type"}, - { "#44", "Unrecognized HEX literal"}, - { "#Z", "Unrecognized HEX literal"}, - { "#ZZFF", "Unrecognized HEX literal"}, - { "u", "Unrecognized color literal"}, - { "#IIFFFFFF", "the input must be a valid hex character"}, - { "#FFIIFFFF", "the input must be a valid hex character"}, - { "#FFFFIIFF", "the input must be a valid hex character"}, - { "#FFFFFFII", "the input must be a valid hex character"}, - { "#FFFF4T", "the input must be a valid hex character"}, - { "#0000001", "Unrecognized HEX literal"}, - { "hsl(0,0,0)", "Unrecognized HSV literal"}, - { "rgg(0,0,0)", "Unrecognized RGB literal"}, - { "hsva(9,9,9)", "s has to be in range 0.0 - 1.0"}, - { "hsva(9,9,9,10212)", "s has to be in range 0.0 - 1.0"}, - { "hsv(-1,0,0)", "the input must be a valid decimal character"}, - { "hsv(404040,0,0)", "h has to be in range 0.0 - 360.0"}, - { "hsv(0,1.4,0)", "s has to be in range 0.0 - 1.0"}, - { "hsv(0,0,1.7)", "v has to be in range 0.0 - 1.0"}, - { "hsva(1321.4,0,0,0)", "h has to be in range 0.0 - 360.0"}, - { "hsva(0,1.4,0,0)", "s has to be in range 0.0 - 1.0"}, - { "hsva(0,0,1.7,0)", "v has to be in range 0.0 - 1.0"}, - { "hsva(0, 0, 0, 256)", "a has to be in range 0 - 255"}, - { "hsv(0,0,1.7.8)", "only one comma allowed"}, - { "hsv(0", "input ended too early"}, - { "rgba(0, 0xFFF, 0, 255)", "g has to be in range 0 - 255"}, - { "rgba(0, 0xFF, 0)", "expected ','"}, - { "rgb(0, 0xFF, 0, 255)", "expected ')'"}, - { "rgba(0, 0xFF, 0, 256)", "a has to be in range 0 - 255"}, - { "rgba(0", "input ended too early"}, - { "rgba(0, 0xFF, 0, 4_294_967_296)", "overflow detected"}, - { "rgba(0, 0xFF, 0, 4_294_967_300)", "overflow detected"}, - {"rgba(0, 0xFF, 0, 121_123_124_294_967_300)", "overflow detected"}, - { "rgb(256,0,0)", "r has to be in range 0 - 255"}, - { "rgb(0)", "expected ','"}, - { "rgb(0,256,0)", "g has to be in range 0 - 255"}, - { "rgb(0,0)", "expected ','"}, - { "rgb(0,0,256)", "b has to be in range 0 - 255"}, - { "rgb(0,0,0,", "expected ')'"}, - { "rgb(0,0,255) ", "expected end of string"}, - { "rgba(256,0,0,0)", "r has to be in range 0 - 255"}, - { "rgba(0)", "expected ','"}, - { "rgba(0,256,0,0)", "g has to be in range 0 - 255"}, - { "rgba(0,0)", "expected ','"}, - { "rgba(0,0,256,0)", "b has to be in range 0 - 255"}, - { "rgba(0,0,0)", "expected ','"}, - { "rgba(0,0,0,256)", "a has to be in range 0 - 255"}, - { "rgba(0,0,0,0,", "expected ')'"}, - { "rgba(0,0,0,255) ", "expected end of string"}, - { "hsv(0)", "expected ','"}, - { "hsv(0,0)", "expected ','"}, - { "hsv(0,0,0,", "expected ')'"}, - { "hsv(0,0,0) ", "expected end of string"}, - { "hsva(0)", "expected ','"}, - { "hsva(0,0)", "expected ','"}, - { "hsva(0,0,0)", "expected ','"}, - { "hsva(0,0,0,0,", "expected ')'"}, - { "hsva(0,0,0,255) ", "expected end of string"}, + { "", "not enough data to determine the literal type" }, + { "#44", "Unrecognized HEX literal" }, + { "#Z", "Unrecognized HEX literal" }, + { "#ZZFF", "Unrecognized HEX literal" }, + { "u", "Unrecognized color literal" }, + { "#IIFFFFFF", "the input must be a valid hex character" }, + { "#FFIIFFFF", "the input must be a valid hex character" }, + { "#FFFFIIFF", "the input must be a valid hex character" }, + { "#FFFFFFII", "the input must be a valid hex character" }, + { "#FFFF4T", "the input must be a valid hex character" }, + { "#0000001", "Unrecognized HEX literal" }, + { "hsl(0,0,0)", "Unrecognized HSV literal" }, + { "rgg(0,0,0)", "Unrecognized RGB literal" }, + { "hsva(9,9,9)", "s has to be in range 0.0 - 1.0" }, + { "hsva(9,9,9,10212)", "s has to be in range 0.0 - 1.0" }, + { "hsv(-1,0,0)", "the input must be a valid decimal character" }, + { "hsv(404040,0,0)", "h has to be in range 0.0 - 360.0" }, + { "hsv(0,1.4,0)", "s has to be in range 0.0 - 1.0" }, + { "hsv(0,0,1.7)", "v has to be in range 0.0 - 1.0" }, + { "hsva(1321.4,0,0,0)", "h has to be in range 0.0 - 360.0" }, + { "hsva(0,1.4,0,0)", "s has to be in range 0.0 - 1.0" }, + { "hsva(0,0,1.7,0)", "v has to be in range 0.0 - 1.0" }, + { "hsva(0, 0, 0, 256)", "a has to be in range 0 - 255" }, + { "hsv(0,0,1.7.8)", "only one comma allowed" }, + { "hsv(0", "input ended too early" }, + { "rgba(0, 0xFFF, 0, 255)", "g has to be in range 0 - 255" }, + { "rgba(0, 0xFF, 0)", "expected ','" }, + { "rgb(0, 0xFF, 0, 255)", "expected ')'" }, + { "rgba(0, 0xFF, 0, 256)", "a has to be in range 0 - 255" }, + { "rgba(0", "input ended too early" }, + { "rgba(0, 0xFF, 0, 4_294_967_296)", "overflow detected" }, + { "rgba(0, 0xFF, 0, 4_294_967_300)", "overflow detected" }, + { "rgba(0, 0xFF, 0, 121_123_124_294_967_300)", "overflow detected" }, + { "rgb(256,0,0)", "r has to be in range 0 - 255" }, + { "rgb(0)", "expected ','" }, + { "rgb(0,256,0)", "g has to be in range 0 - 255" }, + { "rgb(0,0)", "expected ','" }, + { "rgb(0,0,256)", "b has to be in range 0 - 255" }, + { "rgb(0,0,0,", "expected ')'" }, + { "rgb(0,0,255) ", "expected end of string" }, + { "rgba(256,0,0,0)", "r has to be in range 0 - 255" }, + { "rgba(0)", "expected ','" }, + { "rgba(0,256,0,0)", "g has to be in range 0 - 255" }, + { "rgba(0,0)", "expected ','" }, + { "rgba(0,0,256,0)", "b has to be in range 0 - 255" }, + { "rgba(0,0,0)", "expected ','" }, + { "rgba(0,0,0,256)", "a has to be in range 0 - 255" }, + { "rgba(0,0,0,0,", "expected ')'" }, + { "rgba(0,0,0,255) ", "expected end of string" }, + { "hsv(0)", "expected ','" }, + { "hsv(0,0)", "expected ','" }, + { "hsv(0,0,0,", "expected ')'" }, + { "hsv(0,0,0) ", "expected end of string" }, + { "hsva(0)", "expected ','" }, + { "hsva(0,0)", "expected ','" }, + { "hsva(0,0,0)", "expected ','" }, + { "hsva(0,0,0,0,", "expected ')'" }, + { "hsva(0,0,0,255) ", "expected end of string" }, }; for (const auto& [invalid_string, error_message] : invalid_strings) { @@ -181,11 +181,11 @@ TEST(HSVColor, DefaultConstruction) { TEST(HSVColor, ConstructorProperties) { const std::vector> values{ - { 0.0, 0.0, 0.0}, - {360.0, 0.0, 0.0}, - {360.0, 1.0, 0.0}, - {360.0, 1.0, 1.0}, - { 57.0, 0.6, 0.8} + { 0.0, 0.0, 0.0 }, + { 360.0, 0.0, 0.0 }, + { 360.0, 1.0, 0.0 }, + { 360.0, 1.0, 1.0 }, + { 57.0, 0.6, 0.8 } }; for (const auto& [h, s, v] : values) { @@ -198,12 +198,12 @@ TEST(HSVColor, ConstructorProperties) { TEST(HSVColor, InvalidConstructors) { const std::vector> invalid_values{ - { -1.0, 0.0, 0.0}, - {360.0, -1.0, 0.0}, - {360.0, 1.0, -1.0}, - {460.0, 1.0, 1.0}, - { 57.0, 2.6, 0.8}, - { 57.0, 1.6, 3.8} + { -1.0, 0.0, 0.0 }, + { 360.0, -1.0, 0.0 }, + { 360.0, 1.0, -1.0 }, + { 460.0, 1.0, 1.0 }, + { 57.0, 2.6, 0.8 }, + { 57.0, 1.6, 3.8 } }; for (const auto& [h, s, v] : invalid_values) { @@ -223,12 +223,12 @@ TEST(ColorConversion, HSV_to_RGB_to_HSV) { //NOLINT(readability-function-cogniti #if COLOR_TEST_MODE == 0 const std::vector colors{ - HSVColor{ 2, 0.3, 0.6}, - HSVColor{ 82, 0.3, 0.6}, - HSVColor{142, 0.3, 0.6}, - HSVColor{192, 0.3, 0.6}, - HSVColor{252, 0.3, 0.6}, - HSVColor{312, 0.3, 0.6}, + HSVColor{ 2, 0.3, 0.6 }, + HSVColor{ 82, 0.3, 0.6 }, + HSVColor{ 142, 0.3, 0.6 }, + HSVColor{ 192, 0.3, 0.6 }, + HSVColor{ 252, 0.3, 0.6 }, + HSVColor{ 312, 0.3, 0.6 }, }; for (const auto& original_color : colors) { @@ -269,12 +269,12 @@ TEST(ColorConversion, RGG_to_HSV_to_RGB) { //NOLINT(readability-function-cogniti #if COLOR_TEST_MODE == 0 const std::vector colors{ - Color{ 0, 0, 0}, - Color{180, 135, 223}, - Color{ 12, 34, 130}, - Color{ 79, 85, 20}, - Color{155, 174, 2}, - Color{243, 32, 34}, + Color{ 0, 0, 0 }, + Color{ 180, 135, 223 }, + Color{ 12, 34, 130 }, + Color{ 79, 85, 20 }, + Color{ 155, 174, 2 }, + Color{ 243, 32, 34 }, }; for (const auto& original_color : colors) { diff --git a/tests/graphics/sdl_key.cpp b/tests/graphics/sdl_key.cpp index ada3fce9..f1b9b941 100644 --- a/tests/graphics/sdl_key.cpp +++ b/tests/graphics/sdl_key.cpp @@ -75,17 +75,17 @@ TEST(Color, ConstructorProperties) { TEST(Color, FromStringValid) { const std::vector> valid_values{ - { "#FFAA33", { Color{ 0xFF, 0xAA, 0x33 }, color::SerializeMode::Hex, false }}, - { "#FF00FF00", { Color{ 0xFF, 0x00, 0xFF, 0x00 }, color::SerializeMode::Hex, true }}, - { "rgb(0,0,0)", { Color{ 0, 0, 0 }, color::SerializeMode::RGB, false }}, - { "rgba(0,0,0,0)", { Color{ 0, 0, 0, 0 }, color::SerializeMode::RGB, true }}, - { "hsv(0,0,0)", { HSVColor{ 0, 0, 0 }, color::SerializeMode::HSV, false }}, - { "hsva(340,0,0.5,0)", { HSVColor{ 340, 0, 0.5, 0 }, color::SerializeMode::HSV, true }}, - { "#ffaa33", { Color{ 0xff, 0xaa, 0x33 }, color::SerializeMode::Hex, false }}, - {"hsv(0, 0.00_000_000_1, 0)", { HSVColor{ 0, 0.000000001, 0 }, color::SerializeMode::HSV, false }}, - { "hsva(0, 0, 0, 0xFF)", { HSVColor{ 0, 0, 0, 0xFF }, color::SerializeMode::HSV, true }}, - { "rgba(0, 0xFF, 0, 255)", { Color{ 0, 0xFF, 0, 255 }, color::SerializeMode::RGB, true }}, - { "rgba(0, 0xFF, 0, 1_0_0)", { Color{ 0, 0xFF, 0, 100 }, color::SerializeMode::RGB, true }}, + { "#FFAA33", { Color{ 0xFF, 0xAA, 0x33 }, color::SerializeMode::Hex, false } }, + { "#FF00FF00", { Color{ 0xFF, 0x00, 0xFF, 0x00 }, color::SerializeMode::Hex, true } }, + { "rgb(0,0,0)", { Color{ 0, 0, 0 }, color::SerializeMode::RGB, false } }, + { "rgba(0,0,0,0)", { Color{ 0, 0, 0, 0 }, color::SerializeMode::RGB, true } }, + { "hsv(0,0,0)", { HSVColor{ 0, 0, 0 }, color::SerializeMode::HSV, false } }, + { "hsva(340,0,0.5,0)", { HSVColor{ 340, 0, 0.5, 0 }, color::SerializeMode::HSV, true } }, + { "#ffaa33", { Color{ 0xff, 0xaa, 0x33 }, color::SerializeMode::Hex, false } }, + { "hsv(0, 0.00_000_000_1, 0)", { HSVColor{ 0, 0.000000001, 0 }, color::SerializeMode::HSV, false } }, + { "hsva(0, 0, 0, 0xFF)", { HSVColor{ 0, 0, 0, 0xFF }, color::SerializeMode::HSV, true } }, + { "rgba(0, 0xFF, 0, 255)", { Color{ 0, 0xFF, 0, 255 }, color::SerializeMode::RGB, true } }, + { "rgba(0, 0xFF, 0, 1_0_0)", { Color{ 0, 0xFF, 0, 100 }, color::SerializeMode::RGB, true } }, }; for (const auto& [valid_string, expected_result] : valid_values) { @@ -104,64 +104,64 @@ TEST(Color, FromStringValid) { TEST(Color, FromStringInvalid) { const std::vector> invalid_strings{ - { "", "not enough data to determine the literal type"}, - { "#44", "Unrecognized HEX literal"}, - { "#Z", "Unrecognized HEX literal"}, - { "#ZZFF", "Unrecognized HEX literal"}, - { "u", "Unrecognized color literal"}, - { "#IIFFFFFF", "the input must be a valid hex character"}, - { "#FFIIFFFF", "the input must be a valid hex character"}, - { "#FFFFIIFF", "the input must be a valid hex character"}, - { "#FFFFFFII", "the input must be a valid hex character"}, - { "#FFFF4T", "the input must be a valid hex character"}, - { "#0000001", "Unrecognized HEX literal"}, - { "hsl(0,0,0)", "Unrecognized HSV literal"}, - { "rgg(0,0,0)", "Unrecognized RGB literal"}, - { "hsva(9,9,9)", "s has to be in range 0.0 - 1.0"}, - { "hsva(9,9,9,10212)", "s has to be in range 0.0 - 1.0"}, - { "hsv(-1,0,0)", "the input must be a valid decimal character"}, - { "hsv(404040,0,0)", "h has to be in range 0.0 - 360.0"}, - { "hsv(0,1.4,0)", "s has to be in range 0.0 - 1.0"}, - { "hsv(0,0,1.7)", "v has to be in range 0.0 - 1.0"}, - { "hsva(1321.4,0,0,0)", "h has to be in range 0.0 - 360.0"}, - { "hsva(0,1.4,0,0)", "s has to be in range 0.0 - 1.0"}, - { "hsva(0,0,1.7,0)", "v has to be in range 0.0 - 1.0"}, - { "hsva(0, 0, 0, 256)", "a has to be in range 0 - 255"}, - { "hsv(0,0,1.7.8)", "only one comma allowed"}, - { "hsv(0", "input ended too early"}, - { "rgba(0, 0xFFF, 0, 255)", "g has to be in range 0 - 255"}, - { "rgba(0, 0xFF, 0)", "expected ','"}, - { "rgb(0, 0xFF, 0, 255)", "expected ')'"}, - { "rgba(0, 0xFF, 0, 256)", "a has to be in range 0 - 255"}, - { "rgba(0", "input ended too early"}, - { "rgba(0, 0xFF, 0, 4_294_967_296)", "overflow detected"}, - { "rgba(0, 0xFF, 0, 4_294_967_300)", "overflow detected"}, - {"rgba(0, 0xFF, 0, 121_123_124_294_967_300)", "overflow detected"}, - { "rgb(256,0,0)", "r has to be in range 0 - 255"}, - { "rgb(0)", "expected ','"}, - { "rgb(0,256,0)", "g has to be in range 0 - 255"}, - { "rgb(0,0)", "expected ','"}, - { "rgb(0,0,256)", "b has to be in range 0 - 255"}, - { "rgb(0,0,0,", "expected ')'"}, - { "rgb(0,0,255) ", "expected end of string"}, - { "rgba(256,0,0,0)", "r has to be in range 0 - 255"}, - { "rgba(0)", "expected ','"}, - { "rgba(0,256,0,0)", "g has to be in range 0 - 255"}, - { "rgba(0,0)", "expected ','"}, - { "rgba(0,0,256,0)", "b has to be in range 0 - 255"}, - { "rgba(0,0,0)", "expected ','"}, - { "rgba(0,0,0,256)", "a has to be in range 0 - 255"}, - { "rgba(0,0,0,0,", "expected ')'"}, - { "rgba(0,0,0,255) ", "expected end of string"}, - { "hsv(0)", "expected ','"}, - { "hsv(0,0)", "expected ','"}, - { "hsv(0,0,0,", "expected ')'"}, - { "hsv(0,0,0) ", "expected end of string"}, - { "hsva(0)", "expected ','"}, - { "hsva(0,0)", "expected ','"}, - { "hsva(0,0,0)", "expected ','"}, - { "hsva(0,0,0,0,", "expected ')'"}, - { "hsva(0,0,0,255) ", "expected end of string"}, + { "", "not enough data to determine the literal type" }, + { "#44", "Unrecognized HEX literal" }, + { "#Z", "Unrecognized HEX literal" }, + { "#ZZFF", "Unrecognized HEX literal" }, + { "u", "Unrecognized color literal" }, + { "#IIFFFFFF", "the input must be a valid hex character" }, + { "#FFIIFFFF", "the input must be a valid hex character" }, + { "#FFFFIIFF", "the input must be a valid hex character" }, + { "#FFFFFFII", "the input must be a valid hex character" }, + { "#FFFF4T", "the input must be a valid hex character" }, + { "#0000001", "Unrecognized HEX literal" }, + { "hsl(0,0,0)", "Unrecognized HSV literal" }, + { "rgg(0,0,0)", "Unrecognized RGB literal" }, + { "hsva(9,9,9)", "s has to be in range 0.0 - 1.0" }, + { "hsva(9,9,9,10212)", "s has to be in range 0.0 - 1.0" }, + { "hsv(-1,0,0)", "the input must be a valid decimal character" }, + { "hsv(404040,0,0)", "h has to be in range 0.0 - 360.0" }, + { "hsv(0,1.4,0)", "s has to be in range 0.0 - 1.0" }, + { "hsv(0,0,1.7)", "v has to be in range 0.0 - 1.0" }, + { "hsva(1321.4,0,0,0)", "h has to be in range 0.0 - 360.0" }, + { "hsva(0,1.4,0,0)", "s has to be in range 0.0 - 1.0" }, + { "hsva(0,0,1.7,0)", "v has to be in range 0.0 - 1.0" }, + { "hsva(0, 0, 0, 256)", "a has to be in range 0 - 255" }, + { "hsv(0,0,1.7.8)", "only one comma allowed" }, + { "hsv(0", "input ended too early" }, + { "rgba(0, 0xFFF, 0, 255)", "g has to be in range 0 - 255" }, + { "rgba(0, 0xFF, 0)", "expected ','" }, + { "rgb(0, 0xFF, 0, 255)", "expected ')'" }, + { "rgba(0, 0xFF, 0, 256)", "a has to be in range 0 - 255" }, + { "rgba(0", "input ended too early" }, + { "rgba(0, 0xFF, 0, 4_294_967_296)", "overflow detected" }, + { "rgba(0, 0xFF, 0, 4_294_967_300)", "overflow detected" }, + { "rgba(0, 0xFF, 0, 121_123_124_294_967_300)", "overflow detected" }, + { "rgb(256,0,0)", "r has to be in range 0 - 255" }, + { "rgb(0)", "expected ','" }, + { "rgb(0,256,0)", "g has to be in range 0 - 255" }, + { "rgb(0,0)", "expected ','" }, + { "rgb(0,0,256)", "b has to be in range 0 - 255" }, + { "rgb(0,0,0,", "expected ')'" }, + { "rgb(0,0,255) ", "expected end of string" }, + { "rgba(256,0,0,0)", "r has to be in range 0 - 255" }, + { "rgba(0)", "expected ','" }, + { "rgba(0,256,0,0)", "g has to be in range 0 - 255" }, + { "rgba(0,0)", "expected ','" }, + { "rgba(0,0,256,0)", "b has to be in range 0 - 255" }, + { "rgba(0,0,0)", "expected ','" }, + { "rgba(0,0,0,256)", "a has to be in range 0 - 255" }, + { "rgba(0,0,0,0,", "expected ')'" }, + { "rgba(0,0,0,255) ", "expected end of string" }, + { "hsv(0)", "expected ','" }, + { "hsv(0,0)", "expected ','" }, + { "hsv(0,0,0,", "expected ')'" }, + { "hsv(0,0,0) ", "expected end of string" }, + { "hsva(0)", "expected ','" }, + { "hsva(0,0)", "expected ','" }, + { "hsva(0,0,0)", "expected ','" }, + { "hsva(0,0,0,0,", "expected ')'" }, + { "hsva(0,0,0,255) ", "expected end of string" }, }; for (const auto& [invalid_string, error_message] : invalid_strings) { @@ -181,11 +181,11 @@ TEST(HSVColor, DefaultConstruction) { TEST(HSVColor, ConstructorProperties) { const std::vector> values{ - { 0.0, 0.0, 0.0}, - {360.0, 0.0, 0.0}, - {360.0, 1.0, 0.0}, - {360.0, 1.0, 1.0}, - { 57.0, 0.6, 0.8} + { 0.0, 0.0, 0.0 }, + { 360.0, 0.0, 0.0 }, + { 360.0, 1.0, 0.0 }, + { 360.0, 1.0, 1.0 }, + { 57.0, 0.6, 0.8 } }; for (const auto& [h, s, v] : values) { @@ -198,12 +198,12 @@ TEST(HSVColor, ConstructorProperties) { TEST(HSVColor, InvalidConstructors) { const std::vector> invalid_values{ - { -1.0, 0.0, 0.0}, - {360.0, -1.0, 0.0}, - {360.0, 1.0, -1.0}, - {460.0, 1.0, 1.0}, - { 57.0, 2.6, 0.8}, - { 57.0, 1.6, 3.8} + { -1.0, 0.0, 0.0 }, + { 360.0, -1.0, 0.0 }, + { 360.0, 1.0, -1.0 }, + { 460.0, 1.0, 1.0 }, + { 57.0, 2.6, 0.8 }, + { 57.0, 1.6, 3.8 } }; for (const auto& [h, s, v] : invalid_values) { @@ -223,12 +223,12 @@ TEST(ColorConversion, HSV_to_RGB_to_HSV) { //NOLINT(readability-function-cogniti #if COLOR_TEST_MODE == 0 const std::vector colors{ - HSVColor{ 2, 0.3, 0.6}, - HSVColor{ 82, 0.3, 0.6}, - HSVColor{142, 0.3, 0.6}, - HSVColor{192, 0.3, 0.6}, - HSVColor{252, 0.3, 0.6}, - HSVColor{312, 0.3, 0.6}, + HSVColor{ 2, 0.3, 0.6 }, + HSVColor{ 82, 0.3, 0.6 }, + HSVColor{ 142, 0.3, 0.6 }, + HSVColor{ 192, 0.3, 0.6 }, + HSVColor{ 252, 0.3, 0.6 }, + HSVColor{ 312, 0.3, 0.6 }, }; for (const auto& original_color : colors) { @@ -269,12 +269,12 @@ TEST(ColorConversion, RGG_to_HSV_to_RGB) { //NOLINT(readability-function-cogniti #if COLOR_TEST_MODE == 0 const std::vector colors{ - Color{ 0, 0, 0}, - Color{180, 135, 223}, - Color{ 12, 34, 130}, - Color{ 79, 85, 20}, - Color{155, 174, 2}, - Color{243, 32, 34}, + Color{ 0, 0, 0 }, + Color{ 180, 135, 223 }, + Color{ 12, 34, 130 }, + Color{ 79, 85, 20 }, + Color{ 155, 174, 2 }, + Color{ 243, 32, 34 }, }; for (const auto& original_color : colors) { From 51b92c2360aeb144854228d5aca9bc0e76925b48 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 6 May 2024 23:13:40 +0200 Subject: [PATCH 09/76] port joystick navigation names to the new API --- src/input/joystick_input.cpp | 74 ++++++++++++++++++++++++++++------- src/input/joystick_input.hpp | 75 ++++++++++-------------------------- 2 files changed, 80 insertions(+), 69 deletions(-) diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 2095040e..91d76dc4 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -48,16 +48,18 @@ input::JoystickInput::~JoystickInput() { [[nodiscard]] helper::optional> input::JoystickInput::get_joystick_by_guid( const joystick::GUID& guid, SDL_Joystick* joystick, - SDL_JoystickID instance_id + SDL_JoystickID instance_id, + const std::string& name + ) { #if defined(__CONSOLE__) #if defined(__SWITCH__) if (guid == SwitchJoystickInput_Type1::guid) { - return std::make_unique(joystick, instance_id); + return std::make_unique(joystick, instance_id, name); } #elif defined(__3DS__) if (guid == _3DSJoystickInput_Type1::guid) { - return std::make_unique<_3DSJoystickInput_Type1>(joystick, instance_id); + return std::make_unique<_3DSJoystickInput_Type1>(joystick, instance_id, name); } #endif @@ -66,6 +68,7 @@ input::JoystickInput::~JoystickInput() { UNUSED(guid); UNUSED(joystick); UNUSED(instance_id); + UNUSED(name); return helper::nullopt; } @@ -105,7 +108,7 @@ input::JoystickInput::get_by_device_index(int device_index) { return helper::unexpected{ fmt::format("Failed to get joystick GUID: {}", SDL_GetError()) }; } - auto joystick_input = JoystickInput::get_joystick_by_guid(guid, joystick, instance_id); + auto joystick_input = JoystickInput::get_joystick_by_guid(guid, joystick, instance_id, name); if (joystick_input.has_value()) { return std::move(joystick_input.value()); @@ -226,16 +229,12 @@ input::SwitchJoystickInput_Type1::SwitchJoystickInput_Type1( const SDL_Event& event ) const { - //TODO handle SDL_JOYAXISMOTION - - if (event.type == SDL_JOYBUTTONDOWN) { - if (event.jbutton.which != m_id) { + if (event.jbutton.which != m_instance_id) { return helper::nullopt; } - switch (event.jbutton.button) { case JOYCON_A: return NavigationEvent::OK; @@ -257,7 +256,8 @@ input::SwitchJoystickInput_Type1::SwitchJoystickInput_Type1( return NavigationEvent::RIGHT; case JOYCON_MINUS: return NavigationEvent::BACK; - + default: + return helper::nullopt; //note, that NavigationEvent::TAB is not supported } @@ -269,6 +269,28 @@ input::SwitchJoystickInput_Type1::SwitchJoystickInput_Type1( return helper::nullopt; } +[[nodiscard]] std::string input::SwitchJoystickInput_Type1::describe_navigation_event(NavigationEvent event) const { + switch (event) { + case NavigationEvent::OK: + return "A"; + case NavigationEvent::BACK: + return "Minus"; + case NavigationEvent::DOWN: + return "Down"; + case NavigationEvent::UP: + return "Up"; + case NavigationEvent::LEFT: + return "Left"; + case NavigationEvent::RIGHT: + return "Right"; + case NavigationEvent::TAB: + return "Unsupported"; + default: + utils::unreachable(); + } +} + + #elif defined(__3DS__) input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( @@ -286,11 +308,10 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( if (event.type == SDL_JOYBUTTONDOWN) { - if (event.jbutton.which != m_id) { + if (event.jbutton.which != m_instance_id) { return helper::nullopt; } - switch (event.jbutton.button) { case JOYCON_A: return NavigationEvent::OK; @@ -312,6 +333,8 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( return NavigationEvent::RIGHT; case JOYCON_X: return NavigationEvent::BACK; + default: + return helper::nullopt; //note, that NavigationEvent::TAB is not supported } @@ -323,6 +346,28 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( return helper::nullopt; } +[[nodiscard]] std::string input::_3DSJoystickInput_Type1::describe_navigation_event(NavigationEvent event) const { + switch (event) { + case NavigationEvent::OK: + return "A"; + case NavigationEvent::BACK: + return "X"; + case NavigationEvent::DOWN: + return "Down"; + case NavigationEvent::UP: + return "Up"; + case NavigationEvent::LEFT: + return "Left"; + case NavigationEvent::RIGHT: + return "Right"; + case NavigationEvent::TAB: + return "Unsupported"; + default: + utils::unreachable(); + } +} + + #endif void JoystickGameInput::handle_event(const SDL_Event& event, const Window*) { @@ -343,8 +388,9 @@ void JoystickGameInput::update(SimulationStep simulation_step_index) { #if defined(__SWITCH__) -// game_input uses Input to handle events, but stores teh config settings for teh specific button +// game_input uses Input to handle events, but stores the config settings for the specific button +//TODO: use settings helper::optional JoystickSwitchGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event) const { if (event.type == SDL_JOYBUTTONDOWN) { //TODO: use switch case @@ -398,7 +444,7 @@ helper::optional JoystickSwitchGameInput_Type1::sdl_event_to_input_e } #elif defined(__3DS__) - +//TODO: use settings helper::optional JoystickInput::sdl_event_to_input_event(const SDL_Event& event) const { if (event.type == SDL_JOYBUTTONDOWN) { const auto button = event.jbutton.button; diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index 6e423e3e..fe967164 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -41,17 +41,29 @@ struct fmt::formatter : formatter { namespace input { - struct JoystickInput : Input { + + /** + * @brief + * + * @note regarding the NOLINT: the destructor just cleans up the SDL_Joystick, it has nothing to do with class members that would need special member functions to be explicitly defined + * + */ + struct JoystickInput //NOLINT(cppcoreguidelines-special-member-functions) + : Input { private: SDL_Joystick* m_joystick; SDL_JoystickID m_instance_id; - [[nodiscard]] static helper::optional> - get_joystick_by_guid(const joystick::GUID& guid, SDL_Joystick* joystick, SDL_JoystickID instance_id); + [[nodiscard]] static helper::optional> get_joystick_by_guid( + const joystick::GUID& guid, + SDL_Joystick* joystick, + SDL_JoystickID instance_id, + const std::string& name + ); public: JoystickInput(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); - virtual ~JoystickInput(); + ~JoystickInput(); [[nodiscard]] static helper::expected, std::string> get_by_device_index( int device_index @@ -112,6 +124,8 @@ namespace input { SwitchJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; + + [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; }; @@ -126,6 +140,8 @@ namespace input { _3DSJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; + + [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; }; @@ -274,54 +290,3 @@ namespace nlohmann { } }; } // namespace nlohmann - - -//TODO: -/* -#elif defined(__SWITCH__) - switch (action) { - case CrossPlatformAction::OK: - return "A"; - case CrossPlatformAction::PAUSE: - case CrossPlatformAction::UNPAUSE: - return "PLUS"; - case CrossPlatformAction::CLOSE: - case CrossPlatformAction::EXIT: - return "MINUS"; - case CrossPlatformAction::DOWN: - return "Down"; - case CrossPlatformAction::UP: - return "Up"; - case CrossPlatformAction::LEFT: - return "Left"; - case CrossPlatformAction::RIGHT: - return "Right"; - case CrossPlatformAction::OPEN_SETTINGS: - return "Y"; - default: - utils::unreachable(); - } - -#elif defined(__3DS__) - switch (action) { - case CrossPlatformAction::OK: - return "A"; - case CrossPlatformAction::PAUSE: - case CrossPlatformAction::UNPAUSE: - return "Y"; - case CrossPlatformAction::CLOSE: - case CrossPlatformAction::EXIT: - return "X"; - case CrossPlatformAction::DOWN: - return "Down"; - case CrossPlatformAction::UP: - return "Up"; - case CrossPlatformAction::LEFT: - return "Left"; - case CrossPlatformAction::RIGHT: - return "Right"; - case CrossPlatformAction::OPEN_SETTINGS: - return "Select"; - default: - utils::unreachable(); - } */ From 828260aea43cd4b4644db797b160f8031012c3af Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 6 May 2024 23:16:18 +0200 Subject: [PATCH 10/76] implement missing function of "input::PointerEventHelper" --- src/input/input.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/input/input.cpp b/src/input/input.cpp index cc09a8a2..acfc8511 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -12,6 +12,18 @@ #include +input::PointerEventHelper::PointerEventHelper(shapes::IPoint pos, PointerEvent event) + : m_pos{ pos }, + m_event{ event } { } + +[[nodiscard]] input::PointerEvent input::PointerEventHelper::event() const { + return m_event; +} + +[[nodiscard]] shapes::IPoint input::PointerEventHelper::position() const { + return m_pos; +} + [[nodiscard]] bool input::PointerEventHelper::is_in(const shapes::URect& rect) const { using Type = decltype(m_pos)::Type; @@ -36,6 +48,9 @@ return is_in; } +[[nodiscard]] bool input::PointerEventHelper::operator==(PointerEvent event) const { + return m_event == event; +} input::InputManager::InputManager(const std::shared_ptr& window) { From f779ae08e1a9ecaddddb9862702297f628c3a166 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 6 May 2024 23:22:26 +0200 Subject: [PATCH 11/76] readd some used and non input related functionalities from capabilities.cpp -> platform.cpp --- src/helper/meson.build | 3 +- src/helper/platform.cpp | 97 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 src/helper/platform.cpp diff --git a/src/helper/meson.build b/src/helper/meson.build index 2b9135c8..85db1d90 100644 --- a/src/helper/meson.build +++ b/src/helper/meson.build @@ -15,7 +15,6 @@ core_src_files += files( 'optional.hpp', 'parse_json.cpp', 'parse_json.hpp', - 'platform.hpp', 'random.cpp', 'random.hpp', 'sleep.cpp', @@ -36,6 +35,8 @@ graphics_src_files += files( 'message_box.cpp', 'message_box.hpp', 'music_utils.hpp', + 'platform.cpp', + 'platform.hpp', ) if have_file_dialogs diff --git a/src/helper/platform.cpp b/src/helper/platform.cpp new file mode 100644 index 00000000..97b67518 --- /dev/null +++ b/src/helper/platform.cpp @@ -0,0 +1,97 @@ + +#include "platform.hpp" + +#if defined(__CONSOLE__) +#include "helper/console_helpers.hpp" +#include "platform/console_buttons.hpp" +#endif + +#include +#include +#include + +namespace { + + inline std::string get_error_from_errno() { + +#if defined(_MSC_VER) + char buffer[256] = { 0 }; + const auto result = strerror_s<256>(buffer, errno); + + if (result == 0) { + return std::string{ buffer }; + + } else { + return std::string{ "Error while getting error!" }; + } + +#else + return std::string{ std::strerror(errno) }; + +#endif + } + + +} // namespace + + +[[nodiscard]] std::string utils::built_for_platform() { +#if defined(__ANDROID__) + return "Android"; +#elif defined(__SWITCH__) + return "Nintendo Switch"; +#elif defined(__3DS__) + return "Nintendo 3DS"; +#elif defined(FLATPAK_BUILD) + return "Linux (Flatpak)"; +#elif defined(__linux__) + return "Linux"; +#elif defined(_WIN32) + return "Windows"; +#elif defined(__APPLE__) + return "MacOS"; +#else +#error "Unsupported platform" +#endif +} + +// partially from: https://stackoverflow.com/questions/17347950/how-do-i-open-a-url-from-c +[[nodiscard]] bool utils::open_url(const std::string& url) { +#if defined(__ANDROID__) + const auto result = SDL_OpenURL(url.c_str()); + if (result < 0) { + spdlog::error("Error in opening url in android: {}", SDL_GetError()); + return false; + } + + return true; + +#elif defined(__CONSOLE__) + auto result = console::open_url(url); + spdlog::info("Returned string from url open was: {}", result); + return true; +#else + //TODO: this is dangerous, if we supply user input, so use SDL_OpenURL preferably + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) + const std::string shell_command = "start " + url; +#elif defined(__APPLE__) + const std::string shell_command = "open " + url; +#elif defined(__linux__) + const std::string shell_command = "xdg-open " + url; +#else +#error "Unsupported platform" +#endif + + const auto result = system(shell_command.c_str()); + if (result < 0) { + spdlog::error("Error in opening url: {}", get_error_from_errno()); + return false; + } + + + return true; + + +#endif +} From 02e4f4a9ef0fdea0528c475ae1f78e9f5377d87a Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 6 May 2024 23:30:58 +0200 Subject: [PATCH 12/76] implement input::InputManager::get_primary_input --- src/input/input.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/input/input.cpp b/src/input/input.cpp index acfc8511..bd88e98a 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -6,6 +6,7 @@ #include "mouse_input.hpp" #include "touch_input.hpp" +#include #include #include #include @@ -178,3 +179,26 @@ input::InputManager::~InputManager() = default; return nullptr; } + + +[[nodiscard]] const std::unique_ptr& input::InputManager::get_primary_input() { + +#if defined(__ANDROID__) + using PrimaryType = input::TouchInput; +#elif defined(__CONSOLE__) + using PrimaryType = input::JoystickInput; +#else + using PrimaryType = input::KeyboardInput; +#endif + + + for (const auto& input : m_inputs) { + if (const auto pointer_input = utils::is_child_class(input); pointer_input.has_value()) { + return input; + } + } + + // this should always be true, since in the initialization the first one, that is ALWAYS added is the KeyboardInput + assert(not m_inputs.empty() && "at least one input has to be given"); + return m_inputs.at(0); +} From c3a794914723456d8654b3ad2f172998d6c1ae8c Mon Sep 17 00:00:00 2001 From: Totto16 Date: Tue, 7 May 2024 01:45:20 +0200 Subject: [PATCH 13/76] - only include and not some other sdl files - refactor const_utils - refactor expected, it now can take two template arguments and uses a bool to keep track of the state - refactor the color literal parsing due to the above changes --- src/helper/color.hpp | 12 +- src/helper/color_literals.hpp | 331 ++++++++++++++++------------------ src/helper/const_utils.hpp | 81 +++++++++ src/helper/meson.build | 1 + src/helper/platform.cpp | 2 +- src/helper/utils.hpp | 11 -- src/input/guid.cpp | 35 ++++ src/input/guid.hpp | 143 +++++++++++++++ src/input/input.hpp | 1 - src/input/joystick_input.cpp | 31 +--- src/input/joystick_input.hpp | 42 +---- src/input/keyboard_input.cpp | 1 - src/input/keyboard_input.hpp | 1 - src/input/meson.build | 2 + 14 files changed, 438 insertions(+), 256 deletions(-) create mode 100644 src/helper/const_utils.hpp create mode 100644 src/input/guid.cpp create mode 100644 src/input/guid.hpp diff --git a/src/helper/color.hpp b/src/helper/color.hpp index 954ad3e6..3ba79b5a 100644 --- a/src/helper/color.hpp +++ b/src/helper/color.hpp @@ -1,5 +1,6 @@ #pragma once +#include "const_utils.hpp" #include "helper/expected.hpp" #include "helper/types.hpp" #include "helper/utils.hpp" @@ -23,6 +24,7 @@ struct HSVColor { double v; u8 a; + constexpr HSVColor(double h, double s, double v, u8 a) // NOLINT(bugprone-easily-swappable-parameters) : h{ h }, s{ s }, @@ -31,9 +33,9 @@ struct HSVColor { if (utils::is_constant_evaluated()) { - CONSTEVAL_STATIC_ASSERT(h >= 0.0 && h <= 360.0, "h has to be in range 0.0 - 360.0"); - CONSTEVAL_STATIC_ASSERT(s >= 0.0 && s <= 1.0, "s has to be in range 0.0 - 1.0"); - CONSTEVAL_STATIC_ASSERT(v >= 0.0 && v <= 1.0, "v has to be in range 0.0 - 1.0"); + CONSTEVAL_ONLY_STATIC_ASSERT(h >= 0.0 && h <= 360.0, "h has to be in range 0.0 - 360.0"); + CONSTEVAL_ONLY_STATIC_ASSERT(s >= 0.0 && s <= 1.0, "s has to be in range 0.0 - 1.0"); + CONSTEVAL_ONLY_STATIC_ASSERT(v >= 0.0 && v <= 1.0, "v has to be in range 0.0 - 1.0"); } else { @@ -50,10 +52,10 @@ struct HSVColor { } } - constexpr HSVColor() : HSVColor{ 0.0, 0.0, 0.0, 0 } { } - constexpr HSVColor(double h, double s, double v) : HSVColor{ h, s, v, 0xFF } { } + constexpr HSVColor() : HSVColor{ 0.0, 0.0, 0.0, 0 } { } + [[nodiscard]] static helper::expected from_string(const std::string& value); using InfoType = std::tuple; diff --git a/src/helper/color_literals.hpp b/src/helper/color_literals.hpp index e519c711..90b72a25 100644 --- a/src/helper/color_literals.hpp +++ b/src/helper/color_literals.hpp @@ -1,11 +1,11 @@ #pragma once #include "color.hpp" - +#include "const_utils.hpp" #include "helper/types.hpp" -#include "helper/utils.hpp" + #include -#include +#include namespace { @@ -21,96 +21,47 @@ namespace { } // namespace const_constants - namespace const_utils { - - // represents a sort of constexpr std::expected - -#define PROPAGATE(val, V) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ - do { /*NOLINT(cppcoreguidelines-avoid-do-while)*/ \ - if (not((val).has_value())) { \ - return const_utils::expected::error_result((val).error()); \ - } \ - } while (false) - - - template - requires std::is_default_constructible_v - struct expected { - private: - V m_value; - std::string m_error; - - constexpr expected(V value, const std::string& error) //NOLINT(modernize-pass-by-value) - : m_value{ value }, - m_error{ error } { } - - public: - [[nodiscard]] constexpr static expected good_result(V type) { - return { type, "" }; - } - - [[nodiscard]] constexpr static expected error_result(const std::string& error) { - return { V{}, error }; - } - - [[nodiscard]] constexpr bool has_value() const { - return m_error.empty(); - } - - [[nodiscard]] constexpr V value() const { - CONSTEVAL_STATIC_ASSERT((has_value()), "value() call on expected without value"); - return m_value; - } - - [[nodiscard]] constexpr std::string error() const { - CONSTEVAL_STATIC_ASSERT((not has_value()), "error() call on expected without error"); - return m_error; - } - }; - - } // namespace const_utils - // decode a decimal number - [[nodiscard]] constexpr const_utils::expected single_decimal_number(char n) { + [[nodiscard]] constexpr const_utils::expected single_decimal_number(char n) { if (n >= '0' && n <= '9') { - return const_utils::expected::good_result(static_cast(n - '0')); + return const_utils::expected::good_result(static_cast(n - '0')); } - return const_utils::expected::error_result("the input must be a valid decimal character"); + return const_utils::expected::error_result("the input must be a valid decimal character"); } // decode a single_hex_number - [[nodiscard]] constexpr const_utils::expected single_hex_number(char n) { + [[nodiscard]] constexpr const_utils::expected single_hex_number(char n) { if (n >= '0' && n <= '9') { - return const_utils::expected::good_result(static_cast(n - '0')); + return const_utils::expected::good_result(static_cast(n - '0')); } if (n >= 'A' && n <= 'F') { - return const_utils::expected::good_result(static_cast(n - 'A' + 10)); + return const_utils::expected::good_result(static_cast(n - 'A' + 10)); } if (n >= 'a' && n <= 'f') { - return const_utils::expected::good_result(static_cast(n - 'a' + 10)); + return const_utils::expected::good_result(static_cast(n - 'a' + 10)); } - return const_utils::expected::error_result("the input must be a valid hex character"); + return const_utils::expected::error_result("the input must be a valid hex character"); } //NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) // decode a single 2 digit color value in hex - [[nodiscard]] constexpr const_utils::expected single_hex_color_value(const char* input) { + [[nodiscard]] constexpr const_utils::expected single_hex_color_value(const char* input) { const auto first = single_hex_number(input[0]); - PROPAGATE(first, u8); + PROPAGATE(first, u8, std::string); const auto second = single_hex_number(input[1]); - PROPAGATE(second, u8); + PROPAGATE(second, u8, std::string); - return const_utils::expected::good_result((first.value() << 4) | second.value()); + return const_utils::expected::good_result((first.value() << 4) | second.value()); } template @@ -119,7 +70,9 @@ namespace { using DoubleReturnValue = CharIteratorResult; // decode a single color value as double - [[nodiscard]] constexpr const_utils::expected single_double_color_value(const char* value) { + [[nodiscard]] constexpr const_utils::expected single_double_color_value( + const char* value + ) { double result{ 0.0 }; bool after_comma = false; @@ -135,20 +88,22 @@ namespace { break; case '.': if (after_comma) { - return const_utils::expected::error_result("only one comma allowed"); + return const_utils::expected::error_result( + "only one comma allowed" + ); } after_comma = true; break; case ',': case ')': - return const_utils::expected::good_result({ result, value + i }); + return const_utils::expected::good_result({ result, value + i }); case '\0': - return const_utils::expected::error_result("input ended too early"); + return const_utils::expected::error_result("input ended too early"); default: { const auto char_result = single_decimal_number(current_char); - PROPAGATE(char_result, DoubleReturnValue); + PROPAGATE(char_result, DoubleReturnValue, std::string); const auto value_of_char = char_result.value(); @@ -163,7 +118,7 @@ namespace { } } - return const_utils::expected::error_result("unreachable"); + return const_utils::expected::error_result("unreachable"); } using AnySizeType = u32; @@ -171,7 +126,9 @@ namespace { using AnyColorReturnValue = CharIteratorResult; // decode a single_hex_number - [[nodiscard]] constexpr const_utils::expected single_color_value_any(const char* value) { + [[nodiscard]] constexpr const_utils::expected single_color_value_any( + const char* value + ) { bool accept_hex = false; AnySizeType start = 0; @@ -206,25 +163,28 @@ namespace { break; case ',': case ')': - return const_utils::expected::good_result({ result, value + i }); + return const_utils::expected::good_result({ result, value + i }); case '\0': - return const_utils::expected::error_result("input ended too early"); + return const_utils::expected::error_result("input ended too early" + ); default: { const auto char_result = accept_hex ? single_hex_number(current_char) : single_decimal_number(current_char); - PROPAGATE(char_result, AnyColorReturnValue); + PROPAGATE(char_result, AnyColorReturnValue, std::string); const auto value_of_char = char_result.value(); if (result == max_value_before_multiplication && value_of_char > max_value_before_multiplication_rest) { - return const_utils::expected::error_result("overflow detected"); + return const_utils::expected::error_result("overflow detected" + ); } if (result > max_value_before_multiplication) { - return const_utils::expected::error_result("overflow detected"); + return const_utils::expected::error_result("overflow detected" + ); } result *= mul_unit; @@ -234,26 +194,26 @@ namespace { } } - return const_utils::expected::error_result("unreachable"); + return const_utils::expected::error_result("unreachable"); } using ColorFromHexStringReturnType = std::pair; - [[nodiscard]] constexpr const_utils::expected + [[nodiscard]] constexpr const_utils::expected get_color_from_hex_string(const char* input, std::size_t size) { //NOLINT(readability-function-cognitive-complexity if (size == const_constants::hex_rgb_size) { const auto r = single_hex_color_value(input + const_constants::red_offset); - PROPAGATE(r, ColorFromHexStringReturnType); + PROPAGATE(r, ColorFromHexStringReturnType, std::string); const auto g = single_hex_color_value(input + const_constants::green_offset); - PROPAGATE(g, ColorFromHexStringReturnType); + PROPAGATE(g, ColorFromHexStringReturnType, std::string); const auto b = single_hex_color_value(input + const_constants::blue_offset); - PROPAGATE(b, ColorFromHexStringReturnType); + PROPAGATE(b, ColorFromHexStringReturnType, std::string); - return const_utils::expected::good_result({ + return const_utils::expected::good_result({ Color{ r.value(), g.value(), b.value() }, false }); @@ -262,30 +222,31 @@ namespace { if (size == const_constants::hex_rgba_size) { const auto r = single_hex_color_value(input + const_constants::red_offset); - PROPAGATE(r, ColorFromHexStringReturnType); + PROPAGATE(r, ColorFromHexStringReturnType, std::string); const auto g = single_hex_color_value(input + const_constants::green_offset); - PROPAGATE(g, ColorFromHexStringReturnType); + PROPAGATE(g, ColorFromHexStringReturnType, std::string); const auto b = single_hex_color_value(input + const_constants::blue_offset); - PROPAGATE(b, ColorFromHexStringReturnType); + PROPAGATE(b, ColorFromHexStringReturnType, std::string); const auto a = single_hex_color_value(input + const_constants::alpha_offset); - PROPAGATE(a, ColorFromHexStringReturnType); + PROPAGATE(a, ColorFromHexStringReturnType, std::string); - return const_utils::expected::good_result({ + return const_utils::expected::good_result({ Color{ r.value(), g.value(), b.value(), a.value() }, true }); } - return const_utils::expected::error_result("Unrecognized HEX literal"); + return const_utils::expected::error_result("Unrecognized HEX literal" + ); } using ColorFromRGBStringReturnType = std::pair; - [[nodiscard]] constexpr const_utils::expected + [[nodiscard]] constexpr const_utils::expected get_color_from_rgb_string(const char* input, std::size_t) { //NOLINT(readability-function-cognitive-complexity if (input[0] == 'r' && input[1] == 'g' && input[2] == 'b') { @@ -293,60 +254,65 @@ namespace { const auto r_result = single_color_value_any(input + 4); - PROPAGATE(r_result, ColorFromRGBStringReturnType); + PROPAGATE(r_result, ColorFromRGBStringReturnType, std::string); const auto [r, next_g] = r_result.value(); if (r > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "r has to be in range 0 - 255" ); } if (*next_g != ',') { - return const_utils::expected::error_result("expected ','"); + return const_utils::expected::error_result("expected ','" + ); } const auto g_result = single_color_value_any(next_g + 1); - PROPAGATE(g_result, ColorFromRGBStringReturnType); + PROPAGATE(g_result, ColorFromRGBStringReturnType, std::string); const auto [g, next_b] = g_result.value(); if (g > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "g has to be in range 0 - 255" ); } if (*next_b != ',') { - return const_utils::expected::error_result("expected ','"); + return const_utils::expected::error_result("expected ','" + ); } const auto b_result = single_color_value_any(next_b + 1); - PROPAGATE(b_result, ColorFromRGBStringReturnType); + PROPAGATE(b_result, ColorFromRGBStringReturnType, std::string); const auto [b, end] = b_result.value(); if (b > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "b has to be in range 0 - 255" ); } if (*end != ')') { - return const_utils::expected::error_result("expected ')'"); + return const_utils::expected::error_result("expected ')'" + ); } if (*(end + 1) != '\0') { - return const_utils::expected::error_result("expected end of string"); + return const_utils::expected::error_result( + "expected end of string" + ); } - return const_utils::expected::good_result({ + return const_utils::expected::good_result({ Color{ static_cast(r), static_cast(g), static_cast(b) }, false }); @@ -357,77 +323,83 @@ namespace { const auto r_result = single_color_value_any(input + 5); - PROPAGATE(r_result, ColorFromRGBStringReturnType); + PROPAGATE(r_result, ColorFromRGBStringReturnType, std::string); const auto [r, next_g] = r_result.value(); if (r > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "r has to be in range 0 - 255" ); } if (*next_g != ',') { - return const_utils::expected::error_result("expected ','"); + return const_utils::expected::error_result("expected ','" + ); } const auto g_result = single_color_value_any(next_g + 1); - PROPAGATE(g_result, ColorFromRGBStringReturnType); + PROPAGATE(g_result, ColorFromRGBStringReturnType, std::string); const auto [g, next_b] = g_result.value(); if (g > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "g has to be in range 0 - 255" ); } if (*next_b != ',') { - return const_utils::expected::error_result("expected ','"); + return const_utils::expected::error_result("expected ','" + ); } const auto b_result = single_color_value_any(next_b + 1); - PROPAGATE(b_result, ColorFromRGBStringReturnType); + PROPAGATE(b_result, ColorFromRGBStringReturnType, std::string); const auto [b, next_a] = b_result.value(); if (b > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "b has to be in range 0 - 255" ); } if (*next_a != ',') { - return const_utils::expected::error_result("expected ','"); + return const_utils::expected::error_result("expected ','" + ); } const auto a_result = single_color_value_any(next_a + 1); - PROPAGATE(a_result, ColorFromRGBStringReturnType); + PROPAGATE(a_result, ColorFromRGBStringReturnType, std::string); const auto [a, end] = a_result.value(); if (a > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "a has to be in range 0 - 255" ); } if (*end != ')') { - return const_utils::expected::error_result("expected ')'"); + return const_utils::expected::error_result("expected ')'" + ); } if (*(end + 1) != '\0') { - return const_utils::expected::error_result("expected end of string"); + return const_utils::expected::error_result( + "expected end of string" + ); } - return const_utils::expected::good_result({ + return const_utils::expected::good_result({ Color{ static_cast(r), static_cast(g), static_cast(b), static_cast(a) }, true } @@ -436,12 +408,13 @@ namespace { } - return const_utils::expected::error_result("Unrecognized RGB literal"); + return const_utils::expected::error_result("Unrecognized RGB literal" + ); } using ColorFromHSVStringReturnType = std::pair; - [[nodiscard]] constexpr const_utils::expected + [[nodiscard]] constexpr const_utils::expected get_color_from_hsv_string(const char* input, std::size_t) { //NOLINT(readability-function-cognitive-complexity if (input[0] == 'h' && input[1] == 's' && input[2] == 'v') { @@ -449,60 +422,65 @@ namespace { const auto h_result = single_double_color_value(input + 4); - PROPAGATE(h_result, ColorFromHSVStringReturnType); + PROPAGATE(h_result, ColorFromHSVStringReturnType, std::string); const auto [h, next_s] = h_result.value(); if (h < 0.0 || h > 360.0) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "h has to be in range 0.0 - 360.0" ); } if (*next_s != ',') { - return const_utils::expected::error_result("expected ','"); + return const_utils::expected::error_result("expected ','" + ); } const auto s_result = single_double_color_value(next_s + 1); - PROPAGATE(s_result, ColorFromHSVStringReturnType); + PROPAGATE(s_result, ColorFromHSVStringReturnType, std::string); const auto [s, next_v] = s_result.value(); if (s < 0.0 || s > 1.0) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "s has to be in range 0.0 - 1.0" ); } if (*next_v != ',') { - return const_utils::expected::error_result("expected ','"); + return const_utils::expected::error_result("expected ','" + ); } const auto v_result = single_double_color_value(next_v + 1); - PROPAGATE(v_result, ColorFromHSVStringReturnType); + PROPAGATE(v_result, ColorFromHSVStringReturnType, std::string); const auto [v, end] = v_result.value(); if (v < 0.0 || v > 1.0) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "v has to be in range 0.0 - 1.0" ); } if (*end != ')') { - return const_utils::expected::error_result("expected ')'"); + return const_utils::expected::error_result("expected ')'" + ); } if (*(end + 1) != '\0') { - return const_utils::expected::error_result("expected end of string"); + return const_utils::expected::error_result( + "expected end of string" + ); } - return const_utils::expected::good_result({ + return const_utils::expected::good_result({ HSVColor{ h, s, v }, false }); @@ -513,77 +491,83 @@ namespace { const auto h_result = single_double_color_value(input + 5); - PROPAGATE(h_result, ColorFromHSVStringReturnType); + PROPAGATE(h_result, ColorFromHSVStringReturnType, std::string); const auto [h, next_s] = h_result.value(); if (h < 0.0 || h > 360.0) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "h has to be in range 0.0 - 360.0" ); } if (*next_s != ',') { - return const_utils::expected::error_result("expected ','"); + return const_utils::expected::error_result("expected ','" + ); } const auto s_result = single_double_color_value(next_s + 1); - PROPAGATE(s_result, ColorFromHSVStringReturnType); + PROPAGATE(s_result, ColorFromHSVStringReturnType, std::string); const auto [s, next_v] = s_result.value(); if (s < 0.0 || s > 1.0) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "s has to be in range 0.0 - 1.0" ); } if (*next_v != ',') { - return const_utils::expected::error_result("expected ','"); + return const_utils::expected::error_result("expected ','" + ); } const auto v_result = single_double_color_value(next_v + 1); - PROPAGATE(v_result, ColorFromHSVStringReturnType); + PROPAGATE(v_result, ColorFromHSVStringReturnType, std::string); const auto [v, next_a] = v_result.value(); if (v < 0.0 || v > 1.0) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "v has to be in range 0.0 - 1.0" ); } if (*next_a != ',') { - return const_utils::expected::error_result("expected ','"); + return const_utils::expected::error_result("expected ','" + ); } const auto a_result = single_color_value_any(next_a + 1); - PROPAGATE(a_result, ColorFromHSVStringReturnType); + PROPAGATE(a_result, ColorFromHSVStringReturnType, std::string); const auto [a, end] = a_result.value(); if (a > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "a has to be in range 0 - 255" ); } if (*end != ')') { - return const_utils::expected::error_result("expected ')'"); + return const_utils::expected::error_result("expected ')'" + ); } if (*(end + 1) != '\0') { - return const_utils::expected::error_result("expected end of string"); + return const_utils::expected::error_result( + "expected end of string" + ); } - return const_utils::expected::good_result({ + return const_utils::expected::good_result({ HSVColor{ h, s, v, static_cast(a) }, true }); @@ -591,16 +575,17 @@ namespace { } - return const_utils::expected::error_result("Unrecognized HSV literal"); + return const_utils::expected::error_result("Unrecognized HSV literal" + ); } using ColorFromStringReturnType = std::tuple; - [[nodiscard]] constexpr const_utils::expected + [[nodiscard]] constexpr const_utils::expected get_color_from_string_impl(const char* input, std::size_t size) { if (size == 0) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "not enough data to determine the literal type" ); } @@ -608,55 +593,54 @@ namespace { switch (input[0]) { case '#': { const auto result = get_color_from_hex_string(input, size); - if (not result.has_value()) { - return const_utils::expected::error_result(result.error()); - } + + PROPAGATE(result, ColorFromStringReturnType, std::string); const auto value = result.value(); - return const_utils::expected::good_result( + return const_utils::expected::good_result( { value.first, color::SerializeMode::Hex, value.second } ); } case 'r': { const auto result = get_color_from_rgb_string(input, size); - if (not result.has_value()) { - return const_utils::expected::error_result(result.error()); - } + + PROPAGATE(result, ColorFromStringReturnType, std::string); const auto value = result.value(); - return const_utils::expected::good_result( + return const_utils::expected::good_result( { value.first, color::SerializeMode::RGB, value.second } ); } case 'h': { const auto result = get_color_from_hsv_string(input, size); - if (not result.has_value()) { - return const_utils::expected::error_result(result.error()); - } + + PROPAGATE(result, ColorFromStringReturnType, std::string); const auto value = result.value(); - return const_utils::expected::good_result( + return const_utils::expected::good_result( { Color{ value.first }, color::SerializeMode::HSV, value.second } ); } default: - return const_utils::expected::error_result("Unrecognized color literal"); + return const_utils::expected::error_result( + "Unrecognized color literal" + ); } } using HSVColorFromStringReturnType = std::tuple; - [[nodiscard]] constexpr const_utils::expected + [[nodiscard]] constexpr const_utils::expected get_hsv_color_from_string_impl(const char* input, std::size_t size) { if (size == 0) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "not enough data to determine the literal type" ); } @@ -664,42 +648,41 @@ namespace { switch (input[0]) { case '#': { const auto result = get_color_from_hex_string(input, size); - if (not result.has_value()) { - return const_utils::expected::error_result(result.error()); - } + + PROPAGATE(result, HSVColorFromStringReturnType, std::string); const auto value = result.value(); - return const_utils::expected::good_result( + return const_utils::expected::good_result( { value.first.to_hsv_color(), color::SerializeMode::Hex, value.second } ); } case 'r': { const auto result = get_color_from_rgb_string(input, size); - if (not result.has_value()) { - return const_utils::expected::error_result(result.error()); - } + + PROPAGATE(result, HSVColorFromStringReturnType, std::string); const auto value = result.value(); - return const_utils::expected::good_result( + return const_utils::expected::good_result( { value.first.to_hsv_color(), color::SerializeMode::RGB, value.second } ); } case 'h': { const auto result = get_color_from_hsv_string(input, size); - if (not result.has_value()) { - return const_utils::expected::error_result(result.error()); - } + + PROPAGATE(result, HSVColorFromStringReturnType, std::string); const auto value = result.value(); - return const_utils::expected::good_result( + return const_utils::expected::good_result( { value.first, color::SerializeMode::HSV, value.second } ); } default: - return const_utils::expected::error_result("Unrecognized color literal"); + return const_utils::expected::error_result( + "Unrecognized color literal" + ); } } @@ -709,13 +692,13 @@ namespace { namespace detail { - [[nodiscard]] constexpr const_utils::expected get_color_from_string( + [[nodiscard]] constexpr const_utils::expected get_color_from_string( const std::string& input ) { return get_color_from_string_impl(input.c_str(), input.size()); } - [[nodiscard]] constexpr const_utils::expected get_hsv_color_from_string( + [[nodiscard]] constexpr const_utils::expected get_hsv_color_from_string( const std::string& input ) { return get_hsv_color_from_string_impl(input.c_str(), input.size()); diff --git a/src/helper/const_utils.hpp b/src/helper/const_utils.hpp new file mode 100644 index 00000000..5176e715 --- /dev/null +++ b/src/helper/const_utils.hpp @@ -0,0 +1,81 @@ + +#pragma once + +#include "helper/utils.hpp" + +#include +#include + +// define a consteval assert, it isn't a pretty error message, but there's nothing we can do against that atm :( +// this https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2758r2.html tries to fix it +#define CONSTEVAL_ONLY_STATIC_ASSERT(CHECK, MSG) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ + ((CHECK) ? void(0) : [] { \ + /* If you see this really bad c++ error message, follow the origin of MSG, to see the real error message, c++ error messages suck xD */ \ + throw(MSG); \ + }()) + +#define CONSTEVAL_STATIC_ASSERT(CHECK, MSG) \ + do { /*NOLINT(cppcoreguidelines-avoid-do-while)*/ \ + if (utils::is_constant_evaluated()) { \ + CONSTEVAL_ONLY_STATIC_ASSERT(CHECK, MSG); \ + } else { \ + assert(CHECK&& MSG); \ + } \ + } while (false) + + +namespace const_utils { + + +#define PROPAGATE(val, V, E) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ + do { /*NOLINT(cppcoreguidelines-avoid-do-while)*/ \ + if (not((val).has_value())) { \ + return const_utils::expected::error_result((val).error()); \ + } \ + } while (false) + + // represents a sort of constexpr std::expected + template + requires std::is_default_constructible_v && std::is_default_constructible_v + struct expected { + private: + bool m_has_value; + V m_value; + E m_error; + + constexpr expected( + bool has_value, + const V& value, + const E& error + ) //NOLINT(modernize-pass-by-value) + : m_has_value{ has_value }, + m_value{ value }, + m_error{ error } { } + + public: + [[nodiscard]] constexpr static expected good_result(const V& type) { + return { true, type, E{} }; + } + + [[nodiscard]] constexpr static expected error_result(const E& error) { + return { false, V{}, error }; + } + + [[nodiscard]] constexpr bool has_value() const { + return m_has_value; + } + + [[nodiscard]] constexpr V value() const { + CONSTEVAL_STATIC_ASSERT((has_value()), "value() call on expected without value"); + + return m_value; + } + + [[nodiscard]] constexpr E error() const { + CONSTEVAL_STATIC_ASSERT((not has_value()), "error() call on expected without error"); + + return m_error; + } + }; + +} // namespace const_utils diff --git a/src/helper/meson.build b/src/helper/meson.build index 85db1d90..d4d16e6f 100644 --- a/src/helper/meson.build +++ b/src/helper/meson.build @@ -4,6 +4,7 @@ core_src_files += files( 'color.hpp', 'color_literals.hpp', 'command_line_arguments.hpp', + 'const_utils.hpp', 'constants.hpp', 'date.cpp', 'date.hpp', diff --git a/src/helper/platform.cpp b/src/helper/platform.cpp index 97b67518..2ff66e6d 100644 --- a/src/helper/platform.cpp +++ b/src/helper/platform.cpp @@ -6,8 +6,8 @@ #include "platform/console_buttons.hpp" #endif -#include #include +#include #include namespace { diff --git a/src/helper/utils.hpp b/src/helper/utils.hpp index 1b1a3cec..0da4fdab 100644 --- a/src/helper/utils.hpp +++ b/src/helper/utils.hpp @@ -7,11 +7,8 @@ #include #include #include -#include #include -#include #include -#include namespace helper { @@ -117,11 +114,3 @@ namespace utils { #else #define ASSERT(x) assert(x) // NOLINT(cppcoreguidelines-macro-usage) #endif - -// define a consteval assert, it isn't a pretty error message, but there's nothing we can do against that atm :( -// this https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2758r2.html tries to fix it -#define CONSTEVAL_STATIC_ASSERT(CHECK, MSG) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ - ((CHECK) ? void(0) : [] { \ - /* If you see this really bad c++ error message, follow the origin of MSG, to see the real error message, c++ error messages suck xD */ \ - throw(MSG); \ - }()) diff --git a/src/input/guid.cpp b/src/input/guid.cpp new file mode 100644 index 00000000..b3db1dd4 --- /dev/null +++ b/src/input/guid.cpp @@ -0,0 +1,35 @@ + +#include "guid.hpp" +#include "helper/utils.hpp" + +#include +#include + +SDL::GUID::GUID(const SDL_GUID& data) : m_guid{} { + std::copy(std::begin(data.data), std::end(data.data), std::begin(m_guid)); +} + +[[nodiscard]] helper::expected SDL::GUID::from_string(const std::string& value) { + + const auto result = detail::get_guid_from_string(value); + + if (result.has_value()) { + return result.value(); + } + + return helper::unexpected{ result.error() }; +} + + +[[nodiscard]] std::string SDL::GUID::to_string(FormatType type) const { + switch (type) { + case FormatType::Long: { + return fmt::format("{:02x}", fmt::join(m_guid, ":")); + } + case FormatType::Short: { + return fmt::format("{:02x}", fmt::join(m_guid, "")); + } + default: + utils::unreachable(); + } +} diff --git a/src/input/guid.hpp b/src/input/guid.hpp new file mode 100644 index 00000000..2cf24bc9 --- /dev/null +++ b/src/input/guid.hpp @@ -0,0 +1,143 @@ +#pragma once + + +#include "helper/const_utils.hpp" +#include "helper/expected.hpp" +#include "helper/types.hpp" + +#include +#include +#include +#include + +namespace SDL { + + + struct GUID { + public: + using ArrayType = std::array; + + private: + ArrayType m_guid; + + public: + enum class FormatType { Long, Short }; + + constexpr GUID() : m_guid{} { } + constexpr GUID(const ArrayType& data) : m_guid{ data } { } + + GUID(const SDL_GUID& data); + + [[nodiscard]] static GUID zero(); + + [[nodiscard]] static helper::expected from_string(const std::string& value); + + [[nodiscard]] bool operator==(const GUID& other) const; + + [[nodiscard]] std::string to_string(FormatType type = FormatType::Long) const; + }; +} // namespace SDL + + +template<> +struct fmt::formatter : formatter { + auto format(const SDL::GUID& guid, format_context& ctx) { + return formatter::format(guid.to_string(), ctx); + } +}; + +namespace { + + // decode a single_hex_number + [[nodiscard]] constexpr const_utils::expected single_hex_number(char n) { + if (n >= '0' && n <= '9') { + return const_utils::expected::good_result(static_cast(n - '0')); + } + + if (n >= 'A' && n <= 'F') { + return const_utils::expected::good_result(static_cast(n - 'A' + 10)); + } + + if (n >= 'a' && n <= 'f') { + return const_utils::expected::good_result(static_cast(n - 'a' + 10)); + } + + return const_utils::expected::error_result("the input must be a valid hex character"); + } + + // decode a single 2 digit color value in hex + [[nodiscard]] constexpr const_utils::expected single_hex_color_value(const char* input) { + + const auto first = single_hex_number(input[0]); + + PROPAGATE(first, u8, std::string); + + const auto second = single_hex_number(input[1]); + + PROPAGATE(second, u8, std::string); + + return const_utils::expected::good_result((first.value() << 4) | second.value()); + } + + [[nodiscard]] constexpr const_utils::expected + get_guid_from_string_impl(const char* input, std::size_t size) { + + if (size == 0) { + return const_utils::expected::error_result( + "not enough data to determine the literal type" + ); + } + + constexpr std::size_t amount = 16; + + size_t width = 2; + + if (size == amount * 2) { + width = 2; + } else if (size == (amount * 2 + (amount - 1))) { + width = 3; + } else { + + return const_utils::expected::error_result("Unrecognized guid literal"); + } + + + SDL::GUID::ArrayType result{}; + + for (size_t i = 0; i < amount; ++i) { + size_t offset = i * (width); + + + const auto temp_result = + single_hex_color_value(input + offset); //NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + + PROPAGATE(temp_result, SDL::GUID, std::string); + + const auto value = temp_result.value(); + + result.at(i) = value; + } + + return const_utils::expected::good_result(SDL::GUID{ result }); + } + +} // namespace + + +namespace detail { + + [[nodiscard]] constexpr const_utils::expected get_guid_from_string(const std::string& input + ) { + return get_guid_from_string_impl(input.c_str(), input.size()); + } + +} // namespace detail + + +consteval SDL::GUID operator""_guid(const char* input, std::size_t size) { + const auto result = get_guid_from_string_impl(input, size); + + CONSTEVAL_STATIC_ASSERT(result.has_value(), "incorrect guid literal"); + + return result.value(); +} diff --git a/src/input/input.hpp b/src/input/input.hpp index 28236d57..0a927145 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -3,7 +3,6 @@ #pragma once -#include "SDL_events.h" #include "game_input.hpp" #include "graphics/point.hpp" #include "graphics/rect.hpp" diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 91d76dc4..a205c8b6 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -1,39 +1,14 @@ #include "joystick_input.hpp" -#include "SDL_stdinc.h" #include "helper/expected.hpp" #include "helper/optional.hpp" #include "helper/utils.hpp" #include "input/input.hpp" -#include -#include -#include #include -joystick::GUID::GUID(const SDL_GUID& data) : m_guid{} { - std::copy(std::begin(data.data), std::end(data.data), std::begin(m_guid)); -} - -joystick::GUID::GUID(const ArrayType& data) : m_guid{ data } { } - - -joystick::GUID joystick::GUID::zero() { - return joystick::GUID{ joystick::GUID::ArrayType{} }; -} - - -[[nodiscard]] bool joystick::GUID::operator==(const GUID& other) const { - return this->m_guid == other.m_guid; -} - -[[nodiscard]] joystick::GUID::operator std::string() const { - return fmt::format("{}", fmt::join(m_guid, ":")); -} - - input::JoystickInput::JoystickInput(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name) : input::Input{ name, input::InputType::JoyStick }, m_joystick{ joystick }, @@ -46,7 +21,7 @@ input::JoystickInput::~JoystickInput() { [[nodiscard]] helper::optional> input::JoystickInput::get_joystick_by_guid( - const joystick::GUID& guid, + const SDL::GUID& guid, SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name @@ -102,9 +77,9 @@ input::JoystickInput::get_by_device_index(int device_index) { } - const auto guid = joystick::GUID{ SDL_JoystickGetGUID(joystick) }; + const auto guid = SDL::GUID{ SDL_JoystickGetGUID(joystick) }; - if (guid == joystick::GUID::zero()) { + if (guid == SDL::GUID::zero()) { return helper::unexpected{ fmt::format("Failed to get joystick GUID: {}", SDL_GetError()) }; } diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index fe967164..a72ec3c8 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -1,43 +1,17 @@ #pragma once -#include "SDL_joystick.h" +#include "guid.hpp" #include "helper/expected.hpp" #include "helper/parse_json.hpp" #include "input.hpp" #include "input/game_input.hpp" #include "manager/event_dispatcher.hpp" +#include #include #include -namespace joystick { - struct GUID { - private: - using ArrayType = std::array; - ArrayType m_guid; - - public: - GUID(const SDL_GUID& data); - GUID(const ArrayType& data); - - [[nodiscard]] static GUID zero(); - - [[nodiscard]] static helper::expected from_string(const std::string& value); - - [[nodiscard]] bool operator==(const GUID& other) const; - - [[nodiscard]] operator std::string() const; - }; -} // namespace joystick - - -template<> -struct fmt::formatter : formatter { - auto format(const joystick::GUID& guid, format_context& ctx) { - return formatter::format(std::string{ guid }, ctx); - } -}; namespace input { @@ -55,7 +29,7 @@ namespace input { SDL_JoystickID m_instance_id; [[nodiscard]] static helper::optional> get_joystick_by_guid( - const joystick::GUID& guid, + const SDL::GUID& guid, SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name @@ -85,7 +59,7 @@ namespace input { // essentially a GUID struct JoystickIdentification { - joystick::GUID guid; + SDL::GUID guid; static helper::expected from_string(const std::string& value); @@ -118,7 +92,7 @@ namespace input { struct SwitchJoystickInput_Type1 : JoystickInput { //TODO - static joystick::GUID guid{}; + static SDL::GUID guid{}; public: SwitchJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); @@ -134,7 +108,7 @@ namespace input { struct _3DSJoystickInput_Type1 : JoystickInput { //TODO - static joystick::GUID guid{}; + static SDL::GUID guid{}; public: _3DSJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); @@ -203,7 +177,7 @@ namespace nlohmann { std::string input; context.get_to(input); - const auto& value = joystick::GUID::from_string(input); + const auto& value = SDL::GUID::from_string(input); if (not value.has_value()) { throw nlohmann::json::type_error::create( @@ -216,7 +190,7 @@ namespace nlohmann { static void to_json(json& j, const input::JoystickIdentification& identification) { j = nlohmann::json{ - { "guid", std::string{ identification.guid } }, + { "guid", identification.guid.to_string() }, }; } }; diff --git a/src/input/keyboard_input.cpp b/src/input/keyboard_input.cpp index 64374cd6..64af8959 100644 --- a/src/input/keyboard_input.cpp +++ b/src/input/keyboard_input.cpp @@ -1,5 +1,4 @@ #include "keyboard_input.hpp" -#include "SDL_keycode.h" #include "input/input.hpp" diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index 4799486d..90e39425 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -1,6 +1,5 @@ #pragma once -#include "SDL_keycode.h" #include "game_input.hpp" #include "helper/expected.hpp" #include "helper/parse_json.hpp" diff --git a/src/input/meson.build b/src/input/meson.build index 0c9951bd..ce2407d1 100644 --- a/src/input/meson.build +++ b/src/input/meson.build @@ -2,6 +2,8 @@ graphics_src_files += files( 'console_buttons.hpp', 'game_input.cpp', 'game_input.hpp', + 'guid.cpp', + 'guid.hpp', 'input.cpp', 'input.hpp', 'input_creator.cpp', From d9ed0ef174a016081370124b9be2fc1bdb40dceb Mon Sep 17 00:00:00 2001 From: Totto16 Date: Tue, 7 May 2024 20:46:41 +0200 Subject: [PATCH 14/76] improve sdl key: - fix from_string / to_string --- src/input/input.hpp | 4 +- src/input/keyboard_input.hpp | 18 +- src/manager/sdl_key.cpp | 351 ++++++++++++++++++++++++++--------- src/manager/sdl_key.hpp | 67 ++++--- 4 files changed, 301 insertions(+), 139 deletions(-) diff --git a/src/input/input.hpp b/src/input/input.hpp index 0a927145..7524ba37 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -115,9 +115,7 @@ namespace input { for (const auto single_check : to_check) { if (std::find(already_bound.cbegin(), already_bound.cend(), single_check) != already_bound.cend()) { - return helper::unexpected{ - fmt::format("KeyCode already bound: '{}'", std::string{ single_check }) - }; + return helper::unexpected{ fmt::format("KeyCode already bound: '{}'", single_check) }; } already_bound.push_back(single_check); diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index 90e39425..589ebbbe 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -136,17 +136,17 @@ namespace nlohmann { static void to_json(json& j, const input::KeyboardSettings& settings) { j = nlohmann::json{ - { "rotate_left", settings.rotate_left.name() }, - { "rotate_right", settings.rotate_right.name() }, - { "move_left", settings.move_left.name() }, - { "move_right", settings.move_right.name() }, - { "move_down", settings.move_down.name() }, - { "drop", settings.drop.name() }, - { "hold", settings.hold.name() }, + { "rotate_left", settings.rotate_left.to_string() }, + { "rotate_right", settings.rotate_right.to_string() }, + { "move_left", settings.move_left.to_string() }, + { "move_right", settings.move_right.to_string() }, + { "move_down", settings.move_down.to_string() }, + { "drop", settings.drop.to_string() }, + { "hold", settings.hold.to_string() }, { "menu", nlohmann::json{ - { "pause", settings.pause.name() }, - { "open_settings", settings.open_settings.name() }, + { "pause", settings.pause.to_string() }, + { "open_settings", settings.open_settings.to_string() }, }, } }; } diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index 3d2a678f..e25f92ea 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -1,38 +1,33 @@ #include "sdl_key.hpp" +#include "helper/optional.hpp" #include "helper/utils.hpp" +#include #include +#include +#include #include -#include +#include +#include -SDL::Key::Key(SDL_KeyCode keycode, ModifierType modifiers) : m_keycode{ keycode }, m_modifiers{ modifiers } { } +SDL::Key::Key(SDL_KeyCode keycode, UnderlyingModifierType modifiers) + : m_keycode{ keycode }, + m_modifiers{ modifiers } { } SDL::Key::Key(SDL_KeyCode keycode, const std::vector& modifiers) : Key{ keycode, SDL::Key::sdl_modifier_from_modifiers(modifiers) } { } SDL::Key::Key(const SDL_Keysym& keysym) : Key{ static_cast(keysym.sym), keysym.mod } { } -helper::expected -SDL::Key::from_string(const std::string& value, const std::vector& modifiers) { - - const auto keycode = SDL::Key::sdl_keycode_from_string(value); - if (not keycode.has_value()) { - return helper::unexpected{ keycode.error() }; - } - - const auto raw_modifiers = SDL::Key::sdl_modifier_from_modifiers(modifiers); - return SDL::Key{ keycode.value(), raw_modifiers }; -} - [[nodiscard]] bool SDL::Key::is_key(const SDL::Key& other) const { return m_keycode == other.m_keycode; } namespace { - SDL_Keymod to_sdl_modifier(SDL::Modifier modifier) { + constexpr SDL_Keymod to_sdl_modifier(SDL::Modifier modifier) { switch (modifier) { case SDL::Modifier::LSHIFT: return KMOD_LSHIFT; @@ -76,7 +71,7 @@ namespace { } } - SDL::Modifier from_sdl_modifier(SDL_Keymod modifier) { + [[maybe_unused]] constexpr SDL::Modifier from_sdl_modifier(SDL_Keymod modifier) { switch (modifier) { case KMOD_LSHIFT: return SDL::Modifier::LSHIFT; @@ -119,121 +114,295 @@ namespace { utils::unreachable(); } } -} // namespace -[[nodiscard]] bool SDL::Key::has_modifier(const Modifier& modifier) const { - const auto sdl_modifier = to_sdl_modifier(modifier); - return (m_modifiers & sdl_modifier) != KMOD_NONE; -} + constexpr std::tuple, std::array, std::array> + get_modifier_type_array() { + return { + { + SDL::Modifier::LSHIFT, + SDL::Modifier::RSHIFT, + SDL::Modifier::LCTRL, + SDL::Modifier::RCTRL, + SDL::Modifier::LALT, + SDL::Modifier::RALT, + SDL::Modifier::LGUI, + SDL::Modifier::RGUI, + }, + { + SDL::Modifier::NUM, + SDL::Modifier::CAPS, + SDL::Modifier::MODE, + SDL::Modifier::SCROLL, + }, + { + SDL::Modifier::CTRL, + SDL::Modifier::SHIFT, + SDL::Modifier::ALT, + SDL::Modifier::GUI, + } + }; + } -[[nodiscard]] bool SDL::Key::operator==(const Key& other) const { - if (not is_key(other)) { - return false; + [[nodiscard]] std::string sdl_key_name(SDL_KeyCode keycode) { + const auto* name = SDL_GetKeyName(keycode); + if (std::strlen(name) == 0) { + throw std::runtime_error(fmt::format( + "No name for the sdl key {}: {}", static_cast>(keycode), + SDL_GetError() + )); + } + return std::string{ name }; } - // fast path, if the second one has no modifiers - if (other.m_modifiers == KMOD_NONE) { - return m_modifiers == KMOD_NONE; + [[maybe_unused]] SDL::ModifierType typeof_modifier(SDL::Modifier modifier) { + const auto& [normal, special, multiple] = get_modifier_type_array(); + + if (std::find(normal.cbegin(), normal.cend(), modifier) != normal.cend()) { + return SDL::ModifierType::Normal; + } + + if (std::find(special.cbegin(), special.cend(), modifier) != special.cend()) { + return SDL::ModifierType::Special; + } + + if (std::find(multiple.cbegin(), multiple.cend(), modifier) != multiple.cend()) { + return SDL::ModifierType::Multiple; + } + + utils::unreachable(); } - //TODO: use a feaster method, this takes a long time! - const auto it = detail::ModifierIterator(other.m_modifiers); - for (const auto& [present, modifier] : it) { - if (present != not has_modifier(modifier)) { - return false; + constexpr std::string modifier_to_string(SDL::Modifier modifier) { + switch (modifier) { + case SDL::Modifier::LSHIFT: + return "Shift-L"; + case SDL::Modifier::RSHIFT: + return "Shift-R"; + + case SDL::Modifier::LCTRL: + return "Ctrl-L"; + case SDL::Modifier::RCTRL: + return "Ctrl-R"; + + case SDL::Modifier::LALT: + return "Alt-L"; + case SDL::Modifier::RALT: + return "Alt-R"; + + case SDL::Modifier::LGUI: + return "Gui-L"; + case SDL::Modifier::RGUI: + return "Gui-R"; + + case SDL::Modifier::NUM: + return "Num"; + case SDL::Modifier::CAPS: + return "Caps"; + case SDL::Modifier::MODE: + return "Mode"; + case SDL::Modifier::SCROLL: + return "Scroll"; + + case SDL::Modifier::CTRL: + return "Ctrl"; + case SDL::Modifier::SHIFT: + return "Shift"; + case SDL::Modifier::ALT: + return "Alt"; + case SDL::Modifier::GUI: + return "Gui"; + default: + utils::unreachable(); } } - return true; -} + std::string to_lower_case(const std::string& input) { + auto result = input; + for (size_t i = 0; i < result.size(); ++i) { + auto& elem = result.at(i); + elem = std::tolower(elem); + } -[[nodiscard]] std::string SDL::Key::name() const { - const auto* name = SDL_GetKeyName(m_keycode); - if (std::strlen(name) == 0) { - throw std::runtime_error(fmt::format( - "No name for the sdl key {}: {}", static_cast>(m_keycode), - SDL_GetError() - )); + return result; } - return std::string{ name }; -} + // for string delimiter + std::vector split_string_by_char(const std::string& start, const std::string& delimiter) { + size_t pos_start = 0; + size_t pos_end; + const auto delim_len = delimiter.length(); -[[nodiscard]] helper::expected SDL::Key::sdl_keycode_from_string(const std::string& value) { - const auto key = SDL_GetKeyFromName(value.c_str()); - if (key == SDLK_UNKNOWN) { - return helper::unexpected{ - fmt::format("No sdl key for the name '{}': {}", value, SDL_GetError()) - }; + std::vector res{}; + + while ((pos_end = start.find(delimiter, pos_start)) != std::string::npos) { + auto token = start.substr(pos_start, pos_end - pos_start); + pos_start = pos_end + delim_len; + res.push_back(token); + } + + res.push_back(start.substr(pos_start)); + return res; } - return static_cast(key); -} + constexpr helper::optional modifier_from_string(std::string modifier) { -[[nodiscard]] SDL::Key::ModifierType SDL::Key::sdl_modifier_from_modifiers(const std::vector& modifiers) { - ModifierType result = KMOD_NONE; - for (const auto& modifier : modifiers) { - result |= to_sdl_modifier(modifier); + if (modifier.empty()) { + return helper::nullopt; + } + + const auto lower_case = to_lower_case(modifier); + + + const std::unordered_map map{ + { "shift-l", SDL::Modifier::LSHIFT }, + { "shift-r", SDL::Modifier::RSHIFT }, + { "ctrl-l", SDL::Modifier::LCTRL }, + { "ctrl-r", SDL::Modifier::RCTRL }, + { "alt-l", SDL::Modifier::LALT }, + { "alt-r", SDL::Modifier::RALT }, + { "gui-l", SDL::Modifier::LGUI }, + { "gui-r", SDL::Modifier::RGUI }, + { "num", SDL::Modifier::NUM }, + { "caps", SDL::Modifier::CAPS }, + { "mode", SDL::Modifier::MODE }, + { "scroll", SDL::Modifier::SCROLL }, + { "ctrl", SDL::Modifier::CTRL }, + { "shift", SDL::Modifier::SHIFT }, + { "alt", SDL::Modifier::ALT }, + { "gui", SDL::Modifier::GUI }, + }; // namespace + + if (map.contains(modifier)) { + return map.at(modifier); + } + + return helper::nullopt; } - return result; +} // namespace + + +helper::expected SDL::Key::from_string(const std::string& value) { + + + const auto tokens = split_string_by_char(value, "+"); + + std::vector modifiers{}; + + for (size_t i = 0; i < tokens.size(); ++i) { + const auto& token = tokens.at(i); + if (i + 1 == tokens.size()) { + const auto keycode = SDL::Key::sdl_keycode_from_string(token); + if (not keycode.has_value()) { + return helper::unexpected{ keycode.error() }; + } + + return SDL::Key{ keycode.value(), modifiers }; + } + + const auto modifier = modifier_from_string(token); + if (not modifier.has_value()) { + return helper::unexpected{ fmt::format("Not a valid modifier: {}", token) }; + } + + modifiers.push_back(modifier.value()); + } + + return helper::unexpected{ "empty input" }; } -detail::ModifierIterator::ModifierIterator(SDL::Key::ModifierType modifiers) { +[[nodiscard]] bool SDL::Key::has_modifier(const Modifier& modifier) const { + const auto sdl_modifier = to_sdl_modifier(modifier); + ; + + return (m_modifiers & sdl_modifier) != 0; +} + +[[nodiscard]] bool SDL::Key::has_modifier_exact(const Modifier& modifier) const { + const auto sdl_modifier = to_sdl_modifier(modifier); - const std::vector> triples{ - { KMOD_LSHIFT, KMOD_RSHIFT, KMOD_SHIFT }, - { KMOD_LCTRL, KMOD_RCTRL, KMOD_CTRL }, - { KMOD_LALT, KMOD_RALT, KMOD_ALT }, - { KMOD_LGUI, KMOD_RGUI, KMOD_GUI }, - }; + return (m_modifiers & sdl_modifier) == sdl_modifier; +} - const std::vector normal_mods{ - KMOD_NUM, - KMOD_CAPS, - KMOD_MODE, - KMOD_SCROLL, - }; +[[nodiscard]] bool SDL::Key::operator==(const Key& other) const { + return is_equal(other, true); +} - for (const auto& [left_mod, right_mod, both_mod] : triples) { +[[nodiscard]] bool SDL::Key::is_equal(const Key& other, bool ignore_special_modifiers) const { + if (not is_key(other)) { + return false; + } - std::tuple result = { false, false, false }; - if ((modifiers & both_mod) == both_mod) { - result = { true, true, true }; - } else if ((modifiers & left_mod) == left_mod) { - result = { true, false, true }; - } else if ((modifiers & right_mod) == right_mod) { - result = { false, true, true }; + // fast path if they both are exactly the same + if (other.m_modifiers == m_modifiers) { + return true; + } + + + const auto& [_, special, multiple] = get_modifier_type_array(); + + + for (const auto& modifier : multiple) { + const auto sdl_modifier = to_sdl_modifier(modifier); + if (((other.m_modifiers & sdl_modifier) & (m_modifiers & sdl_modifier)) == 0) { + return false; } + } - m_underlying_container.emplace_back(std::get<0>(result), from_sdl_modifier(left_mod)); - m_underlying_container.emplace_back(std::get<1>(result), from_sdl_modifier(right_mod)); - m_underlying_container.emplace_back(std::get<2>(result), from_sdl_modifier(both_mod)); + if (ignore_special_modifiers) { + return true; } - for (const auto& mod : normal_mods) { - m_underlying_container.emplace_back((modifiers & mod) != KMOD_NONE, from_sdl_modifier(mod)); + for (const auto& modifier : special) { + const auto sdl_modifier = to_sdl_modifier(modifier); + if ((other.m_modifiers & sdl_modifier) != (m_modifiers & sdl_modifier)) { + return false; + } } + + return true; } +[[nodiscard]] std::string SDL::Key::to_string() const { + std::vector parts{}; -[[nodiscard]] detail::ModifierIterator::const_iterator detail::ModifierIterator::begin() const { - return m_underlying_container.begin(); -} + const auto& [_, special, multiple] = get_modifier_type_array(); + + for (const auto modifier : special) { + if (has_modifier(modifier)) { + parts.emplace_back(modifier_to_string(modifier)); + } + } + + parts.emplace_back(sdl_key_name(m_keycode)); -[[nodiscard]] detail::ModifierIterator::iterator detail::ModifierIterator::begin() { - return m_underlying_container.begin(); + return fmt::format("{}", fmt::join(parts, "+")); } -[[nodiscard]] detail::ModifierIterator::const_iterator detail::ModifierIterator::end() const { - return m_underlying_container.end(); + +[[nodiscard]] helper::expected SDL::Key::sdl_keycode_from_string(const std::string& value) { + const auto key = SDL_GetKeyFromName(value.c_str()); + if (key == SDLK_UNKNOWN) { + return helper::unexpected{ + fmt::format("No sdl key for the name '{}': {}", value, SDL_GetError()) + }; + } + + return static_cast(key); } -[[nodiscard]] detail::ModifierIterator::iterator detail::ModifierIterator::end() { - return m_underlying_container.end(); +[[nodiscard]] SDL::Key::UnderlyingModifierType SDL::Key::sdl_modifier_from_modifiers( + const std::vector& modifiers +) { + UnderlyingModifierType result = KMOD_NONE; + for (const auto& modifier : modifiers) { + result |= to_sdl_modifier(modifier); + } + + return result; } diff --git a/src/manager/sdl_key.hpp b/src/manager/sdl_key.hpp index 010b183a..46f3898e 100644 --- a/src/manager/sdl_key.hpp +++ b/src/manager/sdl_key.hpp @@ -5,8 +5,8 @@ #include "helper/types.hpp" #include +#include #include -#include #include namespace SDL { @@ -35,68 +35,63 @@ namespace SDL { GUI, }; + enum class ModifierType { Normal, Multiple, Special }; + struct Key { - // the difference between SDL_Keymod and ModifierType type is, that ModifierType is SDL_Keymod or-ed together, and supports arithmetic expressions out of teh box (like & and |) - using ModifierType = std::underlying_type_t; + // the difference between SDL_Keymod and ModifierType type is, that ModifierType is SDL_Keymod or-ed together, and supports arithmetic expressions out of the box (like & and |) + using UnderlyingModifierType = std::underlying_type_t; private: SDL_KeyCode m_keycode; - ModifierType m_modifiers; + UnderlyingModifierType m_modifiers; public: - explicit Key(SDL_KeyCode keycode, ModifierType modifiers); + explicit Key(SDL_KeyCode keycode, UnderlyingModifierType modifiers); explicit Key(SDL_KeyCode keycode, const std::vector& modifiers = {}); explicit Key(const SDL_Keysym& keysym); - //TODO: also parse modifiers according to some format (E.g " + + ") - static helper::expected - from_string(const std::string& value, const std::vector& modifiers = {}); - + static helper::expected from_string(const std::string& value); [[nodiscard]] bool is_key(const Key& other) const; + /** + * @brief Checks if the key has a modifier, this performs a logical check, e.g. LALT and ALT are treated as match + * + * @param modifier + * @return bool + */ [[nodiscard]] bool has_modifier(const Modifier& modifier) const; + /** + * @brief Checks if the key has a modifier, this performs a exact check, e.g. LALT and ALT are treated as NON-match + * + * @param modifier + * @return bool + */ + [[nodiscard]] bool has_modifier_exact(const Modifier& modifier) const; + [[nodiscard]] bool operator==(const Key& other) const; - //TODO: also add function, to serialize the modifiers too - [[nodiscard]] std::string name() const; + [[nodiscard]] bool is_equal(const Key& other, bool ignore_special_modifiers = true) const; - [[nodiscard]] operator std::string() const; + [[nodiscard]] std::string to_string() const; private: [[nodiscard]] static helper::expected sdl_keycode_from_string(const std::string& value ); - [[nodiscard]] static ModifierType sdl_modifier_from_modifiers(const std::vector& modifiers); + [[nodiscard]] static UnderlyingModifierType sdl_modifier_from_modifiers(const std::vector& modifiers); }; } // namespace SDL - -namespace detail { - - struct ModifierIterator { - public: - using ContentType = std::pair; - using Container = std::vector; - using iterator = Container::iterator; - using const_iterator = Container::const_iterator; - - private: - std::vector m_underlying_container{}; - - public: - ModifierIterator(SDL::Key::ModifierType modifiers); - - [[nodiscard]] const_iterator begin() const; - [[nodiscard]] iterator begin(); - - [[nodiscard]] const_iterator end() const; - [[nodiscard]] iterator end(); - }; -} // namespace detail +template<> +struct fmt::formatter : formatter { + auto format(const SDL::Key& key, format_context& ctx) { + return formatter::format(key.to_string(), ctx); + } +}; //TODO: add input manager and rename curretn inputmanager to game_input manager or similar From a6adf17b874cd7677c3ecb407b6bf1d782636df2 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Tue, 7 May 2024 21:09:22 +0200 Subject: [PATCH 15/76] implement missing methods of KeyboardInput --- src/input/keyboard_input.cpp | 56 ++++++++++++++++++++++++++++++++++++ src/input/keyboard_input.hpp | 1 - 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/input/keyboard_input.cpp b/src/input/keyboard_input.cpp index 64af8959..72c1dc14 100644 --- a/src/input/keyboard_input.cpp +++ b/src/input/keyboard_input.cpp @@ -1,4 +1,7 @@ #include "keyboard_input.hpp" +#include "helper/optional.hpp" +#include "helper/utils.hpp" +#include "input/game_input.hpp" #include "input/input.hpp" @@ -51,6 +54,31 @@ input::KeyboardInput::KeyboardInput() : input::Input{ "keyboard", InputType::Key } +[[nodiscard]] std::string input::KeyboardInput::describe_navigation_event(NavigationEvent event) const { + + + switch (event) { + + case NavigationEvent::OK: + return fmt::format("{} or {}", SDL::Key{ SDLK_RETURN }, SDL::Key{ SDLK_SPACE }); + case NavigationEvent::DOWN: + return fmt::format("{} or {}", SDL::Key{ SDLK_DOWN }, SDL::Key{ SDLK_s }); + case NavigationEvent::UP: + return fmt::format("{} or {}", SDL::Key{ SDLK_UP }, SDL::Key{ SDLK_w }); + case NavigationEvent::LEFT: + return fmt::format("{} or {}", SDL::Key{ SDLK_LEFT }, SDL::Key{ SDLK_a }); + case NavigationEvent::RIGHT: + return fmt::format("{} or {}", SDL::Key{ SDLK_RIGHT }, SDL::Key{ SDLK_d }); + case NavigationEvent::BACK: + return fmt::format("{} or {}", SDL::Key{ SDLK_ESCAPE }, SDL::Key{ SDLK_BACKSPACE }); + case NavigationEvent::TAB: + return fmt::format("{}", SDL::Key{ SDLK_TAB }); + default: + utils::unreachable(); + } +} + + void input::KeyboardGameInput::handle_event(const SDL_Event& event) { m_event_buffer.push_back(event); } @@ -158,3 +186,31 @@ SDL::Key json_helper::get_key(const nlohmann::json& j, const std::string& name) } return value.value(); } + + +[[nodiscard]] helper::optional input::KeyboardGameInput::get_menu_event(const SDL_Event& event +) const { + + if (event.type == SDL_KEYDOWN and event.key.repeat == 0) { + const auto key = SDL::Key{ event.key.keysym }; + if (key == m_settings.pause) { + return MenuEvent::PAUSE; + } + if (key == m_settings.open_settings) { + return MenuEvent::OPEN_SETTINGS; + } + } + + return helper::nullopt; +} + +[[nodiscard]] std::string input::KeyboardGameInput::describe_menu_event(MenuEvent event) const { + switch (event) { + case input::MenuEvent::PAUSE: + return m_settings.pause.to_string(); + case input::MenuEvent::OPEN_SETTINGS: + return m_settings.open_settings.to_string(); + default: + utils::unreachable(); + } +} diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index 589ebbbe..40b654f4 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -76,7 +76,6 @@ namespace input { [[nodiscard]] std::string describe_menu_event(MenuEvent event) const override; - private: [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event) const; }; From 39b34d213e822d180c1132cdb70b633471c0ca87 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Tue, 7 May 2024 21:23:05 +0200 Subject: [PATCH 16/76] - implement missing methods of MouseInput - throw error in cases, we need to describe unsupported navigation events instead of returning a string, that says, that it's unsupported --- src/input/joystick_input.cpp | 4 +- src/input/mouse_input.cpp | 89 +++++++++++------------------------- src/input/mouse_input.hpp | 3 -- 3 files changed, 29 insertions(+), 67 deletions(-) diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index a205c8b6..f2e35c04 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -259,7 +259,7 @@ input::SwitchJoystickInput_Type1::SwitchJoystickInput_Type1( case NavigationEvent::RIGHT: return "Right"; case NavigationEvent::TAB: - return "Unsupported"; + throw std::runtime_error("Tab is not supported"); default: utils::unreachable(); } @@ -336,7 +336,7 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( case NavigationEvent::RIGHT: return "Right"; case NavigationEvent::TAB: - return "Unsupported"; + throw std::runtime_error("Tab is not supported"); default: utils::unreachable(); } diff --git a/src/input/mouse_input.cpp b/src/input/mouse_input.cpp index 24747ae6..96a23994 100644 --- a/src/input/mouse_input.cpp +++ b/src/input/mouse_input.cpp @@ -1,8 +1,13 @@ #include "mouse_input.hpp" +#include "graphics/point.hpp" +#include "helper/optional.hpp" +#include "input/input.hpp" +input::MouseInput::MouseInput() : PointerInput("mouse") { } + [[nodiscard]] SDL_Event input::MouseInput::offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) const { @@ -26,79 +31,39 @@ } -//TODO: -/* -[[nodiscard]] bool utils::event_is_click_event(const SDL_Event& event, CrossPlatformClickEvent click_type) { - - - decltype(event.type) desired_type{}; - switch (click_type) { - case CrossPlatformClickEvent::Motion: - desired_type = SDL_MOUSEMOTION; - break; - case CrossPlatformClickEvent::ButtonDown: - desired_type = SDL_MOUSEBUTTONDOWN; - break; - case CrossPlatformClickEvent::ButtonUp: - desired_type = SDL_MOUSEBUTTONUP; - break; - case CrossPlatformClickEvent::Any: - return event.type == SDL_MOUSEMOTION - || ((event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) - && event.button.button == SDL_BUTTON_LEFT); - default: - utils::unreachable(); - } - - - return event.type == desired_type && event.button.button == SDL_BUTTON_LEFT; - */ - - -/** - - -[[nodiscard]] std::pair utils::get_raw_coordinates(const Window* window, const SDL_Event& event) { - - assert(utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any) && "expected a click event"); +[[nodiscard]] helper::optional input::MouseInput::get_navigation_event(const SDL_Event&) const { + return helper::nullopt; +} -#if defined(__ANDROID__) - // These are doubles, from 0-1 (or if using virtual layouts > 0) in percent, the have to be casted to absolut x coordinates! - const double x_percent = event.tfinger.x; - const double y_percent = event.tfinger.y; - const auto window_size = window->size(); - const auto x = static_cast(std::round(x_percent * window_size.x)); - const auto y = static_cast(std::round(y_percent * window_size.y)); +[[nodiscard]] std::string input::MouseInput::describe_navigation_event(NavigationEvent) const { + throw std::runtime_error("not supported"); +} +[[nodiscard]] helper::optional input::MouseInput::get_pointer_event(const SDL_Event& event +) const { -#elif defined(__SWITCH__) - UNUSED(window); - UNUSED(event); - throw std::runtime_error("Not supported on the Nintendo switch"); - int x{}; - int y{}; -#else - UNUSED(window); + auto pointer_event = input::PointerEvent::PointerUp; - Sint32 x{}; - Sint32 y{}; switch (event.type) { case SDL_MOUSEMOTION: - x = event.motion.x; - y = event.motion.y; - break; + return input::PointerEventHelper{ + shapes::IPoint{ event.motion.x, event.motion.y }, + input::PointerEvent::Motion + }; case SDL_MOUSEBUTTONDOWN: + pointer_event = input::PointerEvent::PointerDown; + break; case SDL_MOUSEBUTTONUP: - x = event.button.x; - y = event.button.y; break; default: - utils::unreachable(); + return helper::nullopt; } -#endif + if (event.button.button != SDL_BUTTON_LEFT) { + return helper::nullopt; + } - return { static_cast(x), static_cast(y) }; -} + shapes::IPoint pos{ event.button.x, event.button.y }; - */ + return input::PointerEventHelper{ pos, pointer_event }; +} diff --git a/src/input/mouse_input.hpp b/src/input/mouse_input.hpp index bc4baa36..4ac37c82 100644 --- a/src/input/mouse_input.hpp +++ b/src/input/mouse_input.hpp @@ -1,16 +1,13 @@ #pragma once #include "input.hpp" -#include "recordings/recording_reader.hpp" -#include namespace input { struct MouseInput : public PointerInput { public: MouseInput(); - virtual ~MouseInput(); [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; From f127e7ea8fba8736f18082a8eb36ffdf4d441b09 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Tue, 7 May 2024 03:12:18 +0200 Subject: [PATCH 17/76] fix some small things: - correct the sdl_key tests - check for the m_instance_id on all joystick events --- src/input/guid.cpp | 4 + src/input/guid.hpp | 2 - src/input/joystick_input.cpp | 22 ++- src/input/touch_input.cpp | 94 +++++++++++ src/input/touch_input.hpp | 76 --------- tests/graphics/sdl_key.cpp | 311 +---------------------------------- 6 files changed, 125 insertions(+), 384 deletions(-) diff --git a/src/input/guid.cpp b/src/input/guid.cpp index b3db1dd4..5862510b 100644 --- a/src/input/guid.cpp +++ b/src/input/guid.cpp @@ -20,6 +20,10 @@ SDL::GUID::GUID(const SDL_GUID& data) : m_guid{} { return helper::unexpected{ result.error() }; } +[[nodiscard]] bool SDL::GUID::operator==(const GUID& other) const { + return m_guid == other.m_guid; +} + [[nodiscard]] std::string SDL::GUID::to_string(FormatType type) const { switch (type) { diff --git a/src/input/guid.hpp b/src/input/guid.hpp index 2cf24bc9..a54e5d89 100644 --- a/src/input/guid.hpp +++ b/src/input/guid.hpp @@ -28,8 +28,6 @@ namespace SDL { GUID(const SDL_GUID& data); - [[nodiscard]] static GUID zero(); - [[nodiscard]] static helper::expected from_string(const std::string& value); [[nodiscard]] bool operator==(const GUID& other) const; diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index f2e35c04..66160f9b 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -79,7 +79,7 @@ input::JoystickInput::get_by_device_index(int device_index) { const auto guid = SDL::GUID{ SDL_JoystickGetGUID(joystick) }; - if (guid == SDL::GUID::zero()) { + if (guid == SDL::GUID{}) { return helper::unexpected{ fmt::format("Failed to get joystick GUID: {}", SDL_GetError()) }; } @@ -368,6 +368,11 @@ void JoystickGameInput::update(SimulationStep simulation_step_index) { //TODO: use settings helper::optional JoystickSwitchGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event) const { if (event.type == SDL_JOYBUTTONDOWN) { + + if (event.jbutton.which != m_instance_id) { + return helper::nullopt; + } + //TODO: use switch case const auto button = event.jbutton.button; if (button == JOYCON_DPAD_LEFT) { @@ -392,6 +397,11 @@ helper::optional JoystickSwitchGameInput_Type1::sdl_event_to_input_e return InputEvent::HoldPressed; } } else if (event.type == SDL_JOYBUTTONUP) { + + if (event.jbutton.which != m_instance_id) { + return helper::nullopt; + } + const auto button = event.jbutton.button; if (button == JOYCON_DPAD_LEFT) { return InputEvent::RotateLeftReleased; @@ -422,6 +432,11 @@ helper::optional JoystickSwitchGameInput_Type1::sdl_event_to_input_e //TODO: use settings helper::optional JoystickInput::sdl_event_to_input_event(const SDL_Event& event) const { if (event.type == SDL_JOYBUTTONDOWN) { + + if (event.jbutton.which != m_instance_id) { + return helper::nullopt; + } + const auto button = event.jbutton.button; if (button == JOYCON_L) { return InputEvent::RotateLeftPressed; @@ -445,6 +460,11 @@ helper::optional JoystickInput::sdl_event_to_input_event(const SDL_E return InputEvent::HoldPressed; } } else if (event.type == SDL_JOYBUTTONUP) { + + if (event.jbutton.which != m_instance_id) { + return helper::nullopt; + } + const auto button = event.jbutton.button; if (button == JOYCON_L) { return InputEvent::RotateLeftReleased; diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index f38d8181..0f2c1cc5 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -153,6 +153,23 @@ input::TouchInput::get_by_device_index(const std::shared_ptr& window, in } +[[nodiscard]] helper::optional input::TouchInput::get_navigation_event(const SDL_Event& event) const { + +} + +[[nodiscard]] std::string input::TouchInput::describe_navigation_event(NavigationEvent event) const { } + +[[nodiscard]] helper::optional input::TouchInput::get_pointer_event(const SDL_Event& event) const { + +} + +[[nodiscard]] SDL_Event input::TouchInput::offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) + const { + + + } + + [[nodiscard]] helper::expected input::TouchSettings::validate() const { if (move_x_threshold > 1.0 || move_x_threshold < 0.0) { @@ -219,6 +236,83 @@ void input::TouchInputManager::discover_devices( } +//TODO: +/* + + + decltype(event.type) desired_type{}; + switch (click_type) { + case CrossPlatformClickEvent::Motion: + desired_type = SDL_FINGERMOTION; + break; + case CrossPlatformClickEvent::ButtonDown: + desired_type = SDL_FINGERDOWN; + break; + case CrossPlatformClickEvent::ButtonUp: + desired_type = SDL_FINGERUP; + break; + case CrossPlatformClickEvent::Any: + return event.type == SDL_FINGERMOTION || event.type == SDL_FINGERDOWN || event.type == SDL_FINGERUP; + default: + utils::unreachable(); + } + + return event.type == desired_type; + */ + + +/** + + + +[[nodiscard]] std::pair utils::get_raw_coordinates(const Window* window, const SDL_Event& event) { + + assert(utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any) && "expected a click event"); + +#if defined(__ANDROID__) + // These are doubles, from 0-1 (or if using virtual layouts > 0) in percent, the have to be casted to absolut x coordinates! + const double x_percent = event.tfinger.x; + const double y_percent = event.tfinger.y; + const auto window_size = window->size(); + const auto x = static_cast(std::round(x_percent * window_size.x)); + const auto y = static_cast(std::round(y_percent * window_size.y)); + + +#elif defined(__SWITCH__) + UNUSED(window); + UNUSED(event); + throw std::runtime_error("Not supported on the Nintendo switch"); + int x{}; + int y{}; +#else + UNUSED(window); + + Sint32 x{}; + Sint32 y{}; + switch (event.type) { + case SDL_MOUSEMOTION: + x = event.motion.x; + y = event.motion.y; + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + x = event.button.x; + y = event.button.y; + break; + default: + utils::unreachable(); + } +#endif + + + return { static_cast(x), static_cast(y) }; +} + + + * + */ + + //TODO: /* [[nodiscard]] bool utils::event_is_action(const SDL_Event& event, const CrossPlatformAction action) { diff --git a/src/input/touch_input.hpp b/src/input/touch_input.hpp index 7dd6ec8c..f86f0715 100644 --- a/src/input/touch_input.hpp +++ b/src/input/touch_input.hpp @@ -207,79 +207,3 @@ namespace nlohmann { }; } // namespace nlohmann - -//TODO: -/* - - - decltype(event.type) desired_type{}; - switch (click_type) { - case CrossPlatformClickEvent::Motion: - desired_type = SDL_FINGERMOTION; - break; - case CrossPlatformClickEvent::ButtonDown: - desired_type = SDL_FINGERDOWN; - break; - case CrossPlatformClickEvent::ButtonUp: - desired_type = SDL_FINGERUP; - break; - case CrossPlatformClickEvent::Any: - return event.type == SDL_FINGERMOTION || event.type == SDL_FINGERDOWN || event.type == SDL_FINGERUP; - default: - utils::unreachable(); - } - - return event.type == desired_type; - */ - - -/** - - - -[[nodiscard]] std::pair utils::get_raw_coordinates(const Window* window, const SDL_Event& event) { - - assert(utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any) && "expected a click event"); - -#if defined(__ANDROID__) - // These are doubles, from 0-1 (or if using virtual layouts > 0) in percent, the have to be casted to absolut x coordinates! - const double x_percent = event.tfinger.x; - const double y_percent = event.tfinger.y; - const auto window_size = window->size(); - const auto x = static_cast(std::round(x_percent * window_size.x)); - const auto y = static_cast(std::round(y_percent * window_size.y)); - - -#elif defined(__SWITCH__) - UNUSED(window); - UNUSED(event); - throw std::runtime_error("Not supported on the Nintendo switch"); - int x{}; - int y{}; -#else - UNUSED(window); - - Sint32 x{}; - Sint32 y{}; - switch (event.type) { - case SDL_MOUSEMOTION: - x = event.motion.x; - y = event.motion.y; - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - x = event.button.x; - y = event.button.y; - break; - default: - utils::unreachable(); - } -#endif - - - return { static_cast(x), static_cast(y) }; -} - - - * - */ diff --git a/tests/graphics/sdl_key.cpp b/tests/graphics/sdl_key.cpp index f1b9b941..1bd41014 100644 --- a/tests/graphics/sdl_key.cpp +++ b/tests/graphics/sdl_key.cpp @@ -1,314 +1,15 @@ -#include "helper/color.hpp" +#include "manager/sdl_key.hpp" #include #include -#include -#include -namespace { - using ForeachCallback = std::function; - void foreach_loop(const ForeachCallback& callback) { - u8 r{ 0 }; - u8 g{ 0 }; - u8 b{ 0 }; - do { // NOLINT(cppcoreguidelines-avoid-do-while) - do { // NOLINT(cppcoreguidelines-avoid-do-while) - do { // NOLINT(cppcoreguidelines-avoid-do-while) - callback(r, g, b); - } while (r++ != 255); - } while (g++ != 255); - } while (b++ != 255); - } -} // namespace +//TODO: improve -// helper thought just for the tests -[[nodiscard]] constexpr bool operator==(const HSVColor& value1, const HSVColor& value2) { - return value1.to_rgb_color() == value2.to_rgb_color(); -} - - -// make colors printable -void PrintTo(const Color& color, std::ostream* os) { - *os << color.to_string(); -} - -void PrintTo(const HSVColor& color, std::ostream* os) { - *os << color.to_string(); -} - - -// make helper::expected printable -template -void PrintTo(const helper::expected& value, std::ostream* os) { - if (value.has_value()) { - *os << "Value: " << ::testing::PrintToString(value.value()); - } else { - *os << "Error: " << ::testing::PrintToString(value.error()); - } -} - - -MATCHER(ExpectedHasValue, "expected has value") { - return arg.has_value(); -} - -MATCHER(ExpectedHasError, "expected has error") { - return not arg.has_value(); -} - -TEST(Color, DefaultConstruction) { - const auto c1 = Color{}; - const auto c2 = Color{ 0, 0, 0, 0 }; - ASSERT_EQ(c1, c2); -} - -TEST(Color, ConstructorProperties) { - foreach_loop([](u8 r, u8 g, u8 b) { - const auto c1 = Color{ r, g, b }; - const auto c2 = Color{ r, g, b, 0xFF }; - ASSERT_EQ(c1, c2); - }); -} - -TEST(Color, FromStringValid) { - - const std::vector> valid_values{ - { "#FFAA33", { Color{ 0xFF, 0xAA, 0x33 }, color::SerializeMode::Hex, false } }, - { "#FF00FF00", { Color{ 0xFF, 0x00, 0xFF, 0x00 }, color::SerializeMode::Hex, true } }, - { "rgb(0,0,0)", { Color{ 0, 0, 0 }, color::SerializeMode::RGB, false } }, - { "rgba(0,0,0,0)", { Color{ 0, 0, 0, 0 }, color::SerializeMode::RGB, true } }, - { "hsv(0,0,0)", { HSVColor{ 0, 0, 0 }, color::SerializeMode::HSV, false } }, - { "hsva(340,0,0.5,0)", { HSVColor{ 340, 0, 0.5, 0 }, color::SerializeMode::HSV, true } }, - { "#ffaa33", { Color{ 0xff, 0xaa, 0x33 }, color::SerializeMode::Hex, false } }, - { "hsv(0, 0.00_000_000_1, 0)", { HSVColor{ 0, 0.000000001, 0 }, color::SerializeMode::HSV, false } }, - { "hsva(0, 0, 0, 0xFF)", { HSVColor{ 0, 0, 0, 0xFF }, color::SerializeMode::HSV, true } }, - { "rgba(0, 0xFF, 0, 255)", { Color{ 0, 0xFF, 0, 255 }, color::SerializeMode::RGB, true } }, - { "rgba(0, 0xFF, 0, 1_0_0)", { Color{ 0, 0xFF, 0, 100 }, color::SerializeMode::RGB, true } }, - }; - - for (const auto& [valid_string, expected_result] : valid_values) { - const auto result = Color::from_string_with_info(valid_string); - ASSERT_THAT(result, ExpectedHasValue()) << "Input was: " << valid_string; - ASSERT_EQ(result.value(), expected_result) << "Input was: " << valid_string; - - const auto color_string = std::get<0>(result.value()).to_string(color::SerializeMode::Hex); - - const auto converted_color = Color::from_string_with_info(color_string); - ASSERT_THAT(converted_color, ExpectedHasValue()) << "Input was: " << color_string; - ASSERT_EQ(result.value(), expected_result) << "Input was: " << color_string; - } -} - -TEST(Color, FromStringInvalid) { - - const std::vector> invalid_strings{ - { "", "not enough data to determine the literal type" }, - { "#44", "Unrecognized HEX literal" }, - { "#Z", "Unrecognized HEX literal" }, - { "#ZZFF", "Unrecognized HEX literal" }, - { "u", "Unrecognized color literal" }, - { "#IIFFFFFF", "the input must be a valid hex character" }, - { "#FFIIFFFF", "the input must be a valid hex character" }, - { "#FFFFIIFF", "the input must be a valid hex character" }, - { "#FFFFFFII", "the input must be a valid hex character" }, - { "#FFFF4T", "the input must be a valid hex character" }, - { "#0000001", "Unrecognized HEX literal" }, - { "hsl(0,0,0)", "Unrecognized HSV literal" }, - { "rgg(0,0,0)", "Unrecognized RGB literal" }, - { "hsva(9,9,9)", "s has to be in range 0.0 - 1.0" }, - { "hsva(9,9,9,10212)", "s has to be in range 0.0 - 1.0" }, - { "hsv(-1,0,0)", "the input must be a valid decimal character" }, - { "hsv(404040,0,0)", "h has to be in range 0.0 - 360.0" }, - { "hsv(0,1.4,0)", "s has to be in range 0.0 - 1.0" }, - { "hsv(0,0,1.7)", "v has to be in range 0.0 - 1.0" }, - { "hsva(1321.4,0,0,0)", "h has to be in range 0.0 - 360.0" }, - { "hsva(0,1.4,0,0)", "s has to be in range 0.0 - 1.0" }, - { "hsva(0,0,1.7,0)", "v has to be in range 0.0 - 1.0" }, - { "hsva(0, 0, 0, 256)", "a has to be in range 0 - 255" }, - { "hsv(0,0,1.7.8)", "only one comma allowed" }, - { "hsv(0", "input ended too early" }, - { "rgba(0, 0xFFF, 0, 255)", "g has to be in range 0 - 255" }, - { "rgba(0, 0xFF, 0)", "expected ','" }, - { "rgb(0, 0xFF, 0, 255)", "expected ')'" }, - { "rgba(0, 0xFF, 0, 256)", "a has to be in range 0 - 255" }, - { "rgba(0", "input ended too early" }, - { "rgba(0, 0xFF, 0, 4_294_967_296)", "overflow detected" }, - { "rgba(0, 0xFF, 0, 4_294_967_300)", "overflow detected" }, - { "rgba(0, 0xFF, 0, 121_123_124_294_967_300)", "overflow detected" }, - { "rgb(256,0,0)", "r has to be in range 0 - 255" }, - { "rgb(0)", "expected ','" }, - { "rgb(0,256,0)", "g has to be in range 0 - 255" }, - { "rgb(0,0)", "expected ','" }, - { "rgb(0,0,256)", "b has to be in range 0 - 255" }, - { "rgb(0,0,0,", "expected ')'" }, - { "rgb(0,0,255) ", "expected end of string" }, - { "rgba(256,0,0,0)", "r has to be in range 0 - 255" }, - { "rgba(0)", "expected ','" }, - { "rgba(0,256,0,0)", "g has to be in range 0 - 255" }, - { "rgba(0,0)", "expected ','" }, - { "rgba(0,0,256,0)", "b has to be in range 0 - 255" }, - { "rgba(0,0,0)", "expected ','" }, - { "rgba(0,0,0,256)", "a has to be in range 0 - 255" }, - { "rgba(0,0,0,0,", "expected ')'" }, - { "rgba(0,0,0,255) ", "expected end of string" }, - { "hsv(0)", "expected ','" }, - { "hsv(0,0)", "expected ','" }, - { "hsv(0,0,0,", "expected ')'" }, - { "hsv(0,0,0) ", "expected end of string" }, - { "hsva(0)", "expected ','" }, - { "hsva(0,0)", "expected ','" }, - { "hsva(0,0,0)", "expected ','" }, - { "hsva(0,0,0,0,", "expected ')'" }, - { "hsva(0,0,0,255) ", "expected end of string" }, - }; - - for (const auto& [invalid_string, error_message] : invalid_strings) { - const auto result = Color::from_string(invalid_string); - ASSERT_THAT(result, ExpectedHasError()) << "Input was: " << invalid_string; - ASSERT_EQ(result.error(), error_message) << "Input was: " << invalid_string; - } -} - - -TEST(HSVColor, DefaultConstruction) { - const auto c1 = HSVColor{}; - const auto c2 = HSVColor{ 0, 0, 0, 0 }; - ASSERT_EQ(c1, c2); -} - -TEST(HSVColor, ConstructorProperties) { - - const std::vector> values{ - { 0.0, 0.0, 0.0 }, - { 360.0, 0.0, 0.0 }, - { 360.0, 1.0, 0.0 }, - { 360.0, 1.0, 1.0 }, - { 57.0, 0.6, 0.8 } - }; - - for (const auto& [h, s, v] : values) { - const auto c1 = HSVColor{ h, s, v }; - const auto c2 = HSVColor{ h, s, v, 0xFF }; - ASSERT_EQ(c1, c2); - } -} - -TEST(HSVColor, InvalidConstructors) { +TEST(SDLKey, SimpleComparision) { + const auto key1 = SDL::Key{ SDLK_k }; - const std::vector> invalid_values{ - { -1.0, 0.0, 0.0 }, - { 360.0, -1.0, 0.0 }, - { 360.0, 1.0, -1.0 }, - { 460.0, 1.0, 1.0 }, - { 57.0, 2.6, 0.8 }, - { 57.0, 1.6, 3.8 } - }; - - for (const auto& [h, s, v] : invalid_values) { - - const auto construct = [h, s, v]() { HSVColor{ h, s, v }; }; //NOLINT(clang-analyzer-core.NullDereference) - - ASSERT_ANY_THROW(construct()); //NOLINT(*) - } -} - -#ifndef COLOR_TEST_MODE -#define COLOR_TEST_MODE 0 -#endif - - -TEST(ColorConversion, HSV_to_RGB_to_HSV) { //NOLINT(readability-function-cognitive-complexity) - -#if COLOR_TEST_MODE == 0 - const std::vector colors{ - HSVColor{ 2, 0.3, 0.6 }, - HSVColor{ 82, 0.3, 0.6 }, - HSVColor{ 142, 0.3, 0.6 }, - HSVColor{ 192, 0.3, 0.6 }, - HSVColor{ 252, 0.3, 0.6 }, - HSVColor{ 312, 0.3, 0.6 }, - }; - - for (const auto& original_color : colors) { - -#else -#if COLOR_TEST_MODE == 1 - constexpr const auto step_amount = 1000; // arbitrary number, to make it kinda exhaustive -#else - constexpr const auto step_amount = COLOR_TEST_MODE; -#endif - - for (double h = 0.0; h < 360.0; h += 360.0 / step_amount) { - for (double s = 0.0; s < 1.0; s += 1.0 / step_amount) { - for (double v = 0.0; v < 1.0; v += 1.0 / step_amount) { - const auto original_color = HSVColor{ h, s, v }; - - -#endif - const auto convert = [&original_color]() { - const auto converted_color = original_color.to_rgb_color(); - - const auto result_color = converted_color.to_hsv_color(); - - ASSERT_EQ(original_color, result_color) << "Intermediate step: " << converted_color.to_string(); - }; - - ASSERT_NO_THROW(convert()); //NOLINT(*) - -#if COLOR_TEST_MODE != 0 - } -} -#endif -} -} - - -TEST(ColorConversion, RGG_to_HSV_to_RGB) { //NOLINT(readability-function-cognitive-complexity) - -#if COLOR_TEST_MODE == 0 - const std::vector colors{ - Color{ 0, 0, 0 }, - Color{ 180, 135, 223 }, - Color{ 12, 34, 130 }, - Color{ 79, 85, 20 }, - Color{ 155, 174, 2 }, - Color{ 243, 32, 34 }, - }; - - for (const auto& original_color : colors) { - -#else - -#if COLOR_TEST_MODE == 1 - constexpr const u8 step_amount = 0xFF; // max u8 -#else - - constexpr const u8 step_amount = COLOR_TEST_MODE; -#endif - - constexpr const u8 u8_max = std::numeric_limits::max(); - constexpr const u8 step_size = u8_max / step_amount; - - - for (u8 r = 0.0; u8_max - r < step_amount; r += step_size) { - for (u8 g = 0.0; u8_max - g < step_amount; g += step_size) { - for (u8 b = 0.0; u8_max - b < step_amount; b += step_size) { - const auto original_color = Color{ r, g, b }; -#endif - const auto convert = [&original_color]() { - const auto converted_color = original_color.to_hsv_color(); - - const auto result_color = converted_color.to_rgb_color(); - - ASSERT_EQ(original_color, result_color) << "Intermediate step: " << converted_color.to_string(); - }; - - ASSERT_NO_THROW(convert()); //NOLINT(*) -#if COLOR_TEST_MODE != 0 - } -} -#endif -} + ASSERT_EQ(key1.name(), "K"); + ASSERT_EQ(key1.has_modifier(SDL::Modifier::ALT), false); } From c2322cda101cea4b0a318fd04b994a52cbd0c1cd Mon Sep 17 00:00:00 2001 From: Totto16 Date: Tue, 7 May 2024 03:28:17 +0200 Subject: [PATCH 18/76] implement missing TouchInput methods --- src/input/touch_input.cpp | 242 +++++++++++++------------------------- 1 file changed, 85 insertions(+), 157 deletions(-) diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index 0f2c1cc5..bb16ef39 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -2,6 +2,9 @@ #include "touch_input.hpp" +#include "graphics/point.hpp" +#include "helper/optional.hpp" +#include "input/input.hpp" #include #include @@ -28,13 +31,21 @@ helper::optional input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function-cognitive-complexity) const SDL_Event& event ) { - //TODO to handle those things better, holding has to be supported - // also take into accounts fingerId, since there may be multiple fingers, each finger has it's own saved state - const SDL_FingerID finger_id = event.tfinger.fingerId; + //TODO: + /* if (event.tfinger.touchId != m_id) { + return helper::nullopt; + } */ + + //TODO to handle those things better, holding has to be supported if (event.type == SDL_FINGERDOWN) { + + // also take into accounts fingerId, since there may be multiple fingers, each finger has it's own saved state + const SDL_FingerID finger_id = event.tfinger.fingerId; + + if (m_finger_state.contains(finger_id) and m_finger_state.at(finger_id).has_value()) { // there are some valid reasons, this can occur now return helper::nullopt; @@ -54,6 +65,11 @@ input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function- if (event.type == SDL_FINGERUP) { + + // also take into accounts fingerId, since there may be multiple fingers, each finger has it's own saved state + const SDL_FingerID finger_id = event.tfinger.fingerId; + + if (!m_finger_state.contains(finger_id) or !m_finger_state.at(finger_id).has_value()) { // there are some valid reasons, this can occur now return helper::nullopt; @@ -153,38 +169,66 @@ input::TouchInput::get_by_device_index(const std::shared_ptr& window, in } -[[nodiscard]] helper::optional input::TouchInput::get_navigation_event(const SDL_Event& event) const { +[[nodiscard]] helper::optional input::TouchInput::get_navigation_event(const SDL_Event& event +) const { + //technically no touch event, but it's a navigation event, and by APi design it can also handle those + if (event.type == SDL_KEYDOWN and event.key.keysym.sym == SDLK_AC_BACK) { + return input::NavigationEvent::BACK; + } + return helper::nullopt; } -[[nodiscard]] std::string input::TouchInput::describe_navigation_event(NavigationEvent event) const { } - -[[nodiscard]] helper::optional input::TouchInput::get_pointer_event(const SDL_Event& event) const { - +[[nodiscard]] std::string input::TouchInput::describe_navigation_event(NavigationEvent event) const { + switch (event) { + case NavigationEvent::BACK: + return "Back"; + case NavigationEvent::OK: + case NavigationEvent::DOWN: + case NavigationEvent::UP: + case NavigationEvent::LEFT: + case NavigationEvent::RIGHT: + case NavigationEvent::TAB: + return "Unsupported"; + default: + utils::unreachable(); + } } -[[nodiscard]] SDL_Event input::TouchInput::offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) - const { +[[nodiscard]] helper::optional input::TouchInput::get_pointer_event(const SDL_Event& event +) const { - - } - - -[[nodiscard]] helper::expected input::TouchSettings::validate() const { + auto pointer_event = input::PointerEvent::PointerUp; - if (move_x_threshold > 1.0 || move_x_threshold < 0.0) { - return helper::unexpected{ - fmt::format("move_x_threshold has to be in range [0,1] but was {}", move_x_threshold) - }; + switch (event.type) { + case SDL_FINGERMOTION: + pointer_event = input::PointerEvent::Motion; + break; + case SDL_FINGERDOWN: + pointer_event = input::PointerEvent::PointerDown; + break; + case SDL_FINGERUP: + break; + default: + return helper::nullopt; } - if (move_y_threshold > 1.0 || move_y_threshold < 0.0) { - return helper::unexpected{ - fmt::format("move_y_threshold has to be in range [0,1] but was {}", move_y_threshold) - }; + if (event.tfinger.touchId != m_id) { + return helper::nullopt; } - return true; + // These are doubles, from 0-1 (or if using virtual layouts > 0) in percent, the have to be casted to absolut x coordinates! + const double x_percent = event.tfinger.x; + const double y_percent = event.tfinger.y; + const auto window_size = m_window->size(); + const auto x = static_cast(std::round(x_percent * window_size.x)); + const auto y = static_cast(std::round(y_percent * window_size.y)); + + + return input::PointerEventHelper{ + shapes::IPoint{ x, y }, + pointer_event + }; } @@ -198,7 +242,6 @@ input::TouchInput::get_by_device_index(const std::shared_ptr& window, in throw std::runtime_error("Tried to offset event, that is no pointer event: in Touch Input"); } - const double x_percent = event.tfinger.x; const double y_percent = event.tfinger.y; @@ -210,6 +253,23 @@ input::TouchInput::get_by_device_index(const std::shared_ptr& window, in return new_event; } +[[nodiscard]] helper::expected input::TouchSettings::validate() const { + + if (move_x_threshold > 1.0 || move_x_threshold < 0.0) { + return helper::unexpected{ + fmt::format("move_x_threshold has to be in range [0,1] but was {}", move_x_threshold) + }; + } + + if (move_y_threshold > 1.0 || move_y_threshold < 0.0) { + return helper::unexpected{ + fmt::format("move_y_threshold has to be in range [0,1] but was {}", move_y_threshold) + }; + } + + return true; +} + void input::TouchInputManager::discover_devices( std::vector>& inputs, @@ -234,135 +294,3 @@ void input::TouchInputManager::discover_devices( } } } - - -//TODO: -/* - - - decltype(event.type) desired_type{}; - switch (click_type) { - case CrossPlatformClickEvent::Motion: - desired_type = SDL_FINGERMOTION; - break; - case CrossPlatformClickEvent::ButtonDown: - desired_type = SDL_FINGERDOWN; - break; - case CrossPlatformClickEvent::ButtonUp: - desired_type = SDL_FINGERUP; - break; - case CrossPlatformClickEvent::Any: - return event.type == SDL_FINGERMOTION || event.type == SDL_FINGERDOWN || event.type == SDL_FINGERUP; - default: - utils::unreachable(); - } - - return event.type == desired_type; - */ - - -/** - - - -[[nodiscard]] std::pair utils::get_raw_coordinates(const Window* window, const SDL_Event& event) { - - assert(utils::event_is_click_event(event, utils::CrossPlatformClickEvent::Any) && "expected a click event"); - -#if defined(__ANDROID__) - // These are doubles, from 0-1 (or if using virtual layouts > 0) in percent, the have to be casted to absolut x coordinates! - const double x_percent = event.tfinger.x; - const double y_percent = event.tfinger.y; - const auto window_size = window->size(); - const auto x = static_cast(std::round(x_percent * window_size.x)); - const auto y = static_cast(std::round(y_percent * window_size.y)); - - -#elif defined(__SWITCH__) - UNUSED(window); - UNUSED(event); - throw std::runtime_error("Not supported on the Nintendo switch"); - int x{}; - int y{}; -#else - UNUSED(window); - - Sint32 x{}; - Sint32 y{}; - switch (event.type) { - case SDL_MOUSEMOTION: - x = event.motion.x; - y = event.motion.y; - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - x = event.button.x; - y = event.button.y; - break; - default: - utils::unreachable(); - } -#endif - - - return { static_cast(x), static_cast(y) }; -} - - - * - */ - - -//TODO: -/* -[[nodiscard]] bool utils::event_is_action(const SDL_Event& event, const CrossPlatformAction action) { - switch (action) { - case CrossPlatformAction::OK: - case CrossPlatformAction::DOWN: - case CrossPlatformAction::UP: - case CrossPlatformAction::LEFT: - case CrossPlatformAction::RIGHT: - case CrossPlatformAction::OPEN_SETTINGS: - case CrossPlatformAction::TAB: - // this can't be checked here, it has to be checked via collision on buttons etc. event_is_action(..., ...::DOWN, UP ...) can only be used inside device_supports_keys() clauses! - throw std::runtime_error("Not supported on android 'event_is_action'"); - case CrossPlatformAction::PAUSE: - return (event.type == SDL_KEYDOWN and event.key.keysym.sym == SDLK_AC_BACK); - - case CrossPlatformAction::UNPAUSE: - return event.type == SDL_FINGERDOWN; - - case CrossPlatformAction::EXIT: - case CrossPlatformAction::CLOSE: - return (event.type == SDL_KEYDOWN and event.key.keysym.sym == SDLK_AC_BACK); - - default: - utils::unreachable(); - } - - - [[nodiscard]] std::string utils::action_description(CrossPlatformAction action) { - - - switch (action) { - case CrossPlatformAction::OK: - case CrossPlatformAction::DOWN: - case CrossPlatformAction::UP: - case CrossPlatformAction::LEFT: - case CrossPlatformAction::RIGHT: - case CrossPlatformAction::OPEN_SETTINGS: - case CrossPlatformAction::TAB: - // this can't be checked here, it has to be checked via collision on buttons etc. event_is_action(..., ...::DOWN, UP ...) can only be used inside device_supports_keys() clauses! - throw std::runtime_error("Not supported on android 'action_description'"); - case CrossPlatformAction::UNPAUSE: - return "Tap anywhere"; - case CrossPlatformAction::PAUSE: - case CrossPlatformAction::EXIT: - case CrossPlatformAction::CLOSE: - return "Back"; - - default: - utils::unreachable(); - } - } - */ From 3047f17c084befd557fdb941047eaa08da45e74e Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 00:00:09 +0200 Subject: [PATCH 19/76] add more unimplemented methods --- src/input/input.cpp | 59 ++++++++++++++++---------- src/input/joystick_input.cpp | 54 ++++++++++++++++-------- src/input/joystick_input.hpp | 81 +++++++++++++++++++++++++++++------- src/input/keyboard_input.hpp | 2 - src/input/replay_input.cpp | 10 +++++ src/input/touch_input.cpp | 28 ++++++++++--- src/input/touch_input.hpp | 3 -- tests/graphics/sdl_key.cpp | 2 +- 8 files changed, 172 insertions(+), 67 deletions(-) diff --git a/src/input/input.cpp b/src/input/input.cpp index bd88e98a..23dfc317 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -13,6 +13,10 @@ #include +input::Input::Input(const std::string& name, InputType type) : m_name{ name }, m_type{ type } { } + +input::Input::~Input() = default; + input::PointerEventHelper::PointerEventHelper(shapes::IPoint pos, PointerEvent event) : m_pos{ pos }, m_event{ event } { } @@ -148,31 +152,42 @@ input::InputManager::~InputManager() = default; //TODO: improve this API, to correctly use settings to determine the input to use. [[nodiscard]] std::shared_ptr input::InputManager::get_game_input(ServiceProvider* service_provider) { + //TODO: use smart pointer for the event dispatcher - //TODO: select the first suitable + + //TODO: select the first suitable, by using the primary input method or some other settings! for (const auto& control : service_provider->settings_manager().controls()) { return std::visit( - helper::overloaded{ - [service_provider](const input::KeyboardSettings& keyboard_settings - ) mutable -> std::shared_ptr { - auto* const event_dispatcher = &(service_provider->event_dispatcher()); - auto input = - std::make_shared(keyboard_settings, event_dispatcher); - return input; - }, - [service_provider](const input::JoystickSettings& joystick_settings - ) mutable -> std::shared_ptr { - auto* const event_dispatcher = &(service_provider->event_dispatcher()); - auto input = std::make_shared(joystick_settings, event_dispatcher); - return input; - }, - [service_provider](const input::TouchSettings& touch_settings - ) mutable -> std::shared_ptr { - auto* const event_dispatcher = &(service_provider->event_dispatcher()); - auto input = std::make_shared(touch_settings, event_dispatcher); - return input; - } }, + helper::overloaded{ [service_provider](const input::KeyboardSettings& keyboard_settings + ) mutable -> std::shared_ptr { + auto* const event_dispatcher = &(service_provider->event_dispatcher()); + auto input = std::make_shared( + keyboard_settings, event_dispatcher + ); + return input; + }, + [service_provider](const input::JoystickSettings& joystick_settings + ) mutable -> std::shared_ptr { + auto* const event_dispatcher = &(service_provider->event_dispatcher()); + auto input = input::JoystickGameInput::get_game_input_by_settings( + service_provider->input_manager(), event_dispatcher, joystick_settings + ); + + //TODO: better error handling, if this fails look forward in the + if (not input.has_value()) { + throw std::runtime_error("Not possible to get joystick by settings"); + } + + + return input.value(); + }, + [service_provider](const input::TouchSettings& touch_settings + ) mutable -> std::shared_ptr { + auto* const event_dispatcher = &(service_provider->event_dispatcher()); + auto input = std::make_shared(touch_settings, event_dispatcher); + return input; + } }, control ); } @@ -202,3 +217,5 @@ input::InputManager::~InputManager() = default; assert(not m_inputs.empty() && "at least one input has to be given"); return m_inputs.at(0); } + +input::PointerInput::PointerInput(const std::string& name) : Input{ name, input::InputType::Pointer } { } diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 66160f9b..ea493114 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -4,6 +4,7 @@ #include "helper/expected.hpp" #include "helper/optional.hpp" #include "helper/utils.hpp" +#include "input/game_input.hpp" #include "input/input.hpp" #include @@ -52,7 +53,6 @@ input::JoystickInput::~JoystickInput() { [[nodiscard]] helper::expected, std::string> input::JoystickInput::get_by_device_index(int device_index) { - auto* joystick = SDL_JoystickOpen(device_index); if (joystick == nullptr) { @@ -94,10 +94,12 @@ input::JoystickInput::get_by_device_index(int device_index) { ) }; } +[[nodiscard]] SDL_JoystickID input::JoystickInput::instance_id() const { + return m_instance_id; +} void input::JoyStickInputManager::discover_devices(std::vector>& inputs) { - //initialize joystick input, this needs to call some sdl things const auto result = SDL_InitSubSystem(SDL_INIT_JOYSTICK); @@ -343,30 +345,55 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( } +#endif #endif -void JoystickGameInput::handle_event(const SDL_Event& event, const Window*) { +void input::JoystickGameInput::handle_event(const SDL_Event& event) { m_event_buffer.push_back(event); } -void JoystickGameInput::update(SimulationStep simulation_step_index) { +void input::JoystickGameInput::update(SimulationStep simulation_step_index) { for (const auto& event : m_event_buffer) { const auto input_event = sdl_event_to_input_event(event); if (input_event.has_value()) { - Input::handle_event(*input_event, simulation_step_index); + GameInput::handle_event(*input_event, simulation_step_index); } } m_event_buffer.clear(); - Input::update(simulation_step_index); + GameInput::update(simulation_step_index); +} + + +[[nodiscard]] helper::optional> +input::JoystickGameInput::get_game_input_by_settings( + const input::InputManager& input_manager, + EventDispatcher* event_dispatcher, + const JoystickSettings& settings +) { + + //TODO: filter all input_manager.inputs() by guid, than try to get them in order, by trying to convert the settings validate them and create the game input + + //TODO: set up: that on removal of the joystick_input pause is pressed and either a new gam,einput is created or waited until he reconnects! + + + UNUSED(input_manager); + UNUSED(settings); + UNUSED(event_dispatcher); + UNUSED(settings); + + return helper::nullopt; } + +#if defined(__CONSOLE__) #if defined(__SWITCH__) + // game_input uses Input to handle events, but stores the config settings for the specific button //TODO: use settings -helper::optional JoystickSwitchGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event) const { +helper::optional SwitchJoystickGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event) const { if (event.type == SDL_JOYBUTTONDOWN) { if (event.jbutton.which != m_instance_id) { @@ -430,7 +457,7 @@ helper::optional JoystickSwitchGameInput_Type1::sdl_event_to_input_e #elif defined(__3DS__) //TODO: use settings -helper::optional JoystickInput::sdl_event_to_input_event(const SDL_Event& event) const { +helper::optional _3DSJoystickGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event) const { if (event.type == SDL_JOYBUTTONDOWN) { if (event.jbutton.which != m_instance_id) { @@ -496,18 +523,9 @@ helper::optional JoystickInput::sdl_event_to_input_event(const SDL_E #endif -[[nodiscard]] helper::expected input::JoystickSettings::validate() const { - - const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, - drop, hold, pause, open_settings }; - - return input::InputSettings::has_unique_members(to_use); -} - - std::string json_helper::get_key_from_object(const nlohmann::json& j, const std::string& name) { - auto context = j.at(name); + const auto& context = j.at(name); std::string input; context.get_to(input); diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index a72ec3c8..7c82111f 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -42,7 +42,12 @@ namespace input { [[nodiscard]] static helper::expected, std::string> get_by_device_index( int device_index ); + [[nodiscard]] SDL_JoystickID instance_id() const; + + // Add get_game_input method! + + }; @@ -66,24 +71,33 @@ namespace input { }; //using std::string in here, since we only know, if these are valid joystick button names, after parsing the GUID and than seeing if we support that joystick and than using the string mappings for that specific joystick - struct JoystickSettings { + + template + struct AbstractJoystickSettings { JoystickIdentification identification; - std::string rotate_left; - std::string rotate_right; - std::string move_left; - std::string move_right; - std::string move_down; - std::string drop; - std::string hold; + T rotate_left; + T rotate_right; + T move_left; + T move_right; + T move_down; + T drop; + T hold; - std::string pause; - std::string open_settings; + T pause; + T open_settings; - [[nodiscard]] helper::expected validate() const; + [[nodiscard]] helper::expected validate() const { + const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, + drop, hold, pause, open_settings }; + + return input::InputSettings::has_unique_members(to_use); + } }; + using JoystickSettings = AbstractJoystickSettings; + //TODO: differntiate different controllers and modes, e.g the switch can have pro controller, the included ones, each of them seperate etc. @@ -123,16 +137,15 @@ namespace input { #endif + struct JoystickGameInput : public GameInput, public EventListener { private: - JoystickSettings m_settings; std::vector m_event_buffer; EventDispatcher* m_event_dispatcher; public: - JoystickGameInput(const JoystickSettings& settings, EventDispatcher* event_dispatcher) + JoystickGameInput(EventDispatcher* event_dispatcher) : GameInput{ GameInputType::Controller }, - m_settings{ settings }, m_event_dispatcher{ event_dispatcher } { m_event_dispatcher->register_listener(this); } @@ -145,14 +158,50 @@ namespace input { void update(SimulationStep simulation_step_index) override; + [[nodiscard]] static helper::optional> get_game_input_by_settings( + const input::InputManager& input_manager, + EventDispatcher* event_dispatcher, + const JoystickSettings& settings + ); + + protected: + [[nodiscard]] virtual helper::optional sdl_event_to_input_event(const SDL_Event& event) const = 0; + }; + + +#if defined(__CONSOLE__) +#if defined(__SWITCH__) + + struct SwitchJoystickGameInput_Type1 : public JoystickGameInput { + + public: + SwitchJoystickGameInput_Type1(JoystickSettings settings, EventDispatcher* event_dispatcher); + [[nodiscard]] helper::optional get_menu_event(const SDL_Event& event) const override; [[nodiscard]] std::string describe_menu_event(MenuEvent event) const override; - private: - [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event) const; + protected: + [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event) const override; }; +#elif defined(__3DS__) + struct _3DSJoystickGameInput_Type1 : public JoystickGameInput { + + public: + _3DSJoystickGameInput_Type1(JoystickSettings settings, EventDispatcher* event_dispatcher); + + [[nodiscard]] helper::optional get_menu_event(const SDL_Event& event) const override; + + [[nodiscard]] std::string describe_menu_event(MenuEvent event) const override; + + protected: + [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event) const override; + }; + +#endif +#endif + } // namespace input diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index 40b654f4..80aaea44 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -18,8 +18,6 @@ namespace input { public: KeyboardInput(); - virtual ~KeyboardInput(); - [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; diff --git a/src/input/replay_input.cpp b/src/input/replay_input.cpp index 6e0a99a3..da1c1501 100644 --- a/src/input/replay_input.cpp +++ b/src/input/replay_input.cpp @@ -1,6 +1,7 @@ #include "replay_input.hpp" #include "game/tetrion.hpp" #include "helper/magic_enum_wrapper.hpp" +#include "helper/optional.hpp" input::ReplayGameInput::ReplayGameInput(std::shared_ptr recording_reader) : GameInput{ GameInputType::Recording }, @@ -75,6 +76,15 @@ void input::ReplayGameInput::late_update(const SimulationStep simulation_step_in } } + +[[nodiscard]] helper::optional input::ReplayGameInput::get_menu_event(const SDL_Event&) const { + return helper::nullopt; +} + +[[nodiscard]] std::string input::ReplayGameInput::describe_menu_event(MenuEvent) const { + throw std::runtime_error("not supported"); +} + [[nodiscard]] bool input::ReplayGameInput::is_end_of_recording() const { return m_next_record_index >= m_recording_reader->num_records(); } diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index bb16ef39..2b7bce82 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -1,9 +1,8 @@ - - - #include "touch_input.hpp" #include "graphics/point.hpp" #include "helper/optional.hpp" +#include "helper/utils.hpp" +#include "input/game_input.hpp" #include "input/input.hpp" #include @@ -139,16 +138,34 @@ input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function- } +[[nodiscard]] helper::optional input::TouchGameInput::get_menu_event(const SDL_Event& event) const { + + if (event.type == SDL_KEYDOWN and event.key.keysym.sym == SDLK_AC_BACK) { + return MenuEvent::PAUSE; + } + + return helper::nullopt; +} + +[[nodiscard]] std::string input::TouchGameInput::describe_menu_event(MenuEvent event) const { + switch (event) { + case input::MenuEvent::PAUSE: + return "Back"; + case input::MenuEvent::OPEN_SETTINGS: + throw std::runtime_error("Open Settings is not supported"); + default: + utils::unreachable(); + } +} + input::TouchInput::TouchInput(const std::shared_ptr& window, SDL_TouchID id, const std::string& name) : PointerInput{ name }, m_window{ window }, m_id{ id } { } - [[nodiscard]] helper::expected, std::string> input::TouchInput::get_by_device_index(const std::shared_ptr& window, int device_index) { - const auto touch_id = SDL_GetTouchDevice(device_index); if (touch_id <= 0) { @@ -157,7 +174,6 @@ input::TouchInput::get_by_device_index(const std::shared_ptr& window, in }; } - std::string name = "unknown name"; const auto* char_name = SDL_GetTouchName(device_index); diff --git a/src/input/touch_input.hpp b/src/input/touch_input.hpp index f86f0715..cdb9e5a8 100644 --- a/src/input/touch_input.hpp +++ b/src/input/touch_input.hpp @@ -16,12 +16,10 @@ namespace input { public: TouchInput(const std::shared_ptr& window, SDL_TouchID id, const std::string& name); - virtual ~TouchInput(); [[nodiscard]] static helper::expected, std::string> get_by_device_index(const std::shared_ptr& window, int device_index); - [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; @@ -206,4 +204,3 @@ namespace nlohmann { } }; } // namespace nlohmann - diff --git a/tests/graphics/sdl_key.cpp b/tests/graphics/sdl_key.cpp index 1bd41014..422f289e 100644 --- a/tests/graphics/sdl_key.cpp +++ b/tests/graphics/sdl_key.cpp @@ -10,6 +10,6 @@ TEST(SDLKey, SimpleComparision) { const auto key1 = SDL::Key{ SDLK_k }; - ASSERT_EQ(key1.name(), "K"); + ASSERT_EQ(key1.to_string(), "K"); ASSERT_EQ(key1.has_modifier(SDL::Modifier::ALT), false); } From cc2f05435620af66de922b47678a23e3600e31a5 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 02:14:37 +0200 Subject: [PATCH 20/76] - fix last compile errors - add more sdl_key tests - fix display functions for helper::optional and helper::expected for gtest --- src/manager/sdl_key.cpp | 40 ++++++++++++++++++--- src/manager/settings_manager.cpp | 5 +++ tests/core/color.cpp | 20 +++-------- tests/graphics/sdl_key.cpp | 37 ++++++++++++++++++- tests/meson.build | 4 --- tests/utils/helper.hpp | 24 +++++++++++++ tests/utils/meson.build | 4 +-- tests/utils/printer.hpp | 61 ++++++++++++++++++++++++++++++++ 8 files changed, 167 insertions(+), 28 deletions(-) create mode 100644 tests/utils/helper.hpp create mode 100644 tests/utils/printer.hpp diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index e25f92ea..6fd32a80 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -246,6 +247,21 @@ namespace { return res; } + // trim from start (in place) + inline void ltrim(std::string& s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); + } + + // trim from end (in place) + inline void rtrim(std::string& s) { + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end()); + } + + void trim(std::string& s) { + ltrim(s); + rtrim(s); + } + constexpr helper::optional modifier_from_string(std::string modifier) { if (modifier.empty()) { @@ -274,8 +290,8 @@ namespace { { "gui", SDL::Modifier::GUI }, }; // namespace - if (map.contains(modifier)) { - return map.at(modifier); + if (map.contains(lower_case)) { + return map.at(lower_case); } return helper::nullopt; @@ -287,7 +303,10 @@ namespace { helper::expected SDL::Key::from_string(const std::string& value) { - const auto tokens = split_string_by_char(value, "+"); + auto tokens = split_string_by_char(value, "+"); + for (auto& token : tokens) { + trim(token); + } std::vector modifiers{}; @@ -299,12 +318,23 @@ helper::expected SDL::Key::from_string(const std::string& return helper::unexpected{ keycode.error() }; } + //search for duplicates + std::unordered_set values{}; + for (const auto& modifier : modifiers) { + if (values.contains(modifier)) { + return helper::unexpected{ + fmt::format("Duplicate modifier: '{}'", modifier_to_string(modifier)) + }; + } + values.insert(modifier); + } + return SDL::Key{ keycode.value(), modifiers }; } const auto modifier = modifier_from_string(token); if (not modifier.has_value()) { - return helper::unexpected{ fmt::format("Not a valid modifier: {}", token) }; + return helper::unexpected{ fmt::format("Not a valid modifier: '{}'", token) }; } modifiers.push_back(modifier.value()); @@ -381,7 +411,7 @@ helper::expected SDL::Key::from_string(const std::string& parts.emplace_back(sdl_key_name(m_keycode)); - return fmt::format("{}", fmt::join(parts, "+")); + return fmt::format("{}", fmt::join(parts, " + ")); } diff --git a/src/manager/settings_manager.cpp b/src/manager/settings_manager.cpp index 322f6553..fa377ce0 100644 --- a/src/manager/settings_manager.cpp +++ b/src/manager/settings_manager.cpp @@ -21,3 +21,8 @@ SettingsManager::SettingsManager(ServiceProvider* service_provider) : m_service_ }; } } + + +[[nodiscard]] const std::vector& SettingsManager::controls() const { + return m_current_settings.controls; +} diff --git a/tests/core/color.cpp b/tests/core/color.cpp index f1b9b941..a51cfc5a 100644 --- a/tests/core/color.cpp +++ b/tests/core/color.cpp @@ -1,5 +1,7 @@ #include "helper/color.hpp" +#include "helper/magic_enum_wrapper.hpp" +#include "utils/helper.hpp" #include #include @@ -38,26 +40,14 @@ void PrintTo(const HSVColor& color, std::ostream* os) { *os << color.to_string(); } +namespace color { -// make helper::expected printable -template -void PrintTo(const helper::expected& value, std::ostream* os) { - if (value.has_value()) { - *os << "Value: " << ::testing::PrintToString(value.value()); - } else { - *os << "Error: " << ::testing::PrintToString(value.error()); + void PrintTo(const SerializeMode& value, std::ostream* os) { + *os << magic_enum::enum_name(value); } } -MATCHER(ExpectedHasValue, "expected has value") { - return arg.has_value(); -} - -MATCHER(ExpectedHasError, "expected has error") { - return not arg.has_value(); -} - TEST(Color, DefaultConstruction) { const auto c1 = Color{}; const auto c2 = Color{ 0, 0, 0, 0 }; diff --git a/tests/graphics/sdl_key.cpp b/tests/graphics/sdl_key.cpp index 422f289e..9535214f 100644 --- a/tests/graphics/sdl_key.cpp +++ b/tests/graphics/sdl_key.cpp @@ -1,11 +1,22 @@ #include "manager/sdl_key.hpp" +#include "helper/expected.hpp" +#include "utils/helper.hpp" +#include "gtest/gtest.h" #include #include +#include +#include -//TODO: improve +namespace SDL { + + // make keys printable + void PrintTo(const Key& key, std::ostream* os) { + *os << key.to_string(); + } +} // namespace SDL TEST(SDLKey, SimpleComparision) { const auto key1 = SDL::Key{ SDLK_k }; @@ -13,3 +24,27 @@ TEST(SDLKey, SimpleComparision) { ASSERT_EQ(key1.to_string(), "K"); ASSERT_EQ(key1.has_modifier(SDL::Modifier::ALT), false); } + +TEST(SDLKey, FromString) { + + const std::vector, std::string>> strings{ + { SDL::Key{ SDLK_1, { SDL::Modifier::CTRL } }, "Ctrl + 1" }, + { SDL::Key{ SDLK_1, { SDL::Modifier::LSHIFT } }, "Shift-L + 1" }, + { SDL::Key{ SDLK_1, { SDL::Modifier::RSHIFT } }, "Shift-R + 1" }, + { helper::unexpected{ "Not a valid modifier: 'ShiftL'" }, "ShiftL + 1" }, + { helper::unexpected{ "Duplicate modifier: 'Shift'" }, "Shift + Shift + 1" }, + }; + + for (const auto& [correct, str] : strings) { + + const auto parsed = SDL::Key::from_string(str); + + if (correct.has_value()) { + ASSERT_THAT(parsed, ExpectedHasValue()) << "Input was: " << str; + ASSERT_EQ(correct.value(), parsed.value()); + } else { + ASSERT_THAT(parsed, ExpectedHasError()) << "Input was: " << str; + ASSERT_EQ(correct.error(), parsed.error()); + } + } +} diff --git a/tests/meson.build b/tests/meson.build index bba9d4a0..841f2fdd 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,4 +1,3 @@ - if meson.is_cross_build() error('Tests are not supported for cross builds (atm)') endif @@ -15,7 +14,6 @@ graphics_test_src = [] test_deps += dependency('gtest') test_deps += dependency('gmock') - subdir('core') subdir('graphics') subdir('utils') @@ -52,8 +50,6 @@ graphics_tests = executable( graphics_test_src, include_directories: test_inc_dirs, dependencies: [test_deps, liboopetris_graphics_dep], - ## COLOR_TEST_MODE = 0 (SET_VALUE) | 1 (EXHAUSTIVE) | any other number : use that many steps from exhaustive, see code - cpp_args: ['-DCOLOR_TEST_MODE=0'], override_options: { 'warning_level': '3', 'werror': true, diff --git a/tests/utils/helper.hpp b/tests/utils/helper.hpp new file mode 100644 index 00000000..15c3de0d --- /dev/null +++ b/tests/utils/helper.hpp @@ -0,0 +1,24 @@ + + +#pragma once + +#include "printer.hpp" + +#include + + +MATCHER(ExpectedHasValue, "expected has value") { + return arg.has_value(); +} + +MATCHER(ExpectedHasError, "expected has error") { + return not arg.has_value(); +} + +MATCHER(OptionalHasValue, "optional has value") { + return arg.has_value(); +} + +MATCHER(OptionalHasNoValue, "optional has no value") { + return not arg.has_value(); +} diff --git a/tests/utils/meson.build b/tests/utils/meson.build index aac4e48f..95435d7f 100644 --- a/tests/utils/meson.build +++ b/tests/utils/meson.build @@ -1,3 +1 @@ - - -test_src += files('files.cpp', 'files.hpp') +test_src += files('files.cpp', 'files.hpp', 'helper.hpp', 'printer.hpp') diff --git a/tests/utils/printer.hpp b/tests/utils/printer.hpp new file mode 100644 index 00000000..f799f3f5 --- /dev/null +++ b/tests/utils/printer.hpp @@ -0,0 +1,61 @@ + + +#pragma once + +#include "helper/expected.hpp" +#include "helper/optional.hpp" + +#include + + +namespace +#ifdef _USE_TL_EXPECTED + tl +#else + std +#endif +{ + + // make helper::expected printable + template + void PrintTo(const expected& value, std::ostream* os) { + if (value.has_value()) { + *os << ": " << ::testing::PrintToString(value.value()); + } else { + *os << ": " << ::testing::PrintToString(value.error()); + } + } + + template + std::ostream& operator<<(std::ostream& os, const expected& value) { + PrintTo(value); + return os; + } + +} // namespace tl + +namespace +#ifdef __USE_TL_OPTIONAL + tl +#else + std +#endif +{ + + // make helper::optional printable + template + void PrintTo(const optional& value, std::ostream* os) { + if (value.has_value()) { + *os << ": " << ::testing::PrintToString(value.value()); + } else { + *os << ""; + } + } + + template + std::ostream& operator<<(std::ostream& os, const optional& value) { + PrintTo(value); + return os; + } + +} // namespace tl From 81f57f50d52548958dc52afc8f91df1f381660a6 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 02:34:24 +0200 Subject: [PATCH 21/76] - add more sdl_key test cases - fix few error paths in "SDL::Key::from_string" - fix SDL::Key::has_modifier_exact --- src/manager/sdl_key.cpp | 75 ++++++++++++++++++++++++++++++++++++-- tests/graphics/sdl_key.cpp | 22 ++++++++--- 2 files changed, 89 insertions(+), 8 deletions(-) diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index 6fd32a80..40c84908 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -302,7 +302,6 @@ namespace { helper::expected SDL::Key::from_string(const std::string& value) { - auto tokens = split_string_by_char(value, "+"); for (auto& token : tokens) { trim(token); @@ -312,9 +311,18 @@ helper::expected SDL::Key::from_string(const std::string& for (size_t i = 0; i < tokens.size(); ++i) { const auto& token = tokens.at(i); + + if (token.empty()) { + return helper::unexpected{ "Empty token" }; + } + if (i + 1 == tokens.size()) { const auto keycode = SDL::Key::sdl_keycode_from_string(token); if (not keycode.has_value()) { + const auto modifier = modifier_from_string(token); + if (modifier.has_value()) { + return helper::unexpected{ "No key but only modifiers given" }; + } return helper::unexpected{ keycode.error() }; } @@ -352,9 +360,57 @@ helper::expected SDL::Key::from_string(const std::string& } [[nodiscard]] bool SDL::Key::has_modifier_exact(const Modifier& modifier) const { + + SDL::Modifier has_not; + + switch (modifier) { + case SDL::Modifier::LSHIFT: + has_not = SDL::Modifier::RSHIFT; + break; + case SDL::Modifier::RSHIFT: + has_not = SDL::Modifier::LSHIFT; + break; + case SDL::Modifier::LCTRL: + has_not = SDL::Modifier::RCTRL; + break; + case SDL::Modifier::RCTRL: + has_not = SDL::Modifier::LCTRL; + break; + case SDL::Modifier::LALT: + has_not = SDL::Modifier::RALT; + break; + case SDL::Modifier::RALT: + has_not = SDL::Modifier::LALT; + break; + case SDL::Modifier::LGUI: + has_not = SDL::Modifier::RGUI; + break; + case SDL::Modifier::RGUI: + has_not = SDL::Modifier::LGUI; + break; + + case SDL::Modifier::NUM: + case SDL::Modifier::CAPS: + case SDL::Modifier::MODE: + case SDL::Modifier::SCROLL: + + case SDL::Modifier::CTRL: + case SDL::Modifier::SHIFT: + case SDL::Modifier::ALT: + case SDL::Modifier::GUI: { + const auto sdl_modifier = to_sdl_modifier(modifier); + return (m_modifiers & sdl_modifier) == sdl_modifier; + } + + default: + utils::unreachable(); + } + + const auto sdl_modifier = to_sdl_modifier(modifier); + const auto sdl_modifier_not = to_sdl_modifier(has_not); - return (m_modifiers & sdl_modifier) == sdl_modifier; + return (m_modifiers & sdl_modifier) == sdl_modifier && (m_modifiers & sdl_modifier_not) == 0; } @@ -401,7 +457,7 @@ helper::expected SDL::Key::from_string(const std::string& [[nodiscard]] std::string SDL::Key::to_string() const { std::vector parts{}; - const auto& [_, special, multiple] = get_modifier_type_array(); + const auto& [normal, special, multiple] = get_modifier_type_array(); for (const auto modifier : special) { if (has_modifier(modifier)) { @@ -409,6 +465,19 @@ helper::expected SDL::Key::from_string(const std::string& } } + for (const auto modifier : multiple) { + if (has_modifier_exact(modifier)) { + parts.emplace_back(modifier_to_string(modifier)); + } + } + + for (const auto modifier : normal) { + if (has_modifier_exact(modifier)) { + parts.emplace_back(modifier_to_string(modifier)); + } + } + + parts.emplace_back(sdl_key_name(m_keycode)); return fmt::format("{}", fmt::join(parts, " + ")); diff --git a/tests/graphics/sdl_key.cpp b/tests/graphics/sdl_key.cpp index 9535214f..b016aa57 100644 --- a/tests/graphics/sdl_key.cpp +++ b/tests/graphics/sdl_key.cpp @@ -28,11 +28,23 @@ TEST(SDLKey, SimpleComparision) { TEST(SDLKey, FromString) { const std::vector, std::string>> strings{ - { SDL::Key{ SDLK_1, { SDL::Modifier::CTRL } }, "Ctrl + 1" }, - { SDL::Key{ SDLK_1, { SDL::Modifier::LSHIFT } }, "Shift-L + 1" }, - { SDL::Key{ SDLK_1, { SDL::Modifier::RSHIFT } }, "Shift-R + 1" }, - { helper::unexpected{ "Not a valid modifier: 'ShiftL'" }, "ShiftL + 1" }, - { helper::unexpected{ "Duplicate modifier: 'Shift'" }, "Shift + Shift + 1" }, + { SDL::Key{ SDLK_1, { SDL::Modifier::CTRL } },"Ctrl + 1" }, + { SDL::Key{ SDLK_1, { SDL::Modifier::LSHIFT } }, "Shift-L + 1" }, + { SDL::Key{ SDLK_1, { SDL::Modifier::RSHIFT } }, "Shift-R + 1" }, + { helper::unexpected{ "Not a valid modifier: 'ShiftL'" }, "ShiftL + 1" }, + { helper::unexpected{ "Duplicate modifier: 'Shift'" }, "Shift + Shift + 1" }, + { helper::unexpected{ "No key but only modifiers given" }, "Shift" }, + { helper::unexpected{ "Empty token" }, "" }, + { helper::unexpected{ "Empty token" }, " + \t " }, + { SDL::Key{ SDLK_1 }, "1" }, + { SDL::Key{ SDLK_1, { SDL::Modifier::CTRL, SDL::Modifier::ALT, SDL::Modifier::SHIFT, SDL::Modifier::GUI } }, + "Shift + Alt + Ctrl + Gui + 1" }, + { SDL::Key{ SDLK_1, { SDL::Modifier::LCTRL } }, "Ctrl-L + 1" }, + { SDL::Key{ SDLK_1, { SDL::Modifier::RCTRL } }, "Ctrl-R + 1" }, + { SDL::Key{ SDLK_1, { SDL::Modifier::LALT } }, "Alt-L + 1" }, + { SDL::Key{ SDLK_1, { SDL::Modifier::RALT } }, "Alt-R + 1" }, + { SDL::Key{ SDLK_1, { SDL::Modifier::LGUI } }, "Gui-L + 1" }, + { SDL::Key{ SDLK_1, { SDL::Modifier::RGUI } }, "Gui-R + 1" }, }; for (const auto& [correct, str] : strings) { From 8b2a4b646b36a767db46838ba63822626c8d2c5d Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 02:35:53 +0200 Subject: [PATCH 22/76] require sdl2 >=2.24.0 for SDL_GUID --- tools/dependencies/meson.build | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/tools/dependencies/meson.build b/tools/dependencies/meson.build index 5f14c07e..fad1774a 100644 --- a/tools/dependencies/meson.build +++ b/tools/dependencies/meson.build @@ -1,5 +1,3 @@ - - only_allow_native_libs = false if meson.is_cross_build() if host_machine.system() == 'switch' or host_machine.system() == '3ds' @@ -28,13 +26,12 @@ if meson.is_cross_build() endif endif - - sdl2_dep = dependency( 'sdl2', 'SDL2', allow_fallback: false, required: only_allow_native_libs, + version: '>=2.24.0', ) if sdl2_dep.found() @@ -46,11 +43,13 @@ else 'sdl2', required: true, default_options: {'test': false}, + version: '>=2.24.0', ) sdl2main_dep = dependency( 'sdl2main', required: true, fallback: 'sdl2', + version: '>=2.24.0', ) graphic_application_deps += sdl2main_dep @@ -101,7 +100,6 @@ else endif endif - sdl2_mixer_dep = dependency( 'sdl2_mixer', 'SDL2_mixer', @@ -118,8 +116,7 @@ fmt_use_header_only = false if ( meson.is_cross_build() - and (host_machine.system() == 'switch' - or host_machine.system() == '3ds') + and (host_machine.system() == 'switch' or host_machine.system() == '3ds') ) fmt_use_header_only = true # clang with libc++ creates some really long and confusing linker errors, so just use the header only library @@ -127,7 +124,6 @@ elif cpp.get_id() == 'clang' and build_with_libcpp fmt_use_header_only = true endif - if fmt_use_header_only fmt_header_only_dep = dependency( 'fmt_header_only', @@ -142,7 +138,6 @@ endif core_lib += {'deps': [core_lib.get('deps'), fmt_dep]} - spdlog_dep = dependency( 'spdlog', required: true, @@ -211,8 +206,6 @@ else message('Compiler support std::optional, using that') endif - - magic_enum_dep = dependency( 'magic_enum', required: true, @@ -225,11 +218,9 @@ core_lib += {'deps': [core_lib.get('deps'), argparse_dep]} online_multiplayer_supported = true - if ( meson.is_cross_build() - and (host_machine.system() == 'switch' - or host_machine.system() == '3ds') + and (host_machine.system() == 'switch' or host_machine.system() == '3ds') ) online_multiplayer_supported = false @@ -262,7 +253,6 @@ utf8cpp_dep = dependency( ) core_lib += {'deps': [core_lib.get('deps'), utf8cpp_dep]} - build_installer = get_option('build_installer') is_flatpak_build = false @@ -271,8 +261,8 @@ is_flatpak_build = false if build_installer if get_option('buildtype') != 'release' error( - 'buildtype needs to be \'release\', when building the installer, but was: ' + - get_option('buildtype'), + 'buildtype needs to be \'release\', when building the installer, but was: ' + + get_option('buildtype'), ) endif @@ -288,7 +278,8 @@ if build_installer message('Adding a windows installer target: \'windows_installer\'') else error( - 'unsuported system for building the installer: ' + host_machine.system(), + 'unsuported system for building the installer: ' + + host_machine.system(), ) endif @@ -302,8 +293,6 @@ if build_installer endif - - if is_flatpak_build app_name = 'com.github.mgerhold.OOPetris' core_lib += { @@ -314,11 +303,9 @@ if is_flatpak_build } endif - have_file_dialogs = false have_discord_sdk = false - nfde_dep = dependency( 'nativefiledialog-extended', required: not meson.is_cross_build(), From f781f38958b2f968b5876d15fb19189f85d71fa9 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 02:49:29 +0200 Subject: [PATCH 23/76] add backwards compatible typedef for sdl 2.30.0 feature --- src/input/guid.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/input/guid.hpp b/src/input/guid.hpp index a54e5d89..14a8c8b3 100644 --- a/src/input/guid.hpp +++ b/src/input/guid.hpp @@ -10,9 +10,15 @@ #include #include -namespace SDL { +extern "C" { +#if SDL_MAJOR_VERSION < 2 || SDL_MINOR_VERSION < 30 || SDL_PATCHLEVEL < 0 +typedef SDL_GUID SDL_JoystickGUID; //NOLINT(modernize-use-using), it's used in extern C, there is no using +#endif +} +namespace SDL { + struct GUID { public: using ArrayType = std::array; From 1b38462d136c63af8d94eae9cac585324bd7b008 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 02:50:09 +0200 Subject: [PATCH 24/76] add more sdL_key tests --- src/input/joystick_input.hpp | 2 -- tests/graphics/sdl_key.cpp | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index 7c82111f..f61d2d22 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -46,8 +46,6 @@ namespace input { [[nodiscard]] SDL_JoystickID instance_id() const; // Add get_game_input method! - - }; diff --git a/tests/graphics/sdl_key.cpp b/tests/graphics/sdl_key.cpp index b016aa57..fdaea975 100644 --- a/tests/graphics/sdl_key.cpp +++ b/tests/graphics/sdl_key.cpp @@ -16,6 +16,12 @@ namespace SDL { void PrintTo(const Key& key, std::ostream* os) { *os << key.to_string(); } + + + std::ostream& operator<<(std::ostream& os, const Key& value) { + os << value.to_string(); + return os; + } } // namespace SDL TEST(SDLKey, SimpleComparision) { @@ -60,3 +66,32 @@ TEST(SDLKey, FromString) { } } } + + +TEST(SDLKey, ToString) { + + const std::vector keys{ + SDL::Key{ SDLK_1, { SDL::Modifier::CTRL } }, + SDL::Key{ SDLK_1, { SDL::Modifier::LSHIFT } }, + SDL::Key{ SDLK_1, { SDL::Modifier::RSHIFT } }, + SDL::Key{ SDLK_1 }, + SDL::Key{ SDLK_1, { SDL::Modifier::CTRL, SDL::Modifier::ALT, SDL::Modifier::SHIFT, SDL::Modifier::GUI } }, + SDL::Key{ SDLK_1, { SDL::Modifier::LCTRL } }, + SDL::Key{ SDLK_1, { SDL::Modifier::RCTRL } }, + SDL::Key{ SDLK_1, { SDL::Modifier::LALT } }, + SDL::Key{ SDLK_1, { SDL::Modifier::RALT } }, + SDL::Key{ SDLK_1, { SDL::Modifier::LGUI } }, + SDL::Key{ SDLK_1, { SDL::Modifier::RGUI } }, + }; + + for (const auto& key : keys) { + + const auto keys_string = key.to_string(); + + const auto parsed = SDL::Key::from_string(keys_string); + + + ASSERT_THAT(parsed, ExpectedHasValue()) << "Input was: " << key; + ASSERT_EQ(parsed.value(), key); + } +} From b09c1ec92f1f47aae8851497cb39a5a1a58156ce Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 02:56:26 +0200 Subject: [PATCH 25/76] - add needed include, it was previously not needed, since it was used internally by other headers, but in a newer version of libstdc++ it is needed now --- src/helper/utils.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helper/utils.hpp b/src/helper/utils.hpp index 0da4fdab..23983c27 100644 --- a/src/helper/utils.hpp +++ b/src/helper/utils.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include From df50e7591b05993768319a02538f3b4816d4ae54 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 02:58:13 +0200 Subject: [PATCH 26/76] - fix error in newer gcc, unnecessary copy of std::string in for loop --- src/input/input.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/input.hpp b/src/input/input.hpp index 7524ba37..57c097cb 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -112,7 +112,7 @@ namespace input { std::vector already_bound{}; - for (const auto single_check : to_check) { + for (const auto& single_check : to_check) { if (std::find(already_bound.cbegin(), already_bound.cend(), single_check) != already_bound.cend()) { return helper::unexpected{ fmt::format("KeyCode already bound: '{}'", single_check) }; From 141e50fae5325b318b0a4a8ba478b93d87bdffc0 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 03:00:53 +0200 Subject: [PATCH 27/76] input/guid: fix typedef usage --- src/input/guid.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/guid.hpp b/src/input/guid.hpp index 14a8c8b3..9b90b63f 100644 --- a/src/input/guid.hpp +++ b/src/input/guid.hpp @@ -12,7 +12,7 @@ extern "C" { #if SDL_MAJOR_VERSION < 2 || SDL_MINOR_VERSION < 30 || SDL_PATCHLEVEL < 0 -typedef SDL_GUID SDL_JoystickGUID; //NOLINT(modernize-use-using), it's used in extern C, there is no using +typedef SDL_JoystickGUID SDL_GUID; //NOLINT(modernize-use-using), it's used in extern C, there is no using #endif } From 8d877229252a48bd902fc4fd1d04cbec82a6f095 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 03:13:34 +0200 Subject: [PATCH 28/76] - fix error in newer gcc: const in static_cast --- src/manager/sdl_key.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index 40c84908..64b5c45c 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -3,6 +3,7 @@ #include "helper/optional.hpp" #include "helper/utils.hpp" +#include #include #include #include @@ -20,7 +21,7 @@ SDL::Key::Key(SDL_KeyCode keycode, UnderlyingModifierType modifiers) SDL::Key::Key(SDL_KeyCode keycode, const std::vector& modifiers) : Key{ keycode, SDL::Key::sdl_modifier_from_modifiers(modifiers) } { } -SDL::Key::Key(const SDL_Keysym& keysym) : Key{ static_cast(keysym.sym), keysym.mod } { } +SDL::Key::Key(const SDL_Keysym& keysym) : Key{ static_cast(keysym.sym), keysym.mod } { } [[nodiscard]] bool SDL::Key::is_key(const SDL::Key& other) const { @@ -492,7 +493,7 @@ helper::expected SDL::Key::from_string(const std::string& }; } - return static_cast(key); + return static_cast(key); } [[nodiscard]] SDL::Key::UnderlyingModifierType SDL::Key::sdl_modifier_from_modifiers( From 579bb9649e6aa2b6caa82c4b4913a8ec0657ca31 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 03:16:51 +0200 Subject: [PATCH 29/76] fix android build --- src/helper/platform.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helper/platform.cpp b/src/helper/platform.cpp index 2ff66e6d..aa5c2a92 100644 --- a/src/helper/platform.cpp +++ b/src/helper/platform.cpp @@ -6,6 +6,7 @@ #include "platform/console_buttons.hpp" #endif +#include #include #include #include From 40bc524e007bfca6c900037260bd93f822a0555d Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 03:27:40 +0200 Subject: [PATCH 30/76] fix switch build --- src/helper/platform.cpp | 2 +- src/input/joystick_input.cpp | 22 +++++++++++++--------- src/input/joystick_input.hpp | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/helper/platform.cpp b/src/helper/platform.cpp index aa5c2a92..780048da 100644 --- a/src/helper/platform.cpp +++ b/src/helper/platform.cpp @@ -3,7 +3,7 @@ #if defined(__CONSOLE__) #include "helper/console_helpers.hpp" -#include "platform/console_buttons.hpp" +#include "input/console_buttons.hpp" #endif #include diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index ea493114..ee0949e6 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -4,6 +4,7 @@ #include "helper/expected.hpp" #include "helper/optional.hpp" #include "helper/utils.hpp" +#include "input/console_buttons.hpp" #include "input/game_input.hpp" #include "input/input.hpp" @@ -190,7 +191,6 @@ void input::JoyStickInputManager::discover_devices(std::vector input::SwitchJoystickInput_Type1::get_navigation_event( +[[nodiscard]] helper::optional input::SwitchJoystickInput_Type1::get_navigation_event( const SDL_Event& event ) const { if (event.type == SDL_JOYBUTTONDOWN) { - if (event.jbutton.which != m_instance_id) { + if (event.jbutton.which != instance_id()) { return helper::nullopt; } @@ -393,12 +393,14 @@ input::JoystickGameInput::get_game_input_by_settings( // game_input uses Input to handle events, but stores the config settings for the specific button //TODO: use settings -helper::optional SwitchJoystickGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event) const { +helper::optional input::SwitchJoystickGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event +) const { if (event.type == SDL_JOYBUTTONDOWN) { - if (event.jbutton.which != m_instance_id) { + //TODO + /* if (event.jbutton.which != m_instance_id) { return helper::nullopt; - } + } */ //TODO: use switch case const auto button = event.jbutton.button; @@ -425,9 +427,10 @@ helper::optional SwitchJoystickGameInput_Type1::sdl_event_to_input_e } } else if (event.type == SDL_JOYBUTTONUP) { - if (event.jbutton.which != m_instance_id) { + //TODO + /* if (event.jbutton.which != m_instance_id) { return helper::nullopt; - } + } */ const auto button = event.jbutton.button; if (button == JOYCON_DPAD_LEFT) { @@ -457,7 +460,8 @@ helper::optional SwitchJoystickGameInput_Type1::sdl_event_to_input_e #elif defined(__3DS__) //TODO: use settings -helper::optional _3DSJoystickGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event) const { +helper::optional input::_3DSJoystickGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event +) const { if (event.type == SDL_JOYBUTTONDOWN) { if (event.jbutton.which != m_instance_id) { diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index f61d2d22..c77f97e0 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -12,7 +12,6 @@ #include #include - namespace input { @@ -104,7 +103,7 @@ namespace input { struct SwitchJoystickInput_Type1 : JoystickInput { //TODO - static SDL::GUID guid{}; + static constexpr SDL::GUID guid{}; public: SwitchJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); @@ -171,6 +170,7 @@ namespace input { #if defined(__SWITCH__) struct SwitchJoystickGameInput_Type1 : public JoystickGameInput { + //TODO: reference JoystickInput public: SwitchJoystickGameInput_Type1(JoystickSettings settings, EventDispatcher* event_dispatcher); From 47a4e8ba3a7d4493d7f031d6a4124f64c1285b35 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 10 May 2024 03:35:39 +0200 Subject: [PATCH 31/76] fix 3ds build --- src/input/joystick_input.cpp | 14 ++++++++------ src/input/joystick_input.hpp | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index ee0949e6..5c19eb55 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -278,14 +278,14 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( : JoystickInput{ joystick, instance_id, name } { } -[[nodiscard]] helper::optional input::_3DSJoystickInput_Type1::get_navigation_event( +[[nodiscard]] helper::optional input::_3DSJoystickInput_Type1::get_navigation_event( const SDL_Event& event ) const { if (event.type == SDL_JOYBUTTONDOWN) { - if (event.jbutton.which != m_instance_id) { + if (event.jbutton.which != instance_id()) { return helper::nullopt; } @@ -464,9 +464,10 @@ helper::optional input::_3DSJoystickGameInput_Type1::sdl_event_to_in ) const { if (event.type == SDL_JOYBUTTONDOWN) { - if (event.jbutton.which != m_instance_id) { + //TODO: + /* if (event.jbutton.which != m_instance_id) { return helper::nullopt; - } + } */ const auto button = event.jbutton.button; if (button == JOYCON_L) { @@ -492,9 +493,10 @@ helper::optional input::_3DSJoystickGameInput_Type1::sdl_event_to_in } } else if (event.type == SDL_JOYBUTTONUP) { - if (event.jbutton.which != m_instance_id) { + //TODO: + /* if (event.jbutton.which != m_instance_id) { return helper::nullopt; - } + } */ const auto button = event.jbutton.button; if (button == JOYCON_L) { diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index c77f97e0..4a588d64 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -119,7 +119,7 @@ namespace input { struct _3DSJoystickInput_Type1 : JoystickInput { //TODO - static SDL::GUID guid{}; + static constexpr SDL::GUID guid{}; public: _3DSJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); From aa7096f6b3e3f3a47812bec70049c39d422fc28d Mon Sep 17 00:00:00 2001 From: "Totto16 (Windows VM)" Date: Fri, 10 May 2024 20:23:11 +0200 Subject: [PATCH 32/76] fix MSVC build - input/touch_input: fix floating precission - input/input: fix signed / unsigned comparison --- src/input/input.cpp | 8 ++++---- src/input/touch_input.cpp | 10 ++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/input/input.cpp b/src/input/input.cpp index 23dfc317..fe51d382 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -32,10 +32,10 @@ input::PointerEventHelper::PointerEventHelper(shapes::IPoint pos, PointerEvent e [[nodiscard]] bool input::PointerEventHelper::is_in(const shapes::URect& rect) const { using Type = decltype(m_pos)::Type; - assert(rect.top_left.x <= std::numeric_limits::max()); - assert(rect.top_left.y <= std::numeric_limits::max()); - assert(rect.bottom_right.x <= std::numeric_limits::max()); - assert(rect.bottom_right.y <= std::numeric_limits::max()); + assert(rect.top_left.x <= static_cast(std::numeric_limits::max())); + assert(rect.top_left.y <= static_cast(std::numeric_limits::max())); + assert(rect.bottom_right.x <= static_cast(std::numeric_limits::max())); + assert(rect.bottom_right.y <= static_cast(std::numeric_limits::max())); return is_in(rect.cast()); } diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index 2b7bce82..35050466 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -258,13 +258,15 @@ input::TouchInput::get_by_device_index(const std::shared_ptr& window, in throw std::runtime_error("Tried to offset event, that is no pointer event: in Touch Input"); } - const double x_percent = event.tfinger.x; - const double y_percent = event.tfinger.y; + using FloatType = decltype(event.tfinger.x); + + const FloatType x_percent = event.tfinger.x; + const FloatType y_percent = event.tfinger.y; const auto window_size = m_window->size(); - new_event.tfinger.x = x_percent + static_cast(point.x) / static_cast(window_size.x); - new_event.tfinger.y = y_percent + static_cast(point.y) / static_cast(window_size.y); + new_event.tfinger.x = x_percent + static_cast(point.x) / static_cast(window_size.x); + new_event.tfinger.y = y_percent + static_cast(point.y) / static_cast(window_size.y); return new_event; } From 53c5dfa172bdebc8aaab7a2733c3976645ab7d95 Mon Sep 17 00:00:00 2001 From: "Totto16 (Windows VM)" Date: Fri, 10 May 2024 20:23:31 +0200 Subject: [PATCH 33/76] imporve utils::unrechable: - print something to stderr on debug builds - use utils::unreachable everywhere instead of std::unreachable --- src/helper/utils.hpp | 22 ++++++++++++++++++++-- src/ui/layouts/focus_layout.cpp | 2 +- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/helper/utils.hpp b/src/helper/utils.hpp index 23983c27..3eeebb51 100644 --- a/src/helper/utils.hpp +++ b/src/helper/utils.hpp @@ -7,9 +7,11 @@ #include #include #include +#include #include #include #include +#include namespace helper { @@ -57,11 +59,27 @@ namespace utils { return static_cast>(enum_); } +#if __cpp_lib_unreachable >= 202202L [[noreturn]] inline void unreachable() { - assert(false and "unreachable"); - std::terminate(); +#if !defined(NDEBUG) + std::cerr << "UNREACHABLE\n"; +#endif + + std::unreachable(); } +#else + [[noreturn]] inline void unreachable() { +#if !defined(NDEBUG) + std::cerr << "UNREACHABLE\n"; +#endif +#if defined(_MSC_VER) && !defined(__clang__) // MSVC + __assume(false); +#else // GCC, Clang + __builtin_unreachable(); +#endif + } +#endif template struct size_t_identity { //using type = T; diff --git a/src/ui/layouts/focus_layout.cpp b/src/ui/layouts/focus_layout.cpp index 65923a2f..c2aca12f 100644 --- a/src/ui/layouts/focus_layout.cpp +++ b/src/ui/layouts/focus_layout.cpp @@ -174,7 +174,7 @@ ui::FocusLayout::handle_event_result( // NOLINT(readability-function-cognitive-c return ui::Widget::InnerState{ ui::EventHandleType::RequestAction, value.second }; } default: - std::unreachable(); + utils::unreachable(); } } From 646c7cdbc7ccf77f2eff0dc6033e1c4c39ab9b40 Mon Sep 17 00:00:00 2001 From: "Totto16 (Windows VM)" Date: Fri, 10 May 2024 20:23:38 +0200 Subject: [PATCH 34/76] fix MSVC build - manager/sdl_key: - explicitely cast int to char - mark function not as constexpr, as initializin an unorderd map is not constexpr in MSVC :( --- src/manager/sdl_key.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index 64b5c45c..78f88f72 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -224,7 +224,7 @@ namespace { auto result = input; for (size_t i = 0; i < result.size(); ++i) { auto& elem = result.at(i); - elem = std::tolower(elem); + elem = static_cast(std::tolower(elem)); } return result; @@ -263,7 +263,7 @@ namespace { rtrim(s); } - constexpr helper::optional modifier_from_string(std::string modifier) { + helper::optional modifier_from_string(std::string modifier) { if (modifier.empty()) { return helper::nullopt; @@ -289,7 +289,7 @@ namespace { { "shift", SDL::Modifier::SHIFT }, { "alt", SDL::Modifier::ALT }, { "gui", SDL::Modifier::GUI }, - }; // namespace + }; if (map.contains(lower_case)) { return map.at(lower_case); From 5b595bee20d3bc6a47d6ada5878a0273b527f774 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 13 May 2024 10:56:01 +0200 Subject: [PATCH 35/76] fix error after rebase --- src/application.cpp | 2 +- src/input/input.cpp | 2 +- src/manager/settings_manager.cpp | 8 ++++---- src/manager/settings_manager.hpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/application.cpp b/src/application.cpp index ed0513c8..c1d78364 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -259,7 +259,7 @@ void Application::initialize() { #endif #if defined(_HAVE_DISCORD_SDK) - if (m_settings_manager.discord()) { + if (m_settings_manager.settings().discord) { auto discord_instance = DiscordInstance::initialize(); if (not discord_instance.has_value()) { spdlog::warn( diff --git a/src/input/input.cpp b/src/input/input.cpp index fe51d382..d424930b 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -156,7 +156,7 @@ input::InputManager::~InputManager() = default; //TODO: select the first suitable, by using the primary input method or some other settings! - for (const auto& control : service_provider->settings_manager().controls()) { + for (const auto& control : service_provider->settings_manager().settings().controls) { return std::visit( helper::overloaded{ [service_provider](const input::KeyboardSettings& keyboard_settings diff --git a/src/manager/settings_manager.cpp b/src/manager/settings_manager.cpp index fa377ce0..0e396375 100644 --- a/src/manager/settings_manager.cpp +++ b/src/manager/settings_manager.cpp @@ -10,19 +10,19 @@ SettingsManager::SettingsManager(ServiceProvider* service_provider) : m_service_ const auto result = json::try_parse_json_file(settings_file); if (result.has_value()) { - m_current_settings = result.value(); + m_settings = result.value(); } else { spdlog::error("unable to load settings from \"{}\": {}", detail::settings_filename, result.error()); spdlog::warn("applying default settings"); //TODO: better default settings - m_current_settings = { + m_settings = { detail::Settings{ {}, 1.0 } }; } } -[[nodiscard]] const std::vector& SettingsManager::controls() const { - return m_current_settings.controls; +[[nodiscard]] const detail::Settings& SettingsManager::settings() const { + return m_settings; } diff --git a/src/manager/settings_manager.hpp b/src/manager/settings_manager.hpp index 2ec9f535..9c8aaba2 100644 --- a/src/manager/settings_manager.hpp +++ b/src/manager/settings_manager.hpp @@ -68,7 +68,7 @@ namespace detail { struct SettingsManager { private: ServiceProvider* m_service_provider; - detail::Settings m_current_settings; + detail::Settings m_settings; public: explicit SettingsManager(ServiceProvider* service_provider); From faefebf18ff3e34eb7fa7765b3b55317e6a6983e Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 13 May 2024 14:53:09 +0200 Subject: [PATCH 36/76] clang tidy: - add naming conventions checks --- .clang-tidy | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 2 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index dc6c70d9..fd4de4a0 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -6,6 +6,133 @@ HeaderFilterRegex: "oopetris/src/.*" AnalyzeTemporaryDtors: false FormatStyle: "file" CheckOptions: + ## NAMING CONVENTION SECTION + - key: readability-identifier-naming.AbstractClassCase + value: "CamelCase" + - key: readability-identifier-naming.AggressiveDependentMemberLookup + value: true + - key: readability-identifier-naming.CheckAnonFieldInParent + value: false + - key: readability-identifier-naming.ClassCase + value: "CamelCase" + - key: readability-identifier-naming.ClassConstantCase + value: "lower_case" + - key: readability-identifier-naming.ClassConstantPrefix + value: "c_" + - key: readability-identifier-naming.ClassMemberCase + value: "lower_case" + - key: readability-identifier-naming.ClassMemberPrefix + value: "m_" + - key: readability-identifier-naming.ClassMethodCase + value: "lower_case" + - key: readability-identifier-naming.ConceptCase + value: "CamelCase" + - key: readability-identifier-naming.ConstantCase + value: "lower_case" + - key: readability-identifier-naming.ConstantMemberCase + value: "lower_case" + - key: readability-identifier-naming.ConstantParameterCase + value: "lower_case" + - key: readability-identifier-naming.ConstantPointerParameterCase + value: "lower_case" + - key: readability-identifier-naming.ConstexprFunctionCase + value: "lower_case" + - key: readability-identifier-naming.ConstexprMethodCase + value: "lower_case" + - key: readability-identifier-naming.ConstexprVariableCase + value: "lower_case" + - key: readability-identifier-naming.EnumCase + value: "CamelCase" + - key: readability-identifier-naming.EnumConstantCase + value: "CamelCase" + - key: readability-identifier-naming.FunctionCase + value: "lower_case" + - key: readability-identifier-naming.GlobalConstantCase + value: "lower_case" + - key: readability-identifier-naming.GlobalConstantPointerCase + value: "lower_case" + - key: readability-identifier-naming.GlobalFunctionCase + value: "lower_case" + - key: readability-identifier-naming.GlobalPointerCase + value: "lower_case" + - key: readability-identifier-naming.GlobalVariableCase + value: "lower_case" + - key: readability-identifier-naming.GlobalVariablePrefix + value: "g_" + - key: readability-identifier-naming.LocalConstantCase + value: "lower_case" + - key: readability-identifier-naming.LocalConstantPointerCase + value: "lower_case" + - key: readability-identifier-naming.LocalPointerCase + value: "lower_case" + - key: readability-identifier-naming.LocalVariableCase + value: "lower_case" + - key: readability-identifier-naming.MacroDefinitionCase + value: "UPPER_CASE" + - key: readability-identifier-naming.MemberCase + value: "lower_case" + - key: readability-identifier-naming.MemberPrefix + value: "m_" + - key: readability-identifier-naming.MethodCase + value: "lower_case" + - key: readability-identifier-naming.NamespaceCase + value: "lower_case" + - key: readability-identifier-naming.ParameterCase + value: "lower_case" + - key: readability-identifier-naming.ParameterPackCase + value: "lower_case" + - key: readability-identifier-naming.PointerParameterCase + value: "lower_case" + - key: readability-identifier-naming.PrivateMemberCase + value: "lower_case" + - key: readability-identifier-naming.PrivateMemberPrefix + value: "m_" + - key: readability-identifier-naming.PrivateMethodCase + value: "lower_case" + - key: readability-identifier-naming.ProtectedMemberCase + value: "lower_case" + - key: readability-identifier-naming.ProtectedMemberPrefix + value: "m_" + - key: readability-identifier-naming.ProtectedMethodCase + value: "lower_case" + - key: readability-identifier-naming.PublicMemberCase + value: "lower_case" + - key: readability-identifier-naming.PublicMemberPrefix + value: "" # NO PREFIX + - key: readability-identifier-naming.PublicMethodCase + value: "lower_case" + - key: readability-identifier-naming.ScopedEnumConstantCase + value: "CamelCase" + - key: readability-identifier-naming.StaticConstantCase + value: "lower_case" + - key: readability-identifier-naming.StaticConstantPrefix + value: "s_" + - key: readability-identifier-naming.StaticVariableCase + value: "lower_case" + - key: readability-identifier-naming.StaticVariablePrefix + value: "s_" + - key: readability-identifier-naming.StructCase + value: "CamelCase" + - key: readability-identifier-naming.TemplateParameterCase + value: "CamelCase" + - key: readability-identifier-naming.TemplateTemplateParameterCase + value: "CamelCase" + - key: readability-identifier-naming.TypeAliasCase + value: "CamelCase" + - key: readability-identifier-naming.TypedefCase + value: "CamelCase" + - key: readability-identifier-naming.TypeTemplateParameterCase + value: "CamelCase" + - key: readability-identifier-naming.UnionCase + value: "CamelCase" + - key: readability-identifier-naming.ValueTemplateParameterCase + value: "lower_case" + - key: readability-identifier-naming.VariableCase + value: "lower_case" + - key: readability-identifier-naming.VirtualMethodCase + value: "lower_case" + + - key: bugprone-argument-comment.CommentBoolLiterals value: "0" - key: bugprone-argument-comment.CommentCharacterLiterals @@ -154,8 +281,6 @@ CheckOptions: value: "800" - key: readability-function-size.VariableThreshold value: "4294967295" - - key: readability-identifier-naming.IgnoreFailedSplit - value: "0" - key: readability-implicit-bool-conversion.AllowIntegerConditions value: "0" - key: readability-implicit-bool-conversion.AllowPointerConditions From 81af69bf479e05f0a69e34f54ab9e75173efa91d Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 13 May 2024 15:33:31 +0200 Subject: [PATCH 37/76] run clang-format --- src/input/input.cpp | 6 +++--- src/input/touch_input.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/input/input.cpp b/src/input/input.cpp index d424930b..4bcb20d7 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -33,9 +33,9 @@ input::PointerEventHelper::PointerEventHelper(shapes::IPoint pos, PointerEvent e using Type = decltype(m_pos)::Type; assert(rect.top_left.x <= static_cast(std::numeric_limits::max())); - assert(rect.top_left.y <= static_cast(std::numeric_limits::max())); - assert(rect.bottom_right.x <= static_cast(std::numeric_limits::max())); - assert(rect.bottom_right.y <= static_cast(std::numeric_limits::max())); + assert(rect.top_left.y <= static_cast(std::numeric_limits::max())); + assert(rect.bottom_right.x <= static_cast(std::numeric_limits::max())); + assert(rect.bottom_right.y <= static_cast(std::numeric_limits::max())); return is_in(rect.cast()); } diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index 35050466..279be197 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -258,7 +258,7 @@ input::TouchInput::get_by_device_index(const std::shared_ptr& window, in throw std::runtime_error("Tried to offset event, that is no pointer event: in Touch Input"); } - using FloatType = decltype(event.tfinger.x); + using FloatType = decltype(event.tfinger.x); const FloatType x_percent = event.tfinger.x; const FloatType y_percent = event.tfinger.y; From 7f0bae09c31c1ffdb71896de2dd647d13a0a3deb Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 13 May 2024 15:34:31 +0200 Subject: [PATCH 38/76] clang tidy: - remove deprecated setting "AnalyzeTemporaryDtors" (deprecated in clang-tidy 16 and removed in clang-tidy 18) --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index fd4de4a0..3f67ebc7 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -3,7 +3,6 @@ Checks: "clang-diagnostic-*,clang-analyzer-*,bugprone-*,misc-*,performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,-modernize-use-trailing-return-type,-readability-named-parameter,-readability-identifier-length,-misc-include-cleaner,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-misc-non-private-member-variables-in-classes,-cppcoreguidelines-non-private-member-variables-in-classes" WarningsAsErrors: "" HeaderFilterRegex: "oopetris/src/.*" -AnalyzeTemporaryDtors: false FormatStyle: "file" CheckOptions: ## NAMING CONVENTION SECTION From 8a4ad7f047bac9f4dc7670713626917d5482c10a Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 13 May 2024 15:43:44 +0200 Subject: [PATCH 39/76] clang tidy: refactor settings - remove defaults - add some more global checks - add back some checks, that where ignored before --- .clang-tidy | 460 ++++++++++++++++++---------------------------------- 1 file changed, 155 insertions(+), 305 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 3f67ebc7..22c1bb1e 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,312 +1,162 @@ # taken from https://github.com/cpp-linter/cpp-linter-action/blob/main/demo/.clang-tidy --- -Checks: "clang-diagnostic-*,clang-analyzer-*,bugprone-*,misc-*,performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,-modernize-use-trailing-return-type,-readability-named-parameter,-readability-identifier-length,-misc-include-cleaner,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-misc-non-private-member-variables-in-classes,-cppcoreguidelines-non-private-member-variables-in-classes" +Checks: "clang-diagnostic-*,clang-analyzer-*,bugprone-*,misc-*,performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,google-*,llvm-*,cert-*,-modernize-use-trailing-return-type,-bugprone-argument-comment,-misc-include-cleaner,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers" WarningsAsErrors: "" HeaderFilterRegex: "oopetris/src/.*" FormatStyle: "file" CheckOptions: - ## NAMING CONVENTION SECTION - - key: readability-identifier-naming.AbstractClassCase - value: "CamelCase" - - key: readability-identifier-naming.AggressiveDependentMemberLookup - value: true - - key: readability-identifier-naming.CheckAnonFieldInParent - value: false - - key: readability-identifier-naming.ClassCase - value: "CamelCase" - - key: readability-identifier-naming.ClassConstantCase - value: "lower_case" - - key: readability-identifier-naming.ClassConstantPrefix - value: "c_" - - key: readability-identifier-naming.ClassMemberCase - value: "lower_case" - - key: readability-identifier-naming.ClassMemberPrefix - value: "m_" - - key: readability-identifier-naming.ClassMethodCase - value: "lower_case" - - key: readability-identifier-naming.ConceptCase - value: "CamelCase" - - key: readability-identifier-naming.ConstantCase - value: "lower_case" - - key: readability-identifier-naming.ConstantMemberCase - value: "lower_case" - - key: readability-identifier-naming.ConstantParameterCase - value: "lower_case" - - key: readability-identifier-naming.ConstantPointerParameterCase - value: "lower_case" - - key: readability-identifier-naming.ConstexprFunctionCase - value: "lower_case" - - key: readability-identifier-naming.ConstexprMethodCase - value: "lower_case" - - key: readability-identifier-naming.ConstexprVariableCase - value: "lower_case" - - key: readability-identifier-naming.EnumCase - value: "CamelCase" - - key: readability-identifier-naming.EnumConstantCase - value: "CamelCase" - - key: readability-identifier-naming.FunctionCase - value: "lower_case" - - key: readability-identifier-naming.GlobalConstantCase - value: "lower_case" - - key: readability-identifier-naming.GlobalConstantPointerCase - value: "lower_case" - - key: readability-identifier-naming.GlobalFunctionCase - value: "lower_case" - - key: readability-identifier-naming.GlobalPointerCase - value: "lower_case" - - key: readability-identifier-naming.GlobalVariableCase - value: "lower_case" - - key: readability-identifier-naming.GlobalVariablePrefix - value: "g_" - - key: readability-identifier-naming.LocalConstantCase - value: "lower_case" - - key: readability-identifier-naming.LocalConstantPointerCase - value: "lower_case" - - key: readability-identifier-naming.LocalPointerCase - value: "lower_case" - - key: readability-identifier-naming.LocalVariableCase - value: "lower_case" - - key: readability-identifier-naming.MacroDefinitionCase - value: "UPPER_CASE" - - key: readability-identifier-naming.MemberCase - value: "lower_case" - - key: readability-identifier-naming.MemberPrefix - value: "m_" - - key: readability-identifier-naming.MethodCase - value: "lower_case" - - key: readability-identifier-naming.NamespaceCase - value: "lower_case" - - key: readability-identifier-naming.ParameterCase - value: "lower_case" - - key: readability-identifier-naming.ParameterPackCase - value: "lower_case" - - key: readability-identifier-naming.PointerParameterCase - value: "lower_case" - - key: readability-identifier-naming.PrivateMemberCase - value: "lower_case" - - key: readability-identifier-naming.PrivateMemberPrefix - value: "m_" - - key: readability-identifier-naming.PrivateMethodCase - value: "lower_case" - - key: readability-identifier-naming.ProtectedMemberCase - value: "lower_case" - - key: readability-identifier-naming.ProtectedMemberPrefix - value: "m_" - - key: readability-identifier-naming.ProtectedMethodCase - value: "lower_case" - - key: readability-identifier-naming.PublicMemberCase - value: "lower_case" - - key: readability-identifier-naming.PublicMemberPrefix - value: "" # NO PREFIX - - key: readability-identifier-naming.PublicMethodCase - value: "lower_case" - - key: readability-identifier-naming.ScopedEnumConstantCase - value: "CamelCase" - - key: readability-identifier-naming.StaticConstantCase - value: "lower_case" - - key: readability-identifier-naming.StaticConstantPrefix - value: "s_" - - key: readability-identifier-naming.StaticVariableCase - value: "lower_case" - - key: readability-identifier-naming.StaticVariablePrefix - value: "s_" - - key: readability-identifier-naming.StructCase - value: "CamelCase" - - key: readability-identifier-naming.TemplateParameterCase - value: "CamelCase" - - key: readability-identifier-naming.TemplateTemplateParameterCase - value: "CamelCase" - - key: readability-identifier-naming.TypeAliasCase - value: "CamelCase" - - key: readability-identifier-naming.TypedefCase - value: "CamelCase" - - key: readability-identifier-naming.TypeTemplateParameterCase - value: "CamelCase" - - key: readability-identifier-naming.UnionCase - value: "CamelCase" - - key: readability-identifier-naming.ValueTemplateParameterCase - value: "lower_case" - - key: readability-identifier-naming.VariableCase - value: "lower_case" - - key: readability-identifier-naming.VirtualMethodCase - value: "lower_case" - + ## NAMING CONVENTION SECTION + - key: readability-identifier-naming.AbstractClassCase + value: "CamelCase" + - key: readability-identifier-naming.AggressiveDependentMemberLookup + value: true + - key: readability-identifier-naming.CheckAnonFieldInParent + value: false + - key: readability-identifier-naming.ClassCase + value: "CamelCase" + - key: readability-identifier-naming.ClassConstantCase + value: "lower_case" + - key: readability-identifier-naming.ClassConstantPrefix + value: "c_" + - key: readability-identifier-naming.ClassMemberCase + value: "lower_case" + - key: readability-identifier-naming.ClassMemberPrefix + value: "m_" + - key: readability-identifier-naming.ClassMethodCase + value: "lower_case" + - key: readability-identifier-naming.ConceptCase + value: "CamelCase" + - key: readability-identifier-naming.ConstantCase + value: "lower_case" + - key: readability-identifier-naming.ConstantMemberCase + value: "lower_case" + - key: readability-identifier-naming.ConstantParameterCase + value: "lower_case" + - key: readability-identifier-naming.ConstantPointerParameterCase + value: "lower_case" + - key: readability-identifier-naming.ConstexprFunctionCase + value: "lower_case" + - key: readability-identifier-naming.ConstexprMethodCase + value: "lower_case" + - key: readability-identifier-naming.ConstexprVariableCase + value: "lower_case" + - key: readability-identifier-naming.EnumCase + value: "CamelCase" + - key: readability-identifier-naming.EnumConstantCase + value: "CamelCase" + - key: readability-identifier-naming.FunctionCase + value: "lower_case" + - key: readability-identifier-naming.GlobalConstantCase + value: "lower_case" + - key: readability-identifier-naming.GlobalConstantPointerCase + value: "lower_case" + - key: readability-identifier-naming.GlobalFunctionCase + value: "lower_case" + - key: readability-identifier-naming.GlobalPointerCase + value: "lower_case" + - key: readability-identifier-naming.GlobalVariableCase + value: "lower_case" + - key: readability-identifier-naming.GlobalVariablePrefix + value: "g_" + - key: readability-identifier-naming.LocalConstantCase + value: "lower_case" + - key: readability-identifier-naming.LocalConstantPointerCase + value: "lower_case" + - key: readability-identifier-naming.LocalPointerCase + value: "lower_case" + - key: readability-identifier-naming.LocalVariableCase + value: "lower_case" + - key: readability-identifier-naming.MacroDefinitionCase + value: "UPPER_CASE" + - key: readability-identifier-naming.MemberCase + value: "lower_case" + - key: readability-identifier-naming.MemberPrefix + value: "m_" + - key: readability-identifier-naming.MethodCase + value: "lower_case" + - key: readability-identifier-naming.NamespaceCase + value: "lower_case" + - key: readability-identifier-naming.ParameterCase + value: "lower_case" + - key: readability-identifier-naming.ParameterPackCase + value: "lower_case" + - key: readability-identifier-naming.PointerParameterCase + value: "lower_case" + - key: readability-identifier-naming.PrivateMemberCase + value: "lower_case" + - key: readability-identifier-naming.PrivateMemberPrefix + value: "m_" + - key: readability-identifier-naming.PrivateMethodCase + value: "lower_case" + - key: readability-identifier-naming.ProtectedMemberCase + value: "lower_case" + - key: readability-identifier-naming.ProtectedMemberPrefix + value: "m_" + - key: readability-identifier-naming.ProtectedMethodCase + value: "lower_case" + - key: readability-identifier-naming.PublicMemberCase + value: "lower_case" + - key: readability-identifier-naming.PublicMemberPrefix + value: "" # NO PREFIX + - key: readability-identifier-naming.PublicMethodCase + value: "lower_case" + - key: readability-identifier-naming.ScopedEnumConstantCase + value: "CamelCase" + - key: readability-identifier-naming.StaticConstantCase + value: "lower_case" + - key: readability-identifier-naming.StaticConstantPrefix + value: "s_" + - key: readability-identifier-naming.StaticVariableCase + value: "lower_case" + - key: readability-identifier-naming.StaticVariablePrefix + value: "s_" + - key: readability-identifier-naming.StructCase + value: "CamelCase" + - key: readability-identifier-naming.TemplateParameterCase + value: "CamelCase" + - key: readability-identifier-naming.TemplateTemplateParameterCase + value: "CamelCase" + - key: readability-identifier-naming.TypeAliasCase + value: "CamelCase" + - key: readability-identifier-naming.TypedefCase + value: "CamelCase" + - key: readability-identifier-naming.TypeTemplateParameterCase + value: "CamelCase" + - key: readability-identifier-naming.UnionCase + value: "CamelCase" + - key: readability-identifier-naming.ValueTemplateParameterCase + value: "lower_case" + - key: readability-identifier-naming.VariableCase + value: "lower_case" + - key: readability-identifier-naming.VirtualMethodCase + value: "lower_case" - - key: bugprone-argument-comment.CommentBoolLiterals - value: "0" - - key: bugprone-argument-comment.CommentCharacterLiterals - value: "0" - - key: bugprone-argument-comment.CommentFloatLiterals - value: "0" - - key: bugprone-argument-comment.CommentIntegerLiterals - value: "0" - - key: bugprone-argument-comment.CommentNullPtrs - value: "0" - - key: bugprone-argument-comment.CommentStringLiterals - value: "0" - - key: bugprone-argument-comment.CommentUserDefinedLiterals - value: "0" - - key: bugprone-argument-comment.IgnoreSingleArgument - value: "0" - - key: bugprone-argument-comment.StrictMode - value: "0" - - key: bugprone-assert-side-effect.AssertMacros - value: assert - - key: bugprone-assert-side-effect.CheckFunctionCalls - value: "0" - - key: bugprone-dangling-handle.HandleClasses - value: "std::basic_string_view;std::experimental::basic_string_view" - - key: bugprone-dynamic-static-initializers.HeaderFileExtensions - value: ",h,hh,hpp,hxx" - - key: bugprone-exception-escape.FunctionsThatShouldNotThrow - value: "" - - key: bugprone-exception-escape.IgnoredExceptions - value: "" - - key: bugprone-misplaced-widening-cast.CheckImplicitCasts - value: "0" - - key: bugprone-not-null-terminated-result.WantToUseSafeFunctions - value: "1" - - key: bugprone-signed-char-misuse.CharTypdefsToIgnore - value: "" - - key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant - value: "1" - - key: bugprone-sizeof-expression.WarnOnSizeOfConstant - value: "1" - - key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression - value: "0" - - key: bugprone-sizeof-expression.WarnOnSizeOfThis - value: "1" - - key: bugprone-string-constructor.LargeLengthThreshold - value: "8388608" - - key: bugprone-string-constructor.WarnOnLargeLength - value: "1" - - key: bugprone-suspicious-enum-usage.StrictMode - value: "0" - - key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens - value: "5" - - key: bugprone-suspicious-missing-comma.RatioThreshold - value: "0.200000" - - key: bugprone-suspicious-missing-comma.SizeThreshold - value: "5" - - key: bugprone-suspicious-string-compare.StringCompareLikeFunctions - value: "" - - key: bugprone-suspicious-string-compare.WarnOnImplicitComparison - value: "1" - - key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison - value: "0" - - key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit - value: "16" - - key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField - value: "1" - - key: bugprone-unused-return-value.CheckedFunctions - value: "::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty" - - key: cert-dcl16-c.NewSuffixes - value: "L;LL;LU;LLU" - - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField - value: "0" - - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors - value: "1" - - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic - value: "1" - - key: google-readability-braces-around-statements.ShortStatementLines - value: "1" - - key: google-readability-function-size.StatementThreshold - value: "800" - - key: google-readability-namespace-comments.ShortNamespaceLines - value: "10" - - key: google-readability-namespace-comments.SpacesBeforeComments - value: "2" - - key: misc-definitions-in-headers.HeaderFileExtensions - value: ",h,hh,hpp,hxx" - - key: misc-definitions-in-headers.UseHeaderFileExtension - value: "1" - - key: misc-throw-by-value-catch-by-reference.CheckThrowTemporaries - value: "1" - - key: misc-unused-parameters.StrictMode - value: "0" - - key: modernize-loop-convert.MaxCopySize - value: "16" - - key: modernize-loop-convert.MinConfidence - value: reasonable - - key: modernize-use-trailing-return-type - value: "false" - - key: modernize-loop-convert.NamingStyle - value: CamelCase - - key: modernize-pass-by-value.IncludeStyle - value: llvm - - key: modernize-replace-auto-ptr.IncludeStyle - value: llvm - - key: modernize-use-nullptr.NullMacros - value: "NULL" - - key: performance-faster-string-find.StringLikeClasses - value: "std::basic_string" - - key: performance-for-range-copy.AllowedTypes - value: "" - - key: performance-for-range-copy.WarnOnAllAutoCopies - value: "0" - - key: performance-inefficient-string-concatenation.StrictMode - value: "0" - - key: performance-inefficient-vector-operation.EnableProto - value: "0" - - key: performance-inefficient-vector-operation.VectorLikeClasses - value: "::std::vector" - - key: performance-move-const-arg.CheckTriviallyCopyableMove - value: "1" - - key: performance-move-constructor-init.IncludeStyle - value: llvm - - key: performance-no-automatic-move.AllowedTypes - value: "" - - key: performance-type-promotion-in-math-fn.IncludeStyle - value: llvm - - key: performance-unnecessary-copy-initialization.AllowedTypes - value: "" - - key: performance-unnecessary-value-param.AllowedTypes - value: "" - - key: performance-unnecessary-value-param.IncludeStyle - value: llvm - - key: readability-braces-around-statements.ShortStatementLines - value: "0" - - key: readability-else-after-return.WarnOnUnfixable - value: "1" - - key: readability-function-size.BranchThreshold - value: "4294967295" - - key: readability-function-size.LineThreshold - value: "4294967295" - - key: readability-function-size.NestingThreshold - value: "4294967295" - - key: readability-function-size.ParameterThreshold - value: "4294967295" - - key: readability-function-size.StatementThreshold - value: "800" - - key: readability-function-size.VariableThreshold - value: "4294967295" - - key: readability-implicit-bool-conversion.AllowIntegerConditions - value: "0" - - key: readability-implicit-bool-conversion.AllowPointerConditions - value: "0" - - key: readability-inconsistent-declaration-parameter-name.IgnoreMacros - value: "1" - - key: readability-inconsistent-declaration-parameter-name.Strict - value: "0" - - key: readability-magic-numbers.IgnoredFloatingPointValues - value: "1.0;100.0;" - - key: readability-magic-numbers.IgnoredIntegerValues - value: "1;2;3;4;" - - key: readability-redundant-member-init.IgnoreBaseInCopyConstructors - value: "0" - - key: readability-redundant-smartptr-get.IgnoreMacros - value: "1" - - key: readability-redundant-string-init.StringNames - value: "::std::basic_string" - - key: readability-simplify-boolean-expr.ChainedConditionalAssignment - value: "0" - - key: readability-simplify-boolean-expr.ChainedConditionalReturn - value: "0" - - key: readability-simplify-subscript-expr.Types - value: "::std::basic_string;::std::basic_string_view;::std::vector;::std::array" - - key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold - value: "3" - - key: readability-uppercase-literal-suffix.IgnoreMacros - value: "1" - - key: readability-uppercase-literal-suffix.NewSuffixes - value: "" + # some needed settings, that are non default + - key: bugprone-assert-side-effect.AssertMacros + value: "assert" + - key: bugprone-misplaced-widening-cast.CheckImplicitCasts + value: true + - key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic + value: true + - key: bugprone-suspicious-enum-usage.StrictMode + value: true + - key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison + value: true + - key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField + value: true + - key: misc-unused-parameters.StrictMode + value: true + - key: performance-inefficient-string-concatenation.StrictMode + value: true + - key: readability-inconsistent-declaration-parameter-name.Strict + value: true + + ## special things, that have special values + - key: readability-identifier-length.IgnoredVariableNames + value: "" + - key: readability-identifier-length.IgnoredParameterNames + value: "^[n]$" + - key: readability-identifier-length.MinimumLoopCounterNameLength + value: 1 + - key: readability-identifier-length.MinimumExceptionNameLength + value: 5 From b8fffa7e42f2349fd4bd24436acf646c366df75a Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 13 May 2024 15:55:24 +0200 Subject: [PATCH 40/76] clang-tidy: fix some things --- src/application.cpp | 25 +++++++++++++++++-------- src/helper/errors.cpp | 26 ++++++++++++++++++-------- src/helper/errors.hpp | 18 +++++++++--------- 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/application.cpp b/src/application.cpp index c1d78364..f5ab5ce0 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -22,9 +22,15 @@ namespace { [[nodiscard]] helper::MessageBox::Type get_notification_level(helper::error::Severity severity) { - return severity == helper::error::Severity::Fatal ? helper::MessageBox::Type::Error - : severity == helper::error::Severity::Major ? helper::MessageBox::Type::Warning - : helper::MessageBox::Type::Information; + switch (severity) { + case helper::error::Severity::Minor: + return helper::MessageBox::Type::Information; + case helper::error::Severity::Major: + return helper::MessageBox::Type::Warning; + case helper::error::Severity::Fatal: + default: + return helper::MessageBox::Type::Error; + } } } // namespace @@ -88,7 +94,7 @@ void Application::run() { const Uint64 current_time = SDL_GetPerformanceCounter(); if (current_time - start_time >= update_time) { - double elapsed = static_cast(current_time - start_time) / count_per_s; + const double elapsed = static_cast(current_time - start_time) / count_per_s; m_fps_text->set_text(*this, fmt::format("FPS: {:.2f}", static_cast(frame_counter) / elapsed)); start_time = current_time; frame_counter = 0; @@ -100,7 +106,7 @@ void Application::run() { const auto now = std::chrono::steady_clock::now(); const auto runtime = (now - start_execution_time); if (runtime < sleep_time) { - //TODO: use SDL_DelayNS in sdl >= 3.0 + //TODO(totto): use SDL_DelayNS in sdl >= 3.0 helper::sleep_nanoseconds(sleep_time - runtime); start_execution_time = std::chrono::steady_clock::now(); } else { @@ -190,9 +196,12 @@ void Application::update() { spdlog::info("pushing back scene {}", raw_push.name); m_scene_stack.push_back(std::move(raw_push.scene)); }, - [this](const scenes::Scene::Switch& switch_) { - spdlog::info("switching to scene {}", magic_enum::enum_name(switch_.target_scene)); - auto scene = scenes::create_scene(*this, switch_.target_scene, switch_.layout); + [this](const scenes::Scene::Switch& scene_switch) { + spdlog::info( + "switching to scene {}", magic_enum::enum_name(scene_switch.target_scene) + ); + auto scene = + scenes::create_scene(*this, scene_switch.target_scene, scene_switch.layout); // only clear, after the construction was successful m_scene_stack.clear(); diff --git a/src/helper/errors.cpp b/src/helper/errors.cpp index 88ec58e8..a21f9a65 100644 --- a/src/helper/errors.cpp +++ b/src/helper/errors.cpp @@ -1,13 +1,17 @@ #include "errors.hpp" -helper::GeneralError::GeneralError(const std::string& message, error::Severity severity) +helper::GeneralError::GeneralError(const std::string& message, error::Severity severity) noexcept : m_message{ message }, m_severity{ severity } { } -helper::GeneralError::GeneralError(std::string&& message, error::Severity severity) +helper::GeneralError::GeneralError(std::string&& message, error::Severity severity) noexcept : m_message{ std::move(message) }, m_severity{ severity } { } +helper::GeneralError::GeneralError(const GeneralError& error) noexcept + : m_message{ error.message() }, + m_severity{ error.severity() } { } + [[nodiscard]] const std::string& helper::GeneralError::message() const { return m_message; } @@ -16,14 +20,20 @@ helper::GeneralError::GeneralError(std::string&& message, error::Severity severi return m_severity; } -helper::FatalError::FatalError(const std::string& message) : GeneralError{ message, error::Severity::Fatal } { } +helper::FatalError::FatalError(const std::string& message) noexcept + : GeneralError{ message, error::Severity::Fatal } { } -helper::FatalError::FatalError(std::string&& message) : GeneralError{ std::move(message), error::Severity::Fatal } { } +helper::FatalError::FatalError(std::string&& message) noexcept + : GeneralError{ std::move(message), error::Severity::Fatal } { } -helper::MajorError::MajorError(const std::string& message) : GeneralError{ message, error::Severity::Major } { } +helper::MajorError::MajorError(const std::string& message) noexcept + : GeneralError{ message, error::Severity::Major } { } -helper::MajorError::MajorError(std::string&& message) : GeneralError{ std::move(message), error::Severity::Major } { } +helper::MajorError::MajorError(std::string&& message) noexcept + : GeneralError{ std::move(message), error::Severity::Major } { } -helper::MinorError::MinorError(const std::string& message) : GeneralError{ message, error::Severity::Minor } { } +helper::MinorError::MinorError(const std::string& message) noexcept + : GeneralError{ message, error::Severity::Minor } { } -helper::MinorError::MinorError(std::string&& message) : GeneralError{ std::move(message), error::Severity::Minor } { } +helper::MinorError::MinorError(std::string&& message) noexcept + : GeneralError{ std::move(message), error::Severity::Minor } { } diff --git a/src/helper/errors.hpp b/src/helper/errors.hpp index e6388be3..056ef145 100644 --- a/src/helper/errors.hpp +++ b/src/helper/errors.hpp @@ -17,30 +17,30 @@ namespace helper { error::Severity m_severity; public: - GeneralError(const std::string& message, error::Severity severity); - - GeneralError(std::string&& message, error::Severity severity); + GeneralError(const std::string& message, error::Severity severity) noexcept; + GeneralError(std::string&& message, error::Severity severity) noexcept; + GeneralError(const GeneralError& error) noexcept; [[nodiscard]] const std::string& message() const; [[nodiscard]] error::Severity severity() const; }; struct FatalError : public GeneralError { - FatalError(const std::string& message); + FatalError(const std::string& message) noexcept; - FatalError(std::string&& message); + FatalError(std::string&& message) noexcept; }; struct MajorError : public GeneralError { - MajorError(const std::string& message); + MajorError(const std::string& message) noexcept; - MajorError(std::string&& message); + MajorError(std::string&& message) noexcept; }; struct MinorError : public GeneralError { - MinorError(const std::string& message); + MinorError(const std::string& message) noexcept ; - MinorError(std::string&& message); + MinorError(std::string&& message) noexcept; }; using InitializationError = FatalError; From a0bf1afd501fa747d54d970298604affcf317e94 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 13 May 2024 16:02:29 +0200 Subject: [PATCH 41/76] remove NOLINT's for readability-use-anyofallof and use std::ranges --- src/game/mino_stack.cpp | 11 ++++------- src/game/tetrion.cpp | 18 ++++++------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/game/mino_stack.cpp b/src/game/mino_stack.cpp index 5d8eab4a..f05fde93 100644 --- a/src/game/mino_stack.cpp +++ b/src/game/mino_stack.cpp @@ -1,7 +1,7 @@ #include "mino_stack.hpp" - #include "grid_properties.hpp" #include "helper/magic_enum_wrapper.hpp" + #include void MinoStack::clear_row_and_let_sink(u8 row) { @@ -17,12 +17,9 @@ void MinoStack::clear_row_and_let_sink(u8 row) { } [[nodiscard]] bool MinoStack::is_empty(GridPoint coordinates) const { - for (const Mino& mino : m_minos) { // NOLINT(readability-use-anyofallof) - if (mino.position() == coordinates) { - return false; - } - } - return true; + return not std::ranges::any_of(m_minos, [&coordinates](const Mino& mino) { + return mino.position() == coordinates; + }); } void MinoStack::set(GridPoint coordinates, helper::TetrominoType type) { diff --git a/src/game/tetrion.cpp b/src/game/tetrion.cpp index 7b3efb70..0d9b0964 100644 --- a/src/game/tetrion.cpp +++ b/src/game/tetrion.cpp @@ -522,12 +522,9 @@ helper::TetrominoType Tetrion::get_next_tetromino_type() { } bool Tetrion::tetromino_can_move_down(const Tetromino& tetromino) const { - for (const Mino& mino : tetromino.minos()) { // NOLINT(readability-use-anyofallof) - if (not mino_can_move_down(mino.position())) { - return false; - } - } - return true; + return not std::ranges::any_of(tetromino.minos(), [this](const Mino& mino) { + return not mino_can_move_down(mino.position()); + }); } @@ -568,12 +565,9 @@ u8 Tetrion::rotation_to_index(const Rotation from, const Rotation to) { } bool Tetrion::is_tetromino_position_valid(const Tetromino& tetromino) const { - for (const Mino& mino : tetromino.minos()) { // NOLINT(readability-use-anyofallof) - if (not is_valid_mino_position(mino.position())) { - return false; - } - } - return true; + return not std::ranges::any_of(tetromino.minos(), [this](const Mino& mino) { + return not is_valid_mino_position(mino.position()); + }); } bool Tetrion::rotate(Tetrion::RotationDirection rotation_direction) { From 583b52c3bffa14fb138b6f7214a291a15e29de12 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 13 May 2024 16:23:46 +0200 Subject: [PATCH 42/76] modernize: - use std::ranges where possible --- src/game/mino_stack.cpp | 20 +++++++++----------- src/helper/parse_json.cpp | 2 +- src/helper/static_string.hpp | 4 ++-- src/input/input.hpp | 2 +- src/input/joystick_input.cpp | 2 +- src/manager/event_dispatcher.hpp | 6 ++---- src/manager/sdl_key.cpp | 29 ++++++++++++++++++----------- src/ui/layouts/focus_layout.cpp | 18 ++++++++++-------- 8 files changed, 44 insertions(+), 39 deletions(-) diff --git a/src/game/mino_stack.cpp b/src/game/mino_stack.cpp index f05fde93..770774d6 100644 --- a/src/game/mino_stack.cpp +++ b/src/game/mino_stack.cpp @@ -6,7 +6,7 @@ void MinoStack::clear_row_and_let_sink(u8 row) { m_minos.erase( - std::remove_if(m_minos.begin(), m_minos.end(), [&](const Mino& mino) { return mino.position().y == row; }), + std::ranges::remove_if(m_minos, [&](const Mino& mino) { return mino.position().y == row; }).begin(), m_minos.end() ); for (Mino& mino : m_minos) { @@ -45,18 +45,17 @@ void MinoStack::set(GridPoint coordinates, helper::TetrominoType type) { return false; } - const auto all_of_this_in_other = std::all_of(m_minos.cbegin(), m_minos.cend(), [&](const auto& mino) { - return std::find(other.m_minos.cbegin(), other.m_minos.cend(), mino) != end(other.m_minos); + const auto all_of_this_in_other = std::ranges::all_of(m_minos, [&](const auto& mino) { + return std::ranges::find(other.m_minos, mino) != end(other.m_minos); }); if (not all_of_this_in_other) { return false; } - const auto all_of_other_in_this = - std::all_of(other.m_minos.cbegin(), other.m_minos.cend(), [this](const auto& mino) { - return std::find(m_minos.cbegin(), m_minos.cend(), mino) != end(m_minos); - }); + const auto all_of_other_in_this = std::ranges::all_of(other.m_minos, [this](const auto& mino) { + return std::ranges::find(m_minos, mino) != end(m_minos); + }); return all_of_other_in_this; } @@ -70,10 +69,9 @@ std::ostream& operator<<(std::ostream& ostream, const MinoStack& mino_stack) { ostream << "MinoStack(\n"; for (u8 y = 0; y < grid::height_in_tiles; ++y) { for (u8 x = 0; x < grid::width_in_tiles; ++x) { - const auto find_iterator = - std::find_if(mino_stack.minos().cbegin(), mino_stack.minos().cend(), [&](const auto& mino) { - return mino.position() == shapes::AbstractPoint{ x, y }; - }); + const auto find_iterator = std::ranges::find_if(mino_stack.minos(), [&](const auto& mino) { + return mino.position() == shapes::AbstractPoint{ x, y }; + }); const auto found = (find_iterator != mino_stack.minos().cend()); if (found) { ostream << magic_enum::enum_name(find_iterator->type()); diff --git a/src/helper/parse_json.cpp b/src/helper/parse_json.cpp index a7434863..96b827e6 100644 --- a/src/helper/parse_json.cpp +++ b/src/helper/parse_json.cpp @@ -46,7 +46,7 @@ void json::check_for_no_additional_keys(const nlohmann::json& j, const std::vect for (const auto& [key, _] : object) { - if (std::find(keys.cbegin(), keys.cend(), key) == keys.cend()) { + if (std::ranges::find(keys, key) == keys.cend()) { throw nlohmann::json::type_error::create( 302, fmt::format("object may only contain expected keys, but contained '{}'", key), &j ); diff --git a/src/helper/static_string.hpp b/src/helper/static_string.hpp index 878a8cc4..5b4a96e0 100644 --- a/src/helper/static_string.hpp +++ b/src/helper/static_string.hpp @@ -72,8 +72,8 @@ struct StaticString { template> [[nodiscard]] constexpr Result operator+(const StaticString& other) const { auto concatenated = Result{}; - std::copy(cbegin(), cend(), concatenated.begin()); - std::copy(other.cbegin(), other.cend(), concatenated.begin() + size()); + std::ranges::copy(*this, concatenated.begin()); + std::ranges::copy(other, concatenated.begin() + size()); concatenated.back() = '\0'; return concatenated; } diff --git a/src/input/input.hpp b/src/input/input.hpp index 57c097cb..ddaa54a6 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -114,7 +114,7 @@ namespace input { for (const auto& single_check : to_check) { - if (std::find(already_bound.cbegin(), already_bound.cend(), single_check) != already_bound.cend()) { + if (std::ranges::find(already_bound, single_check) != already_bound.cend()) { return helper::unexpected{ fmt::format("KeyCode already bound: '{}'", single_check) }; } diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 5c19eb55..240b572c 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -167,7 +167,7 @@ void input::JoyStickInputManager::discover_devices(std::vector(*it); joystick_input.has_value()) { diff --git a/src/manager/event_dispatcher.hpp b/src/manager/event_dispatcher.hpp index 5d546a19..1ce3954a 100644 --- a/src/manager/event_dispatcher.hpp +++ b/src/manager/event_dispatcher.hpp @@ -38,7 +38,7 @@ struct EventDispatcher final { } void unregister_listener(const EventListener* listener) { - const auto end = std::remove(m_listeners.begin(), m_listeners.end(), listener); + const auto end = std::ranges::remove(m_listeners, listener).begin(); assert(end != m_listeners.end() and "listener to delete could not be found"); m_listeners.erase(end, m_listeners.end()); } @@ -54,9 +54,7 @@ struct EventDispatcher final { switch (event.type) { case SDL_KEYDOWN: case SDL_KEYUP: { - if (std::find( - allowed_input_keys.cbegin(), allowed_input_keys.cend(), SDL::Key{ event.key.keysym } - ) + if (std::ranges::find(allowed_input_keys, SDL::Key{ event.key.keysym }) == allowed_input_keys.cend()) { return; } diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index 78f88f72..b061b3ca 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -160,15 +162,15 @@ namespace { [[maybe_unused]] SDL::ModifierType typeof_modifier(SDL::Modifier modifier) { const auto& [normal, special, multiple] = get_modifier_type_array(); - if (std::find(normal.cbegin(), normal.cend(), modifier) != normal.cend()) { + if (std::ranges::find(normal, modifier) != normal.cend()) { return SDL::ModifierType::Normal; } - if (std::find(special.cbegin(), special.cend(), modifier) != special.cend()) { + if (std::ranges::find(special, modifier) != special.cend()) { return SDL::ModifierType::Special; } - if (std::find(multiple.cbegin(), multiple.cend(), modifier) != multiple.cend()) { + if (std::ranges::find(multiple, modifier) != multiple.cend()) { return SDL::ModifierType::Multiple; } @@ -249,21 +251,26 @@ namespace { } // trim from start (in place) - inline void ltrim(std::string& s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); + inline void ltrim(std::string& str) { + str.erase(str.begin(), std::ranges::find_if(str, [](unsigned char ch) { return !std::isspace(ch); })); } // trim from end (in place) - inline void rtrim(std::string& s) { - s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end()); + inline void rtrim(std::string& str) { + str.erase( + std::ranges::find_if( + std::ranges::reverse_view(str), [](unsigned char ch) { return !std::isspace(ch); } + ).base(), + str.end() + ); } - void trim(std::string& s) { - ltrim(s); - rtrim(s); + void trim(std::string& str) { + ltrim(str); + rtrim(str); } - helper::optional modifier_from_string(std::string modifier) { + helper::optional modifier_from_string(const std::string& modifier) { if (modifier.empty()) { return helper::nullopt; diff --git a/src/ui/layouts/focus_layout.cpp b/src/ui/layouts/focus_layout.cpp index c2aca12f..a61faf1e 100644 --- a/src/ui/layouts/focus_layout.cpp +++ b/src/ui/layouts/focus_layout.cpp @@ -4,6 +4,8 @@ #include "input/input.hpp" #include "ui/widget.hpp" +#include + ui::FocusLayout::FocusLayout(const Layout& layout, u32 focus_id, FocusOptions options, bool is_top_level) : Widget{ layout, WidgetType::Container, is_top_level }, @@ -179,11 +181,10 @@ ui::FocusLayout::handle_event_result( // NOLINT(readability-function-cognitive-c } [[nodiscard]] u32 ui::FocusLayout::focusable_index_by_id(const u32 id) const { - const auto find_iterator = - std::find_if(m_widgets.begin(), m_widgets.end(), [id](const std::unique_ptr& widget) { - const auto focusable = as_focusable(widget.get()); - return focusable.has_value() and focusable.value()->focus_id() == id; - }); + const auto find_iterator = std::ranges::find_if(m_widgets, [id](const std::unique_ptr& widget) { + const auto focusable = as_focusable(widget.get()); + return focusable.has_value() and focusable.value()->focus_id() == id; + }); assert(find_iterator != m_widgets.end()); const auto index = static_cast(std::distance(m_widgets.begin(), find_iterator)); return index; @@ -199,17 +200,18 @@ ui::FocusLayout::handle_event_result( // NOLINT(readability-function-cognitive-c } #ifdef DEBUG_BUILD - const auto duplicates = std::adjacent_find(result.cbegin(), result.cend()); + // this works, since result is sorted already + const auto duplicates = std::ranges::adjacent_find(result); if (duplicates != result.cend()) { throw std::runtime_error("Focusables have duplicates: " + std::to_string(*duplicates)); } #endif - std::sort(result.begin(), result.end()); + std::ranges::sort(result); return result; } [[nodiscard]] u32 ui::FocusLayout::index_of(const std::vector& ids, const u32 needle) { - return static_cast(std::distance(ids.cbegin(), std::find(ids.cbegin(), ids.cend(), needle))); + return static_cast(std::distance(ids.cbegin(), std::ranges::find(ids, needle))); } [[nodiscard]] bool ui::FocusLayout::try_set_next_focus(const FocusChangeDirection focus_direction) { From ae4644ce8a7efddfb6c2cc0422f73977c116ef7c Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 13 May 2024 16:43:04 +0200 Subject: [PATCH 43/76] c++ std version: remove c++20 and only use c++23 and c++26 (preview) --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 09c8aea7..cb73f7dc 100644 --- a/meson.build +++ b/meson.build @@ -7,7 +7,7 @@ project( 'buildtype': 'debug', 'optimization': '3', 'strip': true, - 'cpp_std': ['c++23', 'c++latest', 'vc++latest', 'c++20'], + 'cpp_std': ['c++26', 'c++23', 'c++latest', 'vc++latest'], 'b_ndebug': 'if-release', }, From 462bfa9e86ac3df0676803951695030a33730eda Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 13 May 2024 18:18:43 +0200 Subject: [PATCH 44/76] c++26: try to use newer features --- src/helper/const_utils.hpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/helper/const_utils.hpp b/src/helper/const_utils.hpp index 5176e715..232399e9 100644 --- a/src/helper/const_utils.hpp +++ b/src/helper/const_utils.hpp @@ -6,14 +6,28 @@ #include #include -// define a consteval assert, it isn't a pretty error message, but there's nothing we can do against that atm :( -// this https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2758r2.html tries to fix it +// use C++26 feature, if available: +#if __cpp_static_assert >= 202306L #define CONSTEVAL_ONLY_STATIC_ASSERT(CHECK, MSG) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ ((CHECK) ? void(0) : [] { \ /* If you see this really bad c++ error message, follow the origin of MSG, to see the real error message, c++ error messages suck xD */ \ throw(MSG); \ }()) +//This doesn't work, since CHECK is in most cases not a constant expression so not constant evaluatable inside the if constexpr, and therefore static_assert(false,..) would trigger always +/* +#define CONSTEVAL_ONLY_STATIC_ASSERT(CHECK, MSG) +(if constexpr (!(CHECK)) { static_assert(false, MSG); }()) +s*/ + +#else +#define CONSTEVAL_ONLY_STATIC_ASSERT(CHECK, MSG) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ + ((CHECK) ? void(0) : [] { \ + /* If you see this really bad c++ error message, follow the origin of MSG, to see the real error message, c++ error messages suck xD */ \ + throw(MSG); \ + }()) +#endif + #define CONSTEVAL_STATIC_ASSERT(CHECK, MSG) \ do { /*NOLINT(cppcoreguidelines-avoid-do-while)*/ \ if (utils::is_constant_evaluated()) { \ From 513a499d367a984c4ab3d472cf4b452210738d49 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 13 May 2024 21:28:34 +0200 Subject: [PATCH 45/76] clang-format files --- src/helper/errors.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper/errors.hpp b/src/helper/errors.hpp index 056ef145..7b65e486 100644 --- a/src/helper/errors.hpp +++ b/src/helper/errors.hpp @@ -38,7 +38,7 @@ namespace helper { }; struct MinorError : public GeneralError { - MinorError(const std::string& message) noexcept ; + MinorError(const std::string& message) noexcept; MinorError(std::string&& message) noexcept; }; From da4bf159d83544ec717d5fed77df7fbca7caee86 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Tue, 14 May 2024 02:53:20 +0200 Subject: [PATCH 46/76] fix a few more clang-tidy things --- .clang-tidy | 12 ++++-- src/application.cpp | 12 ++---- src/game/game.cpp | 2 +- src/game/tetrion.cpp | 36 ++++++++--------- src/helper/color_literals.hpp | 6 +-- src/helper/errors.cpp | 12 ++++-- src/helper/errors.hpp | 20 +++++++--- src/input/keyboard_input.cpp | 5 +-- src/input/touch_input.cpp | 5 +-- src/manager/sdl_key.cpp | 1 - src/recordings/additional_information.cpp | 26 ++++++------- src/recordings/recording_reader.cpp | 3 +- src/recordings/tetrion_snapshot.cpp | 16 ++++---- src/ui/components/abstract_slider.hpp | 7 +--- src/ui/components/color_picker.cpp | 27 ++++++------- src/ui/components/textinput.cpp | 17 ++++---- src/ui/components/textinput.hpp | 7 +--- src/ui/layouts/focus_layout.cpp | 5 +-- src/ui/layouts/scroll_layout.cpp | 8 ++-- src/ui/layouts/tile_layout.cpp | 19 ++++----- src/ui/layouts/tile_layout.hpp | 7 +--- tests/core/color.cpp | 47 ++++++++++++----------- tests/graphics/sdl_key.cpp | 1 - 23 files changed, 140 insertions(+), 161 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 22c1bb1e..816282d7 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,6 +1,6 @@ # taken from https://github.com/cpp-linter/cpp-linter-action/blob/main/demo/.clang-tidy --- -Checks: "clang-diagnostic-*,clang-analyzer-*,bugprone-*,misc-*,performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,google-*,llvm-*,cert-*,-modernize-use-trailing-return-type,-bugprone-argument-comment,-misc-include-cleaner,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers" +Checks: "clang-diagnostic-*,clang-analyzer-*,bugprone-*,misc-*,performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,google-*,llvm-*,cert-*,-modernize-use-trailing-return-type,-bugprone-argument-comment,-misc-include-cleaner,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-readability-avoid-nested-conditional-operator,-llvm-namespace-comment" WarningsAsErrors: "" HeaderFilterRegex: "oopetris/src/.*" FormatStyle: "file" @@ -52,6 +52,8 @@ CheckOptions: value: "lower_case" - key: readability-identifier-naming.GlobalFunctionCase value: "lower_case" + - key: readability-identifier-naming.GlobalFunctionIgnoredRegexp + value: "(PrintTo)" ## for gtest - key: readability-identifier-naming.GlobalPointerCase value: "lower_case" - key: readability-identifier-naming.GlobalVariableCase @@ -132,8 +134,6 @@ CheckOptions: value: "lower_case" # some needed settings, that are non default - - key: bugprone-assert-side-effect.AssertMacros - value: "assert" - key: bugprone-misplaced-widening-cast.CheckImplicitCasts value: true - key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic @@ -153,10 +153,14 @@ CheckOptions: ## special things, that have special values - key: readability-identifier-length.IgnoredVariableNames - value: "" + value: "(os)" # ostream - key: readability-identifier-length.IgnoredParameterNames value: "^[n]$" - key: readability-identifier-length.MinimumLoopCounterNameLength value: 1 - key: readability-identifier-length.MinimumExceptionNameLength value: 5 + - key: readability-function-cognitive-complexity.Threshold + value: 50 + - key: bugprone-assert-side-effect.AssertMacros + value: "assert" diff --git a/src/application.cpp b/src/application.cpp index f5ab5ce0..c962c607 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -22,15 +22,9 @@ namespace { [[nodiscard]] helper::MessageBox::Type get_notification_level(helper::error::Severity severity) { - switch (severity) { - case helper::error::Severity::Minor: - return helper::MessageBox::Type::Information; - case helper::error::Severity::Major: - return helper::MessageBox::Type::Warning; - case helper::error::Severity::Fatal: - default: - return helper::MessageBox::Type::Error; - } + return severity == helper::error::Severity::Fatal ? helper::MessageBox::Type::Error + : severity == helper::error::Severity::Major ? helper::MessageBox::Type::Warning + : helper::MessageBox::Type::Information; } } // namespace diff --git a/src/game/game.cpp b/src/game/game.cpp index 81ca264c..66ab282c 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -13,7 +13,7 @@ Game::Game( ) : ui::Widget{ layout, ui::WidgetType::Component, is_top_level }, m_clock_source{ std::make_unique(starting_parameters.target_fps) }, - m_input{ std::move(input) } { + m_input{ input } { spdlog::info("starting level for tetrion {}", starting_parameters.starting_level); diff --git a/src/game/tetrion.cpp b/src/game/tetrion.cpp index 0d9b0964..e0f8168e 100644 --- a/src/game/tetrion.cpp +++ b/src/game/tetrion.cpp @@ -42,9 +42,9 @@ Tetrion::Tetrion( layout } { - main_layout.add(); + m_main_layout.add(); - main_layout.add( + m_main_layout.add( 1, 3, ui::Direction::Vertical, ui::AbsolutMargin{ 0 }, std::pair{ 0.0, 0.1 } ); @@ -105,7 +105,7 @@ void Tetrion::update_step(const SimulationStep simulation_step_index) { void Tetrion::render(const ServiceProvider& service_provider) const { - main_layout.render(service_provider); + m_main_layout.render(service_provider); const auto* grid = get_grid(); const double original_scale = grid->scale_to_original(); @@ -148,7 +148,7 @@ void Tetrion::render(const ServiceProvider& service_provider) const { } [[nodiscard]] helper::BoolWrapper> -Tetrion::handle_event(const std::shared_ptr&, const SDL_Event&) { +Tetrion::handle_event(const std::shared_ptr& /*input_manager*/, const SDL_Event& /*event*/) { return false; } @@ -179,7 +179,7 @@ bool Tetrion::handle_input_command(const input::GameInputCommand command, const } return false; case input::GameInputCommand::MoveDown: - //TODO: use input_type() != InputType:Touch + //TODO(Totto): use input_type() != InputType:Touch #if not defined(__ANDROID__) m_down_key_pressed = true; m_is_accelerated_down_movement = true; @@ -334,19 +334,19 @@ void Tetrion::hold_tetromino(const SimulationStep simulation_step_index) { } [[nodiscard]] Grid* Tetrion::get_grid() { - return main_layout.get(0); + return m_main_layout.get(0); } [[nodiscard]] const Grid* Tetrion::get_grid() const { - return main_layout.get(0); + return m_main_layout.get(0); } [[nodiscard]] ui::GridLayout* Tetrion::get_text_layout() { - return main_layout.get(1); + return m_main_layout.get(1); } [[nodiscard]] const ui::GridLayout* Tetrion::get_text_layout() const { - return main_layout.get(1); + return m_main_layout.get(1); } [[nodiscard]] u8 Tetrion::tetrion_index() const { @@ -536,29 +536,29 @@ bool Tetrion::tetromino_can_move_down(const Tetromino& tetromino) const { return frames; } -u8 Tetrion::rotation_to_index(const Rotation from, const Rotation to) { - if (from == Rotation::North and to == Rotation::East) { +u8 Tetrion::rotation_to_index(const Rotation from, const Rotation rotation_to) { + if (from == Rotation::North and rotation_to == Rotation::East) { return 0; } - if (from == Rotation::East and to == Rotation::North) { + if (from == Rotation::East and rotation_to == Rotation::North) { return 1; } - if (from == Rotation::East and to == Rotation::South) { + if (from == Rotation::East and rotation_to == Rotation::South) { return 2; } - if (from == Rotation::South and to == Rotation::East) { + if (from == Rotation::South and rotation_to == Rotation::East) { return 3; } - if (from == Rotation::South and to == Rotation::West) { + if (from == Rotation::South and rotation_to == Rotation::West) { return 4; } - if (from == Rotation::West and to == Rotation::South) { + if (from == Rotation::West and rotation_to == Rotation::South) { return 5; } - if (from == Rotation::West and to == Rotation::North) { + if (from == Rotation::West and rotation_to == Rotation::North) { return 6; } - if (from == Rotation::North and to == Rotation::West) { + if (from == Rotation::North and rotation_to == Rotation::West) { return 7; } utils::unreachable(); diff --git a/src/helper/color_literals.hpp b/src/helper/color_literals.hpp index 90b72a25..bc1b5411 100644 --- a/src/helper/color_literals.hpp +++ b/src/helper/color_literals.hpp @@ -200,7 +200,7 @@ namespace { using ColorFromHexStringReturnType = std::pair; [[nodiscard]] constexpr const_utils::expected - get_color_from_hex_string(const char* input, std::size_t size) { //NOLINT(readability-function-cognitive-complexity + get_color_from_hex_string(const char* input, std::size_t size) { if (size == const_constants::hex_rgb_size) { @@ -247,7 +247,7 @@ namespace { using ColorFromRGBStringReturnType = std::pair; [[nodiscard]] constexpr const_utils::expected - get_color_from_rgb_string(const char* input, std::size_t) { //NOLINT(readability-function-cognitive-complexity + get_color_from_rgb_string(const char* input, std::size_t) { if (input[0] == 'r' && input[1] == 'g' && input[2] == 'b') { if (input[3] == '(') { @@ -415,7 +415,7 @@ namespace { using ColorFromHSVStringReturnType = std::pair; [[nodiscard]] constexpr const_utils::expected - get_color_from_hsv_string(const char* input, std::size_t) { //NOLINT(readability-function-cognitive-complexity + get_color_from_hsv_string(const char* input, std::size_t) { if (input[0] == 'h' && input[1] == 's' && input[2] == 'v') { if (input[3] == '(') { diff --git a/src/helper/errors.cpp b/src/helper/errors.cpp index a21f9a65..f0221703 100644 --- a/src/helper/errors.cpp +++ b/src/helper/errors.cpp @@ -8,9 +8,15 @@ helper::GeneralError::GeneralError(std::string&& message, error::Severity severi : m_message{ std::move(message) }, m_severity{ severity } { } -helper::GeneralError::GeneralError(const GeneralError& error) noexcept - : m_message{ error.message() }, - m_severity{ error.severity() } { } +helper::GeneralError::~GeneralError() = default; + +helper::GeneralError::GeneralError(const GeneralError& error) noexcept = default; +[[nodiscard]] helper::GeneralError& helper::GeneralError::operator=(const GeneralError& error) noexcept = default; + +helper::GeneralError::GeneralError(GeneralError&& error) noexcept = default; + +[[nodiscard]] helper::GeneralError& helper::GeneralError::operator=(GeneralError&& error) noexcept = default; + [[nodiscard]] const std::string& helper::GeneralError::message() const { return m_message; diff --git a/src/helper/errors.hpp b/src/helper/errors.hpp index 7b65e486..f1c6550f 100644 --- a/src/helper/errors.hpp +++ b/src/helper/errors.hpp @@ -18,29 +18,37 @@ namespace helper { public: GeneralError(const std::string& message, error::Severity severity) noexcept; + GeneralError(std::string&& message, error::Severity severity) noexcept; + + ~GeneralError(); + GeneralError(const GeneralError& error) noexcept; + [[nodiscard]] GeneralError& operator=(const GeneralError& error) noexcept; + + GeneralError(GeneralError&& error) noexcept; + [[nodiscard]] GeneralError& operator=(GeneralError&& error) noexcept; [[nodiscard]] const std::string& message() const; [[nodiscard]] error::Severity severity() const; }; struct FatalError : public GeneralError { - FatalError(const std::string& message) noexcept; + explicit FatalError(const std::string& message) noexcept; - FatalError(std::string&& message) noexcept; + explicit FatalError(std::string&& message) noexcept; }; struct MajorError : public GeneralError { - MajorError(const std::string& message) noexcept; + explicit MajorError(const std::string& message) noexcept; - MajorError(std::string&& message) noexcept; + explicit MajorError(std::string&& message) noexcept; }; struct MinorError : public GeneralError { - MinorError(const std::string& message) noexcept; + explicit MinorError(const std::string& message) noexcept; - MinorError(std::string&& message) noexcept; + explicit MinorError(std::string&& message) noexcept; }; using InitializationError = FatalError; diff --git a/src/input/keyboard_input.cpp b/src/input/keyboard_input.cpp index 72c1dc14..b4f4e88e 100644 --- a/src/input/keyboard_input.cpp +++ b/src/input/keyboard_input.cpp @@ -95,10 +95,7 @@ void input::KeyboardGameInput::update(SimulationStep simulation_step_index) { GameInput::update(simulation_step_index); } -helper::optional -input::KeyboardGameInput::sdl_event_to_input_event( // NOLINT(readability-function-cognitive-complexity) - const SDL_Event& event -) const { +helper::optional input::KeyboardGameInput::sdl_event_to_input_event(const SDL_Event& event) const { if (event.type == SDL_KEYDOWN and event.key.repeat == 0) { const auto key = SDL::Key{ event.key.keysym }; if (key == m_settings.rotate_left) { diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index 279be197..5db6f16b 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -26,10 +26,7 @@ void input::TouchGameInput::update(SimulationStep simulation_step_index) { GameInput::update(simulation_step_index); } -helper::optional -input::TouchGameInput::sdl_event_to_input_event( // NOLINT(readability-function-cognitive-complexity) - const SDL_Event& event -) { +helper::optional input::TouchGameInput::sdl_event_to_input_event(const SDL_Event& event) { //TODO: /* if (event.tfinger.touchId != m_id) { diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index b061b3ca..3322b56a 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/src/recordings/additional_information.cpp b/src/recordings/additional_information.cpp index e4c62984..0d753a05 100644 --- a/src/recordings/additional_information.cpp +++ b/src/recordings/additional_information.cpp @@ -77,9 +77,9 @@ recorder::InformationValue::to_bytes( // NOLINT(misc-no-recursion) typedef union { u32 original_value; float value; - } float_conversion; + } FloatConversion; - const float_conversion conversion_value{ .value = as() }; + const FloatConversion conversion_value{ .value = as() }; helper::writer::append_value(bytes, conversion_value.original_value); return bytes; } @@ -91,9 +91,9 @@ recorder::InformationValue::to_bytes( // NOLINT(misc-no-recursion) typedef union { u64 original_value; double value; - } double_conversion; + } DoubleConversion; - const double_conversion conversion_value{ .value = as() }; + const DoubleConversion conversion_value{ .value = as() }; helper::writer::append_value(bytes, conversion_value.original_value); return bytes; } @@ -232,11 +232,11 @@ helper::expected recorder::InformationValue::read_stri } -helper::expected recorder::InformationValue:: - read_value_from_istream( // NOLINT(readability-function-cognitive-complexity,misc-no-recursion) - std::istream& istream, - u32 recursion_depth - ) { +helper::expected +recorder::InformationValue::read_value_from_istream( // NOLINT(misc-no-recursion) + std::istream& istream, + u32 recursion_depth +) { const auto magic_byte = helper::reader::read_from_istream>(istream); if (not magic_byte.has_value()) { return helper::unexpected{ "unable to read magic byte" }; @@ -262,9 +262,9 @@ helper::expected recorder::InformationV typedef union { u32 original_value; float value; - } float_conversion; + } FloatConversion; - const float_conversion raw_float_value{ .original_value = raw_float.value() }; + const FloatConversion raw_float_value{ .original_value = raw_float.value() }; return recorder::InformationValue{ raw_float_value.value }; } @@ -278,9 +278,9 @@ helper::expected recorder::InformationV typedef union { u64 original_value; double value; - } double_conversion; + } DoubleConversion; - const double_conversion raw_double_value{ .original_value = raw_double.value() }; + const DoubleConversion raw_double_value{ .original_value = raw_double.value() }; return recorder::InformationValue{ raw_double_value.value }; } diff --git a/src/recordings/recording_reader.cpp b/src/recordings/recording_reader.cpp index 052d0ead..6ed6596b 100644 --- a/src/recordings/recording_reader.cpp +++ b/src/recordings/recording_reader.cpp @@ -101,8 +101,7 @@ recorder::RecordingReader::get_header_from_path(const std::filesystem::path& pat ); } -helper::expected -recorder::RecordingReader::from_path( // NOLINT(readability-function-cognitive-complexity) +helper::expected recorder::RecordingReader::from_path( const std::filesystem::path& path ) { diff --git a/src/recordings/tetrion_snapshot.cpp b/src/recordings/tetrion_snapshot.cpp index 869f7804..0dff1256 100644 --- a/src/recordings/tetrion_snapshot.cpp +++ b/src/recordings/tetrion_snapshot.cpp @@ -59,13 +59,13 @@ helper::expected TetrionSnapshot::from_istream(std MinoStack mino_stack{}; for (MinoCount i = 0; i < num_minos.value(); ++i) { - const auto x = helper::reader::read_from_istream(istream); - if (not x.has_value()) { + const auto x_coord = helper::reader::read_from_istream(istream); + if (not x_coord.has_value()) { return helper::unexpected{ "unable to read x coordinate of mino from snapshot" }; } - const auto y = helper::reader::read_from_istream(istream); - if (not y.has_value()) { + const auto y_coord = helper::reader::read_from_istream(istream); + if (not y_coord.has_value()) { return helper::unexpected{ "unable to read y coordinate of mino from snapshot" }; } @@ -81,7 +81,7 @@ helper::expected TetrionSnapshot::from_istream(std }; } - mino_stack.set(shapes::AbstractPoint(x.value(), y.value()), maybe_type.value()); + mino_stack.set(shapes::AbstractPoint(x_coord.value(), y_coord.value()), maybe_type.value()); } @@ -191,10 +191,10 @@ helper::expected TetrionSnapshot::compare_to(const TetrionSna } if (m_mino_stack != other.m_mino_stack) { - std::stringstream ss; - ss << m_mino_stack << " vs. " << other.m_mino_stack; + std::stringstream string_stream{}; + string_stream << m_mino_stack << " vs. " << other.m_mino_stack; - return helper::unexpected{ fmt::format("mino stacks do not match:\n {}", ss.str()) }; + return helper::unexpected{ fmt::format("mino stacks do not match:\n {}", string_stream.str()) }; } return true; diff --git a/src/ui/components/abstract_slider.hpp b/src/ui/components/abstract_slider.hpp index 25557daf..428d296e 100644 --- a/src/ui/components/abstract_slider.hpp +++ b/src/ui/components/abstract_slider.hpp @@ -91,11 +91,8 @@ namespace ui { } - Widget::EventHandleResult handle_event( - const std::shared_ptr& input_manager, - const SDL_Event& event - ) // NOLINT(readability-function-cognitive-complexity) - override { + Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override { Widget::EventHandleResult handled = false; const auto navigation_event = input_manager->get_navigation_event(event); diff --git a/src/ui/components/color_picker.cpp b/src/ui/components/color_picker.cpp index 91a28b2e..b487b736 100644 --- a/src/ui/components/color_picker.cpp +++ b/src/ui/components/color_picker.cpp @@ -149,10 +149,7 @@ void detail::ColorCanvas::draw_pseudo_circle(const ServiceProvider& service_prov } helper::BoolWrapper> -detail::ColorCanvas::handle_event( //NOLINT(readability-function-cognitive-complexity) - const std::shared_ptr& input_manager, - const SDL_Event& event -) { +detail::ColorCanvas::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { Widget::EventHandleResult handled = false; const auto fill_rect = layout().get_rect(); @@ -261,16 +258,17 @@ void detail::ColorCanvas::redraw_texture() { m_service_provider->renderer().set_render_target(*m_texture); - const auto w = fill_rect.width(); - const auto h = fill_rect.height(); + const auto width = fill_rect.width(); + const auto height = fill_rect.height(); const auto hue = m_current_color.h; - //TODO: try to speed this up, since it is a performance bottle neck, if hovering like a madman (xD) over the color slider - for (u32 y = 0; y < h; y++) { - const auto v = 1.0 - (static_cast(y) / static_cast(h)); - for (u32 x = 0; x < w; x++) { - const Color color = HSVColor(hue, static_cast(x) / static_cast(w), v).to_rgb_color(); + //TODO(Totto): try to speed this up, since it is a performance bottle neck, if hovering like a madman (xD) over the color slider + for (u32 y = 0; y < height; y++) { + const auto value = 1.0 - (static_cast(y) / static_cast(height)); + for (u32 x = 0; x < width; x++) { + const Color color = + HSVColor(hue, static_cast(x) / static_cast(width), value).to_rgb_color(); m_service_provider->renderer().draw_pixel(shapes::UPoint{ x, y }, color); } @@ -293,7 +291,7 @@ ui::ColorPicker::ColorPicker( m_mode{ ColorMode::RGB }, m_callback{ std::move(callback) } { - //TODO: add alpha slider at the side + //TODO(Totto): add alpha slider at the side constexpr double main_rect_height = 0.8; @@ -459,10 +457,7 @@ void ui::ColorPicker::render(const ServiceProvider& service_provider) const { } helper::BoolWrapper> -ui::ColorPicker::handle_event( //NOLINT(readability-function-cognitive-complexity) - const std::shared_ptr& input_manager, - const SDL_Event& event -) { +ui::ColorPicker::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { auto handled = m_color_slider->handle_event(input_manager, event); diff --git a/src/ui/components/textinput.cpp b/src/ui/components/textinput.cpp index 34da52fa..ede08679 100644 --- a/src/ui/components/textinput.cpp +++ b/src/ui/components/textinput.cpp @@ -102,10 +102,7 @@ void ui::TextInput::render(const ServiceProvider& service_provider) const { } helper::BoolWrapper> -ui::TextInput::handle_event( // NOLINT(readability-function-cognitive-complexity) - const std::shared_ptr& input_manager, - const SDL_Event& event -) { +ui::TextInput::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { //TODO: if already has focus, position cursor there, where we clicked if (const auto hover_result = detect_hover(input_manager, event); hover_result) { @@ -246,7 +243,7 @@ void ui::TextInput::set_text(const std::string& text) { return m_text; } -void ui::TextInput::recalculate_textures(bool text_changed) { //NOLINT(readability-function-cognitive-complexity) +void ui::TextInput::recalculate_textures(bool text_changed) { const auto& renderer = m_service_provider->renderer(); @@ -308,17 +305,17 @@ void ui::TextInput::recalculate_textures(bool text_changed) { //NOLINT(readabili utf8::append(utf8::next(current_iterator, m_text.end()), sub_string); } - int w = 0; - int h = 0; - const int result = TTF_SizeUTF8(m_font.get(), sub_string.c_str(), &w, &h); + int width = 0; + int height = 0; + const int result = TTF_SizeUTF8(m_font.get(), sub_string.c_str(), &width, &height); if (result < 0) { throw helper::FatalError{ fmt::format("Error during SDL_TTF_SizeUTF8: {}", SDL_GetError()) }; } - const double ratio_sub_string = static_cast(h) / static_cast(fill_rect().height()); + const double ratio_sub_string = static_cast(height) / static_cast(fill_rect().height()); - cursor_offset = static_cast(static_cast(w) / ratio_sub_string); + cursor_offset = static_cast(static_cast(width) / ratio_sub_string); } m_cursor_rect = (unmoved_cursor >> fill_rect().top_left) >> shapes::UPoint{ cursor_offset, 0 }; diff --git a/src/ui/components/textinput.hpp b/src/ui/components/textinput.hpp index 850b6559..74300a5a 100644 --- a/src/ui/components/textinput.hpp +++ b/src/ui/components/textinput.hpp @@ -62,11 +62,8 @@ namespace ui { //TODO: how to handle text limits (since texture for texts on the gpu can't get unlimitedly big, maybe use software texture?) void render(const ServiceProvider& service_provider) const override; - Widget::EventHandleResult handle_event( - const std::shared_ptr& input_manager, - const SDL_Event& event - ) // NOLINT(readability-function-cognitive-complexity) - override; + Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; void set_text(const std::string& text); diff --git a/src/ui/layouts/focus_layout.cpp b/src/ui/layouts/focus_layout.cpp index a61faf1e..ecc5b214 100644 --- a/src/ui/layouts/focus_layout.cpp +++ b/src/ui/layouts/focus_layout.cpp @@ -93,10 +93,7 @@ ui::Widget::EventHandleResult ui::FocusLayout::handle_focus_change_events( } [[nodiscard]] helper::optional -ui::FocusLayout::handle_event_result( // NOLINT(readability-function-cognitive-complexity) - const helper::optional& result, - Widget* widget -) { +ui::FocusLayout::handle_event_result(const helper::optional& result, Widget* widget) { if (not result.has_value()) { return helper::nullopt; diff --git a/src/ui/layouts/scroll_layout.cpp b/src/ui/layouts/scroll_layout.cpp index 5c5cfba7..a769deaa 100644 --- a/src/ui/layouts/scroll_layout.cpp +++ b/src/ui/layouts/scroll_layout.cpp @@ -107,10 +107,8 @@ void ui::ScrollLayout::render(const ServiceProvider& service_provider) const { } } -ui::Widget::EventHandleResult ui::ScrollLayout::handle_event( // NOLINT(readability-function-cognitive-complexity) - const std::shared_ptr& input_manager, - const SDL_Event& event -) { +ui::Widget::EventHandleResult +ui::ScrollLayout::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { Widget::EventHandleResult handled = handle_focus_change_events(input_manager, event); @@ -173,7 +171,7 @@ ui::Widget::EventHandleResult ui::ScrollLayout::handle_event( // NOLINT(readabil handled = true; } - //TODO: support touch screen scrolling too, factor this out into the input manager + //TODO(Totto): support touch screen scrolling too, factor this out into the input manager } else if (event.type == SDL_MOUSEWHEEL) { // attention the mouse direction changes (it's called natural scrolling on macos/ windows / linux) are not detected by sdl until restart, and here we use the correct scroll behaviour, as the user configured the mouse in it's OS diff --git a/src/ui/layouts/tile_layout.cpp b/src/ui/layouts/tile_layout.cpp index 4b8c4ba3..dcfa4142 100644 --- a/src/ui/layouts/tile_layout.cpp +++ b/src/ui/layouts/tile_layout.cpp @@ -8,11 +8,8 @@ void ui::TileLayout::render(const ServiceProvider& service_provider) const { } } -ui::Widget::EventHandleResult ui::TileLayout::handle_event( - const std::shared_ptr& input_manager, - const SDL_Event& event -) // NOLINT(readability-function-cognitive-complexity) -{ +ui::Widget::EventHandleResult +ui::TileLayout::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { Widget::EventHandleResult handled = handle_focus_change_events(input_manager, event); if (handled) { @@ -54,8 +51,8 @@ ui::Widget::EventHandleResult ui::TileLayout::handle_event( const auto start_point = layout().get_rect().top_left; - u32 x = start_point.x + margin.first; - u32 y = start_point.y + margin.second; + u32 x_pos = start_point.x + margin.first; + u32 y_pos = start_point.y + margin.second; u32 width = layout().get_rect().width() - (margin.first * 2); u32 height = layout().get_rect().height() - (margin.second * 2); @@ -70,7 +67,7 @@ ui::Widget::EventHandleResult ui::TileLayout::handle_event( : static_cast(width * steps.at(index)) - gap.get_margin() / 2); width = current_end - previous_start; - x += previous_start; + x_pos += previous_start; } else { const auto previous_start = index == 0 ? 0 : static_cast(height * steps.at(index - 1)) + gap.get_margin() / 2; @@ -82,13 +79,13 @@ ui::Widget::EventHandleResult ui::TileLayout::handle_event( : static_cast(height * steps.at(index)) - gap.get_margin() / 2); height = current_end - previous_start; - y += previous_start; + y_pos += previous_start; } return AbsolutLayout{ - x, - y, + x_pos, + y_pos, width, height, }; diff --git a/src/ui/layouts/tile_layout.hpp b/src/ui/layouts/tile_layout.hpp index 7d75c8c3..89e103c0 100644 --- a/src/ui/layouts/tile_layout.hpp +++ b/src/ui/layouts/tile_layout.hpp @@ -51,11 +51,8 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; - Widget::EventHandleResult handle_event( - const std::shared_ptr& input_manager, - const SDL_Event& event - ) // NOLINT(readability-function-cognitive-complexity) - override; + Widget::EventHandleResult + handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; private: [[nodiscard]] Layout get_layout_for_index(u32 index) override; diff --git a/tests/core/color.cpp b/tests/core/color.cpp index a51cfc5a..1742c548 100644 --- a/tests/core/color.cpp +++ b/tests/core/color.cpp @@ -9,18 +9,18 @@ #include namespace { - using ForeachCallback = std::function; + using ForeachCallback = std::function; void foreach_loop(const ForeachCallback& callback) { - u8 r{ 0 }; - u8 g{ 0 }; - u8 b{ 0 }; + u8 red{ 0 }; + u8 green{ 0 }; + u8 blue{ 0 }; do { // NOLINT(cppcoreguidelines-avoid-do-while) do { // NOLINT(cppcoreguidelines-avoid-do-while) do { // NOLINT(cppcoreguidelines-avoid-do-while) - callback(r, g, b); - } while (r++ != 255); - } while (g++ != 255); - } while (b++ != 255); + callback(red, green, blue); + } while (red++ != 255); + } while (green++ != 255); + } while (blue++ != 255); } } // namespace @@ -45,20 +45,21 @@ namespace color { void PrintTo(const SerializeMode& value, std::ostream* os) { *os << magic_enum::enum_name(value); } + } TEST(Color, DefaultConstruction) { - const auto c1 = Color{}; - const auto c2 = Color{ 0, 0, 0, 0 }; - ASSERT_EQ(c1, c2); + const auto color1 = Color{}; + const auto color2 = Color{ 0, 0, 0, 0 }; + ASSERT_EQ(color1, color2); } TEST(Color, ConstructorProperties) { - foreach_loop([](u8 r, u8 g, u8 b) { - const auto c1 = Color{ r, g, b }; - const auto c2 = Color{ r, g, b, 0xFF }; - ASSERT_EQ(c1, c2); + foreach_loop([](u8 red, u8 green, u8 blue) { + const auto color1 = Color{ red, green, blue }; + const auto color2 = Color{ red, green, blue, 0xFF }; + ASSERT_EQ(color1, color2); }); } @@ -163,9 +164,9 @@ TEST(Color, FromStringInvalid) { TEST(HSVColor, DefaultConstruction) { - const auto c1 = HSVColor{}; - const auto c2 = HSVColor{ 0, 0, 0, 0 }; - ASSERT_EQ(c1, c2); + const auto color1 = HSVColor{}; + const auto color2 = HSVColor{ 0, 0, 0, 0 }; + ASSERT_EQ(color1, color2); } TEST(HSVColor, ConstructorProperties) { @@ -179,9 +180,9 @@ TEST(HSVColor, ConstructorProperties) { }; for (const auto& [h, s, v] : values) { - const auto c1 = HSVColor{ h, s, v }; - const auto c2 = HSVColor{ h, s, v, 0xFF }; - ASSERT_EQ(c1, c2); + const auto color1 = HSVColor{ h, s, v }; + const auto color2 = HSVColor{ h, s, v, 0xFF }; + ASSERT_EQ(color1, color2); } } @@ -209,7 +210,7 @@ TEST(HSVColor, InvalidConstructors) { #endif -TEST(ColorConversion, HSV_to_RGB_to_HSV) { //NOLINT(readability-function-cognitive-complexity) +TEST(ColorConversion, HSVtoRGBtoHSV) { #if COLOR_TEST_MODE == 0 const std::vector colors{ @@ -255,7 +256,7 @@ TEST(ColorConversion, HSV_to_RGB_to_HSV) { //NOLINT(readability-function-cogniti } -TEST(ColorConversion, RGG_to_HSV_to_RGB) { //NOLINT(readability-function-cognitive-complexity) +TEST(ColorConversion, RGG_to_HSV_to_RGB) { #if COLOR_TEST_MODE == 0 const std::vector colors{ diff --git a/tests/graphics/sdl_key.cpp b/tests/graphics/sdl_key.cpp index fdaea975..d15c6045 100644 --- a/tests/graphics/sdl_key.cpp +++ b/tests/graphics/sdl_key.cpp @@ -3,7 +3,6 @@ #include "helper/expected.hpp" #include "utils/helper.hpp" -#include "gtest/gtest.h" #include #include #include From 9bef844d629a7f05fc7e441fe5dafb06078979ed Mon Sep 17 00:00:00 2001 From: Totto16 Date: Wed, 15 May 2024 18:43:20 +0200 Subject: [PATCH 47/76] clang-tidy: fix more errors --- .clang-tidy | 2 +- src/game/tetrion.cpp | 2 +- src/game/tetrion.hpp | 2 +- .../settings_menu/color_setting_row.cpp | 4 +- src/ui/components/abstract_slider.hpp | 10 ++- src/ui/components/button.hpp | 9 ++- src/ui/components/color_picker.cpp | 4 +- src/ui/components/image_button.cpp | 2 +- src/ui/components/text_button.cpp | 2 +- src/ui/focusable.hpp | 6 +- src/ui/hoverable.hpp | 2 +- src/ui/layout.hpp | 68 +++++++++++-------- 12 files changed, 69 insertions(+), 44 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 816282d7..9a892891 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,6 +1,6 @@ # taken from https://github.com/cpp-linter/cpp-linter-action/blob/main/demo/.clang-tidy --- -Checks: "clang-diagnostic-*,clang-analyzer-*,bugprone-*,misc-*,performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,google-*,llvm-*,cert-*,-modernize-use-trailing-return-type,-bugprone-argument-comment,-misc-include-cleaner,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-readability-avoid-nested-conditional-operator,-llvm-namespace-comment" +Checks: "clang-diagnostic-*,clang-analyzer-*,bugprone-*,misc-*,performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,google-*,llvm-*,cert-*,-modernize-use-trailing-return-type,-bugprone-argument-comment,-misc-include-cleaner,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-readability-avoid-nested-conditional-operator,-llvm-namespace-comment,-llvm-header-guard" WarningsAsErrors: "" HeaderFilterRegex: "oopetris/src/.*" FormatStyle: "file" diff --git a/src/game/tetrion.cpp b/src/game/tetrion.cpp index e0f8168e..ec6dea8a 100644 --- a/src/game/tetrion.cpp +++ b/src/game/tetrion.cpp @@ -32,7 +32,7 @@ Tetrion::Tetrion( m_level{ starting_level }, m_tetrion_index{ tetrion_index }, m_next_gravity_simulation_step_index{ get_gravity_delay_frames() }, - main_layout{ + m_main_layout{ utils::size_t_identity<2>(), 0, ui::Direction::Vertical, diff --git a/src/game/tetrion.hpp b/src/game/tetrion.hpp index f6588599..83f8a3ae 100644 --- a/src/game/tetrion.hpp +++ b/src/game/tetrion.hpp @@ -76,7 +76,7 @@ struct Tetrion final : public ui::Widget { std::array, num_preview_tetrominos> m_preview_tetrominos{}; u8 m_tetrion_index; u64 m_next_gravity_simulation_step_index; - ui::TileLayout main_layout; + ui::TileLayout m_main_layout; public: diff --git a/src/scenes/settings_menu/color_setting_row.cpp b/src/scenes/settings_menu/color_setting_row.cpp index bad82373..88b3bdcf 100644 --- a/src/scenes/settings_menu/color_setting_row.cpp +++ b/src/scenes/settings_menu/color_setting_row.cpp @@ -19,7 +19,7 @@ detail::ColorSettingRectangle::ColorSettingRectangle( bool is_top_level ) : Widget{ layout, ui::WidgetType::Component, is_top_level }, - Focusable{ ui::FocusHelper::FocusIDUnused() }, + Focusable{ ui::FocusHelper::focus_id_unused() }, Hoverable{ fill_rect }, m_color{ start_color }, m_fill_rect{ fill_rect } { } @@ -144,7 +144,7 @@ custom_ui::ColorSettingRow::ColorSettingRow( ui::Hoverable{ layout.get_rect() }, m_service_provider{ service_provider }, m_main_layout{ utils::size_t_identity<2>(), - ui::FocusHelper::FocusIDUnused(), + ui::FocusHelper::focus_id_unused(), ui::Direction::Horizontal, std::array{ 0.7 }, ui::RelativeMargin{ layout.get_rect(), ui::Direction::Vertical, 0.05 }, diff --git a/src/ui/components/abstract_slider.hpp b/src/ui/components/abstract_slider.hpp index 428d296e..ff057965 100644 --- a/src/ui/components/abstract_slider.hpp +++ b/src/ui/components/abstract_slider.hpp @@ -85,12 +85,18 @@ namespace ui { } } - ~AbstractSlider() override { SDL_CaptureMouse(SDL_FALSE); } + AbstractSlider(const AbstractSlider&) = default; + AbstractSlider& operator=(const AbstractSlider&) = default; + + AbstractSlider(AbstractSlider&&) noexcept = default; + AbstractSlider& operator=(AbstractSlider&&) noexcept = default; + + Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override { Widget::EventHandleResult handled = false; @@ -173,7 +179,7 @@ namespace ui { handled = true; } - //TODO: this is not working, since pointer_event.has_value() is wrong in this case + //TODO(Totto): this is not working, since pointer_event.has_value() is wrong in this case } else if (event.type == SDL_MOUSEWHEEL && has_focus()) { // here we use a reverse scroll behaviour, since moving the mouse up is always considered increasing the volume, regardless of you OS setting about natural scrolling or not diff --git a/src/ui/components/button.hpp b/src/ui/components/button.hpp index 944e3e12..8367fc43 100644 --- a/src/ui/components/button.hpp +++ b/src/ui/components/button.hpp @@ -19,12 +19,13 @@ namespace ui { public: using Callback = std::function; - protected: + private: Content m_content; Callback m_callback; shapes::URect m_fill_rect; bool m_enabled; + protected: explicit Button( Content&& content, u32 focus_id, @@ -47,6 +48,10 @@ namespace ui { } } + [[nodiscard]] const Callback& callback() const { + return m_callback; + }; + public: explicit Button( Content&& content, @@ -72,7 +77,7 @@ namespace ui { void render(const ServiceProvider& service_provider) const override { - //TODO: get as input a color palette and use that! + //TODO(Totto): get as input a color palette and use that! const auto color = not m_enabled ? (has_focus() ? "#A36A6A"_c : "#919191"_c) : (has_focus() ? is_hovered() ? "#FF6A00"_c : Color::red() : is_hovered() ? "#00BBFF"_c diff --git a/src/ui/components/color_picker.cpp b/src/ui/components/color_picker.cpp index b487b736..d564fbf0 100644 --- a/src/ui/components/color_picker.cpp +++ b/src/ui/components/color_picker.cpp @@ -23,7 +23,7 @@ detail::ColorSlider::ColorSlider( const ui::Layout& layout, bool is_top_level ) - : AbstractSlider{ ui::FocusHelper::FocusIDUnused(), + : AbstractSlider{ ui::FocusHelper::focus_id_unused(), std::move(range), std::move(getter), std::move(setter), @@ -373,7 +373,7 @@ ui::ColorPicker::ColorPicker( const auto toggle_button_layout = ui::RelativeLayout{ components_fill_layout, 0.0, 0.0, toggle_button_size, 1.0 }; - const auto focus_id_unused = FocusHelper::FocusIDUnused(); + const auto focus_id_unused = FocusHelper::focus_id_unused(); const auto rgb_image_path = utils::get_assets_folder() / "icons" / "rgb_color_selector.png"; diff --git a/src/ui/components/image_button.cpp b/src/ui/components/image_button.cpp index 1d2f439a..07e10a54 100644 --- a/src/ui/components/image_button.cpp +++ b/src/ui/components/image_button.cpp @@ -24,5 +24,5 @@ ui::ImageButton::ImageButton( } { } [[nodiscard]] bool ui::ImageButton::on_clicked() const { - return m_callback(*this); + return callback()(*this); } diff --git a/src/ui/components/text_button.cpp b/src/ui/components/text_button.cpp index 07583c42..be5b8e90 100644 --- a/src/ui/components/text_button.cpp +++ b/src/ui/components/text_button.cpp @@ -62,5 +62,5 @@ ui::TextButton::TextButton( } { } [[nodiscard]] bool ui::TextButton::on_clicked() const { - return m_callback(*this); + return callback()(*this); } diff --git a/src/ui/focusable.hpp b/src/ui/focusable.hpp index a3274ccd..e0c91e40 100644 --- a/src/ui/focusable.hpp +++ b/src/ui/focusable.hpp @@ -5,20 +5,20 @@ namespace ui { - //TODO: replace this by a focus helper per scene! + //TODO(Totto): replace this by a focus helper per scene! struct FocusHelper { private: u32 m_focus_id; public: - FocusHelper(u32 start_focus_id = 0) : m_focus_id{ start_focus_id } {}; + explicit FocusHelper(u32 start_focus_id = 0) : m_focus_id{ start_focus_id } {}; [[nodiscard]] u32 focus_id() { return m_focus_id++; } // return a placeholder, that signifies, this focus id is unused - [[nodiscard]] static u32 FocusIDUnused() { + [[nodiscard]] static u32 focus_id_unused() { return static_cast(-1); } }; diff --git a/src/ui/hoverable.hpp b/src/ui/hoverable.hpp index 0257528d..7d984aa0 100644 --- a/src/ui/hoverable.hpp +++ b/src/ui/hoverable.hpp @@ -72,7 +72,7 @@ namespace ui { m_is_hovered = true; } - //TODO: this has to be used correctly, a click or focus change isn't an event, where an unhover needs to happen! + //TODO(Totto): this has to be used correctly, a click or focus change isn't an event, where an unhover needs to happen! void on_unhover() { m_is_hovered = false; } diff --git a/src/ui/layout.hpp b/src/ui/layout.hpp index 6bb75b45..e5b8e9c0 100644 --- a/src/ui/layout.hpp +++ b/src/ui/layout.hpp @@ -14,67 +14,85 @@ namespace ui { struct Layout { private: shapes::URect m_rect; - LayoutType type; + LayoutType m_type; protected: - Layout(const shapes::URect& rect, LayoutType type) : m_rect{ rect }, type{ type } { } + Layout(const shapes::URect& rect, LayoutType type) : m_rect{ rect }, m_type{ type } { } public: - Layout(const shapes::URect& rect) : m_rect{ rect }, type{ LayoutType::Raw } { } + explicit Layout(const shapes::URect& rect) : m_rect{ rect }, m_type{ LayoutType::Raw } { } [[nodiscard]] const shapes::URect& get_rect() const { return m_rect; } [[nodiscard]] bool is_full_screen() const { - return type == LayoutType::FullScreen; + return m_type == LayoutType::FullScreen; } }; struct AbsolutLayout : public Layout { - AbsolutLayout(const u32 x, const u32 y, const u32 width, const u32 height) + AbsolutLayout(const u32 start_x, const u32 start_y, const u32 width, const u32 height) : Layout{ - shapes::URect{ x, y, width, height }, + shapes::URect{ start_x, start_y, width, height }, LayoutType::Absolut } { } }; struct FullScreenLayout : public Layout { - FullScreenLayout(const shapes::URect& rect) : Layout{ rect, LayoutType::FullScreen } { } - FullScreenLayout(const Window& window) : FullScreenLayout{ window.screen_rect() } { } - FullScreenLayout(const Window* window) : FullScreenLayout{ window->screen_rect() } { } + explicit FullScreenLayout(const shapes::URect& rect) : Layout{ rect, LayoutType::FullScreen } { } + explicit FullScreenLayout(const Window& window) : FullScreenLayout{ window.screen_rect() } { } + explicit FullScreenLayout(const Window* window) : FullScreenLayout{ window->screen_rect() } { } }; struct RelativeLayout : public Layout { RelativeLayout( const shapes::URect& rect, - const double x, - const double y, + const double start_x, + const double start_y, const double width, const double height ) : Layout{ shapes::URect( - static_cast(x * static_cast(rect.width())), - static_cast(y * static_cast(rect.height())), + static_cast(start_x * static_cast(rect.width())), + static_cast(start_y * static_cast(rect.height())), static_cast(width * static_cast(rect.width())), static_cast(height * static_cast(rect.height())) ) >> rect.top_left, LayoutType::Relative } { - assert(x >= 0.0 && x <= 1.0 && "x has to be in correct percentage range!"); - assert(y >= 0.0 && y <= 1.0 && "y has to be in correct percentage range!"); + assert(start_x >= 0.0 && start_x <= 1.0 && "x has to be in correct percentage range!"); + assert(start_y >= 0.0 && start_y <= 1.0 && "y has to be in correct percentage range!"); assert(width >= 0.0 && width <= 1.0 && "width has to be in correct percentage range!"); assert(height >= 0.0 && height <= 1.0 && "height has to be in correct percentage range!"); } - RelativeLayout(const Window* window, const double x, const double y, const double width, const double height) - : RelativeLayout{ window->screen_rect(), x, y, width, height } { } - RelativeLayout(const Window& window, const double x, const double y, const double width, const double height) - : RelativeLayout{ window.screen_rect(), x, y, width, height } { } - RelativeLayout(const Layout& layout, const double x, const double y, const double width, const double height) - : RelativeLayout{ layout.get_rect(), x, y, width, height } { } + RelativeLayout( + const Window* window, + const double start_x, + const double start_y, + const double width, + const double height + ) + : RelativeLayout{ window->screen_rect(), start_x, start_y, width, height } { } + RelativeLayout( + const Window& window, + const double start_x, + const double start_y, + const double width, + const double height + ) + : RelativeLayout{ window.screen_rect(), start_x, start_y, width, height } { } + RelativeLayout( + const Layout& layout, + const double start_x, + const double start_y, + const double width, + const double height + ) + : RelativeLayout{ layout.get_rect(), start_x, start_y, width, height } { } }; @@ -83,10 +101,8 @@ namespace ui { using Alignment = std::pair; - [[nodiscard]] u32 get_horizontal_alignment_offset(const Layout& layout, AlignmentHorizontal alignment, u32 width); - [[nodiscard]] u32 get_vertical_alignment_offset(const Layout& layout, AlignmentVertical alignment, u32 height); [[nodiscard]] shapes::URect @@ -95,7 +111,6 @@ namespace ui { [[nodiscard]] std::pair ratio_helper(const std::pair& size, bool respect_ratio, const shapes::UPoint& original_ratio); - enum class Direction : u8 { Horizontal, Vertical }; struct Margin { @@ -103,8 +118,7 @@ namespace ui { u32 m_margin; public: - Margin(u32 margin) : m_margin{ margin } { } - + explicit Margin(u32 margin) : m_margin{ margin } { } [[nodiscard]] u32 get_margin() const { return m_margin; @@ -112,7 +126,7 @@ namespace ui { }; struct AbsolutMargin : public Margin { - AbsolutMargin(const u32 margin) : Margin{ margin } { } + explicit AbsolutMargin(const u32 margin) : Margin{ margin } { } }; struct RelativeMargin : public Margin { From 011b4f942276ace69f1c9d8b2d24a0af7ef8a813 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Wed, 15 May 2024 23:44:49 +0200 Subject: [PATCH 48/76] clang-tidy: fix more things --- src/helper/nfd.cpp | 54 +++++++++--------- src/input/input.cpp | 13 ++--- src/input/input.hpp | 5 +- src/input/joystick_input.cpp | 11 ++-- src/input/joystick_input.hpp | 2 +- src/input/mouse_input.cpp | 7 ++- src/input/replay_input.cpp | 5 +- src/input/touch_input.cpp | 57 +++++++++++-------- src/input/touch_input.hpp | 2 +- src/manager/sdl_key.cpp | 9 ++- src/scenes/replay_game/replay_game.cpp | 2 +- src/scenes/scene.cpp | 2 +- .../settings_menu/color_setting_row.cpp | 2 +- src/scenes/settings_menu/settings_menu.cpp | 2 +- src/ui/components/color_picker.cpp | 3 +- 15 files changed, 90 insertions(+), 86 deletions(-) diff --git a/src/helper/nfd.cpp b/src/helper/nfd.cpp index b5f703dc..d31aa19c 100644 --- a/src/helper/nfd.cpp +++ b/src/helper/nfd.cpp @@ -20,22 +20,22 @@ namespace { [[nodiscard]] FilterItemType get_filter_items(const std::vector& allowed_files) { const auto size = static_cast(allowed_files.size()); - FilterItemType filterItem{ allowed_files.empty() ? nullptr : new nfdu8filteritem_t[size], - [size](const nfdu8filteritem_t* const value) { - if (value == nullptr) { - return; - } + FilterItemType filter_item{ allowed_files.empty() ? nullptr : new nfdu8filteritem_t[size], + [size](const nfdu8filteritem_t* const value) { + if (value == nullptr) { + return; + } - for (usize i = 0; i < size; ++i) { - const auto& item = - value[i]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + for (usize i = 0; i < size; ++i) { + const auto& item = + value[i]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) - delete item.name; // NOLINT(cppcoreguidelines-owning-memory) - delete item.spec; // NOLINT(cppcoreguidelines-owning-memory) - } + delete item.name; // NOLINT(cppcoreguidelines-owning-memory) + delete item.spec; // NOLINT(cppcoreguidelines-owning-memory) + } - delete[] value; // NOLINT(cppcoreguidelines-owning-memory) - } }; + delete[] value; // NOLINT(cppcoreguidelines-owning-memory) + } }; if (not allowed_files.empty()) { @@ -55,11 +55,11 @@ namespace { auto* extensions = new nfdu8char_t[extension_list_size]; // NOLINT(cppcoreguidelines-owning-memory) std::memcpy(extensions, extension_list.c_str(), extension_list_size * sizeof(nfdu8char_t)); - filterItem.get()[i] = { name, extensions }; + filter_item.get()[i] = { name, extensions }; } } - return filterItem; + return filter_item; } // namespace @@ -72,7 +72,7 @@ helper::expected helper::openFileDialog( helper::optional default_path ) { - NFD::UniquePathU8 outPath{}; + NFD::UniquePathU8 out_path{}; auto filterItem = get_filter_items(allowed_files); const auto path_deallocator = [](const nfdu8char_t* const char_value) { @@ -93,10 +93,10 @@ helper::expected helper::openFileDialog( } const nfdresult_t result = NFD::OpenDialog( - outPath, filterItem.get(), static_cast(allowed_files.size()), default_path_value.get() + out_path, filterItem.get(), static_cast(allowed_files.size()), default_path_value.get() ); if (result == NFD_OKAY) { - return std::filesystem::path{ outPath.get() }; + return std::filesystem::path{ out_path.get() }; } if (result == NFD_CANCEL) { @@ -112,7 +112,7 @@ helper::expected helper::openFileDialog( helper::optional default_path ) { - NFD::UniquePathSet outPaths{}; + NFD::UniquePathSet out_paths{}; auto filterItem = get_filter_items(allowed_files); const auto path_deallocator = [](const nfdu8char_t* const char_value) { @@ -133,20 +133,20 @@ helper::expected helper::openFileDialog( } const nfdresult_t result = NFD::OpenDialogMultiple( - outPaths, filterItem.get(), static_cast(allowed_files.size()), default_path_value.get() + out_paths, filterItem.get(), static_cast(allowed_files.size()), default_path_value.get() ); if (result == NFD_OKAY) { std::vector result_vector{}; nfdpathsetsize_t count_paths{}; - const auto temp_result = NFD::PathSet::Count(outPaths, count_paths); + const auto temp_result = NFD::PathSet::Count(out_paths, count_paths); ASSERT(temp_result == NFD_OKAY && "PathSet get count is successful"); for (nfdpathsetsize_t i = 0; i < count_paths; ++i) { - NFD::UniquePathSetPathU8 outPath{}; - const auto temp_result2 = NFD::PathSet::GetPath(outPaths, i, outPath); + NFD::UniquePathSetPathU8 out_path{}; + const auto temp_result2 = NFD::PathSet::GetPath(out_paths, i, out_path); ASSERT(temp_result2 == NFD_OKAY && "PathSet get path is successful"); - result_vector.emplace_back(outPath.get()); + result_vector.emplace_back(out_path.get()); } return result_vector; @@ -163,7 +163,7 @@ helper::expected helper::openFileDialog( helper::optional default_path ) { - NFD::UniquePathU8 outPath{}; + NFD::UniquePathU8 out_path{}; const auto path_deallocator = [](const nfdu8char_t* const char_value) { if (char_value == nullptr) { @@ -183,9 +183,9 @@ helper::expected helper::openFileDialog( std::memcpy(default_path_value.get(), str.c_str(), str_size * sizeof(nfdu8char_t)); } - const nfdresult_t result = NFD::PickFolder(outPath, default_path_value.get()); + const nfdresult_t result = NFD::PickFolder(out_path, default_path_value.get()); if (result == NFD_OKAY) { - return std::filesystem::path{ outPath.get() }; + return std::filesystem::path{ out_path.get() }; } if (result == NFD_CANCEL) { diff --git a/src/input/input.cpp b/src/input/input.cpp index 4bcb20d7..14da069c 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -13,7 +13,7 @@ #include -input::Input::Input(const std::string& name, InputType type) : m_name{ name }, m_type{ type } { } +input::Input::Input(std::string name, InputType type) : m_name{ std::move(name) }, m_type{ type } { } input::Input::~Input() = default; @@ -72,9 +72,6 @@ input::InputManager::InputManager(const std::shared_ptr& window) { input::JoyStickInputManager::discover_devices(m_inputs); } -input::InputManager::~InputManager() = default; - - [[nodiscard]] const std::vector>& input::InputManager::inputs() const { return m_inputs; } @@ -149,13 +146,13 @@ input::InputManager::~InputManager() = default; return false; } -//TODO: improve this API, to correctly use settings to determine the input to use. +//TODO(Totto): improve this API, to correctly use settings to determine the input to use. [[nodiscard]] std::shared_ptr input::InputManager::get_game_input(ServiceProvider* service_provider) { - //TODO: use smart pointer for the event dispatcher + //TODO(TODO): use smart pointer for the event dispatcher - //TODO: select the first suitable, by using the primary input method or some other settings! + //TODO(Totto): select the first suitable, by using the primary input method or some other settings! for (const auto& control : service_provider->settings_manager().settings().controls) { return std::visit( @@ -174,7 +171,7 @@ input::InputManager::~InputManager() = default; service_provider->input_manager(), event_dispatcher, joystick_settings ); - //TODO: better error handling, if this fails look forward in the + //TODO(Totto): better error handling, if this fails look forward in the if (not input.has_value()) { throw std::runtime_error("Not possible to get joystick by settings"); } diff --git a/src/input/input.hpp b/src/input/input.hpp index ddaa54a6..bab08ca2 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -32,7 +32,7 @@ namespace input { InputType m_type; public: - Input(const std::string& name, InputType type); + Input(std::string name, InputType type); virtual ~Input(); [[nodiscard]] const std::string& name() const; @@ -66,7 +66,7 @@ namespace input { struct PointerInput : Input { - PointerInput(const std::string& name); + explicit PointerInput(const std::string& name); [[nodiscard]] virtual helper::optional get_pointer_event(const SDL_Event& event) const = 0; @@ -80,7 +80,6 @@ namespace input { public: explicit InputManager(const std::shared_ptr& window); - ~InputManager(); [[nodiscard]] const std::vector>& inputs() const; diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 240b572c..dee91229 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -62,7 +62,7 @@ input::JoystickInput::get_by_device_index(int device_index) { }; } - //TODO: add support for gamecontrollers (SDL_IsGameController) + //TODO(Totto): add support for gamecontrollers (SDL_IsGameController) const auto instance_id = SDL_JoystickInstanceID(joystick); @@ -186,7 +186,6 @@ void input::JoyStickInputManager::discover_devices(std::vector input::_3DSJoystickGameInput_Type1::sdl_event_to_in #endif -std::string json_helper::get_key_from_object(const nlohmann::json& j, const std::string& name) { +std::string json_helper::get_key_from_object(const nlohmann::json& obj, const std::string& name) { - const auto& context = j.at(name); + const auto& context = obj.at(name); std::string input; context.get_to(input); diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index 4a588d64..385081d0 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -206,7 +206,7 @@ namespace input { namespace json_helper { - [[nodiscard]] std::string get_key_from_object(const nlohmann::json& j, const std::string& name); + [[nodiscard]] std::string get_key_from_object(const nlohmann::json& obj, const std::string& name); } // namespace json_helper diff --git a/src/input/mouse_input.cpp b/src/input/mouse_input.cpp index 96a23994..b6059abb 100644 --- a/src/input/mouse_input.cpp +++ b/src/input/mouse_input.cpp @@ -31,11 +31,12 @@ input::MouseInput::MouseInput() : PointerInput("mouse") { } } -[[nodiscard]] helper::optional input::MouseInput::get_navigation_event(const SDL_Event&) const { +[[nodiscard]] helper::optional +input::MouseInput::get_navigation_event(const SDL_Event& /*event*/) const { return helper::nullopt; } -[[nodiscard]] std::string input::MouseInput::describe_navigation_event(NavigationEvent) const { +[[nodiscard]] std::string input::MouseInput::describe_navigation_event(NavigationEvent /*event*/) const { throw std::runtime_error("not supported"); } @@ -63,7 +64,7 @@ input::MouseInput::MouseInput() : PointerInput("mouse") { } return helper::nullopt; } - shapes::IPoint pos{ event.button.x, event.button.y }; + const shapes::IPoint pos{ event.button.x, event.button.y }; return input::PointerEventHelper{ pos, pointer_event }; } diff --git a/src/input/replay_input.cpp b/src/input/replay_input.cpp index da1c1501..bc05d31b 100644 --- a/src/input/replay_input.cpp +++ b/src/input/replay_input.cpp @@ -77,11 +77,12 @@ void input::ReplayGameInput::late_update(const SimulationStep simulation_step_in } -[[nodiscard]] helper::optional input::ReplayGameInput::get_menu_event(const SDL_Event&) const { +[[nodiscard]] helper::optional input::ReplayGameInput::get_menu_event(const SDL_Event& /*event*/) + const { return helper::nullopt; } -[[nodiscard]] std::string input::ReplayGameInput::describe_menu_event(MenuEvent) const { +[[nodiscard]] std::string input::ReplayGameInput::describe_menu_event(MenuEvent /*event*/) const { throw std::runtime_error("not supported"); } diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index 5db6f16b..80e55890 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -28,12 +28,12 @@ void input::TouchGameInput::update(SimulationStep simulation_step_index) { helper::optional input::TouchGameInput::sdl_event_to_input_event(const SDL_Event& event) { - //TODO: + //TODO(Totto): fix this /* if (event.tfinger.touchId != m_id) { return helper::nullopt; } */ - //TODO to handle those things better, holding has to be supported + //TODO(Totto): to handle those things better, holding has to be supported if (event.type == SDL_FINGERDOWN) { @@ -47,14 +47,14 @@ helper::optional input::TouchGameInput::sdl_event_to_input_event(con return helper::nullopt; } - const auto x = event.tfinger.x; - const auto y = event.tfinger.y; + const auto x_pos = event.tfinger.x; + const auto y_pos = event.tfinger.y; const auto timestamp = event.tfinger.timestamp; m_finger_state.insert_or_assign( finger_id, helper::optional{ - PressedState{ timestamp, x, y } + PressedState{ timestamp, x_pos, y_pos } } ); } @@ -66,24 +66,31 @@ helper::optional input::TouchGameInput::sdl_event_to_input_event(con const SDL_FingerID finger_id = event.tfinger.fingerId; - if (!m_finger_state.contains(finger_id) or !m_finger_state.at(finger_id).has_value()) { + if (!m_finger_state.contains(finger_id)) { // there are some valid reasons, this can occur now return helper::nullopt; } - const auto pressed_state = m_finger_state.at(finger_id).value(); + const auto& finger_state = m_finger_state.at(finger_id); - const auto x = event.tfinger.x; - const auto y = event.tfinger.y; + if (!finger_state.has_value()) { + return helper::nullopt; + } + + const auto& pressed_state = finger_state.value(); + + + const auto x_pos = event.tfinger.x; + const auto y_pos = event.tfinger.y; const auto timestamp = event.tfinger.timestamp; - const auto dx = x - pressed_state.x; - const auto dy = y - pressed_state.y; + const auto delta_x = x_pos - pressed_state.x; + const auto delta_y = y_pos - pressed_state.y; const auto duration = timestamp - pressed_state.timestamp; - const auto dx_abs = std::fabs(dx); - const auto dy_abs = std::fabs(dy); + const auto dx_abs = std::fabs(delta_x); + const auto dy_abs = std::fabs(delta_y); const auto threshold_x = m_settings.move_x_threshold; const auto threshold_y = m_settings.move_y_threshold; @@ -92,26 +99,26 @@ helper::optional input::TouchGameInput::sdl_event_to_input_event(con if (duration < m_settings.rotation_duration_threshold) { if (dx_abs < threshold_x and dy_abs < threshold_y) { // tap on the right side of the screen - if (x > 0.5) { + if (x_pos > 0.5) { return InputEvent::RotateRightPressed; } // tap on the left side of the screen - if (x <= 0.5) { + if (x_pos <= 0.5) { return InputEvent::RotateLeftPressed; } } } // swipe right - if (dx > threshold_x and dy_abs < threshold_y) { + if (delta_x > threshold_x and dy_abs < threshold_y) { return InputEvent::MoveRightPressed; } // swipe left - if (dx < -threshold_x and dy_abs < threshold_y) { + if (delta_x < -threshold_x and dy_abs < threshold_y) { return InputEvent::MoveLeftPressed; } // swipe down - if (dy > threshold_y and dx_abs < threshold_x) { + if (delta_y > threshold_y and dx_abs < threshold_x) { // swipe down to drop if (duration < m_settings.drop_duration_threshold) { return InputEvent::DropPressed; @@ -120,14 +127,14 @@ helper::optional input::TouchGameInput::sdl_event_to_input_event(con } // swipe up - if (dy < -threshold_y and dx_abs < threshold_x) { + if (delta_y < -threshold_y and dx_abs < threshold_x) { return InputEvent::HoldPressed; } } if (event.type == SDL_FINGERMOTION) { - //TODO support hold + //TODO(Totto): support hold } @@ -155,10 +162,10 @@ helper::optional input::TouchGameInput::sdl_event_to_input_event(con } } -input::TouchInput::TouchInput(const std::shared_ptr& window, SDL_TouchID id, const std::string& name) +input::TouchInput::TouchInput(const std::shared_ptr& window, SDL_TouchID touch_id, const std::string& name) : PointerInput{ name }, m_window{ window }, - m_id{ id } { } + m_id{ touch_id } { } [[nodiscard]] helper::expected, std::string> input::TouchInput::get_by_device_index(const std::shared_ptr& window, int device_index) { @@ -234,12 +241,12 @@ input::TouchInput::get_by_device_index(const std::shared_ptr& window, in const double x_percent = event.tfinger.x; const double y_percent = event.tfinger.y; const auto window_size = m_window->size(); - const auto x = static_cast(std::round(x_percent * window_size.x)); - const auto y = static_cast(std::round(y_percent * window_size.y)); + const auto x_pos = static_cast(std::round(x_percent * window_size.x)); + const auto y_pos = static_cast(std::round(y_percent * window_size.y)); return input::PointerEventHelper{ - shapes::IPoint{ x, y }, + shapes::IPoint{ x_pos, y_pos }, pointer_event }; } diff --git a/src/input/touch_input.hpp b/src/input/touch_input.hpp index cdb9e5a8..86fcb0d6 100644 --- a/src/input/touch_input.hpp +++ b/src/input/touch_input.hpp @@ -15,7 +15,7 @@ namespace input { SDL_TouchID m_id; public: - TouchInput(const std::shared_ptr& window, SDL_TouchID id, const std::string& name); + TouchInput(const std::shared_ptr& window, SDL_TouchID touch_id, const std::string& name); [[nodiscard]] static helper::expected, std::string> get_by_device_index(const std::shared_ptr& window, int device_index); diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index 3322b56a..9cf4955b 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -223,8 +223,7 @@ namespace { std::string to_lower_case(const std::string& input) { auto result = input; - for (size_t i = 0; i < result.size(); ++i) { - auto& elem = result.at(i); + for (auto& elem : result) { elem = static_cast(std::tolower(elem)); } @@ -234,7 +233,7 @@ namespace { // for string delimiter std::vector split_string_by_char(const std::string& start, const std::string& delimiter) { size_t pos_start = 0; - size_t pos_end; + size_t pos_end = 0; const auto delim_len = delimiter.length(); std::vector res{}; @@ -251,14 +250,14 @@ namespace { // trim from start (in place) inline void ltrim(std::string& str) { - str.erase(str.begin(), std::ranges::find_if(str, [](unsigned char ch) { return !std::isspace(ch); })); + str.erase(str.begin(), std::ranges::find_if(str, [](unsigned char chr) { return std::isspace(chr) == 0; })); } // trim from end (in place) inline void rtrim(std::string& str) { str.erase( std::ranges::find_if( - std::ranges::reverse_view(str), [](unsigned char ch) { return !std::isspace(ch); } + std::ranges::reverse_view(str), [](unsigned char chr) { return std::isspace(chr) == 0; } ).base(), str.end() ); diff --git a/src/scenes/replay_game/replay_game.cpp b/src/scenes/replay_game/replay_game.cpp index c4515649..37a580f5 100644 --- a/src/scenes/replay_game/replay_game.cpp +++ b/src/scenes/replay_game/replay_game.cpp @@ -22,7 +22,7 @@ namespace scenes { if (parameters.empty()) { throw std::runtime_error("An empty recording file isn't supported"); - } else if (parameters.size() == 1) { // NOLINT(readability-else-after-return) + } else if (parameters.size() == 1) { // NOLINT(readability-else-after-return,llvm-else-after-return) layouts.push_back(ui::RelativeLayout{ layout, 0.02, 0.01, 0.96, 0.98 }); } else if (parameters.size() == 2) { layouts.push_back(ui::RelativeLayout{ layout, 0.02, 0.01, 0.46, 0.98 }); diff --git a/src/scenes/scene.cpp b/src/scenes/scene.cpp index 46b22a39..e573efa0 100644 --- a/src/scenes/scene.cpp +++ b/src/scenes/scene.cpp @@ -42,7 +42,7 @@ namespace scenes { case SceneId::OnlineLobby: return std::make_unique(&service_provider, layout); #endif - //TODO + //TODO(Totto): implement those /* case SceneId::LocalMultiPlayerGame: return std::make_unique(&service_provider, layout); diff --git a/src/scenes/settings_menu/color_setting_row.cpp b/src/scenes/settings_menu/color_setting_row.cpp index 88b3bdcf..c4cec4f9 100644 --- a/src/scenes/settings_menu/color_setting_row.cpp +++ b/src/scenes/settings_menu/color_setting_row.cpp @@ -50,7 +50,7 @@ detail::ColorSettingRectangle::ColorSettingRectangle( void detail::ColorSettingRectangle::render(const ServiceProvider& service_provider) const { service_provider.renderer().draw_rect_filled(m_fill_rect, m_color); - //TODO: maybe use a dynamic color, to have some contrast? + //TODO(Totto): maybe use a dynamic color, to have some contrast? service_provider.renderer().draw_rect_outline(m_fill_rect, Color::white()); } helper::BoolWrapper> detail::ColorSettingRectangle::handle_event( diff --git a/src/scenes/settings_menu/settings_menu.cpp b/src/scenes/settings_menu/settings_menu.cpp index 9300d83b..8ef5286b 100644 --- a/src/scenes/settings_menu/settings_menu.cpp +++ b/src/scenes/settings_menu/settings_menu.cpp @@ -71,7 +71,7 @@ namespace scenes { }, [service_provider](double amount) { const auto mapped_amount = amount <= 0.0F ? helper::nullopt : helper::optional{ amount }; - return service_provider->music_manager().set_volume(mapped_amount, false, false); + service_provider->music_manager().set_volume(mapped_amount, false, false); }, 0.05F, std::pair{ 0.6, 1.0 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center } diff --git a/src/ui/components/color_picker.cpp b/src/ui/components/color_picker.cpp index d564fbf0..b8c1eb7a 100644 --- a/src/ui/components/color_picker.cpp +++ b/src/ui/components/color_picker.cpp @@ -264,6 +264,7 @@ void detail::ColorCanvas::redraw_texture() { const auto hue = m_current_color.h; //TODO(Totto): try to speed this up, since it is a performance bottle neck, if hovering like a madman (xD) over the color slider + // maybe use shaders? for (u32 y = 0; y < height; y++) { const auto value = 1.0 - (static_cast(y) / static_cast(height)); for (u32 x = 0; x < width; x++) { @@ -505,7 +506,7 @@ ui::ColorPicker::handle_event(const std::shared_ptr& input_ } if (not maybe_color.has_value()) { - //TODO: maybe inform the user, that the input is incorrect? + //TODO(Totto): maybe inform the user, that the input is incorrect? //m_color_text->display_error(); // reset the text From 25772b18228912cc2994d6bb826d318ebddac0a1 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 02:05:42 +0200 Subject: [PATCH 49/76] extract generic string operations, that were used in sdl_key --- src/helper/meson.build | 2 + src/helper/string_manipulation.cpp | 62 ++++++++++++++++++++++++++++++ src/helper/string_manipulation.hpp | 24 ++++++++++++ src/manager/sdl_key.cpp | 53 ++----------------------- 4 files changed, 92 insertions(+), 49 deletions(-) create mode 100644 src/helper/string_manipulation.cpp create mode 100644 src/helper/string_manipulation.hpp diff --git a/src/helper/meson.build b/src/helper/meson.build index d4d16e6f..a8956e18 100644 --- a/src/helper/meson.build +++ b/src/helper/meson.build @@ -21,6 +21,8 @@ core_src_files += files( 'sleep.cpp', 'sleep.hpp', 'static_string.hpp', + 'string_manipulation.cpp', + 'string_manipulation.hpp', 'timer.hpp', 'types.hpp', 'utils.hpp', diff --git a/src/helper/string_manipulation.cpp b/src/helper/string_manipulation.cpp new file mode 100644 index 00000000..881ae20c --- /dev/null +++ b/src/helper/string_manipulation.cpp @@ -0,0 +1,62 @@ + +#include "string_manipulation.hpp" + +#include +#include + +std::string string::to_lower_case(const std::string& input) { + auto result = input; + for (auto& elem : result) { + elem = static_cast(std::tolower(elem)); + } + + return result; +} + +std::string string::to_upper_case(const std::string& input) { + auto result = input; + for (auto& elem : result) { + elem = static_cast(std::toupper(elem)); + } + + return result; +} + + +// for string delimiter +std::vector string::split_string_by_char(const std::string& start, const std::string& delimiter) { + size_t pos_start = 0; + size_t pos_end = 0; + const auto delim_len = delimiter.length(); + + std::vector res{}; + + while ((pos_end = start.find(delimiter, pos_start)) != std::string::npos) { + auto token = start.substr(pos_start, pos_end - pos_start); + pos_start = pos_end + delim_len; + res.push_back(token); + } + + res.push_back(start.substr(pos_start)); + return res; +} + + +void string::ltrim(std::string& str) { + str.erase(str.begin(), std::ranges::find_if(str, [](unsigned char chr) { return std::isspace(chr) == 0; })); +} + + +void string::rtrim(std::string& str) { + str.erase( + std::ranges::find_if( + std::ranges::reverse_view(str), [](unsigned char chr) { return std::isspace(chr) == 0; } + ).base(), + str.end() + ); +} + +void string::trim(std::string& str) { + ltrim(str); + rtrim(str); +} diff --git a/src/helper/string_manipulation.hpp b/src/helper/string_manipulation.hpp new file mode 100644 index 00000000..9debc4ec --- /dev/null +++ b/src/helper/string_manipulation.hpp @@ -0,0 +1,24 @@ + +#pragma once + +#include +#include + +namespace string { + + std::string to_lower_case(const std::string& input); + + std::string to_upper_case(const std::string& input); + + // for string delimiter + std::vector split_string_by_char(const std::string& start, const std::string& delimiter); + + // trim from start (in place) + void ltrim(std::string& str); + + // trim from end (in place) + void rtrim(std::string& str); + + void trim(std::string& str); + +} // namespace string diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index 9cf4955b..a4faddaa 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -1,6 +1,7 @@ #include "sdl_key.hpp" #include "helper/optional.hpp" +#include "helper/string_manipulation.hpp" #include "helper/utils.hpp" #include @@ -221,52 +222,6 @@ namespace { } } - std::string to_lower_case(const std::string& input) { - auto result = input; - for (auto& elem : result) { - elem = static_cast(std::tolower(elem)); - } - - return result; - } - - // for string delimiter - std::vector split_string_by_char(const std::string& start, const std::string& delimiter) { - size_t pos_start = 0; - size_t pos_end = 0; - const auto delim_len = delimiter.length(); - - std::vector res{}; - - while ((pos_end = start.find(delimiter, pos_start)) != std::string::npos) { - auto token = start.substr(pos_start, pos_end - pos_start); - pos_start = pos_end + delim_len; - res.push_back(token); - } - - res.push_back(start.substr(pos_start)); - return res; - } - - // trim from start (in place) - inline void ltrim(std::string& str) { - str.erase(str.begin(), std::ranges::find_if(str, [](unsigned char chr) { return std::isspace(chr) == 0; })); - } - - // trim from end (in place) - inline void rtrim(std::string& str) { - str.erase( - std::ranges::find_if( - std::ranges::reverse_view(str), [](unsigned char chr) { return std::isspace(chr) == 0; } - ).base(), - str.end() - ); - } - - void trim(std::string& str) { - ltrim(str); - rtrim(str); - } helper::optional modifier_from_string(const std::string& modifier) { @@ -274,7 +229,7 @@ namespace { return helper::nullopt; } - const auto lower_case = to_lower_case(modifier); + const auto lower_case = string::to_lower_case(modifier); const std::unordered_map map{ @@ -308,9 +263,9 @@ namespace { helper::expected SDL::Key::from_string(const std::string& value) { - auto tokens = split_string_by_char(value, "+"); + auto tokens = string::split_string_by_char(value, "+"); for (auto& token : tokens) { - trim(token); + string::trim(token); } std::vector modifiers{}; From b8ea07b77fd7f0bf1c1042654da832a5f85f2509 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 02:15:17 +0200 Subject: [PATCH 50/76] input: - implemenet game input getting correctly - it now uses the primary input to get the game input, if one is available, otherwise an error dialog is shown - joystick inputs take a pointer to a JoyStickInput, and TouchGameInput does the same, since they need teh ID's to check incoming events - implement settings parsing for switch game input, WIP --- src/input/input.cpp | 126 ++++++++----- src/input/input.hpp | 4 +- src/input/input_creator.cpp | 8 +- src/input/input_creator.hpp | 2 +- src/input/joystick_input.cpp | 175 +++++++++++++----- src/input/joystick_input.hpp | 127 ++++++++++--- src/input/touch_input.cpp | 6 +- src/input/touch_input.hpp | 10 +- .../single_player_game/single_player_game.cpp | 11 +- 9 files changed, 343 insertions(+), 126 deletions(-) diff --git a/src/input/input.cpp b/src/input/input.cpp index 14da069c..1e918763 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -1,4 +1,6 @@ #include "input.hpp" +#include "helper/expected.hpp" +#include "helper/optional.hpp" #include "helper/utils.hpp" #include "joystick_input.hpp" #include "keyboard_input.hpp" @@ -11,6 +13,7 @@ #include #include #include +#include input::Input::Input(std::string name, InputType type) : m_name{ std::move(name) }, m_type{ type } { } @@ -146,66 +149,101 @@ input::InputManager::InputManager(const std::shared_ptr& window) { return false; } +namespace { +#if defined(__ANDROID__) + using PrimaryInputType = input::TouchInput; + using PrimaryGameInputType = input::TouchGTouchGameInput; +#elif defined(__CONSOLE__) + using PrimaryInputType = input::JoystickInput; + using PrimaryGameInputType = input::JoystickGameInput; +#else + using PrimaryInputType = input::KeyboardInput; + using PrimaryGameInputType = input::KeyboardGameInput; +#endif +} // namespace + + //TODO(Totto): improve this API, to correctly use settings to determine the input to use. -[[nodiscard]] std::shared_ptr input::InputManager::get_game_input(ServiceProvider* service_provider) { +[[nodiscard]] helper::optional> input::InputManager::get_game_input( + ServiceProvider* service_provider +) { //TODO(TODO): use smart pointer for the event dispatcher - //TODO(Totto): select the first suitable, by using the primary input method or some other settings! + using ReturnType = helper::expected, std::string>; + + // TODO(Totto): use primary input only, if there is no setting, on what to use, add setting for what to use! + + std::vector> game_inputs{}; + for (const auto& control : service_provider->settings_manager().settings().controls) { - return std::visit( - helper::overloaded{ [service_provider](const input::KeyboardSettings& keyboard_settings - ) mutable -> std::shared_ptr { - auto* const event_dispatcher = &(service_provider->event_dispatcher()); - auto input = std::make_shared( - keyboard_settings, event_dispatcher - ); - return input; - }, - [service_provider](const input::JoystickSettings& joystick_settings - ) mutable -> std::shared_ptr { - auto* const event_dispatcher = &(service_provider->event_dispatcher()); - auto input = input::JoystickGameInput::get_game_input_by_settings( - service_provider->input_manager(), event_dispatcher, joystick_settings - ); - - //TODO(Totto): better error handling, if this fails look forward in the - if (not input.has_value()) { - throw std::runtime_error("Not possible to get joystick by settings"); - } - - - return input.value(); - }, - [service_provider](const input::TouchSettings& touch_settings - ) mutable -> std::shared_ptr { - auto* const event_dispatcher = &(service_provider->event_dispatcher()); - auto input = std::make_shared(touch_settings, event_dispatcher); - return input; - } }, + auto input = std::visit( + helper::overloaded{ + [service_provider](const input::KeyboardSettings& keyboard_settings) mutable -> ReturnType { + auto* const event_dispatcher = &(service_provider->event_dispatcher()); + auto input = + std::make_shared(keyboard_settings, event_dispatcher); + return input; + }, + [service_provider](const input::JoystickSettings& joystick_settings) mutable -> ReturnType { + auto* const event_dispatcher = &(service_provider->event_dispatcher()); + auto input = input::JoystickGameInput::get_game_input_by_settings( + service_provider->input_manager(), event_dispatcher, joystick_settings + ); + + if (not input.has_value()) { + return helper::unexpected{ + fmt::format("Not possible to get joystick by settings: {}", input.error()) + }; + } + + + return input.value(); + }, + [service_provider](const input::TouchSettings& touch_settings) mutable -> ReturnType { + //TODO(Totto): make it dynamic, which touch input to use + + for (const auto& input : service_provider->input_manager().inputs()) { + if (const auto pointer_input = utils::is_child_class(input); + pointer_input.has_value()) { + auto* const event_dispatcher = &(service_provider->event_dispatcher()); + auto input = std::make_shared( + touch_settings, event_dispatcher, pointer_input.value() + ); + return input; + } + } + + return helper::unexpected{ + "No TouchInput was found, so no TouchGameInput can be created" + }; + } }, control ); - } - return nullptr; -} + if (input.has_value()) { + game_inputs.push_back(std::move(input.value())); + } else { + spdlog::debug("Couldn't get input: {}", input.error()); + } + } -[[nodiscard]] const std::unique_ptr& input::InputManager::get_primary_input() { + for (auto input : game_inputs) { + if (const auto type_input = utils::is_child_class(input); type_input.has_value()) { + return input; + } + } -#if defined(__ANDROID__) - using PrimaryType = input::TouchInput; -#elif defined(__CONSOLE__) - using PrimaryType = input::JoystickInput; -#else - using PrimaryType = input::KeyboardInput; -#endif + return helper::nullopt; +} +[[nodiscard]] const std::unique_ptr& input::InputManager::get_primary_input() { for (const auto& input : m_inputs) { - if (const auto pointer_input = utils::is_child_class(input); pointer_input.has_value()) { + if (const auto pointer_input = utils::is_child_class(input); pointer_input.has_value()) { return input; } } diff --git a/src/input/input.hpp b/src/input/input.hpp index bab08ca2..35d5b626 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -98,7 +98,9 @@ namespace input { [[nodiscard]] helper::BoolWrapper process_special_inputs(const SDL_Event& event); - [[nodiscard]] std::shared_ptr get_game_input(ServiceProvider* service_provider); + [[nodiscard]] helper::optional> get_game_input( + ServiceProvider* service_provider + ); [[nodiscard]] const std::unique_ptr& get_primary_input(); }; diff --git a/src/input/input_creator.cpp b/src/input/input_creator.cpp index 46e41396..851be74f 100644 --- a/src/input/input_creator.cpp +++ b/src/input/input_creator.cpp @@ -4,6 +4,7 @@ #include "helper/command_line_arguments.hpp" #include "helper/date.hpp" #include "helper/errors.hpp" +#include "helper/optional.hpp" #include "input.hpp" #include "input/replay_input.hpp" @@ -88,13 +89,16 @@ namespace { } -[[nodiscard]] input::AdditionalInfo input::get_single_player_game_parameters( +[[nodiscard]] helper::optional input::get_single_player_game_parameters( ServiceProvider* const service_provider, recorder::AdditionalInformation&& information, const date::ISO8601Date& date ) { auto input = service_provider->input_manager().get_game_input(service_provider); + if (not input.has_value()) { + return helper::nullopt; + } const auto starting_level = service_provider->command_line_arguments().starting_level; @@ -104,7 +108,7 @@ namespace { const tetrion::StartingParameters starting_parameters = { target_fps, seed, starting_level, 0 }; - AdditionalInfo result{ input, starting_parameters }; + AdditionalInfo result{ input.value(), starting_parameters }; auto tetrion_header = create_tetrion_headers_for_one(result); diff --git a/src/input/input_creator.hpp b/src/input/input_creator.hpp index 82256858..59f2032e 100644 --- a/src/input/input_creator.hpp +++ b/src/input/input_creator.hpp @@ -39,7 +39,7 @@ namespace input { [[nodiscard]] std::vector get_game_parameters_for_replay(ServiceProvider* service_provider, const std::filesystem::path& recording_path); - [[nodiscard]] AdditionalInfo get_single_player_game_parameters( + [[nodiscard]] helper::optional get_single_player_game_parameters( ServiceProvider* service_provider, recorder::AdditionalInformation&& information, const date::ISO8601Date& date diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index dee91229..b7e239da 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -4,10 +4,10 @@ #include "helper/expected.hpp" #include "helper/optional.hpp" #include "helper/utils.hpp" -#include "input/console_buttons.hpp" #include "input/game_input.hpp" #include "input/input.hpp" +#include #include @@ -173,6 +173,8 @@ void input::JoyStickInputManager::discover_devices(std::vectorinstance_id() == instance_id) { + //TODO(Totto): if we use this joystick as game input we have to notify the user about it,and pause the game, until he is inserted again + inputs.erase(it); return true; } @@ -364,93 +366,167 @@ void input::JoystickGameInput::update(SimulationStep simulation_step_index) { } -[[nodiscard]] helper::optional> +namespace { + + [[nodiscard]] helper::optional> get_game_joystick_by_guid( + const SDL::GUID& guid, + const input::JoystickSettings& settings, + EventDispatcher* event_dispatcher, + input::JoystickInput* underlying_input + + ) { +#if defined(__CONSOLE__) +#if defined(__SWITCH__) + if (guid == input::SwitchJoystickInput_Type1::guid) { + return std::make_shared(settings, event_dispatcher, underlying_input); + } +#elif defined(__3DS__) + if (guid == input::_3DSJoystickInput_Type1::guid) { + return std::make_shared(settings, event_dispatcher, underlying_input); + } + +#endif +#endif + + UNUSED(guid); + UNUSED(settings); + UNUSED(event_dispatcher); + UNUSED(underlying_input); + + return helper::nullopt; + } + + +} // namespace + +[[nodiscard]] helper::expected, std::string> input::JoystickGameInput::get_game_input_by_settings( const input::InputManager& input_manager, EventDispatcher* event_dispatcher, const JoystickSettings& settings ) { - //TODO(Totto): filter all input_manager.inputs() by guid, than try to get them in order, by trying to convert the settings validate them and create the game input - //TODO(Totto): set up: that on removal of the joystick_input pause is pressed and either a new gam,einput is created or waited until he reconnects! + for (const auto& input : input_manager.inputs()) { + if (const auto joystick_input = utils::is_child_class(input); + joystick_input.has_value()) { + try { + auto result = get_game_joystick_by_guid( + settings.identification.guid, settings, event_dispatcher, joystick_input.value() + ); - UNUSED(input_manager); - UNUSED(settings); - UNUSED(event_dispatcher); - UNUSED(settings); + if (result.has_value()) { + return result.value(); + } - return helper::nullopt; + } catch (const std::exception& exception) { + spdlog::warn("Couldn't construct JoystickGameInput: {}", exception.what()); + } + } + } + + return helper::unexpected{ + fmt::format("No JoystickGameInput candidate for the GUID: {}", settings.identification.guid.to_string()) + }; } #if defined(__CONSOLE__) #if defined(__SWITCH__) +input::SwitchJoystickGameInput_Type1::SwitchJoystickGameInput_Type1( + JoystickSettings settings, + EventDispatcher* event_dispatcher, + JoystickInput* underlying_input +) + : JoystickGameInput{ event_dispatcher, underlying_input } { + + //TODO(Totto): make this static in some way + //NOTE: this are not all, but atm only those, who can be checked with a SDL_JOYBUTTONDOWN event + const MappingType key_mappings{ + + { "A", JOYCON_A }, + { "B", JOYCON_B }, + { "X", JOYCON_X }, + { "Y", JOYCON_Y }, + + { "L", JOYCON_L }, + { "R", JOYCON_R }, + { "ZL", JOYCON_ZL }, + { "ZR", JOYCON_ZR }, + { "PLUS", JOYCON_PLUS }, + { "MINUS", JOYCON_MINUS }, + }; + + auto validate_settings = JoystickGameInput::try_resolve_settings(settings, key_mappings); + if (not validate_settings.has_value()) { + throw std::runtime_error("Invalid settings"); + } + + m_settings = validate_settings.value(); +} + // game_input uses Input to handle events, but stores the config settings for the specific button -//TODO: use settings helper::optional input::SwitchJoystickGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event ) const { if (event.type == SDL_JOYBUTTONDOWN) { - //TODO - /* if (event.jbutton.which != m_instance_id) { + if (event.jbutton.which != m_underlying_input->instance_id()) { return helper::nullopt; - } */ + } //TODO: use switch case const auto button = event.jbutton.button; - if (button == JOYCON_DPAD_LEFT) { + if (button == m_settings.rotate_left) { return InputEvent::RotateLeftPressed; } - if (button == JOYCON_DPAD_RIGHT) { + if (button == m_settings.rotate_right) { return InputEvent::RotateRightPressed; } - if (button == JOYCON_LDPAD_DOWN or button == JOYCON_RDPAD_DOWN) { + if (button == m_settings.move_down) { return InputEvent::MoveDownPressed; } - if (button == JOYCON_LDPAD_LEFT or button == JOYCON_RDPAD_LEFT) { + if (button == m_settings.move_left) { return InputEvent::MoveLeftPressed; } - if (button == JOYCON_LDPAD_RIGHT or button == JOYCON_RDPAD_RIGHT) { + if (button == m_settings.rotate_right) { return InputEvent::MoveRightPressed; } - if (button == JOYCON_X) { + if (button == m_settings.drop) { return InputEvent::DropPressed; } - if (button == JOYCON_B) { + if (button == m_settings.hold) { return InputEvent::HoldPressed; } } else if (event.type == SDL_JOYBUTTONUP) { - //TODO - /* if (event.jbutton.which != m_instance_id) { + if (event.jbutton.which != m_underlying_input->instance_id()) { return helper::nullopt; - } */ + } const auto button = event.jbutton.button; - if (button == JOYCON_DPAD_LEFT) { + if (button == m_settings.rotate_left) { return InputEvent::RotateLeftReleased; } - if (button == JOYCON_DPAD_RIGHT) { + if (button == m_settings.rotate_right) { return InputEvent::RotateRightReleased; } - if (button == JOYCON_LDPAD_DOWN or button == JOYCON_RDPAD_DOWN) { + if (button == m_settings.move_down) { return InputEvent::MoveDownReleased; } - if (button == JOYCON_LDPAD_LEFT or button == JOYCON_RDPAD_LEFT) { + if (button == m_settings.move_left) { return InputEvent::MoveLeftReleased; } - if (button == JOYCON_LDPAD_RIGHT or button == JOYCON_RDPAD_RIGHT) { + if (button == m_settings.rotate_right) { return InputEvent::MoveRightReleased; } - if (button == JOYCON_X) { + if (button == m_settings.drop) { return InputEvent::DropReleased; } - if (button == JOYCON_B) { + if (button == m_settings.hold) { return InputEvent::HoldReleased; } } @@ -458,65 +534,62 @@ helper::optional input::SwitchJoystickGameInput_Type1::sdl_event_to_ } #elif defined(__3DS__) -//TODO: use settings helper::optional input::_3DSJoystickGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event ) const { if (event.type == SDL_JOYBUTTONDOWN) { - //TODO: - /* if (event.jbutton.which != m_instance_id) { + if (event.jbutton.which != m_instance_id) { return helper::nullopt; - } */ + } const auto button = event.jbutton.button; - if (button == JOYCON_L) { + if (button == m_settings.rotate_left) { return InputEvent::RotateLeftPressed; } - if (button == JOYCON_R) { + if (button == m_settings.rotate_right) { return InputEvent::RotateRightPressed; } - if (button == JOYCON_DPAD_DOWN or button == JOYCON_CSTICK_DOWN) { + if (button == m_settings.move_down) { return InputEvent::MoveDownPressed; } - if (button == JOYCON_DPAD_LEFT or button == JOYCON_CSTICK_LEFT) { + if (button == m_settings.move_left) { return InputEvent::MoveLeftPressed; } - if (button == JOYCON_DPAD_RIGHT or button == JOYCON_CSTICK_RIGHT) { + if (button == m_settings.rotate_right) { return InputEvent::MoveRightPressed; } - if (button == JOYCON_A) { + if (button == m_settings.drop) { return InputEvent::DropPressed; } - if (button == JOYCON_B) { + if (button == m_settings.hold) { return InputEvent::HoldPressed; } } else if (event.type == SDL_JOYBUTTONUP) { - //TODO: - /* if (event.jbutton.which != m_instance_id) { + if (event.jbutton.which != m_instance_id) { return helper::nullopt; - } */ + } const auto button = event.jbutton.button; - if (button == JOYCON_L) { + if (button == m_settings.rotate_left) { return InputEvent::RotateLeftReleased; } - if (button == JOYCON_R) { + if (button == m_settings.rotate_right) { return InputEvent::RotateRightReleased; } - if (button == JOYCON_DPAD_DOWN or button == JOYCON_CSTICK_DOWN) { + if (button == m_settings.move_down) { return InputEvent::MoveDownReleased; } - if (button == JOYCON_DPAD_LEFT or button == JOYCON_CSTICK_LEFT) { + if (button == m_settings.move_left) { return InputEvent::MoveLeftReleased; } - if (button == JOYCON_DPAD_RIGHT or button == JOYCON_CSTICK_RIGHT) { + if (button == m_settings.rotate_right) { return InputEvent::MoveRightReleased; } - if (button == JOYCON_A) { + if (button == m_settings.drop) { return InputEvent::DropReleased; } - if (button == JOYCON_B) { + if (button == m_settings.hold) { return InputEvent::HoldReleased; } } diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index 385081d0..e1a2cc30 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -5,12 +5,14 @@ #include "helper/expected.hpp" #include "helper/parse_json.hpp" #include "input.hpp" +#include "input/console_buttons.hpp" #include "input/game_input.hpp" #include "manager/event_dispatcher.hpp" #include #include #include +#include namespace input { @@ -63,7 +65,6 @@ namespace input { struct JoystickIdentification { SDL::GUID guid; - static helper::expected from_string(const std::string& value); }; @@ -134,16 +135,35 @@ namespace input { #endif +#define TRY_CONVERT(original, target, map, key) \ + do /*NOLINT(cppcoreguidelines-avoid-do-while)*/ { \ + if (map.contains(original.key)) { \ + target.key = map.at(original.key); \ + } else { \ + return helper::nullopt; \ + } \ + } while (false) + + +#define SETTINGS_TO_STRING(original, target, map, key) \ + do /*NOLINT(cppcoreguidelines-avoid-do-while)*/ { \ + (target).key = map.at((original).key); \ + } while (false) + struct JoystickGameInput : public GameInput, public EventListener { private: std::vector m_event_buffer; EventDispatcher* m_event_dispatcher; + protected: + JoystickInput* m_underlying_input; + public: - JoystickGameInput(EventDispatcher* event_dispatcher) + JoystickGameInput(EventDispatcher* event_dispatcher, JoystickInput* underlying_input) : GameInput{ GameInputType::Controller }, - m_event_dispatcher{ event_dispatcher } { + m_event_dispatcher{ event_dispatcher }, + m_underlying_input{ underlying_input } { m_event_dispatcher->register_listener(this); } @@ -155,7 +175,8 @@ namespace input { void update(SimulationStep simulation_step_index) override; - [[nodiscard]] static helper::optional> get_game_input_by_settings( + [[nodiscard]] static helper::expected, std::string> + get_game_input_by_settings( const input::InputManager& input_manager, EventDispatcher* event_dispatcher, const JoystickSettings& settings @@ -163,6 +184,58 @@ namespace input { protected: [[nodiscard]] virtual helper::optional sdl_event_to_input_event(const SDL_Event& event) const = 0; + + template + using MappingType = std::unordered_map; + + template + [[nodiscard]] static helper::optional> + try_resolve_settings(const JoystickSettings& settings, const MappingType& map) { + + + AbstractJoystickSettings result{}; + + TRY_CONVERT(settings, result, map, rotate_left); + TRY_CONVERT(settings, result, map, rotate_right); + TRY_CONVERT(settings, result, map, move_left); + TRY_CONVERT(settings, result, map, move_right); + TRY_CONVERT(settings, result, map, move_down); + + TRY_CONVERT(settings, result, map, drop); + TRY_CONVERT(settings, result, map, hold); + + TRY_CONVERT(settings, result, map, pause); + TRY_CONVERT(settings, result, map, open_settings); + + return result; + } + + template + [[nodiscard]] static JoystickSettings + to_normal_settings(const AbstractJoystickSettings& settings, const MappingType& original_map) { + + std::unordered_map map{}; + + for (const auto& [key, value] : original_map) { + map.insert_or_assign(value, key); + } + + JoystickSettings result{}; + + SETTINGS_TO_STRING(settings, result, map, rotate_left); + SETTINGS_TO_STRING(settings, result, map, rotate_right); + SETTINGS_TO_STRING(settings, result, map, move_left); + SETTINGS_TO_STRING(settings, result, map, move_right); + SETTINGS_TO_STRING(settings, result, map, move_down); + + SETTINGS_TO_STRING(settings, result, map, drop); + SETTINGS_TO_STRING(settings, result, map, hold); + + SETTINGS_TO_STRING(settings, result, map, pause); + SETTINGS_TO_STRING(settings, result, map, open_settings); + + return result; + } }; @@ -170,10 +243,17 @@ namespace input { #if defined(__SWITCH__) struct SwitchJoystickGameInput_Type1 : public JoystickGameInput { - //TODO: reference JoystickInput + private: + using SettingsType = enum JOYCON; + AbstractJoystickSettings m_settings; + public: - SwitchJoystickGameInput_Type1(JoystickSettings settings, EventDispatcher* event_dispatcher); + SwitchJoystickGameInput_Type1( + JoystickSettings settings, + EventDispatcher* event_dispatcher, + JoystickInput* underlying_input + ); [[nodiscard]] helper::optional get_menu_event(const SDL_Event& event) const override; @@ -185,9 +265,14 @@ namespace input { #elif defined(__3DS__) struct _3DSJoystickGameInput_Type1 : public JoystickGameInput { + AbstractJoystickSettings m_settings; public: - _3DSJoystickGameInput_Type1(JoystickSettings settings, EventDispatcher* event_dispatcher); + _3DSJoystickGameInput_Type1( + JoystickSettings settings, + EventDispatcher* event_dispatcher, + JoystickInput* underlying_input + ); [[nodiscard]] helper::optional get_menu_event(const SDL_Event& event) const override; @@ -244,25 +329,25 @@ namespace nlohmann { template<> struct adl_serializer { - static input::JoystickSettings from_json(const json& j) { + static input::JoystickSettings from_json(const json& obj) { ::json::check_for_no_additional_keys( - j, { "type", "identification", "rotate_left", "rotate_right", "move_left", "move_right", - "move_down", "drop", "hold", "menu" } + obj, { "type", "identification", "rotate_left", "rotate_right", "move_left", "move_right", + "move_down", "drop", "hold", "menu" } ); input::JoystickIdentification identification = - adl_serializer::from_json(j.at("identification")); + adl_serializer::from_json(obj.at("identification")); - const auto rotate_left = json_helper::get_key_from_object(j, "rotate_left"); - const auto rotate_right = json_helper::get_key_from_object(j, "rotate_right"); - const auto move_left = json_helper::get_key_from_object(j, "move_left"); - const auto move_right = json_helper::get_key_from_object(j, "move_right"); - const auto move_down = json_helper::get_key_from_object(j, "move_down"); - const auto drop = json_helper::get_key_from_object(j, "drop"); - const auto hold = json_helper::get_key_from_object(j, "hold"); + const auto rotate_left = json_helper::get_key_from_object(obj, "rotate_left"); + const auto rotate_right = json_helper::get_key_from_object(obj, "rotate_right"); + const auto move_left = json_helper::get_key_from_object(obj, "move_left"); + const auto move_right = json_helper::get_key_from_object(obj, "move_right"); + const auto move_down = json_helper::get_key_from_object(obj, "move_down"); + const auto drop = json_helper::get_key_from_object(obj, "drop"); + const auto hold = json_helper::get_key_from_object(obj, "hold"); - const auto& menu = j.at("menu"); + const auto& menu = obj.at("menu"); ::json::check_for_no_additional_keys(menu, { "pause", "open_settings" }); @@ -288,12 +373,12 @@ namespace nlohmann { return settings; } - static void to_json(json& j, const input::JoystickSettings& settings) { + static void to_json(json& obj, const input::JoystickSettings& settings) { auto identification = nlohmann::json{}; adl_serializer::to_json(identification, settings.identification); - j = nlohmann::json{ + obj = nlohmann::json{ { "identification", identification }, { "rotate_left", settings.rotate_left }, { "rotate_right", settings.rotate_right }, diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index 80e55890..f72218f7 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -28,10 +28,10 @@ void input::TouchGameInput::update(SimulationStep simulation_step_index) { helper::optional input::TouchGameInput::sdl_event_to_input_event(const SDL_Event& event) { - //TODO(Totto): fix this - /* if (event.tfinger.touchId != m_id) { + + if (event.tfinger.touchId != m_underlying_input->m_id) { return helper::nullopt; - } */ + } //TODO(Totto): to handle those things better, holding has to be supported diff --git a/src/input/touch_input.hpp b/src/input/touch_input.hpp index 86fcb0d6..fdddaddd 100644 --- a/src/input/touch_input.hpp +++ b/src/input/touch_input.hpp @@ -70,12 +70,18 @@ namespace input { std::unordered_map> m_finger_state; std::vector m_event_buffer; EventDispatcher* m_event_dispatcher; + TouchInput* m_underlying_input; public: - explicit TouchGameInput(const TouchSettings& settings, EventDispatcher* event_dispatcher) + explicit TouchGameInput( + const TouchSettings& settings, + EventDispatcher* event_dispatcher, + TouchInput* underlying_input + ) : GameInput{ GameInputType::Touch }, m_settings{ settings }, - m_event_dispatcher{ event_dispatcher } { + m_event_dispatcher{ event_dispatcher }, + m_underlying_input{ underlying_input } { m_event_dispatcher->register_listener(this); } diff --git a/src/scenes/single_player_game/single_player_game.cpp b/src/scenes/single_player_game/single_player_game.cpp index 6872203d..d1cad671 100644 --- a/src/scenes/single_player_game/single_player_game.cpp +++ b/src/scenes/single_player_game/single_player_game.cpp @@ -1,5 +1,6 @@ #include "single_player_game.hpp" #include "helper/date.hpp" +#include "helper/errors.hpp" #include "helper/music_utils.hpp" #include "helper/platform.hpp" #include "input/game_input.hpp" @@ -23,9 +24,17 @@ namespace scenes { //TODO: add more information, if logged in - auto [input, starting_parameters] = + auto result = input::get_single_player_game_parameters(service_provider, std::move(additional_information), date); + if (not result.has_value()) { + throw helper::MajorError( + "No suitable input was configured, go into the settings to select a suitable input! " + ); + } + + auto [input, starting_parameters] = result.value(); + m_game = std::make_unique(service_provider, std::move(input), starting_parameters, layout, true); From eaf32aebb4888c98134b4f0e54fb964203b7c01b Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 02:43:41 +0200 Subject: [PATCH 51/76] fix switch build, by providing some missing functions --- src/input/input.cpp | 1 + src/input/joystick_input.cpp | 99 +++++++++++++++++++++++++++++++++--- src/input/joystick_input.hpp | 42 +++++---------- 3 files changed, 105 insertions(+), 37 deletions(-) diff --git a/src/input/input.cpp b/src/input/input.cpp index 1e918763..c3ccf3f3 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -237,6 +237,7 @@ namespace { } } + //TODO: use the default settings for joystick / touch input / keyboard input, whatever return helper::nullopt; } diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index b7e239da..acd94001 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -440,12 +440,9 @@ input::SwitchJoystickGameInput_Type1::SwitchJoystickGameInput_Type1( EventDispatcher* event_dispatcher, JoystickInput* underlying_input ) - : JoystickGameInput{ event_dispatcher, underlying_input } { - - //TODO(Totto): make this static in some way + : JoystickGameInput{ event_dispatcher, underlying_input }, //NOTE: this are not all, but atm only those, who can be checked with a SDL_JOYBUTTONDOWN event - const MappingType key_mappings{ - + m_key_mappings{ { "A", JOYCON_A }, { "B", JOYCON_B }, { "X", JOYCON_X }, @@ -457,9 +454,11 @@ input::SwitchJoystickGameInput_Type1::SwitchJoystickGameInput_Type1( { "ZR", JOYCON_ZR }, { "PLUS", JOYCON_PLUS }, { "MINUS", JOYCON_MINUS }, - }; + } +{ + - auto validate_settings = JoystickGameInput::try_resolve_settings(settings, key_mappings); + auto validate_settings = JoystickGameInput::try_resolve_settings(settings, m_key_mappings); if (not validate_settings.has_value()) { throw std::runtime_error("Invalid settings"); } @@ -467,6 +466,7 @@ input::SwitchJoystickGameInput_Type1::SwitchJoystickGameInput_Type1( m_settings = validate_settings.value(); } +input::SwitchJoystickGameInput_Type1::~SwitchJoystickGameInput_Type1() = default; // game_input uses Input to handle events, but stores the config settings for the specific button @@ -532,6 +532,91 @@ helper::optional input::SwitchJoystickGameInput_Type1::sdl_event_to_ } return helper::nullopt; } + +[[nodiscard]] helper::optional input::SwitchJoystickGameInput_Type1::get_menu_event( + const SDL_Event& event +) const { + + if (event.type == SDL_JOYBUTTONDOWN) { + + if (event.jbutton.which != m_underlying_input->instance_id()) { + return helper::nullopt; + } + + const auto button = event.jbutton.button; + + if (button == m_settings.pause) { + return MenuEvent::PAUSE; + } + if (button == m_settings.open_settings) { + return MenuEvent::OPEN_SETTINGS; + } + } + + return helper::nullopt; +} + + +[[nodiscard]] std::string input::SwitchJoystickGameInput_Type1::describe_menu_event(MenuEvent event) const { + switch (event) { + case input::MenuEvent::PAUSE: + return key_to_string(m_settings.pause); + case input::MenuEvent::OPEN_SETTINGS: + return key_to_string(m_settings.open_settings); + default: + utils::unreachable(); + } +} + +[[nodiscard]] std::string input::SwitchJoystickGameInput_Type1::key_to_string(SettingsType key) { + switch (key) { + case JOYCON_A: + return "A"; + case JOYCON_B: + return "B"; + case JOYCON_X: + return "X"; + case JOYCON_Y: + return "Y"; + case JOYCON_L: + return "L"; + case JOYCON_R: + return "R"; + case JOYCON_ZL: + return "ZL"; + case JOYCON_ZR: + return "ZR"; + case JOYCON_PLUS: + return "PLUS"; + case JOYCON_MINUS: + return "MINUS"; + default: + utils::unreachable(); + } +} + +[[nodiscard]] input::JoystickSettings input::SwitchJoystickGameInput_Type1::to_normal_settings( + const AbstractJoystickSettings& settings +) { + + JoystickSettings result{}; + + SETTINGS_TO_STRING(settings, result, key_to_string, rotate_left); + SETTINGS_TO_STRING(settings, result, key_to_string, rotate_right); + SETTINGS_TO_STRING(settings, result, key_to_string, move_left); + SETTINGS_TO_STRING(settings, result, key_to_string, move_right); + SETTINGS_TO_STRING(settings, result, key_to_string, move_down); + + SETTINGS_TO_STRING(settings, result, key_to_string, drop); + SETTINGS_TO_STRING(settings, result, key_to_string, hold); + + SETTINGS_TO_STRING(settings, result, key_to_string, pause); + SETTINGS_TO_STRING(settings, result, key_to_string, open_settings); + + return result; +} + + #elif defined(__3DS__) helper::optional input::_3DSJoystickGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index e1a2cc30..cd84d820 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -145,9 +145,9 @@ namespace input { } while (false) -#define SETTINGS_TO_STRING(original, target, map, key) \ - do /*NOLINT(cppcoreguidelines-avoid-do-while)*/ { \ - (target).key = map.at((original).key); \ +#define SETTINGS_TO_STRING(original, target, fn, key) \ + do /*NOLINT(cppcoreguidelines-avoid-do-while)*/ { \ + target.key = fn(original.key); \ } while (false) @@ -209,33 +209,6 @@ namespace input { return result; } - - template - [[nodiscard]] static JoystickSettings - to_normal_settings(const AbstractJoystickSettings& settings, const MappingType& original_map) { - - std::unordered_map map{}; - - for (const auto& [key, value] : original_map) { - map.insert_or_assign(value, key); - } - - JoystickSettings result{}; - - SETTINGS_TO_STRING(settings, result, map, rotate_left); - SETTINGS_TO_STRING(settings, result, map, rotate_right); - SETTINGS_TO_STRING(settings, result, map, move_left); - SETTINGS_TO_STRING(settings, result, map, move_right); - SETTINGS_TO_STRING(settings, result, map, move_down); - - SETTINGS_TO_STRING(settings, result, map, drop); - SETTINGS_TO_STRING(settings, result, map, hold); - - SETTINGS_TO_STRING(settings, result, map, pause); - SETTINGS_TO_STRING(settings, result, map, open_settings); - - return result; - } }; @@ -247,6 +220,7 @@ namespace input { using SettingsType = enum JOYCON; AbstractJoystickSettings m_settings; + MappingType m_key_mappings; public: SwitchJoystickGameInput_Type1( @@ -255,12 +229,20 @@ namespace input { JoystickInput* underlying_input ); + virtual ~SwitchJoystickGameInput_Type1(); + [[nodiscard]] helper::optional get_menu_event(const SDL_Event& event) const override; [[nodiscard]] std::string describe_menu_event(MenuEvent event) const override; protected: [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event) const override; + + private: + [[nodiscard]] static std::string key_to_string(SettingsType key); + + [[nodiscard]] static JoystickSettings to_normal_settings(const AbstractJoystickSettings& settings + ); }; #elif defined(__3DS__) From 1376acc400d3ae288dc42901a2c5659b99a6197c Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 02:47:45 +0200 Subject: [PATCH 52/76] use X Macro magic to reduce the duplication of settings keys --- src/input/joystick_input.cpp | 12 +++--------- src/input/joystick_input.hpp | 26 +++++++++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index acd94001..18e90eda 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -601,17 +601,11 @@ helper::optional input::SwitchJoystickGameInput_Type1::sdl_event_to_ JoystickSettings result{}; - SETTINGS_TO_STRING(settings, result, key_to_string, rotate_left); - SETTINGS_TO_STRING(settings, result, key_to_string, rotate_right); - SETTINGS_TO_STRING(settings, result, key_to_string, move_left); - SETTINGS_TO_STRING(settings, result, key_to_string, move_right); - SETTINGS_TO_STRING(settings, result, key_to_string, move_down); +#define X_LIST_MACRO(x) SETTINGS_TO_STRING(settings, result, key_to_string, x); - SETTINGS_TO_STRING(settings, result, key_to_string, drop); - SETTINGS_TO_STRING(settings, result, key_to_string, hold); + X_LIST_OF_SETTINGS_KEYS - SETTINGS_TO_STRING(settings, result, key_to_string, pause); - SETTINGS_TO_STRING(settings, result, key_to_string, open_settings); +#undef X_LIST_MACRO return result; } diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index cd84d820..cee795d7 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -135,6 +135,19 @@ namespace input { #endif + +#define X_LIST_OF_SETTINGS_KEYS \ + X_LIST_MACRO(rotate_left) \ + X_LIST_MACRO(rotate_right) \ + X_LIST_MACRO(move_left) \ + X_LIST_MACRO(move_right) \ + X_LIST_MACRO(move_down) \ + X_LIST_MACRO(drop) \ + X_LIST_MACRO(hold) \ + X_LIST_MACRO(pause) \ + X_LIST_MACRO(open_settings) + + #define TRY_CONVERT(original, target, map, key) \ do /*NOLINT(cppcoreguidelines-avoid-do-while)*/ { \ if (map.contains(original.key)) { \ @@ -195,17 +208,12 @@ namespace input { AbstractJoystickSettings result{}; - TRY_CONVERT(settings, result, map, rotate_left); - TRY_CONVERT(settings, result, map, rotate_right); - TRY_CONVERT(settings, result, map, move_left); - TRY_CONVERT(settings, result, map, move_right); - TRY_CONVERT(settings, result, map, move_down); - TRY_CONVERT(settings, result, map, drop); - TRY_CONVERT(settings, result, map, hold); +#define X_LIST_MACRO(x) TRY_CONVERT(settings, result, map, x); + + X_LIST_OF_SETTINGS_KEYS - TRY_CONVERT(settings, result, map, pause); - TRY_CONVERT(settings, result, map, open_settings); +#undef X_LIST_MACRO return result; } From 04aa055fff7dd777b014302296631961a9da3f01 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 03:02:54 +0200 Subject: [PATCH 53/76] fix a few minor mistakes: - correct the default settings - correct the settings.json file --- settings.json | 8 ++++---- src/input/keyboard_input.hpp | 4 ++-- src/manager/settings_manager.cpp | 6 ++++-- src/scenes/play_select_menu/play_select_menu.cpp | 1 + 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/settings.json b/settings.json index acfa88fe..72dbf7d6 100644 --- a/settings.json +++ b/settings.json @@ -10,8 +10,8 @@ "rotate_left": "Left", "rotate_right": "Right", "menu": { - "pause": "Esc", - "open_settings": "E" + "pause": "Escape", + "open_settings": "P" } }, { @@ -28,7 +28,7 @@ "rotate_right": "X", "menu": { "pause": "Esc", - "open_settings": "E" + "open_settings": "P" } }, { @@ -45,7 +45,7 @@ "rotate_right": "X", "menu": { "pause": "Esc", - "open_settings": "E" + "open_settings": "P" } }, { diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index 80aaea44..aa713b6e 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -46,8 +46,8 @@ namespace input { .rotate_right = SDL::Key{ SDLK_RIGHT }, .move_left = SDL::Key{ SDLK_a }, .move_right = SDL::Key{ SDLK_d }, - .move_down = SDL::Key{ SDLK_a }, - .drop = SDL::Key{ SDLK_s }, + .move_down = SDL::Key{ SDLK_s }, + .drop = SDL::Key{ SDLK_w }, .hold = SDL::Key{ SDLK_TAB }, .pause = SDL::Key{ SDLK_ESCAPE }, .open_settings = SDL::Key{ SDLK_e } }; diff --git a/src/manager/settings_manager.cpp b/src/manager/settings_manager.cpp index 0e396375..ce69df97 100644 --- a/src/manager/settings_manager.cpp +++ b/src/manager/settings_manager.cpp @@ -1,5 +1,7 @@ #include "settings_manager.hpp" #include "helper/graphic_utils.hpp" +#include "input/keyboard_input.hpp" +#include "input/touch_input.hpp" #include @@ -15,9 +17,9 @@ SettingsManager::SettingsManager(ServiceProvider* service_provider) : m_service_ spdlog::error("unable to load settings from \"{}\": {}", detail::settings_filename, result.error()); spdlog::warn("applying default settings"); - //TODO: better default settings m_settings = { - detail::Settings{ {}, 1.0 } + detail::Settings{ { input::KeyboardSettings::default_settings(), input::TouchSettings::default_settings() }, + 1.0 } }; } } diff --git a/src/scenes/play_select_menu/play_select_menu.cpp b/src/scenes/play_select_menu/play_select_menu.cpp index cb06178b..312fafe9 100644 --- a/src/scenes/play_select_menu/play_select_menu.cpp +++ b/src/scenes/play_select_menu/play_select_menu.cpp @@ -78,6 +78,7 @@ namespace scenes { if (m_next_command.has_value()) { switch (m_next_command.value()) { case Command::SinglePlayer: + m_next_command = helper::nullopt; return UpdateResult{ SceneUpdate::StopUpdating, Scene::Switch{ SceneId::SinglePlayerGame, ui::FullScreenLayout{ m_service_provider->window() } } From e685941a534279bcdd0e22f59e88f71ac55b4a59 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 03:08:18 +0200 Subject: [PATCH 54/76] fix android build --- src/input/input.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/input.cpp b/src/input/input.cpp index c3ccf3f3..c229f5b2 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -152,7 +152,7 @@ input::InputManager::InputManager(const std::shared_ptr& window) { namespace { #if defined(__ANDROID__) using PrimaryInputType = input::TouchInput; - using PrimaryGameInputType = input::TouchGTouchGameInput; + using PrimaryGameInputType = input::TouchGameInput; #elif defined(__CONSOLE__) using PrimaryInputType = input::JoystickInput; using PrimaryGameInputType = input::JoystickGameInput; From d5119ca0c511f780aef4733fba7c041170fd8a1d Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 04:08:43 +0200 Subject: [PATCH 55/76] fix windows MSVC build --- src/input/input.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/input/input.cpp b/src/input/input.cpp index c229f5b2..a3b405f7 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -179,7 +179,7 @@ namespace { for (const auto& control : service_provider->settings_manager().settings().controls) { - auto input = std::visit( + auto result = std::visit( helper::overloaded{ [service_provider](const input::KeyboardSettings& keyboard_settings) mutable -> ReturnType { auto* const event_dispatcher = &(service_provider->event_dispatcher()); @@ -209,10 +209,9 @@ namespace { if (const auto pointer_input = utils::is_child_class(input); pointer_input.has_value()) { auto* const event_dispatcher = &(service_provider->event_dispatcher()); - auto input = std::make_shared( + return std::make_shared( touch_settings, event_dispatcher, pointer_input.value() ); - return input; } } @@ -224,10 +223,10 @@ namespace { ); - if (input.has_value()) { - game_inputs.push_back(std::move(input.value())); + if (result.has_value()) { + game_inputs.push_back(std::move(result.value())); } else { - spdlog::debug("Couldn't get input: {}", input.error()); + spdlog::debug("Couldn't get input: {}", result.error()); } } From fc916a3c243ec9698cacc7fcf55e4e8af8ad4f5e Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 21:45:24 +0200 Subject: [PATCH 56/76] refactor console / switch joystick input: - make a abstract class, that describes which methods a new console joystick has to have - deduplicate the same logic of 3ds / switch game input --- src/input/joystick_input.cpp | 283 ++++++++++++++++++----------------- src/input/joystick_input.hpp | 101 +++++++------ 2 files changed, 201 insertions(+), 183 deletions(-) diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 18e90eda..6e299720 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -200,7 +200,34 @@ input::SwitchJoystickInput_Type1::SwitchJoystickInput_Type1( SDL_JoystickID instance_id, const std::string& name ) - : JoystickInput{ joystick, instance_id, name } { } + : ConsoleJoystickInput{ + joystick, + instance_id, + name, + //NOTE: this are not all, but atm only those, who can be checked with a SDL_JOYBUTTONDOWN event + { { "A", JOYCON_A }, + { "B", JOYCON_B }, + { "X", JOYCON_X }, + { "Y", JOYCON_Y }, + { "L", JOYCON_L }, + { "R", JOYCON_R }, + { "ZL", JOYCON_ZL }, + { "ZR", JOYCON_ZR }, + { "PLUS", JOYCON_PLUS }, + { "MINUS", JOYCON_MINUS }, + { "DPAD_LEFT", JOYCON_DPAD_LEFT }, + { "DPAD_UP", JOYCON_DPAD_UP }, + { "DPAD_RIGHT", JOYCON_DPAD_RIGHT }, + { "DPAD_DOWN", JOYCON_DPAD_DOWN }, + { "LDPAD_LEFT", JOYCON_LDPAD_LEFT }, + { "LDPAD_UP", JOYCON_LDPAD_UP }, + { "LDPAD_RIGHT", JOYCON_LDPAD_RIGHT }, + { "LDPAD_DOWN", JOYCON_LDPAD_DOWN }, + { "RDPAD_LEFT", JOYCON_RDPAD_LEFT }, + { "RDPAD_UP", JOYCON_RDPAD_UP }, + { "RDPAD_RIGHT", JOYCON_RDPAD_RIGHT }, + { "RDPAD_DOWN", JOYCON_RDPAD_DOWN } } +} { } [[nodiscard]] helper::optional input::SwitchJoystickInput_Type1::get_navigation_event( @@ -269,6 +296,91 @@ input::SwitchJoystickInput_Type1::SwitchJoystickInput_Type1( } +[[nodiscard]] std::string input::SwitchJoystickInput_Type1::key_to_string(console::SettingsType key) const { + switch (key) { + case JOYCON_A: + return "A"; + case JOYCON_B: + return "B"; + case JOYCON_X: + return "X"; + case JOYCON_Y: + return "Y"; + case JOYCON_L: + return "L"; + case JOYCON_R: + return "R"; + case JOYCON_ZL: + return "ZL"; + case JOYCON_ZR: + return "ZR"; + case JOYCON_PLUS: + return "PLUS"; + case JOYCON_MINUS: + return "MINUS"; + case JOYCON_DPAD_LEFT: + return "DPAD_LEFT"; + case JOYCON_DPAD_UP: + return "DPAD_UP"; + case JOYCON_DPAD_RIGHT: + return "DPAD_RIGHT"; + case JOYCON_DPAD_DOWN: + return "DPAD_DOWN"; + case JOYCON_LDPAD_LEFT: + return "LDPAD_LEFT"; + case JOYCON_LDPAD_UP: + return "LDPAD_UP"; + case JOYCON_LDPAD_RIGHT: + return "LDPAD_RIGHT"; + case JOYCON_LDPAD_DOWN: + return "LDPAD_DOWN"; + case JOYCON_RDPAD_LEFT: + return "RDPAD_LEFT"; + case JOYCON_RDPAD_UP: + return "RDPAD_UP"; + case JOYCON_RDPAD_RIGHT: + return "RDPAD_RIGHT"; + case JOYCON_RDPAD_DOWN: + return "RDPAD_DOWN"; + + + default: + utils::unreachable(); + } +} + +[[nodiscard]] input::JoystickSettings input::SwitchJoystickInput_Type1::to_normal_settings( + const AbstractJoystickSettings& settings +) const { + + JoystickSettings result{}; + +#define X_LIST_MACRO(x) SETTINGS_TO_STRING(settings, result, key_to_string, x); + + X_LIST_OF_SETTINGS_KEYS + +#undef X_LIST_MACRO + + return result; +} + +[[nodiscard]] input::JoystickSettings input::SwitchJoystickInput_Type1::default_settings() const { + const AbstractJoystickSettings settings = // + { .identification = JoystickIdentification{}, + .rotate_left = JOYCON_DPAD_LEFT, + .rotate_right = JOYCON_DPAD_RIGHT, + .move_left = JOYCON_LDPAD_LEFT, + .move_right = JOYCON_LDPAD_RIGHT, + .move_down = JOYCON_LDPAD_DOWN, + .drop = JOYCON_X, + .hold = JOYCON_B, + .pause = JOYCON_MINUS, + .open_settings = JOYCON_PLUS }; + + return to_normal_settings(settings); +} + + #elif defined(__3DS__) input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( @@ -378,11 +490,11 @@ namespace { #if defined(__CONSOLE__) #if defined(__SWITCH__) if (guid == input::SwitchJoystickInput_Type1::guid) { - return std::make_shared(settings, event_dispatcher, underlying_input); + return std::make_shared(settings, event_dispatcher, underlying_input); } #elif defined(__3DS__) if (guid == input::_3DSJoystickInput_Type1::guid) { - return std::make_shared(settings, event_dispatcher, underlying_input); + return std::make_shared(settings, event_dispatcher, underlying_input); } #endif @@ -433,32 +545,39 @@ input::JoystickGameInput::get_game_input_by_settings( #if defined(__CONSOLE__) -#if defined(__SWITCH__) -input::SwitchJoystickGameInput_Type1::SwitchJoystickGameInput_Type1( + +input::ConsoleJoystickInput::ConsoleJoystickInput( + SDL_Joystick* joystick, + SDL_JoystickID instance_id, + const std::string& name, + const MappingType& key_mappings +) + : JoystickInput{ joystick, instance_id, name }, + m_key_mappings{ key_mappings } { } + +[[nodiscard]] const input::MappingType& input::ConsoleJoystickInput::key_mappings( +) const { + return m_key_mappings; +} + +input::ConsoleJoystickGameInput::ConsoleJoystickGameInput( JoystickSettings settings, EventDispatcher* event_dispatcher, JoystickInput* underlying_input ) - : JoystickGameInput{ event_dispatcher, underlying_input }, - //NOTE: this are not all, but atm only those, who can be checked with a SDL_JOYBUTTONDOWN event - m_key_mappings{ - { "A", JOYCON_A }, - { "B", JOYCON_B }, - { "X", JOYCON_X }, - { "Y", JOYCON_Y }, - - { "L", JOYCON_L }, - { "R", JOYCON_R }, - { "ZL", JOYCON_ZL }, - { "ZR", JOYCON_ZR }, - { "PLUS", JOYCON_PLUS }, - { "MINUS", JOYCON_MINUS }, + : JoystickGameInput{ event_dispatcher, underlying_input } { + + auto console_input = utils::is_child_class(underlying_input); + + if (not console_input.has_value()) { + throw std::runtime_error("Invalid input received"); } -{ + m_underlying_joystick_input = console_input.value(); - auto validate_settings = JoystickGameInput::try_resolve_settings(settings, m_key_mappings); + auto validate_settings = + JoystickGameInput::try_resolve_settings(settings, m_underlying_joystick_input->key_mappings()); if (not validate_settings.has_value()) { throw std::runtime_error("Invalid settings"); } @@ -466,12 +585,11 @@ input::SwitchJoystickGameInput_Type1::SwitchJoystickGameInput_Type1( m_settings = validate_settings.value(); } -input::SwitchJoystickGameInput_Type1::~SwitchJoystickGameInput_Type1() = default; +input::ConsoleJoystickGameInput::~ConsoleJoystickGameInput() = default; // game_input uses Input to handle events, but stores the config settings for the specific button -helper::optional input::SwitchJoystickGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event -) const { +helper::optional input::ConsoleJoystickGameInput::sdl_event_to_input_event(const SDL_Event& event) const { if (event.type == SDL_JOYBUTTONDOWN) { if (event.jbutton.which != m_underlying_input->instance_id()) { @@ -533,8 +651,7 @@ helper::optional input::SwitchJoystickGameInput_Type1::sdl_event_to_ return helper::nullopt; } -[[nodiscard]] helper::optional input::SwitchJoystickGameInput_Type1::get_menu_event( - const SDL_Event& event +[[nodiscard]] helper::optional input::ConsoleJoystickGameInput::get_menu_event(const SDL_Event& event ) const { if (event.type == SDL_JOYBUTTONDOWN) { @@ -557,125 +674,17 @@ helper::optional input::SwitchJoystickGameInput_Type1::sdl_event_to_ } -[[nodiscard]] std::string input::SwitchJoystickGameInput_Type1::describe_menu_event(MenuEvent event) const { +[[nodiscard]] std::string input::ConsoleJoystickGameInput::describe_menu_event(MenuEvent event) const { switch (event) { case input::MenuEvent::PAUSE: - return key_to_string(m_settings.pause); + return m_underlying_joystick_input->key_to_string(m_settings.pause); case input::MenuEvent::OPEN_SETTINGS: - return key_to_string(m_settings.open_settings); - default: - utils::unreachable(); - } -} - -[[nodiscard]] std::string input::SwitchJoystickGameInput_Type1::key_to_string(SettingsType key) { - switch (key) { - case JOYCON_A: - return "A"; - case JOYCON_B: - return "B"; - case JOYCON_X: - return "X"; - case JOYCON_Y: - return "Y"; - case JOYCON_L: - return "L"; - case JOYCON_R: - return "R"; - case JOYCON_ZL: - return "ZL"; - case JOYCON_ZR: - return "ZR"; - case JOYCON_PLUS: - return "PLUS"; - case JOYCON_MINUS: - return "MINUS"; + return m_underlying_joystick_input->key_to_string(m_settings.open_settings); default: utils::unreachable(); } } -[[nodiscard]] input::JoystickSettings input::SwitchJoystickGameInput_Type1::to_normal_settings( - const AbstractJoystickSettings& settings -) { - - JoystickSettings result{}; - -#define X_LIST_MACRO(x) SETTINGS_TO_STRING(settings, result, key_to_string, x); - - X_LIST_OF_SETTINGS_KEYS - -#undef X_LIST_MACRO - - return result; -} - - -#elif defined(__3DS__) - -helper::optional input::_3DSJoystickGameInput_Type1::sdl_event_to_input_event(const SDL_Event& event -) const { - if (event.type == SDL_JOYBUTTONDOWN) { - - if (event.jbutton.which != m_instance_id) { - return helper::nullopt; - } - - const auto button = event.jbutton.button; - if (button == m_settings.rotate_left) { - return InputEvent::RotateLeftPressed; - } - if (button == m_settings.rotate_right) { - return InputEvent::RotateRightPressed; - } - if (button == m_settings.move_down) { - return InputEvent::MoveDownPressed; - } - if (button == m_settings.move_left) { - return InputEvent::MoveLeftPressed; - } - if (button == m_settings.rotate_right) { - return InputEvent::MoveRightPressed; - } - if (button == m_settings.drop) { - return InputEvent::DropPressed; - } - if (button == m_settings.hold) { - return InputEvent::HoldPressed; - } - } else if (event.type == SDL_JOYBUTTONUP) { - - if (event.jbutton.which != m_instance_id) { - return helper::nullopt; - } - - const auto button = event.jbutton.button; - if (button == m_settings.rotate_left) { - return InputEvent::RotateLeftReleased; - } - if (button == m_settings.rotate_right) { - return InputEvent::RotateRightReleased; - } - if (button == m_settings.move_down) { - return InputEvent::MoveDownReleased; - } - if (button == m_settings.move_left) { - return InputEvent::MoveLeftReleased; - } - if (button == m_settings.rotate_right) { - return InputEvent::MoveRightReleased; - } - if (button == m_settings.drop) { - return InputEvent::DropReleased; - } - if (button == m_settings.hold) { - return InputEvent::HoldReleased; - } - } - return helper::nullopt; -} -#endif - #endif diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index cee795d7..041fb573 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -99,35 +99,76 @@ namespace input { //TODO: differntiate different controllers and modes, e.g the switch can have pro controller, the included ones, each of them seperate etc. + template + using MappingType = std::unordered_map; + #if defined(__CONSOLE__) -#if defined(__SWITCH__) - struct SwitchJoystickInput_Type1 : JoystickInput { - //TODO - static constexpr SDL::GUID guid{}; + namespace console { + using SettingsType = enum JOYCON; + } // namespace console + + struct ConsoleJoystickInput : JoystickInput { + private: + MappingType m_key_mappings; public: + ConsoleJoystickInput( + SDL_Joystick* joystick, + SDL_JoystickID instance_id, + const std::string& name, + const MappingType& key_mappings + ); + [[nodiscard]] const MappingType& key_mappings() const; + + [[nodiscard]] virtual std::string key_to_string(console::SettingsType key) const = 0; + + [[nodiscard]] virtual JoystickSettings to_normal_settings( + const AbstractJoystickSettings& settings + ) const = 0; + + [[nodiscard]] virtual JoystickSettings default_settings() const = 0; + }; + +#if defined(__SWITCH__) + struct SwitchJoystickInput_Type1 : ConsoleJoystickInput { + //TODO + static constexpr SDL::GUID guid{}; SwitchJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; + + [[nodiscard]] std::string key_to_string(console::SettingsType key) const override; + + [[nodiscard]] JoystickSettings to_normal_settings( + const AbstractJoystickSettings& settings + ) const override; + + [[nodiscard]] JoystickSettings default_settings() const override; }; #elif defined(__3DS__) - struct _3DSJoystickInput_Type1 : JoystickInput { + struct _3DSJoystickInput_Type1 : ConsoleJoystickInput { //TODO static constexpr SDL::GUID guid{}; - - public: _3DSJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; [[nodiscard]] std::string describe_navigation_event(NavigationEvent event) const override; + + [[nodiscard]] std::string key_to_string(console::SettingsType key) const override; + + [[nodiscard]] JoystickSettings to_normal_settings( + const AbstractJoystickSettings& settings + ) const override; + + [[nodiscard]] JoystickSettings default_settings() const override; }; @@ -198,9 +239,6 @@ namespace input { protected: [[nodiscard]] virtual helper::optional sdl_event_to_input_event(const SDL_Event& event) const = 0; - template - using MappingType = std::unordered_map; - template [[nodiscard]] static helper::optional> try_resolve_settings(const JoystickSettings& settings, const MappingType& map) { @@ -221,23 +259,19 @@ namespace input { #if defined(__CONSOLE__) -#if defined(__SWITCH__) - - struct SwitchJoystickGameInput_Type1 : public JoystickGameInput { + struct ConsoleJoystickGameInput : public JoystickGameInput { private: - using SettingsType = enum JOYCON; - AbstractJoystickSettings m_settings; - - MappingType m_key_mappings; + AbstractJoystickSettings m_settings; + ConsoleJoystickInput* m_underlying_joystick_input; public: - SwitchJoystickGameInput_Type1( + ConsoleJoystickGameInput( JoystickSettings settings, EventDispatcher* event_dispatcher, JoystickInput* underlying_input ); - virtual ~SwitchJoystickGameInput_Type1(); + virtual ~ConsoleJoystickGameInput(); [[nodiscard]] helper::optional get_menu_event(const SDL_Event& event) const override; @@ -245,36 +279,11 @@ namespace input { protected: [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event) const override; - - private: - [[nodiscard]] static std::string key_to_string(SettingsType key); - - [[nodiscard]] static JoystickSettings to_normal_settings(const AbstractJoystickSettings& settings - ); }; - -#elif defined(__3DS__) - struct _3DSJoystickGameInput_Type1 : public JoystickGameInput { - AbstractJoystickSettings m_settings; - - public: - _3DSJoystickGameInput_Type1( - JoystickSettings settings, - EventDispatcher* event_dispatcher, - JoystickInput* underlying_input - ); - - [[nodiscard]] helper::optional get_menu_event(const SDL_Event& event) const override; - - [[nodiscard]] std::string describe_menu_event(MenuEvent event) const override; - - protected: - [[nodiscard]] helper::optional sdl_event_to_input_event(const SDL_Event& event) const override; - }; - +#if !defined(__SWITCH__) && !defined(__3DS__) +#error "unsupported console" #endif #endif - } // namespace input From 36eaac345e2f21e6f1c92967799a642b67076877 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 22:14:45 +0200 Subject: [PATCH 57/76] build scripts: fix 3ds and switch, so that the linker is fix, it didn't work with a custom linker override locally previously (e.g. mold) --- platforms/build-3ds.sh | 4 +++- platforms/build-switch.sh | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/platforms/build-3ds.sh b/platforms/build-3ds.sh index 05eed4ef..a01e3734 100755 --- a/platforms/build-3ds.sh +++ b/platforms/build-3ds.sh @@ -31,7 +31,7 @@ export CMAKE="$BIN_DIR/$TOOL_PREFIX-cmake" export PATH="$BIN_DIR:$PATH" export CC="$COMPILER_BIN/$TOOL_PREFIX-gcc" -export CXX="$COMPILER_BIN/$TOOL_PREFIX-g"++ +export CXX="$COMPILER_BIN/$TOOL_PREFIX-g++" export AS="$COMPILER_BIN/$TOOL_PREFIX-as" export AR="$COMPILER_BIN/$TOOL_PREFIX-gcc-ar" export RANLIB="$COMPILER_BIN/$TOOL_PREFIX-gcc-ranlib" @@ -73,6 +73,8 @@ devkitpro = '$DEVKITPRO' [binaries] c = '$CC' cpp = '$CXX' +c_ld = 'bfd' +cpp_ld = 'bfd' ar = '$AR' as = '$AS' ranlib = '$RANLIB' diff --git a/platforms/build-switch.sh b/platforms/build-switch.sh index c9ecd2a5..0f0f9213 100755 --- a/platforms/build-switch.sh +++ b/platforms/build-switch.sh @@ -29,7 +29,7 @@ export CMAKE="$BIN_DIR/$TOOL_PREFIX-cmake" export PATH="$BIN_DIR:$PATH" export CC="$COMPILER_BIN/$TOOL_PREFIX-gcc" -export CXX="$COMPILER_BIN/$TOOL_PREFIX-g"++ +export CXX="$COMPILER_BIN/$TOOL_PREFIX-g++" export AS="$COMPILER_BIN/$TOOL_PREFIX-as" export AR="$COMPILER_BIN/$TOOL_PREFIX-gcc-ar" export RANLIB="$COMPILER_BIN/$TOOL_PREFIX-gcc-ranlib" @@ -71,6 +71,8 @@ devkitpro = '$DEVKITPRO' [binaries] c = '$CC' cpp = '$CXX' +c_ld = 'bfd' +cpp_ld = 'bfd' ar = '$AR' as = '$AS' ranlib = '$RANLIB' From e62606a3e251fe3dd1b10ec37cf448de9086bb49 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 22:23:11 +0200 Subject: [PATCH 58/76] buildscript: make minor improvements for android --- platforms/build-android.sh | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/platforms/build-android.sh b/platforms/build-android.sh index 274aedef..de05f724 100755 --- a/platforms/build-android.sh +++ b/platforms/build-android.sh @@ -150,13 +150,15 @@ for INDEX in "${ARCH_KEYS_INDEX[@]}"; do export BUILD_DIR="build-$ARM_TARGET_ARCH" - export CC=$ARM_TOOL_TRIPLE-clang - export CXX=$ARM_TOOL_TRIPLE-clang++ - export LD=llvm-ld - export AS=llvm-as - export AR=llvm-ar - export RANLIB=llvm-ranlib - export STRIP=llvm-strip + export CC="$ARM_TOOL_TRIPLE-clang" + export CXX="$ARM_TOOL_TRIPLE-clang++" + export LD="llvm-ld" + export AS="llvm-as" + export AR="llvm-ar" + export RANLIB="llvm-ranlib" + export STRIP="llvm-strip" + export OBJCOPY="llvm-objcop" + export LLVM_CONFIG="llvm-config" unset PKG_CONFIG ## BUILD dependencies not buildable with meson (to complicated to port) @@ -300,16 +302,17 @@ android_ndk = '$BIN_DIR' toolchain = '$BIN_DIR/$ARM_TRIPLE' [binaries] -c = '$ARM_TOOL_TRIPLE-clang' -cpp = '$ARM_TOOL_TRIPLE-clang++' -ar = 'llvm-ar' -as = 'llvm-as' -ranlib = 'llvm-ranlib' -ld = 'llvm-link' -strip = 'llvm-strip' -objcopy = 'llvm-objcop' +c = '$CC' +cpp = '$CXX' +c_ld = 'lld' +cpp_ld = 'lld' +ar = '$AR' +as = '$AS' +ranlib = '$RANLIB' +strip = '$STRIP' +objcopy = '$OBJCOPY' pkg-config = 'false' -llvm-config = 'llvm-config' +llvm-config = '$LLVM_CONFIG' [built-in options] c_std = 'gnu11' From faca1477d896ead6dcfcceee8ad4014b1f9a5f67 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 22:32:44 +0200 Subject: [PATCH 59/76] input: - fix 3ds build and link - add more debug to touch and joystick detection --- src/input/joystick_input.cpp | 90 +++++++++++++++++++++++++++++++++++- src/input/touch_input.cpp | 2 + 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 6e299720..378af5ee 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -137,6 +137,8 @@ void input::JoyStickInputManager::discover_devices(std::vector input::_3DSJoystickInput_Type1::get_navigation_event( @@ -458,6 +479,73 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( } +[[nodiscard]] std::string input::_3DSJoystickInput_Type1::key_to_string(console::SettingsType key) const { + switch (key) { + case JOYCON_A: + return "A"; + case JOYCON_B: + return "B"; + case JOYCON_SELECT: + return "SELECT"; + case JOYCON_START: + return "START"; + case JOYCON_DPAD_RIGHT: + return "DPAD_RIGHT"; + case JOYCON_DPAD_LEFT: + return "DPAD_LEFT"; + case JOYCON_DPAD_UP: + return "DPAD_UP"; + case JOYCON_DPAD_DOWN: + return "DPAD_DOWN"; + case JOYCON_R: + return "R"; + case JOYCON_L: + return "L"; + case JOYCON_X: + return "X"; + case JOYCON_Y: + return "Y"; + case JOYCON_ZL: + return "ZL"; + case JOYCON_ZR: + return "ZR"; + default: + utils::unreachable(); + } +} + +[[nodiscard]] input::JoystickSettings input::_3DSJoystickInput_Type1::to_normal_settings( + const AbstractJoystickSettings& settings +) const { + + JoystickSettings result{}; + +#define X_LIST_MACRO(x) SETTINGS_TO_STRING(settings, result, key_to_string, x); + + X_LIST_OF_SETTINGS_KEYS + +#undef X_LIST_MACRO + + return result; +} + +[[nodiscard]] input::JoystickSettings input::_3DSJoystickInput_Type1::default_settings() const { + const AbstractJoystickSettings settings = // + { .identification = JoystickIdentification{}, + .rotate_left = JOYCON_L, + .rotate_right = JOYCON_R, + .move_left = JOYCON_DPAD_LEFT, + .move_right = JOYCON_DPAD_RIGHT, + .move_down = JOYCON_DPAD_DOWN, + .drop = JOYCON_X, + .hold = JOYCON_B, + .pause = JOYCON_START, + .open_settings = JOYCON_SELECT }; + + return to_normal_settings(settings); +} + + #endif #endif diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index f72218f7..4c4d6d75 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -306,6 +306,8 @@ void input::TouchInputManager::discover_devices( return; } + spdlog::debug("Found {} Touch Devices", num_of_touch_devices); + for (auto i = 0; i < num_of_touch_devices; ++i) { auto touch_input = TouchInput::get_by_device_index(window, i); From f7a393185b718b0ba6fe67df65898c58939af9f6 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 22:39:26 +0200 Subject: [PATCH 60/76] input: add guid for 3ds joystick and correct back to use "B" not "X" --- src/input/joystick_input.cpp | 4 ++-- src/input/joystick_input.hpp | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 378af5ee..028afc96 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -442,7 +442,7 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( case JOYCON_CSTICK_RIGHT: case JOYCON_CPAD_RIGHT: return NavigationEvent::RIGHT; - case JOYCON_X: + case JOYCON_B: return NavigationEvent::BACK; default: return helper::nullopt; @@ -462,7 +462,7 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( case NavigationEvent::OK: return "A"; case NavigationEvent::BACK: - return "X"; + return "B"; case NavigationEvent::DOWN: return "Down"; case NavigationEvent::UP: diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index 041fb573..cff562b0 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -155,7 +155,10 @@ namespace input { struct _3DSJoystickInput_Type1 : ConsoleJoystickInput { //TODO - static constexpr SDL::GUID guid{}; + static constexpr SDL::GUID guid{ + SDL::GUID::ArrayType{ 0x00, 0x00, 0x10, 0x32, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f, 0x20, 0x33, + 0x44, 0x00 } + }; _3DSJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; From 6049bbc1984df52400c884296729b7f11a049979 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 16 May 2024 23:41:54 +0200 Subject: [PATCH 61/76] input: - refactor how settings and controls are treated: - you can just use the primary input or you can set an array and an index, that is than used, but if that fails in some way, nothing else is tested. - each input takes loaded settings or default ones,so specifying a controls array and no "selected" index is useful, since than it uses the setting suited for the primary input --- settings.json | 112 +++++++++++----------- src/input/input.cpp | 155 +++++++++++++++++++++++++------ src/input/joystick_input.cpp | 15 ++- src/input/joystick_input.hpp | 97 ++++++++++--------- src/input/keyboard_input.hpp | 4 +- src/manager/settings_manager.cpp | 28 +++++- src/manager/settings_manager.hpp | 8 +- 7 files changed, 285 insertions(+), 134 deletions(-) diff --git a/settings.json b/settings.json index 72dbf7d6..d8451ebb 100644 --- a/settings.json +++ b/settings.json @@ -1,61 +1,65 @@ { - "controls": [ - { - "type": "keyboard", - "drop": "W", - "hold": "E", - "move_down": "S", - "move_left": "A", - "move_right": "D", - "rotate_left": "Left", - "rotate_right": "Right", - "menu": { - "pause": "Escape", - "open_settings": "P" - } - }, - { - "type": "joystick", - "identification": { - "guid": "GUID1" + "controls": { + "selected": null, + "inputs": [ + { + "type": "keyboard", + "drop": "W", + "hold": "E", + "move_down": "S", + "move_left": "A", + "move_right": "D", + "rotate_left": "Left", + "rotate_right": "Right", + "menu": { + "pause": "Escape", + "open_settings": "P" + } }, - "drop": "W", - "hold": "E", - "move_down": "S", - "move_left": "A", - "move_right": "D", - "rotate_left": "Y", - "rotate_right": "X", - "menu": { - "pause": "Esc", - "open_settings": "P" - } - }, - { - "type": "joystick", - "identification": { - "guid": "GUID2" + { + "type": "joystick", + "identification": { + "guid": "00:00:10:32:4e:69:6e:74:65:6e:64:6f:20:33:44:00", + "name": "Nintendo 3DS" + }, + "drop": "W", + "hold": "E", + "move_down": "S", + "move_left": "A", + "move_right": "D", + "rotate_left": "Y", + "rotate_right": "X", + "menu": { + "pause": "Esc", + "open_settings": "P" + } + }, + { + "type": "joystick", + "identification": { + "guid": "GUID2" + }, + "drop": "W", + "hold": "E", + "move_down": "S", + "move_left": "A", + "move_right": "D", + "rotate_left": "Y", + "rotate_right": "X", + "menu": { + "pause": "Esc", + "open_settings": "P" + } }, - "drop": "W", - "hold": "E", - "move_down": "S", - "move_left": "A", - "move_right": "D", - "rotate_left": "Y", - "rotate_right": "X", - "menu": { - "pause": "Esc", - "open_settings": "P" + { + "type": "touch", + "move_x_threshold": 0.07, + "move_y_threshold": 0.37, + "rotation_duration_threshold": 500, + "drop_duration_threshold": 200 } - }, - { - "type": "touch", - "move_x_threshold": 0.07, - "move_y_threshold": 0.37, - "rotation_duration_threshold": 500, - "drop_duration_threshold": 200 - } - ], + ] + }, "volume": 0.2, "discord": false } diff --git a/src/input/input.cpp b/src/input/input.cpp index a3b405f7..69ed1451 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -152,40 +152,27 @@ input::InputManager::InputManager(const std::shared_ptr& window) { namespace { #if defined(__ANDROID__) using PrimaryInputType = input::TouchInput; - using PrimaryGameInputType = input::TouchGameInput; #elif defined(__CONSOLE__) using PrimaryInputType = input::JoystickInput; - using PrimaryGameInputType = input::JoystickGameInput; #else using PrimaryInputType = input::KeyboardInput; - using PrimaryGameInputType = input::KeyboardGameInput; #endif } // namespace -//TODO(Totto): improve this API, to correctly use settings to determine the input to use. -[[nodiscard]] helper::optional> input::InputManager::get_game_input( - ServiceProvider* service_provider -) { - - //TODO(TODO): use smart pointer for the event dispatcher - - - using ReturnType = helper::expected, std::string>; - - // TODO(Totto): use primary input only, if there is no setting, on what to use, add setting for what to use! +namespace { + //TODO(Totto): use smart pointer for the event dispatcher + helper::optional> + get_game_input_by_setting(ServiceProvider* service_provider, const Controls& control) { - std::vector> game_inputs{}; + using ReturnType = helper::expected, std::string>; - for (const auto& control : service_provider->settings_manager().settings().controls) { auto result = std::visit( helper::overloaded{ [service_provider](const input::KeyboardSettings& keyboard_settings) mutable -> ReturnType { auto* const event_dispatcher = &(service_provider->event_dispatcher()); - auto input = - std::make_shared(keyboard_settings, event_dispatcher); - return input; + return std::make_shared(keyboard_settings, event_dispatcher); }, [service_provider](const input::JoystickSettings& joystick_settings) mutable -> ReturnType { auto* const event_dispatcher = &(service_provider->event_dispatcher()); @@ -209,7 +196,7 @@ namespace { if (const auto pointer_input = utils::is_child_class(input); pointer_input.has_value()) { auto* const event_dispatcher = &(service_provider->event_dispatcher()); - return std::make_shared( + return std::make_shared( touch_settings, event_dispatcher, pointer_input.value() ); } @@ -224,19 +211,133 @@ namespace { if (result.has_value()) { - game_inputs.push_back(std::move(result.value())); - } else { - spdlog::debug("Couldn't get input: {}", result.error()); + return std::move(result.value()); } + + return helper::nullopt; } - for (auto input : game_inputs) { - if (const auto type_input = utils::is_child_class(input); type_input.has_value()) { - return input; + + template + T get_settings_or_default(const std::vector& controls) { + for (const auto& control : controls) { + + const T* retrieved = std::get_if(&control); + + if (retrieved != nullptr) { + return *retrieved; + } + } + + + return T::default_settings(); + } + + + input::JoystickSettings + get_settings_or_default_joystick(const input::JoystickInput* input, const std::vector& controls) { + + for (const auto& control : controls) { + + const auto* retrieved = std::get_if(&control); + + if (retrieved != nullptr) { + if (retrieved->identification.guid == input->guid()) { + return *retrieved; + } + } } + + + return input->default_settings(); } - //TODO: use the default settings for joystick / touch input / keyboard input, whatever + + helper::optional> + get_game_input_by_input(ServiceProvider* service_provider, const std::unique_ptr& input) { + + const auto& settings = service_provider->settings_manager().settings(); + + + if (const auto keyboard_input = utils::is_child_class(input); + keyboard_input.has_value()) { + + const auto keyboard_settings = get_settings_or_default(settings.controls); + + auto* const event_dispatcher = &(service_provider->event_dispatcher()); + return std::make_shared(keyboard_settings, event_dispatcher); + } + + + if (const auto joystick_input = utils::is_child_class(input); + joystick_input.has_value()) { + + const auto joystick_settings = get_settings_or_default_joystick(joystick_input.value(), settings.controls); + + auto* const event_dispatcher = &(service_provider->event_dispatcher()); + + auto game_input = input::JoystickGameInput::get_game_input_by_settings( + service_provider->input_manager(), event_dispatcher, joystick_settings + ); + + if (not game_input.has_value()) { + spdlog::warn("Not possible to get joystick by settings: {}", game_input.error()); + return helper::nullopt; + } + + + return game_input.value(); + } + + if (const auto touch_input = utils::is_child_class(input); touch_input.has_value()) { + + const auto touch_settings = get_settings_or_default(settings.controls); + + auto* const event_dispatcher = &(service_provider->event_dispatcher()); + + return std::make_shared(touch_settings, event_dispatcher, touch_input.value()); + } + + + return helper::nullopt; + } + + +} // namespace + + +[[nodiscard]] helper::optional> input::InputManager::get_game_input( + ServiceProvider* service_provider +) { + + const auto& settings = service_provider->settings_manager().settings(); + + // 1. If we have a fixed index, by settings, we use that, if it fails, we don#t try anything other + + if (settings.selected.has_value()) { + const auto index = settings.selected.value(); + if (settings.controls.size() >= index) { + return helper::nullopt; + } + + return get_game_input_by_setting(service_provider, settings.controls.at(index)); + } + + + // 2. We use the primary input for this platform + + for (const auto& input : service_provider->input_manager().inputs()) { + if (auto primary_input = utils::is_child_class(input); primary_input.has_value()) { + auto result = get_game_input_by_input(service_provider, input); + if (result.has_value()) { + return result.value(); + } + } + } + + + // 3. we fail, since no suitable input could be found + return helper::nullopt; } diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 028afc96..eb06bc04 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -99,6 +99,16 @@ input::JoystickInput::get_by_device_index(int device_index) { return m_instance_id; } +[[nodiscard]] SDL::GUID input::JoystickInput::guid() const { + const auto guid = SDL::GUID{ SDL_JoystickGetGUID(m_joystick) }; + + if (guid == SDL::GUID{}) { + throw std::runtime_error{ fmt::format("Failed to get joystick GUID: {}", SDL_GetError()) }; + } + + return guid; +} + void input::JoyStickInputManager::discover_devices(std::vector>& inputs) { //initialize joystick input, this needs to call some sdl things @@ -779,11 +789,8 @@ helper::optional input::ConsoleJoystickGameInput::sdl_event_to_input std::string json_helper::get_key_from_object(const nlohmann::json& obj, const std::string& name) { - const auto& context = obj.at(name); - std::string input; - context.get_to(input); - + obj.at(name).get_to(input); return input; } diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index cff562b0..e1640360 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -17,6 +17,44 @@ namespace input { + // essentially a GUID + struct JoystickIdentification { + SDL::GUID guid; + + std::string name; //optional (can be ""), just for human readable settings + + static helper::expected from_string(const std::string& value); + }; + + //using std::string in here, since we only know, if these are valid joystick button names, after parsing the GUID and than seeing if we support that joystick and than using the string mappings for that specific joystick + + template + struct AbstractJoystickSettings { + JoystickIdentification identification; + + T rotate_left; + T rotate_right; + T move_left; + T move_right; + T move_down; + T drop; + T hold; + + T pause; + T open_settings; + + + [[nodiscard]] helper::expected validate() const { + const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, + drop, hold, pause, open_settings }; + + return input::InputSettings::has_unique_members(to_use); + } + }; + + using JoystickSettings = AbstractJoystickSettings; + + /** * @brief * @@ -46,6 +84,10 @@ namespace input { [[nodiscard]] SDL_JoystickID instance_id() const; + [[nodiscard]] SDL::GUID guid() const; + + [[nodiscard]] virtual JoystickSettings default_settings() const = 0; + // Add get_game_input method! }; @@ -61,42 +103,6 @@ namespace input { }; - // essentially a GUID - struct JoystickIdentification { - SDL::GUID guid; - - static helper::expected from_string(const std::string& value); - }; - - //using std::string in here, since we only know, if these are valid joystick button names, after parsing the GUID and than seeing if we support that joystick and than using the string mappings for that specific joystick - - template - struct AbstractJoystickSettings { - JoystickIdentification identification; - - T rotate_left; - T rotate_right; - T move_left; - T move_right; - T move_down; - T drop; - T hold; - - T pause; - T open_settings; - - - [[nodiscard]] helper::expected validate() const { - const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, - drop, hold, pause, open_settings }; - - return input::InputSettings::has_unique_members(to_use); - } - }; - - using JoystickSettings = AbstractJoystickSettings; - - //TODO: differntiate different controllers and modes, e.g the switch can have pro controller, the included ones, each of them seperate etc. template @@ -126,8 +132,6 @@ namespace input { [[nodiscard]] virtual JoystickSettings to_normal_settings( const AbstractJoystickSettings& settings ) const = 0; - - [[nodiscard]] virtual JoystickSettings default_settings() const = 0; }; #if defined(__SWITCH__) @@ -302,15 +306,16 @@ namespace nlohmann { template<> struct adl_serializer { - static input::JoystickIdentification from_json(const json& j) { + static input::JoystickIdentification from_json(const json& obj) { - ::json::check_for_no_additional_keys(j, { "guid" }); + ::json::check_for_no_additional_keys(obj, { "guid", "name" }); - auto context = j.at("guid"); + auto context = obj.at("guid"); std::string input; context.get_to(input); + const auto& value = SDL::GUID::from_string(input); if (not value.has_value()) { @@ -319,12 +324,18 @@ namespace nlohmann { ); } - return input::JoystickIdentification{ .guid = value.value() }; + std::string name{}; + + if (obj.contains("name")) { + obj.at("name").get_to(name); + } + + return input::JoystickIdentification{ .guid = value.value(), .name = name }; } static void to_json(json& j, const input::JoystickIdentification& identification) { j = nlohmann::json{ - { "guid", identification.guid.to_string() }, + { "guid", identification.guid.to_string(), { "name", identification.name } }, }; } }; diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index aa713b6e..8abef8d7 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -131,8 +131,8 @@ namespace nlohmann { return settings; } - static void to_json(json& j, const input::KeyboardSettings& settings) { - j = nlohmann::json{ + static void to_json(json& obj, const input::KeyboardSettings& settings) { + obj = nlohmann::json{ { "rotate_left", settings.rotate_left.to_string() }, { "rotate_right", settings.rotate_right.to_string() }, { "move_left", settings.move_left.to_string() }, diff --git a/src/manager/settings_manager.cpp b/src/manager/settings_manager.cpp index ce69df97..0ec6caee 100644 --- a/src/manager/settings_manager.cpp +++ b/src/manager/settings_manager.cpp @@ -18,8 +18,7 @@ SettingsManager::SettingsManager(ServiceProvider* service_provider) : m_service_ spdlog::warn("applying default settings"); m_settings = { - detail::Settings{ { input::KeyboardSettings::default_settings(), input::TouchSettings::default_settings() }, - 1.0 } + detail::Settings{ {}, helper::nullopt, 1.0, false } }; } } @@ -28,3 +27,28 @@ SettingsManager::SettingsManager(ServiceProvider* service_provider) : m_service_ [[nodiscard]] const detail::Settings& SettingsManager::settings() const { return m_settings; } + + +void detail::to_json(nlohmann::json& obj, const detail::Settings& settings) { + obj = nlohmann::json{ + { "controls", + nlohmann::json{ { "inputs", settings.controls }, { "selected", settings.selected } }, + { "volume", settings.volume }, + { "discord", settings.discord } } + }; +} + +void detail::from_json(const nlohmann::json& obj, detail::Settings& settings) { + + ::json::check_for_no_additional_keys(obj, { "controls", "volume", "discord" }); + + obj.at("volume").get_to(settings.volume); + obj.at("discord").get_to(settings.discord); + + const auto& controls = obj.at("controls"); + + ::json::check_for_no_additional_keys(controls, { "inputs", "selected" }); + + controls.at("inputs").get_to(settings.controls); + controls.at("selected").get_to(settings.selected); +} diff --git a/src/manager/settings_manager.hpp b/src/manager/settings_manager.hpp index 9c8aaba2..b4bfc93c 100644 --- a/src/manager/settings_manager.hpp +++ b/src/manager/settings_manager.hpp @@ -1,5 +1,6 @@ #pragma once +#include "helper/optional.hpp" #include "input/joystick_input.hpp" #include "input/keyboard_input.hpp" #include "input/touch_input.hpp" @@ -55,12 +56,15 @@ namespace detail { struct Settings { std::vector controls; - float volume{ 0.2f }; + helper::optional selected; + float volume{ 0.2F }; bool discord{ false }; //changing this requires a restart }; - NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Settings, controls, volume, discord) + void to_json(nlohmann::json& obj, const Settings& settings); + + void from_json(const nlohmann::json& obj, Settings& settings); } // namespace detail From 5074c301e39db970d966868b8aa2d0736fa39735 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 00:14:26 +0200 Subject: [PATCH 62/76] input: - use default settings in case the keys are incorrect in joystick settings (that is only checked, after the GUId is resolved) - fixed a few minor typos --- settings.json | 35 +++++++++-------------------------- src/input/joystick_input.cpp | 32 ++++++++++++++++++++------------ src/input/joystick_input.hpp | 26 ++++++++++++++++---------- 3 files changed, 45 insertions(+), 48 deletions(-) diff --git a/settings.json b/settings.json index d8451ebb..02558b4b 100644 --- a/settings.json +++ b/settings.json @@ -22,33 +22,16 @@ "guid": "00:00:10:32:4e:69:6e:74:65:6e:64:6f:20:33:44:00", "name": "Nintendo 3DS" }, - "drop": "W", - "hold": "E", - "move_down": "S", - "move_left": "A", - "move_right": "D", - "rotate_left": "Y", - "rotate_right": "X", + "drop": "X", + "hold": "B", + "move_down": "DPAD_DOWN", + "move_left": "DPAD_LEFT", + "move_right": "DPAD_RIGHT", + "rotate_left": "L", + "rotate_right": "R", "menu": { - "pause": "Esc", - "open_settings": "P" - } - }, - { - "type": "joystick", - "identification": { - "guid": "GUID2" - }, - "drop": "W", - "hold": "E", - "move_down": "S", - "move_left": "A", - "move_right": "D", - "rotate_left": "Y", - "rotate_right": "X", - "menu": { - "pause": "Esc", - "open_settings": "P" + "pause": "START", + "open_settings": "SELECT" } }, { diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index eb06bc04..bbcdfb3c 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -376,7 +376,8 @@ input::SwitchJoystickInput_Type1::SwitchJoystickInput_Type1( return result; } -[[nodiscard]] input::JoystickSettings input::SwitchJoystickInput_Type1::default_settings() const { +[[nodiscard]] input::AbstractJoystickSettings +input::SwitchJoystickInput_Type1::default_settings_raw() const { const AbstractJoystickSettings settings = // { .identification = JoystickIdentification{}, .rotate_left = JOYCON_DPAD_LEFT, @@ -389,7 +390,7 @@ input::SwitchJoystickInput_Type1::SwitchJoystickInput_Type1( .pause = JOYCON_MINUS, .open_settings = JOYCON_PLUS }; - return to_normal_settings(settings); + return settings; } @@ -538,8 +539,8 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( return result; } - -[[nodiscard]] input::JoystickSettings input::_3DSJoystickInput_Type1::default_settings() const { +[[nodiscard]] input::AbstractJoystickSettings +input::_3DSJoystickInput_Type1::default_settings_raw() const { const AbstractJoystickSettings settings = // { .identification = JoystickIdentification{}, .rotate_left = JOYCON_L, @@ -552,7 +553,7 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( .pause = JOYCON_START, .open_settings = JOYCON_SELECT }; - return to_normal_settings(settings); + return settings; } @@ -594,7 +595,6 @@ namespace { if (guid == input::_3DSJoystickInput_Type1::guid) { return std::make_shared(settings, event_dispatcher, underlying_input); } - #endif #endif @@ -659,6 +659,10 @@ input::ConsoleJoystickInput::ConsoleJoystickInput( return m_key_mappings; } +[[nodiscard]] input::JoystickSettings input::ConsoleJoystickInput::default_settings() const { + return to_normal_settings(default_settings_raw()); +} + input::ConsoleJoystickGameInput::ConsoleJoystickGameInput( JoystickSettings settings, EventDispatcher* event_dispatcher, @@ -676,11 +680,15 @@ input::ConsoleJoystickGameInput::ConsoleJoystickGameInput( auto validate_settings = JoystickGameInput::try_resolve_settings(settings, m_underlying_joystick_input->key_mappings()); - if (not validate_settings.has_value()) { - throw std::runtime_error("Invalid settings"); - } + if (validate_settings.has_value()) { + m_settings = validate_settings.value(); + } else { - m_settings = validate_settings.value(); + spdlog::warn("Invalid settings: {}", validate_settings.error()); + spdlog::warn("using default settings"); + + m_settings = m_underlying_joystick_input->default_settings_raw(); + } } input::ConsoleJoystickGameInput::~ConsoleJoystickGameInput() = default; @@ -708,7 +716,7 @@ helper::optional input::ConsoleJoystickGameInput::sdl_event_to_input if (button == m_settings.move_left) { return InputEvent::MoveLeftPressed; } - if (button == m_settings.rotate_right) { + if (button == m_settings.move_right) { return InputEvent::MoveRightPressed; } if (button == m_settings.drop) { @@ -736,7 +744,7 @@ helper::optional input::ConsoleJoystickGameInput::sdl_event_to_input if (button == m_settings.move_left) { return InputEvent::MoveLeftReleased; } - if (button == m_settings.rotate_right) { + if (button == m_settings.move_right) { return InputEvent::MoveRightReleased; } if (button == m_settings.drop) { diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index e1640360..73f02d15 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -132,6 +132,10 @@ namespace input { [[nodiscard]] virtual JoystickSettings to_normal_settings( const AbstractJoystickSettings& settings ) const = 0; + + [[nodiscard]] JoystickSettings default_settings() const override; + + [[nodiscard]] virtual AbstractJoystickSettings default_settings_raw() const = 0; }; #if defined(__SWITCH__) @@ -150,7 +154,7 @@ namespace input { const AbstractJoystickSettings& settings ) const override; - [[nodiscard]] JoystickSettings default_settings() const override; + [[nodiscard]] AbstractJoystickSettings default_settings_raw() const override; }; @@ -175,7 +179,7 @@ namespace input { const AbstractJoystickSettings& settings ) const override; - [[nodiscard]] JoystickSettings default_settings() const override; + [[nodiscard]] AbstractJoystickSettings default_settings_raw() const override; }; @@ -196,13 +200,15 @@ namespace input { X_LIST_MACRO(open_settings) -#define TRY_CONVERT(original, target, map, key) \ - do /*NOLINT(cppcoreguidelines-avoid-do-while)*/ { \ - if (map.contains(original.key)) { \ - target.key = map.at(original.key); \ - } else { \ - return helper::nullopt; \ - } \ +#define TRY_CONVERT(original, target, map, key) \ + do /*NOLINT(cppcoreguidelines-avoid-do-while)*/ { \ + if (map.contains(original.key)) { \ + target.key = map.at(original.key); \ + } else { \ + return helper::unexpected{ \ + fmt::format("While parsing key '{}': '{}' is not a valid joystick input", #key, original.key) \ + }; \ + } \ } while (false) @@ -247,7 +253,7 @@ namespace input { [[nodiscard]] virtual helper::optional sdl_event_to_input_event(const SDL_Event& event) const = 0; template - [[nodiscard]] static helper::optional> + [[nodiscard]] static helper::expected, std::string> try_resolve_settings(const JoystickSettings& settings, const MappingType& map) { From 1b4d0ccea907c92576e94aae692c00f69245379b Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 00:41:24 +0200 Subject: [PATCH 63/76] input: console: add joystick axis support --- src/input/joystick_input.cpp | 58 +++++++++++++++++++++++++++++------- src/input/joystick_input.hpp | 3 ++ 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index bbcdfb3c..4092ba58 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -280,10 +280,7 @@ input::SwitchJoystickInput_Type1::SwitchJoystickInput_Type1( } } - //TODO: handle SDL_JOYAXISMOTION - - - return helper::nullopt; + return handle_axis_navigation_event(event); } [[nodiscard]] std::string input::SwitchJoystickInput_Type1::describe_navigation_event(NavigationEvent event) const { @@ -426,8 +423,6 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( [[nodiscard]] helper::optional input::_3DSJoystickInput_Type1::get_navigation_event( const SDL_Event& event ) const { - - if (event.type == SDL_JOYBUTTONDOWN) { if (event.jbutton.which != instance_id()) { @@ -462,10 +457,7 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( } } - //TODO: handle SDL_JOYAXISMOTION - - - return helper::nullopt; + return handle_axis_navigation_event(event); } [[nodiscard]] std::string input::_3DSJoystickInput_Type1::describe_navigation_event(NavigationEvent event) const { @@ -663,6 +655,52 @@ input::ConsoleJoystickInput::ConsoleJoystickInput( return to_normal_settings(default_settings_raw()); } +[[nodiscard]] helper::optional input::ConsoleJoystickInput::handle_axis_navigation_event( + const SDL_Event& event +) const { + if (event.type == SDL_JOYAXISMOTION) { + + //TODO(Totto). maybe make this configurable + // this constant is here, that slight touches aren't counted as inputs ( really slight wiggles might occur unintentinoally) NOTE: that most inputs use all 16 bits for a normal press, so that this value can be that "big"! + constexpr auto axis_threshold = 1000; + + if (event.jaxis.which != instance_id()) { + return helper::nullopt; + } + + // x axis movement + if (event.jaxis.axis == 0) { + if (event.jaxis.value > axis_threshold) { + return NavigationEvent::RIGHT; + } + + if (event.jaxis.value < -axis_threshold) { + return NavigationEvent::LEFT; + } + + return helper::nullopt; + } + + // y axis movement + if (event.jaxis.axis == 1) { + if (event.jaxis.value > axis_threshold) { + return NavigationEvent::DOWN; + } + + if (event.jaxis.value < -axis_threshold) { + return NavigationEvent::UP; + } + + return helper::nullopt; + } + + throw std::runtime_error(fmt::format("Reached unsupported axis for SDL_JOYAXISMOTION {}", event.jaxis.axis)); + } + + return helper::nullopt; +} + + input::ConsoleJoystickGameInput::ConsoleJoystickGameInput( JoystickSettings settings, EventDispatcher* event_dispatcher, diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index 73f02d15..db59c29b 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -136,6 +136,9 @@ namespace input { [[nodiscard]] JoystickSettings default_settings() const override; [[nodiscard]] virtual AbstractJoystickSettings default_settings_raw() const = 0; + + [[nodiscard]] helper::optional handle_axis_navigation_event(const SDL_Event& event + ) const; }; #if defined(__SWITCH__) From ec64b9f1a896986b99a451e055efec7eeb643298 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 00:46:00 +0200 Subject: [PATCH 64/76] clang-tidy: - fix all todos. add a name to them --- src/application.cpp | 2 +- src/application.hpp | 2 +- src/discord/core.hpp | 4 ++-- src/graphics/renderer.cpp | 2 +- src/helper/color.cpp | 2 +- src/helper/color.hpp | 2 +- src/helper/message_box.hpp | 2 +- src/helper/platform.cpp | 2 +- src/input/joystick_input.cpp | 2 +- src/input/joystick_input.hpp | 4 ++-- src/input/keyboard_input.hpp | 2 +- src/lobby/api.hpp | 4 ++-- src/manager/event_dispatcher.hpp | 2 +- src/manager/music_manager.cpp | 2 +- src/manager/music_manager.hpp | 2 +- src/manager/sdl_key.hpp | 2 +- src/recordings/recording_reader.cpp | 2 +- src/scenes/online_lobby/online_lobby.cpp | 2 +- src/scenes/recording_selector/recording_chooser.cpp | 10 +++++----- src/scenes/recording_selector/recording_component.hpp | 2 +- src/scenes/replay_game/replay_game.cpp | 6 +++--- src/scenes/single_player_game/single_player_game.cpp | 2 +- src/ui/components/textinput.cpp | 2 +- src/ui/components/textinput.hpp | 2 +- src/ui/layouts/scroll_layout.hpp | 2 +- 25 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/application.cpp b/src/application.cpp index c962c607..50962edb 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -281,7 +281,7 @@ void Application::load_resources() { constexpr auto fonts_size = 128; const std::vector> fonts{ #if defined(__3DS__) - //TODO: debug why the other font crashed, not on loading, but on trying to render text! + //TODO(Totto): debug why the other font crashed, not on loading, but on trying to render text! { FontId::Default, "LeroyLetteringLightBeta01.ttf" }, #else { FontId::Default, "PressStart2P.ttf" }, diff --git a/src/application.hpp b/src/application.hpp index 31b1df79..34a713b3 100644 --- a/src/application.hpp +++ b/src/application.hpp @@ -58,7 +58,7 @@ struct Application final : public EventListener, public ServiceProvider { virtual void update(); virtual void render() const; - //TODO: move those functions bodies to the cpp + //TODO(Totto): move those functions bodies to the cpp void push_scene(std::unique_ptr scene) { m_scene_stack.push_back(std::move(scene)); diff --git a/src/discord/core.hpp b/src/discord/core.hpp index 272e69d9..ffad0d68 100644 --- a/src/discord/core.hpp +++ b/src/discord/core.hpp @@ -18,7 +18,7 @@ namespace constants::discord { constexpr auto client_id = 1220147916371394650ULL; - //TODO: this isn't correct for all platforms and needs to be tested + //TODO(Totto): this isn't correct for all platforms and needs to be tested #if defined(__ANDROID__) constexpr const char* platform_dependent_launch_arguments = ""; #elif defined(__CONSOLE__) @@ -49,7 +49,7 @@ struct DiscordActivityWrapper { discord::Activity m_activity{}; public: - //TODO: Add support for party and invites / join / invitations / spectate + //TODO(Totto): Add support for party and invites / join / invitations / spectate DiscordActivityWrapper(const std::string& details, discord::ActivityType type); diff --git a/src/graphics/renderer.cpp b/src/graphics/renderer.cpp index c2eeda71..4e7bc42a 100644 --- a/src/graphics/renderer.cpp +++ b/src/graphics/renderer.cpp @@ -1,7 +1,7 @@ #include "renderer.hpp" #include "helper/errors.hpp" -//TODO: assert return values of all sdl functions +//TODO(Totto): assert return values of all sdl functions Renderer::Renderer(const Window& window, const VSync v_sync) : m_renderer{ SDL_CreateRenderer( diff --git a/src/helper/color.cpp b/src/helper/color.cpp index b45a696c..46e1d3ea 100644 --- a/src/helper/color.cpp +++ b/src/helper/color.cpp @@ -81,7 +81,7 @@ namespace { if (value < static_cast(0.0)) { // see https://math.stackexchange.com/questions/2179579/how-can-i-find-a-mod-with-negative-number T result = value; - //TODO: maybe this is possible faster? + //TODO(Totto): maybe this is possible faster? while (result < static_cast(0.0)) { result += divisor; } diff --git a/src/helper/color.hpp b/src/helper/color.hpp index 3ba79b5a..32163214 100644 --- a/src/helper/color.hpp +++ b/src/helper/color.hpp @@ -70,7 +70,7 @@ struct HSVColor { }; namespace { - //TODO: if everything (also libc++ ) supports c++23 , the std functions are constexpr, so we can use them + //TODO(Totto): if everything (also libc++ ) supports c++23 , the std functions are constexpr, so we can use them template constexpr T fmod_constexpr(T value, T divisor) { if (not utils::is_constant_evaluated()) { diff --git a/src/helper/message_box.hpp b/src/helper/message_box.hpp index c56ca3a5..88a804e7 100644 --- a/src/helper/message_box.hpp +++ b/src/helper/message_box.hpp @@ -25,7 +25,7 @@ namespace helper { */ static void show_simple(Type type, const std::string& title, const std::string& content, SDL_Window* window); - //TODO: add option to use the complicated API, that supports more buttons and also a result which button was pressed! + //TODO(Totto): add option to use the complicated API, that supports more buttons and also a result which button was pressed! }; diff --git a/src/helper/platform.cpp b/src/helper/platform.cpp index 780048da..c469b7c1 100644 --- a/src/helper/platform.cpp +++ b/src/helper/platform.cpp @@ -72,7 +72,7 @@ namespace { spdlog::info("Returned string from url open was: {}", result); return true; #else - //TODO: this is dangerous, if we supply user input, so use SDL_OpenURL preferably + //TODO(Totto): this is dangerous, if we supply user input, so use SDL_OpenURL preferably #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) const std::string shell_command = "start " + url; diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 4092ba58..20babddc 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -740,7 +740,7 @@ helper::optional input::ConsoleJoystickGameInput::sdl_event_to_input return helper::nullopt; } - //TODO: use switch case + //TODO(Totto): use switch case const auto button = event.jbutton.button; if (button == m_settings.rotate_left) { return InputEvent::RotateLeftPressed; diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index db59c29b..b5fcb572 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -92,7 +92,7 @@ namespace input { }; - //TODO: also support gamecontroller API + //TODO(Totto): also support gamecontroller API // see: https://github.com/mdqinc/SDL_GameControllerDB?tab=readme-ov-file struct JoyStickInputManager { @@ -103,7 +103,7 @@ namespace input { }; - //TODO: differntiate different controllers and modes, e.g the switch can have pro controller, the included ones, each of them seperate etc. + //TODO(Totto): differntiate different controllers and modes, e.g the switch can have pro controller, the included ones, each of them seperate etc. template using MappingType = std::unordered_map; diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index 8abef8d7..b6b7f22a 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -25,7 +25,7 @@ namespace input { }; - //TODO: don't default initialize all settings, but rather provide a static default setting, so that everything has to be set explicitly, or you can use the default explicitly + //TODO(Totto): don't default initialize all settings, but rather provide a static default setting, so that everything has to be set explicitly, or you can use the default explicitly struct KeyboardSettings { SDL::Key rotate_left; SDL::Key rotate_right; diff --git a/src/lobby/api.hpp b/src/lobby/api.hpp index 4b7a64bf..2e04aa52 100644 --- a/src/lobby/api.hpp +++ b/src/lobby/api.hpp @@ -157,7 +157,7 @@ namespace lobby { const auto& version = server_version.value(); - //TODO: if version is semver, support semver comparison + //TODO(Totto): if version is semver, support semver comparison if (Client::supported_version.string() != version.version) { return helper::unexpected{ fmt::format( "Connecting to unsupported server, version is {}, but we support only {}", @@ -229,7 +229,7 @@ namespace lobby { return helper::unexpected{ reachable.error() }; } - //TODO: once version is standard, check here if the version is supported + //TODO(Totto): once version is standard, check here if the version is supported return client; } diff --git a/src/manager/event_dispatcher.hpp b/src/manager/event_dispatcher.hpp index 1ce3954a..b7c80ae4 100644 --- a/src/manager/event_dispatcher.hpp +++ b/src/manager/event_dispatcher.hpp @@ -15,7 +15,7 @@ struct EventDispatcher final { bool m_input_activated{ false }; bool m_enabled{ true }; - //TODO: factor out to some other place! + //TODO(Totto): factor out to some other place! std::vector allowed_input_keys{ SDL::Key{ SDLK_RETURN }, SDL::Key{ SDLK_BACKSPACE }, diff --git a/src/manager/music_manager.cpp b/src/manager/music_manager.cpp index 3a6c1c42..0a60a316 100644 --- a/src/manager/music_manager.cpp +++ b/src/manager/music_manager.cpp @@ -31,7 +31,7 @@ MusicManager::MusicManager(ServiceProvider* service_provider, u8 channel_size) throw helper::InitializationError{ fmt::format("Failed to initialize the audio system: {}", SDL_GetError()) }; } - //TODO: dynamically handle codecs + //TODO(Totto): dynamically handle codecs const auto initialized_codecs = Mix_Init(MIX_INIT_FLAC | MIX_INIT_MP3); if (initialized_codecs == 0) { throw helper::InitializationError{ fmt::format("Failed to initialize any audio codec: {}", SDL_GetError()) }; diff --git a/src/manager/music_manager.hpp b/src/manager/music_manager.hpp index 4cc54adb..496ee7bb 100644 --- a/src/manager/music_manager.hpp +++ b/src/manager/music_manager.hpp @@ -47,7 +47,7 @@ struct MusicManager final { helper::optional load_effect(const std::string& name, std::filesystem::path& location); helper::optional play_effect(const std::string& name, u8 channel_num = 1, int loop = 0); - //TODO: atm the volume changers only work on the music channel, when adding more effects, this should support channels via https://wiki.libsdl.org/SDL2_mixer/Mix_Volume + //TODO(Totto): atm the volume changers only work on the music channel, when adding more effects, this should support channels via https://wiki.libsdl.org/SDL2_mixer/Mix_Volume [[nodiscard]] helper::optional get_volume() const; void set_volume(helper::optional new_volume, bool force_update = false, bool notify_listeners = true); // no nodiscard, since the return value is only a side effect, that is maybe useful diff --git a/src/manager/sdl_key.hpp b/src/manager/sdl_key.hpp index 46f3898e..fc6c1250 100644 --- a/src/manager/sdl_key.hpp +++ b/src/manager/sdl_key.hpp @@ -94,7 +94,7 @@ struct fmt::formatter : formatter { }; -//TODO: add input manager and rename curretn inputmanager to game_input manager or similar +//TODO(Totto): add input manager and rename curretn inputmanager to game_input manager or similar // each devices can have multiple input devices, like keyboard, joycon etc. you can select mulltiple ones for navigation, some keys are ficed, like ctrl+c ctrl+v or arrow keys enter, esc tab,, some like wasd and similar can be chnaged by the inpout controller, support both click only and keyboard only, joyocn only, joyncon(s) + keyboard configurations diff --git a/src/recordings/recording_reader.cpp b/src/recordings/recording_reader.cpp index 6ed6596b..ceac9cfa 100644 --- a/src/recordings/recording_reader.cpp +++ b/src/recordings/recording_reader.cpp @@ -116,7 +116,7 @@ helper::expected recorder::RecordingRead std::vector records{}; std::vector snapshots{}; - //TODO: when using larger files and recordings, we should stream the data and discard used, to far away data, to not load everything into memory at once + //TODO(Totto): when using larger files and recordings, we should stream the data and discard used, to far away data, to not load everything into memory at once while (true) { diff --git a/src/scenes/online_lobby/online_lobby.cpp b/src/scenes/online_lobby/online_lobby.cpp index fda25b62..538a5748 100644 --- a/src/scenes/online_lobby/online_lobby.cpp +++ b/src/scenes/online_lobby/online_lobby.cpp @@ -25,7 +25,7 @@ namespace scenes { layout } { - //TODO: after the settings have been reworked, make this url changeable! + //TODO(Totto): after the settings have been reworked, make this url changeable! auto maybe_client = lobby::Client::get_client("http://127.0.0.1:5000"); if (maybe_client.has_value()) { client = std::make_unique(std::move(maybe_client.value())); diff --git a/src/scenes/recording_selector/recording_chooser.cpp b/src/scenes/recording_selector/recording_chooser.cpp index a36364e1..85c193fc 100644 --- a/src/scenes/recording_selector/recording_chooser.cpp +++ b/src/scenes/recording_selector/recording_chooser.cpp @@ -100,8 +100,8 @@ helper::BoolWrapper> custom_ui::Reco const std::shared_ptr& input_manager, const SDL_Event& event ) { - //TODO: this double nested component can't correctly detect focus changes (since the checking for a focus change only occurs at one level deep) - //TODO: allow horizontal RIGHT <-> LEFT focus change on horizontal focus_layouts + //TODO(Totto): this double nested component can't correctly detect focus changes (since the checking for a focus change only occurs at one level deep) + //TODO(Totto): allow horizontal RIGHT <-> LEFT focus change on horizontal focus_layouts if (const auto handled = m_main_grid.handle_event(input_manager, event); handled) { return handled; } @@ -120,10 +120,10 @@ helper::BoolWrapper> custom_ui::Reco return currently_chosen_files; } -//TODO: solve in another way, that is better +//TODO(Totto): solve in another way, that is better void custom_ui::RecordingFileChooser::prepare_dialog(ServiceProvider* service_provider) { - //TODO: show scene on top, that hints of the dialog + //TODO(Totto): show scene on top, that hints of the dialog this->currently_chosen_files.clear(); service_provider->event_dispatcher().disable(); } @@ -132,6 +132,6 @@ void custom_ui::RecordingFileChooser::cleanup_dialog( //NOLINT(readability-conve ServiceProvider* service_provider ) { - //TODO: remove hint scene on top + //TODO(Totto): remove hint scene on top service_provider->event_dispatcher().enable(); } diff --git a/src/scenes/recording_selector/recording_component.hpp b/src/scenes/recording_selector/recording_component.hpp index 9ab066d6..4e554b92 100644 --- a/src/scenes/recording_selector/recording_component.hpp +++ b/src/scenes/recording_selector/recording_component.hpp @@ -15,7 +15,7 @@ namespace data { - //TODO: add drop support + //TODO(Totto): add drop support enum class RecordingSource : u8 { CommandLine, Folder, Manual, Online, Drop }; struct RecordingMetadata { diff --git a/src/scenes/replay_game/replay_game.cpp b/src/scenes/replay_game/replay_game.cpp index 37a580f5..b81ea76e 100644 --- a/src/scenes/replay_game/replay_game.cpp +++ b/src/scenes/replay_game/replay_game.cpp @@ -29,7 +29,7 @@ namespace scenes { layouts.push_back(ui::RelativeLayout{ layout, 0.52, 0.01, 0.46, 0.98 }); } else { - //TODO: support bigger layouts than just 2 + //TODO(Totto): support bigger layouts than just 2 throw std::runtime_error("At the moment only replays from up to two players are supported"); } @@ -116,8 +116,8 @@ namespace scenes { [[nodiscard]] bool ReplayGame::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { - //TODO: add gameInput to this function - //TODO: re-add pause scene + //TODO(Totto): add gameInput to this function + //TODO(Totto): re-add pause scene UNUSED(input_manager); UNUSED(event); /* if (utils::event_is_action(event, utils::CrossPlatformAction::PAUSE)) { diff --git a/src/scenes/single_player_game/single_player_game.cpp b/src/scenes/single_player_game/single_player_game.cpp index d1cad671..29660fe7 100644 --- a/src/scenes/single_player_game/single_player_game.cpp +++ b/src/scenes/single_player_game/single_player_game.cpp @@ -21,7 +21,7 @@ namespace scenes { additional_information.add("mode", "single_player"); additional_information.add("platform", std::string{ magic_enum::enum_name(utils::get_platform()) }); additional_information.add("date", date.value()); - //TODO: add more information, if logged in + //TODO(Totto): add more information, if logged in auto result = diff --git a/src/ui/components/textinput.cpp b/src/ui/components/textinput.cpp index ede08679..d1b9d822 100644 --- a/src/ui/components/textinput.cpp +++ b/src/ui/components/textinput.cpp @@ -104,7 +104,7 @@ void ui::TextInput::render(const ServiceProvider& service_provider) const { helper::BoolWrapper> ui::TextInput::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { - //TODO: if already has focus, position cursor there, where we clicked + //TODO(Totto): if already has focus, position cursor there, where we clicked if (const auto hover_result = detect_hover(input_manager, event); hover_result) { if (hover_result.is(ActionType::Clicked)) { return { diff --git a/src/ui/components/textinput.hpp b/src/ui/components/textinput.hpp index 74300a5a..0d0924cb 100644 --- a/src/ui/components/textinput.hpp +++ b/src/ui/components/textinput.hpp @@ -59,7 +59,7 @@ namespace ui { void update() override; - //TODO: how to handle text limits (since texture for texts on the gpu can't get unlimitedly big, maybe use software texture?) + //TODO(Totto): how to handle text limits (since texture for texts on the gpu can't get unlimitedly big, maybe use software texture?) void render(const ServiceProvider& service_provider) const override; Widget::EventHandleResult diff --git a/src/ui/layouts/scroll_layout.hpp b/src/ui/layouts/scroll_layout.hpp index 6e672461..3f175da7 100644 --- a/src/ui/layouts/scroll_layout.hpp +++ b/src/ui/layouts/scroll_layout.hpp @@ -67,7 +67,7 @@ namespace ui { Widget::EventHandleResult handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) override; - //TODO: with some template paramater and magic make this an option in the base class, so that only get_layout_for_new needs to be overwritten! + //TODO(Totto): with some template paramater and magic make this an option in the base class, so that only get_layout_for_new needs to be overwritten! template u32 add(ItemSize size, Args... args) { From 1392129db66d03e82d06b88128d3a28c9120ede3 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 01:01:58 +0200 Subject: [PATCH 65/76] clang-tidy: - fix many errors --- .clang-tidy | 6 ++- src/game/game.cpp | 2 +- src/game/grid.cpp | 2 +- src/helper/color.hpp | 74 +++++++++++++++++++---------------- src/helper/color_literals.hpp | 65 ++++++++++++++++-------------- 5 files changed, 82 insertions(+), 67 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 9a892891..50df1337 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -153,9 +153,11 @@ CheckOptions: ## special things, that have special values - key: readability-identifier-length.IgnoredVariableNames - value: "(os)" # ostream + value: "" - key: readability-identifier-length.IgnoredParameterNames - value: "^[n]$" + value: "^(os)$" ## std::ostream + - key: readability-identifier-length.IgnoredExceptionVariableNames + value: "" - key: readability-identifier-length.MinimumLoopCounterNameLength value: 1 - key: readability-identifier-length.MinimumExceptionNameLength diff --git a/src/game/game.cpp b/src/game/game.cpp index 66ab282c..aa7922ec 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -62,7 +62,7 @@ void Game::render(const ServiceProvider& service_provider) const { } [[nodiscard]] helper::BoolWrapper> -Game::handle_event(const std::shared_ptr&, const SDL_Event&) { +Game::handle_event(const std::shared_ptr& /*input_manager*/, const SDL_Event& /*event*/) { return false; } diff --git a/src/game/grid.cpp b/src/game/grid.cpp index aec7056f..942f350c 100644 --- a/src/game/grid.cpp +++ b/src/game/grid.cpp @@ -42,7 +42,7 @@ void Grid::render(const ServiceProvider& service_provider) const { } [[nodiscard]] helper::BoolWrapper> -Grid::handle_event(const std::shared_ptr&, const SDL_Event&) { +Grid::handle_event(const std::shared_ptr& /*input_manager*/, const SDL_Event& /*event*/) { return false; } diff --git a/src/helper/color.hpp b/src/helper/color.hpp index 32163214..e0a4968c 100644 --- a/src/helper/color.hpp +++ b/src/helper/color.hpp @@ -25,11 +25,16 @@ struct HSVColor { u8 a; - constexpr HSVColor(double h, double s, double v, u8 a) // NOLINT(bugprone-easily-swappable-parameters) - : h{ h }, - s{ s }, - v{ v }, - a{ a } { + constexpr HSVColor( + double hue, // NOLINT(bugprone-easily-swappable-parameters) + double saturation, + double value, + u8 alpha + ) + : h{ hue }, + s{ saturation }, + v{ value }, + a{ alpha } { if (utils::is_constant_evaluated()) { @@ -52,7 +57,7 @@ struct HSVColor { } } - constexpr HSVColor(double h, double s, double v) : HSVColor{ h, s, v, 0xFF } { } + constexpr HSVColor(double hue, double saturation, double value) : HSVColor{ hue, saturation, value, 0xFF } { } constexpr HSVColor() : HSVColor{ 0.0, 0.0, 0.0, 0 } { } @@ -69,7 +74,7 @@ struct HSVColor { std::ostream& operator<<(std::ostream& os) const; }; -namespace { +namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) //TODO(Totto): if everything (also libc++ ) supports c++23 , the std functions are constexpr, so we can use them template constexpr T fmod_constexpr(T value, T divisor) { @@ -120,15 +125,15 @@ struct Color { u8 a; - constexpr Color(u8 r, u8 g, u8 b, u8 a) // NOLINT(bugprone-easily-swappable-parameters) - : r{ r }, - g{ g }, - b{ b }, - a{ a } { } + constexpr Color(u8 red, u8 green, u8 blue, u8 alpha) // NOLINT(bugprone-easily-swappable-parameters) + : r{ red }, + g{ green }, + b{ blue }, + a{ alpha } { } constexpr Color() : Color{ 0, 0, 0, 0 } { } - constexpr Color(u8 r, u8 g, u8 b) : Color{ r, g, b, 0xFF } { } + constexpr Color(u8 red, u8 green, u8 blue) : Color{ red, green, blue, 0xFF } { } [[nodiscard]] static helper::expected from_string(const std::string& value); @@ -139,30 +144,31 @@ struct Color { [[nodiscard]] HSVColor to_hsv_color() const; - constexpr Color(const HSVColor& color) { + explicit constexpr Color(const HSVColor& color) { using FloatType = double; //for more precision use "long double" here // taken from https://scratch.mit.edu/discuss/topic/694772/ - const auto h = static_cast(color.h); - const auto s = static_cast(color.s); - const auto v = static_cast(color.v); + auto hue = static_cast(color.h); + const auto saturation = static_cast(color.s); + const auto value = static_cast(color.v); + + const FloatType chroma = value * saturation; - const FloatType chroma = v * s; - FloatType hue = h; if (hue >= static_cast(360.0)) { hue = static_cast(0.0); } - const FloatType x = chroma - * (static_cast(1.0) - - fabs_constexpr( - fmod_constexpr(hue / static_cast(60.0), static_cast(2.0)) - - static_cast(1.0) - )); + const FloatType x_offset = + chroma + * (static_cast(1.0) + - fabs_constexpr( + fmod_constexpr(hue / static_cast(60.0), static_cast(2.0)) + - static_cast(1.0) + )); const u64 index = static_cast(hue / static_cast(60.0)); @@ -173,44 +179,44 @@ struct Color { switch (index) { case 0: d_r = chroma; - d_g = x; + d_g = x_offset; d_b = static_cast(0.0); break; case 1: - d_r = x; + d_r = x_offset; d_g = chroma; d_b = static_cast(0.0); break; case 2: d_r = static_cast(0.0); d_g = chroma; - d_b = x; + d_b = x_offset; break; case 3: d_r = static_cast(0.0); - d_g = x; + d_g = x_offset; d_b = chroma; break; case 4: - d_r = x; + d_r = x_offset; d_g = static_cast(0.0); d_b = chroma; break; case 5: d_r = chroma; d_g = static_cast(0.0); - d_b = x; + d_b = x_offset; break; default: utils::unreachable(); } - const FloatType m = v - chroma; + const FloatType offset = value - chroma; - const auto finish_value = [m](FloatType value) -> u8 { + const auto finish_value = [offset](FloatType value) -> u8 { const auto result = - std::clamp(value + m, static_cast(0.0), static_cast(1.0)) + std::clamp(value + offset, static_cast(0.0), static_cast(1.0)) * static_cast(0xFF); return static_cast(round_constexpr(result)); diff --git a/src/helper/color_literals.hpp b/src/helper/color_literals.hpp index bc1b5411..f5957dc4 100644 --- a/src/helper/color_literals.hpp +++ b/src/helper/color_literals.hpp @@ -8,7 +8,8 @@ #include -namespace { +namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) + namespace const_constants { // offsets in C strings for hex rgb and rgba @@ -22,26 +23,26 @@ namespace { } // namespace const_constants // decode a decimal number - [[nodiscard]] constexpr const_utils::expected single_decimal_number(char n) { - if (n >= '0' && n <= '9') { - return const_utils::expected::good_result(static_cast(n - '0')); + [[nodiscard]] constexpr const_utils::expected single_decimal_number(char input) { + if (input >= '0' && input <= '9') { + return const_utils::expected::good_result(static_cast(input - '0')); } return const_utils::expected::error_result("the input must be a valid decimal character"); } // decode a single_hex_number - [[nodiscard]] constexpr const_utils::expected single_hex_number(char n) { - if (n >= '0' && n <= '9') { - return const_utils::expected::good_result(static_cast(n - '0')); + [[nodiscard]] constexpr const_utils::expected single_hex_number(char input) { + if (input >= '0' && input <= '9') { + return const_utils::expected::good_result(static_cast(input - '0')); } - if (n >= 'A' && n <= 'F') { - return const_utils::expected::good_result(static_cast(n - 'A' + 10)); + if (input >= 'A' && input <= 'F') { + return const_utils::expected::good_result(static_cast(input - 'A' + 10)); } - if (n >= 'a' && n <= 'f') { - return const_utils::expected::good_result(static_cast(n - 'a' + 10)); + if (input >= 'a' && input <= 'f') { + return const_utils::expected::good_result(static_cast(input - 'a' + 10)); } return const_utils::expected::error_result("the input must be a valid hex character"); @@ -204,37 +205,37 @@ namespace { if (size == const_constants::hex_rgb_size) { - const auto r = single_hex_color_value(input + const_constants::red_offset); - PROPAGATE(r, ColorFromHexStringReturnType, std::string); + const auto red = single_hex_color_value(input + const_constants::red_offset); + PROPAGATE(red, ColorFromHexStringReturnType, std::string); - const auto g = single_hex_color_value(input + const_constants::green_offset); - PROPAGATE(g, ColorFromHexStringReturnType, std::string); + const auto green = single_hex_color_value(input + const_constants::green_offset); + PROPAGATE(green, ColorFromHexStringReturnType, std::string); - const auto b = single_hex_color_value(input + const_constants::blue_offset); - PROPAGATE(b, ColorFromHexStringReturnType, std::string); + const auto blue = single_hex_color_value(input + const_constants::blue_offset); + PROPAGATE(blue, ColorFromHexStringReturnType, std::string); return const_utils::expected::good_result({ - Color{ r.value(), g.value(), b.value() }, + Color{ red.value(), green.value(), blue.value() }, false }); } if (size == const_constants::hex_rgba_size) { - const auto r = single_hex_color_value(input + const_constants::red_offset); - PROPAGATE(r, ColorFromHexStringReturnType, std::string); + const auto red = single_hex_color_value(input + const_constants::red_offset); + PROPAGATE(red, ColorFromHexStringReturnType, std::string); - const auto g = single_hex_color_value(input + const_constants::green_offset); - PROPAGATE(g, ColorFromHexStringReturnType, std::string); + const auto green = single_hex_color_value(input + const_constants::green_offset); + PROPAGATE(green, ColorFromHexStringReturnType, std::string); - const auto b = single_hex_color_value(input + const_constants::blue_offset); - PROPAGATE(b, ColorFromHexStringReturnType, std::string); + const auto blue = single_hex_color_value(input + const_constants::blue_offset); + PROPAGATE(blue, ColorFromHexStringReturnType, std::string); - const auto a = single_hex_color_value(input + const_constants::alpha_offset); - PROPAGATE(a, ColorFromHexStringReturnType, std::string); + const auto alpha = single_hex_color_value(input + const_constants::alpha_offset); + PROPAGATE(alpha, ColorFromHexStringReturnType, std::string); return const_utils::expected::good_result({ - Color{ r.value(), g.value(), b.value(), a.value() }, + Color{ red.value(), green.value(), blue.value(), alpha.value() }, true }); } @@ -247,7 +248,10 @@ namespace { using ColorFromRGBStringReturnType = std::pair; [[nodiscard]] constexpr const_utils::expected - get_color_from_rgb_string(const char* input, std::size_t) { + get_color_from_rgb_string( //NOLINT(readability-function-cognitive-complexity) + const char* input, + std::size_t /*unused*/ + ) { if (input[0] == 'r' && input[1] == 'g' && input[2] == 'b') { if (input[3] == '(') { @@ -415,7 +419,10 @@ namespace { using ColorFromHSVStringReturnType = std::pair; [[nodiscard]] constexpr const_utils::expected - get_color_from_hsv_string(const char* input, std::size_t) { + get_color_from_hsv_string( //NOLINT(readability-function-cognitive-complexity) + const char* input, + std::size_t /*unused*/ + ) { if (input[0] == 'h' && input[1] == 's' && input[2] == 'v') { if (input[3] == '(') { From a72503c8365caaab372f5cdbb881046b2711df7d Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 01:22:30 +0200 Subject: [PATCH 66/76] clang-tidy: - fix more errors --- src/helper/color.hpp | 2 +- src/input/game_input.hpp | 4 +-- src/input/guid.cpp | 8 +++--- src/input/guid.hpp | 50 ++++++++++++++++++------------------ src/input/joystick_input.cpp | 14 +++++----- src/input/joystick_input.hpp | 14 +++++----- 6 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/helper/color.hpp b/src/helper/color.hpp index e0a4968c..2b0a2a6a 100644 --- a/src/helper/color.hpp +++ b/src/helper/color.hpp @@ -144,7 +144,7 @@ struct Color { [[nodiscard]] HSVColor to_hsv_color() const; - explicit constexpr Color(const HSVColor& color) { + constexpr Color(const HSVColor& color) { //NOLINT(google-explicit-constructor) using FloatType = double; //for more precision use "long double" here diff --git a/src/input/game_input.hpp b/src/input/game_input.hpp index 086cebe6..fdedb3e2 100644 --- a/src/input/game_input.hpp +++ b/src/input/game_input.hpp @@ -50,13 +50,13 @@ namespace input { Tetrion* m_target_tetrion{}; OnEventCallback m_on_event_callback{}; - GameInput(GameInputType input_type) : m_input_type{ input_type } { } + explicit GameInput(GameInputType input_type) : m_input_type{ input_type } { } void handle_event(InputEvent event, SimulationStep simulation_step_index); public: virtual void update(SimulationStep simulation_step_index); - virtual void late_update(SimulationStep){}; + virtual void late_update(SimulationStep /*simulation_step*/){}; [[nodiscard]] virtual helper::optional get_menu_event(const SDL_Event& event) const = 0; diff --git a/src/input/guid.cpp b/src/input/guid.cpp index 5862510b..67014565 100644 --- a/src/input/guid.cpp +++ b/src/input/guid.cpp @@ -5,11 +5,11 @@ #include #include -SDL::GUID::GUID(const SDL_GUID& data) : m_guid{} { +sdl::GUID::GUID(const SDL_GUID& data) : m_guid{} { std::copy(std::begin(data.data), std::end(data.data), std::begin(m_guid)); } -[[nodiscard]] helper::expected SDL::GUID::from_string(const std::string& value) { +[[nodiscard]] helper::expected sdl::GUID::from_string(const std::string& value) { const auto result = detail::get_guid_from_string(value); @@ -20,12 +20,12 @@ SDL::GUID::GUID(const SDL_GUID& data) : m_guid{} { return helper::unexpected{ result.error() }; } -[[nodiscard]] bool SDL::GUID::operator==(const GUID& other) const { +[[nodiscard]] bool sdl::GUID::operator==(const GUID& other) const { return m_guid == other.m_guid; } -[[nodiscard]] std::string SDL::GUID::to_string(FormatType type) const { +[[nodiscard]] std::string sdl::GUID::to_string(FormatType type) const { switch (type) { case FormatType::Long: { return fmt::format("{:02x}", fmt::join(m_guid, ":")); diff --git a/src/input/guid.hpp b/src/input/guid.hpp index 9b90b63f..04d4b370 100644 --- a/src/input/guid.hpp +++ b/src/input/guid.hpp @@ -17,7 +17,7 @@ typedef SDL_JoystickGUID SDL_GUID; //NOLINT(modernize-use-using), it's used in e } -namespace SDL { +namespace sdl { struct GUID { public: @@ -27,12 +27,12 @@ namespace SDL { ArrayType m_guid; public: - enum class FormatType { Long, Short }; + enum class FormatType : u8 { Long, Short }; constexpr GUID() : m_guid{} { } - constexpr GUID(const ArrayType& data) : m_guid{ data } { } + explicit constexpr GUID(const ArrayType& data) : m_guid{ data } { } - GUID(const SDL_GUID& data); + explicit GUID(const SDL_GUID& data); [[nodiscard]] static helper::expected from_string(const std::string& value); @@ -40,30 +40,30 @@ namespace SDL { [[nodiscard]] std::string to_string(FormatType type = FormatType::Long) const; }; -} // namespace SDL +} // namespace sdl template<> -struct fmt::formatter : formatter { - auto format(const SDL::GUID& guid, format_context& ctx) { +struct fmt::formatter : formatter { + auto format(const sdl::GUID& guid, format_context& ctx) { return formatter::format(guid.to_string(), ctx); } }; -namespace { +namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) // decode a single_hex_number - [[nodiscard]] constexpr const_utils::expected single_hex_number(char n) { - if (n >= '0' && n <= '9') { - return const_utils::expected::good_result(static_cast(n - '0')); + [[nodiscard]] constexpr const_utils::expected single_hex_number(char input) { + if (input >= '0' && input <= '9') { + return const_utils::expected::good_result(static_cast(input - '0')); } - if (n >= 'A' && n <= 'F') { - return const_utils::expected::good_result(static_cast(n - 'A' + 10)); + if (input >= 'A' && input <= 'F') { + return const_utils::expected::good_result(static_cast(input - 'A' + 10)); } - if (n >= 'a' && n <= 'f') { - return const_utils::expected::good_result(static_cast(n - 'a' + 10)); + if (input >= 'a' && input <= 'f') { + return const_utils::expected::good_result(static_cast(input - 'a' + 10)); } return const_utils::expected::error_result("the input must be a valid hex character"); @@ -72,22 +72,22 @@ namespace { // decode a single 2 digit color value in hex [[nodiscard]] constexpr const_utils::expected single_hex_color_value(const char* input) { - const auto first = single_hex_number(input[0]); + const auto first = single_hex_number(input[0]); //NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) PROPAGATE(first, u8, std::string); - const auto second = single_hex_number(input[1]); + const auto second = single_hex_number(input[1]); //NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) PROPAGATE(second, u8, std::string); return const_utils::expected::good_result((first.value() << 4) | second.value()); } - [[nodiscard]] constexpr const_utils::expected + [[nodiscard]] constexpr const_utils::expected get_guid_from_string_impl(const char* input, std::size_t size) { if (size == 0) { - return const_utils::expected::error_result( + return const_utils::expected::error_result( "not enough data to determine the literal type" ); } @@ -102,11 +102,11 @@ namespace { width = 3; } else { - return const_utils::expected::error_result("Unrecognized guid literal"); + return const_utils::expected::error_result("Unrecognized guid literal"); } - SDL::GUID::ArrayType result{}; + sdl::GUID::ArrayType result{}; for (size_t i = 0; i < amount; ++i) { size_t offset = i * (width); @@ -115,14 +115,14 @@ namespace { const auto temp_result = single_hex_color_value(input + offset); //NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) - PROPAGATE(temp_result, SDL::GUID, std::string); + PROPAGATE(temp_result, sdl::GUID, std::string); const auto value = temp_result.value(); result.at(i) = value; } - return const_utils::expected::good_result(SDL::GUID{ result }); + return const_utils::expected::good_result(sdl::GUID{ result }); } } // namespace @@ -130,7 +130,7 @@ namespace { namespace detail { - [[nodiscard]] constexpr const_utils::expected get_guid_from_string(const std::string& input + [[nodiscard]] constexpr const_utils::expected get_guid_from_string(const std::string& input ) { return get_guid_from_string_impl(input.c_str(), input.size()); } @@ -138,7 +138,7 @@ namespace detail { } // namespace detail -consteval SDL::GUID operator""_guid(const char* input, std::size_t size) { +consteval sdl::GUID operator""_guid(const char* input, std::size_t size) { const auto result = get_guid_from_string_impl(input, size); CONSTEVAL_STATIC_ASSERT(result.has_value(), "incorrect guid literal"); diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 20babddc..4dbe2f07 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -23,7 +23,7 @@ input::JoystickInput::~JoystickInput() { [[nodiscard]] helper::optional> input::JoystickInput::get_joystick_by_guid( - const SDL::GUID& guid, + const sdl::GUID& guid, SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name @@ -78,9 +78,9 @@ input::JoystickInput::get_by_device_index(int device_index) { } - const auto guid = SDL::GUID{ SDL_JoystickGetGUID(joystick) }; + const auto guid = sdl::GUID{ SDL_JoystickGetGUID(joystick) }; - if (guid == SDL::GUID{}) { + if (guid == sdl::GUID{}) { return helper::unexpected{ fmt::format("Failed to get joystick GUID: {}", SDL_GetError()) }; } @@ -99,10 +99,10 @@ input::JoystickInput::get_by_device_index(int device_index) { return m_instance_id; } -[[nodiscard]] SDL::GUID input::JoystickInput::guid() const { - const auto guid = SDL::GUID{ SDL_JoystickGetGUID(m_joystick) }; +[[nodiscard]] sdl::GUID input::JoystickInput::guid() const { + const auto guid = sdl::GUID{ SDL_JoystickGetGUID(m_joystick) }; - if (guid == SDL::GUID{}) { + if (guid == sdl::GUID{}) { throw std::runtime_error{ fmt::format("Failed to get joystick GUID: {}", SDL_GetError()) }; } @@ -572,7 +572,7 @@ void input::JoystickGameInput::update(SimulationStep simulation_step_index) { namespace { [[nodiscard]] helper::optional> get_game_joystick_by_guid( - const SDL::GUID& guid, + const sdl::GUID& guid, const input::JoystickSettings& settings, EventDispatcher* event_dispatcher, input::JoystickInput* underlying_input diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index b5fcb572..97c0b55e 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -19,7 +19,7 @@ namespace input { // essentially a GUID struct JoystickIdentification { - SDL::GUID guid; + sdl::GUID guid; std::string name; //optional (can be ""), just for human readable settings @@ -68,7 +68,7 @@ namespace input { SDL_JoystickID m_instance_id; [[nodiscard]] static helper::optional> get_joystick_by_guid( - const SDL::GUID& guid, + const sdl::GUID& guid, SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name @@ -84,7 +84,7 @@ namespace input { [[nodiscard]] SDL_JoystickID instance_id() const; - [[nodiscard]] SDL::GUID guid() const; + [[nodiscard]] sdl::GUID guid() const; [[nodiscard]] virtual JoystickSettings default_settings() const = 0; @@ -144,7 +144,7 @@ namespace input { #if defined(__SWITCH__) struct SwitchJoystickInput_Type1 : ConsoleJoystickInput { //TODO - static constexpr SDL::GUID guid{}; + static constexpr sdl::GUID guid{}; SwitchJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; @@ -166,8 +166,8 @@ namespace input { struct _3DSJoystickInput_Type1 : ConsoleJoystickInput { //TODO - static constexpr SDL::GUID guid{ - SDL::GUID::ArrayType{ 0x00, 0x00, 0x10, 0x32, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f, 0x20, 0x33, + static constexpr sdl::GUID guid{ + sdl::GUID::ArrayType{ 0x00, 0x00, 0x10, 0x32, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f, 0x20, 0x33, 0x44, 0x00 } }; _3DSJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); @@ -325,7 +325,7 @@ namespace nlohmann { context.get_to(input); - const auto& value = SDL::GUID::from_string(input); + const auto& value = sdl::GUID::from_string(input); if (not value.has_value()) { throw nlohmann::json::type_error::create( From 4bd7b8d0d915baac465aeb9372adea46f1b363cc Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 01:27:26 +0200 Subject: [PATCH 67/76] clang-tidy: - fix more errors --- src/manager/settings_manager.hpp | 49 ++++++++++--------- .../single_player_game/single_player_game.cpp | 6 ++- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/manager/settings_manager.hpp b/src/manager/settings_manager.hpp index b4bfc93c..365eb794 100644 --- a/src/manager/settings_manager.hpp +++ b/src/manager/settings_manager.hpp @@ -14,34 +14,39 @@ using Controls = std::variant struct adl_serializer { - static Controls from_json(const json& j) { - const auto& type = j.at("type"); + static Controls from_json(const json& obj) { + const auto& type = obj.at("type"); if (type == "keyboard") { - return Controls{ nlohmann::adl_serializer::from_json(j) }; - } else if (type == "joystick") { - return Controls{ nlohmann::adl_serializer::from_json(j) }; - } else if (type == "touch") { - return Controls{ nlohmann::adl_serializer::from_json(j) }; - } else { - throw std::runtime_error{ fmt::format("unsupported control type '{}'", to_string(type)) }; + return Controls{ nlohmann::adl_serializer::from_json(obj) }; } + + if (type == "joystick") { + return Controls{ nlohmann::adl_serializer::from_json(obj) }; + } + + if (type == "touch") { + return Controls{ nlohmann::adl_serializer::from_json(obj) }; + } + + throw std::runtime_error{ fmt::format("unsupported control type '{}'", to_string(type)) }; } - static void to_json(json& j, Controls controls) { + static void to_json(json& obj, Controls controls) { // NOLINT(misc-no-recursion) std::visit( - helper::overloaded{ [&](const input::KeyboardSettings& keyboard_settings) { - to_json(j, keyboard_settings); - j["type"] = "keyboard"; - }, - [&](const input::JoystickSettings& joystick_settings) { - to_json(j, joystick_settings); - j["type"] = "joystick"; - }, - [&](const input::TouchSettings& touch_settings) { - to_json(j, touch_settings); - j["type"] = "touch"; - } }, + helper::overloaded{ + [&](const input::KeyboardSettings& keyboard_settings) { // NOLINT(misc-no-recursion) + to_json(obj, keyboard_settings); + obj["type"] = "keyboard"; + }, + [&](const input::JoystickSettings& joystick_settings) { // NOLINT(misc-no-recursion) + to_json(obj, joystick_settings); + obj["type"] = "joystick"; + }, + [&](const input::TouchSettings& touch_settings) { // NOLINT(misc-no-recursion) + to_json(obj, touch_settings); + obj["type"] = "touch"; + } }, controls ); } diff --git a/src/scenes/single_player_game/single_player_game.cpp b/src/scenes/single_player_game/single_player_game.cpp index 29660fe7..65eac687 100644 --- a/src/scenes/single_player_game/single_player_game.cpp +++ b/src/scenes/single_player_game/single_player_game.cpp @@ -104,8 +104,10 @@ namespace scenes { m_game->render(service_provider); } - [[nodiscard]] bool - SinglePlayerGame::handle_event(const std::shared_ptr&, const SDL_Event& event) { + [[nodiscard]] bool SinglePlayerGame::handle_event( + const std::shared_ptr& /*input_manager*/, + const SDL_Event& event + ) { const auto& game_input = m_game->game_input(); From 96bef6fde1b4f4e775b0f03d8b34740200421d2f Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 01:50:36 +0200 Subject: [PATCH 68/76] input: console: - add support for switch joystick, by adding the guid - also add guid and name in default settings --- settings.json | 18 ++++++++++++++ src/input/joystick_input.cpp | 46 ++++++++++++++++++++---------------- src/input/joystick_input.hpp | 7 +++--- 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/settings.json b/settings.json index 02558b4b..b6cc3ad0 100644 --- a/settings.json +++ b/settings.json @@ -34,6 +34,24 @@ "open_settings": "SELECT" } }, + { + "type": "joystick", + "identification": { + "guid": "00:00:38:f8:53:77:69:74:63:68:20:43:6f:6e:74:00", + "name": "Switch Controller" + }, + "drop": "X", + "hold": "B", + "move_down": "LPAD_DOWN", + "move_left": "LPAD_LEFT", + "move_right": "LPAD_RIGHT", + "rotate_left": "DPAD_LEFT", + "rotate_right": "DPAD_RIGHT", + "menu": { + "pause": "MINUS", + "open_settings": "PLUS" + } + }, { "type": "touch", "move_x_threshold": 0.07, diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 4dbe2f07..1a3e9fc5 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -376,16 +376,19 @@ input::SwitchJoystickInput_Type1::SwitchJoystickInput_Type1( [[nodiscard]] input::AbstractJoystickSettings input::SwitchJoystickInput_Type1::default_settings_raw() const { const AbstractJoystickSettings settings = // - { .identification = JoystickIdentification{}, - .rotate_left = JOYCON_DPAD_LEFT, - .rotate_right = JOYCON_DPAD_RIGHT, - .move_left = JOYCON_LDPAD_LEFT, - .move_right = JOYCON_LDPAD_RIGHT, - .move_down = JOYCON_LDPAD_DOWN, - .drop = JOYCON_X, - .hold = JOYCON_B, - .pause = JOYCON_MINUS, - .open_settings = JOYCON_PLUS }; + { + .identification = + JoystickIdentification{ .guid = SwitchJoystickInput_Type1::guid, .name = "Switch Controller" }, + .rotate_left = JOYCON_DPAD_LEFT, + .rotate_right = JOYCON_DPAD_RIGHT, + .move_left = JOYCON_LDPAD_LEFT, + .move_right = JOYCON_LDPAD_RIGHT, + .move_down = JOYCON_LDPAD_DOWN, + .drop = JOYCON_X, + .hold = JOYCON_B, + .pause = JOYCON_MINUS, + .open_settings = JOYCON_PLUS + }; return settings; } @@ -534,16 +537,19 @@ input::_3DSJoystickInput_Type1::_3DSJoystickInput_Type1( [[nodiscard]] input::AbstractJoystickSettings input::_3DSJoystickInput_Type1::default_settings_raw() const { const AbstractJoystickSettings settings = // - { .identification = JoystickIdentification{}, - .rotate_left = JOYCON_L, - .rotate_right = JOYCON_R, - .move_left = JOYCON_DPAD_LEFT, - .move_right = JOYCON_DPAD_RIGHT, - .move_down = JOYCON_DPAD_DOWN, - .drop = JOYCON_X, - .hold = JOYCON_B, - .pause = JOYCON_START, - .open_settings = JOYCON_SELECT }; + { + .identification = + JoystickIdentification{ .guid = _3DSJoystickInput_Type1::guid, .name = "Nintendo 3DS" }, + .rotate_left = JOYCON_L, + .rotate_right = JOYCON_R, + .move_left = JOYCON_DPAD_LEFT, + .move_right = JOYCON_DPAD_RIGHT, + .move_down = JOYCON_DPAD_DOWN, + .drop = JOYCON_X, + .hold = JOYCON_B, + .pause = JOYCON_START, + .open_settings = JOYCON_SELECT + }; return settings; } diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index 97c0b55e..a0a0dc71 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -143,8 +143,10 @@ namespace input { #if defined(__SWITCH__) struct SwitchJoystickInput_Type1 : ConsoleJoystickInput { - //TODO - static constexpr sdl::GUID guid{}; + static constexpr sdl::GUID guid{ + sdl::GUID::ArrayType{ 0x00, 0x00, 0x38, 0xf8, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x20, 0x43, 0x6f, 0x6e, + 0x74, 0x00 } + }; SwitchJoystickInput_Type1(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); [[nodiscard]] helper::optional get_navigation_event(const SDL_Event& event) const override; @@ -165,7 +167,6 @@ namespace input { struct _3DSJoystickInput_Type1 : ConsoleJoystickInput { - //TODO static constexpr sdl::GUID guid{ sdl::GUID::ArrayType{ 0x00, 0x00, 0x10, 0x32, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f, 0x20, 0x33, 0x44, 0x00 } From cf604f865da621dbd112b20e5167a2e6a1dc7a74 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 02:26:35 +0200 Subject: [PATCH 69/76] clang-tidy: - fix more errors --- .clang-tidy | 2 +- src/helper/color_literals.hpp | 158 +++++++++--------- src/helper/const_utils.hpp | 30 ++-- src/helper/nfd.cpp | 8 +- src/helper/platform.cpp | 2 +- src/input/game_input.hpp | 16 +- src/input/guid.hpp | 24 +-- src/input/joystick_input.cpp | 8 +- src/input/keyboard_input.cpp | 8 +- src/input/replay_input.cpp | 8 +- src/input/touch_input.cpp | 6 +- src/scenes/replay_game/replay_game.cpp | 4 +- src/scenes/settings_menu/settings_menu.cpp | 2 +- src/scenes/single_player_game/pause.cpp | 4 +- .../single_player_game/single_player_game.cpp | 4 +- 15 files changed, 148 insertions(+), 136 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 50df1337..f7a36a5d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -127,7 +127,7 @@ CheckOptions: - key: readability-identifier-naming.UnionCase value: "CamelCase" - key: readability-identifier-naming.ValueTemplateParameterCase - value: "lower_case" + value: "CamelCase" - key: readability-identifier-naming.VariableCase value: "lower_case" - key: readability-identifier-naming.VirtualMethodCase diff --git a/src/helper/color_literals.hpp b/src/helper/color_literals.hpp index f5957dc4..8d0f5cee 100644 --- a/src/helper/color_literals.hpp +++ b/src/helper/color_literals.hpp @@ -23,36 +23,36 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) } // namespace const_constants // decode a decimal number - [[nodiscard]] constexpr const_utils::expected single_decimal_number(char input) { + [[nodiscard]] constexpr const_utils::Expected single_decimal_number(char input) { if (input >= '0' && input <= '9') { - return const_utils::expected::good_result(static_cast(input - '0')); + return const_utils::Expected::good_result(static_cast(input - '0')); } - return const_utils::expected::error_result("the input must be a valid decimal character"); + return const_utils::Expected::error_result("the input must be a valid decimal character"); } // decode a single_hex_number - [[nodiscard]] constexpr const_utils::expected single_hex_number(char input) { + [[nodiscard]] constexpr const_utils::Expected single_hex_number(char input) { if (input >= '0' && input <= '9') { - return const_utils::expected::good_result(static_cast(input - '0')); + return const_utils::Expected::good_result(static_cast(input - '0')); } if (input >= 'A' && input <= 'F') { - return const_utils::expected::good_result(static_cast(input - 'A' + 10)); + return const_utils::Expected::good_result(static_cast(input - 'A' + 10)); } if (input >= 'a' && input <= 'f') { - return const_utils::expected::good_result(static_cast(input - 'a' + 10)); + return const_utils::Expected::good_result(static_cast(input - 'a' + 10)); } - return const_utils::expected::error_result("the input must be a valid hex character"); + return const_utils::Expected::error_result("the input must be a valid hex character"); } //NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) // decode a single 2 digit color value in hex - [[nodiscard]] constexpr const_utils::expected single_hex_color_value(const char* input) { + [[nodiscard]] constexpr const_utils::Expected single_hex_color_value(const char* input) { const auto first = single_hex_number(input[0]); @@ -62,7 +62,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) PROPAGATE(second, u8, std::string); - return const_utils::expected::good_result((first.value() << 4) | second.value()); + return const_utils::Expected::good_result((first.value() << 4) | second.value()); } template @@ -71,7 +71,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) using DoubleReturnValue = CharIteratorResult; // decode a single color value as double - [[nodiscard]] constexpr const_utils::expected single_double_color_value( + [[nodiscard]] constexpr const_utils::Expected single_double_color_value( const char* value ) { @@ -89,7 +89,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) break; case '.': if (after_comma) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "only one comma allowed" ); } @@ -97,9 +97,9 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) break; case ',': case ')': - return const_utils::expected::good_result({ result, value + i }); + return const_utils::Expected::good_result({ result, value + i }); case '\0': - return const_utils::expected::error_result("input ended too early"); + return const_utils::Expected::error_result("input ended too early"); default: { const auto char_result = single_decimal_number(current_char); @@ -119,7 +119,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) } } - return const_utils::expected::error_result("unreachable"); + return const_utils::Expected::error_result("unreachable"); } using AnySizeType = u32; @@ -127,7 +127,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) using AnyColorReturnValue = CharIteratorResult; // decode a single_hex_number - [[nodiscard]] constexpr const_utils::expected single_color_value_any( + [[nodiscard]] constexpr const_utils::Expected single_color_value_any( const char* value ) { @@ -164,9 +164,9 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) break; case ',': case ')': - return const_utils::expected::good_result({ result, value + i }); + return const_utils::Expected::good_result({ result, value + i }); case '\0': - return const_utils::expected::error_result("input ended too early" + return const_utils::Expected::error_result("input ended too early" ); default: { @@ -179,12 +179,12 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) if (result == max_value_before_multiplication && value_of_char > max_value_before_multiplication_rest) { - return const_utils::expected::error_result("overflow detected" + return const_utils::Expected::error_result("overflow detected" ); } if (result > max_value_before_multiplication) { - return const_utils::expected::error_result("overflow detected" + return const_utils::Expected::error_result("overflow detected" ); } @@ -195,12 +195,12 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) } } - return const_utils::expected::error_result("unreachable"); + return const_utils::Expected::error_result("unreachable"); } using ColorFromHexStringReturnType = std::pair; - [[nodiscard]] constexpr const_utils::expected + [[nodiscard]] constexpr const_utils::Expected get_color_from_hex_string(const char* input, std::size_t size) { if (size == const_constants::hex_rgb_size) { @@ -214,7 +214,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto blue = single_hex_color_value(input + const_constants::blue_offset); PROPAGATE(blue, ColorFromHexStringReturnType, std::string); - return const_utils::expected::good_result({ + return const_utils::Expected::good_result({ Color{ red.value(), green.value(), blue.value() }, false }); @@ -234,20 +234,20 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto alpha = single_hex_color_value(input + const_constants::alpha_offset); PROPAGATE(alpha, ColorFromHexStringReturnType, std::string); - return const_utils::expected::good_result({ + return const_utils::Expected::good_result({ Color{ red.value(), green.value(), blue.value(), alpha.value() }, true }); } - return const_utils::expected::error_result("Unrecognized HEX literal" + return const_utils::Expected::error_result("Unrecognized HEX literal" ); } using ColorFromRGBStringReturnType = std::pair; - [[nodiscard]] constexpr const_utils::expected + [[nodiscard]] constexpr const_utils::Expected get_color_from_rgb_string( //NOLINT(readability-function-cognitive-complexity) const char* input, std::size_t /*unused*/ @@ -263,13 +263,13 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [r, next_g] = r_result.value(); if (r > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "r has to be in range 0 - 255" ); } if (*next_g != ',') { - return const_utils::expected::error_result("expected ','" + return const_utils::Expected::error_result("expected ','" ); } @@ -281,13 +281,13 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [g, next_b] = g_result.value(); if (g > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "g has to be in range 0 - 255" ); } if (*next_b != ',') { - return const_utils::expected::error_result("expected ','" + return const_utils::Expected::error_result("expected ','" ); } @@ -299,24 +299,24 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [b, end] = b_result.value(); if (b > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "b has to be in range 0 - 255" ); } if (*end != ')') { - return const_utils::expected::error_result("expected ')'" + return const_utils::Expected::error_result("expected ')'" ); } if (*(end + 1) != '\0') { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "expected end of string" ); } - return const_utils::expected::good_result({ + return const_utils::Expected::good_result({ Color{ static_cast(r), static_cast(g), static_cast(b) }, false }); @@ -332,13 +332,13 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [r, next_g] = r_result.value(); if (r > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "r has to be in range 0 - 255" ); } if (*next_g != ',') { - return const_utils::expected::error_result("expected ','" + return const_utils::Expected::error_result("expected ','" ); } @@ -350,13 +350,13 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [g, next_b] = g_result.value(); if (g > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "g has to be in range 0 - 255" ); } if (*next_b != ',') { - return const_utils::expected::error_result("expected ','" + return const_utils::Expected::error_result("expected ','" ); } @@ -368,13 +368,13 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [b, next_a] = b_result.value(); if (b > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "b has to be in range 0 - 255" ); } if (*next_a != ',') { - return const_utils::expected::error_result("expected ','" + return const_utils::Expected::error_result("expected ','" ); } @@ -385,25 +385,25 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [a, end] = a_result.value(); if (a > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "a has to be in range 0 - 255" ); } if (*end != ')') { - return const_utils::expected::error_result("expected ')'" + return const_utils::Expected::error_result("expected ')'" ); } if (*(end + 1) != '\0') { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "expected end of string" ); } - return const_utils::expected::good_result({ + return const_utils::Expected::good_result({ Color{ static_cast(r), static_cast(g), static_cast(b), static_cast(a) }, true } @@ -412,13 +412,13 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) } - return const_utils::expected::error_result("Unrecognized RGB literal" + return const_utils::Expected::error_result("Unrecognized RGB literal" ); } using ColorFromHSVStringReturnType = std::pair; - [[nodiscard]] constexpr const_utils::expected + [[nodiscard]] constexpr const_utils::Expected get_color_from_hsv_string( //NOLINT(readability-function-cognitive-complexity) const char* input, std::size_t /*unused*/ @@ -434,13 +434,13 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [h, next_s] = h_result.value(); if (h < 0.0 || h > 360.0) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "h has to be in range 0.0 - 360.0" ); } if (*next_s != ',') { - return const_utils::expected::error_result("expected ','" + return const_utils::Expected::error_result("expected ','" ); } @@ -452,13 +452,13 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [s, next_v] = s_result.value(); if (s < 0.0 || s > 1.0) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "s has to be in range 0.0 - 1.0" ); } if (*next_v != ',') { - return const_utils::expected::error_result("expected ','" + return const_utils::Expected::error_result("expected ','" ); } @@ -470,24 +470,24 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [v, end] = v_result.value(); if (v < 0.0 || v > 1.0) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "v has to be in range 0.0 - 1.0" ); } if (*end != ')') { - return const_utils::expected::error_result("expected ')'" + return const_utils::Expected::error_result("expected ')'" ); } if (*(end + 1) != '\0') { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "expected end of string" ); } - return const_utils::expected::good_result({ + return const_utils::Expected::good_result({ HSVColor{ h, s, v }, false }); @@ -503,13 +503,13 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [h, next_s] = h_result.value(); if (h < 0.0 || h > 360.0) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "h has to be in range 0.0 - 360.0" ); } if (*next_s != ',') { - return const_utils::expected::error_result("expected ','" + return const_utils::Expected::error_result("expected ','" ); } @@ -521,13 +521,13 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [s, next_v] = s_result.value(); if (s < 0.0 || s > 1.0) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "s has to be in range 0.0 - 1.0" ); } if (*next_v != ',') { - return const_utils::expected::error_result("expected ','" + return const_utils::Expected::error_result("expected ','" ); } @@ -539,13 +539,13 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [v, next_a] = v_result.value(); if (v < 0.0 || v > 1.0) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "v has to be in range 0.0 - 1.0" ); } if (*next_a != ',') { - return const_utils::expected::error_result("expected ','" + return const_utils::Expected::error_result("expected ','" ); } @@ -556,25 +556,25 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto [a, end] = a_result.value(); if (a > std::numeric_limits::max()) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "a has to be in range 0 - 255" ); } if (*end != ')') { - return const_utils::expected::error_result("expected ')'" + return const_utils::Expected::error_result("expected ')'" ); } if (*(end + 1) != '\0') { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "expected end of string" ); } - return const_utils::expected::good_result({ + return const_utils::Expected::good_result({ HSVColor{ h, s, v, static_cast(a) }, true }); @@ -582,17 +582,17 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) } - return const_utils::expected::error_result("Unrecognized HSV literal" + return const_utils::Expected::error_result("Unrecognized HSV literal" ); } using ColorFromStringReturnType = std::tuple; - [[nodiscard]] constexpr const_utils::expected + [[nodiscard]] constexpr const_utils::Expected get_color_from_string_impl(const char* input, std::size_t size) { if (size == 0) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "not enough data to determine the literal type" ); } @@ -606,7 +606,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto value = result.value(); - return const_utils::expected::good_result( + return const_utils::Expected::good_result( { value.first, color::SerializeMode::Hex, value.second } ); } @@ -618,7 +618,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto value = result.value(); - return const_utils::expected::good_result( + return const_utils::Expected::good_result( { value.first, color::SerializeMode::RGB, value.second } ); } @@ -630,12 +630,12 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto value = result.value(); - return const_utils::expected::good_result( + return const_utils::Expected::good_result( { Color{ value.first }, color::SerializeMode::HSV, value.second } ); } default: - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "Unrecognized color literal" ); } @@ -643,11 +643,11 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) using HSVColorFromStringReturnType = std::tuple; - [[nodiscard]] constexpr const_utils::expected + [[nodiscard]] constexpr const_utils::Expected get_hsv_color_from_string_impl(const char* input, std::size_t size) { if (size == 0) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "not enough data to determine the literal type" ); } @@ -660,7 +660,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto value = result.value(); - return const_utils::expected::good_result( + return const_utils::Expected::good_result( { value.first.to_hsv_color(), color::SerializeMode::Hex, value.second } ); } @@ -671,7 +671,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto value = result.value(); - return const_utils::expected::good_result( + return const_utils::Expected::good_result( { value.first.to_hsv_color(), color::SerializeMode::RGB, value.second } ); } @@ -682,12 +682,12 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) const auto value = result.value(); - return const_utils::expected::good_result( + return const_utils::Expected::good_result( { value.first, color::SerializeMode::HSV, value.second } ); } default: - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "Unrecognized color literal" ); } @@ -699,13 +699,13 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) namespace detail { - [[nodiscard]] constexpr const_utils::expected get_color_from_string( + [[nodiscard]] constexpr const_utils::Expected get_color_from_string( const std::string& input ) { return get_color_from_string_impl(input.c_str(), input.size()); } - [[nodiscard]] constexpr const_utils::expected get_hsv_color_from_string( + [[nodiscard]] constexpr const_utils::Expected get_hsv_color_from_string( const std::string& input ) { return get_hsv_color_from_string_impl(input.c_str(), input.size()); diff --git a/src/helper/const_utils.hpp b/src/helper/const_utils.hpp index 232399e9..0dda909b 100644 --- a/src/helper/const_utils.hpp +++ b/src/helper/const_utils.hpp @@ -28,13 +28,13 @@ s*/ }()) #endif -#define CONSTEVAL_STATIC_ASSERT(CHECK, MSG) \ - do { /*NOLINT(cppcoreguidelines-avoid-do-while)*/ \ - if (utils::is_constant_evaluated()) { \ - CONSTEVAL_ONLY_STATIC_ASSERT(CHECK, MSG); \ - } else { \ - assert(CHECK&& MSG); \ - } \ +#define CONSTEVAL_STATIC_ASSERT(CHECK, MSG) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ + do { /*NOLINT(cppcoreguidelines-avoid-do-while)*/ \ + if (utils::is_constant_evaluated()) { \ + CONSTEVAL_ONLY_STATIC_ASSERT(CHECK, MSG); \ + } else { \ + assert((CHECK) && (MSG)); \ + } \ } while (false) @@ -44,20 +44,20 @@ namespace const_utils { #define PROPAGATE(val, V, E) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ do { /*NOLINT(cppcoreguidelines-avoid-do-while)*/ \ if (not((val).has_value())) { \ - return const_utils::expected::error_result((val).error()); \ + return const_utils::Expected::error_result((val).error()); \ } \ } while (false) - // represents a sort of constexpr std::expected + // represents a sort of constexpr std::Expected template requires std::is_default_constructible_v && std::is_default_constructible_v - struct expected { + struct Expected { private: bool m_has_value; V m_value; E m_error; - constexpr expected( + constexpr Expected( bool has_value, const V& value, const E& error @@ -67,11 +67,11 @@ namespace const_utils { m_error{ error } { } public: - [[nodiscard]] constexpr static expected good_result(const V& type) { + [[nodiscard]] constexpr static Expected good_result(const V& type) { return { true, type, E{} }; } - [[nodiscard]] constexpr static expected error_result(const E& error) { + [[nodiscard]] constexpr static Expected error_result(const E& error) { return { false, V{}, error }; } @@ -80,13 +80,13 @@ namespace const_utils { } [[nodiscard]] constexpr V value() const { - CONSTEVAL_STATIC_ASSERT((has_value()), "value() call on expected without value"); + CONSTEVAL_STATIC_ASSERT((has_value()), "value() call on Expected without value"); return m_value; } [[nodiscard]] constexpr E error() const { - CONSTEVAL_STATIC_ASSERT((not has_value()), "error() call on expected without error"); + CONSTEVAL_STATIC_ASSERT((not has_value()), "error() call on Expected without error"); return m_error; } diff --git a/src/helper/nfd.cpp b/src/helper/nfd.cpp index d31aa19c..a840f498 100644 --- a/src/helper/nfd.cpp +++ b/src/helper/nfd.cpp @@ -73,7 +73,7 @@ helper::expected helper::openFileDialog( ) { NFD::UniquePathU8 out_path{}; - auto filterItem = get_filter_items(allowed_files); + auto filter_item = get_filter_items(allowed_files); const auto path_deallocator = [](const nfdu8char_t* const char_value) { if (char_value == nullptr) { @@ -93,7 +93,7 @@ helper::expected helper::openFileDialog( } const nfdresult_t result = NFD::OpenDialog( - out_path, filterItem.get(), static_cast(allowed_files.size()), default_path_value.get() + out_path, filter_item.get(), static_cast(allowed_files.size()), default_path_value.get() ); if (result == NFD_OKAY) { return std::filesystem::path{ out_path.get() }; @@ -113,7 +113,7 @@ helper::expected helper::openFileDialog( ) { NFD::UniquePathSet out_paths{}; - auto filterItem = get_filter_items(allowed_files); + auto filter_item = get_filter_items(allowed_files); const auto path_deallocator = [](const nfdu8char_t* const char_value) { if (char_value == nullptr) { @@ -133,7 +133,7 @@ helper::expected helper::openFileDialog( } const nfdresult_t result = NFD::OpenDialogMultiple( - out_paths, filterItem.get(), static_cast(allowed_files.size()), default_path_value.get() + out_paths, filter_item.get(), static_cast(allowed_files.size()), default_path_value.get() ); if (result == NFD_OKAY) { std::vector result_vector{}; diff --git a/src/helper/platform.cpp b/src/helper/platform.cpp index c469b7c1..9922cc96 100644 --- a/src/helper/platform.cpp +++ b/src/helper/platform.cpp @@ -84,7 +84,7 @@ namespace { #error "Unsupported platform" #endif - const auto result = system(shell_command.c_str()); + const auto result = system(shell_command.c_str()); //NOLINT(cert-env33-c) if (result < 0) { spdlog::error("Error in opening url: {}", get_error_from_errno()); return false; diff --git a/src/input/game_input.hpp b/src/input/game_input.hpp index fdedb3e2..fa41aba8 100644 --- a/src/input/game_input.hpp +++ b/src/input/game_input.hpp @@ -27,7 +27,7 @@ namespace input { enum class GameInputType : u8 { Touch, Keyboard, Controller, Recording }; - enum class MenuEvent : u8 { OPEN_SETTINGS, PAUSE }; + enum class MenuEvent : u8 { OpenSettings, Pause }; struct GameInput { @@ -46,14 +46,23 @@ namespace input { std::unordered_map m_keys_hold; GameInputType m_input_type; - protected: + private: Tetrion* m_target_tetrion{}; OnEventCallback m_on_event_callback{}; + protected: explicit GameInput(GameInputType input_type) : m_input_type{ input_type } { } void handle_event(InputEvent event, SimulationStep simulation_step_index); + [[nodiscard]] const Tetrion* target_tetrion() const { + return m_target_tetrion; + } + + [[nodiscard]] const OnEventCallback& on_event_callback() const { + return m_on_event_callback; + } + public: virtual void update(SimulationStep simulation_step_index); virtual void late_update(SimulationStep /*simulation_step*/){}; @@ -82,6 +91,9 @@ namespace input { GameInput(const GameInput&) = delete; GameInput& operator=(const GameInput&) = delete; + GameInput(GameInput&&) = default; + GameInput& operator=(GameInput&&) = default; + virtual ~GameInput() = default; }; } // namespace input diff --git a/src/input/guid.hpp b/src/input/guid.hpp index 04d4b370..10cefdb9 100644 --- a/src/input/guid.hpp +++ b/src/input/guid.hpp @@ -53,24 +53,24 @@ struct fmt::formatter : formatter { namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) // decode a single_hex_number - [[nodiscard]] constexpr const_utils::expected single_hex_number(char input) { + [[nodiscard]] constexpr const_utils::Expected single_hex_number(char input) { if (input >= '0' && input <= '9') { - return const_utils::expected::good_result(static_cast(input - '0')); + return const_utils::Expected::good_result(static_cast(input - '0')); } if (input >= 'A' && input <= 'F') { - return const_utils::expected::good_result(static_cast(input - 'A' + 10)); + return const_utils::Expected::good_result(static_cast(input - 'A' + 10)); } if (input >= 'a' && input <= 'f') { - return const_utils::expected::good_result(static_cast(input - 'a' + 10)); + return const_utils::Expected::good_result(static_cast(input - 'a' + 10)); } - return const_utils::expected::error_result("the input must be a valid hex character"); + return const_utils::Expected::error_result("the input must be a valid hex character"); } // decode a single 2 digit color value in hex - [[nodiscard]] constexpr const_utils::expected single_hex_color_value(const char* input) { + [[nodiscard]] constexpr const_utils::Expected single_hex_color_value(const char* input) { const auto first = single_hex_number(input[0]); //NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) @@ -80,14 +80,14 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) PROPAGATE(second, u8, std::string); - return const_utils::expected::good_result((first.value() << 4) | second.value()); + return const_utils::Expected::good_result((first.value() << 4) | second.value()); } - [[nodiscard]] constexpr const_utils::expected + [[nodiscard]] constexpr const_utils::Expected get_guid_from_string_impl(const char* input, std::size_t size) { if (size == 0) { - return const_utils::expected::error_result( + return const_utils::Expected::error_result( "not enough data to determine the literal type" ); } @@ -102,7 +102,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) width = 3; } else { - return const_utils::expected::error_result("Unrecognized guid literal"); + return const_utils::Expected::error_result("Unrecognized guid literal"); } @@ -122,7 +122,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) result.at(i) = value; } - return const_utils::expected::good_result(sdl::GUID{ result }); + return const_utils::Expected::good_result(sdl::GUID{ result }); } } // namespace @@ -130,7 +130,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) namespace detail { - [[nodiscard]] constexpr const_utils::expected get_guid_from_string(const std::string& input + [[nodiscard]] constexpr const_utils::Expected get_guid_from_string(const std::string& input ) { return get_guid_from_string_impl(input.c_str(), input.size()); } diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 1a3e9fc5..18726aa6 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -813,10 +813,10 @@ helper::optional input::ConsoleJoystickGameInput::sdl_event_to_input const auto button = event.jbutton.button; if (button == m_settings.pause) { - return MenuEvent::PAUSE; + return MenuEvent::Pause; } if (button == m_settings.open_settings) { - return MenuEvent::OPEN_SETTINGS; + return MenuEvent::OpenSettings; } } @@ -826,9 +826,9 @@ helper::optional input::ConsoleJoystickGameInput::sdl_event_to_input [[nodiscard]] std::string input::ConsoleJoystickGameInput::describe_menu_event(MenuEvent event) const { switch (event) { - case input::MenuEvent::PAUSE: + case input::MenuEvent::Pause: return m_underlying_joystick_input->key_to_string(m_settings.pause); - case input::MenuEvent::OPEN_SETTINGS: + case input::MenuEvent::OpenSettings: return m_underlying_joystick_input->key_to_string(m_settings.open_settings); default: utils::unreachable(); diff --git a/src/input/keyboard_input.cpp b/src/input/keyboard_input.cpp index b4f4e88e..a89c629a 100644 --- a/src/input/keyboard_input.cpp +++ b/src/input/keyboard_input.cpp @@ -191,10 +191,10 @@ SDL::Key json_helper::get_key(const nlohmann::json& j, const std::string& name) if (event.type == SDL_KEYDOWN and event.key.repeat == 0) { const auto key = SDL::Key{ event.key.keysym }; if (key == m_settings.pause) { - return MenuEvent::PAUSE; + return MenuEvent::Pause; } if (key == m_settings.open_settings) { - return MenuEvent::OPEN_SETTINGS; + return MenuEvent::OpenSettings; } } @@ -203,9 +203,9 @@ SDL::Key json_helper::get_key(const nlohmann::json& j, const std::string& name) [[nodiscard]] std::string input::KeyboardGameInput::describe_menu_event(MenuEvent event) const { switch (event) { - case input::MenuEvent::PAUSE: + case input::MenuEvent::Pause: return m_settings.pause.to_string(); - case input::MenuEvent::OPEN_SETTINGS: + case input::MenuEvent::OpenSettings: return m_settings.open_settings.to_string(); default: utils::unreachable(); diff --git a/src/input/replay_input.cpp b/src/input/replay_input.cpp index bc05d31b..61cc6fda 100644 --- a/src/input/replay_input.cpp +++ b/src/input/replay_input.cpp @@ -15,7 +15,7 @@ void input::ReplayGameInput::update(const SimulationStep simulation_step_index) const auto& record = m_recording_reader->at(m_next_record_index); - if (record.tetrion_index != m_target_tetrion->tetrion_index()) { + if (record.tetrion_index != target_tetrion()->tetrion_index()) { // the current record is not for this tetrion => discard record and keep reading ++m_next_record_index; continue; @@ -46,20 +46,20 @@ void input::ReplayGameInput::late_update(const SimulationStep simulation_step_in } const auto& snapshot = m_recording_reader->snapshots().at(m_next_snapshot_index); - if (snapshot.tetrion_index() != m_target_tetrion->tetrion_index()) { + if (snapshot.tetrion_index() != target_tetrion()->tetrion_index()) { ++m_next_snapshot_index; continue; } // the snapshot corresponds to this tetrion - assert(snapshot.tetrion_index() == m_target_tetrion->tetrion_index()); + assert(snapshot.tetrion_index() == target_tetrion()->tetrion_index()); if (snapshot.simulation_step_index() != simulation_step_index) { break; } // create a snapshot from the current state of the tetrion and compare it to the loaded snapshot - const auto current_snapshot = TetrionSnapshot{ m_target_tetrion->core_information(), simulation_step_index }; + const auto current_snapshot = TetrionSnapshot{ target_tetrion()->core_information(), simulation_step_index }; spdlog::info("comparing tetrion snapshots at simulation_step {}", simulation_step_index); diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index 4c4d6d75..85929eb4 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -145,7 +145,7 @@ helper::optional input::TouchGameInput::sdl_event_to_input_event(con [[nodiscard]] helper::optional input::TouchGameInput::get_menu_event(const SDL_Event& event) const { if (event.type == SDL_KEYDOWN and event.key.keysym.sym == SDLK_AC_BACK) { - return MenuEvent::PAUSE; + return MenuEvent::Pause; } return helper::nullopt; @@ -153,9 +153,9 @@ helper::optional input::TouchGameInput::sdl_event_to_input_event(con [[nodiscard]] std::string input::TouchGameInput::describe_menu_event(MenuEvent event) const { switch (event) { - case input::MenuEvent::PAUSE: + case input::MenuEvent::Pause: return "Back"; - case input::MenuEvent::OPEN_SETTINGS: + case input::MenuEvent::OpenSettings: throw std::runtime_error("Open Settings is not supported"); default: utils::unreachable(); diff --git a/src/scenes/replay_game/replay_game.cpp b/src/scenes/replay_game/replay_game.cpp index b81ea76e..73998625 100644 --- a/src/scenes/replay_game/replay_game.cpp +++ b/src/scenes/replay_game/replay_game.cpp @@ -120,7 +120,7 @@ namespace scenes { //TODO(Totto): re-add pause scene UNUSED(input_manager); UNUSED(event); - /* if (utils::event_is_action(event, utils::CrossPlatformAction::PAUSE)) { + /* if (utils::event_is_action(event, utils::CrossPlatformAction::Pause)) { for (auto& game : m_games) { if (game->is_game_finished()) { @@ -134,7 +134,7 @@ namespace scenes { } - if (utils::event_is_action(event, utils::CrossPlatformAction::OPEN_SETTINGS)) { + if (utils::event_is_action(event, utils::CrossPlatformAction::OpenSettings)) { m_next_scene = NextScene::Settings; return true; } */ diff --git a/src/scenes/settings_menu/settings_menu.cpp b/src/scenes/settings_menu/settings_menu.cpp index 8ef5286b..f3f35b8b 100644 --- a/src/scenes/settings_menu/settings_menu.cpp +++ b/src/scenes/settings_menu/settings_menu.cpp @@ -182,7 +182,7 @@ namespace scenes { if (m_game_input.has_value() - and m_game_input.value()->get_menu_event(event) == input::MenuEvent::OPEN_SETTINGS) { + and m_game_input.value()->get_menu_event(event) == input::MenuEvent::OpenSettings) { m_next_command = Command{ Return{} }; return true; } diff --git a/src/scenes/single_player_game/pause.cpp b/src/scenes/single_player_game/pause.cpp index 993edef5..8dcb7345 100644 --- a/src/scenes/single_player_game/pause.cpp +++ b/src/scenes/single_player_game/pause.cpp @@ -12,7 +12,7 @@ namespace scenes { service_provider, fmt::format( "Pause ({}: continue, {}: quit)", - game_input->describe_menu_event(input::MenuEvent::PAUSE), + game_input->describe_menu_event(input::MenuEvent::Pause), service_provider->input_manager().get_primary_input()->describe_navigation_event(input::NavigationEvent::BACK) ), service_provider->font_manager().get(FontId::Default), @@ -49,7 +49,7 @@ namespace scenes { const auto navigation_event = input_manager->get_navigation_event(event); - if (m_game_input->get_menu_event(event) == input::MenuEvent::OPEN_SETTINGS) { + if (m_game_input->get_menu_event(event) == input::MenuEvent::OpenSettings) { m_should_unpause = true; return true; } diff --git a/src/scenes/single_player_game/single_player_game.cpp b/src/scenes/single_player_game/single_player_game.cpp index 65eac687..ab4b18df 100644 --- a/src/scenes/single_player_game/single_player_game.cpp +++ b/src/scenes/single_player_game/single_player_game.cpp @@ -111,13 +111,13 @@ namespace scenes { const auto& game_input = m_game->game_input(); - if (game_input->get_menu_event(event) == input::MenuEvent::PAUSE and not m_game->is_game_finished()) { + if (game_input->get_menu_event(event) == input::MenuEvent::Pause and not m_game->is_game_finished()) { m_next_scene = NextScene::Pause; m_game->set_paused(true); return true; } - if (game_input->get_menu_event(event) == input::MenuEvent::OPEN_SETTINGS) { + if (game_input->get_menu_event(event) == input::MenuEvent::OpenSettings) { m_next_scene = NextScene::Settings; return true; } From b8d91d07ff81bda160316bb7e3cccc4a0ee5b33b Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 02:32:05 +0200 Subject: [PATCH 70/76] clang-tidy: - fix name errors: namespace SDL -> sdl --- src/input/keyboard_input.cpp | 42 ++--- src/input/keyboard_input.hpp | 38 ++--- src/manager/event_dispatcher.hpp | 26 +-- src/manager/music_manager.cpp | 14 +- src/manager/sdl_key.cpp | 264 +++++++++++++++---------------- src/manager/sdl_key.hpp | 8 +- tests/graphics/sdl_key.cpp | 60 +++---- 7 files changed, 226 insertions(+), 226 deletions(-) diff --git a/src/input/keyboard_input.cpp b/src/input/keyboard_input.cpp index a89c629a..9aa460cf 100644 --- a/src/input/keyboard_input.cpp +++ b/src/input/keyboard_input.cpp @@ -14,38 +14,38 @@ input::KeyboardInput::KeyboardInput() : input::Input{ "keyboard", InputType::Key if (event.type == SDL_KEYDOWN) { - const auto key = SDL::Key{ event.key.keysym }; + const auto key = sdl::Key{ event.key.keysym }; - if (key == SDL::Key{ SDLK_RETURN } or key == SDL::Key{ SDLK_SPACE }) { + if (key == sdl::Key{ SDLK_RETURN } or key == sdl::Key{ SDLK_SPACE }) { return NavigationEvent::OK; } - if (key == SDL::Key{ SDLK_DOWN } or key == SDL::Key{ SDLK_s }) { + if (key == sdl::Key{ SDLK_DOWN } or key == sdl::Key{ SDLK_s }) { return NavigationEvent::DOWN; } - if (key == SDL::Key{ SDLK_UP } or key == SDL::Key{ SDLK_w }) { + if (key == sdl::Key{ SDLK_UP } or key == sdl::Key{ SDLK_w }) { return NavigationEvent::UP; } - if (key == SDL::Key{ SDLK_LEFT } or key == SDL::Key{ SDLK_a }) { + if (key == sdl::Key{ SDLK_LEFT } or key == sdl::Key{ SDLK_a }) { return NavigationEvent::LEFT; } - if (key == SDL::Key{ SDLK_RIGHT } or key == SDL::Key{ SDLK_d }) { + if (key == sdl::Key{ SDLK_RIGHT } or key == sdl::Key{ SDLK_d }) { return NavigationEvent::RIGHT; } - if (key == SDL::Key{ SDLK_ESCAPE } or key == SDL::Key{ SDLK_BACKSPACE }) { + if (key == sdl::Key{ SDLK_ESCAPE } or key == sdl::Key{ SDLK_BACKSPACE }) { return NavigationEvent::BACK; } - if (key == SDL::Key{ SDLK_TAB }) { + if (key == sdl::Key{ SDLK_TAB }) { return NavigationEvent::TAB; } } @@ -60,19 +60,19 @@ input::KeyboardInput::KeyboardInput() : input::Input{ "keyboard", InputType::Key switch (event) { case NavigationEvent::OK: - return fmt::format("{} or {}", SDL::Key{ SDLK_RETURN }, SDL::Key{ SDLK_SPACE }); + return fmt::format("{} or {}", sdl::Key{ SDLK_RETURN }, sdl::Key{ SDLK_SPACE }); case NavigationEvent::DOWN: - return fmt::format("{} or {}", SDL::Key{ SDLK_DOWN }, SDL::Key{ SDLK_s }); + return fmt::format("{} or {}", sdl::Key{ SDLK_DOWN }, sdl::Key{ SDLK_s }); case NavigationEvent::UP: - return fmt::format("{} or {}", SDL::Key{ SDLK_UP }, SDL::Key{ SDLK_w }); + return fmt::format("{} or {}", sdl::Key{ SDLK_UP }, sdl::Key{ SDLK_w }); case NavigationEvent::LEFT: - return fmt::format("{} or {}", SDL::Key{ SDLK_LEFT }, SDL::Key{ SDLK_a }); + return fmt::format("{} or {}", sdl::Key{ SDLK_LEFT }, sdl::Key{ SDLK_a }); case NavigationEvent::RIGHT: - return fmt::format("{} or {}", SDL::Key{ SDLK_RIGHT }, SDL::Key{ SDLK_d }); + return fmt::format("{} or {}", sdl::Key{ SDLK_RIGHT }, sdl::Key{ SDLK_d }); case NavigationEvent::BACK: - return fmt::format("{} or {}", SDL::Key{ SDLK_ESCAPE }, SDL::Key{ SDLK_BACKSPACE }); + return fmt::format("{} or {}", sdl::Key{ SDLK_ESCAPE }, sdl::Key{ SDLK_BACKSPACE }); case NavigationEvent::TAB: - return fmt::format("{}", SDL::Key{ SDLK_TAB }); + return fmt::format("{}", sdl::Key{ SDLK_TAB }); default: utils::unreachable(); } @@ -97,7 +97,7 @@ void input::KeyboardGameInput::update(SimulationStep simulation_step_index) { helper::optional input::KeyboardGameInput::sdl_event_to_input_event(const SDL_Event& event) const { if (event.type == SDL_KEYDOWN and event.key.repeat == 0) { - const auto key = SDL::Key{ event.key.keysym }; + const auto key = sdl::Key{ event.key.keysym }; if (key == m_settings.rotate_left) { return InputEvent::RotateLeftPressed; } @@ -120,7 +120,7 @@ helper::optional input::KeyboardGameInput::sdl_event_to_input_event( return InputEvent::HoldPressed; } } else if (event.type == SDL_KEYUP) { - const auto key = SDL::Key{ event.key.keysym }; + const auto key = sdl::Key{ event.key.keysym }; if (key == m_settings.rotate_left) { return InputEvent::RotateLeftReleased; } @@ -160,20 +160,20 @@ input::KeyboardGameInput::~KeyboardGameInput() { [[nodiscard]] helper::expected input::KeyboardSettings::validate() const { - const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, + const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, drop, hold, pause, open_settings }; return input::InputSettings::has_unique_members(to_use); } -SDL::Key json_helper::get_key(const nlohmann::json& j, const std::string& name) { +sdl::Key json_helper::get_key(const nlohmann::json& j, const std::string& name) { auto context = j.at(name); std::string input; context.get_to(input); - const auto& value = SDL::Key::from_string(input); + const auto& value = sdl::Key::from_string(input); if (not value.has_value()) { throw nlohmann::json::type_error::create( @@ -189,7 +189,7 @@ SDL::Key json_helper::get_key(const nlohmann::json& j, const std::string& name) ) const { if (event.type == SDL_KEYDOWN and event.key.repeat == 0) { - const auto key = SDL::Key{ event.key.keysym }; + const auto key = sdl::Key{ event.key.keysym }; if (key == m_settings.pause) { return MenuEvent::Pause; } diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index b6b7f22a..eaa1eed9 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -27,30 +27,30 @@ namespace input { //TODO(Totto): don't default initialize all settings, but rather provide a static default setting, so that everything has to be set explicitly, or you can use the default explicitly struct KeyboardSettings { - SDL::Key rotate_left; - SDL::Key rotate_right; - SDL::Key move_left; - SDL::Key move_right; - SDL::Key move_down; - SDL::Key drop; - SDL::Key hold; + sdl::Key rotate_left; + sdl::Key rotate_right; + sdl::Key move_left; + sdl::Key move_right; + sdl::Key move_down; + sdl::Key drop; + sdl::Key hold; - SDL::Key pause; - SDL::Key open_settings; + sdl::Key pause; + sdl::Key open_settings; [[nodiscard]] helper::expected validate() const; [[nodiscard]] static KeyboardSettings default_settings() { - return KeyboardSettings{ .rotate_left = SDL::Key{ SDLK_LEFT }, - .rotate_right = SDL::Key{ SDLK_RIGHT }, - .move_left = SDL::Key{ SDLK_a }, - .move_right = SDL::Key{ SDLK_d }, - .move_down = SDL::Key{ SDLK_s }, - .drop = SDL::Key{ SDLK_w }, - .hold = SDL::Key{ SDLK_TAB }, - .pause = SDL::Key{ SDLK_ESCAPE }, - .open_settings = SDL::Key{ SDLK_e } }; + return KeyboardSettings{ .rotate_left = sdl::Key{ SDLK_LEFT }, + .rotate_right = sdl::Key{ SDLK_RIGHT }, + .move_left = sdl::Key{ SDLK_a }, + .move_right = sdl::Key{ SDLK_d }, + .move_down = sdl::Key{ SDLK_s }, + .drop = sdl::Key{ SDLK_w }, + .hold = sdl::Key{ SDLK_TAB }, + .pause = sdl::Key{ SDLK_ESCAPE }, + .open_settings = sdl::Key{ SDLK_e } }; } }; @@ -83,7 +83,7 @@ namespace input { namespace json_helper { - [[nodiscard]] SDL::Key get_key(const nlohmann::json& j, const std::string& name); + [[nodiscard]] sdl::Key get_key(const nlohmann::json& j, const std::string& name); } // namespace json_helper diff --git a/src/manager/event_dispatcher.hpp b/src/manager/event_dispatcher.hpp index b7c80ae4..d76a2ddb 100644 --- a/src/manager/event_dispatcher.hpp +++ b/src/manager/event_dispatcher.hpp @@ -16,18 +16,18 @@ struct EventDispatcher final { bool m_enabled{ true }; //TODO(Totto): factor out to some other place! - std::vector allowed_input_keys{ - SDL::Key{ SDLK_RETURN }, - SDL::Key{ SDLK_BACKSPACE }, - SDL::Key{ SDLK_BACKSPACE, { SDL::Modifier::CTRL } }, - SDL::Key{ SDLK_DOWN }, - SDL::Key{ SDLK_UP }, - SDL::Key{ SDLK_LEFT }, - SDL::Key{ SDLK_RIGHT }, - SDL::Key{ SDLK_ESCAPE }, - SDL::Key{ SDLK_TAB }, - SDL::Key{ SDLK_c, { SDL::Modifier::CTRL } }, - SDL::Key{ SDLK_v, { SDL::Modifier::CTRL } } + std::vector allowed_input_keys{ + sdl::Key{ SDLK_RETURN }, + sdl::Key{ SDLK_BACKSPACE }, + sdl::Key{ SDLK_BACKSPACE, { sdl::Modifier::CTRL } }, + sdl::Key{ SDLK_DOWN }, + sdl::Key{ SDLK_UP }, + sdl::Key{ SDLK_LEFT }, + sdl::Key{ SDLK_RIGHT }, + sdl::Key{ SDLK_ESCAPE }, + sdl::Key{ SDLK_TAB }, + sdl::Key{ SDLK_c, { sdl::Modifier::CTRL } }, + sdl::Key{ SDLK_v, { sdl::Modifier::CTRL } } }; public: @@ -54,7 +54,7 @@ struct EventDispatcher final { switch (event.type) { case SDL_KEYDOWN: case SDL_KEYUP: { - if (std::ranges::find(allowed_input_keys, SDL::Key{ event.key.keysym }) + if (std::ranges::find(allowed_input_keys, sdl::Key{ event.key.keysym }) == allowed_input_keys.cend()) { return; } diff --git a/src/manager/music_manager.cpp b/src/manager/music_manager.cpp index 0a60a316..d8cb40f2 100644 --- a/src/manager/music_manager.cpp +++ b/src/manager/music_manager.cpp @@ -355,21 +355,21 @@ helper::optional MusicManager::change_volume(const std::int8_t steps) { bool MusicManager::handle_event(const std::shared_ptr&, const SDL_Event& event) { if (event.type == SDL_KEYDOWN) { - const auto key = SDL::Key{ event.key.keysym }; + const auto key = sdl::Key{ event.key.keysym }; - if (key.is_key(SDL::Key{ SDLK_PLUS }) or key.is_key(SDL::Key{ SDLK_KP_PLUS })) { - const i8 steps = key.has_modifier(SDL::Modifier::CTRL) ? 100 - : key.has_modifier(SDL::Modifier::SHIFT) ? 10 + if (key.is_key(sdl::Key{ SDLK_PLUS }) or key.is_key(sdl::Key{ SDLK_KP_PLUS })) { + const i8 steps = key.has_modifier(sdl::Modifier::CTRL) ? 100 + : key.has_modifier(sdl::Modifier::SHIFT) ? 10 : 1; change_volume(steps); return true; } - if (key.is_key(SDL::Key{ SDLK_MINUS }) or key.is_key(SDL::Key{ SDLK_KP_MINUS })) { - const i8 steps = key.has_modifier(SDL::Modifier::CTRL) ? -100 - : key.has_modifier(SDL::Modifier::SHIFT) ? -10 + if (key.is_key(sdl::Key{ SDLK_MINUS }) or key.is_key(sdl::Key{ SDLK_KP_MINUS })) { + const i8 steps = key.has_modifier(sdl::Modifier::CTRL) ? -100 + : key.has_modifier(sdl::Modifier::SHIFT) ? -10 : -1; change_volume(steps); return true; diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index a4faddaa..ecbddddc 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -16,133 +16,133 @@ #include -SDL::Key::Key(SDL_KeyCode keycode, UnderlyingModifierType modifiers) +sdl::Key::Key(SDL_KeyCode keycode, UnderlyingModifierType modifiers) : m_keycode{ keycode }, m_modifiers{ modifiers } { } -SDL::Key::Key(SDL_KeyCode keycode, const std::vector& modifiers) - : Key{ keycode, SDL::Key::sdl_modifier_from_modifiers(modifiers) } { } +sdl::Key::Key(SDL_KeyCode keycode, const std::vector& modifiers) + : Key{ keycode, sdl::Key::sdl_modifier_from_modifiers(modifiers) } { } -SDL::Key::Key(const SDL_Keysym& keysym) : Key{ static_cast(keysym.sym), keysym.mod } { } +sdl::Key::Key(const SDL_Keysym& keysym) : Key{ static_cast(keysym.sym), keysym.mod } { } -[[nodiscard]] bool SDL::Key::is_key(const SDL::Key& other) const { +[[nodiscard]] bool sdl::Key::is_key(const sdl::Key& other) const { return m_keycode == other.m_keycode; } namespace { - constexpr SDL_Keymod to_sdl_modifier(SDL::Modifier modifier) { + constexpr SDL_Keymod to_sdl_modifier(sdl::Modifier modifier) { switch (modifier) { - case SDL::Modifier::LSHIFT: + case sdl::Modifier::LSHIFT: return KMOD_LSHIFT; - case SDL::Modifier::RSHIFT: + case sdl::Modifier::RSHIFT: return KMOD_RSHIFT; - case SDL::Modifier::LCTRL: + case sdl::Modifier::LCTRL: return KMOD_LCTRL; - case SDL::Modifier::RCTRL: + case sdl::Modifier::RCTRL: return KMOD_RCTRL; - case SDL::Modifier::LALT: + case sdl::Modifier::LALT: return KMOD_LALT; - case SDL::Modifier::RALT: + case sdl::Modifier::RALT: return KMOD_RALT; - case SDL::Modifier::LGUI: + case sdl::Modifier::LGUI: return KMOD_LGUI; - case SDL::Modifier::RGUI: + case sdl::Modifier::RGUI: return KMOD_RGUI; - case SDL::Modifier::NUM: + case sdl::Modifier::NUM: return KMOD_NUM; - case SDL::Modifier::CAPS: + case sdl::Modifier::CAPS: return KMOD_CAPS; - case SDL::Modifier::MODE: + case sdl::Modifier::MODE: return KMOD_MODE; - case SDL::Modifier::SCROLL: + case sdl::Modifier::SCROLL: return KMOD_SCROLL; - case SDL::Modifier::CTRL: + case sdl::Modifier::CTRL: return KMOD_CTRL; - case SDL::Modifier::SHIFT: + case sdl::Modifier::SHIFT: return KMOD_SHIFT; - case SDL::Modifier::ALT: + case sdl::Modifier::ALT: return KMOD_ALT; - case SDL::Modifier::GUI: + case sdl::Modifier::GUI: return KMOD_GUI; default: utils::unreachable(); } } - [[maybe_unused]] constexpr SDL::Modifier from_sdl_modifier(SDL_Keymod modifier) { + [[maybe_unused]] constexpr sdl::Modifier from_sdl_modifier(SDL_Keymod modifier) { switch (modifier) { case KMOD_LSHIFT: - return SDL::Modifier::LSHIFT; + return sdl::Modifier::LSHIFT; case KMOD_RSHIFT: - return SDL::Modifier::RSHIFT; + return sdl::Modifier::RSHIFT; case KMOD_LCTRL: - return SDL::Modifier::LCTRL; + return sdl::Modifier::LCTRL; case KMOD_RCTRL: - return SDL::Modifier::RCTRL; + return sdl::Modifier::RCTRL; case KMOD_LALT: - return SDL::Modifier::LALT; + return sdl::Modifier::LALT; case KMOD_RALT: - return SDL::Modifier::RALT; + return sdl::Modifier::RALT; case KMOD_LGUI: - return SDL::Modifier::LGUI; + return sdl::Modifier::LGUI; case KMOD_RGUI: - return SDL::Modifier::RGUI; + return sdl::Modifier::RGUI; case KMOD_NUM: - return SDL::Modifier::NUM; + return sdl::Modifier::NUM; case KMOD_CAPS: - return SDL::Modifier::CAPS; + return sdl::Modifier::CAPS; case KMOD_MODE: - return SDL::Modifier::MODE; + return sdl::Modifier::MODE; case KMOD_SCROLL: - return SDL::Modifier::SCROLL; + return sdl::Modifier::SCROLL; case KMOD_CTRL: - return SDL::Modifier::CTRL; + return sdl::Modifier::CTRL; case KMOD_SHIFT: - return SDL::Modifier::SHIFT; + return sdl::Modifier::SHIFT; case KMOD_ALT: - return SDL::Modifier::ALT; + return sdl::Modifier::ALT; case KMOD_GUI: - return SDL::Modifier::GUI; + return sdl::Modifier::GUI; default: utils::unreachable(); } } - constexpr std::tuple, std::array, std::array> + constexpr std::tuple, std::array, std::array> get_modifier_type_array() { return { { - SDL::Modifier::LSHIFT, - SDL::Modifier::RSHIFT, - SDL::Modifier::LCTRL, - SDL::Modifier::RCTRL, - SDL::Modifier::LALT, - SDL::Modifier::RALT, - SDL::Modifier::LGUI, - SDL::Modifier::RGUI, + sdl::Modifier::LSHIFT, + sdl::Modifier::RSHIFT, + sdl::Modifier::LCTRL, + sdl::Modifier::RCTRL, + sdl::Modifier::LALT, + sdl::Modifier::RALT, + sdl::Modifier::LGUI, + sdl::Modifier::RGUI, }, { - SDL::Modifier::NUM, - SDL::Modifier::CAPS, - SDL::Modifier::MODE, - SDL::Modifier::SCROLL, + sdl::Modifier::NUM, + sdl::Modifier::CAPS, + sdl::Modifier::MODE, + sdl::Modifier::SCROLL, }, { - SDL::Modifier::CTRL, - SDL::Modifier::SHIFT, - SDL::Modifier::ALT, - SDL::Modifier::GUI, + sdl::Modifier::CTRL, + sdl::Modifier::SHIFT, + sdl::Modifier::ALT, + sdl::Modifier::GUI, } }; } @@ -159,63 +159,63 @@ namespace { } - [[maybe_unused]] SDL::ModifierType typeof_modifier(SDL::Modifier modifier) { + [[maybe_unused]] sdl::ModifierType typeof_modifier(sdl::Modifier modifier) { const auto& [normal, special, multiple] = get_modifier_type_array(); if (std::ranges::find(normal, modifier) != normal.cend()) { - return SDL::ModifierType::Normal; + return sdl::ModifierType::Normal; } if (std::ranges::find(special, modifier) != special.cend()) { - return SDL::ModifierType::Special; + return sdl::ModifierType::Special; } if (std::ranges::find(multiple, modifier) != multiple.cend()) { - return SDL::ModifierType::Multiple; + return sdl::ModifierType::Multiple; } utils::unreachable(); } - constexpr std::string modifier_to_string(SDL::Modifier modifier) { + constexpr std::string modifier_to_string(sdl::Modifier modifier) { switch (modifier) { - case SDL::Modifier::LSHIFT: + case sdl::Modifier::LSHIFT: return "Shift-L"; - case SDL::Modifier::RSHIFT: + case sdl::Modifier::RSHIFT: return "Shift-R"; - case SDL::Modifier::LCTRL: + case sdl::Modifier::LCTRL: return "Ctrl-L"; - case SDL::Modifier::RCTRL: + case sdl::Modifier::RCTRL: return "Ctrl-R"; - case SDL::Modifier::LALT: + case sdl::Modifier::LALT: return "Alt-L"; - case SDL::Modifier::RALT: + case sdl::Modifier::RALT: return "Alt-R"; - case SDL::Modifier::LGUI: + case sdl::Modifier::LGUI: return "Gui-L"; - case SDL::Modifier::RGUI: + case sdl::Modifier::RGUI: return "Gui-R"; - case SDL::Modifier::NUM: + case sdl::Modifier::NUM: return "Num"; - case SDL::Modifier::CAPS: + case sdl::Modifier::CAPS: return "Caps"; - case SDL::Modifier::MODE: + case sdl::Modifier::MODE: return "Mode"; - case SDL::Modifier::SCROLL: + case sdl::Modifier::SCROLL: return "Scroll"; - case SDL::Modifier::CTRL: + case sdl::Modifier::CTRL: return "Ctrl"; - case SDL::Modifier::SHIFT: + case sdl::Modifier::SHIFT: return "Shift"; - case SDL::Modifier::ALT: + case sdl::Modifier::ALT: return "Alt"; - case SDL::Modifier::GUI: + case sdl::Modifier::GUI: return "Gui"; default: utils::unreachable(); @@ -223,7 +223,7 @@ namespace { } - helper::optional modifier_from_string(const std::string& modifier) { + helper::optional modifier_from_string(const std::string& modifier) { if (modifier.empty()) { return helper::nullopt; @@ -232,23 +232,23 @@ namespace { const auto lower_case = string::to_lower_case(modifier); - const std::unordered_map map{ - { "shift-l", SDL::Modifier::LSHIFT }, - { "shift-r", SDL::Modifier::RSHIFT }, - { "ctrl-l", SDL::Modifier::LCTRL }, - { "ctrl-r", SDL::Modifier::RCTRL }, - { "alt-l", SDL::Modifier::LALT }, - { "alt-r", SDL::Modifier::RALT }, - { "gui-l", SDL::Modifier::LGUI }, - { "gui-r", SDL::Modifier::RGUI }, - { "num", SDL::Modifier::NUM }, - { "caps", SDL::Modifier::CAPS }, - { "mode", SDL::Modifier::MODE }, - { "scroll", SDL::Modifier::SCROLL }, - { "ctrl", SDL::Modifier::CTRL }, - { "shift", SDL::Modifier::SHIFT }, - { "alt", SDL::Modifier::ALT }, - { "gui", SDL::Modifier::GUI }, + const std::unordered_map map{ + { "shift-l", sdl::Modifier::LSHIFT }, + { "shift-r", sdl::Modifier::RSHIFT }, + { "ctrl-l", sdl::Modifier::LCTRL }, + { "ctrl-r", sdl::Modifier::RCTRL }, + { "alt-l", sdl::Modifier::LALT }, + { "alt-r", sdl::Modifier::RALT }, + { "gui-l", sdl::Modifier::LGUI }, + { "gui-r", sdl::Modifier::RGUI }, + { "num", sdl::Modifier::NUM }, + { "caps", sdl::Modifier::CAPS }, + { "mode", sdl::Modifier::MODE }, + { "scroll", sdl::Modifier::SCROLL }, + { "ctrl", sdl::Modifier::CTRL }, + { "shift", sdl::Modifier::SHIFT }, + { "alt", sdl::Modifier::ALT }, + { "gui", sdl::Modifier::GUI }, }; if (map.contains(lower_case)) { @@ -261,14 +261,14 @@ namespace { } // namespace -helper::expected SDL::Key::from_string(const std::string& value) { +helper::expected sdl::Key::from_string(const std::string& value) { auto tokens = string::split_string_by_char(value, "+"); for (auto& token : tokens) { string::trim(token); } - std::vector modifiers{}; + std::vector modifiers{}; for (size_t i = 0; i < tokens.size(); ++i) { const auto& token = tokens.at(i); @@ -278,7 +278,7 @@ helper::expected SDL::Key::from_string(const std::string& } if (i + 1 == tokens.size()) { - const auto keycode = SDL::Key::sdl_keycode_from_string(token); + const auto keycode = sdl::Key::sdl_keycode_from_string(token); if (not keycode.has_value()) { const auto modifier = modifier_from_string(token); if (modifier.has_value()) { @@ -288,7 +288,7 @@ helper::expected SDL::Key::from_string(const std::string& } //search for duplicates - std::unordered_set values{}; + std::unordered_set values{}; for (const auto& modifier : modifiers) { if (values.contains(modifier)) { return helper::unexpected{ @@ -298,7 +298,7 @@ helper::expected SDL::Key::from_string(const std::string& values.insert(modifier); } - return SDL::Key{ keycode.value(), modifiers }; + return sdl::Key{ keycode.value(), modifiers }; } const auto modifier = modifier_from_string(token); @@ -313,52 +313,52 @@ helper::expected SDL::Key::from_string(const std::string& } -[[nodiscard]] bool SDL::Key::has_modifier(const Modifier& modifier) const { +[[nodiscard]] bool sdl::Key::has_modifier(const Modifier& modifier) const { const auto sdl_modifier = to_sdl_modifier(modifier); ; return (m_modifiers & sdl_modifier) != 0; } -[[nodiscard]] bool SDL::Key::has_modifier_exact(const Modifier& modifier) const { +[[nodiscard]] bool sdl::Key::has_modifier_exact(const Modifier& modifier) const { - SDL::Modifier has_not; + sdl::Modifier has_not; switch (modifier) { - case SDL::Modifier::LSHIFT: - has_not = SDL::Modifier::RSHIFT; + case sdl::Modifier::LSHIFT: + has_not = sdl::Modifier::RSHIFT; break; - case SDL::Modifier::RSHIFT: - has_not = SDL::Modifier::LSHIFT; + case sdl::Modifier::RSHIFT: + has_not = sdl::Modifier::LSHIFT; break; - case SDL::Modifier::LCTRL: - has_not = SDL::Modifier::RCTRL; + case sdl::Modifier::LCTRL: + has_not = sdl::Modifier::RCTRL; break; - case SDL::Modifier::RCTRL: - has_not = SDL::Modifier::LCTRL; + case sdl::Modifier::RCTRL: + has_not = sdl::Modifier::LCTRL; break; - case SDL::Modifier::LALT: - has_not = SDL::Modifier::RALT; + case sdl::Modifier::LALT: + has_not = sdl::Modifier::RALT; break; - case SDL::Modifier::RALT: - has_not = SDL::Modifier::LALT; + case sdl::Modifier::RALT: + has_not = sdl::Modifier::LALT; break; - case SDL::Modifier::LGUI: - has_not = SDL::Modifier::RGUI; + case sdl::Modifier::LGUI: + has_not = sdl::Modifier::RGUI; break; - case SDL::Modifier::RGUI: - has_not = SDL::Modifier::LGUI; + case sdl::Modifier::RGUI: + has_not = sdl::Modifier::LGUI; break; - case SDL::Modifier::NUM: - case SDL::Modifier::CAPS: - case SDL::Modifier::MODE: - case SDL::Modifier::SCROLL: + case sdl::Modifier::NUM: + case sdl::Modifier::CAPS: + case sdl::Modifier::MODE: + case sdl::Modifier::SCROLL: - case SDL::Modifier::CTRL: - case SDL::Modifier::SHIFT: - case SDL::Modifier::ALT: - case SDL::Modifier::GUI: { + case sdl::Modifier::CTRL: + case sdl::Modifier::SHIFT: + case sdl::Modifier::ALT: + case sdl::Modifier::GUI: { const auto sdl_modifier = to_sdl_modifier(modifier); return (m_modifiers & sdl_modifier) == sdl_modifier; } @@ -375,11 +375,11 @@ helper::expected SDL::Key::from_string(const std::string& } -[[nodiscard]] bool SDL::Key::operator==(const Key& other) const { +[[nodiscard]] bool sdl::Key::operator==(const Key& other) const { return is_equal(other, true); } -[[nodiscard]] bool SDL::Key::is_equal(const Key& other, bool ignore_special_modifiers) const { +[[nodiscard]] bool sdl::Key::is_equal(const Key& other, bool ignore_special_modifiers) const { if (not is_key(other)) { return false; } @@ -415,7 +415,7 @@ helper::expected SDL::Key::from_string(const std::string& return true; } -[[nodiscard]] std::string SDL::Key::to_string() const { +[[nodiscard]] std::string sdl::Key::to_string() const { std::vector parts{}; const auto& [normal, special, multiple] = get_modifier_type_array(); @@ -445,7 +445,7 @@ helper::expected SDL::Key::from_string(const std::string& } -[[nodiscard]] helper::expected SDL::Key::sdl_keycode_from_string(const std::string& value) { +[[nodiscard]] helper::expected sdl::Key::sdl_keycode_from_string(const std::string& value) { const auto key = SDL_GetKeyFromName(value.c_str()); if (key == SDLK_UNKNOWN) { return helper::unexpected{ @@ -456,7 +456,7 @@ helper::expected SDL::Key::from_string(const std::string& return static_cast(key); } -[[nodiscard]] SDL::Key::UnderlyingModifierType SDL::Key::sdl_modifier_from_modifiers( +[[nodiscard]] sdl::Key::UnderlyingModifierType sdl::Key::sdl_modifier_from_modifiers( const std::vector& modifiers ) { UnderlyingModifierType result = KMOD_NONE; diff --git a/src/manager/sdl_key.hpp b/src/manager/sdl_key.hpp index fc6c1250..19f7b590 100644 --- a/src/manager/sdl_key.hpp +++ b/src/manager/sdl_key.hpp @@ -9,7 +9,7 @@ #include #include -namespace SDL { +namespace sdl { enum class Modifier : u8 { LSHIFT, @@ -84,11 +84,11 @@ namespace SDL { }; -} // namespace SDL +} // namespace sdl template<> -struct fmt::formatter : formatter { - auto format(const SDL::Key& key, format_context& ctx) { +struct fmt::formatter : formatter { + auto format(const sdl::Key& key, format_context& ctx) { return formatter::format(key.to_string(), ctx); } }; diff --git a/tests/graphics/sdl_key.cpp b/tests/graphics/sdl_key.cpp index d15c6045..5d9e2377 100644 --- a/tests/graphics/sdl_key.cpp +++ b/tests/graphics/sdl_key.cpp @@ -9,7 +9,7 @@ #include -namespace SDL { +namespace sdl { // make keys printable void PrintTo(const Key& key, std::ostream* os) { @@ -21,40 +21,40 @@ namespace SDL { os << value.to_string(); return os; } -} // namespace SDL +} // namespace sdl TEST(SDLKey, SimpleComparision) { - const auto key1 = SDL::Key{ SDLK_k }; + const auto key1 = sdl::Key{ SDLK_k }; ASSERT_EQ(key1.to_string(), "K"); - ASSERT_EQ(key1.has_modifier(SDL::Modifier::ALT), false); + ASSERT_EQ(key1.has_modifier(sdl::Modifier::ALT), false); } TEST(SDLKey, FromString) { - const std::vector, std::string>> strings{ - { SDL::Key{ SDLK_1, { SDL::Modifier::CTRL } },"Ctrl + 1" }, - { SDL::Key{ SDLK_1, { SDL::Modifier::LSHIFT } }, "Shift-L + 1" }, - { SDL::Key{ SDLK_1, { SDL::Modifier::RSHIFT } }, "Shift-R + 1" }, + const std::vector, std::string>> strings{ + { sdl::Key{ SDLK_1, { sdl::Modifier::CTRL } },"Ctrl + 1" }, + { sdl::Key{ SDLK_1, { sdl::Modifier::LSHIFT } }, "Shift-L + 1" }, + { sdl::Key{ SDLK_1, { sdl::Modifier::RSHIFT } }, "Shift-R + 1" }, { helper::unexpected{ "Not a valid modifier: 'ShiftL'" }, "ShiftL + 1" }, { helper::unexpected{ "Duplicate modifier: 'Shift'" }, "Shift + Shift + 1" }, { helper::unexpected{ "No key but only modifiers given" }, "Shift" }, { helper::unexpected{ "Empty token" }, "" }, { helper::unexpected{ "Empty token" }, " + \t " }, - { SDL::Key{ SDLK_1 }, "1" }, - { SDL::Key{ SDLK_1, { SDL::Modifier::CTRL, SDL::Modifier::ALT, SDL::Modifier::SHIFT, SDL::Modifier::GUI } }, + { sdl::Key{ SDLK_1 }, "1" }, + { sdl::Key{ SDLK_1, { sdl::Modifier::CTRL, sdl::Modifier::ALT, sdl::Modifier::SHIFT, sdl::Modifier::GUI } }, "Shift + Alt + Ctrl + Gui + 1" }, - { SDL::Key{ SDLK_1, { SDL::Modifier::LCTRL } }, "Ctrl-L + 1" }, - { SDL::Key{ SDLK_1, { SDL::Modifier::RCTRL } }, "Ctrl-R + 1" }, - { SDL::Key{ SDLK_1, { SDL::Modifier::LALT } }, "Alt-L + 1" }, - { SDL::Key{ SDLK_1, { SDL::Modifier::RALT } }, "Alt-R + 1" }, - { SDL::Key{ SDLK_1, { SDL::Modifier::LGUI } }, "Gui-L + 1" }, - { SDL::Key{ SDLK_1, { SDL::Modifier::RGUI } }, "Gui-R + 1" }, + { sdl::Key{ SDLK_1, { sdl::Modifier::LCTRL } }, "Ctrl-L + 1" }, + { sdl::Key{ SDLK_1, { sdl::Modifier::RCTRL } }, "Ctrl-R + 1" }, + { sdl::Key{ SDLK_1, { sdl::Modifier::LALT } }, "Alt-L + 1" }, + { sdl::Key{ SDLK_1, { sdl::Modifier::RALT } }, "Alt-R + 1" }, + { sdl::Key{ SDLK_1, { sdl::Modifier::LGUI } }, "Gui-L + 1" }, + { sdl::Key{ SDLK_1, { sdl::Modifier::RGUI } }, "Gui-R + 1" }, }; for (const auto& [correct, str] : strings) { - const auto parsed = SDL::Key::from_string(str); + const auto parsed = sdl::Key::from_string(str); if (correct.has_value()) { ASSERT_THAT(parsed, ExpectedHasValue()) << "Input was: " << str; @@ -69,25 +69,25 @@ TEST(SDLKey, FromString) { TEST(SDLKey, ToString) { - const std::vector keys{ - SDL::Key{ SDLK_1, { SDL::Modifier::CTRL } }, - SDL::Key{ SDLK_1, { SDL::Modifier::LSHIFT } }, - SDL::Key{ SDLK_1, { SDL::Modifier::RSHIFT } }, - SDL::Key{ SDLK_1 }, - SDL::Key{ SDLK_1, { SDL::Modifier::CTRL, SDL::Modifier::ALT, SDL::Modifier::SHIFT, SDL::Modifier::GUI } }, - SDL::Key{ SDLK_1, { SDL::Modifier::LCTRL } }, - SDL::Key{ SDLK_1, { SDL::Modifier::RCTRL } }, - SDL::Key{ SDLK_1, { SDL::Modifier::LALT } }, - SDL::Key{ SDLK_1, { SDL::Modifier::RALT } }, - SDL::Key{ SDLK_1, { SDL::Modifier::LGUI } }, - SDL::Key{ SDLK_1, { SDL::Modifier::RGUI } }, + const std::vector keys{ + sdl::Key{ SDLK_1, { sdl::Modifier::CTRL } }, + sdl::Key{ SDLK_1, { sdl::Modifier::LSHIFT } }, + sdl::Key{ SDLK_1, { sdl::Modifier::RSHIFT } }, + sdl::Key{ SDLK_1 }, + sdl::Key{ SDLK_1, { sdl::Modifier::CTRL, sdl::Modifier::ALT, sdl::Modifier::SHIFT, sdl::Modifier::GUI } }, + sdl::Key{ SDLK_1, { sdl::Modifier::LCTRL } }, + sdl::Key{ SDLK_1, { sdl::Modifier::RCTRL } }, + sdl::Key{ SDLK_1, { sdl::Modifier::LALT } }, + sdl::Key{ SDLK_1, { sdl::Modifier::RALT } }, + sdl::Key{ SDLK_1, { sdl::Modifier::LGUI } }, + sdl::Key{ SDLK_1, { sdl::Modifier::RGUI } }, }; for (const auto& key : keys) { const auto keys_string = key.to_string(); - const auto parsed = SDL::Key::from_string(keys_string); + const auto parsed = sdl::Key::from_string(keys_string); ASSERT_THAT(parsed, ExpectedHasValue()) << "Input was: " << key; From 9fc93e3facd7ad8a6bbfcf1a521ced9f23d91450 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 02:33:01 +0200 Subject: [PATCH 71/76] clang-tidy: - fix more errors --- src/input/input.cpp | 2 +- src/ui/components/textinput.cpp | 5 ++++- tests/core/color.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/input/input.cpp b/src/input/input.cpp index 69ed1451..82635122 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -330,7 +330,7 @@ namespace { if (auto primary_input = utils::is_child_class(input); primary_input.has_value()) { auto result = get_game_input_by_input(service_provider, input); if (result.has_value()) { - return result.value(); + return result; } } } diff --git a/src/ui/components/textinput.cpp b/src/ui/components/textinput.cpp index d1b9d822..acdde28e 100644 --- a/src/ui/components/textinput.cpp +++ b/src/ui/components/textinput.cpp @@ -102,7 +102,10 @@ void ui::TextInput::render(const ServiceProvider& service_provider) const { } helper::BoolWrapper> -ui::TextInput::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { +ui::TextInput::handle_event( //NOLINT(readability-function-cognitive-complexity) + const std::shared_ptr& input_manager, + const SDL_Event& event +) { //TODO(Totto): if already has focus, position cursor there, where we clicked if (const auto hover_result = detect_hover(input_manager, event); hover_result) { diff --git a/tests/core/color.cpp b/tests/core/color.cpp index 1742c548..4f274ba5 100644 --- a/tests/core/color.cpp +++ b/tests/core/color.cpp @@ -256,7 +256,7 @@ TEST(ColorConversion, HSVtoRGBtoHSV) { } -TEST(ColorConversion, RGG_to_HSV_to_RGB) { +TEST(ColorConversion, RGGtoHSVtoRGB) { #if COLOR_TEST_MODE == 0 const std::vector colors{ From 55f6c4b8d86255b3b227665034f3850742b1d4ff Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 03:50:43 +0200 Subject: [PATCH 72/76] clang-tidy: - fix more errors --- src/helper/errors.cpp | 1 - src/helper/parse_json.cpp | 10 ++--- src/helper/parse_json.hpp | 18 ++++---- src/input/game_input.hpp | 4 +- src/input/guid.hpp | 2 +- src/input/input.cpp | 9 +++- src/input/input.hpp | 9 +++- src/input/joystick_input.cpp | 22 ++++++++++ src/input/joystick_input.hpp | 67 +++++++++++++++++------------- src/input/keyboard_input.cpp | 9 +++- src/input/keyboard_input.hpp | 31 ++++++++------ src/input/replay_input.hpp | 2 +- src/input/touch_input.cpp | 20 +++++++++ src/input/touch_input.hpp | 44 ++++++++++---------- src/manager/event_dispatcher.hpp | 6 +-- src/manager/music_manager.cpp | 14 +++---- src/manager/sdl_key.cpp | 14 +++---- src/manager/sdl_key.hpp | 2 +- src/ui/components/color_picker.cpp | 6 +-- src/ui/components/image_view.cpp | 2 +- src/ui/components/label.cpp | 2 +- tests/utils/printer.hpp | 4 +- 22 files changed, 185 insertions(+), 113 deletions(-) diff --git a/src/helper/errors.cpp b/src/helper/errors.cpp index f0221703..659dc7f0 100644 --- a/src/helper/errors.cpp +++ b/src/helper/errors.cpp @@ -14,7 +14,6 @@ helper::GeneralError::GeneralError(const GeneralError& error) noexcept = default [[nodiscard]] helper::GeneralError& helper::GeneralError::operator=(const GeneralError& error) noexcept = default; helper::GeneralError::GeneralError(GeneralError&& error) noexcept = default; - [[nodiscard]] helper::GeneralError& helper::GeneralError::operator=(GeneralError&& error) noexcept = default; diff --git a/src/helper/parse_json.cpp b/src/helper/parse_json.cpp index 96b827e6..76415fc5 100644 --- a/src/helper/parse_json.cpp +++ b/src/helper/parse_json.cpp @@ -34,21 +34,21 @@ std::string json::get_json_type(const nlohmann::json::value_t& type) { } } -void json::check_for_no_additional_keys(const nlohmann::json& j, const std::vector& keys) { +void json::check_for_no_additional_keys(const nlohmann::json& obj, const std::vector& keys) { - if (not j.is_object()) { + if (not obj.is_object()) { throw nlohmann::json::type_error::create( - 302, fmt::format("expected an object, but got type '{}'", get_json_type(j.type())), &j + 302, fmt::format("expected an object, but got type '{}'", get_json_type(obj.type())), &obj ); } - const auto& object = j.get(); + const auto& object = obj.get(); for (const auto& [key, _] : object) { if (std::ranges::find(keys, key) == keys.cend()) { throw nlohmann::json::type_error::create( - 302, fmt::format("object may only contain expected keys, but contained '{}'", key), &j + 302, fmt::format("object may only contain expected keys, but contained '{}'", key), &obj ); } } diff --git a/src/helper/parse_json.hpp b/src/helper/parse_json.hpp index 2ebaf5b4..c601a77b 100644 --- a/src/helper/parse_json.hpp +++ b/src/helper/parse_json.hpp @@ -23,21 +23,21 @@ NLOHMANN_JSON_NAMESPACE_BEGIN template struct adl_serializer> { - static void to_json(json& j, const helper::optional& opt) { + static void to_json(json& obj, const helper::optional& opt) { if (not opt) { - j = nullptr; + obj = nullptr; } else { - j = *opt; // this will call adl_serializer::to_json which will - // find the free function to_json in T's namespace! + obj = *opt; // this will call adl_serializer::to_json which will + // find the free function to_json in T's namespace! } } - static void from_json(const json& j, helper::optional& opt) { - if (j.is_null()) { + static void from_json(const json& obj, helper::optional& opt) { + if (obj.is_null()) { opt = helper::nullopt; } else { - opt = j.template get(); // same as above, but with - // adl_serializer::from_json + opt = obj.template get(); // same as above, but with + // adl_serializer::from_json } } }; @@ -111,7 +111,7 @@ namespace json { std::string get_json_type(const nlohmann::json::value_t& type); - void check_for_no_additional_keys(const nlohmann::json& j, const std::vector& keys); + void check_for_no_additional_keys(const nlohmann::json& obj, const std::vector& keys); } // namespace json diff --git a/src/input/game_input.hpp b/src/input/game_input.hpp index fa41aba8..8f8bcd79 100644 --- a/src/input/game_input.hpp +++ b/src/input/game_input.hpp @@ -45,10 +45,8 @@ namespace input { std::unordered_map m_keys_hold; GameInputType m_input_type; - - private: Tetrion* m_target_tetrion{}; - OnEventCallback m_on_event_callback{}; + OnEventCallback m_on_event_callback; protected: explicit GameInput(GameInputType input_type) : m_input_type{ input_type } { } diff --git a/src/input/guid.hpp b/src/input/guid.hpp index 10cefdb9..274b9f70 100644 --- a/src/input/guid.hpp +++ b/src/input/guid.hpp @@ -109,7 +109,7 @@ namespace { //NOLINT(cert-dcl59-cpp,google-build-namespaces) sdl::GUID::ArrayType result{}; for (size_t i = 0; i < amount; ++i) { - size_t offset = i * (width); + const size_t offset = i * width; const auto temp_result = diff --git a/src/input/input.cpp b/src/input/input.cpp index 82635122..6a18a18b 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -20,6 +20,12 @@ input::Input::Input(std::string name, InputType type) : m_name{ std::move(name) input::Input::~Input() = default; +input::Input::Input(const Input& input) noexcept = default; +[[nodiscard]] input::Input& input::Input::operator=(const Input& input) noexcept = default; + +input::Input::Input(Input&& input) noexcept = default; +[[nodiscard]] input::Input& input::Input::operator=(Input&& input) noexcept = default; + input::PointerEventHelper::PointerEventHelper(shapes::IPoint pos, PointerEvent event) : m_pos{ pos }, m_event{ event } { } @@ -306,7 +312,8 @@ namespace { } // namespace -[[nodiscard]] helper::optional> input::InputManager::get_game_input( +[[nodiscard]] helper::optional> +input::InputManager::get_game_input( //NOLINT(readability-convert-member-functions-to-static) ServiceProvider* service_provider ) { diff --git a/src/input/input.hpp b/src/input/input.hpp index 35d5b626..da8c998f 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -33,8 +33,15 @@ namespace input { public: Input(std::string name, InputType type); + virtual ~Input(); + Input(const Input& input) noexcept; + Input& operator=(const Input& input) noexcept; + + Input(Input&& input) noexcept; + Input& operator=(Input&& input) noexcept; + [[nodiscard]] const std::string& name() const; [[nodiscard]] InputType type(); @@ -76,7 +83,7 @@ namespace input { struct InputManager { private: - std::vector> m_inputs{}; + std::vector> m_inputs; public: explicit InputManager(const std::shared_ptr& window); diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 18726aa6..d7d5ac9f 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -22,6 +22,12 @@ input::JoystickInput::~JoystickInput() { } +input::JoystickInput::JoystickInput(const JoystickInput& input) noexcept = default; +input::JoystickInput& input::JoystickInput::operator=(const JoystickInput& input) noexcept = default; + +input::JoystickInput::JoystickInput(JoystickInput&& input) noexcept = default; +input::JoystickInput& input::JoystickInput::operator=(JoystickInput&& input) noexcept = default; + [[nodiscard]] helper::optional> input::JoystickInput::get_joystick_by_guid( const sdl::GUID& guid, SDL_Joystick* joystick, @@ -558,6 +564,22 @@ input::_3DSJoystickInput_Type1::default_settings_raw() const { #endif #endif +input::JoystickGameInput::JoystickGameInput(EventDispatcher* event_dispatcher, JoystickInput* underlying_input) + : GameInput{ GameInputType::Controller }, + m_event_dispatcher{ event_dispatcher }, + m_underlying_input{ underlying_input } { + m_event_dispatcher->register_listener(this); +} + + +input::JoystickGameInput::~JoystickGameInput() { + m_event_dispatcher->unregister_listener(this); +} + +input::JoystickGameInput::JoystickGameInput(JoystickGameInput&& input) noexcept = default; +[[nodiscard]] input::JoystickGameInput& input::JoystickGameInput::operator=(JoystickGameInput&& input +) noexcept = default; + void input::JoystickGameInput::handle_event(const SDL_Event& event) { m_event_buffer.push_back(event); } diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index a0a0dc71..5ba24c1f 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -61,8 +61,7 @@ namespace input { * @note regarding the NOLINT: the destructor just cleans up the SDL_Joystick, it has nothing to do with class members that would need special member functions to be explicitly defined * */ - struct JoystickInput //NOLINT(cppcoreguidelines-special-member-functions) - : Input { + struct JoystickInput : Input { private: SDL_Joystick* m_joystick; SDL_JoystickID m_instance_id; @@ -76,7 +75,14 @@ namespace input { public: JoystickInput(SDL_Joystick* joystick, SDL_JoystickID instance_id, const std::string& name); - ~JoystickInput(); + + ~JoystickInput() override; + + JoystickInput(const JoystickInput& input) noexcept; + JoystickInput& operator=(const JoystickInput& input) noexcept; + + JoystickInput(JoystickInput&& input) noexcept; + JoystickInput& operator=(JoystickInput&& input) noexcept; [[nodiscard]] static helper::expected, std::string> get_by_device_index( int device_index @@ -204,21 +210,21 @@ namespace input { X_LIST_MACRO(open_settings) -#define TRY_CONVERT(original, target, map, key) \ - do /*NOLINT(cppcoreguidelines-avoid-do-while)*/ { \ - if (map.contains(original.key)) { \ - target.key = map.at(original.key); \ - } else { \ - return helper::unexpected{ \ - fmt::format("While parsing key '{}': '{}' is not a valid joystick input", #key, original.key) \ - }; \ - } \ +#define TRY_CONVERT(original, target, map, key) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ + do /*NOLINT(cppcoreguidelines-avoid-do-while)*/ { \ + if ((map).contains((original).key)) { \ + (target).key = (map).at((original).key); \ + } else { \ + return helper::unexpected{ \ + fmt::format("While parsing key '{}': '{}' is not a valid joystick input", #key, (original).key) \ + }; \ + } \ } while (false) -#define SETTINGS_TO_STRING(original, target, fn, key) \ - do /*NOLINT(cppcoreguidelines-avoid-do-while)*/ { \ - target.key = fn(original.key); \ +#define SETTINGS_TO_STRING(original, target, fn, key) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ + do /*NOLINT(cppcoreguidelines-avoid-do-while)*/ { \ + (target).key = fn((original).key); \ } while (false) @@ -227,20 +233,23 @@ namespace input { std::vector m_event_buffer; EventDispatcher* m_event_dispatcher; - protected: + JoystickInput* m_underlying_input; + protected: + [[nodiscard]] const JoystickInput* underlying_input() const; + + public: - JoystickGameInput(EventDispatcher* event_dispatcher, JoystickInput* underlying_input) - : GameInput{ GameInputType::Controller }, - m_event_dispatcher{ event_dispatcher }, - m_underlying_input{ underlying_input } { - m_event_dispatcher->register_listener(this); - } + JoystickGameInput(EventDispatcher* event_dispatcher, JoystickInput* underlying_input); - ~JoystickGameInput() override { - m_event_dispatcher->unregister_listener(this); - } + ~JoystickGameInput() override; + + JoystickGameInput(const JoystickGameInput& input) = delete; + [[nodiscard]] JoystickGameInput& operator=(const JoystickGameInput& input) = delete; + + JoystickGameInput(JoystickGameInput&& input) noexcept; + [[nodiscard]] JoystickGameInput& operator=(JoystickGameInput&& input) noexcept; void handle_event(const SDL_Event& event) override; @@ -264,7 +273,7 @@ namespace input { AbstractJoystickSettings result{}; -#define X_LIST_MACRO(x) TRY_CONVERT(settings, result, map, x); +#define X_LIST_MACRO(x) TRY_CONVERT(settings, result, map, x); //NOLINT(cppcoreguidelines-macro-usage) X_LIST_OF_SETTINGS_KEYS @@ -343,8 +352,8 @@ namespace nlohmann { return input::JoystickIdentification{ .guid = value.value(), .name = name }; } - static void to_json(json& j, const input::JoystickIdentification& identification) { - j = nlohmann::json{ + static void to_json(json& obj, const input::JoystickIdentification& identification) { + obj = nlohmann::json{ { "guid", identification.guid.to_string(), { "name", identification.name } }, }; } @@ -359,7 +368,7 @@ namespace nlohmann { "move_down", "drop", "hold", "menu" } ); - input::JoystickIdentification identification = + const input::JoystickIdentification identification = adl_serializer::from_json(obj.at("identification")); const auto rotate_left = json_helper::get_key_from_object(obj, "rotate_left"); diff --git a/src/input/keyboard_input.cpp b/src/input/keyboard_input.cpp index 9aa460cf..6d3e8a4b 100644 --- a/src/input/keyboard_input.cpp +++ b/src/input/keyboard_input.cpp @@ -158,6 +158,11 @@ input::KeyboardGameInput::~KeyboardGameInput() { } +input::KeyboardGameInput::KeyboardGameInput(KeyboardGameInput&& input) noexcept = default; +[[nodiscard]] input::KeyboardGameInput& input::KeyboardGameInput::operator=(KeyboardGameInput&& input +) noexcept = default; + + [[nodiscard]] helper::expected input::KeyboardSettings::validate() const { const std::vector to_use{ rotate_left, rotate_right, move_left, move_right, move_down, @@ -166,9 +171,9 @@ input::KeyboardGameInput::~KeyboardGameInput() { return input::InputSettings::has_unique_members(to_use); } -sdl::Key json_helper::get_key(const nlohmann::json& j, const std::string& name) { +sdl::Key json_helper::get_key(const nlohmann::json& obj, const std::string& name) { - auto context = j.at(name); + auto context = obj.at(name); std::string input; context.get_to(input); diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index eaa1eed9..7df19572 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -66,6 +66,13 @@ namespace input { ~KeyboardGameInput() override; + KeyboardGameInput(const KeyboardGameInput& input) = delete; + [[nodiscard]] KeyboardGameInput& operator=(const KeyboardGameInput& input) = delete; + + KeyboardGameInput(KeyboardGameInput&& input) noexcept; + [[nodiscard]] KeyboardGameInput& operator=(KeyboardGameInput&& input) noexcept; + + void handle_event(const SDL_Event& event) override; void update(SimulationStep simulation_step_index) override; @@ -83,7 +90,7 @@ namespace input { namespace json_helper { - [[nodiscard]] sdl::Key get_key(const nlohmann::json& j, const std::string& name); + [[nodiscard]] sdl::Key get_key(const nlohmann::json& obj, const std::string& name); } // namespace json_helper @@ -91,22 +98,22 @@ namespace json_helper { namespace nlohmann { template<> struct adl_serializer { - static input::KeyboardSettings from_json(const json& j) { + static input::KeyboardSettings from_json(const json& obj) { ::json::check_for_no_additional_keys( - j, { "type", "rotate_left", "rotate_right", "move_left", "move_right", "move_down", "drop", "hold", - "menu" } + obj, { "type", "rotate_left", "rotate_right", "move_left", "move_right", "move_down", "drop", + "hold", "menu" } ); - const auto rotate_left = json_helper::get_key(j, "rotate_left"); - const auto rotate_right = json_helper::get_key(j, "rotate_right"); - const auto move_left = json_helper::get_key(j, "move_left"); - const auto move_right = json_helper::get_key(j, "move_right"); - const auto move_down = json_helper::get_key(j, "move_down"); - const auto drop = json_helper::get_key(j, "drop"); - const auto hold = json_helper::get_key(j, "hold"); + const auto rotate_left = json_helper::get_key(obj, "rotate_left"); + const auto rotate_right = json_helper::get_key(obj, "rotate_right"); + const auto move_left = json_helper::get_key(obj, "move_left"); + const auto move_right = json_helper::get_key(obj, "move_right"); + const auto move_down = json_helper::get_key(obj, "move_down"); + const auto drop = json_helper::get_key(obj, "drop"); + const auto hold = json_helper::get_key(obj, "hold"); - const auto& menu = j.at("menu"); + const auto& menu = obj.at("menu"); ::json::check_for_no_additional_keys(menu, { "pause", "open_settings" }); diff --git a/src/input/replay_input.hpp b/src/input/replay_input.hpp index ec37fa9b..5e5bb3a9 100644 --- a/src/input/replay_input.hpp +++ b/src/input/replay_input.hpp @@ -15,7 +15,7 @@ namespace input { usize m_next_snapshot_index{ 0 }; public: - ReplayGameInput(std::shared_ptr recording_reader); + explicit ReplayGameInput(std::shared_ptr recording_reader); void update(SimulationStep simulation_step_index) override; void late_update(SimulationStep simulation_step_index) override; diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index 85929eb4..18310af2 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -142,6 +142,26 @@ helper::optional input::TouchGameInput::sdl_event_to_input_event(con } +input::TouchGameInput::TouchGameInput( + const TouchSettings& settings, + EventDispatcher* event_dispatcher, + TouchInput* underlying_input +) + : GameInput{ GameInputType::Touch }, + m_settings{ settings }, + m_event_dispatcher{ event_dispatcher }, + m_underlying_input{ underlying_input } { + m_event_dispatcher->register_listener(this); +} + +input::TouchGameInput::~TouchGameInput() { + m_event_dispatcher->unregister_listener(this); +} + + +input::TouchGameInput::TouchGameInput(TouchGameInput&& input) noexcept = default; +[[nodiscard]] input::TouchGameInput& input::TouchGameInput::operator=(TouchGameInput&& input) noexcept = default; + [[nodiscard]] helper::optional input::TouchGameInput::get_menu_event(const SDL_Event& event) const { if (event.type == SDL_KEYDOWN and event.key.keysym.sym == SDLK_AC_BACK) { diff --git a/src/input/touch_input.hpp b/src/input/touch_input.hpp index fdddaddd..6ceb740f 100644 --- a/src/input/touch_input.hpp +++ b/src/input/touch_input.hpp @@ -59,7 +59,10 @@ namespace input { Uint32 timestamp; float x; float y; - explicit PressedState(Uint32 timestamp, float x, float y) : timestamp{ timestamp }, x{ x }, y{ y } { } + explicit PressedState(Uint32 timestamp, float x_pos, float y_pos) //NOLINT(bugprone-easily-swappable-parameters) + : timestamp{ timestamp }, + x{ x_pos }, + y{ y_pos } { } }; struct TouchGameInput final : public GameInput, public EventListener { @@ -77,17 +80,16 @@ namespace input { const TouchSettings& settings, EventDispatcher* event_dispatcher, TouchInput* underlying_input - ) - : GameInput{ GameInputType::Touch }, - m_settings{ settings }, - m_event_dispatcher{ event_dispatcher }, - m_underlying_input{ underlying_input } { - m_event_dispatcher->register_listener(this); - } + ); - ~TouchGameInput() override { - m_event_dispatcher->unregister_listener(this); - } + ~TouchGameInput() override; + + + TouchGameInput(const TouchGameInput& input) = delete; + [[nodiscard]] TouchGameInput& operator=(const TouchGameInput& input) = delete; + + TouchGameInput(TouchGameInput&& input) noexcept; + [[nodiscard]] TouchGameInput& operator=(TouchGameInput&& input) noexcept; void handle_event(const SDL_Event& event) override; void update(SimulationStep simulation_step_index) override; @@ -110,11 +112,11 @@ namespace json_helper { template - [[nodiscard]] T get_number(const nlohmann::json& j, const std::string& name) { + [[nodiscard]] T get_number(const nlohmann::json& obj, const std::string& name) { helper::expected error = true; - auto context = j.at(name); + auto context = obj.at(name); if (not context.is_number()) { @@ -165,11 +167,11 @@ namespace json_helper { namespace nlohmann { template<> struct adl_serializer { - static input::TouchSettings from_json(const json& j) { + static input::TouchSettings from_json(const json& obj) { ::json::check_for_no_additional_keys( - j, + obj, { "type", "move_x_threshold", @@ -179,11 +181,11 @@ namespace nlohmann { } ); - const auto move_x_threshold = json_helper::get_number(j, "move_x_threshold"); - const auto move_y_threshold = json_helper::get_number(j, "move_y_threshold"); + const auto move_x_threshold = json_helper::get_number(obj, "move_x_threshold"); + const auto move_y_threshold = json_helper::get_number(obj, "move_y_threshold"); - const auto rotation_duration_threshold = json_helper::get_number(j, "rotation_duration_threshold"); - const auto drop_duration_threshold = json_helper::get_number(j, "drop_duration_threshold"); + const auto rotation_duration_threshold = json_helper::get_number(obj, "rotation_duration_threshold"); + const auto drop_duration_threshold = json_helper::get_number(obj, "drop_duration_threshold"); auto settings = input::TouchSettings{ .move_x_threshold = move_x_threshold, .move_y_threshold = move_y_threshold, @@ -199,9 +201,9 @@ namespace nlohmann { return settings; } - static void to_json(json& j, const input::TouchSettings& settings) { + static void to_json(json& obj, const input::TouchSettings& settings) { - j = nlohmann::json{ + obj = nlohmann::json{ { "move_x_threshold", settings.move_x_threshold }, { "move_y_threshold", settings.move_y_threshold }, { "rotation_duration_threshold", settings.rotation_duration_threshold }, diff --git a/src/manager/event_dispatcher.hpp b/src/manager/event_dispatcher.hpp index d76a2ddb..66b245ad 100644 --- a/src/manager/event_dispatcher.hpp +++ b/src/manager/event_dispatcher.hpp @@ -16,7 +16,7 @@ struct EventDispatcher final { bool m_enabled{ true }; //TODO(Totto): factor out to some other place! - std::vector allowed_input_keys{ + std::vector m_allowed_input_keys{ sdl::Key{ SDLK_RETURN }, sdl::Key{ SDLK_BACKSPACE }, sdl::Key{ SDLK_BACKSPACE, { sdl::Modifier::CTRL } }, @@ -54,8 +54,8 @@ struct EventDispatcher final { switch (event.type) { case SDL_KEYDOWN: case SDL_KEYUP: { - if (std::ranges::find(allowed_input_keys, sdl::Key{ event.key.keysym }) - == allowed_input_keys.cend()) { + if (std::ranges::find(m_allowed_input_keys, sdl::Key{ event.key.keysym }) + == m_allowed_input_keys.cend()) { return; } diff --git a/src/manager/music_manager.cpp b/src/manager/music_manager.cpp index d8cb40f2..d040ae02 100644 --- a/src/manager/music_manager.cpp +++ b/src/manager/music_manager.cpp @@ -352,25 +352,25 @@ helper::optional MusicManager::change_volume(const std::int8_t steps) { return new_volume; } -bool MusicManager::handle_event(const std::shared_ptr&, const SDL_Event& event) { +bool MusicManager::handle_event(const std::shared_ptr /*unused*/&, const SDL_Event& event) { if (event.type == SDL_KEYDOWN) { const auto key = sdl::Key{ event.key.keysym }; if (key.is_key(sdl::Key{ SDLK_PLUS }) or key.is_key(sdl::Key{ SDLK_KP_PLUS })) { - const i8 steps = key.has_modifier(sdl::Modifier::CTRL) ? 100 - : key.has_modifier(sdl::Modifier::SHIFT) ? 10 - : 1; + const i8 steps = key.has_modifier(sdl::Modifier::CTRL) ? static_cast(100) + : key.has_modifier(sdl::Modifier::SHIFT) ? static_cast(10) + : static_cast(1); change_volume(steps); return true; } if (key.is_key(sdl::Key{ SDLK_MINUS }) or key.is_key(sdl::Key{ SDLK_KP_MINUS })) { - const i8 steps = key.has_modifier(sdl::Modifier::CTRL) ? -100 - : key.has_modifier(sdl::Modifier::SHIFT) ? -10 - : -1; + const i8 steps = key.has_modifier(sdl::Modifier::CTRL) ? static_cast(-100) + : key.has_modifier(sdl::Modifier::SHIFT) ? static_cast(-10) + : static_cast(-1); change_volume(steps); return true; } diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index ecbddddc..3c82b538 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -322,7 +322,7 @@ helper::expected sdl::Key::from_string(const std::string& [[nodiscard]] bool sdl::Key::has_modifier_exact(const Modifier& modifier) const { - sdl::Modifier has_not; + sdl::Modifier has_not{}; switch (modifier) { case sdl::Modifier::LSHIFT: @@ -396,7 +396,7 @@ helper::expected sdl::Key::from_string(const std::string& for (const auto& modifier : multiple) { const auto sdl_modifier = to_sdl_modifier(modifier); - if (((other.m_modifiers & sdl_modifier) & (m_modifiers & sdl_modifier)) == 0) { + if (((other.m_modifiers & sdl_modifier) & (this->m_modifiers & sdl_modifier)) == 0) { return false; } } @@ -405,14 +405,10 @@ helper::expected sdl::Key::from_string(const std::string& return true; } - for (const auto& modifier : special) { + return std::ranges::all_of(special, [this, &other](const auto& modifier) { const auto sdl_modifier = to_sdl_modifier(modifier); - if ((other.m_modifiers & sdl_modifier) != (m_modifiers & sdl_modifier)) { - return false; - } - } - - return true; + return ((other.m_modifiers & sdl_modifier) == (m_modifiers & sdl_modifier)); + }); } [[nodiscard]] std::string sdl::Key::to_string() const { diff --git a/src/manager/sdl_key.hpp b/src/manager/sdl_key.hpp index 19f7b590..279850b5 100644 --- a/src/manager/sdl_key.hpp +++ b/src/manager/sdl_key.hpp @@ -35,7 +35,7 @@ namespace sdl { GUI, }; - enum class ModifierType { Normal, Multiple, Special }; + enum class ModifierType : u8 { Normal, Multiple, Special }; struct Key { // the difference between SDL_Keymod and ModifierType type is, that ModifierType is SDL_Keymod or-ed together, and supports arithmetic expressions out of the box (like & and |) diff --git a/src/ui/components/color_picker.cpp b/src/ui/components/color_picker.cpp index b8c1eb7a..11cf161f 100644 --- a/src/ui/components/color_picker.cpp +++ b/src/ui/components/color_picker.cpp @@ -156,9 +156,9 @@ detail::ColorCanvas::handle_event(const std::shared_ptr& in const auto pointer_event = input_manager->get_pointer_event(event); - if (pointer_event.has_value() and pointer_event.value() == input::PointerEvent::PointerDown) { + if (pointer_event == input::PointerEvent::PointerDown) { - if (pointer_event.value().is_in(fill_rect)) { + if (pointer_event->is_in(fill_rect)) { m_is_dragging = true; SDL_CaptureMouse(SDL_TRUE); @@ -174,7 +174,7 @@ detail::ColorCanvas::handle_event(const std::shared_ptr& in SDL_CaptureMouse(SDL_FALSE); handled = true; } - } else if (pointer_event.value() == input::PointerEvent::Motion) { + } else if (pointer_event == input::PointerEvent::Motion) { if (m_is_dragging) { handled = true; diff --git a/src/ui/components/image_view.cpp b/src/ui/components/image_view.cpp index 65102ea6..d6f44e15 100644 --- a/src/ui/components/image_view.cpp +++ b/src/ui/components/image_view.cpp @@ -30,6 +30,6 @@ void ui::ImageView::render(const ServiceProvider& service_provider) const { } helper::BoolWrapper> -ui::ImageView::handle_event(const std::shared_ptr&, const SDL_Event&) { +ui::ImageView::handle_event(const std::shared_ptr& /*input_manager*/, const SDL_Event& /*event*/) { return false; } diff --git a/src/ui/components/label.cpp b/src/ui/components/label.cpp index c204e0e7..622318de 100644 --- a/src/ui/components/label.cpp +++ b/src/ui/components/label.cpp @@ -27,7 +27,7 @@ void ui::Label::render(const ServiceProvider& service_provider) const { } helper::BoolWrapper> -ui::Label::handle_event(const std::shared_ptr&, const SDL_Event&) { +ui::Label::handle_event(const std::shared_ptr& /*input_manager*/, const SDL_Event& /*event*/) { return false; } diff --git a/tests/utils/printer.hpp b/tests/utils/printer.hpp index f799f3f5..216a57f9 100644 --- a/tests/utils/printer.hpp +++ b/tests/utils/printer.hpp @@ -44,7 +44,7 @@ namespace // make helper::optional printable template - void PrintTo(const optional& value, std::ostream* os) { + void PrintTo(const optional& value, std::ostream* os) { //NOLINT(cert-dcl58-cpp) if (value.has_value()) { *os << ": " << ::testing::PrintToString(value.value()); } else { @@ -53,7 +53,7 @@ namespace } template - std::ostream& operator<<(std::ostream& os, const optional& value) { + std::ostream& operator<<(std::ostream& os, const optional& value) { //NOLINT(cert-dcl58-cpp) PrintTo(value); return os; } From d153d4c5d4baa9c29096cac1bb9a5d3566a14e47 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 03:55:15 +0200 Subject: [PATCH 73/76] input: - fix clashes in default keys and navigation keys --- settings.json | 2 +- src/input/keyboard_input.hpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/settings.json b/settings.json index b6cc3ad0..2107fe78 100644 --- a/settings.json +++ b/settings.json @@ -12,7 +12,7 @@ "rotate_left": "Left", "rotate_right": "Right", "menu": { - "pause": "Escape", + "pause": "Space", "open_settings": "P" } }, diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index 7df19572..198f7bd0 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -1,5 +1,6 @@ #pragma once +#include "SDL_keycode.h" #include "game_input.hpp" #include "helper/expected.hpp" #include "helper/parse_json.hpp" @@ -49,7 +50,7 @@ namespace input { .move_down = sdl::Key{ SDLK_s }, .drop = sdl::Key{ SDLK_w }, .hold = sdl::Key{ SDLK_TAB }, - .pause = sdl::Key{ SDLK_ESCAPE }, + .pause = sdl::Key{ SDLK_SPACE }, .open_settings = sdl::Key{ SDLK_e } }; } }; From 9f728ad5cf11791f3820c4a6033e806a68601b1d Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 04:00:33 +0200 Subject: [PATCH 74/76] input: - fix handling of pausing, it no works as intended, as pressing also pauses the game --- src/scenes/single_player_game/pause.cpp | 2 +- src/scenes/single_player_game/single_player_game.cpp | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/scenes/single_player_game/pause.cpp b/src/scenes/single_player_game/pause.cpp index 8dcb7345..c9836213 100644 --- a/src/scenes/single_player_game/pause.cpp +++ b/src/scenes/single_player_game/pause.cpp @@ -49,7 +49,7 @@ namespace scenes { const auto navigation_event = input_manager->get_navigation_event(event); - if (m_game_input->get_menu_event(event) == input::MenuEvent::OpenSettings) { + if (m_game_input->get_menu_event(event) == input::MenuEvent::Pause) { m_should_unpause = true; return true; } diff --git a/src/scenes/single_player_game/single_player_game.cpp b/src/scenes/single_player_game/single_player_game.cpp index ab4b18df..5ac11ca3 100644 --- a/src/scenes/single_player_game/single_player_game.cpp +++ b/src/scenes/single_player_game/single_player_game.cpp @@ -4,6 +4,7 @@ #include "helper/music_utils.hpp" #include "helper/platform.hpp" #include "input/game_input.hpp" +#include "input/input.hpp" #include "magic_enum.hpp" #include "manager/music_manager.hpp" #include "scenes/scene.hpp" @@ -104,14 +105,14 @@ namespace scenes { m_game->render(service_provider); } - [[nodiscard]] bool SinglePlayerGame::handle_event( - const std::shared_ptr& /*input_manager*/, - const SDL_Event& event - ) { + [[nodiscard]] bool + SinglePlayerGame::handle_event(const std::shared_ptr& input_manager, const SDL_Event& event) { const auto& game_input = m_game->game_input(); - if (game_input->get_menu_event(event) == input::MenuEvent::Pause and not m_game->is_game_finished()) { + if ((game_input->get_menu_event(event) == input::MenuEvent::Pause + or input_manager->get_navigation_event(event) == input::NavigationEvent::BACK) + and not m_game->is_game_finished()) { m_next_scene = NextScene::Pause; m_game->set_paused(true); return true; From a41c76c1abddbf6b830bf63838f3ed1dd428cd13 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 04:25:39 +0200 Subject: [PATCH 75/76] input: console: - fix console build, by providing missing function definition --- src/input/joystick_input.cpp | 10 +++++++--- src/input/joystick_input.hpp | 1 - 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index d7d5ac9f..785e04cb 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -580,6 +580,10 @@ input::JoystickGameInput::JoystickGameInput(JoystickGameInput&& input) noexcept [[nodiscard]] input::JoystickGameInput& input::JoystickGameInput::operator=(JoystickGameInput&& input ) noexcept = default; +[[nodiscard]] const input::JoystickInput* input::JoystickGameInput::underlying_input() const { + return m_underlying_input; +} + void input::JoystickGameInput::handle_event(const SDL_Event& event) { m_event_buffer.push_back(event); } @@ -764,7 +768,7 @@ input::ConsoleJoystickGameInput::~ConsoleJoystickGameInput() = default; helper::optional input::ConsoleJoystickGameInput::sdl_event_to_input_event(const SDL_Event& event) const { if (event.type == SDL_JOYBUTTONDOWN) { - if (event.jbutton.which != m_underlying_input->instance_id()) { + if (event.jbutton.which != underlying_input()->instance_id()) { return helper::nullopt; } @@ -793,7 +797,7 @@ helper::optional input::ConsoleJoystickGameInput::sdl_event_to_input } } else if (event.type == SDL_JOYBUTTONUP) { - if (event.jbutton.which != m_underlying_input->instance_id()) { + if (event.jbutton.which != underlying_input()->instance_id()) { return helper::nullopt; } @@ -828,7 +832,7 @@ helper::optional input::ConsoleJoystickGameInput::sdl_event_to_input if (event.type == SDL_JOYBUTTONDOWN) { - if (event.jbutton.which != m_underlying_input->instance_id()) { + if (event.jbutton.which != underlying_input()->instance_id()) { return helper::nullopt; } diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index 5ba24c1f..079da857 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -239,7 +239,6 @@ namespace input { protected: [[nodiscard]] const JoystickInput* underlying_input() const; - public: JoystickGameInput(EventDispatcher* event_dispatcher, JoystickInput* underlying_input); From 9e1ed5ff7cd49cd32b2970d14347ef27598910e7 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Fri, 17 May 2024 04:38:55 +0200 Subject: [PATCH 76/76] clang-tidy, input: - fix more errors - remove duplicate call to get_menu_event --- src/manager/sdl_key.cpp | 4 +++- src/scenes/single_player_game/single_player_game.cpp | 6 ++++-- src/ui/components/label.hpp | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index 3c82b538..97498223 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -396,7 +396,9 @@ helper::expected sdl::Key::from_string(const std::string& for (const auto& modifier : multiple) { const auto sdl_modifier = to_sdl_modifier(modifier); - if (((other.m_modifiers & sdl_modifier) & (this->m_modifiers & sdl_modifier)) == 0) { + if (((other.m_modifiers & sdl_modifier) & (this->m_modifiers & sdl_modifier) //NOLINT(misc-redundant-expression) + ) + == 0) { return false; } } diff --git a/src/scenes/single_player_game/single_player_game.cpp b/src/scenes/single_player_game/single_player_game.cpp index 5ac11ca3..820aa45f 100644 --- a/src/scenes/single_player_game/single_player_game.cpp +++ b/src/scenes/single_player_game/single_player_game.cpp @@ -110,7 +110,9 @@ namespace scenes { const auto& game_input = m_game->game_input(); - if ((game_input->get_menu_event(event) == input::MenuEvent::Pause + const auto& menu_event = game_input->get_menu_event(event); + + if ((menu_event == input::MenuEvent::Pause or input_manager->get_navigation_event(event) == input::NavigationEvent::BACK) and not m_game->is_game_finished()) { m_next_scene = NextScene::Pause; @@ -118,7 +120,7 @@ namespace scenes { return true; } - if (game_input->get_menu_event(event) == input::MenuEvent::OpenSettings) { + if (menu_event == input::MenuEvent::OpenSettings) { m_next_scene = NextScene::Settings; return true; } diff --git a/src/ui/components/label.hpp b/src/ui/components/label.hpp index 6bf99e86..4d0007f6 100644 --- a/src/ui/components/label.hpp +++ b/src/ui/components/label.hpp @@ -23,7 +23,7 @@ namespace ui { void render(const ServiceProvider& service_provider) const override; [[nodiscard]] Widget::EventHandleResult - handle_event(const std::shared_ptr& input_manager, const SDL_Event&) override; + handle_event(const std::shared_ptr& input_manager, const SDL_Event& /*event*/) override; void set_text(const ServiceProvider& service_provider, const std::string& text); };