Changeset View
Changeset View
Standalone View
Standalone View
source/gui/scripting/JSInterface_IGUIObject.cpp
Show All 12 Lines | |||||
* | * | ||||
* 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_IGUIObject.h" | ||||
#include "JSInterface_GUITypes.h" | |||||
#include "gui/IGUIObject.h" | |||||
#include "gui/CGUI.h" | #include "gui/CGUI.h" | ||||
#include "gui/IGUIScrollBar.h" | #include "gui/CGUIList.h" | ||||
#include "gui/CList.h" | #include "gui/CGUISprite.h" | ||||
#include "gui/GUIManager.h" | #include "gui/CGUISeries.h" | ||||
#include "gui/GUIutil.h" | |||||
#include "gui/IGUIObject.h" | |||||
#include "gui/scripting/JSInterface_GUITypes.h" | |||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "ps/CStr.h" | |||||
#include "scriptinterface/ScriptInterface.h" | #include "scriptinterface/ScriptInterface.h" | ||||
#include "scriptinterface/ScriptExtraHeaders.h" | #include "scriptinterface/ScriptExtraHeaders.h" | ||||
#include <map> | |||||
#include <string> | |||||
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, | JSI_IGUIObject::getProperty, JSI_IGUIObject::setProperty, | ||||
nullptr, nullptr, nullptr, nullptr, | nullptr, nullptr, nullptr, nullptr, | ||||
nullptr, nullptr, JSI_IGUIObject::construct, nullptr | nullptr, nullptr, nullptr, nullptr | ||||
}; | }; | ||||
JSPropertySpec JSI_IGUIObject::JSI_props[] = | JSPropertySpec JSI_IGUIObject::JSI_props[] = | ||||
{ | { | ||||
{ 0 } | JS_PS_END | ||||
}; | }; | ||||
JSFunctionSpec JSI_IGUIObject::JSI_methods[] = | JSFunctionSpec JSI_IGUIObject::JSI_methods[] = | ||||
{ | { | ||||
JS_FS("toString", JSI_IGUIObject::toString, 0, 0), | JS_FS("toString", JSI_IGUIObject::toString, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT), | ||||
JS_FS("focus", JSI_IGUIObject::focus, 0, 0), | JS_FS("focus", JSI_IGUIObject::focus, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT), | ||||
JS_FS("blur", JSI_IGUIObject::blur, 0, 0), | JS_FS("blur", JSI_IGUIObject::blur, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT), | ||||
JS_FS("getComputedSize", JSI_IGUIObject::getComputedSize, 0, 0), | JS_FS("getComputedSize", JSI_IGUIObject::getComputedSize, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT), | ||||
JS_FS_END | JS_FS_END | ||||
}; | }; | ||||
void JSI_IGUIObject::RegisterScriptClass(ScriptInterface& scriptInterface) | |||||
{ | |||||
scriptInterface.DefineCustomObjectType(&JSI_class, nullptr, 1, JSI_props, JSI_methods, nullptr, nullptr); | |||||
} | |||||
bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) | bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) | ||||
{ | { | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; | ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; | ||||
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); | IGUIObject* guiObject = static_cast<IGUIObject*>(JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, nullptr)); | ||||
if (!e) | if (!guiObject) | ||||
return false; | return false; | ||||
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; | ||||
// Skip some things which are known to be functions rather than properties. | // Skip some things which are known to be functions rather than properties. | ||||
// ("constructor" *must* be here, else it'll try to GetSettingType before | // ("constructor" *must* be here, else it'll try to GetSettingType before | ||||
// the private IGUIObject* has been set (and thus crash). The others are | // the private IGUIObject* has been set (and thus crash). The others are | ||||
// partly for efficiency, and also to allow correct reporting of attempts to | // partly for efficiency, and also to allow correct reporting of attempts to | ||||
// access nonexistent properties.) | // access nonexistent properties.) | ||||
if (propName == "constructor" || | if (propName == "prototype" || | ||||
propName == "prototype" || | |||||
propName == "toString" || | propName == "toString" || | ||||
propName == "toJSON" || | propName == "toJSON" || | ||||
propName == "focus" || | propName == "focus" || | ||||
propName == "blur" || | propName == "blur" || | ||||
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") | ||||
{ | { | ||||
CStr eventName(CStr(propName.substr(2)).LowerCase()); | CStr eventName(CStr(propName.substr(2)).LowerCase()); | ||||
std::map<CStr, JS::Heap<JSObject*>>::iterator it = e->m_ScriptHandlers.find(eventName); | std::map<CStr, JS::Heap<JSObject*>>::iterator it = guiObject->m_ScriptHandlers.find(eventName); | ||||
if (it == e->m_ScriptHandlers.end()) | if (it == guiObject->m_ScriptHandlers.end()) | ||||
vp.setNull(); | vp.setNull(); | ||||
else | else | ||||
vp.setObject(*it->second.get()); | vp.setObject(*it->second.get()); | ||||
return true; | return true; | ||||
} | } | ||||
if (propName == "parent") | if (propName == "parent") | ||||
{ | { | ||||
IGUIObject* parent = e->GetParent(); | IGUIObject* parent = guiObject->GetParent(); | ||||
if (parent) | if (parent) | ||||
vp.set(JS::ObjectValue(*parent->GetJSObject())); | vp.set(JS::ObjectValue(*parent->GetJSObject())); | ||||
else | else | ||||
vp.set(JS::NullValue()); | vp.set(JS::NullValue()); | ||||
return true; | return true; | ||||
} | } | ||||
else if (propName == "children") | else if (propName == "children") | ||||
{ | { | ||||
JS::RootedObject obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty())); | JS::RootedObject obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty())); | ||||
vp.setObject(*obj); | vp.setObject(*obj); | ||||
for (size_t i = 0; i < e->m_Children.size(); ++i) | for (size_t i = 0; i < guiObject->m_Children.size(); ++i) | ||||
Stan: Range loop ? | |||||
elexisAuthorUnsubmitted Done Inline ActionsCheck again elexis: Check again | |||||
{ | { | ||||
JS::RootedValue val(cx); | JS::RootedValue val(cx); | ||||
ScriptInterface::ToJSVal(cx, &val, e->m_Children[i]); | ScriptInterface::ToJSVal(cx, &val, guiObject->m_Children[i]); | ||||
JS_SetElement(cx, obj, i, val); | JS_SetElement(cx, obj, i, val); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
else if (propName == "name") | else if (propName == "name") | ||||
{ | { | ||||
vp.set(JS::StringValue(JS_NewStringCopyZ(cx, e->GetName().c_str()))); | vp.set(JS::StringValue(JS_NewStringCopyZ(cx, guiObject->GetName().c_str()))); | ||||
return true; | return true; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
// Retrieve the setting's type (and make sure it actually exists) | // Retrieve the setting's type (and make sure it actually exists) | ||||
EGUISettingType Type; | EGUISettingType Type; | ||||
if (e->GetSettingType(propName, Type) != PSRETURN_OK) | if (guiObject->GetSettingType(propName, Type) != PSRETURN_OK) | ||||
{ | { | ||||
JS_ReportError(cx, "Invalid GUIObject property '%s'", propName.c_str()); | JS_ReportError(cx, "Invalid GUIObject property '%s'", propName.c_str()); | ||||
return false; | return false; | ||||
} | } | ||||
// (All the cases are in {...} to avoid scoping problems) | // (All the cases are in {...} to avoid scoping problems) | ||||
switch (Type) | switch (Type) | ||||
{ | { | ||||
case GUIST_bool: | case GUIST_bool: | ||||
{ | { | ||||
bool value; | bool value; | ||||
GUI<bool>::GetSetting(e, propName, value); | GUI<bool>::GetSetting(guiObject, propName, value); | ||||
vp.set(JS::BooleanValue(value)); | vp.set(JS::BooleanValue(value)); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_int: | case GUIST_int: | ||||
{ | { | ||||
int value; | int value; | ||||
GUI<int>::GetSetting(e, propName, value); | GUI<int>::GetSetting(guiObject, propName, value); | ||||
vp.set(JS::Int32Value(value)); | vp.set(JS::Int32Value(value)); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_uint: | case GUIST_uint: | ||||
{ | { | ||||
u32 value; | u32 value; | ||||
GUI<u32>::GetSetting(e, propName, value); | GUI<u32>::GetSetting(guiObject, propName, value); | ||||
if (value >= std::numeric_limits<u32>::max()) | if (value >= std::numeric_limits<u32>::max()) | ||||
LOGERROR("Integer overflow on converting to GUIST_uint"); | LOGERROR("Integer overflow on converting to GUIST_uint"); | ||||
else | else | ||||
vp.set(JS::Int32Value(value)); | vp.set(JS::Int32Value(value)); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_float: | case GUIST_float: | ||||
{ | { | ||||
float value; | float value; | ||||
GUI<float>::GetSetting(e, propName, value); | GUI<float>::GetSetting(guiObject, propName, value); | ||||
// Create a garbage-collectable double | // Create a garbage-collectable double | ||||
vp.set(JS::NumberValue(value)); | vp.set(JS::NumberValue(value)); | ||||
return !vp.isNull(); | return !vp.isNull(); | ||||
} | } | ||||
case GUIST_CColor: | case GUIST_CColor: | ||||
{ | { | ||||
CColor color; | CColor color; | ||||
GUI<CColor>::GetSetting(e, propName, color); | GUI<CColor>::GetSetting(guiObject, propName, color); | ||||
JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUIColor")); | JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUIColor")); | ||||
vp.setObject(*obj); | vp.setObject(*obj); | ||||
JS::RootedValue c(cx); | JS::RootedValue c(cx); | ||||
// Attempt to minimise ugliness through macrosity | // Attempt to minimise ugliness through macrosity | ||||
#define P(x) \ | #define P(x) \ | ||||
c = JS::NumberValue(color.x); \ | c = JS::NumberValue(color.x); \ | ||||
if (c.isNull()) \ | if (c.isNull()) \ | ||||
return false; \ | return false; \ | ||||
JS_SetProperty(cx, obj, #x, c) | JS_SetProperty(cx, obj, #x, c) | ||||
P(r); | P(r); | ||||
P(g); | P(g); | ||||
P(b); | P(b); | ||||
P(a); | P(a); | ||||
#undef P | #undef P | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CClientArea: | case GUIST_CClientArea: | ||||
{ | { | ||||
CClientArea area; | CClientArea area; | ||||
GUI<CClientArea>::GetSetting(e, propName, area); | GUI<CClientArea>::GetSetting(guiObject, propName, area); | ||||
JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUISize")); | JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUISize")); | ||||
vp.setObject(*obj); | vp.setObject(*obj); | ||||
try | try | ||||
{ | { | ||||
#define P(x, y, z) pScriptInterface->SetProperty(vp, #z, area.x.y, false, true) | #define P(x, y, z) pScriptInterface->SetProperty(vp, #z, area.x.y, false, true) | ||||
P(pixel, left, left); | P(pixel, left, left); | ||||
P(pixel, top, top); | P(pixel, top, top); | ||||
Show All 12 Lines | #undef P | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CGUIString: | case GUIST_CGUIString: | ||||
{ | { | ||||
CGUIString value; | CGUIString value; | ||||
GUI<CGUIString>::GetSetting(e, propName, value); | GUI<CGUIString>::GetSetting(guiObject, propName, value); | ||||
ScriptInterface::ToJSVal(cx, vp, value.GetOriginalString()); | ScriptInterface::ToJSVal(cx, vp, value.GetOriginalString()); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CStr: | case GUIST_CStr: | ||||
{ | { | ||||
CStr value; | CStr value; | ||||
GUI<CStr>::GetSetting(e, propName, value); | GUI<CStr>::GetSetting(guiObject, propName, value); | ||||
ScriptInterface::ToJSVal(cx, vp, value); | ScriptInterface::ToJSVal(cx, vp, value); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CStrW: | case GUIST_CStrW: | ||||
{ | { | ||||
CStrW value; | CStrW value; | ||||
GUI<CStrW>::GetSetting(e, propName, value); | GUI<CStrW>::GetSetting(guiObject, propName, value); | ||||
ScriptInterface::ToJSVal(cx, vp, value); | ScriptInterface::ToJSVal(cx, vp, value); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CGUISpriteInstance: | case GUIST_CGUISpriteInstance: | ||||
{ | { | ||||
CGUISpriteInstance *value; | CGUISpriteInstance *value; | ||||
GUI<CGUISpriteInstance>::GetSettingPointer(e, propName, value); | GUI<CGUISpriteInstance>::GetSettingPointer(guiObject, propName, value); | ||||
ScriptInterface::ToJSVal(cx, vp, value->GetName()); | ScriptInterface::ToJSVal(cx, vp, value->GetName()); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_EAlign: | case GUIST_EAlign: | ||||
{ | { | ||||
EAlign value; | EAlign value; | ||||
GUI<EAlign>::GetSetting(e, propName, value); | GUI<EAlign>::GetSetting(guiObject, propName, value); | ||||
CStr word; | CStr word; | ||||
switch (value) | switch (value) | ||||
{ | { | ||||
case EAlign_Left: word = "left"; break; | case EAlign_Left: word = "left"; break; | ||||
case EAlign_Right: word = "right"; break; | case EAlign_Right: word = "right"; break; | ||||
case EAlign_Center: word = "center"; break; | case EAlign_Center: word = "center"; break; | ||||
default: debug_warn(L"Invalid EAlign!"); word = "error"; break; | default: debug_warn(L"Invalid EAlign!"); word = "error"; break; | ||||
} | } | ||||
ScriptInterface::ToJSVal(cx, vp, word); | ScriptInterface::ToJSVal(cx, vp, word); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_EVAlign: | case GUIST_EVAlign: | ||||
{ | { | ||||
EVAlign value; | EVAlign value; | ||||
GUI<EVAlign>::GetSetting(e, propName, value); | GUI<EVAlign>::GetSetting(guiObject, propName, value); | ||||
CStr word; | CStr word; | ||||
switch (value) | switch (value) | ||||
{ | { | ||||
case EVAlign_Top: word = "top"; break; | case EVAlign_Top: word = "top"; break; | ||||
case EVAlign_Bottom: word = "bottom"; break; | case EVAlign_Bottom: word = "bottom"; break; | ||||
case EVAlign_Center: word = "center"; break; | case EVAlign_Center: word = "center"; break; | ||||
default: debug_warn(L"Invalid EVAlign!"); word = "error"; break; | default: debug_warn(L"Invalid EVAlign!"); word = "error"; break; | ||||
} | } | ||||
ScriptInterface::ToJSVal(cx, vp, word); | ScriptInterface::ToJSVal(cx, vp, word); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CGUIList: | case GUIST_CGUIList: | ||||
{ | { | ||||
CGUIList value; | CGUIList value; | ||||
GUI<CGUIList>::GetSetting(e, propName, value); | GUI<CGUIList>::GetSetting(guiObject, propName, value); | ||||
ScriptInterface::ToJSVal(cx, vp, value.m_Items); | ScriptInterface::ToJSVal(cx, vp, value.m_Items); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CGUISeries: | case GUIST_CGUISeries: | ||||
{ | { | ||||
CGUISeries value; | CGUISeries value; | ||||
GUI<CGUISeries>::GetSetting(e, propName, value); | GUI<CGUISeries>::GetSetting(guiObject, propName, value); | ||||
ScriptInterface::ToJSVal(cx, vp, value.m_Series); | ScriptInterface::ToJSVal(cx, vp, value.m_Series); | ||||
break; | break; | ||||
} | } | ||||
default: | default: | ||||
JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str()); | JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str()); | ||||
DEBUG_WARN_ERR(ERR::LOGIC); | DEBUG_WARN_ERR(ERR::LOGIC); | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool UNUSED(strict), JS::MutableHandleValue vp) | bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool UNUSED(strict), JS::MutableHandleValue vp) | ||||
{ | { | ||||
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); | IGUIObject* guiObject = static_cast<IGUIObject*>(JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, nullptr)); | ||||
if (!e) | if (!guiObject) | ||||
return false; | return false; | ||||
JSAutoRequest rq(cx); | 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; | ||||
if (propName == "name") | if (propName == "name") | ||||
{ | { | ||||
std::string value; | std::string value; | ||||
if (!ScriptInterface::FromJSVal(cx, vp, value)) | if (!ScriptInterface::FromJSVal(cx, vp, value)) | ||||
return false; | return false; | ||||
e->SetName(value); | guiObject->SetName(value); | ||||
return true; | return true; | ||||
} | } | ||||
JS::RootedObject vpObj(cx); | JS::RootedObject vpObj(cx); | ||||
if (vp.isObject()) | if (vp.isObject()) | ||||
vpObj = &vp.toObject(); | 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") | ||||
{ | { | ||||
if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(cx, &vp.toObject())) | if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(cx, &vp.toObject())) | ||||
{ | { | ||||
JS_ReportError(cx, "on- event-handlers must be functions"); | JS_ReportError(cx, "on- event-handlers must be functions"); | ||||
return false; | return false; | ||||
} | } | ||||
CStr eventName(CStr(propName.substr(2)).LowerCase()); | CStr eventName(CStr(propName.substr(2)).LowerCase()); | ||||
e->SetScriptHandler(eventName, vpObj); | guiObject->SetScriptHandler(eventName, vpObj); | ||||
return true; | return true; | ||||
} | } | ||||
// Retrieve the setting's type (and make sure it actually exists) | // Retrieve the setting's type (and make sure it actually exists) | ||||
EGUISettingType Type; | EGUISettingType Type; | ||||
if (e->GetSettingType(propName, Type) != PSRETURN_OK) | if (guiObject->GetSettingType(propName, Type) != PSRETURN_OK) | ||||
{ | { | ||||
JS_ReportError(cx, "Invalid setting '%s'", propName.c_str()); | JS_ReportError(cx, "Invalid setting '%s'", propName.c_str()); | ||||
return true; | return true; | ||||
} | } | ||||
switch (Type) | switch (Type) | ||||
{ | { | ||||
case GUIST_CStr: | case GUIST_CStr: | ||||
{ | { | ||||
std::string value; | std::string value; | ||||
if (!ScriptInterface::FromJSVal(cx, vp, value)) | if (!ScriptInterface::FromJSVal(cx, vp, value)) | ||||
return false; | return false; | ||||
GUI<CStr>::SetSetting(e, propName, value); | GUI<CStr>::SetSetting(guiObject, propName, value); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CStrW: | case GUIST_CStrW: | ||||
{ | { | ||||
std::wstring value; | std::wstring value; | ||||
if (!ScriptInterface::FromJSVal(cx, vp, value)) | if (!ScriptInterface::FromJSVal(cx, vp, value)) | ||||
return false; | return false; | ||||
GUI<CStrW>::SetSetting(e, propName, value); | GUI<CStrW>::SetSetting(guiObject, propName, value); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CGUISpriteInstance: | case GUIST_CGUISpriteInstance: | ||||
{ | { | ||||
std::string value; | std::string value; | ||||
if (!ScriptInterface::FromJSVal(cx, vp, value)) | if (!ScriptInterface::FromJSVal(cx, vp, value)) | ||||
return false; | return false; | ||||
GUI<CGUISpriteInstance>::SetSetting(e, propName, CGUISpriteInstance(value)); | GUI<CGUISpriteInstance>::SetSetting(guiObject, propName, CGUISpriteInstance(value)); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CGUIString: | case GUIST_CGUIString: | ||||
{ | { | ||||
std::wstring value; | std::wstring value; | ||||
if (!ScriptInterface::FromJSVal(cx, vp, value)) | if (!ScriptInterface::FromJSVal(cx, vp, value)) | ||||
return false; | return false; | ||||
CGUIString str; | CGUIString str; | ||||
str.SetValue(value); | str.SetValue(value); | ||||
GUI<CGUIString>::SetSetting(e, propName, str); | GUI<CGUIString>::SetSetting(guiObject, propName, str); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_EAlign: | case GUIST_EAlign: | ||||
{ | { | ||||
std::string value; | std::string value; | ||||
if (!ScriptInterface::FromJSVal(cx, vp, value)) | if (!ScriptInterface::FromJSVal(cx, vp, value)) | ||||
return false; | return false; | ||||
EAlign a; | EAlign a; | ||||
if (value == "left") a = EAlign_Left; | if (value == "left") a = EAlign_Left; | ||||
else if (value == "right") a = EAlign_Right; | else if (value == "right") a = EAlign_Right; | ||||
else if (value == "center" || value == "centre") a = EAlign_Center; | else if (value == "center" || value == "centre") a = EAlign_Center; | ||||
else | else | ||||
{ | { | ||||
JS_ReportError(cx, "Invalid alignment (should be 'left', 'right' or 'center')"); | JS_ReportError(cx, "Invalid alignment (should be 'left', 'right' or 'center')"); | ||||
return false; | return false; | ||||
} | } | ||||
GUI<EAlign>::SetSetting(e, propName, a); | GUI<EAlign>::SetSetting(guiObject, propName, a); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_EVAlign: | case GUIST_EVAlign: | ||||
{ | { | ||||
std::string value; | std::string value; | ||||
if (!ScriptInterface::FromJSVal(cx, vp, value)) | if (!ScriptInterface::FromJSVal(cx, vp, value)) | ||||
return false; | return false; | ||||
EVAlign a; | EVAlign a; | ||||
if (value == "top") a = EVAlign_Top; | if (value == "top") a = EVAlign_Top; | ||||
else if (value == "bottom") a = EVAlign_Bottom; | else if (value == "bottom") a = EVAlign_Bottom; | ||||
else if (value == "center" || value == "centre") a = EVAlign_Center; | else if (value == "center" || value == "centre") a = EVAlign_Center; | ||||
else | else | ||||
{ | { | ||||
JS_ReportError(cx, "Invalid alignment (should be 'top', 'bottom' or 'center')"); | JS_ReportError(cx, "Invalid alignment (should be 'top', 'bottom' or 'center')"); | ||||
return false; | return false; | ||||
} | } | ||||
GUI<EVAlign>::SetSetting(e, propName, a); | GUI<EVAlign>::SetSetting(guiObject, propName, a); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_int: | case GUIST_int: | ||||
{ | { | ||||
int value; | int value; | ||||
if (ScriptInterface::FromJSVal(cx, vp, value)) | if (ScriptInterface::FromJSVal(cx, vp, value)) | ||||
GUI<int>::SetSetting(e, propName, value); | GUI<int>::SetSetting(guiObject, propName, value); | ||||
else | else | ||||
{ | { | ||||
JS_ReportError(cx, "Cannot convert value to int"); | JS_ReportError(cx, "Cannot convert value to int"); | ||||
return false; | return false; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case GUIST_uint: | case GUIST_uint: | ||||
{ | { | ||||
u32 value; | u32 value; | ||||
if (ScriptInterface::FromJSVal(cx, vp, value)) | if (ScriptInterface::FromJSVal(cx, vp, value)) | ||||
GUI<u32>::SetSetting(e, propName, value); | GUI<u32>::SetSetting(guiObject, propName, value); | ||||
else | else | ||||
{ | { | ||||
JS_ReportError(cx, "Cannot convert value to u32"); | JS_ReportError(cx, "Cannot convert value to u32"); | ||||
return false; | return false; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case GUIST_float: | case GUIST_float: | ||||
{ | { | ||||
double value; | double value; | ||||
if (JS::ToNumber(cx, vp, &value) == true) | if (JS::ToNumber(cx, vp, &value) == true) | ||||
GUI<float>::SetSetting(e, propName, (float)value); | GUI<float>::SetSetting(guiObject, propName, (float)value); | ||||
else | else | ||||
{ | { | ||||
JS_ReportError(cx, "Cannot convert value to float"); | JS_ReportError(cx, "Cannot convert value to float"); | ||||
return false; | return false; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case GUIST_bool: | case GUIST_bool: | ||||
{ | { | ||||
bool value = JS::ToBoolean(vp); | bool value = JS::ToBoolean(vp); | ||||
GUI<bool>::SetSetting(e, propName, value); | GUI<bool>::SetSetting(guiObject, propName, value); | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CClientArea: | case GUIST_CClientArea: | ||||
{ | { | ||||
if (vp.isString()) | if (vp.isString()) | ||||
{ | { | ||||
std::wstring value; | std::wstring value; | ||||
if (!ScriptInterface::FromJSVal(cx, vp, value)) | if (!ScriptInterface::FromJSVal(cx, vp, value)) | ||||
return false; | return false; | ||||
if (e->SetSetting(propName, value) != PSRETURN_OK) | if (guiObject->SetSetting(propName, value) != PSRETURN_OK) | ||||
{ | { | ||||
JS_ReportError(cx, "Invalid value for setting '%s'", propName.c_str()); | JS_ReportError(cx, "Invalid value for setting '%s'", propName.c_str()); | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
else if (vp.isObject() && JS_InstanceOf(cx, vpObj, &JSI_GUISize::JSI_class, NULL)) | else if (vp.isObject() && JS_InstanceOf(cx, vpObj, &JSI_GUISize::JSI_class, nullptr)) | ||||
{ | { | ||||
CClientArea area; | CClientArea area; | ||||
GUI<CClientArea>::GetSetting(e, propName, area); | GUI<CClientArea>::GetSetting(guiObject, propName, area); | ||||
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; | ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; | ||||
#define P(x, y, z) pScriptInterface->GetProperty(vp, #z, area.x.y) | #define P(x, y, z) pScriptInterface->GetProperty(vp, #z, area.x.y) | ||||
P(pixel, left, left); | P(pixel, left, left); | ||||
P(pixel, top, top); | P(pixel, top, top); | ||||
P(pixel, right, right); | P(pixel, right, right); | ||||
P(pixel, bottom, bottom); | P(pixel, bottom, bottom); | ||||
P(percent, left, rleft); | P(percent, left, rleft); | ||||
P(percent, top, rtop); | P(percent, top, rtop); | ||||
P(percent, right, rright); | P(percent, right, rright); | ||||
P(percent, bottom, rbottom); | P(percent, bottom, rbottom); | ||||
#undef P | #undef P | ||||
GUI<CClientArea>::SetSetting(e, propName, area); | GUI<CClientArea>::SetSetting(guiObject, propName, area); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
JS_ReportError(cx, "Size only accepts strings or GUISize objects"); | JS_ReportError(cx, "Size only accepts strings or GUISize objects"); | ||||
return false; | return false; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CColor: | case GUIST_CColor: | ||||
{ | { | ||||
if (vp.isString()) | if (vp.isString()) | ||||
{ | { | ||||
std::wstring value; | std::wstring value; | ||||
if (!ScriptInterface::FromJSVal(cx, vp, value)) | if (!ScriptInterface::FromJSVal(cx, vp, value)) | ||||
return false; | return false; | ||||
if (e->SetSetting(propName, value) != PSRETURN_OK) | if (guiObject->SetSetting(propName, value) != PSRETURN_OK) | ||||
{ | { | ||||
JS_ReportError(cx, "Invalid value for setting '%s'", propName.c_str()); | JS_ReportError(cx, "Invalid value for setting '%s'", propName.c_str()); | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
else if (vp.isObject() && JS_InstanceOf(cx, vpObj, &JSI_GUIColor::JSI_class, NULL)) | else if (vp.isObject() && JS_InstanceOf(cx, vpObj, &JSI_GUIColor::JSI_class, nullptr)) | ||||
{ | { | ||||
CColor color; | CColor color; | ||||
JS::RootedValue t(cx); | JS::RootedValue t(cx); | ||||
double s; | double s; | ||||
#define PROP(x) \ | #define PROP(x) \ | ||||
JS_GetProperty(cx, vpObj, #x, &t); \ | JS_GetProperty(cx, vpObj, #x, &t); \ | ||||
s = t.toDouble(); \ | s = t.toDouble(); \ | ||||
color.x = (float)s | color.x = (float)s | ||||
PROP(r); | PROP(r); | ||||
PROP(g); | PROP(g); | ||||
PROP(b); | PROP(b); | ||||
PROP(a); | PROP(a); | ||||
#undef PROP | #undef PROP | ||||
GUI<CColor>::SetSetting(e, propName, color); | GUI<CColor>::SetSetting(guiObject, propName, color); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
JS_ReportError(cx, "Color only accepts strings or GUIColor objects"); | JS_ReportError(cx, "Color only accepts strings or GUIColor objects"); | ||||
return false; | return false; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CGUIList: | case GUIST_CGUIList: | ||||
{ | { | ||||
CGUIList list; | CGUIList list; | ||||
if (ScriptInterface::FromJSVal(cx, vp, list.m_Items)) | if (ScriptInterface::FromJSVal(cx, vp, list.m_Items)) | ||||
GUI<CGUIList>::SetSetting(e, propName, list); | GUI<CGUIList>::SetSetting(guiObject, propName, list); | ||||
else | else | ||||
{ | { | ||||
JS_ReportError(cx, "Failed to get list '%s'", propName.c_str()); | JS_ReportError(cx, "Failed to get list '%s'", propName.c_str()); | ||||
return false; | return false; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case GUIST_CGUISeries: | case GUIST_CGUISeries: | ||||
{ | { | ||||
CGUISeries series; | CGUISeries series; | ||||
if (ScriptInterface::FromJSVal(cx, vp, series.m_Series)) | if (ScriptInterface::FromJSVal(cx, vp, series.m_Series)) | ||||
GUI<CGUISeries>::SetSetting(e, propName, series); | GUI<CGUISeries>::SetSetting(guiObject, propName, series); | ||||
else | else | ||||
{ | { | ||||
JS_ReportError(cx, "Invalid value for chart series '%s'", propName.c_str()); | JS_ReportError(cx, "Invalid value for chart series '%s'", propName.c_str()); | ||||
return false; | return false; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
default: | default: | ||||
JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str()); | JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str()); | ||||
break; | break; | ||||
} | } | ||||
return !JS_IsExceptionPending(cx); | return !JS_IsExceptionPending(cx); | ||||
} | } | ||||
bool JSI_IGUIObject::toString(JSContext* cx, uint argc, JS::Value* vp) | |||||
bool JSI_IGUIObject::construct(JSContext* cx, uint argc, JS::Value* vp) | |||||
{ | { | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); | JS::RootedObject thisObj(cx, &JS::CallArgsFromVp(argc, vp).thisv().toObject()); | ||||
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; | |||||
if (args.length() == 0) | IGUIObject* guiObject = static_cast<IGUIObject*>(JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, nullptr)); | ||||
{ | if (!guiObject) | ||||
JS_ReportError(cx, "GUIObject has no default constructor"); | |||||
return false; | |||||
} | |||||
JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUIObject")); | |||||
// Store the IGUIObject in the JS object's 'private' area | |||||
IGUIObject* guiObject = (IGUIObject*)args[0].get().toPrivate(); | |||||
JS_SetPrivate(obj, guiObject); | |||||
elexisAuthorUnsubmitted Done Inline ActionsAlso this is the only place that uses toPrivate. The code looks kind of wrong: where would that IGUIObject instance created (if not ConstructObject in Xeromyces_ReadObject)? The two statements look like it would would parse the existing private value to an IGUIObject pointer and set that pointer back to the private object, i.e. noop with at most errors occuring. elexis: Also this is the only place that uses `toPrivate`. The code looks kind of wrong: where would… | |||||
args.rval().setObject(*obj); | |||||
return true; | |||||
} | |||||
void JSI_IGUIObject::init(ScriptInterface& scriptInterface) | |||||
{ | |||||
scriptInterface.DefineCustomObjectType(&JSI_class, construct, 1, JSI_props, JSI_methods, NULL, NULL); | |||||
} | |||||
bool JSI_IGUIObject::toString(JSContext* cx, uint UNUSED(argc), JS::Value* vp) | |||||
{ | |||||
JSAutoRequest rq(cx); | |||||
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); | |||||
if (!e) | |||||
return false; | return false; | ||||
char buffer[256]; | char buffer[256]; | ||||
snprintf(buffer, 256, "[GUIObject: %s]", e->GetName().c_str()); | snprintf(buffer, 256, "[GUIObject: %s]", guiObject->GetName().c_str()); | ||||
buffer[255] = 0; | buffer[255] = 0; | ||||
rec.rval().setString(JS_NewStringCopyZ(cx, buffer)); | JS::CallReceiverFromVp(vp).rval().setString(JS_NewStringCopyZ(cx, buffer)); | ||||
return true; | return true; | ||||
} | } | ||||
bool JSI_IGUIObject::focus(JSContext* cx, uint UNUSED(argc), JS::Value* vp) | bool JSI_IGUIObject::focus(JSContext* cx, uint argc, JS::Value* vp) | ||||
{ | { | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
JS::CallReceiver rec = JS::CallReceiverFromVp(vp); | JS::RootedObject thisObj(cx, &JS::CallArgsFromVp(argc, vp).thisv().toObject()); | ||||
JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); | IGUIObject* guiObject = static_cast<IGUIObject*>(JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, nullptr)); | ||||
if (!guiObject) | |||||
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); | |||||
if (!e) | |||||
return false; | return false; | ||||
e->GetGUI()->SetFocusedObject(e); | guiObject->GetGUI()->SetFocusedObject(guiObject); | ||||
rec.rval().setUndefined(); | JS::CallReceiverFromVp(vp).rval().setUndefined(); | ||||
return true; | return true; | ||||
} | } | ||||
bool JSI_IGUIObject::blur(JSContext* cx, uint UNUSED(argc), JS::Value* vp) | bool JSI_IGUIObject::blur(JSContext* cx, uint argc, JS::Value* vp) | ||||
{ | { | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
JS::CallReceiver rec = JS::CallReceiverFromVp(vp); | JS::RootedObject thisObj(cx, &JS::CallArgsFromVp(argc, vp).thisv().toObject()); | ||||
JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); | |||||
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); | IGUIObject* guiObject = static_cast<IGUIObject*>(JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, nullptr)); | ||||
if (!e) | if (!guiObject) | ||||
return false; | return false; | ||||
e->GetGUI()->SetFocusedObject(NULL); | guiObject->GetGUI()->SetFocusedObject(nullptr); | ||||
rec.rval().setUndefined(); | JS::CallReceiverFromVp(vp).rval().setUndefined(); | ||||
return true; | return true; | ||||
} | } | ||||
bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint UNUSED(argc), JS::Value* vp) | bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, JS::Value* vp) | ||||
{ | { | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
JS::CallReceiver rec = JS::CallReceiverFromVp(vp); | JS::RootedObject thisObj(cx, &JS::CallArgsFromVp(argc, vp).thisv().toObject()); | ||||
JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); | |||||
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); | IGUIObject* guiObject = static_cast<IGUIObject*>(JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, nullptr)); | ||||
if (!e) | if (!guiObject) | ||||
return false; | return false; | ||||
e->UpdateCachedSize(); | guiObject->UpdateCachedSize(); | ||||
CRect size = e->m_CachedActualSize; | CRect size = guiObject->m_CachedActualSize; | ||||
JS::RootedValue objVal(cx, JS::ObjectValue(*JS_NewPlainObject(cx))); | JS::RootedValue objVal(cx, JS::ObjectValue(*JS_NewPlainObject(cx))); | ||||
try | try | ||||
{ | { | ||||
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; | ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; | ||||
pScriptInterface->SetProperty(objVal, "left", size.left, false, true); | pScriptInterface->SetProperty(objVal, "left", size.left, false, true); | ||||
pScriptInterface->SetProperty(objVal, "right", size.right, false, true); | pScriptInterface->SetProperty(objVal, "right", size.right, false, true); | ||||
pScriptInterface->SetProperty(objVal, "top", size.top, false, true); | pScriptInterface->SetProperty(objVal, "top", size.top, false, true); | ||||
pScriptInterface->SetProperty(objVal, "bottom", size.bottom, false, true); | pScriptInterface->SetProperty(objVal, "bottom", size.bottom, false, true); | ||||
} | } | ||||
catch (PSERROR_Scripting_ConversionFailed&) | catch (PSERROR_Scripting_ConversionFailed&) | ||||
{ | { | ||||
debug_warn(L"Error creating size object!"); | debug_warn(L"Error creating size object!"); | ||||
return false; | return false; | ||||
} | } | ||||
rec.rval().set(objVal); | JS::CallReceiverFromVp(vp).rval().set(objVal); | ||||
return true; | return true; | ||||
} | } |
Wildfire Games · Phabricator
Range loop ?