From f7137610390804b8016240bc6401540a912e2495 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 17 Nov 2010 12:02:36 +0000 Subject: [PATCH] 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. --- source/blender/blenkernel/BKE_fcurve.h | 8 ++ source/blender/blenkernel/intern/fcurve.c | 103 ++++++++++++++++-- .../editors/animation/anim_channels_defines.c | 6 +- source/blender/editors/animation/keyframing.c | 50 +++++---- source/blender/editors/animation/keyingsets.c | 5 +- source/blender/editors/include/ED_anim_api.h | 4 +- .../blender/editors/include/ED_keyframing.h | 7 +- .../editors/interface/interface_anim.c | 3 +- .../blender/editors/interface/interface_ops.c | 51 ++++++++- .../editors/interface/interface_templates.c | 16 ++- .../editors/space_action/action_edit.c | 3 +- .../blender/editors/space_graph/graph_draw.c | 2 +- .../blender/editors/space_graph/graph_edit.c | 43 +++++--- .../blender/editors/space_graph/graph_utils.c | 69 ++---------- .../editors/transform/transform_conversions.c | 7 +- source/blender/python/intern/bpy_rna.c | 4 +- 16 files changed, 254 insertions(+), 127 deletions(-) diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 8dbfb4f2c73..46392c2c8ea 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -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); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 75029af4b10..2f886d8ab43 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -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) @@ -298,36 +298,36 @@ int list_find_data_fcurves (ListBase *dst, ListBase *src, const char *dataPrefix return matches; } -FCurve *rna_get_fcurve(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, bAction **action, int *driven) +FCurve *rna_get_fcurve (PointerRNA *ptr, PropertyRNA *prop, int rnaindex, bAction **action, int *driven) { FCurve *fcu= NULL; *driven= 0; /* there must be some RNA-pointer + property combon */ - if(prop && ptr->id.data && RNA_property_animateable(ptr, prop)) { + if (prop && ptr->id.data && RNA_property_animateable(ptr, prop)) { AnimData *adt= BKE_animdata_from_id(ptr->id.data); char *path; - if(adt) { - if((adt->action && adt->action->curves.first) || (adt->drivers.first)) { + if (adt) { + if ((adt->action && adt->action->curves.first) || (adt->drivers.first)) { /* XXX this function call can become a performance bottleneck */ path= RNA_path_from_ID_to_property(ptr, prop); - if(path) { + if (path) { /* animation takes priority over drivers */ - if(adt->action && adt->action->curves.first) + if (adt->action && adt->action->curves.first) fcu= list_find_fcurve(&adt->action->curves, path, rnaindex); /* if not animated, check if driven */ - if(!fcu && (adt->drivers.first)) { + if (!fcu && (adt->drivers.first)) { fcu= list_find_fcurve(&adt->drivers, path, rnaindex); - if(fcu) + if (fcu) *driven= 1; } - if(fcu && action) + if (fcu && action) *action= adt->action; MEM_freeN(path); @@ -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 */ diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 9121d8cd66c..4d28bed0ffb 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -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); diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 7f99a5e3b47..fd8487973c8 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -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 : ""; - 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 : "", 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; areports, 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) @@ -1456,14 +1462,14 @@ static int delete_key_button_exec (bContext *C, wmOperator *op) if (all) { length= RNA_property_array_length(&ptr, prop); - if(length) index= 0; + if (length) index= 0; else length= 1; } else length= 1; for (a=0; areports, ptr.id.data, NULL, NULL, path, index+a, cfra, 0); MEM_freeN(path); } diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index 643ba96f7fe..5d96c015caa 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -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 */ diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 40478ddcbc2..ce2d6044e1a 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -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 */ diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index d2f30939fbb..ff4ec92562f 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -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 ********************** */ diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 2a30a36ffe0..4021e4208dc 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -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); } } diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 10458a763e6..b4a6f9e77a3 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -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" @@ -402,7 +406,51 @@ void UI_OT_copy_to_selected_button(wmOperatorType *ot) /* properties */ 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? } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index a5964d595dd..8237e175794 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -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, ""); - } diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 32bb02ddcda..4d35b5ca4ff 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -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); } diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 01a8ba4797c..1f92f32cc88 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -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) { diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index e1d1e4194d5..35307a78e65 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -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,19 +508,33 @@ static int graphkeys_click_insert_exec (bContext *C, wmOperator *op) } fcu = ale->data; - /* get frame and value from props */ - frame= RNA_float_get(op->ptr, "frame"); - val= RNA_float_get(op->ptr, "value"); - - /* apply inverse NLA-mapping to frame to get correct time in un-scaled action */ - adt= ANIM_nla_mapping_get(&ac, ale); - frame= BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP); - - /* apply inverse unit-mapping to value to get correct value for F-Curves */ - val *= ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, 1); - - /* insert keyframe on the specified frame + value */ - insert_vert_fcurve(fcu, frame, val, 0); + /* 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"); + + /* apply inverse NLA-mapping to frame to get correct time in un-scaled action */ + adt= ANIM_nla_mapping_get(&ac, ale); + frame= BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP); + + /* apply inverse unit-mapping to value to get correct value for F-Curves */ + val *= ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, 1); + + /* 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); diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c index 927149a268d..417d92782cc 100644 --- a/source/blender/editors/space_graph/graph_utils.c +++ b/source/blender/editors/space_graph/graph_utils.c @@ -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 */ diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 54b724d69f7..e1cda354872 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -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); } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 2bffd7f6b88..8daad50f5d0 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -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;