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:
authorAlexander Gavrilov <angavrilov@gmail.com>2018-11-20 09:34:56 +0300
committerCampbell Barton <ideasman42@gmail.com>2018-11-20 09:38:35 +0300
commitd227c58e3ec2020683d9b7e8280f5e48350fd1fd (patch)
tree8531da3080fce08e69fe4a492a85420c305c2fe2 /source/blender/editors/object/object_select.c
parent93f82698e759bb7b4aa999173433d2053cf99606 (diff)
UI: support jumping to target object/bone
Complex rigs are built from many bones (often overlapping) connected by constraints. When investigating or debugging such rigs one often wants to switch to the target of a constraint, or a parent bone, but it is difficult to do manually due to overlap confusion. This adds a right click menu option that automatically selects and makes the target object or bone active for UI fields where a suitable reference is readily available.
Diffstat (limited to 'source/blender/editors/object/object_select.c')
-rw-r--r--source/blender/editors/object/object_select.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index c4c86c0bd72..8a82fb2bf06 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -51,6 +51,8 @@
#include "BLT_translation.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_deform.h"
@@ -70,6 +72,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_armature.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
@@ -159,6 +162,165 @@ void ED_object_base_activate(bContext *C, Base *base)
DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_SELECT_UPDATE);
}
+/********************** Jump To Object Utilities **********************/
+
+static int get_base_select_priority(Base *base)
+{
+ if (base->flag & BASE_VISIBLE) {
+ if (base->flag & BASE_SELECTABLE) {
+ return 3;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+}
+
+/**
+ * If id is not already an Object, try to find an object that uses it as data.
+ * Prefers active, then selected, then visible/selectable.
+ */
+Base *ED_object_find_first_by_data_id(ViewLayer *view_layer, ID *id)
+{
+ BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
+
+ /* Try active object. */
+ Base *basact = view_layer->basact;
+
+ if (basact && basact->object && basact->object->data == id) {
+ return basact;
+ }
+
+ /* Try all objects. */
+ Base *base_best = NULL;
+ int priority_best = 0;
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object && base->object->data == id) {
+ if (base->flag & BASE_SELECTED) {
+ return base;
+ }
+ else {
+ int priority_test = get_base_select_priority(base);
+
+ if (priority_test > priority_best) {
+ priority_best = priority_test;
+ base_best = base;
+ }
+ }
+ }
+ }
+
+ return base_best;
+}
+
+/**
+ * Select and make the target object active in the view layer.
+ * If already selected, selection isn't changed.
+ *
+ * \returns false if not found in current view layer
+ */
+bool ED_object_jump_to_object(bContext *C, Object *ob)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (base == NULL) {
+ return false;
+ }
+
+ if (view_layer->basact != base) {
+ /* Select if not selected. */
+ if (!(base->flag & BASE_SELECTED)) {
+ ED_object_base_deselect_all_visible(view_layer);
+
+ if (base->flag & BASE_VISIBLE) {
+ ED_object_base_select(base, BA_SELECT);
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
+ }
+
+ /* Make active if not active. */
+ ED_object_base_activate(C, base);
+ }
+
+ return true;
+}
+
+/**
+ * Select and make the target object and bone active.
+ * Switches to Pose mode if in Object mode so the selection is visible.
+ *
+ * \returns false if object not in layer, bone not found, or other error
+ */
+bool ED_object_jump_to_bone(bContext *C, Object *ob, const char *bone_name)
+{
+ /* Verify it's a valid armature object. */
+ if (ob == NULL || ob->type != OB_ARMATURE) {
+ return false;
+ }
+
+ bArmature *arm = ob->data;
+
+ if (arm == NULL || GS(arm->id.name) != ID_AR) {
+ return false;
+ }
+
+ /* Activate the armature object. */
+ if (!ED_object_jump_to_object(C, ob)) {
+ return false;
+ }
+
+ /* Switch to pose mode from object mode. */
+ if (!ELEM(ob->mode, OB_MODE_EDIT, OB_MODE_POSE)) {
+ ED_object_mode_set(C, OB_MODE_POSE);
+ }
+
+ if (ob->mode == OB_MODE_EDIT && arm->edbo != NULL) {
+ /* In Edit mode select and activate the target Edit-Bone. */
+ EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
+ if (ebone != NULL) {
+ ED_armature_edit_deselect_all(ob);
+
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ ED_armature_ebone_select_set(ebone, true);
+ ED_armature_edit_sync_selection(arm->edbo);
+ }
+
+ if (EBONE_VISIBLE(arm, ebone)) {
+ arm->act_edbone = ebone;
+ }
+
+ ED_pose_bone_select_tag_update(ob);
+ return true;
+ }
+ }
+ else if (ob->mode == OB_MODE_POSE && ob->pose != NULL) {
+ /* In Pose mode select and activate the target Bone/Pose-Channel. */
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+ if (pchan != NULL) {
+ ED_pose_deselect_all(ob, SEL_DESELECT, true);
+
+ if (PBONE_SELECTABLE(arm, pchan->bone)) {
+ ED_pose_bone_select(ob, pchan, true);
+ }
+
+ if (PBONE_VISIBLE(arm, pchan->bone)) {
+ arm->act_bone = pchan->bone;
+ }
+
+ ED_pose_bone_select_tag_update(ob);
+ return true;
+ }
+ }
+
+ return false;
+}
+
/********************** Selection Operators **********************/
static bool objects_selectable_poll(bContext *C)