seefood_diet / Assets / UIKit / UIElement.cs
UIElement.cs
Raw
using System;
using UnityEngine;
using UnityEngine.UI;

namespace UIKit {

    [ExecuteInEditMode]
    public class UIElement : Image {

        private static readonly int widthProp = Shader.PropertyToID ("_Width");
        private static readonly int heightProp = Shader.PropertyToID ("_Height");
        private static readonly int cornerRadiusProp = Shader.PropertyToID ("_CornerRadius");
        private static readonly int independentCornersProp = Shader.PropertyToID ("_EnableIndependentCorners");
        private static readonly int independentCornerRadiiProp = Shader.PropertyToID ("_IndependentCornerRadii");
        private static readonly int borderColorProp = Shader.PropertyToID ("_BorderColor");
        private static readonly int borderProp = Shader.PropertyToID ("_Border");
        private static readonly int shadowColorProp = Shader.PropertyToID ("_ShadowColor");
        private static readonly int shadowBlurProp = Shader.PropertyToID ("_ShadowBlur");
        private static readonly int shadowLayoutProp = Shader.PropertyToID ("_ShadowLayout");
        private static readonly int innerShadowColorProp = Shader.PropertyToID ("_InnerShadowColor");
        private static readonly int innerShadowBlurProp = Shader.PropertyToID ("_InnerShadowBlur");
        private static readonly int innerShadowLayoutProp = Shader.PropertyToID ("_InnerShadowLayout");
        private static readonly int imageWidthProp = Shader.PropertyToID ("_ImageWidth");
        private static readonly int imageHeightProp = Shader.PropertyToID ("_ImageHeight");
        private static readonly int imageOffsetXProp = Shader.PropertyToID ("_ImageOffsetX");
        private static readonly int imageOffsetYProp = Shader.PropertyToID ("_ImageOffsetY");
        private static readonly int imageColorProp = Shader.PropertyToID ("_ImageColor");

        public float Radius;
        public bool EnableIndependentConers;
        public Vector4 IndependentCornerRadii;

        [HideInInspector] public float Border;
        [HideInInspector] public Color BorderColor;

        public Color ShadowColor;
        [Range (0, 150)] public float ShadowBlur;
        public float ShadowRadius;
        public Vector2 ShadowOffset;
        public Vector2 ShadowScale = Vector2.one;

        public bool EnableInnerShadow;
        public Color InnerShadowColor;
        [Range (0, 150)] public float InnerShadowBlur;
        public float InnerShadowRadius;
        public Vector2 InnerShadowOffset;
        public float InnerShadowSpread = 1;

        public Color ImageColor;
        public Vector2 ImageOffset;

        public Color PressedColor;

        //  shadow, texture, inner shadow, border
        static Vector4 IsShadow = new Vector4 (1, 0, 0, 0);
        static Vector4 IsTexture = new Vector4 (0, 1, 0, 0);
        static Vector4 IsInnerShadow = new Vector4 (0, 0, 1, 0);
        static Vector4 IsBorder = new Vector4 (0, 0, 0, 1);

        public override Material material {

            get {

                if (m_Material == null) {

                    m_Material = new Material (Shader.Find ("UIElement"));
                }

                return m_Material;
            }

            set {

                m_Material = value;
            }
        }

        protected override void OnPopulateMesh (VertexHelper vh) {

            var r = GetPixelAdjustedRect ();
            var v = GetVertexPositions (r);

            vh.Clear ();

            Vector2 roundedAndBorder = new Vector2 (Radius, Border);

            var uvs = GetUVValues (r);
            Vector2 uv1 = new Vector2 (uvs.x, uvs.y);
            Vector2 uv2 = new Vector2 (uvs.x, uvs.w);
            Vector2 uv3 = new Vector2 (uvs.z, uvs.w);
            Vector2 uv4 = new Vector2 (uvs.z, uvs.y);

            int i = 0;

            Vector2 shadowScale = ShadowScale * new Vector2 (ShadowBlur / 2f, ShadowBlur / 2f);

            vh.AddVert (new Vector3 (v.x - shadowScale.x + ShadowOffset.x, v.y - shadowScale.y + ShadowOffset.y), ShadowColor, uv1, Vector2.right, Vector3.zero, IsShadow);
            vh.AddVert (new Vector3 (v.x - shadowScale.x + ShadowOffset.x, v.w + shadowScale.y + ShadowOffset.y), ShadowColor, uv2, Vector2.right, Vector3.zero, IsShadow);
            vh.AddVert (new Vector3 (v.z + shadowScale.x + ShadowOffset.x, v.w + shadowScale.y + ShadowOffset.y), ShadowColor, uv3, Vector2.right, Vector3.zero, IsShadow);
            vh.AddVert (new Vector3 (v.z + shadowScale.x + ShadowOffset.x, v.y - shadowScale.y + ShadowOffset.y), ShadowColor, uv4, Vector2.right, Vector3.zero, IsShadow);

            vh.AddTriangle (i + 0, i + 1, i + 2);
            vh.AddTriangle (i + 2, i + 3, i + 0);
            i += 4;

            vh.AddVert (new Vector3 (v.x, v.y), color, uv1, Vector2.zero, Vector3.zero, sprite == null ? Vector4.zero : IsTexture);
            vh.AddVert (new Vector3 (v.x, v.w), color, uv2, Vector2.zero, Vector3.zero, sprite == null ? Vector4.zero : IsTexture);
            vh.AddVert (new Vector3 (v.z, v.w), color, uv3, Vector2.zero, Vector3.zero, sprite == null ? Vector4.zero : IsTexture);
            vh.AddVert (new Vector3 (v.z, v.y), color, uv4, Vector2.zero, Vector3.zero, sprite == null ? Vector4.zero : IsTexture);

            vh.AddTriangle (i + 0, i + 1, i + 2);
            vh.AddTriangle (i + 2, i + 3, i + 0);

            i += 4;

            vh.AddVert (new Vector3 (v.x, v.y), InnerShadowColor, uv1, Vector2.zero, new Vector3 (InnerShadowOffset.x, InnerShadowOffset.y, InnerShadowSpread), IsInnerShadow);
            vh.AddVert (new Vector3 (v.x, v.w), InnerShadowColor, uv2, Vector2.zero, new Vector3 (InnerShadowOffset.x, InnerShadowOffset.y, InnerShadowSpread), IsInnerShadow);
            vh.AddVert (new Vector3 (v.z, v.w), InnerShadowColor, uv3, Vector2.zero, new Vector3 (InnerShadowOffset.x, InnerShadowOffset.y, InnerShadowSpread), IsInnerShadow);
            vh.AddVert (new Vector3 (v.z, v.y), InnerShadowColor, uv4, Vector2.zero, new Vector3 (InnerShadowOffset.x, InnerShadowOffset.y, InnerShadowSpread), IsInnerShadow);

            vh.AddTriangle (i + 0, i + 1, i + 2);
            vh.AddTriangle (i + 2, i + 3, i + 0);
        }

        protected override void OnRectTransformDimensionsChange () {

            if (gameObject.activeInHierarchy) {

                SetMaterialProperties ();

                if (CanvasUpdateRegistry.IsRebuildingLayout ())
                    SetVerticesDirty ();
                else {
                    SetVerticesDirty ();
                    SetLayoutDirty ();
                }
            }
        }

        protected override void OnDidApplyAnimationProperties () {

            SetAllDirty ();
        }

        public override void SetAllDirty () {

            SetMaterialProperties ();
            base.SetAllDirty ();
        }

        private void SetMaterialProperties () {

            if (materialForRendering == null) return;

            var rect = ((RectTransform) transform).rect;

            materialForRendering.SetFloat (widthProp, rect == null ? 0 : rect.width);
            materialForRendering.SetFloat (heightProp, rect == null ? 0 : rect.height);

            materialForRendering.SetFloat (cornerRadiusProp, Radius * 2);

            if (EnableIndependentConers) {

                materialForRendering.EnableKeyword ("ENABLE_INDEPENDENT_CORNERS");
            } else {

                materialForRendering.DisableKeyword ("ENABLE_INDEPENDENT_CORNERS");
            }

            materialForRendering.SetInt (independentCornersProp, EnableIndependentConers ? 1 : 0);
            materialForRendering.SetVector (independentCornerRadiiProp, IndependentCornerRadii * 2);

            materialForRendering.SetFloat (borderProp, Border);
            materialForRendering.SetColor (borderColorProp, BorderColor);

            materialForRendering.SetColor (shadowColorProp, ShadowColor);
            materialForRendering.SetFloat (shadowBlurProp, ShadowBlur);
            materialForRendering.SetVector (shadowLayoutProp, new Vector4 (ShadowOffset.x, ShadowOffset.y, ShadowScale.x, ShadowScale.y));

            materialForRendering.SetFloat (imageWidthProp, sprite == null ? 0 : sprite.rect.width);
            materialForRendering.SetFloat (imageHeightProp, sprite == null ? 0 : sprite.rect.height);

            materialForRendering.SetFloat (imageOffsetXProp, ImageOffset.x);
            materialForRendering.SetFloat (imageOffsetYProp, ImageOffset.y);
            materialForRendering.SetColor (imageColorProp, ImageColor);
        }

        private Vector4 GetVertexPositions (Rect r) {

            var v = new Vector4 (r.x, r.y, r.x + r.width, r.y + r.height);
            // float oneMinusFill = 1f - fillAmount;

            // if (fillStyle == FillStyle.HorizontalBackwards) {
            //     v.x += r.width * oneMinusFill;
            // } else if (fillStyle == FillStyle.HorizontalForward) {
            //     v.z -= r.width * oneMinusFill;
            // } else if (fillStyle == FillStyle.VerticalBackwards) {
            //     v.y += r.height * oneMinusFill;
            // } else if (fillStyle == FillStyle.VerticalForward) {
            //     v.w -= r.height * oneMinusFill;
            // }

            return v;
        }

        private Vector4 GetUVValues (Rect r) {

            var uvs = new Vector4 (0, 0, 1, 1);
            float oneMinusFill = 1f - fillAmount;

            // if (fillStyle == FillStyle.HorizontalBackwards) {
            //     uvs.x = oneMinusFill;
            // } else if (fillStyle == FillStyle.HorizontalForward) {
            //     uvs.z = fillAmount;
            // } else if (fillStyle == FillStyle.VerticalBackwards) {
            //     uvs.y = oneMinusFill;
            // } else if (fillStyle == FillStyle.VerticalForward) {
            //     uvs.w = fillAmount;
            // }

            return uvs;
        }
    }

    public static class UIElementExtension {

        public static void SetStyle (this UIElement element, UIStyle style) {

            element.Radius = style.Radius;
            element.EnableIndependentConers = style.ToggleIndependentRadii;
            element.IndependentCornerRadii = style.IndependentRadii;

            element.Border = style.Border;

            element.ShadowBlur = style.ShadowBlur;
            element.ShadowRadius = style.ShadowRadius;
            element.ShadowOffset = style.ShadowOffset;
            element.ShadowScale = style.ShadowScale;

            element.SetAllDirty ();
        }

        public static void SetColor (this UIElement element, UIColor color) {

            element.color = color.Color;
            element.BorderColor = color.Border;
            element.ShadowColor = color.Shadow;
            element.ImageColor = color.Content;
            element.PressedColor = color.Pressed;

            element.SetAllDirty ();
        }

        public static UIStyle GetStyle (this UIElement element) {

            UIStyle style = new UIStyle ();

            style.Radius = element.Radius;
            style.ToggleIndependentRadii = element.EnableIndependentConers;
            style.IndependentRadii = element.IndependentCornerRadii;

            style.Border = element.Border;

            style.ShadowBlur = element.ShadowBlur;
            style.ShadowRadius = element.ShadowRadius;
            style.ShadowOffset = element.ShadowOffset;
            style.ShadowScale = element.ShadowScale;

            return style;
        }

        public static UIColor GetColor (this UIElement element) {

            UIColor color = UIColor.Create ();

            color.Color = element.color;
            color.Border = element.BorderColor;
            color.Shadow = element.ShadowColor;
            color.Content = element.ImageColor;
            color.Pressed = element.PressedColor;

            return color;
        }
    }
}