Changeset View
Changeset View
Standalone View
Standalone View
source/gui/Scripting/JSInterface_IGUIObject.cpp
- This file was copied to source/gui/Scripting/JSInterface_GUIProxy_impl.h.
/* Copyright (C) 2020 Wildfire Games. | /* Copyright (C) 2019 Wildfire Games. | ||||
Stan: 2020 | |||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 0 A.D. is free software: you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
* GNU General Public License for more details. | * GNU General Public License for more details. | ||||
* | * | ||||
* You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | ||||
*/ | */ | ||||
#include "precompiled.h" | #include "precompiled.h" | ||||
#include "JSInterface_IGUIObject.h" | #include "JSInterface_GUIProxy.h" | ||||
#include "gui/CGUI.h" | #include "gui/CGUI.h" | ||||
#include "gui/CGUISetting.h" | #include "gui/CGUISetting.h" | ||||
#include "gui/ObjectBases/IGUIObject.h" | #include "gui/ObjectBases/IGUIObject.h" | ||||
#include "gui/ObjectTypes/CText.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 = { | // Include the definition of the generic templates. | ||||
"GUIObject", JSCLASS_HAS_PRIVATE, &JSI_IGUIObject::JSI_classops | #include "JSInterface_GUIProxy_impl.h" | ||||
}; | |||||
JSClassOps JSI_IGUIObject::JSI_classops = { | |||||
nullptr, | |||||
JSI_IGUIObject::deleteProperty, | |||||
JSI_IGUIObject::getProperty, | |||||
JSI_IGUIObject::setProperty, | |||||
nullptr, nullptr, nullptr, nullptr, | |||||
nullptr, nullptr, nullptr, nullptr | |||||
}; | |||||
JSFunctionSpec JSI_IGUIObject::JSI_methods[] = | namespace { | ||||
struct SData | |||||
{ | { | ||||
JS_FN("toString", JSI_IGUIObject::toString, 0, 0), | JS::PersistentRootedObject m_ToString; | ||||
JS_FN("focus", JSI_IGUIObject::focus, 0, 0), | JS::PersistentRootedObject m_Focus; | ||||
JS_FN("blur", JSI_IGUIObject::blur, 0, 0), | JS::PersistentRootedObject m_Blur; | ||||
JS_FN("getComputedSize", JSI_IGUIObject::getComputedSize, 0, 0), | JS::PersistentRootedObject m_GetComputedSize; | ||||
JS_FS_END | |||||
}; | }; | ||||
void JSI_IGUIObject::RegisterScriptClass(ScriptInterface& scriptInterface) | |||||
{ | |||||
scriptInterface.DefineCustomObjectType(&JSI_class, nullptr, 0, nullptr, JSI_methods, nullptr, nullptr); | |||||
} | } | ||||
bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) | template <> | ||||
bool JSI_GUIProxy<IGUIObject>::funcGetter(IGUIObject* elem, const std::string& propName, JS::MutableHandleValue vp) const | |||||
Done Inline ActionsCome C++14, I think these all become: wraitii: Come C++14, I think these all become:
`SetupHandler<&CText::GetTextSize>(scriptInterface. | |||||
Not Done Inline ActionsYou should put this comment with the future code instead of the vague TODO ? Itms: You should put this comment with the future code instead of the vague TODO ? | |||||
StanUnsubmitted Done Inline Actions#include <string> Stan: ```lang=cpp
#include <string>
``` | |||||
{ | { | ||||
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; | const SData& data = *static_cast<const SData*>(elem->GetGUI().GetProxyData(this)); | ||||
ScriptRequest rq(*pScriptInterface); | if (propName == "toString") | ||||
return vp.setObjectOrNull(data.m_ToString), true; | |||||
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, obj, &JSI_IGUIObject::JSI_class); | if (propName == "focus") | ||||
if (!e) | return vp.setObjectOrNull(data.m_Focus), true; | ||||
if (propName == "blur") | |||||
return vp.setObjectOrNull(data.m_Blur), true; | |||||
if (propName == "getComputedSize") | |||||
return vp.setObjectOrNull(data.m_GetComputedSize), true; | |||||
return false; | return false; | ||||
JS::RootedValue idval(rq.cx); | |||||
if (!JS_IdToValue(rq.cx, id, &idval)) | |||||
return false; | |||||
std::string propName; | |||||
if (!ScriptInterface::FromJSVal(rq, idval, propName)) | |||||
return false; | |||||
// Skip registered functions and inherited properties | |||||
// including JSInterfaces of derived classes | |||||
if (propName == "constructor" || | |||||
propName == "prototype" || | |||||
propName == "toString" || | |||||
propName == "toJSON" || | |||||
propName == "focus" || | |||||
propName == "blur" || | |||||
propName == "getTextSize" || | |||||
propName == "getComputedSize" | |||||
) | |||||
return true; | |||||
// Use onWhatever to access event handlers | |||||
if (propName.substr(0, 2) == "on") | |||||
{ | |||||
CStr eventName(propName.substr(2)); | |||||
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") | |||||
{ | |||||
IGUIObject* parent = e->GetParent(); | |||||
if (parent) | |||||
vp.set(JS::ObjectValue(*parent->GetJSObject())); | |||||
else | |||||
vp.set(JS::NullValue()); | |||||
return true; | |||||
} | } | ||||
else if (propName == "children") | |||||
{ | |||||
ScriptInterface::CreateArray(rq, vp); | |||||
for (size_t i = 0; i < e->m_Children.size(); ++i) | template <> | ||||
pScriptInterface->SetPropertyInt(vp, i, e->m_Children[i]); | std::pair<const js::BaseProxyHandler*, void*> JSI_GUIProxy<IGUIObject>::CreateData(ScriptInterface& scriptInterface) | ||||
{ | |||||
return true; | SData* data = new SData(); | ||||
ScriptRequest rq(scriptInterface); | |||||
#define func(class, func) &apply_to<IGUIObject, class, &class::func> | |||||
data->m_ToString.init(rq.cx, JS_GetFunctionObject(JS_NewFunction(rq.cx, func(IGUIObject, toString), 0, 0, "toString"))); | |||||
data->m_Focus.init(rq.cx, JS_GetFunctionObject(JS_NewFunction(rq.cx, func(IGUIObject, focus), 0, 0, "focus"))); | |||||
data->m_Blur.init(rq.cx, JS_GetFunctionObject(JS_NewFunction(rq.cx, func(IGUIObject, blur), 0, 0, "blur"))); | |||||
data->m_GetComputedSize.init(rq.cx, JS_GetFunctionObject(JS_NewFunction(rq.cx, func(IGUIObject, getComputedSize), 0, 0, "getComputedSize"))); | |||||
#undef func | |||||
return { &Singleton(), data }; | |||||
} | } | ||||
else if (propName == "name") | |||||
{ | |||||
ScriptInterface::ToJSVal(rq, vp, e->GetName()); | |||||
return true; | |||||
} | |||||
else if (e->SettingExists(propName)) | |||||
{ | |||||
e->m_Settings[propName]->ToJSVal(rq, vp); | |||||
return true; | |||||
} | |||||
LOGERROR("Property '%s' does not exist!", propName.c_str()); | |||||
return false; | |||||
} | |||||
bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result) | |||||
{ | |||||
ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); | |||||
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, obj, &JSI_IGUIObject::JSI_class); | |||||
Not Done Inline ActionsI think you should add a new static method to ScriptInterface for the new use. The new calls to the proxy private and the static casts are a bit ugly. Itms: I think you should add a new static method to ScriptInterface for the new use. The new calls to… | |||||
if (!e) | |||||
return result.fail(JSMSG_NOT_NONNULL_OBJECT); | |||||
JS::RootedValue idval(rq.cx); | |||||
if (!JS_IdToValue(rq.cx, id, &idval)) | |||||
return result.fail(JSMSG_NOT_NONNULL_OBJECT); | |||||
std::string propName; | |||||
if (!ScriptInterface::FromJSVal(rq, idval, propName)) | |||||
return result.fail(JSMSG_UNDEFINED_PROP); | |||||
if (propName == "name") | |||||
{ | |||||
std::string value; | |||||
if (!ScriptInterface::FromJSVal(rq, vp, value)) | |||||
return result.fail(JSMSG_UNDEFINED_PROP); | |||||
e->SetName(value); | |||||
return result.succeed(); | |||||
} | |||||
JS::RootedObject vpObj(rq.cx); | |||||
if (vp.isObject()) | |||||
vpObj = &vp.toObject(); | |||||
// Use onWhatever to set event handlers | |||||
if (propName.substr(0, 2) == "on") | |||||
{ | |||||
if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(rq.cx, &vp.toObject())) | |||||
{ | |||||
LOGERROR("on- event-handlers must be functions"); | |||||
return result.fail(JSMSG_NOT_FUNCTION); | |||||
} | |||||
CStr eventName(propName.substr(2)); | |||||
e->SetScriptHandler(eventName, vpObj); | |||||
return result.succeed(); | template class JSI_GUIProxy<IGUIObject>; | ||||
} | |||||
if (e->SettingExists(propName)) | |||||
return e->m_Settings[propName]->FromJSVal(rq, vp, true) ? result.succeed() : result.fail(JSMSG_USER_DEFINED_ERROR); | |||||
LOGERROR("Property '%s' does not exist!", propName.c_str()); | |||||
return result.fail(JSMSG_UNDEFINED_PROP); | |||||
} | |||||
bool JSI_IGUIObject::deleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result) | |||||
{ | |||||
ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); | |||||
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, obj, &JSI_IGUIObject::JSI_class); | |||||
if (!e) | |||||
return result.fail(JSMSG_NOT_NONNULL_OBJECT); | |||||
JS::RootedValue idval(rq.cx); | |||||
if (!JS_IdToValue(rq.cx, id, &idval)) | |||||
return result.fail(JSMSG_NOT_NONNULL_OBJECT); | |||||
std::string propName; | |||||
if (!ScriptInterface::FromJSVal(rq, idval, propName)) | |||||
return result.fail(JSMSG_UNDEFINED_PROP); | |||||
// event handlers | |||||
if (propName.substr(0, 2) == "on") | |||||
{ | |||||
CStr eventName(propName.substr(2)); | |||||
e->UnsetScriptHandler(eventName); | |||||
return result.succeed(); | |||||
} | |||||
LOGERROR("Only event handlers can be deleted from GUI objects!"); | |||||
return result.fail(JSMSG_UNDEFINED_PROP); | |||||
} | |||||
bool JSI_IGUIObject::toString(JSContext* cx, uint argc, JS::Value* vp) | |||||
{ | |||||
ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); | |||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); | |||||
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, args, &JSI_IGUIObject::JSI_class); | |||||
if (!e) | |||||
return false; | |||||
ScriptInterface::ToJSVal(rq, args.rval(), "[GUIObject: " + e->GetName() + "]"); | |||||
return true; | |||||
} | |||||
bool JSI_IGUIObject::focus(JSContext* cx, uint argc, JS::Value* vp) | |||||
{ | |||||
ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); | |||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); | |||||
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, args, &JSI_IGUIObject::JSI_class); | |||||
if (!e) | |||||
return false; | |||||
e->GetGUI().SetFocusedObject(e); | |||||
args.rval().setUndefined(); | |||||
return true; | |||||
} | |||||
bool JSI_IGUIObject::blur(JSContext* cx, uint argc, JS::Value* vp) | |||||
{ | |||||
ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); | |||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); | |||||
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, args, &JSI_IGUIObject::JSI_class); | |||||
if (!e) | |||||
return false; | |||||
e->GetGUI().SetFocusedObject(nullptr); | |||||
args.rval().setUndefined(); | |||||
return true; | |||||
} | |||||
bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, JS::Value* vp) | |||||
{ | |||||
ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); | |||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); | |||||
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, args, &JSI_IGUIObject::JSI_class); | |||||
if (!e) | |||||
return false; | |||||
e->UpdateCachedSize(); | |||||
ScriptInterface::ToJSVal(rq, args.rval(), e->m_CachedActualSize); | |||||
return true; | |||||
} |
Wildfire Games · Phabricator
2020