using System; using System.Collections.Generic; using UnityEngine; namespace UnityEditor.XR.Interaction.Toolkit.Utilities { class CompactPropertyControl { /// /// 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 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 an info help box below the properties. /// /// public bool hasInfoHelpBox { get; set; } /// /// The text message to show in the info help box. /// /// public GUIContent infoHelpBoxMessage { get; set; } /// /// Whether to show a help icon with mouseover tooltip next to the second property. /// Does not show up if there is only one property. /// /// public bool hasHelpTooltip { get; set; } /// /// The tooltip to show when hovering over the help icon. /// /// public string helpTooltip { get; set; } readonly HelpBoxPopup m_HelpBoxPopup = new HelpBoxPopup { messageType = MessageType.Warning }; readonly GUIContent m_TempContent = new GUIContent(); public float GetPropertyHeight() { var height = 0f; if (properties.Count == 0) height = EditorGUI.GetPropertyHeight(modeProperty); else { 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 DrawCompactGUI(Rect position, GUIContent label) { Debug.Assert(modeProperty != null); position = EditorGUI.PrefixLabel(position, label); // Calculate rect for configuration button var buttonRect = position; var popupStyle = Styles.popup; buttonRect.yMin += popupStyle.margin.top + 1f; buttonRect.width = popupStyle.fixedWidth + popupStyle.margin.right; buttonRect.height = EditorGUIUtility.singleLineHeight; position.xMin = buttonRect.xMax; // Don't make child fields be indented var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; // Using BeginProperty / EndProperty on the popup button allows the user to // revert prefab overrides to mode by right-clicking the configuration button. EditorGUI.BeginProperty(buttonRect, GUIContent.none, modeProperty); using (var check = new EditorGUI.ChangeCheckScope()) { var newPopupIndex = EditorGUI.Popup(buttonRect, modeProperty.intValue, modePopupOptions, popupStyle); if (check.changed) modeProperty.intValue = newPopupIndex; } EditorGUI.EndProperty(); if (properties.Count > 0) { // Rect for the first property, including the warning icon if applicable. var rowRect = position; rowRect.height = EditorGUI.GetPropertyHeight(properties[0]); // Rect for the property itself, which may be shifted over if there is a warning icon. var rect = rowRect; if (propertiesWarningMessage.Count > 0) DrawWarningIcon(ref rect, propertiesWarningMessage[0]); using (var check = new EditorGUI.ChangeCheckScope()) { EditorGUI.PropertyField(rect, properties[0], GUIContent.none); if (check.changed) propertyChanged?.Invoke(properties[0]); } if (properties.Count > 1 && hasHelpTooltip) { var helpRect = buttonRect; helpRect.y += rowRect.height + EditorGUIUtility.standardVerticalSpacing; m_TempContent.image = Contents.helpIcon.image; m_TempContent.tooltip = helpTooltip; EditorGUI.LabelField(helpRect, m_TempContent, EditorStyles.iconButton); } for (var index = 1; index < properties.Count; ++index) { rowRect.y += rowRect.height + EditorGUIUtility.standardVerticalSpacing; rowRect.height = EditorGUI.GetPropertyHeight(properties[index]); rect = rowRect; if (propertiesWarningMessage.Count > index) DrawWarningIcon(ref rect, propertiesWarningMessage[index]); using (var check = new EditorGUI.ChangeCheckScope()) { EditorGUI.PropertyField(rect, properties[index], GUIContent.none); if (check.changed) propertyChanged?.Invoke(properties[index]); } } if (hasInfoHelpBox) { rowRect.y += rowRect.height + EditorGUIUtility.standardVerticalSpacing; rowRect.height = EditorGUIUtility.singleLineHeight; EditorGUI.HelpBox(rowRect, infoHelpBoxMessage.text, MessageType.Info); } } else { EditorGUI.LabelField(position, Contents.unusedLabelText, EditorStyles.miniLabel); } // Set indent back to what it was EditorGUI.indentLevel = indent; } void DrawWarningIcon(ref Rect rowRect, string warningMessage) { if (warningMessage == null) return; // Create space for the warning icon and shift the property rect over. var warningRect = rowRect; var iconButtonStyle = EditorStyles.iconButton; warningRect.yMin += iconButtonStyle.margin.top + 1f; warningRect.width = iconButtonStyle.fixedWidth + iconButtonStyle.margin.right; warningRect.height = EditorGUIUtility.singleLineHeight; rowRect.xMin = warningRect.xMax; 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 unusedLabelText = EditorGUIUtility.TrTextContent("Unused"); public static readonly GUIContent helpIcon = EditorGUIUtility.TrIconContent("_Help"); public static readonly GUIContent warningIcon = EditorGUIUtility.TrIconContent("console.warnicon.sml"); } static class Styles { public static readonly GUIStyle popup = new GUIStyle("PaneOptions") { imagePosition = ImagePosition.ImageOnly }; } } }