IMGUI (Immediate Mode GUI) is Unitys legacy UI system that handles game UI pre-Unity 4.6 and editor UI. It generally consts of GUI.xyz and GUILayout.xyz calls within an OnGUI function. It could get cumbersome and very difficult to read. Especially if you have a lot of GUI controls.
Whilst I was refactoring Blockout, I came across some APIs that managed to slip passed me when Unity 5.0 was launched. Admittedly, a lot of new APIs can get passed without a programmer knowing as there’s usually a large code change in various parts of the engine with each new update. This was GUILayout.xyzScope where xyz was either Horizontal, Vertical, Area or ScrollView. This makes code more readable and easier to understand. A positive side effect is that there is potentially less code that the coder needs to write to accomplish the same thing.
Upon looking into Unity Decompiled on how GUI Scopes functioned, I decided to create my own take on it that auto centred in an axis. This would further eliminate the need to Flexible Spaces every 3 lines.
The way these work is similar to how the normal version of both scopes work. At a base level it uses in IDisposable C# interface so it can be wrapped in a using tag. All this means, is that when the class is created it calls the appropriate begining UI functions for GUILayout.BeginXYZ() and GUILayout.FlexibleSpace(). When the disposbale class goes out of scope, usually the end of the using block section, the disposable class gets destroyed so you have to do some cleanup. For this it was the case of calling GUILayout.FlexibleSpace() and GUILayout.EndXYZ() to ensure the encapsulated GUI code is centred.
This is great advantage of the IDisposbale interface class that GUI.Scope inherits – even though the ‘bookend’ (begin/end) nature of the GUI code was not what it was originally meant for!
Whilst UI scoping is great, I found out that since I was writing a lot of editor code, it needed to ability to Undo. Blockout usually performs large quantities of changes to multiple objects at the press of a button that all need to be undone together. This is where things get a little more interesting. I found myself calling the following block of code fairly frequently:
This was getting cumbersome. In the first released version of Blockout, I call this block of code ~12-15 times. Now the by the book and really ‘good’ coder in me went OK, lets inherit the IDisposbale class and create an UndoScope() disposable function that encapsulates all of this without the need for much repetition. This however turned out to be a lot of effort for 2am. So to that end, since that class was already written, at least from a base level in the GUI system, I created a derived class which inherited from GUI.Scope.
A string (the name of the undo operation for that block) is passed on creation of the UndoScope. This increases the current group index and sets the name of that group block. The rest of the code continues as normal for example creating a GameObject. Upon leaving the scope and subsequently the class being destroyed, CloseScope() is called on the class which can perform cleanup and close off any block code that was started in the constructor.
This has immensely helped in the refactor of Blockout which went from >4000 lines of code to somewhere under <= ~ 2500 – 3000. This has made code navigation 10x easier to locate and read and is something that has now been ingrained into me for whenever I need to write editor code.
Hoorah for the non standard use of the GUI.Scope class to make a simple disposable class! ( I mean the Microsoft documentation on how to crate a disposable class from an IDisposable interface look super complex for me at 2am which is why I decided to base it off of Unitys GUI.Scope.