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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/editors/armature/armature_select.c204
-rw-r--r--source/blender/editors/armature/pose_select.c186
-rw-r--r--source/blender/editors/include/ED_armature.h14
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h1
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c259
6 files changed, 477 insertions, 188 deletions
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 226253cc063..9b598872d8b 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -961,131 +961,145 @@ bool ED_armature_edit_deselect_all_visible_multi(bContext *C)
/** \name Select Cursor Pick API
* \{ */
-/* context: editmode armature in view3d */
-bool ED_armature_edit_select_pick(
- bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+bool ED_armature_edit_select_pick_bone(bContext *C,
+ Base *basact,
+ EditBone *ebone,
+ const int selmask,
+ const bool extend,
+ const bool deselect,
+ const bool toggle)
{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ViewContext vc;
- EditBone *nearBone = NULL;
- int selmask;
- Base *basact = NULL;
+ if (!ebone) {
+ return false;
+ }
- ED_view3d_viewcontext_init(C, &vc, depsgraph);
- vc.mval[0] = mval[0];
- vc.mval[1] = mval[1];
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
- nearBone = get_nearest_editbonepoint(&vc, true, true, &basact, &selmask);
- if (nearBone) {
- ED_view3d_viewcontext_init_object(&vc, basact->object);
- bArmature *arm = vc.obedit->data;
+ BLI_assert(BKE_object_is_in_editmode(basact->object));
+ bArmature *arm = basact->object->data;
- if (!EBONE_SELECTABLE(arm, nearBone)) {
- return false;
- }
+ if (!EBONE_SELECTABLE(arm, ebone)) {
+ return false;
+ }
- if (!extend && !deselect && !toggle) {
- uint bases_len = 0;
- Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
- vc.view_layer, vc.v3d, &bases_len);
- ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
- MEM_freeN(bases);
- }
+ if (!extend && !deselect && !toggle) {
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
+ view_layer, v3d, &bases_len);
+ ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
+ MEM_freeN(bases);
+ }
- /* by definition the non-root connected bones have no root point drawn,
- * so a root selection needs to be delivered to the parent tip */
+ /* By definition the non-root connected bones have no root point drawn,
+ * so a root selection needs to be delivered to the parent tip. */
- if (selmask & BONE_SELECTED) {
- if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) {
- /* click in a chain */
- if (extend) {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
- }
- else if (deselect) {
- /* deselect this bone */
- nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
- /* only deselect parent tip if it is not selected */
- if (!(nearBone->parent->flag & BONE_SELECTED)) {
- nearBone->parent->flag &= ~BONE_TIPSEL;
- }
+ if (selmask & BONE_SELECTED) {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ /* Bone is in a chain. */
+ if (extend) {
+ /* Select this bone. */
+ ebone->flag |= BONE_TIPSEL;
+ ebone->parent->flag |= BONE_TIPSEL;
+ }
+ else if (deselect) {
+ /* Deselect this bone. */
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
+ /* Only deselect parent tip if it is not selected. */
+ if (!(ebone->parent->flag & BONE_SELECTED)) {
+ ebone->parent->flag &= ~BONE_TIPSEL;
}
- else if (toggle) {
- /* hold shift inverts this bone's selection */
- if (nearBone->flag & BONE_SELECTED) {
- /* deselect this bone */
- nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
- /* only deselect parent tip if it is not selected */
- if (!(nearBone->parent->flag & BONE_SELECTED)) {
- nearBone->parent->flag &= ~BONE_TIPSEL;
- }
- }
- else {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
+ }
+ else if (toggle) {
+ /* Toggle inverts this bone's selection. */
+ if (ebone->flag & BONE_SELECTED) {
+ /* Deselect this bone. */
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
+ /* Only deselect parent tip if it is not selected. */
+ if (!(ebone->parent->flag & BONE_SELECTED)) {
+ ebone->parent->flag &= ~BONE_TIPSEL;
}
}
else {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
+ /* Select this bone. */
+ ebone->flag |= BONE_TIPSEL;
+ ebone->parent->flag |= BONE_TIPSEL;
}
}
else {
- if (extend) {
- nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (deselect) {
- nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (toggle) {
- /* hold shift inverts this bone's selection */
- if (nearBone->flag & BONE_SELECTED) {
- nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
- else {
- nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
+ /* Select this bone. */
+ ebone->flag |= BONE_TIPSEL;
+ ebone->parent->flag |= BONE_TIPSEL;
}
}
else {
if (extend) {
- nearBone->flag |= selmask;
+ ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
}
else if (deselect) {
- nearBone->flag &= ~selmask;
+ ebone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
}
- else if (toggle && (nearBone->flag & selmask)) {
- nearBone->flag &= ~selmask;
+ else if (toggle) {
+ /* Toggle inverts this bone's selection. */
+ if (ebone->flag & BONE_SELECTED) {
+ ebone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ }
}
else {
- nearBone->flag |= selmask;
+ ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
}
}
-
- ED_armature_edit_sync_selection(arm->edbo);
-
- /* then now check for active status */
- if (ED_armature_ebone_selectflag_get(nearBone)) {
- arm->act_edbone = nearBone;
+ }
+ else {
+ if (extend) {
+ ebone->flag |= selmask;
}
-
- if (vc.view_layer->basact != basact) {
- ED_object_base_activate(C, basact);
+ else if (deselect) {
+ ebone->flag &= ~selmask;
+ }
+ else if (toggle && (ebone->flag & selmask)) {
+ ebone->flag &= ~selmask;
}
+ else {
+ ebone->flag |= selmask;
+ }
+ }
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
- return true;
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ /* Then now check for active status. */
+ if (ED_armature_ebone_selectflag_get(ebone)) {
+ arm->act_edbone = ebone;
+ }
+
+ if (view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
}
- return false;
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ return true;
+}
+
+/* context: editmode armature in view3d */
+bool ED_armature_edit_select_pick(
+ bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ViewContext vc;
+ EditBone *nearBone = NULL;
+ int selmask;
+ Base *basact = NULL;
+
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
+ vc.mval[0] = mval[0];
+ vc.mval[1] = mval[1];
+
+ nearBone = get_nearest_editbonepoint(&vc, true, true, &basact, &selmask);
+ return ED_armature_edit_select_pick_bone(C, basact, nearBone, selmask, extend, deselect, toggle);
}
/** \} */
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index a3f97000509..0b0f1925746 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -138,6 +138,106 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
}
}
+void ED_armature_pose_select_pick_bone(ViewLayer *view_layer,
+ View3D *v3d,
+ Object *ob,
+ Bone *bone,
+ const bool extend,
+ const bool deselect,
+ const bool toggle)
+{
+ if (!ob || !ob->pose) {
+ return;
+ }
+
+ Object *ob_act = OBACT(view_layer);
+ BLI_assert(OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL);
+
+ /* If the bone cannot be affected, don't do anything. */
+ if (bone == NULL || (bone->flag & BONE_UNSELECTABLE)) {
+ return;
+ }
+ bArmature *arm = ob->data;
+
+ /* Since we do unified select, we don't shift+select a bone if the
+ * armature object was not active yet.
+ * Note, special exception for armature mode so we can do multi-select
+ * we could check for multi-select explicitly but think its fine to
+ * always give predictable behavior in weight paint mode - campbell */
+ if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) == 0)) {
+ /* When we are entering into posemode via toggle-select,
+ * from another active object - always select the bone. */
+ if (!extend && !deselect && toggle) {
+ /* Re-select the bone again later in this function. */
+ bone->flag &= ~BONE_SELECTED;
+ }
+ }
+
+ if (!extend && !deselect && !toggle) {
+ {
+ /* Don't use 'BKE_object_pose_base_array_get_unique'
+ * because we may be selecting from object mode. */
+ FOREACH_VISIBLE_BASE_BEGIN (view_layer, v3d, base_iter) {
+ Object *ob_iter = base_iter->object;
+ if ((ob_iter->type == OB_ARMATURE) && (ob_iter->mode & OB_MODE_POSE)) {
+ if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, true)) {
+ ED_pose_bone_select_tag_update(ob_iter);
+ }
+ }
+ }
+ FOREACH_VISIBLE_BASE_END;
+ }
+ bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = bone;
+ }
+ else {
+ if (extend) {
+ bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = bone;
+ }
+ else if (deselect) {
+ bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (toggle) {
+ if (bone->flag & BONE_SELECTED) {
+ /* If not active, we make it active. */
+ if (bone != arm->act_bone) {
+ arm->act_bone = bone;
+ }
+ else {
+ bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ else {
+ bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = bone;
+ }
+ }
+ }
+
+ if (ob_act) {
+ /* In weightpaint we select the associated vertex group too. */
+ if (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) {
+ if (bone == arm->act_bone) {
+ ED_vgroup_select_by_name(ob_act, bone->name);
+ DEG_id_tag_update(&ob_act->id, ID_RECALC_GEOMETRY);
+ }
+ }
+ /* If there are some dependencies for visualizing armature state
+ * (e.g. Mask Modifier in 'Armature' mode), force update.
+ */
+ else 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->id, ID_RECALC_GEOMETRY);
+ }
+
+ /* Tag armature for copy-on-write update (since act_bone is in armature not object). */
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ }
+}
+
/**
* Called for mode-less pose selection.
* assumes the active object is still on old situation.
@@ -159,96 +259,12 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
return 0;
}
- Object *ob_act = OBACT(view_layer);
- BLI_assert(OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL);
-
/* Callers happen to already get the active base */
Base *base_dummy = NULL;
nearBone = ED_armature_pick_bone_from_selectbuffer(
&base, 1, buffer, hits, 1, do_nearest, &base_dummy);
- /* if the bone cannot be affected, don't do anything */
- if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
- bArmature *arm = ob->data;
-
- /* since we do unified select, we don't shift+select a bone if the
- * armature object was not active yet.
- * note, special exception for armature mode so we can do multi-select
- * we could check for multi-select explicitly but think its fine to
- * always give predictable behavior in weight paint mode - campbell */
- if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) == 0)) {
- /* when we are entering into posemode via toggle-select,
- * from another active object - always select the bone. */
- if (!extend && !deselect && toggle) {
- /* re-select below */
- nearBone->flag &= ~BONE_SELECTED;
- }
- }
-
- if (!extend && !deselect && !toggle) {
- {
- /* Don't use 'BKE_object_pose_base_array_get_unique'
- * because we may be selecting from object mode. */
- FOREACH_VISIBLE_BASE_BEGIN (view_layer, v3d, base_iter) {
- Object *ob_iter = base_iter->object;
- if ((ob_iter->type == OB_ARMATURE) && (ob_iter->mode & OB_MODE_POSE)) {
- if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, true)) {
- ED_pose_bone_select_tag_update(ob_iter);
- }
- }
- }
- FOREACH_VISIBLE_BASE_END;
- }
- nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = nearBone;
- }
- else {
- if (extend) {
- nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = nearBone;
- }
- else if (deselect) {
- nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (toggle) {
- if (nearBone->flag & BONE_SELECTED) {
- /* if not active, we make it active */
- if (nearBone != arm->act_bone) {
- arm->act_bone = nearBone;
- }
- else {
- nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
- else {
- nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = nearBone;
- }
- }
- }
-
- if (ob_act) {
- /* in weightpaint we select the associated vertex group too */
- if (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) {
- if (nearBone == arm->act_bone) {
- ED_vgroup_select_by_name(ob_act, nearBone->name);
- DEG_id_tag_update(&ob_act->id, ID_RECALC_GEOMETRY);
- }
- }
- /* if there are some dependencies for visualizing armature state
- * (e.g. Mask Modifier in 'Armature' mode), force update
- */
- else 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->id, ID_RECALC_GEOMETRY);
- }
-
- /* tag armature for copy-on-write update (since act_bone is in armature not object) */
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
+ ED_armature_pose_select_pick_bone(view_layer, v3d, ob, nearBone, extend, deselect, toggle);
return nearBone != NULL;
}
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 0c4576096fb..85563b76f38 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -125,6 +125,13 @@ bool ED_armature_edit_deselect_all_visible(struct Object *obedit);
bool ED_armature_edit_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint bases_len);
bool ED_armature_edit_deselect_all_visible_multi(struct bContext *C);
+bool ED_armature_edit_select_pick_bone(struct bContext *C,
+ struct Base *basact,
+ struct EditBone *ebone,
+ int selmask,
+ bool extend,
+ bool deselect,
+ bool toggle);
bool ED_armature_edit_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, const int sel_op);
@@ -201,6 +208,13 @@ void ED_pose_recalculate_paths(struct bContext *C,
ePosePathCalcRange range);
/* pose_select.c */
+void ED_armature_pose_select_pick_bone(struct ViewLayer *view_layer,
+ struct View3D *v3d,
+ struct Object *ob,
+ struct Bone *bone,
+ bool extend,
+ bool deselect,
+ bool toggle);
bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer,
struct View3D *v3d,
struct Base *base,
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index e766ae96c2f..6f07cb8b44d 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -146,6 +146,7 @@ void VIEW3D_OT_select_circle(struct wmOperatorType *ot);
void VIEW3D_OT_select_box(struct wmOperatorType *ot);
void VIEW3D_OT_select_lasso(struct wmOperatorType *ot);
void VIEW3D_OT_select_menu(struct wmOperatorType *ot);
+void VIEW3D_OT_bone_select_menu(struct wmOperatorType *ot);
/* view3d_view.c */
void VIEW3D_OT_smoothview(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 344168e895b..56dedbbdbb2 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -187,6 +187,7 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_cursor3d);
WM_operatortype_append(VIEW3D_OT_select_lasso);
WM_operatortype_append(VIEW3D_OT_select_menu);
+ WM_operatortype_append(VIEW3D_OT_bone_select_menu);
WM_operatortype_append(VIEW3D_OT_camera_to_view);
WM_operatortype_append(VIEW3D_OT_camera_to_view_selected);
WM_operatortype_append(VIEW3D_OT_object_as_camera);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 3166b818d3c..757ed13ac28 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -96,6 +96,7 @@
#include "ED_select_utils.h"
#include "UI_interface.h"
+#include "UI_resources.h"
#include "GPU_matrix.h"
@@ -1432,6 +1433,8 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot)
typedef struct SelMenuItemF {
char idname[MAX_ID_NAME - 2];
int icon;
+ Base *base_ptr;
+ void *item_ptr;
} SelMenuItemF;
#define SEL_MENU_SIZE 22
@@ -1580,7 +1583,7 @@ static Base *object_mouse_select_menu(bContext *C,
{
short baseCount = 0;
bool ok;
- LinkNode *linklist = NULL;
+ LinkNodePair linklist = {NULL, NULL};
/* handle base->object->select_id */
CTX_DATA_BEGIN (C, Base *, base, selectable_bases) {
@@ -1608,7 +1611,7 @@ static Base *object_mouse_select_menu(bContext *C,
if (ok) {
baseCount++;
- BLI_linklist_prepend(&linklist, base);
+ BLI_linklist_append(&linklist, base);
if (baseCount == SEL_MENU_SIZE) {
break;
@@ -1621,8 +1624,8 @@ static Base *object_mouse_select_menu(bContext *C,
return NULL;
}
if (baseCount == 1) {
- Base *base = (Base *)linklist->link;
- BLI_linklist_free(linklist, NULL);
+ Base *base = (Base *)linklist.list->link;
+ BLI_linklist_free(linklist.list, NULL);
return base;
}
@@ -1632,7 +1635,7 @@ static Base *object_mouse_select_menu(bContext *C,
memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data));
- for (node = linklist, i = 0; node; node = node->next, i++) {
+ for (node = linklist.list, i = 0; node; node = node->next, i++) {
Base *base = node->link;
Object *ob = base->object;
const char *name = ob->id.name + 2;
@@ -1651,10 +1654,231 @@ static Base *object_mouse_select_menu(bContext *C,
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
WM_operator_properties_free(&ptr);
- BLI_linklist_free(linklist, NULL);
+ BLI_linklist_free(linklist.list, NULL);
return NULL;
}
+static int bone_select_menu_exec(bContext *C, wmOperator *op)
+{
+ const int name_index = RNA_enum_get(op->ptr, "name");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool deselect = RNA_boolean_get(op->ptr, "deselect");
+ const bool toggle = RNA_boolean_get(op->ptr, "toggle");
+
+ View3D *v3d = CTX_wm_view3d(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const Base *oldbasact = BASACT(view_layer);
+
+ Base *basact = object_mouse_select_menu_data[name_index].base_ptr;
+
+ if (basact == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_assert(BASE_SELECTABLE(v3d, basact));
+
+ if (basact->object->mode == OB_MODE_EDIT) {
+ EditBone *ebone = (EditBone *)object_mouse_select_menu_data[name_index].item_ptr;
+ ED_armature_edit_select_pick_bone(C, basact, ebone, BONE_SELECTED, extend, deselect, toggle);
+ }
+ else {
+ bPoseChannel *pchan = (bPoseChannel *)object_mouse_select_menu_data[name_index].item_ptr;
+ ED_armature_pose_select_pick_bone(
+ view_layer, v3d, basact->object, pchan->bone, extend, deselect, toggle);
+ }
+
+ /* Weak but ensures we activate the menu again before using the enum. */
+ memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data));
+
+ /* We make the armature selected:
+ * Not-selected active object in posemode won't work well for tools. */
+ ED_object_base_select(basact, BA_SELECT);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object);
+
+ /* In weight-paint, we use selected bone to select vertex-group,
+ * so don't switch to new active object. */
+ if (oldbasact && (oldbasact->object->mode & OB_MODE_ALL_WEIGHT_PAINT)) {
+ /* Prevent activating.
+ * Selection causes this to be considered the 'active' pose in weight-paint mode.
+ * Eventually this limitation may be removed.
+ * For now, de-select all other pose objects deforming this mesh. */
+ ED_armature_pose_select_in_wpaint_mode(view_layer, basact);
+
+ basact = NULL;
+ }
+
+ /* Undo? */
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+
+ ED_outliner_select_sync_from_object_tag(C);
+
+ return OPERATOR_FINISHED;
+}
+
+void VIEW3D_OT_bone_select_menu(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select Menu";
+ ot->description = "Menu bone selection";
+ ot->idname = "VIEW3D_OT_bone_select_menu";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = bone_select_menu_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* keyingset to use (dynamic enum) */
+ prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Bone Name", "");
+ RNA_def_enum_funcs(prop, object_select_menu_enum_itemf);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
+
+ RNA_def_boolean(ot->srna, "extend", 0, "Extend", "");
+ RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
+ RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
+}
+static bool bone_mouse_select_menu(bContext *C,
+ const uint *buffer,
+ const int hits,
+ const bool is_editmode,
+ const bool extend,
+ const bool deselect,
+ const bool toggle)
+{
+ BLI_assert(buffer);
+
+ short baseCount = 0;
+ LinkNodePair base_list = {NULL, NULL};
+ LinkNodePair bone_list = {NULL, NULL};
+ GSet *added_bones = BLI_gset_ptr_new("Bone mouse select menu");
+
+ /* Select logic taken from ed_armature_pick_bone_from_selectbuffer_impl in armature_select.c */
+ for (int a = 0; a < hits; a++) {
+ void *bone_ptr = NULL;
+ Base *bone_base = NULL;
+ uint hitresult = buffer[3 + (a * 4)];
+
+ if (!(hitresult & BONESEL_ANY)) {
+ /* To avoid including objects in selection. */
+ continue;
+ }
+
+ hitresult &= ~BONESEL_ANY;
+ const uint hit_object = hitresult & 0xFFFF;
+
+ /* Find the hit bone base (armature object). */
+ CTX_DATA_BEGIN (C, Base *, base, selectable_bases) {
+ if (base->object->runtime.select_id == hit_object) {
+ bone_base = base;
+ break;
+ }
+ }
+ CTX_DATA_END;
+
+ if (!bone_base) {
+ continue;
+ }
+
+ /* Determine what the current bone is */
+ if (is_editmode) {
+ EditBone *ebone;
+ const uint hit_bone = (hitresult & ~BONESEL_ANY) >> 16;
+ bArmature *arm = bone_base->object->data;
+ ebone = BLI_findlink(arm->edbo, hit_bone);
+ if (ebone && !(ebone->flag & BONE_UNSELECTABLE)) {
+ bone_ptr = ebone;
+ }
+ }
+ else {
+ bPoseChannel *pchan;
+ const uint hit_bone = (hitresult & ~BONESEL_ANY) >> 16;
+ pchan = BLI_findlink(&bone_base->object->pose->chanbase, hit_bone);
+ if (pchan && !(pchan->bone->flag & BONE_UNSELECTABLE)) {
+ bone_ptr = pchan;
+ }
+ }
+
+ if (!bone_ptr) {
+ continue;
+ }
+ /* We can hit a bone multiple times, so make sure we are not adding an already included bone
+ * to the list.*/
+ const bool is_duplicate_bone = BLI_gset_haskey(added_bones, bone_ptr);
+
+ if (!is_duplicate_bone) {
+ baseCount++;
+ BLI_linklist_append(&base_list, bone_base);
+ BLI_linklist_append(&bone_list, bone_ptr);
+ BLI_gset_insert(added_bones, bone_ptr);
+
+ if (baseCount == SEL_MENU_SIZE) {
+ break;
+ }
+ }
+ }
+
+ BLI_gset_free(added_bones, NULL);
+
+ if (baseCount == 0) {
+ return false;
+ }
+ if (baseCount == 1) {
+ BLI_linklist_free(base_list.list, NULL);
+ BLI_linklist_free(bone_list.list, NULL);
+ return false;
+ }
+
+ /* UI, full in static array values that we later use in an enum function */
+ LinkNode *bone_node, *base_node;
+ int i;
+
+ memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data));
+
+ for (base_node = base_list.list, bone_node = bone_list.list, i = 0; bone_node;
+ base_node = base_node->next, bone_node = bone_node->next, i++) {
+ char *name;
+
+ object_mouse_select_menu_data[i].base_ptr = base_node->link;
+
+ if (is_editmode) {
+ EditBone *ebone = bone_node->link;
+ object_mouse_select_menu_data[i].item_ptr = ebone;
+ name = ebone->name;
+ }
+ else {
+ bPoseChannel *pchan = bone_node->link;
+ object_mouse_select_menu_data[i].item_ptr = pchan;
+ name = pchan->name;
+ }
+
+ BLI_strncpy(object_mouse_select_menu_data[i].idname, name, MAX_ID_NAME - 2);
+ object_mouse_select_menu_data[i].icon = ICON_BONE_DATA;
+ }
+
+ wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_bone_select_menu", false);
+ PointerRNA ptr;
+
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_boolean_set(&ptr, "extend", extend);
+ RNA_boolean_set(&ptr, "deselect", deselect);
+ RNA_boolean_set(&ptr, "toggle", toggle);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_properties_free(&ptr);
+
+ BLI_linklist_free(base_list.list, NULL);
+ BLI_linklist_free(bone_list.list, NULL);
+ return true;
+}
+
static bool selectbuffer_has_bones(const uint *buffer, const uint hits)
{
for (uint i = 0; i < hits; i++) {
@@ -2113,7 +2337,13 @@ static bool ed_object_select_pick(bContext *C,
/* note; shift+alt goes to group-flush-selecting */
if (enumerate) {
- basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, extend, deselect, toggle);
+ if (has_bones &&
+ bone_mouse_select_menu(C, buffer, hits, false, extend, deselect, toggle)) {
+ basact = NULL;
+ }
+ else {
+ basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, extend, deselect, toggle);
+ }
}
else {
basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest);
@@ -2410,7 +2640,20 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
}
}
else if (obedit->type == OB_ARMATURE) {
- retval = ED_armature_edit_select_pick(C, location, extend, deselect, toggle);
+ if (enumerate) {
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
+
+ uint buffer[MAXPICKBUF];
+ const int hits = mixed_bones_object_selectbuffer(
+ &vc, buffer, location, VIEW3D_SELECT_FILTER_NOP, false, true);
+ retval = bone_mouse_select_menu(C, buffer, hits, true, extend, deselect, toggle);
+ }
+ if (!retval) {
+ retval = ED_armature_edit_select_pick(C, location, extend, deselect, toggle);
+ }
+
if (!retval && deselect_all) {
retval = ED_armature_edit_deselect_all_visible_multi(C);
}