39#include "RNA_prototypes.hh"
51#include <fmt/format.h>
100 if (this->opptr !=
nullptr) {
102 MEM_delete(this->opptr);
104 MEM_delete(this->context);
114 std::variant<OperatorData, PropertyData>
data;
150 std::string drawstr_override;
153 const bool drawstr_is_empty = sep_index == 0 || but->
drawstr.empty();
155 if (but->
optype !=
nullptr) {
156 if (drawstr_is_empty) {
162 auto &op_data = std::get<MenuSearch_Item::OperatorData>(item->
data);
163 op_data.type = but->
optype;
165 op_data.context = but->
context ? MEM_new<bContextStore>(__func__, *but->
context) :
nullptr;
166 op_data.opptr = but->
opptr;
170 but->
opptr =
nullptr;
172 else if (but->
rnaprop !=
nullptr) {
175 if (drawstr_is_empty) {
177 const int value_enum = int(but->
hardmax);
185 drawstr_override = enum_item.
name;
189 drawstr_override =
"Unknown";
200 printf(
"Button '%s' in menu '%s' is a menu item with unsupported RNA type %d\n",
210 auto &rna_data = std::get<MenuSearch_Item::PropertyData>(item->
data);
215 rna_data.enum_value = int(but->
hardmax);
220 if (item !=
nullptr) {
222 if (!drawstr_override.empty()) {
223 const StringRef drawstr_suffix = sep_index == std::string::npos ?
226 std::string drawstr = std::string(
"(") + drawstr_override +
")" + drawstr_suffix;
241 data->items.append(*item);
253 bool changed =
false;
254 if (
auto *op_data = std::get_if<MenuSearch_Item::OperatorData>(&item->
data)) {
255 but->
optype = op_data->type;
257 but->
context = op_data->context;
258 but->
opptr = op_data->opptr;
261 else if (
auto *rna_data = std::get_if<MenuSearch_Item::PropertyData>(&item->
data)) {
269 but->
hardmax = rna_data->enum_value;
278 if (sep_index != std::string::npos) {
279 but->
drawstr.resize(sep_index);
309 region ? ®ion->
runtime->handlers :
nullptr,
314 for (
int handler_index = 0; handler_index <
ARRAY_SIZE(handlers); handler_index++) {
315 if (handlers[handler_index] ==
nullptr) {
327 if (handler_base->poll ==
nullptr || handler_base->poll(win, area, region, win->
eventstate))
332 for (
int km_index = 0; km_index < km_result.
keymaps_len; km_index++) {
339 if (
STR_ELEM(kmi->idname,
"WM_OT_call_menu",
"WM_OT_call_menu_pie")) {
344 if (mt && menu_tagged.
add(mt)) {
346 menu_stack.
push({mt});
347 menu_to_kmi.
add(mt, kmi);
373 const char *ot_ui_name =
CTX_IFACE_(
ot->translation_context,
ot->name);
377 auto &op_data = std::get<MenuSearch_Item::OperatorData>(item.
data);
380 op_data.context =
nullptr;
393 operator_items.
append(item);
399 data->items.extend(operator_items);
412 bool include_all_areas,
413 const char *single_menu_idname)
421 if (old_context_store) {
422 context_store = *old_context_store;
431 fmt::memory_buffer str_buf;
443 const char *idname_array[] = {
445 (single_menu_idname &&
STREQ(single_menu_idname,
"TOPBAR_MT_file_open_recent")) ?
447 "TOPBAR_MT_file_open_recent",
450 "TOPBAR_MT_undo_history",
453 if (!idname_array[
i]) {
463 if (!single_menu_idname) {
475 const char *idname_array[] = {
477 "OUTLINER_MT_context_menu",
491 int space_type_ui_items_len = 0;
492 bool space_type_ui_items_free =
false;
495 const char *global_menu_prefix =
nullptr;
497 if (include_all_areas) {
513 &space_type_ui_items,
514 &space_type_ui_items_len,
515 &space_type_ui_items_free);
519 for (
int i = 0;
i < space_type_ui_items_len;
i++) {
526 if (region !=
nullptr) {
531 if (space_type_ui_index == -1) {
535 if (wm_contexts[space_type_ui_index].space_type_ui_index != -1) {
536 ScrArea *area_best = wm_contexts[space_type_ui_index].
area;
538 const uint value_test =
uint(area->winx) *
uint(area->winy);
539 if (value_best > value_test) {
545 wm_contexts[space_type_ui_index].
area = area;
546 wm_contexts[space_type_ui_index].
region = region;
553 for (
int space_type_ui_index = -1; space_type_ui_index < space_type_ui_items_len;
554 space_type_ui_index += 1)
561 if (include_all_areas) {
562 if (space_type_ui_index == -1) {
564 wm_context =
nullptr;
569 wm_context = &wm_contexts[space_type_ui_index];
574 area = wm_context->
area;
575 region = wm_context->
region;
583 region = region_init;
586 if (single_menu_idname) {
588 if (menu_tagged.
add(mt)) {
589 menu_stack.
push({mt});
598 const char *idname_array[2] = {
nullptr};
599 int idname_array_len = 0;
602 if (space_type_ui_index == -1) {
603 idname_array[idname_array_len++] =
"TOPBAR_MT_editor_menus";
606#define SPACE_MENU_MAP(space_type, menu_id) \
608 idname_array[idname_array_len++] = menu_id; \
610#define SPACE_MENU_NOP(space_type) \
614 if (area !=
nullptr) {
628 "TIME_MT_editor_menus" :
629 "DOPESHEET_MT_editor_menus");
636 "CLIP_MT_tracking_editor_menus" :
637 "CLIP_MT_masking_editor_menus");
645 for (
int i = 0;
i < idname_array_len;
i++) {
649 if (menu_tagged.
add(mt)) {
650 menu_stack.
push({mt});
658 bool has_keymap_menu_items =
false;
673 if (current_menu.
context.has_value()) {
682 const std::unique_ptr<uiBut> &but = block->
buttons[
i];
689 const std::unique_ptr<uiBut> *but_test = block->
buttons.
begin() +
i - 1;
694 if (but_test < block->buttons.begin()) {
704 const bool uses_context = but->context &&
706 const bool tagged_first_time = menu_tagged.
add(mt_from_but);
707 const bool scan_submenu = tagged_first_time || uses_context;
719 bool drawstr_is_empty =
false;
720 if (drawstr_sep !=
nullptr) {
723 const char *drawstr = but->drawstr.c_str();
724 int drawstr_len = drawstr_sep - but->drawstr.c_str();
727 drawstr_len = strlen(drawstr);
728 if (drawstr[0] ==
'\0') {
729 drawstr_is_empty =
true;
732 str_buf.append(
StringRef(drawstr, drawstr_len));
733 fmt::format_to(fmt::appender(str_buf),
" ({})", drawstr_sep + 1);
735 StringRef(str_buf.data(), str_buf.size()));
739 const char *drawstr = but->drawstr.c_str();
742 if (drawstr[0] ==
'\0') {
743 drawstr_is_empty =
true;
750 if (drawstr_is_empty) {
751 printf(
"Warning: '%s' menu has empty 'bl_label'.\n", mt_from_but->
idname);
755 menu_stack.
push({mt_from_but, menu_parent, *but->context});
758 menu_stack.
push({mt_from_but, menu_parent});
762 else if (but->menu_create_func !=
nullptr) {
781 bool poll_success =
true;
783 if (pt->poll && (pt->poll(
C, pt) ==
false)) {
784 poll_success =
false;
789 but->menu_create_func(
C, sub_layout, but->poin);
799 for (
const std::unique_ptr<uiBut> &sub_but : sub_block->
buttons) {
801 data, scope, mt, sub_but.get(), wm_context, menu_parent);
806 region->
runtime->block_name_map.remove(sub_block->
name);
813 region->
runtime->block_name_map.remove(block->
name);
818 if (single_menu_idname ==
nullptr) {
821 if (menu_stack.
is_empty() && (has_keymap_menu_items ==
false)) {
822 has_keymap_menu_items =
true;
824 C, win, area, region, menu_stack, menu_to_kmi, menu_tagged);
837 if (include_all_areas) {
838 fmt::format_to(fmt::appender(str_buf),
848 while (menu_parent && menu_parent->
parent) {
850 menu_parent = menu_parent->
parent;
852 while (menu_parent) {
853 str_buf.append(menu_parent->
drawstr);
859 const char *drawstr = menu_display_name_map.
lookup_default(item.
mt,
nullptr);
860 if (drawstr ==
nullptr) {
866 if (kmi !=
nullptr) {
868 fmt::format_to(fmt::appender(str_buf),
" ({})", kmi_str);
885 if (include_all_areas) {
889 if (space_type_ui_items_free) {
920 if (item ==
nullptr) {
935 if (
auto *op_data = std::get_if<MenuSearch_Item::OperatorData>(&item->
data)) {
938 C, op_data->type, op_data->opcontext, op_data->opptr,
nullptr, item->
drawstr);
941 else if (
auto *rna_data = std::get_if<MenuSearch_Item::PropertyData>(&item->
data)) {
944 const int index = rna_data->index;
946 bool changed =
false;
1016 bool has_menu =
false;
1018 new (&
data->context_menu_data.but)
uiBut();
1020 uiBut *but = &
data->context_menu_data.but;
1059 new (&
data->context_menu_data.but)
uiBut();
1061 uiBut *but = &
data->context_menu_data.but;
1071 tip_init[0] =
event->
xy[0];
1072 tip_init[1] =
event->xy[1] - (
UI_UNIT_Y / 2);
1115 !single_menu_idname;
1117 C, win, area, region, include_all_areas, single_menu_idname);
1137 static char search[256] =
"";
1143 block, search, 0, ICON_VIEWZOOM,
sizeof(search), 0, 0,
UI_UNIT_X * 6,
UI_UNIT_Y,
"");
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
const bContextStore * CTX_store_get(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)
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
#define LISTBASE_FOREACH(type, var, list)
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void unit_m4(float m[4][4])
#define BLI_SCOPED_DEFER(function_to_defer)
#define SNPRINTF(dst, format,...)
int bool bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL(1
#define CTX_IFACE_(context, msgid)
Read Guarded memory(de)allocation.
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, blender::ui::EmbossType emboss)
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)
MenuType * UI_but_menutype_get(const uiBut *but)
const uiStyle * UI_style_get_dpi()
void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn)
uiBut * uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxncpy, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
ARegion * UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_quick_tip)
bool UI_search_item_add(uiSearchItems *items, blender::StringRef name, void *poin, int iconid, int but_flag, uint8_t name_prefix_offset)
void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn)
PanelType * UI_but_paneltype_get(const uiBut *but)
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_flag_enable(uiBlock *block, int flag)
@ UI_BLOCK_SHOW_SHORTCUT_ALWAYS
void UI_block_end(const bContext *C, uiBlock *block)
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)
void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout)
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
void uiLayoutContextCopy(uiLayout *layout, const bContextStore *context)
@ WM_OP_INVOKE_REGION_WIN
BMesh const char void * data
void append(const T &value)
IndexRange index_range() const
StringRefNull copy_string(StringRef str)
bool add(const Key &key, const Value &value)
Value lookup_default(const Key &key, const Value &default_value) const
T & construct(Args &&...args)
LinearAllocator & allocator()
bool remove(const Key &key)
void push(const T &value)
constexpr const char * c_str() const
constexpr StringRef drop_prefix(int64_t n) const
void append(const T &value)
void add(const StringRef str, T *user_data, const int weight=0)
Vector< T * > query(const StringRef query) const
void ui_window_to_block_fl(const ARegion *region, const uiBlock *block, float *x, float *y)
ARegion * ui_searchbox_create_menu(bContext *C, ARegion *butregion, uiButSearch *search_but)
int ui_but_icon(const uiBut *but)
void MEM_freeN(void *vmemh)
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)
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
#define UI_MENU_ARROW_SEP
ARegionRuntimeHandle * runtime
blender::Vector< bContextStoreEntry > entries
blender::Vector< std::unique_ptr< uiBut > > buttons
wmOperatorCallContext opcontext
const bContextStore * context
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 StringRef drawstr)
bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
std::optional< std::string > WM_keymap_item_to_string(const wmKeyMapItem *kmi, const bool compact)
blender::Span< wmOperatorType * > WM_operatortypes_registered_get()
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
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)