Scientia Conditorium

UnityEditor 를 이용한 눈에 확 띄는 로그 만들기 본문

프로그래밍/Unity

UnityEditor 를 이용한 눈에 확 띄는 로그 만들기

Yumera 2021. 2. 17. 05:01

회사 내부에서 유니티를 사용하고 개발자 뿐만 아니라 디자이너를 포함한 다른 분들이 유니티를 사용할 때

개발자가 자체적으로 구현한 유니티 에디터 기반의 GUI 를 사용하고 있을 때 등등 시스템의 예외상황을 사용자에게 알리는 것은 중요하다. 허나..

 

개발자라면 바로 알아차리겠지만 그 외 나머지 직군들은 오류가 나타나도 무시하고 사용하다 오작동을 일으키는 경우도 드물게 발생한다

항상 바쁜 개발직군 사람들에게 콘솔창을 볼 여유는 없다. 그래서 생각한 방법이 '눈에 보이도록 팝업을 띄어주자' 생각으로 만든 에디터 코드이다

 

using UnityEngine;

namespace UnityEditor
{
    public enum PopupLogType : int
    {
        Info = 0,
        Warning, Error
    }

    public class LogPopup : PopupWindowContent
    {
        #region Overload Method
        public static void Log(PopupLogType logType, string message, bool isPrintConsole = true)
            => Log(logType, message, null, null, null, isPrintConsole);

        public static void Log(PopupLogType logType, string header, string message, bool isPrintConsole = true)
            => Log(logType, message, header, null, null, isPrintConsole);

        public static void LogWarning(string message, bool isPrintConsole = true)
            => Log(PopupLogType.Warning, message, null, null, null, isPrintConsole);

        public static void LogWarning(string header, string message, bool isPrintConsole = true)
            => Log(PopupLogType.Warning, message, header, null, null, isPrintConsole);

        public static void LogWarning(string message, string header, string urlHeader, string url, bool isPrintConsole = true)
            => Log(PopupLogType.Warning, message, header, urlHeader, url, isPrintConsole);

        public static void LogError(string message, bool isPrintConsole = true)
            => Log(PopupLogType.Error, message, null, null, null, isPrintConsole);

        public static void LogError(string header, string message, bool isPrintConsole = true)
            => Log(PopupLogType.Error, message, header, null, null, isPrintConsole);

        public static void LogError(string message, string header, string urlHeader, string url, bool isPrintConsole = true)
            => Log(PopupLogType.Error, message, header, urlHeader, url, isPrintConsole);
        #endregion

        public static void Log(PopupLogType logType, string message, string header, string urlHeader, string url, bool isPrintConsole = true)
        {
            if (isPrintConsole)
            {
                //  https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/ConsoleWindow.cs
                int count = EditorPrefs.GetInt("ConsoleWindowLogLineCount", 2);
                string str = null;

                if (count > 1)
                {
                    if (!string.IsNullOrWhiteSpace(url))
                    {
                        str = $"<b>{header}</b> {message}\n{urlHeader} : " +
                            string.Format("<color=#{0:X2}{1:X2}{2:X2}>{3}</color>",
                            (byte)(Styles.R * 255f), (byte)(Styles.G * 255f), (byte)(Styles.B * 255f), url);
                    }
                    else str = $"<b>{header}</b>\n{message}";
                }
                else str = $"<b>{header}</b> {message}";

                if (logType == PopupLogType.Info) Debug.Log(str);
                else if (logType == PopupLogType.Warning) Debug.LogWarning(str);
                else Debug.LogError(str);
            }

            Vector2 mousePosition = Event.current.mousePosition;

            if (m_LogWindow != null) m_LogWindow.editorWindow.Focus();
            else
                PopupWindow.Show(
                    new Rect(mousePosition.x, mousePosition.y, 0, 0),
                    new LogPopup(logType, message, header, urlHeader, url));
        }

        private static LogPopup m_LogWindow = null;

        public static class Styles
        {
            //  Hyperlink Color
            public const float R = 0.3241f;
            public const float G = 0.5084f;
            public const float B = 0.9829f;

            public static GUIStyle HeaderStyle = new GUIStyle(EditorStyles.boldLabel)
            {
                alignment = TextAnchor.UpperCenter,
                wordWrap = true
            };
            public static GUIStyle LabelStyle = new GUIStyle(EditorStyles.label)
            {
                alignment = TextAnchor.UpperLeft,
                wordWrap = true
            };
            public static GUIStyle LinkStyle = new GUIStyle(EditorStyles.label)
            {
                normal = new GUIStyleState()
                {
                    textColor = new Color(R, G, B)
                },
                alignment = TextAnchor.UpperLeft,
                wordWrap = true
            };
        }

        public LogPopup(PopupLogType logType, string message, string header, string linkMsg, string url) : base()
        {
            m_Type = logType;
            m_IconContext = logType == PopupLogType.Info ? EditorGUIUtility.IconContent("console.infoicon") :
                logType == PopupLogType.Warning ? EditorGUIUtility.IconContent("console.warnicon") :
                EditorGUIUtility.IconContent("console.erroricon");

            m_Message = message;
            m_HeaderMsg = header;
            m_HyperLinkMsg = linkMsg;
            m_LinkURL = url;
        }

        private readonly PopupLogType m_Type;
        private readonly GUIContent m_IconContext;

        private readonly string m_Message;
        private readonly string m_HeaderMsg;
        private readonly string m_HyperLinkMsg;
        private readonly string m_LinkURL;

        private Texture GetIcon { get => m_IconContext.image; }

        public override void OnGUI(Rect rect)
        {
            rect = new Rect(rect.x + 5, rect.y + 5, rect.width - 10, rect.height - 10);

            OnHeader(rect);
            bool isClick = OnMessage(rect);

            if (!isClick &&
                Event.current.type == EventType.MouseDown && rect.Contains(Event.current.mousePosition))
                editorWindow.Close();
        }

        private void OnHeader(Rect rect)
        {
            using (GUI.GroupScope gs = new GUI.GroupScope(rect))
            {
                Rect iconRect = new Rect(0, 0, GetIcon.width, GetIcon.height);

                EditorGUI.LabelField(iconRect, m_IconContext);
                EditorGUI.LabelField(new Rect(iconRect.xMax, 0, rect.width - iconRect.xMax, iconRect.height),
                    m_HeaderMsg, Styles.HeaderStyle);
            }
        }

        private bool OnMessage(Rect rect)
        {
            bool isClick = false;
            using (GUI.GroupScope gs = new GUI.GroupScope(rect))
            {
                Rect labelRect = new Rect(0, GetIcon.height, rect.width, rect.height - GetIcon.height - 5);
                if (!string.IsNullOrWhiteSpace(m_HyperLinkMsg))
                {
                    Rect linkRect = new Rect(labelRect) { x = labelRect.x + 5, height = 20 };
                    EditorGUI.LabelField(linkRect, m_HyperLinkMsg, Styles.LinkStyle);

                    if (Event.current.type == EventType.MouseDown &&
                        linkRect.Contains(Event.current.mousePosition))
                    {
                        Application.OpenURL(m_LinkURL);
                        isClick = true;
                    }

                    labelRect = new Rect(labelRect) { y = labelRect.y + 20 };
                }

                EditorGUI.LabelField(labelRect, m_Message, Styles.LabelStyle);

                return isClick;
            }
        }
    }

}

 

사용법은 간단하다

LogPopup.LogError("Im Message");
LogPopup.LogWarning("Im Message", "Im Header");
LogPopup.Log(PopupLogType.Error, "Do not Showing!", "Exception error!", "Help Message", "Https://ShowWikiSite");

 

구체적인 사용법은 오버로드 메소드 참조

 

팝업 리사이징이라던가 그 외 나머지 기능은 천천히 추가해볼 예정이다

일단 보여주는 것이 목적이므로 ..