Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/gui/GUIManager.cpp
Show First 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | void CGUIManager::SwitchPage(const CStrW& pageName, ScriptInterface* srcScriptInterface, JS::HandleValue initData) | ||||
// therefore we have to clone initData. | // therefore we have to clone initData. | ||||
shared_ptr<ScriptInterface::StructuredClone> initDataClone; | shared_ptr<ScriptInterface::StructuredClone> initDataClone; | ||||
if (!initData.isUndefined()) | if (!initData.isUndefined()) | ||||
initDataClone = srcScriptInterface->WriteStructuredClone(initData); | initDataClone = srcScriptInterface->WriteStructuredClone(initData); | ||||
m_PageStack.clear(); | m_PageStack.clear(); | ||||
PushPage(pageName, initDataClone); | PushPage(pageName, initDataClone, JS::UndefinedHandleValue); | ||||
} | } | ||||
void CGUIManager::PushPage(const CStrW& pageName, shared_ptr<ScriptInterface::StructuredClone> initData) | void CGUIManager::PushPage(const CStrW& pageName, shared_ptr<ScriptInterface::StructuredClone> initData, JS::HandleValue callbackFunction) | ||||
{ | { | ||||
// Store the callback handler in the current GUI page before opening the new one | |||||
if (!m_PageStack.empty() && !callbackFunction.isUndefined()) | |||||
m_PageStack.back().SetCallbackFunction(*m_ScriptInterface, callbackFunction); | |||||
// Push the page prior to loading its contents, because that may push | // Push the page prior to loading its contents, because that may push | ||||
// another GUI page on init which should be pushed on top of this new page. | // another GUI page on init which should be pushed on top of this new page. | ||||
m_PageStack.emplace_back(pageName, initData); | m_PageStack.emplace_back(pageName, initData); | ||||
m_PageStack.back().LoadPage(m_ScriptRuntime); | m_PageStack.back().LoadPage(m_ScriptRuntime); | ||||
ResetCursor(); | ResetCursor(); | ||||
} | } | ||||
void CGUIManager::PopPage() | void CGUIManager::PopPage(shared_ptr<ScriptInterface::StructuredClone> args) | ||||
{ | { | ||||
if (m_PageStack.size() < 2) | if (m_PageStack.size() < 2) | ||||
{ | { | ||||
debug_warn(L"Tried to pop GUI page when there's < 2 in the stack"); | debug_warn(L"Tried to pop GUI page when there's < 2 in the stack"); | ||||
return; | return; | ||||
} | } | ||||
m_PageStack.pop_back(); | m_PageStack.pop_back(); | ||||
} | m_PageStack.back().PerformCallbackFunction(args); | ||||
void CGUIManager::PopPageCB(shared_ptr<ScriptInterface::StructuredClone> args) | |||||
{ | |||||
shared_ptr<ScriptInterface::StructuredClone> initDataClone = m_PageStack.back().initData; | |||||
PopPage(); | |||||
shared_ptr<ScriptInterface> scriptInterface = m_PageStack.back().gui->GetScriptInterface(); | |||||
JSContext* cx = scriptInterface->GetContext(); | |||||
JSAutoRequest rq(cx); | |||||
JS::RootedValue initDataVal(cx); | |||||
if (!initDataClone) | |||||
{ | |||||
LOGERROR("Called PopPageCB when initData (which should contain the callback function name) isn't set!"); | |||||
return; | |||||
} | |||||
scriptInterface->ReadStructuredClone(initDataClone, &initDataVal); | |||||
if (!scriptInterface->HasProperty(initDataVal, "callback")) | |||||
{ | |||||
LOGERROR("Called PopPageCB when the callback function name isn't set!"); | |||||
return; | |||||
} | |||||
std::string callback; | |||||
if (!scriptInterface->GetProperty(initDataVal, "callback", callback)) | |||||
{ | |||||
LOGERROR("Failed to get the callback property as a string from initData in PopPageCB!"); | |||||
return; | |||||
} | |||||
JS::RootedValue global(cx, scriptInterface->GetGlobalObject()); | |||||
if (!scriptInterface->HasProperty(global, callback.c_str())) | |||||
{ | |||||
LOGERROR("The specified callback function %s does not exist in the page %s", callback, utf8_from_wstring(m_PageStack.back().name)); | |||||
return; | |||||
} | |||||
JS::RootedValue argVal(cx); | |||||
if (args) | |||||
scriptInterface->ReadStructuredClone(args, &argVal); | |||||
if (!scriptInterface->CallFunctionVoid(global, callback.c_str(), argVal)) | |||||
{ | |||||
LOGERROR("Failed to call the callback function %s in the page %s", callback, utf8_from_wstring(m_PageStack.back().name)); | |||||
return; | |||||
} | |||||
} | } | ||||
CGUIManager::SGUIPage::SGUIPage(const CStrW& pageName, const shared_ptr<ScriptInterface::StructuredClone> initData) | CGUIManager::SGUIPage::SGUIPage(const CStrW& pageName, const shared_ptr<ScriptInterface::StructuredClone> initData) | ||||
: name(pageName), initData(initData), inputs(), gui() | : name(pageName), initData(initData), inputs(), gui(), callbackFunction() | ||||
{ | { | ||||
} | } | ||||
void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptRuntime> scriptRuntime) | void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptRuntime> scriptRuntime) | ||||
{ | { | ||||
// If we're hotloading then try to grab some data from the previous page | // If we're hotloading then try to grab some data from the previous page | ||||
shared_ptr<ScriptInterface::StructuredClone> hotloadData; | shared_ptr<ScriptInterface::StructuredClone> hotloadData; | ||||
if (gui) | if (gui) | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptRuntime> scriptRuntime) | ||||
if (hotloadData) | if (hotloadData) | ||||
scriptInterface->ReadStructuredClone(hotloadData, &hotloadDataVal); | scriptInterface->ReadStructuredClone(hotloadData, &hotloadDataVal); | ||||
if (scriptInterface->HasProperty(global, "init") && | if (scriptInterface->HasProperty(global, "init") && | ||||
!scriptInterface->CallFunctionVoid(global, "init", initDataVal, hotloadDataVal)) | !scriptInterface->CallFunctionVoid(global, "init", initDataVal, hotloadDataVal)) | ||||
LOGERROR("GUI page '%s': Failed to call init() function", utf8_from_wstring(name)); | LOGERROR("GUI page '%s': Failed to call init() function", utf8_from_wstring(name)); | ||||
} | } | ||||
void CGUIManager::SGUIPage::SetCallbackFunction(ScriptInterface& scriptInterface, JS::HandleValue callbackFunc) | |||||
{ | |||||
if (!callbackFunc.isObject()) | |||||
{ | |||||
LOGERROR("Given callback handler is not an object!"); | |||||
return; | |||||
} | |||||
// Does not require JSAutoRequest | |||||
if (!JS_ObjectIsFunction(scriptInterface.GetContext(), &callbackFunc.toObject())) | |||||
{ | |||||
LOGERROR("Given callback handler is not a function!"); | |||||
return; | |||||
} | |||||
callbackFunction = std::make_shared<JS::PersistentRootedValue>(scriptInterface.GetJSRuntime(), callbackFunc); | |||||
} | |||||
void CGUIManager::SGUIPage::PerformCallbackFunction(shared_ptr<ScriptInterface::StructuredClone> args) | |||||
{ | |||||
if (!callbackFunction) | |||||
return; | |||||
shared_ptr<ScriptInterface> scriptInterface = gui->GetScriptInterface(); | |||||
JSContext* cx = scriptInterface->GetContext(); | |||||
JSAutoRequest rq(cx); | |||||
JS::RootedObject globalObj(cx, &scriptInterface->GetGlobalObject().toObject()); | |||||
JS::RootedValue funcVal(cx, *callbackFunction); | |||||
// Delete the callback function, so that it is not called again | |||||
callbackFunction.reset(); | |||||
JS::RootedValue argVal(cx); | |||||
if (args) | |||||
scriptInterface->ReadStructuredClone(args, &argVal); | |||||
JS::AutoValueVector paramData(cx); | |||||
paramData.append(argVal); | |||||
JS::RootedValue result(cx); | |||||
JS_CallFunctionValue(cx, globalObj, funcVal, paramData, &result); | |||||
} | |||||
Status CGUIManager::ReloadChangedFile(const VfsPath& path) | Status CGUIManager::ReloadChangedFile(const VfsPath& path) | ||||
{ | { | ||||
for (SGUIPage& p : m_PageStack) | for (SGUIPage& p : m_PageStack) | ||||
if (p.inputs.count(path)) | if (p.inputs.count(path)) | ||||
{ | { | ||||
LOGMESSAGE("GUI file '%s' changed - reloading page '%s'", path.string8(), utf8_from_wstring(p.name)); | LOGMESSAGE("GUI file '%s' changed - reloading page '%s'", path.string8(), utf8_from_wstring(p.name)); | ||||
p.LoadPage(m_ScriptRuntime); | p.LoadPage(m_ScriptRuntime); | ||||
// TODO: this can crash if LoadPage runs an init script which modifies the page stack and breaks our iterators | // TODO: this can crash if LoadPage runs an init script which modifies the page stack and breaks our iterators | ||||
▲ Show 20 Lines • Show All 153 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator