Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_view3d/view3d_select.c
| Show First 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | |||||
| #include "ED_object.h" | #include "ED_object.h" | ||||
| #include "ED_outliner.h" | #include "ED_outliner.h" | ||||
| #include "ED_particle.h" | #include "ED_particle.h" | ||||
| #include "ED_screen.h" | #include "ED_screen.h" | ||||
| #include "ED_sculpt.h" | #include "ED_sculpt.h" | ||||
| #include "ED_select_utils.h" | #include "ED_select_utils.h" | ||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "UI_resources.h" | |||||
| #include "GPU_matrix.h" | #include "GPU_matrix.h" | ||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| #include "DRW_engine.h" | #include "DRW_engine.h" | ||||
| #include "DRW_select_buffer.h" | #include "DRW_select_buffer.h" | ||||
| ▲ Show 20 Lines • Show All 1,320 Lines • ▼ Show 20 Lines | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Cursor Picking | /** \name Cursor Picking | ||||
| * \{ */ | * \{ */ | ||||
| /* The max number of menu items in an object select menu */ | /* The max number of menu items in an object select menu */ | ||||
| typedef struct SelMenuItemF { | typedef struct SelMenuItemF { | ||||
| char idname[MAX_ID_NAME - 2]; | char idname[MAX_ID_NAME - 2]; | ||||
| int icon; | int icon; | ||||
| Base *base_ptr; | |||||
| void *item_ptr; | |||||
| } SelMenuItemF; | } SelMenuItemF; | ||||
| #define SEL_MENU_SIZE 22 | #define SEL_MENU_SIZE 22 | ||||
| static SelMenuItemF object_mouse_select_menu_data[SEL_MENU_SIZE]; | static SelMenuItemF object_mouse_select_menu_data[SEL_MENU_SIZE]; | ||||
| /* special (crappy) operator only for menu select */ | /* special (crappy) operator only for menu select */ | ||||
| static const EnumPropertyItem *object_select_menu_enum_itemf(bContext *C, | static const EnumPropertyItem *object_select_menu_enum_itemf(bContext *C, | ||||
| PointerRNA *UNUSED(ptr), | PointerRNA *UNUSED(ptr), | ||||
| ▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Lines | static Base *object_mouse_select_menu(bContext *C, | ||||
| int hits, | int hits, | ||||
| const int mval[2], | const int mval[2], | ||||
| bool extend, | bool extend, | ||||
| bool deselect, | bool deselect, | ||||
| bool toggle) | bool toggle) | ||||
| { | { | ||||
| short baseCount = 0; | short baseCount = 0; | ||||
| bool ok; | bool ok; | ||||
| LinkNode *linklist = NULL; | LinkNodePair linklist = {NULL, NULL}; | ||||
| /* handle base->object->select_id */ | /* handle base->object->select_id */ | ||||
| CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { | CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { | ||||
| ok = false; | ok = false; | ||||
| /* two selection methods, the CTRL select uses max dist of 15 */ | /* two selection methods, the CTRL select uses max dist of 15 */ | ||||
| if (buffer) { | if (buffer) { | ||||
| for (int a = 0; a < hits; a++) { | for (int a = 0; a < hits; a++) { | ||||
| Show All 11 Lines | else { | ||||
| if (len_manhattan_v2_int(delta_px) < dist) { | if (len_manhattan_v2_int(delta_px) < dist) { | ||||
| ok = true; | ok = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (ok) { | if (ok) { | ||||
| baseCount++; | baseCount++; | ||||
| BLI_linklist_prepend(&linklist, base); | BLI_linklist_append(&linklist, base); | ||||
| if (baseCount == SEL_MENU_SIZE) { | if (baseCount == SEL_MENU_SIZE) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| if (baseCount == 0) { | if (baseCount == 0) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| if (baseCount == 1) { | if (baseCount == 1) { | ||||
| Base *base = (Base *)linklist->link; | Base *base = (Base *)linklist.list->link; | ||||
| BLI_linklist_free(linklist, NULL); | BLI_linklist_free(linklist.list, NULL); | ||||
| return base; | return base; | ||||
| } | } | ||||
| /* UI, full in static array values that we later use in an enum function */ | /* UI, full in static array values that we later use in an enum function */ | ||||
| LinkNode *node; | LinkNode *node; | ||||
| int i; | int i; | ||||
| memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data)); | 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; | Base *base = node->link; | ||||
| Object *ob = base->object; | Object *ob = base->object; | ||||
| const char *name = ob->id.name + 2; | const char *name = ob->id.name + 2; | ||||
| BLI_strncpy(object_mouse_select_menu_data[i].idname, name, MAX_ID_NAME - 2); | BLI_strncpy(object_mouse_select_menu_data[i].idname, name, MAX_ID_NAME - 2); | ||||
| object_mouse_select_menu_data[i].icon = UI_icon_from_id(&ob->id); | object_mouse_select_menu_data[i].icon = UI_icon_from_id(&ob->id); | ||||
| } | } | ||||
| wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_select_menu", false); | wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_select_menu", false); | ||||
| PointerRNA ptr; | PointerRNA ptr; | ||||
| WM_operator_properties_create_ptr(&ptr, ot); | WM_operator_properties_create_ptr(&ptr, ot); | ||||
| RNA_boolean_set(&ptr, "extend", extend); | RNA_boolean_set(&ptr, "extend", extend); | ||||
| RNA_boolean_set(&ptr, "deselect", deselect); | RNA_boolean_set(&ptr, "deselect", deselect); | ||||
| RNA_boolean_set(&ptr, "toggle", toggle); | RNA_boolean_set(&ptr, "toggle", toggle); | ||||
| WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); | WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); | ||||
| WM_operator_properties_free(&ptr); | WM_operator_properties_free(&ptr); | ||||
| BLI_linklist_free(linklist, NULL); | BLI_linklist_free(linklist.list, NULL); | ||||
| return 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) | static bool selectbuffer_has_bones(const uint *buffer, const uint hits) | ||||
| { | { | ||||
| for (uint i = 0; i < hits; i++) { | for (uint i = 0; i < hits; i++) { | ||||
| if (buffer[(4 * i) + 3] & 0xFFFF0000) { | if (buffer[(4 * i) + 3] & 0xFFFF0000) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| ▲ Show 20 Lines • Show All 442 Lines • ▼ Show 20 Lines | else { | ||||
| // TIMEIT_END(select_time); | // TIMEIT_END(select_time); | ||||
| if (hits > 0) { | if (hits > 0) { | ||||
| /* note: bundles are handling in the same way as bones */ | /* note: bundles are handling in the same way as bones */ | ||||
| const bool has_bones = object ? false : selectbuffer_has_bones(buffer, hits); | const bool has_bones = object ? false : selectbuffer_has_bones(buffer, hits); | ||||
| /* note; shift+alt goes to group-flush-selecting */ | /* note; shift+alt goes to group-flush-selecting */ | ||||
| if (enumerate) { | if (enumerate) { | ||||
| 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); | basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, extend, deselect, toggle); | ||||
| } | } | ||||
| } | |||||
| else { | else { | ||||
| basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest); | basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest); | ||||
| } | } | ||||
| if (has_bones && basact) { | if (has_bones && basact) { | ||||
| if (basact->object->type == OB_CAMERA) { | if (basact->object->type == OB_CAMERA) { | ||||
| MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false); | MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false); | ||||
| if (clip != NULL && oldbasact == basact) { | if (clip != NULL && oldbasact == basact) { | ||||
| ▲ Show 20 Lines • Show All 279 Lines • ▼ Show 20 Lines | static int view3d_select_exec(bContext *C, wmOperator *op) | ||||
| if (obedit && object == false) { | if (obedit && object == false) { | ||||
| if (obedit->type == OB_MESH) { | if (obedit->type == OB_MESH) { | ||||
| retval = EDBM_select_pick(C, location, extend, deselect, toggle); | retval = EDBM_select_pick(C, location, extend, deselect, toggle); | ||||
| if (!retval && deselect_all) { | if (!retval && deselect_all) { | ||||
| retval = EDBM_mesh_deselect_all_multi(C); | retval = EDBM_mesh_deselect_all_multi(C); | ||||
| } | } | ||||
| } | } | ||||
| else if (obedit->type == OB_ARMATURE) { | else if (obedit->type == OB_ARMATURE) { | ||||
| 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); | retval = ED_armature_edit_select_pick(C, location, extend, deselect, toggle); | ||||
| } | |||||
| if (!retval && deselect_all) { | if (!retval && deselect_all) { | ||||
| retval = ED_armature_edit_deselect_all_visible_multi(C); | retval = ED_armature_edit_deselect_all_visible_multi(C); | ||||
| } | } | ||||
| if (retval) { | if (retval) { | ||||
| ED_outliner_select_sync_from_edit_bone_tag(C); | ED_outliner_select_sync_from_edit_bone_tag(C); | ||||
| } | } | ||||
| } | } | ||||
| else if (obedit->type == OB_LATTICE) { | else if (obedit->type == OB_LATTICE) { | ||||
| ▲ Show 20 Lines • Show All 1,753 Lines • Show Last 20 Lines | |||||