[Bf-blender-cvs] [0c1d4769235] master: UI: Allow UI to pass focused data-block to operators via context

Julian Eisel noreply at git.blender.org
Fri Dec 11 23:10:03 CET 2020


Commit: 0c1d4769235c95fc976be8988e2d4c529f3fdf49
Author: Julian Eisel
Date:   Fri Dec 11 22:20:31 2020 +0100
Branches: master
https://developer.blender.org/rB0c1d4769235c95fc976be8988e2d4c529f3fdf49

UI: Allow UI to pass focused data-block to operators via context

This is similar to c4a2067130130d, but applies to the general UI and is only
about single data-blocks. Here there was a similar problem: How can buttons
pass the data they represent to operators? We currently resort to ugly ad-hoc
solutions like `UI_context_active_but_get_tab_ID()`. So the operator would need
to know that it is executed on a tab button that represents a data-block.

A single button can now hand operators a data-block to operate on. The operator
can request it via the "id" context member (`CTX_data_pointer_get_type(C, "id",
&RNA_ID)` in C, `bpy.context.id` in .py).
In this commit, it is already set in the following places:
* Generic RNA button code sets it to the pointed to data-block, if the button
  represents a data-block RNA pointer property. (I.e for general data-block
  search buttons.)
* Data-block selectors (`templateID`) set it to the currently active data-block.
* The material slot UI-List sets it for each slot to the material it represents.
The button context menu code is modified so its operators use the context set
for the layout of its parent button (i.e. `layout.context_pointer_set()`).

No user visible changes. This new design isn't actually used yet. It will be
soon for asset operators.

Reviewed as part of https://developer.blender.org/D9717.
Reviewed by: Brecht Van Lommel

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

M	release/scripts/startup/bl_ui/properties_material.py
M	source/blender/blenkernel/BKE_context.h
M	source/blender/blenkernel/intern/context.c
M	source/blender/editors/include/UI_interface.h
M	source/blender/editors/interface/interface.c
M	source/blender/editors/interface/interface_context_menu.c
M	source/blender/editors/interface/interface_layout.c
M	source/blender/editors/interface/interface_templates.c

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

diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py
index 6aaec9940e8..47ab98386f4 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -42,6 +42,9 @@ class MATERIAL_UL_matslots(UIList):
         # ob = data
         slot = item
         ma = slot.material
+
+        layout.context_pointer_set("id", ma)
+
         if self.layout_type in {'DEFAULT', 'COMPACT'}:
             if ma:
                 layout.prop(ma, "name", text="", emboss=False, icon_value=icon)
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index af9a95e1753..94392dd78da 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -143,8 +143,9 @@ bContext *CTX_copy(const bContext *C);
 
 /* Stored Context */
 
-bContextStore *CTX_store_add(ListBase *contexts, const char *name, PointerRNA *ptr);
+bContextStore *CTX_store_add(ListBase *contexts, const char *name, const PointerRNA *ptr);
 bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context);
+bContextStore *CTX_store_get(bContext *C);
 void CTX_store_set(bContext *C, bContextStore *store);
 bContextStore *CTX_store_copy(bContextStore *store);
 void CTX_store_free(bContextStore *store);
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 2e4d3d62925..65accc66084 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -123,7 +123,7 @@ void CTX_free(bContext *C)
 
 /* store */
 
-bContextStore *CTX_store_add(ListBase *contexts, const char *name, PointerRNA *ptr)
+bContextStore *CTX_store_add(ListBase *contexts, const char *name, const PointerRNA *ptr)
 {
   /* ensure we have a context to put the entry in, if it was already used
    * we have to copy the context to ensure */
@@ -178,6 +178,11 @@ bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context)
   return ctx;
 }
 
+bContextStore *CTX_store_get(bContext *C)
+{
+  return C->wm.store;
+}
+
 void CTX_store_set(bContext *C, bContextStore *store)
 {
   C->wm.store = store;
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 005dbf0e381..352c58032f5 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1879,6 +1879,7 @@ uiBlock *uiLayoutGetBlock(uiLayout *layout);
 
 void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv);
 void uiLayoutSetContextPointer(uiLayout *layout, const char *name, struct PointerRNA *ptr);
+struct bContextStore *uiLayoutGetContextStore(uiLayout *layout);
 void uiLayoutContextCopy(uiLayout *layout, struct bContextStore *context);
 struct wmOperatorType *UI_but_operatortype_get_from_enum_menu(struct uiBut *but,
                                                               PropertyRNA **r_prop);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 4a02c6b6e88..254d0909367 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -4552,6 +4552,15 @@ static uiBut *ui_def_but_rna(uiBlock *block,
     UI_but_disable(but, info);
   }
 
+  if (proptype == PROP_POINTER) {
+    /* If the button shows an ID, automatically set it as focused in context so operators can
+     * access it.*/
+    const PointerRNA pptr = RNA_property_pointer_get(ptr, prop);
+    if (pptr.data && RNA_struct_is_ID(pptr.type)) {
+      but->context = CTX_store_add(&block->contexts, "id", &pptr);
+    }
+  }
+
   if (but->flag & UI_BUT_UNDO && (ui_but_is_rna_undo(but) == false)) {
     but->flag &= ~UI_BUT_UNDO;
   }
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 39b405a02b8..3e76cd1cde4 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -503,6 +503,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
 
   uiPopupMenu *pup;
   uiLayout *layout;
+  bContextStore *previous_ctx = CTX_store_get(C);
   {
     uiStringInfo label = {BUT_GET_LABEL, NULL};
 
@@ -514,6 +515,11 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
     if (label.strinfo) {
       MEM_freeN(label.strinfo);
     }
+
+    if (but->context) {
+      uiLayoutContextCopy(layout, but->context);
+      CTX_store_set(C, uiLayoutGetContextStore(layout));
+    }
     uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
   }
 
@@ -1210,6 +1216,10 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
     UI_menutype_draw(C, mt, uiLayoutColumn(layout, false));
   }
 
+  if (but->context) {
+    CTX_store_set(C, previous_ctx);
+  }
+
   return UI_popup_menu_end_or_cancel(C, pup);
 }
 
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index ebd2235cb82..4b19b8f97f4 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -5663,6 +5663,11 @@ void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *p
   layout->context = CTX_store_add(&block->contexts, name, ptr);
 }
 
+bContextStore *uiLayoutGetContextStore(uiLayout *layout)
+{
+  return layout->context;
+}
+
 void uiLayoutContextCopy(uiLayout *layout, bContextStore *context)
 {
   uiBlock *block = layout->root->block;
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 43ead511cfe..352afe72e76 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -895,6 +895,9 @@ static void template_ID(const bContext *C,
   idfrom = template_ui->ptr.owner_id;
   // lb = template_ui->idlb;
 
+  /* Allow opertators to take the ID from context. */
+  uiLayoutSetContextPointer(layout, "id", &idptr);
+
   block = uiLayoutGetBlock(layout);
   UI_block_align_begin(block);
 
@@ -6170,6 +6173,10 @@ void uiTemplateList(uiLayout *layout,
                     org_i,
                     flt_flag);
 
+          /* Items should be able to set context pointers for the layout. But the listrow button
+           * swallows events, so it needs the context storage too for handlers to see it. */
+          but->context = uiLayoutGetContextStore(sub);
+
           /* If we are "drawing" active item, set all labels as active. */
           if (i == activei) {
             ui_layout_list_set_labels_active(sub);



More information about the Bf-blender-cvs mailing list