Creating a Clone of Unity’s Console Window

In our last post we created a Unity window and added two resizable panels. In this post, we will improve upon it and make it a clone of Unity’s console window. This post is going to be a little bit longer, so I will omit the previously written code, but the final version will still be available in full at the end.

Before we start coding, let’s examine the console window and see what we should add.

Unity's console window

The window starts with a menu bar (1) which has one button and six toggles. The button and three toggles are aligned to left, and the remaining toggles are aligned to right. The button clears the window, while toggles turn on and off specific options. Then there is a scroll view (2) that contains clickable boxes with icons and text. Boxes change color when you click on them, and their content is displayed in the bottom panel (3), a text area which is not editable but selectable.

Alright then, we can start. But, before we do, I would like to fix a tiny issue from the previous post’s code. I left a magic number as the height of the resizer area, and I would like to convert it to a proper variable:

And, further down the code, once again replace the magic number with the variable:

Menu Bar

Now we can start adding our menu bar. We will draw this bar just as we drew other panels: by feeding GUILayout.BeginArea() a rectangle which would define its position and size (basically, its area). I am going to steal this area  from the upper panel, so that we won’t have to change other panels’ positions or heights. You can make this bar as tall as you would like, but since we are cloning Unity’s console window, we should stick to default and make it 20 pixels in height. Also, please note that this time, GUILayout.BeginArea() takes a second parameter: EditorStyles.toolbar. As the name suggests, this parameter tells Unity to draw this area in toolbar style. EditorStyles has many other options to choose from which affects how the GUI elements are displayed, so I would suggest checking them out and see Unity team used them in their own editor windows.

OK, we are ready to add our buttons and toggles. I could have added them in the code above, but there are a couple of new concepts that I should explain beforehand. First of all, there is GUILayout.BeginHorizontal(). You see, GUILayout, as the name suggests, lays out the GUI automatically vertically. However, a toolbar is laid out horizontally, so we need to use GUILayout.BeginHorizontal() and then use GUILayout.EndHorizontal() so that Unity stops horizontal layout and continues automatic vertical layout. Then, there is GUILayout.FlexibleSpace() which acts like a spring and pushes other UI elements to the edges of its container by filling the space between them. On the other hand, GUILayout.Space(int) creates just the amount of space you need. GUILayout.Button() returns true when it is clicked and GUILayout.Toggle() returns a boolean depending on the status of the toggle: true when it is on and false when it is off.

It looks pretty good, but the toggles on the right are missing their icons. Adding icons and textures to GUI elements is rather easy, but Unity lacks the documentation on how to do it. Here’s a piece of information you probably can’t find on the internet: Unity uses EditorGUIUtility.Load(string) to load editor resources and this piece of script lists some of the default Unity editor textures (all the icons). I checked the list and found the icons used in the console editor, so let’s add them into our own clone.

It definitely looks like a clone of the console window, right? 🙂

Resizable Panels

Upper Panel

Let’s move on to the upper panel. This panel should be scrollable, because it could contain more content than it can display. Here is another new concept: GUILayout.BeginScrollView(Vector2 scroll) creates a scroll view in the area it is defined. All the GUI elements between GUILayout.BeginScrollView(Vector2 scroll) and GUILayout.EndScrollView() will be displayed in this scroll area.

Unity’s console window displays boxes in this panel, so will we. However, it is not going to be one liner, because we need to know what kind of content needs to be displayed (info, warning or error), and what its index number is (so that we can do a zebra effect on the boxes). For these reasons, it is going to be a little more work than we did previously. First of all, we need an enum for the content type of the box, which fortunately exists: LogType. Then, we should create a method for drawing boxes. This method will draw a box, add an icon to the left of the content based on its type, set the background color to a lighter or darker color based on its index (lighter if the index is odd, darker if the index is even) and then display a text.

Now we can use DrawBox() method in DrawUpperPanel() to actually display some content:

And the result is a scrollable panel with a zebra effect and icons!:

Lower Panel

Up next is the lower panel. All this panel does is to display a message, so we will just add a scroll view and a text area.

It looks great!

Adding Interaction

Yes, our window looks good, but it doesn’t do anything useful right now. Since this is a console window clone, I would like it to receive log messages from Unity’s own Debug class and display them in a similar manner. A log contains some data, such as a log string, a stack trace and a type, hence we need a class for it. We will be keeping the instances of this class in a list and a reference to the selected log. When we modify the upper and lower panel code, our window will start behaving exactly like the console window.

In order to receive logs from Debug.Log() calls, we need to tap into Unity’s log message event. Generally, we can’t access parts of Unity API that are restricted to main thread but, fortunately, Unity exposes an application event called logMessageReceived. We are going to subscribe to this event in OnEnable() and in the subscriber method we will create a Log object and add it the list of logs.

Time for the ultimate test: take your ResizablePanels.cs code to a working application of yours or just create a new Monobehaviour in your current project. Throw in a couple of Debug.Log(), Debug.LogWarning() and Debug.LogError() calls and see how your window works.

resizable-panels-working

Conclusion

This concludes our tutorial on creating a clone of the console window. Now we have a window that looks almost exactly like a console, and has similar functionality (implementing the rest of the functionality can be an exercise for the reader 🙂 ). Let’s review what we learned in this post:

  • Styling GUI elements as a menu bar.
  • Laying out GUI elements both vertically and horizontally.
  • Creating buttons and toggles.
  • Adding texture to GUI elements.
  • Creating scroll views.
  • Subscribing to Unity’s Debug events.

It doesn’t seem like a lot, but believe me, we have covered everything you need to know in order to build your own editor windows. In the next blog post, we will have a look at node-based editors and start creating them for ourselves. And as I promised, here is the script in full, below. Until next time.