Emscripten: Remove direct blocking prompt calls from Lua

Notable changes:

 - tpt.{input,throw_error,message_box,confirm} have been superseded by ui.begin{Input,ThrowError,MessageBox,Confirm}, each with an extra callback argument and no blocking behaviour, but otherwise the same semantics as their predecessors.
 - The "script not responding" error doesn't wait for user confirmation anymore, it fires without asking. Future exercise: maybe let the user configure the timeout.
 - Remove the confirmPrompt argument of tpt.getscript; this also means it unconditionally fails if the destination file exists.
This commit is contained in:
Tamás Bálint Misius 2023-02-12 08:44:13 +01:00
parent 67e41b6705
commit 4f31f85b6b
No known key found for this signature in database
GPG Key ID: 5B472A12F6ECA9F2
6 changed files with 142 additions and 65 deletions

View File

@ -8,8 +8,9 @@
#include "graphics/Graphics.h"
InformationMessage::InformationMessage(String title, String message, bool large):
ui::Window(ui::Point(-1, -1), ui::Point(200, 35))
InformationMessage::InformationMessage(String title, String message, bool large, DismissCallback callback_):
ui::Window(ui::Point(-1, -1), ui::Point(200, 35)),
callback(callback_)
{
if (large) //Maybe also use this large mode for changelogs eventually, or have it as a customizable size?
{
@ -61,6 +62,8 @@ InformationMessage::InformationMessage(String title, String message, bool large)
okayButton->Appearance.BorderInactive = ui::Colour(200, 200, 200);
okayButton->SetActionCallback({ [this] {
CloseActiveWindow();
if (callback.dismiss)
callback.dismiss();
SelfDestruct(); //TODO: Fix component disposal
} });
AddComponent(okayButton);

View File

@ -3,8 +3,15 @@
class InformationMessage : public ui::Window
{
struct DismissCallback
{
std::function<void ()> dismiss;
};
DismissCallback callback;
public:
InformationMessage(String title, String message, bool large);
InformationMessage(String title, String message, bool large, DismissCallback callback_ = {});
virtual ~InformationMessage() = default;
void OnDraw() override;

View File

@ -11,10 +11,6 @@
#include "simulation/gravity/Gravity.h"
#include "simulation/Simulation.h"
#include "simulation/SimulationData.h"
#include "gui/dialogues/ConfirmPrompt.h"
#include "gui/dialogues/ErrorMessage.h"
#include "gui/dialogues/InformationMessage.h"
#include "gui/dialogues/TextPrompt.h"
#include "gui/game/GameController.h"
#include "gui/game/GameModel.h"
#include "gui/interface/Engine.h"
@ -264,8 +260,7 @@ void luacon_hook(lua_State * l, lua_Debug * ar)
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
if (ar->event == LUA_HOOKCOUNT && Platform::GetTime() - luacon_ci->luaExecutionStart > 3000)
{
if(ConfirmPrompt::Blocking("Script not responding", "The Lua script may have stopped responding. There might be an infinite loop. Press \"Stop\" to stop it", "Stop"))
luaL_error(l, "Error: Script not responding");
luaL_error(l, "Error: Script not responding");
luacon_ci->luaExecutionStart = Platform::GetTime();
}
}
@ -303,13 +298,6 @@ int luatpt_getelement(lua_State *l)
return 1;
}
int luatpt_error(lua_State* l)
{
String errorMessage = tpt_lua_optString(l, 1, "Error text");
ErrorMessage::Blocking("Error", errorMessage);
return 0;
}
int luatpt_drawtext(lua_State* l)
{
int textx, texty, textred, textgreen, textblue, textalpha;
@ -1038,38 +1026,6 @@ int luatpt_delete(lua_State* l)
return luaL_error(l,"Invalid coordinates or particle ID");
}
int luatpt_input(lua_State* l)
{
String title = tpt_lua_optString(l, 1, "Title");
String prompt = tpt_lua_optString(l, 2, "Enter some text:");
String text = tpt_lua_optString(l, 3, "");
String shadow = tpt_lua_optString(l, 4, "");
String result = TextPrompt::Blocking(title, prompt, text, shadow, false);
tpt_lua_pushString(l, result);
return 1;
}
int luatpt_message_box(lua_State* l)
{
String title = tpt_lua_optString(l, 1, "Title");
String message = tpt_lua_optString(l, 2, "Message");
int large = lua_toboolean(l, 3);
new InformationMessage(title, message, large);
return 0;
}
int luatpt_confirm(lua_State *l)
{
String title = tpt_lua_optString(l, 1, "Title");
String message = tpt_lua_optString(l, 2, "Message");
String buttonText = tpt_lua_optString(l, 3, "Confirm");
bool ret = ConfirmPrompt::Blocking(title, message, buttonText);
lua_pushboolean(l, ret ? 1 : 0);
return 1;
}
int luatpt_get_numOfParts(lua_State* l)
{
lua_pushinteger(l, luacon_sim->NUM_PARTS);

View File

@ -49,7 +49,6 @@ int luacon_transitionwrite(lua_State* l);
//tpt. api
int luatpt_getelement(lua_State *l);
int luatpt_error(lua_State* l);
int luatpt_drawtext(lua_State* l);
int luatpt_create(lua_State* l);
@ -96,9 +95,6 @@ int luatpt_textwidth(lua_State* l);
int luatpt_get_name(lua_State* l);
int luatpt_delete(lua_State* l);
int luatpt_input(lua_State* l);
int luatpt_message_box(lua_State* l);
int luatpt_confirm(lua_State* l);
int luatpt_get_numOfParts(lua_State* l);
int luatpt_start_getPartIndex(lua_State* l);
int luatpt_next_getPartIndex(lua_State* l);

View File

@ -38,6 +38,10 @@
#include "simulation/SaveRenderer.h"
#include "simulation/Snapshot.h"
#include "gui/dialogues/ConfirmPrompt.h"
#include "gui/dialogues/ErrorMessage.h"
#include "gui/dialogues/InformationMessage.h"
#include "gui/dialogues/TextPrompt.h"
#include "gui/interface/Window.h"
#include "gui/interface/Engine.h"
#include "gui/game/GameView.h"
@ -345,9 +349,6 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
{"textwidth", &luatpt_textwidth},
{"get_name", &luatpt_get_name},
{"delete", &luatpt_delete},
{"input", &luatpt_input},
{"message_box", &luatpt_message_box},
{"confirm", &luatpt_confirm},
{"get_numOfParts", &luatpt_get_numOfParts},
{"start_getPartIndex", &luatpt_start_getPartIndex},
{"next_getPartIndex", &luatpt_next_getPartIndex},
@ -360,7 +361,6 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
{"num_menus", &luatpt_num_menus},
{"decorations_enable", &luatpt_decorations_enable},
{"display_mode", &luatpt_cmode_set},
{"throw_error", &luatpt_error},
{"heat", &luatpt_heat},
{"setfire", &luatpt_setfire},
{"setdebug", &luatpt_setdebug},
@ -660,7 +660,124 @@ int LuaScriptInterface::tpt_newIndex(lua_State *l)
return 0;
}
//// Begin Interface API
static int beginMessageBox(lua_State* l)
{
String title = tpt_lua_optString(l, 1, "Title");
String message = tpt_lua_optString(l, 2, "Message");
int large = lua_toboolean(l, 3);
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
auto cb = std::make_shared<LuaSmartRef>(luacon_ci->l); // * Bind to main lua state (might be different from l).
cb->Assign(l, 4);
new InformationMessage(title, message, large, { [cb]() {
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
auto l = luacon_ci->l;
cb->Push(l);
if (lua_isfunction(l, -1))
{
if (lua_pcall(l, 0, 0, 0))
{
luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
}
}
else
{
lua_pop(l, 1);
}
} });
return 0;
}
static int beginThrowError(lua_State* l)
{
String errorMessage = tpt_lua_optString(l, 1, "Error text");
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
auto cb = std::make_shared<LuaSmartRef>(luacon_ci->l); // * Bind to main lua state (might be different from l).
cb->Assign(l, 2);
new ErrorMessage("Error", errorMessage, { [cb]() {
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
auto l = luacon_ci->l;
cb->Push(l);
if (lua_isfunction(l, -1))
{
if (lua_pcall(l, 0, 0, 0))
{
luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
}
}
else
{
lua_pop(l, 1);
}
} });
return 0;
}
static int beginInput(lua_State* l)
{
String title = tpt_lua_optString(l, 1, "Title");
String prompt = tpt_lua_optString(l, 2, "Enter some text:");
String text = tpt_lua_optString(l, 3, "");
String shadow = tpt_lua_optString(l, 4, "");
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
auto cb = std::make_shared<LuaSmartRef>(luacon_ci->l); // * Bind to main lua state (might be different from l).
cb->Assign(l, 5);
auto handle = [cb](const String &input) {
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
auto l = luacon_ci->l;
cb->Push(l);
if (lua_isfunction(l, -1))
{
tpt_lua_pushString(l, input);
if (lua_pcall(l, 1, 0, 0))
{
luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
}
}
else
{
lua_pop(l, 1);
}
};
new TextPrompt(title, prompt, text, shadow, false, { [handle](const String &input) {
handle(input);
}, [handle]() {
handle({}); // * Has always returned empty string >_>
} });
return 0;
}
static int beginConfirm(lua_State *l)
{
String title = tpt_lua_optString(l, 1, "Title");
String message = tpt_lua_optString(l, 2, "Message");
String buttonText = tpt_lua_optString(l, 3, "Confirm");
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
auto cb = std::make_shared<LuaSmartRef>(luacon_ci->l); // * Bind to main lua state (might be different from l).
cb->Assign(l, 4);
auto handle = [cb](int result) {
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
auto l = luacon_ci->l;
cb->Push(l);
if (lua_isfunction(l, -1))
{
lua_pushboolean(l, result);
if (lua_pcall(l, 1, 0, 0))
{
luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
}
}
else
{
lua_pop(l, 1);
}
};
new ConfirmPrompt(title, message, { [handle]() {
handle(1);
}, [handle]() {
handle(0);
} }, buttonText);
return 0;
}
void LuaScriptInterface::initInterfaceAPI()
{
@ -672,6 +789,10 @@ void LuaScriptInterface::initInterfaceAPI()
{"grabTextInput", interface_grabTextInput},
{"dropTextInput", interface_dropTextInput},
{"textInputRect", interface_textInputRect},
{"beginInput", beginInput},
{"beginMessageBox", beginMessageBox},
{"beginConfirm", beginConfirm},
{"beginThrowError", beginThrowError},
{NULL, NULL}
};
luaL_register(l, "interface", interfaceAPIMethods);
@ -4431,8 +4552,9 @@ void LuaScriptInterface::OnTick()
new ErrorMessage("Script download", ByteString(http::StatusText(ret)).FromUtf8());
return;
}
if (Platform::FileExists(scriptDownloadFilename) && scriptDownloadConfirmPrompt && !ConfirmPrompt::Blocking("File already exists, overwrite?", scriptDownloadFilename.FromUtf8(), "Overwrite"))
if (Platform::FileExists(scriptDownloadFilename))
{
new ErrorMessage("Script download", "File already exists");
return;
}
if (!Platform::WriteFile(std::vector<char>(scriptData.begin(), scriptData.end()), scriptDownloadFilename))
@ -4885,7 +5007,6 @@ int LuaScriptInterface::luatpt_getscript(lua_State* l)
int scriptID = luaL_checkinteger(l, 1);
auto filename = tpt_lua_checkByteString(l, 2);
bool runScript = luaL_optint(l, 3, 0);
int confirmPrompt = luaL_optint(l, 4, 1);
if (luacon_ci->scriptDownload)
{
@ -4894,16 +5015,11 @@ int LuaScriptInterface::luatpt_getscript(lua_State* l)
}
ByteString url = ByteString::Build(SCHEME, "starcatcher.us/scripts/main.lua?get=", scriptID);
if (confirmPrompt && !ConfirmPrompt::Blocking("Do you want to install script?", url.FromUtf8(), "Install"))
{
return 0;
}
luacon_ci->scriptDownload = std::make_unique<http::Request>(url);
luacon_ci->scriptDownload->Start();
luacon_ci->scriptDownloadFilename = filename;
luacon_ci->scriptDownloadRunScript = runScript;
luacon_ci->scriptDownloadConfirmPrompt = confirmPrompt;
luacon_controller->HideConsole();
return 0;

View File

@ -31,7 +31,6 @@ class LuaScriptInterface: public TPTScriptInterface
std::unique_ptr<http::Request> scriptDownload;
ByteString scriptDownloadFilename;
bool scriptDownloadRunScript;
bool scriptDownloadConfirmPrompt;
int luacon_mousex, luacon_mousey, luacon_mousebutton;
ByteString luacon_selectedl, luacon_selectedr, luacon_selectedalt, luacon_selectedreplace;