using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.XR.Interaction.Toolkit.Utilities
{
class MultilinePropertyControl
{
const float k_Indent = 15f;
///
/// Invoked when one of the has changed.
/// Does not include .
///
public event Action propertyChanged;
///
/// The serialized property that determines which property to show.
///
public SerializedProperty modeProperty { get; set; }
///
/// The text options to show in the mode popup.
///
public GUIContent[] modePopupOptions { get; set; }
///
/// The subset of serialized properties to actively show. Should not include the mode property.
///
public List properties { get; } = new List();
///
/// The label to show for each property. Corresponds 1:1 with the list.
///
public List propertiesContent { get; } = new List();
///
/// The text message for a warning icon to show next to each property. Corresponds 1:1 with the list.
/// May be less than the size of the properties list if remaining properties do not have warnings.
///
public List propertiesWarningMessage { get; } = new List();
///
/// Whether to show a warning help box below the properties.
///
///
public bool hasInfoHelpBox { get; set; }
///
/// The text message to show in the warning help box.
///
///
public GUIContent infoHelpBoxMessage { get; set; }
readonly HelpBoxPopup m_HelpBoxPopup = new HelpBoxPopup { messageType = MessageType.Warning };
readonly GUIContent m_TempContent = new GUIContent();
public float GetPropertyHeight()
{
var height = 0f;
// Field label.
height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
// Mode dropdown.
height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
for (var index = 0; index < properties.Count; ++index)
{
height += EditorGUI.GetPropertyHeight(properties[index]);
}
// Add spacing between properties
if (properties.Count > 1)
height += EditorGUIUtility.standardVerticalSpacing * (properties.Count - 1);
if (hasInfoHelpBox)
height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
return height;
}
public void DrawMultilineGUI(Rect position, GUIContent label)
{
Debug.Assert(modeProperty != null);
Debug.Assert(properties.Count == propertiesContent.Count);
var titleRect = position;
titleRect.height = EditorGUIUtility.singleLineHeight;
var inputSourceModeRect = position;
inputSourceModeRect.x += k_Indent;
inputSourceModeRect.width -= k_Indent;
inputSourceModeRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
inputSourceModeRect.height = EditorGUI.GetPropertyHeight(modeProperty);
var firstRowRect = position;
firstRowRect.x += k_Indent;
firstRowRect.width -= k_Indent;
firstRowRect.y += (titleRect.height + inputSourceModeRect.height) + (EditorGUIUtility.standardVerticalSpacing * 2f);
EditorGUI.LabelField(titleRect, label);
EditorGUI.PropertyField(inputSourceModeRect, modeProperty);
if (properties.Count > 0)
{
// Rect for the first property, including the warning icon if applicable.
firstRowRect.height = EditorGUI.GetPropertyHeight(properties[0]);
if (propertiesWarningMessage.Count > 0)
DrawWarningIcon(firstRowRect, propertiesWarningMessage[0]);
using (var check = new EditorGUI.ChangeCheckScope())
{
EditorGUI.PropertyField(firstRowRect, properties[0], propertiesContent[0]);
if (check.changed)
propertyChanged?.Invoke(properties[0]);
}
var rect = firstRowRect;
for (var index = 1; index < properties.Count; ++index)
{
rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing;
rect.height = EditorGUI.GetPropertyHeight(properties[index]);
if (propertiesWarningMessage.Count > index)
DrawWarningIcon(rect, propertiesWarningMessage[index]);
using (var check = new EditorGUI.ChangeCheckScope())
{
EditorGUI.PropertyField(rect, properties[index], propertiesContent[index]);
if (check.changed)
propertyChanged?.Invoke(properties[index]);
}
}
if (hasInfoHelpBox)
{
rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing;
rect.height = EditorGUIUtility.singleLineHeight;
EditorGUI.HelpBox(rect, infoHelpBoxMessage.text, MessageType.Info);
}
}
}
void DrawWarningIcon(Rect rowRect, string warningMessage)
{
if (warningMessage == null)
return;
// Show the warning icon to the left of the property, and do not shift the property rect over.
// This is different from the Compact drawer, which shows the warning icon next to the value
// and shifts the value over to the right. This is because we are using PropertyField to draw the
// property with a label, which does not allow us to shift the object field over without also shifting
// the label. The right edge of the label should always line up vertically with all property fields.
var warningRect = rowRect;
var iconButtonStyle = EditorStyles.iconButton;
warningRect.yMin += iconButtonStyle.margin.top + 1f;
warningRect.width = iconButtonStyle.fixedWidth + iconButtonStyle.margin.right;
warningRect.height = EditorGUIUtility.singleLineHeight;
warningRect.x = warningRect.x - warningRect.width + (EditorGUI.indentLevel * k_Indent);
m_TempContent.image = Contents.warningIcon.image;
m_TempContent.tooltip = string.Empty;
if (EditorGUI.DropdownButton(warningRect, m_TempContent, FocusType.Keyboard, EditorStyles.iconButton))
{
m_HelpBoxPopup.message = warningMessage;
PopupWindow.Show(warningRect, m_HelpBoxPopup);
}
}
static class Contents
{
public static readonly GUIContent warningIcon = EditorGUIUtility.TrIconContent("console.warnicon.sml");
}
}
}