Blender V4.3
interface_template_search_menu.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12#include <cstdio>
13#include <cstring>
14
15#include "MEM_guardedalloc.h"
16
17#include "DNA_action_types.h"
18#include "DNA_node_types.h"
19#include "DNA_scene_types.h"
20#include "DNA_texture_types.h"
21
22#include "BLI_dynstr.h"
23#include "BLI_ghash.h"
24#include "BLI_listbase.h"
25#include "BLI_map.hh"
26#include "BLI_math_matrix.h"
27#include "BLI_memarena.h"
28#include "BLI_set.hh"
29#include "BLI_stack.hh"
30#include "BLI_string.h"
31#include "BLI_utildefines.h"
32
33#include "BLT_translation.hh"
34
35#include "BKE_context.hh"
36#include "BKE_global.hh"
37#include "BKE_screen.hh"
38
39#include "ED_screen.hh"
40
41#include "RNA_access.hh"
42#include "RNA_prototypes.hh"
43
44#include "WM_api.hh"
45#include "WM_types.hh"
46
47#include "UI_interface.hh"
48#include "UI_string_search.hh"
49#include "interface_intern.hh"
50
51/* For key-map item access. */
52#include "wm_event_system.hh"
53
54/* -------------------------------------------------------------------- */
72
80
119
132
133static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v)
134{
135 const MenuSearch_Item *menu_item_a = (MenuSearch_Item *)menu_item_a_v;
136 const MenuSearch_Item *menu_item_b = (MenuSearch_Item *)menu_item_b_v;
137 return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full);
138}
139
140static const char *strdup_memarena(MemArena *memarena, const char *str)
141{
142 const uint str_size = strlen(str) + 1;
143 char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size);
144 memcpy(str_dst, str, str_size);
145 return str_dst;
146}
147
148static const char *strdup_memarena_from_dynstr(MemArena *memarena, const DynStr *dyn_str)
149{
150 const uint str_size = BLI_dynstr_get_len(dyn_str) + 1;
151 char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size);
152 BLI_dynstr_get_cstring_ex(dyn_str, str_dst);
153 return str_dst;
154}
155
157 MemArena *memarena,
158 MenuType *mt,
159 uiBut *but,
160 MenuSearch_Context *wm_context,
161 MenuSearch_Parent *menu_parent)
162{
163 using namespace blender;
164 MenuSearch_Item *item = nullptr;
165
166 /* Use override if the name is empty, this can happen with popovers. */
167 std::string drawstr_override;
168 const size_t sep_index = (but->flag & UI_BUT_HAS_SEP_CHAR) ? but->drawstr.find(UI_SEP_CHAR) :
169 std::string::npos;
170 const bool drawstr_is_empty = sep_index == 0 || but->drawstr.empty();
171
172 if (but->optype != nullptr) {
173 if (drawstr_is_empty) {
174 drawstr_override = WM_operatortype_name(but->optype, but->opptr);
175 }
176
177 item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item));
179 item->weight = but->search_weight;
180
181 item->op.type = but->optype;
182 item->op.opcontext = but->opcontext;
183 item->op.context = but->context ? MEM_new<bContextStore>(__func__, *but->context) : nullptr;
184 item->op.opptr = but->opptr;
185 but->opptr = nullptr;
186 }
187 else if (but->rnaprop != nullptr) {
188 const int prop_type = RNA_property_type(but->rnaprop);
189
190 if (drawstr_is_empty) {
191 if (prop_type == PROP_ENUM) {
192 const int value_enum = int(but->hardmax);
193 EnumPropertyItem enum_item;
195 &but->rnapoin,
196 but->rnaprop,
197 value_enum,
198 &enum_item))
199 {
200 drawstr_override = enum_item.name;
201 }
202 else {
203 /* Should never happen. */
204 drawstr_override = "Unknown";
205 }
206 }
207 else {
208 drawstr_override = RNA_property_ui_name(but->rnaprop);
209 }
210 }
211
212 if (!ELEM(prop_type, PROP_BOOLEAN, PROP_ENUM)) {
213 /* Note that these buttons are not prevented,
214 * but aren't typically used in menus. */
215 printf("Button '%s' in menu '%s' is a menu item with unsupported RNA type %d\n",
216 but->drawstr.c_str(),
217 mt->idname,
218 prop_type);
219 }
220 else {
221 item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item));
223 item->weight = but->search_weight;
224
225 item->rna.ptr = but->rnapoin;
226 item->rna.prop = but->rnaprop;
227 item->rna.index = but->rnaindex;
228
229 if (prop_type == PROP_ENUM) {
230 item->rna.enum_value = int(but->hardmax);
231 }
232 }
233 }
234
235 if (item != nullptr) {
236 /* Handle shared settings. */
237 if (!drawstr_override.empty()) {
238 const StringRef drawstr_suffix = sep_index == std::string::npos ?
239 "" :
240 StringRef(but->drawstr).drop_prefix(sep_index);
241 std::string drawstr = std::string("(") + drawstr_override + ")" + drawstr_suffix;
242 item->drawstr = strdup_memarena(memarena, drawstr.c_str());
243 }
244 else {
245 item->drawstr = strdup_memarena(memarena, but->drawstr.c_str());
246 }
247
248 item->icon = ui_but_icon(but);
249 item->state = (but->flag &
251 item->mt = mt;
252
253 item->wm_context = wm_context;
254 item->menu_parent = menu_parent;
255
256 BLI_addtail(&data->items, item);
257 return true;
258 }
259
260 return false;
261}
262
267{
268 bool changed = false;
269 switch (item->type) {
271 but->optype = item->op.type;
272 but->opcontext = item->op.opcontext;
273 but->context = item->op.context;
274 but->opptr = item->op.opptr;
275 changed = true;
276 break;
277 }
279 const int prop_type = RNA_property_type(item->rna.prop);
280
281 but->rnapoin = item->rna.ptr;
282 but->rnaprop = item->rna.prop;
283 but->rnaindex = item->rna.index;
284
285 if (prop_type == PROP_ENUM) {
286 but->hardmax = item->rna.enum_value;
287 }
288 changed = true;
289 break;
290 }
291 }
292
293 if (changed) {
294 but->drawstr = item->drawstr;
295 const size_t sep_index = but->drawstr.find(UI_SEP_CHAR);
296
297 if (sep_index != std::string::npos) {
298 but->drawstr.resize(sep_index);
299 }
300
301 but->icon = item->icon;
302 }
303
304 return changed;
305}
306
308 MenuType *mt = nullptr;
312 std::optional<bContextStore> context;
313};
314
319 wmWindow *win,
320 ScrArea *area,
321 ARegion *region,
324 blender::Set<MenuType *> &menu_tagged)
325{
327 ListBase *handlers[] = {
328 region ? &region->handlers : nullptr,
329 area ? &area->handlers : nullptr,
330 &win->handlers,
331 };
332
333 for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
334 if (handlers[handler_index] == nullptr) {
335 continue;
336 }
337 LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) {
338 /* During this loop, UI handlers for nested menus can tag multiple handlers free. */
339 if (handler_base->flag & WM_HANDLER_DO_FREE) {
340 continue;
341 }
342 if (handler_base->type != WM_HANDLER_TYPE_KEYMAP) {
343 continue;
344 }
345
346 if (handler_base->poll == nullptr || handler_base->poll(region, win->eventstate)) {
347 wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
349 WM_event_get_keymaps_from_handler(wm, win, handler, &km_result);
350 for (int km_index = 0; km_index < km_result.keymaps_len; km_index++) {
351 wmKeyMap *keymap = km_result.keymaps[km_index];
352 if (keymap && WM_keymap_poll(C, keymap)) {
353 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
354 if (kmi->flag & KMI_INACTIVE) {
355 continue;
356 }
357 if (STR_ELEM(kmi->idname, "WM_OT_call_menu", "WM_OT_call_menu_pie")) {
358 char menu_idname[MAX_NAME];
359 RNA_string_get(kmi->ptr, "name", menu_idname);
360 MenuType *mt = WM_menutype_find(menu_idname, false);
361
362 if (mt && menu_tagged.add(mt)) {
363 /* Unlikely, but possible this will be included twice. */
364 menu_stack.push({mt});
365 menu_to_kmi.add(mt, kmi);
366 }
367 }
368 }
369 }
370 }
371 }
372 }
373 }
374}
375
380{
381 /* Add to temporary list so we can sort them separately. */
382 ListBase operator_items = {nullptr, nullptr};
383
384 MemArena *memarena = data->memarena;
386 if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
387 continue;
388 }
389
390 if (WM_operator_poll((bContext *)C, ot)) {
391 const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
392
393 MenuSearch_Item *item = nullptr;
394 item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item));
396
397 item->op.type = ot;
399 item->op.context = nullptr;
400
401 char idname_as_py[OP_MAX_TYPENAME];
402 char uiname[256];
403 WM_operator_py_idname(idname_as_py, ot->idname);
404
405 SNPRINTF(uiname, "%s " UI_MENU_ARROW_SEP "%s", idname_as_py, ot_ui_name);
406
407 item->drawwstr_full = strdup_memarena(memarena, uiname);
408 item->drawstr = ot_ui_name;
409
410 item->wm_context = nullptr;
411
412 BLI_addtail(&operator_items, item);
413 }
414 }
415
417
418 BLI_movelisttolist(&data->items, &operator_items);
419}
420
428 wmWindow *win,
429 ScrArea *area_init,
430 ARegion *region_init,
431 bool include_all_areas,
432 const char *single_menu_idname)
433{
435 blender::Map<MenuType *, const char *> menu_display_name_map;
436 const uiStyle *style = UI_style_get_dpi();
437
438 /* Convert into non-ui structure. */
439 MenuSearch_Data *data = MEM_new<MenuSearch_Data>(__func__);
440
441 DynStr *dyn_str = BLI_dynstr_new_memarena();
442
443 /* Use a stack of menus to handle and discover new menus in passes. */
445
446 /* Tag menu types not to add, either because they have already been added
447 * or they have been blacklisted. */
448 blender::Set<MenuType *> menu_tagged;
450
451 /* Blacklist menus we don't want to show. */
452 {
453 const char *idname_array[] = {
454 /* While we could include this, it's just showing filenames to load. */
455 (single_menu_idname && STREQ(single_menu_idname, "TOPBAR_MT_file_open_recent")) ?
456 nullptr :
457 "TOPBAR_MT_file_open_recent",
458 /* Showing undo history is not helpful since users may accidentally undo
459 * an action they intend to run. */
460 "TOPBAR_MT_undo_history",
461 };
462 for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
463 if (!idname_array[i]) {
464 continue;
465 }
466 MenuType *mt = WM_menutype_find(idname_array[i], false);
467 if (mt != nullptr) {
468 menu_tagged.add(mt);
469 }
470 }
471 }
472
473 if (!single_menu_idname) {
474 /* Exclude context menus (when not searching in a specific single menu) because:
475 * - The menu items are available elsewhere (and will show up multiple times).
476 * - Menu items depend on exact context, making search results unpredictable
477 * (exact number of items selected for example). See design doc #74158.
478 * There is one exception,
479 * as the outliner only exposes functionality via the context menu. */
480 GHashIterator iter;
481
484 if (BLI_str_endswith(mt->idname, "_context_menu")) {
485 menu_tagged.add(mt);
486 }
487 }
488 const char *idname_array[] = {
489 /* Add back some context menus. */
490 "OUTLINER_MT_context_menu",
491 };
492 for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
493 MenuType *mt = WM_menutype_find(idname_array[i], false);
494 if (mt != nullptr) {
495 menu_tagged.remove(mt);
496 }
497 }
498 }
499
500 /* Collect contexts, one for each 'ui_type'. */
501 MenuSearch_Context *wm_contexts = nullptr;
502
503 const EnumPropertyItem *space_type_ui_items = nullptr;
504 int space_type_ui_items_len = 0;
505 bool space_type_ui_items_free = false;
506
507 /* Text used as prefix for top-bar menu items. */
508 const char *global_menu_prefix = nullptr;
509
510 if (include_all_areas) {
512
513 /* First create arrays for ui_type. */
514 PropertyRNA *prop_ui_type = nullptr;
515 {
516 /* This must be a valid pointer, with only it's type checked. */
517 ScrArea area_dummy{};
518 /* Anything besides #SPACE_EMPTY is fine,
519 * as this value is only included in the enum when set. */
520 area_dummy.spacetype = SPACE_TOPBAR;
521 PointerRNA ptr = RNA_pointer_create(&screen->id, &RNA_Area, &area_dummy);
522 prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
524 &ptr,
525 prop_ui_type,
526 &space_type_ui_items,
527 &space_type_ui_items_len,
528 &space_type_ui_items_free);
529
531 memarena, sizeof(*wm_contexts) * space_type_ui_items_len);
532 for (int i = 0; i < space_type_ui_items_len; i++) {
533 wm_contexts[i].space_type_ui_index = -1;
534 }
535 }
536
537 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
539 if (region != nullptr) {
540 PointerRNA ptr = RNA_pointer_create(&screen->id, &RNA_Area, area);
541 const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type);
542
543 const int space_type_ui_index = RNA_enum_from_value(space_type_ui_items, space_type_ui);
544 if (space_type_ui_index == -1) {
545 continue;
546 }
547
548 if (wm_contexts[space_type_ui_index].space_type_ui_index != -1) {
549 ScrArea *area_best = wm_contexts[space_type_ui_index].area;
550 const uint value_best = uint(area_best->winx) * uint(area_best->winy);
551 const uint value_test = uint(area->winx) * uint(area->winy);
552 if (value_best > value_test) {
553 continue;
554 }
555 }
556
557 wm_contexts[space_type_ui_index].space_type_ui_index = space_type_ui_index;
558 wm_contexts[space_type_ui_index].area = area;
559 wm_contexts[space_type_ui_index].region = region;
560 }
561 }
562
563 global_menu_prefix = CTX_IFACE_(RNA_property_translation_context(prop_ui_type), "Top Bar");
564 }
565
566 for (int space_type_ui_index = -1; space_type_ui_index < space_type_ui_items_len;
567 space_type_ui_index += 1)
568 {
569
570 ScrArea *area = nullptr;
571 ARegion *region = nullptr;
572 MenuSearch_Context *wm_context = nullptr;
573
574 if (include_all_areas) {
575 if (space_type_ui_index == -1) {
576 /* First run without any context, to populate the top-bar without. */
577 wm_context = nullptr;
578 area = nullptr;
579 region = nullptr;
580 }
581 else {
582 wm_context = &wm_contexts[space_type_ui_index];
583 if (wm_context->space_type_ui_index == -1) {
584 continue;
585 }
586
587 area = wm_context->area;
588 region = wm_context->region;
589
590 CTX_wm_area_set(C, area);
591 CTX_wm_region_set(C, region);
592 }
593 }
594 else {
595 area = area_init;
596 region = region_init;
597 }
598
599 if (single_menu_idname) {
600 if (MenuType *mt = WM_menutype_find(single_menu_idname, false)) {
601 if (menu_tagged.add(mt)) {
602 menu_stack.push({mt});
603 }
604 }
605 }
606 else {
607 /* Populate menus from the editors,
608 * note that we could create a fake header, draw the header and extract the menus
609 * from the buttons, however this is quite involved and can be avoided as by convention
610 * each space-type has a single root-menu that headers use. */
611 const char *idname_array[2] = {nullptr};
612 int idname_array_len = 0;
613
614 /* Use negative for global (no area) context, populate the top-bar. */
615 if (space_type_ui_index == -1) {
616 idname_array[idname_array_len++] = "TOPBAR_MT_editor_menus";
617 }
618
619#define SPACE_MENU_MAP(space_type, menu_id) \
620 case space_type: \
621 idname_array[idname_array_len++] = menu_id; \
622 break
623#define SPACE_MENU_NOP(space_type) \
624 case space_type: \
625 break
626
627 if (area != nullptr) {
628 SpaceLink *sl = (SpaceLink *)area->spacedata.first;
629 switch ((eSpace_Type)area->spacetype) {
630 SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus");
631 SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus");
632 SPACE_MENU_MAP(SPACE_OUTLINER, "OUTLINER_MT_editor_menus");
634 SPACE_MENU_MAP(SPACE_FILE, "FILEBROWSER_MT_editor_menus");
635 SPACE_MENU_MAP(SPACE_IMAGE, "IMAGE_MT_editor_menus");
636 SPACE_MENU_MAP(SPACE_INFO, "INFO_MT_editor_menus");
637 SPACE_MENU_MAP(SPACE_SEQ, "SEQUENCER_MT_editor_menus");
638 SPACE_MENU_MAP(SPACE_TEXT, "TEXT_MT_editor_menus");
640 (((const SpaceAction *)sl)->mode == SACTCONT_TIMELINE) ?
641 "TIME_MT_editor_menus" :
642 "DOPESHEET_MT_editor_menus");
643 SPACE_MENU_MAP(SPACE_NLA, "NLA_MT_editor_menus");
644 SPACE_MENU_MAP(SPACE_NODE, "NODE_MT_editor_menus");
645 SPACE_MENU_MAP(SPACE_CONSOLE, "CONSOLE_MT_editor_menus");
646 SPACE_MENU_MAP(SPACE_USERPREF, "USERPREF_MT_editor_menus");
648 (((const SpaceClip *)sl)->mode == SC_MODE_TRACKING) ?
649 "CLIP_MT_tracking_editor_menus" :
650 "CLIP_MT_masking_editor_menus");
656 }
657 }
658 for (int i = 0; i < idname_array_len; i++) {
659 MenuType *mt = WM_menutype_find(idname_array[i], false);
660 if (mt != nullptr) {
661 /* Check if this exists because of 'include_all_areas'. */
662 if (menu_tagged.add(mt)) {
663 menu_stack.push({mt});
664 }
665 }
666 }
667 }
668#undef SPACE_MENU_MAP
669#undef SPACE_MENU_NOP
670
671 bool has_keymap_menu_items = false;
672
673 while (!menu_stack.is_empty()) {
674 MenuStackEntry current_menu = menu_stack.pop();
675 MenuType *mt = current_menu.mt;
676 if (!WM_menutype_poll(C, mt)) {
677 continue;
678 }
679
680 uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
681 uiLayout *layout = UI_block_layout(
682 block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
683
685
686 if (current_menu.context.has_value()) {
687 uiLayoutContextCopy(layout, &*current_menu.context);
688 }
690 UI_menutype_draw(C, mt, layout);
691
692 UI_block_end(C, block);
693
694 LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
695 MenuType *mt_from_but = nullptr;
696 /* Support menu titles with dynamic from initial labels
697 * (used by edit-mesh context menu). */
698 if (but->type == UI_BTYPE_LABEL) {
699
700 /* Check if the label is the title. */
701 uiBut *but_test = but->prev;
702 while (but_test && but_test->type == UI_BTYPE_SEPR) {
703 but_test = but_test->prev;
704 }
705
706 if (but_test == nullptr) {
707 menu_display_name_map.add(mt, strdup_memarena(memarena, but->drawstr.c_str()));
708 }
709 }
711 data, memarena, mt, but, wm_context, current_menu.self_as_parent))
712 {
713 /* pass */
714 }
715 else if ((mt_from_but = UI_but_menutype_get(but))) {
716 const bool uses_context = but->context &&
717 bool(mt_from_but->flag & MenuTypeFlag::ContextDependent);
718 const bool tagged_first_time = menu_tagged.add(mt_from_but);
719 const bool scan_submenu = tagged_first_time || uses_context;
720
721 if (scan_submenu) {
723 memarena, sizeof(*menu_parent));
724 /* Use brackets for menu key shortcuts,
725 * converting "Text|Some-Shortcut" to "Text (Some-Shortcut)".
726 * This is needed so we don't right align sub-menu contents
727 * we only want to do that for the last menu item, not the path that leads to it.
728 */
729 const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ?
730 strrchr(but->drawstr.c_str(), UI_SEP_CHAR) :
731 nullptr;
732 bool drawstr_is_empty = false;
733 if (drawstr_sep != nullptr) {
734 BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
735 /* Detect empty string, fallback to menu name. */
736 const char *drawstr = but->drawstr.c_str();
737 int drawstr_len = drawstr_sep - but->drawstr.c_str();
738 if (UNLIKELY(drawstr_len == 0)) {
739 drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label);
740 drawstr_len = strlen(drawstr);
741 if (drawstr[0] == '\0') {
742 drawstr_is_empty = true;
743 }
744 }
745 BLI_dynstr_nappend(dyn_str, drawstr, drawstr_len);
746 BLI_dynstr_appendf(dyn_str, " (%s)", drawstr_sep + 1);
747 menu_parent->drawstr = strdup_memarena_from_dynstr(memarena, dyn_str);
748 BLI_dynstr_clear(dyn_str);
749 }
750 else {
751 const char *drawstr = but->drawstr.c_str();
752 if (UNLIKELY(drawstr[0] == '\0')) {
753 drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label);
754 if (drawstr[0] == '\0') {
755 drawstr_is_empty = true;
756 }
757 }
758 menu_parent->drawstr = strdup_memarena(memarena, drawstr);
759 }
760 menu_parent->parent = current_menu.self_as_parent;
761
762 if (drawstr_is_empty) {
763 printf("Warning: '%s' menu has empty 'bl_label'.\n", mt_from_but->idname);
764 }
765
766 if (uses_context) {
767 menu_stack.push({mt_from_but, menu_parent, *but->context});
768 }
769 else {
770 menu_stack.push({mt_from_but, menu_parent});
771 }
772 }
773 }
774 else if (but->menu_create_func != nullptr) {
775 /* A non 'MenuType' menu button. */
776
777 /* +1 to avoid overlap with the current 'block'. */
778 uiBlock *sub_block = UI_block_begin(C, region, __func__ + 1, UI_EMBOSS);
779 uiLayout *sub_layout = UI_block_layout(
780 sub_block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
781
783
785
786 but->menu_create_func(C, sub_layout, but->poin);
787
788 UI_block_end(C, sub_block);
789
791 memarena, sizeof(*menu_parent));
792 menu_parent->drawstr = strdup_memarena(memarena, but->drawstr.c_str());
793 menu_parent->parent = current_menu.self_as_parent;
794
795 LISTBASE_FOREACH (uiBut *, sub_but, &sub_block->buttons) {
797 data, memarena, mt, sub_but, wm_context, menu_parent);
798 }
799
800 if (region) {
802 region->runtime.block_name_map, sub_block->name.c_str(), nullptr, nullptr);
803 BLI_remlink(&region->uiblocks, sub_block);
804 }
805 UI_block_free(nullptr, sub_block);
806 }
807 }
808 if (region) {
809 BLI_ghash_remove(region->runtime.block_name_map, block->name.c_str(), nullptr, nullptr);
810 BLI_remlink(&region->uiblocks, block);
811 }
812 UI_block_free(nullptr, block);
813
814 if (single_menu_idname == nullptr) {
815 /* Add key-map items as a second pass, so all menus are accessed from the header & top-bar
816 * before key shortcuts are expanded. */
817 if (menu_stack.is_empty() && (has_keymap_menu_items == false)) {
818 has_keymap_menu_items = true;
820 C, win, area, region, menu_stack, menu_to_kmi, menu_tagged);
821 }
822 }
823 }
824 }
825
826 /* NOTE: currently this builds the full path for each menu item,
827 * that could be moved into the parent menu. */
828
829 /* Set names as full paths. */
830 LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
831 BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
832
833 if (include_all_areas) {
834 BLI_dynstr_appendf(dyn_str,
835 "%s: ",
836 (item->wm_context != nullptr) ?
837 space_type_ui_items[item->wm_context->space_type_ui_index].name :
838 global_menu_prefix);
839 }
840
841 if (item->menu_parent != nullptr) {
842 MenuSearch_Parent *menu_parent = item->menu_parent;
843 menu_parent->temp_child = nullptr;
844 while (menu_parent && menu_parent->parent) {
845 menu_parent->parent->temp_child = menu_parent;
846 menu_parent = menu_parent->parent;
847 }
848 while (menu_parent) {
849 BLI_dynstr_append(dyn_str, menu_parent->drawstr);
850 BLI_dynstr_append(dyn_str, " " UI_MENU_ARROW_SEP " ");
851 menu_parent = menu_parent->temp_child;
852 }
853 }
854 else {
855 const char *drawstr = menu_display_name_map.lookup_default(item->mt, nullptr);
856 if (drawstr == nullptr) {
857 drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label);
858 }
859 BLI_dynstr_append(dyn_str, drawstr);
860
861 wmKeyMapItem *kmi = menu_to_kmi.lookup_default(item->mt, nullptr);
862 if (kmi != nullptr) {
863 std::string kmi_str = WM_keymap_item_to_string(kmi, false).value_or("");
864 BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str.c_str());
865 }
866
867 BLI_dynstr_append(dyn_str, " " UI_MENU_ARROW_SEP " ");
868 }
869
870 BLI_dynstr_append(dyn_str, item->drawstr);
871
872 item->drawwstr_full = strdup_memarena_from_dynstr(memarena, dyn_str);
873 BLI_dynstr_clear(dyn_str);
874 }
875 BLI_dynstr_free(dyn_str);
876
877 /* Finally sort menu items.
878 *
879 * NOTE: we might want to keep the in-menu order, for now sort all. */
881
882 data->memarena = memarena;
883
884 if (include_all_areas) {
885 CTX_wm_area_set(C, area_init);
886 CTX_wm_region_set(C, region_init);
887
888 if (space_type_ui_items_free) {
889 MEM_freeN((void *)space_type_ui_items);
890 }
891 }
892
893 /* Include all operators for developers,
894 * since it can be handy to have a quick way to access any operator,
895 * including operators being developed which haven't yet been added into the interface.
896 *
897 * These are added after all menu items so developers still get normal behavior by default,
898 * unless searching for something that isn't already in a menu (or scroll down).
899 *
900 * Keep this behind a developer only check:
901 * - Many operators need options to be set to give useful results, see: #74157.
902 * - User who really prefer to list all operators can use #WM_OT_search_operator.
903 */
904 if ((U.flag & USER_DEVELOPER_UI) && single_menu_idname == nullptr) {
906 }
907
908 return data;
909}
910
911static void menu_search_arg_free_fn(void *data_v)
912{
913 MenuSearch_Data *data = (MenuSearch_Data *)data_v;
914 LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
915 switch (item->type) {
917 if (item->op.opptr != nullptr) {
918 WM_operator_properties_free(item->op.opptr);
919 MEM_delete(item->op.opptr);
920 }
921 MEM_delete(item->op.context);
922 break;
923 }
925 break;
926 }
927 }
928 }
929
930 BLI_memarena_free(data->memarena);
931
932 MEM_delete(data);
933}
934
935static void menu_search_exec_fn(bContext *C, void * /*arg1*/, void *arg2)
936{
937 MenuSearch_Item *item = (MenuSearch_Item *)arg2;
938 if (item == nullptr) {
939 return;
940 }
941 if (item->state & UI_BUT_DISABLED) {
942 return;
943 }
944
945 ScrArea *area_prev = CTX_wm_area(C);
946 ARegion *region_prev = CTX_wm_region(C);
947
948 if (item->wm_context != nullptr) {
951 }
952
953 switch (item->type) {
955 CTX_store_set(C, item->op.context);
957 C, item->op.type, item->op.opcontext, item->op.opptr, nullptr, item->drawstr);
958 CTX_store_set(C, nullptr);
959 break;
960 }
962 PointerRNA *ptr = &item->rna.ptr;
963 PropertyRNA *prop = item->rna.prop;
964 const int index = item->rna.index;
965 const int prop_type = RNA_property_type(prop);
966 bool changed = false;
967
968 if (prop_type == PROP_BOOLEAN) {
969 const bool is_array = RNA_property_array_check(prop);
970 if (is_array) {
971 const bool value = RNA_property_boolean_get_index(ptr, prop, index);
972 RNA_property_boolean_set_index(ptr, prop, index, !value);
973 }
974 else {
975 const bool value = RNA_property_boolean_get(ptr, prop);
976 RNA_property_boolean_set(ptr, prop, !value);
977 }
978 changed = true;
979 }
980 else if (prop_type == PROP_ENUM) {
982 changed = true;
983 }
984
985 if (changed) {
986 RNA_property_update(C, ptr, prop);
987 }
988 break;
989 }
990 }
991
992 if (item->wm_context != nullptr) {
993 CTX_wm_area_set(C, area_prev);
994 CTX_wm_region_set(C, region_prev);
995 }
996}
997
998static void menu_search_update_fn(const bContext * /*C*/,
999 void *arg,
1000 const char *str,
1001 uiSearchItems *items,
1002 const bool /*is_first*/)
1003{
1004 MenuSearch_Data *data = (MenuSearch_Data *)arg;
1005
1007
1008 LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
1009 search.add(item->drawwstr_full, item, item->weight);
1010 }
1011
1012 const blender::Vector<MenuSearch_Item *> filtered_items = search.query(str);
1013
1014 for (MenuSearch_Item *item : filtered_items) {
1015 if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state, 0)) {
1016 break;
1017 }
1018 }
1019}
1020
1023/* -------------------------------------------------------------------- */
1032 void *arg,
1033 void *active,
1034 const wmEvent *event)
1035{
1036 MenuSearch_Data *data = (MenuSearch_Data *)arg;
1037 MenuSearch_Item *item = (MenuSearch_Item *)active;
1038 bool has_menu = false;
1039
1040 new (&data->context_menu_data.but) uiBut();
1041 new (&data->context_menu_data.block) uiBlock();
1042 uiBut *but = &data->context_menu_data.but;
1043 uiBlock *block = &data->context_menu_data.block;
1044
1045 but->block = block;
1046
1047 if (menu_items_to_ui_button(item, but)) {
1048 ScrArea *area_prev = CTX_wm_area(C);
1049 ARegion *region_prev = CTX_wm_region(C);
1050
1051 if (item->wm_context != nullptr) {
1052 CTX_wm_area_set(C, item->wm_context->area);
1054 }
1055
1056 if (ui_popup_context_menu_for_button(C, but, event)) {
1057 has_menu = true;
1058 }
1059
1060 if (item->wm_context != nullptr) {
1061 CTX_wm_area_set(C, area_prev);
1062 CTX_wm_region_set(C, region_prev);
1063 }
1064 }
1065
1066 return has_menu;
1067}
1068
1071/* -------------------------------------------------------------------- */
1076 bContext *C, ARegion *region, const rcti * /*item_rect*/, void *arg, void *active)
1077{
1078 MenuSearch_Data *data = (MenuSearch_Data *)arg;
1079 MenuSearch_Item *item = (MenuSearch_Item *)active;
1080
1081 new (&data->context_menu_data.but) uiBut();
1082 new (&data->context_menu_data.block) uiBlock();
1083 uiBut *but = &data->context_menu_data.but;
1084 uiBlock *block = &data->context_menu_data.block;
1085 unit_m4(block->winmat);
1086 block->aspect = 1;
1087
1088 but->block = block;
1089
1090 /* Place the fake button at the cursor so the tool-tip is places properly. */
1091 float tip_init[2];
1092 const wmEvent *event = CTX_wm_window(C)->eventstate;
1093 tip_init[0] = event->xy[0];
1094 tip_init[1] = event->xy[1] - (UI_UNIT_Y / 2);
1095 ui_window_to_block_fl(region, block, &tip_init[0], &tip_init[1]);
1096
1097 but->rect.xmin = tip_init[0];
1098 but->rect.xmax = tip_init[0];
1099 but->rect.ymin = tip_init[1];
1100 but->rect.ymax = tip_init[1];
1101
1102 if (menu_items_to_ui_button(item, but)) {
1103 ScrArea *area_prev = CTX_wm_area(C);
1104 ARegion *region_prev = CTX_wm_region(C);
1105
1106 if (item->wm_context != nullptr) {
1107 CTX_wm_area_set(C, item->wm_context->area);
1109 }
1110
1111 ARegion *region_tip = UI_tooltip_create_from_button(C, region, but, false);
1112
1113 if (item->wm_context != nullptr) {
1114 CTX_wm_area_set(C, area_prev);
1115 CTX_wm_region_set(C, region_prev);
1116 }
1117 return region_tip;
1118 }
1119
1120 return nullptr;
1121}
1122
1125/* -------------------------------------------------------------------- */
1129void UI_but_func_menu_search(uiBut *but, const char *single_menu_idname)
1130{
1131 bContext *C = (bContext *)but->block->evil_C;
1132 wmWindow *win = CTX_wm_window(C);
1133 ScrArea *area = CTX_wm_area(C);
1134 ARegion *region = CTX_wm_region(C);
1135 /* When run from top-bar scan all areas in the current window. */
1136 const bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR)) &&
1137 !single_menu_idname;
1139 C, win, area, region, include_all_areas, single_menu_idname);
1141 /* Generic callback. */
1144 data,
1145 false,
1148 nullptr);
1149
1153}
1154
1156{
1157 uiBlock *block;
1158 uiBut *but;
1159 static char search[256] = "";
1160
1161 block = uiLayoutGetBlock(layout);
1162 UI_block_layout_set_current(block, layout);
1163
1164 but = uiDefSearchBut(
1165 block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, "");
1167}
1168
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
void CTX_store_set(bContext *C, const bContextStore *store)
void CTX_wm_area_set(bContext *C, ScrArea *area)
void CTX_wm_region_set(bContext *C, ARegion *region)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
@ G_DEBUG_WM
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:815
#define BLI_assert(a)
Definition BLI_assert.h:50
A dynamically sized string ADT.
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL()
Definition BLI_dynstr.c:81
int BLI_dynstr_get_len(const DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition BLI_dynstr.c:128
DynStr * BLI_dynstr_new_memarena(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.c:47
void BLI_dynstr_clear(DynStr *ds) ATTR_NONNULL()
Definition BLI_dynstr.c:156
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition BLI_dynstr.c:174
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets) ATTR_NONNULL()
Definition BLI_dynstr.c:133
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL()
Definition BLI_dynstr.c:62
void BLI_ghashIterator_step(GHashIterator *ghi)
Definition BLI_ghash.c:911
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:303
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:787
BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:311
#define LISTBASE_FOREACH(type, var, list)
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.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
void unit_m4(float m[4][4])
Definition rct.c:1127
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void * BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
#define BLI_MEMARENA_STD_BUFSIZE
#define STR_ELEM(...)
Definition BLI_string.h:653
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
int bool bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL(1
unsigned int uint
#define ARRAY_SIZE(arr)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define CTX_IFACE_(context, msgid)
@ SACTCONT_TIMELINE
#define MAX_NAME
Definition DNA_defs.h:50
@ 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.
@ PROP_BOOLEAN
Definition RNA_types.hh:65
@ PROP_ENUM
Definition RNA_types.hh:69
#define C
Definition RandGen.cpp:29
#define UI_UNIT_Y
@ UI_EMBOSS
@ UI_BLOCK_SHOW_SHORTCUT_ALWAYS
#define UI_SEP_CHAR
void UI_but_func_search_set(uiBut *but, uiButSearchCreateFn search_create_fn, uiButSearchUpdateFn search_update_fn, void *arg, bool free_arg, uiFreeArgFunc search_arg_free_fn, uiButHandleFunc search_exec_fn, void *active)
bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid, int but_flag, uint8_t name_prefix_offset)
MenuType * UI_but_menutype_get(const uiBut *but)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
uiLayout * UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, const uiStyle *style)
const uiStyle * UI_style_get_dpi()
void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, eUIEmbossType emboss)
void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn)
@ UI_LAYOUT_VERTICAL
@ UI_LAYOUT_MENU
uiBut * uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxncpy, int x, int y, short width, short height, const char *tip)
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
void UI_block_free(const bContext *C, uiBlock *block)
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout)
ARegion * UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label)
#define UI_UNIT_X
void UI_block_flag_enable(uiBlock *block, int flag)
@ UI_BTYPE_LABEL
@ UI_BTYPE_SEPR
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
void UI_block_end(const bContext *C, uiBlock *block)
void uiLayoutContextCopy(uiLayout *layout, const bContextStore *context)
@ UI_BUT_REDALERT
@ UI_BUT_DISABLED
@ UI_BUT_INACTIVE
@ UI_BUT_HAS_SEP_CHAR
@ WM_HANDLER_DO_FREE
Definition WM_api.hh:470
@ OPTYPE_INTERNAL
Definition WM_types.hh:182
wmOperatorCallContext
Definition WM_types.hh:216
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:219
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
unsigned int U
Definition btGjkEpa3.h:78
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:271
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:531
ValueIterator values() const
Definition BLI_map.hh:846
bool add(const Key &key)
Definition BLI_set.hh:248
bool remove(const Key &key)
Definition BLI_set.hh:366
bool is_empty() const
Definition BLI_stack.hh:308
void push(const T &value)
Definition BLI_stack.hh:213
constexpr StringRef drop_prefix(int64_t n) const
void add(const StringRef str, T *user_data, const int weight=0)
Vector< T * > query(const StringRef query) const
#define printf
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define str(s)
void ui_window_to_block_fl(const ARegion *region, const uiBlock *block, float *x, float *y)
Definition interface.cc:184
bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *event)
ARegion * ui_searchbox_create_menu(bContext *C, ARegion *butregion, uiButSearch *search_but)
#define UI_MENU_PADDING
int ui_but_icon(const uiBut *but)
static void menu_search_update_fn(const bContext *, void *arg, const char *str, uiSearchItems *items, const bool)
static bool ui_search_menu_create_context_menu(bContext *C, void *arg, void *active, const wmEvent *event)
static void menu_items_from_all_operators(bContext *C, MenuSearch_Data *data)
static bool menu_items_to_ui_button(MenuSearch_Item *item, uiBut *but)
static void menu_search_exec_fn(bContext *C, void *, void *arg2)
static ARegion * ui_search_menu_create_tooltip(bContext *C, ARegion *region, const rcti *, void *arg, void *active)
static bool menu_items_from_ui_create_item_from_button(MenuSearch_Data *data, MemArena *memarena, MenuType *mt, uiBut *but, MenuSearch_Context *wm_context, MenuSearch_Parent *menu_parent)
void uiTemplateMenuSearch(uiLayout *layout)
static MenuSearch_Data * menu_items_from_ui_create(bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas, const char *single_menu_idname)
#define SPACE_MENU_NOP(space_type)
static const char * strdup_memarena(MemArena *memarena, const char *str)
void UI_but_func_menu_search(uiBut *but, const char *single_menu_idname)
static void menu_types_add_from_keymap_items(bContext *C, wmWindow *win, ScrArea *area, ARegion *region, blender::Stack< MenuStackEntry > &menu_stack, blender::Map< MenuType *, wmKeyMapItem * > &menu_to_kmi, blender::Set< MenuType * > &menu_tagged)
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 const char * strdup_memarena_from_dynstr(MemArena *memarena, const DynStr *dyn_str)
static void menu_search_arg_free_fn(void *data_v)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#define G(x, y, z)
void RNA_property_boolean_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, bool value)
bool RNA_property_array_check(PropertyRNA *prop)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
PropertyType RNA_property_type(PropertyRNA *prop)
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_property_translation_context(const PropertyRNA *prop)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
bool RNA_property_enum_item_from_value_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, EnumPropertyItem *r_item)
const char * RNA_property_ui_name(const PropertyRNA *prop)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
void RNA_property_enum_items(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
#define UI_MENU_ARROW_SEP
const char * name
Definition RNA_types.hh:510
struct MenuSearch_Data::@404 context_menu_data
struct MenuSearch_Item::@400::@403 rna
wmOperatorCallContext opcontext
enum MenuSearch_Item::Type type
struct MenuSearch_Item::@400::@402 op
std::optional< bContextStore > context
MenuSearch_Parent * self_as_parent
MenuTypeFlag flag
char label[BKE_ST_MAXNAME]
char idname[BKE_ST_MAXNAME]
char translation_context[BKE_ST_MAXNAME]
float xmax
float xmin
float ymax
float ymin
float winmat[4][4]
ListBase buttons
std::string name
wmOperatorCallContext opcontext
PropertyRNA * rnaprop
wmOperatorType * optype
eButType type
float search_weight
uiBlock * block
PointerRNA * opptr
const bContextStore * context
std::string drawstr
uiBut * prev
BIFIconID icon
PointerRNA rnapoin
int xy[2]
Definition WM_types.hh:726
const char * name
Definition WM_types.hh:990
const char * idname
Definition WM_types.hh:992
const char * translation_context
Definition WM_types.hh:994
struct wmEvent * eventstate
bool WM_operator_poll(bContext *C, wmOperatorType *ot)
void WM_event_get_keymaps_from_handler(wmWindowManager *wm, wmWindow *win, wmEventHandler_Keymap *handler, wmEventHandler_KeymapResult *km_result)
void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C, wmOperatorType *ot, wmOperatorCallContext opcontext, PointerRNA *properties, const wmEvent *event, const char *drawstr)
@ WM_HANDLER_TYPE_KEYMAP
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
Definition wm_keymap.cc:469
std::optional< std::string > WM_keymap_item_to_string(const wmKeyMapItem *kmi, const bool compact)
void WM_menutype_iter(GHashIterator *ghi)
MenuType * WM_menutype_find(const char *idname, bool quiet)
bool WM_menutype_poll(bContext *C, MenuType *mt)
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
const wmOperatorTypeMap & WM_operatortype_map()
size_t WM_operator_py_idname(char *dst, const char *src)
void WM_operator_properties_free(PointerRNA *ptr)
bScreen * WM_window_get_active_screen(const wmWindow *win)