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" #include "graphics/Graphics.h"
InformationMessage::InformationMessage(String title, String message, bool large): InformationMessage::InformationMessage(String title, String message, bool large, DismissCallback callback_):
ui::Window(ui::Point(-1, -1), ui::Point(200, 35)) 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? 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->Appearance.BorderInactive = ui::Colour(200, 200, 200);
okayButton->SetActionCallback({ [this] { okayButton->SetActionCallback({ [this] {
CloseActiveWindow(); CloseActiveWindow();
if (callback.dismiss)
callback.dismiss();
SelfDestruct(); //TODO: Fix component disposal SelfDestruct(); //TODO: Fix component disposal
} }); } });
AddComponent(okayButton); AddComponent(okayButton);

View File

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

View File

@ -11,10 +11,6 @@
#include "simulation/gravity/Gravity.h" #include "simulation/gravity/Gravity.h"
#include "simulation/Simulation.h" #include "simulation/Simulation.h"
#include "simulation/SimulationData.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/GameController.h"
#include "gui/game/GameModel.h" #include "gui/game/GameModel.h"
#include "gui/interface/Engine.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); auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
if (ar->event == LUA_HOOKCOUNT && Platform::GetTime() - luacon_ci->luaExecutionStart > 3000) 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(); luacon_ci->luaExecutionStart = Platform::GetTime();
} }
} }
@ -303,13 +298,6 @@ int luatpt_getelement(lua_State *l)
return 1; 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 luatpt_drawtext(lua_State* l)
{ {
int textx, texty, textred, textgreen, textblue, textalpha; 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"); 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) int luatpt_get_numOfParts(lua_State* l)
{ {
lua_pushinteger(l, luacon_sim->NUM_PARTS); lua_pushinteger(l, luacon_sim->NUM_PARTS);

View File

@ -49,7 +49,6 @@ int luacon_transitionwrite(lua_State* l);
//tpt. api //tpt. api
int luatpt_getelement(lua_State *l); int luatpt_getelement(lua_State *l);
int luatpt_error(lua_State* l);
int luatpt_drawtext(lua_State* l); int luatpt_drawtext(lua_State* l);
int luatpt_create(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_get_name(lua_State* l);
int luatpt_delete(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_get_numOfParts(lua_State* l);
int luatpt_start_getPartIndex(lua_State* l); int luatpt_start_getPartIndex(lua_State* l);
int luatpt_next_getPartIndex(lua_State* l); int luatpt_next_getPartIndex(lua_State* l);

View File

@ -38,6 +38,10 @@
#include "simulation/SaveRenderer.h" #include "simulation/SaveRenderer.h"
#include "simulation/Snapshot.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/Window.h"
#include "gui/interface/Engine.h" #include "gui/interface/Engine.h"
#include "gui/game/GameView.h" #include "gui/game/GameView.h"
@ -345,9 +349,6 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
{"textwidth", &luatpt_textwidth}, {"textwidth", &luatpt_textwidth},
{"get_name", &luatpt_get_name}, {"get_name", &luatpt_get_name},
{"delete", &luatpt_delete}, {"delete", &luatpt_delete},
{"input", &luatpt_input},
{"message_box", &luatpt_message_box},
{"confirm", &luatpt_confirm},
{"get_numOfParts", &luatpt_get_numOfParts}, {"get_numOfParts", &luatpt_get_numOfParts},
{"start_getPartIndex", &luatpt_start_getPartIndex}, {"start_getPartIndex", &luatpt_start_getPartIndex},
{"next_getPartIndex", &luatpt_next_getPartIndex}, {"next_getPartIndex", &luatpt_next_getPartIndex},
@ -360,7 +361,6 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
{"num_menus", &luatpt_num_menus}, {"num_menus", &luatpt_num_menus},
{"decorations_enable", &luatpt_decorations_enable}, {"decorations_enable", &luatpt_decorations_enable},
{"display_mode", &luatpt_cmode_set}, {"display_mode", &luatpt_cmode_set},
{"throw_error", &luatpt_error},
{"heat", &luatpt_heat}, {"heat", &luatpt_heat},
{"setfire", &luatpt_setfire}, {"setfire", &luatpt_setfire},
{"setdebug", &luatpt_setdebug}, {"setdebug", &luatpt_setdebug},
@ -660,7 +660,124 @@ int LuaScriptInterface::tpt_newIndex(lua_State *l)
return 0; 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() void LuaScriptInterface::initInterfaceAPI()
{ {
@ -672,6 +789,10 @@ void LuaScriptInterface::initInterfaceAPI()
{"grabTextInput", interface_grabTextInput}, {"grabTextInput", interface_grabTextInput},
{"dropTextInput", interface_dropTextInput}, {"dropTextInput", interface_dropTextInput},
{"textInputRect", interface_textInputRect}, {"textInputRect", interface_textInputRect},
{"beginInput", beginInput},
{"beginMessageBox", beginMessageBox},
{"beginConfirm", beginConfirm},
{"beginThrowError", beginThrowError},
{NULL, NULL} {NULL, NULL}
}; };
luaL_register(l, "interface", interfaceAPIMethods); luaL_register(l, "interface", interfaceAPIMethods);
@ -4431,8 +4552,9 @@ void LuaScriptInterface::OnTick()
new ErrorMessage("Script download", ByteString(http::StatusText(ret)).FromUtf8()); new ErrorMessage("Script download", ByteString(http::StatusText(ret)).FromUtf8());
return; 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; return;
} }
if (!Platform::WriteFile(std::vector<char>(scriptData.begin(), scriptData.end()), scriptDownloadFilename)) 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); int scriptID = luaL_checkinteger(l, 1);
auto filename = tpt_lua_checkByteString(l, 2); auto filename = tpt_lua_checkByteString(l, 2);
bool runScript = luaL_optint(l, 3, 0); bool runScript = luaL_optint(l, 3, 0);
int confirmPrompt = luaL_optint(l, 4, 1);
if (luacon_ci->scriptDownload) 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); 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 = std::make_unique<http::Request>(url);
luacon_ci->scriptDownload->Start(); luacon_ci->scriptDownload->Start();
luacon_ci->scriptDownloadFilename = filename; luacon_ci->scriptDownloadFilename = filename;
luacon_ci->scriptDownloadRunScript = runScript; luacon_ci->scriptDownloadRunScript = runScript;
luacon_ci->scriptDownloadConfirmPrompt = confirmPrompt;
luacon_controller->HideConsole(); luacon_controller->HideConsole();
return 0; return 0;

View File

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