From 5dc71785afb8badbf539be1883170b096c763c5c Mon Sep 17 00:00:00 2001 From: VladV Date: Fri, 16 Jun 2023 17:25:07 +0400 Subject: [PATCH] Add inline fix for validation messages --- .../Validators_ValidateInputSample.cs | 14 ++++ Editor/Elements/TriInfoBoxElement.cs | 72 +++++++++++++++++-- Editor/ValidatorsDrawer.cs | 16 ++++- Runtime/TriValidationResult.cs | 19 ++++- 4 files changed, 112 insertions(+), 9 deletions(-) diff --git a/Editor.Samples/Validators/Validators_ValidateInputSample.cs b/Editor.Samples/Validators/Validators_ValidateInputSample.cs index bc9c198..45c93f0 100644 --- a/Editor.Samples/Validators/Validators_ValidateInputSample.cs +++ b/Editor.Samples/Validators/Validators_ValidateInputSample.cs @@ -6,10 +6,24 @@ public class Validators_ValidateInputSample : ScriptableObject [ValidateInput(nameof(ValidateTexture))] public Texture tex; + [ValidateInput(nameof(ValidateNumber))] + public int number; + private TriValidationResult ValidateTexture() { if (tex == null) return TriValidationResult.Error("Tex is null"); if (!tex.isReadable) return TriValidationResult.Warning("Tex must be readable"); return TriValidationResult.Valid; } + + private TriValidationResult ValidateNumber() + { + if (number == 1) + { + return TriValidationResult.Valid; + } + + return TriValidationResult.Error("Number must be equal 1") + .WithFix(() => number = 1, "Set to 1"); + } } \ No newline at end of file diff --git a/Editor/Elements/TriInfoBoxElement.cs b/Editor/Elements/TriInfoBoxElement.cs index dcceb54..bcce49a 100644 --- a/Editor/Elements/TriInfoBoxElement.cs +++ b/Editor/Elements/TriInfoBoxElement.cs @@ -1,4 +1,5 @@ -using TriInspector.Utilities; +using System; +using TriInspector.Utilities; using TriInspectorUnityInternalBridge; using UnityEditor; using UnityEngine; @@ -7,22 +8,44 @@ namespace TriInspector.Elements { public class TriInfoBoxElement : TriElement { + private const int ActionSpacing = 5; + private const int ActionWidth = 100; + private const int ActionWidthWithSpacing = ActionWidth + ActionSpacing * 2; + private readonly GUIContent _message; private readonly Texture2D _icon; private readonly Color _color; + private readonly Action _inlineAction; + private readonly GUIContent _inlineActionContent; - public TriInfoBoxElement(string message, TriMessageType type = TriMessageType.None, Color? color = null) + public TriInfoBoxElement(string message, TriMessageType type = TriMessageType.None, Color? color = null, + Action inlineAction = null, GUIContent inlineActionContent = null) { var messageType = GetMessageType(type); _icon = EditorGUIUtilityProxy.GetHelpIcon(messageType); _message = new GUIContent(message); _color = color ?? GetColor(type); + _inlineAction = inlineAction; + _inlineActionContent = inlineActionContent ?? GUIContent.none; } public override float GetHeight(float width) { + var labelWidth = width; + + if (_inlineAction != null) + { + labelWidth -= ActionWidthWithSpacing; + } + var style = _icon == null ? Styles.InfoBoxContentNone : Styles.InfoBoxContent; - var height = style.CalcHeight(_message, width); + var height = style.CalcHeight(_message, labelWidth); + + if (_inlineAction != null) + { + height = Mathf.Max(height, CalcActionHeight() + ActionSpacing * 2); + } + return Mathf.Max(26, height); } @@ -33,21 +56,57 @@ namespace TriInspector.Elements GUI.Label(position, string.Empty, Styles.InfoBoxBg); } + var labelWidth = position.width; + + if (_inlineAction != null) + { + labelWidth -= ActionWidthWithSpacing; + } + if (_icon != null) { + var labelRect = new Rect(position) + { + width = labelWidth, + }; + var iconRect = new Rect(position) { xMin = position.xMin + 4, width = 20, }; - GUI.Label(position, _message, Styles.InfoBoxContent); + GUI.Label(labelRect, _message, Styles.InfoBoxContent); GUI.DrawTexture(iconRect, _icon, ScaleMode.ScaleToFit); } else { GUI.Label(position, _message, Styles.InfoBoxContentNone); } + + if (_inlineAction != null) + { + var fixHeight = CalcActionHeight(); + + var actionRect = new Rect(position) + { + xMax = position.xMax - ActionSpacing, + xMin = position.xMax - ActionWidth - ActionSpacing, + yMin = position.center.y - fixHeight / 2, + yMax = position.center.y + fixHeight / 2, + }; + + if (GUI.Button(actionRect, _inlineActionContent, Styles.InfoBoxInlineAction)) + { + _inlineAction?.Invoke(); + } + } + } + + + private float CalcActionHeight() + { + return Styles.InfoBoxInlineAction.CalcHeight(_inlineActionContent, ActionWidth); } private static Color GetColor(TriMessageType type) @@ -82,6 +141,7 @@ namespace TriInspector.Elements public static readonly GUIStyle InfoBoxBg; public static readonly GUIStyle InfoBoxContent; public static readonly GUIStyle InfoBoxContentNone; + public static readonly GUIStyle InfoBoxInlineAction; static Styles() { @@ -97,6 +157,10 @@ namespace TriInspector.Elements { padding = new RectOffset(26, 4, 4, 4), }; + InfoBoxInlineAction = new GUIStyle(GUI.skin.button) + { + wordWrap = true, + }; } } } diff --git a/Editor/ValidatorsDrawer.cs b/Editor/ValidatorsDrawer.cs index e414c1f..a78f98a 100644 --- a/Editor/ValidatorsDrawer.cs +++ b/Editor/ValidatorsDrawer.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using TriInspector.Elements; using UnityEditor; @@ -61,11 +62,22 @@ namespace TriInspector foreach (var result in _validationResults) { - AddChild(new TriInfoBoxElement(result.Message, result.MessageType)); + var infoBox = result.FixAction != null + ? new TriInfoBoxElement(result.Message, result.MessageType, + inlineAction: () => ExecuteFix(result.FixAction), + inlineActionContent: result.FixActionContent) + : new TriInfoBoxElement(result.Message, result.MessageType); + + AddChild(infoBox); } return true; } + + private void ExecuteFix(Action fixAction) + { + _property.ModifyAndRecordForUndo(targetIndex => fixAction?.Invoke()); + } } } } \ No newline at end of file diff --git a/Runtime/TriValidationResult.cs b/Runtime/TriValidationResult.cs index ac0cb1d..78d18cd 100644 --- a/Runtime/TriValidationResult.cs +++ b/Runtime/TriValidationResult.cs @@ -1,25 +1,38 @@ -namespace TriInspector +using System; +using UnityEngine; + +namespace TriInspector { public readonly struct TriValidationResult { public static TriValidationResult Valid => new TriValidationResult(true, null, TriMessageType.None); - public TriValidationResult(bool valid, string message, TriMessageType messageType) + public TriValidationResult(bool valid, string message, TriMessageType messageType, + Action fixAction = null, GUIContent fixActionContent = null) { IsValid = valid; Message = message; MessageType = messageType; + FixAction = fixAction; + FixActionContent = fixActionContent; } public bool IsValid { get; } public string Message { get; } public TriMessageType MessageType { get; } + public Action FixAction { get; } + public GUIContent FixActionContent { get; } + + public TriValidationResult WithFix(Action action, string name = null) + { + return new TriValidationResult(IsValid, Message, MessageType, action, new GUIContent(name)); + } public static TriValidationResult Info(string error) { return new TriValidationResult(false, error, TriMessageType.Info); } - + public static TriValidationResult Error(string error) { return new TriValidationResult(false, error, TriMessageType.Error);