Search Unity

Pulldown Menu

Discussion in 'Immediate Mode GUI (IMGUI)' started by R.A.E., May 17, 2008.

  1. R.A.E.

    R.A.E.

    Joined:
    Apr 24, 2008
    Posts:
    44
    First of all I´m still new to Unity so this might be easy for the Pros here. :D But I could not find a solution yet.

    I try to create a pulldown menu with the Unity GUI.

    1st option selected , other options only visible on change.



    Could somebody give me a little hint ?

    Thanks
    Marc
     
  2. jeffcraighead

    jeffcraighead

    Joined:
    Nov 15, 2006
    Posts:
    740
    You need a label, a button, a selection grid and a ScrollView :D

    The label will display the name of the selected item. The button activates the drop-down. This can be done simply with a flag like

    Code (csharp):
    1.  
    2. if(Button(icon)) {
    3.     showDropdown=true;
    4.     lastSelection=currentGridSelection;
    5. }
    6.  
    Then the drop-down consists of the selection grid with the columns parameter set to 1 inside a ScrollView. Put the code for that in an

    Code (csharp):
    1.  
    2. if(showDropdown){
    3.    //code for Scrollview  SelectionGrid
    4.    BeginScrollView(..);
    5.    currentSelection=SelectionGrid(...);
    6.    if(currentSelection!=lastSelection) showDropdown=false;
    7.    EndScrollView();
    8. }
    9.  
    This is just one way to do it. You could use a bunch of buttons instead of a SelectionGrid.
     
  3. R.A.E.

    R.A.E.

    Joined:
    Apr 24, 2008
    Posts:
    44
    Hi Jeff,

    Thanks for the quick tips. Tried it out but i get several errors. Hope you can help again :wink:

    First if I use selectionGrid i get the following error


    (That happens for some reason always if i try to use SelectionGrid)

    error BCE0023: No appropriate version of 'UnityEngine.GUI.SelectionGrid' for the argument list '(UnityEngine.Rect, int, (String), int, int)' was found.

    Thats how my code looks so far:

    Code (csharp):
    1.  
    2.  
    3. // For dropdownselect
    4. var showDropdown= false;
    5.  
    6. var dropdownGridInt : int = 0;
    7. var dropdownStrings : String[] = ["drop1", "drop 2"];
    8.  
    9. var scrollViewVector : Vector2 = Vector2.zero;
    10.  
    11. function OnGUI () {
    12.  
    13. if(GUI.Button (Rect (100, 50, 150, 30), "Select")) {
    14.            
    15.                  showDropdown = true;
    16.                  lastSelection = currentGridSelection;
    17.                  
    18.         }
    19.        
    20.        
    21.        
    22.         if(showDropdown){
    23.            
    24.              //code for Scrollview  SelectionGrid
    25.              
    26.             GUI.BeginScrollView (Rect (100, 50, 150, 10), scrollViewVector, Rect (0, 0, 10, 10));
    27.                 currentSelection= GUI.SelectionGrid (Rect (100, 50, 150, 10), dropdownGridInt, dropdownStrings, 1, 1);
    28.                 if(currentSelection!=lastSelection) showDropdown=false;
    29.              GUI.EndScrollView();
    30.        
    31.         }
    32.  
    33.  
    34.  
    35.  
    36. }
    37.  
    38.  
    Copy/Pasted the code for the SelectionGrid from the GUI Basics, But if i try it i get an error.

    Also i get Unknown identifier: 'currentGridSelection'.

    so how do I init that upfront?

    lastSelection = currentGridSelection;


    As I said I´m still a newbie, so please be patient.

    Thanks again.
     
  4. jeffcraighead

    jeffcraighead

    Joined:
    Nov 15, 2006
    Posts:
    740
    Here is working code. Not too much different. You needed to assign the Vector2 returned from the Scrollview to scrollViewVector. Also dropdownGridInt and currentSelection were the same so I replaced all instances of currentSelection with dropdownGridInt. Also adjusted the sized of things a bit. You had them all drawn on top of each other and didn't give the scrollview much space to render in. :D

    I've been converting a lot of my GUI to use the GUILayout class, then you don't have to worry about the Rects for the internal structures.

    Code (csharp):
    1.  
    2. // For dropdownselect
    3. var showDropdown= false;
    4.  
    5. var dropdownGridInt : int = 0;
    6. private var dropdownStrings : String[] = ["drop1", "drop 2","drop3", "drop 4","drop5", "drop 6"];
    7.  
    8. private var scrollViewVector : Vector2 = Vector2.zero;
    9. private var lastSelection = 0;
    10.  
    11. function OnGUI () {
    12.     if(GUI.Button (Rect (100, 50, 200, 30), "Select Stuff - Current Selection: " + dropdownGridInt)) {
    13.         showDropdown = !showDropdown;
    14.         lastSelection = dropdownGridInt;
    15.     }
    16.     if(showDropdown){
    17.         //code for Scrollview  SelectionGrid
    18.         scrollViewVector=GUI.BeginScrollView (Rect (120, 80, 200, 100), scrollViewVector, Rect (0, 0, 180, 300),false,true);
    19.             dropdownGridInt= GUI.SelectionGrid (Rect (0, 0, 170, 200), dropdownGridInt, dropdownStrings, 1);
    20.             if(dropdownGridInt!=lastSelection) showDropdown=false;
    21.         GUI.EndScrollView();
    22.     }
    23. }
    24.  
     
  5. DocSWAB

    DocSWAB

    Joined:
    Aug 28, 2006
    Posts:
    615
    Just a plug for GUI.Layout -- I use it for everything and I prefer it.

    In a word, it's the best thing to use for any complex window, etc., that has multiple elements. It all flows into the area or window rect you define first and it's much easier to do. Vertical and Horizontal groups and flexible spaces are your friends!

    To save typing, add:
    Code (csharp):
    1.  
    2. import UnityEngine.GUILayout;
    3.  
    to the beginning of your .js scripts and then you can just say:

    Code (csharp):
    1.  
    2. BeginVertical();
    3.  
    etc.
     
  6. R.A.E.

    R.A.E.

    Joined:
    Apr 24, 2008
    Posts:
    44
    Thanks a lot fo your help the suggestions. It is a great support. And I m learnig a lot thru this.

    Jeff, thanks to code you posted works fine.

    Regarding GUILayout i just started to check it out you are right it is very convinient.

    Two more question to that:

    1. How can I say draw that group at exactly this position? Lets say I have a psd mockup want to rebuild it using GUILayout.

    eg. : Draw MyButtonGroup at positon 200,150.


    2. the evaluation of the events (button pressed , selection grid etc. goes still in the OnGUI (), or better in an Update() ?
     
  7. shaun

    shaun

    Joined:
    Mar 23, 2007
    Posts:
    728
    Here's a dropdown selection control I wrote a while back. It sounds like what you want. You can reassign the button items GUIStyle to suit your look and feel.

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class NewBehaviourScript : MonoBehaviour
    6. {
    7.     private Rect DropDownRect;
    8.     private Vector2 ListScrollPos;
    9.     private bool DropdownVisible;
    10.     private int SelectedListItem;
    11.     public class GuiListItem //The class that contains our list items
    12.     {
    13.         public bool Selected;
    14.         public string Name;
    15.         public GuiListItem(bool mSelected, string mName)
    16.         {
    17.             Selected = mSelected;
    18.             Name = mName;
    19.         }
    20.         public GuiListItem(string mName)
    21.         {
    22.             Selected = false;
    23.             Name = mName;
    24.         }
    25.         public void enable()
    26.         {
    27.             Selected = true;
    28.         }
    29.         public void disable()
    30.         {
    31.             Selected = false;
    32.         }
    33.     }
    34.     private List<GuiListItem> MyListOfStuff; //Declare our list of stuff
    35.     void Start()
    36.     {
    37.  
    38.         DropDownRect = new Rect(100, 300, 160, 28);//We need to manually position our list, because the dropdown will appear over other controls
    39.         DropdownVisible = false;
    40.         SelectedListItem = -1;
    41.         MyListOfStuff = new List<GuiListItem>(); //Initialize our list of stuff
    42.         for (int i = 0; i < 32; i++)//Fill it with some stuff
    43.         {
    44.             MyListOfStuff.Add(new GuiListItem("Item Number" + i.ToString()));
    45.         }
    46.     }
    47.  
    48.     void OnGUI()
    49.     {
    50.         //Show the dropdown list if required (make sure any controls that should appear behind the list are before this block)
    51.         if (DropdownVisible)
    52.         {
    53.             GUILayout.BeginArea(new Rect(DropDownRect.left, DropDownRect.top + DropDownRect.height, 160, 256), "", "box");
    54.             ListScrollPos = GUILayout.BeginScrollView(ListScrollPos, false, true);
    55.             GUILayout.BeginVertical(GUILayout.Width(120));
    56.             for (int i = 0; i < MyListOfStuff.Count; i++)
    57.             {
    58.                     if (!MyListOfStuff[i].Selected  GUILayout.Button(MyListOfStuff[i].Name))
    59.                     {
    60.                         if (SelectedListItem != -1) MyListOfStuff[SelectedListItem].disable();//Turn off the previously selected item
    61.                         SelectedListItem = i;//Set the index for our currrently selected item
    62.                         MyListOfStuff[SelectedListItem].enable();//Turn on the item we clicked
    63.                         DropdownVisible = false; //Hide the list
    64.                     }
    65.             }
    66.             GUILayout.EndVertical();
    67.             GUILayout.EndScrollView();
    68.             GUILayout.EndArea();
    69.         }
    70.         //Draw the dropdown control
    71.         GUILayout.BeginArea(DropDownRect, "", "box");
    72.         GUILayout.BeginHorizontal();
    73.         string SelectedItemCaption = (SelectedListItem == -1) ? "Select an item..." : MyListOfStuff[SelectedListItem].Name;
    74.         string ButtonText = (DropdownVisible) ? "<<" : ">>";
    75.         GUILayout.TextField(SelectedItemCaption);
    76.         DropdownVisible = GUILayout.Toggle(DropdownVisible, ButtonText, "button", GUILayout.Width(32), GUILayout.Height(20));
    77.         GUILayout.EndHorizontal();
    78.         GUILayout.EndArea();
    79.     }
    80. }
     

    Attached Files:

  8. DocSWAB

    DocSWAB

    Joined:
    Aug 28, 2006
    Posts:
    615
    Really you don't want to try to reproduce a comp pixel for pixel. The beauty of GUILayout is that it will adjust things for you if something like the length of text in a label changes.

    Comps are great for getting a feeling for how it can be. And if you need a specific element to be a specific size, you can force it using GUILayout.Height and GUILayout.Width parameters in your element calls. But that I love about using it, compared to manually laying out windows in Flash, say, is I don't have to calculate exact pixel dimensions and offsets for everything!

    Button actions are often taken in the button block, since they are constructed as if (Button ()) { }

    For other controls, you can have an if (GUI.changed) { } block in OnGUI to evaluate new values and act on them.

    If you are trying to to abstract your control system from your display layer completely, then you would want your GUI to set flags and then have Update or even other scripts read those flags and perform the actual evaluations and actions.

    That is good programming practice, but it can be overkill, too, depend on how complex your GUI system is overall and the types of events you are influencing with your GUI.

    For example, GUI elements that are deeply integrated into your gameplay should probably abstract the display from the action. A save window or alert box can probably do its own work directly.
     
  9. R.A.E.

    R.A.E.

    Joined:
    Apr 24, 2008
    Posts:
    44
    Hi guys,

    thanks a lot for all your tips. Really great help!


    Shaun thanks a lot for that code. That is really a nice solution.

    Will try to implement that in my menu.
     
  10. rdeluz

    rdeluz

    Joined:
    Dec 17, 2008
    Posts:
    13
    I think it is nice to be able to click the item to get the drop down to appear, not just the ">>" arrows.

    To do this, change the GUILayout.TextField line of shaun's code to:

    Code (csharp):
    1. DropdownVisible = GUILayout.Toggle(DropdownVisible, SelectedItemCaption, "textField");
     
  11. rdeluz

    rdeluz

    Joined:
    Dec 17, 2008
    Posts:
    13
    After using this for a bit, I realized that if there were less than 10 items, i.e. no need to scroll vertically, a horizontal scroll bar showed. I fixed this by removing the scroll bar when appropriate. Also this looks nicer, since the buttons fill to the sides if they don't need to scroll vertically:


    Code (csharp):
    1. if (DropdownVisible)
    2.         {
    3.             GUILayout.BeginArea(new Rect(DropDownRect.left, DropDownRect.top + DropDownRect.height, 160, 256), "", "box");
    4.             if (MyListOfStuff.Count > 10) {
    5.                 ListScrollPos = GUILayout.BeginScrollView(ListScrollPos, false, true);
    6.                 GUILayout.BeginVertical(GUILayout.Width(120));
    7.             } else {
    8.                 GUILayout.BeginVertical();
    9.             }
    10.             for (int i = 0; i < MyListOfStuff.Count; i++)
    11.             {
    12.                     if (!MyListOfStuff[i].Selected  GUILayout.Button(MyListOfStuff[i].Name))
    13.                     {
    14.                         if (SelectedListItem != -1) MyListOfStuff[SelectedListItem].disable();//Turn off the previously selected item
    15.                         SelectedListItem = i;//Set the index for our currrently selected item
    16.                         MyListOfStuff[SelectedListItem].enable();//Turn on the item we clicked
    17.                         DropdownVisible = false; //Hide the list
    18.                     }
    19.             }
    20.             GUILayout.EndVertical();
    21.             if (MyListOfStuff.Count > 10) {
    22.                 GUILayout.EndScrollView();
    23.             }
    24.             GUILayout.EndArea();
    25.         }
     
  12. phil.cooper@mtcl.net

    phil.cooper@mtcl.net

    Joined:
    Nov 10, 2009
    Posts:
    265
    how would i assign an action to each of the items in the drop down.

    ive got a script to link to a file from a button, but how would i assign this script to the dropdown items?
     
  13. phil.cooper@mtcl.net

    phil.cooper@mtcl.net

    Joined:
    Nov 10, 2009
    Posts:
    265
    any help would be really appreciated.
     
  14. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    You can use a "switch" statement to take different actions depending on the value of the selected item variable:-
    Code (csharp):
    1. switch (selectedItem) {
    2.     case 0:
    3.         // Action for button 0
    4.         break;
    5.  
    6.     case 1:
    7.         // Action for button 1
    8.        break;
    9.  
    10.     // etc...
    11. }
     
  15. Noobzilla

    Noobzilla

    Joined:
    Dec 31, 2009
    Posts:
    41
    Hey Andeeee -- I used the case code you posted above for my dropdown list. It works great, except that the action keeps repeating. In the case below, the action is to launch a webpage, but the web page keeps launching until a different item is selected then that one repeats. Something I'm missing? Thanks!

    Code (csharp):
    1.  
    2. switch (dropdownGridInt) {
    3.     case 0:
    4.     dropdownGridString = "Overview";
    5.     Application.OpenURL ("http://baybridgeinfo.org/projects/corridor-overview");
    6.         break;
     
  16. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    In that case, you need to store the selected button index on each OnGUI call. Then, on the next call, check to see if the new selected button is the same as the old one. Only if they're different do you enter the switch statement:-
    Code (csharp):
    1. var lastSelectedItem: int;
    2.  
    3. function OnGUI() {
    4.    selectedItem = ... // as before...
    5.  
    6.    if (selectedItem != lastSelectedItem {
    7.         switch (...) {
    8.             // as before
    9.         }
    10.  
    11.         lastSelectedItem = selectedItem;
    12.    }
    13. }
     
  17. Noobzilla

    Noobzilla

    Joined:
    Dec 31, 2009
    Posts:
    41
    Awesome Andeeee - got it. Thanks a lot!
     
  18. phil.cooper@mtcl.net

    phil.cooper@mtcl.net

    Joined:
    Nov 10, 2009
    Posts:
    265
    where you put -

    im not too sure what you mean by "as before".

    could you explain this for me?
     
  19. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    I just mean that the switch statement itself has the same structure as in the previous example and doesn't need to be altered to make this work.
     
  20. phil.cooper@mtcl.net

    phil.cooper@mtcl.net

    Joined:
    Nov 10, 2009
    Posts:
    265
    im having trouble figuring this out. Here is my script -

    Code (csharp):
    1. // For dropdownselect
    2. var showDropdown= false;
    3.  
    4. var dropdownGridInt : int = 0;
    5. private var dropdownStrings : String[] = ["MTCL", "GOOGLE","drop3", "drop 4","drop5", "drop 6", "drop 7", "drop 8", "drop 9", "drop 10"];
    6.  
    7. private var scrollViewVector : Vector2 = Vector2.zero;
    8. private var lastSelection = 0;
    9.  
    10. function OnGUI () {
    11.    if(GUI.Button (Rect(10, Screen.height/7, Screen.width/8, Screen.height/20), "Information")) {
    12.       showDropdown = !showDropdown;
    13.       lastSelection = dropdownGridInt;
    14.    }
    15.    if(showDropdown){
    16.       //code for Scrollview  SelectionGrid
    17.       scrollViewVector=GUI.BeginScrollView (Rect (10, Screen.height/5, Screen.width/8, Screen.height/14), scrollViewVector, Rect (0, 0, Screen.width/12, 300),false,true);
    18.          dropdownGridInt= GUI.SelectionGrid (Rect (0, 0, Screen.width/10, Screen.height/3), dropdownGridInt, dropdownStrings, 1);
    19.          if(dropdownGridInt!=lastSelection) showDropdown=true;
    20.       GUI.EndScrollView();
    21. }
    22.  
    23. var lastSelectedItem: int;
    24.  
    25. function OnGUI(); {
    26.    selectedItem = dropdownGridInt
    27.  
    28.    if (selectedItem != lastSelectedItem {
    29.         switch (dropdownGridInt) {
    30.     case 0:
    31.    dropdownGridString = "MTCL";
    32.    Application.OpenURL ("www.mtcl.net");
    33.         break;
    34.  
    35. if (selectedItem != lastSelectedItem {
    36.         switch (dropdownGridInt) {
    37.     case 0:
    38.    dropdownGridString = "GOOGLE";
    39.    Application.OpenURL ("www.google.co.uk");
    40.         break;
    41.  
    42.         lastSelectedItem = selectedItem;
    43.    }
    44. }
    45.  
    it is coming up with the errors -

    and

    any ideas what is goin wrong? my brain is fried.
     
  21. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    You've got a semicolon after the name of the OnGUI function. Also, you have defined OnGUI twice, which will also not work - you need to take the code out of one of the OnGUI functions and add it to the other one.
     
  22. phil.cooper@mtcl.net

    phil.cooper@mtcl.net

    Joined:
    Nov 10, 2009
    Posts:
    265
    ive tried doin what you said, but i am getting more errors that i dont understand. Here is the script -

    Code (csharp):
    1. // For dropdownselect
    2. var showDropdown= false;
    3.  
    4. var dropdownGridInt : int = 0;
    5. private var dropdownStrings : String[] = ["MTCL", "GOOGLE","drop3", "drop 4","drop5", "drop 6", "drop 7", "drop 8", "drop 9", "drop 10"];
    6.  
    7. private var scrollViewVector : Vector2 = Vector2.zero;
    8. private var lastSelection = 0;
    9.  
    10. function OnGUI () {
    11.    if(GUI.Button (Rect(10, Screen.height/7, Screen.width/8, Screen.height/20), "Information"))
    12.       showDropdown = !showDropdown;
    13.       lastSelection = dropdownGridInt;
    14.      
    15.     var lastSelectedItem: int;
    16.    
    17. selectedItem = dropdownGridInt ;
    18.  
    19.    if (selectedItem != lastSelectedItem  
    20.         switch (dropdownGridInt);  
    21.     case 0:
    22.    dropdownGridString = "MTCL";
    23.    Application.OpenURL ("www.mtcl.net");
    24.         break;
    25.  
    26. if (selectedItem != lastSelectedItem  
    27.         switch (dropdownGridInt);  
    28.     case 0:
    29.    dropdownGridString = "GOOGLE";
    30.    Application.OpenURL ("www.google.co.uk");
    31.         break;
    32.  
    33.         lastSelectedItem = selectedItem;
    34.    }
    35.    
    36.    if(showDropdown){
    37.       //code for Scrollview  SelectionGrid
    38.       scrollViewVector=GUI.BeginScrollView (Rect (10, Screen.height/5, Screen.width/8, Screen.height/14), scrollViewVector, Rect (0, 0, Screen.width/12, 300),false,true);
    39.          dropdownGridInt= GUI.SelectionGrid (Rect (0, 0, Screen.width/10, Screen.height/3), dropdownGridInt, dropdownStrings, 1);
    40.          if(dropdownGridInt!=lastSelection) showDropdown=true;
    41.       GUI.EndScrollView();
    42. }
    im getting these errors -

    and

    and

     
  23. phil.cooper@mtcl.net

    phil.cooper@mtcl.net

    Joined:
    Nov 10, 2009
    Posts:
    265
  24. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    You don't appear to understand the basic syntax of these statements. More or less every statement (apart from single-line statements) has the following structure:-
    Code (csharp):
    1. if (...) {
    2.    // Code
    3. }
    4.  
    5. while (...) {
    6.    // Code
    7. }
    8.  
    You really need to get your head around the basic language constructs before attempting anything more complicated. It's all but impossible to write code by making well-meaning changes to an existing script in the hope that they will work.
     
  25. Cawas

    Cawas

    Joined:
    Jan 14, 2010
    Posts:
    121
    While I haven't read the whole topic, I just wanted to share my own pulldown menu I've build with little help from the code I've found here.

    Code (csharp):
    1.  
    2. private var dropdown = true;
    3. private var dropdownAdjustWindow = false;
    4.  
    5. private var currentScene;
    6.  
    7. private var scene;
    8. var scenes : String[];
    9. var sceneButtonNames : String[];
    10.  
    11. function Awake () {
    12.     if (GameObject.Find("Level (Original)")) {
    13.         currentScene = 0;
    14.     } else {
    15.         currentScene = 1;
    16.     }
    17.     scene = currentScene;
    18. }
    19.  
    20. private var windowRect = Rect(20,20,200,0);
    21.  
    22. function OnGUI () {
    23.     // Make a popup window
    24.     windowRect = GUILayout.Window(0, windowRect, DoControlsWindow, "Options");
    25.    
    26.     // The window can be dragged around by the users - make sure that it doesn't go offscreen.
    27.     windowRect.x = Mathf.Clamp(windowRect.x, 0.0, Screen.width - windowRect.width);
    28.     windowRect.y = Mathf.Clamp(windowRect.y, 0.0, Screen.height - windowRect.height);
    29. }
    30.  
    31. // Make the contents of the window
    32. function DoControlsWindow (windowID : int) {
    33.     // Make the button or area to activate the dropdown
    34.     dropdown = GUI.Toggle(Rect(0,0,16,16), dropdown, "");//, "label");
    35.    
    36.     // Make the window be draggable in the top 20 pixels.
    37.     GUI.DragWindow(Rect(0,0, System.Decimal.MaxValue, 20));
    38.  
    39.     // Adjust the droped down window
    40.     if (!dropdown) {
    41.         GUILayout.Label("Click above to see the options");
    42.         if (dropdownAdjustWindow) {
    43.             windowRect = Rect(windowRect.xMin,windowRect.yMin,200,0);
    44.             dropdownAdjustWindow = false;
    45.         }
    46.     } else {
    47.         dropdownAdjustWindow = true;
    48.        
    49.         GUILayout.Label("Select a scene to load...");
    50.    
    51.         scene = GUILayout.Toolbar(scene, sceneButtonNames);
    52.        
    53.         if (GUI.changed  scene != currentScene) {
    54.             Application.LoadLevel(scenes[scene]);
    55.         }
    56.     }
    57. }
    58.  
    This is mostly based on a script (CameraFocus.js) from 2D Platformer with our beloved Lerpz, but heavily modified. It will draw a window and a toggle button on the top which will "minimize" it, or pull up and down. I'm missing the proper word here.

    Anyway, thanks guys for sharing code!