2020/DebugConsole

From Unify Community Wiki
Revision as of 04:42, 15 April 2020 by Serge Billault (Talk | contribs)

Jump to: navigation, search

Author: Serge Billault

Contents

Description

A more up to date, as of 2020 (Unity 5.6.1f1 through 2019.3.8.f1), a little more professional, minimal debug console.

Archive File

UnityDebugConsole

Archive content

A c# script.
A Resources folder containing a GUI skin.

Usage

. Installation: Unzip the archive content in your Standard Assets folder (required).


. Setup: no action required.


. Scripting: no action required.


. Unity Legacy Compatibility (old VS new Unity Input System): no action required.

Professionals

. Net compatibility level: 2.0 minimum - no dynamic methods.


. Unsafe code: None.


. Reflectivity: Some.


. Networking: None.


. QA Teams functions support: None.


. Advanced features: None.


. Performances: Suitable for productions (translation for students: High).

C# - DebugConsole.cs

The script must be named DebugConsole.cs. It has no real use. It is for compliance with other wiki articles only. The script is available through the archive linked at the top of this page.


using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
 
//********************************************************************************************************
//
//********************************************************************************************************
 
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
 
//********************************************************************************************************
//
//********************************************************************************************************
 
namespace DEBUG
{
    //****************************************************************************************************
    //
    //****************************************************************************************************
 
    public enum TRACE { NONE, SHORT, FULL, DEFAULT = NONE }
 
	//****************************************************************************************************
	//
	//****************************************************************************************************
 
	static public class Debug
	{
		//************************************************************************************************
		//
		//************************************************************************************************
 
		private const string FMT_TRACE  = "  * {0} : line {1} : {2}()\r\n";
 
		private const char   MEMBER_SEP = '.';
 
		//************************************************************************************************
		//
		//************************************************************************************************
 
		static private string QualifiedMethodName( StackFrame frame )
		{
			return frame.GetMethod().DeclaringType.Name + MEMBER_SEP + frame.GetMethod().Name;
		}
 
		//************************************************************************************************
		//
		//************************************************************************************************
 
		static private string Msg( string msg, TRACE trace = TRACE.DEFAULT )
		{
			switch( trace )
			{
				//****************************************************************************************
				//
				//****************************************************************************************
 
				case TRACE.FULL:
				{
					StackTrace   full   = new StackTrace ( 2 , true );
 
					StackFrame[] frames = full.GetFrames();
 
					string       output = string.Empty;
 
					for( int frame = frames.Length - 1; frame >= 0; --frame )
					{
						StackFrame Frame = frames[ frame ];
 
						output += string.Format( FMT_TRACE, Frame.GetFileName(), Frame.GetFileLineNumber(), QualifiedMethodName( Frame ) );
					}
 
					return output + msg;
				}
 
				//****************************************************************************************
				//
				//****************************************************************************************
 
				case TRACE.SHORT:
				{
					StackTrace stack = new StackTrace( 2 , true );
 
					StackFrame Frame = stack.GetFrame( 0 );
 
					return string.Format( FMT_TRACE, Frame.GetFileName(), Frame.GetFileLineNumber(), QualifiedMethodName( Frame ) ) + msg;
				}
 
				//****************************************************************************************
				//
				//****************************************************************************************
 
				default :
				{
					return msg;
				}
			}
		}
 
		//************************************************************************************************
		//
		//************************************************************************************************
 
		static public void Log       ( object msg, TRACE trace = TRACE.DEFAULT ) { if( UnityEngine.Debug.isDebugBuild ) UnityEngine.Debug.Log       ( Msg( msg.ToString(), trace ) ); }
 
		static public void LogWarning( object msg, TRACE trace = TRACE.DEFAULT ) { if( UnityEngine.Debug.isDebugBuild ) UnityEngine.Debug.LogWarning( Msg( msg.ToString(), trace ) ); }
 
		static public void LogError  ( object msg, TRACE trace = TRACE.DEFAULT ) { if( UnityEngine.Debug.isDebugBuild ) UnityEngine.Debug.LogError  ( Msg( msg.ToString(), trace ) ); }
 
		//************************************************************************************************
		//
		//************************************************************************************************
 
		static public void Log       ( object msg, UnityEngine.Object context, TRACE trace = TRACE.DEFAULT ) { if( UnityEngine.Debug.isDebugBuild ) UnityEngine.Debug.Log       ( Msg( msg.ToString(), trace ), context ); }
 
		static public void LogWarning( object msg, UnityEngine.Object context, TRACE trace = TRACE.DEFAULT ) { if( UnityEngine.Debug.isDebugBuild ) UnityEngine.Debug.LogWarning( Msg( msg.ToString(), trace ), context ); }
 
		static public void LogError  ( object msg, UnityEngine.Object context, TRACE trace = TRACE.DEFAULT ) { if( UnityEngine.Debug.isDebugBuild ) UnityEngine.Debug.LogError  ( Msg( msg.ToString(), trace ), context ); }
	}
 
    //****************************************************************************************************
    //
    //****************************************************************************************************
 
	public struct Entry
	{
		public int      category;
 
		public string   date;
 
		public string   msg;
	}
 
    //****************************************************************************************************
    //
    //****************************************************************************************************
 
    public class Buffer
    {
        //************************************************************************************************
        //
        //************************************************************************************************
 
        private Entry[] m_entries  = null;
 
        private int     m_capacity = 0;
 
        private int     m_start    = 0;
 
        private int     m_end      = 0;
 
        private int     m_count    = 0;
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        public int capacity { get { return m_capacity; } }
 
        public int start    { get { return m_start;    } }
 
        public int end      { get { return m_end;      } }
 
        public int count    { get { return m_count;    } }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static public ulong Align( ulong s, ulong a ) { return ( s + ( a - 1 ) ) & ~( a - 1 ); }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        public Buffer( int paramCapacity = 0 )
        {
            m_capacity = ( paramCapacity != 0 ) ? ( int )Align( ( ulong )Mathf.Max( 4, paramCapacity ), 4 ) : 1024;
 
            m_entries  = new Entry[ m_capacity ];
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        public void Clear( )
        {
            m_start = 0;
 
            m_end   = 0;
 
            m_count = 0;
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        public void Push( string date, string msg, int category )
        {
            if( m_count < m_capacity ) ++m_count;
 
            else      m_start = ( m_start + 1 )   & ( m_capacity - 1 );
 
            m_end = ( m_start + ( m_count - 1 ) ) & ( m_capacity - 1 );
 
 
            m_entries[ m_end ].category = category;
 
            m_entries[ m_end ].date     = date;
 
            m_entries[ m_end ].msg      = msg;
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        public Entry this[ int index ] { get { return m_entries[ index & ( m_capacity - 1 ) ]; } }
    }
 
    //****************************************************************************************************
    //
    //****************************************************************************************************
 
    static public class GUIStacks
    {
        static private readonly Stack< GUISkin > m_skin  = new Stack< GUISkin >( 16 );
 
        static private readonly Stack< Color   > m_color = new Stack< Color   >( 16 );
 
        static private readonly Stack< Color   > m_cont  = new Stack< Color   >( 16 );
 
        static private readonly Stack< Color   > m_bgnd  = new Stack< Color   >( 16 );
 
 
        static public void PushSkin           ( GUISkin skin  ) { m_skin.Push ( GUI.skin );            GUI.skin            = skin;  }
 
        static public void PushColor          ( Color   color ) { m_color.Push( GUI.color );           GUI.color           = color; }
 
        static public void PushContentColor   ( Color   color ) { m_cont.Push ( GUI.contentColor );    GUI.contentColor    = color; }
 
        static public void PushBackgroundColor( Color   color ) { m_bgnd.Push ( GUI.backgroundColor ); GUI.backgroundColor = color; }
 
        static public void PushSkin           () { m_skin.Push ( GUI.skin );            }
 
        static public void PushColor          () { m_color.Push( GUI.color );           }
 
        static public void PushContentColor   () { m_cont.Push ( GUI.contentColor );    }
 
        static public void PushBackgroundColor() { m_bgnd.Push ( GUI.backgroundColor ); }
 
        static public void PopSkin            () { GUI.skin            = m_skin.Pop (); }
 
        static public void PopColor           () { GUI.color           = m_color.Pop(); }
 
        static public void PopContentColor    () { GUI.contentColor    = m_cont.Pop (); }
 
        static public void PopBackgroundColor () { GUI.backgroundColor = m_bgnd.Pop (); }
    }
 
    //****************************************************************************************************
    //
    //****************************************************************************************************
 
    public class GUIDropDown
    {
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private Color COLOR_NORMAL   = new Color( 0.6f, 0.6f, 0.6f, 1.0f );
 
        static private Color COLOR_SELECTED = new Color( 1.0f, 1.0f, 1.0f, 1.0f );
 
        private const int    MAX_LINES      = 8;
 
        private const float  LINE_H         = 32.0f;
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        private Rect     m_selectionRect = default( Rect );
 
        private Rect     m_scrollRect    = default( Rect );
 
        private Rect     m_viewRect      = default( Rect );
 
        private object[] m_options       = null;
 
        private int      m_nbOptions     = 0;
 
        private int      m_nbDisplayed   = 0;
 
        private bool     m_expanded      = false;
 
        private Vector2  m_scroll        = Vector2.zero;
 
        private int      m_selected      = 0;
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        public GUIDropDown( params object[] options )
        {
            m_options = options;
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        private void UpdateLayout( Rect rect, int selected, object[] options )
        {
            if( Event.current.type != EventType.Layout ) return;
 
            m_options       = options;
 
            m_nbOptions     = ( options != null ) ? options.Length : 0;
 
            m_nbDisplayed   = Mathf.Min( m_nbOptions, MAX_LINES );
 
            m_selected      = Mathf.Min( m_nbOptions - 1, selected );
 
            m_selectionRect = rect;
 
 
            if( m_expanded )
            {
                m_scrollRect = new Rect ( rect.x, rect.y + rect.height, rect.width, m_nbDisplayed * LINE_H );
 
                m_viewRect   = new Rect ( 0.0f, 0.0f, m_scrollRect.width - ( m_nbDisplayed < m_nbOptions ? 15.0f : 0.0f ), m_nbOptions * LINE_H );
            }
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        private void DrawOptions( GUISkin skin )
        {
            if( m_expanded )
            {
                GUI.skin = skin;
 
                int firstVisible = ( int )( m_scroll.y / LINE_H );
 
                int lastVisible  = Mathf.Clamp( firstVisible + m_nbDisplayed, 0, m_nbOptions - 1 );
 
 
                GUIStacks.PushContentColor();
 
                m_scroll = GUI.BeginScrollView( m_scrollRect, m_scroll, m_viewRect, false, false );
 
                for( int option = firstVisible; option <= lastVisible; ++option )
                {
                    GUI.contentColor = ( option == m_selected ) ? COLOR_SELECTED : COLOR_NORMAL;
 
                    if( GUI.Button( new Rect( 0.0f, option * LINE_H, m_viewRect.width, LINE_H ), m_options[ option ].ToString() ) )
                    {
                        m_selected = option;
 
                        m_expanded = false;
                    }
                }
 
                GUI.EndScrollView();
 
                GUIStacks.PopContentColor();
            }
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        private void DrawSelection( GUISkin skin )
        {
            GUI.skin = skin;
 
            object selection    = ( m_nbOptions  >  0 ) ? m_options[ m_selected ]  : null;
 
            string selectionStr = ( selection != null ) ? selection.ToString() : "<NULL>";
 
            if( GUI.Button( m_selectionRect, selectionStr ) && ( m_nbOptions > 0 ) )
            {
                m_expanded = ! m_expanded;
            }
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        public int Draw( GUISkin btn_skin, GUISkin drop_down_skin, Rect rect, int selected, object[] options = null )
        {
            GUIStacks.PushSkin();
 
                UpdateLayout ( rect, selected, ( options != null ) ? options : m_options );
 
                DrawSelection( btn_skin );
 
                DrawOptions  ( drop_down_skin );
 
            GUIStacks.PopSkin();
 
            return m_selected;
        }
    }
 
    //****************************************************************************************************
    //
    //****************************************************************************************************
 
    static public class Console
    {
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static public List< MethodInfo > GetApplicationProperties()
        {
            List< MethodInfo > result = new List< MethodInfo >( 64 );
 
            System.Type        type   = typeof( Application );
 
            PropertyInfo[]     props  = type.GetProperties( BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static );
 
            for( int pr = 0; pr < props.Length; ++pr )
            {
                PropertyInfo prop = props[ pr ];
 
                MethodInfo   func = prop.GetGetMethod();
 
                if( func != null ) result.Add( func );
            }
 
            return result;
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        [ RuntimeInitializeOnLoadMethod( RuntimeInitializeLoadType.BeforeSceneLoad ) ] static private void OnBeforeSceneLoadRuntimeMethod()
        {
            if( UnityEngine.Debug.isDebugBuild )
            {
                SceneManager.sceneLoaded += OnSceneLoaded;
 
 
 
                Scene  scene      = SceneManager.GetActiveScene();
 
                string scene_name = ( scene != null ) ? scene.name : "None";
 
                Console.LogSystem( string.Format( "Console init from scene: {0}", scene_name ) );
 
 
 
                List< MethodInfo > properties = GetApplicationProperties();
 
                for( int pr = 0; pr < properties.Count; ++pr )
                {
                    MethodInfo  prop  = properties[ pr ];
 
                    string      value = prop.Invoke( null, null ).ToString();
 
                    Console.LogSystem( string.Format( "Application.{0}: {1}", prop.Name.Substring( 4 ), value ) );
                }
            }
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private void OnSceneLoaded( Scene scene, LoadSceneMode mode )
        {
            if( DebugConsole.Instance == null )
            {
                GameObject console = new GameObject( "DebugConsole", typeof( DebugConsole ) );
 
                if( console != null ) UnityEngine.Object.DontDestroyOnLoad( console );
            }
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
               public enum CATEGORY { INFO, WARNING, ERROR, SYSTEM, COUNT }
 
               private const string STR_HIDE     = "HIDE";
 
               private const string STR_SHOW     = "SHOW";
 
               private const string STR_SORT_ASC = "RECENT FIRST";
 
               private const string STR_SORT_DSC = "OLDER FIRST";
 
               private const string STR_CLEAR    = "CLEAR";
 
               private const int    CLIPING      = 1024;
 
        static private string[]     SPLIT_SEMS   = new string[ 3 ] { "\r\n", "\r", "\n" };
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private Color   m_colDate = new Color( 0.7f, 0.7f, 0.7f, 1.0f );
 
        static private Color   m_colInfo = new Color( 1.0f, 1.0f, 1.0f, 1.0f );
 
        static private Color   m_colWarn = new Color( 0.8f, 0.8f, 0.4f, 1.0f );
 
        static private Color   m_colErr  = new Color( 1.0f, 0.4f, 0.4f, 1.0f );
 
        static private Color   m_colSys  = new Color( 0.7f, 0.7f, 1.0f, 1.0f );
 
        static private Color[] m_cols    = new Color[ ( int )CATEGORY.COUNT ] { m_colInfo, m_colWarn, m_colErr, m_colSys };
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private object    m_lock       = new object();
 
        static private Buffer    m_buffer     = new Buffer();
 
        static private Buffer[]  m_catBuffers = new Buffer[ ( int )CATEGORY.COUNT ] { new Buffer(), new Buffer(), new Buffer(), new Buffer() };
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private EventSystem  m_eventSystem  = null;
 
        static private GUISkin      m_skin         = null;
 
        static private GUISkin      m_skin_dd      = null;
 
        static private bool         m_layout_dirty = false;
 
        static private Vector2      m_pos          = Vector2.zero;
 
        static private Vector2      m_size         = Vector2.zero;
 
        static private Vector2      m_headerSize   = Vector2.zero;
 
        static private Vector2      m_scrollSize   = Vector2.zero;
 
        static private Vector2      m_scrollPos    = Vector2.zero;
 
        static private Rect         m_globalRect   = default( Rect );
 
        static private Rect         m_headerRect   = default( Rect );
 
        static private Rect         m_scrollRect   = default( Rect );
 
        static private bool         m_expanded     = true;
 
        static private bool         m_ascending    = true;
 
        static private CATEGORY     m_filter       = CATEGORY.COUNT;
 
        static private GUIDropDown  m_dropDown    = new GUIDropDown( "INFOS", "WARNINGS", "ERRORS", "SYSTEM", "ALL" );
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static Console()
        {
            LoadResources();
 
            if( UnityEngine.Debug.isDebugBuild )
            {
                Application.logMessageReceivedThreaded += LogCallback;
 
                Application.lowMemory                  += LowMemoryCallback;
            }
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private void LoadResources()
        {
            if( m_skin    == null ) { m_skin    = Resources.Load< GUISkin >( "DebugConsoleSkin"         ); }
 
            if( m_skin_dd == null ) { m_skin_dd = Resources.Load< GUISkin >( "DebugConsoleDropDownSkin" ); }
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private void Clear()
        {
            lock( m_lock )
            {
                m_buffer.Clear();
 
                for( int buf = 0; buf < m_catBuffers.Length; ++buf ) m_catBuffers[ buf ].Clear();
            }
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private void LowMemoryCallback()
        {
            Log( "LOW MEMORY", CATEGORY.ERROR );
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private void LogCallback( string condition, string stackTrace, LogType type )
        {
            bool   trace = ( type != LogType.Log );
 
            string entry = ( trace ) ? stackTrace + condition : condition;
 
            if     ( type == LogType.Log     ) Log( entry, CATEGORY.INFO    );
 
            else if( type == LogType.Warning ) Log( entry, CATEGORY.WARNING );
 
            else                               Log( entry, CATEGORY.ERROR   );
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static public void LogInfo   ( string entry ) { Log( entry, CATEGORY.INFO    ); }
 
        static public void LogWarning( string entry ) { Log( entry, CATEGORY.WARNING ); }
 
        static public void LogError  ( string entry ) { Log( entry, CATEGORY.ERROR   ); }
 
        static public void LogSystem ( string entry ) { Log( entry, CATEGORY.SYSTEM  ); }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static public void Log( string entry, CATEGORY category = CATEGORY.INFO )
        {
            if( UnityEngine.Debug.isDebugBuild == false ) return;
 
            if( string.IsNullOrEmpty( entry ) )           return;
 
            if( category >= CATEGORY.COUNT    )           return;
 
 
            string[] entries = entry.Split( SPLIT_SEMS, System.StringSplitOptions.RemoveEmptyEntries );
 
            for( int ent = 0; ent < entries.Length; ++ent ) LogEntry( entries[ ent ], category );
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private void LogEntry( string entry, CATEGORY category )
        {
            if( entry.Length > CLIPING ) entry = entry.Substring( 0, CLIPING );
 
            string date = System.DateTime.Now.ToString();
 
 
            lock( m_lock )
            {
                m_buffer.Push                       ( date, entry, ( int )category );
 
                m_catBuffers[ ( int )category ].Push( date, entry, ( int )category );
            }
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private void ConsumeMouseEvents()
        {
            #if ENABLE_INPUT_SYSTEM
 
                Vector2 pointerPos = UnityEngine.InputSystem.Pointer.current.position.ReadValue();
 
            #else
 
                Vector2 pointerPos = Input.mousePosition;
 
            #endif
 
 
            Vector2 mousePos = new Vector2( pointerPos.x, Screen.height - pointerPos.y );
 
            bool    focused  = m_globalRect.Contains( mousePos );
 
            if( ( Event.current.isMouse ) && ( focused ) ) Event.current.Use();
 
 
            if( EventSystem.current != null ) m_eventSystem         = EventSystem.current;
 
            if( m_eventSystem       != null ) m_eventSystem.enabled = ( focused == false );
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private void UpdateLayout()
        {
            if( Event.current.type != EventType.Layout ) return;
 
            Vector2 size = new Vector2( Screen.width * ( Application.isMobilePlatform ? 1.0f : 0.5f ), Screen.height * 0.5f );
 
            if( ( m_size != size ) || ( m_layout_dirty ) )
            {
                m_size         = size;
 
                m_layout_dirty = false;
 
 
                m_headerSize   = new Vector2( m_size.x, 24.0f );
 
                m_scrollSize   = new Vector2( m_size.x, ( m_expanded ) ? ( m_size.y - m_headerSize.y ) : 0.0f );
 
                m_pos          = new Vector2( 0.0f,     ( m_expanded ) ? ( Screen.height - m_size.y  ) : Screen.height - m_headerSize.y );
 
 
                m_headerRect   = new Rect   ( m_pos.x, m_pos.y,                  m_headerSize.x, m_headerSize.y );
 
                m_scrollRect   = new Rect   ( m_pos.x, m_pos.y + m_headerSize.y, m_scrollSize.x, m_scrollSize.y );
 
                m_globalRect   = new Rect   ( m_pos.x, m_pos.y, m_size.x, m_size.y );
            }
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private void DrawHeader()
        {
            const int nbButtons = 5;
 
            float     buttonsW  = m_headerSize.x / nbButtons;
 
            Rect      butRect   = new Rect( m_headerRect.x, m_headerRect.y, buttonsW, m_headerSize.y );
 
 
            if( GUI.Button( butRect, ( m_expanded ) ? STR_HIDE : STR_SHOW  ) ) 
            { 
                m_expanded = ( ! m_expanded ); 
 
                m_layout_dirty = true; 
            }
 
 
            if( m_expanded )
            {
                butRect.x += buttonsW; if( GUI.Button( butRect, STR_SORT_ASC ) ) m_ascending =  true;
 
                butRect.x += buttonsW; if( GUI.Button( butRect, STR_SORT_DSC ) ) m_ascending = false;
 
                butRect.x += buttonsW; if( GUI.Button( butRect, STR_CLEAR    ) ) Clear(); 
 
                butRect.x += buttonsW; 
 
 
                m_filter = ( CATEGORY )m_dropDown.Draw( m_skin, m_skin_dd, butRect, ( int )m_filter );
            }
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static private void DrawMessages()
        {
            const float dateW    = 140.0f;
 
            const float lineH    =  21.0f;
 
            Buffer      buffer   = ( ( m_filter < 0 ) || ( m_filter >= CATEGORY.COUNT ) ) ? m_buffer : m_catBuffers[ ( int )m_filter ];
 
            int         count    = buffer.count;
 
            Rect        viewRect = new Rect( 0.0f,  0.0f, Screen.width, lineH * count );
 
 
 
            GUI.Box( m_scrollRect, ( Texture )null );
 
            m_scrollPos = GUI.BeginScrollView( m_scrollRect, m_scrollPos, viewRect, false, true );
 
            if( Event.current.type == EventType.Repaint )
            {
                Rect  dateRect     = new Rect( 0.0f,  0.0f,                  dateW, lineH );
 
                Rect  lineRect     = new Rect( dateW, 0.0f, viewRect.width - dateW, lineH );
 
                int   maxVisibles  = ( int )( m_scrollRect.height / lineH ) + 1;
 
                int   firstVisible = ( int )( m_scrollPos.y       / lineH );
 
                int   lastVisible  = firstVisible + ( Mathf.Min( maxVisibles, count ) - 1 );
 
                int   start        = buffer.start;
 
 
                GUIStacks.PushColor();
 
                for( int entry = firstVisible; entry <= lastVisible; ++entry )
                {
                    dateRect.y  = lineRect.y = entry * lineH;
 
                    int   index = ( m_ascending ) ? start + ( ( count - 1 ) - entry ) : start + entry;
 
                    Entry Entry = buffer[ index ];
 
                    GUI.color   = m_colDate;                       GUI.Label( dateRect, Entry.date );
 
                    GUI.color   = m_cols[ ( int )Entry.category ]; GUI.Label( lineRect, Entry.msg  );
                }
 
                GUIStacks.PopColor();
            }
 
            GUI.EndScrollView ();
        }
 
        //************************************************************************************************
        //
        //************************************************************************************************
 
        static public void OnGUI()
        {
            if( UnityEngine.Debug.isDebugBuild == false ) return;
 
            GUIStacks.PushSkin( m_skin );
 
            UpdateLayout();
 
            if( m_expanded )
            {
                lock( m_lock ) { DrawMessages(); }
            }
 
            DrawHeader();
 
            ConsumeMouseEvents();
 
            GUIStacks.PopSkin ();
        }
    }
 
    //****************************************************************************************************
    //
    //****************************************************************************************************
 
    public class DebugConsole : MonoBehaviour
    {
        static public DebugConsole Instance { get; private set; }
 
        private void Awake    () { if( Instance == null ) Instance = this; }
 
        private void OnDestroy() { if( Instance == this ) Instance = null; }
 
        public void  OnGUI    () { if( Instance == this ) DEBUG.Console.OnGUI(); }
    }
}
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox