mkxp/src/settingsmenu.cpp

931 lines
21 KiB
C++

/*
** settingsmenu.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2014 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "settingsmenu.h"
#include <SDL.h>
#include <SDL_video.h>
#include <SDL_keyboard.h>
#include "keybindings.h"
#include "eventthread.h"
#include "font.h"
#include "input.h"
#include "etc-internal.h"
#include "util.h"
#include "gl-fun.h"
#include "bundledfont.h"
#include "eventthread.h"
#include "imgui/imgui.h"
#include "imgui/imgui_impl_sdl.h"
#include <algorithm>
#include <assert.h>
const Vec2i winSize(740, 400);
const float fontSize = 16.0f;
const ImVec4 colButton = ImColor(96,96,96);
const ImVec4 colButtonHover = ImColor(51,51,51);
const ImVec4 colBackground = ImColor(128,128,128);
const uint8_t numCols = 3;
const uint8_t numRows = 4;
typedef SettingsMenuPrivate SMP;
#define BTN_STRING(btn,desc) { Input:: btn, #desc }
struct VButton
{
Input::ButtonCode code;
const char *str;
} static const vButtons[] =
{
BTN_STRING(Up,Up),
BTN_STRING(Down,Down),
BTN_STRING(L,L),
BTN_STRING(Left,Left),
BTN_STRING(Right,Right),
BTN_STRING(R,W-Atk),
BTN_STRING(A,Dismount),
BTN_STRING(B,Cancel),
BTN_STRING(C,Confirm),
BTN_STRING(X,A-Atk),
BTN_STRING(Y,S-Atk),
BTN_STRING(Z,D-Atk)
};
static elementsN(vButtons);
/* Macros to read/write central config and check for changed values */
#define STORE_CONFIG(key) rtData.config. key = tempConfig. key; rtData.config.store(#key, rtData.config. key )
#define VALUE_CHANGED(key) (rtData.config. key != tempConfig. key)
/* Holds configurables that can be modified in the settings menu
/* until they get all written out the config file and applied */
struct Configurables
{
bool fullscreen;
bool fixedAspectRatio;
bool smoothScaling;
bool vsync;
int defScreenW;
int defScreenH;
bool frameSkip;
bool solidFonts;
Configurables()
{
}
Configurables(Config &c)
{
fullscreen = c.fullscreen;
fixedAspectRatio = c.fixedAspectRatio;
smoothScaling = c.smoothScaling;
vsync = c.vsync;
defScreenW = c.defScreenW;
defScreenH = c.defScreenH;
frameSkip = c.frameSkip;
solidFonts = c.solidFonts;
}
} static tempConfig;
/* Human readable string representation */
std::string sourceDescString(const SourceDesc &src)
{
char buf[128];
char pos;
switch (src.type)
{
case Invalid:
return std::string();
case Key:
{
if (src.d.scan == SDL_SCANCODE_LSHIFT)
return "Shift";
SDL_Keycode key = SDL_GetKeyFromScancode(src.d.scan);
const char *str = SDL_GetKeyName(key);
if (*str == '\0')
return "Unknown key";
else
return str;
}
case JButton:
snprintf(buf, sizeof(buf), "JS %d", src.d.jb);
return buf;
case JHat:
switch(src.d.jh.pos)
{
case SDL_HAT_UP:
pos = 'U';
break;
case SDL_HAT_DOWN:
pos = 'D';
break;
case SDL_HAT_LEFT:
pos = 'L';
break;
case SDL_HAT_RIGHT:
pos = 'R';
break;
default:
pos = '-';
}
snprintf(buf, sizeof(buf), "Hat %d:%c",
src.d.jh.hat, pos);
return buf;
case JAxis:
snprintf(buf, sizeof(buf), "Axis %d%c",
src.d.ja.axis, src.d.ja.dir == Negative ? '-' : '+');
return buf;
}
assert(!"unreachable");
return "";
}
struct BindingWidget
{
SMP *p;
VButton vb;
/* Source slots */
SourceDesc src[4];
/* Flag indicating whether a slot source is used
* for multiple button targets (red indicator) */
bool dupFlag[4];
BindingWidget(int vbIndex, SMP *p)
: vb(vButtons[vbIndex]), p(p)
{}
void appendBindings(BDescVec &d) const;
void click(SourceDesc& desc);
void displayWidget(uint32_t width, uint32_t height);
};
enum State
{
Idle,
AwaitingInput
};
static bool resCheckbox[3];
struct SettingsMenuPrivate
{
State state;
/* Necessary to decide which window gets to
* process joystick events */
bool hasFocus;
/* Tell the outer EventThread to destroy us */
bool destroyReq;
/* Set to true if there are any duplicate bindings */
bool dupWarn;
SDL_Window *window;
SDL_GLContext glContext;
uint32_t winID;
enum tabs
{
CONTROLS,
GRAPHICS
};
enum tabs currentTab;
RGSSThreadData &rtData;
std::vector<BindingWidget> bWidgets;
SourceDesc *captureDesc;
const char *captureName;
SettingsMenuPrivate(RGSSThreadData &rtData)
: rtData(rtData)
{
}
void setupBindingData(const BDescVec &d)
{
size_t slotI[vButtonsN] = { 0 };
for (size_t i = 0; i < bWidgets.size(); ++i)
for (size_t j = 0; j < 4; ++j)
bWidgets[i].src[j].type = Invalid;
for (size_t i = 0; i < d.size(); ++i)
{
const BindingDesc &desc = d[i];
const Input::ButtonCode trg = desc.target;
size_t j;
for (j = 0; j < vButtonsN; ++j)
if (bWidgets[j].vb.code == trg)
break;
assert(j < vButtonsN);
size_t &slot = slotI[j];
BindingWidget &w = bWidgets[j];
if (slot == 4)
continue;
w.src[slot++] = desc.src;
}
}
void updateDuplicateStatus()
{
for (size_t i = 0; i < bWidgets.size(); ++i)
for (size_t j = 0; j < 4; ++j)
bWidgets[i].dupFlag[j] = false;
dupWarn = false;
for (size_t i = 0; i < bWidgets.size(); ++i)
{
for (size_t j = 0; j < 4; ++j)
{
const SourceDesc &src = bWidgets[i].src[j];
if (src.type == Invalid)
continue;
for (size_t k = 0; k < bWidgets.size(); ++k)
{
if (k == i)
continue;
for (size_t l = 0; l < 4; ++l)
{
if (bWidgets[k].src[l] != src)
continue;
bWidgets[i].dupFlag[j] = true;
bWidgets[k].dupFlag[l] = true;
dupWarn = true;
}
}
}
}
}
void redraw()
{
ImGui_ImplSdl_NewFrame(window);
{
ImGui::SetNextWindowSize(ImVec2((float)winSize.x,(float)winSize.y));
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGuiWindowFlags WindowFlags = 0;
WindowFlags |= ImGuiWindowFlags_NoTitleBar;
WindowFlags |= ImGuiWindowFlags_NoResize;
WindowFlags |= ImGuiWindowFlags_NoMove;
WindowFlags |= ImGuiWindowFlags_NoScrollbar;
WindowFlags |= ImGuiWindowFlags_NoCollapse;
WindowFlags |= ImGuiWindowFlags_NoScrollWithMouse;
WindowFlags |= ImGuiWindowFlags_NoSavedSettings;
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
ImGui::PushStyleColor(ImGuiCol_Button, colButton);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colButtonHover);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, colButtonHover);
ImGui::PushStyleColor(ImGuiCol_WindowBg, colBackground);
bool bTrue = true;
ImGui::Begin("Container", &bTrue, WindowFlags);
tabSelector("Controls", CONTROLS);
ImGui::SameLine();
ImGui::Text("|");
ImGui::SameLine();
if(tabSelector("Graphics", GRAPHICS))
{
tempConfig = Configurables(rtData.config);
}
ImGui::Separator();
switch(currentTab)
{
case CONTROLS:
displayControllerTab();
break;
case GRAPHICS:
displayGraphicsTab();
break;
}
ImGui::End();
ImGui::PopStyleColor(4);
ImGui::PopStyleVar();
}
ImGui::Render();
SDL_GL_SwapWindow(window);
}
bool tabSelector(const char * tabName, tabs tabId)
{
if (ImGui::Selectable(tabName, currentTab == tabId, 0, ImGui::CalcTextSize(tabName)) && (state == Idle))
{
currentTab = tabId;
return true;
}
return false;
}
void displayControllerTab()
{
ImVec4 red = ImColor(255, 0, 0);
if(state == AwaitingInput)
{
ImGui::Dummy(ImVec2(0, ImGui::GetWindowContentRegionMax().y/2 - fontSize/2));
ImGui::Text("Press key or joystick button for \"%s\"", captureName);
}
else
{
/* Header Text */
ImGui::Text("Use left click to bind a slot, right click to clear its binding");
if(dupWarn)
{
ImGui::TextColored(red, "Warning: Same physical key bound to multiple slots");
}
/* Button Assignment Widgets */
uint32_t widgetWidth = (ImGui::GetWindowContentRegionMax().x-ImGui::GetStyle().WindowPadding.x) / numCols;
uint32_t widgetHeight = 64;
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2));
ImGui::PushStyleColor(ImGuiCol_ChildWindowBg, ImColor(0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_Button, colBackground);
ImGui::BeginChild("Table", ImVec2(numCols*widgetWidth+8, numRows*widgetHeight+2));
ImGui::Spacing();
int i = 0;
for(int y = 0; y < numRows; y++)
{
ImGui::Dummy(ImVec2(0, 0));
for(int x = 0; x < numCols; x++)
{
ImGui::SameLine();
bWidgets[i].displayWidget(widgetWidth, widgetHeight);
i++;
}
}
ImGui::EndChild();
ImGui::PopStyleColor(2);
ImGui::PopStyleVar();
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
/* Bottom Buttons */
ImVec2 btnDim = ImVec2(100, 24);
if(ImGui::Button("Reset Default", btnDim))
{
onResetToDefault();
}
ImGui::SameLine();
ImGui::Dummy(ImVec2(ImGui::GetWindowContentRegionMax().x - ImGui::GetStyle().WindowPadding.x - 3*btnDim.x - 2*ImGui::GetStyle().ItemSpacing.x, btnDim.y));
ImGui::SameLine();
if(ImGui::Button("Cancel", btnDim))
{
onCancel();
}
ImGui::SameLine();
if(ImGui::Button("Store", btnDim))
{
onAccept();
}
}
}
static inline bool resolutionEqualsN(int* x, int* y, int n)
{
return ((x[0] == n*y[0]) && (x[1] == n*y[1]));
}
static inline bool TextCheckbox(const char* str_id, bool active, bool &hovered, const ImVec2 &size)
{
bool result;
ImVec2 innerPadding = ImGui::GetStyle().FramePadding;
ImVec2 innerSize = ImVec2(size.x-2*innerPadding.x, size.y-2*innerPadding.y);
ImGuiID id = ImGui::GetID(str_id);
/* Set button colors to match checkbox */
if(active)
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
else
ImGui::PushStyleColor(ImGuiCol_Button, ImColor(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetStyle().Colors[ImGuiCol_Button]);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
/* Was item hovered in the previous frame? */
if(hovered)
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGui::GetStyle().Colors[ImGuiCol_FrameBgHovered]);
ImGui::BeginChildFrame(id, size);
if(hovered)
ImGui::PopStyleColor();
hovered = ImGui::IsWindowHovered();
/* Align button properly in child window */
ImVec2 pos = ImGui::GetWindowPos();
pos.x += innerPadding.x;
pos.y += innerPadding.y;
ImGui::SetWindowPos(pos);
result = ImGui::Button(str_id, innerSize);
ImGui::EndChildFrame();
ImGui::PopStyleColor(3);
return result;
}
static inline void TextCentered(const char* str_id, const ImVec2 &size)
{
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_WindowBg]);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetStyle().Colors[ImGuiCol_WindowBg]);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetStyle().Colors[ImGuiCol_WindowBg]);
ImGui::Button(str_id, size);
ImGui::PopStyleColor(3);
}
void displayGraphicsTab()
{
if(ImGui::CollapsingHeader("Display Settings", 0, true, true))
{
/* current resolution and native rendering resolution */
int *res = &tempConfig.defScreenW;
int native[2] = {(rtData.config.rgssVersion == 1 ? 640 : 544),
(rtData.config.rgssVersion == 1 ? 480 : 416)};
if(ImGui::InputInt2("Window Size", res))
{
/* clamp to between 320x240 and 4K resolutions */
tempConfig.defScreenW = std::min(std::max(tempConfig.defScreenW, 320),4096);
tempConfig.defScreenH = std::min(std::max(tempConfig.defScreenH, 240),2160);
}
if(TextCheckbox("1X native", resolutionEqualsN(res, native, 1), resCheckbox[0], ImVec2(80, 24)))
{
res[0] = native[0];
res[1] = native[1];
}
ImGui::SameLine();
if(TextCheckbox("2X native", resolutionEqualsN(res, native, 2), resCheckbox[1], ImVec2(80, 24)))
{
res[0] = 2*native[0];
res[1] = 2*native[1];
}
ImGui::SameLine();
if(TextCheckbox("3X native", resolutionEqualsN(res, native, 3), resCheckbox[2], ImVec2(80, 24)))
{
res[0] = 3*native[0];
res[1] = 3*native[1];
}
ImGui::SameLine();
TextCentered("Recommended if no smooth upscaling.", ImVec2(0, 24));
ImGui::Checkbox("Start in fullscreen", &tempConfig.fullscreen);
ImGui::SameLine();
ImGui::Checkbox("Keep aspect ratio", &tempConfig.fixedAspectRatio);
}
ImGui::Dummy(ImVec2(0, 48));
if(ImGui::CollapsingHeader("Quality Settings", 0, true, true))
{
ImGui::Checkbox("Enable smooth upscaling", &tempConfig.smoothScaling);
ImGui::Checkbox("Enable vertical sync", &tempConfig.vsync);
ImGui::Checkbox("Skip frames when too slow", &tempConfig.frameSkip);
ImGui::Checkbox("Fast font rendering", &tempConfig.solidFonts);
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
/* Buttons */
ImVec2 btnDim = ImVec2(150, 24);
ImGui::Dummy(ImVec2(ImGui::GetWindowContentRegionMax().x - ImGui::GetStyle().WindowPadding.x - 2*btnDim.x - 1*ImGui::GetStyle().ItemSpacing.x, btnDim.y));
ImGui::SameLine();
if(ImGui::Button("Discard Changes", btnDim))
{
tempConfig = Configurables(rtData.config);
}
ImGui::SameLine();
if(ImGui::Button("Apply Changes", btnDim))
{
bool refreshWindow = false;
if(VALUE_CHANGED(defScreenW) || VALUE_CHANGED(defScreenH))
{
STORE_CONFIG(defScreenW);
STORE_CONFIG(defScreenH);
refreshWindow = true;
}
if(VALUE_CHANGED(fullscreen))
{
STORE_CONFIG(fullscreen);
}
if(VALUE_CHANGED(fixedAspectRatio))
{
STORE_CONFIG(fixedAspectRatio);
refreshWindow = true;
}
if(VALUE_CHANGED(smoothScaling))
{
STORE_CONFIG(smoothScaling);
}
if(VALUE_CHANGED(vsync))
{
STORE_CONFIG(vsync);
}
if(VALUE_CHANGED(frameSkip))
{
STORE_CONFIG(frameSkip);
}
if(VALUE_CHANGED(solidFonts))
{
STORE_CONFIG(solidFonts);
}
if(refreshWindow)
SDL_SetWindowSize(rtData.window, tempConfig.defScreenW, tempConfig.defScreenH);
}
}
bool onCaptureInputEvent(const SDL_Event &event)
{
assert(captureDesc);
SourceDesc &desc = *captureDesc;
switch (event.type)
{
case SDL_KEYDOWN:
desc.type = Key;
desc.d.scan = event.key.keysym.scancode;
/* Special case aliases */
if (desc.d.scan == SDL_SCANCODE_RSHIFT)
desc.d.scan = SDL_SCANCODE_LSHIFT;
if (desc.d.scan == SDL_SCANCODE_KP_ENTER)
desc.d.scan = SDL_SCANCODE_RETURN;
break;
case SDL_JOYBUTTONDOWN:
desc.type = JButton;
desc.d.jb = event.jbutton.button;
break;
case SDL_JOYHATMOTION:
{
int v = event.jhat.value;
/* Only register if single directional input */
if (v != SDL_HAT_LEFT && v != SDL_HAT_RIGHT &&
v != SDL_HAT_UP && v != SDL_HAT_DOWN)
return true;
desc.type = JHat;
desc.d.jh.hat = event.jhat.hat;
desc.d.jh.pos = v;
break;
}
case SDL_JOYAXISMOTION:
{
int v = event.jaxis.value;
/* Only register if pushed halfway through */
if (v > -JAXIS_THRESHOLD && v < JAXIS_THRESHOLD)
return true;
desc.type = JAxis;
desc.d.ja.axis = event.jaxis.axis;
desc.d.ja.dir = v < 0 ? Negative : Positive;
break;
}
default:
return false;
}
captureDesc = 0;
state = Idle;
updateDuplicateStatus();
return true;
}
void onResetToDefault()
{
setupBindingData(genDefaultBindings(rtData.config, rtData.gamecontroller));
updateDuplicateStatus();
}
void onAccept()
{
BDescVec binds;
for (size_t i = 0; i < bWidgets.size(); ++i)
bWidgets[i].appendBindings(binds);
rtData.bindingUpdateMsg.post(binds);
/* Store the key bindings to disk as well to prevent config loss */
storeBindings(binds, rtData.config);
}
void onCancel()
{
destroyReq = true;
}
};
void BindingWidget::click(SourceDesc &desc)
{
/* Check for right click */
if(ImGui::IsMouseClicked(1))
{
desc.type = Invalid;
p->updateDuplicateStatus();
return;
}
p->captureDesc = &desc;
p->captureName = vb.str;
p->state = AwaitingInput;
}
void BindingWidget::displayWidget(uint32_t width, uint32_t height)
{
ImVec2 buttonSize = ImVec2((width-6)/3, height/2-ImGui::GetStyle().ItemSpacing.x);
ImGui::PushID(vb.code);
/* Label for Widget */
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetStyle().Colors[ImGuiCol_WindowBg]);
ImGui::Button(vb.str, ImVec2(width/3, height-ImGui::GetStyle().ItemSpacing.x));
ImGui::PopStyleColor();
ImGui::SameLine();
/* Group of buttons */
ImGui::BeginGroup();
for(int i=0; i<4; i++)
{
if(dupFlag[i])
ImGui::PushStyleColor(ImGuiCol_Text, ImColor(255, 0, 0));
if(ImGui::Button(sourceDescString(src[i]).c_str(), buttonSize))
click(src[i]);
if(dupFlag[i])
ImGui::PopStyleColor();
if(i%2 == 0)
ImGui::SameLine();
}
ImGui::EndGroup();
ImGui::PopID();
}
void BindingWidget::appendBindings(BDescVec &d) const
{
for (size_t i = 0; i < 4; ++i)
{
if (src[i].type == Invalid)
continue;
BindingDesc desc;
desc.src = src[i];
desc.target = vb.code;
d.push_back(desc);
}
}
SettingsMenu::SettingsMenu(RGSSThreadData &rtData)
{
p = new SettingsMenuPrivate(rtData);
p->state = Idle;
p->hasFocus = false;
p->destroyReq = false;
p->dupWarn = false;
p->currentTab = SettingsMenuPrivate::CONTROLS;
p->window = SDL_CreateWindow("Settings Menu",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
winSize.x, winSize.y, SDL_WINDOW_OPENGL|SDL_WINDOW_INPUT_FOCUS);
p->winID = SDL_GetWindowID(p->window);
p->glContext = SDL_GL_CreateContext(p->window);
ImGui_ImplSdl_Init(p->window);
/* ImGUI wants to own the memory with the TTF data, so requires a copy. */
void * liberation_copy = malloc(BNDL_F_L(BUNDLED_FONT));
memcpy(liberation_copy, BNDL_F_D(BUNDLED_FONT), BNDL_F_L(BUNDLED_FONT));
ImGuiIO& io = ImGui::GetIO();
ImFont* im_font = io.Fonts->AddFontFromMemoryTTF(liberation_copy, BNDL_F_L(BUNDLED_FONT), 16.0f);
/* Generate Binding Widgets */
assert(numRows*numCols == vButtonsN);
for (int i = 0; i < vButtonsN; i++)
{
BindingWidget w(i, p);
p->bWidgets.push_back(w);
}
BDescVec binds;
rtData.bindingUpdateMsg.get(binds);
p->setupBindingData(binds);
p->captureDesc = 0;
p->captureName = 0;
p->updateDuplicateStatus();
p->redraw();
}
SettingsMenu::~SettingsMenu()
{
ImGui_ImplSdl_Shutdown();
SDL_GL_DeleteContext(p->glContext);
SDL_DestroyWindow(p->window);
delete p;
}
bool SettingsMenu::onEvent(const SDL_Event &event)
{
/* Check for a redraw event first */
if(event.type == EventThread::UPDATE_POPUP + EventThread::UsrIdStart)
{
if(p->hasFocus)
p->redraw();
}
/* Check whether this event is for us */
switch (event.type)
{
case SDL_WINDOWEVENT :
case SDL_MOUSEBUTTONDOWN :
case SDL_MOUSEBUTTONUP :
case SDL_MOUSEMOTION :
case SDL_KEYDOWN :
case SDL_KEYUP :
case SDL_TEXTINPUT :
/* We can do this because windowID has the same
* struct offset in all these event types */
if (event.window.windowID != p->winID)
return false;
break;
case SDL_JOYBUTTONDOWN :
case SDL_JOYBUTTONUP :
case SDL_JOYHATMOTION :
case SDL_JOYAXISMOTION :
if (!p->hasFocus)
return false;
break;
/* Don't try to handle something we don't understand */
default:
return false;
}
/* Pass through event data to ImGUI */
ImGui_ImplSdl_ProcessEvent(event);
/* Now process it.. */
switch (event.type)
{
/* Ignore these event */
case SDL_MOUSEBUTTONUP :
case SDL_KEYUP :
return true;
case SDL_WINDOWEVENT :
switch (event.window.event)
{
case SDL_WINDOWEVENT_SHOWN : // SDL is bugged and doesn't give us a first FOCUS_GAINED event
case SDL_WINDOWEVENT_FOCUS_GAINED :
p->hasFocus = true;
break;
case SDL_WINDOWEVENT_FOCUS_LOST :
p->hasFocus = false;
break;
case SDL_WINDOWEVENT_EXPOSED :
p->redraw();
break;
case SDL_WINDOWEVENT_CLOSE:
p->onCancel();
}
return true;
case SDL_MOUSEMOTION:
//p->onMotion(event.motion);
return true;
case SDL_KEYDOWN:
if (p->state != AwaitingInput)
{
if (event.key.keysym.sym == SDLK_RETURN)
p->onAccept();
else if (event.key.keysym.sym == SDLK_ESCAPE)
p->onCancel();
return true;
}
/* Don't let the user bind keys that trigger
* mkxp functions */
switch(event.key.keysym.scancode)
{
case SDL_SCANCODE_F1:
case SDL_SCANCODE_F2:
case SDL_SCANCODE_F12:
return true;
default:
break;
}
case SDL_JOYBUTTONDOWN:
case SDL_JOYHATMOTION:
case SDL_JOYAXISMOTION:
if (p->state != AwaitingInput)
return true;
break;
case SDL_MOUSEBUTTONDOWN:
return true;
default:
return true;
}
if (p->state == AwaitingInput)
return p->onCaptureInputEvent(event);
return true;
}
void SettingsMenu::raise()
{
SDL_RaiseWindow(p->window);
}
bool SettingsMenu::destroyReq() const
{
return p->destroyReq;
}