Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/animation')
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c319
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c264
-rw-r--r--source/blender/editors/animation/anim_deps.c4
-rw-r--r--source/blender/editors/animation/anim_draw.c214
-rw-r--r--source/blender/editors/animation/anim_filter.c128
-rw-r--r--source/blender/editors/animation/anim_markers.c54
-rw-r--r--source/blender/editors/animation/anim_ops.c4
-rw-r--r--source/blender/editors/animation/drivers.c7
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c4
-rw-r--r--source/blender/editors/animation/keyframes_general.c54
-rw-r--r--source/blender/editors/animation/keyframing.c130
11 files changed, 992 insertions, 190 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 37c40052275..ebd05d8b16b 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -110,7 +110,7 @@ static void acf_generic_root_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUS
/* backdrop for top-level widgets (Scene and Object only) */
static void acf_generic_root_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
@@ -136,7 +136,7 @@ static void acf_generic_dataexpand_color(bAnimContext *UNUSED(ac), bAnimListElem
/* backdrop for data expanders under top-level Scene/Object */
static void acf_generic_dataexpand_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
@@ -177,7 +177,7 @@ static bool acf_show_channel_colors(bAnimContext *ac)
/* get backdrop color for generic channels */
static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, float r_color[3])
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
bActionGroup *grp = NULL;
short indent = (acf->get_indent_level) ? acf->get_indent_level(ac, ale) : 0;
bool showGroupColors = acf_show_channel_colors(ac);
@@ -217,7 +217,7 @@ static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, floa
/* backdrop for generic channels */
static void acf_generic_channel_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
@@ -269,7 +269,7 @@ static short acf_generic_indention_flexible(bAnimContext *UNUSED(ac), bAnimListE
/* basic offset for channels derived from indention */
static short acf_generic_basic_offset(bAnimContext *ac, bAnimListElem *ale)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
if (acf && acf->get_indent_level)
return acf->get_indent_level(ac, ale) * INDENT_STEP_SIZE;
@@ -409,7 +409,7 @@ static void acf_summary_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(al
/* backdrop for summary widget */
static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
float color[3];
@@ -790,7 +790,7 @@ static void acf_group_color(bAnimContext *ac, bAnimListElem *ale, float r_color[
/* backdrop for group widget */
static void acf_group_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
@@ -1017,6 +1017,149 @@ static bAnimChannelType ACF_FCURVE =
acf_fcurve_setting_ptr /* pointer for setting */
};
+/* NLA Control FCurves Expander ----------------------- */
+
+/* get backdrop color for nla controls widget */
+static void acf_nla_controls_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3])
+{
+ // TODO: give this its own theme setting?
+ UI_GetThemeColorShade3fv(TH_GROUP, 55, r_color);
+}
+
+/* backdrop for nla controls expander widget */
+static void acf_nla_controls_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
+{
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ View2D *v2d = &ac->ar->v2d;
+ short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
+ short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
+ float color[3];
+
+ /* set backdrop drawing color */
+ acf->get_backdrop_color(ac, ale, color);
+ glColor3fv(color);
+
+ /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
+ UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
+ UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5);
+}
+
+/* name for nla controls expander entries */
+static void acf_nla_controls_name(bAnimListElem *UNUSED(ale), char *name)
+{
+ BLI_strncpy(name, IFACE_("NLA Strip Controls"), ANIM_CHAN_NAME_SIZE);
+}
+
+/* check if some setting exists for this channel */
+static bool acf_nla_controls_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting)
+{
+ /* for now, all settings are supported, though some are only conditionally */
+ switch (setting) {
+ /* supported */
+ case ACHANNEL_SETTING_EXPAND:
+ return true;
+
+ // TOOD: selected?
+
+ default: /* unsupported */
+ return false;
+ }
+}
+
+/* get the appropriate flag(s) for the setting when it is valid */
+static int acf_nla_controls_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg)
+{
+ /* clear extra return data first */
+ *neg = false;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ *neg = true;
+ return ADT_NLA_SKEYS_COLLAPSED;
+
+ default:
+ /* this shouldn't happen */
+ return 0;
+ }
+}
+
+/* get pointer to the setting */
+static void *acf_nla_controls_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type)
+{
+ AnimData *adt = (AnimData *)ale->data;
+
+ /* all flags are just in adt->flag for now... */
+ return GET_ACF_FLAG_PTR(adt->flag, type);
+}
+
+static int acf_nla_controls_icon(bAnimListElem *UNUSED(ale))
+{
+ return ICON_NLA;
+}
+
+/* NLA Control FCurves Expander type define */
+static bAnimChannelType ACF_NLACONTROLS =
+{
+ "NLA Controls Expander", /* type name */
+ ACHANNEL_ROLE_EXPANDER, /* role */
+
+ acf_nla_controls_color, /* backdrop color */
+ acf_nla_controls_backdrop, /* backdrop */
+ acf_generic_indention_0, /* indent level */
+ acf_generic_group_offset, /* offset */
+
+ acf_nla_controls_name, /* name */
+ NULL, /* name prop */
+ acf_nla_controls_icon, /* icon */
+
+ acf_nla_controls_setting_valid, /* has setting */
+ acf_nla_controls_setting_flag, /* flag for setting */
+ acf_nla_controls_setting_ptr /* pointer for setting */
+};
+
+
+/* NLA Control F-Curve -------------------------------- */
+
+/* name for nla control fcurve entries */
+static void acf_nla_curve_name(bAnimListElem *ale, char *name)
+{
+ NlaStrip *strip = ale->owner;
+ FCurve *fcu = ale->data;
+ PropertyRNA *prop;
+
+ /* try to get RNA property that this shortened path (relative to the strip) refers to */
+ prop = RNA_struct_type_find_property(&RNA_NlaStrip, fcu->rna_path);
+ if (prop) {
+ /* "name" of this strip displays the UI identifier + the name of the NlaStrip */
+ BLI_snprintf(name, 256, "%s (%s)", RNA_property_ui_name(prop), strip->name);
+ }
+ else {
+ /* unknown property... */
+ BLI_snprintf(name, 256, "%s[%d]", fcu->rna_path, fcu->array_index);
+ }
+}
+
+
+/* NLA Control F-Curve type define */
+static bAnimChannelType ACF_NLACURVE =
+{
+ "NLA Control F-Curve", /* type name */
+ ACHANNEL_ROLE_CHANNEL, /* role */
+
+ acf_generic_channel_color, /* backdrop color */
+ acf_generic_channel_backdrop, /* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_group_offset, /* offset */
+
+ acf_nla_curve_name, /* name */
+ acf_fcurve_name_prop, /* name prop */
+ NULL, /* icon */
+
+ acf_fcurve_setting_valid, /* has setting */
+ acf_fcurve_setting_flag, /* flag for setting */
+ acf_fcurve_setting_ptr /* pointer for setting */
+};
+
/* Object Action Expander ------------------------------------------- */
// TODO: just get this from RNA?
@@ -3063,7 +3206,7 @@ static void acf_nlaaction_color(bAnimContext *UNUSED(ac), bAnimListElem *ale, fl
/* backdrop for nla action channel */
static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
AnimData *adt = ale->adt;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
@@ -3222,6 +3365,9 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_GROUP; /* Group */
animchannelTypeInfo[type++] = &ACF_FCURVE; /* F-Curve */
+ animchannelTypeInfo[type++] = &ACF_NLACONTROLS; /* NLA Control FCurve Expander */
+ animchannelTypeInfo[type++] = &ACF_NLACURVE; /* NLA Control FCurve Channel */
+
animchannelTypeInfo[type++] = &ACF_FILLACTD; /* Object Action Expander */
animchannelTypeInfo[type++] = &ACF_FILLDRIVERS; /* Drivers Expander */
@@ -3256,7 +3402,7 @@ static void ANIM_init_channel_typeinfo_data(void)
}
/* Get type info from given channel type */
-bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
+const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
{
/* santiy checks */
if (ale == NULL)
@@ -3277,7 +3423,7 @@ bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
/* Print debug info string for the given channel */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* print indents */
for (; indent_level > 0; indent_level--)
@@ -3309,7 +3455,7 @@ void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
*/
short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* 1) check that the setting exists for the current context */
if ((acf) && (!acf->has_setting || acf->has_setting(ac, ale, setting))) {
@@ -3382,7 +3528,7 @@ short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChanne
*/
void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* 1) check that the setting exists for the current context */
if ((acf) && (!acf->has_setting || acf->has_setting(ac, ale, setting))) {
@@ -3430,10 +3576,26 @@ void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, eAnimChannel
// width of rename textboxes
#define RENAME_TEXT_WIDTH (5 * U.widget_unit)
+
+/* Helper - Check if a channel needs renaming */
+static bool achannel_is_being_renamed(const bAnimContext *ac, const bAnimChannelType *acf, size_t channel_index)
+{
+ if (acf->name_prop && ac->ads) {
+ /* if rename index matches, this channel is being renamed */
+ if (ac->ads->renameIndex == channel_index + 1) {
+ return true;
+ }
+ }
+
+ /* not being renamed */
+ return false;
+}
+
+
/* Draw the given channel */
-void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
+void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short selected, offset;
float y, ymid, ytext;
@@ -3491,7 +3653,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
if (ac->sl) {
if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
/* for F-Curves, draw color-preview of curve behind checkbox */
- if (ale->type == ANIMTYPE_FCURVE) {
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
FCurve *fcu = (FCurve *)ale->data;
/* F-Curve channels need to have a special 'color code' box drawn, which is colored with whatever
@@ -3518,8 +3680,8 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
}
/* step 5) draw name ............................................... */
- /* TODO: when renaming, we might not want to draw this, especially if name happens to be longer than channel */
- if (acf->name) {
+ /* Don't draw this if renaming... */
+ if (acf->name && !achannel_is_being_renamed(ac, acf, channel_index)) {
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */
@@ -3537,7 +3699,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
UI_fontstyle_draw_simple(fstyle, offset, ytext, name);
/* draw red underline if channel is disabled */
- if ((ale->type == ANIMTYPE_FCURVE) && (ale->flag & FCURVE_DISABLED)) {
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE) && (ale->flag & FCURVE_DISABLED)) {
/* FIXME: replace hardcoded color here, and check on extents! */
glColor3f(1.0f, 0.0f, 0.0f);
glLineWidth(2.0);
@@ -3604,7 +3766,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
* (only only F-Curves really can support them for now)
* - slider should start before the toggles (if they're visible) to keep a clean line down the side
*/
- if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) {
+ if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) {
/* adjust offset */
offset += SLIDER_WIDTH;
}
@@ -3771,8 +3933,46 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
MEM_freeN(rna_path);
}
+/* callback for NLA Control Curve widget sliders - insert keyframes */
+static void achannel_setting_slider_nla_curve_cb(bContext *C, void *UNUSED(id_poin), void *fcu_poin)
+{
+ /* ID *id = (ID *)id_poin; */
+ FCurve *fcu = (FCurve *)fcu_poin;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ ReportList *reports = CTX_wm_reports(C);
+ Scene *scene = CTX_data_scene(C);
+ short flag = 0;
+ bool done = false;
+ float cfra;
+
+ /* get current frame - *no* NLA mapping should be done */
+ cfra = (float)CFRA;
+
+ /* get flags for keyframing */
+ flag = ANIM_get_keyframing_flags(scene, 1);
+
+ /* get pointer and property from the slider - this should all match up with the NlaStrip required... */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ if (fcu && prop) {
+ /* set the special 'replace' flag if on a keyframe */
+ if (fcurve_frame_has_keyframe(fcu, cfra, 0))
+ flag |= INSERTKEY_REPLACE;
+
+ /* insert a keyframe for this F-Curve */
+ done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, flag);
+
+ if (done)
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ }
+}
+
/* Draw a widget for some setting */
-static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChannelType *acf,
+static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAnimChannelType *acf,
uiBlock *block, int xpos, int ypos, int setting)
{
short ptrsize, butType;
@@ -3793,7 +3993,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
//icon = ((enabled) ? ICON_VISIBLE_IPO_ON : ICON_VISIBLE_IPO_OFF);
icon = ICON_VISIBLE_IPO_OFF;
- if (ale->type == ANIMTYPE_FCURVE)
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
tooltip = TIP_("F-Curve is visible in Graph Editor for editing");
else
tooltip = TIP_("Channels are visible in Graph Editor for editing");
@@ -3828,7 +4028,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
//icon = ((enabled) ? ICON_MUTE_IPO_ON : ICON_MUTE_IPO_OFF);
icon = ICON_MUTE_IPO_OFF;
- if (ale->type == ANIMTYPE_FCURVE) {
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
tooltip = TIP_("Does F-Curve contribute to result");
}
else if ((ac) && (ac->spacetype == SPACE_NLA) && (ale->type != ANIMTYPE_NLATRACK)) {
@@ -3912,7 +4112,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
/* Draw UI widgets the given channel */
void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListElem *ale, uiBlock *block, float yminc, float ymaxc, size_t channel_index)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
float y, ymid /*, ytext*/;
short offset;
@@ -3991,36 +4191,32 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
}
/* step 4) draw text - check if renaming widget is in use... */
- if (acf->name_prop && ac->ads) {
- float channel_height = ymaxc - yminc;
+ if (achannel_is_being_renamed(ac, acf, channel_index)) {
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
- /* if rename index matches, add widget for this */
- if (ac->ads->renameIndex == channel_index + 1) {
- PointerRNA ptr = {{NULL}};
- PropertyRNA *prop = NULL;
+ /* draw renaming widget if we can get RNA pointer for it
+ * NOTE: property may only be available in some cases, even if we have
+ * a callback available (e.g. broken F-Curve rename)
+ */
+ if (acf->name_prop(ale, &ptr, &prop)) {
+ const float channel_height = ymaxc - yminc;
+ uiBut *but;
- /* draw renaming widget if we can get RNA pointer for it
- * NOTE: property may only be available in some cases, even if we have
- * a callback available (e.g. broken F-Curve rename)
- */
- if (acf->name_prop(ale, &ptr, &prop)) {
- uiBut *but;
-
- UI_block_emboss_set(block, UI_EMBOSS);
-
- but = uiDefButR(block, UI_BTYPE_TEXT, 1, "", offset + 3, yminc, RENAME_TEXT_WIDTH, channel_height,
- &ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL);
-
- /* copy what outliner does here, see outliner_buttons */
- if (UI_but_active_only(C, ac->ar, block, but) == false) {
- ac->ads->renameIndex = 0;
-
- /* send notifiers */
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL);
- }
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ but = uiDefButR(block, UI_BTYPE_TEXT, 1, "", offset + 3, yminc, RENAME_TEXT_WIDTH, channel_height,
+ &ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL);
+
+ /* copy what outliner does here, see outliner_buttons */
+ if (UI_but_active_only(C, ac->ar, block, but) == false) {
+ ac->ads->renameIndex = 0;
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ /* send notifiers */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL);
}
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
}
}
@@ -4097,7 +4293,7 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
* and wouldn't be able to auto-keyframe...
* - slider should start before the toggles (if they're visible) to keep a clean line down the side
*/
- if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) {
+ if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) {
/* adjust offset */
// TODO: make slider width dynamic, so that they can be easier to use when the view is wide enough
offset += SLIDER_WIDTH;
@@ -4105,7 +4301,28 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
/* need backdrop behind sliders... */
UI_block_emboss_set(block, UI_EMBOSS);
- if (ale->id) { /* Slider using RNA Access -------------------- */
+ if (ale->owner) { /* Slider using custom RNA Access ---------- */
+ if (ale->type == ANIMTYPE_NLACURVE) {
+ NlaStrip *strip = (NlaStrip *)ale->owner;
+ FCurve *fcu = (FCurve *)ale->data;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ /* create RNA pointers */
+ RNA_pointer_create(ale->id, &RNA_NlaStrip, strip, &ptr);
+ prop = RNA_struct_find_property(&ptr, fcu->rna_path);
+
+ /* create property slider */
+ if (prop) {
+ uiBut *but;
+
+ /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */
+ but = uiDefAutoButR(block, &ptr, prop, fcu->array_index, "", ICON_NONE, (int)v2d->cur.xmax - offset, ymid, SLIDER_WIDTH, (int)ymaxc - yminc);
+ UI_but_func_set(but, achannel_setting_slider_nla_curve_cb, ale->id, ale->data);
+ }
+ }
+ }
+ else if (ale->id) { /* Slider using RNA Access --------------- */
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
char *rna_path = NULL;
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index d8ad6506186..f9e3c8a9fa6 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
+#include "BKE_depsgraph.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
@@ -101,6 +102,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)ale->data;
@@ -157,6 +159,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)channel_data;
fcu->flag |= FCURVE_ACTIVE;
@@ -255,6 +258,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
sel = ACHANNEL_SETFLAG_CLEAR;
break;
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
if (ale->flag & FCURVE_SELECTED)
sel = ACHANNEL_SETFLAG_CLEAR;
break;
@@ -339,6 +343,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)ale->data;
@@ -444,7 +449,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
return;
}
else {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
if (acf == NULL) {
printf("ERROR: no channel info for the changed channel\n");
@@ -473,7 +478,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
{
/* go backwards in the list, until the highest-ranking element (by indention has been covered) */
for (ale = match->prev; ale; ale = ale->prev) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
int level;
/* if no channel info was found, skip, since this type might not have any useful info */
@@ -517,7 +522,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
{
/* go forwards in the list, until the lowest-ranking element (by indention has been covered) */
for (ale = match->next; ale; ale = ale->next) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
int level;
/* if no channel info was found, skip, since this type might not have any useful info */
@@ -847,6 +852,7 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)channel;
@@ -868,7 +874,7 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
break;
}
default:
- printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type);
+ printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %u\n", type);
return;
}
@@ -1191,6 +1197,40 @@ static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrange
/* ------------------- */
+static void rearrange_nla_control_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
+{
+ ListBase anim_data_visible = {NULL, NULL};
+
+ NlaTrack *nlt;
+ NlaStrip *strip;
+
+ /* get rearranging function */
+ AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
+
+ if (rearrange_func == NULL)
+ return;
+
+ /* skip if these curves aren't being shown */
+ if (adt->flag & ADT_NLA_SKEYS_COLLAPSED)
+ return;
+
+ /* Filter visible data. */
+ rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLACURVE);
+
+ /* we cannot rearrange between strips, but within each strip, we can rearrange those curves */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ rearrange_animchannel_islands(&strip->fcurves, rearrange_func, mode, ANIMTYPE_NLACURVE,
+ &anim_data_visible);
+ }
+ }
+
+ /* free temp data */
+ BLI_freelistN(&anim_data_visible);
+}
+
+/* ------------------- */
+
static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode mode)
{
ListBase anim_data = {NULL, NULL};
@@ -1278,13 +1318,29 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
rearrange_driver_channels(&ac, adt, mode);
break;
+ case ANIMCONT_ACTION: /* Single Action only... */
case ANIMCONT_SHAPEKEY: // DOUBLE CHECK ME...
- default: /* some collection of actions */
+ {
if (adt->action)
rearrange_action_channels(&ac, adt->action, mode);
else if (G.debug & G_DEBUG)
printf("Animdata has no action\n");
break;
+ }
+
+ default: /* DopeSheet/Graph Editor - Some Actions + NLA Control Curves */
+ {
+ /* NLA Control Curves */
+ if (adt->nla_tracks.first)
+ rearrange_nla_control_channels(&ac, adt, mode);
+
+ /* Action */
+ if (adt->action)
+ rearrange_action_channels(&ac, adt->action, mode);
+ else if (G.debug & G_DEBUG)
+ printf("Animdata has no action\n");
+ break;
+ }
}
}
@@ -1602,6 +1658,27 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
break;
}
+ case ANIMTYPE_NLACURVE:
+ {
+ /* NLA Control Curve - Deleting it should disable the corresponding setting... */
+ NlaStrip *strip = (NlaStrip *)ale->owner;
+ FCurve *fcu = (FCurve *)ale->data;
+
+ if (STREQ(fcu->rna_path, "strip_time")) {
+ strip->flag &= ~NLASTRIP_FLAG_USR_TIME;
+ }
+ else if (STREQ(fcu->rna_path, "influence")) {
+ strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
+ }
+ else {
+ printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n", fcu->rna_path);
+ }
+
+ /* unlink and free the F-Curve */
+ BLI_remlink(&strip->fcurves, fcu);
+ free_fcurve(fcu);
+ break;
+ }
case ANIMTYPE_GPLAYER:
{
/* Grease Pencil layer */
@@ -1631,7 +1708,8 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-
+ DAG_relations_tag_update(CTX_data_main(C));
+
return OPERATOR_FINISHED;
}
@@ -2041,7 +2119,7 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
/* remove AnimData? */
if (action_empty && nla_empty && drivers_empty) {
- BKE_free_animdata(id);
+ BKE_animdata_free(id);
}
}
@@ -2420,12 +2498,13 @@ static void ANIM_OT_channels_select_border(wmOperatorType *ot)
/* ******************* Rename Operator ***************************** */
/* Allow renaming some channels by clicking on them */
-static void rename_anim_channels(bAnimContext *ac, int channel_index)
+static bool rename_anim_channels(bAnimContext *ac, int channel_index)
{
ListBase anim_data = {NULL, NULL};
- bAnimChannelType *acf;
+ const bAnimChannelType *acf;
bAnimListElem *ale;
int filter;
+ bool success = false;
/* get the channel that was clicked on */
/* filter channels */
@@ -2440,7 +2519,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
ANIM_animdata_freelist(&anim_data);
- return;
+ return false;
}
/* check that channel can be renamed */
@@ -2460,6 +2539,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
*/
if (ac->ads) {
ac->ads->renameIndex = channel_index + 1;
+ success = true;
}
}
}
@@ -2467,22 +2547,18 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
/* free temp data and tag for refresh */
ANIM_animdata_freelist(&anim_data);
ED_region_tag_redraw(ac->ar);
+ return success;
}
-static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
{
- bAnimContext ac;
ARegion *ar;
View2D *v2d;
int channel_index;
float x, y;
- /* get editor data */
- if (ANIM_animdata_get_context(C, &ac) == 0)
- return OPERATOR_CANCELLED;
-
/* get useful pointers from animation context data */
- ar = ac.ar;
+ ar = ac->ar;
v2d = &ar->v2d;
/* figure out which channel user clicked in
@@ -2490,20 +2566,36 @@ static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const
* so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
* ACHANNEL_HEIGHT_HALF.
*/
- UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
+ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
- if (ac.datatype == ANIMCONT_NLA) {
- SpaceNla *snla = (SpaceNla *)ac.sl;
+ if (ac->datatype == ANIMCONT_NLA) {
+ SpaceNla *snla = (SpaceNla *)ac->sl;
UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
}
else {
UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
}
-
+
+ return channel_index;
+}
+
+static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ bAnimContext ac;
+ int channel_index;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ channel_index = animchannels_channel_get(&ac, event->mval);
+
/* handle click */
- rename_anim_channels(&ac, channel_index);
-
- return OPERATOR_FINISHED;
+ if (rename_anim_channels(&ac, channel_index))
+ return OPERATOR_FINISHED;
+ else
+ /* allow event to be handled by selectall operator */
+ return OPERATOR_PASS_THROUGH;
}
static void ANIM_OT_channels_rename(wmOperatorType *ot)
@@ -2727,7 +2819,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
- case ANIMTYPE_FCURVE:
+ case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)ale->data;
@@ -2744,7 +2837,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
if (fcu->flag & FCURVE_SELECTED)
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
@@ -2767,6 +2860,19 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
+ case ANIMTYPE_NLACONTROLS:
+ {
+ AnimData *adt = (AnimData *)ale->data;
+
+ /* toggle expand
+ * - Although the triangle widget already allows this, since there's nothing else that can be done here now,
+ * let's just use it for easier expand/collapse for now
+ */
+ adt->flag ^= ADT_NLA_SKEYS_COLLAPSED;
+
+ notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
+ break;
+ }
case ANIMTYPE_GPDATABLOCK:
{
bGPdata *gpd = (bGPdata *)ale->data;
@@ -2918,6 +3024,105 @@ static void ANIM_OT_channels_click(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool extend)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+ bool success = false;
+ FCurve *fcu;
+ int i;
+
+ /* get the channel that was clicked on */
+ /* filter channels */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* get channel from index */
+ ale = BLI_findlink(&anim_data, channel_index);
+ if (ale == NULL) {
+ /* channel not found */
+ if (G.debug & G_DEBUG)
+ printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
+
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+
+ fcu = (FCurve *)ale->key_data;
+ success = (fcu != NULL);
+
+ ANIM_animdata_freelist(&anim_data);
+
+ /* F-Curve may not have any keyframes */
+ if (fcu && fcu->bezt) {
+ BezTriple *bezt;
+
+ if (!extend) {
+ filter = (ANIMFILTER_DATA_VISIBLE);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu_inner = (FCurve *)ale->key_data;
+
+ if (fcu_inner) {
+ for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) {
+ bezt->f2 = bezt->f1 = bezt->f3 = 0;
+ }
+ }
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+ }
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ bezt->f2 = bezt->f1 = bezt->f3 = SELECT;
+ }
+ }
+
+ /* free temp data and tag for refresh */
+ ED_region_tag_redraw(ac->ar);
+ return success;
+}
+
+static int animchannels_channel_select_keys_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ bAnimContext ac;
+ int channel_index;
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ channel_index = animchannels_channel_get(&ac, event->mval);
+
+ /* handle click */
+ if (select_anim_channel_keys(&ac, channel_index, extend)) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else
+ /* allow event to be handled by selectall operator */
+ return OPERATOR_PASS_THROUGH;
+}
+
+static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select Channel keyframes";
+ ot->idname = "ANIM_OT_channel_select_keys";
+ ot->description = "Select all keyframes of channel under mouse";
+
+ /* api callbacks */
+ ot->invoke = animchannels_channel_select_keys_invoke;
+ ot->poll = animedit_poll_channels_active;
+
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
/* ************************************************************************** */
/* Operator Registration */
@@ -2927,8 +3132,9 @@ void ED_operatortypes_animchannels(void)
WM_operatortype_append(ANIM_OT_channels_select_border);
WM_operatortype_append(ANIM_OT_channels_click);
+ WM_operatortype_append(ANIM_OT_channel_select_keys);
WM_operatortype_append(ANIM_OT_channels_rename);
-
+
WM_operatortype_append(ANIM_OT_channels_find);
WM_operatortype_append(ANIM_OT_channels_setting_enable);
@@ -2968,7 +3174,9 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
/* rename */
WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
-
+ WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
+ RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, KM_SHIFT, 0)->ptr, "extend", true);
+
/* find (i.e. a shortcut for setting the name filter) */
WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index eb57907c9ec..a38f5dbc8ea 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -73,8 +73,10 @@ void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale)
/* tag AnimData for refresh so that other views will update in realtime with these changes */
adt = BKE_animdata_from_id(id);
- if (adt)
+ if (adt) {
adt->recalc |= ADT_RECALC_ANIM;
+ DAG_id_tag_update(id, OB_RECALC_TIME);
+ }
/* update data */
fcu = (ale->datatype == ALE_FCURVE) ? ale->key_data : NULL;
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 0e052279796..d5945425576 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -34,16 +34,25 @@
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
#include "BLI_math.h"
#include "BLI_timecode.h"
+#include "BLI_utildefines.h"
+#include "BLI_rect.h"
+#include "BLI_dlrbTree.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_nla.h"
+#include "BKE_mask.h"
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
+#include "ED_keyframes_draw.h"
#include "RNA_access.h"
@@ -173,10 +182,14 @@ AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
if (G.is_rendering) return NULL;
/* handling depends on the type of animation-context we've got */
- if (ale)
- return ale->adt;
- else
- return NULL;
+ if (ale) {
+ /* NLA Control Curves occur on NLA strips, and shouldn't be subjected to this kind of mapping */
+ if (ale->type != ANIMTYPE_NLACURVE)
+ return ale->adt;
+ }
+
+ /* cannot handle... */
+ return NULL;
}
/* ------------------- */
@@ -262,19 +275,26 @@ short ANIM_get_normalization_flags(bAnimContext *ac)
return 0;
}
-static float normalzation_factor_get(FCurve *fcu, short flag)
+static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, float *r_offset)
{
- float factor = 1.0f;
+ float factor = 1.0f, offset = 0.0f;
if (flag & ANIM_UNITCONV_RESTORE) {
+ if (r_offset)
+ *r_offset = fcu->prev_offset;
+
return 1.0f / fcu->prev_norm_factor;
}
if (flag & ANIM_UNITCONV_NORMALIZE_FREEZE) {
+ if (r_offset)
+ *r_offset = fcu->prev_offset;
return fcu->prev_norm_factor;
}
if (G.moving & G_TRANSFORM_FCURVES) {
+ if (r_offset)
+ *r_offset = fcu->prev_offset;
return fcu->prev_norm_factor;
}
@@ -283,32 +303,65 @@ static float normalzation_factor_get(FCurve *fcu, short flag)
BezTriple *bezt;
int i;
float max_coord = -FLT_MAX;
+ float min_coord = FLT_MAX;
+ float range;
if (fcu->totvert < 1) {
return 1.0f;
}
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- max_coord = max_ff(max_coord, fabsf(bezt->vec[0][1]));
- max_coord = max_ff(max_coord, fabsf(bezt->vec[1][1]));
- max_coord = max_ff(max_coord, fabsf(bezt->vec[2][1]));
+ if (PRVRANGEON) {
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (IN_RANGE_INCL(bezt->vec[1][0], scene->r.psfra, scene->r.pefra)) {
+ max_coord = max_ff(max_coord, bezt->vec[0][1]);
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
+ max_coord = max_ff(max_coord, bezt->vec[2][1]);
+
+ min_coord = min_ff(min_coord, bezt->vec[0][1]);
+ min_coord = min_ff(min_coord, bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, bezt->vec[2][1]);
+ }
+ }
+ }
+ else {
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ max_coord = max_ff(max_coord, bezt->vec[0][1]);
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
+ max_coord = max_ff(max_coord, bezt->vec[2][1]);
+
+ min_coord = min_ff(min_coord, bezt->vec[0][1]);
+ min_coord = min_ff(min_coord, bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, bezt->vec[2][1]);
+ }
}
- if (max_coord > FLT_EPSILON) {
- factor = 1.0f / max_coord;
+ range = max_coord - min_coord;
+
+ if (range > FLT_EPSILON) {
+ factor = 2.0f / range;
}
+ offset = -min_coord - range / 2.0f;
}
+
+ if (r_offset) {
+ *r_offset = offset;
+ }
+
fcu->prev_norm_factor = factor;
+ fcu->prev_offset = offset;
return factor;
}
/* Get unit conversion factor for given ID + F-Curve */
-float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag)
+float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
{
if (flag & ANIM_UNITCONV_NORMALIZE) {
- return normalzation_factor_get(fcu, flag);
+ return normalization_factor_get(scene, fcu, flag, r_offset);
}
+ if (r_offset)
+ *r_offset = 0.0f;
+
/* sanity checks */
if (id && fcu && fcu->rna_path) {
PointerRNA ptr, id_ptr;
@@ -336,4 +389,137 @@ float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag
return 1.0f;
}
+static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prevfra)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Mask *mask = CTX_data_edit_mask(C);
+ bDopeSheet ads = {NULL};
+ DLRBT_Tree keys;
+ ActKeyColumn *aknext, *akprev;
+ float cfranext, cfraprev;
+ bool donenext = false, doneprev = false;
+ int nextcount = 0, prevcount = 0;
+
+ cfranext = cfraprev = (float)(CFRA);
+
+ /* init binarytree-list for getting keyframes */
+ BLI_dlrbTree_init(&keys);
+
+ /* seed up dummy dopesheet context with flags to perform necessary filtering */
+ if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
+ /* only selected channels are included */
+ ads.filterflag |= ADS_FILTER_ONLYSEL;
+ }
+
+ /* populate tree with keyframe nodes */
+ scene_to_keylist(&ads, scene, &keys, NULL);
+
+ if (ob)
+ ob_to_keylist(&ads, ob, &keys, NULL);
+
+ gpencil_to_keylist(&ads, gpd, &keys);
+
+ if (mask) {
+ MaskLayer *masklay = BKE_mask_layer_active(mask);
+ mask_to_keylist(&ads, masklay, &keys);
+ }
+
+ /* build linked-list for searching */
+ BLI_dlrbTree_linkedlist_sync(&keys);
+
+ /* find matching keyframe in the right direction */
+ do {
+ aknext = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfranext);
+
+ if (aknext) {
+ if (CFRA == (int)aknext->cfra) {
+ /* make this the new starting point for the search and ignore */
+ cfranext = aknext->cfra;
+ }
+ else {
+ /* this changes the frame, so set the frame and we're done */
+ if (++nextcount == U.view_frame_keyframes)
+ donenext = true;
+ }
+ cfranext = aknext->cfra;
+ }
+ } while ((aknext != NULL) && (donenext == false));
+
+ do {
+ akprev = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfraprev);
+
+ if (akprev) {
+ if (CFRA == (int)akprev->cfra) {
+ /* make this the new starting point for the search */
+ }
+ else {
+ /* this changes the frame, so set the frame and we're done */
+ if (++prevcount == U.view_frame_keyframes)
+ doneprev = true;
+ }
+ cfraprev = akprev->cfra;
+ }
+ } while ((akprev != NULL) && (doneprev == false));
+
+ /* free temp stuff */
+ BLI_dlrbTree_free(&keys);
+
+ /* any success? */
+ if (doneprev || donenext) {
+ if (doneprev)
+ *prevfra = cfraprev;
+ else
+ *prevfra = CFRA - (cfranext - CFRA);
+
+ if (donenext)
+ *nextfra = cfranext;
+ else
+ *nextfra = CFRA + (CFRA - cfraprev);
+
+ return true;
+ }
+
+ return false;
+}
+
+void ANIM_center_frame(struct bContext *C, int smooth_viewtx)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ float w = BLI_rctf_size_x(&ar->v2d.cur);
+ rctf newrct;
+ int nextfra, prevfra;
+
+ switch (U.view_frame_type) {
+ case ZOOM_FRAME_MODE_SECONDS:
+ newrct.xmax = scene->r.cfra + U.view_frame_seconds * FPS + 1;
+ newrct.xmin = scene->r.cfra - U.view_frame_seconds * FPS - 1;
+ newrct.ymax = ar->v2d.cur.ymax;
+ newrct.ymin = ar->v2d.cur.ymin;
+ break;
+
+ /* hardest case of all, look for all keyframes around frame and display those */
+ case ZOOM_FRAME_MODE_KEYFRAMES:
+ if (find_prev_next_keyframes(C, &nextfra, &prevfra)) {
+ newrct.xmax = nextfra;
+ newrct.xmin = prevfra;
+ newrct.ymax = ar->v2d.cur.ymax;
+ newrct.ymin = ar->v2d.cur.ymin;
+ break;
+ }
+ /* else drop through, keep range instead */
+
+ case ZOOM_FRAME_MODE_KEEP_RANGE:
+ default:
+ newrct.xmax = scene->r.cfra + (w / 2);
+ newrct.xmin = scene->r.cfra - (w / 2);
+ newrct.ymax = ar->v2d.cur.ymax;
+ newrct.ymin = ar->v2d.cur.ymin;
+ break;
+ }
+
+ UI_view2d_smooth_view(C, ar, &newrct, smooth_viewtx);
+}
/* *************************************************** */
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index d6daa64a9f2..75f5eb17b09 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -423,6 +423,7 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
* - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
* - nlaOk: line or block of code to execute for NLA tracks+strips case
* - driversOk: line or block of code to execute for Drivers case
+ * - nlaKeysOk: line or block of code for NLA Strip Keyframes case
* - keysOk: line or block of code for Keyframes case
*
* The checks for the various cases are as follows:
@@ -433,9 +434,10 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
* converted to a new NLA strip, and the filtering options allow this
* 2C) allow non-animated datablocks to be included so that datablocks can be added
* 3) drivers: include drivers from animdata block (for Drivers mode in Graph Editor)
- * 4) normal keyframes: only when there is an active action
+ * 4A) nla strip keyframes: these are the per-strip controls for time and influence
+ * 4B) normal keyframes: only when there is an active action
*/
-#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \
+#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, nlaKeysOk, keysOk) \
{ \
if ((id)->adt) { \
if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) { \
@@ -456,6 +458,9 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
} \
} \
else { \
+ if (ANIMDATA_HAS_NLA(id)) { \
+ nlaKeysOk \
+ } \
if (ANIMDATA_HAS_KEYS(id)) { \
keysOk \
} \
@@ -786,6 +791,16 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
ale->adt = BKE_animdata_from_id(data);
break;
}
+ case ANIMTYPE_NLACONTROLS:
+ {
+ AnimData *adt = (AnimData *)data;
+
+ ale->flag = adt->flag;
+
+ ale->key_data = NULL;
+ ale->datatype = ALE_NONE;
+ break;
+ }
case ANIMTYPE_GROUP:
{
bActionGroup *agrp = (bActionGroup *)data;
@@ -977,7 +992,7 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id
static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, ID *owner_id)
{
bAnimListElem ale_dummy = {NULL};
- bAnimChannelType *acf;
+ const bAnimChannelType *acf;
/* create a dummy wrapper for the F-Curve */
ale_dummy.type = ANIMTYPE_FCURVE;
@@ -1286,7 +1301,7 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
* - active track should still get shown though (even though it has disabled flag set)
*/
// FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel
- if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && !(nlt->flag & NLATRACK_ACTIVE))
+ if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && (adt->act_track != nlt))
continue;
/* only work with this channel and its subchannels if it is editable */
@@ -1295,6 +1310,30 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
if (ANIMCHANNEL_SELOK(SEL_NLT(nlt))) {
/* only include if this track is active */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
+ /* name based filtering... */
+ if (((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id)) {
+ bool track_ok = false, strip_ok = false;
+
+ /* check if the name of the track, or the strips it has are ok... */
+ track_ok = BLI_strcasestr(nlt->name, ads->searchstr);
+
+ if (track_ok == false) {
+ NlaStrip *strip;
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ if (BLI_strcasestr(strip->name, ads->searchstr)) {
+ strip_ok = true;
+ break;
+ }
+ }
+ }
+
+ /* skip if both fail this test... */
+ if (!track_ok && !strip_ok) {
+ continue;
+ }
+ }
+
+ /* add the track now that it has passed all our tests */
ANIMCHANNEL_NEW_CHANNEL(nlt, ANIMTYPE_NLATRACK, owner_id);
}
}
@@ -1305,6 +1344,80 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
return items;
}
+/* Include the control FCurves per NLA Strip in the channel list
+ * NOTE: This is includes the expander too...
+ */
+static size_t animfilter_nla_controls(ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id)
+{
+ ListBase tmp_data = {NULL, NULL};
+ size_t tmp_items = 0;
+ size_t items = 0;
+
+ /* add control curves from each NLA strip... */
+ /* NOTE: ANIMTYPE_FCURVES are created here, to avoid duplicating the code needed */
+ BEGIN_ANIMFILTER_SUBCHANNELS(((adt->flag & ADT_NLA_SKEYS_COLLAPSED) == 0))
+ {
+ NlaTrack *nlt;
+ NlaStrip *strip;
+
+ /* for now, we only go one level deep - so controls on grouped FCurves are not handled */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ ListBase strip_curves = {NULL, NULL};
+ size_t strip_items = 0;
+
+ /* create the raw items */
+ strip_items += animfilter_fcurves(&strip_curves, ads, strip->fcurves.first, NULL, filter_mode, owner_id);
+
+ /* change their types and add extra data
+ * - There is no point making a separate copy of animfilter_fcurves for this now/yet,
+ * unless we later get per-element control curves for other stuff too
+ */
+ if (strip_items) {
+ bAnimListElem *ale, *ale_n = NULL;
+
+ for (ale = strip_curves.first; ale; ale = ale_n) {
+ ale_n = ale->next;
+
+ /* change the type to being a FCurve for editing NLA strip controls */
+ BLI_assert(ale->type == ANIMTYPE_FCURVE);
+
+ ale->type = ANIMTYPE_NLACURVE;
+ ale->owner = strip;
+
+ ale->adt = NULL; /* XXX: This way, there are no problems with time mapping errors */
+ }
+ }
+
+ /* add strip curves to the set of channels inside the group being collected */
+ BLI_movelisttolist(&tmp_data, &strip_curves);
+ BLI_assert(BLI_listbase_is_empty(&strip_curves));
+ tmp_items += strip_items;
+ }
+ }
+ }
+ END_ANIMFILTER_SUBCHANNELS;
+
+ /* did we find anything? */
+ if (tmp_items) {
+ /* add the expander as a channel first */
+ if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+ /* currently these channels cannot be selected, so they should be skipped */
+ if ((filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) == 0) {
+ ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_NLACONTROLS, owner_id);
+ }
+ }
+
+ /* now add the list of collected channels */
+ BLI_movelisttolist(anim_data, &tmp_data);
+ BLI_assert(BLI_listbase_is_empty(&tmp_data));
+ items += tmp_items;
+ }
+
+ /* return the numebr of items added to the list */
+ return items;
+}
+
/* determine what animation data from AnimData block should get displayed */
static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *id, int filter_mode)
{
@@ -1332,6 +1445,9 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope
{ /* Drivers */
items += animfilter_fcurves(anim_data, ads, adt->drivers.first, NULL, filter_mode, id);
},
+ { /* NLA Control Keyframes */
+ items += animfilter_nla_controls(anim_data, ads, adt, filter_mode, id);
+ },
{ /* Keyframes */
items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id);
}
@@ -2214,6 +2330,7 @@ static size_t animdata_filter_ds_obanim(bAnimContext *ac, ListBase *anim_data, b
cdata = adt;
expanded = EXPANDED_DRVD(adt);
},
+ { /* NLA Strip Controls - no dedicated channel for now (XXX) */ },
{ /* Keyframes */
type = ANIMTYPE_FILLACTD;
cdata = adt->action;
@@ -2385,6 +2502,7 @@ static size_t animdata_filter_ds_scene(bAnimContext *ac, ListBase *anim_data, bD
cdata = adt;
expanded = EXPANDED_DRVD(adt);
},
+ { /* NLA Strip Controls - no dedicated channel for now (XXX) */ },
{ /* Keyframes */
type = ANIMTYPE_FILLACTD;
cdata = adt->action;
@@ -2804,7 +2922,7 @@ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_F
/* unhandled */
default:
{
- printf("ANIM_animdata_filter() - Invalid datatype argument %d\n", datatype);
+ printf("ANIM_animdata_filter() - Invalid datatype argument %u\n", datatype);
break;
}
}
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 140b7e0b117..40376c38c3b 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -266,8 +266,20 @@ void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
{
TimeMarker *marker;
- if (markers == NULL)
+ if (lb) {
+ /* Clear the list first, since callers have no way of knowing
+ * whether this terminated early otherwise. This may lead
+ * to crashes if the user didn't clear the memory first.
+ */
+ lb->first = lb->last = NULL;
+ }
+ else {
+ return;
+ }
+
+ if (markers == NULL) {
return;
+ }
for (marker = markers->first; marker; marker = marker->next)
add_marker_to_cfra_elem(lb, marker, only_sel);
@@ -487,11 +499,32 @@ static int ed_markers_poll_selected_markers(bContext *C)
return ED_markers_get_first_selected(markers) != NULL;
}
+static int ed_markers_poll_selected_no_locked_markers(bContext *C)
+{
+ ListBase *markers = ED_context_get_markers(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ if (ts->lock_markers)
+ return 0;
+
+ /* first things first: markers can only exist in timeline views */
+ if (ED_operator_animview_active(C) == 0)
+ return 0;
+
+ /* check if some marker is selected */
+ return ED_markers_get_first_selected(markers) != NULL;
+}
+
+
/* special poll() which checks if there are any markers at all first */
static int ed_markers_poll_markers_exist(bContext *C)
{
ListBase *markers = ED_context_get_markers(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ if (ts->lock_markers)
+ return 0;
+
/* first things first: markers can only exist in timeline views */
if (ED_operator_animview_active(C) == 0)
return 0;
@@ -929,11 +962,11 @@ static void MARKER_OT_move(wmOperatorType *ot)
ot->exec = ed_marker_move_exec;
ot->invoke = ed_marker_move_invoke_wrapper;
ot->modal = ed_marker_move_modal;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
ot->cancel = ed_marker_move_cancel;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* rna storage */
RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
@@ -1022,7 +1055,7 @@ static void MARKER_OT_duplicate(wmOperatorType *ot)
ot->exec = ed_marker_duplicate_exec;
ot->invoke = ed_marker_duplicate_invoke_wrapper;
ot->modal = ed_marker_move_modal;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
ot->cancel = ed_marker_move_cancel;
/* flags */
@@ -1352,7 +1385,7 @@ static void MARKER_OT_delete(wmOperatorType *ot)
/* api callbacks */
ot->invoke = ed_marker_delete_invoke_wrapper;
ot->exec = ed_marker_delete_exec;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1400,7 +1433,7 @@ static void MARKER_OT_rename(wmOperatorType *ot)
/* api callbacks */
ot->invoke = ed_marker_rename_invoke_wrapper;
ot->exec = ed_marker_rename_exec;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1428,6 +1461,11 @@ static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ if (scene_to->toolsettings->lock_markers) {
+ BKE_report(op->reports, RPT_ERROR, "Target scene has locked markers");
+ return OPERATOR_CANCELLED;
+ }
+
/* copy markers */
for (marker = markers->first; marker; marker = marker->next) {
if (marker->flag & SELECT) {
@@ -1503,13 +1541,13 @@ static void MARKER_OT_camera_bind(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Bind Camera to Markers";
- ot->description = "Bind the active camera to selected markers(s)";
+ ot->description = "Bind the active camera to selected marker(s)";
ot->idname = "MARKER_OT_camera_bind";
/* api callbacks */
ot->exec = ed_marker_camera_bind_exec;
ot->invoke = ed_markers_opwrap_invoke;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index cbcbc8743f1..2de42933dc0 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -107,7 +107,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
SUBFRA = 0.0f;
/* do updates */
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -247,7 +247,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
ot->poll = change_frame_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR;
/* rna */
ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 67ba82f1858..b2a34d7c317 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -42,6 +42,7 @@
#include "DNA_texture_types.h"
#include "BKE_animsys.h"
+#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_context.h"
#include "BKE_report.h"
@@ -84,7 +85,7 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if ((adt == NULL) && (add))
- adt = BKE_id_add_animdata(id);
+ adt = BKE_animdata_add_id(id);
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
return NULL;
@@ -450,7 +451,7 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
if (success) {
/* send updates */
UI_context_update_anim_flag(C);
-
+ DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
}
@@ -504,7 +505,7 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op)
if (success) {
/* send updates */
UI_context_update_anim_flag(C);
-
+ DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
}
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index bcdad1c93ad..2c0018b000d 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -78,7 +78,7 @@
static void validate_fmodifier_cb(bContext *UNUSED(C), void *fcm_v, void *UNUSED(arg))
{
FModifier *fcm = (FModifier *)fcm_v;
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
/* call the verify callback on the modifier if applicable */
if (fmi && fmi->verify_data)
@@ -555,7 +555,7 @@ static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, sho
void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm)
{
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
uiLayout *box, *row, *sub, *col;
uiBlock *block;
uiBut *but;
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 2d869d272bd..b3dc0021f00 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -199,13 +199,17 @@ void clean_fcurve(FCurve *fcu, float thresh)
/* now insert first keyframe, as it should be ok */
bezt = old_bezts;
insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
+ if (!(bezt->f2 & SELECT)) {
+ lastb = fcu->bezt;
+ lastb->f1 = lastb->f2 = lastb->f3 = 0;
+ }
/* Loop through BezTriples, comparing them. Skip any that do
* not fit the criteria for "ok" points.
*/
for (i = 1; i < totCount; i++) {
float prev[2], cur[2], next[2];
-
+
/* get BezTriples and their values */
if (i < (totCount - 1)) {
beztn = (old_bezts + (i + 1));
@@ -217,10 +221,17 @@ void clean_fcurve(FCurve *fcu, float thresh)
}
lastb = (fcu->bezt + (fcu->totvert - 1));
bezt = (old_bezts + i);
-
+
/* get references for quicker access */
prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
+
+ if (!(bezt->f2 & SELECT)) {
+ insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ lastb = (fcu->bezt + (fcu->totvert - 1));
+ lastb->f1 = lastb->f2 = lastb->f3 = 0;
+ continue;
+ }
/* check if current bezt occurs at same time as last ok */
if (IS_EQT(cur[0], prev[0], thresh)) {
@@ -228,7 +239,7 @@ void clean_fcurve(FCurve *fcu, float thresh)
* if there is a considerable distance between the points, and also if the
* current is further away than the next one is to the previous.
*/
- if (beztn && (IS_EQT(cur[0], next[0], thresh)) &&
+ if (beztn && (IS_EQT(cur[0], next[0], thresh)) &&
(IS_EQT(next[1], prev[1], thresh) == 0))
{
/* only add if current is further away from previous */
@@ -548,24 +559,15 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
* storing the relevant information here helps avoiding crashes if we undo-repaste */
if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) {
Object *ob = (Object *)aci->id;
- char *str_start;
-
- if ((str_start = strstr(aci->rna_path, "pose.bones["))) {
- bPoseChannel *pchan;
- int length = 0;
- char *str_end;
-
- str_start += 12;
- str_end = strchr(str_start, '\"');
- length = str_end - str_start;
- str_start[length] = 0;
- pchan = BKE_pose_channel_find_name(ob->pose, str_start);
- str_start[length] = '\"';
-
- if (pchan) {
- aci->is_bone = true;
- }
+ bPoseChannel *pchan;
+ char *bone_name;
+
+ bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones[");
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+ if (pchan) {
+ aci->is_bone = true;
}
+ if (bone_name) MEM_freeN(bone_name);
}
BLI_addtail(&animcopybuf, aci);
@@ -624,22 +626,22 @@ static void flip_names(tAnimCopybufItem *aci, char **name)
char bname_new[MAX_VGROUP_NAME];
char *str_iter, *str_end;
int length, prefix_l, postfix_l;
-
+
str_start += 12;
prefix_l = str_start - aci->rna_path;
-
+
str_end = strchr(str_start, '\"');
-
+
length = str_end - str_start;
postfix_l = strlen(str_end);
-
+
/* more ninja stuff, temporary substitute with NULL terminator */
str_start[length] = 0;
BKE_deform_flip_side_name(bname_new, str_start, false);
str_start[length] = '\"';
-
+
str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path");
-
+
BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1);
str_iter += prefix_l;
BLI_strncpy(str_iter, bname_new, length + 1);
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 7e2ce4cd3f1..85ea5526908 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -130,7 +130,7 @@ bAction *verify_adt_action(ID *id, short add)
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if ((adt == NULL) && (add))
- adt = BKE_id_add_animdata(id);
+ adt = BKE_animdata_add_id(id);
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
printf("ERROR: Couldn't add AnimData (ID = %s)\n", (id) ? (id->name) : "<None>");
@@ -152,6 +152,10 @@ bAction *verify_adt_action(ID *id, short add)
* to the wrong places
*/
adt->action->idroot = GS(id->name);
+
+ /* tag depsgraph to be rebuilt to include time dependency */
+ /* XXX: we probably should have bmain passed down, but that involves altering too many API's */
+ DAG_relations_tag_update(G.main);
}
/* return the action */
@@ -1696,7 +1700,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
char *path;
float cfra = (float)CFRA;
short success = 0;
- int a, index, length;
+ int index;
const bool all = RNA_boolean_get(op->ptr, "all");
short flag = 0;
@@ -1707,33 +1711,35 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if ((ptr.id.data && ptr.data && prop) && RNA_property_animateable(&ptr, prop)) {
- path = RNA_path_from_ID_to_property(&ptr, prop);
-
- if (path) {
- if (all) {
- length = RNA_property_array_length(&ptr, prop);
-
- if (length) index = 0;
- else length = 1;
- }
- else
- length = 1;
-
- for (a = 0; a < length; a++)
- success += insert_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, cfra, flag);
-
- MEM_freeN(path);
- }
- else if (ptr.type == &RNA_NlaStrip) {
- /* handle special vars for NLA-strips */
+ if (ptr.type == &RNA_NlaStrip) {
+ /* Handle special properties for NLA Strips, whose F-Curves are stored on the
+ * strips themselves. These are stored separately or else the properties will
+ * not have any effect.
+ */
NlaStrip *strip = (NlaStrip *)ptr.data;
FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), flag);
- success += insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, 0);
+ success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, 0);
}
else {
- BKE_report(op->reports, RPT_WARNING,
- "Failed to resolve path to property, try manually specifying this using a Keying Set instead");
+ /* standard properties */
+ path = RNA_path_from_ID_to_property(&ptr, prop);
+
+ if (path) {
+ if (all) {
+ /* -1 indicates operating on the entire array (or the property itself otherwise) */
+ index = -1;
+ }
+
+ success = insert_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, cfra, flag);
+
+ MEM_freeN(path);
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING,
+ "Failed to resolve path to property, "
+ "try manually specifying this using a Keying Set instead");
+ }
}
}
else {
@@ -1788,32 +1794,62 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
char *path;
float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
short success = 0;
- int a, index, length;
+ int index;
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop) {
- path = RNA_path_from_ID_to_property(&ptr, prop);
-
- if (path) {
- if (all) {
- length = RNA_property_array_length(&ptr, prop);
+ if (ptr.type == &RNA_NlaStrip) {
+ /* Handle special properties for NLA Strips, whose F-Curves are stored on the
+ * strips themselves. These are stored separately or else the properties will
+ * not have any effect.
+ */
+ ID *id = ptr.id.data;
+ NlaStrip *strip = (NlaStrip *)ptr.data;
+ FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0);
+
+ BLI_assert(fcu != NULL); /* NOTE: This should be true, or else we wouldn't be able to get here */
+
+ if (BKE_fcurve_is_protected(fcu)) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'",
+ strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2);
+ }
+ else {
+ /* remove the keyframe directly
+ * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve,
+ * and delete_keyframe() expects the FCurve to be part of an action
+ */
+ bool found = false;
+ int i;
- if (length) index = 0;
- else length = 1;
+ /* try to find index of beztriple to get rid of */
+ i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
+ if (found) {
+ /* delete the key at the index (will sanity check + do recalc afterwards) */
+ delete_fcurve_key(fcu, i, 1);
+ success = true;
+ }
}
- else
- length = 1;
-
- for (a = 0; a < length; a++)
- success += delete_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, cfra, 0);
+ }
+ else {
+ /* standard properties */
+ path = RNA_path_from_ID_to_property(&ptr, prop);
- MEM_freeN(path);
+ if (path) {
+ if (all) {
+ /* -1 indicates operating on the entire array (or the property itself otherwise) */
+ index = -1;
+ }
+
+ success = delete_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, cfra, 0);
+ MEM_freeN(path);
+ }
+ else if (G.debug & G_DEBUG)
+ printf("Button Delete-Key: no path to property\n");
}
- else if (G.debug & G_DEBUG)
- printf("Button Delete-Key: no path to property\n");
}
else if (G.debug & G_DEBUG) {
printf("ptr.data = %p, prop = %p\n", (void *)ptr.data, (void *)prop);
@@ -1858,7 +1894,7 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
PropertyRNA *prop = NULL;
char *path;
short success = 0;
- int a, index, length;
+ int index;
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
@@ -1869,17 +1905,11 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
if (path) {
if (all) {
- length = RNA_property_array_length(&ptr, prop);
-
- if (length) index = 0;
- else length = 1;
+ /* -1 indicates operating on the entire array (or the property itself otherwise) */
+ index = -1;
}
- else
- length = 1;
-
- for (a = 0; a < length; a++)
- success += clear_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, 0);
+ success += clear_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, 0);
MEM_freeN(path);
}
else if (G.debug & G_DEBUG)