Add inline fix for validation messages

This commit is contained in:
VladV 2023-06-16 17:25:07 +04:00
parent 945dc0bad9
commit 5dc71785af
4 changed files with 112 additions and 9 deletions

View File

@ -6,10 +6,24 @@ public class Validators_ValidateInputSample : ScriptableObject
[ValidateInput(nameof(ValidateTexture))] [ValidateInput(nameof(ValidateTexture))]
public Texture tex; public Texture tex;
[ValidateInput(nameof(ValidateNumber))]
public int number;
private TriValidationResult ValidateTexture() private TriValidationResult ValidateTexture()
{ {
if (tex == null) return TriValidationResult.Error("Tex is null"); if (tex == null) return TriValidationResult.Error("Tex is null");
if (!tex.isReadable) return TriValidationResult.Warning("Tex must be readable"); if (!tex.isReadable) return TriValidationResult.Warning("Tex must be readable");
return TriValidationResult.Valid; 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");
}
} }

View File

@ -1,4 +1,5 @@
using TriInspector.Utilities; using System;
using TriInspector.Utilities;
using TriInspectorUnityInternalBridge; using TriInspectorUnityInternalBridge;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
@ -7,22 +8,44 @@ namespace TriInspector.Elements
{ {
public class TriInfoBoxElement : TriElement 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 GUIContent _message;
private readonly Texture2D _icon; private readonly Texture2D _icon;
private readonly Color _color; 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); var messageType = GetMessageType(type);
_icon = EditorGUIUtilityProxy.GetHelpIcon(messageType); _icon = EditorGUIUtilityProxy.GetHelpIcon(messageType);
_message = new GUIContent(message); _message = new GUIContent(message);
_color = color ?? GetColor(type); _color = color ?? GetColor(type);
_inlineAction = inlineAction;
_inlineActionContent = inlineActionContent ?? GUIContent.none;
} }
public override float GetHeight(float width) public override float GetHeight(float width)
{ {
var labelWidth = width;
if (_inlineAction != null)
{
labelWidth -= ActionWidthWithSpacing;
}
var style = _icon == null ? Styles.InfoBoxContentNone : Styles.InfoBoxContent; 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); return Mathf.Max(26, height);
} }
@ -33,21 +56,57 @@ namespace TriInspector.Elements
GUI.Label(position, string.Empty, Styles.InfoBoxBg); GUI.Label(position, string.Empty, Styles.InfoBoxBg);
} }
var labelWidth = position.width;
if (_inlineAction != null)
{
labelWidth -= ActionWidthWithSpacing;
}
if (_icon != null) if (_icon != null)
{ {
var labelRect = new Rect(position)
{
width = labelWidth,
};
var iconRect = new Rect(position) var iconRect = new Rect(position)
{ {
xMin = position.xMin + 4, xMin = position.xMin + 4,
width = 20, width = 20,
}; };
GUI.Label(position, _message, Styles.InfoBoxContent); GUI.Label(labelRect, _message, Styles.InfoBoxContent);
GUI.DrawTexture(iconRect, _icon, ScaleMode.ScaleToFit); GUI.DrawTexture(iconRect, _icon, ScaleMode.ScaleToFit);
} }
else else
{ {
GUI.Label(position, _message, Styles.InfoBoxContentNone); 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) private static Color GetColor(TriMessageType type)
@ -82,6 +141,7 @@ namespace TriInspector.Elements
public static readonly GUIStyle InfoBoxBg; public static readonly GUIStyle InfoBoxBg;
public static readonly GUIStyle InfoBoxContent; public static readonly GUIStyle InfoBoxContent;
public static readonly GUIStyle InfoBoxContentNone; public static readonly GUIStyle InfoBoxContentNone;
public static readonly GUIStyle InfoBoxInlineAction;
static Styles() static Styles()
{ {
@ -97,6 +157,10 @@ namespace TriInspector.Elements
{ {
padding = new RectOffset(26, 4, 4, 4), padding = new RectOffset(26, 4, 4, 4),
}; };
InfoBoxInlineAction = new GUIStyle(GUI.skin.button)
{
wordWrap = true,
};
} }
} }
} }

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using TriInspector.Elements; using TriInspector.Elements;
using UnityEditor; using UnityEditor;
@ -61,11 +62,22 @@ namespace TriInspector
foreach (var result in _validationResults) 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; return true;
} }
private void ExecuteFix(Action fixAction)
{
_property.ModifyAndRecordForUndo(targetIndex => fixAction?.Invoke());
}
} }
} }
} }

View File

@ -1,25 +1,38 @@
namespace TriInspector using System;
using UnityEngine;
namespace TriInspector
{ {
public readonly struct TriValidationResult public readonly struct TriValidationResult
{ {
public static TriValidationResult Valid => new TriValidationResult(true, null, TriMessageType.None); 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; IsValid = valid;
Message = message; Message = message;
MessageType = messageType; MessageType = messageType;
FixAction = fixAction;
FixActionContent = fixActionContent;
} }
public bool IsValid { get; } public bool IsValid { get; }
public string Message { get; } public string Message { get; }
public TriMessageType MessageType { 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) public static TriValidationResult Info(string error)
{ {
return new TriValidationResult(false, error, TriMessageType.Info); return new TriValidationResult(false, error, TriMessageType.Info);
} }
public static TriValidationResult Error(string error) public static TriValidationResult Error(string error)
{ {
return new TriValidationResult(false, error, TriMessageType.Error); return new TriValidationResult(false, error, TriMessageType.Error);