Keyframing Operators: Improved Error Messages

* Keyframing operators now use the reports system for displaying all its error messages. 
- The benefit of this is that users no longer need to check the console for error messages if keyframing fails.
- Unfortunately, reports are not currently viewable in any space/view in Blender, so...

* Added a temporary operator (UI_OT_reports_to_textblock), which can be accessed in the UI from the button which appears in place of the icon when more than one report exists. This dumps the current list of reports to a textblock "Recent Reports", from which they can be viewed. 

This isn't really nice, but at least we now have a way to view these again, which makes debugging some things a pain.

* Bugfix #24606 - when trying to add keyframes to F-Curves with F-Modifiers already which alter the curve significantly enough that the keyframes will have no effect, there are now warnings which aim to alleviate any confusion.
This commit is contained in:
Joshua Leung 2010-11-17 12:02:36 +00:00
parent 91217f117f
commit f713761039
16 changed files with 254 additions and 127 deletions

@ -214,6 +214,14 @@ void calc_fcurve_range(struct FCurve *fcu, float *min, float *max);
/* get the bounding-box extents for F-Curve */
void calc_fcurve_bounds(struct FCurve *fcu, float *xmin, float *xmax, float *ymin, float *ymax);
/* .............. */
/* Are keyframes on F-Curve of any use (to final result, and to show in editors)? */
short fcurve_are_keyframes_usable(struct FCurve *fcu);
/* Can keyframes be added to F-Curve? */
short fcurve_is_keyframable(struct FCurve *fcu);
/* -------- Curve Sanity -------- */
void calchandles_fcurve(struct FCurve *fcu);

@ -163,7 +163,7 @@ void copy_fcurves (ListBase *dst, ListBase *src)
}
}
/* --------------------- Finding -------------------------- */
/* ----------------- Finding F-Curves -------------------------- */
/* high level function to get an fcurve from C without having the rna */
FCurve *id_data_find_fcurve(ID *id, void *data, StructRNA *type, char *prop_name, int index)
@ -339,6 +339,8 @@ FCurve *rna_get_fcurve(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, bAction
return fcu;
}
/* ----------------- Finding Keyframes/Extents -------------------------- */
/* threshold for binary-searching keyframes - threshold here should be good enough for now, but should become userpref */
#define BEZT_BINARYSEARCH_THRESH 0.01f /* was 0.00001, but giving errors */
@ -520,6 +522,87 @@ void calc_fcurve_range (FCurve *fcu, float *start, float *end)
}
}
/* ----------------- Status Checks -------------------------- */
/* Are keyframes on F-Curve of any use?
* Usability of keyframes refers to whether they should be displayed,
* and also whether they will have any influence on the final result.
*/
short fcurve_are_keyframes_usable (FCurve *fcu)
{
/* F-Curve must exist */
if (fcu == NULL)
return 0;
/* F-Curve must not have samples - samples are mutually exclusive of keyframes */
if (fcu->fpt)
return 0;
/* if it has modifiers, none of these should "drastically" alter the curve */
if (fcu->modifiers.first) {
FModifier *fcm;
/* check modifiers from last to first, as last will be more influential */
// TODO: optionally, only check modifier if it is the active one...
for (fcm = fcu->modifiers.last; fcm; fcm = fcm->prev) {
/* ignore if muted/disabled */
if (fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED))
continue;
/* type checks */
switch (fcm->type) {
/* clearly harmless - do nothing */
case FMODIFIER_TYPE_CYCLES:
case FMODIFIER_TYPE_STEPPED:
case FMODIFIER_TYPE_NOISE:
break;
/* sometimes harmful - depending on whether they're "additive" or not */
case FMODIFIER_TYPE_GENERATOR:
{
FMod_Generator *data = (FMod_Generator *)fcm->data;
if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
return 0;
}
break;
case FMODIFIER_TYPE_FN_GENERATOR:
{
FMod_FunctionGenerator *data = (FMod_FunctionGenerator *)fcm->data;
if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
return 0;
}
break;
/* always harmful - cannot allow */
default:
return 0;
}
}
}
/* keyframes are usable */
return 1;
}
/* Can keyframes be added to F-Curve?
* Keyframes can only be added if they are already visible
*/
short fcurve_is_keyframable (FCurve *fcu)
{
/* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
if (fcurve_are_keyframes_usable(fcu) == 0)
return 0;
/* F-Curve must currently be editable too */
if ( (fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) )
return 0;
/* F-Curve is keyframable */
return 1;
}
/* ***************************** Keyframe Column Tools ********************************* */
/* add a BezTriple to a column */

@ -2917,6 +2917,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
ID *id= (ID *)id_poin;
FCurve *fcu= (FCurve *)fcu_poin;
ReportList *reports = CTX_wm_reports(C);
Scene *scene= CTX_data_scene(C);
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
@ -2940,7 +2941,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
flag |= INSERTKEY_REPLACE;
/* insert a keyframe for this F-Curve */
done= insert_keyframe_direct(ptr, prop, fcu, cfra, flag);
done= insert_keyframe_direct(reports, ptr, prop, fcu, cfra, flag);
if (done)
WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
@ -2954,6 +2955,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
KeyBlock *kb= (KeyBlock *)kb_poin;
char *rna_path= key_get_curValue_rnaPath(key, kb);
ReportList *reports = CTX_wm_reports(C);
Scene *scene= CTX_data_scene(C);
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
@ -2982,7 +2984,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
flag |= INSERTKEY_REPLACE;
/* insert a keyframe for this F-Curve */
done= insert_keyframe_direct(ptr, prop, fcu, cfra, flag);
done= insert_keyframe_direct(reports, ptr, prop, fcu, cfra, flag);
if (done)
WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);

@ -697,25 +697,26 @@ static float visualkey_get_value (PointerRNA *ptr, PropertyRNA *prop, int array_
* the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
* and extra keyframe filtering.
*/
short insert_keyframe_direct (PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, short flag)
short insert_keyframe_direct (ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, short flag)
{
float curval= 0.0f;
/* no F-Curve to add keyframe to? */
if (fcu == NULL) {
printf("ERROR: no F-Curve to add keyframes to \n");
BKE_report(reports, RPT_ERROR, "No F-Curve to add keyframes to");
return 0;
}
/* F-Curve not editable? */
if ( (fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ) {
if (G.f & G_DEBUG)
printf("WARNING: not inserting keyframe for locked F-Curve \n");
if (fcurve_is_keyframable(fcu) == 0) {
BKE_reportf(reports, RPT_ERROR,
"F-Curve with path = '%s' [%d] cannot be keyframed. Ensure that it is not locked or sampled. Also, try removing F-Modifiers.",
fcu->rna_path, fcu->array_index);
return 0;
}
/* if no property given yet, try to validate from F-Curve info */
if ((ptr.id.data == NULL) && (ptr.data==NULL)) {
printf("ERROR: no RNA-pointer available to retrieve values for keyframing from\n");
BKE_report(reports, RPT_ERROR, "No RNA-pointer available to retrieve values for keyframing from");
return 0;
}
if (prop == NULL) {
@ -726,7 +727,9 @@ short insert_keyframe_direct (PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, fl
/* property not found... */
char *idname= (ptr.id.data) ? ((ID *)ptr.id.data)->name : "<No ID-Pointer>";
printf("Insert Key: Could not insert keyframe, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", idname, fcu->rna_path);
BKE_reportf(reports, RPT_ERROR,
"Could not insert keyframe, as RNA Path is invalid for the given ID (ID = %s, Path = %s)",
idname, fcu->rna_path);
return 0;
}
else {
@ -815,7 +818,7 @@ short insert_keyframe_direct (PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, fl
*
* index of -1 keys all array indices
*/
short insert_keyframe (ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag)
short insert_keyframe (ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag)
{
PointerRNA id_ptr, ptr;
PropertyRNA *prop = NULL;
@ -825,13 +828,14 @@ short insert_keyframe (ID *id, bAction *act, const char group[], const char rna_
/* validate pointer first - exit if failure */
if (id == NULL) {
printf("Insert Key: no ID-block to insert keyframe in (Path = %s) \n", rna_path);
BKE_reportf(reports, RPT_ERROR, "No ID-block to insert keyframe in (Path = %s)", rna_path);
return 0;
}
RNA_id_pointer_create(id, &id_ptr);
if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
printf("Insert Key: Could not insert keyframe, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n",
BKE_reportf(reports, RPT_ERROR,
"Could not insert keyframe, as RNA Path is invalid for the given ID (ID = %s, Path = %s)",
(id)? id->name : "<Missing ID-Block>", rna_path);
return 0;
}
@ -844,7 +848,9 @@ short insert_keyframe (ID *id, bAction *act, const char group[], const char rna_
act= verify_adt_action(id, 1);
if (act == NULL) {
printf("Insert Key: Could not insert keyframe, as this type does not support animation data (ID = %s, Path = %s)\n", id->name, rna_path);
BKE_reportf(reports, RPT_ERROR,
"Could not insert keyframe, as this type does not support animation data (ID = %s, Path = %s)",
id->name, rna_path);
return 0;
}
@ -900,7 +906,7 @@ short insert_keyframe (ID *id, bAction *act, const char group[], const char rna_
}
/* insert keyframe */
ret += insert_keyframe_direct(ptr, prop, fcu, cfra, flag);
ret += insert_keyframe_direct(reports, ptr, prop, fcu, cfra, flag);
}
}
@ -917,7 +923,7 @@ short insert_keyframe (ID *id, bAction *act, const char group[], const char rna_
* The flag argument is used for special settings that alter the behaviour of
* the keyframe deletion. These include the quick refresh options.
*/
short delete_keyframe (ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short UNUSED(flag))
short delete_keyframe (ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short UNUSED(flag))
{
AnimData *adt= BKE_animdata_from_id(id);
PointerRNA id_ptr, ptr;
@ -927,14 +933,14 @@ short delete_keyframe (ID *id, bAction *act, const char group[], const char rna_
/* sanity checks */
if ELEM(NULL, id, adt) {
printf("ERROR: no ID-block and/or AnimData to delete keyframe from \n");
BKE_report(reports, RPT_ERROR, "No ID-Block and/Or AnimData to delete keyframe from");
return 0;
}
/* validate pointer first - exit if failure */
RNA_id_pointer_create(id, &id_ptr);
if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
printf("Delete Key: Could not delete keyframe, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path);
BKE_reportf(reports, RPT_ERROR, "Could not delete keyframe, as RNA Path is invalid for the given ID (ID = %s, Path = %s)", id->name, rna_path);
return 0;
}
@ -953,7 +959,7 @@ short delete_keyframe (ID *id, bAction *act, const char group[], const char rna_
cfra= BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
}
else {
printf("ERROR: no Action to delete keyframes from for ID = %s \n", id->name);
BKE_reportf(reports, RPT_ERROR, "No Action to delete keyframes from for ID = %s \n", id->name);
return 0;
}
}
@ -997,7 +1003,7 @@ short delete_keyframe (ID *id, bAction *act, const char group[], const char rna_
if ( (fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ) {
if (G.f & G_DEBUG)
printf("WARNING: not inserting keyframe for locked F-Curve \n");
printf("WARNING: not deleting keyframe for locked F-Curve \n");
continue;
}
@ -1308,7 +1314,7 @@ static int delete_key_v3d_exec (bContext *C, wmOperator *op)
for (fcu= act->curves.first; fcu; fcu= fcn) {
fcn= fcu->next;
success+= delete_keyframe(id, NULL, NULL, fcu->rna_path, fcu->array_index, cfra, 0);
success+= delete_keyframe(op->reports, id, NULL, NULL, fcu->rna_path, fcu->array_index, cfra, 0);
}
}
@ -1378,7 +1384,7 @@ static int insert_key_button_exec (bContext *C, wmOperator *op)
length= 1;
for (a=0; a<length; a++)
success+= insert_keyframe(ptr.id.data, NULL, NULL, path, index+a, cfra, flag);
success+= insert_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index+a, cfra, flag);
MEM_freeN(path);
}
@ -1387,7 +1393,7 @@ static int insert_key_button_exec (bContext *C, wmOperator *op)
NlaStrip *strip= (NlaStrip *)ptr.data;
FCurve *fcu= list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), flag);
success+= insert_keyframe_direct(ptr, prop, fcu, cfra, 0);
success+= insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, 0);
}
else {
if (G.f & G_DEBUG)
@ -1463,7 +1469,7 @@ static int delete_key_button_exec (bContext *C, wmOperator *op)
length= 1;
for (a=0; a<length; a++)
success+= delete_keyframe(ptr.id.data, NULL, NULL, path, index+a, cfra, 0);
success+= delete_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index+a, cfra, 0);
MEM_freeN(path);
}

@ -818,6 +818,7 @@ void ANIM_relative_keyingset_add_source (ListBase *dsources, ID *id, StructRNA *
int ANIM_apply_keyingset (bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra)
{
Scene *scene= CTX_data_scene(C);
ReportList *reports = CTX_wm_reports(C);
KS_Path *ksp;
int kflag=0, success= 0;
char *groupname= NULL;
@ -913,9 +914,9 @@ int ANIM_apply_keyingset (bContext *C, ListBase *dsources, bAction *act, KeyingS
for (; i < arraylen; i++) {
/* action to take depends on mode */
if (mode == MODIFYKEY_MODE_INSERT)
success += insert_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
success += insert_keyframe(reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
else if (mode == MODIFYKEY_MODE_DELETE)
success += delete_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
success += delete_keyframe(reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
}
/* set recalc-flags */

@ -35,6 +35,7 @@ struct AnimData;
struct bContext;
struct wmKeyConfig;
struct ReportList;
struct ScrArea;
struct ARegion;
struct View2D;
@ -73,7 +74,8 @@ typedef struct bAnimContext {
struct Scene *scene; /* active scene */
struct Object *obact; /* active object */
ListBase *markers; /* active set of markers */
ListBase *reports; /* pointer to current reports list */ // XXX not yet used
struct ReportList *reports; /* pointer to current reports list */
} bAnimContext;
/* Main Data container types */

@ -47,6 +47,7 @@ struct bConstraint;
struct bContext;
struct wmOperatorType;
struct ReportList;
struct PointerRNA;
struct PropertyRNA;
@ -93,7 +94,7 @@ int insert_vert_fcurve(struct FCurve *fcu, float x, float y, short flag);
* Use this to insert a keyframe using the current value being keyframed, in the
* nominated F-Curve (no creation of animation data performed). Returns success.
*/
short insert_keyframe_direct(struct PointerRNA ptr, struct PropertyRNA *prop, struct FCurve *fcu, float cfra, short flag);
short insert_keyframe_direct(struct ReportList *reports, struct PointerRNA ptr, struct PropertyRNA *prop, struct FCurve *fcu, float cfra, short flag);
/* -------- */
@ -101,12 +102,12 @@ short insert_keyframe_direct(struct PointerRNA ptr, struct PropertyRNA *prop, st
* Use this to create any necessary animation data, and then insert a keyframe
* using the current value being keyframed, in the relevant place. Returns success.
*/
short insert_keyframe(struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag);
short insert_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag);
/* Main Keyframing API call:
* Use this to delete keyframe on current frame for relevant channel. Will perform checks just in case.
*/
short delete_keyframe(struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag);
short delete_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag);
/* ************ Keying Sets ********************** */

@ -105,10 +105,11 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
// TODO: this should probably respect the keyingset only option for anim
if(autokeyframe_cfra_can_key(scene, id)) {
ReportList *reports = CTX_wm_reports(C);
short flag = ANIM_get_keyframing_flags(scene, 1);
fcu->flag &= ~FCURVE_SELECTED;
insert_keyframe(id, action, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
insert_keyframe(reports, id, action, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
}
}

@ -34,11 +34,15 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_text_types.h" /* for UI_OT_reports_to_text */
#include "BLI_blenlib.h"
#include "BLI_math_color.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_text.h" /* for UI_OT_reports_to_text */
#include "BKE_report.h"
#include "RNA_access.h"
#include "RNA_define.h"
@ -403,6 +407,50 @@ void UI_OT_copy_to_selected_button(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array.");
}
/* Reports to Textblock Operator ------------------------ */
/* FIXME: this is just a temporary operator so that we can see all the reports somewhere
* when there are too many to display...
*/
static int reports_to_text_poll(bContext *C)
{
return CTX_wm_reports(C) != NULL;
}
static int reports_to_text_exec(bContext *C, wmOperator *op)
{
ReportList *reports = CTX_wm_reports(C);
Text *txt;
char *str;
/* create new text-block to write to */
txt = add_empty_text("Recent Reports");
/* convert entire list to a display string, and add this to the text-block
* - if commandline debug option enabled, show debug reports too
* - otherwise, up to info (which is what users normally see)
*/
str = BKE_reports_string(reports, (G.f & G_DEBUG)? RPT_DEBUG : RPT_INFO);
write_text(txt, str);
MEM_freeN(str);
return OPERATOR_FINISHED;
}
void UI_OT_reports_to_textblock(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Reports to Text Block";
ot->idname= "UI_OT_reports_to_textblock";
ot->description= "Write the reports ";
/* callbacks */
ot->poll= reports_to_text_poll;
ot->exec= reports_to_text_exec;
}
/* ********************************************************* */
/* Registration */
@ -413,5 +461,6 @@ void UI_buttons_operatortypes(void)
WM_operatortype_append(UI_OT_copy_data_path_button);
WM_operatortype_append(UI_OT_reset_default_button);
WM_operatortype_append(UI_OT_copy_to_selected_button);
WM_operatortype_append(UI_OT_reports_to_textblock); // XXX: temp?
}

@ -2331,6 +2331,7 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
uiBut *but;
uiStyle *style= U.uistyles.first;
int width;
int icon=0;
/* if the report display has timed out, don't show */
if (!reports->reporttimer) return;
@ -2364,13 +2365,20 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
/* icon and report message on top */
if(report->type & RPT_ERROR_ALL)
uiDefIconBut(block, LABEL, 0, ICON_ERROR, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
icon = ICON_ERROR;
else if(report->type & RPT_WARNING_ALL)
uiDefIconBut(block, LABEL, 0, ICON_ERROR, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
icon = ICON_ERROR;
else if(report->type & RPT_INFO_ALL)
uiDefIconBut(block, LABEL, 0, ICON_INFO, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
icon = ICON_INFO;
/* XXX: temporary operator to dump all reports to a text block, but only if more than 1 report
* to be shown instead of icon when appropriate...
*/
if (reports->list.first != reports->list.last)
uiDefIconButO(block, BUT, "UI_OT_reports_to_textblock", WM_OP_INVOKE_REGION_WIN, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Click to see rest of reports in textblock: 'Recent Reports'");
else
uiDefIconBut(block, LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
uiDefBut(block, LABEL, 0, report->message, UI_UNIT_X+10, 0, UI_UNIT_X+width, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
}

@ -410,6 +410,7 @@ static void insert_action_keys(bAnimContext *ac, short mode)
bAnimListElem *ale;
int filter;
ReportList *reports = ac->reports;
Scene *scene= ac->scene;
float cfra= (float)CFRA;
short flag = 0;
@ -437,7 +438,7 @@ static void insert_action_keys(bAnimContext *ac, short mode)
/* if there's an id */
if (ale->id)
insert_keyframe(ale->id, NULL, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
insert_keyframe(reports, ale->id, NULL, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
else
insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
}

@ -899,7 +899,7 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGri
* - if the option to only show controls if the F-Curve is selected is enabled, we must obey this
*/
if (!(sipo->flag & SIPO_SELCUVERTSONLY) || (fcu->flag & FCURVE_SELECTED)) {
if (fcurve_needs_draw_fmodifier_controls(fcu, fcm)) {
if (fcurve_are_keyframes_usable(fcu) == 0) {
/* only draw controls if this is the active modifier */
if ((fcu->flag & FCURVE_ACTIVE) && (fcm)) {
switch (fcm->type) {

@ -406,6 +406,7 @@ static void insert_graph_keys(bAnimContext *ac, short mode)
bAnimListElem *ale;
int filter;
ReportList *reports = ac->reports;
Scene *scene= ac->scene;
float cfra= (float)CFRA;
short flag = 0;
@ -432,7 +433,7 @@ static void insert_graph_keys(bAnimContext *ac, short mode)
/* if there's an id */
if (ale->id)
insert_keyframe(ale->id, NULL, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
insert_keyframe(reports, ale->id, NULL, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
else
insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
}
@ -507,6 +508,10 @@ static int graphkeys_click_insert_exec (bContext *C, wmOperator *op)
}
fcu = ale->data;
/* when there are F-Modifiers on the curve, only allow adding
* keyframes if these will be visible after doing so...
*/
if (fcurve_is_keyframable(fcu)) {
/* get frame and value from props */
frame= RNA_float_get(op->ptr, "frame");
val= RNA_float_get(op->ptr, "value");
@ -520,6 +525,16 @@ static int graphkeys_click_insert_exec (bContext *C, wmOperator *op)
/* insert keyframe on the specified frame + value */
insert_vert_fcurve(fcu, frame, val, 0);
}
else {
/* warn about why this can't happen */
if (fcu->fpt)
BKE_report(op->reports, RPT_ERROR, "Keyframes cannot be added to sampled F-Curves");
else if (fcu->flag & FCURVE_PROTECTED)
BKE_report(op->reports, RPT_ERROR, "Active F-Curve is not editable");
else
BKE_report(op->reports, RPT_ERROR, "Remove F-Modifiers from F-Curve to add keyframes");
}
/* free temp data */
MEM_freeN(ale);

@ -87,57 +87,6 @@ bAnimListElem *get_active_fcurve_channel (bAnimContext *ac)
/* ************************************************************** */
/* Operator Polling Callbacks */
/* check if any FModifiers to draw controls for - fcm is 'active' modifier
* used for the polling callbacks + also for drawing
*/
// TODO: restructure these tests
// TODO: maybe for now, just allow editing always for now...
short fcurve_needs_draw_fmodifier_controls (FCurve *fcu, FModifier *fcm)
{
/* don't draw if there aren't any modifiers at all */
if (fcu->modifiers.first == NULL)
return 0;
/* if only one modifier
* - don't draw if it is muted or disabled
* - set it as the active one if no active one is present
*/
if (fcu->modifiers.first == fcu->modifiers.last) {
fcm= fcu->modifiers.first;
if (fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED))
return 0;
}
/* if there's an active modifier - don't draw if it doesn't drastically
* alter the curve...
*/
if (fcm) {
switch (fcm->type) {
/* clearly harmless */
case FMODIFIER_TYPE_CYCLES:
return 0;
case FMODIFIER_TYPE_STEPPED:
return 0;
/* borderline... */
case FMODIFIER_TYPE_NOISE:
return 0;
}
}
/* if only active modifier - don't draw if it is muted or disabled */
if (fcm) {
if (fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED))
return 0;
}
/* if we're still here, this means that there are modifiers with controls to be drawn */
// FIXME: what happens if all the modifiers were muted/disabled
return 1;
}
/* ------------------- */
/* Check if there are any visible keyframes (for selection tools) */
int graphop_visible_keyframes_poll (bContext *C)
{
@ -167,7 +116,6 @@ int graphop_visible_keyframes_poll (bContext *C)
for (ale = anim_data.first; ale; ale= ale->next) {
FCurve *fcu= (FCurve *)ale->data;
FModifier *fcm;
/* visible curves for selection must fulfull the following criteria:
* - it has bezier keyframes
@ -176,10 +124,10 @@ int graphop_visible_keyframes_poll (bContext *C)
*/
if (fcu->bezt == NULL)
continue;
fcm= find_active_fmodifier(&fcu->modifiers);
found= (fcurve_needs_draw_fmodifier_controls(fcu, fcm) == 0);
if (found) break;
if (fcurve_are_keyframes_usable(fcu)) {
found = 1;
break;
}
}
/* cleanup and return findings */
@ -216,7 +164,6 @@ int graphop_editable_keyframes_poll (bContext *C)
for (ale = anim_data.first; ale; ale= ale->next) {
FCurve *fcu= (FCurve *)ale->data;
FModifier *fcm;
/* editable curves must fulfull the following criteria:
* - it has bezier keyframes
@ -226,10 +173,10 @@ int graphop_editable_keyframes_poll (bContext *C)
*/
if (fcu->bezt == NULL)
continue;
fcm= find_active_fmodifier(&fcu->modifiers);
found= (fcurve_needs_draw_fmodifier_controls(fcu, fcm) == 0);
if (found) break;
if (fcurve_is_keyframable(fcu)) {
found = 1;
break;
}
}
/* cleanup and return findings */

@ -68,6 +68,7 @@
#include "BKE_pointcache.h"
#include "BKE_bmesh.h"
#include "BKE_scene.h"
#include "BKE_report.h"
#include "ED_anim_api.h"
@ -4546,6 +4547,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
// TODO: this should probably be done per channel instead...
if (autokeyframe_cfra_can_key(scene, id)) {
ReportList *reports = CTX_wm_reports(C);
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
ListBase dsources = {NULL, NULL};
float cfra= (float)CFRA; // xxx this will do for now
@ -4570,7 +4572,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
if (adt && adt->action) {
for (fcu= adt->action->curves.first; fcu; fcu= fcu->next) {
fcu->flag &= ~FCURVE_SELECTED;
insert_keyframe(id, adt->action, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
insert_keyframe(reports, id, adt->action, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
}
}
}
@ -4645,6 +4647,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
// TODO: this should probably be done per channel instead...
if (autokeyframe_cfra_can_key(scene, id)) {
ReportList *reports = CTX_wm_reports(C);
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
float cfra= (float)CFRA;
short flag= 0;
@ -4686,7 +4689,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
* NOTE: this will do constraints too, but those are ok to do here too?
*/
if (pchanName && strcmp(pchanName, pchan->name) == 0)
insert_keyframe(id, act, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
insert_keyframe(reports, id, act, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
if (pchanName) MEM_freeN(pchanName);
}

@ -2122,7 +2122,7 @@ static PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *arg
if(pyrna_struct_keyframe_parse(&self->ptr, args, kw, "s|ifs:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()", &path_full, &index, &cfra, &group_name) == -1)
return NULL;
result= PyBool_FromLong(insert_keyframe((ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0));
result= PyBool_FromLong(insert_keyframe(/*ReportList*/NULL, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0));
MEM_freeN(path_full);
return result;
@ -2156,7 +2156,7 @@ static PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *arg
if(pyrna_struct_keyframe_parse(&self->ptr, args, kw, "s|ifs:bpy_struct.keyframe_delete()", "bpy_struct.keyframe_insert()", &path_full, &index, &cfra, &group_name) == -1)
return NULL;
result= PyBool_FromLong(delete_keyframe((ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0));
result= PyBool_FromLong(delete_keyframe(/*ReportList*/NULL, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0));
MEM_freeN(path_full);
return result;