- Home /
Detect EditorWindow.OnGUI vs. MonoBehaviour.OnGUI to facilitate code sharing?
I'm working on some GUI code (line drawing) that I plan to share between a game component and an editor window. The code is mostly the same, but a couple of things need to be different for use from EditorWindow.OnGUI than for MonoBehaviour.OnGUI. Is there a way to detect which context is active?
EDIT
I want something like this ...
In my component class:
public class MyComponent: MonoBehaviour
{
void OnGUI()
{
Drawing.DrawLine(Vector2.zero, Vector2.one * 100.0f);
}
}
In my editor window ... public class MyEditorWindow: EditorWindow { void OnGUI() { Drawing.DrawLine(Vector2.zero, Vector2.one * 100.0f); } }
With an implementation that can tell which is which:
public static class Drawing
{
public static DrawLine(Vector2 start, Vector2 end)
{
if (isCalledFromEditorWindow)
{
...
}
else
{
...
}
...
}
}
END EDIT
Here's what I've thought of so far:
Use #if UNITY_EDITOR or Application.isEditor. Sort of works, but I really want the code to be different in the Game panel than it is in my custom editor window, not just different in the editor than in a build.
Pass in an extra parameter to the API indicating that I'm in editor window mode. This would work, but I prefer the caller not have to worry about it.
Use System.Diagnostics.StackTrace to see where I'm being called from. This would work, but would be slow, and what I'm doing is performance-intensive.
What would be great is something like Camera.current.isEditorWindow, but of course that doesn't exist.
Any suggestions?
Turns out my line drawing is fully shareable after all, but I'm still curious to know for future reference.
Answer by Jamora · Aug 21, 2013 at 12:18 AM
Your question doesn't mention if the shared code is static or not, so I'll have a crack at both the alternatives.
In case the shared code is not static, I would create two interfaces: IMonoBehaviourLineDrawer and IEditorLineDrawer. The line drawer class would implement both these interfaces. Then, depending on whether the context is an EditorWindow or a MonoBehaviour, I would just treat the line drawer as the appropriate interface. It would look something like:
public interface IMonoBehaviourLineDrawer{
void MonoBehaviourSpecificMethod();
}
public interface IEditorWindowLineDrawer{
void EditorWindowSpecificMethod();
}
public class LineRenderer : IMonoBehaviourLineDrawer, IEditorWindowLineDrawer
{/*implementation*/}
//in a MonoBehaviour somewhere
IMonoBehaviourLineDrawer lineDrawer = new LineRenderer(/*parameters*/);
lineDrawer.MonoBehaviourSpecificMethod();
//in an EditorWindow
IEditorWindowLineDrawer lineDrawer = new LineRenderer(/*parameters*/);
lineDrawer.EditorWindowSpecificMethod();
The methods implemented from the interface would just do whatever specific to the current mode, then call the common code at an appropriate moment.
You might also have to create a hierarchy of interfaces if you have lots of common methods in LineDrawer
that you want to call from both modes. Just inherit the above interfaces from ILineDrawer
, which contains all the common method declarations.
In case your code is static you could either do an extension method for it, or if you have access to the code just create two different methods that separate between the modes. Basically the same as above, just without the interfaces.
Your example shows the $$anonymous$$onoBehaviour and the EditorWindow calling two different methods, which is precisely what I don't want (and if I did I could use different classes). Interfaces could come in handy, but I'd probably choose to have different extensions of the same base class ins$$anonymous$$d. Also note that extension methods are only for instance methods, you can't use them to add static methods.
I will edit my question to be more clear about what I'm trying to do.
$$anonymous$$y example does call two different methods. However, it is completely comparable to the if-else statement in your code currently: one method calls the if-branch, the other method the else branch.
But with a static class using interfaces won't work.
Answer by Bunny83 · Aug 21, 2013 at 01:00 PM
I would suggest to use a static state variable in your Drawing class which will set the whole class into "editor mode". Since your editor window is a special case the OnGUI code of your editor could look like this
void OnGUI()
{
Drawing.editorMode = true;
// Your gui stuff
Drawing.editorMode = false;
}
That way you don't have to care about the runtime code.
Your answer
Follow this Question
Related Questions
Editor GUI Drag Selection Box 1 Answer
Handling NullReferenceException in EditorWindow OnGUI() 0 Answers
How to get an array inside a simple class at Editor window and change arraysize? 0 Answers
How to resize preference window to fit gui contents. 1 Answer
Code executes more than once when key press event is triggered in OnGui in Custom Editor Window 3 Answers