| 7135 | } |
| 7136 | |
| 7137 | bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) |
| 7138 | { |
| 7139 | ImGuiWindow* window = GetCurrentWindow(); |
| 7140 | if (window->SkipItems) |
| 7141 | return false; |
| 7142 | |
| 7143 | ImGuiContext& g = *GImGui; |
| 7144 | const ImGuiStyle& style = g.Style; |
| 7145 | const ImGuiID id = window->GetID(label); |
| 7146 | bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None); |
| 7147 | |
| 7148 | // 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) |
| 7149 | // The first menu in a hierarchy isn't so hovering doesn't get across (otherwise e.g. resizing borders with ImGuiButtonFlags_FlattenChildren would react), but top-most BeginMenu() will bypass that limitation. |
| 7150 | ImGuiWindowFlags window_flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; |
| 7151 | if (window->Flags & ImGuiWindowFlags_ChildMenu) |
| 7152 | window_flags |= ImGuiWindowFlags_ChildWindow; |
| 7153 | |
| 7154 | // If a menu with same the ID was already submitted, we will append to it, matching the behavior of Begin(). |
| 7155 | // 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. |
| 7156 | // If somehow this is ever becoming a problem we can switch to use e.g. ImGuiStorage mapping key to last frame used. |
| 7157 | if (g.MenusIdSubmittedThisFrame.contains(id)) |
| 7158 | { |
| 7159 | if (menu_is_open) |
| 7160 | menu_is_open = BeginPopupEx(id, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) |
| 7161 | else |
| 7162 | g.NextWindowData.ClearFlags(); // we behave like Begin() and need to consume those values |
| 7163 | return menu_is_open; |
| 7164 | } |
| 7165 | |
| 7166 | // Tag menu as used. Next time BeginMenu() with same ID is called it will append to existing menu |
| 7167 | g.MenusIdSubmittedThisFrame.push_back(id); |
| 7168 | |
| 7169 | ImVec2 label_size = CalcTextSize(label, NULL, true); |
| 7170 | |
| 7171 | // 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) |
| 7172 | // This is only done for items for the menu set and not the full parent window. |
| 7173 | const bool menuset_is_open = IsRootOfOpenMenuSet(); |
| 7174 | if (menuset_is_open) |
| 7175 | PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true); |
| 7176 | |
| 7177 | // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu, |
| 7178 | // However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). |
| 7179 | // e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering. |
| 7180 | ImVec2 popup_pos, pos = window->DC.CursorPos; |
| 7181 | PushID(label); |
| 7182 | if (!enabled) |
| 7183 | BeginDisabled(); |
| 7184 | const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; |
| 7185 | bool pressed; |
| 7186 | |
| 7187 | // We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another. |
| 7188 | const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups; |
| 7189 | if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) |
| 7190 | { |
| 7191 | // Menu inside an horizontal menu bar |
| 7192 | // Selectable extend their highlight by half ItemSpacing in each direction. |
| 7193 | // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() |
| 7194 | popup_pos = ImVec2(pos.x - 1.0f - IM_FLOOR(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight()); |
nothing calls this directly
no test coverage detected