- Home /
SceneView GUI uses different skin on component toggle - bug or mistake?
I have a class [InitializeOnLoad] SceneViewWindow which draws buttons and a window into the scene view by calling the onSceneGUIDelegate. It appears to work fine, see first picture. All buttons are dark gray (I haven't set that style, it just was the default).
However, as soon as I toggle down a different component, which has a Custom Inspector with a OnSceneGUI function on it, the style/skin of the scene view GUILayout elements seem to change and I don't know why.
This is my code to draw to the scene view:
using UnityEngine;
using UnityEditor;
[InitializeOnLoad]
public class SceneViewWindow
{
static SceneViewWindow()
{
SceneView.onSceneGUIDelegate += OnSceneGUI;
}
static void OnSceneGUI(SceneView sceneView)
{
Handles.BeginGUI();
Rect windowRect = new Rect(Screen.width - 183, Screen.height - 65, 180, EditorGUIUtility.singleLineHeight * 2f);
GUILayout.Window(666, windowRect, DrawWindowForSpriteRenderer, "Satellite Tool");
Handles.EndGUI();
}
static void DrawWindowForSpriteRenderer(int windowID)
{
...
GUIStyle buttonStyle = new GUIStyle(GUI.skin.button);
buttonStyle.margin = new RectOffset(0, 5, 2, 0);
if(GUILayout.Button(plusTexture, buttonStyle, GUILayout.Width(buttonSize), GUILayout.Height(buttonSize)))
{
...
}
...
}
}
Next, my Custom Inspector, which shouldn't have to do anything with the previous class:
[CustomEditor(typeof(OrbitingBehaviour), true), CanEditMultipleObjects]
public class OrbitingBehaviourEditor : Editor
{
void OnEnable ()
{
_altitude = serializedObject.FindProperty("_altitude");
Tools.hidden = true;
}
void OnDisable ()
{
Tools.hidden = false;
}
void OnSceneGUI ()
{
//MoveWithHandle((OrbitingBehaviour)target);
//DrawGizmos((OrbitingBehaviour)target);
}
}
Right now the OnSceneGUI function doesn't do anything. However, as soon as the OrbitingBehaviour component is toggled down, the scene view elements turn light gray. If I completely remove OnSceneGUI from the script, the scene view elements remain dark gray.
I'm not actually changing any Editor styles or skins in any script, so I have no clue what might be going on here. Any ideas? Maybe this is just a bug. I'm using Unity Free, but the dark gray skin should only be available to Pro users anyway, right?
Answer by mattmanj17 · Jul 30, 2015 at 10:22 PM
did some digging in https://github.com/MattRix/UnityDecompiled to find out how OnScene gui was actually called, and found this
private void CallOnSceneGUI()
{
Editor[] activeEditors = this.GetActiveEditors();
for (int i = 0; i < activeEditors.Length; i++)
{
Editor editor = activeEditors[i];
if (EditorGUIUtility.IsGizmosAllowedForObject(editor.target))
{
MethodInfo method = editor.GetType().GetMethod("OnSceneGUI", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
if (method != null)
{
for (int j = 0; j < editor.targets.Length; j++)
{
this.ResetOnSceneGUIState();
editor.referenceTargetIndex = j;
EditorGUI.BeginChangeCheck();
Editor.m_AllowMultiObjectAccess = !editor.canEditMultipleObjects;
method.Invoke(editor, null);
Editor.m_AllowMultiObjectAccess = true;
if (EditorGUI.EndChangeCheck())
{
editor.serializedObject.SetIsDifferentCacheDirty();
}
}
this.ResetOnSceneGUIState();
}
}
}
if (SceneView.onSceneGUIDelegate != null)
{
SceneView.onSceneGUIDelegate(this);
this.ResetOnSceneGUIState();
}
}
the ResetOnSceneGUIState function is what causes the problem. it is an internal function that does this. it is only called if the OnSceneGui function exists in the editor.
internal static void ResetGUIState()
{
GUI.skin = null;
Color white = Color.white;
GUI.contentColor = white;
GUI.backgroundColor = white;
GUI.color = ((!EditorApplication.isPlayingOrWillChangePlaymode) ? Color.white : HostView.kPlayModeDarken);
GUI.enabled = true;
GUI.changed = false;
EditorGUI.indentLevel = 0;
EditorGUI.ClearStacks();
EditorGUIUtility.fieldWidth = 0f;
EditorGUIUtility.labelWidth = 0f;
EditorGUIUtility.SetBoldDefaultFont(false);
EditorGUIUtility.UnlockContextWidth();
EditorGUIUtility.hierarchyMode = false;
EditorGUIUtility.wideMode = false;
ScriptAttributeUtility.propertyHandlerCache = null;
}
so the gui gets set back to the default (which is the light gui i guess). so the best solution might be to figure out what all the gui styling values are for the other style, and manually set them to what they need to be before starting to draw in the scene view.
the IsGizmosAllowedForObject function that controls whether the scene view function gets called is external c++, so i cant be sure, but i bet that returns false if the foldout for the component isn't open
EDIT:
after doing somepoking around with the monodevelopdebugger, i found the values i needed. I added these lines to the beginning of my scene drawing
GUI.skin = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Scene);
//the next three lines are most likely over kill
EditorGUIUtility.fieldWidth = 50;
EditorGUIUtility.labelWidth = 100;
typeof(EditorGUIUtility).GetField("s_ContextWidth",System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).SetValue(null,408);
It looks alright if you only do the first line, but the other three lines set the values back to what they were before ResetOnSceneGUIState was called.
Thanks a lot for this elaborate answer! Setting GUI.skin to the built-in skin works.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
How can I do this with gizmos? 0 Answers
Expose Private Field in Custom Editor 3 Answers
Custom Assets do not save data that is not primitive 0 Answers