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
path: root/source
diff options
context:
space:
mode:
authorSebastian Parborg <darkdefende@gmail.com>2021-04-08 18:21:01 +0300
committerSebastian Parborg <darkdefende@gmail.com>2021-04-08 18:26:33 +0300
commit5e77ff79ccdaffb2df4d54c97f17359c017c9b85 (patch)
tree187207537fe318dd45cfbf7a42ab7be513536dbf /source
parent5c4d24e1fd752a8a89d44d05e8e3f9b31f2d7db0 (diff)
Add ability to get a selection list of bones
This adds the ability to get a selection list for both edit mode bones and pose mode bones. To do this the selection menu list logic had to be reworked a bit. Before it only stored the names of objects. This might work will of objects, however as stated in the code, it might fail for linked objects (so multiple object can have the same name in some corner cases). For bones it is a very common occurance where you can have multiple armature that has the same bone names. So now it also stores the object and bone pointers for this case. Reviewed By: Sybren Differential Revision: http://developer.blender.org/D10570 Fix T85796
Diffstat (limited to 'source')
-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);
}