Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/bad_level_call_stubs/stubs.c11
-rw-r--r--source/blender/blenkernel/intern/constraint.c88
-rw-r--r--source/blender/blenkernel/intern/idprop.c1
-rw-r--r--source/blender/blenloader/intern/readfile.c21
-rw-r--r--source/blender/blenloader/intern/writefile.c10
-rw-r--r--source/blender/include/BIF_editconstraint.h7
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h20
-rw-r--r--source/blender/python/BPY_extern.h7
-rw-r--r--source/blender/python/BPY_interface.c388
-rw-r--r--source/blender/python/api2_2x/Constraint.c2
-rw-r--r--source/blender/src/buttons_object.c75
-rw-r--r--source/blender/src/editconstraint.c137
-rw-r--r--source/blender/src/header_text.c132
13 files changed, 862 insertions, 37 deletions
diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c
index 344f763608c..e76c53fc72c 100644
--- a/source/blender/blenkernel/bad_level_call_stubs/stubs.c
+++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c
@@ -54,6 +54,7 @@ struct IpoCurve;
struct FluidsimSettings;
struct Render;
struct RenderResult;
+struct bPythonConstraint;
char *getIpoCurveName( struct IpoCurve * icu );
void insert_vert_ipo(struct IpoCurve *icu, float x, float y);
@@ -124,6 +125,16 @@ int BPY_button_eval(char *expr, double *value)
return 0;
}
+/* constraint.c */
+void BPY_pyconstraint_eval(struct bPythonConstraint *con, float obmat[][4], short ownertype, void *ownerdata, float targetmat[][4])
+{
+}
+int BPY_pyconstraint_targets(struct bPythonConstraint *con, float targetmat[][4])
+{
+ return 0;
+}
+
+
/* writefile.c */
/* struct Oops; */
void free_oops(struct Oops *oops){}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 97f5ed18cbe..9c03db824af 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -58,6 +58,9 @@
#include "BKE_ipo.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_idprop.h"
+
+#include "BPY_extern.h"
#include "blendef.h"
@@ -80,6 +83,15 @@ void free_constraint_data (bConstraint *con)
{
if (con->data) {
/* any constraint-type specific stuff here */
+ switch (con->type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data= con->data;
+ IDP_FreeProperty(data->prop);
+ MEM_freeN(data->prop);
+ }
+ break;
+ }
MEM_freeN(con->data);
}
@@ -117,6 +129,14 @@ void relink_constraints (struct ListBase *list)
for (con = list->first; con; con=con->next) {
switch (con->type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data;
+ data = con->data;
+
+ ID_NEW(data->tar);
+ }
+ break;
case CONSTRAINT_TYPE_KINEMATIC:
{
bKinematicConstraint *data;
@@ -260,6 +280,13 @@ void copy_constraints (ListBase *dst, ListBase *src)
char constraint_has_target (bConstraint *con)
{
switch (con->type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = con->data;
+ if (data->tar)
+ return 1;
+ }
+ break;
case CONSTRAINT_TYPE_TRACKTO:
{
bTrackToConstraint *data = con->data;
@@ -354,6 +381,13 @@ Object *get_constraint_target(bConstraint *con, char **subtarget)
* to the name for this constraints subtarget ... NULL otherwise
*/
switch (con->type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data=con->data;
+ *subtarget = data->subtarget;
+ return data->tar;
+ }
+ break;
case CONSTRAINT_TYPE_ACTION:
{
bActionConstraint *data = con->data;
@@ -450,6 +484,14 @@ void set_constraint_target(bConstraint *con, Object *ob, char *subtarget)
{
/* Set the target for this constraint */
switch (con->type) {
+
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = con->data;
+ data->tar= ob;
+ if(subtarget) BLI_strncpy(data->subtarget, subtarget, 32);
+ }
+ break;
case CONSTRAINT_TYPE_ACTION:
{
bActionConstraint *data = con->data;
@@ -590,6 +632,18 @@ void *new_constraint_data (short type)
void *result;
switch (type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data;
+ data = MEM_callocN(sizeof(bPythonConstraint), "pythonConstraint");
+
+ /* everything should be set correctly by calloc, except for the prop->type constant.*/
+ data->prop = MEM_callocN(sizeof(IDProperty), "PyConstraintProps");
+ data->prop->type = IDP_GROUP;
+
+ result = data;
+ }
+ break;
case CONSTRAINT_TYPE_KINEMATIC:
{
bKinematicConstraint *data;
@@ -1272,6 +1326,31 @@ short get_constraint_target_matrix (bConstraint *con, short ownertype, void* own
Mat4One (mat);
}
break;
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data;
+ data = (bPythonConstraint*)con->data;
+
+ /* special exception for curves - depsgraph issues */
+ if (data->tar && data->tar->type == OB_CURVE) {
+ Curve *cu= data->tar->data;
+
+ /* this check is to make sure curve objects get updated on file load correctly.*/
+ if(cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */
+ makeDispListCurveTypes(data->tar, 0);
+ }
+
+ /* if the script doesn't set the target matrix for any reason, fall back to standard methods */
+ if (BPY_pyconstraint_targets(data, mat) < 1) {
+ if (data->tar) {
+ constraint_target_to_mat4(data->tar, data->subtarget, mat, size);
+ valid = 1;
+ }
+ else
+ Mat4One (mat);
+ }
+ }
+ break;
case CONSTRAINT_TYPE_CLAMPTO:
{
bClampToConstraint *data;
@@ -1316,7 +1395,14 @@ void evaluate_constraint (bConstraint *constraint, Object *ob, short ownertype,
case CONSTRAINT_TYPE_NULL:
case CONSTRAINT_TYPE_KINEMATIC: /* removed */
break;
-
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data;
+
+ data= constraint->data;
+ BPY_pyconstraint_eval(data, ob->obmat, ownertype, ownerdata, targetmat);
+ }
+ break;
case CONSTRAINT_TYPE_ACTION:
{
bActionConstraint *data;
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 4ff4073fdbe..bb4c66da0b1 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -274,6 +274,7 @@ void IDP_FreeGroup(IDProperty *prop)
for (loop=prop->data.group.first; loop; loop=next)
{
next = loop->next;
+ BLI_remlink(&prop->data.group, loop);
IDP_FreeProperty(loop);
MEM_freeN(loop);
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 10f9be743ea..7cfef325f63 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -1611,6 +1611,15 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist)
}
switch (con->type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data;
+ data= (bPythonConstraint*)con->data;
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ data->text = newlibadr(fd, id->lib, data->text);
+ //IDP_LibLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+ break;
case CONSTRAINT_TYPE_ACTION:
{
bActionConstraint *data;
@@ -1717,6 +1726,11 @@ static void direct_link_constraints(FileData *fd, ListBase *lb)
link_list(fd, lb);
for (cons=lb->first; cons; cons=cons->next) {
cons->data = newdataadr(fd, cons->data);
+ if (cons->type == CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data= cons->data;
+ data->prop = newdataadr(fd, data->prop);
+ IDP_DirectLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
}
}
@@ -6885,6 +6899,13 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb)
for (curcon=lb->first; curcon; curcon=curcon->next) {
switch (curcon->type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = (bPythonConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ expand_doit(fd, mainvar, data->text);
+ break;
+ }
case CONSTRAINT_TYPE_ACTION:
{
bActionConstraint *data = (bActionConstraint*)curcon->data;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 226561ab97b..2ac3063f248 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -702,6 +702,16 @@ static void write_constraints(WriteData *wd, ListBase *conlist)
switch (con->type) {
case CONSTRAINT_TYPE_NULL:
break;
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = (bPythonConstraint*) con->data;
+ writestruct(wd, DATA, "bPythonConstraint", 1, data);
+
+ /*Write ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ IDP_WriteProperty(data->prop, wd);
+ }
+ break;
case CONSTRAINT_TYPE_TRACKTO:
writestruct(wd, DATA, "bTrackToConstraint", 1, con->data);
break;
diff --git a/source/blender/include/BIF_editconstraint.h b/source/blender/include/BIF_editconstraint.h
index db55bc5c7d7..68327bdd684 100644
--- a/source/blender/include/BIF_editconstraint.h
+++ b/source/blender/include/BIF_editconstraint.h
@@ -38,6 +38,9 @@ struct ListBase;
struct Object;
struct bConstraint;
struct bConstraintChannel;
+struct Text;
+
+/* generic constraint editing functions */
struct bConstraint *add_new_constraint(short type);
@@ -58,5 +61,9 @@ char *get_con_subtarget_name(struct bConstraint *con, struct Object *target);
void rename_constraint(struct Object *ob, struct bConstraint *con, char *newname);
+/* two special functions for PyConstraints */
+char *buildmenu_pyconstraints(struct Text *con_text, int *pyconindex);
+void validate_pyconstraint_cb(void *arg1, void *arg2);
+
#endif
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 74307454187..3179d1035ff 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -39,6 +39,10 @@
#include "DNA_object_types.h"
struct Action;
+struct Text;
+#ifndef __cplusplus
+struct PyObject;
+#endif
/* channels reside in Object or Action (ListBase) constraintChannels */
typedef struct bConstraintChannel{
@@ -59,6 +63,18 @@ typedef struct bConstraint{
float enforce;
} bConstraint;
+/* Python Script Constraint */
+typedef struct bPythonConstraint {
+ Object *tar; /* object to use as target (if required) */
+ char subtarget[32]; /* bone to use as subtarget (if required) */
+
+ struct Text *text; /* text-buffer (containing script) to execute */
+ IDProperty *prop; /* 'id-properties' used to store custom properties for constraint */
+
+ int flag; /* general settings/state indicators accessed by bitmapping */
+ int pad;
+} bPythonConstraint;
+
/* Single-target subobject constraints */
typedef struct bKinematicConstraint{
Object *tar;
@@ -350,6 +366,10 @@ typedef struct bClampToConstraint {
#define LIMIT_NOPARENT 0x01
+/* python constraint -> flag */
+#define PYCON_USETARGETS 0x01
+#define PYCON_SCRIPTERROR 0x02
+
#define CONSTRAINT_DRAW_PIVOT 0x40
/* important: these defines need to match up with PHY_DynamicTypes headerfile */
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index d7db680a458..34271efc4f1 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -46,11 +46,16 @@ struct SpaceScript; /* DNA_space_types.h */
struct Script; /* BPI_script.h */
struct ScrArea; /* DNA_screen_types.h */
struct bScreen; /* DNA_screen_types.h */
-
+struct bPythonConstraint; /* DNA_constraint_types.h */
#ifdef __cplusplus
extern "C" {
#endif
+ void BPY_pyconstraint_eval(struct bPythonConstraint *con, float obmat[][4], short ownertype, void *ownerdata, float targetmat[][4]);
+ void BPY_pyconstraint_settings(void *arg1, void *arg2);
+ int BPY_pyconstraint_targets(struct bPythonConstraint *con, float targetmat[][4]);
+ int BPY_is_pyconstraint(struct Text *text);
+
void BPY_start_python( int argc, char **argv );
void BPY_end_python( void );
void BPY_post_start_python( void );
diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c
index f8a3c269292..6ee06c64cc7 100644
--- a/source/blender/python/BPY_interface.c
+++ b/source/blender/python/BPY_interface.c
@@ -40,6 +40,7 @@
#include "BIF_space.h"
#include "BIF_screen.h"
#include "BIF_toolbox.h"
+#include "BKE_action.h" /* for get_pose_channel() */
#include "BKE_library.h"
#include "BKE_object.h" /* during_scriptlink() */
#include "BKE_text.h"
@@ -47,6 +48,7 @@
#include "DNA_curve_types.h" /* for struct IpoDriver */
#include "DNA_ID.h" /* ipo driver */
#include "DNA_object_types.h" /* ipo driver */
+#include "DNA_constraint_types.h" /* for pyconstraint */
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h" /* for U.pythondir */
@@ -66,8 +68,13 @@
#include "api2_2x/Draw.h"
#include "api2_2x/Object.h"
#include "api2_2x/Registry.h"
+#include "api2_2x/Pose.h"
#include "api2_2x/bpy.h" /* for the new "bpy" module */
+/*these next two are for pyconstraints*/
+#include "api2_2x/IDProp.h"
+#include "api2_2x/matrix.h"
+
/* for scriptlinks */
#include "DNA_lamp_types.h"
#include "DNA_camera_types.h"
@@ -86,7 +93,6 @@
/* for pydrivers (ipo drivers defined by one-line Python expressions) */
PyObject *bpy_pydriver_Dict = NULL;
-
/*
* set up a weakref list for Armatures
* creates list in __main__ module dict
@@ -160,6 +166,7 @@ PyObject *importText( char *name );
void init_ourImport( void );
void init_ourReload( void );
PyObject *blender_import( PyObject * self, PyObject * args );
+PyObject *RunPython2( Text * text, PyObject * globaldict, PyObject *localdict );
void BPY_Err_Handle( char *script_name );
@@ -462,10 +469,11 @@ void BPY_Err_Handle( char *script_name )
PyErr_Fetch( &exception, &err, &tb );
- if( !exception && !tb ) {
- printf( "FATAL: spurious exception\n" );
- return;
- }
+ if (!script_name) script_name = "untitled";
+ //if( !exception && !tb ) {
+ // printf( "FATAL: spurious exception\n" );
+ // return;
+ //}
strcpy( g_script_error.filename, script_name );
@@ -1138,6 +1146,376 @@ static float pydriver_error(IpoDriver *driver) {
return 0.0f;
}
+
+/********PyConstraints*********/
+
+int BPY_is_pyconstraint(Text *text)
+{
+ TextLine *tline = text->lines.first;
+
+ if (tline && (tline->len > 10)) {
+ char *line = tline->line;
+
+ /* Expected format: #BPYCONSTRAINT
+ * The actual checks are forgiving, so slight variations also work. */
+ if (line && line[0] == '#' && strstr(line, "BPYCONSTRAINT")) return 1;
+ }
+ return 0;
+}
+
+/* This evals py constraints. It is passed all the arguments the normal constraints recieve */
+void BPY_pyconstraint_eval(bPythonConstraint *con, float obmat[][4], short ownertype, void *ownerdata, float targetmat[][4])
+{
+ PyObject *srcmat, *tarmat, *idprop;
+ PyObject *globals;
+ PyObject *gval;
+ PyObject *pyargs, *retval;
+ MatrixObject *retmat;
+ int row, col;
+
+ if ( !con->text ) return;
+ if ( con->flag & PYCON_SCRIPTERROR) return;
+
+ globals = CreateGlobalDictionary();
+
+ srcmat = newMatrixObject( (float*)obmat, 4, 4, Py_NEW );
+ tarmat = newMatrixObject( (float*)targetmat, 4, 4, Py_NEW );
+ idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL);
+
+/* since I can't remember what the armature weakrefs do, I'll just leave this here
+ commented out. This function was based on pydrivers, and it might still be relevent.
+ if( !setup_armature_weakrefs()){
+ fprintf( stderr, "Oops - weakref dict setup\n");
+ return result;
+ }
+*/
+ retval = RunPython( con->text, globals );
+
+ if ( retval == NULL ) {
+ BPY_Err_Handle(con->text->id.name);
+ ReleaseGlobalDictionary( globals );
+ con->flag |= PYCON_SCRIPTERROR;
+
+ /* free temp objects */
+ Py_XDECREF( idprop );
+ Py_XDECREF( srcmat );
+ Py_XDECREF( tarmat );
+ return;
+ }
+
+ if (retval) {Py_XDECREF( retval );}
+ retval = NULL;
+
+ gval = PyDict_GetItemString(globals, "doConstraint");
+ if (!gval) {
+ ReleaseGlobalDictionary( globals );
+
+ /* free temp objects */
+ Py_XDECREF( idprop );
+ Py_XDECREF( srcmat );
+ Py_XDECREF( tarmat );
+ printf("ERROR: no doConstraint function in constraint!\n");
+ return;
+ }
+
+ /* Now for the fun part! Try and find the functions we need. */
+ if (PyFunction_Check(gval) ) {
+ pyargs = Py_BuildValue("OOO", srcmat, tarmat, idprop);
+ retval = PyObject_CallObject(gval, pyargs);
+ Py_XDECREF( pyargs );
+ } else {
+ printf("ERROR: doConstraint is supposed to be a function!\n");
+ con->flag |= PYCON_SCRIPTERROR;
+ ReleaseGlobalDictionary( globals );
+
+ Py_XDECREF( idprop );
+ Py_XDECREF( srcmat );
+ Py_XDECREF( tarmat );
+ return;
+ }
+
+ if (!retval) {
+ BPY_Err_Handle(con->text->id.name);
+ con->flag |= PYCON_SCRIPTERROR;
+
+ /* free temp objects */
+ ReleaseGlobalDictionary( globals );
+
+ Py_XDECREF( idprop );
+ Py_XDECREF( srcmat );
+ Py_XDECREF( tarmat );
+ return;
+ }
+
+
+ if (!PyObject_TypeCheck(retval, &matrix_Type)) {
+ printf("Error in PyConstraint - doConstraint: Function not returning a matrix!\n");
+ con->flag |= PYCON_SCRIPTERROR;
+ ReleaseGlobalDictionary( globals );
+
+ Py_XDECREF( idprop );
+ Py_XDECREF( srcmat );
+ Py_XDECREF( tarmat );
+ Py_XDECREF( retval );
+ return;
+ }
+
+ retmat = (MatrixObject*) retval;
+ if (retmat->rowSize != 4 || retmat->colSize != 4) {
+ printf("Error in PyConstraint - doConstraint: Matrix returned is the wrong size!\n");
+ con->flag |= PYCON_SCRIPTERROR;
+ ReleaseGlobalDictionary( globals );
+
+ Py_XDECREF( idprop );
+ Py_XDECREF( srcmat );
+ Py_XDECREF( tarmat );
+ Py_XDECREF( retval );
+ return;
+ }
+
+ /* this is the reverse of code taken from newMatrix() */
+ for(row = 0; row < 4; row++) {
+ for(col = 0; col < 4; col++) {
+ obmat[row][col] = retmat->contigPtr[row*4+col];
+ }
+ }
+
+ /* clear globals */
+ ReleaseGlobalDictionary( globals );
+
+ /* free temp objects */
+ Py_XDECREF( idprop );
+ Py_XDECREF( srcmat );
+ Py_XDECREF( tarmat );
+ Py_XDECREF( retval );
+}
+
+/* This evaluates whether constraint uses targets, and also the target matrix
+ * Return code of 0 = doesn't use targets, 1 = uses targets + matrix set, -1 = uses targets + matrix not set
+ */
+int BPY_pyconstraint_targets(bPythonConstraint *con, float targetmat[][4])
+{
+ PyObject *tar, *subtar;
+ PyObject *tarmat, *idprop;
+ PyObject *globals;
+ PyObject *gval, *gval2;
+ PyObject *pyargs, *retval;
+ MatrixObject *retmat;
+ bPoseChannel *pchan;
+ int row, col;
+
+ if ( !con->text ) return 0;
+ if ( con->flag & PYCON_SCRIPTERROR) return 0;
+
+ globals = CreateGlobalDictionary();
+
+ tar = Object_CreatePyObject( con->tar );
+ if ( con->tar )
+ pchan = get_pose_channel( con->tar->pose, con->subtarget );
+ else
+ pchan = NULL;
+ subtar = PyPoseBone_FromPosechannel( pchan );
+
+ tarmat = newMatrixObject( (float*)targetmat, 4, 4, Py_NEW );
+ idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL);
+
+/* since I can't remember what the armature weakrefs do, I'll just leave this here
+ commented out. This function was based on pydrivers, and it might still be relevent.
+ if( !setup_armature_weakrefs()){
+ fprintf( stderr, "Oops - weakref dict setup\n");
+ return result;
+ }
+*/
+ retval = RunPython( con->text, globals );
+
+ if ( retval == NULL ) {
+ BPY_Err_Handle(con->text->id.name);
+ ReleaseGlobalDictionary( globals );
+ con->flag |= PYCON_SCRIPTERROR;
+
+ /* free temp objects */
+ Py_XDECREF( tar );
+ Py_XDECREF( subtar );
+ Py_XDECREF( idprop );
+ Py_XDECREF( tarmat );
+ return 0;
+ }
+
+ if (retval) {Py_XDECREF( retval );}
+ retval = NULL;
+
+ /* try to find USE_TARGET global constant */
+ gval = PyDict_GetItemString(globals, "USE_TARGET");
+ if (!gval) {
+ ReleaseGlobalDictionary( globals );
+
+ /* free temp objects */
+ Py_XDECREF( tar );
+ Py_XDECREF( subtar );
+ Py_XDECREF( idprop );
+ Py_XDECREF( tarmat );
+ return 0;
+ }
+
+ /* try to find doTarget function to set the target matrix */
+ gval2 = PyDict_GetItemString(globals, "doTarget");
+ if (!gval2) {
+ ReleaseGlobalDictionary( globals );
+
+ /* free temp objects */
+ Py_XDECREF( tar );
+ Py_XDECREF( subtar );
+ Py_XDECREF( idprop );
+ Py_XDECREF( tarmat );
+ return -1;
+ }
+
+ /* Now for the fun part! Try and find the functions we need.*/
+ if (PyFunction_Check(gval2) ) {
+ pyargs = Py_BuildValue("OOOO", tar, subtar, tarmat, idprop);
+ retval = PyObject_CallObject(gval2, pyargs);
+ Py_XDECREF( pyargs );
+ } else {
+ printf("ERROR: doTarget is supposed to be a function!\n");
+ con->flag |= PYCON_SCRIPTERROR;
+ ReleaseGlobalDictionary( globals );
+
+ Py_XDECREF( tar );
+ Py_XDECREF( subtar );
+ Py_XDECREF( idprop );
+ Py_XDECREF( tarmat );
+ return -1;
+ }
+
+ if (!retval) {
+ BPY_Err_Handle(con->text->id.name);
+ con->flag |= PYCON_SCRIPTERROR;
+
+ /* free temp objects */
+ ReleaseGlobalDictionary( globals );
+
+ Py_XDECREF( tar );
+ Py_XDECREF( subtar );
+ Py_XDECREF( idprop );
+ Py_XDECREF( tarmat );
+ return -1;
+ }
+
+ if (!PyObject_TypeCheck(retval, &matrix_Type)) {
+ ReleaseGlobalDictionary( globals );
+
+ Py_XDECREF( tar );
+ Py_XDECREF( subtar );
+ Py_XDECREF( idprop );
+ Py_XDECREF( tarmat );
+ Py_XDECREF( retval );
+ return -1;
+ }
+
+ retmat = (MatrixObject*) retval;
+ if (retmat->rowSize != 4 || retmat->colSize != 4) {
+ printf("Error in PyConstraint - doTarget: Matrix returned is the wrong size!\n");
+ con->flag |= PYCON_SCRIPTERROR;
+ ReleaseGlobalDictionary( globals );
+
+ Py_XDECREF( tar );
+ Py_XDECREF( subtar );
+ Py_XDECREF( idprop );
+ Py_XDECREF( tarmat );
+ Py_XDECREF( retval );
+ return -1;
+ }
+
+ /* this is the reverse of code taken from newMatrix() */
+ for(row = 0; row < 4; row++) {
+ for(col = 0; col < 4; col++) {
+ targetmat[row][col] = retmat->contigPtr[row*4+col];
+ }
+ }
+
+ /* clear globals */
+ ReleaseGlobalDictionary( globals );
+
+ /* free temp objects */
+ Py_XDECREF( tar );
+ Py_XDECREF( subtar );
+ Py_XDECREF( idprop );
+ Py_XDECREF( tarmat );
+ Py_XDECREF( retval );
+ return 1;
+}
+
+/* This draws+handles the user-defined interface for editing pyconstraints idprops */
+void BPY_pyconstraint_settings(void *arg1, void *arg2)
+{
+ bPythonConstraint *con= (bPythonConstraint *)arg1;
+ PyObject *idprop;
+ PyObject *globals;
+ PyObject *gval;
+ PyObject *retval;
+
+ if ( !con->text ) return;
+ if ( con->flag & PYCON_SCRIPTERROR) return;
+
+ globals = CreateGlobalDictionary();
+
+ idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL);
+
+ retval = RunPython( con->text, globals );
+
+ if ( retval == NULL ) {
+ BPY_Err_Handle(con->text->id.name);
+ ReleaseGlobalDictionary( globals );
+ con->flag |= PYCON_SCRIPTERROR;
+
+ /* free temp objects */
+ Py_XDECREF( idprop );
+ return;
+ }
+
+ if (retval) {Py_XDECREF( retval );}
+ retval = NULL;
+
+ gval = PyDict_GetItemString(globals, "getSettings");
+ if (!gval) {
+ printf("ERROR: no getSettings function in constraint!");
+
+ /* free temp objects */
+ ReleaseGlobalDictionary( globals );
+ Py_XDECREF( idprop );
+ return;
+ }
+
+ /* Now for the fun part! Try and find the functions we need. */
+ if (PyFunction_Check(gval) ) {
+ retval = PyObject_CallFunction(gval, "O", idprop);
+ } else {
+ printf("ERROR: getSettings is supposed to be a function!\n");
+ ReleaseGlobalDictionary( globals );
+
+ Py_XDECREF( idprop );
+ return;
+ }
+
+ if (!retval) {
+ BPY_Err_Handle(con->text->id.name);
+ con->flag |= PYCON_SCRIPTERROR;
+
+ /* free temp objects */
+ ReleaseGlobalDictionary( globals );
+ Py_XDECREF( idprop );
+ return;
+ }
+ else {
+ /* clear globals */
+ ReleaseGlobalDictionary( globals );
+
+ /* free temp objects */
+ Py_XDECREF( idprop );
+ return;
+ }
+}
+
/* Update function, it gets rid of pydrivers global dictionary, forcing
* BPY_pydriver_eval to recreate it. This function is used to force
* reloading the Blender text module "pydrivers.py", if available, so
diff --git a/source/blender/python/api2_2x/Constraint.c b/source/blender/python/api2_2x/Constraint.c
index 55e7e480d6b..71dbef5f2d5 100644
--- a/source/blender/python/api2_2x/Constraint.c
+++ b/source/blender/python/api2_2x/Constraint.c
@@ -1918,6 +1918,8 @@ static PyObject *M_Constraint_TypeDict( void )
PyInt_FromLong( CONSTRAINT_TYPE_RIGIDBODYJOINT ) );
PyConstant_Insert( d, "CLAMPTO",
PyInt_FromLong( CONSTRAINT_TYPE_CLAMPTO ) );
+ PyConstant_Insert( d, "PYTHON",
+ PyInt_FromLong( CONSTRAINT_TYPE_PYTHON ) );
}
return S;
}
diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c
index bb5ac2ba682..7d2c5dd5f00 100644
--- a/source/blender/src/buttons_object.c
+++ b/source/blender/src/buttons_object.c
@@ -109,6 +109,7 @@
#include "DNA_vfont_types.h"
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
+#include "DNA_text_types.h"
#include "BKE_anim.h"
#include "BKE_armature.h"
@@ -143,6 +144,7 @@
#include "BSE_edit.h"
#include "BDR_editobject.h"
+#include "BPY_extern.h"
#include "butspace.h" // own module
@@ -328,6 +330,9 @@ void get_constraint_typestring (char *str, void *con_v)
bConstraint *con= con_v;
switch (con->type){
+ case CONSTRAINT_TYPE_PYTHON:
+ strcpy(str, "Script");
+ return;
case CONSTRAINT_TYPE_CHILDOF:
strcpy (str, "Child Of");
return;
@@ -508,6 +513,7 @@ void autocomplete_vgroup(char *str, void *arg_v)
}
}
+/* draw panel showing settings for a constraint */
static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, short *xco, short *yco)
{
Object *ob= OBACT, *target;
@@ -599,10 +605,60 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
}
else {
switch (con->type){
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = con->data;
+ uiBut *but2;
+ static int pyconindex=0;
+ char *menustr;
+
+ height = 90;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40, height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Script:", *xco+60, *yco-24, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* do the scripts menu */
+ menustr = buildmenu_pyconstraints(data->text, &pyconindex);
+ but2 = uiDefButI(block, MENU, B_CONSTRAINT_TEST, menustr,
+ *xco+120, *yco-24, 150, 20, &pyconindex,
+ 0.0, 1.0, 0, 0, "Set the Script Constraint to use");
+ uiButSetFunc(but2, validate_pyconstraint_cb, data, &pyconindex);
+ MEM_freeN(menustr);
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+60, *yco-48, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ if (data->flag & PYCON_USETARGETS) {
+ /* Draw target parameters */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-48, 150, 18, &data->tar, "Target Object");
+
+ if (is_armature_target) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-66,150,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+ }
+ else {
+ strcpy (data->subtarget, "");
+ }
+
+ uiBlockEndAlign(block);
+ }
+ else {
+ /* Draw indication that no target needed */
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Not Applicable", *xco+120, *yco-48, 150, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ }
+
+ /* settings */
+ uiBlockBeginAlign(block);
+ but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Options", *xco, *yco-88, (width/2),18, NULL, 0, 24, 0, 0, "Change some of the constraint's settings.");
+ uiButSetFunc(but, BPY_pyconstraint_settings, data, NULL);
+
+ uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Refresh", *xco+((width/2)+10), *yco-88, (width/2),18, NULL, 0, 24, 0, 0, "Force constraint to refresh it's settings");
+ uiBlockEndAlign(block);
+ }
+ break;
case CONSTRAINT_TYPE_ACTION:
{
bActionConstraint *data = con->data;
-
+
height = 88;
uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
@@ -1336,8 +1392,13 @@ static uiBlock *add_constraintmenu(void *arg_unused)
}
uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_PYTHON, "Script", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
+
uiDefBut(block, BUTM, B_CONSTRAINT_ADD_NULL,"Null", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+
uiTextBoundsBlock(block, 50);
uiBlockSetDirection(block, UI_DOWN);
@@ -1360,7 +1421,17 @@ void do_constraintbuts(unsigned short event)
if(ob->pose) ob->pose->flag |= POSE_RECALC; // checks & sorts pose channels
DAG_scene_sort(G.scene);
break;
-
+
+ case B_CONSTRAINT_ADD_PYTHON:
+ {
+ bConstraint *con;
+
+ con = add_new_constraint(CONSTRAINT_TYPE_PYTHON);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
case B_CONSTRAINT_ADD_NULL:
{
bConstraint *con;
diff --git a/source/blender/src/editconstraint.c b/source/blender/src/editconstraint.c
index 2eef0f55978..32cfde2eb86 100644
--- a/source/blender/src/editconstraint.c
+++ b/source/blender/src/editconstraint.c
@@ -45,6 +45,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_text_types.h"
#include "DNA_view3d_types.h"
#include "BKE_action.h"
@@ -52,6 +53,7 @@
#include "BKE_constraint.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_main.h"
#include "BKE_ipo.h"
#include "BKE_object.h"
#include "BKE_utildefines.h"
@@ -65,6 +67,8 @@
#include "BIF_space.h"
#include "BIF_toolbox.h"
+#include "BPY_extern.h"
+
#include "blendef.h"
#include "nla.h"
#include "mydevice.h"
@@ -247,7 +251,14 @@ char *get_con_subtarget_name(bConstraint *con, Object *target)
* to the name for this constraints subtarget ... NULL otherwise
*/
switch (con->type) {
-
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = con->data;
+ if (data->flag & PYCON_USETARGETS) {
+ if (data->tar==target) return data->subtarget;
+ }
+ }
+ break;
case CONSTRAINT_TYPE_ACTION:
{
bActionConstraint *data = con->data;
@@ -376,6 +387,51 @@ static void test_constraints (Object *owner, const char* substring)
curcon->flag &= ~CONSTRAINT_DISABLE;
switch (curcon->type){
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = curcon->data;
+ float dummy_matrix[4][4];
+
+ /* is there are valid script? */
+ if (!data->text) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ else if (!BPY_is_pyconstraint(data->text)) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ data->flag &= ~PYCON_SCRIPTERROR;
+
+ /* does the constraint require target input? */
+ if (BPY_pyconstraint_targets(data, dummy_matrix))
+ data->flag |= PYCON_USETARGETS;
+ else
+ data->flag &= ~PYCON_USETARGETS;
+
+ /* check whether we have a valid target */
+ if (data->flag & PYCON_USETARGETS) {
+ /* validate target */
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if ( (data->tar == owner) &&
+ (!get_named_bone(get_armature(owner),
+ data->subtarget))) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ }
+ else {
+ /* don't hold onto target */
+ data->tar = NULL;
+ BLI_strncpy(data->subtarget, "", 32);
+ }
+ }
+ break;
case CONSTRAINT_TYPE_ACTION:
{
bActionConstraint *data = curcon->data;
@@ -688,21 +744,21 @@ void add_constraint(int only_IK)
else {
if(pchanact) {
if(pchansel)
- nr= pupmenu("Add Constraint to Active Bone%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|Action%x16");
+ nr= pupmenu("Add Constraint to Active Bone%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|Action%x16|%l|Script%x18");
else if(obsel && obsel->type==OB_CURVE)
- nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|Stretch To%x7|Action%x16");
+ nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|Stretch To%x7|Action%x16|%l|Script%x18");
else if(obsel)
- nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|Action%x16");
+ nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|Action%x16|%l|Script%x18");
else
- nr= pupmenu("Add Constraint to New Empty Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7");
+ nr= pupmenu("Add Constraint to New Empty Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Script%x18");
}
else {
if(obsel && obsel->type==OB_CURVE)
- nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17");
+ nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|%l|Script%x18");
else if(obsel)
- nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5");
+ nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Script%x18");
else
- nr= pupmenu("Add Constraint to New Empty Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5");
+ nr= pupmenu("Add Constraint to New Empty Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Script%x18");
}
}
@@ -762,6 +818,21 @@ void add_constraint(int only_IK)
cu->flag |= CU_PATH;
con = add_new_constraint(CONSTRAINT_TYPE_CLAMPTO);
}
+ else if(nr==18) {
+ char *menustr;
+ int scriptint= 0, dummy_active=0;
+
+ /* popup a list of usable scripts */
+ menustr = buildmenu_pyconstraints(NULL, &dummy_active);
+ scriptint = pupmenu(menustr);
+ MEM_freeN(menustr);
+
+ /* only add constraint if a script was chosen */
+ if (scriptint) {
+ con = add_new_constraint(CONSTRAINT_TYPE_PYTHON);
+ validate_pyconstraint_cb(con->data, &scriptint);
+ }
+ }
if(con==NULL) return; /* paranoia */
@@ -921,3 +992,53 @@ void rename_constraint(Object *ob, bConstraint *con, char *oldname)
}
+/* ********************** CONSTRAINT-SPECIFIC STUFF ********************* */
+/* ------------- PyConstraints ------------------ */
+
+/* this callback sets the text-file to be used for selected menu item */
+void validate_pyconstraint_cb(void *arg1, void *arg2)
+{
+ bPythonConstraint *data = arg1;
+ Text *text;
+ int index = *((int *)arg2);
+ int i;
+
+ /* innovative use of a for loop to search */
+ for (text=G.main->text.first, i=1; text && index!=i; i++, text=text->id.next);
+ data->text = text;
+}
+
+/* this returns a string for the list of usable pyconstraint script names */
+char *buildmenu_pyconstraints(Text *con_text, int *pyconindex)
+{
+ Text *text;
+ char *menustr = MEM_callocN(128, "menustr pyconstraints");
+ char *name, stmp[128];
+ int buf = 128;
+ int used = strlen("Scripts: %t") + 1;
+ int i;
+
+ sprintf(menustr, "%s", "Scripts: %t");
+
+ for (text=G.main->text.first, i=1; text; i++, text=text->id.next) {
+ /* this is important to ensure that right script is shown as active */
+ if (text == con_text) *pyconindex = i;
+
+ /* menu entry is length of name + 3(len(|%X)) + 6 characters for the int.*/
+ if (BPY_is_pyconstraint(text)) {
+ name= text->id.name;
+ if (strlen(name)+used+10 >= buf) {
+ char *newbuf = MEM_callocN(buf+128, "menustr pyconstraints 2");
+ memcpy(newbuf, menustr, used);
+ MEM_freeN(menustr);
+ menustr = newbuf;
+ buf += 128;
+ }
+ sprintf(stmp, "|%s%%x%d", name, i);
+ strcat(menustr, stmp);
+ used += strlen(name)+10;
+ }
+ }
+
+ return menustr;
+}
diff --git a/source/blender/src/header_text.c b/source/blender/src/header_text.c
index 92a5a49a681..32268c35210 100644
--- a/source/blender/src/header_text.c
+++ b/source/blender/src/header_text.c
@@ -52,6 +52,8 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_text_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_action_types.h"
#include "BIF_drawtext.h"
#include "BIF_interface.h"
@@ -59,11 +61,14 @@
#include "BIF_screen.h"
#include "BIF_space.h"
#include "BIF_toolbox.h"
+
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_sca.h"
#include "BKE_text.h"
+#include "BKE_depsgraph.h"
+
#include "BSE_filesel.h"
#include "BPY_extern.h"
@@ -135,27 +140,68 @@ void do_text_buttons(unsigned short event)
break;
case B_TEXTDELETE:
-
- text= st->text;
- if (!text) return;
-
- /* make the previous text active, if its not there make the next text active */
- if (st->text->id.prev) {
- st->text = st->text->id.prev;
- pop_space_text(st);
- } else if (st->text->id.next) {
- st->text = st->text->id.next;
- pop_space_text(st);
- }
+ {
+ Object *obt;
+ bConstraint *con;
+ int update;
- BPY_clear_bad_scriptlinks(text);
- free_text_controllers(text);
-
- unlink_text(text);
- free_libblock(&G.main->text, text);
-
- allqueue(REDRAWTEXT, 0);
- allqueue(REDRAWHEADERS, 0);
+ text= st->text;
+ if (!text) return;
+
+ /* make the previous text active, if its not there make the next text active */
+ if (st->text->id.prev) {
+ st->text = st->text->id.prev;
+ pop_space_text(st);
+ } else if (st->text->id.next) {
+ st->text = st->text->id.next;
+ pop_space_text(st);
+ }
+
+ /*check all pyconstraints*/
+ for (obt=G.main->object.first; obt; obt=obt->id.next) {
+ update = 0;
+ if(obt->type==OB_ARMATURE && obt->pose) {
+ bPoseChannel *pchan;
+ for(pchan= obt->pose->chanbase.first; pchan; pchan= pchan->next) {
+ for (con = pchan->constraints.first; con; con=con->next) {
+ if (con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data = con->data;
+ if (data->text==text) data->text = NULL;
+ update = 1;
+
+ }
+ }
+ }
+ }
+ for (con = obt->constraints.first; con; con=con->next) {
+ if (con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data = con->data;
+ if (data->text==text) data->text = NULL;
+ update = 1;
+ }
+ }
+
+ if (update) {
+ DAG_object_flush_update(G.scene, obt, OB_RECALC_DATA);
+ }
+ }
+
+ BPY_clear_bad_scriptlinks(text);
+ free_text_controllers(text);
+
+ unlink_text(text);
+ free_libblock(&G.main->text, text);
+
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+
+ /*for if any object constraints were changed.*/
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ BIF_undo_push("Delete Text");
+ }
break;
/*
@@ -265,6 +311,42 @@ static void do_text_filemenu(void *arg, int event)
case 6:
run_python_script(st);
break;
+ case 7:
+ {
+ Object *obt;
+ bConstraint *con;
+ short update;
+
+ /* check all pyconstraints */
+ for (obt=G.main->object.first; obt; obt=obt->id.next) {
+ update = 0;
+ if(obt->type==OB_ARMATURE && obt->pose) {
+ bPoseChannel *pchan;
+ for(pchan= obt->pose->chanbase.first; pchan; pchan= pchan->next) {
+ for (con = pchan->constraints.first; con; con=con->next) {
+ if (con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data = con->data;
+ if (data->text==text) data->flag = 0;
+ update = 1;
+
+ }
+ }
+ }
+ }
+ for (con = obt->constraints.first; con; con=con->next) {
+ if (con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data = con->data;
+ if (data->text==text) data->flag = 0;
+ update = 1;
+ }
+ }
+
+ if (update) {
+ DAG_object_flush_update(G.scene, obt, OB_RECALC_DATA);
+ }
+ }
+ }
+ break;
default:
break;
}
@@ -608,13 +690,23 @@ static uiBlock *text_filemenu(void *arg_unused)
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "New|Alt N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Open...|Alt O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
if(text) {
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reopen|Alt R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save As...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Run Python Script|Alt P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+
+ if (BPY_is_pyconstraint(text))
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Refresh All PyConstraints", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
}
uiDefIconTextBlockBut(block, text_template_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Script Templates", 0, yco-=20, 120, 19, "");