557 lines
16 KiB
C
557 lines
16 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version. The Blender
|
|
* Foundation also sells licenses for use in proprietary software under
|
|
* the Blender License. See http://www.blender.org/BL/ for information
|
|
* about this.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* This is a new part of Blender.
|
|
*
|
|
* Contributor(s): Joseph Gilbert
|
|
*
|
|
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include "logic.h" /*This must come first*/
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
#include "BLI_blenlib.h"
|
|
#include "gen_utils.h"
|
|
|
|
//--------------- Python BPy_Property methods declarations:---------------
|
|
static PyObject *Property_getName( BPy_Property * self );
|
|
static PyObject *Property_setName( BPy_Property * self, PyObject * args );
|
|
static PyObject *Property_getData( BPy_Property * self );
|
|
static PyObject *Property_setData( BPy_Property * self, PyObject * args );
|
|
static PyObject *Property_getType( BPy_Property * self );
|
|
//--------------- Python BPy_Property methods table:----------------------
|
|
static PyMethodDef BPy_Property_methods[] = {
|
|
{"getName", ( PyCFunction ) Property_getName, METH_NOARGS,
|
|
"() - return Property name"},
|
|
{"setName", ( PyCFunction ) Property_setName, METH_VARARGS,
|
|
"() - set the name of this Property"},
|
|
{"getData", ( PyCFunction ) Property_getData, METH_NOARGS,
|
|
"() - return Property data"},
|
|
{"setData", ( PyCFunction ) Property_setData, METH_VARARGS,
|
|
"() - set the data of this Property"},
|
|
{"getType", ( PyCFunction ) Property_getType, METH_NOARGS,
|
|
"() - return Property type"},
|
|
{NULL, NULL, 0, NULL}
|
|
};
|
|
//--------------- Python TypeProperty callback function prototypes--------
|
|
static void Property_dealloc( BPy_Property * Property );
|
|
static PyObject *Property_getAttr( BPy_Property * Property, char *name );
|
|
static int Property_setAttr( BPy_Property * Property, char *name,
|
|
PyObject * v );
|
|
static PyObject *Property_repr( BPy_Property * Property );
|
|
static int Property_compare( BPy_Property * a1, BPy_Property * a2 );
|
|
//--------------- Python TypeProperty structure definition----------------
|
|
PyTypeObject property_Type = {
|
|
PyObject_HEAD_INIT( NULL )
|
|
0, /* ob_size */
|
|
"Blender Property", /* tp_name */
|
|
sizeof( BPy_Property ), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
( destructor ) Property_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
( getattrfunc ) Property_getAttr, /* tp_getattr */
|
|
( setattrfunc ) Property_setAttr, /* tp_setattr */
|
|
( cmpfunc ) Property_compare, /* tp_compare */
|
|
( reprfunc ) Property_repr, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_as_hash */
|
|
0, 0, 0, 0, 0, 0,
|
|
0, /* tp_doc */
|
|
0, 0, 0, 0, 0, 0,
|
|
BPy_Property_methods, /* tp_methods */
|
|
0, /* tp_members */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
};
|
|
//--------------- Property module internal callbacks-------------------
|
|
|
|
//--------------- updatePyProperty-------------------------------------
|
|
int updatePyProperty( BPy_Property * self )
|
|
{
|
|
if( !self->property ) {
|
|
return 0; //nothing to update - not linked
|
|
} else {
|
|
BLI_strncpy( self->name, self->property->name, 32 );
|
|
self->type = self->property->type;
|
|
if( self->property->type == PROP_BOOL ) {
|
|
if( *( ( int * ) &self->property->poin ) ) {
|
|
self->data = EXPP_incr_ret_True();
|
|
} else {
|
|
self->data = EXPP_incr_ret_False();
|
|
}
|
|
} else if( self->property->type == PROP_INT ) {
|
|
self->data = PyInt_FromLong( self->property->data );
|
|
} else if( self->property->type == PROP_FLOAT ) {
|
|
self->data =
|
|
PyFloat_FromDouble( *
|
|
( ( float * ) &self->
|
|
property->data ) );
|
|
} else if( self->property->type == PROP_TIME ) {
|
|
self->data =
|
|
PyFloat_FromDouble( *
|
|
( ( float * ) &self->
|
|
property->data ) );
|
|
} else if( self->property->type == PROP_STRING ) {
|
|
self->data =
|
|
PyString_FromString( self->property->poin );
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
//--------------- updatePropertyData------------------------------------
|
|
int updateProperyData( BPy_Property * self )
|
|
{
|
|
if( !self->property ) {
|
|
//nothing to update - not linked
|
|
return 0;
|
|
} else {
|
|
BLI_strncpy( self->property->name, self->name, 32 );
|
|
self->property->type = self->type;
|
|
if( PyInt_Check( self->data ) ) {
|
|
*( ( int * ) &self->property->data ) =
|
|
( int ) PyInt_AsLong( self->data );
|
|
} else if( PyFloat_Check( self->data ) ) {
|
|
*( ( float * ) &self->property->data ) =
|
|
( float ) PyFloat_AsDouble( self->data );
|
|
} else if( PyString_Check( self->data ) ) {
|
|
BLI_strncpy( self->property->poin,
|
|
PyString_AsString( self->data ),
|
|
MAX_PROPSTRING );
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
//--------------- checkValidData_ptr--------------------------------
|
|
static int checkValidData_ptr( BPy_Property * self )
|
|
{
|
|
int length;
|
|
//test pointer to see if data was removed (oops)
|
|
length = MEM_allocN_len( self->property );
|
|
if( length != sizeof( bProperty ) ) { //data was freed
|
|
self->property = NULL;
|
|
return 0;
|
|
} else { //it's ok as far as we can tell
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
//---------------BPy_Property internal callbacks/methods------------
|
|
|
|
//--------------- dealloc-------------------------------------------
|
|
static void Property_dealloc( BPy_Property * self )
|
|
{
|
|
PyMem_Free( self->name );
|
|
PyObject_DEL( self );
|
|
}
|
|
|
|
//---------------getattr--------------------------------------------
|
|
static PyObject *Property_getAttr( BPy_Property * self, char *name )
|
|
{
|
|
PyObject *attr = Py_None;
|
|
|
|
checkValidData_ptr( self );
|
|
if( strcmp( name, "name" ) == 0 )
|
|
attr = Property_getName( self );
|
|
else if( strcmp( name, "data" ) == 0 )
|
|
attr = Property_getData( self );
|
|
else if( strcmp( name, "type" ) == 0 )
|
|
attr = Property_getType( self );
|
|
else if( strcmp( name, "__members__" ) == 0 ) {
|
|
attr = Py_BuildValue( "[s,s,s]", "name", "data", "type" );
|
|
}
|
|
|
|
if( !attr )
|
|
return ( EXPP_ReturnPyObjError
|
|
( PyExc_MemoryError, "couldn't create PyObject" ) );
|
|
|
|
if( attr != Py_None )
|
|
return attr;
|
|
|
|
return Py_FindMethod( BPy_Property_methods, ( PyObject * ) self,
|
|
name );
|
|
}
|
|
|
|
//--------------- setattr-------------------------------------------
|
|
static int
|
|
Property_setAttr( BPy_Property * self, char *name, PyObject * value )
|
|
{
|
|
PyObject *valtuple;
|
|
PyObject *error = NULL;
|
|
|
|
checkValidData_ptr( self );
|
|
valtuple = Py_BuildValue( "(O)", value );
|
|
if( !valtuple )
|
|
return EXPP_ReturnIntError( PyExc_MemoryError,
|
|
"PropertySetAttr: couldn't create tuple" );
|
|
|
|
if( strcmp( name, "name" ) == 0 )
|
|
error = Property_setName( self, valtuple );
|
|
else if( strcmp( name, "data" ) == 0 )
|
|
error = Property_setData( self, valtuple );
|
|
else {
|
|
Py_DECREF( valtuple );
|
|
return ( EXPP_ReturnIntError
|
|
( PyExc_KeyError, "attribute not found" ) );
|
|
}
|
|
Py_DECREF( valtuple );
|
|
|
|
if( error != Py_None )
|
|
return -1;
|
|
|
|
Py_DECREF( Py_None );
|
|
return 0;
|
|
}
|
|
|
|
//--------------- repr----------------------------------------------
|
|
static PyObject *Property_repr( BPy_Property * self )
|
|
{
|
|
checkValidData_ptr( self );
|
|
if( self->property ) {
|
|
return PyString_FromFormat( "[Property \"%s\"]",
|
|
self->property->name );
|
|
} else {
|
|
return PyString_FromFormat( "[Property \"%s\"]", self->name );
|
|
}
|
|
}
|
|
|
|
//--------------- compare-------------------------------------------
|
|
//compares property.name and property.data
|
|
static int Property_compare( BPy_Property * a, BPy_Property * b )
|
|
{
|
|
BPy_Property *py_propA, *py_propB;
|
|
int retval = -1;
|
|
|
|
checkValidData_ptr( a );
|
|
checkValidData_ptr( b );
|
|
//2 python objects
|
|
if( !a->property && !b->property ) {
|
|
if( a->type != b->type )
|
|
retval = -1;
|
|
if( BLI_streq( a->name, b->name ) ) {
|
|
retval = PyObject_Compare( a->data, b->data );
|
|
} else
|
|
retval = -1;
|
|
} else if( a->property && b->property ) { //2 real properties
|
|
if( a->property->type != b->property->type )
|
|
retval = -1;
|
|
if( BLI_streq( a->property->name, b->property->name ) ) {
|
|
if( a->property->type == PROP_BOOL
|
|
|| a->property->type == PROP_INT ) {
|
|
if( a->property->data == b->property->data )
|
|
retval = 0;
|
|
else
|
|
retval = -1;
|
|
} else if( a->property->type == PROP_FLOAT
|
|
|| a->property->type == PROP_TIME ) {
|
|
if( *( ( float * ) &a->property->data ) ==
|
|
*( ( float * ) &b->property->data ) )
|
|
retval = 0;
|
|
else
|
|
retval = -1;
|
|
} else if( a->property->type == PROP_STRING ) {
|
|
if( BLI_streq
|
|
( a->property->poin, b->property->poin ) )
|
|
retval = 0;
|
|
else
|
|
retval = -1;
|
|
}
|
|
} else
|
|
retval = -1;
|
|
} else { //1 real 1 python
|
|
if( !a->property ) {
|
|
py_propA = a;
|
|
py_propB = b;
|
|
} else {
|
|
py_propA = b;
|
|
py_propB = a;
|
|
}
|
|
if( py_propB->property->type != py_propA->type )
|
|
retval = -1;
|
|
if( BLI_streq( py_propB->property->name, py_propA->name ) ) {
|
|
if( py_propB->property->type == PROP_BOOL ||
|
|
py_propB->property->type == PROP_INT ) {
|
|
retval = PyObject_Compare( py_propA->data,
|
|
PyInt_FromLong
|
|
( py_propB->
|
|
property->
|
|
data ) );
|
|
} else if( py_propB->property->type == PROP_FLOAT
|
|
|| py_propB->property->type == PROP_TIME ) {
|
|
retval = PyObject_Compare( py_propA->data,
|
|
PyFloat_FromDouble
|
|
( *
|
|
( ( float * )
|
|
&py_propB->
|
|
property->
|
|
data ) ) );
|
|
} else if( py_propB->property->type == PROP_STRING ) {
|
|
retval = PyObject_Compare( py_propA->data,
|
|
PyString_FromString
|
|
( py_propB->
|
|
property->
|
|
poin ) );
|
|
}
|
|
} else
|
|
retval = -1;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
//--------------- Property visible functions------------------------
|
|
//--------------- Property_CreatePyObject---------------------------
|
|
PyObject *Property_CreatePyObject( struct bProperty * Property )
|
|
{
|
|
BPy_Property *py_property;
|
|
|
|
py_property =
|
|
( BPy_Property * ) PyObject_NEW( BPy_Property,
|
|
&property_Type );
|
|
|
|
//set the struct flag
|
|
py_property->property = Property;
|
|
|
|
//allocate space for python vars
|
|
py_property->name = PyMem_Malloc( 32 );
|
|
|
|
if( !updatePyProperty( py_property ) )
|
|
return ( EXPP_ReturnPyObjError
|
|
( PyExc_AttributeError, "Property struct empty" ) );
|
|
|
|
return ( ( PyObject * ) py_property );
|
|
}
|
|
|
|
//--------------- Property_CheckPyObject----------------------------
|
|
int Property_CheckPyObject( PyObject * py_obj )
|
|
{
|
|
return ( py_obj->ob_type == &property_Type );
|
|
}
|
|
|
|
//--------------- Property_FromPyObject-----------------------------
|
|
struct bProperty *Property_FromPyObject( PyObject * py_obj )
|
|
{
|
|
BPy_Property *py_property;
|
|
|
|
py_property = ( BPy_Property * ) py_obj;
|
|
if( !py_property->property )
|
|
return NULL;
|
|
else
|
|
return ( py_property->property );
|
|
}
|
|
|
|
//--------------- newPropertyObject()-------------------------------
|
|
PyObject *newPropertyObject( char *name, PyObject * data, int type )
|
|
{
|
|
BPy_Property *py_property;
|
|
|
|
py_property =
|
|
( BPy_Property * ) PyObject_NEW( BPy_Property,
|
|
&property_Type );
|
|
py_property->name = PyMem_Malloc( 32 );
|
|
py_property->property = NULL;
|
|
|
|
BLI_strncpy( py_property->name, name, 32 );
|
|
py_property->data = data;
|
|
py_property->type = (short)type;
|
|
|
|
return ( PyObject * ) py_property;
|
|
}
|
|
|
|
//--------------- Python BPy_Property methods-----------------------
|
|
//--------------- BPy_Property.getName()----------------------------
|
|
static PyObject *Property_getName( BPy_Property * self )
|
|
{
|
|
PyObject *attr = NULL;
|
|
|
|
if( !self->property )
|
|
attr = PyString_FromString( self->name );
|
|
else
|
|
attr = PyString_FromString( self->property->name );
|
|
|
|
if( attr )
|
|
return attr;
|
|
|
|
return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
|
"couldn't get Property.name attribute" ) );
|
|
}
|
|
|
|
//--------------- BPy_Property.setName()----------------------------
|
|
static PyObject *Property_setName( BPy_Property * self, PyObject * args )
|
|
{
|
|
char *name;
|
|
|
|
if( !PyArg_ParseTuple( args, "s", &name ) )
|
|
return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"expected string argument" ) );
|
|
|
|
if( !self->property ) {
|
|
BLI_strncpy( self->name, name, 32 );
|
|
} else {
|
|
BLI_strncpy( self->property->name, name, 32 );
|
|
updatePyProperty( self );
|
|
}
|
|
|
|
return EXPP_incr_ret( Py_None );
|
|
}
|
|
|
|
//--------------- BPy_Property.getData()----------------------------
|
|
static PyObject *Property_getData( BPy_Property * self )
|
|
{
|
|
PyObject *attr = NULL;
|
|
|
|
if( !self->property ) {
|
|
attr = EXPP_incr_ret( self->data );
|
|
} else {
|
|
if( self->property->type == PROP_BOOL ) {
|
|
if( self->property->data )
|
|
attr = EXPP_incr_ret_True();
|
|
else
|
|
attr = EXPP_incr_ret_False();
|
|
} else if( self->property->type == PROP_INT ) {
|
|
attr = PyInt_FromLong( self->property->data );
|
|
} else if( self->property->type == PROP_FLOAT ||
|
|
self->property->type == PROP_TIME ) {
|
|
attr = PyFloat_FromDouble( *
|
|
( ( float * ) &self->
|
|
property->data ) );
|
|
} else if( self->property->type == PROP_STRING ) {
|
|
attr = PyString_FromString( self->property->poin );
|
|
}
|
|
}
|
|
if( attr )
|
|
return attr;
|
|
|
|
return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
|
"couldn't get Property.name attribute" ) );
|
|
}
|
|
|
|
//--------------- BPy_Property.setData()----------------------------
|
|
static PyObject *Property_setData( BPy_Property * self, PyObject * args )
|
|
{
|
|
PyObject *data;
|
|
char *type_str = NULL;
|
|
int type = -1;
|
|
short *p_type = NULL;
|
|
|
|
if( !PyArg_ParseTuple( args, "O|s", &data, &type_str ) )
|
|
return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"expected object and optional string argument" ) );
|
|
|
|
if( !PyInt_Check( data ) && !PyFloat_Check( data )
|
|
&& !PyString_Check( data ) )
|
|
return ( EXPP_ReturnPyObjError
|
|
( PyExc_RuntimeError,
|
|
"float, int, or string expected as data" ) );
|
|
|
|
//parse property name
|
|
if( type_str ) {
|
|
if( BLI_streq( type_str, "BOOL" ) )
|
|
type = PROP_BOOL;
|
|
else if( BLI_streq( type_str, "INT" ) )
|
|
type = PROP_INT;
|
|
else if( BLI_streq( type_str, "FLOAT" ) )
|
|
type = PROP_FLOAT;
|
|
else if( BLI_streq( type_str, "TIME" ) )
|
|
type = PROP_TIME;
|
|
else if( BLI_streq( type_str, "STRING" ) )
|
|
type = PROP_STRING;
|
|
else
|
|
return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
|
"BOOL, INT, FLOAT, TIME or STRING expected" ) );
|
|
}
|
|
//get pointer to type
|
|
if( self->property )
|
|
p_type = &self->property->type;
|
|
else
|
|
p_type = &self->type;
|
|
|
|
//set the type
|
|
if( PyInt_Check( data ) ) {
|
|
if( type == -1 || type == PROP_INT )
|
|
*p_type = PROP_INT;
|
|
else
|
|
*p_type = PROP_BOOL;
|
|
} else if( PyFloat_Check( data ) ) {
|
|
if( type == -1 || type == PROP_FLOAT )
|
|
*p_type = PROP_FLOAT;
|
|
else
|
|
*p_type = PROP_TIME;
|
|
} else if( PyString_Check( data ) ) {
|
|
if( type == -1 || type == PROP_STRING )
|
|
*p_type = PROP_STRING;
|
|
} else {
|
|
return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
|
"cant set unknown data type" ) );
|
|
}
|
|
|
|
//set the data
|
|
if( self->property ) {
|
|
if( PyInt_Check( data ) ) {
|
|
*( ( int * ) &self->property->data ) =
|
|
( int ) PyInt_AsLong( data );
|
|
} else if( PyFloat_Check( data ) ) {
|
|
*( ( float * ) &self->property->data ) =
|
|
( float ) PyFloat_AsDouble( data );
|
|
} else if( PyString_Check( data ) ) {
|
|
BLI_strncpy( self->property->poin,
|
|
PyString_AsString( data ),
|
|
MAX_PROPSTRING );
|
|
}
|
|
updatePyProperty( self );
|
|
} else {
|
|
self->data = data;
|
|
}
|
|
return EXPP_incr_ret( Py_None );
|
|
}
|
|
|
|
//--------------- BPy_Property.getType()----------------------------
|
|
static PyObject *Property_getType( BPy_Property * self )
|
|
{
|
|
PyObject *attr = Py_None;
|
|
int type;
|
|
|
|
if( self->property )
|
|
type = self->property->type;
|
|
else
|
|
type = self->type;
|
|
|
|
if( type == PROP_BOOL )
|
|
attr = PyString_FromString( "BOOL" );
|
|
else if( type == PROP_INT )
|
|
attr = PyString_FromString( "INT" );
|
|
else if( type == PROP_FLOAT )
|
|
attr = PyString_FromString( "FLOAT" );
|
|
else if( type == PROP_STRING )
|
|
attr = PyString_FromString( "STRING" );
|
|
else if( type == PROP_TIME )
|
|
attr = PyString_FromString( "TIME" );
|
|
|
|
return attr;
|
|
}
|