-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pie menu test #434
Comments
Great job :-) |
Looking really good! Will you be adding it to the lib or will it just be a snippet? |
Eventually it should be added but it's not complete nor good enough yet. In order to support submenus the API would likely need to be changed? |
What would submenues within a pie-popup look like? |
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. I 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. |
Another idea would perhaps be to expand the pie outwards, presenting a top-down menu. The amount of choices could be increased by increasing the size of the extended pie-slice upwards/downwards? |
It does not work when trying to display in without a window ? I try to display it on a simple OpenGL window ! After a drag & drop... I drop inside a 3D view... and nothing appear ! |
It always bothered me, that the border between the items increased from the inner ring to the outer, so here is a fix for that (only listing the inner rendering for-loop):
Furthermore here are inspirational videos from other pie menu implementations: https://www.youtube.com/watch?v=nXh1Tm24kTE&t=50s https://www.youtube.com/watch?v=Job4Rg-sbDo |
I really like the simple Ubuntu "look", just a simple set of "alpha blended" pies over the screen :-P |
Thanks @Horrowind, really useful! |
You should be able to, the pie-menu is its own window. Krys please provide more detailed information and standalone repro code with your questions when possible! Lots of your questions are really unclear, if you can't clarify the question then please provide the smallest set of code that demonstrate the issue you have. Thanks! |
What he means is, start a new, tiny application that just reproduces a On Thu, Dec 17, 2015 at 12:25 PM, krys-spectralpixel <
|
It is your job to provide a repro to ensure that your request is well formed and thought up. It also in many cases helps you understand the issue better. Your code above is not a repro I can paste. Have you noticed that my pie code above close automatically if mouse is released? This works without a window for me:
|
I propose to replace:
with
In order to avoid selection when the mouse is out of the pie menu ! |
I did that intentionally to avoid false negatives and also considering that pie menus have a "gesture" feel to them. e.g. click and drag left, release, by not worrying about distance travelled you can accomplish faster actions. Maybe it isn't as important with mouse controls. Both ways have legit uses, it could be a global setting of the pie menus potentially. |
Right. Sure there can be plenty of options for this control :-D |
The PathFill function in theory only handle convex fill, so I suppose that's an artefact of this limitation. |
Great explanation ! Thanks for it. You helped me a lot. |
@zhouxs1023 this is caused by the popup background, I don't know why it dosen't follow the style pushed but I "fixed" it by adding this code just before
|
Thank you very much! |
A modified version with support of sub menu, it's not finished or optimized and need a new struct for storing values and items label. if( ImGui::IsWindowHovered() && ImGui::IsMouseClicked( 1 ) )
{
ImGui::OpenPopup( "PieMenu" );
}
if( BeginPiePopup( "PieMenu", 1 ) )
{
if( PieMenuItem( "Test1" ) ) { /*TODO*/ }
if( PieMenuItem( "Test2" ) ) { /*TODO*/ }
if( PieMenuItem( "Test3", false ) ) { /*TODO*/ }
if( BeginPieMenu( "Sub" ) )
{
if( BeginPieMenu( "Sub sub\nmenu" ) )
{
if( PieMenuItem( "SubSub" ) ) { /*TODO*/ }
if( PieMenuItem( "SubSub2" ) ) { /*TODO*/ }
EndPieMenu();
}
if( PieMenuItem( "TestSub" ) ) { /*TODO*/ }
if( PieMenuItem( "TestSub2" ) ) { /*TODO*/ }
EndPieMenu();
}
EndPiePopup();
} Full source here |
There's a helper ImGuiTextBuffer which is close to what you are doing. Maybe a stripped down version of https://github.com/ocornut/Str would generally be useful, but if you can use a single buffer like ImGuiTextBuffer it helps.
I've been considering it, perhaps a way for a external subsystem to register a slot instead an array of pointers stored in ImGuiContext, so you can store one PieMenuContext per ImGuiContext. Is that were you were thinking of? |
I use an ImVector< char > for storing strings.
Yes, I want to store one PieMenuContext per ImGuiContext. |
@thennequin You probably haven't updated this in a while nor remember how you wrote it, but it's worth the shot. I tried your implementation, and I've seen only 1 issue, and a weird quirk I wanted to see if I can change. The issue is that there is no background color, and yes, I've tried to change the color, didn't budge, and the quirk is that if it goes a little offscreen, it pushes itself away from the border, if I wanted to remove this quirk, how would I go about doing that? |
I updated the gist to fix the "quirk" (if you talk about the black rectangle) and I fixed the background (wrong UV). |
does this work with controller navigation? |
Well no this is old code but nowadays you can use GetKeyData(ImGuiKey_GamepadLStickX)->AnalogValue and ditto for Y to construct a 2D vector and use that in your pie menu code.
|
For those of you that want to implement controller support:
|
This could maybe better live within ImPlot? https://github.com/epezent/implot |
Hi! just dropping by to say thanks for the initial idea. I've managed to make sth cool with it |
Nice! I used it to make a combat art + prosthetic wheel in Sekiro. Yours seems much more polished though. I was considering doing a rewrite that would fix the bugs, crashes, and terrible spaghetti code. Mind if I yoink parts of that with credit? (if I even get to it lol) |
@tmsrise It's MIT licensed so take anything you'd like :) |
Posting a minor update to the 2015 version (some code simplification) note however that it is functionally the same. I reckon Thibault's version may be better suited: #434 (comment) #include "imgui_internal.h"
// Return >= 0 on mouse release
// Optional int* p_selected display and update a currently selected item
int PiePopupSelectMenu(const ImVec2& center, const char* popup_id, const char** items, int items_count, int* p_selected)
{
int ret = -1;
if (ImGui::BeginPopup(popup_id, ImGuiWindowFlags_NoDecoration))
{
const ImVec2 drag_delta = ImVec2(ImGui::GetIO().MousePos.x - center.x, ImGui::GetIO().MousePos.y - center.y);
const float drag_dist2 = drag_delta.x * drag_delta.x + drag_delta.y * drag_delta.y;
const ImGuiStyle& style = ImGui::GetStyle();
const float RADIUS_MIN = 30.0f;
const float RADIUS_MAX = 120.0f;
const float RADIUS_INTERACT_MIN = 20.0f; // Handle hit testing slightly below RADIUS_MIN
const int ITEMS_MIN = 6; // If they are less than 6 items, we still make each item fill a 1/6 slice.
// Draw background
ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->PushClipRectFullScreen();
draw_list->PathArcTo(center, (RADIUS_MIN + RADIUS_MAX) * 0.5f, 0.0f, IM_PI * 2.0f);
draw_list->PathStroke(IM_COL32(0, 0, 0, 255), ImDrawFlags_Closed, RADIUS_MAX - RADIUS_MIN);
const float item_arc_span = 2 * IM_PI / ImMax(ITEMS_MIN, items_count);
float drag_angle = ImAtan2(drag_delta.y, drag_delta.x);
if (drag_angle < -0.5f * item_arc_span)
drag_angle += 2.0f * IM_PI;
//ImGui::Text("%f", drag_angle); // [Debug]
// Draw items
int item_hovered = -1;
for (int item_n = 0; item_n < items_count; item_n++)
{
const char* item_label = items[item_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
const float item_ang_max = item_arc_span * (item_n + 0.98f) - item_arc_span * 0.5f;
bool hovered = false;
if (drag_dist2 >= RADIUS_INTERACT_MIN * RADIUS_INTERACT_MIN)
if (drag_angle >= item_ang_min && drag_angle < item_ang_max)
hovered = true;
bool selected = p_selected && (*p_selected == item_n);
draw_list->PathArcTo(center, RADIUS_MAX - style.ItemInnerSpacing.x, item_ang_min, item_ang_max);
draw_list->PathArcTo(center, RADIUS_MIN + style.ItemInnerSpacing.x, item_ang_max, item_ang_min);
draw_list->PathFillConvex(ImGui::GetColorU32(hovered ? ImGuiCol_HeaderHovered : selected ? ImGuiCol_HeaderActive : ImGuiCol_Header));
ImVec2 text_size = ImGui::CalcTextSize(item_label);
ImVec2 text_pos = ImVec2(
center.x + cosf((item_ang_min + item_ang_max) * 0.5f) * (RADIUS_MIN + RADIUS_MAX) * 0.5f - text_size.x * 0.5f,
center.y + sinf((item_ang_min + item_ang_max) * 0.5f) * (RADIUS_MIN + RADIUS_MAX) * 0.5f - text_size.y * 0.5f);
draw_list->AddText(text_pos, ImGui::GetColorU32(ImGuiCol_Text), item_label);
if (hovered)
item_hovered = item_n;
}
draw_list->PopClipRect();
if (ImGui::IsMouseReleased(0))
{
ImGui::CloseCurrentPopup();
ret = item_hovered;
if (p_selected)
*p_selected = item_hovered;
}
ImGui::EndPopup();
}
return ret;
} Usage: static const char* test_data = "Menu";
const char* items[] = { "Orange", "Blue", "Purple", "Gray", "Yellow", "Las Vegas" };
int items_count = sizeof(items) / sizeof(*items);
static int selected = -1;
ImGui::Button(selected >= 0 ? items[selected] : "Menu", ImVec2(50, 50));
if (ImGui::IsItemActive()) // Don't wait for button release to activate the pie menu
ImGui::OpenPopup("##piepopup");
ImVec2 pie_menu_center = ImGui::GetIO().MouseClickedPos[0];
int n = PiePopupSelectMenu(pie_menu_center, "##piepopup", items, items_count, &selected);
if (n >= 0)
printf("returned %d\n", n);
} |
This is more a proof of concept that a finished api.
The text was updated successfully, but these errors were encountered: