Skip to content

Instantly share code, notes, and snippets.

@Valeour
Last active September 8, 2018 15:23
Show Gist options
  • Save Valeour/31422811482ad0b7975d354ff8e3d457 to your computer and use it in GitHub Desktop.
Save Valeour/31422811482ad0b7975d354ff8e3d457 to your computer and use it in GitHub Desktop.
Open Unity Preferences Window with Section
/**
* PreferenceWindow helper created by Chance Millar at Two Tails Games on 2018/07/24
* Use freely. That's a license, right?
*
* Be sure to place in an Editor folder inside Assets.
*/
using System;
using System.Collections;
using System.Reflection;
using UnityEngine;
/// Helper class to Open a Preference Window, as well as selecting a Section.
/// Source for PreferencesWindow can be viewed here: https://github.com/Unity-Technologies/UnityCsReference/blob/cc0513fdae7a5624a12f99f3a05bd0a82dd9a366/Editor/Mono/PreferencesWindow/PreferencesWindow.cs
public static class PreferencesWindow
{
/// Get the Assembly that the internal PreferencesWindow belongs to.
private static readonly Assembly kAssembly = Assembly.GetAssembly( typeof(EditorWindow) );
/// Reflect the type.
private static readonly Type kPreferencesType = kAssembly.GetType( "UnityEditor.PreferencesWindow" );
/// PreferencesWindow has an inner class called "Section". This is the class that the sections are stored in, so get the Type for that so we can read the data.
private static readonly Type kSectionType = kPreferencesType.GetNestedType( "Section", BindingFlags.NonPublic );
/// Reflect a reference to the method that opens the Preferences Window.
private static readonly MethodInfo kInvokePreferences = kPreferencesType.GetMethod( "ShowPreferencesWindow", BindingFlags.NonPublic | BindingFlags.Static );
/// Section class has a GUIContent field called "content", which contains the name for each section.
private static readonly FieldInfo kSectionContentField = kSectionType.GetField( "content" );
/// This is the list of Sections that PreferencesWindow contains.
private static readonly FieldInfo kSectionSectionsField = kPreferencesType.GetField( "m_Sections", BindingFlags.NonPublic | BindingFlags.Instance );
/// This is the index value used to determine what Section is selected in the Preferences window.
private static readonly PropertyInfo kSelectedSection = kPreferencesType.GetProperty( "selectedSectionIndex", BindingFlags.NonPublic | BindingFlags.Instance );
/// Open the Unity Preferences Window
public static void Open()
{
/// Because ShowPreferencesWindow() is static, we don't need to pass in any data. Invoking this will open the window.
kInvokePreferences.Invoke( null, null );
}
/// Open the Unity Preferences Window with a specified Section.
public static void Open( string sectionName )
{
// Need to make sure the window is open first.
Open();
// It takes a frame to populate all the info in Preferences Window, so by using DelayCall, we can wait until a frame after before we set the Section.
EditorApplication.delayCall += () => {
FindAndSetSection( sectionName );
};
}
/// Find if a PreferencesWindow is open and close it.
public static void Close()
{
EditorWindow window = EditorWindow.GetWindow( kPreferencesType );
window.Close();
}
/// Search the sections and select the matching Section.
private static void FindAndSetSection( string sectionName )
{
/// The window should already be open, so now we need to get a reference to it.
EditorWindow window = EditorWindow.GetWindow( kPreferencesType );
/// Next we need to get the m_Sections field. We have the reflected reference, but we need to pass in the window to get the actual object's member.
/// We can't really do List<PreferenceWindow.Section> either, but we can use the IList interface that comes with List<>.
IList list = (IList)kSectionSectionsField.GetValue( window );
for( int i = 0; i < list.Count; ++i )
{
/// We know each element is a Section type, so we can use the "content" reflection to get the appropriate value from each Section.
GUIContent content = (GUIContent)kSectionContentField.GetValue( list[i] );
/// If the strings match, then we have a winner.
if( content.text == sectionName )
{
/// Set the Preference Window's selectedSection to the current index.
kSelectedSection.SetValue( window, i, null );
return;
}
}
/// Reflection didn't fail, but the sectionName couldn't be found.
/// This can either be because the PreferencesWindow isn't populated yet, or there's a typo with sectionName value.
Debug.LogError( "PreferencesWindow: Section Name not found." );
}
}
@Valeour
Copy link
Author

Valeour commented Jul 24, 2018

Usage:

PreferencesWindow.Open()
To just open the Preferences Window.

PreferencesWindow.Open("External Tools")
To open Preferences Window with External Tools section selected.

PreferencesWindow.Close()
To close an open PreferencesWindow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment