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:
authorCampbell Barton <ideasman42@gmail.com>2020-05-07 16:16:22 +0300
committerCampbell Barton <ideasman42@gmail.com>2020-05-07 16:38:44 +0300
commit82704ac3edf0e37d9eea2860bc565bcf521ae593 (patch)
treef5a1f73cca5b0399f92247fac030163213cbd79a
parentdaf10d17f46c933341be12bc9a9baf359d3280f7 (diff)
UI: support context menu in menu search popup
-rw-r--r--source/blender/editors/include/UI_interface.h5
-rw-r--r--source/blender/editors/interface/interface.c6
-rw-r--r--source/blender/editors/interface/interface_handlers.c15
-rw-r--r--source/blender/editors/interface/interface_intern.h4
-rw-r--r--source/blender/editors/interface/interface_region_search.c30
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.c104
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c2
7 files changed, 161 insertions, 5 deletions
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;
@@ -222,6 +229,51 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
}
/**
+ * 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.
*/
static void menu_types_add_from_keymap_items(bContext *C,
@@ -318,6 +370,7 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d
SNPRINTF(uiname, "%s " MENU_SEP "%s", idname_as_py, ot_ui_name);
item->drawwstr_full = strdup_memarena(memarena, uiname);
+ item->drawstr = ot_ui_name;
item->wm_context = NULL;
@@ -896,6 +949,53 @@ static void menu_search_cb(const bContext *UNUSED(C),
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Context Menu
+ *
+ * This uses a fake button to create a context menu,
+ * if this ever causes hard to solve bugs we may need to create
+ * a separate context menu just for the search, however this is fairly involved.
+ * \{ */
+
+static bool menu_search_context_menu_fn(struct bContext *C,
+ void *arg,
+ void *active,
+ const struct wmEvent *UNUSED(event))
+{
+ struct MenuSearch_Data *data = arg;
+ struct MenuSearch_Item *item = active;
+ bool has_menu = false;
+
+ memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
+ uiBut *but = &data->context_menu_data.but;
+ uiBlock *block = &data->context_menu_data.block;
+
+ but->block = block;
+
+ if (menu_items_to_ui_button(item, but)) {
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *region_prev = CTX_wm_region(C);
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, item->wm_context->area);
+ CTX_wm_region_set(C, item->wm_context->region);
+ }
+
+ if (ui_popup_context_menu_for_button(C, but)) {
+ has_menu = true;
+ }
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, region_prev);
+ }
+ }
+
+ return has_menu;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Menu Search Template Public API
* \{ */
@@ -916,6 +1016,8 @@ void UI_but_func_menu_search(uiBut *but)
menu_items_from_ui_destroy,
menu_call_fn,
NULL);
+
+ UI_but_func_search_set_context_menu(but, menu_search_context_menu_fn);
UI_but_func_search_set_sep_string(but, MENU_SEP);
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 96b2fcf92e7..ad1f5430872 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1799,7 +1799,7 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *eve
.size = {UI_searchbox_size_x() * 2, UI_searchbox_size_y()},
};
- UI_popup_block_invoke(C, wm_block_search_menu, &data, NULL);
+ UI_popup_block_invoke_ex(C, wm_block_search_menu, &data, NULL, false);
return OPERATOR_INTERFACE;
}