// // Copyright (c) 2017 Anthony Marmont. All rights reserved. // Licensed for use under the Unity Asset Store EULA. See https://unity3d.com/legal/as_terms for full license information. // #if UNITY_EDITOR #pragma warning disable using AssetIcons.Editors.Internal.Drawing; using AssetIcons.Editors.Internal.Expresser; using AssetIcons.Editors.Internal.Expresser.Input; using UnityEngine; namespace AssetIcons.Editors { /// /// A formatted representation of the for drawing graphics in the . /// /// /// public sealed class AssetIconsCompiledStyle { private static readonly AssetIconsCompiledStyle defaultStyle = new AssetIconsCompiledStyle(new AssetIconsStyle()); /// /// A for the default constructor of . /// /// public static AssetIconsCompiledStyle Default { get { return defaultStyle; } } private class PositioningProcessor { private float lastWidth; private float lastHeight; private float cachedWidth; private float cachedHeight; private float cachedX; private float cachedY; private bool cachedDisplay; private readonly CompiledExpression compiledWidth; private readonly CompiledExpression compiledHeight; private readonly CompiledExpression compiledX; private readonly CompiledExpression compiledY; private readonly CompiledExpression compiledDisplay; private readonly StaticValueProvider widthProvider; private readonly StaticValueProvider heightProvider; private readonly Vector2 styleAnchoring; public PositioningProcessor(AssetIconsCompiledStyle compiledStyleDefinition, AssetIconsStyle style) { widthProvider = new StaticValueProvider(new MathValue(1.0f, true)); heightProvider = new StaticValueProvider(new MathValue(1.0f, true)); var horizontalContext = new MathContextBuilder() .WithTerm("width", widthProvider) .WithTerm("height", heightProvider) .ImplicitlyReferences(widthProvider) .Build(); var verticalContext = new MathContextBuilder() .WithTerm("width", widthProvider) .WithTerm("height", heightProvider) .ImplicitlyReferences(heightProvider) .Build(); compiledWidth = CompiledExpression.Compile(style.Width, horizontalContext); compiledHeight = CompiledExpression.Compile(style.Height, verticalContext); compiledX = CompiledExpression.Compile(style.X, horizontalContext); compiledY = CompiledExpression.Compile(style.Y, verticalContext); compiledDisplay = CompiledExpression.Compile(style.Display, horizontalContext); styleAnchoring = compiledStyleDefinition.Anchor; } /// /// Applies this to a . /// /// A source to apply position modifications to. /// A Boolean value indicating whether the should be displayed. /// /// A rect that has been modified by this . /// public Rect Filter(Rect rect, out bool display) { if (Mathf.Abs(rect.width - lastWidth) > 0.01f || Mathf.Abs(rect.height - lastHeight) > 0.01f) { lastWidth = rect.width; lastHeight = rect.height; widthProvider.Value = new MathValue(lastWidth, false); heightProvider.Value = new MathValue(lastHeight, false); if (compiledDisplay != null) { var newDisplayValue = compiledDisplay.Evaluate(); if (newDisplayValue.ValueClass == ValueClassifier.Boolean) { cachedDisplay = newDisplayValue.BoolValue; if (!cachedDisplay) { display = false; return rect; } } } else { cachedDisplay = true; } if (compiledX != null) { var xOffsetValue = compiledX.Evaluate(); if (xOffsetValue.ValueClass == ValueClassifier.Float) { cachedX = xOffsetValue.FloatValue; } else if (xOffsetValue.ValueClass == ValueClassifier.FloatFractional) { cachedX = xOffsetValue.FloatValue * rect.width; } } if (compiledY != null) { var yOffsetValue = compiledY.Evaluate(); if (yOffsetValue.ValueClass == ValueClassifier.Float) { cachedY = yOffsetValue.FloatValue; } else if (yOffsetValue.ValueClass == ValueClassifier.FloatFractional) { cachedY = yOffsetValue.FloatValue * rect.height; } } if (compiledWidth != null) { var newWidthValue = compiledWidth.Evaluate(); if (newWidthValue.ValueClass == ValueClassifier.Float) { cachedWidth = newWidthValue.FloatValue; } else if (newWidthValue.ValueClass == ValueClassifier.FloatFractional) { cachedWidth = newWidthValue.FloatValue * rect.width; } } else { cachedWidth = rect.width; } if (compiledHeight != null) { var newHeightValue = compiledHeight.Evaluate(); if (newHeightValue.ValueClass == ValueClassifier.Float) { cachedHeight = newHeightValue.FloatValue; } else if (newHeightValue.ValueClass == ValueClassifier.FloatFractional) { cachedHeight = newHeightValue.FloatValue * rect.height; } } else { cachedHeight = rect.height; } } if (!cachedDisplay) { display = false; return rect; } rect.x += cachedX + ((rect.width - cachedWidth) * styleAnchoring.x); rect.y += (-cachedY) + ((rect.height - cachedHeight) * (1.0f - styleAnchoring.y)); rect.width = cachedWidth; rect.height = cachedHeight; display = true; return rect; } } /// /// A value used to determine the max size of the icon. /// public int MaxSize { get; set; } /// /// A value used to determine the aspect of the icon. /// public IconAspect Aspect { get; set; } /// /// An anchor that all difference in scale is orientated around. /// public Vector2 Anchor { get; set; } /// /// A tint to apply to the icon. /// public Color Tint { get; set; } /// /// A value used to determine the layer of the icon. /// public int Layer { get; set; } /// /// A font style to use on all rendered text. /// public FontStyle FontStyle { get; set; } /// /// An anchor for all rendered text. /// public TextAnchor TextAnchor { get; set; } /// /// A camera projection for all rendered Prefabs. /// public IconProjection Projection { get; set; } /// /// A compiled representation of the positioning expressions. /// private PositioningProcessor Positioning { get; set; } /// /// Constructs a new instance of the from a . /// public AssetIconsCompiledStyle(AssetIconsStyle style) { MaxSize = style.MaxSize; Aspect = style.Aspect; Anchor = AnchorToVector(style.Anchor); Layer = style.Layer; Tint = ExpressionParser.ParseHexColor(style.Tint); FontStyle = style.FontStyle; TextAnchor = ToTextAnchor(style.TextAnchor); Projection = style.Projection; Positioning = new PositioningProcessor(this, style); } /// /// Applies this to a . /// /// A source to apply position modifications to. /// A Boolean value indicating whether the should be displayed. /// /// A that has been modified by this . /// public Rect Filter(Rect rect, out bool display) { return Positioning.Filter(rect, out display); } private static TextAnchor ToTextAnchor(IconAnchor anchor) { switch (anchor) { default: case IconAnchor.Center: return TextAnchor.MiddleCenter; case IconAnchor.Top: return TextAnchor.UpperCenter; case IconAnchor.Bottom: return TextAnchor.LowerCenter; case IconAnchor.Left: return TextAnchor.MiddleLeft; case IconAnchor.Right: return TextAnchor.MiddleRight; case IconAnchor.TopLeft: return TextAnchor.UpperLeft; case IconAnchor.TopRight: return TextAnchor.UpperRight; case IconAnchor.BottomLeft: return TextAnchor.LowerLeft; case IconAnchor.BottomRight: return TextAnchor.LowerRight; } } private static Vector2 AnchorToVector(IconAnchor anchor) { switch (anchor) { default: case IconAnchor.Center: return new Vector2(0.5f, 0.5f); case IconAnchor.Top: return new Vector2(0.5f, 1.0f); case IconAnchor.Bottom: return new Vector2(0.5f, 0.0f); case IconAnchor.Left: return new Vector2(0.0f, 0.5f); case IconAnchor.Right: return new Vector2(1.0f, 0.5f); case IconAnchor.TopLeft: return new Vector2(0.0f, 1.0f); case IconAnchor.TopRight: return new Vector2(1.0f, 1.0f); case IconAnchor.BottomLeft: return new Vector2(0.0f, 0.0f); case IconAnchor.BottomRight: return new Vector2(1.0f, 0.0f); } } } } #pragma warning restore #endif