{"action":"created","issue":{"url":"https://api.github.com/repos/ocornut/imgui/issues/434","labels_url":"https://api.github.com/repos/ocornut/imgui/issues/434/labels{/name}","comments_url":"https://api.github.com/repos/ocornut/imgui/issues/434/comments","events_url":"https://api.github.com/repos/ocornut/imgui/issues/434/events","html_url":"https://github.com/ocornut/imgui/issues/434","id":121741235,"number":434,"title":"Pie menu test","user":{"login":"ocornut","id":8225057,"avatar_url":"https://avatars.githubusercontent.com/u/8225057?v=3","gravatar_id":"","url":"https://api.github.com/users/ocornut","html_url":"https://github.com/ocornut","followers_url":"https://api.github.com/users/ocornut/followers","following_url":"https://api.github.com/users/ocornut/following{/other_user}","gists_url":"https://api.github.com/users/ocornut/gists{/gist_id}","starred_url":"https://api.github.com/users/ocornut/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ocornut/subscriptions","organizations_url":"https://api.github.com/users/ocornut/orgs","repos_url":"https://api.github.com/users/ocornut/repos","events_url":"https://api.github.com/users/ocornut/events{/privacy}","received_events_url":"https://api.github.com/users/ocornut/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":5,"created_at":"2015-12-11T16:22:41Z","updated_at":"2015-12-13T16:30:24Z","closed_at":null,"body":"This is more a proof of concept that a finished api.\r\n\r\n![pie_menu2](https://cloud.githubusercontent.com/assets/8225057/11749030/46b00068-a023-11e5-88a0-2c86962cba0e.gif)\r\n\r\n```\r\n#include <imgui_internal.h>\r\n\r\n// Return >= 0 on mouse release\r\n// Optional int* p_selected display and update a currently selected item\r\nint PiePopupSelectMenu(const ImVec2& center, const char* popup_id, const char** items, int items_count, int* p_selected)\r\n{\r\n    int ret = -1;\r\n    \r\n    // FIXME: Missing a call to query if Popup is open so we can move the PushStyleColor inside the BeginPopupBlock (e.g. IsPopupOpen() in imgui.cpp)\r\n    // FIXME: Our PathFill function only handle convex polygons, so we can't have items spanning an arc too large else inner concave edge artifact is too visible, hence the ImMax(7,items_count)\r\n    ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0,0,0,0));\r\n    ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0,0,0,0));\r\n    if (ImGui::BeginPopup(popup_id))\r\n    {\r\n        const ImVec2 drag_delta = ImVec2(ImGui::GetIO().MousePos.x - center.x, ImGui::GetIO().MousePos.y - center.y);\r\n        const float drag_dist2 = drag_delta.x*drag_delta.x + drag_delta.y*drag_delta.y;\r\n\r\n        const ImGuiStyle& style = ImGui::GetStyle();\r\n        const float RADIUS_MIN = 30.0f;\r\n        const float RADIUS_MAX = 120.0f;\r\n        const float RADIUS_INTERACT_MIN = 20.0f;\r\n        const int ITEMS_MIN = 6;\r\n\r\n        ImDrawList* draw_list = ImGui::GetWindowDrawList();\r\n        //ImGuiWindow* window = ImGui::GetCurrentWindow();\r\n        draw_list->PushClipRectFullScreen();\r\n        draw_list->PathArcTo(center, (RADIUS_MIN + RADIUS_MAX)*0.5f, 0.0f, IM_PI*2.0f*0.99f, 32);   // FIXME: 0.99f look like full arc with closed thick stroke has a bug now\r\n        draw_list->PathStroke(ImColor(0,0,0), true, RADIUS_MAX - RADIUS_MIN);\r\n\r\n        const float item_arc_span = 2*IM_PI / ImMax(ITEMS_MIN, items_count);\r\n        float drag_angle = atan2f(drag_delta.y, drag_delta.x);\r\n        if (drag_angle < -0.5f*item_arc_span)\r\n            drag_angle += 2.0f*IM_PI;\r\n        //ImGui::Text(\"%f\", drag_angle);    // [Debug]\r\n        \r\n        int item_hovered = -1;\r\n        for (int item_n = 0; item_n < items_count; item_n++)\r\n        {\r\n            const char* item_label = items[item_n];\r\n            const float item_ang_min = item_arc_span * (item_n+0.02f) - item_arc_span*0.5f; // FIXME: Could calculate padding angle based on how many pixels they'll take\r\n            const float item_ang_max = item_arc_span * (item_n+0.98f) - item_arc_span*0.5f;\r\n\r\n            bool hovered = false;\r\n            if (drag_dist2 >= RADIUS_INTERACT_MIN*RADIUS_INTERACT_MIN)\r\n            {\r\n                if (drag_angle >= item_ang_min && drag_angle < item_ang_max)\r\n                    hovered = true;\r\n            }\r\n            bool selected = p_selected && (*p_selected == item_n);\r\n\r\n            int arc_segments = (int)(32 * item_arc_span / (2*IM_PI)) + 1;\r\n            draw_list->PathArcTo(center, RADIUS_MAX - style.ItemInnerSpacing.x, item_ang_min, item_ang_max, arc_segments);\r\n            draw_list->PathArcTo(center, RADIUS_MIN + style.ItemInnerSpacing.x, item_ang_max, item_ang_min, arc_segments);\r\n            //draw_list->PathFill(window->Color(hovered ? ImGuiCol_HeaderHovered : ImGuiCol_FrameBg));\r\n            draw_list->PathFill(hovered ? ImColor(100,100,150) : selected ? ImColor(120,120,140) : ImColor(70,70,70));\r\n \r\n            ImVec2 text_size = ImGui::GetWindowFont()->CalcTextSizeA(ImGui::GetWindowFontSize(), FLT_MAX, 0.0f, item_label);\r\n            ImVec2 text_pos = ImVec2(\r\n                center.x + cosf((item_ang_min + item_ang_max) * 0.5f) * (RADIUS_MIN + RADIUS_MAX) * 0.5f - text_size.x * 0.5f,\r\n                center.y + sinf((item_ang_min + item_ang_max) * 0.5f) * (RADIUS_MIN + RADIUS_MAX) * 0.5f - text_size.y * 0.5f);\r\n            draw_list->AddText(text_pos, ImColor(255,255,255), item_label);\r\n\r\n            if (hovered)\r\n                item_hovered = item_n;\r\n        }\r\n        draw_list->PopClipRect();\r\n\r\n        if (ImGui::IsMouseReleased(0))\r\n        {\r\n            ImGui::CloseCurrentPopup();\r\n            ret = item_hovered;\r\n            if (p_selected)\r\n                *p_selected = item_hovered;\r\n        }\r\n        ImGui::EndPopup();\r\n    }\r\n    ImGui::PopStyleColor(2);\r\n    return ret;\r\n}\r\n```\r\n\r\n```\r\n{\r\nstatic const char* test_data = \"Menu\";\r\nconst char* items[] = { \"Orange\", \"Blue\", \"Purple\", \"Gray\", \"Yellow\", \"Las Vegas\" };\r\nint items_count = sizeof(items)/sizeof(*items);\r\n\r\nstatic int selected = -1;\r\n\r\nImGui::Button(selected >= 0 ? items[selected] : \"Menu\", ImVec2(50,50));\r\nif (ImGui::IsItemActive())          // Don't wait for button release to activate the pie menu\r\n    ImGui::OpenPopup(\"##piepopup\");\r\n            \r\nImVec2 pie_menu_center = ImGui::GetIO().MouseClickedPos[0];\r\nint n = PiePopupSelectMenu(pie_menu_center, \"##piepopup\", items, items_count, &selected);\r\nif (n >= 0)\r\n    printf(\"returned %d\\n\", n);\r\n```\r\n"},"comment":{"url":"https://api.github.com/repos/ocornut/imgui/issues/comments/164274306","html_url":"https://github.com/ocornut/imgui/issues/434#issuecomment-164274306","issue_url":"https://api.github.com/repos/ocornut/imgui/issues/434","id":164274306,"user":{"login":"ocornut","id":8225057,"avatar_url":"https://avatars.githubusercontent.com/u/8225057?v=3","gravatar_id":"","url":"https://api.github.com/users/ocornut","html_url":"https://github.com/ocornut","followers_url":"https://api.github.com/users/ocornut/followers","following_url":"https://api.github.com/users/ocornut/following{/other_user}","gists_url":"https://api.github.com/users/ocornut/gists{/gist_id}","starred_url":"https://api.github.com/users/ocornut/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ocornut/subscriptions","organizations_url":"https://api.github.com/users/ocornut/orgs","repos_url":"https://api.github.com/users/ocornut/repos","events_url":"https://api.github.com/users/ocornut/events{/privacy}","received_events_url":"https://api.github.com/users/ocornut/received_events","type":"User","site_admin":false},"created_at":"2015-12-13T16:30:24Z","updated_at":"2015-12-13T16:30:24Z","body":"I'm not sure. Open a second pie-popup over the center of the previous button? That would suggest that merely holding mouse would open the sub-menu (like normal menu), which in turn ask the question of how we can get back to the parent menu.\r\n\r\nI haven't spend time to think about it in details, just implemented something as fast as I can for someone, which is essentially why this is a proof of concept rather than a feature. "}}