diff --git a/src/modules/window/Window.cpp b/src/modules/window/Window.cpp index 87a8d14fe..3e74db675 100644 --- a/src/modules/window/Window.cpp +++ b/src/modules/window/Window.cpp @@ -74,6 +74,16 @@ bool Window::getConstant(Window::Setting in, const char *&out) return settings.find(in, out); } +bool Window::getConstant(const char *in, MessageBoxType &out) +{ + return messageBoxTypes.find(in, out); +} + +bool Window::getConstant(MessageBoxType in, const char *&out) +{ + return messageBoxTypes.find(in, out); +} + StringMap::Entry Window::settingEntries[] = { {"fullscreen", SETTING_FULLSCREEN}, @@ -101,5 +111,14 @@ StringMap::Entry Windo StringMap Window::fullscreenTypes(Window::fullscreenTypeEntries, sizeof(Window::fullscreenTypeEntries)); +StringMap::Entry Window::messageBoxTypeEntries[] = +{ + {"error", Window::MESSAGEBOX_ERROR}, + {"warning", Window::MESSAGEBOX_WARNING}, + {"info", Window::MESSAGEBOX_INFO}, +}; + +StringMap Window::messageBoxTypes(Window::messageBoxTypeEntries, sizeof(Window::messageBoxTypeEntries)); + } // window } // love diff --git a/src/modules/window/Window.h b/src/modules/window/Window.h index 393d51fec..dd0e1a18d 100644 --- a/src/modules/window/Window.h +++ b/src/modules/window/Window.h @@ -69,12 +69,34 @@ public: FULLSCREEN_TYPE_MAX_ENUM }; + enum MessageBoxType + { + MESSAGEBOX_ERROR, + MESSAGEBOX_WARNING, + MESSAGEBOX_INFO, + MESSAGEBOX_MAX_ENUM + }; + struct WindowSize { int width; int height; }; + struct MessageBoxData + { + MessageBoxType type; + + std::string title; + std::string message; + + std::vector buttons; + int enterButtonIndex; + int escapeButtonIndex; + + bool attachToWindow; + }; + virtual ~Window(); // Implements Module. @@ -127,6 +149,9 @@ public: virtual const void *getHandle() const = 0; + virtual bool showMessageBox(MessageBoxType type, const std::string &title, const std::string &message, bool attachtowindow) = 0; + virtual int showMessageBox(const MessageBoxData &data) = 0; + //virtual static Window *createSingleton() = 0; //virtual static Window *getSingleton() = 0; // No virtual statics, of course, but you are supposed to implement these statics. @@ -137,6 +162,9 @@ public: static bool getConstant(const char *in, FullscreenType &out); static bool getConstant(FullscreenType in, const char *&out); + static bool getConstant(const char *in, MessageBoxType &out); + static bool getConstant(MessageBoxType in, const char *&out); + protected: static Window *singleton; @@ -149,6 +177,9 @@ private: static StringMap::Entry fullscreenTypeEntries[]; static StringMap fullscreenTypes; + static StringMap::Entry messageBoxTypeEntries[]; + static StringMap messageBoxTypes; + }; // Window struct WindowSettings diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 88fde1db2..8e8567b5b 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -678,6 +678,65 @@ const void *Window::getHandle() const return window; } +SDL_MessageBoxFlags Window::convertMessageBoxType(MessageBoxType type) const +{ + switch (type) + { + case MESSAGEBOX_ERROR: + return SDL_MESSAGEBOX_ERROR; + case MESSAGEBOX_WARNING: + return SDL_MESSAGEBOX_WARNING; + case MESSAGEBOX_INFO: + default: + return SDL_MESSAGEBOX_INFORMATION; + } +} + +bool Window::showMessageBox(MessageBoxType type, const std::string &title, const std::string &message, bool attachtowindow) +{ + SDL_MessageBoxFlags flags = convertMessageBoxType(type); + SDL_Window *sdlwindow = attachtowindow ? window : nullptr; + + return SDL_ShowSimpleMessageBox(flags, title.c_str(), message.c_str(), sdlwindow) >= 0; +} + +int Window::showMessageBox(const MessageBoxData &data) +{ + SDL_MessageBoxData sdldata = {}; + + sdldata.flags = convertMessageBoxType(data.type); + sdldata.title = data.title.c_str(); + sdldata.message = data.message.c_str(); + sdldata.window = data.attachToWindow ? window : nullptr; + + sdldata.numbuttons = (int) data.buttons.size(); + + std::vector sdlbuttons; + + for (size_t i = 0; i < data.buttons.size(); i++) + { + SDL_MessageBoxButtonData sdlbutton = {}; + + sdlbutton.buttonid = (int) i; + sdlbutton.text = data.buttons[i].c_str(); + + if ((int) i == data.enterButtonIndex) + sdlbutton.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT; + + if ((int) i == data.escapeButtonIndex) + sdlbutton.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT; + + sdlbuttons.push_back(sdlbutton); + } + + sdldata.buttons = &sdlbuttons[0]; + + int pressedbutton = -2; + SDL_ShowMessageBox(&sdldata, &pressedbutton); + + return pressedbutton; +} + love::window::Window *Window::createSingleton() { if (!singleton) diff --git a/src/modules/window/sdl/Window.h b/src/modules/window/sdl/Window.h index 996e99c7d..c60cfa620 100644 --- a/src/modules/window/sdl/Window.h +++ b/src/modules/window/sdl/Window.h @@ -87,6 +87,9 @@ public: const void *getHandle() const; + bool showMessageBox(MessageBoxType type, const std::string &title, const std::string &message, bool attachtowindow); + int showMessageBox(const MessageBoxData &data); + static love::window::Window *createSingleton(); static love::window::Window *getSingleton(); @@ -100,6 +103,8 @@ private: // Update the saved window settings based on the window's actual state. void updateSettings(const WindowSettings &newsettings); + SDL_MessageBoxFlags convertMessageBoxType(MessageBoxType type) const; + std::string windowTitle; struct _currentMode diff --git a/src/modules/window/wrap_Window.cpp b/src/modules/window/wrap_Window.cpp index 9d22fba29..5982dd881 100644 --- a/src/modules/window/wrap_Window.cpp +++ b/src/modules/window/wrap_Window.cpp @@ -340,6 +340,66 @@ int w_minimize(lua_State* /*L*/) return 0; } +int w_showMessageBox(lua_State *L) +{ + Window::MessageBoxData data = {}; + + const char *typestr = luaL_checkstring(L, 1); + if (!Window::getConstant(typestr, data.type)) + return luaL_error(L, "Invalid messagebox type: %s", typestr); + + data.title = luaL_checkstring(L, 2); + data.message = luaL_checkstring(L, 3); + + // If we have a table argument, we assume a list of button names, which + // means we should use the more complex message box API. + if (lua_istable(L, 4)) + { + size_t numbuttons = lua_objlen(L, 4); + if (numbuttons == 0) + return luaL_error(L, "Must have at least one messagebox button."); + + // Array of button names. + for (size_t i = 0; i < numbuttons; i++) + { + lua_rawgeti(L, 4, i + 1); + data.buttons.push_back(luax_checkstring(L, -1)); + lua_pop(L, 1); + } + + // Optional table entry specifying the button to use when enter is pressed. + lua_getfield(L, 4, "enterbutton"); + if (!lua_isnoneornil(L, -1)) + data.enterButtonIndex = luaL_checkint(L, -1) - 1; + else + data.enterButtonIndex = 0; + lua_pop(L, 1); + + // Optional table entry specifying the button to use when esc is pressed. + lua_getfield(L, 4, "escapebutton"); + if (!lua_isnoneornil(L, -1)) + data.escapeButtonIndex = luaL_checkint(L, -1) - 1; + else + data.escapeButtonIndex = (int) data.buttons.size() - 1; + lua_pop(L, 1); + + data.attachToWindow = luax_optboolean(L, 5, true); + + int pressedbutton = instance()->showMessageBox(data); + lua_pushinteger(L, pressedbutton + 1); + } + else + { + data.attachToWindow = luax_optboolean(L, 4, true); + + // Display a simple message box. + bool success = instance()->showMessageBox(data.type, data.title, data.message, data.attachToWindow); + luax_pushboolean(L, success); + } + + return 1; +} + static const luaL_Reg functions[] = { { "getDisplayCount", w_getDisplayCount }, @@ -363,6 +423,7 @@ static const luaL_Reg functions[] = { "isVisible", w_isVisible }, { "getPixelScale", w_getPixelScale }, { "minimize", w_minimize }, + { "showMessageBox", w_showMessageBox }, { 0, 0 } }; diff --git a/src/modules/window/wrap_Window.h b/src/modules/window/wrap_Window.h index 1b5277a11..ea7383aac 100644 --- a/src/modules/window/wrap_Window.h +++ b/src/modules/window/wrap_Window.h @@ -50,6 +50,7 @@ int w_hasMouseFocus(lua_State *L); int w_isVisible(lua_State *L); int w_getPixelScale(lua_State *L); int w_minimize(lua_State *L); +int w_showMessageBox(lua_State *L); extern "C" LOVE_EXPORT int luaopen_love_window(lua_State *L); } // window