Changeset View
Changeset View
Standalone View
Standalone View
source/gui/scripting/JSInterface_IGUIObject.cpp
Show All 27 Lines | |||||
#include "gui/scripting/JSInterface_GUITypes.h" | #include "gui/scripting/JSInterface_GUITypes.h" | ||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "scriptinterface/ScriptExtraHeaders.h" | #include "scriptinterface/ScriptExtraHeaders.h" | ||||
#include "scriptinterface/ScriptInterface.h" | #include "scriptinterface/ScriptInterface.h" | ||||
JSClass JSI_IGUIObject::JSI_class = { | JSClass JSI_IGUIObject::JSI_class = { | ||||
"GUIObject", JSCLASS_HAS_PRIVATE, | "GUIObject", JSCLASS_HAS_PRIVATE, | ||||
nullptr, nullptr, | nullptr, nullptr, | ||||
JSI_IGUIObject::getProperty, JSI_IGUIObject::setProperty, | [](JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) { return performObjectProperty(cx, obj, id, vp, getProperty); }, | ||||
[](JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool UNUSED(strict), JS::MutableHandleValue vp) { return performObjectProperty(cx, obj, id, vp, setProperty); }, | |||||
nullptr, nullptr, nullptr, nullptr, | nullptr, nullptr, nullptr, nullptr, | ||||
nullptr, nullptr, nullptr, nullptr | nullptr, nullptr, nullptr, nullptr | ||||
}; | }; | ||||
JSFunctionSpec JSI_IGUIObject::JSI_methods[] = | JSFunctionSpec JSI_IGUIObject::JSI_methods[] = | ||||
{ | { | ||||
JS_FN("toString", JSI_IGUIObject::toString, 0, 0), | JS_FN("toString", [](JSContext* cx, uint UNUSED(argc), JS::Value* vp){ return performObjectFunction(cx, vp, toString); }, 0, 0), | ||||
JS_FN("focus", JSI_IGUIObject::focus, 0, 0), | JS_FN("focus", [](JSContext* cx, uint UNUSED(argc), JS::Value* vp){ return performObjectFunction(cx, vp, focus); }, 0, 0), | ||||
JS_FN("blur", JSI_IGUIObject::blur, 0, 0), | JS_FN("blur", [](JSContext* cx, uint UNUSED(argc), JS::Value* vp){ return performObjectFunction(cx, vp, blur); }, 0, 0), | ||||
JS_FN("getComputedSize", JSI_IGUIObject::getComputedSize, 0, 0), | JS_FN("getComputedSize", [](JSContext* cx, uint UNUSED(argc), JS::Value* vp){ return performObjectFunction(cx, vp, getComputedSize); }, 0, 0), | ||||
JS_FS_END | JS_FS_END | ||||
}; | }; | ||||
bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) | bool JSI_IGUIObject::performOnGUIObject(JSContext* cx, JS::HandleObject thisObj, JS::MutableHandleValue vp, std::function<bool(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue vp)> action) | ||||
{ | { | ||||
JSAutoRequest rq(cx); | IGUIObject* obj = static_cast<IGUIObject*>( | ||||
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; | JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, nullptr)); | ||||
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); | if (!obj) | ||||
if (!e) | { | ||||
JS_ReportError(cx, "JSI_IGUIObject could not determine the IGUIObject instance!"); | |||||
return false; | return false; | ||||
} | |||||
action(cx, *obj, vp); | |||||
return true; | |||||
} | |||||
bool JSI_IGUIObject::performObjectFunction(JSContext* cx, JS::Value* vp, std::function<bool(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue vp)> action) | |||||
{ | |||||
JSAutoRequest rq(cx); | |||||
JS::CallReceiver rec = JS::CallReceiverFromVp(vp); | |||||
JS::RootedObject thisObj(cx, &rec.thisv().toObject()); | |||||
return performOnGUIObject(cx, thisObj, rec.rval(), action); | |||||
} | |||||
bool JSI_IGUIObject::performObjectProperty(JSContext* cx, JS::HandleObject thisObj, JS::HandleId id, JS::MutableHandleValue vp, std::function<bool(JSContext* cx, IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp)> action) | |||||
{ | |||||
JSAutoRequest rq(cx); | |||||
JS::RootedValue idval(cx); | JS::RootedValue idval(cx); | ||||
if (!JS_IdToValue(cx, id, &idval)) | if (!JS_IdToValue(cx, id, &idval)) | ||||
return false; | return false; | ||||
std::string propName; | std::string propName; | ||||
if (!ScriptInterface::FromJSVal(cx, idval, propName)) | if (!ScriptInterface::FromJSVal(cx, idval, propName)) | ||||
return false; | return false; | ||||
return performOnGUIObject(cx, thisObj, vp, [&propName, action](JSContext* cx, IGUIObject& obj, JS::MutableHandleValue vp) | |||||
{ | |||||
return action(cx, obj, propName, vp); | |||||
}); | |||||
} | |||||
bool JSI_IGUIObject::getProperty(JSContext* cx, IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp) | |||||
{ | |||||
// Skip registered functions and inherited properties | // Skip registered functions and inherited properties | ||||
// including JSInterfaces of derived classes | // including JSInterfaces of derived classes | ||||
if (propName == "constructor" || | if (propName == "constructor" || | ||||
propName == "prototype" || | propName == "prototype" || | ||||
propName == "toString" || | propName == "toString" || | ||||
propName == "toJSON" || | propName == "toJSON" || | ||||
propName == "focus" || | propName == "focus" || | ||||
propName == "blur" || | propName == "blur" || | ||||
propName == "getTextSize" || | propName == "getTextSize" || | ||||
propName == "getComputedSize" | propName == "getComputedSize" | ||||
) | ) | ||||
return true; | return true; | ||||
// Use onWhatever to access event handlers | // Use onWhatever to access event handlers | ||||
if (propName.substr(0, 2) == "on") | if (propName.substr(0, 2) == "on") | ||||
{ | return getEventHandler(cx, obj, propName, vp); | ||||
CStr eventName(CStr(propName.substr(2)).LowerCase()); | |||||
std::map<CStr, JS::Heap<JSObject*>>::iterator it = e->m_ScriptHandlers.find(eventName); | |||||
if (it == e->m_ScriptHandlers.end()) | |||||
vp.setNull(); | |||||
else | |||||
vp.setObject(*it->second.get()); | |||||
return true; | |||||
} | |||||
if (propName == "parent") | if (propName == "parent") | ||||
{ | return getParent(cx, obj, propName, vp); | ||||
IGUIObject* parent = e->GetParent(); | |||||
if (parent) | |||||
vp.set(JS::ObjectValue(*parent->GetJSObject())); | |||||
else | |||||
vp.set(JS::NullValue()); | |||||
return true; | if (propName == "children") | ||||
} | return getChildren(cx, obj, propName, vp); | ||||
else if (propName == "children") | |||||
{ | |||||
pScriptInterface->CreateArray(vp); | |||||
for (size_t i = 0; i < e->m_Children.size(); ++i) | if (propName == "name") | ||||
pScriptInterface->SetPropertyInt(vp, i, e->m_Children[i]); | return getName(cx, obj, propName, vp); | ||||
return true; | if (obj.SettingExists(propName)) | ||||
} | |||||
else if (propName == "name") | |||||
{ | { | ||||
ScriptInterface::ToJSVal(cx, vp, e->GetName()); | obj.m_Settings[propName].m_ToJSVal(cx, vp); | ||||
return true; | |||||
} | |||||
else if (e->SettingExists(propName)) | |||||
{ | |||||
e->m_Settings[propName].m_ToJSVal(cx, vp); | |||||
return true; | return true; | ||||
} | } | ||||
JS_ReportError(cx, "Property '%s' does not exist!", propName.c_str()); | JS_ReportError(cx, "Property '%s' does not exist!", propName.c_str()); | ||||
return false; | return false; | ||||
} | } | ||||
bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool UNUSED(strict), JS::MutableHandleValue vp) | bool JSI_IGUIObject::setProperty(JSContext* cx, IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp) | ||||
{ | { | ||||
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); | |||||
if (!e) | |||||
return false; | |||||
JSAutoRequest rq(cx); | |||||
JS::RootedValue idval(cx); | |||||
if (!JS_IdToValue(cx, id, &idval)) | |||||
return false; | |||||
std::string propName; | |||||
if (!ScriptInterface::FromJSVal(cx, idval, propName)) | |||||
return false; | |||||
if (propName == "name") | if (propName == "name") | ||||
{ | return setName(cx, obj, propName, vp); | ||||
std::string value; | |||||
if (!ScriptInterface::FromJSVal(cx, vp, value)) | |||||
return false; | |||||
e->SetName(value); | |||||
return true; | |||||
} | |||||
JS::RootedObject vpObj(cx); | |||||
if (vp.isObject()) | |||||
vpObj = &vp.toObject(); | |||||
// Use onWhatever to set event handlers | // Use onWhatever to set event handlers | ||||
if (propName.substr(0, 2) == "on") | if (propName.substr(0, 2) == "on") | ||||
{ | return setEventHandler(cx, obj, propName, vp); | ||||
if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(cx, &vp.toObject())) | |||||
{ | |||||
JS_ReportError(cx, "on- event-handlers must be functions"); | |||||
return false; | |||||
} | |||||
CStr eventName(CStr(propName.substr(2)).LowerCase()); | if (obj.SettingExists(propName)) | ||||
e->SetScriptHandler(eventName, vpObj); | return obj.m_Settings[propName].m_FromJSVal(cx, vp); | ||||
return true; | |||||
} | |||||
if (e->SettingExists(propName)) | |||||
return e->m_Settings[propName].m_FromJSVal(cx, vp); | |||||
JS_ReportError(cx, "Property '%s' does not exist!", propName.c_str()); | JS_ReportError(cx, "Property '%s' does not exist!", propName.c_str()); | ||||
return false; | return false; | ||||
} | } | ||||
void JSI_IGUIObject::init(ScriptInterface& scriptInterface) | void JSI_IGUIObject::init(ScriptInterface& scriptInterface) | ||||
{ | { | ||||
scriptInterface.DefineCustomObjectType(&JSI_class, nullptr, 1, nullptr, JSI_methods, nullptr, nullptr); | scriptInterface.DefineCustomObjectType(&JSI_class, nullptr, 1, nullptr, JSI_methods, nullptr, nullptr); | ||||
} | } | ||||
bool JSI_IGUIObject::toString(JSContext* cx, uint UNUSED(argc), JS::Value* vp) | bool JSI_IGUIObject::toString(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue vp) | ||||
{ | { | ||||
JSAutoRequest rq(cx); | ScriptInterface::ToJSVal(cx, vp, "[GUIObject: " + obj.GetName() + "]"); | ||||
JS::CallReceiver rec = JS::CallReceiverFromVp(vp); | return true; | ||||
} | |||||
JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); | bool JSI_IGUIObject::getName(JSContext* cx, IGUIObject& obj, const CStr& UNUSED(propName), JS::MutableHandleValue vp) | ||||
{ | |||||
ScriptInterface::ToJSVal(cx, vp, obj.GetName()); | |||||
return true; | |||||
} | |||||
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); | bool JSI_IGUIObject::setName(JSContext* cx, IGUIObject& obj, const CStr& UNUSED(propName), JS::MutableHandleValue vp) | ||||
if (!e) | { | ||||
CStr value; | |||||
if (!ScriptInterface::FromJSVal(cx, vp, value)) | |||||
return false; | return false; | ||||
ScriptInterface::ToJSVal(cx, rec.rval(), "[GUIObject: " + e->GetName() + "]"); | obj.SetName(value); | ||||
return true; | return true; | ||||
} | } | ||||
bool JSI_IGUIObject::focus(JSContext* cx, uint UNUSED(argc), JS::Value* vp) | CStr JSI_IGUIObject::getEventName(const CStr& propName) | ||||
{ | { | ||||
JSAutoRequest rq(cx); | return CStr(propName.substr(2)).LowerCase(); | ||||
JS::CallReceiver rec = JS::CallReceiverFromVp(vp); | } | ||||
JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); | |||||
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); | bool JSI_IGUIObject::getEventHandler(JSContext* UNUSED(cx), IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp) | ||||
if (!e) | { | ||||
return false; | std::map<CStr, JS::Heap<JSObject*>>::iterator it = obj.m_ScriptHandlers.find(getEventName(propName)); | ||||
e->GetGUI()->SetFocusedObject(e); | if (it == obj.m_ScriptHandlers.end()) | ||||
vp.setNull(); | |||||
else | |||||
vp.setObject(*it->second.get()); | |||||
rec.rval().setUndefined(); | |||||
return true; | return true; | ||||
} | } | ||||
bool JSI_IGUIObject::blur(JSContext* cx, uint UNUSED(argc), JS::Value* vp) | bool JSI_IGUIObject::setEventHandler(JSContext* cx, IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp) | ||||
{ | { | ||||
JSAutoRequest rq(cx); | if (!vp.isObject() || !JS_ObjectIsFunction(cx, &vp.toObject())) | ||||
JS::CallReceiver rec = JS::CallReceiverFromVp(vp); | { | ||||
JS_ReportError(cx, "on- event-handlers must be functions"); | |||||
return false; | |||||
} | |||||
JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); | JS::RootedObject vpObj(cx, &vp.toObject()); | ||||
obj.SetScriptHandler(getEventName(propName), vpObj); | |||||
return true; | |||||
} | |||||
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); | bool JSI_IGUIObject::getParent(JSContext* UNUSED(cx), IGUIObject& obj, const CStr& UNUSED(propName), JS::MutableHandleValue vp) | ||||
if (!e) | { | ||||
return false; | IGUIObject* parent = obj.GetParent(); | ||||
e->GetGUI()->SetFocusedObject(NULL); | if (parent) | ||||
vp.set(JS::ObjectValue(*parent->GetJSObject())); | |||||
else | |||||
vp.set(JS::NullValue()); | |||||
rec.rval().setUndefined(); | |||||
return true; | return true; | ||||
} | } | ||||
bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint UNUSED(argc), JS::Value* vp) | bool JSI_IGUIObject::getChildren(JSContext* cx, IGUIObject& obj, const CStr& UNUSED(propName), JS::MutableHandleValue vp) | ||||
{ | { | ||||
JSAutoRequest rq(cx); | ScriptInterface& pScriptInterface = *ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; | ||||
JS::CallReceiver rec = JS::CallReceiverFromVp(vp); | pScriptInterface.CreateArray(vp); | ||||
JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); | for (size_t i = 0; i < obj.m_Children.size(); ++i) | ||||
pScriptInterface.SetPropertyInt(vp, i, obj.m_Children[i]); | |||||
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); | return true; | ||||
if (!e) | } | ||||
return false; | |||||
e->UpdateCachedSize(); | |||||
CRect size = e->m_CachedActualSize; | |||||
JS::RootedValue objVal(cx); | bool JSI_IGUIObject::focus(JSContext* UNUSED(cx), IGUIObject& obj, JS::MutableHandleValue vp) | ||||
try | |||||
{ | { | ||||
ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface->CreateObject( | obj.GetGUI()->SetFocusedObject(&obj); | ||||
&objVal, | vp.setUndefined(); | ||||
"left", size.left, | return true; | ||||
"right", size.right, | |||||
"top", size.top, | |||||
"bottom", size.bottom); | |||||
} | } | ||||
catch (PSERROR_Scripting_ConversionFailed&) | |||||
bool JSI_IGUIObject::blur(JSContext* UNUSED(cx), IGUIObject& obj, JS::MutableHandleValue vp) | |||||
{ | { | ||||
debug_warn(L"Error creating size object!"); | obj.GetGUI()->SetFocusedObject(nullptr); | ||||
return false; | vp.setUndefined(); | ||||
return true; | |||||
} | } | ||||
rec.rval().set(objVal); | bool JSI_IGUIObject::getComputedSize(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue vp) | ||||
{ | |||||
obj.UpdateCachedSize(); | |||||
ScriptInterface::ToJSVal(cx, vp, obj.m_CachedActualSize); | |||||
return true; | return true; | ||||
} | } |
Wildfire Games · Phabricator