diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 82ae4930526..ca03dd00521 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -131,6 +131,7 @@ struct bConstraint *BKE_constraints_find_name(struct ListBase *list, const char struct bConstraint *BKE_constraint_add_for_object(struct Object *ob, const char *name, short type); struct bConstraint *BKE_constraint_add_for_pose(struct Object *ob, struct bPoseChannel *pchan, const char *name, short type); +bool BKE_constraint_remove_ex(ListBase *list, struct Object *ob, struct bConstraint *con, bool clear_dep); bool BKE_constraint_remove(ListBase *list, struct bConstraint *con); /* Constraints + Proxies function prototypes */ diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 668b78a08d4..71b2e7df4b2 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -79,6 +79,8 @@ #include "BKE_tracking.h" #include "BKE_movieclip.h" +#include "BIK_api.h" + #ifdef WITH_PYTHON # include "BPY_extern.h" #endif @@ -4410,8 +4412,23 @@ bool BKE_constraint_remove(ListBase *list, bConstraint *con) BLI_freelinkN(list, con); return true; } - else + else { return false; + } +} + +bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool clear_dep) +{ + if (BKE_constraint_remove(list, con)) { + /* ITASC needs to be rebuilt once a constraint is removed [#26920] */ + if (clear_dep && ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) { + BIK_clear_data(ob->pose); + } + return true; + } + else { + return false; + } } /* ......... */ diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 8f793f7f7f9..97d926761b5 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -1182,20 +1182,13 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = ptr.id.data; bConstraint *con = ptr.data; ListBase *lb = get_constraint_lb(ob, con, NULL); - const bool is_ik = ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK); /* free the constraint */ - if (BKE_constraint_remove(lb, con)) { + if (BKE_constraint_remove_ex(lb, ob, con, true)) { /* there's no active constraint now, so make sure this is the case */ - BKE_constraints_active_set(lb, NULL); - + BKE_constraints_active_set(&ob->constraints, NULL); ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */ - /* ITASC needs to be rebuilt once a constraint is removed [#26920] */ - if (is_ik) { - BIK_clear_data(ob->pose); - } - /* notifiers */ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index f0920466b85..aa2a8896b17 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -250,7 +250,8 @@ void OUTLINER_OT_id_operation(struct wmOperatorType *ot); void OUTLINER_OT_data_operation(struct wmOperatorType *ot); void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot); void OUTLINER_OT_action_set(struct wmOperatorType *ot); - +void OUTLINER_OT_constraint_operation(struct wmOperatorType *ot); +void OUTLINER_OT_modifier_operation(struct wmOperatorType *ot); /* ---------------------------------------------------------------- */ /* outliner_ops.c */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index d54ae3f22a7..fbfaf26104e 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -54,6 +54,8 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_data_operation); WM_operatortype_append(OUTLINER_OT_animdata_operation); WM_operatortype_append(OUTLINER_OT_action_set); + WM_operatortype_append(OUTLINER_OT_constraint_operation); + WM_operatortype_append(OUTLINER_OT_modifier_operation); WM_operatortype_append(OUTLINER_OT_show_one_level); WM_operatortype_append(OUTLINER_OT_show_active); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index bd884039b30..34eec3a4c56 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -43,12 +43,15 @@ #include "DNA_sequence_types.h" #include "DNA_world_types.h" #include "DNA_object_types.h" +#include "DNA_constraint_types.h" +#include "DNA_modifier_types.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BKE_animsys.h" #include "BKE_context.h" +#include "BKE_constraint.h" #include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_group.h" @@ -69,6 +72,7 @@ #include "UI_interface.h" #include "UI_view2d.h" +#include "UI_resources.h" #include "RNA_access.h" #include "RNA_define.h" @@ -500,14 +504,25 @@ static void refreshdrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te /* --------------------------------- */ typedef enum eOutliner_PropDataOps { - OL_DOP_INVALID = 0, - OL_DOP_SELECT, + OL_DOP_SELECT = 1, OL_DOP_DESELECT, OL_DOP_HIDE, OL_DOP_UNHIDE, OL_DOP_SELECT_LINKED, } eOutliner_PropDataOps; +typedef enum eOutliner_PropConstraintOps { + OL_CONSTRAINTOP_ENABLE = 1, + OL_CONSTRAINTOP_DISABLE, + OL_CONSTRAINTOP_DELETE +} eOutliner_PropConstraintOps; + +typedef enum eOutliner_PropModifierOps { + OL_MODIFIER_OP_TOGVIS = 1, + OL_MODIFIER_OP_TOGREN, + OL_MODIFIER_OP_DELETE +} eOutliner_PropModifierOps; + static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) { bPoseChannel *pchan = (bPoseChannel *)te->directdata; @@ -582,6 +597,68 @@ static void data_select_linked_cb(int event, TreeElement *te, TreeStoreElem *UNU } } +static void constraint_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v) +{ + bContext *C = C_v; + SpaceOops *soops = CTX_wm_space_outliner(C); + bConstraint *constraint = (bConstraint *)te->directdata; + Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); + + if (event == OL_CONSTRAINTOP_ENABLE) { + constraint->flag &= ~CONSTRAINT_OFF; + ED_object_constraint_update(ob); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + } + else if (event == OL_CONSTRAINTOP_DISABLE) { + constraint->flag = CONSTRAINT_OFF; + ED_object_constraint_update(ob); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + } + else if (event == OL_CONSTRAINTOP_DELETE) { + ListBase *lb = NULL; + + if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) { + lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints; + } + else { + lb = &ob->constraints; + } + + if (BKE_constraint_remove_ex(lb, ob, constraint, true)) { + /* there's no active constraint now, so make sure this is the case */ + BKE_constraints_active_set(&ob->constraints, NULL); + ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */ + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); + te->store_elem->flag &= ~TSE_SELECTED; + } + } +} + +static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg) +{ + bContext *C = (bContext *)Carg; + Main *bmain = CTX_data_main(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + ModifierData *md = (ModifierData *)te->directdata; + Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); + + if (event == OL_MODIFIER_OP_TOGVIS) { + md->mode ^= eModifierMode_Realtime; + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + } + else if (event == OL_MODIFIER_OP_TOGREN) { + md->mode ^= eModifierMode_Render; + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + } + else if (event == OL_MODIFIER_OP_DELETE) { + ED_object_modifier_remove(NULL, bmain, ob, md); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob); + te->store_elem->flag &= ~TSE_SELECTED; + } +} + static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, void (*operation_cb)(int, TreeElement *, TreeStoreElem *, void *), void *arg) @@ -648,8 +725,7 @@ static void object_delete_hierarchy_cb( /* **************************************** */ enum { - OL_OP_ENDMARKER = 0, - OL_OP_SELECT, + OL_OP_SELECT = 1, OL_OP_DESELECT, OL_OP_SELECT_HIERARCHY, OL_OP_DELETE, @@ -671,7 +747,7 @@ static EnumPropertyItem prop_object_op_types[] = { {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""}, {OL_OP_RENAME, "RENAME", 0, "Rename", ""}, - {OL_OP_ENDMARKER, NULL, 0, NULL, NULL} + {0, NULL, 0, NULL, NULL} }; static int outliner_object_operation_exec(bContext *C, wmOperator *op) @@ -1259,6 +1335,98 @@ void OUTLINER_OT_animdata_operation(wmOperatorType *ot) /* **************************************** */ +static EnumPropertyItem prop_constraint_op_types[] = { + {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_RESTRICT_VIEW_OFF, "Enable", ""}, + {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_RESTRICT_VIEW_ON, "Disable", ""}, + {OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static int outliner_constraint_operation_exec(bContext *C, wmOperator *op) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + eOutliner_PropConstraintOps event; + + event = RNA_enum_get(op->ptr, "type"); + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + + outliner_do_data_operation(soops, datalevel, event, &soops->tree, constraint_cb, C); + + if (event == OL_CONSTRAINTOP_DELETE) { + outliner_cleanup_tree(soops); + } + + ED_undo_push(C, "Constraint operation"); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_constraint_operation(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Outliner Constraint Operation"; + ot->idname = "OUTLINER_OT_constraint_operation"; + ot->description = "Outliner ContextMenu Constraint Operation"; + + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_constraint_operation_exec; + ot->poll = ED_operator_outliner_active; + + ot->flag = 0; + + ot->prop = RNA_def_enum(ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", ""); +} + +/* ******************** */ + +static EnumPropertyItem prop_modifier_op_types[] = { + {OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle viewport use", ""}, + {OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle render use", ""}, + {OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static int outliner_modifier_operation_exec(bContext *C, wmOperator *op) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + eOutliner_PropModifierOps event; + + event = RNA_enum_get(op->ptr, "type"); + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + + outliner_do_data_operation(soops, datalevel, event, &soops->tree, modifier_cb, C); + + if (event == OL_MODIFIER_OP_DELETE) { + outliner_cleanup_tree(soops); + } + + ED_undo_push(C, "Modifier operation"); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_modifier_operation(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Outliner Modifier Operation"; + ot->idname = "OUTLINER_OT_modifier_operation"; + ot->description = "Outliner ContextMenu Modifier Operation"; + + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_modifier_operation_exec; + ot->poll = ED_operator_outliner_active; + + ot->flag = 0; + + ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", ""); +} + +/* ******************** */ + static EnumPropertyItem prop_data_op_types[] = { {OL_DOP_SELECT, "SELECT", 0, "Select", ""}, {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""}, @@ -1281,9 +1449,6 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op) event = RNA_enum_get(op->ptr, "type"); set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - if (event <= OL_DOP_INVALID) - return OPERATOR_CANCELLED; - switch (datalevel) { case TSE_POSE_CHANNEL: { @@ -1406,6 +1571,12 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) { /*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/ } + else if (datalevel == TSE_CONSTRAINT) { + WM_operator_name_call(C, "OUTLINER_OT_constraint_operation", WM_OP_INVOKE_REGION_WIN, NULL); + } + else if (datalevel == TSE_MODIFIER) { + WM_operator_name_call(C, "OUTLINER_OT_modifier_operation", WM_OP_INVOKE_REGION_WIN, NULL); + } else { WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL); }