Blender  V2.93
interface_template_search_menu.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include "MEM_guardedalloc.h"
28 
29 #include "DNA_action_types.h"
31 #include "DNA_node_types.h"
32 #include "DNA_object_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_shader_fx_types.h"
35 #include "DNA_texture_types.h"
36 
37 #include "BLI_alloca.h"
38 #include "BLI_dynstr.h"
39 #include "BLI_ghash.h"
40 #include "BLI_linklist.h"
41 #include "BLI_listbase.h"
42 #include "BLI_math_matrix.h"
43 #include "BLI_memarena.h"
44 #include "BLI_string.h"
45 #include "BLI_string_search.h"
46 #include "BLI_string_utils.h"
47 #include "BLI_utildefines.h"
48 
49 #include "BLT_translation.h"
50 
51 #include "BKE_context.h"
52 #include "BKE_global.h"
53 #include "BKE_screen.h"
54 
55 #include "ED_screen.h"
56 
57 #include "RNA_access.h"
58 
59 #include "WM_api.h"
60 #include "WM_types.h"
61 
62 #include "UI_interface.h"
63 #include "interface_intern.h"
64 
65 /* For key-map item access. */
66 #include "wm_event_system.h"
67 
68 /* -------------------------------------------------------------------- */
72 /* Unicode arrow. */
73 #define MENU_SEP "\xe2\x96\xb6"
74 
85 
88 };
89 
93  const char *drawstr;
94 
97 };
98 
101  const char *drawstr;
102  const char *drawwstr_full;
104  const char *drawstr_submenu;
105  int icon;
106  int state;
107 
110 
111  enum {
114  } type;
115 
116  union {
118  struct {
121  short opcontext;
123  } op;
124 
126  struct {
129  int index;
132  } rna;
133  };
134 
137 };
138 
144 
146  struct {
150 };
151 
152 static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v)
153 {
154  const struct MenuSearch_Item *menu_item_a = menu_item_a_v;
155  const struct MenuSearch_Item *menu_item_b = menu_item_b_v;
156  return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full);
157 }
158 
159 static const char *strdup_memarena(MemArena *memarena, const char *str)
160 {
161  const uint str_size = strlen(str) + 1;
162  char *str_dst = BLI_memarena_alloc(memarena, str_size);
163  memcpy(str_dst, str, str_size);
164  return str_dst;
165 }
166 
167 static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str)
168 {
169  const uint str_size = BLI_dynstr_get_len(dyn_str) + 1;
170  char *str_dst = BLI_memarena_alloc(memarena, str_size);
171  BLI_dynstr_get_cstring_ex(dyn_str, str_dst);
172  return str_dst;
173 }
174 
176  MemArena *memarena,
177  struct MenuType *mt,
178  const char *drawstr_submenu,
179  uiBut *but,
181 {
182  struct MenuSearch_Item *item = NULL;
183 
184  /* Use override if the name is empty, this can happen with popovers. */
185  const char *drawstr_override = NULL;
186  const char *drawstr_sep = (but->flag & UI_BUT_HAS_SEP_CHAR) ?
187  strrchr(but->drawstr, UI_SEP_CHAR) :
188  NULL;
189  const bool drawstr_is_empty = (drawstr_sep == but->drawstr) || (but->drawstr[0] == '\0');
190 
191  if (but->optype != NULL) {
192  if (drawstr_is_empty) {
193  drawstr_override = WM_operatortype_name(but->optype, but->opptr);
194  }
195 
196  item = BLI_memarena_calloc(memarena, sizeof(*item));
197  item->type = MENU_SEARCH_TYPE_OP;
198 
199  item->op.type = but->optype;
200  item->op.opcontext = but->opcontext;
201  item->op.context = but->context;
202  item->op.opptr = but->opptr;
203  but->opptr = NULL;
204  }
205  else if (but->rnaprop != NULL) {
206  const int prop_type = RNA_property_type(but->rnaprop);
207 
208  if (drawstr_is_empty) {
209  if (prop_type == PROP_ENUM) {
210  const int value_enum = (int)but->hardmax;
211  EnumPropertyItem enum_item;
213  but->block->evil_C, &but->rnapoin, but->rnaprop, value_enum, &enum_item)) {
214  drawstr_override = enum_item.name;
215  }
216  else {
217  /* Should never happen. */
218  drawstr_override = "Unknown";
219  }
220  }
221  else {
222  drawstr_override = RNA_property_ui_name(but->rnaprop);
223  }
224  }
225 
226  if (!ELEM(prop_type, PROP_BOOLEAN, PROP_ENUM)) {
227  /* Note that these buttons are not prevented,
228  * but aren't typically used in menus. */
229  printf("Button '%s' in menu '%s' is a menu item with unsupported RNA type %d\n",
230  but->drawstr,
231  mt->idname,
232  prop_type);
233  }
234  else {
235  item = BLI_memarena_calloc(memarena, sizeof(*item));
236  item->type = MENU_SEARCH_TYPE_RNA;
237 
238  item->rna.ptr = but->rnapoin;
239  item->rna.prop = but->rnaprop;
240  item->rna.index = but->rnaindex;
241 
242  if (prop_type == PROP_ENUM) {
243  item->rna.enum_value = (int)but->hardmax;
244  }
245  }
246  }
247 
248  if (item != NULL) {
249  /* Handle shared settings. */
250  if (drawstr_override != NULL) {
251  const char *drawstr_suffix = drawstr_sep ? drawstr_sep : "";
252  char *drawstr_alloc = BLI_string_joinN("(", drawstr_override, ")", drawstr_suffix);
253  item->drawstr = strdup_memarena(memarena, drawstr_alloc);
254  MEM_freeN(drawstr_alloc);
255  }
256  else {
257  item->drawstr = strdup_memarena(memarena, but->drawstr);
258  }
259 
260  item->icon = ui_but_icon(but);
261  item->state = (but->flag &
263  item->mt = mt;
265 
266  item->wm_context = wm_context;
267 
268  BLI_addtail(&data->items, item);
269  return true;
270  }
271 
272  return false;
273 }
274 
278 static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
279 {
280  bool changed = false;
281  switch (item->type) {
282  case MENU_SEARCH_TYPE_OP: {
283  but->optype = item->op.type;
284  but->opcontext = item->op.opcontext;
285  but->context = item->op.context;
286  but->opptr = item->op.opptr;
287  changed = true;
288  break;
289  }
290  case MENU_SEARCH_TYPE_RNA: {
291  const int prop_type = RNA_property_type(item->rna.prop);
292 
293  but->rnapoin = item->rna.ptr;
294  but->rnaprop = item->rna.prop;
295  but->rnaindex = item->rna.index;
296 
297  if (prop_type == PROP_ENUM) {
298  but->hardmax = item->rna.enum_value;
299  }
300  changed = true;
301  break;
302  }
303  }
304 
305  if (changed) {
306  STRNCPY(but->drawstr, item->drawstr);
307  char *drawstr_sep = (item->state & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) :
308  NULL;
309  if (drawstr_sep) {
310  *drawstr_sep = '\0';
311  }
312 
313  but->icon = item->icon;
314  but->str = but->strdata;
315  }
316 
317  return changed;
318 }
319 
324  wmWindow *win,
325  ScrArea *area,
326  ARegion *region,
327  LinkNode **menuid_stack_p,
328  GHash *menu_to_kmi,
329  GSet *menu_tagged)
330 {
332  ListBase *handlers[] = {
333  region ? &region->handlers : NULL,
334  area ? &area->handlers : NULL,
335  &win->handlers,
336  };
337 
338  for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
339  if (handlers[handler_index] == NULL) {
340  continue;
341  }
342  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) {
343  /* During this loop, UI handlers for nested menus can tag multiple handlers free. */
344  if (handler_base->flag & WM_HANDLER_DO_FREE) {
345  continue;
346  }
347  if (handler_base->type != WM_HANDLER_TYPE_KEYMAP) {
348  continue;
349  }
350 
351  if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) {
352  wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
353  wmKeyMap *keymap = WM_event_get_keymap_from_handler(wm, handler);
354  if (keymap && WM_keymap_poll(C, keymap)) {
355  LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
356  if (kmi->flag & KMI_INACTIVE) {
357  continue;
358  }
359  if (STR_ELEM(kmi->idname, "WM_OT_call_menu", "WM_OT_call_menu_pie")) {
360  char menu_idname[MAX_NAME];
361  RNA_string_get(kmi->ptr, "name", menu_idname);
362  MenuType *mt = WM_menutype_find(menu_idname, false);
363 
364  if (mt && BLI_gset_add(menu_tagged, mt)) {
365  /* Unlikely, but possible this will be included twice. */
366  BLI_linklist_prepend(menuid_stack_p, mt);
367 
368  void **kmi_p;
369  if (!BLI_ghash_ensure_p(menu_to_kmi, mt, &kmi_p)) {
370  *kmi_p = kmi;
371  }
372  }
373  }
374  }
375  }
376  }
377  }
378  }
379 }
380 
385 {
386  /* Add to temporary list so we can sort them separately. */
387  ListBase operator_items = {NULL, NULL};
388 
389  MemArena *memarena = data->memarena;
390  GHashIterator iter;
391  for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter);
392  BLI_ghashIterator_step(&iter)) {
394 
395  if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
396  continue;
397  }
398 
399  if (WM_operator_poll((bContext *)C, ot)) {
400  const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
401 
402  struct MenuSearch_Item *item = NULL;
403  item = BLI_memarena_calloc(memarena, sizeof(*item));
404  item->type = MENU_SEARCH_TYPE_OP;
405 
406  item->op.type = ot;
407  item->op.opcontext = WM_OP_INVOKE_DEFAULT;
408  item->op.context = NULL;
409 
410  char idname_as_py[OP_MAX_TYPENAME];
411  char uiname[256];
412  WM_operator_py_idname(idname_as_py, ot->idname);
413 
414  SNPRINTF(uiname, "%s " MENU_SEP "%s", idname_as_py, ot_ui_name);
415 
416  item->drawwstr_full = strdup_memarena(memarena, uiname);
417  item->drawstr = ot_ui_name;
418 
419  item->wm_context = NULL;
420 
421  BLI_addtail(&operator_items, item);
422  }
423  }
424 
426 
427  BLI_movelisttolist(&data->items, &operator_items);
428 }
429 
437  bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas)
438 {
441  GHash *menu_parent_map = BLI_ghash_ptr_new(__func__);
442  GHash *menu_display_name_map = BLI_ghash_ptr_new(__func__);
443  const uiStyle *style = UI_style_get_dpi();
444 
445  /* Convert into non-ui structure. */
446  struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__);
447 
448  DynStr *dyn_str = BLI_dynstr_new_memarena();
449 
450  /* Use a stack of menus to handle and discover new menus in passes. */
451  LinkNode *menu_stack = NULL;
452 
453  /* Tag menu types not to add, either because they have already been added
454  * or they have been blacklisted.
455  * Set of #MenuType. */
456  GSet *menu_tagged = BLI_gset_ptr_new(__func__);
458  GHash *menu_to_kmi = BLI_ghash_ptr_new(__func__);
459 
460  /* Blacklist menus we don't want to show. */
461  {
462  const char *idname_array[] = {
463  /* While we could include this, it's just showing filenames to load. */
464  "TOPBAR_MT_file_open_recent",
465  };
466  for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
467  MenuType *mt = WM_menutype_find(idname_array[i], false);
468  if (mt != NULL) {
469  BLI_gset_add(menu_tagged, mt);
470  }
471  }
472  }
473 
474  {
475  /* Exclude context menus because:
476  * - The menu items are available elsewhere (and will show up multiple times).
477  * - Menu items depend on exact context, making search results unpredictable
478  * (exact number of items selected for example). See design doc T74158.
479  * There is one exception,
480  * as the outliner only exposes functionality via the context menu. */
481  GHashIterator iter;
482 
483  for (WM_menutype_iter(&iter); (!BLI_ghashIterator_done(&iter));
484  (BLI_ghashIterator_step(&iter))) {
486  if (BLI_str_endswith(mt->idname, "_context_menu")) {
487  BLI_gset_add(menu_tagged, mt);
488  }
489  }
490  const char *idname_array[] = {
491  /* Add back some context menus. */
492  "OUTLINER_MT_context_menu",
493  };
494  for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
495  MenuType *mt = WM_menutype_find(idname_array[i], false);
496  if (mt != NULL) {
497  BLI_gset_remove(menu_tagged, mt, NULL);
498  }
499  }
500  }
501 
502  /* Collect contexts, one for each 'ui_type'. */
503  struct MenuSearch_Context *wm_contexts = NULL;
504 
505  const EnumPropertyItem *space_type_ui_items = NULL;
506  int space_type_ui_items_len = 0;
507  bool space_type_ui_items_free = false;
508 
509  /* Text used as prefix for top-bar menu items. */
510  const char *global_menu_prefix = NULL;
511 
512  if (include_all_areas) {
513  bScreen *screen = WM_window_get_active_screen(win);
514 
515  /* First create arrays for ui_type. */
516  PropertyRNA *prop_ui_type = NULL;
517  {
518  /* This must be a valid pointer, with only it's type checked. */
519  ScrArea area_dummy = {
520  /* Anything besides #SPACE_EMPTY is fine,
521  * as this value is only included in the enum when set. */
523  };
524  PointerRNA ptr;
525  RNA_pointer_create(&screen->id, &RNA_Area, &area_dummy, &ptr);
526  prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
528  &ptr,
529  prop_ui_type,
530  &space_type_ui_items,
531  &space_type_ui_items_len,
532  &space_type_ui_items_free);
533 
534  wm_contexts = BLI_memarena_calloc(memarena, sizeof(*wm_contexts) * space_type_ui_items_len);
535  for (int i = 0; i < space_type_ui_items_len; i++) {
536  wm_contexts[i].space_type_ui_index = -1;
537  }
538  }
539 
540  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
542  if (region != NULL) {
543  PointerRNA ptr;
544  RNA_pointer_create(&screen->id, &RNA_Area, area, &ptr);
545  const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type);
546 
547  const int space_type_ui_index = RNA_enum_from_value(space_type_ui_items, space_type_ui);
548  if (space_type_ui_index == -1) {
549  continue;
550  }
551 
552  if (wm_contexts[space_type_ui_index].space_type_ui_index != -1) {
553  ScrArea *area_best = wm_contexts[space_type_ui_index].area;
554  const uint value_best = (uint)area_best->winx * (uint)area_best->winy;
555  const uint value_test = (uint)area->winx * (uint)area->winy;
556  if (value_best > value_test) {
557  continue;
558  }
559  }
560 
562  wm_contexts[space_type_ui_index].area = area;
563  wm_contexts[space_type_ui_index].region = region;
564  }
565  }
566 
567  global_menu_prefix = CTX_IFACE_(RNA_property_translation_context(prop_ui_type), "Top Bar");
568  }
569 
570  GHashIterator iter;
571 
572  for (int space_type_ui_index = -1; space_type_ui_index < space_type_ui_items_len;
573  space_type_ui_index += 1) {
574 
575  ScrArea *area = NULL;
576  ARegion *region = NULL;
577  struct MenuSearch_Context *wm_context = NULL;
578 
579  if (include_all_areas) {
580  if (space_type_ui_index == -1) {
581  /* First run without any context, to populate the top-bar without. */
582  wm_context = NULL;
583  area = NULL;
584  region = NULL;
585  }
586  else {
587  wm_context = &wm_contexts[space_type_ui_index];
588  if (wm_context->space_type_ui_index == -1) {
589  continue;
590  }
591 
592  area = wm_context->area;
593  region = wm_context->region;
594 
597  }
598  }
599  else {
600  area = area_init;
601  region = region_init;
602  }
603 
604  /* Populate menus from the editors,
605  * note that we could create a fake header, draw the header and extract the menus
606  * from the buttons, however this is quite involved and can be avoided as by convention
607  * each space-type has a single root-menu that headers use. */
608  {
609  const char *idname_array[2] = {NULL};
610  int idname_array_len = 0;
611 
612  /* Use negative for global (no area) context, populate the top-bar. */
613  if (space_type_ui_index == -1) {
614  idname_array[idname_array_len++] = "TOPBAR_MT_editor_menus";
615  }
616 
617 #define SPACE_MENU_MAP(space_type, menu_id) \
618  case space_type: \
619  idname_array[idname_array_len++] = menu_id; \
620  break
621 #define SPACE_MENU_NOP(space_type) \
622  case space_type: \
623  break
624 
625  if (area != NULL) {
626  SpaceLink *sl = area->spacedata.first;
627  switch ((eSpace_Type)area->spacetype) {
628  SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus");
629  SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus");
630  SPACE_MENU_MAP(SPACE_OUTLINER, "OUTLINER_MT_editor_menus");
632  SPACE_MENU_MAP(SPACE_FILE, "FILEBROWSER_MT_editor_menus");
633  SPACE_MENU_MAP(SPACE_IMAGE, "IMAGE_MT_editor_menus");
634  SPACE_MENU_MAP(SPACE_INFO, "INFO_MT_editor_menus");
635  SPACE_MENU_MAP(SPACE_SEQ, "SEQUENCER_MT_editor_menus");
636  SPACE_MENU_MAP(SPACE_TEXT, "TEXT_MT_editor_menus");
638  (((const SpaceAction *)sl)->mode == SACTCONT_TIMELINE) ?
639  "TIME_MT_editor_menus" :
640  "DOPESHEET_MT_editor_menus");
641  SPACE_MENU_MAP(SPACE_NLA, "NLA_MT_editor_menus");
642  SPACE_MENU_MAP(SPACE_NODE, "NODE_MT_editor_menus");
643  SPACE_MENU_MAP(SPACE_CONSOLE, "CONSOLE_MT_editor_menus");
644  SPACE_MENU_MAP(SPACE_USERPREF, "USERPREF_MT_editor_menus");
646  (((const SpaceClip *)sl)->mode == SC_MODE_TRACKING) ?
647  "CLIP_MT_tracking_editor_menus" :
648  "CLIP_MT_masking_editor_menus");
654  }
655  }
656  for (int i = 0; i < idname_array_len; i++) {
657  MenuType *mt = WM_menutype_find(idname_array[i], false);
658  if (mt != NULL) {
659  /* Check if this exists because of 'include_all_areas'. */
660  if (BLI_gset_add(menu_tagged, mt)) {
661  BLI_linklist_prepend(&menu_stack, mt);
662  }
663  }
664  }
665  }
666 #undef SPACE_MENU_MAP
667 #undef SPACE_MENU_NOP
668 
669  bool has_keymap_menu_items = false;
670 
671  while (menu_stack != NULL) {
672  MenuType *mt = BLI_linklist_pop(&menu_stack);
673  if (!WM_menutype_poll(C, mt)) {
674  continue;
675  }
676 
677  uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
678  uiLayout *layout = UI_block_layout(
679  block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
680 
682 
684  UI_menutype_draw(C, mt, layout);
685 
686  UI_block_end(C, block);
687 
688  LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
689  MenuType *mt_from_but = NULL;
690  /* Support menu titles with dynamic from initial labels
691  * (used by edit-mesh context menu). */
692  if (but->type == UI_BTYPE_LABEL) {
693 
694  /* Check if the label is the title. */
695  uiBut *but_test = but->prev;
696  while (but_test && but_test->type == UI_BTYPE_SEPR) {
697  but_test = but_test->prev;
698  }
699 
700  if (but_test == NULL) {
702  menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr));
703  }
704  }
706  data, memarena, mt, NULL, but, wm_context)) {
707  /* pass */
708  }
709  else if ((mt_from_but = UI_but_menutype_get(but))) {
710 
711  if (BLI_gset_add(menu_tagged, mt_from_but)) {
712  BLI_linklist_prepend(&menu_stack, mt_from_but);
713  }
714 
715  if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) {
716  struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena,
717  sizeof(*menu_parent));
718  /* Use brackets for menu key shortcuts,
719  * converting "Text|Some-Shortcut" to "Text (Some-Shortcut)".
720  * This is needed so we don't right align sub-menu contents
721  * we only want to do that for the last menu item, not the path that leads to it.
722  */
723  const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ?
724  strrchr(but->drawstr, UI_SEP_CHAR) :
725  NULL;
726  bool drawstr_is_empty = false;
727  if (drawstr_sep != NULL) {
728  BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
729  /* Detect empty string, fallback to menu name. */
730  const char *drawstr = but->drawstr;
731  int drawstr_len = drawstr_sep - but->drawstr;
732  if (UNLIKELY(drawstr_len == 0)) {
733  drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label);
734  drawstr_len = strlen(drawstr);
735  if (drawstr[0] == '\0') {
736  drawstr_is_empty = true;
737  }
738  }
739  BLI_dynstr_nappend(dyn_str, drawstr, drawstr_len);
740  BLI_dynstr_appendf(dyn_str, " (%s)", drawstr_sep + 1);
741  menu_parent->drawstr = strdup_memarena_from_dynstr(memarena, dyn_str);
742  BLI_dynstr_clear(dyn_str);
743  }
744  else {
745  const char *drawstr = but->drawstr;
746  if (UNLIKELY(drawstr[0] == '\0')) {
747  drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label);
748  if (drawstr[0] == '\0') {
749  drawstr_is_empty = true;
750  }
751  }
752  menu_parent->drawstr = strdup_memarena(memarena, drawstr);
753  }
754  menu_parent->parent_mt = mt;
755  BLI_ghash_insert(menu_parent_map, mt_from_but, menu_parent);
756 
757  if (drawstr_is_empty) {
758  printf("Warning: '%s' menu has empty 'bl_label'.\n", mt_from_but->idname);
759  }
760  }
761  }
762  else if (but->menu_create_func != NULL) {
763  /* A non 'MenuType' menu button. */
764 
765  /* Only expand one level deep, this is mainly for expanding operator menus. */
766  const char *drawstr_submenu = but->drawstr;
767 
768  /* +1 to avoid overlap with the current 'block'. */
769  uiBlock *sub_block = UI_block_begin(C, region, __func__ + 1, UI_EMBOSS);
770  uiLayout *sub_layout = UI_block_layout(
771  sub_block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
772 
774 
776 
777  but->menu_create_func(C, sub_layout, but->poin);
778 
779  UI_block_end(C, sub_block);
780 
781  LISTBASE_FOREACH (uiBut *, sub_but, &sub_block->buttons) {
783  data, memarena, mt, drawstr_submenu, sub_but, wm_context);
784  }
785 
786  if (region) {
787  BLI_remlink(&region->uiblocks, sub_block);
788  }
789  UI_block_free(NULL, sub_block);
790  }
791  }
792  if (region) {
793  BLI_remlink(&region->uiblocks, block);
794  }
795  UI_block_free(NULL, block);
796 
797  /* Add key-map items as a second pass,
798  * so all menus are accessed from the header & top-bar before key shortcuts are expanded. */
799  if ((menu_stack == NULL) && (has_keymap_menu_items == false)) {
800  has_keymap_menu_items = true;
802  C, win, area, region, &menu_stack, menu_to_kmi, menu_tagged);
803  }
804  }
805  }
806 
807  LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
808  item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt);
809  }
810 
811  GHASH_ITER (iter, menu_parent_map) {
812  struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter);
813  menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt);
814  }
815 
816  /* NOTE: currently this builds the full path for each menu item,
817  * that could be moved into the parent menu. */
818 
819  /* Set names as full paths. */
820  LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
821  BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
822 
823  if (include_all_areas) {
824  BLI_dynstr_appendf(dyn_str,
825  "%s: ",
826  (item->wm_context != NULL) ?
827  space_type_ui_items[item->wm_context->space_type_ui_index].name :
828  global_menu_prefix);
829  }
830 
831  if (item->menu_parent != NULL) {
832  struct MenuSearch_Parent *menu_parent = item->menu_parent;
833  menu_parent->temp_child = NULL;
834  while (menu_parent && menu_parent->parent) {
835  menu_parent->parent->temp_child = menu_parent;
836  menu_parent = menu_parent->parent;
837  }
838  while (menu_parent) {
839  BLI_dynstr_append(dyn_str, menu_parent->drawstr);
840  BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
841  menu_parent = menu_parent->temp_child;
842  }
843  }
844  else {
845  const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt);
846  if (drawstr == NULL) {
847  drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label);
848  }
849  BLI_dynstr_append(dyn_str, drawstr);
850 
851  wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt);
852  if (kmi != NULL) {
853  char kmi_str[128];
854  WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str));
855  BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str);
856  }
857 
858  BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
859  }
860 
861  /* Optional nested menu. */
862  if (item->drawstr_submenu != NULL) {
863  BLI_dynstr_append(dyn_str, item->drawstr_submenu);
864  BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
865  }
866 
867  BLI_dynstr_append(dyn_str, item->drawstr);
868 
869  item->drawwstr_full = strdup_memarena_from_dynstr(memarena, dyn_str);
870  BLI_dynstr_clear(dyn_str);
871  }
872  BLI_dynstr_free(dyn_str);
873 
874  /* Finally sort menu items.
875  *
876  * Note: we might want to keep the in-menu order, for now sort all. */
878 
879  BLI_ghash_free(menu_parent_map, NULL, NULL);
880  BLI_ghash_free(menu_display_name_map, NULL, NULL);
881 
882  BLI_ghash_free(menu_to_kmi, NULL, NULL);
883 
884  BLI_gset_free(menu_tagged, NULL);
885 
886  data->memarena = memarena;
887 
888  if (include_all_areas) {
889  CTX_wm_area_set(C, area_init);
890  CTX_wm_region_set(C, region_init);
891 
892  if (space_type_ui_items_free) {
893  MEM_freeN((void *)space_type_ui_items);
894  }
895  }
896 
897  /* Include all operators for developers,
898  * since it can be handy to have a quick way to access any operator,
899  * including operators being developed which haven't yet been added into the interface.
900  *
901  * These are added after all menu items so developers still get normal behavior by default,
902  * unless searching for something that isn't already in a menu (or scroll down).
903  *
904  * Keep this behind a developer only check:
905  * - Many operators need options to be set to give useful results, see: T74157.
906  * - User who really prefer to list all operators can use #WM_OT_search_operator.
907  */
908  if (U.flag & USER_DEVELOPER_UI) {
910  }
911 
912  return data;
913 }
914 
915 static void menu_search_arg_free_fn(void *data_v)
916 {
917  struct MenuSearch_Data *data = data_v;
918  LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
919  switch (item->type) {
920  case MENU_SEARCH_TYPE_OP: {
921  if (item->op.opptr != NULL) {
922  WM_operator_properties_free(item->op.opptr);
923  MEM_freeN(item->op.opptr);
924  }
925  }
926  case MENU_SEARCH_TYPE_RNA: {
927  break;
928  }
929  }
930  }
931 
932  BLI_memarena_free(data->memarena);
933 
934  MEM_freeN(data);
935 }
936 
937 static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
938 {
939  struct MenuSearch_Item *item = arg2;
940  if (item == NULL) {
941  return;
942  }
943  if (item->state & UI_BUT_DISABLED) {
944  return;
945  }
946 
947  ScrArea *area_prev = CTX_wm_area(C);
948  ARegion *region_prev = CTX_wm_region(C);
949 
950  if (item->wm_context != NULL) {
951  CTX_wm_area_set(C, item->wm_context->area);
953  }
954 
955  switch (item->type) {
956  case MENU_SEARCH_TYPE_OP: {
957  CTX_store_set(C, item->op.context);
958  WM_operator_name_call_ptr(C, item->op.type, item->op.opcontext, item->op.opptr);
959  CTX_store_set(C, NULL);
960  break;
961  }
962  case MENU_SEARCH_TYPE_RNA: {
963  PointerRNA *ptr = &item->rna.ptr;
964  PropertyRNA *prop = item->rna.prop;
965  const int index = item->rna.index;
966  const int prop_type = RNA_property_type(prop);
967  bool changed = false;
968 
969  if (prop_type == PROP_BOOLEAN) {
970  const bool is_array = RNA_property_array_check(prop);
971  if (is_array) {
972  const bool value = RNA_property_boolean_get_index(ptr, prop, index);
974  }
975  else {
976  const bool value = RNA_property_boolean_get(ptr, prop);
978  }
979  changed = true;
980  }
981  else if (prop_type == PROP_ENUM) {
982  RNA_property_enum_set(ptr, prop, item->rna.enum_value);
983  changed = true;
984  }
985 
986  if (changed) {
988  }
989  break;
990  }
991  }
992 
993  if (item->wm_context != NULL) {
994  CTX_wm_area_set(C, area_prev);
995  CTX_wm_region_set(C, region_prev);
996  }
997 }
998 
1000  void *arg,
1001  const char *str,
1002  uiSearchItems *items,
1003  const bool UNUSED(is_first))
1004 {
1005  struct MenuSearch_Data *data = arg;
1006 
1007  StringSearch *search = BLI_string_search_new();
1008 
1009  LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
1010  BLI_string_search_add(search, item->drawwstr_full, item);
1011  }
1012 
1013  struct MenuSearch_Item **filtered_items;
1014  const int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items);
1015 
1016  for (int i = 0; i < filtered_amount; i++) {
1017  struct MenuSearch_Item *item = filtered_items[i];
1018  if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state, 0)) {
1019  break;
1020  }
1021  }
1022 
1023  MEM_freeN(filtered_items);
1024  BLI_string_search_free(search);
1025 }
1026 
1029 /* -------------------------------------------------------------------- */
1038  void *arg,
1039  void *active,
1040  const struct wmEvent *UNUSED(event))
1041 {
1042  struct MenuSearch_Data *data = arg;
1043  struct MenuSearch_Item *item = active;
1044  bool has_menu = false;
1045 
1046  memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
1047  uiBut *but = &data->context_menu_data.but;
1048  uiBlock *block = &data->context_menu_data.block;
1049 
1050  but->block = block;
1051 
1052  if (menu_items_to_ui_button(item, but)) {
1053  ScrArea *area_prev = CTX_wm_area(C);
1054  ARegion *region_prev = CTX_wm_region(C);
1055 
1056  if (item->wm_context != NULL) {
1057  CTX_wm_area_set(C, item->wm_context->area);
1059  }
1060 
1061  if (ui_popup_context_menu_for_button(C, but)) {
1062  has_menu = true;
1063  }
1064 
1065  if (item->wm_context != NULL) {
1066  CTX_wm_area_set(C, area_prev);
1067  CTX_wm_region_set(C, region_prev);
1068  }
1069  }
1070 
1071  return has_menu;
1072 }
1073 
1076 /* -------------------------------------------------------------------- */
1081  struct ARegion *region,
1082  const rcti *UNUSED(item_rect),
1083  void *arg,
1084  void *active)
1085 {
1086  struct MenuSearch_Data *data = arg;
1087  struct MenuSearch_Item *item = active;
1088 
1089  memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
1090  uiBut *but = &data->context_menu_data.but;
1091  uiBlock *block = &data->context_menu_data.block;
1092  unit_m4(block->winmat);
1093  block->aspect = 1;
1094 
1095  but->block = block;
1096 
1097  /* Place the fake button at the cursor so the tool-tip is places properly. */
1098  float tip_init[2];
1099  const wmEvent *event = CTX_wm_window(C)->eventstate;
1100  tip_init[0] = event->x;
1101  tip_init[1] = event->y - (UI_UNIT_Y / 2);
1102  ui_window_to_block_fl(region, block, &tip_init[0], &tip_init[1]);
1103 
1104  but->rect.xmin = tip_init[0];
1105  but->rect.xmax = tip_init[0];
1106  but->rect.ymin = tip_init[1];
1107  but->rect.ymax = tip_init[1];
1108 
1109  if (menu_items_to_ui_button(item, but)) {
1110  ScrArea *area_prev = CTX_wm_area(C);
1111  ARegion *region_prev = CTX_wm_region(C);
1112 
1113  if (item->wm_context != NULL) {
1114  CTX_wm_area_set(C, item->wm_context->area);
1116  }
1117 
1118  ARegion *region_tip = UI_tooltip_create_from_button(C, region, but, false);
1119 
1120  if (item->wm_context != NULL) {
1121  CTX_wm_area_set(C, area_prev);
1122  CTX_wm_region_set(C, region_prev);
1123  }
1124  return region_tip;
1125  }
1126 
1127  return NULL;
1128 }
1129 
1132 /* -------------------------------------------------------------------- */
1137 {
1138  bContext *C = but->block->evil_C;
1139  wmWindow *win = CTX_wm_window(C);
1140  ScrArea *area = CTX_wm_area(C);
1141  ARegion *region = CTX_wm_region(C);
1142  /* When run from top-bar scan all areas in the current window. */
1143  const bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR));
1145  C, win, area, region, include_all_areas);
1147  /* Generic callback. */
1150  data,
1151  false,
1154  NULL);
1155 
1159 }
1160 
1162 {
1163  uiBlock *block;
1164  uiBut *but;
1165  static char search[256] = "";
1166 
1167  block = uiLayoutGetBlock(layout);
1169 
1170  but = uiDefSearchBut(
1171  block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, "");
1173 }
1174 
1175 #undef MENU_SEP
1176 
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
void CTX_store_set(bContext *C, bContextStore *store)
Definition: context.c:186
void CTX_wm_region_set(bContext *C, struct ARegion *region)
Definition: context.c:985
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
void CTX_wm_area_set(bContext *C, struct ScrArea *area)
Definition: context.c:973
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
@ G_DEBUG_WM
Definition: BKE_global.h:138
struct ARegion * BKE_area_find_region_type(const struct ScrArea *area, int type)
#define BLI_assert(a)
Definition: BLI_assert.h:58
A dynamically sized string ADT.
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL()
Definition: BLI_dynstr.c:133
int BLI_dynstr_get_len(DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_dynstr.c:286
void BLI_dynstr_clear(DynStr *ds) ATTR_NONNULL()
Definition: BLI_dynstr.c:335
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition: BLI_dynstr.c:358
DynStr * BLI_dynstr_new_memarena(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_dynstr.c:86
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
void BLI_dynstr_get_cstring_ex(DynStr *__restrict ds, char *__restrict rets) ATTR_NONNULL()
Definition: BLI_dynstr.c:299
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL()
Definition: BLI_dynstr.c:107
struct GSet GSet
Definition: BLI_ghash.h:189
void BLI_ghashIterator_step(GHashIterator *ghi)
Definition: BLI_ghash.c:1086
BLI_INLINE bool BLI_ghashIterator_done(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:158
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:150
#define GHASH_ITER(gh_iter_, ghash_)
Definition: BLI_ghash.h:169
GSet * BLI_gset_ptr_new(const char *info)
bool BLI_ghash_haskey(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:941
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:851
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:1160
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1211
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void void BLI_listbase_sort(struct ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
void unit_m4(float m[4][4])
Definition: rct.c:1140
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:109
#define BLI_MEMARENA_STD_BUFSIZE
Definition: BLI_memarena.h:36
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:131
struct MemArena * BLI_memarena_new(const size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:79
void * BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:168
#define STR_ELEM(...)
Definition: BLI_string.h:218
#define STRNCPY(dst, src)
Definition: BLI_string.h:163
#define SNPRINTF(dst, format,...)
Definition: BLI_string.h:165
bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL()
Definition: string.c:1040
void BLI_string_search_free(StringSearch *search)
void BLI_string_search_add(StringSearch *search, const char *str, void *user_data)
StringSearch * BLI_string_search_new(void)
int BLI_string_search_query(StringSearch *search, const char *query, void ***r_data)
#define BLI_string_joinN(...)
unsigned int uint
Definition: BLI_sys_types.h:83
#define ARRAY_SIZE(arr)
#define UNUSED(x)
#define UNLIKELY(x)
#define ELEM(...)
#define CTX_IFACE_(context, msgid)
@ SACTCONT_TIMELINE
#define MAX_NAME
Definition: DNA_defs.h:62
Object is a sort of wrapper for general info.
@ RGN_TYPE_WINDOW
eSpace_Type
@ SPACE_TEXT
@ SPACE_CLIP
@ SPACE_ACTION
@ SPACE_CONSOLE
@ SPACE_OUTLINER
@ SPACE_STATUSBAR
@ SPACE_TOPBAR
@ SPACE_NODE
@ SPACE_SPREADSHEET
@ SPACE_USERPREF
@ SPACE_FILE
@ SPACE_PROPERTIES
@ SPACE_NLA
@ SPACE_SEQ
@ SPACE_EMPTY
@ SPACE_SCRIPT
@ SPACE_IMAGE
@ SPACE_GRAPH
@ SPACE_VIEW3D
@ SPACE_INFO
@ SC_MODE_TRACKING
@ USER_DEVELOPER_UI
#define OP_MAX_TYPENAME
Read Guarded memory(de)allocation.
StructRNA RNA_Area
@ PROP_BOOLEAN
Definition: RNA_types.h:73
@ PROP_ENUM
Definition: RNA_types.h:77
#define C
Definition: RandGen.cpp:39
#define UI_UNIT_Y
uiBlock * uiLayoutGetBlock(uiLayout *layout)
@ UI_EMBOSS
Definition: UI_interface.h:107
const struct uiStyle * UI_style_get_dpi(void)
void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
@ UI_BUT_REDALERT
Definition: UI_interface.h:204
@ UI_BUT_DISABLED
Definition: UI_interface.h:199
@ UI_BUT_INACTIVE
Definition: UI_interface.h:206
@ UI_BUT_HAS_SEP_CHAR
Definition: UI_interface.h:225
struct ARegion * UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but, bool is_label)
@ UI_LAYOUT_MENU
void UI_menutype_draw(struct bContext *C, struct MenuType *mt, struct uiLayout *layout)
#define UI_SEP_CHAR
Definition: UI_interface.h:86
bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid, int state, const uint8_t name_prefix_offset)
void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn)
Definition: interface.c:6691
void UI_but_func_search_set(uiBut *but, uiButSearchCreateFn search_create_fn, uiButSearchUpdateFn search_update_fn, void *arg, const bool free_arg, uiButSearchArgFreeFn search_arg_free_fn, uiButHandleFunc search_exec_fn, void *active)
Definition: interface.c:6613
void UI_block_end(const struct bContext *C, uiBlock *block)
void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn)
Definition: interface.c:6671
@ UI_BLOCK_SHOW_SHORTCUT_ALWAYS
Definition: UI_interface.h:165
uiLayout * UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, const struct uiStyle *style)
struct MenuType * UI_but_menutype_get(uiBut *but)
void UI_block_free(const struct bContext *C, uiBlock *block)
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
Definition: interface.c:6683
uiBlock * UI_block_begin(const struct bContext *C, struct ARegion *region, const char *name, eUIEmbossType emboss)
uiBut * uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, int x, int y, short width, short height, float a1, float a2, const char *tip)
Definition: interface.c:6573
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout)
#define UI_UNIT_X
@ UI_LAYOUT_VERTICAL
void UI_block_flag_enable(uiBlock *block, int flag)
Definition: interface.c:6067
@ UI_BTYPE_LABEL
Definition: UI_interface.h:358
@ UI_BTYPE_SEPR
Definition: UI_interface.h:386
@ WM_HANDLER_DO_FREE
Definition: WM_api.h:318
@ OPTYPE_INTERNAL
Definition: WM_types.h:175
@ WM_OP_INVOKE_REGION_WIN
Definition: WM_types.h:198
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:197
unsigned int U
Definition: btGjkEpa3.h:78
#define str(s)
void ui_window_to_block_fl(const ARegion *region, uiBlock *block, float *r_x, float *r_y)
Definition: interface.c:190
bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
#define UI_MENU_PADDING
struct ARegion * ui_searchbox_create_menu(struct bContext *C, struct ARegion *butregion, uiButSearch *search_but)
int ui_but_icon(const uiBut *but)
static const char * strdup_memarena(MemArena *memarena, const char *str)
static const char * strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str)
static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *data)
static bool ui_search_menu_create_context_menu(struct bContext *C, void *arg, void *active, const struct wmEvent *UNUSED(event))
static void menu_types_add_from_keymap_items(bContext *C, wmWindow *win, ScrArea *area, ARegion *region, LinkNode **menuid_stack_p, GHash *menu_to_kmi, GSet *menu_tagged)
static struct ARegion * ui_search_menu_create_tooltip(struct bContext *C, struct ARegion *region, const rcti *UNUSED(item_rect), void *arg, void *active)
static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data, MemArena *memarena, struct MenuType *mt, const char *drawstr_submenu, uiBut *but, struct MenuSearch_Context *wm_context)
void UI_but_func_menu_search(uiBut *but)
void uiTemplateMenuSearch(uiLayout *layout)
static struct MenuSearch_Data * menu_items_from_ui_create(bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas)
#define SPACE_MENU_NOP(space_type)
static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
static void menu_search_update_fn(const bContext *UNUSED(C), void *arg, const char *str, uiSearchItems *items, const bool UNUSED(is_first))
static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v)
#define SPACE_MENU_MAP(space_type, menu_id)
static void menu_search_arg_free_fn(void *data_v)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static void area(int d1, int d2, int e1, int e2, float weights[2])
bool active
all scheduled work for the GPU.
void RNA_property_boolean_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, bool value)
Definition: rna_access.c:2530
bool RNA_property_array_check(PropertyRNA *prop)
Definition: rna_access.c:1223
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
PropertyType RNA_property_type(PropertyRNA *prop)
Definition: rna_access.c:1155
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
Definition: rna_access.c:3562
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2317
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2331
const char * RNA_property_translation_context(const PropertyRNA *prop)
Definition: rna_access.c:2063
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
Definition: rna_access.c:6514
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
Definition: rna_access.c:2358
bool RNA_property_enum_item_from_value_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, EnumPropertyItem *r_item)
Definition: rna_access.c:2008
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3543
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
Definition: rna_access.c:1902
void RNA_property_enum_items(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
Definition: rna_access.c:1657
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
Definition: rna_access.c:2453
const char * RNA_property_ui_name(const PropertyRNA *prop)
Definition: rna_access.c:2043
ListBase handlers
ListBase uiblocks
const char * name
Definition: RNA_types.h:450
struct MenuSearch_Data::@416 context_menu_data
enum MenuSearch_Item::@411 type
struct MenuSearch_Parent * menu_parent
struct MenuSearch_Item * prev
struct MenuSearch_Item::@412::@415 rna
struct MenuSearch_Item * next
struct MenuSearch_Item::@412::@414 op
struct MenuSearch_Context * wm_context
struct MenuSearch_Parent * parent
struct MenuSearch_Parent * temp_child
char label[BKE_ST_MAXNAME]
Definition: BKE_screen.h:376
char idname[BKE_ST_MAXNAME]
Definition: BKE_screen.h:375
char translation_context[BKE_ST_MAXNAME]
Definition: BKE_screen.h:377
ListBase areabase
float xmax
Definition: DNA_vec_types.h:85
float xmin
Definition: DNA_vec_types.h:85
float ymax
Definition: DNA_vec_types.h:86
float ymin
Definition: DNA_vec_types.h:86
float winmat[4][4]
ListBase buttons
void * evil_C
struct bContextStore * context
struct uiBut * prev
eButType type
float hardmax
uiBlock * block
BIFIconID icon
struct PointerRNA * opptr
struct wmOperatorType * optype
short opcontext
char drawstr[UI_MAX_DRAW_STR]
char strdata[UI_MAX_NAME_STR]
struct PropertyRNA * rnaprop
char * str
struct PointerRNA rnapoin
int x
Definition: WM_types.h:581
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
const char * translation_context
Definition: WM_types.h:724
struct wmEvent * eventstate
#define G(x, y, z)
bool WM_operator_poll(bContext *C, wmOperatorType *ot)
wmKeyMap * WM_event_get_keymap_from_handler(wmWindowManager *wm, wmEventHandler_Keymap *handler)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, short context, PointerRNA *properties)
@ WM_HANDLER_TYPE_KEYMAP
PointerRNA * ptr
Definition: wm_files.c:3157
wmOperatorType * ot
Definition: wm_files.c:3156
int WM_keymap_item_to_string(const wmKeyMapItem *kmi, const bool compact, char *result, const int result_len)
Definition: wm_keymap.c:1213
bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
Definition: wm_keymap.c:451
void WM_menutype_iter(GHashIterator *ghi)
Definition: wm_menu_type.c:60
MenuType * WM_menutype_find(const char *idname, bool quiet)
Definition: wm_menu_type.c:44
bool WM_menutype_poll(bContext *C, MenuType *mt)
Definition: wm_menu_type.c:102
void WM_operatortype_iter(GHashIterator *ghi)
const char * WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *properties)
void WM_operator_py_idname(char *to, const char *from)
Definition: wm_operators.c:123
void WM_operator_properties_free(PointerRNA *ptr)
Definition: wm_operators.c:711
bScreen * WM_window_get_active_screen(const wmWindow *win)
Definition: wm_window.c:2372