Invalid Driver Targets are now indicated appropriately (using Red Backgrounds)

in the UI

This is the second part of the fixes for [#32492], making it easier to identify
which part of a driver (i.e. which of its targets) is causing problems

A number of additional/related changes needed to be made:
* Red-alert status for layouts is now propagated down to child layouts when they
are created. This is needed as otherwise some of the templates used in the Graph
Editor driver settings won't actually get the red-alert status flushed down to
them. Also, note that this status needs to be set before any widgets are added
to the layout, or else the settings aren't applied when the relevant widgets get
created.

* "Single Property" RNA-Paths resulting in out of bounds array access will now
trigger an error status and appropriate warnings

TODO:
* The error tagging doesn't get applied immediately after variables are created,
or their types changed
* There was also some other weirdness involved when a higher-value flag (1<<10)
was used for this setting, which needs further attention
This commit is contained in:
Joshua Leung 2013-02-28 07:13:33 +00:00
parent 2afca3e317
commit ac6c218cf4
4 changed files with 80 additions and 27 deletions

@ -1014,7 +1014,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
ID *id;
int index;
int index = -1;
float value = 0.0f;
/* sanity check */
@ -1029,6 +1029,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
printf("Error: driver has an invalid target to use\n");
if (G.debug & G_DEBUG) printf("\tpath = %s\n", dtar->rna_path);
driver->flag |= DRIVER_FLAG_INVALID;
dtar->flag |= DTAR_FLAG_INVALID;
return 0.0f;
}
@ -1039,7 +1040,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
if (RNA_path_resolve_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
if (RNA_property_array_check(prop)) {
/* array */
if (index < RNA_property_array_length(&ptr, prop)) {
if ((index >= 0) && (index < RNA_property_array_length(&ptr, prop))) {
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
value = (float)RNA_property_boolean_get_index(&ptr, prop, index);
@ -1054,6 +1055,17 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
break;
}
}
else {
/* out of bounds */
if (G.debug & G_DEBUG) {
printf("Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
id->name, dtar->rna_path, index);
}
driver->flag |= DRIVER_FLAG_INVALID;
dtar->flag |= DTAR_FLAG_INVALID;
return 0.0f;
}
}
else {
/* not an array */
@ -1074,16 +1086,19 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
break;
}
}
}
else {
/* path couldn't be resolved */
if (G.debug & G_DEBUG)
printf("Driver Evaluation Error: cannot resolve target for %s -> %s\n", id->name, dtar->rna_path);
driver->flag |= DRIVER_FLAG_INVALID;
dtar->flag |= DTAR_FLAG_INVALID;
return 0.0f;
}
/* if we're still here, we should be ok... */
dtar->flag &= ~DTAR_FLAG_INVALID;
return value;
}
@ -1122,25 +1137,39 @@ static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
/* evaluate 'rotation difference' driver variable */
static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
{
DriverTarget *dtar1 = &dvar->targets[0];
DriverTarget *dtar2 = &dvar->targets[1];
bPoseChannel *pchan, *pchan2;
float q1[4], q2[4], quat[4], angle;
/* get pose channels, and check if we've got two */
pchan = dtar_get_pchan_ptr(driver, &dvar->targets[0]);
pchan2 = dtar_get_pchan_ptr(driver, &dvar->targets[1]);
pchan = dtar_get_pchan_ptr(driver, dtar1);
pchan2 = dtar_get_pchan_ptr(driver, dtar2);
if (ELEM(NULL, pchan, pchan2)) {
/* disable this driver, since it doesn't work correctly... */
driver->flag |= DRIVER_FLAG_INVALID;
/* check what the error was */
if ((pchan == NULL) && (pchan2 == NULL))
if ((pchan == NULL) && (pchan2 == NULL)) {
printf("Driver Evaluation Error: Rotational difference failed - first 2 targets invalid\n");
else if (pchan == NULL)
dtar1->flag |= DTAR_FLAG_INVALID;
dtar2->flag |= DTAR_FLAG_INVALID;
}
else if (pchan == NULL) {
printf("Driver Evaluation Error: Rotational difference failed - first target not valid PoseChannel\n");
else if (pchan2 == NULL)
dtar1->flag |= DTAR_FLAG_INVALID;
dtar2->flag &= ~DTAR_FLAG_INVALID;
}
else if (pchan2 == NULL) {
printf("Driver Evaluation Error: Rotational difference failed - second target not valid PoseChannel\n");
dtar1->flag &= ~DTAR_FLAG_INVALID;
dtar2->flag |= DTAR_FLAG_INVALID;
}
/* stop here... */
return 0.0f;
}
@ -1177,8 +1206,13 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
/* invalid target, so will not have enough targets */
driver->flag |= DRIVER_FLAG_INVALID;
dtar->flag |= DTAR_FLAG_INVALID;
return 0.0f;
}
else {
/* target seems to be OK now... */
dtar->flag &= ~DTAR_FLAG_INVALID;
}
/* try to get posechannel */
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
@ -1264,8 +1298,13 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
/* invalid target, so will not have enough targets */
driver->flag |= DRIVER_FLAG_INVALID;
dtar->flag |= DTAR_FLAG_INVALID;
return 0.0f;
}
else {
/* target should be valid now */
dtar->flag &= ~DTAR_FLAG_INVALID;
}
/* try to get posechannel */
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
@ -1463,7 +1502,7 @@ void driver_change_variable_type(DriverVar *dvar, int type)
/* store the flags */
dtar->flag = flags;
/* object ID types only, or idtype not yet initialized*/
/* object ID types only, or idtype not yet initialized */
if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0))
dtar->idtype = ID_OB;
}

@ -2263,6 +2263,7 @@ uiLayout *uiLayoutRow(uiLayout *layout, int align)
litem->enabled = 1;
litem->context = layout->context;
litem->space = (align) ? 0 : layout->root->style->buttonspacex;
litem->redalert = layout->redalert;
litem->w = layout->w;
BLI_addtail(&layout->items, litem);
@ -2283,6 +2284,7 @@ uiLayout *uiLayoutColumn(uiLayout *layout, int align)
litem->enabled = 1;
litem->context = layout->context;
litem->space = (litem->align) ? 0 : layout->root->style->buttonspacey;
litem->redalert = layout->redalert;
litem->w = layout->w;
BLI_addtail(&layout->items, litem);
@ -2303,6 +2305,7 @@ uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align)
flow->litem.enabled = 1;
flow->litem.context = layout->context;
flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
flow->litem.redalert = layout->redalert;
flow->litem.w = layout->w;
flow->number = number;
BLI_addtail(&layout->items, flow);
@ -2323,6 +2326,7 @@ static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
box->litem.enabled = 1;
box->litem.context = layout->context;
box->litem.space = layout->root->style->columnspace;
box->litem.redalert = layout->redalert;
box->litem.w = layout->w;
BLI_addtail(&layout->items, box);

@ -461,6 +461,7 @@ static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVa
/* Target ID */
row = uiLayoutRow(layout, FALSE);
uiLayoutSetRedAlert(row, ((dtar->flag & DTAR_FLAG_INVALID) && !dtar->id));
uiTemplateAnyID(row, &dtar_ptr, "id", "id_type", IFACE_("Prop:"));
/* Target Property */
@ -470,8 +471,9 @@ static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVa
/* get pointer for resolving the property selected */
RNA_id_pointer_create(dtar->id, &root_ptr);
col = uiLayoutColumn(layout, TRUE);
/* rna path */
col = uiLayoutColumn(layout, TRUE);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID));
uiTemplatePathBuilder(col, &dtar_ptr, "data_path", &root_ptr, IFACE_("Path"));
}
}
@ -492,21 +494,23 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
/* Bone 1 */
col = uiLayoutColumn(layout, TRUE);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Bone 1:"));
if (dtar->id && ob1->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
col = uiLayoutColumn(layout, TRUE);
uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Bone 2:"));
if (dtar2->id && ob2->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
@ -515,7 +519,7 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
/* settings for 'location difference' driver variable type */
static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *dvar)
{
DriverTarget *dtar = &dvar->targets[0];
DriverTarget *dtar = &dvar->targets[0];
DriverTarget *dtar2 = &dvar->targets[1];
Object *ob1 = (Object *)dtar->id;
Object *ob2 = (Object *)dtar2->id;
@ -523,16 +527,17 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
uiLayout *col;
/* initialize RNA pointer to the target */
RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
/* Bone 1 */
col = uiLayoutColumn(layout, TRUE);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone 1:"));
if (dtar->id && ob1->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
@ -540,11 +545,12 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
uiItemR(col, &dtar_ptr, "transform_space", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, TRUE);
uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Ob/Bone 2:"));
if (dtar2->id && ob2->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
@ -565,11 +571,12 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar
/* properties */
col = uiLayoutColumn(layout, TRUE);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone:"));
if (dtar->id && ob->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar->id, &RNA_Pose, ob->pose, &tar_ptr);
uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
@ -623,7 +630,7 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
if (driver->type == DRIVER_TYPE_PYTHON) {
/* expression */
uiItemR(col, &driver_ptr, "expression", 0, IFACE_("Expr"), ICON_NONE);
/* errors? */
if (driver->flag & DRIVER_FLAG_INVALID)
uiItemL(col, IFACE_("ERROR: Invalid Python expression"), ICON_ERROR);
@ -668,19 +675,19 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
box = uiLayoutBox(col);
/* first row context info for driver */
RNA_pointer_create(ale->id, &RNA_DriverVariable, dvar, &dvar_ptr);
row = uiLayoutRow(box, FALSE);
block = uiLayoutGetBlock(row);
/* variable name */
uiItemR(row, &dvar_ptr, "name", 0, "", ICON_NONE);
/* remove button */
uiBlockSetEmboss(block, UI_EMBOSSN);
but = uiDefIconBut(block, BUT, B_IPO_DEPCHANGE, ICON_X, 290, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, IFACE_("Delete target variable"));
uiButSetFunc(but, driver_delete_var_cb, driver, dvar);
uiBlockSetEmboss(block, UI_EMBOSS);
/* variable type */
row = uiLayoutRow(box, FALSE);
uiItemR(row, &dvar_ptr, "type", 0, "", ICON_NONE);
@ -721,7 +728,7 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
else {
BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", dvar->curval);
}
uiItemL(row, valBuf, ICON_NONE);
}
}

@ -284,15 +284,18 @@ typedef enum eDriverTarget_Flag {
/* used for targets that use the pchan_name instead of RNA path
* (i.e. rotation difference)
*/
DTAR_FLAG_STRUCT_REF = (1<<0),
DTAR_FLAG_STRUCT_REF = (1 << 0),
/* idtype can only be 'Object' */
DTAR_FLAG_ID_OB_ONLY = (1<<1),
DTAR_FLAG_ID_OB_ONLY = (1 << 1),
/* "localspace" flags */
/* base flag - basically "pre parent+constraints" */
DTAR_FLAG_LOCALSPACE = (1<<2),
DTAR_FLAG_LOCALSPACE = (1 << 2),
/* include constraints transformed to space including parents */
DTAR_FLAG_LOCAL_CONSTS = (1<<3),
DTAR_FLAG_LOCAL_CONSTS = (1 << 3),
/* error flags */
DTAR_FLAG_INVALID = (1 << 4),
} eDriverTarget_Flag;
/* Transform Channels for Driver Targets */