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:
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
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue