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:
Diffstat (limited to 'source/blender/editors/space_view3d/view3d_select.c')
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c259
1 files changed, 251 insertions, 8 deletions
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);
}