Browse Source

Menus: Implement BeginMenu() appending to existing menu when executed with same ID multiple times. (#1207)

Rokas Kupstys 5 years ago
parent
commit
0342a3c548
5 changed files with 23 additions and 7 deletions
  1. 1 0
      docs/CHANGELOG.txt
  2. 0 1
      docs/TODO.txt
  3. 1 0
      imgui.cpp
  4. 1 0
      imgui_internal.h
  5. 20 6
      imgui_widgets.cpp

+ 1 - 0
docs/CHANGELOG.txt

@@ -40,6 +40,7 @@ Other Changes:
   branch pressing arrow keys while dragging a window from a tab could trigger an assert. (#3025)
 - ColorButton: Added ImGuiColorEditFlags_NoBorder flag to remove the border normally enforced
   by default for standalone ColorButton.
+- BeginMenu: Using same ID multiple times appends content to a menu. (#1207)
 - BeginMenu: Fixed a bug where SetNextWindowXXX data before a BeginMenu() would not be cleared
   when the menu is not open. (#3030)
 - InputText: Fixed password fields displaying ASCII spaces as blanks instead of using the '*'

+ 0 - 1
docs/TODO.txt

@@ -214,7 +214,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
  - tooltip: tooltips with delay timers? or general timer policy? (instantaneous vs timed): IsItemHovered() with timer + implicit aabb-id for items with no ID. (#1485)
  - tooltip: drag tooltip hovering over source widget with IsItemHovered/SetTooltip flickers.
 
- - menus: calling BeginMenu() twice with a same name doesn't append as Begin() does for regular windows (#1207)
  - menus: menu bars inside modal windows are acting weird.
  - status-bar: add a per-window status bar helper similar to what menu-bar does.
  - shortcuts: local-style shortcut api, e.g. parse "&Save"

+ 1 - 0
imgui.cpp

@@ -3623,6 +3623,7 @@ void ImGui::NewFrame()
     g.FrameCount += 1;
     g.TooltipOverrideCount = 0;
     g.WindowsActiveCount = 0;
+    g.RenderedMenusId.resize(0);
 
     // Setup current font and draw list shared data
     g.IO.Fonts->Locked = true;

+ 1 - 0
imgui_internal.h

@@ -1159,6 +1159,7 @@ struct ImGuiContext
     float                   ScrollbarClickDeltaToGrabCenter;    // Distance between mouse and center of grab box, normalized in parent space. Use storage?
     int                     TooltipOverrideCount;
     ImVector<char>          PrivateClipboard;                   // If no custom clipboard handler is defined
+    ImVector<ImGuiID>       RenderedMenusId;                    // A list of menu IDs that were rendered at least once
 
     // Platform support
     ImVec2                  PlatformImePos;                     // Cursor position request & last passed to the OS Input Method Editor

+ 20 - 6
imgui_widgets.cpp

@@ -6222,11 +6222,29 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
     ImGuiContext& g = *GImGui;
     const ImGuiStyle& style = g.Style;
     const ImGuiID id = window->GetID(label);
+    bool menu_is_open = IsPopupOpen(id);
+    ImGuiWindowFlags flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus;
 
-    ImVec2 label_size = CalcTextSize(label, NULL, true);
+    // 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)
+    if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu))
+        flags |= ImGuiWindowFlags_ChildWindow;
+
+    if (g.RenderedMenusId.contains(id))
+    {
+        // Menu with same ID was already created - append to it.
+        if (menu_is_open)
+            menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
+        if (!menu_is_open)
+            g.NextWindowData.ClearFlags();          // We behave like Begin() and need to consume those values
+        return menu_is_open;
+    }
+    else
+    {
+        g.RenderedMenusId.push_back(id);            // Tag menu as used. Next time BeginMenu() with same ID is called it will append to existing menu.
+    }
 
+    ImVec2 label_size = CalcTextSize(label, NULL, true);
     bool pressed;
-    bool menu_is_open = IsPopupOpen(id);
     bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].OpenParentId == window->IDStack.back());
     ImGuiWindow* backed_nav_window = g.NavWindow;
     if (menuset_is_open)
@@ -6345,11 +6363,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
 
     if (menu_is_open)
     {
-        // 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)
         SetNextWindowPos(popup_pos, ImGuiCond_Always);
-        ImGuiWindowFlags flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus;
-        if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu))
-            flags |= ImGuiWindowFlags_ChildWindow;
         menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
     }
     else