diff --git a/src/event/event-dispatcher.cpp b/src/event/event-dispatcher.cpp index 1b0a9bc..9f221a0 100644 --- a/src/event/event-dispatcher.cpp +++ b/src/event/event-dispatcher.cpp @@ -19,7 +19,8 @@ #include "event-dispatcher.hpp" -event_dispatcher::event_dispatcher() +event_dispatcher::event_dispatcher(): + updating(false) {} event_dispatcher::~event_dispatcher() @@ -29,6 +30,8 @@ event_dispatcher::~event_dispatcher() void event_dispatcher::update(double time) { + updating = true; + // Process pending subscriptions for (auto it = to_subscribe.begin(); it != to_subscribe.end(); ++it) { @@ -64,6 +67,21 @@ void event_dispatcher::update(double time) break; } } + + updating = false; +} + +void event_dispatcher::dispatch(const event_base& event) +{ + // Get list of handlers for this type of event + const std::list& handlers = handler_map[event.get_event_type_id()]; + + // For each handler + for (auto handler = handlers.begin(); handler != handlers.end(); ++handler) + { + // Pass event to the handler + (*handler)->route_event(event); + } } void event_dispatcher::flush() diff --git a/src/event/event-dispatcher.hpp b/src/event/event-dispatcher.hpp index 516bf42..7a656ed 100644 --- a/src/event/event-dispatcher.hpp +++ b/src/event/event-dispatcher.hpp @@ -97,18 +97,33 @@ private: std::map> handler_map; std::list queued_events; std::multimap scheduled_events; + bool updating; }; template void event_dispatcher::subscribe(event_handler* handler) { - to_subscribe.push_back(std::make_tuple(handler->get_handled_event_type_id(), handler)); + if (updating) + { + to_subscribe.push_back(std::make_tuple(handler->get_handled_event_type_id(), handler)); + } + else + { + handler_map[handler->get_handled_event_type_id()].push_back(handler); + } } template void event_dispatcher::unsubscribe(event_handler* handler) { - to_unsubscribe.push_back(std::make_tuple(handler->get_handled_event_type_id(), handler)); + if (updating) + { + to_unsubscribe.push_back(std::make_tuple(handler->get_handled_event_type_id(), handler)); + } + else + { + handler_map[handler->get_handled_event_type_id()].remove(handler); + } } inline void event_dispatcher::queue(const event_base& event) @@ -121,18 +136,5 @@ inline void event_dispatcher::schedule(const event_base& event, double time) scheduled_events.insert(std::pair(time, event.clone())); } -inline void event_dispatcher::dispatch(const event_base& event) -{ - // Get list of handlers for this type of event - const std::list& handlers = handler_map[event.get_event_type_id()]; - - // For each handler - for (auto handler = handlers.begin(); handler != handlers.end(); ++handler) - { - // Pass event to the handler - (*handler)->route_event(event); - } -} - #endif // ANTKEEPER_EVENT_DISPATCHER_HPP diff --git a/src/game/context.hpp b/src/game/context.hpp index 96bdb6a..d5513f3 100644 --- a/src/game/context.hpp +++ b/src/game/context.hpp @@ -205,81 +205,10 @@ struct context scene::billboard* camera_flash_billboard; scene::text* title_text; scene::text* title_press_any_key_text; - scene::text* main_menu_start_text; - scene::text* main_menu_options_text; - scene::text* main_menu_credits_text; - scene::text* main_menu_quit_text; - std::vector main_menu_texts; - int main_menu_index; scene::text* credits_text; - scene::text* options_menu_controls_text; - scene::text* options_menu_graphics_text; - scene::text* options_menu_sound_text; - scene::text* options_menu_language_text; - scene::text* options_menu_back_text; - std::vector options_menu_texts; - std::vector> options_menu_callbacks; - int options_menu_index; - scene::text* controls_menu_configure_keyboard_mouse_label_text; - scene::text* controls_menu_configure_game_controller_label_text; - scene::text* controls_menu_back_label_text; - std::vector controls_menu_label_texts; - std::vector controls_menu_value_texts; - int controls_menu_index; - std::vector> controls_menu_select_callbacks; - std::vector> controls_menu_left_callbacks; - std::vector> controls_menu_right_callbacks; - scene::text* language_menu_language_text; - scene::text* language_menu_back_text; - std::vector language_menu_texts; - std::vector> language_menu_callbacks; - int language_menu_index; - scene::text* sound_menu_master_volume_label_text; - scene::text* sound_menu_master_volume_value_text; - scene::text* sound_menu_ambience_volume_label_text; - scene::text* sound_menu_ambience_volume_value_text; - scene::text* sound_menu_effects_volume_label_text; - scene::text* sound_menu_effects_volume_value_text; - scene::text* sound_menu_mono_audio_label_text; - scene::text* sound_menu_mono_audio_value_text; - scene::text* sound_menu_captions_label_text; - scene::text* sound_menu_captions_value_text; - scene::text* sound_menu_captions_size_label_text; - scene::text* sound_menu_captions_size_value_text; - scene::text* sound_menu_back_label_text; - std::vector sound_menu_label_texts; - std::vector sound_menu_value_texts; - int sound_menu_index; - std::vector> sound_menu_select_callbacks; - std::vector> sound_menu_left_callbacks; - std::vector> sound_menu_right_callbacks; - scene::text* graphics_menu_display_mode_label_text; - scene::text* graphics_menu_display_mode_value_text; - scene::text* graphics_menu_render_resolution_label_text; - scene::text* graphics_menu_render_resolution_value_text; - scene::text* graphics_menu_v_sync_label_text; - scene::text* graphics_menu_v_sync_value_text; - scene::text* graphics_menu_font_size_label_text; - scene::text* graphics_menu_font_size_value_text; - scene::text* graphics_menu_dyslexia_font_label_text; - scene::text* graphics_menu_dyslexia_font_value_text; - scene::text* graphics_menu_back_label_text; - std::vector graphics_menu_label_texts; - std::vector graphics_menu_value_texts; - int graphics_menu_index; - std::vector> graphics_menu_select_callbacks; - std::vector> graphics_menu_left_callbacks; - std::vector> graphics_menu_right_callbacks; - std::vector keyboard_config_menu_label_texts; - std::vector keyboard_config_menu_value_texts; - int keyboard_config_menu_index; - std::vector> keyboard_config_menu_select_callbacks; - std::vector> keyboard_config_menu_left_callbacks; - std::vector> keyboard_config_menu_right_callbacks; float font_size; bool dyslexia_font; ui::mouse_tracker* menu_mouse_tracker; - std::vector> menu_select_callbacks; std::vector> menu_left_callbacks; std::vector> menu_right_callbacks; diff --git a/src/game/states/boot.cpp b/src/game/states/boot.cpp index a780d05..5a2d947 100644 --- a/src/game/states/boot.cpp +++ b/src/game/states/boot.cpp @@ -1004,14 +1004,6 @@ void setup_ui(game::context* ctx) if (ctx->config->contains("dyslexia_font")) ctx->dyslexia_font = (*ctx->config)["dyslexia_font"].get(); - ctx->main_menu_index = 0; - ctx->options_menu_index = 0; - ctx->controls_menu_index = 0; - ctx->graphics_menu_index = 0; - ctx->sound_menu_index = 0; - ctx->language_menu_index = 0; - ctx->keyboard_config_menu_index = 0; - // Construct mouse tracker ctx->menu_mouse_tracker = new ui::mouse_tracker(); ctx->app->get_event_dispatcher()->subscribe(ctx->menu_mouse_tracker); diff --git a/src/game/states/controller-config-menu.cpp b/src/game/states/controller-config-menu.cpp index 08d2a6e..fea7de7 100644 --- a/src/game/states/controller-config-menu.cpp +++ b/src/game/states/controller-config-menu.cpp @@ -23,19 +23,322 @@ #include "scene/text.hpp" #include "render/passes/clear-pass.hpp" #include "debug/logger.hpp" +#include "resources/resource-manager.hpp" +#include "game/menu.hpp" +#include "animation/timeline.hpp" namespace game { namespace state { namespace controller_config_menu { -void enter(game::context* ctx) +static std::string get_binding_string(game::context* ctx, input::control* control) { + std::string binding_string; + + auto mappings = ctx->input_event_router->get_mappings(control); + for (input::mapping* mapping: *mappings) + { + std::string mapping_string; + + switch (mapping->get_type()) + { + case input::mapping_type::gamepad_axis: + { + const input::gamepad_axis_mapping* axis_mapping = static_cast(mapping); + + switch (axis_mapping->axis) + { + case input::gamepad_axis::left_x: + if (axis_mapping->negative) + mapping_string = (*ctx->strings)["gamepad_left_stick_left"]; + else + mapping_string = (*ctx->strings)["gamepad_left_stick_right"]; + break; + + case input::gamepad_axis::left_y: + if (axis_mapping->negative) + mapping_string = (*ctx->strings)["gamepad_left_stick_up"]; + else + mapping_string = (*ctx->strings)["gamepad_left_stick_down"]; + break; + + case input::gamepad_axis::right_x: + if (axis_mapping->negative) + mapping_string = (*ctx->strings)["gamepad_right_stick_left"]; + else + mapping_string = (*ctx->strings)["gamepad_right_stick_right"]; + break; + + case input::gamepad_axis::right_y: + if (axis_mapping->negative) + mapping_string = (*ctx->strings)["gamepad_right_stick_up"]; + else + mapping_string = (*ctx->strings)["gamepad_right_stick_down"]; + break; + + case input::gamepad_axis::left_trigger: + mapping_string = (*ctx->strings)["gamepad_left_trigger"]; + break; + + case input::gamepad_axis::right_trigger: + mapping_string = (*ctx->strings)["gamepad_right_trigger"]; + break; + + default: + break; + } + break; + } + + case input::mapping_type::gamepad_button: + { + const input::gamepad_button_mapping* button_mapping = static_cast(mapping); + + switch (button_mapping->button) + { + case input::gamepad_button::a: + mapping_string = (*ctx->strings)["gamepad_button_a"]; + break; + + case input::gamepad_button::b: + mapping_string = (*ctx->strings)["gamepad_button_b"]; + break; + + case input::gamepad_button::x: + mapping_string = (*ctx->strings)["gamepad_button_x"]; + break; + + case input::gamepad_button::y: + mapping_string = (*ctx->strings)["gamepad_button_y"]; + break; + + case input::gamepad_button::back: + mapping_string = (*ctx->strings)["gamepad_button_back"]; + break; + + case input::gamepad_button::guide: + mapping_string = (*ctx->strings)["gamepad_button_guide"]; + break; + + case input::gamepad_button::start: + mapping_string = (*ctx->strings)["gamepad_button_start"]; + break; + + case input::gamepad_button::left_stick: + mapping_string = (*ctx->strings)["gamepad_button_left_stick"]; + break; + + case input::gamepad_button::right_stick: + mapping_string = (*ctx->strings)["gamepad_button_right_stick"]; + break; + + case input::gamepad_button::left_shoulder: + mapping_string = (*ctx->strings)["gamepad_button_left_shoulder"]; + break; + + case input::gamepad_button::right_shoulder: + mapping_string = (*ctx->strings)["gamepad_button_right_shoulder"]; + break; + + case input::gamepad_button::dpad_up: + mapping_string = (*ctx->strings)["gamepad_button_dpad_up"]; + break; + + case input::gamepad_button::dpad_down: + mapping_string = (*ctx->strings)["gamepad_button_dpad_down"]; + break; + + case input::gamepad_button::dpad_left: + mapping_string = (*ctx->strings)["gamepad_button_dpad_left"]; + break; + + case input::gamepad_button::dpad_right: + mapping_string = (*ctx->strings)["gamepad_button_dpad_right"]; + break; + + default: + break; + } + break; + } + + default: + break; + } + + if (!mapping_string.empty()) + { + if (binding_string.empty()) + { + binding_string = mapping_string; + } + else + { + binding_string += " " + mapping_string; + } + } + } + + return binding_string; +} +static void add_control_item(game::context* ctx, const std::string& control_name) +{ + // Get pointer to control + input::control* control = ctx->controls[control_name]; + + // Construct texts + scene::text* name_text = new scene::text(); + scene::text* value_text = new scene::text(); + + // Add texts to list of menu item texts + ctx->menu_item_texts.push_back({name_text, value_text}); + + // Set content of name text + std::string string_name = "control_" + control_name; + if (auto it = ctx->strings->find(string_name); it != ctx->strings->end()) + name_text->set_content(it->second); + else + name_text->set_content(control_name); + + // Set content of value text + value_text->set_content(get_binding_string(ctx, control)); + + auto select_callback = [ctx, control, value_text]() + { + // Clear binding string from value text + value_text->set_content((*ctx->strings)["ellipsis"]); + game::menu::align_text(ctx); + game::menu::update_text_tweens(ctx); + + // Disable controls + game::menu::clear_controls(ctx); + + // Remove gamepad event mappings from control + ctx->input_event_router->remove_mappings(control, input::mapping_type::gamepad_axis); + ctx->input_event_router->remove_mappings(control, input::mapping_type::gamepad_button); + + // Setup input binding listener + ctx->input_listener->set_callback + ( + [ctx, control, value_text](const event_base& event) + { + auto id = event.get_event_type_id(); + if (id == gamepad_axis_moved_event::event_type_id) + { + // Map gamepad axis event to control + const gamepad_axis_moved_event& axis_event = static_cast(event); + if (std::abs(axis_event.value) < 0.5f) + return; + + ctx->input_event_router->add_mapping(input::gamepad_axis_mapping(control, nullptr, axis_event.axis, (axis_event.value < 0))); + } + else if (id == gamepad_button_pressed_event::event_type_id) + { + // Map gamepad button event to control + const gamepad_button_pressed_event& button_event = static_cast(event); + ctx->input_event_router->add_mapping(input::gamepad_button_mapping(control, nullptr, button_event.button)); + } + else + { + return; + } + + // Update menu text + value_text->set_content(get_binding_string(ctx, control)); + game::menu::align_text(ctx); + game::menu::update_text_tweens(ctx); + + // Disable input listener + ctx->input_listener->set_enabled(false); + ctx->input_listener->set_callback(nullptr); + + // Schedule re-enabling of menu controls + timeline* timeline = ctx->timeline; + float t = timeline->get_position(); + timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); + } + ); + ctx->input_listener->set_enabled(true); + }; + + // Register menu item callbacks + ctx->menu_select_callbacks.push_back(select_callback); + ctx->menu_left_callbacks.push_back(nullptr); + ctx->menu_right_callbacks.push_back(nullptr); } -void exit(game::context* ctx) +void enter(game::context* ctx) { + ctx->ui_clear_pass->set_cleared_buffers(true, true, false); + + // Add camera control menu items + add_control_item(ctx, "dolly_forward"); + add_control_item(ctx, "dolly_backward"); + add_control_item(ctx, "truck_left"); + add_control_item(ctx, "truck_right"); + add_control_item(ctx, "pedestal_up"); + add_control_item(ctx, "pedestal_down"); + + // Add application control menu items + add_control_item(ctx, "toggle_fullscreen"); + add_control_item(ctx, "screenshot"); + + // Construct menu item texts + scene::text* back_text = new scene::text(); + + // Build list of menu item texts + ctx->menu_item_texts.push_back({back_text, nullptr}); + + // Set content of menu item texts + back_text->set_content((*ctx->strings)["back"]); + + // Init menu item index + game::menu::init_menu_item_index(ctx, "controller_config"); + + game::menu::update_text_color(ctx); + game::menu::update_text_font(ctx); + game::menu::align_text(ctx); + game::menu::update_text_tweens(ctx); + game::menu::add_text_to_ui(ctx); + + // Construct menu item callbacks + auto select_back_callback = [ctx]() + { + application::state next_state; + next_state.name = "controls_menu"; + next_state.enter = std::bind(game::state::controls_menu::enter, ctx); + next_state.exit = std::bind(game::state::controls_menu::exit, ctx); + ctx->app->change_state(next_state); + }; + + // Build list of menu select callbacks + ctx->menu_select_callbacks.push_back(select_back_callback); + + // Build list of menu left callbacks + ctx->menu_left_callbacks.push_back(nullptr); + + // Build list of menu right callbacks + ctx->menu_right_callbacks.push_back(nullptr); + + // Set menu back callback + ctx->menu_back_callback = select_back_callback; + + // Schedule menu control setup + timeline* timeline = ctx->timeline; + float t = timeline->get_position(); + timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); +} +void exit(game::context* ctx) +{ + // Destruct menu + game::menu::clear_controls(ctx); + game::menu::clear_callbacks(ctx); + game::menu::remove_text_from_ui(ctx); + game::menu::delete_text(ctx); + + ctx->ui_clear_pass->set_cleared_buffers(false, true, false); } } // namespace controller_config_menu diff --git a/src/game/states/keyboard-config-menu.cpp b/src/game/states/keyboard-config-menu.cpp index 91fdb45..ab79c54 100644 --- a/src/game/states/keyboard-config-menu.cpp +++ b/src/game/states/keyboard-config-menu.cpp @@ -24,30 +24,282 @@ #include "render/passes/clear-pass.hpp" #include "debug/logger.hpp" #include "resources/resource-manager.hpp" +#include "game/menu.hpp" +#include "animation/timeline.hpp" namespace game { namespace state { namespace keyboard_config_menu { -void enter(game::context* ctx) +static std::string get_binding_string(game::context* ctx, input::control* control) { - // Load control profile - if (ctx->config->contains("control_profile")) + std::string binding_string; + + auto mappings = ctx->input_event_router->get_mappings(control); + for (input::mapping* mapping: *mappings) { - json* profile = ctx->resource_manager->load((*ctx->config)["control_profile"].get()); + std::string mapping_string; - for (auto& control_element: (*profile)["controls"].items()) + switch (mapping->get_type()) { - ctx->logger->log(control_element.key()); + case input::mapping_type::key: + { + const input::key_mapping* key_mapping = static_cast(mapping); + const char* scancode_name = input::keyboard::get_scancode_name(key_mapping->scancode); + mapping_string = scancode_name; + break; + } + + case input::mapping_type::mouse_wheel: + { + const input::mouse_wheel_mapping* wheel_mapping = static_cast(mapping); + + switch (wheel_mapping->axis) + { + case input::mouse_wheel_axis::negative_x: + mapping_string = (*ctx->strings)["mouse_wheel_left"]; + break; + + case input::mouse_wheel_axis::positive_x: + mapping_string = (*ctx->strings)["mouse_wheel_right"]; + break; + + case input::mouse_wheel_axis::negative_y: + mapping_string = (*ctx->strings)["mouse_wheel_down"]; + break; + + case input::mouse_wheel_axis::positive_y: + mapping_string = (*ctx->strings)["mouse_wheel_up"]; + break; + + default: + break; + } + break; + } + + case input::mapping_type::mouse_button: + { + const input::mouse_button_mapping* button_mapping = static_cast(mapping); + + if (button_mapping->button == 1) + { + mapping_string = (*ctx->strings)["mouse_button_left"]; + } + else if (button_mapping->button == 2) + { + mapping_string = (*ctx->strings)["mouse_button_middle"]; + } + else if (button_mapping->button == 3) + { + mapping_string = (*ctx->strings)["mouse_button_right"]; + } + else + { + const std::string& format = (*ctx->strings)["mouse_button_n"]; + char buffer[64]; + std::snprintf(buffer, 64, format.c_str(), button_mapping->button); + mapping_string = buffer; + } + break; + } + default: + break; + } + + if (!mapping_string.empty()) + { + if (binding_string.empty()) + { + binding_string = mapping_string; + } + else + { + binding_string += " " + mapping_string; + } } } + + return binding_string; } -void exit(game::context* ctx) +static void add_control_item(game::context* ctx, const std::string& control_name) { + // Get pointer to control + input::control* control = ctx->controls[control_name]; + + // Construct texts + scene::text* name_text = new scene::text(); + scene::text* value_text = new scene::text(); + + // Add texts to list of menu item texts + ctx->menu_item_texts.push_back({name_text, value_text}); + + // Set content of name text + std::string string_name = "control_" + control_name; + if (auto it = ctx->strings->find(string_name); it != ctx->strings->end()) + name_text->set_content(it->second); + else + name_text->set_content(control_name); + + // Set content of value text + value_text->set_content(get_binding_string(ctx, control)); + + auto select_callback = [ctx, control, value_text]() + { + // Clear binding string from value text + value_text->set_content((*ctx->strings)["ellipsis"]); + game::menu::align_text(ctx); + game::menu::update_text_tweens(ctx); + + // Disable controls + game::menu::clear_controls(ctx); + + // Remove keyboard and mouse event mappings from control + ctx->input_event_router->remove_mappings(control, input::mapping_type::key); + ctx->input_event_router->remove_mappings(control, input::mapping_type::mouse_motion); + ctx->input_event_router->remove_mappings(control, input::mapping_type::mouse_wheel); + ctx->input_event_router->remove_mappings(control, input::mapping_type::mouse_button); + + // Setup input binding listener + ctx->input_listener->set_callback + ( + [ctx, control, value_text](const event_base& event) + { + auto id = event.get_event_type_id(); + if (id == key_pressed_event::event_type_id) + { + // Map key pressed event to control + const key_pressed_event& key_event = static_cast(event); + ctx->input_event_router->add_mapping(input::key_mapping(control, key_event.keyboard, key_event.scancode)); + } + else if (id == mouse_wheel_scrolled_event::event_type_id) + { + // Map mouse wheel scrolled event to control + const mouse_wheel_scrolled_event& wheel_event = static_cast(event); + input::mouse_wheel_axis axis; + + if (wheel_event.x < 0) + axis = input::mouse_wheel_axis::negative_x; + else if (wheel_event.x > 0) + axis = input::mouse_wheel_axis::positive_x; + else if (wheel_event.y < 0) + axis = input::mouse_wheel_axis::negative_y; + else if (wheel_event.y > 0) + axis = input::mouse_wheel_axis::positive_y; + else + return; + + ctx->input_event_router->add_mapping(input::mouse_wheel_mapping(control, wheel_event.mouse, axis)); + } + else if (id == mouse_button_pressed_event::event_type_id) + { + // Map mouse button pressed event to control + const mouse_button_pressed_event& button_event = static_cast(event); + ctx->input_event_router->add_mapping(input::mouse_button_mapping(control, button_event.mouse, button_event.button)); + } + else + { + return; + } + + // Update menu text + value_text->set_content(get_binding_string(ctx, control)); + game::menu::align_text(ctx); + game::menu::update_text_tweens(ctx); + + // Disable input listener + ctx->input_listener->set_enabled(false); + ctx->input_listener->set_callback(nullptr); + + // Schedule re-enabling of menu controls + timeline* timeline = ctx->timeline; + float t = timeline->get_position(); + timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); + } + ); + ctx->input_listener->set_enabled(true); + }; + + // Register menu item callbacks + ctx->menu_select_callbacks.push_back(select_callback); + ctx->menu_left_callbacks.push_back(nullptr); + ctx->menu_right_callbacks.push_back(nullptr); +} +void enter(game::context* ctx) +{ + ctx->ui_clear_pass->set_cleared_buffers(true, true, false); + + // Add camera control menu items + add_control_item(ctx, "dolly_forward"); + add_control_item(ctx, "dolly_backward"); + add_control_item(ctx, "truck_left"); + add_control_item(ctx, "truck_right"); + add_control_item(ctx, "pedestal_up"); + add_control_item(ctx, "pedestal_down"); + + // Add application control menu items + add_control_item(ctx, "toggle_fullscreen"); + add_control_item(ctx, "screenshot"); + + // Construct menu item texts + scene::text* back_text = new scene::text(); + + // Build list of menu item texts + ctx->menu_item_texts.push_back({back_text, nullptr}); + + // Set content of menu item texts + back_text->set_content((*ctx->strings)["back"]); + + // Init menu item index + game::menu::init_menu_item_index(ctx, "keyboard_config"); + + game::menu::update_text_color(ctx); + game::menu::update_text_font(ctx); + game::menu::align_text(ctx); + game::menu::update_text_tweens(ctx); + game::menu::add_text_to_ui(ctx); + + // Construct menu item callbacks + auto select_back_callback = [ctx]() + { + application::state next_state; + next_state.name = "controls_menu"; + next_state.enter = std::bind(game::state::controls_menu::enter, ctx); + next_state.exit = std::bind(game::state::controls_menu::exit, ctx); + ctx->app->change_state(next_state); + }; + + // Build list of menu select callbacks + ctx->menu_select_callbacks.push_back(select_back_callback); + + // Build list of menu left callbacks + ctx->menu_left_callbacks.push_back(nullptr); + + // Build list of menu right callbacks + ctx->menu_right_callbacks.push_back(nullptr); + + // Set menu back callback + ctx->menu_back_callback = select_back_callback; + + // Schedule menu control setup + timeline* timeline = ctx->timeline; + float t = timeline->get_position(); + timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); +} + +void exit(game::context* ctx) +{ + // Destruct menu + game::menu::clear_controls(ctx); + game::menu::clear_callbacks(ctx); + game::menu::remove_text_from_ui(ctx); + game::menu::delete_text(ctx); + + ctx->ui_clear_pass->set_cleared_buffers(false, true, false); } } // namespace keyboard_config_menu diff --git a/src/input/event-router.cpp b/src/input/event-router.cpp index bc94930..157f65b 100644 --- a/src/input/event-router.cpp +++ b/src/input/event-router.cpp @@ -144,6 +144,61 @@ void event_router::remove_mappings(control* control) } } +void event_router::remove_mappings(control* control, mapping_type type) +{ + auto it = controls.find(control); + if (it != controls.end()) + { + std::list flagged_mappings; + + for (mapping* mapping: it->second) + { + if (mapping->get_type() != type) + continue; + + // Flag mapping for deletion + flagged_mappings.push_back(mapping); + + switch (mapping->get_type()) + { + case mapping_type::key: + key_mappings.remove(static_cast(mapping)); + break; + + case mapping_type::mouse_motion: + mouse_motion_mappings.remove(static_cast(mapping)); + break; + + case mapping_type::mouse_wheel: + mouse_wheel_mappings.remove(static_cast(mapping)); + break; + + case mapping_type::mouse_button: + mouse_button_mappings.remove(static_cast(mapping)); + break; + + case mapping_type::gamepad_axis: + gamepad_axis_mappings.remove(static_cast(mapping)); + break; + + case mapping_type::gamepad_button: + gamepad_button_mappings.remove(static_cast(mapping)); + break; + + default: + break; + } + } + + // Delete flagged mappings + for (mapping* mapping: flagged_mappings) + { + it->second.remove(mapping); + delete mapping; + } + } +} + void event_router::set_event_dispatcher(::event_dispatcher* event_dispatcher) { if (this->event_dispatcher) diff --git a/src/input/event-router.hpp b/src/input/event-router.hpp index dc60c82..00ba571 100644 --- a/src/input/event-router.hpp +++ b/src/input/event-router.hpp @@ -29,6 +29,7 @@ namespace input { class control; +enum class mapping_type; class mapping; class key_mapping; class mouse_motion_mapping; @@ -75,19 +76,27 @@ public: /** * Removes all input mappings from the router that are associated with the specified control. * - * @param control control with which associated input mappings should be removed. + * @param control Control with which associated input mappings should be removed. */ void remove_mappings(control* control); - + /** - * Sets the event dispatcher to which this input event router will subscribe itself. + * Removes all input mappings of a given type from the router that are associated with the specified control. + * + * @param control Control with which associated input mappings should be removed. + * @param type Type of input mapping to be removed. */ - void set_event_dispatcher(event_dispatcher* event_dispatcher); + void remove_mappings(control* control, mapping_type type); /** * Removes all input mappings from the router. */ void remove_mappings(); + + /** + * Sets the event dispatcher to which this input event router will subscribe itself. + */ + void set_event_dispatcher(event_dispatcher* event_dispatcher); /// Returns a list of mappings for the specified control, or nullptr if the control is unmapped. const std::list* get_mappings(control* control) const; diff --git a/src/input/listener.cpp b/src/input/listener.cpp index 1cb9a74..c1f10ee 100644 --- a/src/input/listener.cpp +++ b/src/input/listener.cpp @@ -19,6 +19,7 @@ #include "listener.hpp" #include "event/event-dispatcher.hpp" +#include namespace input { @@ -35,26 +36,29 @@ listener::~listener() void listener::set_event_dispatcher(::event_dispatcher* event_dispatcher) { - if (this->event_dispatcher) + if (event_dispatcher != this->event_dispatcher) { - this->event_dispatcher->unsubscribe(this); - this->event_dispatcher->unsubscribe(this); - this->event_dispatcher->unsubscribe(this); - this->event_dispatcher->unsubscribe(this); - this->event_dispatcher->unsubscribe(this); - this->event_dispatcher->unsubscribe(this); - } - - this->event_dispatcher = event_dispatcher; - - if (event_dispatcher) - { - event_dispatcher->subscribe(this); - event_dispatcher->subscribe(this); - event_dispatcher->subscribe(this); - event_dispatcher->subscribe(this); - event_dispatcher->subscribe(this); - event_dispatcher->subscribe(this); + if (this->event_dispatcher) + { + this->event_dispatcher->unsubscribe(this); + this->event_dispatcher->unsubscribe(this); + this->event_dispatcher->unsubscribe(this); + this->event_dispatcher->unsubscribe(this); + this->event_dispatcher->unsubscribe(this); + this->event_dispatcher->unsubscribe(this); + } + + if (event_dispatcher) + { + event_dispatcher->subscribe(this); + event_dispatcher->subscribe(this); + event_dispatcher->subscribe(this); + event_dispatcher->subscribe(this); + event_dispatcher->subscribe(this); + event_dispatcher->subscribe(this); + } + + this->event_dispatcher = event_dispatcher; } } @@ -70,62 +74,38 @@ void listener::set_enabled(bool enabled) void listener::handle_event(const key_pressed_event& event) { - if (!is_enabled() || !callback) - { - return; - } - - callback(event); + if (enabled && callback) + callback(event); } void listener::handle_event(const mouse_moved_event& event) { - if (!is_enabled() || !callback) - { - return; - } - - callback(event); + if (enabled && callback) + callback(event); } void listener::handle_event(const mouse_button_pressed_event& event) { - if (!is_enabled() || !callback) - { - return; - } - - callback(event); + if (enabled && callback) + callback(event); } void listener::handle_event(const mouse_wheel_scrolled_event& event) { - if (!is_enabled() || !callback) - { - return; - } - - callback(event); + if (enabled && callback) + callback(event); } void listener::handle_event(const gamepad_button_pressed_event& event) { - if (!is_enabled() || !callback) - { - return; - } - - callback(event); + if (enabled && callback) + callback(event); } void listener::handle_event(const gamepad_axis_moved_event& event) { - if (!is_enabled() || !callback) - { - return; - } - - callback(event); + if (enabled && callback) + callback(event); } } // namespace input