EditorWindow with a SceneView and inspector/non-scene GUI without reflection?

Hi,

my goal: have a custom EditorWindow containing a scene view (not just scene preview, but “interactive”, as in being able to select objects and using the default transform handles) and a custom GUI including inspectors. In other words, I want a single window in which I can display, select and move objects (from a PreviewSceneStage created for the EditorWindow) and edit specific components on them, plus some EditorWindow-specific GUI elements (e.g. some buttons).
The ideal way would be a custom SceneView with a custom EditorWindow (drawing inspectors and Editor GUI) docked to the right of it, as I’ve done by hand in this screenshot:

What I’ve tried so far / found online:
I currently have a SceneView subclass, which is perfect for the scene view part and my plan was to create a EditorWindow subclass for the inspectors and other GUI part, which I would ideally dock to the right of the SceneView window from C#.
From what I found (e.g. here and in the Github repo linked there), it seems docking EditorWindows from code requires quite a bit of reflection, which I would like to avoid in case the internal APIs change at some point (note: overloads of EditorWindow#GetWindow only make the second EditorWindow appear in a (unopened) tab next to the SceneView window, but not docked next to it).
I’ve also thought about using the UIToolkit method CreateGUI() in the Scene View subclass, but it is not straightforward to add GUI next to the scene view in the same EditorWindow.
To do that cleanly, I believe I would need to be able to manipulate the visual tree somewhere farther up to add something like a TwoPaneSplitView, put the all the scene view stuff on one side and my other GUI stuff on the other. I don’t really know UIToolkit, but that seems hard/impossible.
I can only think of weird hacks like adding margin to the scene view then add GUI into that margin or misusing Overlays to marry my “normal” UI stuff with the Scene View, but that all feels nightmarish to get right in terms of look and feel, resizing and scrolling.

Is there no way to get a scene view and normal UI combined nicely in one EditorWindow without having to resort to reflection or other brittle hacks?

No, not really. Note that an EditorWindow is just a ScriptableObject derived type. It just represents the concept of a high-level window. EditorWindow instances may be used by a HostView instance which is just an internal management class to “slot” the actual editor window behaviour into their internal concept of a View. Then there’s the SplitView class which is in use when you “dock” EditorWindows next to each other. Splitviews can be nested and build the common structure we know.

Besides those internal View classes, there’s the internal native window class called ContainerWindow. It’s also an abstraction of an actual OS window class. So a ContainerWindow represents an actual window in the sense of the OS. Unity by default only has the “MainWindow” which has the main menu and ribbon at the top and one view area where the above mentioned view classes can be “docked”. When you drag an Editorwindow out of a “TabView” (also internal class), Unity will create a new separate ContainerWindow and depending on the window style it may just contain a HostView (for popups and tool windows) or it will slot a TabView in between which is the normal case.

As you figured out yourself, those classes are internal and can not be used without reflection. You can not really nest EditorWindows inside EditorWindows. So reflection may be the only viable solution if you desperately want to take away the control of the layout from the user :stuck_out_tongue:

2 Likes

Darn, I feared as much.

I think the best I can do while staying away from reflection and other unstable hacks is do everything I did to my custom SceneView to the normal, active SceneView instead (plus save and restore the settings before / after) and add an EditorWindow or Overlay with the GUI I need, plus maybe some help box explaining that things are to be manipulated using the Scene View and inspector, and then applied via the extra GUI to return back to the “normal” SceneView.

Is there some way to ensure a SceneView and Inspector tab are currently open or open them / bring them to front if not?

Well, yes and no :slight_smile: GetWindow will get you (one of) the open window or will open one if not yet open. However it does not really bring it to the front. I don’t think there’s a built-in way. Since the inspector and the sceneview could be in the same TabView, you couldn’t even bring both of them to the front.

I don’t think using reflection would be that much of a risk. Most of this mechanic hasn’t changed in the last 10 years, but of course there’s no guarantee. Since the rearranging would just be an optional gimmick, I would ensure to not cause any errors, check everything you try to use and if something is off, just ignore the reflection stuff. I once thought about writing some helper classes to wrap all those management classes (View, HostView, SplitView, ContainerWindow, etc) so they can be used without having to deal with all that reflection mess. But I never really found the time. I think I’ve started a couple of times but providing a good interface is quite difficult and quickly becomes complicated.

1 Like

What puts me off even more is that it’s not just reflection so API changes could break it, but the docking - at least in that thread I found - is seemingly done by simulating the mouse drag’n’drop, adding more ways it could go wrong. Sure, there might be another way to do that part, but digging through undocumented internals for that and then better still having some alternative in place should something go wrong as you suggested doesn’t sound fun.

Interestingly, for the open/bring to front part, I’ve found EditorApplication.ExecuteMenuItem(), which used with “Window/General/Scene” and “Window/General/Inspector” does work nicely. I think GetWindow would also require reflection since I can’t find a (public) Inspector type (though that should really be rename-proof). Of course having the Scene View and Inspector as tabs in the same host view would ultimately only show the Inspector, but that I can live with (the assumption that most people have them arranged separate from each other is one I am willing to make).
Highlighter.Highlight() to highlight parts of the editor is interesting as well, just thought I’d mention it here real quick since I’ve never heard of it before.

That would be kinda crazy, yes. I was thinking about manually setting up the hierachy of SplitViews and such. Though I have to agree that this was mainly and idea. It it’s actually possible needs to be worked out