From e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 17 Apr 2019 06:17:24 +0200 Subject: ClangFormat: apply to source, most of intern Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat --- source/blender/editors/space_action/CMakeLists.txt | 42 +- .../blender/editors/space_action/action_buttons.c | 82 +- source/blender/editors/space_action/action_data.c | 1427 +++++------ source/blender/editors/space_action/action_draw.c | 939 +++---- source/blender/editors/space_action/action_edit.c | 2556 +++++++++---------- .../blender/editors/space_action/action_intern.h | 30 +- source/blender/editors/space_action/action_ops.c | 138 +- .../blender/editors/space_action/action_select.c | 2605 ++++++++++---------- source/blender/editors/space_action/space_action.c | 1445 +++++------ 9 files changed, 4704 insertions(+), 4560 deletions(-) (limited to 'source/blender/editors/space_action') diff --git a/source/blender/editors/space_action/CMakeLists.txt b/source/blender/editors/space_action/CMakeLists.txt index 853577180bb..5251ebb1267 100644 --- a/source/blender/editors/space_action/CMakeLists.txt +++ b/source/blender/editors/space_action/CMakeLists.txt @@ -16,37 +16,37 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - ../include - ../../blenkernel - ../../blenlib - ../../blentranslation - ../../gpu - ../../makesdna - ../../makesrna - ../../windowmanager - ../../../../intern/guardedalloc - ../../../../intern/glew-mx + ../include + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../gpu + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/guardedalloc + ../../../../intern/glew-mx ) set(INC_SYS - ${GLEW_INCLUDE_PATH} + ${GLEW_INCLUDE_PATH} ) set(SRC - action_buttons.c - action_data.c - action_draw.c - action_edit.c - action_ops.c - action_select.c - space_action.c + action_buttons.c + action_data.c + action_draw.c + action_edit.c + action_ops.c + action_select.c + space_action.c - action_intern.h + action_intern.h ) set(LIB - bf_blenkernel - bf_blenlib + bf_blenkernel + bf_blenlib ) add_definitions(${GL_DEFINITIONS}) diff --git a/source/blender/editors/space_action/action_buttons.c b/source/blender/editors/space_action/action_buttons.c index eaeeca6dfd1..a30d5f34ed0 100644 --- a/source/blender/editors/space_action/action_buttons.c +++ b/source/blender/editors/space_action/action_buttons.c @@ -21,7 +21,6 @@ * \ingroup spaction */ - #include #include #include @@ -43,7 +42,6 @@ #include "BKE_screen.h" #include "BKE_unit.h" - #include "WM_api.h" #include "WM_types.h" @@ -56,7 +54,7 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "action_intern.h" // own include +#include "action_intern.h" // own include /* ******************* action editor space & buttons ************** */ @@ -65,56 +63,56 @@ void action_buttons_register(ARegionType *UNUSED(art)) { #if 0 - PanelType *pt; - - // TODO: AnimData / Actions List - - pt = MEM_callocN(sizeof(PanelType), "spacetype action panel properties"); - strcpy(pt->idname, "ACTION_PT_properties"); - strcpy(pt->label, N_("Active F-Curve")); - strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw = action_anim_panel_properties; - pt->poll = action_anim_panel_poll; - BLI_addtail(&art->paneltypes, pt); - - pt = MEM_callocN(sizeof(PanelType), "spacetype action panel properties"); - strcpy(pt->idname, "ACTION_PT_key_properties"); - strcpy(pt->label, N_("Active Keyframe")); - strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw = action_anim_panel_key_properties; - pt->poll = action_anim_panel_poll; - BLI_addtail(&art->paneltypes, pt); - - pt = MEM_callocN(sizeof(PanelType), "spacetype action panel modifiers"); - strcpy(pt->idname, "ACTION_PT_modifiers"); - strcpy(pt->label, N_("Modifiers")); - strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw = action_anim_panel_modifiers; - pt->poll = action_anim_panel_poll; - BLI_addtail(&art->paneltypes, pt); + PanelType *pt; + + // TODO: AnimData / Actions List + + pt = MEM_callocN(sizeof(PanelType), "spacetype action panel properties"); + strcpy(pt->idname, "ACTION_PT_properties"); + strcpy(pt->label, N_("Active F-Curve")); + strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + pt->draw = action_anim_panel_properties; + pt->poll = action_anim_panel_poll; + BLI_addtail(&art->paneltypes, pt); + + pt = MEM_callocN(sizeof(PanelType), "spacetype action panel properties"); + strcpy(pt->idname, "ACTION_PT_key_properties"); + strcpy(pt->label, N_("Active Keyframe")); + strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + pt->draw = action_anim_panel_key_properties; + pt->poll = action_anim_panel_poll; + BLI_addtail(&art->paneltypes, pt); + + pt = MEM_callocN(sizeof(PanelType), "spacetype action panel modifiers"); + strcpy(pt->idname, "ACTION_PT_modifiers"); + strcpy(pt->label, N_("Modifiers")); + strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + pt->draw = action_anim_panel_modifiers; + pt->poll = action_anim_panel_poll; + BLI_addtail(&art->paneltypes, pt); #endif } static int action_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = action_has_buttons_region(sa); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = action_has_buttons_region(sa); - if (ar) - ED_region_toggle_hidden(C, ar); + if (ar) + ED_region_toggle_hidden(C, ar); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_properties(wmOperatorType *ot) { - ot->name = "Toggle Sidebar"; - ot->idname = "ACTION_OT_properties"; - ot->description = "Toggle the properties region visibility"; + ot->name = "Toggle Sidebar"; + ot->idname = "ACTION_OT_properties"; + ot->description = "Toggle the properties region visibility"; - ot->exec = action_properties_toggle_exec; - ot->poll = ED_operator_action_active; + ot->exec = action_properties_toggle_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = 0; + /* flags */ + ot->flag = 0; } diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index 8ecf32a2c6c..e9670a0048d 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -21,13 +21,11 @@ * \ingroup spaction */ - #include #include #include #include - #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -76,25 +74,25 @@ /* Helper function to find the active AnimData block from the Action Editor context */ AnimData *ED_actedit_animdata_from_context(bContext *C) { - SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); - Object *ob = CTX_data_active_object(C); - AnimData *adt = NULL; - - /* Get AnimData block to use */ - if (saction->mode == SACTCONT_ACTION) { - /* Currently, "Action Editor" means object-level only... */ - if (ob) { - adt = ob->adt; - } - } - else if (saction->mode == SACTCONT_SHAPEKEY) { - Key *key = BKE_key_from_object(ob); - if (key) { - adt = key->adt; - } - } - - return adt; + SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); + Object *ob = CTX_data_active_object(C); + AnimData *adt = NULL; + + /* Get AnimData block to use */ + if (saction->mode == SACTCONT_ACTION) { + /* Currently, "Action Editor" means object-level only... */ + if (ob) { + adt = ob->adt; + } + } + else if (saction->mode == SACTCONT_SHAPEKEY) { + Key *key = BKE_key_from_object(ob); + if (key) { + adt = key->adt; + } + } + + return adt; } /* -------------------------------------------------------------------- */ @@ -102,61 +100,61 @@ AnimData *ED_actedit_animdata_from_context(bContext *C) /* Create new action */ static bAction *action_create_new(bContext *C, bAction *oldact) { - ScrArea *sa = CTX_wm_area(C); - bAction *action; - - /* create action - the way to do this depends on whether we've got an - * existing one there already, in which case we make a copy of it - * (which is useful for "versioning" actions within the same file) - */ - if (oldact && GS(oldact->id.name) == ID_AC) { - /* make a copy of the existing action */ - action = BKE_action_copy(CTX_data_main(C), oldact); - } - else { - /* just make a new (empty) action */ - action = BKE_action_add(CTX_data_main(C), "Action"); - } - - /* when creating new ID blocks, there is already 1 user (as for all new datablocks), - * but the RNA pointer code will assign all the proper users instead, so we compensate - * for that here - */ - BLI_assert(action->id.us == 1); - id_us_min(&action->id); - - /* set ID-Root type */ - if (sa->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)sa->spacedata.first; - - if (saction->mode == SACTCONT_SHAPEKEY) - action->idroot = ID_KE; - else - action->idroot = ID_OB; - } - - return action; + ScrArea *sa = CTX_wm_area(C); + bAction *action; + + /* create action - the way to do this depends on whether we've got an + * existing one there already, in which case we make a copy of it + * (which is useful for "versioning" actions within the same file) + */ + if (oldact && GS(oldact->id.name) == ID_AC) { + /* make a copy of the existing action */ + action = BKE_action_copy(CTX_data_main(C), oldact); + } + else { + /* just make a new (empty) action */ + action = BKE_action_add(CTX_data_main(C), "Action"); + } + + /* when creating new ID blocks, there is already 1 user (as for all new datablocks), + * but the RNA pointer code will assign all the proper users instead, so we compensate + * for that here + */ + BLI_assert(action->id.us == 1); + id_us_min(&action->id); + + /* set ID-Root type */ + if (sa->spacetype == SPACE_ACTION) { + SpaceAction *saction = (SpaceAction *)sa->spacedata.first; + + if (saction->mode == SACTCONT_SHAPEKEY) + action->idroot = ID_KE; + else + action->idroot = ID_OB; + } + + return action; } /* Change the active action used by the action editor */ static void actedit_change_action(bContext *C, bAction *act) { - bScreen *screen = CTX_wm_screen(C); - SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); + bScreen *screen = CTX_wm_screen(C); + SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); - PointerRNA ptr, idptr; - PropertyRNA *prop; + PointerRNA ptr, idptr; + PropertyRNA *prop; - /* create RNA pointers and get the property */ - RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, saction, &ptr); - prop = RNA_struct_find_property(&ptr, "action"); + /* create RNA pointers and get the property */ + RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, saction, &ptr); + prop = RNA_struct_find_property(&ptr, "action"); - /* NOTE: act may be NULL here, so better to just use a cast here */ - RNA_id_pointer_create((ID *)act, &idptr); + /* NOTE: act may be NULL here, so better to just use a cast here */ + RNA_id_pointer_create((ID *)act, &idptr); - /* set the new pointer, and force a refresh */ - RNA_property_pointer_set(&ptr, prop, idptr); - RNA_property_update(C, &ptr, prop); + /* set the new pointer, and force a refresh */ + RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_update(C, &ptr, prop); } /* ******************** New Action Operator *********************** */ @@ -169,115 +167,115 @@ static void actedit_change_action(bContext *C, bAction *act) */ static bool action_new_poll(bContext *C) { - Scene *scene = CTX_data_scene(C); - - /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */ - /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */ - if (ED_operator_action_active(C)) { - SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); - Object *ob = CTX_data_active_object(C); - - /* For now, actions are only for the active object, and on object and shapekey levels... */ - if (saction->mode == SACTCONT_ACTION) { - /* XXX: This assumes that actions are assigned to the active object in this mode */ - if (ob) { - if ((ob->adt == NULL) || (ob->adt->flag & ADT_NLA_EDIT_ON) == 0) - return true; - } - } - else if (saction->mode == SACTCONT_SHAPEKEY) { - Key *key = BKE_key_from_object(ob); - if (key) { - if ((key->adt == NULL) || (key->adt->flag & ADT_NLA_EDIT_ON) == 0) - return true; - } - } - } - else if (ED_operator_nla_active(C)) { - if (!(scene->flag & SCE_NLA_EDIT_ON)) { - return true; - } - } - - /* something failed... */ - return false; + Scene *scene = CTX_data_scene(C); + + /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */ + /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */ + if (ED_operator_action_active(C)) { + SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); + Object *ob = CTX_data_active_object(C); + + /* For now, actions are only for the active object, and on object and shapekey levels... */ + if (saction->mode == SACTCONT_ACTION) { + /* XXX: This assumes that actions are assigned to the active object in this mode */ + if (ob) { + if ((ob->adt == NULL) || (ob->adt->flag & ADT_NLA_EDIT_ON) == 0) + return true; + } + } + else if (saction->mode == SACTCONT_SHAPEKEY) { + Key *key = BKE_key_from_object(ob); + if (key) { + if ((key->adt == NULL) || (key->adt->flag & ADT_NLA_EDIT_ON) == 0) + return true; + } + } + } + else if (ED_operator_nla_active(C)) { + if (!(scene->flag & SCE_NLA_EDIT_ON)) { + return true; + } + } + + /* something failed... */ + return false; } static int action_new_exec(bContext *C, wmOperator *UNUSED(op)) { - PointerRNA ptr, idptr; - PropertyRNA *prop; - - /* hook into UI */ - UI_context_active_but_prop_get_templateID(C, &ptr, &prop); - - if (prop) { - bAction *action = NULL, *oldact = NULL; - AnimData *adt = NULL; - PointerRNA oldptr; - - oldptr = RNA_property_pointer_get(&ptr, prop); - oldact = (bAction *)oldptr.id.data; - - /* stash the old action to prevent it from being lost */ - if (ptr.type == &RNA_AnimData) { - adt = ptr.data; - } - else if (ptr.type == &RNA_SpaceDopeSheetEditor) { - adt = ED_actedit_animdata_from_context(C); - } - - /* Perform stashing operation - But only if there is an action */ - if (adt && oldact) { - /* stash the action */ - if (BKE_nla_action_stash(adt)) { - /* The stash operation will remove the user already - * (and unlink the action from the AnimData action slot). - * Hence, we must unset the ref to the action in the - * action editor too (if this is where we're being called from) - * first before setting the new action once it is created, - * or else the user gets decremented twice! - */ - if (ptr.type == &RNA_SpaceDopeSheetEditor) { - SpaceAction *saction = (SpaceAction *)ptr.data; - saction->action = NULL; - } - } - else { - //printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n", oldact->id.name); - } - } - - /* create action */ - action = action_create_new(C, oldact); - - /* set this new action - * NOTE: we can't use actedit_change_action, as this function is also called from the NLA - */ - RNA_id_pointer_create(&action->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr); - RNA_property_update(C, &ptr, prop); - } - - /* set notifier that keyframes have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); - - return OPERATOR_FINISHED; + PointerRNA ptr, idptr; + PropertyRNA *prop; + + /* hook into UI */ + UI_context_active_but_prop_get_templateID(C, &ptr, &prop); + + if (prop) { + bAction *action = NULL, *oldact = NULL; + AnimData *adt = NULL; + PointerRNA oldptr; + + oldptr = RNA_property_pointer_get(&ptr, prop); + oldact = (bAction *)oldptr.id.data; + + /* stash the old action to prevent it from being lost */ + if (ptr.type == &RNA_AnimData) { + adt = ptr.data; + } + else if (ptr.type == &RNA_SpaceDopeSheetEditor) { + adt = ED_actedit_animdata_from_context(C); + } + + /* Perform stashing operation - But only if there is an action */ + if (adt && oldact) { + /* stash the action */ + if (BKE_nla_action_stash(adt)) { + /* The stash operation will remove the user already + * (and unlink the action from the AnimData action slot). + * Hence, we must unset the ref to the action in the + * action editor too (if this is where we're being called from) + * first before setting the new action once it is created, + * or else the user gets decremented twice! + */ + if (ptr.type == &RNA_SpaceDopeSheetEditor) { + SpaceAction *saction = (SpaceAction *)ptr.data; + saction->action = NULL; + } + } + else { + //printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n", oldact->id.name); + } + } + + /* create action */ + action = action_create_new(C, oldact); + + /* set this new action + * NOTE: we can't use actedit_change_action, as this function is also called from the NLA + */ + RNA_id_pointer_create(&action->id, &idptr); + RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_update(C, &ptr, prop); + } + + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); + + return OPERATOR_FINISHED; } void ACTION_OT_new(wmOperatorType *ot) { - /* identifiers */ - ot->name = "New Action"; - ot->idname = "ACTION_OT_new"; - ot->description = "Create new action"; + /* identifiers */ + ot->name = "New Action"; + ot->idname = "ACTION_OT_new"; + ot->description = "Create new action"; - /* api callbacks */ - ot->exec = action_new_exec; - ot->poll = action_new_poll; + /* api callbacks */ + ot->exec = action_new_exec; + ot->poll = action_new_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************* Action Push-Down Operator ******************** */ @@ -289,127 +287,130 @@ void ACTION_OT_new(wmOperatorType *ot) */ static bool action_pushdown_poll(bContext *C) { - if (ED_operator_action_active(C)) { - SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); - AnimData *adt = ED_actedit_animdata_from_context(C); - - /* Check for AnimData, Actions, and that tweakmode is off */ - if (adt && saction->action) { - /* NOTE: We check this for the AnimData block in question and not the global flag, - * as the global flag may be left dirty by some of the browsing ops here. - */ - if (!(adt->flag & ADT_NLA_EDIT_ON)) - return true; - } - } - - /* something failed... */ - return false; + if (ED_operator_action_active(C)) { + SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); + AnimData *adt = ED_actedit_animdata_from_context(C); + + /* Check for AnimData, Actions, and that tweakmode is off */ + if (adt && saction->action) { + /* NOTE: We check this for the AnimData block in question and not the global flag, + * as the global flag may be left dirty by some of the browsing ops here. + */ + if (!(adt->flag & ADT_NLA_EDIT_ON)) + return true; + } + } + + /* something failed... */ + return false; } static int action_pushdown_exec(bContext *C, wmOperator *op) { - SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); - AnimData *adt = ED_actedit_animdata_from_context(C); - - /* Do the deed... */ - if (adt) { - /* Perform the pushdown operation - * - This will deal with all the AnimData-side usercounts - */ - if (action_has_motion(adt->action) == 0) { - /* action may not be suitable... */ - BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier"); - return OPERATOR_CANCELLED; - } - else { - /* action can be safely added */ - BKE_nla_action_pushdown(adt); - } - - /* Stop displaying this action in this editor - * NOTE: The editor itself doesn't set a user... - */ - saction->action = NULL; - } - - /* Send notifiers that stuff has changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); - return OPERATOR_FINISHED; + SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); + AnimData *adt = ED_actedit_animdata_from_context(C); + + /* Do the deed... */ + if (adt) { + /* Perform the pushdown operation + * - This will deal with all the AnimData-side usercounts + */ + if (action_has_motion(adt->action) == 0) { + /* action may not be suitable... */ + BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier"); + return OPERATOR_CANCELLED; + } + else { + /* action can be safely added */ + BKE_nla_action_pushdown(adt); + } + + /* Stop displaying this action in this editor + * NOTE: The editor itself doesn't set a user... + */ + saction->action = NULL; + } + + /* Send notifiers that stuff has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + return OPERATOR_FINISHED; } void ACTION_OT_push_down(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Push Down Action"; - ot->idname = "ACTION_OT_push_down"; - ot->description = "Push action down on to the NLA stack as a new strip"; + /* identifiers */ + ot->name = "Push Down Action"; + ot->idname = "ACTION_OT_push_down"; + ot->description = "Push action down on to the NLA stack as a new strip"; - /* callbacks */ - ot->exec = action_pushdown_exec; - ot->poll = action_pushdown_poll; + /* callbacks */ + ot->exec = action_pushdown_exec; + ot->poll = action_pushdown_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************* Action Stash Operator ******************** */ static int action_stash_exec(bContext *C, wmOperator *op) { - SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); - AnimData *adt = ED_actedit_animdata_from_context(C); - - /* Perform stashing operation */ - if (adt) { - /* don't do anything if this action is empty... */ - if (action_has_motion(adt->action) == 0) { - /* action may not be suitable... */ - BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier"); - return OPERATOR_CANCELLED; - } - else { - /* stash the action */ - if (BKE_nla_action_stash(adt)) { - /* The stash operation will remove the user already, - * so the flushing step later shouldn't double up - * the usercount fixes. Hence, we must unset this ref - * first before setting the new action. - */ - saction->action = NULL; - } - else { - /* action has already been added - simply warn about this, and clear */ - BKE_report(op->reports, RPT_ERROR, "Action has already been stashed"); - } - - /* clear action refs from editor, and then also the backing data (not necessary) */ - actedit_change_action(C, NULL); - } - } - - /* Send notifiers that stuff has changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); - return OPERATOR_FINISHED; + SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); + AnimData *adt = ED_actedit_animdata_from_context(C); + + /* Perform stashing operation */ + if (adt) { + /* don't do anything if this action is empty... */ + if (action_has_motion(adt->action) == 0) { + /* action may not be suitable... */ + BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier"); + return OPERATOR_CANCELLED; + } + else { + /* stash the action */ + if (BKE_nla_action_stash(adt)) { + /* The stash operation will remove the user already, + * so the flushing step later shouldn't double up + * the usercount fixes. Hence, we must unset this ref + * first before setting the new action. + */ + saction->action = NULL; + } + else { + /* action has already been added - simply warn about this, and clear */ + BKE_report(op->reports, RPT_ERROR, "Action has already been stashed"); + } + + /* clear action refs from editor, and then also the backing data (not necessary) */ + actedit_change_action(C, NULL); + } + } + + /* Send notifiers that stuff has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + return OPERATOR_FINISHED; } void ACTION_OT_stash(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Stash Action"; - ot->idname = "ACTION_OT_stash"; - ot->description = "Store this action in the NLA stack as a non-contributing strip for later use"; - - /* callbacks */ - ot->exec = action_stash_exec; - ot->poll = action_pushdown_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_boolean(ot->srna, "create_new", true, "Create New Action", - "Create a new action once the existing one has been safely stored"); + /* identifiers */ + ot->name = "Stash Action"; + ot->idname = "ACTION_OT_stash"; + ot->description = "Store this action in the NLA stack as a non-contributing strip for later use"; + + /* callbacks */ + ot->exec = action_stash_exec; + ot->poll = action_pushdown_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_boolean(ot->srna, + "create_new", + true, + "Create New Action", + "Create a new action once the existing one has been safely stored"); } /* ----------------- */ @@ -420,94 +421,96 @@ void ACTION_OT_stash(wmOperatorType *ot) */ static bool action_stash_create_poll(bContext *C) { - if (ED_operator_action_active(C)) { - AnimData *adt = ED_actedit_animdata_from_context(C); - - /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */ - /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */ - if (adt) { - if (!(adt->flag & ADT_NLA_EDIT_ON)) - return true; - } - else { - /* There may not be any action/animdata yet, so, just fallback to the global setting - * (which may not be totally valid yet if the action editor was used and things are - * now in an inconsistent state) - */ - SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); - Scene *scene = CTX_data_scene(C); - - if (!(scene->flag & SCE_NLA_EDIT_ON)) { - /* For now, actions are only for the active object, and on object and shapekey levels... */ - return ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY); - } - } - } - - /* something failed... */ - return false; + if (ED_operator_action_active(C)) { + AnimData *adt = ED_actedit_animdata_from_context(C); + + /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */ + /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */ + if (adt) { + if (!(adt->flag & ADT_NLA_EDIT_ON)) + return true; + } + else { + /* There may not be any action/animdata yet, so, just fallback to the global setting + * (which may not be totally valid yet if the action editor was used and things are + * now in an inconsistent state) + */ + SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); + Scene *scene = CTX_data_scene(C); + + if (!(scene->flag & SCE_NLA_EDIT_ON)) { + /* For now, actions are only for the active object, and on object and shapekey levels... */ + return ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY); + } + } + } + + /* something failed... */ + return false; } static int action_stash_create_exec(bContext *C, wmOperator *op) { - SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); - AnimData *adt = ED_actedit_animdata_from_context(C); - - /* Check for no action... */ - if (saction->action == NULL) { - /* just create a new action */ - bAction *action = action_create_new(C, NULL); - actedit_change_action(C, action); - } - else if (adt) { - /* Perform stashing operation */ - if (action_has_motion(adt->action) == 0) { - /* don't do anything if this action is empty... */ - BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier"); - return OPERATOR_CANCELLED; - } - else { - /* stash the action */ - if (BKE_nla_action_stash(adt)) { - bAction *new_action = NULL; - - /* create new action not based on the old one (since the "new" operator already does that) */ - new_action = action_create_new(C, NULL); - - /* The stash operation will remove the user already, - * so the flushing step later shouldn't double up - * the usercount fixes. Hence, we must unset this ref - * first before setting the new action. - */ - saction->action = NULL; - actedit_change_action(C, new_action); - } - else { - /* action has already been added - simply warn about this, and clear */ - BKE_report(op->reports, RPT_ERROR, "Action has already been stashed"); - actedit_change_action(C, NULL); - } - } - } - - /* Send notifiers that stuff has changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); - return OPERATOR_FINISHED; + SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); + AnimData *adt = ED_actedit_animdata_from_context(C); + + /* Check for no action... */ + if (saction->action == NULL) { + /* just create a new action */ + bAction *action = action_create_new(C, NULL); + actedit_change_action(C, action); + } + else if (adt) { + /* Perform stashing operation */ + if (action_has_motion(adt->action) == 0) { + /* don't do anything if this action is empty... */ + BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier"); + return OPERATOR_CANCELLED; + } + else { + /* stash the action */ + if (BKE_nla_action_stash(adt)) { + bAction *new_action = NULL; + + /* create new action not based on the old one (since the "new" operator already does that) */ + new_action = action_create_new(C, NULL); + + /* The stash operation will remove the user already, + * so the flushing step later shouldn't double up + * the usercount fixes. Hence, we must unset this ref + * first before setting the new action. + */ + saction->action = NULL; + actedit_change_action(C, new_action); + } + else { + /* action has already been added - simply warn about this, and clear */ + BKE_report(op->reports, RPT_ERROR, "Action has already been stashed"); + actedit_change_action(C, NULL); + } + } + } + + /* Send notifiers that stuff has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + return OPERATOR_FINISHED; } void ACTION_OT_stash_and_create(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Stash Action"; - ot->idname = "ACTION_OT_stash_and_create"; - ot->description = "Store this action in the NLA stack as a non-contributing strip for later use, and create a new action"; - - /* callbacks */ - ot->exec = action_stash_create_exec; - ot->poll = action_stash_create_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Stash Action"; + ot->idname = "ACTION_OT_stash_and_create"; + ot->description = + "Store this action in the NLA stack as a non-contributing strip for later use, and create a " + "new action"; + + /* callbacks */ + ot->exec = action_stash_create_exec; + ot->poll = action_stash_create_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ************************************************************************** */ @@ -522,146 +525,152 @@ void ACTION_OT_stash_and_create(wmOperatorType *ot) * 3) We need a convenient way to exit Tweak Mode from the Action Editor */ -void ED_animedit_unlink_action(bContext *C, ID *id, AnimData *adt, bAction *act, ReportList *reports, bool force_delete) +void ED_animedit_unlink_action( + bContext *C, ID *id, AnimData *adt, bAction *act, ReportList *reports, bool force_delete) { - ScrArea *sa = CTX_wm_area(C); - - /* If the old action only has a single user (that it's about to lose), - * warn user about it - * - * TODO: Maybe we should just save it for them? But then, there's the problem of - * trying to get rid of stuff that's actually unwanted! - */ - if (act->id.us == 1) { - BKE_reportf(reports, RPT_WARNING, - "Action '%s' will not be saved, create Fake User or Stash in NLA Stack to retain", - act->id.name + 2); - } - - /* Clear Fake User and remove action stashing strip (if present) */ - if (force_delete) { - /* Remove stashed strip binding this action to this datablock */ - /* XXX: we cannot unlink it from *OTHER* datablocks that may also be stashing it, - * but GE users only seem to use/care about single-object binding for now so this - * should be fine - */ - if (adt) { - NlaTrack *nlt, *nlt_next; - NlaStrip *strip, *nstrip; - - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt_next) { - nlt_next = nlt->next; - - if (strstr(nlt->name, DATA_("[Action Stash]"))) { - for (strip = nlt->strips.first; strip; strip = nstrip) { - nstrip = strip->next; - - if (strip->act == act) { - /* Remove this strip, and the track too if it doesn't have anything else */ - BKE_nlastrip_free(&nlt->strips, strip, true); - - if (nlt->strips.first == NULL) { - BLI_assert(nstrip == NULL); - BKE_nlatrack_free(&adt->nla_tracks, nlt, true); - } - } - } - } - } - } - - /* Clear Fake User */ - id_fake_user_clear(&act->id); - } - - /* If in Tweak Mode, don't unlink. Instead, this - * becomes a shortcut to exit Tweak Mode instead - */ - if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) { - /* Exit Tweak Mode */ - BKE_nla_tweakmode_exit(adt); - - /* Flush this to the Action Editor (if that's where this change was initiated) */ - if (sa->spacetype == SPACE_ACTION) { - actedit_change_action(C, NULL); - } - } - else { - /* Unlink normally - Setting it to NULL should be enough to get the old one unlinked */ - if (sa->spacetype == SPACE_ACTION) { - /* clear action editor -> action */ - actedit_change_action(C, NULL); - } - else { - /* clear AnimData -> action */ - PointerRNA ptr; - PropertyRNA *prop; - - /* create AnimData RNA pointers */ - RNA_pointer_create(id, &RNA_AnimData, adt, &ptr); - prop = RNA_struct_find_property(&ptr, "action"); - - /* clear... */ - RNA_property_pointer_set(&ptr, prop, PointerRNA_NULL); - RNA_property_update(C, &ptr, prop); - } - } + ScrArea *sa = CTX_wm_area(C); + + /* If the old action only has a single user (that it's about to lose), + * warn user about it + * + * TODO: Maybe we should just save it for them? But then, there's the problem of + * trying to get rid of stuff that's actually unwanted! + */ + if (act->id.us == 1) { + BKE_reportf(reports, + RPT_WARNING, + "Action '%s' will not be saved, create Fake User or Stash in NLA Stack to retain", + act->id.name + 2); + } + + /* Clear Fake User and remove action stashing strip (if present) */ + if (force_delete) { + /* Remove stashed strip binding this action to this datablock */ + /* XXX: we cannot unlink it from *OTHER* datablocks that may also be stashing it, + * but GE users only seem to use/care about single-object binding for now so this + * should be fine + */ + if (adt) { + NlaTrack *nlt, *nlt_next; + NlaStrip *strip, *nstrip; + + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt_next) { + nlt_next = nlt->next; + + if (strstr(nlt->name, DATA_("[Action Stash]"))) { + for (strip = nlt->strips.first; strip; strip = nstrip) { + nstrip = strip->next; + + if (strip->act == act) { + /* Remove this strip, and the track too if it doesn't have anything else */ + BKE_nlastrip_free(&nlt->strips, strip, true); + + if (nlt->strips.first == NULL) { + BLI_assert(nstrip == NULL); + BKE_nlatrack_free(&adt->nla_tracks, nlt, true); + } + } + } + } + } + } + + /* Clear Fake User */ + id_fake_user_clear(&act->id); + } + + /* If in Tweak Mode, don't unlink. Instead, this + * becomes a shortcut to exit Tweak Mode instead + */ + if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) { + /* Exit Tweak Mode */ + BKE_nla_tweakmode_exit(adt); + + /* Flush this to the Action Editor (if that's where this change was initiated) */ + if (sa->spacetype == SPACE_ACTION) { + actedit_change_action(C, NULL); + } + } + else { + /* Unlink normally - Setting it to NULL should be enough to get the old one unlinked */ + if (sa->spacetype == SPACE_ACTION) { + /* clear action editor -> action */ + actedit_change_action(C, NULL); + } + else { + /* clear AnimData -> action */ + PointerRNA ptr; + PropertyRNA *prop; + + /* create AnimData RNA pointers */ + RNA_pointer_create(id, &RNA_AnimData, adt, &ptr); + prop = RNA_struct_find_property(&ptr, "action"); + + /* clear... */ + RNA_property_pointer_set(&ptr, prop, PointerRNA_NULL); + RNA_property_update(C, &ptr, prop); + } + } } /* -------------------------- */ static bool action_unlink_poll(bContext *C) { - if (ED_operator_action_active(C)) { - SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); - AnimData *adt = ED_actedit_animdata_from_context(C); + if (ED_operator_action_active(C)) { + SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); + AnimData *adt = ED_actedit_animdata_from_context(C); - /* Only when there's an active action, in the right modes... */ - if (saction->action && adt) - return true; - } + /* Only when there's an active action, in the right modes... */ + if (saction->action && adt) + return true; + } - /* something failed... */ - return false; + /* something failed... */ + return false; } static int action_unlink_exec(bContext *C, wmOperator *op) { - AnimData *adt = ED_actedit_animdata_from_context(C); - bool force_delete = RNA_boolean_get(op->ptr, "force_delete"); + AnimData *adt = ED_actedit_animdata_from_context(C); + bool force_delete = RNA_boolean_get(op->ptr, "force_delete"); - if (adt && adt->action) { - ED_animedit_unlink_action(C, NULL, adt, adt->action, op->reports, force_delete); - } + if (adt && adt->action) { + ED_animedit_unlink_action(C, NULL, adt, adt->action, op->reports, force_delete); + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *evt) { - /* NOTE: this is hardcoded to match the behavior for the unlink button (in interface_templates.c) */ - RNA_boolean_set(op->ptr, "force_delete", evt->shift != 0); - return action_unlink_exec(C, op); + /* NOTE: this is hardcoded to match the behavior for the unlink button (in interface_templates.c) */ + RNA_boolean_set(op->ptr, "force_delete", evt->shift != 0); + return action_unlink_exec(C, op); } void ACTION_OT_unlink(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Unlink Action"; - ot->idname = "ACTION_OT_unlink"; - ot->description = "Unlink this action from the active action slot (and/or exit Tweak Mode)"; - - /* callbacks */ - ot->invoke = action_unlink_invoke; - ot->exec = action_unlink_exec; - ot->poll = action_unlink_poll; - - /* properties */ - prop = RNA_def_boolean(ot->srna, "force_delete", false, "Force Delete", "Clear Fake User and remove " - "copy stashed in this data-block's NLA stack"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Unlink Action"; + ot->idname = "ACTION_OT_unlink"; + ot->description = "Unlink this action from the active action slot (and/or exit Tweak Mode)"; + + /* callbacks */ + ot->invoke = action_unlink_invoke; + ot->exec = action_unlink_exec; + ot->poll = action_unlink_poll; + + /* properties */ + prop = RNA_def_boolean(ot->srna, + "force_delete", + false, + "Force Delete", + "Clear Fake User and remove " + "copy stashed in this data-block's NLA stack"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* ************************************************************************** */ @@ -670,282 +679,284 @@ void ACTION_OT_unlink(wmOperatorType *ot) /* Try to find NLA Strip to use for action layer up/down tool */ static NlaStrip *action_layer_get_nlastrip(ListBase *strips, float ctime) { - NlaStrip *strip; - - for (strip = strips->first; strip; strip = strip->next) { - /* Can we use this? */ - if (IN_RANGE_INCL(ctime, strip->start, strip->end)) { - /* in range - use this one */ - return strip; - } - else if ((ctime < strip->start) && (strip->prev == NULL)) { - /* before first - use this one */ - return strip; - } - else if ((ctime > strip->end) && (strip->next == NULL)) { - /* after last - use this one */ - return strip; - } - } - - /* nothing suitable found... */ - return NULL; + NlaStrip *strip; + + for (strip = strips->first; strip; strip = strip->next) { + /* Can we use this? */ + if (IN_RANGE_INCL(ctime, strip->start, strip->end)) { + /* in range - use this one */ + return strip; + } + else if ((ctime < strip->start) && (strip->prev == NULL)) { + /* before first - use this one */ + return strip; + } + else if ((ctime > strip->end) && (strip->next == NULL)) { + /* after last - use this one */ + return strip; + } + } + + /* nothing suitable found... */ + return NULL; } /* Switch NLA Strips/Actions */ -static void action_layer_switch_strip(AnimData *adt, - NlaTrack *old_track, NlaStrip *old_strip, - NlaTrack *nlt, NlaStrip *strip) +static void action_layer_switch_strip( + AnimData *adt, NlaTrack *old_track, NlaStrip *old_strip, NlaTrack *nlt, NlaStrip *strip) { - /* Exit tweakmode on old strip - * NOTE: We need to manually clear this stuff ourselves, as tweakmode exit doesn't do it - */ - BKE_nla_tweakmode_exit(adt); - - if (old_strip) { - old_strip->flag &= ~(NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT); - } - if (old_track) { - old_track->flag &= ~(NLATRACK_ACTIVE | NLATRACK_SELECTED); - } - - /* Make this one the active one instead */ - strip->flag |= (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT); - nlt->flag |= NLATRACK_ACTIVE; - - /* Copy over "solo" flag - This is useful for stashed actions... */ - if (old_track) { - if (old_track->flag & NLATRACK_SOLO) { - old_track->flag &= ~NLATRACK_SOLO; - nlt->flag |= NLATRACK_SOLO; - } - } - else { - /* NLA muting <==> Solo Tracks */ - if (adt->flag & ADT_NLA_EVAL_OFF) { - /* disable NLA muting */ - adt->flag &= ~ADT_NLA_EVAL_OFF; - - /* mark this track as being solo */ - adt->flag |= ADT_NLA_SOLO_TRACK; - nlt->flag |= NLATRACK_SOLO; - - // TODO: Needs restpose flushing (when we get reference track) - } - } - - /* Enter tweakmode again - hopefully we're now "it" */ - BKE_nla_tweakmode_enter(adt); - BLI_assert(adt->actstrip == strip); + /* Exit tweakmode on old strip + * NOTE: We need to manually clear this stuff ourselves, as tweakmode exit doesn't do it + */ + BKE_nla_tweakmode_exit(adt); + + if (old_strip) { + old_strip->flag &= ~(NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT); + } + if (old_track) { + old_track->flag &= ~(NLATRACK_ACTIVE | NLATRACK_SELECTED); + } + + /* Make this one the active one instead */ + strip->flag |= (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT); + nlt->flag |= NLATRACK_ACTIVE; + + /* Copy over "solo" flag - This is useful for stashed actions... */ + if (old_track) { + if (old_track->flag & NLATRACK_SOLO) { + old_track->flag &= ~NLATRACK_SOLO; + nlt->flag |= NLATRACK_SOLO; + } + } + else { + /* NLA muting <==> Solo Tracks */ + if (adt->flag & ADT_NLA_EVAL_OFF) { + /* disable NLA muting */ + adt->flag &= ~ADT_NLA_EVAL_OFF; + + /* mark this track as being solo */ + adt->flag |= ADT_NLA_SOLO_TRACK; + nlt->flag |= NLATRACK_SOLO; + + // TODO: Needs restpose flushing (when we get reference track) + } + } + + /* Enter tweakmode again - hopefully we're now "it" */ + BKE_nla_tweakmode_enter(adt); + BLI_assert(adt->actstrip == strip); } /* ********************** One Layer Up Operator ************************** */ static bool action_layer_next_poll(bContext *C) { - /* Action Editor's action editing modes only */ - if (ED_operator_action_active(C)) { - AnimData *adt = ED_actedit_animdata_from_context(C); - if (adt) { - /* only allow if we're in tweakmode, and there's something above us... */ - if (adt->flag & ADT_NLA_EDIT_ON) { - /* We need to check if there are any tracks above the active one - * since the track the action comes from is not stored in AnimData - */ - if (adt->nla_tracks.last) { - NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.last; - - if (nlt->flag & NLATRACK_DISABLED) { - /* A disabled track will either be the track itself, - * or one of the ones above it. - * - * If this is the top-most one, there is the possibility - * that there is no active action. For now, we let this - * case return true too, so that there is a natural way - * to "move to an empty layer", even though this means - * that we won't actually have an action. - */ - // return (adt->tmpact != NULL); - return true; - } - } - } - } - } - - /* something failed... */ - return false; + /* Action Editor's action editing modes only */ + if (ED_operator_action_active(C)) { + AnimData *adt = ED_actedit_animdata_from_context(C); + if (adt) { + /* only allow if we're in tweakmode, and there's something above us... */ + if (adt->flag & ADT_NLA_EDIT_ON) { + /* We need to check if there are any tracks above the active one + * since the track the action comes from is not stored in AnimData + */ + if (adt->nla_tracks.last) { + NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.last; + + if (nlt->flag & NLATRACK_DISABLED) { + /* A disabled track will either be the track itself, + * or one of the ones above it. + * + * If this is the top-most one, there is the possibility + * that there is no active action. For now, we let this + * case return true too, so that there is a natural way + * to "move to an empty layer", even though this means + * that we won't actually have an action. + */ + // return (adt->tmpact != NULL); + return true; + } + } + } + } + } + + /* something failed... */ + return false; } static int action_layer_next_exec(bContext *C, wmOperator *op) { - AnimData *adt = ED_actedit_animdata_from_context(C); - NlaTrack *act_track; - - Scene *scene = CTX_data_scene(C); - float ctime = BKE_scene_frame_get(scene); - - /* Get active track */ - act_track = BKE_nlatrack_find_tweaked(adt); - - if (act_track == NULL) { - BKE_report(op->reports, RPT_ERROR, "Could not find current NLA Track"); - return OPERATOR_CANCELLED; - } - - /* Find next action, and hook it up */ - if (act_track->next) { - NlaTrack *nlt; - - /* Find next action to use */ - for (nlt = act_track->next; nlt; nlt = nlt->next) { - NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime); - - if (strip) { - action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip); - break; - } - } - } - else { - /* No more actions (strips) - Go back to editing the original active action - * NOTE: This will mean exiting tweakmode... - */ - BKE_nla_tweakmode_exit(adt); - - /* Deal with solo flags... - * Assume: Solo Track == NLA Muting - */ - if (adt->flag & ADT_NLA_SOLO_TRACK) { - /* turn off solo flags on tracks */ - act_track->flag &= ~NLATRACK_SOLO; - adt->flag &= ~ADT_NLA_SOLO_TRACK; - - /* turn on NLA muting (to keep same effect) */ - adt->flag |= ADT_NLA_EVAL_OFF; - - // TODO: Needs restpose flushing (when we get reference track) - } - } - - /* Update the action that this editor now uses - * NOTE: The calls above have already handled the usercount/animdata side of things - */ - actedit_change_action(C, adt->action); - return OPERATOR_FINISHED; + AnimData *adt = ED_actedit_animdata_from_context(C); + NlaTrack *act_track; + + Scene *scene = CTX_data_scene(C); + float ctime = BKE_scene_frame_get(scene); + + /* Get active track */ + act_track = BKE_nlatrack_find_tweaked(adt); + + if (act_track == NULL) { + BKE_report(op->reports, RPT_ERROR, "Could not find current NLA Track"); + return OPERATOR_CANCELLED; + } + + /* Find next action, and hook it up */ + if (act_track->next) { + NlaTrack *nlt; + + /* Find next action to use */ + for (nlt = act_track->next; nlt; nlt = nlt->next) { + NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime); + + if (strip) { + action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip); + break; + } + } + } + else { + /* No more actions (strips) - Go back to editing the original active action + * NOTE: This will mean exiting tweakmode... + */ + BKE_nla_tweakmode_exit(adt); + + /* Deal with solo flags... + * Assume: Solo Track == NLA Muting + */ + if (adt->flag & ADT_NLA_SOLO_TRACK) { + /* turn off solo flags on tracks */ + act_track->flag &= ~NLATRACK_SOLO; + adt->flag &= ~ADT_NLA_SOLO_TRACK; + + /* turn on NLA muting (to keep same effect) */ + adt->flag |= ADT_NLA_EVAL_OFF; + + // TODO: Needs restpose flushing (when we get reference track) + } + } + + /* Update the action that this editor now uses + * NOTE: The calls above have already handled the usercount/animdata side of things + */ + actedit_change_action(C, adt->action); + return OPERATOR_FINISHED; } void ACTION_OT_layer_next(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Next Layer"; - ot->idname = "ACTION_OT_layer_next"; - ot->description = "Switch to editing action in animation layer above the current action in the NLA Stack"; - - /* callbacks */ - ot->exec = action_layer_next_exec; - ot->poll = action_layer_next_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Next Layer"; + ot->idname = "ACTION_OT_layer_next"; + ot->description = + "Switch to editing action in animation layer above the current action in the NLA Stack"; + + /* callbacks */ + ot->exec = action_layer_next_exec; + ot->poll = action_layer_next_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ********************* One Layer Down Operator ************************* */ static bool action_layer_prev_poll(bContext *C) { - /* Action Editor's action editing modes only */ - if (ED_operator_action_active(C)) { - AnimData *adt = ED_actedit_animdata_from_context(C); - if (adt) { - if (adt->flag & ADT_NLA_EDIT_ON) { - /* Tweak Mode: We need to check if there are any tracks below the active one - * that we can move to */ - if (adt->nla_tracks.first) { - NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.first; - - /* Since the first disabled track is the track being tweaked/edited, - * we can simplify things by only checking the first track: - * - If it is disabled, this is the track being tweaked, - * so there can't be anything below it - * - Otherwise, there is at least 1 track below the tweaking - * track that we can descend to - */ - if ((nlt->flag & NLATRACK_DISABLED) == 0) { - /* not disabled = there are actions below the one being tweaked */ - return true; - } - } - } - else { - /* Normal Mode: If there are any tracks, we can try moving to those */ - return (adt->nla_tracks.first != NULL); - } - } - } - - /* something failed... */ - return false; + /* Action Editor's action editing modes only */ + if (ED_operator_action_active(C)) { + AnimData *adt = ED_actedit_animdata_from_context(C); + if (adt) { + if (adt->flag & ADT_NLA_EDIT_ON) { + /* Tweak Mode: We need to check if there are any tracks below the active one + * that we can move to */ + if (adt->nla_tracks.first) { + NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.first; + + /* Since the first disabled track is the track being tweaked/edited, + * we can simplify things by only checking the first track: + * - If it is disabled, this is the track being tweaked, + * so there can't be anything below it + * - Otherwise, there is at least 1 track below the tweaking + * track that we can descend to + */ + if ((nlt->flag & NLATRACK_DISABLED) == 0) { + /* not disabled = there are actions below the one being tweaked */ + return true; + } + } + } + else { + /* Normal Mode: If there are any tracks, we can try moving to those */ + return (adt->nla_tracks.first != NULL); + } + } + } + + /* something failed... */ + return false; } static int action_layer_prev_exec(bContext *C, wmOperator *op) { - AnimData *adt = ED_actedit_animdata_from_context(C); - NlaTrack *act_track; - NlaTrack *nlt; - - Scene *scene = CTX_data_scene(C); - float ctime = BKE_scene_frame_get(scene); - - /* Sanity Check */ - if (adt == NULL) { - BKE_report(op->reports, RPT_ERROR, "Internal Error: Could not find Animation Data/NLA Stack to use"); - return OPERATOR_CANCELLED; - } - - /* Get active track */ - act_track = BKE_nlatrack_find_tweaked(adt); - - /* If there is no active track, that means we are using the active action... */ - if (act_track) { - /* Active Track - Start from the one below it */ - nlt = act_track->prev; - } - else { - /* Active Action - Use the top-most track */ - nlt = adt->nla_tracks.last; - } - - /* Find previous action and hook it up */ - for (; nlt; nlt = nlt->prev) { - NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime); - - if (strip) { - action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip); - break; - } - } - - /* Update the action that this editor now uses - * NOTE: The calls above have already handled the usercount/animdata side of things - */ - actedit_change_action(C, adt->action); - return OPERATOR_FINISHED; + AnimData *adt = ED_actedit_animdata_from_context(C); + NlaTrack *act_track; + NlaTrack *nlt; + + Scene *scene = CTX_data_scene(C); + float ctime = BKE_scene_frame_get(scene); + + /* Sanity Check */ + if (adt == NULL) { + BKE_report( + op->reports, RPT_ERROR, "Internal Error: Could not find Animation Data/NLA Stack to use"); + return OPERATOR_CANCELLED; + } + + /* Get active track */ + act_track = BKE_nlatrack_find_tweaked(adt); + + /* If there is no active track, that means we are using the active action... */ + if (act_track) { + /* Active Track - Start from the one below it */ + nlt = act_track->prev; + } + else { + /* Active Action - Use the top-most track */ + nlt = adt->nla_tracks.last; + } + + /* Find previous action and hook it up */ + for (; nlt; nlt = nlt->prev) { + NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime); + + if (strip) { + action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip); + break; + } + } + + /* Update the action that this editor now uses + * NOTE: The calls above have already handled the usercount/animdata side of things + */ + actedit_change_action(C, adt->action); + return OPERATOR_FINISHED; } void ACTION_OT_layer_prev(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Previous Layer"; - ot->idname = "ACTION_OT_layer_prev"; - ot->description = "Switch to editing action in animation layer below the current action in the NLA Stack"; - - /* callbacks */ - ot->exec = action_layer_prev_exec; - ot->poll = action_layer_prev_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Previous Layer"; + ot->idname = "ACTION_OT_layer_prev"; + ot->description = + "Switch to editing action in animation layer below the current action in the NLA Stack"; + + /* callbacks */ + ot->exec = action_layer_prev_exec; + ot->poll = action_layer_prev_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ************************************************************************** */ diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 0db1fd6eec3..b2baace1592 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -21,7 +21,6 @@ * \ingroup spaction */ - /* System includes ----------------------------------------------------- */ #include @@ -46,10 +45,8 @@ #include "BKE_context.h" #include "BKE_pointcache.h" - /* Everything from source (BIF, BDR, BSE) ------------------------------ */ - #include "GPU_immediate.h" #include "GPU_matrix.h" #include "GPU_state.h" @@ -69,325 +66,335 @@ /* left hand part */ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - View2D *v2d = &ar->v2d; - float y = 0.0f; - size_t items; - int height; - - /* build list of channels to draw */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); - items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac))); - if (height > BLI_rcti_size_y(&v2d->mask)) { - /* don't use totrect set, as the width stays the same - * (NOTE: this is ok here, the configuration is pretty straightforward) - */ - v2d->tot.ymin = (float)(-height); - } - /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */ - UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY); - - /* loop through channels, and set up drawing depending on their type */ - { /* first pass: just the standard GL-drawing for backdrop + text */ - size_t channel_index = 0; - - y = (float)ACHANNEL_FIRST(ac); - - for (ale = anim_data.first; ale; ale = ale->next) { - float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); - - /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) - { - /* draw all channels using standard channel-drawing API */ - ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index); - } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); - channel_index++; - } - } - { /* second pass: widgets */ - uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); - size_t channel_index = 0; - - y = (float)ACHANNEL_FIRST(ac); - - for (ale = anim_data.first; ale; ale = ale->next) { - float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); - - /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) - { - /* draw all channels using standard channel-drawing API */ - rctf channel_rect; - BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, yminc, ymaxc); - ANIM_channel_draw_widgets(C, ac, ale, block, &channel_rect, channel_index); - } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); - channel_index++; - } - - UI_block_end(C, block); - UI_block_draw(C, block); - } - - /* free tempolary channels */ - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + View2D *v2d = &ar->v2d; + float y = 0.0f; + size_t items; + int height; + + /* build list of channels to draw */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac))); + if (height > BLI_rcti_size_y(&v2d->mask)) { + /* don't use totrect set, as the width stays the same + * (NOTE: this is ok here, the configuration is pretty straightforward) + */ + v2d->tot.ymin = (float)(-height); + } + /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */ + UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY); + + /* loop through channels, and set up drawing depending on their type */ + { /* first pass: just the standard GL-drawing for backdrop + text */ + size_t channel_index = 0; + + y = (float)ACHANNEL_FIRST(ac); + + for (ale = anim_data.first; ale; ale = ale->next) { + float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); + float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + + /* check if visible */ + if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + /* draw all channels using standard channel-drawing API */ + ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index); + } + + /* adjust y-position for next one */ + y -= ACHANNEL_STEP(ac); + channel_index++; + } + } + { /* second pass: widgets */ + uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); + size_t channel_index = 0; + + y = (float)ACHANNEL_FIRST(ac); + + for (ale = anim_data.first; ale; ale = ale->next) { + float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); + float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + + /* check if visible */ + if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + /* draw all channels using standard channel-drawing API */ + rctf channel_rect; + BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, yminc, ymaxc); + ANIM_channel_draw_widgets(C, ac, ale, block, &channel_rect, channel_index); + } + + /* adjust y-position for next one */ + y -= ACHANNEL_STEP(ac); + channel_index++; + } + + UI_block_end(C, block); + UI_block_draw(C, block); + } + + /* free tempolary channels */ + ANIM_animdata_freelist(&anim_data); } /* ************************************************************************* */ /* Keyframes */ /* extra padding for lengths (to go under scrollers) */ -#define EXTRA_SCROLL_PAD 100.0f +#define EXTRA_SCROLL_PAD 100.0f /* draw keyframes in each channel */ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - - View2D *v2d = &ar->v2d; - bDopeSheet *ads = &saction->ads; - AnimData *adt = NULL; - - float y; - - unsigned char col1[4], col2[4]; - unsigned char col1a[4], col2a[4]; - unsigned char col1b[4], col2b[4]; - - const bool show_group_colors = !(saction->flag & SACTION_NODRAWGCOLORS); - - - /* get theme colors */ - UI_GetThemeColor4ubv(TH_SHADE2, col2); - UI_GetThemeColor4ubv(TH_HILITE, col1); - - UI_GetThemeColor4ubv(TH_GROUP, col2a); - UI_GetThemeColor4ubv(TH_GROUP_ACTIVE, col1a); - - UI_GetThemeColor4ubv(TH_DOPESHEET_CHANNELOB, col1b); - UI_GetThemeColor4ubv(TH_DOPESHEET_CHANNELSUBOB, col2b); - - /* build list of channels to draw */ - int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); - size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - int height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac))); - /* don't use totrect set, as the width stays the same - * (NOTE: this is ok here, the configuration is pretty straightforward) - */ - v2d->tot.ymin = (float)(-height); - - /* first backdrop strips */ - y = (float)(-ACHANNEL_HEIGHT(ac)); - - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - GPU_blend(true); - - for (ale = anim_data.first; ale; ale = ale->next) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); - - /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) - { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - int sel = 0; - - /* determine if any need to draw channel */ - if (ale->datatype != ALE_NONE) { - /* determine if channel is selected */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT)) - sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT); - - if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) { - switch (ale->type) { - case ANIMTYPE_SUMMARY: - { - /* reddish color from NLA */ - immUniformThemeColor(TH_ANIM_ACTIVE); - break; - } - case ANIMTYPE_SCENE: - case ANIMTYPE_OBJECT: - { - immUniformColor3ubvAlpha(col1b, sel ? col1[3] : col1b[3]); - break; - } - case ANIMTYPE_FILLACTD: - case ANIMTYPE_DSSKEY: - case ANIMTYPE_DSWOR: - { - immUniformColor3ubvAlpha(col2b, sel ? col1[3] : col2b[3]); - break; - } - case ANIMTYPE_GROUP: - { - bActionGroup *agrp = ale->data; - if (show_group_colors && agrp->customCol) { - if (sel) { - immUniformColor3ubvAlpha((unsigned char *)agrp->cs.select, col1a[3]); - } - else { - immUniformColor3ubvAlpha((unsigned char *)agrp->cs.solid, col2a[3]); - } - } - else { - immUniformColor4ubv(sel ? col1a : col2a); - } - break; - } - case ANIMTYPE_FCURVE: - { - FCurve *fcu = ale->data; - if (show_group_colors && fcu->grp && fcu->grp->customCol) { - immUniformColor3ubvAlpha((unsigned char *)fcu->grp->cs.active, sel ? col1[3] : col2[3]); - } - else { - immUniformColor4ubv(sel ? col1 : col2); - } - break; - } - default: - { - immUniformColor4ubv(sel ? col1 : col2); - } - } - - /* draw region twice: firstly backdrop, then the current range */ - immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); - } - else if (ac->datatype == ANIMCONT_GPENCIL) { - unsigned char *color; - if ((show_group_colors) && (ale->type == ANIMTYPE_GPLAYER)) { - bGPDlayer *gpl = (bGPDlayer *)ale->data; - unsigned char gpl_col[4]; - rgb_float_to_uchar(gpl_col, gpl->color); - gpl_col[3] = col1[3]; - - color = sel ? col1 : gpl_col; - } - else { - color = sel ? col1 : col2; - } - /* frames less than one get less saturated background */ - immUniformColor4ubv(color); - immRectf(pos, 0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac)); - - /* frames one and higher get a saturated background */ - immUniformColor3ubvAlpha(color, MIN2(255, color[3] * 2)); - immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); - } - else if (ac->datatype == ANIMCONT_MASK) { - /* TODO --- this is a copy of gpencil */ - /* frames less than one get less saturated background */ - unsigned char *color = sel ? col1 : col2; - immUniformColor4ubv(color); - immRectf(pos, 0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac)); - - /* frames one and higher get a saturated background */ - immUniformColor3ubvAlpha(color, MIN2(255, color[3] * 2)); - immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); - } - } - } - - /* Increment the step */ - y -= ACHANNEL_STEP(ac); - } - GPU_blend(false); - - /* black line marking 'current frame' for Time-Slide transform mode */ - if (saction->flag & SACTION_MOVING) { - immUniformColor3f(0.0f, 0.0f, 0.0f); - - immBegin(GPU_PRIM_LINES, 2); - immVertex2f(pos, saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD); - immVertex2f(pos, saction->timeslide, v2d->cur.ymax); - immEnd(); - } - immUnbindProgram(); - - /* Draw keyframes - * 1) Only channels that are visible in the Action Editor get drawn/evaluated. - * This is to try to optimize this for heavier data sets - * 2) Keyframes which are out of view horizontally are disregarded - */ - y = (float)(-ACHANNEL_HEIGHT(ac)); - - int action_flag = saction->flag; - - if (saction->mode == SACTCONT_TIMELINE) { - action_flag &= ~(SACTION_SHOW_INTERPOLATION | SACTION_SHOW_EXTREMES); - } - - for (ale = anim_data.first; ale; ale = ale->next) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); - - /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) - { - /* check if anything to show for this channel */ - if (ale->datatype != ALE_NONE) { - adt = ANIM_nla_mapping_get(ac, ale); - - /* draw 'keyframes' for each specific datatype */ - switch (ale->datatype) { - case ALE_ALL: - draw_summary_channel(v2d, ale->data, y, ac->yscale_fac, action_flag); - break; - case ALE_SCE: - draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, action_flag); - break; - case ALE_OB: - draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, action_flag); - break; - case ALE_ACT: - draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, action_flag); - break; - case ALE_GROUP: - draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac, action_flag); - break; - case ALE_FCURVE: - draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, action_flag); - break; - case ALE_GPFRAME: - draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac, action_flag); - break; - case ALE_MASKLAY: - draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac, action_flag); - break; - } - } - } - - y -= ACHANNEL_STEP(ac); - } - - /* free temporary channels used for drawing */ - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + + View2D *v2d = &ar->v2d; + bDopeSheet *ads = &saction->ads; + AnimData *adt = NULL; + + float y; + + unsigned char col1[4], col2[4]; + unsigned char col1a[4], col2a[4]; + unsigned char col1b[4], col2b[4]; + + const bool show_group_colors = !(saction->flag & SACTION_NODRAWGCOLORS); + + /* get theme colors */ + UI_GetThemeColor4ubv(TH_SHADE2, col2); + UI_GetThemeColor4ubv(TH_HILITE, col1); + + UI_GetThemeColor4ubv(TH_GROUP, col2a); + UI_GetThemeColor4ubv(TH_GROUP_ACTIVE, col1a); + + UI_GetThemeColor4ubv(TH_DOPESHEET_CHANNELOB, col1b); + UI_GetThemeColor4ubv(TH_DOPESHEET_CHANNELSUBOB, col2b); + + /* build list of channels to draw */ + int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + int height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac))); + /* don't use totrect set, as the width stays the same + * (NOTE: this is ok here, the configuration is pretty straightforward) + */ + v2d->tot.ymin = (float)(-height); + + /* first backdrop strips */ + y = (float)(-ACHANNEL_HEIGHT(ac)); + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + GPU_blend(true); + + for (ale = anim_data.first; ale; ale = ale->next) { + const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); + const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + + /* check if visible */ + if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + int sel = 0; + + /* determine if any need to draw channel */ + if (ale->datatype != ALE_NONE) { + /* determine if channel is selected */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT)) + sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT); + + if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) { + switch (ale->type) { + case ANIMTYPE_SUMMARY: { + /* reddish color from NLA */ + immUniformThemeColor(TH_ANIM_ACTIVE); + break; + } + case ANIMTYPE_SCENE: + case ANIMTYPE_OBJECT: { + immUniformColor3ubvAlpha(col1b, sel ? col1[3] : col1b[3]); + break; + } + case ANIMTYPE_FILLACTD: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: { + immUniformColor3ubvAlpha(col2b, sel ? col1[3] : col2b[3]); + break; + } + case ANIMTYPE_GROUP: { + bActionGroup *agrp = ale->data; + if (show_group_colors && agrp->customCol) { + if (sel) { + immUniformColor3ubvAlpha((unsigned char *)agrp->cs.select, col1a[3]); + } + else { + immUniformColor3ubvAlpha((unsigned char *)agrp->cs.solid, col2a[3]); + } + } + else { + immUniformColor4ubv(sel ? col1a : col2a); + } + break; + } + case ANIMTYPE_FCURVE: { + FCurve *fcu = ale->data; + if (show_group_colors && fcu->grp && fcu->grp->customCol) { + immUniformColor3ubvAlpha((unsigned char *)fcu->grp->cs.active, + sel ? col1[3] : col2[3]); + } + else { + immUniformColor4ubv(sel ? col1 : col2); + } + break; + } + default: { + immUniformColor4ubv(sel ? col1 : col2); + } + } + + /* draw region twice: firstly backdrop, then the current range */ + immRectf(pos, + v2d->cur.xmin, + (float)y - ACHANNEL_HEIGHT_HALF(ac), + v2d->cur.xmax + EXTRA_SCROLL_PAD, + (float)y + ACHANNEL_HEIGHT_HALF(ac)); + } + else if (ac->datatype == ANIMCONT_GPENCIL) { + unsigned char *color; + if ((show_group_colors) && (ale->type == ANIMTYPE_GPLAYER)) { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + unsigned char gpl_col[4]; + rgb_float_to_uchar(gpl_col, gpl->color); + gpl_col[3] = col1[3]; + + color = sel ? col1 : gpl_col; + } + else { + color = sel ? col1 : col2; + } + /* frames less than one get less saturated background */ + immUniformColor4ubv(color); + immRectf(pos, + 0.0f, + (float)y - ACHANNEL_HEIGHT_HALF(ac), + v2d->cur.xmin, + (float)y + ACHANNEL_HEIGHT_HALF(ac)); + + /* frames one and higher get a saturated background */ + immUniformColor3ubvAlpha(color, MIN2(255, color[3] * 2)); + immRectf(pos, + v2d->cur.xmin, + (float)y - ACHANNEL_HEIGHT_HALF(ac), + v2d->cur.xmax + EXTRA_SCROLL_PAD, + (float)y + ACHANNEL_HEIGHT_HALF(ac)); + } + else if (ac->datatype == ANIMCONT_MASK) { + /* TODO --- this is a copy of gpencil */ + /* frames less than one get less saturated background */ + unsigned char *color = sel ? col1 : col2; + immUniformColor4ubv(color); + immRectf(pos, + 0.0f, + (float)y - ACHANNEL_HEIGHT_HALF(ac), + v2d->cur.xmin, + (float)y + ACHANNEL_HEIGHT_HALF(ac)); + + /* frames one and higher get a saturated background */ + immUniformColor3ubvAlpha(color, MIN2(255, color[3] * 2)); + immRectf(pos, + v2d->cur.xmin, + (float)y - ACHANNEL_HEIGHT_HALF(ac), + v2d->cur.xmax + EXTRA_SCROLL_PAD, + (float)y + ACHANNEL_HEIGHT_HALF(ac)); + } + } + } + + /* Increment the step */ + y -= ACHANNEL_STEP(ac); + } + GPU_blend(false); + + /* black line marking 'current frame' for Time-Slide transform mode */ + if (saction->flag & SACTION_MOVING) { + immUniformColor3f(0.0f, 0.0f, 0.0f); + + immBegin(GPU_PRIM_LINES, 2); + immVertex2f(pos, saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD); + immVertex2f(pos, saction->timeslide, v2d->cur.ymax); + immEnd(); + } + immUnbindProgram(); + + /* Draw keyframes + * 1) Only channels that are visible in the Action Editor get drawn/evaluated. + * This is to try to optimize this for heavier data sets + * 2) Keyframes which are out of view horizontally are disregarded + */ + y = (float)(-ACHANNEL_HEIGHT(ac)); + + int action_flag = saction->flag; + + if (saction->mode == SACTCONT_TIMELINE) { + action_flag &= ~(SACTION_SHOW_INTERPOLATION | SACTION_SHOW_EXTREMES); + } + + for (ale = anim_data.first; ale; ale = ale->next) { + const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); + const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + + /* check if visible */ + if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + /* check if anything to show for this channel */ + if (ale->datatype != ALE_NONE) { + adt = ANIM_nla_mapping_get(ac, ale); + + /* draw 'keyframes' for each specific datatype */ + switch (ale->datatype) { + case ALE_ALL: + draw_summary_channel(v2d, ale->data, y, ac->yscale_fac, action_flag); + break; + case ALE_SCE: + draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, action_flag); + break; + case ALE_OB: + draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, action_flag); + break; + case ALE_ACT: + draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, action_flag); + break; + case ALE_GROUP: + draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac, action_flag); + break; + case ALE_FCURVE: + draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, action_flag); + break; + case ALE_GPFRAME: + draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac, action_flag); + break; + case ALE_MASKLAY: + draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac, action_flag); + break; + } + } + } + + y -= ACHANNEL_STEP(ac); + } + + /* free temporary channels used for drawing */ + ANIM_animdata_freelist(&anim_data); } /* ************************************************************************* */ @@ -395,148 +402,172 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) void timeline_draw_cache(SpaceAction *saction, Object *ob, Scene *scene) { - PTCacheID *pid; - ListBase pidlist; - const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize); - float yoffs = 0.f; - - if (!(saction->cache_display & TIME_CACHE_DISPLAY) || (!ob)) - return; - - BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0); - - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - /* iterate over pointcaches on the active object, and draw each one's range */ - for (pid = pidlist.first; pid; pid = pid->next) { - float col[4]; - - switch (pid->type) { - case PTCACHE_TYPE_SOFTBODY: - if (!(saction->cache_display & TIME_CACHE_SOFTBODY)) continue; - break; - case PTCACHE_TYPE_PARTICLES: - if (!(saction->cache_display & TIME_CACHE_PARTICLES)) continue; - break; - case PTCACHE_TYPE_CLOTH: - if (!(saction->cache_display & TIME_CACHE_CLOTH)) continue; - break; - case PTCACHE_TYPE_SMOKE_DOMAIN: - case PTCACHE_TYPE_SMOKE_HIGHRES: - if (!(saction->cache_display & TIME_CACHE_SMOKE)) continue; - break; - case PTCACHE_TYPE_DYNAMICPAINT: - if (!(saction->cache_display & TIME_CACHE_DYNAMICPAINT)) continue; - break; - case PTCACHE_TYPE_RIGIDBODY: - if (!(saction->cache_display & TIME_CACHE_RIGIDBODY)) continue; - break; - } - - if (pid->cache->cached_frames == NULL) - continue; - - GPU_matrix_push(); - GPU_matrix_translate_2f(0.0, (float)V2D_SCROLL_HEIGHT_TEXT + yoffs); - GPU_matrix_scale_2f(1.0, cache_draw_height); - - switch (pid->type) { - case PTCACHE_TYPE_SOFTBODY: - col[0] = 1.0; col[1] = 0.4; col[2] = 0.02; - col[3] = 0.1; - break; - case PTCACHE_TYPE_PARTICLES: - col[0] = 1.0; col[1] = 0.1; col[2] = 0.02; - col[3] = 0.1; - break; - case PTCACHE_TYPE_CLOTH: - col[0] = 0.1; col[1] = 0.1; col[2] = 0.75; - col[3] = 0.1; - break; - case PTCACHE_TYPE_SMOKE_DOMAIN: - case PTCACHE_TYPE_SMOKE_HIGHRES: - col[0] = 0.2; col[1] = 0.2; col[2] = 0.2; - col[3] = 0.1; - break; - case PTCACHE_TYPE_DYNAMICPAINT: - col[0] = 1.0; col[1] = 0.1; col[2] = 0.75; - col[3] = 0.1; - break; - case PTCACHE_TYPE_RIGIDBODY: - col[0] = 1.0; col[1] = 0.6; col[2] = 0.0; - col[3] = 0.1; - break; - default: - col[0] = 1.0; col[1] = 0.0; col[2] = 1.0; - col[3] = 0.1; - BLI_assert(0); - break; - } - - const int sta = pid->cache->startframe, end = pid->cache->endframe; - - GPU_blend(true); - - immUniformColor4fv(col); - immRectf(pos, (float)sta, 0.0, (float)end, 1.0); - - col[3] = 0.4f; - if (pid->cache->flag & PTCACHE_BAKED) { - col[0] -= 0.4f; col[1] -= 0.4f; col[2] -= 0.4f; - } - else if (pid->cache->flag & PTCACHE_OUTDATED) { - col[0] += 0.4f; col[1] += 0.4f; col[2] += 0.4f; - } - - immUniformColor4fv(col); - - { - /* draw a quad for each chunk of consecutive cached frames */ - const int chunk_tot = 32; - int chunk_len = 0; - int ista = 0, iend = -1; - - for (int i = sta; i <= end; i++) { - if (pid->cache->cached_frames[i - sta]) { - if (chunk_len == 0) { - immBeginAtMost(GPU_PRIM_TRIS, chunk_tot * 6); - } - if (ista > iend) { - chunk_len++; - ista = i; - } - iend = i; - } - else { - if (ista <= iend) { - immRectf_fast(pos, (float)ista - 0.5f, 0.0f, (float)iend + 0.5f, 1.0f); - iend = ista - 1; - } - if (chunk_len >= chunk_tot) { - immEnd(); - chunk_len = 0; - } - } - } - if (ista <= iend) { - immRectf_fast(pos, (float)ista - 0.5f, 0.0f, (float)iend + 0.5f, 1.0f); - } - if (chunk_len != 0) { - immEnd(); - } - } - - GPU_blend(false); - - GPU_matrix_pop(); - - yoffs += cache_draw_height; - } - - immUnbindProgram(); - - BLI_freelistN(&pidlist); + PTCacheID *pid; + ListBase pidlist; + const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize); + float yoffs = 0.f; + + if (!(saction->cache_display & TIME_CACHE_DISPLAY) || (!ob)) + return; + + BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0); + + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + /* iterate over pointcaches on the active object, and draw each one's range */ + for (pid = pidlist.first; pid; pid = pid->next) { + float col[4]; + + switch (pid->type) { + case PTCACHE_TYPE_SOFTBODY: + if (!(saction->cache_display & TIME_CACHE_SOFTBODY)) + continue; + break; + case PTCACHE_TYPE_PARTICLES: + if (!(saction->cache_display & TIME_CACHE_PARTICLES)) + continue; + break; + case PTCACHE_TYPE_CLOTH: + if (!(saction->cache_display & TIME_CACHE_CLOTH)) + continue; + break; + case PTCACHE_TYPE_SMOKE_DOMAIN: + case PTCACHE_TYPE_SMOKE_HIGHRES: + if (!(saction->cache_display & TIME_CACHE_SMOKE)) + continue; + break; + case PTCACHE_TYPE_DYNAMICPAINT: + if (!(saction->cache_display & TIME_CACHE_DYNAMICPAINT)) + continue; + break; + case PTCACHE_TYPE_RIGIDBODY: + if (!(saction->cache_display & TIME_CACHE_RIGIDBODY)) + continue; + break; + } + + if (pid->cache->cached_frames == NULL) + continue; + + GPU_matrix_push(); + GPU_matrix_translate_2f(0.0, (float)V2D_SCROLL_HEIGHT_TEXT + yoffs); + GPU_matrix_scale_2f(1.0, cache_draw_height); + + switch (pid->type) { + case PTCACHE_TYPE_SOFTBODY: + col[0] = 1.0; + col[1] = 0.4; + col[2] = 0.02; + col[3] = 0.1; + break; + case PTCACHE_TYPE_PARTICLES: + col[0] = 1.0; + col[1] = 0.1; + col[2] = 0.02; + col[3] = 0.1; + break; + case PTCACHE_TYPE_CLOTH: + col[0] = 0.1; + col[1] = 0.1; + col[2] = 0.75; + col[3] = 0.1; + break; + case PTCACHE_TYPE_SMOKE_DOMAIN: + case PTCACHE_TYPE_SMOKE_HIGHRES: + col[0] = 0.2; + col[1] = 0.2; + col[2] = 0.2; + col[3] = 0.1; + break; + case PTCACHE_TYPE_DYNAMICPAINT: + col[0] = 1.0; + col[1] = 0.1; + col[2] = 0.75; + col[3] = 0.1; + break; + case PTCACHE_TYPE_RIGIDBODY: + col[0] = 1.0; + col[1] = 0.6; + col[2] = 0.0; + col[3] = 0.1; + break; + default: + col[0] = 1.0; + col[1] = 0.0; + col[2] = 1.0; + col[3] = 0.1; + BLI_assert(0); + break; + } + + const int sta = pid->cache->startframe, end = pid->cache->endframe; + + GPU_blend(true); + + immUniformColor4fv(col); + immRectf(pos, (float)sta, 0.0, (float)end, 1.0); + + col[3] = 0.4f; + if (pid->cache->flag & PTCACHE_BAKED) { + col[0] -= 0.4f; + col[1] -= 0.4f; + col[2] -= 0.4f; + } + else if (pid->cache->flag & PTCACHE_OUTDATED) { + col[0] += 0.4f; + col[1] += 0.4f; + col[2] += 0.4f; + } + + immUniformColor4fv(col); + + { + /* draw a quad for each chunk of consecutive cached frames */ + const int chunk_tot = 32; + int chunk_len = 0; + int ista = 0, iend = -1; + + for (int i = sta; i <= end; i++) { + if (pid->cache->cached_frames[i - sta]) { + if (chunk_len == 0) { + immBeginAtMost(GPU_PRIM_TRIS, chunk_tot * 6); + } + if (ista > iend) { + chunk_len++; + ista = i; + } + iend = i; + } + else { + if (ista <= iend) { + immRectf_fast(pos, (float)ista - 0.5f, 0.0f, (float)iend + 0.5f, 1.0f); + iend = ista - 1; + } + if (chunk_len >= chunk_tot) { + immEnd(); + chunk_len = 0; + } + } + } + if (ista <= iend) { + immRectf_fast(pos, (float)ista - 0.5f, 0.0f, (float)iend + 0.5f, 1.0f); + } + if (chunk_len != 0) { + immEnd(); + } + } + + GPU_blend(false); + + GPU_matrix_pop(); + + yoffs += cache_draw_height; + } + + immUnbindProgram(); + + BLI_freelistN(&pidlist); } /* ************************************************************************* */ diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index b0cc1b72b27..9ce709e1134 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -21,13 +21,11 @@ * \ingroup spaction */ - #include #include #include #include - #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -72,7 +70,6 @@ #include "action_intern.h" - /* ************************************************************************** */ /* POSE MARKERS STUFF */ @@ -86,73 +83,73 @@ */ static bool act_markers_make_local_poll(bContext *C) { - SpaceAction *sact = CTX_wm_space_action(C); + SpaceAction *sact = CTX_wm_space_action(C); - /* 1) */ - if (sact == NULL) - return 0; + /* 1) */ + if (sact == NULL) + return 0; - /* 2) */ - if (ELEM(sact->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) == 0) - return 0; - if (sact->action == NULL) - return 0; + /* 2) */ + if (ELEM(sact->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) == 0) + return 0; + if (sact->action == NULL) + return 0; - /* 3) */ - if (sact->flag & SACTION_POSEMARKERS_SHOW) - return 0; + /* 3) */ + if (sact->flag & SACTION_POSEMARKERS_SHOW) + return 0; - /* 4) */ - return ED_markers_get_first_selected(ED_context_get_markers(C)) != NULL; + /* 4) */ + return ED_markers_get_first_selected(ED_context_get_markers(C)) != NULL; } static int act_markers_make_local_exec(bContext *C, wmOperator *UNUSED(op)) { - ListBase *markers = ED_context_get_markers(C); + ListBase *markers = ED_context_get_markers(C); - SpaceAction *sact = CTX_wm_space_action(C); - bAction *act = (sact) ? sact->action : NULL; + SpaceAction *sact = CTX_wm_space_action(C); + bAction *act = (sact) ? sact->action : NULL; - TimeMarker *marker, *markern = NULL; + TimeMarker *marker, *markern = NULL; - /* sanity checks */ - if (ELEM(NULL, markers, act)) - return OPERATOR_CANCELLED; + /* sanity checks */ + if (ELEM(NULL, markers, act)) + return OPERATOR_CANCELLED; - /* migrate markers */ - for (marker = markers->first; marker; marker = markern) { - markern = marker->next; + /* migrate markers */ + for (marker = markers->first; marker; marker = markern) { + markern = marker->next; - /* move if marker is selected */ - if (marker->flag & SELECT) { - BLI_remlink(markers, marker); - BLI_addtail(&act->markers, marker); - } - } + /* move if marker is selected */ + if (marker->flag & SELECT) { + BLI_remlink(markers, marker); + BLI_addtail(&act->markers, marker); + } + } - /* now enable the "show posemarkers only" setting, so that we can see that something did happen */ - sact->flag |= SACTION_POSEMARKERS_SHOW; + /* now enable the "show posemarkers only" setting, so that we can see that something did happen */ + sact->flag |= SACTION_POSEMARKERS_SHOW; - /* notifiers - both sets, as this change affects both */ - WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL); - WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); + /* notifiers - both sets, as this change affects both */ + WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_markers_make_local(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Make Markers Local"; - ot->idname = "ACTION_OT_markers_make_local"; - ot->description = "Move selected scene markers to the active Action as local 'pose' markers"; + /* identifiers */ + ot->name = "Make Markers Local"; + ot->idname = "ACTION_OT_markers_make_local"; + ot->description = "Move selected scene markers to the active Action as local 'pose' markers"; - /* callbacks */ - ot->exec = act_markers_make_local_exec; - ot->poll = act_markers_make_local_poll; + /* callbacks */ + ot->exec = act_markers_make_local_exec; + ot->poll = act_markers_make_local_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ************************************************************************** */ @@ -163,142 +160,142 @@ void ACTION_OT_markers_make_local(wmOperatorType *ot) /* Get the min/max keyframes*/ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const short onlySel) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - bool found = false; - - /* get data to filter, from Action or Dopesheet */ - /* XXX: what is sel doing here?! - * Commented it, was breaking things (eg. the "auto preview range" tool). */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_SEL *//*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* set large values to try to override */ - *min = 999999999.0f; - *max = -999999999.0f; - - /* check if any channels to set range with */ - if (anim_data.first) { - /* go through channels, finding max extents */ - for (ale = anim_data.first; ale; ale = ale->next) { - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - if (ale->datatype == ALE_GPFRAME) { - bGPDlayer *gpl = ale->data; - bGPDframe *gpf; - - /* find gp-frame which is less than or equal to cframe */ - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { - const float framenum = (float)gpf->framenum; - *min = min_ff(*min, framenum); - *max = max_ff(*max, framenum); - found = true; - } - } - else if (ale->datatype == ALE_MASKLAY) { - MaskLayer *masklay = ale->data; - MaskLayerShape *masklay_shape; - - /* find mask layer which is less than or equal to cframe */ - for (masklay_shape = masklay->splines_shapes.first; - masklay_shape; - masklay_shape = masklay_shape->next) - { - const float framenum = (float)masklay_shape->frame; - *min = min_ff(*min, framenum); - *max = max_ff(*max, framenum); - found = true; - } - } - else { - FCurve *fcu = (FCurve *)ale->key_data; - float tmin, tmax; - - /* get range and apply necessary scaling before processing */ - if (calc_fcurve_range(fcu, &tmin, &tmax, onlySel, false)) { - - if (adt) { - tmin = BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP); - tmax = BKE_nla_tweakedit_remap(adt, tmax, NLATIME_CONVERT_MAP); - } - - /* try to set cur using these values, if they're more extreme than previously set values */ - *min = min_ff(*min, tmin); - *max = max_ff(*max, tmax); - found = true; - } - } - } - - if (fabsf(*max - *min) < 0.001f) { - *min -= 0.0005f; - *max += 0.0005f; - } - - /* free memory */ - ANIM_animdata_freelist(&anim_data); - } - else { - /* set default range */ - if (ac->scene) { - *min = (float)ac->scene->r.sfra; - *max = (float)ac->scene->r.efra; - } - else { - *min = -5; - *max = 100; - } - } - - return found; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + bool found = false; + + /* get data to filter, from Action or Dopesheet */ + /* XXX: what is sel doing here?! + * Commented it, was breaking things (eg. the "auto preview range" tool). */ + filter = (ANIMFILTER_DATA_VISIBLE | + ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_SEL */ /*| ANIMFILTER_CURVESONLY*/ | + ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* set large values to try to override */ + *min = 999999999.0f; + *max = -999999999.0f; + + /* check if any channels to set range with */ + if (anim_data.first) { + /* go through channels, finding max extents */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + if (ale->datatype == ALE_GPFRAME) { + bGPDlayer *gpl = ale->data; + bGPDframe *gpf; + + /* find gp-frame which is less than or equal to cframe */ + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + const float framenum = (float)gpf->framenum; + *min = min_ff(*min, framenum); + *max = max_ff(*max, framenum); + found = true; + } + } + else if (ale->datatype == ALE_MASKLAY) { + MaskLayer *masklay = ale->data; + MaskLayerShape *masklay_shape; + + /* find mask layer which is less than or equal to cframe */ + for (masklay_shape = masklay->splines_shapes.first; masklay_shape; + masklay_shape = masklay_shape->next) { + const float framenum = (float)masklay_shape->frame; + *min = min_ff(*min, framenum); + *max = max_ff(*max, framenum); + found = true; + } + } + else { + FCurve *fcu = (FCurve *)ale->key_data; + float tmin, tmax; + + /* get range and apply necessary scaling before processing */ + if (calc_fcurve_range(fcu, &tmin, &tmax, onlySel, false)) { + + if (adt) { + tmin = BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP); + tmax = BKE_nla_tweakedit_remap(adt, tmax, NLATIME_CONVERT_MAP); + } + + /* try to set cur using these values, if they're more extreme than previously set values */ + *min = min_ff(*min, tmin); + *max = max_ff(*max, tmax); + found = true; + } + } + } + + if (fabsf(*max - *min) < 0.001f) { + *min -= 0.0005f; + *max += 0.0005f; + } + + /* free memory */ + ANIM_animdata_freelist(&anim_data); + } + else { + /* set default range */ + if (ac->scene) { + *min = (float)ac->scene->r.sfra; + *max = (float)ac->scene->r.efra; + } + else { + *min = -5; + *max = 100; + } + } + + return found; } /* ****************** Automatic Preview-Range Operator ****************** */ static int actkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) { - bAnimContext ac; - Scene *scene; - float min, max; - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - if (ac.scene == NULL) - return OPERATOR_CANCELLED; - else - scene = ac.scene; - - /* set the range directly */ - get_keyframe_extents(&ac, &min, &max, false); - scene->r.flag |= SCER_PRV_RANGE; - scene->r.psfra = floorf(min); - scene->r.pefra = ceilf(max); - - if (scene->r.psfra == scene->r.pefra) { - scene->r.pefra = scene->r.psfra + 1; - } - - /* set notifier that things have changed */ - // XXX err... there's nothing for frame ranges yet, but this should do fine too - WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene); - - return OPERATOR_FINISHED; + bAnimContext ac; + Scene *scene; + float min, max; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + if (ac.scene == NULL) + return OPERATOR_CANCELLED; + else + scene = ac.scene; + + /* set the range directly */ + get_keyframe_extents(&ac, &min, &max, false); + scene->r.flag |= SCER_PRV_RANGE; + scene->r.psfra = floorf(min); + scene->r.pefra = ceilf(max); + + if (scene->r.psfra == scene->r.pefra) { + scene->r.pefra = scene->r.psfra + 1; + } + + /* set notifier that things have changed */ + // XXX err... there's nothing for frame ranges yet, but this should do fine too + WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene); + + return OPERATOR_FINISHED; } void ACTION_OT_previewrange_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Auto-Set Preview Range"; - ot->idname = "ACTION_OT_previewrange_set"; - ot->description = "Set Preview Range based on extents of selected Keyframes"; + /* identifiers */ + ot->name = "Auto-Set Preview Range"; + ot->idname = "ACTION_OT_previewrange_set"; + ot->description = "Set Preview Range based on extents of selected Keyframes"; - /* api callbacks */ - ot->exec = actkeys_previewrange_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->exec = actkeys_previewrange_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ****************** View-All Operator ****************** */ @@ -312,187 +309,186 @@ void ACTION_OT_previewrange_set(wmOperatorType *ot) */ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, float *max) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* NOTE: not bool, since we want prioritise individual channels over expanders */ - short found = 0; - float y; - - /* get all items - we need to do it this way */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* loop through all channels, finding the first one that's selected */ - y = (float)ACHANNEL_FIRST(ac); - - for (ale = anim_data.first; ale; ale = ale->next) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - - /* must be selected... */ - if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) && - ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT)) - { - /* update best estimate */ - *min = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - *max = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); - - /* is this high enough priority yet? */ - found = acf->channel_role; - - /* only stop our search when we've found an actual channel - * - datablock expanders get less priority so that we don't abort prematurely - */ - if (found == ACHANNEL_ROLE_CHANNEL) { - break; - } - } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); - } - - /* free all temp data */ - ANIM_animdata_freelist(&anim_data); - - return (found != 0); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* NOTE: not bool, since we want prioritise individual channels over expanders */ + short found = 0; + float y; + + /* get all items - we need to do it this way */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through all channels, finding the first one that's selected */ + y = (float)ACHANNEL_FIRST(ac); + + for (ale = anim_data.first; ale; ale = ale->next) { + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + + /* must be selected... */ + if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) && + ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT)) { + /* update best estimate */ + *min = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); + *max = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + + /* is this high enough priority yet? */ + found = acf->channel_role; + + /* only stop our search when we've found an actual channel + * - datablock expanders get less priority so that we don't abort prematurely + */ + if (found == ACHANNEL_ROLE_CHANNEL) { + break; + } + } + + /* adjust y-position for next one */ + y -= ACHANNEL_STEP(ac); + } + + /* free all temp data */ + ANIM_animdata_freelist(&anim_data); + + return (found != 0); } static int actkeys_viewall(bContext *C, const bool only_sel) { - bAnimContext ac; - View2D *v2d; - float extra, min, max; - bool found; - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - v2d = &ac.ar->v2d; - - /* set the horizontal range, with an extra offset so that the extreme keys will be in view */ - found = get_keyframe_extents(&ac, &min, &max, only_sel); - - if (only_sel && (found == false)) - return OPERATOR_CANCELLED; - - if (fabsf(max - min) < 1.0f) { - /* Exception - center the single keyfrme */ - float xwidth = BLI_rctf_size_x(&v2d->cur); - - v2d->cur.xmin = min - xwidth / 2.0f; - v2d->cur.xmax = max + xwidth / 2.0f; - } - else { - /* Normal case - stretch the two keyframes out to fill the space, with extra spacing */ - v2d->cur.xmin = min; - v2d->cur.xmax = max; - - extra = 0.125f * BLI_rctf_size_x(&v2d->cur); - v2d->cur.xmin -= extra; - v2d->cur.xmax += extra; - } - - /* set vertical range */ - if (only_sel == false) { - /* view all -> the summary channel is usually the shows everything, and resides right at the top... */ - v2d->cur.ymax = 0.0f; - v2d->cur.ymin = (float)-BLI_rcti_size_y(&v2d->mask); - } - else { - /* locate first selected channel (or the active one), and frame those */ - float ymin = v2d->cur.ymin; - float ymax = v2d->cur.ymax; - - if (actkeys_channels_get_selected_extents(&ac, &ymin, &ymax)) { - /* recenter the view so that this range is in the middle */ - float ymid = (ymax - ymin) / 2.0f + ymin; - float x_center; - - UI_view2d_center_get(v2d, &x_center, NULL); - UI_view2d_center_set(v2d, x_center, ymid); - } - } - - /* do View2D syncing */ - UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); - - /* just redraw this view */ - ED_area_tag_redraw(CTX_wm_area(C)); - - return OPERATOR_FINISHED; + bAnimContext ac; + View2D *v2d; + float extra, min, max; + bool found; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + v2d = &ac.ar->v2d; + + /* set the horizontal range, with an extra offset so that the extreme keys will be in view */ + found = get_keyframe_extents(&ac, &min, &max, only_sel); + + if (only_sel && (found == false)) + return OPERATOR_CANCELLED; + + if (fabsf(max - min) < 1.0f) { + /* Exception - center the single keyfrme */ + float xwidth = BLI_rctf_size_x(&v2d->cur); + + v2d->cur.xmin = min - xwidth / 2.0f; + v2d->cur.xmax = max + xwidth / 2.0f; + } + else { + /* Normal case - stretch the two keyframes out to fill the space, with extra spacing */ + v2d->cur.xmin = min; + v2d->cur.xmax = max; + + extra = 0.125f * BLI_rctf_size_x(&v2d->cur); + v2d->cur.xmin -= extra; + v2d->cur.xmax += extra; + } + + /* set vertical range */ + if (only_sel == false) { + /* view all -> the summary channel is usually the shows everything, and resides right at the top... */ + v2d->cur.ymax = 0.0f; + v2d->cur.ymin = (float)-BLI_rcti_size_y(&v2d->mask); + } + else { + /* locate first selected channel (or the active one), and frame those */ + float ymin = v2d->cur.ymin; + float ymax = v2d->cur.ymax; + + if (actkeys_channels_get_selected_extents(&ac, &ymin, &ymax)) { + /* recenter the view so that this range is in the middle */ + float ymid = (ymax - ymin) / 2.0f + ymin; + float x_center; + + UI_view2d_center_get(v2d, &x_center, NULL); + UI_view2d_center_set(v2d, x_center, ymid); + } + } + + /* do View2D syncing */ + UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); + + /* just redraw this view */ + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; } /* ......... */ static int actkeys_viewall_exec(bContext *C, wmOperator *UNUSED(op)) { - /* whole range */ - return actkeys_viewall(C, false); + /* whole range */ + return actkeys_viewall(C, false); } static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op)) { - /* only selected */ - return actkeys_viewall(C, true); + /* only selected */ + return actkeys_viewall(C, true); } /* ......... */ void ACTION_OT_view_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "View All"; - ot->idname = "ACTION_OT_view_all"; - ot->description = "Reset viewable area to show full keyframe range"; + /* identifiers */ + ot->name = "View All"; + ot->idname = "ACTION_OT_view_all"; + ot->description = "Reset viewable area to show full keyframe range"; - /* api callbacks */ - ot->exec = actkeys_viewall_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->exec = actkeys_viewall_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void ACTION_OT_view_selected(wmOperatorType *ot) { - /* identifiers */ - ot->name = "View Selected"; - ot->idname = "ACTION_OT_view_selected"; - ot->description = "Reset viewable area to show selected keyframes range"; + /* identifiers */ + ot->name = "View Selected"; + ot->idname = "ACTION_OT_view_selected"; + ot->description = "Reset viewable area to show selected keyframes range"; - /* api callbacks */ - ot->exec = actkeys_viewsel_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->exec = actkeys_viewsel_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ****************** View-All Operator ****************** */ static int actkeys_view_frame_exec(bContext *C, wmOperator *op) { - const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - ANIM_center_frame(C, smooth_viewtx); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + ANIM_center_frame(C, smooth_viewtx); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_view_frame(wmOperatorType *ot) { - /* identifiers */ - ot->name = "View Frame"; - ot->idname = "ACTION_OT_view_frame"; - ot->description = "Reset viewable area to show range around current frame"; + /* identifiers */ + ot->name = "View Frame"; + ot->idname = "ACTION_OT_view_frame"; + ot->description = "Reset viewable area to show range around current frame"; - /* api callbacks */ - ot->exec = actkeys_view_frame_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->exec = actkeys_view_frame_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ************************************************************************** */ @@ -503,553 +499,589 @@ void ACTION_OT_view_frame(wmOperatorType *ot) static short copy_action_keys(bAnimContext *ac) { - ListBase anim_data = {NULL, NULL}; - int filter, ok = 0; + ListBase anim_data = {NULL, NULL}; + int filter, ok = 0; - /* clear buffer first */ - ANIM_fcurves_copybuf_free(); + /* clear buffer first */ + ANIM_fcurves_copybuf_free(); - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | + ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - /* copy keyframes */ - ok = copy_animedit_keys(ac, &anim_data); + /* copy keyframes */ + ok = copy_animedit_keys(ac, &anim_data); - /* clean up */ - ANIM_animdata_freelist(&anim_data); + /* clean up */ + ANIM_animdata_freelist(&anim_data); - return ok; + return ok; } - static short paste_action_keys(bAnimContext *ac, - const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip) + const eKeyPasteOffset offset_mode, + const eKeyMergeMode merge_mode, + bool flip) { - ListBase anim_data = {NULL, NULL}; - int filter, ok = 0; + ListBase anim_data = {NULL, NULL}; + int filter, ok = 0; - /* filter data - * - First time we try to filter more strictly, allowing only selected channels - * to allow copying animation between channels - * - Second time, we loosen things up if nothing was found the first time, allowing - * users to just paste keyframes back into the original curve again [#31670] - */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + /* filter data + * - First time we try to filter more strictly, allowing only selected channels + * to allow copying animation between channels + * - Second time, we loosen things up if nothing was found the first time, allowing + * users to just paste keyframes back into the original curve again [#31670] + */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | + ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) { - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - } + if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) { + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + } - /* paste keyframes */ - ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip); + /* paste keyframes */ + ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip); - /* clean up */ - ANIM_animdata_freelist(&anim_data); + /* clean up */ + ANIM_animdata_freelist(&anim_data); - return ok; + return ok; } /* ------------------- */ static int actkeys_copy_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* copy keyframes */ - if (ac.datatype == ANIMCONT_GPENCIL) { - if (ED_gpencil_anim_copybuf_copy(&ac) == false) { - /* Nothing got copied - An error about this should be been logged already */ - return OPERATOR_CANCELLED; - } - } - else if (ac.datatype == ANIMCONT_MASK) { - /* FIXME... */ - BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for mask mode"); - return OPERATOR_CANCELLED; - } - else { - if (copy_action_keys(&ac)) { - BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer"); - return OPERATOR_CANCELLED; - } - } - - return OPERATOR_FINISHED; + bAnimContext ac; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* copy keyframes */ + if (ac.datatype == ANIMCONT_GPENCIL) { + if (ED_gpencil_anim_copybuf_copy(&ac) == false) { + /* Nothing got copied - An error about this should be been logged already */ + return OPERATOR_CANCELLED; + } + } + else if (ac.datatype == ANIMCONT_MASK) { + /* FIXME... */ + BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for mask mode"); + return OPERATOR_CANCELLED; + } + else { + if (copy_action_keys(&ac)) { + BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer"); + return OPERATOR_CANCELLED; + } + } + + return OPERATOR_FINISHED; } void ACTION_OT_copy(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Copy Keyframes"; - ot->idname = "ACTION_OT_copy"; - ot->description = "Copy selected keyframes to the copy/paste buffer"; + /* identifiers */ + ot->name = "Copy Keyframes"; + ot->idname = "ACTION_OT_copy"; + ot->description = "Copy selected keyframes to the copy/paste buffer"; - /* api callbacks */ - ot->exec = actkeys_copy_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->exec = actkeys_copy_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int actkeys_paste_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - - const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset"); - const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge"); - const bool flipped = RNA_boolean_get(op->ptr, "flipped"); - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* ac.reports by default will be the global reports list, which won't show warnings */ - ac.reports = op->reports; - - /* paste keyframes */ - if (ac.datatype == ANIMCONT_GPENCIL) { - if (ED_gpencil_anim_copybuf_paste(&ac, offset_mode) == false) { - /* An error occurred - Reports should have been fired already */ - return OPERATOR_CANCELLED; - } - } - else if (ac.datatype == ANIMCONT_MASK) { - /* FIXME... */ - BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for grease pencil or mask mode"); - return OPERATOR_CANCELLED; - } - else { - /* non-zero return means an error occurred while trying to paste */ - if (paste_action_keys(&ac, offset_mode, merge_mode, flipped)) { - return OPERATOR_CANCELLED; - } - } - - /* set notifier that keyframes have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - - return OPERATOR_FINISHED; + bAnimContext ac; + + const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset"); + const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge"); + const bool flipped = RNA_boolean_get(op->ptr, "flipped"); + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* ac.reports by default will be the global reports list, which won't show warnings */ + ac.reports = op->reports; + + /* paste keyframes */ + if (ac.datatype == ANIMCONT_GPENCIL) { + if (ED_gpencil_anim_copybuf_paste(&ac, offset_mode) == false) { + /* An error occurred - Reports should have been fired already */ + return OPERATOR_CANCELLED; + } + } + else if (ac.datatype == ANIMCONT_MASK) { + /* FIXME... */ + BKE_report(op->reports, + RPT_ERROR, + "Keyframe pasting is not available for grease pencil or mask mode"); + return OPERATOR_CANCELLED; + } + else { + /* non-zero return means an error occurred while trying to paste */ + if (paste_action_keys(&ac, offset_mode, merge_mode, flipped)) { + return OPERATOR_CANCELLED; + } + } + + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + + return OPERATOR_FINISHED; } void ACTION_OT_paste(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ - ot->name = "Paste Keyframes"; - ot->idname = "ACTION_OT_paste"; - ot->description = "Paste keyframes from copy/paste buffer for the selected channels, starting on the current frame"; - - /* api callbacks */ -// ot->invoke = WM_operator_props_popup; // better wait for action redo panel - ot->exec = actkeys_paste_exec; - ot->poll = ED_operator_action_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_enum(ot->srna, "offset", rna_enum_keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys"); - RNA_def_enum(ot->srna, "merge", rna_enum_keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing"); - prop = RNA_def_boolean(ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + PropertyRNA *prop; + /* identifiers */ + ot->name = "Paste Keyframes"; + ot->idname = "ACTION_OT_paste"; + ot->description = + "Paste keyframes from copy/paste buffer for the selected channels, starting on the current " + "frame"; + + /* api callbacks */ + // ot->invoke = WM_operator_props_popup; // better wait for action redo panel + ot->exec = actkeys_paste_exec; + ot->poll = ED_operator_action_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + RNA_def_enum(ot->srna, + "offset", + rna_enum_keyframe_paste_offset_items, + KEYFRAME_PASTE_OFFSET_CFRA_START, + "Offset", + "Paste time offset of keys"); + RNA_def_enum(ot->srna, + "merge", + rna_enum_keyframe_paste_merge_items, + KEYFRAME_PASTE_MERGE_MIX, + "Type", + "Method of merging pasted keys and existing"); + prop = RNA_def_boolean( + ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* ******************** Insert Keyframes Operator ************************* */ /* defines for insert keyframes tool */ static const EnumPropertyItem prop_actkeys_insertkey_types[] = { - {1, "ALL", 0, "All Channels", ""}, - {2, "SEL", 0, "Only Selected Channels", ""}, - {3, "GROUP", 0, "In Active Group", ""}, /* XXX not in all cases */ - {0, NULL, 0, NULL, NULL}, + {1, "ALL", 0, "All Channels", ""}, + {2, "SEL", 0, "Only Selected Channels", ""}, + {3, "GROUP", 0, "In Active Group", ""}, /* XXX not in all cases */ + {0, NULL, 0, NULL, NULL}, }; /* this function is responsible for inserting new keyframes */ static void insert_action_keys(bAnimContext *ac, short mode) { - ListBase anim_data = {NULL, NULL}; - ListBase nla_cache = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - struct Depsgraph *depsgraph = ac->depsgraph; - ReportList *reports = ac->reports; - Scene *scene = ac->scene; - ToolSettings *ts = scene->toolsettings; - short flag = 0; - - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - if (mode == 2) { - filter |= ANIMFILTER_SEL; - } - else if (mode == 3) { - filter |= ANIMFILTER_ACTGROUPED; - } - - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* init keyframing flag */ - flag = ANIM_get_keyframing_flags(scene, 1); - - /* insert keyframes */ - for (ale = anim_data.first; ale; ale = ale->next) { - FCurve *fcu = (FCurve *)ale->key_data; - float 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...) - */ - if (ale->id && !ale->owner) { - insert_keyframe(ac->bmain, depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), - fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, &nla_cache, flag); - } - else { - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - - /* adjust current frame for NLA-scaling */ - if (adt) - cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); - - const float curval = evaluate_fcurve(fcu, cfra); - insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0); - } - - ale->update |= ANIM_UPDATE_DEFAULT; - } - - BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + ListBase nla_cache = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + struct Depsgraph *depsgraph = ac->depsgraph; + ReportList *reports = ac->reports; + Scene *scene = ac->scene; + ToolSettings *ts = scene->toolsettings; + short flag = 0; + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | + ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + if (mode == 2) { + filter |= ANIMFILTER_SEL; + } + else if (mode == 3) { + filter |= ANIMFILTER_ACTGROUPED; + } + + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* init keyframing flag */ + flag = ANIM_get_keyframing_flags(scene, 1); + + /* insert keyframes */ + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->key_data; + float 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...) + */ + if (ale->id && !ale->owner) { + insert_keyframe(ac->bmain, + depsgraph, + reports, + ale->id, + NULL, + ((fcu->grp) ? (fcu->grp->name) : (NULL)), + fcu->rna_path, + fcu->array_index, + cfra, + ts->keyframe_type, + &nla_cache, + flag); + } + else { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + /* adjust current frame for NLA-scaling */ + if (adt) + cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); + + const float curval = evaluate_fcurve(fcu, cfra); + insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0); + } + + ale->update |= ANIM_UPDATE_DEFAULT; + } + + BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* this function is for inserting new grease pencil frames */ static void insert_gpencil_keys(bAnimContext *ac, short mode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - Scene *scene = ac->scene; - ToolSettings *ts = scene->toolsettings; - eGP_GetFrame_Mode add_frame_mode; - - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); - if (mode == 2) filter |= ANIMFILTER_SEL; - - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - - /* add a copy or a blank frame? */ - if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) - add_frame_mode = GP_GETFRAME_ADD_COPY; /* XXX: actframe may not be what we want? */ - else - add_frame_mode = GP_GETFRAME_ADD_NEW; - - - /* insert gp frames */ - for (ale = anim_data.first; ale; ale = ale->next) { - bGPDlayer *gpl = (bGPDlayer *)ale->data; - BKE_gpencil_layer_getframe(gpl, CFRA, add_frame_mode); - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + Scene *scene = ac->scene; + ToolSettings *ts = scene->toolsettings; + eGP_GetFrame_Mode add_frame_mode; + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | + ANIMFILTER_NODUPLIS); + if (mode == 2) + filter |= ANIMFILTER_SEL; + + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* add a copy or a blank frame? */ + if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) + add_frame_mode = GP_GETFRAME_ADD_COPY; /* XXX: actframe may not be what we want? */ + else + add_frame_mode = GP_GETFRAME_ADD_NEW; + + /* insert gp frames */ + for (ale = anim_data.first; ale; ale = ale->next) { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + BKE_gpencil_layer_getframe(gpl, CFRA, add_frame_mode); + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_insertkey_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - short mode; + bAnimContext ac; + short mode; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - if (ac.datatype == ANIMCONT_MASK) { - BKE_report(op->reports, RPT_ERROR, "Insert Keyframes is not yet implemented for this mode"); - return OPERATOR_CANCELLED; - } + if (ac.datatype == ANIMCONT_MASK) { + BKE_report(op->reports, RPT_ERROR, "Insert Keyframes is not yet implemented for this mode"); + return OPERATOR_CANCELLED; + } - /* what channels to affect? */ - mode = RNA_enum_get(op->ptr, "type"); + /* what channels to affect? */ + mode = RNA_enum_get(op->ptr, "type"); - /* insert keyframes */ - if (ac.datatype == ANIMCONT_GPENCIL) { - insert_gpencil_keys(&ac, mode); - } - else { - insert_action_keys(&ac, mode); - } + /* insert keyframes */ + if (ac.datatype == ANIMCONT_GPENCIL) { + insert_gpencil_keys(&ac, mode); + } + else { + insert_action_keys(&ac, mode); + } - /* set notifier that keyframes have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_keyframe_insert(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Insert Keyframes"; - ot->idname = "ACTION_OT_keyframe_insert"; - ot->description = "Insert keyframes for the specified channels"; + /* identifiers */ + ot->name = "Insert Keyframes"; + ot->idname = "ACTION_OT_keyframe_insert"; + ot->description = "Insert keyframes for the specified channels"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = actkeys_insertkey_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = actkeys_insertkey_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* id-props */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_insertkey_types, 0, "Type", ""); + /* id-props */ + ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_insertkey_types, 0, "Type", ""); } /* ******************** Duplicate Keyframes Operator ************************* */ static void duplicate_action_keys(bAnimContext *ac) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* filter data */ - if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); - } - else { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - } - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* loop through filtered data and delete selected keys */ - for (ale = anim_data.first; ale; ale = ale->next) { - if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) - duplicate_fcurve_keys((FCurve *)ale->key_data); - else if (ale->type == ANIMTYPE_GPLAYER) - ED_gplayer_frames_duplicate((bGPDlayer *)ale->data); - else if (ale->type == ANIMTYPE_MASKLAYER) - ED_masklayer_frames_duplicate((MaskLayer *)ale->data); - else - BLI_assert(0); - - ale->update |= ANIM_UPDATE_DEFAULT; - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* filter data */ + if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | + ANIMFILTER_NODUPLIS); + } + else { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | + ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + } + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through filtered data and delete selected keys */ + for (ale = anim_data.first; ale; ale = ale->next) { + if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) + duplicate_fcurve_keys((FCurve *)ale->key_data); + else if (ale->type == ANIMTYPE_GPLAYER) + ED_gplayer_frames_duplicate((bGPDlayer *)ale->data); + else if (ale->type == ANIMTYPE_MASKLAYER) + ED_masklayer_frames_duplicate((MaskLayer *)ale->data); + else + BLI_assert(0); + + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) { - bAnimContext ac; + bAnimContext ac; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* duplicate keyframes */ - duplicate_action_keys(&ac); + /* duplicate keyframes */ + duplicate_action_keys(&ac); - /* set notifier that keyframes have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_duplicate(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Duplicate Keyframes"; - ot->idname = "ACTION_OT_duplicate"; - ot->description = "Make a copy of all selected keyframes"; + /* identifiers */ + ot->name = "Duplicate Keyframes"; + ot->idname = "ACTION_OT_duplicate"; + ot->description = "Make a copy of all selected keyframes"; - /* api callbacks */ - ot->exec = actkeys_duplicate_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->exec = actkeys_duplicate_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************** Delete Keyframes Operator ************************* */ static bool delete_action_keys(bAnimContext *ac) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - bool changed_final = false; - - /* filter data */ - if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); - } - else { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - } - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* loop through filtered data and delete selected keys */ - for (ale = anim_data.first; ale; ale = ale->next) { - bool changed = false; - - if (ale->type == ANIMTYPE_GPLAYER) { - changed = ED_gplayer_frames_delete((bGPDlayer *)ale->data); - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - changed = ED_masklayer_frames_delete((MaskLayer *)ale->data); - } - else { - FCurve *fcu = (FCurve *)ale->key_data; - AnimData *adt = ale->adt; - - /* delete selected keyframes only */ - changed = delete_fcurve_keys(fcu); - - /* Only delete curve too if it won't be doing anything anymore */ - if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) { - ANIM_fcurve_delete_from_animdata(ac, adt, fcu); - ale->key_data = NULL; - } - } - - if (changed) { - ale->update |= ANIM_UPDATE_DEFAULT; - changed_final = true; - } - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); - - return changed_final; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + bool changed_final = false; + + /* filter data */ + if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | + ANIMFILTER_NODUPLIS); + } + else { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | + ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + } + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through filtered data and delete selected keys */ + for (ale = anim_data.first; ale; ale = ale->next) { + bool changed = false; + + if (ale->type == ANIMTYPE_GPLAYER) { + changed = ED_gplayer_frames_delete((bGPDlayer *)ale->data); + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + changed = ED_masklayer_frames_delete((MaskLayer *)ale->data); + } + else { + FCurve *fcu = (FCurve *)ale->key_data; + AnimData *adt = ale->adt; + + /* delete selected keyframes only */ + changed = delete_fcurve_keys(fcu); + + /* Only delete curve too if it won't be doing anything anymore */ + if ((fcu->totvert == 0) && + (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) { + ANIM_fcurve_delete_from_animdata(ac, adt, fcu); + ale->key_data = NULL; + } + } + + if (changed) { + ale->update |= ANIM_UPDATE_DEFAULT; + changed_final = true; + } + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); + + return changed_final; } /* ------------------- */ static int actkeys_delete_exec(bContext *C, wmOperator *UNUSED(op)) { - bAnimContext ac; + bAnimContext ac; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* delete keyframes */ - if (!delete_action_keys(&ac)) - return OPERATOR_CANCELLED; + /* delete keyframes */ + if (!delete_action_keys(&ac)) + return OPERATOR_CANCELLED; - /* set notifier that keyframes have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_delete(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete Keyframes"; - ot->idname = "ACTION_OT_delete"; - ot->description = "Remove all selected keyframes"; - - /* api callbacks */ - ot->invoke = WM_operator_confirm; - ot->exec = actkeys_delete_exec; - ot->poll = ED_operator_action_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Delete Keyframes"; + ot->idname = "ACTION_OT_delete"; + ot->description = "Remove all selected keyframes"; + + /* api callbacks */ + ot->invoke = WM_operator_confirm; + ot->exec = actkeys_delete_exec; + ot->poll = ED_operator_action_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************** Clean Keyframes Operator ************************* */ static void clean_action_keys(bAnimContext *ac, float thresh, bool clean_chan) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | + ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - /* loop through filtered data and clean curves */ - for (ale = anim_data.first; ale; ale = ale->next) { - clean_fcurve(ac, ale, thresh, clean_chan); + /* loop through filtered data and clean curves */ + for (ale = anim_data.first; ale; ale = ale->next) { + clean_fcurve(ac, ale, thresh, clean_chan); - ale->update |= ANIM_UPDATE_DEFAULT; - } + ale->update |= ANIM_UPDATE_DEFAULT; + } - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_clean_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - float thresh; - bool clean_chan; + bAnimContext ac; + float thresh; + bool clean_chan; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - BKE_report(op->reports, RPT_ERROR, "Not implemented"); - return OPERATOR_PASS_THROUGH; - } + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + BKE_report(op->reports, RPT_ERROR, "Not implemented"); + return OPERATOR_PASS_THROUGH; + } - /* get cleaning threshold */ - thresh = RNA_float_get(op->ptr, "threshold"); - clean_chan = RNA_boolean_get(op->ptr, "channels"); + /* get cleaning threshold */ + thresh = RNA_float_get(op->ptr, "threshold"); + clean_chan = RNA_boolean_get(op->ptr, "channels"); - /* clean keyframes */ - clean_action_keys(&ac, thresh, clean_chan); + /* clean keyframes */ + clean_action_keys(&ac, thresh, clean_chan); - /* set notifier that keyframes have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_clean(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clean Keyframes"; - ot->idname = "ACTION_OT_clean"; - ot->description = "Simplify F-Curves by removing closely spaced keyframes"; - - /* api callbacks */ - //ot->invoke = // XXX we need that number popup for this! - ot->exec = actkeys_clean_exec; - ot->poll = ED_operator_action_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f); - RNA_def_boolean(ot->srna, "channels", false, "Channels", ""); + /* identifiers */ + ot->name = "Clean Keyframes"; + ot->idname = "ACTION_OT_clean"; + ot->description = "Simplify F-Curves by removing closely spaced keyframes"; + + /* api callbacks */ + //ot->invoke = // XXX we need that number popup for this! + ot->exec = actkeys_clean_exec; + ot->poll = ED_operator_action_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_float( + ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f); + RNA_def_boolean(ot->srna, "channels", false, "Channels", ""); } /* ******************** Sample Keyframes Operator *********************** */ @@ -1057,62 +1089,63 @@ void ACTION_OT_clean(wmOperatorType *ot) /* Evaluates the curves between each selected keyframe on each frame, and keys the value */ static void sample_action_keys(bAnimContext *ac) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | + ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - /* loop through filtered data and add keys between selected keyframes on every frame */ - for (ale = anim_data.first; ale; ale = ale->next) { - sample_fcurve((FCurve *)ale->key_data); + /* loop through filtered data and add keys between selected keyframes on every frame */ + for (ale = anim_data.first; ale; ale = ale->next) { + sample_fcurve((FCurve *)ale->key_data); - ale->update |= ANIM_UPDATE_DEPS; - } + ale->update |= ANIM_UPDATE_DEPS; + } - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_sample_exec(bContext *C, wmOperator *op) { - bAnimContext ac; + bAnimContext ac; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - BKE_report(op->reports, RPT_ERROR, "Not implemented"); - return OPERATOR_PASS_THROUGH; - } + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + BKE_report(op->reports, RPT_ERROR, "Not implemented"); + return OPERATOR_PASS_THROUGH; + } - /* sample keyframes */ - sample_action_keys(&ac); + /* sample keyframes */ + sample_action_keys(&ac); - /* set notifier that keyframes have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_sample(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Sample Keyframes"; - ot->idname = "ACTION_OT_sample"; - ot->description = "Add keyframes on every frame between the selected keyframes"; + /* identifiers */ + ot->name = "Sample Keyframes"; + ot->idname = "ACTION_OT_sample"; + ot->description = "Add keyframes on every frame between the selected keyframes"; - /* api callbacks */ - ot->exec = actkeys_sample_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->exec = actkeys_sample_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ************************************************************************** */ @@ -1121,114 +1154,131 @@ void ACTION_OT_sample(wmOperatorType *ot) /* ******************** Set Extrapolation-Type Operator *********************** */ /* defines for make/clear cyclic extrapolation tools */ -#define MAKE_CYCLIC_EXPO -1 -#define CLEAR_CYCLIC_EXPO -2 +#define MAKE_CYCLIC_EXPO -1 +#define CLEAR_CYCLIC_EXPO -2 /* defines for set extrapolation-type for selected keyframes tool */ static const EnumPropertyItem prop_actkeys_expo_types[] = { - {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", 0, "Constant Extrapolation", "Values on endpoint keyframes are held"}, - {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", 0, "Linear Extrapolation", "Straight-line slope of end segments are extended past the endpoint keyframes"}, - - {MAKE_CYCLIC_EXPO, "MAKE_CYCLIC", 0, "Make Cyclic (F-Modifier)", "Add Cycles F-Modifier if one doesn't exist already"}, - {CLEAR_CYCLIC_EXPO, "CLEAR_CYCLIC", 0, "Clear Cyclic (F-Modifier)", "Remove Cycles F-Modifier if not needed anymore"}, - {0, NULL, 0, NULL, NULL}, + {FCURVE_EXTRAPOLATE_CONSTANT, + "CONSTANT", + 0, + "Constant Extrapolation", + "Values on endpoint keyframes are held"}, + {FCURVE_EXTRAPOLATE_LINEAR, + "LINEAR", + 0, + "Linear Extrapolation", + "Straight-line slope of end segments are extended past the endpoint keyframes"}, + + {MAKE_CYCLIC_EXPO, + "MAKE_CYCLIC", + 0, + "Make Cyclic (F-Modifier)", + "Add Cycles F-Modifier if one doesn't exist already"}, + {CLEAR_CYCLIC_EXPO, + "CLEAR_CYCLIC", + 0, + "Clear Cyclic (F-Modifier)", + "Remove Cycles F-Modifier if not needed anymore"}, + {0, NULL, 0, NULL, NULL}, }; /* this function is responsible for setting extrapolation mode for keyframes */ static void setexpo_action_keys(bAnimContext *ac, short mode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* loop through setting mode per F-Curve */ - for (ale = anim_data.first; ale; ale = ale->next) { - FCurve *fcu = (FCurve *)ale->data; - - if (mode >= 0) { - /* just set mode setting */ - fcu->extend = mode; - } - else { - /* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation - * without having to go through FModifier UI in Graph Editor to do so - */ - if (mode == MAKE_CYCLIC_EXPO) { - /* only add if one doesn't exist */ - if (list_has_suitable_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, -1) == 0) { - /* TODO: add some more preset versions which set different extrapolation options? */ - add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, fcu); - } - } - else if (mode == CLEAR_CYCLIC_EXPO) { - /* remove all the modifiers fitting this description */ - FModifier *fcm, *fcn = NULL; - - for (fcm = fcu->modifiers.first; fcm; fcm = fcn) { - fcn = fcm->next; - - if (fcm->type == FMODIFIER_TYPE_CYCLES) - remove_fmodifier(&fcu->modifiers, fcm); - } - } - } - - ale->update |= ANIM_UPDATE_DEFAULT; - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | + ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through setting mode per F-Curve */ + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->data; + + if (mode >= 0) { + /* just set mode setting */ + fcu->extend = mode; + } + else { + /* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation + * without having to go through FModifier UI in Graph Editor to do so + */ + if (mode == MAKE_CYCLIC_EXPO) { + /* only add if one doesn't exist */ + if (list_has_suitable_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, -1) == 0) { + /* TODO: add some more preset versions which set different extrapolation options? */ + add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, fcu); + } + } + else if (mode == CLEAR_CYCLIC_EXPO) { + /* remove all the modifiers fitting this description */ + FModifier *fcm, *fcn = NULL; + + for (fcm = fcu->modifiers.first; fcm; fcm = fcn) { + fcn = fcm->next; + + if (fcm->type == FMODIFIER_TYPE_CYCLES) + remove_fmodifier(&fcu->modifiers, fcm); + } + } + } + + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_expo_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - short mode; + bAnimContext ac; + short mode; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - BKE_report(op->reports, RPT_ERROR, "Not implemented"); - return OPERATOR_PASS_THROUGH; - } + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + BKE_report(op->reports, RPT_ERROR, "Not implemented"); + return OPERATOR_PASS_THROUGH; + } - /* get handle setting mode */ - mode = RNA_enum_get(op->ptr, "type"); + /* get handle setting mode */ + mode = RNA_enum_get(op->ptr, "type"); - /* set handle type */ - setexpo_action_keys(&ac, mode); + /* set handle type */ + setexpo_action_keys(&ac, mode); - /* set notifier that keyframe properties have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); + /* set notifier that keyframe properties have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_extrapolation_type(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set Keyframe Extrapolation"; - ot->idname = "ACTION_OT_extrapolation_type"; - ot->description = "Set extrapolation mode for selected F-Curves"; + /* identifiers */ + ot->name = "Set Keyframe Extrapolation"; + ot->idname = "ACTION_OT_extrapolation_type"; + ot->description = "Set extrapolation mode for selected F-Curves"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = actkeys_expo_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = actkeys_expo_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* id-props */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_expo_types, 0, "Type", ""); + /* id-props */ + ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_expo_types, 0, "Type", ""); } /* ******************** Set Interpolation-Type Operator *********************** */ @@ -1236,73 +1286,76 @@ void ACTION_OT_extrapolation_type(wmOperatorType *ot) /* this function is responsible for setting interpolation mode for keyframes */ static void setipo_action_keys(bAnimContext *ac, short mode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - KeyframeEditFunc set_cb = ANIM_editkeyframes_ipo(mode); - - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* loop through setting BezTriple interpolation - * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here... - */ - for (ale = anim_data.first; ale; ale = ale->next) { - ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve); - - ale->update |= ANIM_UPDATE_DEFAULT; - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + KeyframeEditFunc set_cb = ANIM_editkeyframes_ipo(mode); + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | + ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through setting BezTriple interpolation + * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here... + */ + for (ale = anim_data.first; ale; ale = ale->next) { + ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve); + + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_ipo_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - short mode; + bAnimContext ac; + short mode; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - BKE_report(op->reports, RPT_ERROR, "Not implemented"); - return OPERATOR_PASS_THROUGH; - } + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + BKE_report(op->reports, RPT_ERROR, "Not implemented"); + return OPERATOR_PASS_THROUGH; + } - /* get handle setting mode */ - mode = RNA_enum_get(op->ptr, "type"); + /* get handle setting mode */ + mode = RNA_enum_get(op->ptr, "type"); - /* set handle type */ - setipo_action_keys(&ac, mode); + /* set handle type */ + setipo_action_keys(&ac, mode); - /* set notifier that keyframe properties have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); + /* set notifier that keyframe properties have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_interpolation_type(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set Keyframe Interpolation"; - ot->idname = "ACTION_OT_interpolation_type"; - ot->description = "Set interpolation mode for the F-Curve segments starting from the selected keyframes"; - - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = actkeys_ipo_exec; - ot->poll = ED_operator_action_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* id-props */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", ""); + /* identifiers */ + ot->name = "Set Keyframe Interpolation"; + ot->idname = "ACTION_OT_interpolation_type"; + ot->description = + "Set interpolation mode for the F-Curve segments starting from the selected keyframes"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = actkeys_ipo_exec; + ot->poll = ED_operator_action_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* id-props */ + ot->prop = RNA_def_enum( + ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", ""); } /* ******************** Set Handle-Type Operator *********************** */ @@ -1310,81 +1363,82 @@ void ACTION_OT_interpolation_type(wmOperatorType *ot) /* this function is responsible for setting handle-type of selected keyframes */ static void sethandles_action_keys(bAnimContext *ac, short mode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - KeyframeEditFunc edit_cb = ANIM_editkeyframes_handles(mode); - KeyframeEditFunc sel_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED); - - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* loop through setting flags for handles - * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here... - */ - for (ale = anim_data.first; ale; ale = ale->next) { - FCurve *fcu = (FCurve *)ale->key_data; - - /* any selected keyframes for editing? */ - if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) { - /* change type of selected handles */ - ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve); - - ale->update |= ANIM_UPDATE_DEFAULT; - } - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditFunc edit_cb = ANIM_editkeyframes_handles(mode); + KeyframeEditFunc sel_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED); + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | + ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through setting flags for handles + * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here... + */ + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->key_data; + + /* any selected keyframes for editing? */ + if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) { + /* change type of selected handles */ + ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve); + + ale->update |= ANIM_UPDATE_DEFAULT; + } + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_handletype_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - short mode; + bAnimContext ac; + short mode; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - BKE_report(op->reports, RPT_ERROR, "Not implemented"); - return OPERATOR_PASS_THROUGH; - } + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + BKE_report(op->reports, RPT_ERROR, "Not implemented"); + return OPERATOR_PASS_THROUGH; + } - /* get handle setting mode */ - mode = RNA_enum_get(op->ptr, "type"); + /* get handle setting mode */ + mode = RNA_enum_get(op->ptr, "type"); - /* set handle type */ - sethandles_action_keys(&ac, mode); + /* set handle type */ + sethandles_action_keys(&ac, mode); - /* set notifier that keyframe properties have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); + /* set notifier that keyframe properties have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_handle_type(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set Keyframe Handle Type"; - ot->idname = "ACTION_OT_handle_type"; - ot->description = "Set type of handle for selected keyframes"; + /* identifiers */ + ot->name = "Set Keyframe Handle Type"; + ot->idname = "ACTION_OT_handle_type"; + ot->description = "Set type of handle for selected keyframes"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = actkeys_handletype_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = actkeys_handletype_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* id-props */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", ""); + /* id-props */ + ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", ""); } /* ******************** Set Keyframe-Type Operator *********************** */ @@ -1392,101 +1446,103 @@ void ACTION_OT_handle_type(wmOperatorType *ot) /* this function is responsible for setting keyframe type for keyframes */ static void setkeytype_action_keys(bAnimContext *ac, short mode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - KeyframeEditFunc set_cb = ANIM_editkeyframes_keytype(mode); - - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* loop through setting BezTriple interpolation - * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here... - */ - for (ale = anim_data.first; ale; ale = ale->next) { - ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, NULL); - - ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES; - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + KeyframeEditFunc set_cb = ANIM_editkeyframes_keytype(mode); + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | + ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through setting BezTriple interpolation + * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here... + */ + for (ale = anim_data.first; ale; ale = ale->next) { + ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, NULL); + + ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* this function is responsible for setting the keyframe type for Grease Pencil frames */ static void setkeytype_gpencil_keys(bAnimContext *ac, short mode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* loop through each layer */ - for (ale = anim_data.first; ale; ale = ale->next) { - if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_frames_keytype_set(ale->data, mode); - ale->update |= ANIM_UPDATE_DEPS; - } - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | + ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through each layer */ + for (ale = anim_data.first; ale; ale = ale->next) { + if (ale->type == ANIMTYPE_GPLAYER) { + ED_gplayer_frames_keytype_set(ale->data, mode); + ale->update |= ANIM_UPDATE_DEPS; + } + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_keytype_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - short mode; + bAnimContext ac; + short mode; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - if (ac.datatype == ANIMCONT_MASK) { - BKE_report(op->reports, RPT_ERROR, "Not implemented for Masks"); - return OPERATOR_PASS_THROUGH; - } + if (ac.datatype == ANIMCONT_MASK) { + BKE_report(op->reports, RPT_ERROR, "Not implemented for Masks"); + return OPERATOR_PASS_THROUGH; + } - /* get handle setting mode */ - mode = RNA_enum_get(op->ptr, "type"); + /* get handle setting mode */ + mode = RNA_enum_get(op->ptr, "type"); - /* set handle type */ - if (ac.datatype == ANIMCONT_GPENCIL) { - setkeytype_gpencil_keys(&ac, mode); - } - else { - setkeytype_action_keys(&ac, mode); - } + /* set handle type */ + if (ac.datatype == ANIMCONT_GPENCIL) { + setkeytype_gpencil_keys(&ac, mode); + } + else { + setkeytype_action_keys(&ac, mode); + } - /* set notifier that keyframe properties have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); + /* set notifier that keyframe properties have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_keyframe_type(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set Keyframe Type"; - ot->idname = "ACTION_OT_keyframe_type"; - ot->description = "Set type of keyframe for the selected keyframes"; + /* identifiers */ + ot->name = "Set Keyframe Type"; + ot->idname = "ACTION_OT_keyframe_type"; + ot->description = "Set type of keyframe for the selected keyframes"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = actkeys_keytype_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = actkeys_keytype_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* id-props */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_keyframe_type_items, 0, "Type", ""); + /* id-props */ + ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_keyframe_type_items, 0, "Type", ""); } /* ************************************************************************** */ @@ -1496,297 +1552,323 @@ void ACTION_OT_keyframe_type(wmOperatorType *ot) static bool actkeys_framejump_poll(bContext *C) { - /* prevent changes during render */ - if (G.is_rendering) - return 0; + /* prevent changes during render */ + if (G.is_rendering) + return 0; - return ED_operator_action_active(C); + return ED_operator_action_active(C); } /* snap current-frame indicator to 'average time' of selected keyframe */ static int actkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op)) { - bAnimContext ac; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - KeyframeEditData ked = {{NULL}}; - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* init edit data */ - /* loop over action data, averaging values */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - - for (ale = anim_data.first; ale; ale = ale->next) { - AnimData *adt = ANIM_nla_mapping_get(&ac, ale); - if (adt) { - ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL); - ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); - } - else - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL); - } - - ANIM_animdata_freelist(&anim_data); - - /* set the new current frame value, based on the average time */ - if (ked.i1) { - Scene *scene = ac.scene; - CFRA = round_fl_to_int(ked.f1 / ked.i1); - SUBFRA = 0.f; - } - - /* set notifier that things have changed */ - WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene); - - return OPERATOR_FINISHED; + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + KeyframeEditData ked = {{NULL}}; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* init edit data */ + /* loop over action data, averaging values */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | + ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(&ac, ale); + if (adt) { + ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL); + ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); + } + else + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL); + } + + ANIM_animdata_freelist(&anim_data); + + /* set the new current frame value, based on the average time */ + if (ked.i1) { + Scene *scene = ac.scene; + CFRA = round_fl_to_int(ked.f1 / ked.i1); + SUBFRA = 0.f; + } + + /* set notifier that things have changed */ + WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene); + + return OPERATOR_FINISHED; } void ACTION_OT_frame_jump(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Jump to Keyframes"; - ot->idname = "ACTION_OT_frame_jump"; - ot->description = "Set the current frame to the average frame value of selected keyframes"; + /* identifiers */ + ot->name = "Jump to Keyframes"; + ot->idname = "ACTION_OT_frame_jump"; + ot->description = "Set the current frame to the average frame value of selected keyframes"; - /* api callbacks */ - ot->exec = actkeys_framejump_exec; - ot->poll = actkeys_framejump_poll; + /* api callbacks */ + ot->exec = actkeys_framejump_exec; + ot->poll = actkeys_framejump_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************** Snap Keyframes Operator *********************** */ /* defines for snap keyframes tool */ static const EnumPropertyItem prop_actkeys_snap_types[] = { - {ACTKEYS_SNAP_CFRA, "CFRA", 0, "Current frame", - "Snap selected keyframes to the current frame"}, - {ACTKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", - "Snap selected keyframes to the nearest (whole) frame (use to fix accidental sub-frame offsets)"}, - {ACTKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", - "Snap selected keyframes to the nearest second"}, - {ACTKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", - "Snap selected keyframes to the nearest marker"}, - {0, NULL, 0, NULL, NULL}, + {ACTKEYS_SNAP_CFRA, + "CFRA", + 0, + "Current frame", + "Snap selected keyframes to the current frame"}, + {ACTKEYS_SNAP_NEAREST_FRAME, + "NEAREST_FRAME", + 0, + "Nearest Frame", + "Snap selected keyframes to the nearest (whole) frame (use to fix accidental sub-frame " + "offsets)"}, + {ACTKEYS_SNAP_NEAREST_SECOND, + "NEAREST_SECOND", + 0, + "Nearest Second", + "Snap selected keyframes to the nearest second"}, + {ACTKEYS_SNAP_NEAREST_MARKER, + "NEAREST_MARKER", + 0, + "Nearest Marker", + "Snap selected keyframes to the nearest marker"}, + {0, NULL, 0, NULL, NULL}, }; /* this function is responsible for snapping keyframes to frame-times */ static void snap_action_keys(bAnimContext *ac, short mode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - KeyframeEditData ked = {{NULL}}; - KeyframeEditFunc edit_cb; - - /* filter data */ - if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT); - } - else { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - } - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* get beztriple editing callbacks */ - edit_cb = ANIM_editkeyframes_snap(mode); - - ked.scene = ac->scene; - if (mode == ACTKEYS_SNAP_NEAREST_MARKER) { - ked.list.first = (ac->markers) ? ac->markers->first : NULL; - ked.list.last = (ac->markers) ? ac->markers->last : NULL; - } - - /* snap keyframes */ - for (ale = anim_data.first; ale; ale = ale->next) { - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - - if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_snap_frames(ale->data, ac->scene, mode); - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - ED_masklayer_snap_frames(ale->data, ac->scene, mode); - } - else if (adt) { - ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0); - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); - ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0); - } - else { - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); - } - - ale->update |= ANIM_UPDATE_DEFAULT; - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditData ked = {{NULL}}; + KeyframeEditFunc edit_cb; + + /* filter data */ + if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT); + } + else { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | + ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + } + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* get beztriple editing callbacks */ + edit_cb = ANIM_editkeyframes_snap(mode); + + ked.scene = ac->scene; + if (mode == ACTKEYS_SNAP_NEAREST_MARKER) { + ked.list.first = (ac->markers) ? ac->markers->first : NULL; + ked.list.last = (ac->markers) ? ac->markers->last : NULL; + } + + /* snap keyframes */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + if (ale->type == ANIMTYPE_GPLAYER) { + ED_gplayer_snap_frames(ale->data, ac->scene, mode); + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + ED_masklayer_snap_frames(ale->data, ac->scene, mode); + } + else if (adt) { + ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0); + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); + ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0); + } + else { + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); + } + + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_snap_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - short mode; + bAnimContext ac; + short mode; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* get snapping mode */ - mode = RNA_enum_get(op->ptr, "type"); + /* get snapping mode */ + mode = RNA_enum_get(op->ptr, "type"); - /* snap keyframes */ - snap_action_keys(&ac, mode); + /* snap keyframes */ + snap_action_keys(&ac, mode); - /* set notifier that keyframes have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_snap(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Snap Keys"; - ot->idname = "ACTION_OT_snap"; - ot->description = "Snap selected keyframes to the times specified"; + /* identifiers */ + ot->name = "Snap Keys"; + ot->idname = "ACTION_OT_snap"; + ot->description = "Snap selected keyframes to the times specified"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = actkeys_snap_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = actkeys_snap_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* id-props */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_snap_types, 0, "Type", ""); + /* id-props */ + ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_snap_types, 0, "Type", ""); } /* ******************** Mirror Keyframes Operator *********************** */ /* defines for mirror keyframes tool */ static const EnumPropertyItem prop_actkeys_mirror_types[] = { - {ACTKEYS_MIRROR_CFRA, "CFRA", 0, "By Times over Current frame", - "Flip times of selected keyframes using the current frame as the mirror line"}, - {ACTKEYS_MIRROR_XAXIS, "XAXIS", 0, "By Values over Value=0", - "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"}, - {ACTKEYS_MIRROR_MARKER, "MARKER", 0, "By Times over First Selected Marker", - "Flip times of selected keyframes using the first selected marker as the reference point"}, - {0, NULL, 0, NULL, NULL}, + {ACTKEYS_MIRROR_CFRA, + "CFRA", + 0, + "By Times over Current frame", + "Flip times of selected keyframes using the current frame as the mirror line"}, + {ACTKEYS_MIRROR_XAXIS, + "XAXIS", + 0, + "By Values over Value=0", + "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"}, + {ACTKEYS_MIRROR_MARKER, + "MARKER", + 0, + "By Times over First Selected Marker", + "Flip times of selected keyframes using the first selected marker as the reference point"}, + {0, NULL, 0, NULL, NULL}, }; /* this function is responsible for mirroring keyframes */ static void mirror_action_keys(bAnimContext *ac, short mode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - KeyframeEditData ked = {{NULL}}; - KeyframeEditFunc edit_cb; - - /* get beztriple editing callbacks */ - edit_cb = ANIM_editkeyframes_mirror(mode); - - ked.scene = ac->scene; - - /* for 'first selected marker' mode, need to find first selected marker first! */ - /* XXX should this be made into a helper func in the API? */ - if (mode == ACTKEYS_MIRROR_MARKER) { - TimeMarker *marker = ED_markers_get_first_selected(ac->markers); - - if (marker) - ked.f1 = (float)marker->frame; - else - return; - } - - /* filter data */ - if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); - } - else { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - } - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* mirror keyframes */ - for (ale = anim_data.first; ale; ale = ale->next) { - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - - if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_mirror_frames(ale->data, ac->scene, mode); - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - /* TODO */ - } - else if (adt) { - ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0); - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); - ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0); - } - else { - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); - } - - ale->update |= ANIM_UPDATE_DEFAULT; - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditData ked = {{NULL}}; + KeyframeEditFunc edit_cb; + + /* get beztriple editing callbacks */ + edit_cb = ANIM_editkeyframes_mirror(mode); + + ked.scene = ac->scene; + + /* for 'first selected marker' mode, need to find first selected marker first! */ + /* XXX should this be made into a helper func in the API? */ + if (mode == ACTKEYS_MIRROR_MARKER) { + TimeMarker *marker = ED_markers_get_first_selected(ac->markers); + + if (marker) + ked.f1 = (float)marker->frame; + else + return; + } + + /* filter data */ + if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | + ANIMFILTER_NODUPLIS); + } + else { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | + ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + } + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* mirror keyframes */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + if (ale->type == ANIMTYPE_GPLAYER) { + ED_gplayer_mirror_frames(ale->data, ac->scene, mode); + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + /* TODO */ + } + else if (adt) { + ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0); + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); + ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0); + } + else { + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); + } + + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_mirror_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - short mode; + bAnimContext ac; + short mode; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* get mirroring mode */ - mode = RNA_enum_get(op->ptr, "type"); + /* get mirroring mode */ + mode = RNA_enum_get(op->ptr, "type"); - /* mirror keyframes */ - mirror_action_keys(&ac, mode); + /* mirror keyframes */ + mirror_action_keys(&ac, mode); - /* set notifier that keyframes have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_mirror(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Mirror Keys"; - ot->idname = "ACTION_OT_mirror"; - ot->description = "Flip selected keyframes over the selected mirror line"; + /* identifiers */ + ot->name = "Mirror Keys"; + ot->idname = "ACTION_OT_mirror"; + ot->description = "Flip selected keyframes over the selected mirror line"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = actkeys_mirror_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = actkeys_mirror_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* id-props */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", ""); + /* id-props */ + ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", ""); } /* ************************************************************************** */ diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index 74da8aafcc8..5d86cf6faec 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -68,17 +68,17 @@ void ACTION_OT_clickselect(struct wmOperatorType *ot); /* defines for left-right select tool */ enum eActKeys_LeftRightSelect_Mode { - ACTKEYS_LRSEL_TEST = 0, - ACTKEYS_LRSEL_LEFT, - ACTKEYS_LRSEL_RIGHT, + ACTKEYS_LRSEL_TEST = 0, + ACTKEYS_LRSEL_LEFT, + ACTKEYS_LRSEL_RIGHT, }; /* defines for column-select mode */ enum eActKeys_ColumnSelect_Mode { - ACTKEYS_COLUMNSEL_KEYS = 0, - ACTKEYS_COLUMNSEL_CFRA, - ACTKEYS_COLUMNSEL_MARKERS_COLUMN, - ACTKEYS_COLUMNSEL_MARKERS_BETWEEN, + ACTKEYS_COLUMNSEL_KEYS = 0, + ACTKEYS_COLUMNSEL_CFRA, + ACTKEYS_COLUMNSEL_MARKERS_COLUMN, + ACTKEYS_COLUMNSEL_MARKERS_BETWEEN, }; /* ***************************************** */ @@ -124,20 +124,20 @@ void ACTION_OT_markers_make_local(struct wmOperatorType *ot); * NOTE: keep in sync with eEditKeyframes_Snap (in ED_keyframes_edit.h) */ enum eActKeys_Snap_Mode { - ACTKEYS_SNAP_CFRA = 1, - ACTKEYS_SNAP_NEAREST_FRAME, - ACTKEYS_SNAP_NEAREST_SECOND, - ACTKEYS_SNAP_NEAREST_MARKER, + ACTKEYS_SNAP_CFRA = 1, + ACTKEYS_SNAP_NEAREST_FRAME, + ACTKEYS_SNAP_NEAREST_SECOND, + ACTKEYS_SNAP_NEAREST_MARKER, }; /* defines for mirror keyframes * NOTE: keep in sync with eEditKeyframes_Mirror (in ED_keyframes_edit.h) */ enum eActKeys_Mirror_Mode { - ACTKEYS_MIRROR_CFRA = 1, - ACTKEYS_MIRROR_YAXIS, - ACTKEYS_MIRROR_XAXIS, - ACTKEYS_MIRROR_MARKER, + ACTKEYS_MIRROR_CFRA = 1, + ACTKEYS_MIRROR_YAXIS, + ACTKEYS_MIRROR_XAXIS, + ACTKEYS_MIRROR_MARKER, }; /* ***************************************** */ diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index 87b9ee4e1ef..d5ddf974284 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -21,14 +21,11 @@ * \ingroup spaction */ - #include #include - #include "DNA_space_types.h" - #include "ED_anim_api.h" #include "ED_markers.h" #include "ED_transform.h" @@ -46,68 +43,69 @@ void action_operatortypes(void) { - /* view */ - WM_operatortype_append(ACTION_OT_properties); - - /* keyframes */ - /* selection */ - WM_operatortype_append(ACTION_OT_clickselect); - WM_operatortype_append(ACTION_OT_select_all); - WM_operatortype_append(ACTION_OT_select_box); - WM_operatortype_append(ACTION_OT_select_lasso); - WM_operatortype_append(ACTION_OT_select_circle); - WM_operatortype_append(ACTION_OT_select_column); - WM_operatortype_append(ACTION_OT_select_linked); - WM_operatortype_append(ACTION_OT_select_more); - WM_operatortype_append(ACTION_OT_select_less); - WM_operatortype_append(ACTION_OT_select_leftright); - - /* editing */ - WM_operatortype_append(ACTION_OT_snap); - WM_operatortype_append(ACTION_OT_mirror); - WM_operatortype_append(ACTION_OT_frame_jump); - WM_operatortype_append(ACTION_OT_handle_type); - WM_operatortype_append(ACTION_OT_interpolation_type); - WM_operatortype_append(ACTION_OT_extrapolation_type); - WM_operatortype_append(ACTION_OT_keyframe_type); - WM_operatortype_append(ACTION_OT_sample); - WM_operatortype_append(ACTION_OT_clean); - WM_operatortype_append(ACTION_OT_delete); - WM_operatortype_append(ACTION_OT_duplicate); - WM_operatortype_append(ACTION_OT_keyframe_insert); - WM_operatortype_append(ACTION_OT_copy); - WM_operatortype_append(ACTION_OT_paste); - - WM_operatortype_append(ACTION_OT_new); - WM_operatortype_append(ACTION_OT_unlink); - - WM_operatortype_append(ACTION_OT_push_down); - WM_operatortype_append(ACTION_OT_stash); - WM_operatortype_append(ACTION_OT_stash_and_create); - - WM_operatortype_append(ACTION_OT_layer_next); - WM_operatortype_append(ACTION_OT_layer_prev); - - WM_operatortype_append(ACTION_OT_previewrange_set); - WM_operatortype_append(ACTION_OT_view_all); - WM_operatortype_append(ACTION_OT_view_selected); - WM_operatortype_append(ACTION_OT_view_frame); - - WM_operatortype_append(ACTION_OT_markers_make_local); + /* view */ + WM_operatortype_append(ACTION_OT_properties); + + /* keyframes */ + /* selection */ + WM_operatortype_append(ACTION_OT_clickselect); + WM_operatortype_append(ACTION_OT_select_all); + WM_operatortype_append(ACTION_OT_select_box); + WM_operatortype_append(ACTION_OT_select_lasso); + WM_operatortype_append(ACTION_OT_select_circle); + WM_operatortype_append(ACTION_OT_select_column); + WM_operatortype_append(ACTION_OT_select_linked); + WM_operatortype_append(ACTION_OT_select_more); + WM_operatortype_append(ACTION_OT_select_less); + WM_operatortype_append(ACTION_OT_select_leftright); + + /* editing */ + WM_operatortype_append(ACTION_OT_snap); + WM_operatortype_append(ACTION_OT_mirror); + WM_operatortype_append(ACTION_OT_frame_jump); + WM_operatortype_append(ACTION_OT_handle_type); + WM_operatortype_append(ACTION_OT_interpolation_type); + WM_operatortype_append(ACTION_OT_extrapolation_type); + WM_operatortype_append(ACTION_OT_keyframe_type); + WM_operatortype_append(ACTION_OT_sample); + WM_operatortype_append(ACTION_OT_clean); + WM_operatortype_append(ACTION_OT_delete); + WM_operatortype_append(ACTION_OT_duplicate); + WM_operatortype_append(ACTION_OT_keyframe_insert); + WM_operatortype_append(ACTION_OT_copy); + WM_operatortype_append(ACTION_OT_paste); + + WM_operatortype_append(ACTION_OT_new); + WM_operatortype_append(ACTION_OT_unlink); + + WM_operatortype_append(ACTION_OT_push_down); + WM_operatortype_append(ACTION_OT_stash); + WM_operatortype_append(ACTION_OT_stash_and_create); + + WM_operatortype_append(ACTION_OT_layer_next); + WM_operatortype_append(ACTION_OT_layer_prev); + + WM_operatortype_append(ACTION_OT_previewrange_set); + WM_operatortype_append(ACTION_OT_view_all); + WM_operatortype_append(ACTION_OT_view_selected); + WM_operatortype_append(ACTION_OT_view_frame); + + WM_operatortype_append(ACTION_OT_markers_make_local); } void ED_operatormacros_action(void) { - wmOperatorType *ot; - wmOperatorTypeMacro *otmacro; - - ot = WM_operatortype_append_macro("ACTION_OT_duplicate_move", "Duplicate", - "Make a copy of all selected keyframes and move them", - OPTYPE_UNDO | OPTYPE_REGISTER); - WM_operatortype_macro_define(ot, "ACTION_OT_duplicate"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_transform"); - RNA_enum_set(otmacro->ptr, "mode", TFM_TIME_DUPLICATE); - RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF); + wmOperatorType *ot; + wmOperatorTypeMacro *otmacro; + + ot = WM_operatortype_append_macro("ACTION_OT_duplicate_move", + "Duplicate", + "Make a copy of all selected keyframes and move them", + OPTYPE_UNDO | OPTYPE_REGISTER); + WM_operatortype_macro_define(ot, "ACTION_OT_duplicate"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_transform"); + RNA_enum_set(otmacro->ptr, "mode", TFM_TIME_DUPLICATE); + RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF); } /* ************************** registration - keymaps **********************************/ @@ -116,15 +114,15 @@ void ED_operatormacros_action(void) void action_keymap(wmKeyConfig *keyconf) { - /* keymap for all regions */ - WM_keymap_ensure(keyconf, "Dopesheet Generic", SPACE_ACTION, 0); + /* keymap for all regions */ + WM_keymap_ensure(keyconf, "Dopesheet Generic", SPACE_ACTION, 0); - /* channels */ - /* Channels are not directly handled by the Action Editor module, but are inherited from the Animation module. - * All the relevant operations, keymaps, drawing, etc. can therefore all be found in that module instead, as these - * are all used for the Graph-Editor too. - */ + /* channels */ + /* Channels are not directly handled by the Action Editor module, but are inherited from the Animation module. + * All the relevant operations, keymaps, drawing, etc. can therefore all be found in that module instead, as these + * are all used for the Graph-Editor too. + */ - /* keyframes */ - WM_keymap_ensure(keyconf, "Dopesheet", SPACE_ACTION, 0); + /* keyframes */ + WM_keymap_ensure(keyconf, "Dopesheet", SPACE_ACTION, 0); } diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 872f889e8b4..7499458181e 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -20,7 +20,6 @@ * \ingroup spaction */ - #include #include #include @@ -63,7 +62,6 @@ #include "action_intern.h" - /* ************************************************************************** */ /* KEYFRAMES STUFF */ @@ -82,125 +80,126 @@ */ static void deselect_action_keys(bAnimContext *ac, short test, short sel) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - KeyframeEditData ked = {{NULL}}; - KeyframeEditFunc test_cb, sel_cb; - - /* determine type-based settings */ - if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS); - } - else { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - } - - /* filter data */ - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* init BezTriple looping data */ - test_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED); - - /* See if we should be selecting or deselecting */ - if (test) { - for (ale = anim_data.first; ale; ale = ale->next) { - if (ale->type == ANIMTYPE_GPLAYER) { - if (ED_gplayer_frame_select_check(ale->data)) { - sel = SELECT_SUBTRACT; - break; - } - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - if (ED_masklayer_frame_select_check(ale->data)) { - sel = SELECT_SUBTRACT; - break; - } - } - else { - if (ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, test_cb, NULL)) { - sel = SELECT_SUBTRACT; - break; - } - } - } - } - - /* convert sel to selectmode, and use that to get editor */ - sel_cb = ANIM_editkeyframes_select(sel); - - /* Now set the flags */ - for (ale = anim_data.first; ale; ale = ale->next) { - if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_frame_select_set(ale->data, sel); - ale->update |= ANIM_UPDATE_DEPS; - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - ED_masklayer_frame_select_set(ale->data, sel); - } - else { - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, sel_cb, NULL); - } - } - - /* Cleanup */ - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditData ked = {{NULL}}; + KeyframeEditFunc test_cb, sel_cb; + + /* determine type-based settings */ + if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS); + } + else { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | + ANIMFILTER_NODUPLIS); + } + + /* filter data */ + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* init BezTriple looping data */ + test_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED); + + /* See if we should be selecting or deselecting */ + if (test) { + for (ale = anim_data.first; ale; ale = ale->next) { + if (ale->type == ANIMTYPE_GPLAYER) { + if (ED_gplayer_frame_select_check(ale->data)) { + sel = SELECT_SUBTRACT; + break; + } + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + if (ED_masklayer_frame_select_check(ale->data)) { + sel = SELECT_SUBTRACT; + break; + } + } + else { + if (ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, test_cb, NULL)) { + sel = SELECT_SUBTRACT; + break; + } + } + } + } + + /* convert sel to selectmode, and use that to get editor */ + sel_cb = ANIM_editkeyframes_select(sel); + + /* Now set the flags */ + for (ale = anim_data.first; ale; ale = ale->next) { + if (ale->type == ANIMTYPE_GPLAYER) { + ED_gplayer_frame_select_set(ale->data, sel); + ale->update |= ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + ED_masklayer_frame_select_set(ale->data, sel); + } + else { + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, sel_cb, NULL); + } + } + + /* Cleanup */ + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_deselectall_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* 'standard' behavior - check if selected, then apply relevant selection */ - const int action = RNA_enum_get(op->ptr, "action"); - switch (action) { - case SEL_TOGGLE: - deselect_action_keys(&ac, 1, SELECT_ADD); - break; - case SEL_SELECT: - deselect_action_keys(&ac, 0, SELECT_ADD); - break; - case SEL_DESELECT: - deselect_action_keys(&ac, 0, SELECT_SUBTRACT); - break; - case SEL_INVERT: - deselect_action_keys(&ac, 0, SELECT_INVERT); - break; - default: - BLI_assert(0); - break; - } - - /* set notifier that keyframe selection have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - - return OPERATOR_FINISHED; + bAnimContext ac; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* 'standard' behavior - check if selected, then apply relevant selection */ + const int action = RNA_enum_get(op->ptr, "action"); + switch (action) { + case SEL_TOGGLE: + deselect_action_keys(&ac, 1, SELECT_ADD); + break; + case SEL_SELECT: + deselect_action_keys(&ac, 0, SELECT_ADD); + break; + case SEL_DESELECT: + deselect_action_keys(&ac, 0, SELECT_SUBTRACT); + break; + case SEL_INVERT: + deselect_action_keys(&ac, 0, SELECT_INVERT); + break; + default: + BLI_assert(0); + break; + } + + /* set notifier that keyframe selection have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; } void ACTION_OT_select_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select All"; - ot->idname = "ACTION_OT_select_all"; - ot->description = "Toggle selection of all keyframes"; + /* identifiers */ + ot->name = "Select All"; + ot->idname = "ACTION_OT_select_all"; + ot->description = "Toggle selection of all keyframes"; - /* api callbacks */ - ot->exec = actkeys_deselectall_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->exec = actkeys_deselectall_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - WM_operator_properties_select_all(ot); + /* properties */ + WM_operator_properties_select_all(ot); } /* ******************** Box Select Operator **************************** */ @@ -213,190 +212,183 @@ void ACTION_OT_select_all(wmOperatorType *ot) /* defines for box_select mode */ enum { - ACTKEYS_BORDERSEL_ALLKEYS = 0, - ACTKEYS_BORDERSEL_FRAMERANGE, - ACTKEYS_BORDERSEL_CHANNELS, + ACTKEYS_BORDERSEL_ALLKEYS = 0, + ACTKEYS_BORDERSEL_FRAMERANGE, + ACTKEYS_BORDERSEL_CHANNELS, } /*eActKeys_BoxSelect_Mode*/; - static void box_select_action(bAnimContext *ac, const rcti rect, short mode, short selectmode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - KeyframeEditData ked; - KeyframeEditFunc ok_cb, select_cb; - View2D *v2d = &ac->ar->v2d; - rctf rectf; - float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac)); - - /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ - UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin + 2, &rectf.xmin, &rectf.ymin); - UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax - 2, &rectf.xmax, &rectf.ymax); - - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* get beztriple editing/validation funcs */ - select_cb = ANIM_editkeyframes_select(selectmode); - - if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) - ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); - else - ok_cb = NULL; - - /* init editing data */ - memset(&ked, 0, sizeof(KeyframeEditData)); - - /* loop over data, doing box select */ - for (ale = anim_data.first; ale; ale = ale->next) { - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - - /* get new vertical minimum extent of channel */ - ymin = ymax - ACHANNEL_STEP(ac); - - /* set horizontal range (if applicable) */ - if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) { - /* if channel is mapped in NLA, apply correction */ - if (adt) { - ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); - ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP); - ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP); - } - else { - ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */ - ked.f1 = rectf.xmin; - ked.f2 = rectf.xmax; - } - } - - /* perform vertical suitability check (if applicable) */ - if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || - !((ymax < rectf.ymin) || (ymin > rectf.ymax))) - { - /* loop over data selecting */ - switch (ale->type) { + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditData ked; + KeyframeEditFunc ok_cb, select_cb; + View2D *v2d = &ac->ar->v2d; + rctf rectf; + float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac)); + + /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ + UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin + 2, &rectf.xmin, &rectf.ymin); + UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax - 2, &rectf.xmax, &rectf.ymax); + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* get beztriple editing/validation funcs */ + select_cb = ANIM_editkeyframes_select(selectmode); + + if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) + ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); + else + ok_cb = NULL; + + /* init editing data */ + memset(&ked, 0, sizeof(KeyframeEditData)); + + /* loop over data, doing box select */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + /* get new vertical minimum extent of channel */ + ymin = ymax - ACHANNEL_STEP(ac); + + /* set horizontal range (if applicable) */ + if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) { + /* if channel is mapped in NLA, apply correction */ + if (adt) { + ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); + ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP); + ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP); + } + else { + ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */ + ked.f1 = rectf.xmin; + ked.f2 = rectf.xmax; + } + } + + /* perform vertical suitability check (if applicable) */ + if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || !((ymax < rectf.ymin) || (ymin > rectf.ymax))) { + /* loop over data selecting */ + switch (ale->type) { #if 0 /* XXX: Keyframes are not currently shown here */ - case ANIMTYPE_GPDATABLOCK: - { - bGPdata *gpd = ale->data; - bGPDlayer *gpl; - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - ED_gplayer_frames_select_box(gpl, rectf.xmin, rectf.xmax, selectmode); - } - ale->update |= ANIM_UPDATE_DEPS; - break; - } + case ANIMTYPE_GPDATABLOCK: + { + bGPdata *gpd = ale->data; + bGPDlayer *gpl; + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + ED_gplayer_frames_select_box(gpl, rectf.xmin, rectf.xmax, selectmode); + } + ale->update |= ANIM_UPDATE_DEPS; + break; + } #endif - case ANIMTYPE_GPLAYER: - { - ED_gplayer_frames_select_box(ale->data, rectf.xmin, rectf.xmax, selectmode); - ale->update |= ANIM_UPDATE_DEPS; - break; - } - case ANIMTYPE_MASKDATABLOCK: - { - Mask *mask = ale->data; - MaskLayer *masklay; - for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { - ED_masklayer_frames_select_box(masklay, rectf.xmin, rectf.xmax, selectmode); - } - break; - } - case ANIMTYPE_MASKLAYER: - { - ED_masklayer_frames_select_box(ale->data, rectf.xmin, rectf.xmax, selectmode); - break; - } - default: - { - ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL); - break; - } - } - } - - /* set minimum extent to be the maximum of the next channel */ - ymax = ymin; - } - - /* cleanup */ - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + case ANIMTYPE_GPLAYER: { + ED_gplayer_frames_select_box(ale->data, rectf.xmin, rectf.xmax, selectmode); + ale->update |= ANIM_UPDATE_DEPS; + break; + } + case ANIMTYPE_MASKDATABLOCK: { + Mask *mask = ale->data; + MaskLayer *masklay; + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + ED_masklayer_frames_select_box(masklay, rectf.xmin, rectf.xmax, selectmode); + } + break; + } + case ANIMTYPE_MASKLAYER: { + ED_masklayer_frames_select_box(ale->data, rectf.xmin, rectf.xmax, selectmode); + break; + } + default: { + ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL); + break; + } + } + } + + /* set minimum extent to be the maximum of the next channel */ + ymax = ymin; + } + + /* cleanup */ + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_box_select_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - rcti rect; - short mode = 0; - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) { - return OPERATOR_CANCELLED; - } - - const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - const int selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT; - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - deselect_action_keys(&ac, 1, SELECT_SUBTRACT); - } - - /* get settings from operator */ - WM_operator_properties_border_to_rcti(op, &rect); - - /* selection 'mode' depends on whether box_select region only matters on one axis */ - if (RNA_boolean_get(op->ptr, "axis_range")) { - /* mode depends on which axis of the range is larger to determine which axis to use - * - checking this in region-space is fine, as it's fundamentally still going to be a different rect size - * - the frame-range select option is favored over the channel one (x over y), as frame-range one is often - * used for tweaking timing when "blocking", while channels is not that useful... - */ - if (BLI_rcti_size_x(&rect) >= BLI_rcti_size_y(&rect)) - mode = ACTKEYS_BORDERSEL_FRAMERANGE; - else - mode = ACTKEYS_BORDERSEL_CHANNELS; - } - else - mode = ACTKEYS_BORDERSEL_ALLKEYS; - - /* apply box_select action */ - box_select_action(&ac, rect, mode, selectmode); - - /* set notifier that keyframe selection have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - - return OPERATOR_FINISHED; + bAnimContext ac; + rcti rect; + short mode = 0; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) { + return OPERATOR_CANCELLED; + } + + const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + const int selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT; + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + deselect_action_keys(&ac, 1, SELECT_SUBTRACT); + } + + /* get settings from operator */ + WM_operator_properties_border_to_rcti(op, &rect); + + /* selection 'mode' depends on whether box_select region only matters on one axis */ + if (RNA_boolean_get(op->ptr, "axis_range")) { + /* mode depends on which axis of the range is larger to determine which axis to use + * - checking this in region-space is fine, as it's fundamentally still going to be a different rect size + * - the frame-range select option is favored over the channel one (x over y), as frame-range one is often + * used for tweaking timing when "blocking", while channels is not that useful... + */ + if (BLI_rcti_size_x(&rect) >= BLI_rcti_size_y(&rect)) + mode = ACTKEYS_BORDERSEL_FRAMERANGE; + else + mode = ACTKEYS_BORDERSEL_CHANNELS; + } + else + mode = ACTKEYS_BORDERSEL_ALLKEYS; + + /* apply box_select action */ + box_select_action(&ac, rect, mode, selectmode); + + /* set notifier that keyframe selection have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; } void ACTION_OT_select_box(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Box Select"; - ot->idname = "ACTION_OT_select_box"; - ot->description = "Select all keyframes within the specified region"; + /* identifiers */ + ot->name = "Box Select"; + ot->idname = "ACTION_OT_select_box"; + ot->description = "Select all keyframes within the specified region"; - /* api callbacks */ - ot->invoke = WM_gesture_box_invoke; - ot->exec = actkeys_box_select_exec; - ot->modal = WM_gesture_box_modal; - ot->cancel = WM_gesture_box_cancel; + /* api callbacks */ + ot->invoke = WM_gesture_box_invoke; + ot->exec = actkeys_box_select_exec; + ot->modal = WM_gesture_box_modal; + ot->cancel = WM_gesture_box_cancel; - ot->poll = ED_operator_action_active; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* rna */ - ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", ""); + /* rna */ + ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", ""); - /* properties */ - WM_operator_properties_gesture_box(ot); - WM_operator_properties_select_operation_simple(ot); + /* properties */ + WM_operator_properties_gesture_box(ot); + WM_operator_properties_select_operation_simple(ot); } /* ******************** Region Select Operators ***************************** */ @@ -405,256 +397,252 @@ void ACTION_OT_select_box(wmOperatorType *ot) * original Graph Editor implementation of these to do it this way. */ -static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data) +static void region_select_action_keys( + bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - KeyframeEditData ked; - KeyframeEditFunc ok_cb, select_cb; - View2D *v2d = &ac->ar->v2d; - rctf rectf, scaled_rectf; - float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac)); - - /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ - UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf); - - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* get beztriple editing/validation funcs */ - select_cb = ANIM_editkeyframes_select(selectmode); - ok_cb = ANIM_editkeyframes_ok(mode); - - /* init editing data */ - memset(&ked, 0, sizeof(KeyframeEditData)); - if (mode == BEZT_OK_CHANNEL_LASSO) { - KeyframeEdit_LassoData *data_lasso = data; - data_lasso->rectf_scaled = &scaled_rectf; - ked.data = data_lasso; - } - else if (mode == BEZT_OK_CHANNEL_CIRCLE) { - KeyframeEdit_CircleData *data_circle = data; - data_circle->rectf_scaled = &scaled_rectf; - ked.data = data; - } - else { - ked.data = &scaled_rectf; - } - - /* loop over data, doing region select */ - for (ale = anim_data.first; ale; ale = ale->next) { - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - - /* get new vertical minimum extent of channel */ - ymin = ymax - ACHANNEL_STEP(ac); - - /* compute midpoint of channel (used for testing if the key is in the region or not) */ - ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF(ac); - - /* if channel is mapped in NLA, apply correction - * - Apply to the bounds being checked, not all the keyframe points, - * to avoid having scaling everything - * - Save result to the scaled_rect, which is all that these operators - * will read from - */ - if (adt) { - ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); - ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP); - ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP); - } - else { - ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */ - ked.f1 = rectf.xmin; - ked.f2 = rectf.xmax; - } - - /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks - * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these - * with the properly remapped ked.f1/f2 values, when needed - */ - scaled_rectf.xmin = ked.f1; - scaled_rectf.xmax = ked.f2; - scaled_rectf.ymin = ymin; - scaled_rectf.ymax = ymax; - - /* perform vertical suitability check (if applicable) */ - if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || - !((ymax < rectf.ymin) || (ymin > rectf.ymax))) - { - /* loop over data selecting */ - switch (ale->type) { + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditData ked; + KeyframeEditFunc ok_cb, select_cb; + View2D *v2d = &ac->ar->v2d; + rctf rectf, scaled_rectf; + float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac)); + + /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ + UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf); + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* get beztriple editing/validation funcs */ + select_cb = ANIM_editkeyframes_select(selectmode); + ok_cb = ANIM_editkeyframes_ok(mode); + + /* init editing data */ + memset(&ked, 0, sizeof(KeyframeEditData)); + if (mode == BEZT_OK_CHANNEL_LASSO) { + KeyframeEdit_LassoData *data_lasso = data; + data_lasso->rectf_scaled = &scaled_rectf; + ked.data = data_lasso; + } + else if (mode == BEZT_OK_CHANNEL_CIRCLE) { + KeyframeEdit_CircleData *data_circle = data; + data_circle->rectf_scaled = &scaled_rectf; + ked.data = data; + } + else { + ked.data = &scaled_rectf; + } + + /* loop over data, doing region select */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + /* get new vertical minimum extent of channel */ + ymin = ymax - ACHANNEL_STEP(ac); + + /* compute midpoint of channel (used for testing if the key is in the region or not) */ + ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF(ac); + + /* if channel is mapped in NLA, apply correction + * - Apply to the bounds being checked, not all the keyframe points, + * to avoid having scaling everything + * - Save result to the scaled_rect, which is all that these operators + * will read from + */ + if (adt) { + ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); + ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP); + ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP); + } + else { + ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */ + ked.f1 = rectf.xmin; + ked.f2 = rectf.xmax; + } + + /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks + * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these + * with the properly remapped ked.f1/f2 values, when needed + */ + scaled_rectf.xmin = ked.f1; + scaled_rectf.xmax = ked.f2; + scaled_rectf.ymin = ymin; + scaled_rectf.ymax = ymax; + + /* perform vertical suitability check (if applicable) */ + if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || !((ymax < rectf.ymin) || (ymin > rectf.ymax))) { + /* loop over data selecting */ + switch (ale->type) { #if 0 /* XXX: Keyframes are not currently shown here */ - case ANIMTYPE_GPDATABLOCK: - { - bGPdata *gpd = ale->data; - bGPDlayer *gpl; - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); - } - break; - } + case ANIMTYPE_GPDATABLOCK: + { + bGPdata *gpd = ale->data; + bGPDlayer *gpl; + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); + } + break; + } #endif - case ANIMTYPE_GPLAYER: - { - ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); - ale->update |= ANIM_UPDATE_DEPS; - break; - } - case ANIMTYPE_MASKDATABLOCK: - { - Mask *mask = ale->data; - MaskLayer *masklay; - for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { - ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode); - } - break; - } - case ANIMTYPE_MASKLAYER: - { - ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode); - break; - } - default: - ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL); - break; - } - } - - /* set minimum extent to be the maximum of the next channel */ - ymax = ymin; - } - - /* cleanup */ - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + case ANIMTYPE_GPLAYER: { + ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); + ale->update |= ANIM_UPDATE_DEPS; + break; + } + case ANIMTYPE_MASKDATABLOCK: { + Mask *mask = ale->data; + MaskLayer *masklay; + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode); + } + break; + } + case ANIMTYPE_MASKLAYER: { + ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode); + break; + } + default: + ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL); + break; + } + } + + /* set minimum extent to be the maximum of the next channel */ + ymax = ymin; + } + + /* cleanup */ + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ----------------------------------- */ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op) { - bAnimContext ac; + bAnimContext ac; - KeyframeEdit_LassoData data_lasso; - rcti rect; - rctf rect_fl; + KeyframeEdit_LassoData data_lasso; + rcti rect; + rctf rect_fl; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - data_lasso.rectf_view = &rect_fl; - data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); - if (data_lasso.mcords == NULL) - return OPERATOR_CANCELLED; + data_lasso.rectf_view = &rect_fl; + data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); + if (data_lasso.mcords == NULL) + return OPERATOR_CANCELLED; - const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - const int selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT; - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - deselect_action_keys(&ac, 1, SELECT_SUBTRACT); - } + const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + const int selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT; + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + deselect_action_keys(&ac, 1, SELECT_SUBTRACT); + } - /* get settings from operator */ - BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); - BLI_rctf_rcti_copy(&rect_fl, &rect); + /* get settings from operator */ + BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); + BLI_rctf_rcti_copy(&rect_fl, &rect); - /* apply box_select action */ - region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso); + /* apply box_select action */ + region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso); - MEM_freeN((void *)data_lasso.mcords); + MEM_freeN((void *)data_lasso.mcords); - /* send notifier that keyframe selection has changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + /* send notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_select_lasso(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Lasso Select"; - ot->description = "Select keyframe points using lasso selection"; - ot->idname = "ACTION_OT_select_lasso"; - - /* api callbacks */ - ot->invoke = WM_gesture_lasso_invoke; - ot->modal = WM_gesture_lasso_modal; - ot->exec = actkeys_lassoselect_exec; - ot->poll = ED_operator_action_active; - ot->cancel = WM_gesture_lasso_cancel; - - /* flags */ - ot->flag = OPTYPE_UNDO; - - /* properties */ - WM_operator_properties_gesture_lasso(ot); - WM_operator_properties_select_operation_simple(ot); + /* identifiers */ + ot->name = "Lasso Select"; + ot->description = "Select keyframe points using lasso selection"; + ot->idname = "ACTION_OT_select_lasso"; + + /* api callbacks */ + ot->invoke = WM_gesture_lasso_invoke; + ot->modal = WM_gesture_lasso_modal; + ot->exec = actkeys_lassoselect_exec; + ot->poll = ED_operator_action_active; + ot->cancel = WM_gesture_lasso_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_gesture_lasso(ot); + WM_operator_properties_select_operation_simple(ot); } /* ------------------- */ static int action_circle_select_exec(bContext *C, wmOperator *op) { - bAnimContext ac; + bAnimContext ac; - KeyframeEdit_CircleData data = {0}; - rctf rect_fl; + KeyframeEdit_CircleData data = {0}; + rctf rect_fl; - float x = RNA_int_get(op->ptr, "x"); - float y = RNA_int_get(op->ptr, "y"); - float radius = RNA_int_get(op->ptr, "radius"); + float x = RNA_int_get(op->ptr, "x"); + float y = RNA_int_get(op->ptr, "y"); + float radius = RNA_int_get(op->ptr, "radius"); - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - const eSelectOp sel_op = ED_select_op_modal( - RNA_enum_get(op->ptr, "mode"), WM_gesture_is_modal_first(op->customdata)); - const short selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT; - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - deselect_action_keys(&ac, 0, SELECT_SUBTRACT); - } + const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"), + WM_gesture_is_modal_first(op->customdata)); + const short selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT; + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + deselect_action_keys(&ac, 0, SELECT_SUBTRACT); + } - data.mval[0] = x; - data.mval[1] = y; - data.radius_squared = radius * radius; - data.rectf_view = &rect_fl; + data.mval[0] = x; + data.mval[1] = y; + data.radius_squared = radius * radius; + data.rectf_view = &rect_fl; - rect_fl.xmin = x - radius; - rect_fl.xmax = x + radius; - rect_fl.ymin = y - radius; - rect_fl.ymax = y + radius; + rect_fl.xmin = x - radius; + rect_fl.xmax = x + radius; + rect_fl.ymin = y - radius; + rect_fl.ymax = y + radius; - /* apply region select action */ - region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data); + /* apply region select action */ + region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data); - /* send notifier that keyframe selection has changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + /* send notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_select_circle(wmOperatorType *ot) { - ot->name = "Circle Select"; - ot->description = "Select keyframe points using circle selection"; - ot->idname = "ACTION_OT_select_circle"; - - ot->invoke = WM_gesture_circle_invoke; - ot->modal = WM_gesture_circle_modal; - ot->exec = action_circle_select_exec; - ot->poll = ED_operator_action_active; - ot->cancel = WM_gesture_circle_cancel; - - /* flags */ - ot->flag = OPTYPE_UNDO; - - /* properties */ - WM_operator_properties_gesture_circle(ot); - WM_operator_properties_select_operation_simple(ot); + ot->name = "Circle Select"; + ot->description = "Select keyframe points using circle selection"; + ot->idname = "ACTION_OT_select_circle"; + + ot->invoke = WM_gesture_circle_invoke; + ot->modal = WM_gesture_circle_modal; + ot->exec = action_circle_select_exec; + ot->poll = ED_operator_action_active; + ot->cancel = WM_gesture_circle_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_gesture_circle(ot); + WM_operator_properties_select_operation_simple(ot); } /* ******************** Column Select Operator **************************** */ @@ -667,11 +655,15 @@ void ACTION_OT_select_circle(wmOperatorType *ot) /* defines for column-select mode */ static const EnumPropertyItem prop_column_select_types[] = { - {ACTKEYS_COLUMNSEL_KEYS, "KEYS", 0, "On Selected Keyframes", ""}, - {ACTKEYS_COLUMNSEL_CFRA, "CFRA", 0, "On Current Frame", ""}, - {ACTKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", 0, "On Selected Markers", ""}, - {ACTKEYS_COLUMNSEL_MARKERS_BETWEEN, "MARKERS_BETWEEN", 0, "Between Min/Max Selected Markers", ""}, - {0, NULL, 0, NULL, NULL}, + {ACTKEYS_COLUMNSEL_KEYS, "KEYS", 0, "On Selected Keyframes", ""}, + {ACTKEYS_COLUMNSEL_CFRA, "CFRA", 0, "On Current Frame", ""}, + {ACTKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", 0, "On Selected Markers", ""}, + {ACTKEYS_COLUMNSEL_MARKERS_BETWEEN, + "MARKERS_BETWEEN", + 0, + "Between Min/Max Selected Markers", + ""}, + {0, NULL, 0, NULL, NULL}, }; /* ------------------- */ @@ -681,248 +673,249 @@ static const EnumPropertyItem prop_column_select_types[] = { * should de-duplicate - campbell */ static void markers_selectkeys_between(bAnimContext *ac) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - KeyframeEditFunc ok_cb, select_cb; - KeyframeEditData ked = {{NULL}}; - float min, max; - - /* get extreme markers */ - ED_markers_get_minmax(ac->markers, 1, &min, &max); - min -= 0.5f; - max += 0.5f; - - /* get editing funcs + data */ - ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); - select_cb = ANIM_editkeyframes_select(SELECT_ADD); - - ked.f1 = min; - ked.f2 = max; - - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* select keys in-between */ - for (ale = anim_data.first; ale; ale = ale->next) { - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - - if (adt) { - ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); - ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); - } - else if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_frames_select_box(ale->data, min, max, SELECT_ADD); - ale->update |= ANIM_UPDATE_DEPS; - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - ED_masklayer_frames_select_box(ale->data, min, max, SELECT_ADD); - } - else { - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); - } - } - - /* Cleanup */ - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditFunc ok_cb, select_cb; + KeyframeEditData ked = {{NULL}}; + float min, max; + + /* get extreme markers */ + ED_markers_get_minmax(ac->markers, 1, &min, &max); + min -= 0.5f; + max += 0.5f; + + /* get editing funcs + data */ + ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); + select_cb = ANIM_editkeyframes_select(SELECT_ADD); + + ked.f1 = min; + ked.f2 = max; + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | + ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* select keys in-between */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + if (adt) { + ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); + ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); + } + else if (ale->type == ANIMTYPE_GPLAYER) { + ED_gplayer_frames_select_box(ale->data, min, max, SELECT_ADD); + ale->update |= ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + ED_masklayer_frames_select_box(ale->data, min, max, SELECT_ADD); + } + else { + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); + } + } + + /* Cleanup */ + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } - /* Selects all visible keyframes in the same frames as the specified elements */ static void columnselect_action_keys(bAnimContext *ac, short mode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - Scene *scene = ac->scene; - CfraElem *ce; - KeyframeEditFunc select_cb, ok_cb; - KeyframeEditData ked = {{NULL}}; - - /* build list of columns */ - switch (mode) { - case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */ - if (ac->datatype == ANIMCONT_GPENCIL) { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - for (ale = anim_data.first; ale; ale = ale->next) - ED_gplayer_make_cfra_list(ale->data, &ked.list, 1); - } - else { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - for (ale = anim_data.first; ale; ale = ale->next) - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL); - } - ANIM_animdata_freelist(&anim_data); - break; - - case ACTKEYS_COLUMNSEL_CFRA: /* current frame */ - /* make a single CfraElem for storing this */ - ce = MEM_callocN(sizeof(CfraElem), "cfraElem"); - BLI_addtail(&ked.list, ce); - - ce->cfra = (float)CFRA; - break; - - case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */ - ED_markers_make_cfra_list(ac->markers, &ked.list, SELECT); - break; - - default: /* invalid option */ - return; - } - - /* set up BezTriple edit callbacks */ - select_cb = ANIM_editkeyframes_select(SELECT_ADD); - ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAME); - - /* loop through all of the keys and select additional keyframes - * based on the keys found to be selected above - */ - if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE); - else - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - for (ale = anim_data.first; ale; ale = ale->next) { - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - - /* loop over cfraelems (stored in the KeyframeEditData->list) - * - we need to do this here, as we can apply fewer NLA-mapping conversions - */ - for (ce = ked.list.first; ce; ce = ce->next) { - /* set frame for validation callback to refer to */ - if (adt) - ked.f1 = BKE_nla_tweakedit_remap(adt, ce->cfra, NLATIME_CONVERT_UNMAP); - else - ked.f1 = ce->cfra; - - /* select elements with frame number matching cfraelem */ - if (ale->type == ANIMTYPE_GPLAYER) { - ED_gpencil_select_frame(ale->data, ce->cfra, SELECT_ADD); - ale->update |= ANIM_UPDATE_DEPS; - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - ED_mask_select_frame(ale->data, ce->cfra, SELECT_ADD); - } - else { - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); - } - } - } - - /* free elements */ - BLI_freelistN(&ked.list); - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + Scene *scene = ac->scene; + CfraElem *ce; + KeyframeEditFunc select_cb, ok_cb; + KeyframeEditData ked = {{NULL}}; + + /* build list of columns */ + switch (mode) { + case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */ + if (ac->datatype == ANIMCONT_GPENCIL) { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + for (ale = anim_data.first; ale; ale = ale->next) + ED_gplayer_make_cfra_list(ale->data, &ked.list, 1); + } + else { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + for (ale = anim_data.first; ale; ale = ale->next) + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL); + } + ANIM_animdata_freelist(&anim_data); + break; + + case ACTKEYS_COLUMNSEL_CFRA: /* current frame */ + /* make a single CfraElem for storing this */ + ce = MEM_callocN(sizeof(CfraElem), "cfraElem"); + BLI_addtail(&ked.list, ce); + + ce->cfra = (float)CFRA; + break; + + case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */ + ED_markers_make_cfra_list(ac->markers, &ked.list, SELECT); + break; + + default: /* invalid option */ + return; + } + + /* set up BezTriple edit callbacks */ + select_cb = ANIM_editkeyframes_select(SELECT_ADD); + ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAME); + + /* loop through all of the keys and select additional keyframes + * based on the keys found to be selected above + */ + if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE); + else + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + /* loop over cfraelems (stored in the KeyframeEditData->list) + * - we need to do this here, as we can apply fewer NLA-mapping conversions + */ + for (ce = ked.list.first; ce; ce = ce->next) { + /* set frame for validation callback to refer to */ + if (adt) + ked.f1 = BKE_nla_tweakedit_remap(adt, ce->cfra, NLATIME_CONVERT_UNMAP); + else + ked.f1 = ce->cfra; + + /* select elements with frame number matching cfraelem */ + if (ale->type == ANIMTYPE_GPLAYER) { + ED_gpencil_select_frame(ale->data, ce->cfra, SELECT_ADD); + ale->update |= ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + ED_mask_select_frame(ale->data, ce->cfra, SELECT_ADD); + } + else { + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); + } + } + } + + /* free elements */ + BLI_freelistN(&ked.list); + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int actkeys_columnselect_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - short mode; + bAnimContext ac; + short mode; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* action to take depends on the mode */ - mode = RNA_enum_get(op->ptr, "mode"); + /* action to take depends on the mode */ + mode = RNA_enum_get(op->ptr, "mode"); - if (mode == ACTKEYS_COLUMNSEL_MARKERS_BETWEEN) - markers_selectkeys_between(&ac); - else - columnselect_action_keys(&ac, mode); + if (mode == ACTKEYS_COLUMNSEL_MARKERS_BETWEEN) + markers_selectkeys_between(&ac); + else + columnselect_action_keys(&ac, mode); - /* set notifier that keyframe selection have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + /* set notifier that keyframe selection have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_select_column(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select All"; - ot->idname = "ACTION_OT_select_column"; - ot->description = "Select all keyframes on the specified frame(s)"; + /* identifiers */ + ot->name = "Select All"; + ot->idname = "ACTION_OT_select_column"; + ot->description = "Select all keyframes on the specified frame(s)"; - /* api callbacks */ - ot->exec = actkeys_columnselect_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->exec = actkeys_columnselect_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - ot->prop = RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", ""); + /* props */ + ot->prop = RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", ""); } /* ******************** Select Linked Operator *********************** */ static int actkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op)) { - bAnimContext ac; + bAnimContext ac; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; - KeyframeEditFunc ok_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED); - KeyframeEditFunc sel_cb = ANIM_editkeyframes_select(SELECT_ADD); + KeyframeEditFunc ok_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED); + KeyframeEditFunc sel_cb = ANIM_editkeyframes_select(SELECT_ADD); - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* loop through all of the keys and select additional keyframes based on these */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + /* loop through all of the keys and select additional keyframes based on these */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | + ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - for (ale = anim_data.first; ale; ale = ale->next) { - FCurve *fcu = (FCurve *)ale->key_data; + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->key_data; - /* check if anything selected? */ - if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ok_cb, NULL)) { - /* select every keyframe in this curve then */ - ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL); - } - } + /* check if anything selected? */ + if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ok_cb, NULL)) { + /* select every keyframe in this curve then */ + ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL); + } + } - /* Cleanup */ - ANIM_animdata_freelist(&anim_data); + /* Cleanup */ + ANIM_animdata_freelist(&anim_data); - /* set notifier that keyframe selection has changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + /* set notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_select_linked(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Linked"; - ot->idname = "ACTION_OT_select_linked"; - ot->description = "Select keyframes occurring in the same F-Curves as selected ones"; + /* identifiers */ + ot->name = "Select Linked"; + ot->idname = "ACTION_OT_select_linked"; + ot->description = "Select keyframes occurring in the same F-Curves as selected ones"; - /* api callbacks */ - ot->exec = actkeys_select_linked_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->exec = actkeys_select_linked_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************** Select More/Less Operators *********************** */ @@ -930,110 +923,110 @@ void ACTION_OT_select_linked(wmOperatorType *ot) /* Common code to perform selection */ static void select_moreless_action_keys(bAnimContext *ac, short mode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - KeyframeEditData ked = {{NULL}}; - KeyframeEditFunc build_cb; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + KeyframeEditData ked = {{NULL}}; + KeyframeEditFunc build_cb; - /* init selmap building data */ - build_cb = ANIM_editkeyframes_buildselmap(mode); + /* init selmap building data */ + build_cb = ANIM_editkeyframes_buildselmap(mode); - /* loop through all of the keys and select additional keyframes based on these */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + /* loop through all of the keys and select additional keyframes based on these */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | + ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - for (ale = anim_data.first; ale; ale = ale->next) { - FCurve *fcu = (FCurve *)ale->key_data; + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->key_data; - /* only continue if F-Curve has keyframes */ - if (fcu->bezt == NULL) - continue; + /* only continue if F-Curve has keyframes */ + if (fcu->bezt == NULL) + continue; - /* build up map of whether F-Curve's keyframes should be selected or not */ - ked.data = MEM_callocN(fcu->totvert, "selmap actEdit more"); - ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, build_cb, NULL); + /* build up map of whether F-Curve's keyframes should be selected or not */ + ked.data = MEM_callocN(fcu->totvert, "selmap actEdit more"); + ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, build_cb, NULL); - /* based on this map, adjust the selection status of the keyframes */ - ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, bezt_selmap_flush, NULL); + /* based on this map, adjust the selection status of the keyframes */ + ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, bezt_selmap_flush, NULL); - /* free the selmap used here */ - MEM_freeN(ked.data); - ked.data = NULL; - } + /* free the selmap used here */ + MEM_freeN(ked.data); + ked.data = NULL; + } - /* Cleanup */ - ANIM_animdata_freelist(&anim_data); + /* Cleanup */ + ANIM_animdata_freelist(&anim_data); } /* ----------------- */ static int actkeys_select_more_exec(bContext *C, wmOperator *UNUSED(op)) { - bAnimContext ac; + bAnimContext ac; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* perform select changes */ - select_moreless_action_keys(&ac, SELMAP_MORE); + /* perform select changes */ + select_moreless_action_keys(&ac, SELMAP_MORE); - /* set notifier that keyframe selection has changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + /* set notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_select_more(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select More"; - ot->idname = "ACTION_OT_select_more"; - ot->description = "Select keyframes beside already selected ones"; + /* identifiers */ + ot->name = "Select More"; + ot->idname = "ACTION_OT_select_more"; + ot->description = "Select keyframes beside already selected ones"; - /* api callbacks */ - ot->exec = actkeys_select_more_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->exec = actkeys_select_more_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ----------------- */ static int actkeys_select_less_exec(bContext *C, wmOperator *UNUSED(op)) { - bAnimContext ac; + bAnimContext ac; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* perform select changes */ - select_moreless_action_keys(&ac, SELMAP_LESS); + /* perform select changes */ + select_moreless_action_keys(&ac, SELMAP_LESS); - /* set notifier that keyframe selection has changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + /* set notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ACTION_OT_select_less(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Less"; - ot->idname = "ACTION_OT_select_less"; - ot->description = "Deselect keyframes on ends of selection islands"; + /* identifiers */ + ot->name = "Select Less"; + ot->idname = "ACTION_OT_select_less"; + ot->description = "Deselect keyframes on ends of selection islands"; - /* api callbacks */ - ot->exec = actkeys_select_less_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->exec = actkeys_select_less_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************** Select Left/Right Operator ************************* */ @@ -1041,186 +1034,187 @@ void ACTION_OT_select_less(wmOperatorType *ot) /* defines for left-right select tool */ static const EnumPropertyItem prop_actkeys_leftright_select_types[] = { - {ACTKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""}, - {ACTKEYS_LRSEL_LEFT, "LEFT", 0, "Before current frame", ""}, - {ACTKEYS_LRSEL_RIGHT, "RIGHT", 0, "After current frame", ""}, - {0, NULL, 0, NULL, NULL}, + {ACTKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""}, + {ACTKEYS_LRSEL_LEFT, "LEFT", 0, "Before current frame", ""}, + {ACTKEYS_LRSEL_RIGHT, "RIGHT", 0, "After current frame", ""}, + {0, NULL, 0, NULL, NULL}, }; /* --------------------------------- */ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short select_mode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - KeyframeEditFunc ok_cb, select_cb; - KeyframeEditData ked = {{NULL}}; - Scene *scene = ac->scene; - - /* if select mode is replace, deselect all keyframes (and channels) first */ - if (select_mode == SELECT_REPLACE) { - select_mode = SELECT_ADD; - - /* - deselect all other keyframes, so that just the newly selected remain - * - channels aren't deselected, since we don't re-select any as a consequence - */ - deselect_action_keys(ac, 0, SELECT_SUBTRACT); - } - - /* set callbacks and editing data */ - ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); - select_cb = ANIM_editkeyframes_select(select_mode); - - if (leftright == ACTKEYS_LRSEL_LEFT) { - ked.f1 = MINAFRAMEF; - ked.f2 = (float)(CFRA + 0.1f); - } - else { - ked.f1 = (float)(CFRA - 0.1f); - ked.f2 = MAXFRAMEF; - } - - /* filter data */ - if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS); - } - else { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); - } - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* select keys */ - for (ale = anim_data.first; ale; ale = ale->next) { - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - - if (adt) { - ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); - ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); - } - else if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode); - ale->update |= ANIM_UPDATE_DEPS; - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - ED_masklayer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode); - } - else { - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); - } - } - - /* Sync marker support */ - if (select_mode == SELECT_ADD) { - SpaceAction *saction = (SpaceAction *)ac->sl; - - if ((saction) && (saction->flag & SACTION_MARKERS_MOVE)) { - ListBase *markers = ED_animcontext_get_markers(ac); - TimeMarker *marker; - - for (marker = markers->first; marker; marker = marker->next) { - if (((leftright == ACTKEYS_LRSEL_LEFT) && (marker->frame < CFRA)) || - ((leftright == ACTKEYS_LRSEL_RIGHT) && (marker->frame >= CFRA))) - { - marker->flag |= SELECT; - } - else { - marker->flag &= ~SELECT; - } - } - } - } - - /* Cleanup */ - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditFunc ok_cb, select_cb; + KeyframeEditData ked = {{NULL}}; + Scene *scene = ac->scene; + + /* if select mode is replace, deselect all keyframes (and channels) first */ + if (select_mode == SELECT_REPLACE) { + select_mode = SELECT_ADD; + + /* - deselect all other keyframes, so that just the newly selected remain + * - channels aren't deselected, since we don't re-select any as a consequence + */ + deselect_action_keys(ac, 0, SELECT_SUBTRACT); + } + + /* set callbacks and editing data */ + ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); + select_cb = ANIM_editkeyframes_select(select_mode); + + if (leftright == ACTKEYS_LRSEL_LEFT) { + ked.f1 = MINAFRAMEF; + ked.f2 = (float)(CFRA + 0.1f); + } + else { + ked.f1 = (float)(CFRA - 0.1f); + ked.f2 = MAXFRAMEF; + } + + /* filter data */ + if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS); + } + else { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | + ANIMFILTER_NODUPLIS); + } + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* select keys */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + if (adt) { + ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); + ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); + } + else if (ale->type == ANIMTYPE_GPLAYER) { + ED_gplayer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode); + ale->update |= ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + ED_masklayer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode); + } + else { + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); + } + } + + /* Sync marker support */ + if (select_mode == SELECT_ADD) { + SpaceAction *saction = (SpaceAction *)ac->sl; + + if ((saction) && (saction->flag & SACTION_MARKERS_MOVE)) { + ListBase *markers = ED_animcontext_get_markers(ac); + TimeMarker *marker; + + for (marker = markers->first; marker; marker = marker->next) { + if (((leftright == ACTKEYS_LRSEL_LEFT) && (marker->frame < CFRA)) || + ((leftright == ACTKEYS_LRSEL_RIGHT) && (marker->frame >= CFRA))) { + marker->flag |= SELECT; + } + else { + marker->flag &= ~SELECT; + } + } + } + } + + /* Cleanup */ + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ----------------- */ static int actkeys_select_leftright_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - short leftright = RNA_enum_get(op->ptr, "mode"); - short selectmode; + bAnimContext ac; + short leftright = RNA_enum_get(op->ptr, "mode"); + short selectmode; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* select mode is either replace (deselect all, then add) or add/extend */ - if (RNA_boolean_get(op->ptr, "extend")) - selectmode = SELECT_INVERT; - else - selectmode = SELECT_REPLACE; + /* select mode is either replace (deselect all, then add) or add/extend */ + if (RNA_boolean_get(op->ptr, "extend")) + selectmode = SELECT_INVERT; + else + selectmode = SELECT_REPLACE; - /* if "test" mode is set, we don't have any info to set this with */ - if (leftright == ACTKEYS_LRSEL_TEST) - return OPERATOR_CANCELLED; + /* if "test" mode is set, we don't have any info to set this with */ + if (leftright == ACTKEYS_LRSEL_TEST) + return OPERATOR_CANCELLED; - /* do the selecting now */ - actkeys_select_leftright(&ac, leftright, selectmode); + /* do the selecting now */ + actkeys_select_leftright(&ac, leftright, selectmode); - /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); + /* set notifier that keyframe selection (and channels too) have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int actkeys_select_leftright_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - bAnimContext ac; - short leftright = RNA_enum_get(op->ptr, "mode"); - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* handle mode-based testing */ - if (leftright == ACTKEYS_LRSEL_TEST) { - Scene *scene = ac.scene; - ARegion *ar = ac.ar; - View2D *v2d = &ar->v2d; - float x; - - /* determine which side of the current frame mouse is on */ - x = UI_view2d_region_to_view_x(v2d, event->mval[0]); - if (x < CFRA) - RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_LEFT); - else - RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_RIGHT); - } - - /* perform selection */ - return actkeys_select_leftright_exec(C, op); + bAnimContext ac; + short leftright = RNA_enum_get(op->ptr, "mode"); + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* handle mode-based testing */ + if (leftright == ACTKEYS_LRSEL_TEST) { + Scene *scene = ac.scene; + ARegion *ar = ac.ar; + View2D *v2d = &ar->v2d; + float x; + + /* determine which side of the current frame mouse is on */ + x = UI_view2d_region_to_view_x(v2d, event->mval[0]); + if (x < CFRA) + RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_LEFT); + else + RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_RIGHT); + } + + /* perform selection */ + return actkeys_select_leftright_exec(C, op); } void ACTION_OT_select_leftright(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Select Left/Right"; - ot->idname = "ACTION_OT_select_leftright"; - ot->description = "Select keyframes to the left or the right of the current frame"; + /* identifiers */ + ot->name = "Select Left/Right"; + ot->idname = "ACTION_OT_select_leftright"; + ot->description = "Select keyframes to the left or the right of the current frame"; - /* api callbacks */ - ot->invoke = actkeys_select_leftright_invoke; - ot->exec = actkeys_select_leftright_exec; - ot->poll = ED_operator_action_active; + /* api callbacks */ + ot->invoke = actkeys_select_leftright_invoke; + ot->exec = actkeys_select_leftright_exec; + ot->poll = ED_operator_action_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "mode", prop_actkeys_leftright_select_types, ACTKEYS_LRSEL_TEST, "Mode", ""); - RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); + /* properties */ + ot->prop = RNA_def_enum( + ot->srna, "mode", prop_actkeys_leftright_select_types, ACTKEYS_LRSEL_TEST, "Mode", ""); + RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* ******************** Mouse-Click Select Operator *********************** */ @@ -1237,52 +1231,55 @@ void ACTION_OT_select_leftright(wmOperatorType *ot) /* ------------------- */ /* option 1) select keyframe directly under mouse */ -static void actkeys_mselect_single(bAnimContext *ac, bAnimListElem *ale, short select_mode, float selx) +static void actkeys_mselect_single(bAnimContext *ac, + bAnimListElem *ale, + short select_mode, + float selx) { - KeyframeEditData ked = {{NULL}}; - KeyframeEditFunc select_cb, ok_cb; - - /* get functions for selecting keyframes */ - select_cb = ANIM_editkeyframes_select(select_mode); - ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAME); - ked.f1 = selx; - ked.iterflags |= KED_F1_NLA_UNMAP; - - /* select the nominated keyframe on the given frame */ - if (ale->type == ANIMTYPE_GPLAYER) { - ED_gpencil_select_frame(ale->data, selx, select_mode); - ale->update |= ANIM_UPDATE_DEPS; - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - ED_mask_select_frame(ale->data, selx, select_mode); - } - else { - if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK) && - (ale->type == ANIMTYPE_SUMMARY) && (ale->datatype == ALE_ALL)) - { - ListBase anim_data = {NULL, NULL}; - int filter; - - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - for (ale = anim_data.first; ale; ale = ale->next) { - if (ale->type == ANIMTYPE_GPLAYER) { - ED_gpencil_select_frame(ale->data, selx, select_mode); - ale->update |= ANIM_UPDATE_DEPS; - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - ED_mask_select_frame(ale->data, selx, select_mode); - } - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); - } - else { - ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL); - } - } + KeyframeEditData ked = {{NULL}}; + KeyframeEditFunc select_cb, ok_cb; + + /* get functions for selecting keyframes */ + select_cb = ANIM_editkeyframes_select(select_mode); + ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAME); + ked.f1 = selx; + ked.iterflags |= KED_F1_NLA_UNMAP; + + /* select the nominated keyframe on the given frame */ + if (ale->type == ANIMTYPE_GPLAYER) { + ED_gpencil_select_frame(ale->data, selx, select_mode); + ale->update |= ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + ED_mask_select_frame(ale->data, selx, select_mode); + } + else { + if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK) && (ale->type == ANIMTYPE_SUMMARY) && + (ale->datatype == ALE_ALL)) { + ListBase anim_data = {NULL, NULL}; + int filter; + + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | + ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + for (ale = anim_data.first; ale; ale = ale->next) { + if (ale->type == ANIMTYPE_GPLAYER) { + ED_gpencil_select_frame(ale->data, selx, select_mode); + ale->update |= ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + ED_mask_select_frame(ale->data, selx, select_mode); + } + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); + } + else { + ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL); + } + } } /* Option 2) Selects all the keyframes on either side of the current frame @@ -1292,390 +1289,402 @@ static void actkeys_mselect_single(bAnimContext *ac, bAnimListElem *ale, short s /* Option 3) Selects all visible keyframes in the same frame as the mouse click */ static void actkeys_mselect_column(bAnimContext *ac, short select_mode, float selx) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - KeyframeEditFunc select_cb, ok_cb; - KeyframeEditData ked = {{NULL}}; - - /* set up BezTriple edit callbacks */ - select_cb = ANIM_editkeyframes_select(select_mode); - ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAME); - - /* loop through all of the keys and select additional keyframes - * based on the keys found to be selected above - */ - if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | ANIMFILTER_NODUPLIS); - } - else { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS); - } - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - for (ale = anim_data.first; ale; ale = ale->next) { - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - - /* set frame for validation callback to refer to */ - if (adt) - ked.f1 = BKE_nla_tweakedit_remap(adt, selx, NLATIME_CONVERT_UNMAP); - else - ked.f1 = selx; - - /* select elements with frame number matching cfra */ - if (ale->type == ANIMTYPE_GPLAYER) { - ED_gpencil_select_frame(ale->key_data, selx, select_mode); - ale->update |= ANIM_UPDATE_DEPS; - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - ED_mask_select_frame(ale->key_data, selx, select_mode); - } - else { - ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); - } - } - - /* free elements */ - BLI_freelistN(&ked.list); - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditFunc select_cb, ok_cb; + KeyframeEditData ked = {{NULL}}; + + /* set up BezTriple edit callbacks */ + select_cb = ANIM_editkeyframes_select(select_mode); + ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAME); + + /* loop through all of the keys and select additional keyframes + * based on the keys found to be selected above + */ + if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | + ANIMFILTER_NODUPLIS); + } + else { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS); + } + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + /* set frame for validation callback to refer to */ + if (adt) + ked.f1 = BKE_nla_tweakedit_remap(adt, selx, NLATIME_CONVERT_UNMAP); + else + ked.f1 = selx; + + /* select elements with frame number matching cfra */ + if (ale->type == ANIMTYPE_GPLAYER) { + ED_gpencil_select_frame(ale->key_data, selx, select_mode); + ale->update |= ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + ED_mask_select_frame(ale->key_data, selx, select_mode); + } + else { + ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); + } + } + + /* free elements */ + BLI_freelistN(&ked.list); + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* option 4) select all keyframes in same channel */ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, short select_mode) { - KeyframeEditFunc select_cb; - - /* get functions for selecting keyframes */ - select_cb = ANIM_editkeyframes_select(select_mode); - - /* select all keyframes in this channel */ - if (ale->type == ANIMTYPE_GPLAYER) { - ED_gpencil_select_frames(ale->data, select_mode); - ale->update = ANIM_UPDATE_DEPS; - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - ED_mask_select_frames(ale->data, select_mode); - } - else { - if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK) && - (ale->type == ANIMTYPE_SUMMARY) && (ale->datatype == ALE_ALL)) - { - ListBase anim_data = {NULL, NULL}; - int filter; - - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - for (ale = anim_data.first; ale; ale = ale->next) { - if (ale->type == ANIMTYPE_GPLAYER) { - ED_gpencil_select_frames(ale->data, select_mode); - ale->update |= ANIM_UPDATE_DEPS; - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - ED_mask_select_frames(ale->data, select_mode); - } - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); - } - else { - ANIM_animchannel_keyframes_loop(NULL, ac->ads, ale, NULL, select_cb, NULL); - } - } + KeyframeEditFunc select_cb; + + /* get functions for selecting keyframes */ + select_cb = ANIM_editkeyframes_select(select_mode); + + /* select all keyframes in this channel */ + if (ale->type == ANIMTYPE_GPLAYER) { + ED_gpencil_select_frames(ale->data, select_mode); + ale->update = ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + ED_mask_select_frames(ale->data, select_mode); + } + else { + if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK) && (ale->type == ANIMTYPE_SUMMARY) && + (ale->datatype == ALE_ALL)) { + ListBase anim_data = {NULL, NULL}; + int filter; + + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | + ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + for (ale = anim_data.first; ale; ale = ale->next) { + if (ale->type == ANIMTYPE_GPLAYER) { + ED_gpencil_select_frames(ale->data, select_mode); + ale->update |= ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + ED_mask_select_frames(ale->data, select_mode); + } + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); + } + else { + ANIM_animchannel_keyframes_loop(NULL, ac->ads, ale, NULL, select_cb, NULL); + } + } } /* ------------------- */ -static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_mode, bool column, bool same_channel) +static void mouse_action_keys( + bAnimContext *ac, const int mval[2], short select_mode, bool column, bool same_channel) { - ListBase anim_data = {NULL, NULL}; - DLRBT_Tree anim_keys; - bAnimListElem *ale; - int filter; - - View2D *v2d = &ac->ar->v2d; - bDopeSheet *ads = NULL; - int channel_index; - bool found = false; - float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */ - float selx = 0.0f; /* frame of keyframe under mouse */ - float key_hsize; - float x, y; - rctf rectf; - - /* get dopesheet info */ - if (ELEM(ac->datatype, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) - ads = ac->data; - - /* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */ - UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); - UI_view2d_listview_view_to_cell(v2d, 0, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index); - - /* x-range to check is +/- 7px for standard keyframe under standard dpi/y-scale (in screen/region-space), - * on either side of mouse click (size of keyframe icon) - */ - - /* standard channel height (to allow for some slop) */ - key_hsize = ACHANNEL_HEIGHT(ac) * 0.8f; - /* half-size (for either side), but rounded up to nearest int (for easier targeting) */ - key_hsize = roundf(key_hsize / 2.0f); - - UI_view2d_region_to_view(v2d, mval[0] - (int)key_hsize, mval[1], &rectf.xmin, &rectf.ymin); - UI_view2d_region_to_view(v2d, mval[0] + (int)key_hsize, mval[1], &rectf.xmax, &rectf.ymax); - - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* try to get channel */ - ale = BLI_findlink(&anim_data, channel_index); - if (ale == NULL) { - /* channel not found */ - printf("Error: animation channel (index = %d) not found in mouse_action_keys()\n", channel_index); - ANIM_animdata_freelist(&anim_data); - return; - } - else { - /* found match - must return here... */ - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - ActKeyColumn *ak, *akn = NULL; - - /* make list of keyframes */ - BLI_dlrbTree_init(&anim_keys); - - if (ale->key_data) { - switch (ale->datatype) { - case ALE_SCE: - { - Scene *scene = (Scene *)ale->key_data; - scene_to_keylist(ads, scene, &anim_keys, 0); - break; - } - case ALE_OB: - { - Object *ob = (Object *)ale->key_data; - ob_to_keylist(ads, ob, &anim_keys, 0); - break; - } - case ALE_ACT: - { - bAction *act = (bAction *)ale->key_data; - action_to_keylist(adt, act, &anim_keys, 0); - break; - } - case ALE_FCURVE: - { - FCurve *fcu = (FCurve *)ale->key_data; - fcurve_to_keylist(adt, fcu, &anim_keys, 0); - break; - } - } - } - else if (ale->type == ANIMTYPE_SUMMARY) { - /* dopesheet summary covers everything */ - summary_to_keylist(ac, &anim_keys, 0); - } - else if (ale->type == ANIMTYPE_GROUP) { - // TODO: why don't we just give groups key_data too? - bActionGroup *agrp = (bActionGroup *)ale->data; - agroup_to_keylist(adt, agrp, &anim_keys, 0); - } - else if (ale->type == ANIMTYPE_GPLAYER) { - // TODO: why don't we just give gplayers key_data too? - bGPDlayer *gpl = (bGPDlayer *)ale->data; - gpl_to_keylist(ads, gpl, &anim_keys); - } - else if (ale->type == ANIMTYPE_MASKLAYER) { - // TODO: why don't we just give masklayers key_data too? - MaskLayer *masklay = (MaskLayer *)ale->data; - mask_to_keylist(ads, masklay, &anim_keys); - } - - /* start from keyframe at root of BST, - * traversing until we find one within the range that was clicked on */ - for (ak = anim_keys.root; ak; ak = akn) { - if (IN_RANGE(ak->cfra, rectf.xmin, rectf.xmax)) { - /* set the frame to use, and apply inverse-correction for NLA-mapping - * so that the frame will get selected by the selection functions without - * requiring to map each frame once again... - */ - selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP); - frame = ak->cfra; - found = true; - break; - } - else if (ak->cfra < rectf.xmin) - akn = ak->right; - else - akn = ak->left; - } - - /* remove active channel from list of channels for separate treatment (since it's needed later on) */ - BLI_remlink(&anim_data, ale); - ale->next = ale->prev = NULL; - - /* cleanup temporary lists */ - BLI_dlrbTree_free(&anim_keys); - - /* free list of channels, since it's not used anymore */ - ANIM_animdata_freelist(&anim_data); - } - - /* for replacing selection, firstly need to clear existing selection */ - if (select_mode == SELECT_REPLACE) { - /* reset selection mode for next steps */ - select_mode = SELECT_ADD; - - /* deselect all keyframes */ - deselect_action_keys(ac, 0, SELECT_SUBTRACT); - - /* highlight channel clicked on */ - if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) { - /* deselect all other channels first */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); - - /* Highlight Action-Group or F-Curve? */ - if (ale && ale->data) { - if (ale->type == ANIMTYPE_GROUP) { - bActionGroup *agrp = ale->data; - - agrp->flag |= AGRP_SELECTED; - ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); - } - else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { - FCurve *fcu = ale->data; - - fcu->flag |= FCURVE_SELECTED; - ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type); - } - } - } - else if (ac->datatype == ANIMCONT_GPENCIL) { - /* deselect all other channels first */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); - - /* Highlight GPencil Layer */ - if ((ale && ale->data) && (ale->type == ANIMTYPE_GPLAYER)) { - bGPDlayer *gpl = ale->data; - - gpl->flag |= GP_LAYER_SELECT; - //gpencil_layer_setactive(gpd, gpl); - } - } - else if (ac->datatype == ANIMCONT_MASK) { - /* deselect all other channels first */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); - - /* Highlight GPencil Layer */ - if ((ale && ale->data) && (ale->type == ANIMTYPE_MASKLAYER)) { - MaskLayer *masklay = ale->data; - - masklay->flag |= MASK_LAYERFLAG_SELECT; - //gpencil_layer_setactive(gpd, gpl); - } - } - } - - /* only select keyframes if we clicked on a valid channel and hit something */ - if (ale) { - if (found) { - /* apply selection to keyframes */ - if (column) { - /* select all keyframes in the same frame as the one we hit on the active channel - * [T41077]: "frame" not "selx" here (i.e. no NLA corrections yet) as the code here - * does that itself again as it needs to work on multiple datablocks - */ - actkeys_mselect_column(ac, select_mode, frame); - } - else if (same_channel) { - /* select all keyframes in the active channel */ - actkeys_mselect_channel_only(ac, ale, select_mode); - } - else { - /* select the nominated keyframe on the given frame */ - actkeys_mselect_single(ac, ale, select_mode, selx); - } - } - - /* flush tagged updates - * NOTE: We temporarily add this channel back to the list so that this can happen - */ - anim_data.first = anim_data.last = ale; - ANIM_animdata_update(ac, &anim_data); - - /* free this channel */ - MEM_freeN(ale); - } + ListBase anim_data = {NULL, NULL}; + DLRBT_Tree anim_keys; + bAnimListElem *ale; + int filter; + + View2D *v2d = &ac->ar->v2d; + bDopeSheet *ads = NULL; + int channel_index; + bool found = false; + float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */ + float selx = 0.0f; /* frame of keyframe under mouse */ + float key_hsize; + float x, y; + rctf rectf; + + /* get dopesheet info */ + if (ELEM(ac->datatype, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) + ads = ac->data; + + /* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */ + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + UI_view2d_listview_view_to_cell( + v2d, 0, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index); + + /* x-range to check is +/- 7px for standard keyframe under standard dpi/y-scale (in screen/region-space), + * on either side of mouse click (size of keyframe icon) + */ + + /* standard channel height (to allow for some slop) */ + key_hsize = ACHANNEL_HEIGHT(ac) * 0.8f; + /* half-size (for either side), but rounded up to nearest int (for easier targeting) */ + key_hsize = roundf(key_hsize / 2.0f); + + UI_view2d_region_to_view(v2d, mval[0] - (int)key_hsize, mval[1], &rectf.xmin, &rectf.ymin); + UI_view2d_region_to_view(v2d, mval[0] + (int)key_hsize, mval[1], &rectf.xmax, &rectf.ymax); + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* try to get channel */ + ale = BLI_findlink(&anim_data, channel_index); + if (ale == NULL) { + /* channel not found */ + printf("Error: animation channel (index = %d) not found in mouse_action_keys()\n", + channel_index); + ANIM_animdata_freelist(&anim_data); + return; + } + else { + /* found match - must return here... */ + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + ActKeyColumn *ak, *akn = NULL; + + /* make list of keyframes */ + BLI_dlrbTree_init(&anim_keys); + + if (ale->key_data) { + switch (ale->datatype) { + case ALE_SCE: { + Scene *scene = (Scene *)ale->key_data; + scene_to_keylist(ads, scene, &anim_keys, 0); + break; + } + case ALE_OB: { + Object *ob = (Object *)ale->key_data; + ob_to_keylist(ads, ob, &anim_keys, 0); + break; + } + case ALE_ACT: { + bAction *act = (bAction *)ale->key_data; + action_to_keylist(adt, act, &anim_keys, 0); + break; + } + case ALE_FCURVE: { + FCurve *fcu = (FCurve *)ale->key_data; + fcurve_to_keylist(adt, fcu, &anim_keys, 0); + break; + } + } + } + else if (ale->type == ANIMTYPE_SUMMARY) { + /* dopesheet summary covers everything */ + summary_to_keylist(ac, &anim_keys, 0); + } + else if (ale->type == ANIMTYPE_GROUP) { + // TODO: why don't we just give groups key_data too? + bActionGroup *agrp = (bActionGroup *)ale->data; + agroup_to_keylist(adt, agrp, &anim_keys, 0); + } + else if (ale->type == ANIMTYPE_GPLAYER) { + // TODO: why don't we just give gplayers key_data too? + bGPDlayer *gpl = (bGPDlayer *)ale->data; + gpl_to_keylist(ads, gpl, &anim_keys); + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + // TODO: why don't we just give masklayers key_data too? + MaskLayer *masklay = (MaskLayer *)ale->data; + mask_to_keylist(ads, masklay, &anim_keys); + } + + /* start from keyframe at root of BST, + * traversing until we find one within the range that was clicked on */ + for (ak = anim_keys.root; ak; ak = akn) { + if (IN_RANGE(ak->cfra, rectf.xmin, rectf.xmax)) { + /* set the frame to use, and apply inverse-correction for NLA-mapping + * so that the frame will get selected by the selection functions without + * requiring to map each frame once again... + */ + selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP); + frame = ak->cfra; + found = true; + break; + } + else if (ak->cfra < rectf.xmin) + akn = ak->right; + else + akn = ak->left; + } + + /* remove active channel from list of channels for separate treatment (since it's needed later on) */ + BLI_remlink(&anim_data, ale); + ale->next = ale->prev = NULL; + + /* cleanup temporary lists */ + BLI_dlrbTree_free(&anim_keys); + + /* free list of channels, since it's not used anymore */ + ANIM_animdata_freelist(&anim_data); + } + + /* for replacing selection, firstly need to clear existing selection */ + if (select_mode == SELECT_REPLACE) { + /* reset selection mode for next steps */ + select_mode = SELECT_ADD; + + /* deselect all keyframes */ + deselect_action_keys(ac, 0, SELECT_SUBTRACT); + + /* highlight channel clicked on */ + if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) { + /* deselect all other channels first */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + + /* Highlight Action-Group or F-Curve? */ + if (ale && ale->data) { + if (ale->type == ANIMTYPE_GROUP) { + bActionGroup *agrp = ale->data; + + agrp->flag |= AGRP_SELECTED; + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); + } + else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { + FCurve *fcu = ale->data; + + fcu->flag |= FCURVE_SELECTED; + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type); + } + } + } + else if (ac->datatype == ANIMCONT_GPENCIL) { + /* deselect all other channels first */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + + /* Highlight GPencil Layer */ + if ((ale && ale->data) && (ale->type == ANIMTYPE_GPLAYER)) { + bGPDlayer *gpl = ale->data; + + gpl->flag |= GP_LAYER_SELECT; + //gpencil_layer_setactive(gpd, gpl); + } + } + else if (ac->datatype == ANIMCONT_MASK) { + /* deselect all other channels first */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + + /* Highlight GPencil Layer */ + if ((ale && ale->data) && (ale->type == ANIMTYPE_MASKLAYER)) { + MaskLayer *masklay = ale->data; + + masklay->flag |= MASK_LAYERFLAG_SELECT; + //gpencil_layer_setactive(gpd, gpl); + } + } + } + + /* only select keyframes if we clicked on a valid channel and hit something */ + if (ale) { + if (found) { + /* apply selection to keyframes */ + if (column) { + /* select all keyframes in the same frame as the one we hit on the active channel + * [T41077]: "frame" not "selx" here (i.e. no NLA corrections yet) as the code here + * does that itself again as it needs to work on multiple datablocks + */ + actkeys_mselect_column(ac, select_mode, frame); + } + else if (same_channel) { + /* select all keyframes in the active channel */ + actkeys_mselect_channel_only(ac, ale, select_mode); + } + else { + /* select the nominated keyframe on the given frame */ + actkeys_mselect_single(ac, ale, select_mode, selx); + } + } + + /* flush tagged updates + * NOTE: We temporarily add this channel back to the list so that this can happen + */ + anim_data.first = anim_data.last = ale; + ANIM_animdata_update(ac, &anim_data); + + /* free this channel */ + MEM_freeN(ale); + } } /* handle clicking */ static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - bAnimContext ac; - /* ARegion *ar; */ /* UNUSED */ - short selectmode; - bool column, channel; + bAnimContext ac; + /* ARegion *ar; */ /* UNUSED */ + short selectmode; + bool column, channel; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* get useful pointers from animation context data */ - /* ar = ac.ar; */ /* UNUSED */ + /* get useful pointers from animation context data */ + /* ar = ac.ar; */ /* UNUSED */ - /* select mode is either replace (deselect all, then add) or add/extend */ - if (RNA_boolean_get(op->ptr, "extend")) - selectmode = SELECT_INVERT; - else - selectmode = SELECT_REPLACE; + /* select mode is either replace (deselect all, then add) or add/extend */ + if (RNA_boolean_get(op->ptr, "extend")) + selectmode = SELECT_INVERT; + else + selectmode = SELECT_REPLACE; - /* column selection */ - column = RNA_boolean_get(op->ptr, "column"); - channel = RNA_boolean_get(op->ptr, "channel"); + /* column selection */ + column = RNA_boolean_get(op->ptr, "column"); + channel = RNA_boolean_get(op->ptr, "channel"); - /* select keyframe(s) based upon mouse position*/ - mouse_action_keys(&ac, event->mval, selectmode, column, channel); + /* select keyframe(s) based upon mouse position*/ + mouse_action_keys(&ac, event->mval, selectmode, column, channel); - /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); + /* set notifier that keyframe selection (and channels too) have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); - /* for tweak grab to work */ - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + /* for tweak grab to work */ + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; } void ACTION_OT_clickselect(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Select Keyframes"; - ot->idname = "ACTION_OT_clickselect"; - ot->description = "Select keyframes by clicking on them"; - - /* callbacks */ - ot->invoke = actkeys_clickselect_invoke; - ot->poll = ED_operator_action_active; - - /* flags */ - ot->flag = OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", - "Toggle keyframe selection instead of leaving newly selected keyframes only"); // SHIFTKEY - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - prop = RNA_def_boolean(ot->srna, "column", 0, "Column Select", - "Select all keyframes that occur on the same frame as the one under the mouse"); // ALTKEY - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - prop = RNA_def_boolean(ot->srna, "channel", 0, "Only Channel", - "Select all the keyframes in the channel under the mouse"); // CTRLKEY + ALTKEY - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Select Keyframes"; + ot->idname = "ACTION_OT_clickselect"; + ot->description = "Select keyframes by clicking on them"; + + /* callbacks */ + ot->invoke = actkeys_clickselect_invoke; + ot->poll = ED_operator_action_active; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_boolean( + ot->srna, + "extend", + 0, + "Extend Select", + "Toggle keyframe selection instead of leaving newly selected keyframes only"); // SHIFTKEY + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_boolean( + ot->srna, + "column", + 0, + "Column Select", + "Select all keyframes that occur on the same frame as the one under the mouse"); // ALTKEY + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_boolean( + ot->srna, + "channel", + 0, + "Only Channel", + "Select all the keyframes in the channel under the mouse"); // CTRLKEY + ALTKEY + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* ************************************************************************** */ diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index f2550550bc1..bfbca07d530 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -53,770 +53,784 @@ #include "ED_anim_api.h" #include "ED_markers.h" -#include "action_intern.h" /* own include */ +#include "action_intern.h" /* own include */ #include "GPU_framebuffer.h" /* ******************** manage regions ********************* */ ARegion *action_has_buttons_region(ScrArea *sa) { - ARegion *ar, *arnew; + ARegion *ar, *arnew; - ar = BKE_area_find_region_type(sa, RGN_TYPE_UI); - if (ar) return ar; + ar = BKE_area_find_region_type(sa, RGN_TYPE_UI); + if (ar) + return ar; - /* add subdiv level; after main */ - ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + /* add subdiv level; after main */ + ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); - /* is error! */ - if (ar == NULL) return NULL; + /* is error! */ + if (ar == NULL) + return NULL; - arnew = MEM_callocN(sizeof(ARegion), "buttons for action"); + arnew = MEM_callocN(sizeof(ARegion), "buttons for action"); - BLI_insertlinkafter(&sa->regionbase, ar, arnew); - arnew->regiontype = RGN_TYPE_UI; - arnew->alignment = RGN_ALIGN_RIGHT; + BLI_insertlinkafter(&sa->regionbase, ar, arnew); + arnew->regiontype = RGN_TYPE_UI; + arnew->alignment = RGN_ALIGN_RIGHT; - arnew->flag = RGN_FLAG_HIDDEN; + arnew->flag = RGN_FLAG_HIDDEN; - return arnew; + return arnew; } /* ******************** default callbacks for action space ***************** */ static SpaceLink *action_new(const ScrArea *sa, const Scene *scene) { - SpaceAction *saction; - ARegion *ar; + SpaceAction *saction; + ARegion *ar; - saction = MEM_callocN(sizeof(SpaceAction), "initaction"); - saction->spacetype = SPACE_ACTION; + saction = MEM_callocN(sizeof(SpaceAction), "initaction"); + saction->spacetype = SPACE_ACTION; - saction->autosnap = SACTSNAP_FRAME; - saction->mode = SACTCONT_DOPESHEET; - saction->mode_prev = SACTCONT_DOPESHEET; - saction->flag = SACTION_SHOW_INTERPOLATION; + saction->autosnap = SACTSNAP_FRAME; + saction->mode = SACTCONT_DOPESHEET; + saction->mode_prev = SACTCONT_DOPESHEET; + saction->flag = SACTION_SHOW_INTERPOLATION; - saction->ads.filterflag |= ADS_FILTER_SUMMARY; + saction->ads.filterflag |= ADS_FILTER_SUMMARY; - /* enable all cache display */ - saction->cache_display |= TIME_CACHE_DISPLAY; - saction->cache_display |= (TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES); - saction->cache_display |= (TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT); - saction->cache_display |= TIME_CACHE_RIGIDBODY; + /* enable all cache display */ + saction->cache_display |= TIME_CACHE_DISPLAY; + saction->cache_display |= (TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES); + saction->cache_display |= (TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT); + saction->cache_display |= TIME_CACHE_RIGIDBODY; - /* header */ - ar = MEM_callocN(sizeof(ARegion), "header for action"); + /* header */ + ar = MEM_callocN(sizeof(ARegion), "header for action"); - BLI_addtail(&saction->regionbase, ar); - ar->regiontype = RGN_TYPE_HEADER; - ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; + BLI_addtail(&saction->regionbase, ar); + ar->regiontype = RGN_TYPE_HEADER; + ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; - /* channel list region */ - ar = MEM_callocN(sizeof(ARegion), "channel region for action"); - BLI_addtail(&saction->regionbase, ar); - ar->regiontype = RGN_TYPE_CHANNELS; - ar->alignment = RGN_ALIGN_LEFT; + /* channel list region */ + ar = MEM_callocN(sizeof(ARegion), "channel region for action"); + BLI_addtail(&saction->regionbase, ar); + ar->regiontype = RGN_TYPE_CHANNELS; + ar->alignment = RGN_ALIGN_LEFT; - /* only need to set scroll settings, as this will use 'listview' v2d configuration */ - ar->v2d.scroll = V2D_SCROLL_BOTTOM; - ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; + /* only need to set scroll settings, as this will use 'listview' v2d configuration */ + ar->v2d.scroll = V2D_SCROLL_BOTTOM; + ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; - /* ui buttons */ - ar = MEM_callocN(sizeof(ARegion), "buttons region for action"); + /* ui buttons */ + ar = MEM_callocN(sizeof(ARegion), "buttons region for action"); - BLI_addtail(&saction->regionbase, ar); - ar->regiontype = RGN_TYPE_UI; - ar->alignment = RGN_ALIGN_RIGHT; - ar->flag = RGN_FLAG_HIDDEN; + BLI_addtail(&saction->regionbase, ar); + ar->regiontype = RGN_TYPE_UI; + ar->alignment = RGN_ALIGN_RIGHT; + ar->flag = RGN_FLAG_HIDDEN; - /* main region */ - ar = MEM_callocN(sizeof(ARegion), "main region for action"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for action"); - BLI_addtail(&saction->regionbase, ar); - ar->regiontype = RGN_TYPE_WINDOW; + BLI_addtail(&saction->regionbase, ar); + ar->regiontype = RGN_TYPE_WINDOW; - ar->v2d.tot.xmin = (float)(SFRA - 10); - ar->v2d.tot.ymin = (float)(-sa->winy) / 3.0f; - ar->v2d.tot.xmax = (float)(EFRA + 10); - ar->v2d.tot.ymax = 0.0f; + ar->v2d.tot.xmin = (float)(SFRA - 10); + ar->v2d.tot.ymin = (float)(-sa->winy) / 3.0f; + ar->v2d.tot.xmax = (float)(EFRA + 10); + ar->v2d.tot.ymax = 0.0f; - ar->v2d.cur = ar->v2d.tot; + ar->v2d.cur = ar->v2d.tot; - ar->v2d.min[0] = 0.0f; - ar->v2d.min[1] = 0.0f; + ar->v2d.min[0] = 0.0f; + ar->v2d.min[1] = 0.0f; - ar->v2d.max[0] = MAXFRAMEF; - ar->v2d.max[1] = FLT_MAX; + ar->v2d.max[0] = MAXFRAMEF; + ar->v2d.max[1] = FLT_MAX; - ar->v2d.minzoom = 0.01f; - ar->v2d.maxzoom = 50; - ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); - ar->v2d.scroll |= (V2D_SCROLL_RIGHT); - ar->v2d.keepzoom = V2D_LOCKZOOM_Y; - ar->v2d.keepofs = V2D_KEEPOFS_Y; - ar->v2d.align = V2D_ALIGN_NO_POS_Y; - ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; + ar->v2d.minzoom = 0.01f; + ar->v2d.maxzoom = 50; + ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); + ar->v2d.scroll |= (V2D_SCROLL_RIGHT); + ar->v2d.keepzoom = V2D_LOCKZOOM_Y; + ar->v2d.keepofs = V2D_KEEPOFS_Y; + ar->v2d.align = V2D_ALIGN_NO_POS_Y; + ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; - return (SpaceLink *)saction; + return (SpaceLink *)saction; } /* not spacelink itself */ static void action_free(SpaceLink *UNUSED(sl)) { -// SpaceAction *saction = (SpaceAction *) sl; + // SpaceAction *saction = (SpaceAction *) sl; } - /* spacetype; init callback */ static void action_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa) { - SpaceAction *saction = sa->spacedata.first; - saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; + SpaceAction *saction = sa->spacedata.first; + saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; } static SpaceLink *action_duplicate(SpaceLink *sl) { - SpaceAction *sactionn = MEM_dupallocN(sl); + SpaceAction *sactionn = MEM_dupallocN(sl); - /* clear or remove stuff from old */ + /* clear or remove stuff from old */ - return (SpaceLink *)sactionn; + return (SpaceLink *)sactionn; } - - /* add handlers, stuff you only do once or on area/region changes */ static void action_main_region_init(wmWindowManager *wm, ARegion *ar) { - wmKeyMap *keymap; + wmKeyMap *keymap; - UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); - /* own keymap */ - keymap = WM_keymap_ensure(wm->defaultconf, "Dopesheet", SPACE_ACTION, 0); - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap = WM_keymap_ensure(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0); - WM_event_add_keymap_handler(&ar->handlers, keymap); + /* own keymap */ + keymap = WM_keymap_ensure(wm->defaultconf, "Dopesheet", SPACE_ACTION, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + keymap = WM_keymap_ensure(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); } static void action_main_region_draw(const bContext *C, ARegion *ar) { - /* draw entirely, view changes should be handled here */ - SpaceAction *saction = CTX_wm_space_action(C); - Scene *scene = CTX_data_scene(C); - Object *obact = CTX_data_active_object(C); - bAnimContext ac; - View2D *v2d = &ar->v2d; - View2DGrid *grid; - View2DScrollers *scrollers; - short marker_flag = 0; - short cfra_flag = 0; - short unit = 0; - - /* clear and setup matrix */ - UI_ThemeClearColor(TH_BACK); - GPU_clear(GPU_COLOR_BIT); - - UI_view2d_view_ortho(v2d); - - /* time grid */ - unit = (saction->flag & SACTION_DRAWTIME) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMES; - grid = UI_view2d_grid_calc(CTX_data_scene(C), v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY, ar->winx, ar->winy); - UI_view2d_grid_draw(v2d, grid, V2D_GRIDLINES_ALL); - UI_view2d_grid_free(grid); - - ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); - - /* start and end frame */ - ANIM_draw_framerange(scene, v2d); - - /* data */ - if (ANIM_animdata_get_context(C, &ac)) { - draw_channel_strips(&ac, saction, ar); - } - - /* current frame */ - if (saction->flag & SACTION_DRAWTIME) cfra_flag |= DRAWCFRA_UNIT_SECONDS; - ANIM_draw_cfra(C, v2d, cfra_flag); - - /* markers */ - UI_view2d_view_orthoSpecial(ar, v2d, 1); - - marker_flag = ((ac.markers && (ac.markers != &ac.scene->markers)) ? DRAW_MARKERS_LOCAL : 0) | DRAW_MARKERS_MARGIN; - if (saction->flag & SACTION_SHOW_MARKER_LINES) marker_flag |= DRAW_MARKERS_LINES; - ED_markers_draw(C, marker_flag); - - /* caches */ - if (saction->mode == SACTCONT_TIMELINE) { - timeline_draw_cache(saction, obact, scene); - } - - /* preview range */ - UI_view2d_view_ortho(v2d); - ANIM_draw_previewrange(C, v2d, 0); - - /* callback */ - UI_view2d_view_ortho(v2d); - ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); - - /* reset view matrix */ - UI_view2d_view_restore(C); - - /* scrollers */ - scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY); - UI_view2d_scrollers_draw(C, v2d, scrollers); - UI_view2d_scrollers_free(scrollers); - - /* draw current frame number-indicator on top of scrollers */ - if ((saction->flag & SACTION_NODRAWCFRANUM) == 0) { - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); - } + /* draw entirely, view changes should be handled here */ + SpaceAction *saction = CTX_wm_space_action(C); + Scene *scene = CTX_data_scene(C); + Object *obact = CTX_data_active_object(C); + bAnimContext ac; + View2D *v2d = &ar->v2d; + View2DGrid *grid; + View2DScrollers *scrollers; + short marker_flag = 0; + short cfra_flag = 0; + short unit = 0; + + /* clear and setup matrix */ + UI_ThemeClearColor(TH_BACK); + GPU_clear(GPU_COLOR_BIT); + + UI_view2d_view_ortho(v2d); + + /* time grid */ + unit = (saction->flag & SACTION_DRAWTIME) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMES; + grid = UI_view2d_grid_calc(CTX_data_scene(C), + v2d, + unit, + V2D_GRID_CLAMP, + V2D_ARG_DUMMY, + V2D_ARG_DUMMY, + ar->winx, + ar->winy); + UI_view2d_grid_draw(v2d, grid, V2D_GRIDLINES_ALL); + UI_view2d_grid_free(grid); + + ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); + + /* start and end frame */ + ANIM_draw_framerange(scene, v2d); + + /* data */ + if (ANIM_animdata_get_context(C, &ac)) { + draw_channel_strips(&ac, saction, ar); + } + + /* current frame */ + if (saction->flag & SACTION_DRAWTIME) + cfra_flag |= DRAWCFRA_UNIT_SECONDS; + ANIM_draw_cfra(C, v2d, cfra_flag); + + /* markers */ + UI_view2d_view_orthoSpecial(ar, v2d, 1); + + marker_flag = ((ac.markers && (ac.markers != &ac.scene->markers)) ? DRAW_MARKERS_LOCAL : 0) | + DRAW_MARKERS_MARGIN; + if (saction->flag & SACTION_SHOW_MARKER_LINES) + marker_flag |= DRAW_MARKERS_LINES; + ED_markers_draw(C, marker_flag); + + /* caches */ + if (saction->mode == SACTCONT_TIMELINE) { + timeline_draw_cache(saction, obact, scene); + } + + /* preview range */ + UI_view2d_view_ortho(v2d); + ANIM_draw_previewrange(C, v2d, 0); + + /* callback */ + UI_view2d_view_ortho(v2d); + ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); + + /* reset view matrix */ + UI_view2d_view_restore(C); + + /* scrollers */ + scrollers = UI_view2d_scrollers_calc( + C, v2d, NULL, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY); + UI_view2d_scrollers_draw(C, v2d, scrollers); + UI_view2d_scrollers_free(scrollers); + + /* draw current frame number-indicator on top of scrollers */ + if ((saction->flag & SACTION_NODRAWCFRANUM) == 0) { + UI_view2d_view_orthoSpecial(ar, v2d, 1); + ANIM_draw_cfra_number(C, v2d, cfra_flag); + } } /* add handlers, stuff you only do once or on area/region changes */ static void action_channel_region_init(wmWindowManager *wm, ARegion *ar) { - wmKeyMap *keymap; + wmKeyMap *keymap; - /* ensure the 2d view sync works - main region has bottom scroller */ - ar->v2d.scroll = V2D_SCROLL_BOTTOM; + /* ensure the 2d view sync works - main region has bottom scroller */ + ar->v2d.scroll = V2D_SCROLL_BOTTOM; - UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); - /* own keymap */ - keymap = WM_keymap_ensure(wm->defaultconf, "Animation Channels", 0, 0); - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + /* own keymap */ + keymap = WM_keymap_ensure(wm->defaultconf, "Animation Channels", 0, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap = WM_keymap_ensure(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0); - WM_event_add_keymap_handler(&ar->handlers, keymap); + keymap = WM_keymap_ensure(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); } static void action_channel_region_draw(const bContext *C, ARegion *ar) { - /* draw entirely, view changes should be handled here */ - bAnimContext ac; - View2D *v2d = &ar->v2d; + /* draw entirely, view changes should be handled here */ + bAnimContext ac; + View2D *v2d = &ar->v2d; - /* clear and setup matrix */ - UI_ThemeClearColor(TH_BACK); - GPU_clear(GPU_COLOR_BIT); + /* clear and setup matrix */ + UI_ThemeClearColor(TH_BACK); + GPU_clear(GPU_COLOR_BIT); - UI_view2d_view_ortho(v2d); + UI_view2d_view_ortho(v2d); - /* data */ - if (ANIM_animdata_get_context(C, &ac)) { - draw_channel_names((bContext *)C, &ac, ar); - } + /* data */ + if (ANIM_animdata_get_context(C, &ac)) { + draw_channel_names((bContext *)C, &ac, ar); + } - /* reset view matrix */ - UI_view2d_view_restore(C); + /* reset view matrix */ + UI_view2d_view_restore(C); - /* no scrollers here */ + /* no scrollers here */ } - /* add handlers, stuff you only do once or on area/region changes */ static void action_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { - ED_region_header_init(ar); + ED_region_header_init(ar); } static void action_header_region_draw(const bContext *C, ARegion *ar) { - ED_region_header(C, ar); + ED_region_header(C, ar); } -static void action_channel_region_listener( - wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar, - wmNotifier *wmn, const Scene *UNUSED(scene)) +static void action_channel_region_listener(wmWindow *UNUSED(win), + ScrArea *UNUSED(sa), + ARegion *ar, + wmNotifier *wmn, + const Scene *UNUSED(scene)) { - /* context changes */ - switch (wmn->category) { - case NC_ANIMATION: - ED_region_tag_redraw(ar); - break; - case NC_SCENE: - switch (wmn->data) { - case ND_OB_ACTIVE: - case ND_FRAME: - ED_region_tag_redraw(ar); - break; - } - break; - case NC_OBJECT: - switch (wmn->data) { - case ND_BONE_ACTIVE: - case ND_BONE_SELECT: - case ND_KEYS: - ED_region_tag_redraw(ar); - break; - case ND_MODIFIER: - if (wmn->action == NA_RENAME) - ED_region_tag_redraw(ar); - break; - } - break; - case NC_GPENCIL: - if (ELEM(wmn->action, NA_RENAME, NA_SELECTED)) - ED_region_tag_redraw(ar); - break; - case NC_ID: - if (wmn->action == NA_RENAME) - ED_region_tag_redraw(ar); - break; - default: - if (wmn->data == ND_KEYS) - ED_region_tag_redraw(ar); - break; - } + /* context changes */ + switch (wmn->category) { + case NC_ANIMATION: + ED_region_tag_redraw(ar); + break; + case NC_SCENE: + switch (wmn->data) { + case ND_OB_ACTIVE: + case ND_FRAME: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_OBJECT: + switch (wmn->data) { + case ND_BONE_ACTIVE: + case ND_BONE_SELECT: + case ND_KEYS: + ED_region_tag_redraw(ar); + break; + case ND_MODIFIER: + if (wmn->action == NA_RENAME) + ED_region_tag_redraw(ar); + break; + } + break; + case NC_GPENCIL: + if (ELEM(wmn->action, NA_RENAME, NA_SELECTED)) + ED_region_tag_redraw(ar); + break; + case NC_ID: + if (wmn->action == NA_RENAME) + ED_region_tag_redraw(ar); + break; + default: + if (wmn->data == ND_KEYS) + ED_region_tag_redraw(ar); + break; + } } -static void saction_channel_region_message_subscribe( - const struct bContext *UNUSED(C), - struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), - struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar, - struct wmMsgBus *mbus) +static void saction_channel_region_message_subscribe(const struct bContext *UNUSED(C), + struct WorkSpace *UNUSED(workspace), + struct Scene *UNUSED(scene), + struct bScreen *screen, + struct ScrArea *sa, + struct ARegion *ar, + struct wmMsgBus *mbus) { - PointerRNA ptr; - RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, sa->spacedata.first, &ptr); - - wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { - .owner = ar, - .user_data = ar, - .notify = ED_region_do_msg_notify_tag_redraw, - }; - - /* All dopesheet filter settings, etc. affect the drawing of this editor, - * also same applies for all animation-related datatypes that may appear here, - * so just whitelist the entire structs for updates - */ - { - wmMsgParams_RNA msg_key_params = {{{0}}}; - StructRNA *type_array[] = { - &RNA_DopeSheet, /* dopesheet filters */ - - &RNA_ActionGroup, /* channel groups */ - - &RNA_FCurve, /* F-Curve */ - &RNA_Keyframe, - &RNA_FCurveSample, - - &RNA_GreasePencil, /* Grease Pencil */ - &RNA_GPencilLayer, - &RNA_GPencilFrame, - }; - - for (int i = 0; i < ARRAY_SIZE(type_array); i++) { - msg_key_params.ptr.type = type_array[i]; - WM_msg_subscribe_rna_params( - mbus, - &msg_key_params, - &msg_sub_value_region_tag_redraw, - __func__); - } - } + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, sa->spacedata.first, &ptr); + + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + /* All dopesheet filter settings, etc. affect the drawing of this editor, + * also same applies for all animation-related datatypes that may appear here, + * so just whitelist the entire structs for updates + */ + { + wmMsgParams_RNA msg_key_params = {{{0}}}; + StructRNA *type_array[] = { + &RNA_DopeSheet, /* dopesheet filters */ + + &RNA_ActionGroup, /* channel groups */ + + &RNA_FCurve, /* F-Curve */ + &RNA_Keyframe, + &RNA_FCurveSample, + + &RNA_GreasePencil, /* Grease Pencil */ + &RNA_GPencilLayer, + &RNA_GPencilFrame, + }; + + for (int i = 0; i < ARRAY_SIZE(type_array); i++) { + msg_key_params.ptr.type = type_array[i]; + WM_msg_subscribe_rna_params( + mbus, &msg_key_params, &msg_sub_value_region_tag_redraw, __func__); + } + } } -static void action_main_region_listener( - wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar, - wmNotifier *wmn, const Scene *UNUSED(scene)) +static void action_main_region_listener(wmWindow *UNUSED(win), + ScrArea *UNUSED(sa), + ARegion *ar, + wmNotifier *wmn, + const Scene *UNUSED(scene)) { - /* context changes */ - switch (wmn->category) { - case NC_ANIMATION: - ED_region_tag_redraw(ar); - break; - case NC_SCENE: - switch (wmn->data) { - case ND_RENDER_OPTIONS: - case ND_OB_ACTIVE: - case ND_FRAME: - case ND_FRAME_RANGE: - case ND_MARKERS: - ED_region_tag_redraw(ar); - break; - } - break; - case NC_OBJECT: - switch (wmn->data) { - case ND_TRANSFORM: - /* moving object shouldn't need to redraw action */ - break; - case ND_BONE_ACTIVE: - case ND_BONE_SELECT: - case ND_KEYS: - ED_region_tag_redraw(ar); - break; - } - break; - case NC_NODE: - switch (wmn->action) { - case NA_EDITED: - ED_region_tag_redraw(ar); - break; - } - break; - case NC_ID: - if (wmn->action == NA_RENAME) - ED_region_tag_redraw(ar); - break; - case NC_SCREEN: - if (ELEM(wmn->data, ND_LAYER)) { - ED_region_tag_redraw(ar); - } - break; - default: - if (wmn->data == ND_KEYS) - ED_region_tag_redraw(ar); - break; - } + /* context changes */ + switch (wmn->category) { + case NC_ANIMATION: + ED_region_tag_redraw(ar); + break; + case NC_SCENE: + switch (wmn->data) { + case ND_RENDER_OPTIONS: + case ND_OB_ACTIVE: + case ND_FRAME: + case ND_FRAME_RANGE: + case ND_MARKERS: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_OBJECT: + switch (wmn->data) { + case ND_TRANSFORM: + /* moving object shouldn't need to redraw action */ + break; + case ND_BONE_ACTIVE: + case ND_BONE_SELECT: + case ND_KEYS: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_NODE: + switch (wmn->action) { + case NA_EDITED: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_ID: + if (wmn->action == NA_RENAME) + ED_region_tag_redraw(ar); + break; + case NC_SCREEN: + if (ELEM(wmn->data, ND_LAYER)) { + ED_region_tag_redraw(ar); + } + break; + default: + if (wmn->data == ND_KEYS) + ED_region_tag_redraw(ar); + break; + } } -static void saction_main_region_message_subscribe( - const struct bContext *C, - struct WorkSpace *workspace, struct Scene *scene, - struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar, - struct wmMsgBus *mbus) +static void saction_main_region_message_subscribe(const struct bContext *C, + struct WorkSpace *workspace, + struct Scene *scene, + struct bScreen *screen, + struct ScrArea *sa, + struct ARegion *ar, + struct wmMsgBus *mbus) { - PointerRNA ptr; - RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, sa->spacedata.first, &ptr); - - wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { - .owner = ar, - .user_data = ar, - .notify = ED_region_do_msg_notify_tag_redraw, - }; - - /* Timeline depends on scene properties. */ - { - bool use_preview = (scene->r.flag & SCER_PRV_RANGE); - extern PropertyRNA rna_Scene_frame_start; - extern PropertyRNA rna_Scene_frame_end; - extern PropertyRNA rna_Scene_frame_preview_start; - extern PropertyRNA rna_Scene_frame_preview_end; - extern PropertyRNA rna_Scene_use_preview_range; - extern PropertyRNA rna_Scene_frame_current; - const PropertyRNA *props[] = { - use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start, - use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end, - &rna_Scene_use_preview_range, - &rna_Scene_frame_current, - }; - - PointerRNA idptr; - RNA_id_pointer_create(&scene->id, &idptr); - - for (int i = 0; i < ARRAY_SIZE(props); i++) { - WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__); - } - } - - /* Now run the general "channels region" one - since channels and main should be in sync */ - saction_channel_region_message_subscribe(C, workspace, scene, screen, sa, ar, mbus); + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, sa->spacedata.first, &ptr); + + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + /* Timeline depends on scene properties. */ + { + bool use_preview = (scene->r.flag & SCER_PRV_RANGE); + extern PropertyRNA rna_Scene_frame_start; + extern PropertyRNA rna_Scene_frame_end; + extern PropertyRNA rna_Scene_frame_preview_start; + extern PropertyRNA rna_Scene_frame_preview_end; + extern PropertyRNA rna_Scene_use_preview_range; + extern PropertyRNA rna_Scene_frame_current; + const PropertyRNA *props[] = { + use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start, + use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end, + &rna_Scene_use_preview_range, + &rna_Scene_frame_current, + }; + + PointerRNA idptr; + RNA_id_pointer_create(&scene->id, &idptr); + + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__); + } + } + + /* Now run the general "channels region" one - since channels and main should be in sync */ + saction_channel_region_message_subscribe(C, workspace, scene, screen, sa, ar, mbus); } /* editor level listener */ -static void action_listener( - wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene)) +static void action_listener(wmWindow *UNUSED(win), + ScrArea *sa, + wmNotifier *wmn, + Scene *UNUSED(scene)) { - SpaceAction *saction = (SpaceAction *)sa->spacedata.first; - - /* context changes */ - switch (wmn->category) { - case NC_GPENCIL: - /* only handle these events in GPencil mode for performance considerations */ - if (saction->mode == SACTCONT_GPENCIL) { - if (wmn->action == NA_EDITED) { - ED_area_tag_redraw(sa); - } - else if (wmn->action == NA_SELECTED) { - saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; - ED_area_tag_refresh(sa); - } - } - break; - case NC_ANIMATION: - /* for NLA tweakmode enter/exit, need complete refresh */ - if (wmn->data == ND_NLA_ACTCHANGE) { - saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; - ED_area_tag_refresh(sa); - } - /* autocolor only really needs to change when channels are added/removed, - * or previously hidden stuff appears - * (assume for now that if just adding these works, that will be fine) - */ - else if (((wmn->data == ND_KEYFRAME) && ELEM(wmn->action, NA_ADDED, NA_REMOVED)) || - ((wmn->data == ND_ANIMCHAN) && (wmn->action != NA_SELECTED))) - { - ED_area_tag_refresh(sa); - } - /* for simple edits to the curve data though (or just plain selections), - * a simple redraw should work - * (see T39851 for an example of how this can go wrong) - */ - else { - ED_area_tag_redraw(sa); - } - break; - case NC_SCENE: - switch (wmn->data) { - case ND_OB_ACTIVE: - case ND_OB_SELECT: - /* Selection changed, so force refresh to flush - * (needs flag set to do syncing). */ - saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; - ED_area_tag_refresh(sa); - break; - case ND_RENDER_RESULT: - ED_area_tag_redraw(sa); - break; - case ND_FRAME_RANGE: - for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype == RGN_TYPE_WINDOW) { - Scene *scene = wmn->reference; - ar->v2d.tot.xmin = (float)(SFRA - 4); - ar->v2d.tot.xmax = (float)(EFRA + 4); - break; - } - } - break; - default: - if (saction->mode != SACTCONT_TIMELINE) { - /* Just redrawing the view will do. */ - ED_area_tag_redraw(sa); - } - break; - } - break; - case NC_OBJECT: - switch (wmn->data) { - case ND_BONE_SELECT: /* selection changed, so force refresh to flush - * (needs flag set to do syncing) */ - case ND_BONE_ACTIVE: - saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; - ED_area_tag_refresh(sa); - break; - case ND_TRANSFORM: - /* moving object shouldn't need to redraw action */ - break; - case ND_POINTCACHE: - case ND_MODIFIER: - case ND_PARTICLE: - /* only needed in timeline mode */ - if (saction->mode == SACTCONT_TIMELINE) { - ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); - } - break; - default: /* just redrawing the view will do */ - ED_area_tag_redraw(sa); - break; - } - break; - case NC_MASK: - if (saction->mode == SACTCONT_MASK) { - switch (wmn->data) { - case ND_DATA: - ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); - break; - default: /* just redrawing the view will do */ - ED_area_tag_redraw(sa); - break; - } - } - break; - case NC_NODE: - if (wmn->action == NA_SELECTED) { - /* selection changed, so force refresh to flush (needs flag set to do syncing) */ - saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; - ED_area_tag_refresh(sa); - } - break; - case NC_SPACE: - switch (wmn->data) { - case ND_SPACE_DOPESHEET: - ED_area_tag_redraw(sa); - break; - case ND_SPACE_TIME: - ED_area_tag_redraw(sa); - break; - case ND_SPACE_CHANGED: - saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; - ED_area_tag_refresh(sa); - break; - } - break; - case NC_WINDOW: - if (saction->runtime.flag & SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC) { - /* force redraw/refresh after undo/redo - [#28962] */ - ED_area_tag_refresh(sa); - } - break; - case NC_WM: - switch (wmn->data) { - case ND_FILEREAD: - ED_area_tag_refresh(sa); - break; - } - break; - } + SpaceAction *saction = (SpaceAction *)sa->spacedata.first; + + /* context changes */ + switch (wmn->category) { + case NC_GPENCIL: + /* only handle these events in GPencil mode for performance considerations */ + if (saction->mode == SACTCONT_GPENCIL) { + if (wmn->action == NA_EDITED) { + ED_area_tag_redraw(sa); + } + else if (wmn->action == NA_SELECTED) { + saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; + ED_area_tag_refresh(sa); + } + } + break; + case NC_ANIMATION: + /* for NLA tweakmode enter/exit, need complete refresh */ + if (wmn->data == ND_NLA_ACTCHANGE) { + saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; + ED_area_tag_refresh(sa); + } + /* autocolor only really needs to change when channels are added/removed, + * or previously hidden stuff appears + * (assume for now that if just adding these works, that will be fine) + */ + else if (((wmn->data == ND_KEYFRAME) && ELEM(wmn->action, NA_ADDED, NA_REMOVED)) || + ((wmn->data == ND_ANIMCHAN) && (wmn->action != NA_SELECTED))) { + ED_area_tag_refresh(sa); + } + /* for simple edits to the curve data though (or just plain selections), + * a simple redraw should work + * (see T39851 for an example of how this can go wrong) + */ + else { + ED_area_tag_redraw(sa); + } + break; + case NC_SCENE: + switch (wmn->data) { + case ND_OB_ACTIVE: + case ND_OB_SELECT: + /* Selection changed, so force refresh to flush + * (needs flag set to do syncing). */ + saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; + ED_area_tag_refresh(sa); + break; + case ND_RENDER_RESULT: + ED_area_tag_redraw(sa); + break; + case ND_FRAME_RANGE: + for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_WINDOW) { + Scene *scene = wmn->reference; + ar->v2d.tot.xmin = (float)(SFRA - 4); + ar->v2d.tot.xmax = (float)(EFRA + 4); + break; + } + } + break; + default: + if (saction->mode != SACTCONT_TIMELINE) { + /* Just redrawing the view will do. */ + ED_area_tag_redraw(sa); + } + break; + } + break; + case NC_OBJECT: + switch (wmn->data) { + case ND_BONE_SELECT: /* selection changed, so force refresh to flush + * (needs flag set to do syncing) */ + case ND_BONE_ACTIVE: + saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; + ED_area_tag_refresh(sa); + break; + case ND_TRANSFORM: + /* moving object shouldn't need to redraw action */ + break; + case ND_POINTCACHE: + case ND_MODIFIER: + case ND_PARTICLE: + /* only needed in timeline mode */ + if (saction->mode == SACTCONT_TIMELINE) { + ED_area_tag_refresh(sa); + ED_area_tag_redraw(sa); + } + break; + default: /* just redrawing the view will do */ + ED_area_tag_redraw(sa); + break; + } + break; + case NC_MASK: + if (saction->mode == SACTCONT_MASK) { + switch (wmn->data) { + case ND_DATA: + ED_area_tag_refresh(sa); + ED_area_tag_redraw(sa); + break; + default: /* just redrawing the view will do */ + ED_area_tag_redraw(sa); + break; + } + } + break; + case NC_NODE: + if (wmn->action == NA_SELECTED) { + /* selection changed, so force refresh to flush (needs flag set to do syncing) */ + saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; + ED_area_tag_refresh(sa); + } + break; + case NC_SPACE: + switch (wmn->data) { + case ND_SPACE_DOPESHEET: + ED_area_tag_redraw(sa); + break; + case ND_SPACE_TIME: + ED_area_tag_redraw(sa); + break; + case ND_SPACE_CHANGED: + saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; + ED_area_tag_refresh(sa); + break; + } + break; + case NC_WINDOW: + if (saction->runtime.flag & SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC) { + /* force redraw/refresh after undo/redo - [#28962] */ + ED_area_tag_refresh(sa); + } + break; + case NC_WM: + switch (wmn->data) { + case ND_FILEREAD: + ED_area_tag_refresh(sa); + break; + } + break; + } } static void action_header_region_listener( - wmWindow *UNUSED(win), ScrArea *sa, ARegion *ar, - wmNotifier *wmn, const Scene *UNUSED(scene)) + wmWindow *UNUSED(win), ScrArea *sa, ARegion *ar, wmNotifier *wmn, const Scene *UNUSED(scene)) { - SpaceAction *saction = (SpaceAction *)sa->spacedata.first; - - /* context changes */ - switch (wmn->category) { - case NC_SCREEN: - if (saction->mode == SACTCONT_TIMELINE) { - if (wmn->data == ND_ANIMPLAY) - ED_region_tag_redraw(ar); - } - break; - case NC_SCENE: - if (saction->mode == SACTCONT_TIMELINE) { - switch (wmn->data) { - case ND_RENDER_RESULT: - case ND_OB_SELECT: - case ND_FRAME: - case ND_FRAME_RANGE: - case ND_KEYINGSET: - case ND_RENDER_OPTIONS: - ED_region_tag_redraw(ar); - break; - } - } - else { - switch (wmn->data) { - case ND_OB_ACTIVE: - ED_region_tag_redraw(ar); - break; - } - } - break; - case NC_ID: - if (wmn->action == NA_RENAME) - ED_region_tag_redraw(ar); - break; - case NC_ANIMATION: - switch (wmn->data) { - case ND_ANIMCHAN: /* set of visible animchannels changed */ - /* NOTE: for now, this should usually just mean that the filters changed - * It may be better if we had a dedicated flag for that though - */ - ED_region_tag_redraw(ar); - break; - - case ND_KEYFRAME: /* new keyframed added -> active action may have changed */ - //saction->flag |= SACTION_TEMP_NEEDCHANSYNC; - ED_region_tag_redraw(ar); - break; - } - break; - } - + SpaceAction *saction = (SpaceAction *)sa->spacedata.first; + + /* context changes */ + switch (wmn->category) { + case NC_SCREEN: + if (saction->mode == SACTCONT_TIMELINE) { + if (wmn->data == ND_ANIMPLAY) + ED_region_tag_redraw(ar); + } + break; + case NC_SCENE: + if (saction->mode == SACTCONT_TIMELINE) { + switch (wmn->data) { + case ND_RENDER_RESULT: + case ND_OB_SELECT: + case ND_FRAME: + case ND_FRAME_RANGE: + case ND_KEYINGSET: + case ND_RENDER_OPTIONS: + ED_region_tag_redraw(ar); + break; + } + } + else { + switch (wmn->data) { + case ND_OB_ACTIVE: + ED_region_tag_redraw(ar); + break; + } + } + break; + case NC_ID: + if (wmn->action == NA_RENAME) + ED_region_tag_redraw(ar); + break; + case NC_ANIMATION: + switch (wmn->data) { + case ND_ANIMCHAN: /* set of visible animchannels changed */ + /* NOTE: for now, this should usually just mean that the filters changed + * It may be better if we had a dedicated flag for that though + */ + ED_region_tag_redraw(ar); + break; + + case ND_KEYFRAME: /* new keyframed added -> active action may have changed */ + //saction->flag |= SACTION_TEMP_NEEDCHANSYNC; + ED_region_tag_redraw(ar); + break; + } + break; + } } /* add handlers, stuff you only do once or on area/region changes */ static void action_buttons_area_init(wmWindowManager *wm, ARegion *ar) { - wmKeyMap *keymap; + wmKeyMap *keymap; - ED_region_panels_init(wm, ar); + ED_region_panels_init(wm, ar); - keymap = WM_keymap_ensure(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0); - WM_event_add_keymap_handler(&ar->handlers, keymap); + keymap = WM_keymap_ensure(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); } static void action_buttons_area_draw(const bContext *C, ARegion *ar) { - ED_region_panels(C, ar); + ED_region_panels(C, ar); } -static void action_region_listener( - wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar, - wmNotifier *wmn, const Scene *UNUSED(scene)) +static void action_region_listener(wmWindow *UNUSED(win), + ScrArea *UNUSED(sa), + ARegion *ar, + wmNotifier *wmn, + const Scene *UNUSED(scene)) { - /* context changes */ - switch (wmn->category) { - case NC_ANIMATION: - ED_region_tag_redraw(ar); - break; - case NC_SCENE: - switch (wmn->data) { - case ND_OB_ACTIVE: - case ND_FRAME: - case ND_MARKERS: - ED_region_tag_redraw(ar); - break; - } - break; - case NC_OBJECT: - switch (wmn->data) { - case ND_BONE_ACTIVE: - case ND_BONE_SELECT: - case ND_KEYS: - ED_region_tag_redraw(ar); - break; - } - break; - default: - if (wmn->data == ND_KEYS) - ED_region_tag_redraw(ar); - break; - } + /* context changes */ + switch (wmn->category) { + case NC_ANIMATION: + ED_region_tag_redraw(ar); + break; + case NC_SCENE: + switch (wmn->data) { + case ND_OB_ACTIVE: + case ND_FRAME: + case ND_MARKERS: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_OBJECT: + switch (wmn->data) { + case ND_BONE_ACTIVE: + case ND_BONE_SELECT: + case ND_KEYS: + ED_region_tag_redraw(ar); + break; + } + break; + default: + if (wmn->data == ND_KEYS) + ED_region_tag_redraw(ar); + break; + } } static void action_refresh(const bContext *C, ScrArea *sa) { - SpaceAction *saction = (SpaceAction *)sa->spacedata.first; - - /* update the state of the animchannels in response to changes from the data they represent - * NOTE: the temp flag is used to indicate when this needs to be done, and will be cleared once handled - */ - if (saction->runtime.flag & SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC) { - ARegion *ar; - - /* Perform syncing of channel state incl. selection - * Active action setting also occurs here (as part of anim channel filtering in anim_filter.c) - */ - ANIM_sync_animchannels_to_data(C); - saction->runtime.flag &= ~SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; - - /* Tag everything for redraw - * - Regions (such as header) need to be manually tagged for redraw too - * or else they don't update [#28962] - */ - ED_area_tag_redraw(sa); - for (ar = sa->regionbase.first; ar; ar = ar->next) - ED_region_tag_redraw(ar); - } - - /* region updates? */ - // XXX re-sizing y-extents of tot should go here? + SpaceAction *saction = (SpaceAction *)sa->spacedata.first; + + /* update the state of the animchannels in response to changes from the data they represent + * NOTE: the temp flag is used to indicate when this needs to be done, and will be cleared once handled + */ + if (saction->runtime.flag & SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC) { + ARegion *ar; + + /* Perform syncing of channel state incl. selection + * Active action setting also occurs here (as part of anim channel filtering in anim_filter.c) + */ + ANIM_sync_animchannels_to_data(C); + saction->runtime.flag &= ~SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC; + + /* Tag everything for redraw + * - Regions (such as header) need to be manually tagged for redraw too + * or else they don't update [#28962] + */ + ED_area_tag_redraw(sa); + for (ar = sa->regionbase.first; ar; ar = ar->next) + ED_region_tag_redraw(ar); + } + + /* region updates? */ + // XXX re-sizing y-extents of tot should go here? } static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) { - SpaceAction *sact = (SpaceAction *)slink; - - if ((ID *)sact->action == old_id) { - sact->action = (bAction *)new_id; - } - - if ((ID *)sact->ads.filter_grp == old_id) { - sact->ads.filter_grp = (Collection *)new_id; - } - if ((ID *)sact->ads.source == old_id) { - sact->ads.source = new_id; - } - + SpaceAction *sact = (SpaceAction *)slink; + + if ((ID *)sact->action == old_id) { + sact->action = (bAction *)new_id; + } + + if ((ID *)sact->ads.filter_grp == old_id) { + sact->ads.filter_grp = (Collection *)new_id; + } + if ((ID *)sact->ads.source == old_id) { + sact->ads.source = new_id; + } } /** @@ -826,100 +840,101 @@ static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, I */ static int action_space_subtype_get(ScrArea *sa) { - SpaceAction *sact = sa->spacedata.first; - return sact->mode == SACTCONT_TIMELINE ? SACTCONT_TIMELINE : SACTCONT_DOPESHEET; + SpaceAction *sact = sa->spacedata.first; + return sact->mode == SACTCONT_TIMELINE ? SACTCONT_TIMELINE : SACTCONT_DOPESHEET; } static void action_space_subtype_set(ScrArea *sa, int value) { - SpaceAction *sact = sa->spacedata.first; - if (value == SACTCONT_TIMELINE) { - if (sact->mode != SACTCONT_TIMELINE) { - sact->mode_prev = sact->mode; - } - sact->mode = value; - } - else { - sact->mode = sact->mode_prev; - } + SpaceAction *sact = sa->spacedata.first; + if (value == SACTCONT_TIMELINE) { + if (sact->mode != SACTCONT_TIMELINE) { + sact->mode_prev = sact->mode; + } + sact->mode = value; + } + else { + sact->mode = sact->mode_prev; + } } -static void action_space_subtype_item_extend( - bContext *UNUSED(C), EnumPropertyItem **item, int *totitem) +static void action_space_subtype_item_extend(bContext *UNUSED(C), + EnumPropertyItem **item, + int *totitem) { - RNA_enum_items_add(item, totitem, rna_enum_space_action_mode_items); + RNA_enum_items_add(item, totitem, rna_enum_space_action_mode_items); } /* only called once, from space/spacetypes.c */ void ED_spacetype_action(void) { - SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype action"); - ARegionType *art; - - st->spaceid = SPACE_ACTION; - strncpy(st->name, "Action", BKE_ST_MAXNAME); - - st->new = action_new; - st->free = action_free; - st->init = action_init; - st->duplicate = action_duplicate; - st->operatortypes = action_operatortypes; - st->keymap = action_keymap; - st->listener = action_listener; - st->refresh = action_refresh; - st->id_remap = action_id_remap; - st->space_subtype_item_extend = action_space_subtype_item_extend; - st->space_subtype_get = action_space_subtype_get; - st->space_subtype_set = action_space_subtype_set; - - /* regions: main window */ - art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); - art->regionid = RGN_TYPE_WINDOW; - art->init = action_main_region_init; - art->draw = action_main_region_draw; - art->listener = action_main_region_listener; - art->message_subscribe = saction_main_region_message_subscribe; - art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; - - BLI_addhead(&st->regiontypes, art); - - /* regions: header */ - art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); - art->regionid = RGN_TYPE_HEADER; - art->prefsizey = HEADERY; - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - - art->init = action_header_region_init; - art->draw = action_header_region_draw; - art->listener = action_header_region_listener; - - BLI_addhead(&st->regiontypes, art); - - /* regions: channels */ - art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); - art->regionid = RGN_TYPE_CHANNELS; - art->prefsizex = 200; - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES; - - art->init = action_channel_region_init; - art->draw = action_channel_region_draw; - art->listener = action_channel_region_listener; - art->message_subscribe = saction_channel_region_message_subscribe; - - BLI_addhead(&st->regiontypes, art); - - /* regions: UI buttons */ - art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); - art->regionid = RGN_TYPE_UI; - art->prefsizex = 200; - art->keymapflag = ED_KEYMAP_UI; - art->listener = action_region_listener; - art->init = action_buttons_area_init; - art->draw = action_buttons_area_draw; - - BLI_addhead(&st->regiontypes, art); - - action_buttons_register(art); - - BKE_spacetype_register(st); + SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype action"); + ARegionType *art; + + st->spaceid = SPACE_ACTION; + strncpy(st->name, "Action", BKE_ST_MAXNAME); + + st->new = action_new; + st->free = action_free; + st->init = action_init; + st->duplicate = action_duplicate; + st->operatortypes = action_operatortypes; + st->keymap = action_keymap; + st->listener = action_listener; + st->refresh = action_refresh; + st->id_remap = action_id_remap; + st->space_subtype_item_extend = action_space_subtype_item_extend; + st->space_subtype_get = action_space_subtype_get; + st->space_subtype_set = action_space_subtype_set; + + /* regions: main window */ + art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); + art->regionid = RGN_TYPE_WINDOW; + art->init = action_main_region_init; + art->draw = action_main_region_draw; + art->listener = action_main_region_listener; + art->message_subscribe = saction_main_region_message_subscribe; + art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; + + BLI_addhead(&st->regiontypes, art); + + /* regions: header */ + art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); + art->regionid = RGN_TYPE_HEADER; + art->prefsizey = HEADERY; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; + + art->init = action_header_region_init; + art->draw = action_header_region_draw; + art->listener = action_header_region_listener; + + BLI_addhead(&st->regiontypes, art); + + /* regions: channels */ + art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); + art->regionid = RGN_TYPE_CHANNELS; + art->prefsizex = 200; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES; + + art->init = action_channel_region_init; + art->draw = action_channel_region_draw; + art->listener = action_channel_region_listener; + art->message_subscribe = saction_channel_region_message_subscribe; + + BLI_addhead(&st->regiontypes, art); + + /* regions: UI buttons */ + art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); + art->regionid = RGN_TYPE_UI; + art->prefsizex = 200; + art->keymapflag = ED_KEYMAP_UI; + art->listener = action_region_listener; + art->init = action_buttons_area_init; + art->draw = action_buttons_area_draw; + + BLI_addhead(&st->regiontypes, art); + + action_buttons_register(art); + + BKE_spacetype_register(st); } -- cgit v1.2.3