Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/gui/GUIManager.cpp
Show All 20 Lines | |||||
#include "gui/CGUI.h" | #include "gui/CGUI.h" | ||||
#include "lib/timer.h" | #include "lib/timer.h" | ||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "ps/Filesystem.h" | #include "ps/Filesystem.h" | ||||
#include "ps/GameSetup/Config.h" | #include "ps/GameSetup/Config.h" | ||||
#include "ps/Profile.h" | #include "ps/Profile.h" | ||||
#include "ps/XML/Xeromyces.h" | #include "ps/XML/Xeromyces.h" | ||||
#include "scriptinterface/ScriptContext.h" | |||||
#include "scriptinterface/ScriptInterface.h" | #include "scriptinterface/ScriptInterface.h" | ||||
#include "scriptinterface/ScriptRuntime.h" | |||||
CGUIManager* g_GUI = nullptr; | CGUIManager* g_GUI = nullptr; | ||||
const CStr CGUIManager::EventNameWindowResized = "WindowResized"; | const CStr CGUIManager::EventNameWindowResized = "WindowResized"; | ||||
// General TODOs: | // General TODOs: | ||||
// | // | ||||
Show All 16 Lines | |||||
static Status ReloadChangedFileCB(void* param, const VfsPath& path) | static Status ReloadChangedFileCB(void* param, const VfsPath& path) | ||||
{ | { | ||||
return static_cast<CGUIManager*>(param)->ReloadChangedFile(path); | return static_cast<CGUIManager*>(param)->ReloadChangedFile(path); | ||||
} | } | ||||
CGUIManager::CGUIManager() | CGUIManager::CGUIManager() | ||||
{ | { | ||||
m_ScriptRuntime = g_ScriptRuntime; | m_ScriptContext = g_ScriptContext; | ||||
m_ScriptInterface.reset(new ScriptInterface("Engine", "GUIManager", m_ScriptRuntime)); | m_ScriptInterface.reset(new ScriptInterface("Engine", "GUIManager", m_ScriptContext)); | ||||
m_ScriptInterface->SetCallbackData(this); | m_ScriptInterface->SetCallbackData(this); | ||||
m_ScriptInterface->LoadGlobalScripts(); | m_ScriptInterface->LoadGlobalScripts(); | ||||
if (!CXeromyces::AddValidator(g_VFS, "gui_page", "gui/gui_page.rng")) | if (!CXeromyces::AddValidator(g_VFS, "gui_page", "gui/gui_page.rng")) | ||||
LOGERROR("CGUIManager: failed to load GUI page grammar file 'gui/gui_page.rng'"); | LOGERROR("CGUIManager: failed to load GUI page grammar file 'gui/gui_page.rng'"); | ||||
if (!CXeromyces::AddValidator(g_VFS, "gui", "gui/gui.rng")) | if (!CXeromyces::AddValidator(g_VFS, "gui", "gui/gui.rng")) | ||||
LOGERROR("CGUIManager: failed to load GUI XML grammar file 'gui/gui.rng'"); | LOGERROR("CGUIManager: failed to load GUI XML grammar file 'gui/gui.rng'"); | ||||
Show All 28 Lines | |||||
{ | { | ||||
// Store the callback handler in the current GUI page before opening the new one | // Store the callback handler in the current GUI page before opening the new one | ||||
if (!m_PageStack.empty() && !callbackFunction.isUndefined()) | if (!m_PageStack.empty() && !callbackFunction.isUndefined()) | ||||
m_PageStack.back().SetCallbackFunction(*m_ScriptInterface, callbackFunction); | 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_ScriptContext); | ||||
} | } | ||||
void CGUIManager::PopPage(shared_ptr<ScriptInterface::StructuredClone> args) | 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); | m_PageStack.back().PerformCallbackFunction(args); | ||||
} | } | ||||
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(), callbackFunction() | : name(pageName), initData(initData), inputs(), gui(), callbackFunction() | ||||
{ | { | ||||
} | } | ||||
void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptRuntime> scriptRuntime) | void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptContext> scriptContext) | ||||
{ | { | ||||
// 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) | ||||
{ | { | ||||
shared_ptr<ScriptInterface> scriptInterface = gui->GetScriptInterface(); | shared_ptr<ScriptInterface> scriptInterface = gui->GetScriptInterface(); | ||||
ScriptInterface::Request rq(scriptInterface); | ScriptInterface::Request rq(scriptInterface); | ||||
JS::RootedValue global(rq.cx, rq.globalValue()); | JS::RootedValue global(rq.cx, rq.globalValue()); | ||||
JS::RootedValue hotloadDataVal(rq.cx); | JS::RootedValue hotloadDataVal(rq.cx); | ||||
scriptInterface->CallFunction(global, "getHotloadData", &hotloadDataVal); | scriptInterface->CallFunction(global, "getHotloadData", &hotloadDataVal); | ||||
hotloadData = scriptInterface->WriteStructuredClone(hotloadDataVal); | hotloadData = scriptInterface->WriteStructuredClone(hotloadDataVal); | ||||
} | } | ||||
g_CursorName = g_DefaultCursor; | g_CursorName = g_DefaultCursor; | ||||
inputs.clear(); | inputs.clear(); | ||||
gui.reset(new CGUI(scriptRuntime)); | gui.reset(new CGUI(scriptContext)); | ||||
gui->AddObjectTypes(); | gui->AddObjectTypes(); | ||||
VfsPath path = VfsPath("gui") / name; | VfsPath path = VfsPath("gui") / name; | ||||
inputs.insert(path); | inputs.insert(path); | ||||
CXeromyces xero; | CXeromyces xero; | ||||
if (xero.Load(g_VFS, path, "gui_page") != PSRETURN_OK) | if (xero.Load(g_VFS, path, "gui_page") != PSRETURN_OK) | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
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.find(path) != p.inputs.end()) | if (p.inputs.find(path) != p.inputs.end()) | ||||
{ | { | ||||
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_ScriptContext); | ||||
// 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 | ||||
} | } | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
Status CGUIManager::ReloadAllPages() | Status CGUIManager::ReloadAllPages() | ||||
{ | { | ||||
// 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 | ||||
for (SGUIPage& p : m_PageStack) | for (SGUIPage& p : m_PageStack) | ||||
p.LoadPage(m_ScriptRuntime); | p.LoadPage(m_ScriptContext); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
InReaction CGUIManager::HandleEvent(const SDL_Event_* ev) | InReaction CGUIManager::HandleEvent(const SDL_Event_* ev) | ||||
{ | { | ||||
// We want scripts to have access to the raw input events, so they can do complex | // We want scripts to have access to the raw input events, so they can do complex | ||||
// processing when necessary (e.g. for unit selection and camera movement). | // processing when necessary (e.g. for unit selection and camera movement). | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | void CGUIManager::SendEventToAll(const CStr& eventName, JS::HandleValueArray paramData) const | ||||
for (const SGUIPage& p : pageStack) | for (const SGUIPage& p : pageStack) | ||||
p.gui->SendEventToAll(eventName, paramData); | p.gui->SendEventToAll(eventName, paramData); | ||||
} | } | ||||
void CGUIManager::TickObjects() | void CGUIManager::TickObjects() | ||||
{ | { | ||||
PROFILE3("gui tick"); | PROFILE3("gui tick"); | ||||
// We share the script runtime with everything else that runs in the same thread. | // We share the script context with everything else that runs in the same thread. | ||||
// This call makes sure we trigger GC regularly even if the simulation is not running. | // This call makes sure we trigger GC regularly even if the simulation is not running. | ||||
m_ScriptInterface->GetRuntime()->MaybeIncrementalGC(1.0f); | m_ScriptInterface->GetContext()->MaybeIncrementalGC(1.0f); | ||||
// Save an immutable copy so iterators aren't invalidated by tick handlers | // Save an immutable copy so iterators aren't invalidated by tick handlers | ||||
PageStackType pageStack = m_PageStack; | PageStackType pageStack = m_PageStack; | ||||
for (const SGUIPage& p : pageStack) | for (const SGUIPage& p : pageStack) | ||||
p.gui->TickObjects(); | p.gui->TickObjects(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 42 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator