- Home /
C# Editor GUI custom list type PopUp return string and not int
Hi,
Is there a way to create a popup selector for a custom list in Unity EditorWindow?
This is the code I currently have,
buildingsConfiguration.category = EditorGUILayout.Popup("Category", buildingsConfiguration.category, buildingsList.buildingsCategories, EditorStyles.popup);
buildingsConfiguration.category
is int
and buildingsList.buildingsCategories
is the custom list class. The custom list class is non monobehaviour class.
UPDATE
After googling for sometime, I found out there isn't a way to use a list directly. So here is my solution,
using System.Linq;
private string[] category[];
private void ReloadCategory()
{
category = null;
category = buildingsList.buildingsCategories.Select(I => I.name).ToArray();
}
//And within OnGUI
buildingsConfiguration.category = EditorGUILayout.Popup("Category", buildingsConfiguration.category, category, EditorStyles.popup);
The reloadcategory is called onenable and also a option within the editorwindow to call it manually.
Though I am not entirely sure if this is a good idea. Cause I could remove a category within the list and add another one, and the script will never know it changed. (Or I could remove a category and that index number will be not found which could cause errors). My best option is no never delete any category once made.
Is there anyway I could make the popup return a string instead of int?
Answer by Bunny83 · Mar 08, 2017 at 01:53 PM
Well, i'm not sure if the question is more about how to make that Popup work properly or how to ensure data integrity for your inspected object. Of course indices into an array / List have the general problem that they don't like reorder, insert in the middle and deletion as it will messup or break the proper link.
A common and neat solution to the integrity problem is to use ScriptableObjects as categories. In that case the object doesn't store an index or a string but a serialized reference to your category object which is stored as asset in your project. Of course deleting such an asset would turn all references to it into null ("fake null") references, but all other categories and objects wouldn't even notice.
You could probably use Awake and OnDisable of each category object to automatically add / remove itself to / from a static list or a CategoryManager object.
When building the string array cache you might want to add an index field to each category object to indicate the "current" index. Of course when you mess around with the order or add / remove some they would be messed up. However since we have a cached array we can simply update that information. There are generally 3 situations:
The array length / number of categories stay the same but the list is messed up in some way. This could be due to a reorder, the same amount of add and remove at the same time or a rename.
The array is too short compared to the list of categories.
The array is too long compared to the list of categories.
Case 1 would be already covered when we simply copy the names over each time our GUI is called. Since the array already exists and the count is the same, no garbage is generated. Since strings are immutable reference types, copying the names into the cache array doesn't generate garbage.
The other two cases would require you to resize the cache array. So you would simply first check if the list count and the cache array length are the same, if not, create a new array with the proper size.
Finally just loop through all your categories, copy the name over to the array and in turn set the index of the category objects.
When calling the Popup function you would simply use the cache array and the current index of your category. Of course the category could be "null" in which case you have to use something like "-1".
When the method returns you would check the returned index for valid range (>=0 and
Hi,
I am not entirely sure on what you mean by using the string array. If I am gonna loop through a list using a string array and then reference the index number as the category (the category that is set for a building), if the string array is again updated and the order is changed how can the category of the building?
I have been reading around on ScriptableObjects
. What kind of data type should I use in it? (A list? cause if I only use a category name then should I create one .asset file for each category?).
Ok, since you clearly want to avoid ScriptableObjects here's an example of what i menr:
private string[] category[];
void OnGUI()
{
// [ ... ]
// ensure the array has the same size as the buildingsCategories list
if (category == null || buildingsList.buildingsCategories.Count != category.Length)
category = new array[buildingsList.buildingsCategories.Count];
// keep the array up to date and find current index.
string cat = buildingsConfiguration.category;
int index = -1;
for (int i = 0; i < category.Length; i++)
{
category[i] = buildingsList.buildingsCategories[i].name;
if (index == -1 && category[i] == cat)
index = i;
}
// show the popup
int newIndex = EditorGUILayout.Popup("Category", index, category, EditorStyles.popup);
// if the index has changed, set the new category string
if (newIndex != index)
{
if (newIndex >=0 && newIndex < category.Length)
buildingsConfiguration.category = category[i];
}
// [ ... ]
}
This now assumes that you changed the type of buildingsConfiguration.category
from int to string. This will efficiently keep the category array up to date. No garbage is allocated, only when you add or remove an item from the category list. When you remove a category that is still in use by an object, the category string will stay as it is. The popup will simply show nothing as highlighted. You could tint the popup field in red when the index is "-1" to indicate that the object's category string doesn't exist inside the category array / List.
Alternativaly you could simply auto select a category if it is required to always have one. Or when you detect that the current category string doesn't exist, you would set the string to ""
to avoid keeping a deprecated name. But this is up to you.
Your answer
![](https://koobas.hobune.stream/wayback/20220612112645im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
A node in a childnode? 1 Answer
What is wrong? no overload for method 'List' takes '6' 2 Answers
drop down list c# 1 Answer