2006-04-24 01:14:18 +02:00
|
|
|
// ScriptableComplex.h
|
|
|
|
//
|
|
|
|
// The version of CJSObject<> that retains the ability to use inheritance
|
|
|
|
// in its objects. Shouldn't be used any more for anything but entity code.
|
|
|
|
|
|
|
|
#include "scripting/ScriptingHost.h"
|
|
|
|
#include "simulation/ScriptObject.h"
|
|
|
|
#include "JSConversions.h"
|
|
|
|
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
#ifndef SCRIPTABLE_COMPLEX_INCLUDED
|
|
|
|
#define SCRIPTABLE_COMPLEX_INCLUDED
|
|
|
|
|
|
|
|
class IJSComplex;
|
|
|
|
|
|
|
|
class IJSComplexProperty
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
bool m_AllowsInheritance;
|
|
|
|
bool m_Inherited;
|
|
|
|
bool m_Intrinsic;
|
|
|
|
|
|
|
|
// This is to make sure that all the fields are initialized at construction
|
|
|
|
inline IJSComplexProperty():
|
|
|
|
m_AllowsInheritance(true),
|
|
|
|
m_Inherited(true),
|
|
|
|
m_Intrinsic(true)
|
|
|
|
{}
|
|
|
|
|
|
|
|
virtual jsval Get( JSContext* cx, IJSComplex* owner ) = 0;
|
|
|
|
virtual void Set( JSContext* cx, IJSComplex* owner, jsval Value ) = 0;
|
|
|
|
|
|
|
|
// Copies the data directly out of a parent property
|
|
|
|
// Warning: Don't use if you're not certain the properties are not of the same type.
|
|
|
|
virtual void ImmediateCopy( IJSComplex* CopyTo, IJSComplex* CopyFrom, IJSComplexProperty* CopyProperty ) = 0;
|
|
|
|
|
|
|
|
jsval Get( IJSComplex* owner ) { return( Get( g_ScriptingHost.GetContext(), owner ) ); }
|
|
|
|
void Set( IJSComplex* owner, jsval Value ) { return( Set( g_ScriptingHost.GetContext(), owner, Value ) ); }
|
|
|
|
|
|
|
|
virtual ~IJSComplexProperty() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class IJSComplex
|
|
|
|
{
|
|
|
|
// Make copy constructor and assignment operator private - since copying of
|
|
|
|
// these objects is unsafe unless done specially.
|
|
|
|
// These will never be implemented (they are, after all, here to *prevent*
|
|
|
|
// copying)
|
|
|
|
IJSComplex(const IJSComplex &other);
|
|
|
|
IJSComplex& operator=(const IJSComplex &other);
|
|
|
|
|
|
|
|
public:
|
|
|
|
typedef STL_HASH_MAP<CStrW, IJSComplexProperty*, CStrW_hash_compare> PropertyTable;
|
|
|
|
typedef std::vector<IJSComplex*> InheritorsList;
|
|
|
|
typedef std::set<CStrW> StringTable;
|
|
|
|
typedef std::pair<StringTable, StringTable::iterator> IteratorState;
|
|
|
|
|
|
|
|
// Used for freshen/update
|
|
|
|
typedef void (IJSComplex::*NotifyFn)();
|
|
|
|
|
|
|
|
// Property getters and setters
|
|
|
|
typedef jsval (IJSComplex::*GetFn)();
|
|
|
|
typedef void (IJSComplex::*SetFn)( jsval );
|
|
|
|
|
|
|
|
// Properties of this object
|
|
|
|
PropertyTable m_Properties;
|
|
|
|
|
|
|
|
// Parent object
|
|
|
|
IJSComplex* m_Parent;
|
|
|
|
|
|
|
|
// Objects that inherit from this
|
|
|
|
InheritorsList m_Inheritors;
|
|
|
|
|
|
|
|
// Destructor
|
|
|
|
virtual ~IJSComplex() { }
|
|
|
|
|
|
|
|
// Set the base, and rebuild
|
|
|
|
void SetBase( IJSComplex* m_Parent );
|
|
|
|
|
|
|
|
// Rebuild any intrinsic (mapped-to-C++-variable) properties
|
|
|
|
virtual void Rebuild() = 0;
|
|
|
|
|
|
|
|
// HACK: Doesn't belong here.
|
|
|
|
virtual void rebuildClassSet() = 0;
|
|
|
|
|
|
|
|
// Check for a property
|
2006-07-17 01:03:26 +02:00
|
|
|
virtual IJSComplexProperty* HasProperty( const CStrW& PropertyName ) = 0;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
// Get all properties of an object
|
|
|
|
virtual void FillEnumerateSet( IteratorState* it, CStrW* PropertyRoot = NULL ) = 0;
|
|
|
|
|
|
|
|
// Retrieve the value of a property (returning false if that property is not defined)
|
2006-07-17 01:03:26 +02:00
|
|
|
virtual bool GetProperty( JSContext* cx, const CStrW& PropertyName, jsval* vp ) = 0;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
// Add a property (with immediate value)
|
2006-07-17 01:03:26 +02:00
|
|
|
virtual void AddProperty( const CStrW& PropertyName, jsval Value ) = 0;
|
|
|
|
virtual void AddProperty( const CStrW& PropertyName, const CStrW& Value ) = 0;
|
2006-05-14 00:11:46 +02:00
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
inline IJSComplex() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
class CJSReflector;
|
2006-05-14 00:11:46 +02:00
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
template<typename T, bool ReadOnly, typename ReturnType, ReturnType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )>
|
|
|
|
void AddMethodImpl( const char* Name, uintN MinArgs );
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
template<typename T, bool ReadOnly, typename PropType>
|
|
|
|
void AddClassPropertyImpl( const CStrW& PropertyName, PropType T::*Native, bool PropAllowInheritance = true, IJSComplex::NotifyFn Update = NULL, IJSComplex::NotifyFn Refresh = NULL );
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
template<typename T, bool ReadOnly, typename PropType>
|
|
|
|
void AddReadOnlyClassPropertyImpl( const CStrW& PropertyName, PropType T::*Native, bool PropAllowInheritance = true, IJSComplex::NotifyFn Update = NULL, IJSComplex::NotifyFn Refresh = NULL );
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
template<typename T, bool ReadOnly, typename PropType>
|
|
|
|
void MemberAddPropertyImpl( IJSComplex* obj, const CStrW& PropertyName, PropType* Native, bool PropAllowInheritance = true, IJSComplex::NotifyFn Update = NULL, IJSComplex::NotifyFn Refresh = NULL );
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
template<typename T, bool ReadOnly, typename PropType>
|
|
|
|
void MemberAddReadOnlyPropertyImpl( IJSComplex* obj, const CStrW& PropertyName, PropType* Native, bool PropAllowInheritance = true, IJSComplex::NotifyFn Update = NULL, IJSComplex::NotifyFn Refresh = NULL );
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
template<typename T, bool ReadOnly = false> class CJSComplex : public IJSComplex
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef STL_HASH_MAP<CStrW, CJSReflector*, CStrW_hash_compare> ReflectorTable;
|
|
|
|
template<typename Q> friend class CJSComplexPropertyAccessor;
|
|
|
|
JSObject* m_JS;
|
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
std::vector<CScriptObject> m_Watches;
|
|
|
|
|
|
|
|
ReflectorTable m_Reflectors;
|
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
static JSPropertySpec JSI_props[];
|
|
|
|
static std::vector<JSFunctionSpec> m_Methods;
|
|
|
|
static PropertyTable m_IntrinsicProperties;
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
static JSClass JSI_class;
|
|
|
|
|
|
|
|
// Whether native code is responsible for managing this object.
|
|
|
|
// Script constructors should clear this *BEFORE* creating a JS
|
|
|
|
// mirror (otherwise it'll be rooted).
|
|
|
|
|
|
|
|
bool m_EngineOwned;
|
|
|
|
|
|
|
|
// JS Property access
|
2006-07-17 01:03:26 +02:00
|
|
|
bool GetProperty( JSContext* cx, const CStrW& PropertyName, jsval* vp );
|
2006-07-27 04:42:35 +02:00
|
|
|
void SetProperty( JSContext* cx, const CStrW& PropertyName, jsval* vp );
|
|
|
|
void WatchNotify( JSContext* cx, const CStrW& PropertyName, jsval* newval );
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// Functions that must be provided to JavaScript
|
|
|
|
//
|
2006-07-27 04:42:35 +02:00
|
|
|
static JSBool JSGetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
|
|
|
|
static JSBool JSSetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
|
|
|
|
static JSBool JSEnumerate( JSContext* cx, JSObject* obj, JSIterateOp enum_op, jsval* statep, jsid *idp );
|
|
|
|
static JSBool SetWatchAll( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
|
|
|
static JSBool UnWatchAll( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
|
|
|
static void ScriptingInit( const char* ClassName, JSNative Constructor = NULL, uintN ConstructorMinArgs = 0 );
|
|
|
|
static void ScriptingShutdown();
|
|
|
|
static void DefaultFinalize( JSContext *cx, JSObject *obj );
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
public:
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
JSObject* GetScript();
|
|
|
|
// Creating and releasing script objects is done automatically most of the time, but you
|
|
|
|
// can do it explicitly.
|
|
|
|
void CreateScriptObject();
|
|
|
|
void ReleaseScriptObject();
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
CJSComplex();
|
|
|
|
virtual ~CJSComplex();
|
|
|
|
void Shutdown();
|
|
|
|
void SetBase( IJSComplex* Parent );
|
|
|
|
void Rebuild();
|
2006-05-14 00:11:46 +02:00
|
|
|
|
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
IJSComplexProperty* HasProperty( const CStrW& PropertyName );
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
void FillEnumerateSet( IteratorState* it, CStrW* PropertyRoot = NULL );
|
|
|
|
|
|
|
|
void AddProperty( const CStrW& PropertyName, jsval Value );
|
|
|
|
|
|
|
|
void AddProperty( const CStrW& PropertyName, const CStrW& Value );
|
2006-05-14 00:11:46 +02:00
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
static void AddClassProperty( const CStrW& PropertyName, GetFn Getter, SetFn Setter = NULL );
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
// these functions are themselves templatized. we don't want to implement
|
|
|
|
// them in the header because that would drag in many dependencies.
|
|
|
|
//
|
|
|
|
// therefore, the publicly visibleare functions actually onl/ to y thunks
|
|
|
|
// external friend functions implemented in the cpp file.
|
|
|
|
// these receive the template parameters from the class as well as the
|
|
|
|
// ones added for the member function.
|
|
|
|
//
|
|
|
|
// for non-static members, the friends additionally take a "this" pointer.
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
template<typename ReturnType, ReturnType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )>
|
|
|
|
static void AddMethod( const char* Name, uintN MinArgs )
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2006-07-27 04:42:35 +02:00
|
|
|
AddMethodImpl<T, ReadOnly, ReturnType, NativeFunction>(Name, MinArgs);
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
template<typename PropType>
|
|
|
|
static void AddClassProperty( const CStrW& PropertyName, PropType T::*Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2006-07-27 04:42:35 +02:00
|
|
|
AddClassPropertyImpl<T, ReadOnly, PropType>(PropertyName, Native, PropAllowInheritance, Update, Refresh);
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
template<typename PropType>
|
|
|
|
static void AddReadOnlyClassProperty( const CStrW& PropertyName, PropType T::*Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2006-07-27 04:42:35 +02:00
|
|
|
AddReadOnlyClassPropertyImpl<T, ReadOnly, PropType>(PropertyName, Native, PropAllowInheritance, Update, Refresh);
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
// PropertyName must not already exist! (verified in debug build)
|
|
|
|
template<typename PropType>
|
|
|
|
void AddProperty( const CStrW& PropertyName, PropType* Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2006-07-27 04:42:35 +02:00
|
|
|
MemberAddPropertyImpl<T, ReadOnly, PropType>(this, PropertyName, Native, PropAllowInheritance, Update, Refresh);
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
// PropertyName must not already exist! (verified in debug build)
|
|
|
|
template<typename PropType>
|
|
|
|
void AddReadOnlyProperty( const CStrW& PropertyName, PropType* Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2006-07-27 04:42:35 +02:00
|
|
|
MemberAddReadOnlyPropertyImpl<T, ReadOnly, PropType>(this, PropertyName, Native, PropAllowInheritance, Update, Refresh);
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// helper routine for Add*Property. Their interface requires the
|
2006-07-13 21:12:50 +02:00
|
|
|
// property not already exist; we check for this (in debug builds)
|
2006-04-24 01:14:18 +02:00
|
|
|
// and if so, warn and free the previously new-ed memory in
|
|
|
|
// m_Properties[PropertyName] (avoids mem leak).
|
2006-07-27 04:42:35 +02:00
|
|
|
void DeletePreviouslyAssignedProperty( const CStrW& PropertyName );
|
2006-04-24 01:14:18 +02:00
|
|
|
};
|
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// static members
|
|
|
|
//
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
template<typename T, bool ReadOnly> JSClass CJSComplex<T, ReadOnly>::JSI_class = {
|
|
|
|
NULL, JSCLASS_HAS_PRIVATE | JSCLASS_NEW_ENUMERATE,
|
|
|
|
JS_PropertyStub, JS_PropertyStub,
|
|
|
|
JSGetProperty, JSSetProperty,
|
|
|
|
(JSEnumerateOp)JSEnumerate, JS_ResolveStub,
|
|
|
|
JS_ConvertStub, DefaultFinalize,
|
|
|
|
NULL, NULL, NULL, NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T, bool ReadOnly> JSPropertySpec CJSComplex<T, ReadOnly>::JSI_props[] = {
|
|
|
|
{ 0 },
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T, bool ReadOnly> std::vector<JSFunctionSpec> CJSComplex<T, ReadOnly>::m_Methods;
|
|
|
|
template<typename T, bool ReadOnly> typename CJSComplex<T, ReadOnly>::PropertyTable CJSComplex<T, ReadOnly>::m_IntrinsicProperties;
|
|
|
|
|
2006-07-27 04:42:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void ScriptableComplex_InitComplexPropertyAccessor();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// suballocator for CJSComplex.m_Properties elements
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
extern void jscomplexproperty_suballoc_attach();
|
|
|
|
extern void jscomplexproperty_suballoc_detach();
|
|
|
|
extern void* jscomplexproperty_suballoc();
|
|
|
|
extern void jscomplexproperty_suballoc_free(IJSComplexProperty* p);
|
|
|
|
|
|
|
|
|
|
|
|
#include "ScriptableComplex.inl"
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|