Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Tired of the limited viewing capabilities of strings in your inspector?

Discussion in 'Scripting' started by naked_chicken, Feb 9, 2014.

  1. naked_chicken

    naked_chicken

    Joined:
    Sep 10, 2012
    Posts:
    186
    While working on a side project I got fed up with the way strings were represented in the inspector so I made this property drawer:



    It changes your single line strings to a word wrapping, auto extending text area. It also allows you to re-order your array of strings.

    You can download everything you need here

    And here is the actual code for your viewing pleasure:

    Code (csharp):
    1. //Goes in your main directory
    2. using UnityEngine;
    3.  
    4. public class TextBlockAttribute : PropertyAttribute {}
    Code (csharp):
    1. //Goes in an Editor Folder
    2. using UnityEngine;
    3. using UnityEditor;
    4. using System.Collections;
    5.  
    6. [CustomPropertyDrawer(typeof(TextBlockAttribute))]
    7. public class TextBlockPropertyDrawer : PropertyDrawer {
    8.  
    9.     public override float GetPropertyHeight (SerializedProperty prop, GUIContent label) {
    10.         //override height to adjust for word wrapping.
    11.         GUIStyle style = new GUIStyle(EditorStyles.textField);
    12.         style.wordWrap = true;
    13.  
    14.         return Mathf.Clamp(style.CalcHeight(new GUIContent(prop.stringValue), Screen.width - 34) + 16f, 32f, 128f);
    15.     }
    16.  
    17.     public override void OnGUI (Rect position, SerializedProperty prop, GUIContent label) {
    18.         //First we need to look at the property path to see if it is an array
    19.         string path = prop.propertyPath;
    20.         int arrayInd = path.LastIndexOf(".Array");
    21.         bool bIsArray = false;
    22.         if(arrayInd >= 0)
    23.             bIsArray = true;
    24.        
    25.        
    26.         Rect labelRect = position;
    27.         labelRect.height = 16f;
    28.        
    29.         EditorGUI.LabelField(labelRect, label);
    30.        
    31.         if(bIsArray){
    32.             //If we're dealing with an array then we need to get the object and find the array property so we can mess with it
    33.             SerializedObject so = prop.serializedObject;
    34.             string arrayPath = path.Substring(0, arrayInd);
    35.             SerializedProperty arrayProp = so.FindProperty(arrayPath);
    36.  
    37.             //Next we need to grab the index from the path string
    38.             int indStart = path.IndexOf("[") + 1;
    39.             int indEnd = path.IndexOf("]");
    40.            
    41.             string indString = path.Substring(indStart, indEnd - indStart);
    42.            
    43.             int myIndex = int.Parse(indString);
    44.  
    45.             //And finaly we place our buttons
    46.             labelRect.x += 80;
    47.             labelRect.width = 75;
    48.            
    49.             if(GUI.Button(labelRect, "Move Up")){
    50.                 if(myIndex > 0){
    51.                     string temp = arrayProp.GetArrayElementAtIndex(myIndex-1).stringValue;
    52.                     arrayProp.GetArrayElementAtIndex(myIndex-1).stringValue = arrayProp.GetArrayElementAtIndex(myIndex).stringValue;
    53.                     arrayProp.GetArrayElementAtIndex(myIndex).stringValue = temp;
    54.                    
    55.                     so.ApplyModifiedProperties();
    56.                 }
    57.             }
    58.            
    59.             labelRect.x += 90;
    60.            
    61.             if(GUI.Button(labelRect, "Move Down")){
    62.                 if(myIndex < arrayProp.arraySize-1){
    63.                     string temp = arrayProp.GetArrayElementAtIndex(myIndex+1).stringValue;
    64.                     arrayProp.GetArrayElementAtIndex(myIndex+1).stringValue = arrayProp.GetArrayElementAtIndex(myIndex).stringValue;
    65.                     arrayProp.GetArrayElementAtIndex(myIndex).stringValue = temp;
    66.                    
    67.                     so.ApplyModifiedProperties();
    68.                 }
    69.             }
    70.         }
    71.  
    72.         Rect blockRect = position;
    73.         blockRect.height -= 16f;
    74.         blockRect.y += 16f;
    75.        
    76.         GUIStyle style = new GUIStyle(EditorStyles.textField);
    77.         style.wordWrap = true;
    78.        
    79.         EditorGUI.BeginChangeCheck ();
    80.         string value = EditorGUI.TextArea (blockRect, prop.stringValue, style);
    81.         if (EditorGUI.EndChangeCheck ()){
    82.             prop.stringValue = value;
    83.         }
    84.     }
    85. }
     

    Attached Files:

    Last edited: Feb 9, 2014
  2. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Nice one.

    Wonder if I'll ever release my own inspector one day. I rewrote the whole damn thing from the ground up.
     
  3. MDragon

    MDragon

    Joined:
    Dec 26, 2013
    Posts:
    329
    Nice, recently began to make my own Inspectors (with my super multi-purpose scripts, it's a must ;) ). I may implement... when I have time to actually understand it all.

    By the way, what's the purpose of the first script? And I'm guessing it has something to do with the way you implement this editor, or does this somehow affect ALL string arrays? My inexperience shows, doesn't it? :D

    Thanks!
     
  4. naked_chicken

    naked_chicken

    Joined:
    Sep 10, 2012
    Posts:
    186
    The first script goes in your main directory and then you can use it on any string property by throwing [TextBlock] on it:

    Code (csharp):
    1. public class Test : MonoBehaviour {
    2.  
    3.     [TextBlock]
    4.     public string exampleString;
    5.  
    6.     [TextBlock]
    7.     public string[] exampleArray;
    8.  
    9. }
     
  5. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    You could also pass an enum to that attribute to display different string kind;

    - TextArea (you got that one)
    - Password
    - Tags
    - Path (file or folder) picker
    - etc.
     
  6. naked_chicken

    naked_chicken

    Joined:
    Sep 10, 2012
    Posts:
    186
    Good idea LightStriker, thanks.
     
  7. MDragon

    MDragon

    Joined:
    Dec 26, 2013
    Posts:
    329
    Once again, thanks for this. However, now that I'm at the point where I want to edit string arrays in my editor, I was just about to make my own string array editor, then remembered this thread. I also remembered that this one was better than anything I was thinking of ;)

    A small question: How would I call on this from my own editor scripts? I've tried something like...

    (My object's script)
    Code (csharp):
    1.     public string[] tabNames = new string[3];    // Names for each tab
    2.     public string[] tabMesages = new string[3]; // Message within each tab
    (My custom editor for that script)
    Code (csharp):
    1.         // myTarget: scriptName myTarget = (scriptName) target;
    2.         myTarget.tabNames = EditorGUILayout.TextField(myTarget.tabNames);
    3.         myTarget.tabMessages = EditorGUILayout.TextField(myTarget.tabMessages);
    However, it says that string[] cannot be converted into string, which makes sense. Now I'm at a lost on how to call on the basic Inspector's behavior.

    Once again, thanks for sharing this. Interesting to see what's out there and what I could do on top of it as well :D
     
  8. naked_chicken

    naked_chicken

    Joined:
    Sep 10, 2012
    Posts:
    186
    It sounds like what you're trying to do is a custom Editor, the example I put up is a property drawer. Both will work but in a custom editor you have to either use the array field or do a for-loop on your arrays. Something like:

    Code (csharp):
    1. for(int i=0; i<myArray.Length; i++){
    2.      myArray[i] = EditorGUILayout.textField(myArray[i]);
    3. }
     
  9. cfloutier

    cfloutier

    Joined:
    Jul 30, 2009
    Posts:
    34
    Thanks fot the very first post. It answered a question of mine : how to add moive up and move down in array ?
    I'm trying to make it generic to handle any type of class. I'll post the answer here if I succeed
     
  10. cfloutier

    cfloutier

    Joined:
    Jul 30, 2009
    Posts:
    34