Graph Editor: "Add at Cursor" options for Insert Key operator in Graph Editor

* Added the ability to add a keyframe at the current cursor location in the
  Graph Editor. This is useful for precisely defining the shape of driver F-Curves.

* Fixed a bug where the wrong cursor-x time was being used in Drivers mode
  (i.e. it was still using time, and not just any time-value, but the NLA-mapped time!)
This commit is contained in:
Joshua Leung 2015-12-15 04:03:25 +13:00
parent 236d094865
commit 1fbd74296d
Notes: blender-bot 2023-02-14 08:22:54 +01:00
Referenced by issue #46992, Can't reload .py from blender\2.76\scripts\addons folder
Referenced by issue #46973, New GP causes errors with Pie menus
Referenced by issue #46968, Bmesh Editmode Booleanss; Missing faces when subtracting many islands from a cube
1 changed files with 97 additions and 29 deletions

View File

@ -483,57 +483,125 @@ void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot)
/* ******************** Insert Keyframes Operator ************************* */
/* defines for insert keyframes tool */
/* Mode defines for insert keyframes tool */
typedef enum eGraphKeys_InsertKey_Types {
GRAPHKEYS_INSERTKEY_ALL = (1 << 0),
GRAPHKEYS_INSERTKEY_SEL = (1 << 1),
GRAPHKEYS_INSERTKEY_CURSOR = (1 << 2),
GRAPHKEYS_INSERTKEY_ACTIVE = (1 << 3),
} eGraphKeys_InsertKey_Types;
/* RNA mode types for insert keyframes tool */
static EnumPropertyItem prop_graphkeys_insertkey_types[] = {
{1, "ALL", 0, "All Channels", ""},
{2, "SEL", 0, "Only Selected Channels", ""},
{GRAPHKEYS_INSERTKEY_ALL, "ALL", 0, "All Channels",
"Insert a keyframe on all visible and editable F-Curves using each curve's current value"},
{GRAPHKEYS_INSERTKEY_SEL, "SEL", 0, "Only Selected Channels",
"Insert a keyframe on selected F-Curves using each curve's current value"},
{0, "", 0, "", ""},
{GRAPHKEYS_INSERTKEY_ACTIVE | GRAPHKEYS_INSERTKEY_CURSOR, "CURSOR_ACTIVE", 0,
"Active Channels At Cursor", "Insert a keyframe for the active F-Curve at the cursor point"},
{GRAPHKEYS_INSERTKEY_SEL | GRAPHKEYS_INSERTKEY_CURSOR, "CURSOR_SEL", 0,
"Selected Channels At Cursor", "Insert a keyframe for selected F-Curves at the cursor point"},
{0, NULL, 0, NULL, NULL}
};
/* this function is responsible for snapping keyframes to frame-times */
static void insert_graph_keys(bAnimContext *ac, short mode)
static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
size_t num_items;
ReportList *reports = ac->reports;
SpaceIpo *sipo = (SpaceIpo *)ac->sl;
Scene *scene = ac->scene;
short flag = 0;
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
if (mode == 2) filter |= ANIMFILTER_SEL;
if (mode & GRAPHKEYS_INSERTKEY_SEL)
filter |= ANIMFILTER_SEL;
else if (mode & GRAPHKEYS_INSERTKEY_ACTIVE)
filter |= ANIMFILTER_ACTIVE;
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
num_items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
if (num_items == 0) {
if (mode & GRAPHKEYS_INSERTKEY_ACTIVE)
BKE_report(reports, RPT_ERROR, "No active F-Curve to add a keyframe to. Select an editable F-Curve first");
else if (mode & GRAPHKEYS_INSERTKEY_SEL)
BKE_report(reports, RPT_ERROR, "No selected F-Curves to add keyframes to");
else
BKE_report(reports, RPT_ERROR, "No channels to add keyframes to");
return;
}
/* init keyframing flag */
flag = ANIM_get_keyframing_flags(scene, 1);
/* insert keyframes */
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
float cfra;
/* adjust current frame for NLA-mapping */
if (adt)
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
cfra = (float)CFRA;
if (mode & GRAPHKEYS_INSERTKEY_CURSOR) {
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
/* read value from property the F-Curve represents, or from the curve only?
* - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
* - ale->owner != NULL: If this is set, then the path may not be resolvable from the ID alone,
* so it's easier for now to just read the F-Curve directly.
* (TODO: add the full-blown PointerRNA relative parsing case here...)
*/
if (ale->id && !ale->owner)
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);
ale->update |= ANIM_UPDATE_DEFAULT;
short mapping_flag = ANIM_get_normalization_flags(ac);
float offset;
float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag, &offset);
float x, y;
/* perform time remapping for x-coordinate (if necessary) */
if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS))
x = sipo->cursorTime;
else if (adt)
x = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
x = (float)CFRA;
/* normalise units of cursor's value */
if (sipo)
y = (sipo->cursorVal / unit_scale) - offset;
else
y = 0.0f;
/* insert keyframe directly into the F-Curve */
insert_vert_fcurve(fcu, x, y, 0);
ale->update |= ANIM_UPDATE_DEFAULT;
}
}
else {
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
float cfra;
/* adjust current frame for NLA-mapping */
if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS))
cfra = sipo->cursorTime;
else if (adt)
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
cfra = (float)CFRA;
/* read value from property the F-Curve represents, or from the curve only?
* - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
* - ale->owner != NULL: If this is set, then the path may not be resolvable from the ID alone,
* so it's easier for now to just read the F-Curve directly.
* (TODO: add the full-blown PointerRNA relative parsing case here...)
* - fcu->driver != NULL: If this is set, then it's a driver. If we don't check for this, we'd end
* up adding the keyframes on a new F-Curve in the action data instead.
*/
if (ale->id && !ale->owner && !fcu->driver)
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);
ale->update |= ANIM_UPDATE_DEFAULT;
}
}
ANIM_animdata_update(ac, &anim_data);
@ -545,7 +613,7 @@ static void insert_graph_keys(bAnimContext *ac, short mode)
static int graphkeys_insertkey_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
short mode;
eGraphKeys_InsertKey_Types mode;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)