[Bf-blender-cvs] [82704ac3edf] master: UI: support context menu in menu search popup

Campbell Barton noreply at git.blender.org
Thu May 7 15:40:13 CEST 2020


Commit: 82704ac3edf0e37d9eea2860bc565bcf521ae593
Author: Campbell Barton
Date:   Thu May 7 23:16:22 2020 +1000
Branches: master
https://developer.blender.org/rB82704ac3edf0e37d9eea2860bc565bcf521ae593

UI: support context menu in menu search popup

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

M	source/blender/editors/include/UI_interface.h
M	source/blender/editors/interface/interface.c
M	source/blender/editors/interface/interface_handlers.c
M	source/blender/editors/interface/interface_intern.h
M	source/blender/editors/interface/interface_region_search.c
M	source/blender/editors/interface/interface_template_search_menu.c
M	source/blender/windowmanager/intern/wm_operators.c

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

diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 4f010156c17..2ea03fa5bc2 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -512,6 +512,10 @@ typedef void (*uiButSearchUpdateFn)(const struct bContext *C,
                                     const char *str,
                                     uiSearchItems *items);
 typedef void (*uiButSearchArgFreeFn)(void *arg);
+typedef bool (*uiButSearchContextMenuFn)(struct bContext *C,
+                                         void *arg,
+                                         void *active,
+                                         const struct wmEvent *event);
 
 /* Must return allocated string. */
 typedef char *(*uiButToolTipFunc)(struct bContext *C, void *argN, const char *tip);
@@ -1579,6 +1583,7 @@ void UI_but_func_search_set(uiBut *but,
                             uiButSearchArgFreeFn search_arg_free_fn,
                             uiButHandleFunc handle_fn,
                             void *active);
+void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn);
 void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string);
 
 /* height in pixels, it's using hardcoded values still */
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 5c38ee1ee08..93caa97db73 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -6409,6 +6409,12 @@ void UI_but_func_search_set(uiBut *but,
   }
 }
 
+void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn)
+{
+  struct uiButSearchData *search = but->search;
+  search->context_menu_fn = context_menu_fn;
+}
+
 void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
 {
   struct uiButSearchData *search = but->search;
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 42cb8c566dd..a976c5fa334 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -3473,6 +3473,16 @@ static void ui_do_but_textedit(
     case RIGHTMOUSE:
     case EVT_ESCKEY:
       if (event->val == KM_PRESS) {
+        /* Support search context menu. */
+        if (event->type == RIGHTMOUSE) {
+          if (data->searchbox) {
+            if (ui_searchbox_event(C, data->searchbox, but, event)) {
+              /* Only break if the event was handled. */
+              break;
+            }
+          }
+        }
+
 #ifdef WITH_INPUT_IME
         /* skips button handling since it is not wanted */
         if (is_ime_composing) {
@@ -9333,6 +9343,11 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
     if (event->val == KM_RELEASE) {
       /* pass, needed so we can exit active menu-items when click-dragging out of them */
     }
+    else if (but->type == UI_BTYPE_SEARCH_MENU) {
+      /* Pass, needed so search popup can have RMB context menu.
+       * This may be useful for other interactions which happen in the search popup
+       * without being directly over the search button. */
+    }
     else if (!ui_block_is_menu(but->block) || ui_block_is_pie_menu(but->block)) {
       /* pass, skip for dialogs */
     }
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index da7cbc8638b..b69d8fb7245 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -150,6 +150,8 @@ struct uiButSearchData {
   uiButSearchUpdateFn update_fn;
   void *arg;
   uiButSearchArgFreeFn arg_free_fn;
+  uiButSearchContextMenuFn context_menu_fn;
+
   const char *sep_string;
 };
 
@@ -658,7 +660,7 @@ bool ui_searchbox_inside(struct ARegion *region, int x, int y);
 int ui_searchbox_find_index(struct ARegion *region, const char *name);
 void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, const bool reset);
 int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *region, uiBut *but, char *str);
-void ui_searchbox_event(struct bContext *C,
+bool ui_searchbox_event(struct bContext *C,
                         struct ARegion *region,
                         uiBut *but,
                         const struct wmEvent *event);
diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c
index e7b90f9654f..cefb584eed4 100644
--- a/source/blender/editors/interface/interface_region_search.c
+++ b/source/blender/editors/interface/interface_region_search.c
@@ -153,7 +153,8 @@ bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int
 
   /* Limit flags that can be set so flags such as 'UI_SELECT' aren't accidentally set
    * which will cause problems, add others as needed. */
-  BLI_assert((state & ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT)) == 0);
+  BLI_assert(
+      (state & ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)) == 0);
   if (items->states) {
     items->states[items->totitem] = state;
   }
@@ -295,10 +296,11 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region)
   }
 }
 
-void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent *event)
+bool ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent *event)
 {
   uiSearchboxData *data = region->regiondata;
   int type = event->type, val = event->val;
+  bool handled = false;
 
   if (type == MOUSEPAN) {
     ui_pan_to_scroll(event, &type, &val);
@@ -308,10 +310,32 @@ void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent
     case WHEELUPMOUSE:
     case EVT_UPARROWKEY:
       ui_searchbox_select(C, region, but, -1);
+      handled = true;
       break;
     case WHEELDOWNMOUSE:
     case EVT_DOWNARROWKEY:
       ui_searchbox_select(C, region, but, 1);
+      handled = true;
+      break;
+    case RIGHTMOUSE:
+      if (val) {
+        if (but->search->context_menu_fn) {
+          if (data->active != -1) {
+            /* Check the cursor is over the active element
+             * (a little confusing if this isn't the case, although it does work). */
+            rcti rect;
+            ui_searchbox_butrect(&rect, data, data->active);
+            if (BLI_rcti_isect_pt(
+                    &rect, event->x - region->winrct.xmin, event->y - region->winrct.ymin)) {
+
+              void *active = data->items.pointers[data->active];
+              if (but->search->context_menu_fn(C, but->search->arg, active, event)) {
+                handled = true;
+              }
+            }
+          }
+        }
+      }
       break;
     case MOUSEMOVE:
       if (BLI_rcti_isect_pt(&region->winrct, event->x, event->y)) {
@@ -325,6 +349,7 @@ void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent
             if (data->active != a) {
               data->active = a;
               ui_searchbox_select(C, region, but, 0);
+              handled = true;
               break;
             }
           }
@@ -332,6 +357,7 @@ void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent
       }
       break;
   }
+  return handled;
 }
 
 /* region is the search box itself */
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c
index 1e8d32abf67..8bd61ccd038 100644
--- a/source/blender/editors/interface/interface_template_search_menu.c
+++ b/source/blender/editors/interface/interface_template_search_menu.c
@@ -137,6 +137,12 @@ struct MenuSearch_Data {
   ListBase items;
   /** Use for all small allocations. */
   MemArena *memarena;
+
+  /** Use for context menu, to fake a button to create a context menu. */
+  struct {
+    uiBut but;
+    uiBlock block;
+  } context_menu_data;
 };
 
 static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v)
@@ -208,7 +214,8 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
     /* Handle shared settings. */
     item->drawstr = strdup_memarena(memarena, but->drawstr);
     item->icon = ui_but_icon(but);
-    item->state = (but->flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT));
+    item->state = (but->flag &
+                   (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR));
     item->mt = mt;
     item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL;
 
@@ -221,6 +228,51 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
   return false;
 }
 
+/**
+ * Populate a fake button from a menu item (use for context menu).
+ */
+static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
+{
+  bool changed = false;
+  switch (item->type) {
+    case MENU_SEARCH_TYPE_OP: {
+      but->optype = item->op.type;
+      but->opcontext = item->op.opcontext;
+      but->context = item->op.context;
+      but->opptr = item->op.opptr;
+      changed = true;
+      break;
+    }
+    case MENU_SEARCH_TYPE_RNA: {
+      const int prop_type = RNA_property_type(item->rna.prop);
+
+      but->rnapoin = item->rna.ptr;
+      but->rnaprop = item->rna.prop;
+      but->rnaindex = item->rna.index;
+
+      if (prop_type == PROP_ENUM) {
+        but->hardmax = item->rna.enum_value;
+      }
+      changed = true;
+      break;
+    }
+  }
+
+  if (changed) {
+    STRNCPY(but->drawstr, item->drawstr);
+    char *drawstr_sep = (item->state & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) :
+                                                              NULL;
+    if (drawstr_sep) {
+      *drawstr_sep = '\0';
+    }
+
+    but->icon = item->icon;
+    but->str = but->strdata;
+  }
+
+  return changed;
+}
+
 /**
  * Populate \a menu_stack with menus from inspecting active key-maps for this context.
  */
@@ -318,6 +370,7 @@ 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list