JSBool JSI_IGUIObject::toString(JSContext* cx, uintN argc, jsval* vp) { UNUSED2(argc); IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_IGUIObject::JSI_class, NULL); if (!e) return JS_FALSE; char buffer[256]; snprintf(buffer, 256, "[GUIObject: %s]", e->GetName().c_str()); buffer[255] = 0; JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer))); return JS_TRUE; }
JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp) { IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); if (!e) return JS_FALSE; jsval idval; if (!JS_IdToValue(cx, id, &idval)) return JS_FALSE; std::string propName; if (!ScriptInterface::FromJSVal(cx, idval, propName)) return JS_FALSE; // Skip some things which are known to be functions rather than properties. // ("constructor" *must* be here, else it'll try to GetSettingType before // the private IGUIObject* has been set (and thus crash). The others are // partly for efficiency, and also to allow correct reporting of attempts to // access nonexistent properties.) if (propName == "constructor" || propName == "prototype" || propName == "toString" || propName == "focus" || propName == "blur" || propName == "getComputedSize" ) return JS_TRUE; // Use onWhatever to access event handlers if (propName.substr(0, 2) == "on") { CStr eventName (CStr(propName.substr(2)).LowerCase()); std::map<CStr, JSObject**>::iterator it = e->m_ScriptHandlers.find(eventName); if (it == e->m_ScriptHandlers.end()) *vp = JSVAL_NULL; else *vp = OBJECT_TO_JSVAL(*(it->second)); return JS_TRUE; } // Handle the "parent" property specially if (propName == "parent") { IGUIObject* parent = e->GetParent(); if (parent) { // If the object isn't parentless, return a new object *vp = OBJECT_TO_JSVAL(parent->GetJSObject()); } else { // Return null if there's no parent *vp = JSVAL_NULL; } return JS_TRUE; } // Also handle "name" specially else if (propName == "name") { *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, e->GetName().c_str())); return JS_TRUE; } // Handle all other properties else { // Retrieve the setting's type (and make sure it actually exists) EGUISettingType Type; if (e->GetSettingType(propName, Type) != PSRETURN_OK) { JS_ReportError(cx, "Invalid GUIObject property '%s'", propName.c_str()); return JS_FALSE; } // (All the cases are in {...} to avoid scoping problems) switch (Type) { case GUIST_bool: { bool value; GUI<bool>::GetSetting(e, propName, value); *vp = value ? JSVAL_TRUE : JSVAL_FALSE; break; } case GUIST_int: { int value; GUI<int>::GetSetting(e, propName, value); *vp = INT_TO_JSVAL(value); break; } case GUIST_float: { float value; GUI<float>::GetSetting(e, propName, value); // Create a garbage-collectable double return JS_NewNumberValue(cx, value, vp); } case GUIST_CColor: { CColor colour; GUI<CColor>::GetSetting(e, propName, colour); JSObject* obj = JS_NewObject(cx, &JSI_GUIColor::JSI_class, NULL, NULL); *vp = OBJECT_TO_JSVAL(obj); // root it jsval c; // Attempt to minimise ugliness through macrosity #define P(x) if (!JS_NewNumberValue(cx, colour.x, &c)) return JS_FALSE; JS_SetProperty(cx, obj, #x, &c) P(r); P(g); P(b); P(a); #undef P break; } case GUIST_CClientArea: { CClientArea area; GUI<CClientArea>::GetSetting(e, propName, area); JSObject* obj = JS_NewObject(cx, &JSI_GUISize::JSI_class, NULL, NULL); *vp = OBJECT_TO_JSVAL(obj); // root it try { #define P(x, y, z) g_ScriptingHost.SetObjectProperty_Double(obj, #z, area.x.y) P(pixel, left, left); P(pixel, top, top); P(pixel, right, right); P(pixel, bottom, bottom); P(percent, left, rleft); P(percent, top, rtop); P(percent, right, rright); P(percent, bottom, rbottom); #undef P } catch (PSERROR_Scripting_ConversionFailed) { debug_warn(L"Error creating size object!"); break; } break; } case GUIST_CGUIString: { CGUIString value; GUI<CGUIString>::GetSetting(e, propName, value); *vp = ScriptInterface::ToJSVal(cx, value.GetOriginalString()); break; } case GUIST_CStr: { CStr value; GUI<CStr>::GetSetting(e, propName, value); *vp = ScriptInterface::ToJSVal(cx, value); break; } case GUIST_CStrW: { CStrW value; GUI<CStrW>::GetSetting(e, propName, value); *vp = ScriptInterface::ToJSVal(cx, value); break; } case GUIST_CGUISpriteInstance: { CGUISpriteInstance *value; GUI<CGUISpriteInstance>::GetSettingPointer(e, propName, value); *vp = ScriptInterface::ToJSVal(cx, value->GetName()); break; } case GUIST_EAlign: { EAlign value; GUI<EAlign>::GetSetting(e, propName, value); CStr word; switch (value) { case EAlign_Left: word = "left"; break; case EAlign_Right: word = "right"; break; case EAlign_Center: word = "center"; break; default: debug_warn(L"Invalid EAlign!"); word = "error"; break; } *vp = ScriptInterface::ToJSVal(cx, word); break; } case GUIST_EVAlign: { EVAlign value; GUI<EVAlign>::GetSetting(e, propName, value); CStr word; switch (value) { case EVAlign_Top: word = "top"; break; case EVAlign_Bottom: word = "bottom"; break; case EVAlign_Center: word = "center"; break; default: debug_warn(L"Invalid EVAlign!"); word = "error"; break; } *vp = ScriptInterface::ToJSVal(cx, word); break; } case GUIST_CGUIList: { CGUIList value; GUI<CGUIList>::GetSetting(e, propName, value); JSObject *obj = JS_NewArrayObject(cx, 0, NULL); *vp = OBJECT_TO_JSVAL(obj); // root it for (size_t i = 0; i < value.m_Items.size(); ++i) { jsval val = ScriptInterface::ToJSVal(cx, value.m_Items[i].GetOriginalString()); JS_SetElement(cx, obj, (jsint)i, &val); } break; } default: JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str()); DEBUG_WARN_ERR(ERR::LOGIC); return JS_FALSE; } return JS_TRUE; } }