forked from bartvdbraak/blender
BGE API cleanup: introduction of a generic framework to link Python attributes to logic brick class member. See KX_PYATTRIBUTE macros in PyObjectPlus.h.
This commit is contained in:
parent
eee013d9b9
commit
2dfd34994f
@ -131,6 +131,449 @@ int PyObjectPlus::_setattr(const STR_String& attr, PyObject *value)
|
||||
return 1;
|
||||
}
|
||||
|
||||
PyObject *PyObjectPlus::_getattr_self(const PyAttributeDef attrlist[], void *self, const STR_String &attr)
|
||||
{
|
||||
const PyAttributeDef *attrdef;
|
||||
for (attrdef=attrlist; attrdef->m_name != NULL; attrdef++)
|
||||
{
|
||||
if (attr == attrdef->m_name)
|
||||
{
|
||||
if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY)
|
||||
{
|
||||
// fake attribute, ignore
|
||||
return NULL;
|
||||
}
|
||||
char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset;
|
||||
if (attrdef->m_length > 1)
|
||||
{
|
||||
PyObject* resultlist = PyList_New(attrdef->m_length);
|
||||
for (int i=0; i<attrdef->m_length; i++)
|
||||
{
|
||||
switch (attrdef->m_type) {
|
||||
case KX_PYATTRIBUTE_TYPE_BOOL:
|
||||
{
|
||||
bool *val = reinterpret_cast<bool*>(ptr);
|
||||
ptr += sizeof(bool);
|
||||
PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
|
||||
break;
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_SHORT:
|
||||
{
|
||||
short int *val = reinterpret_cast<short int*>(ptr);
|
||||
ptr += sizeof(short int);
|
||||
PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
|
||||
break;
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_INT:
|
||||
{
|
||||
int *val = reinterpret_cast<int*>(ptr);
|
||||
ptr += sizeof(int);
|
||||
PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
|
||||
break;
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_FLOAT:
|
||||
{
|
||||
float *val = reinterpret_cast<float*>(ptr);
|
||||
ptr += sizeof(float);
|
||||
PyList_SetItem(resultlist,i,PyFloat_FromDouble(*val));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// no support for array of complex data
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return resultlist;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (attrdef->m_type) {
|
||||
case KX_PYATTRIBUTE_TYPE_BOOL:
|
||||
{
|
||||
bool *val = reinterpret_cast<bool*>(ptr);
|
||||
return PyInt_FromLong(*val);
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_SHORT:
|
||||
{
|
||||
short int *val = reinterpret_cast<short int*>(ptr);
|
||||
return PyInt_FromLong(*val);
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_INT:
|
||||
{
|
||||
int *val = reinterpret_cast<int*>(ptr);
|
||||
return PyInt_FromLong(*val);
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_FLOAT:
|
||||
{
|
||||
float *val = reinterpret_cast<float*>(ptr);
|
||||
return PyFloat_FromDouble(*val);
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_STRING:
|
||||
{
|
||||
STR_String *val = reinterpret_cast<STR_String*>(ptr);
|
||||
return PyString_FromString(*val);
|
||||
}
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, const STR_String &attr, PyObject *value)
|
||||
{
|
||||
const PyAttributeDef *attrdef;
|
||||
void *undoBuffer = NULL;
|
||||
void *sourceBuffer = NULL;
|
||||
size_t bufferSize = 0;
|
||||
|
||||
for (attrdef=attrlist; attrdef->m_name != NULL; attrdef++)
|
||||
{
|
||||
if (attr == attrdef->m_name)
|
||||
{
|
||||
if (attrdef->m_access == KX_PYATTRIBUTE_RO ||
|
||||
attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY)
|
||||
{
|
||||
PyErr_SetString(PyExc_AttributeError, "property is read-only");
|
||||
return 1;
|
||||
}
|
||||
char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset;
|
||||
if (attrdef->m_length > 1)
|
||||
{
|
||||
if (!PySequence_Check(value))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "expected a sequence");
|
||||
return 1;
|
||||
}
|
||||
if (PySequence_Size(value) != attrdef->m_length)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "incorrect number of elements in sequence");
|
||||
return 1;
|
||||
}
|
||||
switch (attrdef->m_type)
|
||||
{
|
||||
case KX_PYATTRIBUTE_TYPE_BOOL:
|
||||
bufferSize = sizeof(bool);
|
||||
break;
|
||||
case KX_PYATTRIBUTE_TYPE_SHORT:
|
||||
bufferSize = sizeof(short int);
|
||||
break;
|
||||
case KX_PYATTRIBUTE_TYPE_INT:
|
||||
bufferSize = sizeof(int);
|
||||
break;
|
||||
case KX_PYATTRIBUTE_TYPE_FLOAT:
|
||||
bufferSize = sizeof(float);
|
||||
break;
|
||||
default:
|
||||
// should not happen
|
||||
PyErr_SetString(PyExc_AttributeError, "Unsupported attribute type, report to blender.org");
|
||||
return 1;
|
||||
}
|
||||
// let's implement a smart undo method
|
||||
bufferSize *= attrdef->m_length;
|
||||
undoBuffer = malloc(bufferSize);
|
||||
sourceBuffer = ptr;
|
||||
if (undoBuffer)
|
||||
{
|
||||
memcpy(undoBuffer, sourceBuffer, bufferSize);
|
||||
}
|
||||
for (int i=0; i<attrdef->m_length; i++)
|
||||
{
|
||||
PyObject *item = PySequence_GetItem(value, i); /* new ref */
|
||||
// we can decrement the reference immediately, the reference count
|
||||
// is at least 1 because the item is part of an array
|
||||
Py_DECREF(item);
|
||||
switch (attrdef->m_type)
|
||||
{
|
||||
case KX_PYATTRIBUTE_TYPE_BOOL:
|
||||
{
|
||||
bool *var = reinterpret_cast<bool*>(ptr);
|
||||
ptr += sizeof(bool);
|
||||
if (PyInt_Check(item))
|
||||
{
|
||||
*var = (PyInt_AsLong(item) != 0);
|
||||
}
|
||||
else if (PyBool_Check(item))
|
||||
{
|
||||
*var = (item == Py_True);
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "expected an integer or a bool");
|
||||
goto UNDO_AND_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_SHORT:
|
||||
{
|
||||
short int *var = reinterpret_cast<short int*>(ptr);
|
||||
ptr += sizeof(short int);
|
||||
if (PyInt_Check(item))
|
||||
{
|
||||
long val = PyInt_AsLong(item);
|
||||
if (val < attrdef->m_imin || val > attrdef->m_imax)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "item value out of range");
|
||||
goto UNDO_AND_ERROR;
|
||||
}
|
||||
*var = (short int)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "expected an integer");
|
||||
goto UNDO_AND_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_INT:
|
||||
{
|
||||
int *var = reinterpret_cast<int*>(ptr);
|
||||
ptr += sizeof(int);
|
||||
if (PyInt_Check(item))
|
||||
{
|
||||
long val = PyInt_AsLong(item);
|
||||
if (val < attrdef->m_imin || val > attrdef->m_imax)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "item value out of range");
|
||||
goto UNDO_AND_ERROR;
|
||||
}
|
||||
*var = (int)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "expected an integer");
|
||||
goto UNDO_AND_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_FLOAT:
|
||||
{
|
||||
float *var = reinterpret_cast<float*>(ptr);
|
||||
ptr += sizeof(float);
|
||||
if (PyFloat_Check(item))
|
||||
{
|
||||
double val = PyFloat_AsDouble(item);
|
||||
if (val < attrdef->m_fmin || val > attrdef->m_fmax)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "item value out of range");
|
||||
goto UNDO_AND_ERROR;
|
||||
}
|
||||
*var = (float)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "expected a float");
|
||||
goto UNDO_AND_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// should not happen
|
||||
PyErr_SetString(PyExc_AttributeError, "attribute type check error, report to blender.org");
|
||||
goto UNDO_AND_ERROR;
|
||||
}
|
||||
}
|
||||
// no error, call check function if any
|
||||
if (attrdef->m_function != NULL)
|
||||
{
|
||||
if ((*attrdef->m_function)(self) != 0)
|
||||
{
|
||||
// post check returned an error, restore values
|
||||
UNDO_AND_ERROR:
|
||||
if (undoBuffer)
|
||||
{
|
||||
memcpy(sourceBuffer, undoBuffer, bufferSize);
|
||||
free(undoBuffer);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (undoBuffer)
|
||||
free(undoBuffer);
|
||||
return 0;
|
||||
}
|
||||
else // simple attribute value
|
||||
{
|
||||
|
||||
if (attrdef->m_function != NULL)
|
||||
{
|
||||
// post check function is provided, prepare undo buffer
|
||||
sourceBuffer = ptr;
|
||||
switch (attrdef->m_type)
|
||||
{
|
||||
case KX_PYATTRIBUTE_TYPE_BOOL:
|
||||
bufferSize = sizeof(bool);
|
||||
break;
|
||||
case KX_PYATTRIBUTE_TYPE_SHORT:
|
||||
bufferSize = sizeof(short);
|
||||
break;
|
||||
case KX_PYATTRIBUTE_TYPE_INT:
|
||||
bufferSize = sizeof(int);
|
||||
break;
|
||||
case KX_PYATTRIBUTE_TYPE_FLOAT:
|
||||
bufferSize = sizeof(float);
|
||||
break;
|
||||
case KX_PYATTRIBUTE_TYPE_STRING:
|
||||
sourceBuffer = reinterpret_cast<STR_String*>(ptr)->Ptr();
|
||||
if (sourceBuffer)
|
||||
bufferSize = strlen(reinterpret_cast<char*>(sourceBuffer))+1;
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_AttributeError, "unknown attribute type, report to blender.org");
|
||||
return 1;
|
||||
}
|
||||
if (bufferSize)
|
||||
{
|
||||
undoBuffer = malloc(bufferSize);
|
||||
if (undoBuffer)
|
||||
{
|
||||
memcpy(undoBuffer, sourceBuffer, bufferSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (attrdef->m_type)
|
||||
{
|
||||
case KX_PYATTRIBUTE_TYPE_BOOL:
|
||||
{
|
||||
bool *var = reinterpret_cast<bool*>(ptr);
|
||||
if (PyInt_Check(value))
|
||||
{
|
||||
*var = (PyInt_AsLong(value) != 0);
|
||||
}
|
||||
else if (PyBool_Check(value))
|
||||
{
|
||||
*var = (value == Py_True);
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "expected an integer or a bool");
|
||||
goto FREE_AND_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_SHORT:
|
||||
{
|
||||
short int *var = reinterpret_cast<short int*>(ptr);
|
||||
if (PyInt_Check(value))
|
||||
{
|
||||
long val = PyInt_AsLong(value);
|
||||
if (val < attrdef->m_imin || val > attrdef->m_imax)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "value out of range");
|
||||
goto FREE_AND_ERROR;
|
||||
}
|
||||
*var = (short int)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "expected an integer");
|
||||
goto FREE_AND_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_INT:
|
||||
{
|
||||
int *var = reinterpret_cast<int*>(ptr);
|
||||
if (PyInt_Check(value))
|
||||
{
|
||||
long val = PyInt_AsLong(value);
|
||||
if (val < attrdef->m_imin || val > attrdef->m_imax)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "value out of range");
|
||||
goto FREE_AND_ERROR;
|
||||
}
|
||||
*var = (int)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "expected an integer");
|
||||
goto FREE_AND_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_FLOAT:
|
||||
{
|
||||
float *var = reinterpret_cast<float*>(ptr);
|
||||
if (PyFloat_Check(value))
|
||||
{
|
||||
double val = PyFloat_AsDouble(value);
|
||||
if (val < attrdef->m_fmin || val > attrdef->m_fmax)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "value out of range");
|
||||
goto FREE_AND_ERROR;
|
||||
}
|
||||
*var = (float)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "expected a float");
|
||||
goto FREE_AND_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KX_PYATTRIBUTE_TYPE_STRING:
|
||||
{
|
||||
STR_String *var = reinterpret_cast<STR_String*>(ptr);
|
||||
if (PyString_Check(value))
|
||||
{
|
||||
char *val = PyString_AsString(value);
|
||||
if (strlen(val) < attrdef->m_imin || strlen(val) > attrdef->m_imax)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "string length out of range");
|
||||
goto FREE_AND_ERROR;
|
||||
}
|
||||
*var = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "expected a string");
|
||||
goto FREE_AND_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// should not happen
|
||||
PyErr_SetString(PyExc_AttributeError, "unknown attribute type, report to blender.org");
|
||||
goto FREE_AND_ERROR;
|
||||
}
|
||||
}
|
||||
// check if post processing is needed
|
||||
if (attrdef->m_function != NULL)
|
||||
{
|
||||
if ((*attrdef->m_function)(self) != 0)
|
||||
{
|
||||
// restore value
|
||||
if (undoBuffer)
|
||||
{
|
||||
if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_STRING)
|
||||
{
|
||||
// special case for STR_String: restore the string
|
||||
STR_String *var = reinterpret_cast<STR_String*>(ptr);
|
||||
*var = reinterpret_cast<char*>(undoBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// other field type have direct values
|
||||
memcpy(ptr, undoBuffer, bufferSize);
|
||||
}
|
||||
}
|
||||
FREE_AND_ERROR:
|
||||
if (undoBuffer)
|
||||
free(undoBuffer);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (undoBuffer)
|
||||
free(undoBuffer);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*------------------------------
|
||||
* PyObjectPlus repr -- representations
|
||||
------------------------------*/
|
||||
|
@ -86,6 +86,7 @@ static inline void Py_Fatal(const char *M) {
|
||||
public: \
|
||||
static PyTypeObject Type; \
|
||||
static PyMethodDef Methods[]; \
|
||||
static PyAttributeDef Attributes[]; \
|
||||
static PyParentObject Parents[]; \
|
||||
virtual PyTypeObject *GetType(void) {return &Type;}; \
|
||||
virtual PyParentObject *GetParents(void) {return Parents;}
|
||||
@ -210,6 +211,104 @@ PyObject* class_name::Py##method_name(PyObject*, PyObject* value)
|
||||
const char class_name::method_name##_doc[] = doc_string; \
|
||||
PyObject* class_name::Py##method_name(PyObject*)
|
||||
|
||||
/**
|
||||
* Attribute management
|
||||
*/
|
||||
enum KX_PYATTRIBUTE_TYPE {
|
||||
KX_PYATTRIBUTE_TYPE_BOOL,
|
||||
KX_PYATTRIBUTE_TYPE_SHORT,
|
||||
KX_PYATTRIBUTE_TYPE_INT,
|
||||
KX_PYATTRIBUTE_TYPE_FLOAT,
|
||||
KX_PYATTRIBUTE_TYPE_STRING,
|
||||
KX_PYATTRIBUTE_TYPE_DUMMY,
|
||||
};
|
||||
|
||||
enum KX_PYATTRIBUTE_ACCESS {
|
||||
KX_PYATTRIBUTE_RW,
|
||||
KX_PYATTRIBUTE_RO
|
||||
};
|
||||
|
||||
typedef int (*KX_PYATTRIBUTE_FUNCTION)(void *self);
|
||||
|
||||
typedef struct KX_PYATTRIBUTE_DEF {
|
||||
const char *m_name; // name of the python attribute
|
||||
KX_PYATTRIBUTE_TYPE m_type; // type of value
|
||||
KX_PYATTRIBUTE_ACCESS m_access; // read/write access or read-only
|
||||
int m_imin; // minimum value in case of integer attributes
|
||||
int m_imax; // maximum value in case of integer attributes
|
||||
float m_fmin; // minimum value in case of float attributes
|
||||
float m_fmax; // maximum value in case of float attributes
|
||||
size_t m_offset; // position of field in structure
|
||||
size_t m_length; // length of array, 1=simple attribute
|
||||
KX_PYATTRIBUTE_FUNCTION m_function; // static function to check the assignment, returns 0 if no error
|
||||
// The following pointers are just used to have compile time check for attribute type.
|
||||
// It would have been good to use a union but that would require C99 compatibility
|
||||
// to initialize specific union fields through designated initializers.
|
||||
struct {
|
||||
bool *m_boolPtr;
|
||||
short int *m_shortPtr;
|
||||
int *m_intPtr;
|
||||
float *m_floatPtr;
|
||||
STR_String *m_stringPtr;
|
||||
} m_typeCheck;
|
||||
} PyAttributeDef;
|
||||
|
||||
#define KX_PYATTRIBUTE_DUMMY(name) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, 0, 1, NULL, {NULL, NULL, NULL, NULL, NULL} }
|
||||
|
||||
#define KX_PYATTRIBUTE_BOOL_RW(name,object,field) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, offsetof(object,field), 1, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL} }
|
||||
#define KX_PYATTRIBUTE_BOOL_RW_CHECK(name,object,field,function) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, offsetof(object,field), 1, &object::function, {&((object *)0)->field, NULL, NULL, NULL, NULL} }
|
||||
#define KX_PYATTRIBUTE_BOOL_RO(name,object,field) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, offsetof(object,field), 1, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL} }
|
||||
|
||||
#define KX_PYATTRIBUTE_SHORT_RW(name,min,max,object,field) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} }
|
||||
#define KX_PYATTRIBUTE_SHORT_RW_CHECK(name,min,max,object,field,function) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, &object::function, {NULL, &((object *)0)->field, NULL, NULL, NULL} }
|
||||
#define KX_PYATTRIBUTE_SHORT_RO(name,object,field) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} }
|
||||
#define KX_PYATTRIBUTE_SHORT_ARRAY_RW(name,min,max,object,field,length) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), length, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} }
|
||||
#define KX_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), length, &object::function, {NULL, &((object *)0)->field, NULL, NULL, NULL} }
|
||||
#define KX_PYATTRIBUTE_SHORT_ARRAY_RO(name,object,field,length) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), length, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} }
|
||||
|
||||
#define KX_PYATTRIBUTE_INT_RW(name,min,max,object,field) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} }
|
||||
#define KX_PYATTRIBUTE_INT_RW_CHECK(name,min,max,object,field,function) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, &object::function, {NULL, NULL, &((object *)0)->field, NULL, NULL} }
|
||||
#define KX_PYATTRIBUTE_INT_RO(name,object,field) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} }
|
||||
#define KX_PYATTRIBUTE_INT_ARRAY_RW(name,min,max,object,field,length) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), length, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} }
|
||||
#define KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), length, &object::function, {NULL, NULL, &((object *)0)->field, NULL, NULL} }
|
||||
#define KX_PYATTRIBUTE_INT_ARRAY_RO(name,object,field,length) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), length, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} }
|
||||
|
||||
#define KX_PYATTRIBUTE_FLOAT_RW(name,min,max,object,field) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, offsetof(object,field), 1, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL} }
|
||||
#define KX_PYATTRIBUTE_FLOAT_RW_CHECK(name,min,max,object,field,function) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, offsetof(object,field), 1, &object::function, {NULL, NULL, NULL, &((object *)0)->field, NULL} }
|
||||
#define KX_PYATTRIBUTE_FLOAT_RO(name,object,field) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL} }
|
||||
#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW(name,min,max,object,field,length) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, offsetof(object,field), length, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL} }
|
||||
#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, offsetof(object,field), length, &object::function, {NULL, NULL, NULL, &((object *)0)->field, NULL} }
|
||||
#define KX_PYATTRIBUTE_FLOAT_ARRAY_RO(name,object,field,length) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), length, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL} }
|
||||
|
||||
#define KX_PYATTRIBUTE_STRING_RW(name,min,max,object,field) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field} }
|
||||
#define KX_PYATTRIBUTE_STRING_RW_CHECK(name,min,max,object,field,function) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, &object::function, {NULL, NULL, NULL, NULL, &((object *)0)->field} }
|
||||
#define KX_PYATTRIBUTE_STRING_RO(name,object,field) \
|
||||
{ name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), 1 , NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field} }
|
||||
|
||||
/*------------------------------
|
||||
* PyObjectPlus
|
||||
------------------------------*/
|
||||
@ -240,6 +339,8 @@ public:
|
||||
{
|
||||
return ((PyObjectPlus*) PyObj)->_getattr(STR_String(attr));
|
||||
}
|
||||
static PyObject *_getattr_self(const PyAttributeDef attrlist[], void *self, const STR_String &attr);
|
||||
static int _setattr_self(const PyAttributeDef attrlist[], void *self, const STR_String &attr, PyObject *value);
|
||||
|
||||
virtual int _delattr(const STR_String& attr);
|
||||
virtual int _setattr(const STR_String& attr, PyObject *value); // _setattr method
|
||||
|
@ -327,6 +327,21 @@ PyMethodDef SCA_JoystickSensor::Methods[] = {
|
||||
{NULL,NULL} //Sentinel
|
||||
};
|
||||
|
||||
PyAttributeDef SCA_JoystickSensor::Attributes[] = {
|
||||
KX_PYATTRIBUTE_SHORT_RW("index",0,JOYINDEX_MAX-1,SCA_JoystickSensor,m_joyindex),
|
||||
KX_PYATTRIBUTE_INT_RW("threshold",0,32768,SCA_JoystickSensor,m_precision),
|
||||
KX_PYATTRIBUTE_INT_RW("button",0,100,SCA_JoystickSensor,m_button),
|
||||
KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK("axis",0,3,SCA_JoystickSensor,m_axis,2,CheckAxis),
|
||||
KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK("hat",0,12,SCA_JoystickSensor,m_hat,2,CheckHat),
|
||||
// dummy attributes will just be read-only in _setattr
|
||||
// you still need to defined them in _getattr
|
||||
KX_PYATTRIBUTE_DUMMY("axisPosition"),
|
||||
KX_PYATTRIBUTE_DUMMY("numAxis"),
|
||||
KX_PYATTRIBUTE_DUMMY("numButtons"),
|
||||
KX_PYATTRIBUTE_DUMMY("numHats"),
|
||||
KX_PYATTRIBUTE_DUMMY("connected"),
|
||||
{ NULL } //Sentinel
|
||||
};
|
||||
|
||||
PyObject* SCA_JoystickSensor::_getattr(const STR_String& attr) {
|
||||
SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex);
|
||||
@ -348,100 +363,17 @@ PyObject* SCA_JoystickSensor::_getattr(const STR_String& attr) {
|
||||
if (attr == "connected") {
|
||||
return PyBool_FromLong( joy ? joy->Connected() : 0 );
|
||||
}
|
||||
if (attr == "index") {
|
||||
return PyInt_FromLong(m_joyindex);
|
||||
}
|
||||
if (attr == "threshold") {
|
||||
return PyInt_FromLong(m_precision);
|
||||
}
|
||||
if (attr == "button") {
|
||||
return PyInt_FromLong(m_button);
|
||||
}
|
||||
if (attr == "axis") {
|
||||
return Py_BuildValue("[ii]",m_axis, m_axisf);
|
||||
}
|
||||
if (attr == "hat") {
|
||||
return Py_BuildValue("[ii]",m_hat, m_hatf);
|
||||
}
|
||||
PyObject* object = _getattr_self(Attributes, this, attr);
|
||||
if (object != NULL)
|
||||
return object;
|
||||
_getattr_up(SCA_ISensor);
|
||||
}
|
||||
|
||||
int SCA_JoystickSensor::_setattr(const STR_String& attr, PyObject *value) {
|
||||
if (attr == "axisPosition") {
|
||||
PyErr_SetString(PyExc_AttributeError, "axisPosition is read only");
|
||||
return 1;
|
||||
}
|
||||
if (attr == "numAxis") {
|
||||
PyErr_SetString(PyExc_AttributeError, "numaxis is read only");
|
||||
return 1;
|
||||
}
|
||||
if (attr == "numButtons") {
|
||||
PyErr_SetString(PyExc_AttributeError, "numbuttons is read only");
|
||||
return 1;
|
||||
}
|
||||
if (attr == "numHats") {
|
||||
PyErr_SetString(PyExc_AttributeError, "numhats is read only");
|
||||
return 1;
|
||||
}
|
||||
if (attr == "connected") {
|
||||
PyErr_SetString(PyExc_AttributeError, "connected is read only");
|
||||
return 1;
|
||||
}
|
||||
if (PyInt_Check(value)) {
|
||||
int ival = PyInt_AsLong(value);
|
||||
if (attr == "index") {
|
||||
if (ival < 0 || ival >= JOYINDEX_MAX) {
|
||||
PyErr_SetString(PyExc_ValueError, "joystick index out of range");
|
||||
return 1;
|
||||
}
|
||||
m_joyindex = ival;
|
||||
} else if (attr == "threshold") {
|
||||
m_precision = ival;
|
||||
} else if (attr == "button") {
|
||||
if (ival < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "button out of range");
|
||||
return 1;
|
||||
}
|
||||
m_button = ival;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (PySequence_Check(value)) {
|
||||
if (attr == "axis" || attr == "hat") {
|
||||
if (PySequence_Size(value) != 2) {
|
||||
PyErr_SetString(PyExc_ValueError, "value must be sequence of 2 integers");
|
||||
return 1;
|
||||
}
|
||||
int ival = -1;
|
||||
int ivalf = -1;
|
||||
PyObject *item = PySequence_GetItem(value, 0); /* new ref */
|
||||
ival = PyInt_AsLong(item);
|
||||
Py_DECREF(item);
|
||||
item = PySequence_GetItem(value, 1); /* new ref */
|
||||
ivalf = PyInt_AsLong(item);
|
||||
Py_DECREF(item);
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_ValueError, "one or more of the items in the sequence was not an integer");
|
||||
return 1;
|
||||
}
|
||||
if (attr == "axis") {
|
||||
if (ival < 1 || ival > 2 || ivalf < 0 || ivalf > 3) {
|
||||
PyErr_SetString(PyExc_ValueError, "items in the sequence are out of range");
|
||||
return 1;
|
||||
}
|
||||
m_axis = ival;
|
||||
m_axisf = ivalf;
|
||||
} else {
|
||||
if (ival < 1 || ival > 2) {
|
||||
PyErr_SetString(PyExc_ValueError, "items in the sequence are out of range");
|
||||
return 1;
|
||||
}
|
||||
m_hat = ival;
|
||||
m_hatf = ivalf;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int SCA_JoystickSensor::_setattr(const STR_String& attr, PyObject *value)
|
||||
{
|
||||
int ret = _setattr_self(Attributes, this, attr, value);
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
return SCA_ISensor::_setattr(attr, value);
|
||||
}
|
||||
|
||||
|
@ -37,11 +37,11 @@ class SCA_JoystickSensor :public SCA_ISensor
|
||||
class SCA_JoystickManager* m_pJoystickMgr;
|
||||
|
||||
/**
|
||||
* Axis 1-or-2
|
||||
* Axis 1-or-2, MUST be followed by m_axisf
|
||||
*/
|
||||
int m_axis;
|
||||
/**
|
||||
* Axis flag to find direction
|
||||
* Axis flag to find direction, MUST be an int
|
||||
*/
|
||||
int m_axisf;
|
||||
/**
|
||||
@ -53,11 +53,11 @@ class SCA_JoystickSensor :public SCA_ISensor
|
||||
*/
|
||||
int m_buttonf;
|
||||
/**
|
||||
* The actual hat
|
||||
* The actual hat. MUST be followed by m_hatf
|
||||
*/
|
||||
int m_hat;
|
||||
/**
|
||||
* Flag to find direction 1-12
|
||||
* Flag to find direction 0-11, MUST be an int
|
||||
*/
|
||||
int m_hatf;
|
||||
/**
|
||||
@ -148,6 +148,28 @@ public:
|
||||
KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,NumberOfHats);
|
||||
KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,Connected);
|
||||
|
||||
/* attribute check */
|
||||
static int CheckAxis(void *self)
|
||||
{
|
||||
SCA_JoystickSensor* sensor = reinterpret_cast<SCA_JoystickSensor*>(self);
|
||||
if (sensor->m_axis < 1 || sensor->m_axis > 2)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "axis number must be 1 or 2");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int CheckHat(void *self)
|
||||
{
|
||||
SCA_JoystickSensor* sensor = reinterpret_cast<SCA_JoystickSensor*>(self);
|
||||
if (sensor->m_hat < 1 || sensor->m_hat > 2)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "hat number must be 1 or 2");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -820,91 +820,29 @@ PyMethodDef SCA_KeyboardSensor::Methods[] = {
|
||||
{NULL,NULL} //Sentinel
|
||||
};
|
||||
|
||||
PyAttributeDef SCA_KeyboardSensor::Attributes[] = {
|
||||
KX_PYATTRIBUTE_BOOL_RW("useAllKeys",SCA_KeyboardSensor,m_bAllKeys),
|
||||
KX_PYATTRIBUTE_INT_RW("key",0,1000,SCA_KeyboardSensor,m_hotkey),
|
||||
KX_PYATTRIBUTE_SHORT_RW("hold1",0,1000,SCA_KeyboardSensor,m_qual),
|
||||
KX_PYATTRIBUTE_SHORT_RW("hold2",0,1000,SCA_KeyboardSensor,m_qual2),
|
||||
KX_PYATTRIBUTE_STRING_RW("toggleProperty",0,100,SCA_KeyboardSensor,m_toggleprop),
|
||||
KX_PYATTRIBUTE_STRING_RW("targetProperty",0,100,SCA_KeyboardSensor,m_targetprop),
|
||||
{ NULL } //Sentinel
|
||||
};
|
||||
|
||||
PyObject*
|
||||
SCA_KeyboardSensor::_getattr(const STR_String& attr)
|
||||
{
|
||||
if (attr == "key")
|
||||
return PyInt_FromLong(m_hotkey);
|
||||
|
||||
if (attr == "hold1")
|
||||
return PyInt_FromLong(m_qual);
|
||||
|
||||
if (attr == "hold2")
|
||||
return PyInt_FromLong(m_qual2);
|
||||
|
||||
if (attr == "toggleProperty")
|
||||
return PyString_FromString(m_toggleprop);
|
||||
|
||||
if (attr == "targetProperty")
|
||||
return PyString_FromString(m_targetprop);
|
||||
|
||||
if (attr == "useAllKeys")
|
||||
return PyInt_FromLong(m_bAllKeys);
|
||||
|
||||
PyObject* object = _getattr_self(Attributes, this, attr);
|
||||
if (object != NULL)
|
||||
return object;
|
||||
_getattr_up(SCA_ISensor);
|
||||
}
|
||||
|
||||
int SCA_KeyboardSensor::_setattr(const STR_String& attr, PyObject *value)
|
||||
{
|
||||
if (attr == "key")
|
||||
{
|
||||
if (!PyInt_Check(value)){
|
||||
PyErr_SetString(PyExc_TypeError, "expected an integer");
|
||||
return 1;
|
||||
}
|
||||
m_hotkey = PyInt_AsLong(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (attr == "hold1")
|
||||
{
|
||||
if (!PyInt_Check(value)){
|
||||
PyErr_SetString(PyExc_TypeError, "expected an integer");
|
||||
return 1;
|
||||
}
|
||||
m_qual = PyInt_AsLong(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (attr == "hold2")
|
||||
{
|
||||
if (!PyInt_Check(value)){
|
||||
PyErr_SetString(PyExc_TypeError, "expected an integer");
|
||||
return 1;
|
||||
}
|
||||
m_qual2 = PyInt_AsLong(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (attr == "useAllKeys")
|
||||
{
|
||||
if (!PyInt_Check(value)){
|
||||
PyErr_SetString(PyExc_TypeError, "expected an integer");
|
||||
return 1;
|
||||
}
|
||||
m_bAllKeys = (PyInt_AsLong(value) != 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (attr == "logToggleProperty")
|
||||
{
|
||||
if (!PyString_Check(value)){
|
||||
PyErr_SetString(PyExc_TypeError, "expected a string");
|
||||
return 1;
|
||||
}
|
||||
m_toggleprop = PyString_AsString(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (attr == "logTargetProperty")
|
||||
{
|
||||
if (!PyString_Check(value)){
|
||||
PyErr_SetString(PyExc_TypeError, "expected a string");
|
||||
return 1;
|
||||
}
|
||||
m_targetprop = PyString_AsString(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = _setattr_self(Attributes, this, attr, value);
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
return SCA_ISensor::_setattr(attr, value);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ SCA_MouseSensor::SCA_MouseSensor(SCA_MouseManager* eventmgr,
|
||||
m_mousemode = mousemode;
|
||||
m_triggermode = true;
|
||||
|
||||
UpdateHotkey();
|
||||
UpdateHotkey(this);
|
||||
Init();
|
||||
}
|
||||
|
||||
@ -74,33 +74,37 @@ SCA_MouseSensor::~SCA_MouseSensor()
|
||||
/* Nothing to be done here. */
|
||||
}
|
||||
|
||||
void SCA_MouseSensor::UpdateHotkey()
|
||||
int SCA_MouseSensor::UpdateHotkey(void *self)
|
||||
{
|
||||
// gosh, this function is so damn stupid
|
||||
// its here because of a design mistake in the mouse sensor, it should only
|
||||
// have 3 trigger modes (button, wheel, move), and let the user set the
|
||||
// hotkey separately, like the other sensors. but instead it has a mode for
|
||||
// each friggin key and i have to update the hotkey based on it... genius!
|
||||
SCA_MouseSensor* sensor = reinterpret_cast<SCA_MouseSensor*>(self);
|
||||
|
||||
switch (m_mousemode) {
|
||||
switch (sensor->m_mousemode) {
|
||||
case KX_MOUSESENSORMODE_LEFTBUTTON:
|
||||
m_hotkey = SCA_IInputDevice::KX_LEFTMOUSE;
|
||||
sensor->m_hotkey = SCA_IInputDevice::KX_LEFTMOUSE;
|
||||
break;
|
||||
case KX_MOUSESENSORMODE_MIDDLEBUTTON:
|
||||
m_hotkey = SCA_IInputDevice::KX_MIDDLEMOUSE;
|
||||
sensor->m_hotkey = SCA_IInputDevice::KX_MIDDLEMOUSE;
|
||||
break;
|
||||
case KX_MOUSESENSORMODE_RIGHTBUTTON:
|
||||
m_hotkey = SCA_IInputDevice::KX_RIGHTMOUSE;
|
||||
sensor->m_hotkey = SCA_IInputDevice::KX_RIGHTMOUSE;
|
||||
break;
|
||||
case KX_MOUSESENSORMODE_WHEELUP:
|
||||
m_hotkey = SCA_IInputDevice::KX_WHEELUPMOUSE;
|
||||
sensor->m_hotkey = SCA_IInputDevice::KX_WHEELUPMOUSE;
|
||||
break;
|
||||
case KX_MOUSESENSORMODE_WHEELDOWN:
|
||||
m_hotkey = SCA_IInputDevice::KX_WHEELDOWNMOUSE;
|
||||
sensor->m_hotkey = SCA_IInputDevice::KX_WHEELDOWNMOUSE;
|
||||
break;
|
||||
default:
|
||||
; /* ignore, no hotkey */
|
||||
}
|
||||
// return value is used in _setattr(),
|
||||
// 0=attribute checked ok (see Attributes array definition)
|
||||
return 0;
|
||||
}
|
||||
|
||||
CValue* SCA_MouseSensor::GetReplica()
|
||||
@ -331,44 +335,25 @@ PyMethodDef SCA_MouseSensor::Methods[] = {
|
||||
{NULL,NULL} //Sentinel
|
||||
};
|
||||
|
||||
PyObject* SCA_MouseSensor::_getattr(const STR_String& attr) {
|
||||
if (attr == "position")
|
||||
return Py_BuildValue("[ii]", m_x, m_y);
|
||||
|
||||
if (attr == "mode")
|
||||
return PyInt_FromLong(m_mousemode);
|
||||
PyAttributeDef SCA_MouseSensor::Attributes[] = {
|
||||
KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",KX_MOUSESENSORMODE_NODEF,KX_MOUSESENSORMODE_MAX-1,SCA_MouseSensor,m_mousemode,UpdateHotkey),
|
||||
KX_PYATTRIBUTE_SHORT_ARRAY_RO("position",SCA_MouseSensor,m_x,2),
|
||||
{ NULL } //Sentinel
|
||||
};
|
||||
|
||||
PyObject* SCA_MouseSensor::_getattr(const STR_String& attr)
|
||||
{
|
||||
PyObject* object = _getattr_self(Attributes, this, attr);
|
||||
if (object != NULL)
|
||||
return object;
|
||||
_getattr_up(SCA_ISensor);
|
||||
}
|
||||
|
||||
int SCA_MouseSensor::_setattr(const STR_String& attr, PyObject *value)
|
||||
{
|
||||
if (attr == "mode")
|
||||
{
|
||||
if (!PyInt_Check(value)){
|
||||
PyErr_SetString(PyExc_TypeError, "expected an integer");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int val = PyInt_AsLong(value);
|
||||
|
||||
if ((val < KX_MOUSESENSORMODE_NODEF)
|
||||
|| (val > KX_MOUSESENSORMODE_MAX)){
|
||||
PyErr_SetString(PyExc_ValueError, "invalid mode specified!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
m_mousemode = val;
|
||||
UpdateHotkey();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (attr == "position")
|
||||
{
|
||||
PyErr_SetString(PyExc_AttributeError, "'position' is a read-only property!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ret = _setattr_self(Attributes, this, attr, value);
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
return SCA_ISensor::_setattr(attr, value);
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ class SCA_MouseSensor : public SCA_ISensor
|
||||
SCA_IInputDevice::KX_EnumInputs m_hotkey;
|
||||
|
||||
/**
|
||||
* valid x coordinate
|
||||
* valid x coordinate, MUST be followed by y coordinate
|
||||
*/
|
||||
short m_x;
|
||||
|
||||
@ -87,7 +87,7 @@ class SCA_MouseSensor : public SCA_ISensor
|
||||
|
||||
bool isValid(KX_MOUSESENSORMODE);
|
||||
|
||||
void UpdateHotkey();
|
||||
static int UpdateHotkey(void *self);
|
||||
|
||||
SCA_MouseSensor(class SCA_MouseManager* keybdmgr,
|
||||
int startx,int starty,
|
||||
|
Loading…
Reference in New Issue
Block a user