| 6886 | } |
| 6887 | |
| 6888 | bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) |
| 6889 | { |
| 6890 | ImGuiWindow* window = GetCurrentWindow(); |
| 6891 | if (window->SkipItems) |
| 6892 | return false; |
| 6893 | |
| 6894 | ImGuiContext& g = *GImGui; |
| 6895 | const ImGuiStyle& style = g.Style; |
| 6896 | const ImGuiID id = window->GetID(label); |
| 6897 | bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None); |
| 6898 | |
| 6899 | // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu) |
| 6900 | // The first menu in a hierarchy isn't so hovering doesn't get accross (otherwise e.g. resizing borders with ImGuiButtonFlags_FlattenChildren would react), but top-most BeginMenu() will bypass that limitation. |
| 6901 | ImGuiWindowFlags flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; |
| 6902 | if (window->Flags & ImGuiWindowFlags_ChildMenu) |
| 6903 | flags |= ImGuiWindowFlags_ChildWindow; |
| 6904 | |
| 6905 | // If a menu with same the ID was already submitted, we will append to it, matching the behavior of Begin(). |
| 6906 | // We are relying on a O(N) search - so O(N log N) over the frame - which seems like the most efficient for the expected small amount of BeginMenu() calls per frame. |
| 6907 | // If somehow this is ever becoming a problem we can switch to use e.g. ImGuiStorage mapping key to last frame used. |
| 6908 | if (g.MenusIdSubmittedThisFrame.contains(id)) |
| 6909 | { |
| 6910 | if (menu_is_open) |
| 6911 | menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) |
| 6912 | else |
| 6913 | g.NextWindowData.ClearFlags(); // we behave like Begin() and need to consume those values |
| 6914 | return menu_is_open; |
| 6915 | } |
| 6916 | |
| 6917 | // Tag menu as used. Next time BeginMenu() with same ID is called it will append to existing menu |
| 6918 | g.MenusIdSubmittedThisFrame.push_back(id); |
| 6919 | |
| 6920 | ImVec2 label_size = CalcTextSize(label, NULL, true); |
| 6921 | |
| 6922 | // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent without always being a Child window) |
| 6923 | const bool menuset_is_open = IsRootOfOpenMenuSet(); |
| 6924 | ImGuiWindow* backed_nav_window = g.NavWindow; |
| 6925 | if (menuset_is_open) |
| 6926 | g.NavWindow = window; |
| 6927 | |
| 6928 | // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu, |
| 6929 | // However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). |
| 6930 | // e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering. |
| 6931 | ImVec2 popup_pos, pos = window->DC.CursorPos; |
| 6932 | PushID(label); |
| 6933 | if (!enabled) |
| 6934 | BeginDisabled(); |
| 6935 | const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; |
| 6936 | bool pressed; |
| 6937 | if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) |
| 6938 | { |
| 6939 | // Menu inside an horizontal menu bar |
| 6940 | // Selectable extend their highlight by half ItemSpacing in each direction. |
| 6941 | // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() |
| 6942 | popup_pos = ImVec2(pos.x - 1.0f - IM_FLOOR(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight()); |
| 6943 | window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); |
| 6944 | PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); |
| 6945 | float w = label_size.x; |
nothing calls this directly
no test coverage detected