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

Question How can I combine EditorGUILayout and EditorGUI?

Discussion in 'Immediate Mode GUI (IMGUI)' started by idbrii, Jul 21, 2020.

  1. idbrii

    idbrii

    Joined:
    Aug 18, 2014
    Posts:
    51
    According to the documentation, PropertyDrawers don't support EditorGUILayout (and if you try to use them in 2019.4, you get tons of ArgumentErrors). I don't want to lay out my own widget sizes when writing EditorWindows. But I have a widget that is used both from a PropertyDrawer (an attribute on a string) and in an EditorWindow.

    How can I combine EditorGUILayout and EditorGUI?

    Looks like I have to use AreaRect to specify the region of my manual layouts. But it is inconvenient:
    • it doesn't provide a position that is relative to my last EditorGUILayout widget
    • it doesn't insert space so that the next EditorGUILayout widget will be positioned below my AreaRect

    Here's some simplified but nontrivial sample code. I've tuned it to properly display the widgets, but it seemed very inconvenient -- I'm hoping there's a better way.

    It makes sense to me that I need to provide Width and Height. How do I avoid computing k_AbsoluteSpace too? Why isn't it k_AbsoluteHeight? Am I doing something wrong?



    Code (CSharp):
    1. // To use: Create a canvas with a bunch of Text children, select the canvas, open Window/Text Dashboard, and click Refresh Selection.
    2.  
    3. using System.Collections.Generic;
    4. using System.Collections;
    5. using System.IO;
    6. using System.Linq;
    7. using System;
    8. using UnityEditor;
    9. using UnityEngine.UI;
    10. using UnityEngine;
    11.  
    12. using Text = UnityEngine.UI.Text;
    13.  
    14. namespace Test.L10n
    15. {
    16.     public class LocalizationDashboard : EditorWindow
    17.     {
    18.  
    19.         [MenuItem("Window/Text Dashboard")]
    20.         static void ShowToolbar()
    21.         {
    22.             EditorWindow.GetWindow<LocalizationDashboard>("Localization");
    23.         }
    24.  
    25.         Text[] m_Widgets;
    26.  
    27.         float k_AbsoluteWidth = 500f;
    28.         float k_AbsoluteHeight = 80.5f;
    29.         float k_AbsoluteSpace = 40.6f;
    30.         void OnGUI()
    31.         {
    32.             if (GUILayout.Button("Refresh From Selection"))
    33.             {
    34.                 m_Widgets = Selection.activeTransform.GetComponentsInChildren<Text>();
    35.             }
    36.  
    37.             if (m_Widgets == null)
    38.             {
    39.                 GUILayout.Label("Stale data. Please refresh.");
    40.                 return;
    41.             }
    42.  
    43.             float absolute_y = 63.8f; // below the first block of stuff.
    44.             EditorGUI.indentLevel += 2;
    45.             foreach (var widget in m_Widgets)
    46.             {
    47.                 EditorGUILayout.ObjectField(widget, typeof(Component), allowSceneObjects: true);
    48.                 var placeholder = EditorGUILayout.DelayedTextField(new GUIContent(widget.name, "Put placeholder text here"), widget.text);
    49.                 if (widget.text != placeholder)
    50.                 {
    51.                     Undo.RecordObject(widget, "Change Text in "+ widget.name);
    52.                     widget.text = placeholder;
    53.                 }
    54.  
    55.                 // RELEVANT STUFF HERE
    56.                 // Makes sense that I need to provide k_AbsoluteWidth and
    57.                 // k_AbsoluteHeight. How do I avoid computing k_AbsoluteSpace
    58.                 // too? Why isn't it k_AbsoluteHeight?
    59.                 Rect position = new Rect(8, absolute_y, k_AbsoluteWidth, k_AbsoluteHeight);
    60.                 using (var area_scope = new GUILayout.AreaScope(position))
    61.                 {
    62.                     position.y = 0;
    63.                     var text_pos = new Rect(position);
    64.                     text_pos.height = EditorGUIUtility.singleLineHeight;
    65.                     position.y += text_pos.height;
    66.                     var new_key = Localization_Editor.TranslatedTextField(text_pos, new GUIContent("Key"), widget.text);
    67.                     if (widget.text != new_key)
    68.                     {
    69.                         Undo.RecordObject(widget, "Change Key in "+ widget.name);
    70.                         widget.text = new_key;
    71.                     }
    72.  
    73.                     var preview_pos = new Rect(position);
    74.                     preview_pos.height = EditorGUIUtility.singleLineHeight;
    75.                     Localization_Editor.DrawPreview(preview_pos, widget.text);
    76.                 }
    77.                 absolute_y += k_AbsoluteHeight;
    78.                 GUILayout.Space(k_AbsoluteSpace);
    79.             }
    80.             EditorGUI.indentLevel -= 2;
    81.  
    82.             GUILayout.Space(10);
    83.             GUILayout.Label("LocalizationDashboard workflow:");
    84.             GUILayout.Label("1. Select a scene object and refresh.");
    85.             GUILayout.Label("2. ???");
    86.             GUILayout.Label("7. Test!");
    87.  
    88.             // Add some sliders to make finding the right values easier.
    89.             k_AbsoluteWidth  = EditorGUILayout.Slider("Absolute Width delta", k_AbsoluteWidth, 0f, 1000f);
    90.             k_AbsoluteHeight = EditorGUILayout.Slider("Absolute Height delta", k_AbsoluteHeight, 0f, 500f);
    91.             k_AbsoluteSpace = EditorGUILayout.Slider("Absolute Space delta", k_AbsoluteSpace, 0f, 500f);
    92.         }
    93.     }
    94.  
    95.     // This implementation is also used in a PropertyDrawer so it cannot use
    96.     // EditorGUILayout. (According to the docs and the infinite
    97.     // ArgumentExceptions.)
    98.     public static class Localization_Editor
    99.     {
    100.         public static string TranslatedTextField(Rect position, GUIContent label, string text)
    101.         {
    102.             // omitted: some buttons and other stuff laid out within the bounds
    103.             // of position that make this more useful.
    104.             text = EditorGUI.TextField(position, label, text);
    105.             return text;
    106.         }
    107.  
    108.         public static void DrawPreview(Rect position, string key)
    109.         {
    110.             // omitted: lookup from key to value.
    111.             using (new EditorGUI.DisabledScope(true))
    112.             {
    113.                 EditorGUI.TextField(position, "Preview", key);
    114.             }
    115.         }
    116.     }
    117.  
    118. }
    119.