mirror of
https://github.com/k4zmu2a/SpaceCadetPinball.git
synced 2024-12-19 02:47:54 +01:00
Options refactor part 3: added key bindings for menu shortcuts.
Issue #168.
This commit is contained in:
parent
8df996f452
commit
215599684c
7 changed files with 176 additions and 80 deletions
|
@ -63,6 +63,55 @@ optionsStruct options::Options
|
|||
{InputTypes::Mouse,SDL_BUTTON_X2 + 1},
|
||||
{InputTypes::GameController, SDL_CONTROLLER_BUTTON_DPAD_UP}
|
||||
},
|
||||
{
|
||||
"New Game",
|
||||
Msg::Menu1_New_Game,
|
||||
{InputTypes::Keyboard, SDLK_F2},
|
||||
{InputTypes::None,-1},
|
||||
{InputTypes::None, -1}
|
||||
},
|
||||
{
|
||||
"Toggle Pause",
|
||||
Msg::Menu1_Pause_Resume_Game,
|
||||
{InputTypes::Keyboard, SDLK_F3},
|
||||
{InputTypes::None,-1},
|
||||
{InputTypes::GameController, SDL_CONTROLLER_BUTTON_START}
|
||||
},
|
||||
{
|
||||
"Toggle FullScreen",
|
||||
Msg::Menu1_Full_Screen,
|
||||
{InputTypes::Keyboard, SDLK_F4},
|
||||
{InputTypes::None,-1},
|
||||
{InputTypes::None, -1}
|
||||
},
|
||||
{
|
||||
"Toggle Sounds",
|
||||
Msg::Menu1_Sounds,
|
||||
{InputTypes::Keyboard, SDLK_F5},
|
||||
{InputTypes::None,-1},
|
||||
{InputTypes::None, -1}
|
||||
},
|
||||
{
|
||||
"Toggle Music",
|
||||
Msg::Menu1_Music,
|
||||
{InputTypes::Keyboard, SDLK_F6},
|
||||
{InputTypes::None,-1},
|
||||
{InputTypes::None, -1}
|
||||
},
|
||||
{
|
||||
"Show Control Dialog",
|
||||
Msg::Menu1_Player_Controls,
|
||||
{InputTypes::Keyboard, SDLK_F8},
|
||||
{InputTypes::None,-1},
|
||||
{InputTypes::None, -1}
|
||||
},
|
||||
{
|
||||
"Toggle Menu Display",
|
||||
Msg::Menu1_ToggleShowMenu,
|
||||
{InputTypes::Keyboard, SDLK_F9},
|
||||
{InputTypes::None,-1},
|
||||
{InputTypes::None, -1}
|
||||
},
|
||||
},
|
||||
{"Sounds", true},
|
||||
{"Music", false},
|
||||
|
@ -276,14 +325,6 @@ void options::InputDown(GameInput input)
|
|||
{
|
||||
if (ControlWaitingForInput)
|
||||
{
|
||||
// Skip function keys, just in case.
|
||||
if (input.Type == InputTypes::Keyboard && input.Value >= SDLK_F1 && input.Value <= SDLK_F12)
|
||||
return;
|
||||
|
||||
// Start is reserved for pause
|
||||
if (input.Type == InputTypes::GameController && input.Value == SDL_CONTROLLER_BUTTON_START)
|
||||
return;
|
||||
|
||||
*ControlWaitingForInput = input;
|
||||
ControlWaitingForInput = nullptr;
|
||||
}
|
||||
|
@ -311,13 +352,14 @@ void options::RenderControlDialog()
|
|||
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2{550, 550});
|
||||
if (ImGui::Begin(pb::get_rc_string(Msg::KEYMAPPER_Caption), &ShowDialog))
|
||||
{
|
||||
ImGui::TextUnformatted(pb::get_rc_string(Msg::KEYMAPPER_Groupbox2));
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::TreeNode(pb::get_rc_string(Msg::KEYMAPPER_Groupbox2)))
|
||||
{
|
||||
ImGui::TextWrapped("%s", pb::get_rc_string(Msg::KEYMAPPER_Help1));
|
||||
ImGui::TextWrapped("%s", pb::get_rc_string(Msg::KEYMAPPER_Help2));
|
||||
ImGui::Spacing();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::TextUnformatted(pb::get_rc_string(Msg::KEYMAPPER_Groupbox1));
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{5, 10});
|
||||
|
@ -355,7 +397,7 @@ void options::RenderControlDialog()
|
|||
}
|
||||
else
|
||||
{
|
||||
auto inputDescription = input.GetInputDescription();
|
||||
auto inputDescription = input.GetFullInputDescription();
|
||||
if (ImGui::Button((inputDescription + "##" + std::to_string(rowHash++)).c_str(),
|
||||
ImVec2(-1, 0)))
|
||||
{
|
||||
|
@ -447,7 +489,30 @@ void options::MyUserData_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handl
|
|||
buf->append("\n");
|
||||
}
|
||||
|
||||
std::string GameInput::GetInputDescription() const
|
||||
std::string GameInput::GetFullInputDescription() const
|
||||
{
|
||||
std::string prefix;
|
||||
switch (Type)
|
||||
{
|
||||
case InputTypes::Keyboard:
|
||||
prefix = "Keyboard\n";
|
||||
break;
|
||||
case InputTypes::Mouse:
|
||||
prefix = "Mouse\n";
|
||||
break;
|
||||
case InputTypes::GameController:
|
||||
prefix = "Controller\n";
|
||||
break;
|
||||
case InputTypes::None:
|
||||
default:
|
||||
prefix = "Unused";
|
||||
break;
|
||||
}
|
||||
|
||||
return prefix + GetShortInputDescription();
|
||||
}
|
||||
|
||||
std::string GameInput::GetShortInputDescription() const
|
||||
{
|
||||
static LPCSTR mouseButtons[]
|
||||
{
|
||||
|
@ -488,26 +553,23 @@ std::string GameInput::GetInputDescription() const
|
|||
switch (Type)
|
||||
{
|
||||
case InputTypes::Keyboard:
|
||||
keyName = "Keyboard\n";
|
||||
keyName += SDL_GetKeyName(Value);
|
||||
keyName = SDL_GetKeyName(Value);
|
||||
break;
|
||||
case InputTypes::Mouse:
|
||||
keyName = "Mouse\n";
|
||||
if (Value >= SDL_BUTTON_LEFT && Value <= SDL_BUTTON_X2)
|
||||
keyName += mouseButtons[Value];
|
||||
keyName = mouseButtons[Value];
|
||||
else
|
||||
keyName += std::to_string(Value);
|
||||
keyName = std::to_string(Value);
|
||||
break;
|
||||
case InputTypes::GameController:
|
||||
keyName = "Controller\n";
|
||||
if (Value >= SDL_CONTROLLER_BUTTON_A && Value <= SDL_CONTROLLER_BUTTON_TOUCHPAD)
|
||||
keyName += controllerButtons[Value];
|
||||
keyName = controllerButtons[Value];
|
||||
else
|
||||
keyName += std::to_string(Value);
|
||||
keyName = std::to_string(Value);
|
||||
break;
|
||||
case InputTypes::None:
|
||||
default:
|
||||
keyName = "Unused";
|
||||
break;
|
||||
}
|
||||
|
||||
return keyName;
|
||||
|
@ -545,3 +607,17 @@ OptionBase::~OptionBase()
|
|||
if (position != vec.end())
|
||||
vec.erase(position);
|
||||
}
|
||||
|
||||
std::string ControlOption::GetShortcutDescription() const
|
||||
{
|
||||
std::string result;
|
||||
for (const auto& input : Inputs)
|
||||
{
|
||||
if (input.Type != InputTypes::None)
|
||||
{
|
||||
result = input.GetShortInputDescription();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,9 @@ struct GameInput
|
|||
return Type == other.Type && Value == other.Value;
|
||||
}
|
||||
|
||||
std::string GetInputDescription() const;
|
||||
std::string GetFullInputDescription() const;
|
||||
|
||||
std::string GetShortInputDescription() const;
|
||||
};
|
||||
|
||||
enum class GameBindings
|
||||
|
@ -63,6 +65,13 @@ enum class GameBindings
|
|||
LeftTableBump,
|
||||
RightTableBump,
|
||||
BottomTableBump,
|
||||
NewGame,
|
||||
TogglePause,
|
||||
ToggleFullScreen,
|
||||
ToggleSounds,
|
||||
ToggleMusic,
|
||||
ShowControlDialog,
|
||||
ToggleMenuDisplay,
|
||||
Max
|
||||
};
|
||||
|
||||
|
@ -234,6 +243,8 @@ struct ControlOption : OptionBase
|
|||
{
|
||||
std::copy(std::begin(Defaults), std::end(Defaults), std::begin(Inputs));
|
||||
}
|
||||
|
||||
std::string GetShortcutDescription() const;
|
||||
};
|
||||
|
||||
struct optionsStruct
|
||||
|
|
|
@ -455,13 +455,18 @@ void pb::InputUp(GameInput input)
|
|||
void pb::InputDown(GameInput input)
|
||||
{
|
||||
options::InputDown(input);
|
||||
const auto bindings = options::MapGameInput(input);
|
||||
for (const auto binding : bindings)
|
||||
{
|
||||
winmain::HandleGameBinding(binding);
|
||||
}
|
||||
|
||||
if (game_mode != GameModes::InGame || winmain::single_step || demo_mode)
|
||||
return;
|
||||
|
||||
if (input.Type == InputTypes::Keyboard)
|
||||
control::pbctrl_bdoor_controller(static_cast<char>(input.Value));
|
||||
|
||||
const auto bindings = options::MapGameInput(input);
|
||||
for (const auto binding : bindings)
|
||||
{
|
||||
switch (binding)
|
||||
|
|
|
@ -6289,4 +6289,10 @@ const TextArray translations::Translations =
|
|||
{ Lang::TraditionalChinese, "使用最大解析度 (1024 x 768)" },
|
||||
},
|
||||
},
|
||||
{
|
||||
Msg::Menu1_ToggleShowMenu,
|
||||
{
|
||||
{ Lang::English, "Show Menu"},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -218,6 +218,7 @@ enum class Msg : int
|
|||
Menu1_Select_Players,
|
||||
Menu1_Table_Resolution,
|
||||
Menu1_Help,
|
||||
Menu1_ToggleShowMenu,
|
||||
|
||||
Menu1_UseMaxResolution_640x480,
|
||||
Menu1_UseMaxResolution_800x600,
|
||||
|
|
|
@ -469,19 +469,13 @@ void winmain::RenderUi()
|
|||
|
||||
if (ImGui::BeginMenu(pb::get_rc_string(Msg::Menu1_Game)))
|
||||
{
|
||||
if (ImGui::MenuItem(pb::get_rc_string(Msg::Menu1_New_Game), "F2"))
|
||||
{
|
||||
new_game();
|
||||
}
|
||||
ImGuiMenuItemWShortcut(GameBindings::NewGame);
|
||||
if (ImGui::MenuItem(pb::get_rc_string(Msg::Menu1_Launch_Ball), nullptr, false, LaunchBallEnabled))
|
||||
{
|
||||
end_pause();
|
||||
pb::launch_ball();
|
||||
}
|
||||
if (ImGui::MenuItem(pb::get_rc_string(Msg::Menu1_Pause_Resume_Game), "F3"))
|
||||
{
|
||||
pause();
|
||||
}
|
||||
ImGuiMenuItemWShortcut(GameBindings::TogglePause);
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem(pb::get_rc_string(Msg::Menu1_High_Scores), nullptr, false, HighScoresEnabled))
|
||||
|
@ -504,14 +498,8 @@ void winmain::RenderUi()
|
|||
|
||||
if (ImGui::BeginMenu(pb::get_rc_string(Msg::Menu1_Options)))
|
||||
{
|
||||
if (ImGui::MenuItem("Show Menu", "F9", Options.ShowMenu))
|
||||
{
|
||||
options::toggle(Menu1::Show_Menu);
|
||||
}
|
||||
if (ImGui::MenuItem(pb::get_rc_string(Msg::Menu1_Full_Screen), "F4", Options.FullScreen))
|
||||
{
|
||||
options::toggle(Menu1::Full_Screen);
|
||||
}
|
||||
ImGuiMenuItemWShortcut(GameBindings::ToggleMenuDisplay, Options.ShowMenu);
|
||||
ImGuiMenuItemWShortcut(GameBindings::ToggleFullScreen, Options.FullScreen);
|
||||
if (ImGui::BeginMenu(pb::get_rc_string(Msg::Menu1_Select_Players)))
|
||||
{
|
||||
if (ImGui::MenuItem(pb::get_rc_string(Msg::Menu1_1Player), nullptr, Options.Players == 1))
|
||||
|
@ -536,11 +524,7 @@ void winmain::RenderUi()
|
|||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::MenuItem(pb::get_rc_string(Msg::Menu1_Player_Controls), "F8"))
|
||||
{
|
||||
pause(false);
|
||||
options::ShowControlDialog();
|
||||
}
|
||||
ImGuiMenuItemWShortcut(GameBindings::ShowControlDialog);
|
||||
if (ImGui::BeginMenu("Language"))
|
||||
{
|
||||
auto currentLanguage = translations::GetCurrentLanguage();
|
||||
|
@ -561,10 +545,7 @@ void winmain::RenderUi()
|
|||
|
||||
if (ImGui::BeginMenu("Audio"))
|
||||
{
|
||||
if (ImGui::MenuItem("Sound", "F5", Options.Sounds))
|
||||
{
|
||||
options::toggle(Menu1::Sounds);
|
||||
}
|
||||
ImGuiMenuItemWShortcut(GameBindings::ToggleSounds, Options.Sounds);
|
||||
if (ImGui::MenuItem("Stereo Sound Effects", nullptr, Options.SoundStereo))
|
||||
{
|
||||
options::toggle(Menu1::SoundStereo);
|
||||
|
@ -584,10 +565,7 @@ void winmain::RenderUi()
|
|||
}
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem(pb::get_rc_string(Msg::Menu1_Music), "F6", Options.Music))
|
||||
{
|
||||
options::toggle(Menu1::Music);
|
||||
}
|
||||
ImGuiMenuItemWShortcut(GameBindings::ToggleMusic, Options.Music);
|
||||
ImGui::TextUnformatted("Music Volume");
|
||||
if (ImGui::SliderInt("##Music Volume", &Options.MusicVolume.V, options::MinVolume, options::MaxVolume,
|
||||
"%d",
|
||||
|
@ -852,28 +830,6 @@ int winmain::event_handler(const SDL_Event* event)
|
|||
options::toggle(Menu1::Full_Screen);
|
||||
SDL_MinimizeWindow(MainWindow);
|
||||
break;
|
||||
case SDLK_F2:
|
||||
new_game();
|
||||
break;
|
||||
case SDLK_F3:
|
||||
pause();
|
||||
break;
|
||||
case SDLK_F4:
|
||||
options::toggle(Menu1::Full_Screen);
|
||||
break;
|
||||
case SDLK_F5:
|
||||
options::toggle(Menu1::Sounds);
|
||||
break;
|
||||
case SDLK_F6:
|
||||
options::toggle(Menu1::Music);
|
||||
break;
|
||||
case SDLK_F8:
|
||||
pause(false);
|
||||
options::ShowControlDialog();
|
||||
break;
|
||||
case SDLK_F9:
|
||||
options::toggle(Menu1::Show_Menu);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1014,9 +970,6 @@ int winmain::event_handler(const SDL_Event* event)
|
|||
pb::InputDown({InputTypes::GameController, event->cbutton.button});
|
||||
switch (event->cbutton.button)
|
||||
{
|
||||
case SDL_CONTROLLER_BUTTON_START:
|
||||
pause();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_BACK:
|
||||
if (single_step)
|
||||
{
|
||||
|
@ -1145,6 +1098,37 @@ void winmain::UpdateFrameRate()
|
|||
TargetFrameTime = DurationMs(1000.0 / ups);
|
||||
}
|
||||
|
||||
void winmain::HandleGameBinding(GameBindings binding)
|
||||
{
|
||||
switch (binding)
|
||||
{
|
||||
case GameBindings::TogglePause:
|
||||
pause();
|
||||
break;
|
||||
case GameBindings::NewGame:
|
||||
new_game();
|
||||
break;
|
||||
case GameBindings::ToggleFullScreen:
|
||||
options::toggle(Menu1::Full_Screen);
|
||||
break;
|
||||
case GameBindings::ToggleSounds:
|
||||
options::toggle(Menu1::Sounds);
|
||||
break;
|
||||
case GameBindings::ToggleMusic:
|
||||
options::toggle(Menu1::Music);
|
||||
break;
|
||||
case GameBindings::ShowControlDialog:
|
||||
pause(false);
|
||||
options::ShowControlDialog();
|
||||
break;
|
||||
case GameBindings::ToggleMenuDisplay:
|
||||
options::toggle(Menu1::Show_Menu);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void winmain::RenderFrameTimeDialog()
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2{300, 70});
|
||||
|
@ -1208,3 +1192,12 @@ void winmain::HybridSleep(DurationMs sleepTarget)
|
|||
// spin lock
|
||||
for (auto start = Clock::now(); DurationMs(Clock::now() - start) < sleepTarget;);
|
||||
}
|
||||
|
||||
void winmain::ImGuiMenuItemWShortcut(GameBindings binding, bool selected)
|
||||
{
|
||||
const auto& keyDef = Options.Key[~binding];
|
||||
if (ImGui::MenuItem(pb::get_rc_string(keyDef.Description), keyDef.GetShortcutDescription().c_str(), selected))
|
||||
{
|
||||
HandleGameBinding(binding);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
#include "gdrv.h"
|
||||
|
||||
enum class GameBindings;
|
||||
|
||||
struct SdlTickClock
|
||||
{
|
||||
using duration = std::chrono::milliseconds;
|
||||
|
@ -85,6 +87,7 @@ public:
|
|||
static void pause(bool toggle = true);
|
||||
static void Restart();
|
||||
static void UpdateFrameRate();
|
||||
static void HandleGameBinding(GameBindings binding);
|
||||
private:
|
||||
static int return_value, DispFrameRate;
|
||||
static int mouse_down, last_mouse_x, last_mouse_y;
|
||||
|
@ -108,4 +111,5 @@ private:
|
|||
static void RenderFrameTimeDialog();
|
||||
static void HybridSleep(DurationMs seconds);
|
||||
static void MainLoop();
|
||||
static void ImGuiMenuItemWShortcut(GameBindings binding, bool selected = false);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue