[Bf-blender-cvs] [d227c58e3ec] blender2.8: UI: support jumping to target object/bone

Alexander Gavrilov noreply at git.blender.org
Tue Nov 20 07:39:00 CET 2018


Commit: d227c58e3ec2020683d9b7e8280f5e48350fd1fd
Author: Alexander Gavrilov
Date:   Tue Nov 20 17:34:56 2018 +1100
Branches: blender2.8
https://developer.blender.org/rBd227c58e3ec2020683d9b7e8280f5e48350fd1fd

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.

===================================================================

M	source/blender/editors/include/ED_object.h
M	source/blender/editors/interface/interface_context_menu.c
M	source/blender/editors/interface/interface_handlers.c
M	source/blender/editors/interface/interface_ops.c
M	source/blender/editors/object/object_select.c

===================================================================

diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 29047f02e5a..37b27c461ae 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -302,6 +302,11 @@ const struct EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(
 void ED_object_check_force_modifiers(
         struct Main *bmain, struct Scene *scene, struct Object *object);
 
+struct Base *ED_object_find_first_by_data_id(struct ViewLayer *view_layer, struct ID *id);
+
+bool ED_object_jump_to_object(struct bContext *C, struct Object *ob);
+bool ED_object_jump_to_bone(struct bContext *C, struct Object *ob, const char *bone_name);
+
 /* object_facemap_ops.c */
 void ED_object_facemap_face_add(struct Object *ob, struct bFaceMap *fmap, int facenum);
 void ED_object_facemap_face_remove(struct Object *ob, struct bFaceMap *fmap, int facenum);
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 03d941c2387..0ffc97444e1 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -361,7 +361,12 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
 		uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
 	}
 
-	if (but->type == UI_BTYPE_TAB) {
+	const bool is_disabled = but->flag & UI_BUT_DISABLED;
+
+	if (is_disabled) {
+		/* Suppress editing commands. */
+	}
+	else if (but->type == UI_BTYPE_TAB) {
 		uiButTab *tab = (uiButTab *)but;
 		if (tab->menu) {
 			UI_menutype_draw(C, tab->menu, layout);
@@ -639,6 +644,17 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
 		}
 	}
 
+	/* Pointer properties and string properties with prop_search support jumping to target object/bone. */
+	if (but->rnapoin.data && but->rnaprop) {
+		const PropertyType type = RNA_property_type(but->rnaprop);
+
+		if ((type == PROP_POINTER) || (type == PROP_STRING && but->type == UI_BTYPE_SEARCH_MENU && but->search_func == ui_rna_collection_search_cb)) {
+			uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump To Target"),
+			        ICON_NONE, "UI_OT_jump_to_target_button");
+			uiItemS(layout);
+		}
+	}
+
 	/* Favorites Menu */
 	if (ui_but_is_user_menu_compatible(C, but)) {
 		uiBlock *block = uiLayoutGetBlock(layout);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index fffc28d1cdf..2f84045a73f 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -6614,6 +6614,17 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
 			return WM_UI_HANDLER_BREAK;
 		}
 
+		/* handle menu */
+		if ((event->type == RIGHTMOUSE) &&
+		    !IS_EVENT_MOD(event, shift, ctrl, alt, oskey) &&
+		    (event->val == KM_PRESS))
+		{
+			/* RMB has two options now */
+			if (ui_popup_context_menu_for_button(C, but)) {
+				return WM_UI_HANDLER_BREAK;
+			}
+		}
+
 		if (is_disabled) {
 			return WM_UI_HANDLER_CONTINUE;
 		}
@@ -6627,16 +6638,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
 		if (event->type == EVT_DROP) {
 			ui_but_drop(C, event, but, data);
 		}
-		/* handle menu */
-		else if ((event->type == RIGHTMOUSE) &&
-		         !IS_EVENT_MOD(event, shift, ctrl, alt, oskey) &&
-		         (event->val == KM_PRESS))
-		{
-			/* RMB has two options now */
-			if (ui_popup_context_menu_for_button(C, but)) {
-				return WM_UI_HANDLER_BREAK;
-			}
-		}
 	}
 
 	if (but->flag & UI_BUT_DISABLED) {
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index d2bed210f9c..0b35961483e 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -31,6 +31,7 @@
 
 #include "MEM_guardedalloc.h"
 
+#include "DNA_armature_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_text_types.h" /* for UI_OT_reports_to_text */
 #include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
@@ -65,6 +66,7 @@
 #include "WM_api.h"
 #include "WM_types.h"
 
+#include "ED_object.h"
 #include "ED_paint.h"
 
 /* only for UI_OT_editsource */
@@ -802,6 +804,151 @@ static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "all", true, "All", "Copy to selected all elements of the array");
 }
 
+
+/* -------------------------------------------------------------------- */
+/** \name Jump to Target Operator
+ * \{ */
+
+/** Jump to the object or bone referenced by the pointer, or check if it is possible. */
+static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll)
+{
+	if (RNA_pointer_is_null(&ptr)) {
+		return false;
+	}
+
+	/* Verify pointer type. */
+	char bone_name[MAXBONENAME];
+	const StructRNA *target_type = NULL;
+
+	if (ELEM(ptr.type, &RNA_EditBone, &RNA_PoseBone, &RNA_Bone)) {
+		RNA_string_get(&ptr, "name", bone_name);
+		if (bone_name[0] != '\0') {
+			target_type = &RNA_Bone;
+		}
+	}
+	else if (RNA_struct_is_a(ptr.type, &RNA_Object)) {
+		target_type = &RNA_Object;
+	}
+
+	if (target_type == NULL) {
+		return false;
+	}
+
+	/* Find the containing Object. */
+	ViewLayer *view_layer = CTX_data_view_layer(C);
+	Base *base = NULL;
+	const short id_type = GS(((ID *)ptr.id.data)->name);
+	if (id_type == ID_OB) {
+		base = BKE_view_layer_base_find(view_layer, ptr.id.data);
+	}
+	else if (OB_DATA_SUPPORT_ID(id_type)) {
+		base = ED_object_find_first_by_data_id(view_layer, ptr.id.data);
+	}
+
+	bool ok = false;
+	if ((base == NULL) ||
+	    ((target_type == &RNA_Bone) && (base->object->type != OB_ARMATURE)))
+	{
+		/* pass */
+	}
+	else if (poll) {
+		ok = true;
+	}
+	else {
+		/* Select and activate the target. */
+		if (target_type == &RNA_Bone) {
+			ok = ED_object_jump_to_bone(C, base->object, bone_name);
+		}
+		else if (target_type == &RNA_Object) {
+			ok = ED_object_jump_to_object(C, base->object);
+		}
+		else {
+			BLI_assert(0);
+		}
+	}
+	return ok;
+}
+
+/**
+ * Jump to the object or bone referred to by the current UI field value.
+ *
+ * \note quite heavy for a poll callback, but the operator is only
+ * used as a right click menu item for certain UI field types, and
+ * this will fail quickly if the context is completely unsuitable.
+ */
+static bool jump_to_target_button(bContext *C, bool poll)
+{
+	PointerRNA ptr, target_ptr;
+	PropertyRNA *prop;
+	int index;
+
+	UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+	/* If there is a valid property... */
+	if (ptr.data && prop) {
+		const PropertyType type = RNA_property_type(prop);
+
+		/* For pointer properties, use their value directly. */
+		if (type == PROP_POINTER) {
+			target_ptr = RNA_property_pointer_get(&ptr, prop);
+
+			return jump_to_target_ptr(C, target_ptr, poll);
+		}
+		/* For string properties with prop_search, look up the search collection item. */
+		else if (type == PROP_STRING) {
+			const uiBut *but = UI_context_active_but_get(C);
+
+			if (but->type == UI_BTYPE_SEARCH_MENU && but->search_func == ui_rna_collection_search_cb) {
+				uiRNACollectionSearch *coll_search = but->search_arg;
+
+				char str_buf[MAXBONENAME];
+				char *str_ptr = RNA_property_string_get_alloc(&ptr, prop, str_buf, sizeof(str_buf), NULL);
+
+				int found = RNA_property_collection_lookup_string(&coll_search->search_ptr, coll_search->search_prop, str_ptr, &target_ptr);
+
+				if (str_ptr != str_buf) {
+					MEM_freeN(str_ptr);
+				}
+
+				if (found) {
+					return jump_to_target_ptr(C, target_ptr, poll);
+				}
+			}
+		}
+	}
+
+	return false;
+}
+
+static bool jump_to_target_button_poll(bContext *C)
+{
+	return jump_to_target_button(C, true);
+}
+
+static int jump_to_target_button_exec(bContext *C, wmOperator *UNUSED(op))
+{
+	bool success = jump_to_target_button(C, false);
+
+	return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+static void UI_OT_jump_to_target_button(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Jump To Target";
+	ot->idname = "UI_OT_jump_to_target_button";
+	ot->description = "Switch to the target object or bone";
+
+	/* callbacks */
+	ot->poll = jump_to_target_button_poll;
+	ot->exec = jump_to_target_button_exec;
+
+	/* flags */
+	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
 /* Reports to Textblock Operator ------------------------ */
 
 /* FIXME: this is just a temporary operator so that we can see all the reports somewhere
@@ -1410,6 +1557,7 @@ void ED_operatortypes_ui(void)
 	WM_operatortype_append(UI_OT_override_type_set_button);
 	WM_operatortype_append(UI_OT_override_remove_button);
 	WM_operatortype_append(UI_OT_copy_to_selected_button);
+	WM_operatortype_append(UI_OT_jump_to_target_button);
 	WM_operatortype_append(UI_OT_reports_to_textblock);  /* XXX: temp? */
 	WM_operatortype_append(UI_OT_drop_color);
 #ifdef WITH_PYTHON
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

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list