PropertyDrawer vs Array

Раздел, посвящённый всему, что связано с программированием для Редактора Юнити. Скрипты Редактора, Wizards и прочее.

PropertyDrawer vs Array

Сообщение KingPeas 24 июл 2014, 11:42

Нужна помощь.
Пытаюсь сделать контрол в котором совмещено текстовое поле с кнопкой выбора варианта. Реализовано следующим образом
Синтаксис:
Используется csharp
using System;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using System.Collections;

public class PopupTextAttribute : PropertyAttribute
{
    public PopupTextAttribute()
    {

    }


}

#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(PopupTextAttribute))]
public class PopupTextDrawer : PropertyDrawer
{
    protected string selectVal = null;
    override public void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        position.height = EditorGUIUtility.singleLineHeight;
        Rect r = EditorGUI.PrefixLabel(position, label);
        EditorGUI.BeginChangeCheck();
        Color oldColor = GUI.color;
        r.width -= EditorGUIUtility.singleLineHeight * 2;
        string result = property.stringValue;
        if (!CheckCorrect(property.stringValue))
        {
            GUI.color = Color.grey;
        }
        result = GUI.TextField(r, result, EditorStyles.textField);
       
        GUI.color = oldColor;
                r.x += r.width;
                r.width = EditorGUIUtility.singleLineHeight + 2;
               
                if (GUI.Button(r, "L", EditorStyles.miniButton))
                {
                        var menu = new GenericMenu();
                        string[] options = GetOptions();
                        foreach (string s in options)
                        {
                                string localS = s;
                                menu.AddItem(new GUIContent(localS.Replace(".", "/")),
                                             false,
                                             () => selectVal = localS
                                             );
                               
                        }
                        menu.ShowAsContext();
                       
                }
        if (EditorGUI.EndChangeCheck())
        {
            SetValue(property, result);
        }
       
        r.x += r.width;
        r.width = EditorGUIUtility.singleLineHeight + 2;

        if (GUI.Button(r, "C", EditorStyles.miniButton))
        {
            Clear(property);
        }
        if (GetOptions().Length == 0)
        {
            position.y += EditorGUIUtility.singleLineHeight;
            r = EditorGUI.PrefixLabel(position, new GUIContent(" "));

            EditorGUI.LabelField(position, " ", "Не удалось получить список значений.");
            return;
        }

                if (!string.IsNullOrEmpty(selectVal))
        {
                        SetValue(property, selectVal);
            selectVal = null;
        }

    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return EditorGUIUtility.singleLineHeight * (GetOptions().Length > 0 ? 1 : 2 ) + 2;
    }

    virtual public void Clear(SerializedProperty property)
    {
        property.stringValue = "";
    }

    virtual public void SetValue(SerializedProperty property, string option)
    {
        property.stringValue = option;
    }

    /*virtual public void SetValue(SerializedProperty property, int selected)
    {
       
    }*/


    virtual public bool CheckCorrect(string selected)
    {
        string[] options = GetOptions();

        return Array.Exists(options, r => r == selected);
    }

    virtual public string[] GetOptions()
    {
        string[] ss = {"1","2","3","4","5"};
        return ss;
    }
        virtual public bool IsSupported(SerializedProperty property){
                return property.propertyType == SerializedPropertyType.String;
        }
}
#endif
 

Все отлично работает пока поле представлено обычным значением, но как только мне надо вывести массив начинаются проблемы. Ввод вручную работает нормально, а вот выбор изменяет только значение в первом элементе.
Вот тестовый скрипт, вешаем на любой объект сцены и смотрим результат в редакторе
Синтаксис:
Используется csharp
using UnityEngine;
using System.Collections;

public class PopupTextTest : MonoBehaviour
{

    [PopupText] public string t1 = "";
    [PopupText] public string t2 = "";
    [PopupText] public string[] tt = new string[0];
 
}
 


подозреваю что проблема вот в этом месте
Синтаксис:
Используется csharp
menu.AddItem(new GUIContent(localS.Replace(".", "/")),
                                             false,
                                             () => selectVal = localS
                                             );

пробовал selectVal делать локальной для метода или сохранять значение сразу в property.stringValue но так не работает...
может кто знает как сие победить?
Хочу IQ как ICQ, ну или хотя бы ICQ как IQ...
Мой первый плагин PropertyDrawerCollection
Аватара пользователя
KingPeas
UNIт
 
Сообщения: 78
Зарегистрирован: 12 сен 2012, 12:34
Откуда: Новосибирск
Skype: evgeniygurlev
  • Сайт
  • ICQ

Re: PropertyDrawer vs Array

Сообщение KingPeas 24 июл 2014, 21:43

уж не знаю на сколько правильно, сделал так.
В propertyDrawer добавил еще одну переменную int, назвал ее selectIdx. Дальше завел функцию которая для поля типа массив возвращает номер индекса, для обычного всегда 0. Функция распарсивает строку из property.propertyPath через регулярные выражения и так получаем индекс. При установке selectVal в selectIdx выставляю индекс элемента в котором произошел выбор и свойство обновляю только тогда когда у текущего элемента индекс совпадает с ним и selectVal задана.
теперь вроде бы работает)
Хочу IQ как ICQ, ну или хотя бы ICQ как IQ...
Мой первый плагин PropertyDrawerCollection
Аватара пользователя
KingPeas
UNIт
 
Сообщения: 78
Зарегистрирован: 12 сен 2012, 12:34
Откуда: Новосибирск
Skype: evgeniygurlev
  • Сайт
  • ICQ


Вернуться в Editor

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1