1
0
mirror of synced 2025-02-02 12:27:20 +01:00

Key Mapping menu

This commit is contained in:
Stepland 2020-03-08 03:25:07 +01:00
parent 4d153414b7
commit f4a4dc7de7
15 changed files with 341 additions and 18 deletions

View File

@ -33,6 +33,7 @@
- Options menu
- Marker Selection
- Fix screen filter not resizing properly
- Controller mapping
## Misc
- Handling Resolution changes

View File

@ -2,8 +2,6 @@
## Misc
## Music Select Screen
- Options menu
- Controller mapping
- Visible controls
- Start Button

View File

@ -53,8 +53,10 @@ sources = [
'src/Screens/MusicSelect/MusicPreview.cpp',
'src/Screens/MusicSelect/MusicSelect.hpp',
'src/Screens/MusicSelect/MusicSelect.cpp',
'src/Screens/MusicSelect/OptionPage.hpp',
'src/Screens/MusicSelect/OptionPage.cpp',
'src/Screens/MusicSelect/Options/OptionPage.hpp',
'src/Screens/MusicSelect/Options/OptionPage.cpp',
'src/Screens/MusicSelect/Options/InputRemap.hpp',
'src/Screens/MusicSelect/Options/InputRemap.cpp',
'src/Screens/MusicSelect/Panels/MarkerPanel.hpp',
'src/Screens/MusicSelect/Panels/MarkerPanel.cpp',
'src/Screens/MusicSelect/Panels/Panel.hpp',

View File

@ -30,7 +30,14 @@ namespace Data {
for (auto &&[button, key] : m_button_to_key) {
m_key_to_button[key] = button;
}
assert((m_button_to_key.size() == m_key_to_button.size()));
}
KeyMapping::KeyMapping(std::unordered_map<sf::Keyboard::Key, Button> key_to_button) : m_key_to_button(key_to_button) {
for (auto &&[key, button] : m_key_to_button) {
m_button_to_key[button] = key;
}
assert((m_button_to_key.size() == m_key_to_button.size()));
}
void KeyMapping::set_button_to_key(const Button& button, const sf::Keyboard::Key& key) {

View File

@ -16,6 +16,7 @@ namespace Data {
public:
KeyMapping();
explicit KeyMapping(std::unordered_map<Button, sf::Keyboard::Key> button_to_key);
explicit KeyMapping(std::unordered_map<sf::Keyboard::Key, Button> button_to_key);
void set_button_to_key(const Button& button, const sf::Keyboard::Key& key);
std::optional<Button> key_to_button(const sf::Keyboard::Key& key);
std::optional<sf::Keyboard::Key> button_to_key(const Button& button);

View File

@ -136,9 +136,10 @@ namespace Data {
float get_screen_height() const {return static_cast<float>(preferences.screen.height);};
float get_panel_size() const {return preferences.layout.panel_size*get_screen_width();};
float get_panel_spacing() const {return preferences.layout.panel_spacing*get_screen_width();};
float get_panel_step() const {return preferences.layout.panel_step()*get_screen_width();};
float get_ribbon_x() const {return preferences.layout.ribbon_x*get_screen_width();};
float get_ribbon_y() const {return preferences.layout.ribbon_y*get_screen_width();};
float get_panel_step() const {return preferences.layout.panel_step()*get_screen_width();};
float get_ribbon_size() const {return 3*get_panel_spacing()+4*get_panel_size();};
float get_big_cover_x() const {return preferences.layout.big_cover_x*get_screen_width();};
float get_big_cover_y() const {return preferences.layout.big_cover_y*get_screen_width();};
float get_big_level_x() const {return preferences.layout.big_level_x*get_screen_width();};

View File

@ -70,6 +70,13 @@ void MusicSelect::Screen::select_chart(sf::RenderWindow& window) {
if (not resources.options_state.empty()) {
window.draw(panel_filter);
window.draw(resources.options_state.back());
if (resources.options_state.back().get().should_exit()) {
resources.options_state.back().get().exit();
resources.options_state.pop_back();
if (not resources.options_state.empty()) {
resources.options_state.back().get().update();
}
}
}
window.draw(resources.button_highlight);
window.draw(black_frame);
@ -125,6 +132,7 @@ void MusicSelect::Screen::handle_key_press(const sf::Event::KeyEvent& key_event)
if (not resources.options_state.empty()) {
// Safety measure, pressing escape will alway pop the menu page
if (key_event.code == sf::Keyboard::Escape) {
resources.options_state.back().get().exit();
resources.options_state.pop_back();
if (not resources.options_state.empty()) {
resources.options_state.back().get().update();
@ -137,7 +145,7 @@ void MusicSelect::Screen::handle_key_press(const sf::Event::KeyEvent& key_event)
if (output_used) {
return;
}
auto button = key_mapping.key_to_button(key_event.code);
auto button = resources.preferences.key_mapping.key_to_button(key_event.code);
if (button) {
press_button(*button);
} else {
@ -200,6 +208,7 @@ void MusicSelect::Screen::press_button(const Data::Button& button) {
resources.options_state.push_back(main_option_page);
resources.options_state.back().get().update();
} else {
resources.options_state.back().get().exit();
resources.options_state.pop_back();
if (not resources.options_state.empty()) {
resources.options_state.back().get().update();

View File

@ -16,7 +16,7 @@
#include "Ribbon.hpp"
#include "SongInfo.hpp"
#include "SharedResources.hpp"
#include "OptionPage.hpp"
#include "Options/OptionPage.hpp"
namespace MusicSelect {
@ -43,7 +43,6 @@ namespace MusicSelect {
Drawables::BlackFrame black_frame;
sf::RectangleShape panel_filter;
Data::KeyMapping key_mapping;
// converts a key press into a button press
void handle_key_press(const sf::Event::KeyEvent& key_event);
// converts a mouse click into a button press

View File

@ -0,0 +1,201 @@
#include "InputRemap.hpp"
#include <cmath>
#include <magic_enum.hpp>
#include "../../../Toolkit/HSL.hpp"
#include "../../../Toolkit/NormalizedOrigin.hpp"
namespace MusicSelect {
PressHere::PressHere(SharedResources& t_resources) :
HoldsSharedResources(t_resources),
color_anim(0.0f, 1.0f, 1.0f, 0.1f),
size_anim(0.0f, 1.0f, 1.0f, 0.7f)
{
message.setFont(resources.fallback_font.black);
message.setString("PRESS\nHERE!");
message.setFillColor(sf::Color::White);
message.setCharacterSize(static_cast<unsigned int>(0.2f*get_panel_size()));
auto bounds = message.getLocalBounds();
auto biggest_side = std::max(bounds.width, bounds.height);
if (biggest_side > get_panel_size()*0.8f) {
message.setScale(get_panel_size()*0.8f / biggest_side, get_panel_size()*0.8f / biggest_side);
}
}
void PressHere::update() {
message.setCharacterSize(static_cast<unsigned int>(0.2f*get_panel_size()));
Toolkit::set_local_origin_normalized(message, 0.5f, 0.5f);
message.setPosition(get_panel_size()*0.5f, get_panel_size()*0.5f);
auto anim_time = std::fmod(time.getElapsedTime().asSeconds(), 1.f);
auto color_factor = color_anim.transform(anim_time);
background.setFillColor(sf::Color(255, 255, 255, static_cast<unsigned int>(128*color_factor)));
auto size_factor = size_anim.transform(anim_time);
background.setSize(sf::Vector2f{get_panel_size()*size_factor, get_panel_size()*size_factor});
Toolkit::set_local_origin_normalized(background, 0.5f, 0.5f);
background.setPosition(get_panel_size()/2.f, get_panel_size()/2.f);
}
void PressHere::draw(sf::RenderTarget& target, sf::RenderStates states) const {
states.transform *= getTransform();
target.draw(background, states);
target.draw(message, states);
}
AlreadyMapped::AlreadyMapped(SharedResources& t_resources) : HoldsSharedResources(t_resources) {
background.setFillColor(resources.BSC_color);
}
void AlreadyMapped::update() {
background.setSize(sf::Vector2f{get_panel_size(), get_panel_size()});
}
void AlreadyMapped::draw(sf::RenderTarget& target, sf::RenderStates states) const {
states.transform *= getTransform();
target.draw(background, states);
}
MappingPreview::MappingPreview(
SharedResources& t_resources,
const std::unordered_map<sf::Keyboard::Key, Data::Button>& t_key_to_button
) :
HoldsSharedResources(t_resources),
key_to_button(t_key_to_button)
{
square.setFillColor(sf::Color::Transparent);
square.setOutlineThickness(1.f);
square.setOutlineColor(sf::Color::White);
key_label.setFillColor(sf::Color::White);
key_label.setFont(resources.fallback_font.medium);
}
void MappingPreview::draw(sf::RenderTarget& target, sf::RenderStates states) const {
states.transform *= getTransform();
auto gird_size = preferences.layout.big_cover_size*get_screen_width();
auto square_size = 0.22f*gird_size;
auto square_step = 0.26f*gird_size;
square.setSize(sf::Vector2f(square_size, square_size));
for (size_t i = 0; i < 16; i++) {
auto column = i%4;
auto row = i/4;
square.setPosition(column*square_step, row*square_step);
target.draw(square, states);
}
auto text_size = square_size*0.33f;
for (auto &&[key, button] : key_to_button) {
auto coord = Data::button_to_coords(button);
std::string key_name{magic_enum::enum_name(key)};
key_label.setString(key_name);
key_label.setCharacterSize(static_cast<unsigned int>(text_size));
Toolkit::set_local_origin_normalized(key_label, 0.5f, 0.5f);
auto bounds = key_label.getLocalBounds();
auto biggest_side = std::max(bounds.width, bounds.height);
if (biggest_side > square_size*0.95f) {
key_label.setScale(square_size*0.95f / biggest_side, square_size*0.95f / biggest_side);
}
key_label.setPosition(coord.x*square_step + 0.5f*square_size, coord.y*square_step + 0.5f*square_size);
target.draw(key_label, states);
}
}
InputRemap::InputRemap(SharedResources& t_resources) :
OptionPage(t_resources),
press_here_panel(t_resources),
already_mapped_panel(t_resources),
mapping_preview(t_resources, m_key_to_button)
{
confirm_text_top.setString("Are you sure about this setting ?");
confirm_text_top.setFillColor(resources.EXT_color);
confirm_text_top.setFont(resources.fallback_font.black);
confirm_text_bottom.setString("Press any key to cancel");
confirm_text_bottom.setFillColor(resources.EXT_color);
confirm_text_bottom.setFont(resources.fallback_font.black);
big_number.setFillColor(sf::Color::Black);
big_number.setFont(resources.fallback_font.black);
}
bool InputRemap::handle_raw_input(const sf::Event::KeyEvent& event) {
if (next_button < 16) {
if (m_key_to_button.find(event.code) == m_key_to_button.end()) {
m_key_to_button[event.code] = *Data::index_to_button(next_button);
last_key_press.restart();
next_button++;
if (next_button == 16) {
confirm_clock.emplace();
}
}
} else {
cancel_remapping = true;
}
return true; // we need to capute all input
}
bool InputRemap::should_exit() {
if (cancel_remapping) {
return true;
} else {
if (confirm_clock) {
return confirm_clock->getElapsedTime() > sf::seconds(5);
} else {
return false;
}
}
}
void InputRemap::exit() {
if (not cancel_remapping) {
if (confirm_clock) {
if (confirm_clock->getElapsedTime() > sf::seconds(5)) {
preferences.key_mapping = Data::KeyMapping(m_key_to_button);
}
}
}
next_button = 0;
cancel_remapping = false;
m_key_to_button.clear();
confirm_clock.reset();
resources.options_state.pop_back();
}
void InputRemap::draw(sf::RenderTarget& target, sf::RenderStates states) const {
states.transform *= getTransform();
already_mapped_panel.update();
for (size_t button_index = 0; button_index < next_button; button_index++) {
already_mapped_panel.setPosition(button_index%4*get_panel_step(), button_index/4*get_panel_step());
target.draw(already_mapped_panel, states);
}
if (next_button < 16) {
press_here_panel.update();
press_here_panel.setPosition(next_button%4*get_panel_step(), next_button/4*get_panel_step());
target.draw(press_here_panel, states);
}
auto grid_size = preferences.layout.big_cover_size*get_screen_width();
mapping_preview.setOrigin(grid_size*0.5f, 0.f);
mapping_preview.setPosition(get_big_cover_x(), get_big_cover_y());
target.draw(mapping_preview);
if (confirm_clock) {
if (confirm_clock->getElapsedTime() > sf::seconds(5)) {
preferences.key_mapping = Data::KeyMapping{m_key_to_button};
}
std::string seconds = std::to_string(5 - static_cast<int>(confirm_clock->getElapsedTime().asSeconds()));
big_number.setString(seconds);
big_number.setCharacterSize(static_cast<unsigned int>(3*get_panel_step()));
Toolkit::set_local_origin_normalized(big_number, 0.5f, 0.5f);
big_number.setPosition(get_ribbon_size()*0.5f, get_ribbon_size()*0.5f);
target.draw(big_number, states);
auto text_size = 0.1f*grid_size;
confirm_text_top.setCharacterSize(static_cast<unsigned int>(text_size));
confirm_text_bottom.setCharacterSize(static_cast<unsigned int>(text_size));
Toolkit::set_local_origin_normalized(confirm_text_top, 0.5f, 0.f);
Toolkit::set_local_origin_normalized(confirm_text_bottom, 0.5f, 0.f);
confirm_text_top.setPosition(get_big_cover_x(), get_big_cover_y()+grid_size*1.1f);
confirm_text_bottom.setPosition(get_big_cover_x(), get_big_cover_y()+grid_size*1.1f+text_size*1.1f);
target.draw(confirm_text_top);
target.draw(confirm_text_bottom);
}
}
}

View File

@ -0,0 +1,68 @@
#pragma once
#include <optional>
#include <unordered_map>
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include "../../../Toolkit/AffineTransform.hpp"
#include "../SharedResources.hpp"
#include "OptionPage.hpp"
namespace MusicSelect {
class PressHere final : public sf::Drawable, public sf::Transformable, public HoldsSharedResources {
public:
PressHere(SharedResources& t_resources);
void update();
private:
void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
sf::Text message;
sf::RectangleShape background;
sf::Clock time;
Toolkit::AffineTransform<float> color_anim;
Toolkit::AffineTransform<float> size_anim;
};
class AlreadyMapped final : public sf::Drawable, public sf::Transformable, public HoldsSharedResources {
public:
AlreadyMapped(SharedResources& t_resources);
void update();
private:
void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
sf::RectangleShape background;
};
class MappingPreview final : public sf::Drawable, public sf::Transformable, public HoldsSharedResources {
public:
MappingPreview(SharedResources& t_resources, const std::unordered_map<sf::Keyboard::Key, Data::Button>& t_key_to_button);
private:
void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
const std::unordered_map<sf::Keyboard::Key, Data::Button>& key_to_button;
mutable sf::RectangleShape square;
mutable sf::Text key_label;
};
class InputRemap final : public OptionPage {
public:
InputRemap(SharedResources& t_resources);
bool handle_raw_input(const sf::Event::KeyEvent& event) override;
const std::string name = "Mapping";
bool should_exit() override;
void exit() override;
private:
void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
bool cancel_remapping = false;
std::size_t next_button = 0;
sf::Clock last_key_press;
std::optional<sf::Clock> confirm_clock;
mutable sf::Text confirm_text_top;
mutable sf::Text confirm_text_bottom;
mutable sf::Text big_number;
std::unordered_map<sf::Keyboard::Key, Data::Button> m_key_to_button;
mutable PressHere press_here_panel;
mutable AlreadyMapped already_mapped_panel;
mutable MappingPreview mapping_preview;
};
}

View File

@ -4,9 +4,10 @@
#include <memory>
#include <vector>
#include "Ribbon.hpp"
#include "Panels/SubpagePanel.hpp"
#include "Panels/MarkerPanel.hpp"
#include "../Ribbon.hpp"
#include "../Panels/SubpagePanel.hpp"
#include "../Panels/MarkerPanel.hpp"
#include "InputRemap.hpp"
namespace MusicSelect {
@ -62,11 +63,24 @@ namespace MusicSelect {
{
}
PanelLayout MainOptionPage::create_layout(SharedResources& t_resources) {
std::vector<std::shared_ptr<Panel>> subpages;
auto marker_select = std::make_shared<MarkerSelect>(t_resources);
subpages.emplace_back(std::make_shared<SubpagePanel>(t_resources, std::move(marker_select), "markers"));
auto input_page = std::make_shared<InputOptionPage>(t_resources);
subpages.emplace_back(std::make_shared<SubpagePanel>(t_resources, std::move(input_page), "input"));
return PanelLayout{subpages, t_resources};
}
InputOptionPage::InputOptionPage(SharedResources& t_resources) :
RibbonPage(InputOptionPage::create_layout(t_resources), t_resources)
{
}
PanelLayout InputOptionPage::create_layout(SharedResources& t_resources) {
std::vector<std::shared_ptr<Panel>> subpages;
auto input_remap = std::make_shared<InputRemap>(t_resources);
subpages.emplace_back(std::make_shared<SubpagePanel>(t_resources, std::move(input_remap), "remap\nbuttons"));
return PanelLayout{subpages, t_resources};
}

View File

@ -4,9 +4,9 @@
#include <SFML/Graphics.hpp>
#include <SFML/Window/Event.hpp>
#include "../../Data/Buttons.hpp"
#include "Ribbon.hpp"
#include "SharedResources.hpp"
#include "../../../Data/Buttons.hpp"
#include "../Ribbon.hpp"
#include "../SharedResources.hpp"
namespace MusicSelect {
@ -20,6 +20,12 @@ namespace MusicSelect {
virtual bool handle_raw_input(const sf::Event::KeyEvent& event) = 0;
virtual ~OptionPage() = default;
void update();
virtual bool should_exit() {return false;};
virtual void exit() {return;};
const std::string name;
};
class ButtonRemapping : public OptionPage {
};
class RibbonPage : public OptionPage {
@ -35,6 +41,15 @@ namespace MusicSelect {
class MainOptionPage final : public RibbonPage {
public:
MainOptionPage(SharedResources& t_resources);
const std::string name = "Options";
private:
static PanelLayout create_layout(SharedResources& t_resources);
};
class InputOptionPage final : public RibbonPage {
public:
InputOptionPage(SharedResources& t_resources);
const std::string name = "Input";
private:
static PanelLayout create_layout(SharedResources& t_resources);
};
@ -43,6 +58,7 @@ namespace MusicSelect {
public:
MarkerSelect(SharedResources& t_resources);
~MarkerSelect();
const std::string name = "Marker Select";
private:
static PanelLayout create_layout(SharedResources& t_resources);
};

View File

@ -1,6 +1,6 @@
#include "SubpagePanel.hpp"
#include "../OptionPage.hpp"
#include "../Options/OptionPage.hpp"
namespace MusicSelect {
void SubpagePanel::click(Ribbon&, const Data::Button&) {

View File

@ -4,7 +4,7 @@
#include "../../Toolkit/HSL.hpp"
#include "OptionPage.hpp"
#include "Options/OptionPage.hpp"
#include "Panels/Panel.hpp"
namespace MusicSelect {

View File

@ -8,6 +8,12 @@ namespace Toolkit {
auto bounds = s.getGlobalBounds();
s.setOrigin(bounds.left+x*bounds.width, bounds.top+y*bounds.height);
}
template<class T>
void set_local_origin_normalized(T& s, float x, float y) {
auto bounds = s.getLocalBounds();
s.setOrigin(bounds.left+x*bounds.width, bounds.top+y*bounds.height);
}
template<class T>
void set_origin_normalized_no_position(T& s, float x, float y) {