diff --git a/scripts/startup/bl_ui/space_dopesheet.py b/scripts/startup/bl_ui/space_dopesheet.py index 8633d8c4f27..7215e1bf401 100644 --- a/scripts/startup/bl_ui/space_dopesheet.py +++ b/scripts/startup/bl_ui/space_dopesheet.py @@ -909,6 +909,7 @@ class DOPESHEET_MT_channel_context_menu(Menu): if is_graph_editor: layout.operator_menu_enum("graph.fmodifier_add", "type", text="Add F-Curve Modifier").only_active = False + layout.operator("graph.fmodifier_delete", text="Delete F-Curve Modifiers") layout.separator() layout.operator("graph.hide", text="Hide Selected Curves").unselected = False layout.operator("graph.hide", text="Hide Unselected Curves").unselected = True diff --git a/scripts/startup/bl_ui/space_graph.py b/scripts/startup/bl_ui/space_graph.py index 165e2d99e52..05688851bed 100644 --- a/scripts/startup/bl_ui/space_graph.py +++ b/scripts/startup/bl_ui/space_graph.py @@ -353,7 +353,7 @@ class GRAPH_MT_channel(Menu): # To get it to display the hotkey. layout.operator_context = operator_context layout.operator_menu_enum("graph.fmodifier_add", "type").only_active = False - layout.operator_context = 'INVOKE_REGION_CHANNELS' + layout.operator("graph.fmodifier_delete", text="Delete F-Curve Modifiers") layout.separator() layout.operator("graph.hide", text="Hide Selected Curves").unselected = False diff --git a/source/blender/editors/space_graph/graph_edit.cc b/source/blender/editors/space_graph/graph_edit.cc index c27a9bb1904..29b6a94a561 100644 --- a/source/blender/editors/space_graph/graph_edit.cc +++ b/source/blender/editors/space_graph/graph_edit.cc @@ -58,6 +58,9 @@ #include "ED_screen.hh" #include "ED_transform.hh" +#include "UI_interface_layout.hh" +#include "UI_resources.hh" + #include "WM_api.hh" #include "WM_types.hh" @@ -2951,6 +2954,148 @@ void GRAPH_OT_fmodifier_add(wmOperatorType *ot) ot->srna, "only_active", false, "Only Active", "Only add F-Modifier to active F-Curve"); } +/* -------------------------------------------------------------------- */ +/** \name Delete F-Modifiers Operator + * \{ */ + +enum class RemovalMode { ALL = 0, FIRST = 1, TYPE = 2 }; + +static wmOperatorStatus graph_fmodifier_delete_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + ListBaseT anim_data = {nullptr, nullptr}; + + const eFModifier_Types type = static_cast(RNA_enum_get(op->ptr, "type")); + + /* Get editor data. */ + if (ANIM_animdata_get_context(C, &ac) == 0) { + return OPERATOR_CANCELLED; + } + + /* Filter data. */ + eAnimFilter_Flags filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS | + ANIMFILTER_FCURVESONLY | ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE); + + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + const RemovalMode mode = RemovalMode(RNA_enum_get(op->ptr, "mode")); + int num_fmods_deleted = 0; + int num_fcurves_affected = 0; + + /* Collect the F-Mods to delete. */ + for (bAnimListElem &ale : anim_data) { + FCurve *fcu = static_cast(ale.data); + + /* Keep track of the modifiers to delete, so that we don't delete + * them while looping over them. */ + Vector fmods_to_delete; + + for (FModifier &fcm : fcu->modifiers) { + if (mode == RemovalMode::ALL || (mode == RemovalMode::TYPE && fcm.type == type)) { + fmods_to_delete.append(&fcm); + } + } + + if (mode == RemovalMode::FIRST) { + if (FModifier *first = static_cast(fcu->modifiers.first)) { + fmods_to_delete.append(first); + } + } + + /* Delete the modifiers. */ + for (FModifier *fmod : fmods_to_delete) { + remove_fmodifier(&fcu->modifiers, fmod); + num_fmods_deleted++; + } + + if (!fmods_to_delete.is_empty()) { + num_fcurves_affected++; + } + + ale.update |= ANIM_UPDATE_DEPS; + } + + ANIM_animdata_update(&ac, &anim_data); + ANIM_animdata_freelist(&anim_data); + + /* Set notifier that things have changed. */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, nullptr); + + if (num_fmods_deleted == 0) { + BKE_report(op->reports, RPT_INFO, "No F-Modifiers found to delete"); + } + else { + BKE_reportf(op->reports, + RPT_INFO, + "Removed %d F-Modifier(s) from %d selected F-Curve(s)", + num_fmods_deleted, + num_fcurves_affected); + } + + return OPERATOR_FINISHED; +} + +static void fmodifier_delete_ui(bContext * /*C*/, wmOperator *op) +{ + ui::Layout &layout = *op->layout; + layout.use_property_split_set(true); + + layout.prop(op->ptr, "mode", UI_ITEM_NONE, std::nullopt, ICON_NONE); + if (RNA_enum_get(op->ptr, "mode") == int(RemovalMode::TYPE)) { + layout.prop(op->ptr, "type", UI_ITEM_NONE, std::nullopt, ICON_NONE); + } +} + +void GRAPH_OT_fmodifier_delete(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* Identifiers */ + ot->name = "Delete F-Curve Modifiers"; + ot->idname = "GRAPH_OT_fmodifier_delete"; + ot->description = "Remove Modifier(s) from the selected F-Curves"; + + /* API callbacks */ + ot->exec = graph_fmodifier_delete_exec; + ot->ui = fmodifier_delete_ui; + ot->poll = graphop_selected_fcurve_poll; + + /* Flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Id-props */ + static const EnumPropertyItem mode_items[] = { + {int(RemovalMode::ALL), + "ALL", + 0, + "Remove All", + "Remove all modifiers from the selected F-Curves"}, + {int(RemovalMode::FIRST), + "FIRST", + 0, + "Remove First", + "Only remove the first modifier from each F-Curve regardless of type"}, + {int(RemovalMode::TYPE), + "TYPE", + 0, + "Remove Type", + "Only remove the specified type of F-Curve modifier"}, + {0, nullptr, 0, nullptr, nullptr}}; + + RNA_def_enum(ot->srna, + "mode", + mode_items, + int(RemovalMode::ALL), + "Mode", + "Decide what the operator will remove"); + + prop = RNA_def_enum( + ot->srna, "type", rna_enum_fmodifier_type_items, FMODIFIER_TYPE_GENERATOR, "Type", ""); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ACTION); + RNA_def_enum_funcs(prop, graph_fmodifier_itemf); + ot->prop = prop; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/space_graph/graph_intern.hh b/source/blender/editors/space_graph/graph_intern.hh index b6a4e332190..8aa97b6b4c5 100644 --- a/source/blender/editors/space_graph/graph_intern.hh +++ b/source/blender/editors/space_graph/graph_intern.hh @@ -192,6 +192,7 @@ enum eGraphKeys_Mirror_Mode { /* ----------- */ void GRAPH_OT_fmodifier_add(wmOperatorType *ot); +void GRAPH_OT_fmodifier_delete(wmOperatorType *ot); void GRAPH_OT_fmodifier_copy(wmOperatorType *ot); void GRAPH_OT_fmodifier_paste(wmOperatorType *ot); diff --git a/source/blender/editors/space_graph/graph_ops.cc b/source/blender/editors/space_graph/graph_ops.cc index ca81d4059cd..6b7279df9a2 100644 --- a/source/blender/editors/space_graph/graph_ops.cc +++ b/source/blender/editors/space_graph/graph_ops.cc @@ -498,6 +498,7 @@ void graphedit_operatortypes() /* F-Curve Modifiers */ WM_operatortype_append(GRAPH_OT_fmodifier_add); + WM_operatortype_append(GRAPH_OT_fmodifier_delete); WM_operatortype_append(GRAPH_OT_fmodifier_copy); WM_operatortype_append(GRAPH_OT_fmodifier_paste);