Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / armature / pose_select.c
index 1389b26..75fd952 100644 (file)
 #include "BKE_armature.h"
 #include "BKE_constraint.h"
 #include "BKE_context.h"
-#include "BKE_depsgraph.h"
 #include "BKE_object.h"
 #include "BKE_report.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
 
 #include "RNA_access.h"
 #include "RNA_define.h"
@@ -122,18 +124,21 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
                 * (see rna_Bone_select_update() in rna_armature.c for details)
                 */
                if (arm->flag & ARM_HAS_VIZ_DEPS) {
-                       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+                       DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
                }
 
                /* send necessary notifiers */
                WM_main_add_notifier(NC_GEOM | ND_DATA, ob);
+
+               /* tag armature for copy-on-write update (since act_bone is in armature not object) */
+               DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
        }
 }
 
 /* called from editview.c, for mode-less pose selection */
 /* assumes scene obact and basact is still on old situation */
 bool ED_armature_pose_select_pick_with_buffer(
-        Scene *scene, Base *base, const unsigned int *buffer, short hits,
+        ViewLayer *view_layer, Base *base, const unsigned int *buffer, short hits,
         bool extend, bool deselect, bool toggle, bool do_nearest)
 {
        Object *ob = base->object;
@@ -141,11 +146,15 @@ bool ED_armature_pose_select_pick_with_buffer(
 
        if (!ob || !ob->pose) return 0;
 
-       nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1, do_nearest);
+       Object *ob_act = OBACT(view_layer);
+       Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+
+       /* Callers happen to already get the active base */
+       Base *base_dummy = NULL;
+       nearBone = get_bone_from_selectbuffer(&base, 1, obedit != NULL, buffer, hits, 1, do_nearest, &base_dummy);
 
        /* if the bone cannot be affected, don't do anything */
        if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
-               Object *ob_act = OBACT;
                bArmature *arm = ob->data;
 
                /* since we do unified select, we don't shift+select a bone if the
@@ -163,7 +172,12 @@ bool ED_armature_pose_select_pick_with_buffer(
                }
 
                if (!extend && !deselect && !toggle) {
-                       ED_pose_deselect_all(ob, SEL_DESELECT, true);
+                       {
+                               uint objects_len = 0;
+                               Object **objects = BKE_object_pose_array_get_unique(view_layer, &objects_len);
+                               ED_pose_deselect_all_multi(objects, objects_len, SEL_DESELECT, true);
+                               MEM_freeN(objects);
+                       }
                        nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
                        arm->act_bone = nearBone;
                }
@@ -197,7 +211,7 @@ bool ED_armature_pose_select_pick_with_buffer(
                        if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
                                if (nearBone == arm->act_bone) {
                                        ED_vgroup_select_by_name(ob_act, nearBone->name);
-                                       DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+                                       DEG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
                                }
                        }
                        /* if there are some dependencies for visualizing armature state
@@ -207,8 +221,11 @@ bool ED_armature_pose_select_pick_with_buffer(
                                /* NOTE: ob not ob_act here is intentional - it's the source of the
                                 *       bones being selected  [T37247]
                                 */
-                               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+                               DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
                        }
+
+                       /* tag armature for copy-on-write update (since act_bone is in armature not object) */
+                       DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
                }
        }
 
@@ -249,6 +266,58 @@ void ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibil
        }
 }
 
+static bool ed_pose_is_any_selected(Object *ob, bool ignore_visibility)
+{
+       bArmature *arm = ob->data;
+       for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+               if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
+                       if (pchan->bone->flag & BONE_SELECTED) {
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
+static bool ed_pose_is_any_selected_multi(Object **objects, uint objects_len, bool ignore_visibility)
+{
+       for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+               Object *ob_iter = objects[ob_index];
+               if (ed_pose_is_any_selected(ob_iter, ignore_visibility)) {
+                       return true;
+               }
+       }
+       return false;
+}
+
+void ED_pose_deselect_all_multi(Object **objects, uint objects_len, int select_mode, const bool ignore_visibility)
+{
+       if (select_mode == SEL_TOGGLE) {
+               select_mode = ed_pose_is_any_selected_multi(
+                       objects, objects_len, ignore_visibility) ? SEL_DESELECT : SEL_SELECT;
+       }
+
+       for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+               Object *ob_iter = objects[ob_index];
+               bArmature *arm = ob_iter->data;
+
+               ED_pose_deselect_all(ob_iter, select_mode, ignore_visibility);
+
+               /* if there are some dependencies for visualizing armature state
+                * (e.g. Mask Modifier in 'Armature' mode), force update
+                */
+               if (arm->flag & ARM_HAS_VIZ_DEPS) {
+                       /* NOTE: ob not ob_act here is intentional - it's the source of the
+                        *       bones being selected  [T37247]
+                        */
+                       DEG_id_tag_update(&ob_iter->id, OB_RECALC_DATA);
+               }
+
+               /* need to tag armature for cow updates, or else selection doesn't update */
+               DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+       }
+}
+
 /* ***************** Selections ********************** */
 
 static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
@@ -259,9 +328,6 @@ static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
        if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE))
                return;
 
-       /* XXX old cruft! use notifiers instead */
-       //select_actionchannel_by_name (ob->action, bone->name, !(shift));
-
        if (extend)
                bone->flag &= ~BONE_SELECTED;
        else
@@ -275,18 +341,19 @@ static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
 /* previously known as "selectconnected_posearmature" */
 static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
-       Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-       bArmature *arm = (bArmature *)ob->data;
        Bone *bone, *curBone, *next = NULL;
        const bool extend = RNA_boolean_get(op->ptr, "extend");
 
        view3d_operator_needs_opengl(C);
 
-       bone = get_nearest_bone(C, event->mval, !extend);
+       Base *base = NULL;
+       bone = get_nearest_bone(C, event->mval, !extend, &base);
 
        if (!bone)
                return OPERATOR_CANCELLED;
 
+       bArmature *arm = base->object->data;
+
        /* Select parents */
        for (curBone = bone; curBone; curBone = next) {
                /* ignore bone if cannot be selected */
@@ -307,16 +374,19 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
 
        /* Select children */
        for (curBone = bone->childbase.first; curBone; curBone = next)
-               selectconnected_posebonechildren(ob, curBone, extend);
+               selectconnected_posebonechildren(base->object, curBone, extend);
 
        /* updates */
-       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
 
        if (arm->flag & ARM_HAS_VIZ_DEPS) {
                /* mask modifier ('armature' mode), etc. */
-               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+               DEG_id_tag_update(&base->object->id, OB_RECALC_DATA);
        }
 
+       /* need to tag armature for cow updates, or else selection doesn't update */
+       DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+
        return OPERATOR_FINISHED;
 }
 
@@ -332,7 +402,7 @@ void POSE_OT_select_linked(wmOperatorType *ot)
        ot->idname = "POSE_OT_select_linked";
        ot->description = "Select bones related to selected ones by parent/child relationships";
 
-       /* api callbacks */
+       /* callbacks */
        /* leave 'exec' unset */
        ot->invoke = pose_select_connected_invoke;
        ot->poll = pose_select_linked_poll;
@@ -351,28 +421,34 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
        int action = RNA_enum_get(op->ptr, "action");
 
        Scene *scene = CTX_data_scene(C);
-       Object *ob = ED_object_context(C);
-       bArmature *arm = ob->data;
        int multipaint = scene->toolsettings->multipaint;
 
        if (action == SEL_TOGGLE) {
                action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
        }
 
+       Object *ob_prev = NULL;
+
        /*      Set the flags */
-       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones)
+       CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
        {
+               bArmature *arm = ob->data;
                pose_do_bone_select(pchan, action);
+
+               if (ob_prev != ob) {
+                       /* weightpaint or mask modifiers need depsgraph updates */
+                       if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
+                               DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+                       }
+                       /* need to tag armature for cow updates, or else selection doesn't update */
+                       DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+                       ob_prev = ob;
+               }
        }
        CTX_DATA_END;
 
        WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
 
-       /* weightpaint or mask modifiers need depsgraph updates */
-       if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
-               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-       }
-
        return OPERATOR_FINISHED;
 }
 
@@ -397,33 +473,44 @@ void POSE_OT_select_all(wmOperatorType *ot)
 
 static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op))
 {
-       Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-       bArmature *arm = (bArmature *)ob->data;
-       bPoseChannel *pchan, *parent;
-
-       /* Determine if there is an active bone */
-       pchan = CTX_data_active_pose_bone(C);
-       if (pchan) {
-               parent = pchan->parent;
-               if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
-                       parent->bone->flag |= BONE_SELECTED;
-                       arm->act_bone = parent->bone;
-               }
-               else {
-                       return OPERATOR_CANCELLED;
-               }
-       }
-       else {
-               return OPERATOR_CANCELLED;
-       }
+       /* only clear relevant transforms for selected bones */
+       ViewLayer *view_layer = CTX_data_view_layer(C);
+       FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_POSE, ob_iter)
+       {
+               Object *ob = ob_iter;
+               bArmature *arm = (bArmature *)ob->data;
 
-       /* updates */
-       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+               FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan)
+               {
+                       if (pchan) {
+                               bPoseChannel *parent = pchan->parent;
+                               if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
+                                       parent->bone->flag |= BONE_SELECTED;
+                                       arm->act_bone = parent->bone;
+                               }
+                               else {
+                                       continue;
+                               }
+                       }
+                       else {
+                               continue;
+                       }
 
-       if (arm->flag & ARM_HAS_VIZ_DEPS) {
-               /* mask modifier ('armature' mode), etc. */
-               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+                       /* updates */
+                       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+                       if (arm->flag & ARM_HAS_VIZ_DEPS) {
+                               /* mask modifier ('armature' mode), etc. */
+                               DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+                       }
+
+                       /* tag armature for copy-on-write update (since act_bone is in armature not object) */
+                       DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+
+               }
+               FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
        }
+       FOREACH_OBJECT_IN_MODE_END;
 
        return OPERATOR_FINISHED;
 }
@@ -447,13 +534,13 @@ void POSE_OT_select_parent(wmOperatorType *ot)
 
 static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op))
 {
-       Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-       bArmature *arm = (bArmature *)ob->data;
        bConstraint *con;
        int found = 0;
+       Object *ob_prev = NULL;
 
-       CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+       CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
        {
+               bArmature *arm = ob->data;
                if (pchan->bone->flag & BONE_SELECTED) {
                        for (con = pchan->constraints.first; con; con = con->next) {
                                const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
@@ -469,6 +556,18 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
                                                        if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
                                                                pchanc->bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
                                                                found = 1;
+
+                                                               if (ob != ob_prev) {
+                                                                       /* updates */
+                                                                       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+                                                                       if (arm->flag & ARM_HAS_VIZ_DEPS) {
+                                                                               /* mask modifier ('armature' mode), etc. */
+                                                                               DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+                                                                       }
+                                                                       /* tag armature for copy on write, since selection status is armature data */
+                                                                       DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+                                                                       ob_prev = ob;
+                                                               }
                                                        }
                                                }
                                        }
@@ -484,14 +583,6 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
        if (!found)
                return OPERATOR_CANCELLED;
 
-       /* updates */
-       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
-       if (arm->flag & ARM_HAS_VIZ_DEPS) {
-               /* mask modifier ('armature' mode), etc. */
-               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-       }
-
        return OPERATOR_FINISHED;
 }
 
@@ -583,9 +674,12 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
 
        if (arm->flag & ARM_HAS_VIZ_DEPS) {
                /* mask modifier ('armature' mode), etc. */
-               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+               DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
        }
 
+       /* tag armature for copy-on-write update (since act_bone is in armature not object) */
+       DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+
        return OPERATOR_FINISHED;
 }
 
@@ -828,9 +922,12 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
 
        if (arm->flag & ARM_HAS_VIZ_DEPS) {
                /* mask modifier ('armature' mode), etc. */
-               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+               DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
        }
 
+       /* need to tag armature for cow updates, or else selection doesn't update */
+       DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+
        /* report done status */
        if (changed)
                return OPERATOR_FINISHED;
@@ -873,59 +970,63 @@ void POSE_OT_select_grouped(wmOperatorType *ot)
 static int pose_select_mirror_exec(bContext *C, wmOperator *op)
 {
        Object *ob_act = CTX_data_active_object(C);
-       Object *ob = BKE_object_pose_armature_get(ob_act);
-       bArmature *arm;
-       bPoseChannel *pchan, *pchan_mirror_act = NULL;
-       const bool active_only = RNA_boolean_get(op->ptr, "only_active");
-       const bool extend = RNA_boolean_get(op->ptr, "extend");
+       ViewLayer *view_layer = CTX_data_view_layer(C);
 
-       if ((ob && (ob->mode & OB_MODE_POSE)) == 0) {
-               return OPERATOR_CANCELLED;
-       }
-
-       arm = ob->data;
+       FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, OB_MODE_POSE, ob)
+       {
+               bArmature *arm;
+               bPoseChannel *pchan, *pchan_mirror_act = NULL;
+               const bool active_only = RNA_boolean_get(op->ptr, "only_active");
+               const bool extend = RNA_boolean_get(op->ptr, "extend");
 
-       for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
-               const int flag = (pchan->bone->flag & BONE_SELECTED);
-               PBONE_PREV_FLAG_SET(pchan, flag);
-       }
+               arm = ob->data;
 
-       for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
-               if (PBONE_SELECTABLE(arm, pchan->bone)) {
-                       bPoseChannel *pchan_mirror;
-                       int flag_new = extend ? PBONE_PREV_FLAG_GET(pchan) : 0;
+               for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+                       const int flag = (pchan->bone->flag & BONE_SELECTED);
+                       PBONE_PREV_FLAG_SET(pchan, flag);
+               }
 
-                       if ((pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) &&
-                           (PBONE_VISIBLE(arm, pchan_mirror->bone)))
-                       {
-                               const int flag_mirror = PBONE_PREV_FLAG_GET(pchan_mirror);
-                               flag_new |= flag_mirror;
+               for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+                       if (PBONE_SELECTABLE(arm, pchan->bone)) {
+                               bPoseChannel *pchan_mirror;
+                               int flag_new = extend ? PBONE_PREV_FLAG_GET(pchan) : 0;
+
+                               if ((pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) &&
+                                   (PBONE_VISIBLE(arm, pchan_mirror->bone)))
+                               {
+                                       const int flag_mirror = PBONE_PREV_FLAG_GET(pchan_mirror);
+                                       flag_new |= flag_mirror;
+
+                                       if (pchan->bone == arm->act_bone) {
+                                               pchan_mirror_act = pchan_mirror;
+                                       }
 
-                               if (pchan->bone == arm->act_bone) {
-                                       pchan_mirror_act = pchan_mirror;
+                                       /* skip all but the active or its mirror */
+                                       if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) {
+                                               continue;
+                                       }
                                }
 
-                               /* skip all but the active or its mirror */
-                               if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) {
-                                       continue;
-                               }
+                               pchan->bone->flag = (pchan->bone->flag & ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) | flag_new;
                        }
-
-                       pchan->bone->flag = (pchan->bone->flag & ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) | flag_new;
                }
-       }
 
-       if (pchan_mirror_act) {
-               arm->act_bone = pchan_mirror_act->bone;
+               if (pchan_mirror_act) {
+                       arm->act_bone = pchan_mirror_act->bone;
 
-               /* in weightpaint we select the associated vertex group too */
-               if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
-                       ED_vgroup_select_by_name(ob_act, pchan_mirror_act->name);
-                       DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+                       /* in weightpaint we select the associated vertex group too */
+                       if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
+                               ED_vgroup_select_by_name(ob_act, pchan_mirror_act->name);
+                               DEG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+                       }
                }
-       }
 
-       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+               WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+               /* need to tag armature for cow updates, or else selection doesn't update */
+               DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+       }
+       FOREACH_OBJECT_IN_MODE_END;
 
        return OPERATOR_FINISHED;
 }