I want to create a menu that works like a regular Windows or Mac pulldown menu (i.e. File → Save As). I’ve searched around the forums a bit, but all scripts I’ve found require two clicks:
click 1: open pulldown menu
click 2: select item
That’s one click too many! I want to open the menu on mouse down, allow the user to make a selection and then close the menu again on mouse up.
I tried using a RepeatButton, like so:
if (GUI.RepeatButton(new Rect(x, y, w, h), "File"))
{
selected = GUI.Toolbar(...); // sub menu
}
Unfortunately, the above doesn’t work, since the menu closes as soon as the user moves the cursor away from the [File] button. You can work around that, but then the next problem is that the sub menu buttons don’t respond since as far as the UnityGUI is concerned, the [File] button hasn’t been released yet.
So… any GUI experts out there who know how to crack this one?
you need to use a different coding structure and have states.
when you click the button, the state is set / reset and if the state is set at the time, the menu is shown
bool isMenuOpen = false;
void OnGUI()
{
if (GUI.RepeatButton(..., "File")) // main menu
isMenuOpen = true;
if (isMenuOpen)
{
if (GUI.Button(..., "Save As")); // submenu
isMenuOpen = false;
}
}
I still need two clicks to activate the “Save As” action. Plus, my menu doesn’t fold up when the user clicks outside of the pulldown.
I’m beginning to think that UnityGUI simply isn’t suited to build pulldown menus that behave like the standard OS controls… perhaps I should just roll my own.
It is (look at the pop-up menu in the file requester I made for this), but you have to use the right functions; clearly using buttons isn’t going to work. I used a SelectionGrid for the menu.
So… there’s something you do differently that tells the GUI to transfer the focus from the double arrow button at the end of your combo to the selection grid that contains the directories.
Actually you can click anywhere in that bar rather than just the double arrow. But anyway, that’s a label rather than a button and I’m checking the label’s rect for the mouse position. I’m not sure if there’s a reason for that or if I just forgot about RepeatButton, but it sounds like the focus thing might be the reason…
Rect menuRect = new Rect(10, 100, 200, 20);
Vector3 mousePos = Input.mousePosition;
mousePos.y = Screen.height - mousePos.y;
// Manual hittest against menu rect to open/close the menu
if (mousePos.x >= menuRect.x mousePos.x <= (menuRect.x + menuRect.width)
mousePos.y >= menuRect.y mousePos.y <= (menuRect.y + menuRect.height))
{
if (Input.GetMouseButtonDown(0))
m_menuOpen = true;
if (Input.GetMouseButtonUp(0))
m_menuOpen = false;
}
if (m_menuOpen)
{
// Menu is open.
// Use a selection grid that contains both the main menu item and the sub menu.
// (tricks Unity into giving this item focus)
string[] submenu = { "File", "Open", "Save", "Save As..." };
m_subSel = GUI.SelectionGrid(new Rect(10, 100, 200, 90), m_subSel, submenu, 1);
if (GUI.changed)
m_menuOpen = false; // Close menu once user makes a selection
}
else
{
// Menu is closed.
// Use a repeat button to get rollover effect for free.
GUI.RepeatButton(menuRect, "File", GUI.skin.button);
}
It’s still not 100% what I want, but it will do for now.
You can use Rect.Contains instead of a bunch of if/then logic to see if the mouse position is inside a rect. Also it’s recommended to use the Event class for OnGUI stuff rather than Input, such as Event.current.mousePosition (which is in the correct OnGUI coordinate system).