UIElementsでEditorWindowをダークテーマに固定する

# 事件
せっかくつくったエディタ拡張が、エディタのテーマを変更したら文字が背景に同化した……
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124429/9a6e5308-0d3c-10b8-8c3c-2fd0093b7eb6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124429/f849c62a-05df-dd04-56d2-6337804650a6.png)


個人プロジェクトならまだいいですが、人に配るものとなるとこうはいきません。
いやしかし、全部の要素のUSSを書き換えて文字色・背景色を変えるのは難しいですし、新しい要素を追加するときも面倒です。
環境によらずつねに同じ色で表示されてほしい……

そんなわけで今回は、UIElementsでテーマをダークテーマに（またはライトテーマに）固定するというお話です。

# UIElementsとエディタテーマ
UIElementsはUXML/USSという言語でUIを作ります。ちょうどHTML/CSSとよく似た仕組みで、USSがスタイルを制御するファイルにあたります。
UIElementsでは、読み込んでいるテーマに応じて自動的にそのテーマ用のUSSが適用されるようになっています。

これはUIElements Debuggerをみるとよくわかります。適当なEditorWindowのタイトル部分を右クリックしてUIElements Debuggerを見てみましょう：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124429/e4cfadc1-0da6-5aba-f97d-4ce978cfe6e6.png)
ありました。 **DefaultCommonLight_inter.uss**っていうこいつです。ダークテーマの時は**DefaultCommonDark_inter.uss**というUSSが読み込まれます。
「じゃあこのファイルを探してきて読み込めばいいのでは？」と行きたいところですが、実はこのファイル、Unityのエディタビルトインアセットとして保存されています。EditorGUIUtility.Load(string path)で読み込めるのですが、Unityのバージョンによってアセットのパスが同一である保証はありません。ついでに使用している言語やフォントによってUSSが異なります。
つまりどういうことかというと、ちゃんとUnity側のAPIを通してスタイルシートを取得するのがよさそうということです。

# Unity側の処理を見てみる
Unity側にEditorWindowに対して自動的にテーマに応じたUSSを適用する処理が存在しているわけですが、そこの処理を拝借してくればよさそうです。

EditorWindowがテーマを取得しているのは以下の箇所です。

[UnityCsReference/EditorWindow.cs at master · Unity-Technologies/UnityCsReference](https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/EditorWindow.cs#L1218)

ここからさらに処理を辿ると、 **UIElementsEditorUtility** に辿り着きました。

[UnityCsReference/UIElementsEditorUtility.cs at master · Unity-Technologies/UnityCsReference](https://github.com/Unity-Technologies/UnityCsReference/blob/master/Modules/UIElementsEditor/UIElementsEditorUtility.cs#L30)

ありました。**UIElementsEditorUtility.s_DefaultCommonDarkStyleSheet**と**UIElementsEditorUtility.s_DefaultCommonLightStyleSheet**です。

しかし（予想はしていましたが）、こいつらはinternalです。つまりリフレクションの出番です。ゴリ押していきましょう。

```csharp:SkinFixedEditorWindow.cs
using System.Reflection;
using UnityEditor;
using UnityEngine.UIElements;

public class SkinFixedEditorWindow : EditorWindow
{
    [MenuItem("Window/SkinFixedEditorWindow")]
    public static void ShowWindow()
    {
        GetWindow(typeof(SkinFixedEditorWindow));
    }

    private static StyleSheet defaultCommonDarkStyleSheet;
    private static StyleSheet defaultCommonLightStyleSheet;

    private static void GetSkins()
    {
        //UnityEditor.UIElementsのアセンブリを取得
        var assembly = typeof(Toolbar).Assembly;

        //UIElementsEditorUtilityのTypeを取得
        var type = assembly.GetType("UnityEditor.UIElements.UIElementsEditorUtility");
        if (type == null) return;

        //StyleSheetを格納するフィールドを取得
        var darkField = type.GetField("s_DefaultCommonDarkStyleSheet", BindingFlags.Static | BindingFlags.NonPublic);
        var lightField = type.GetField("s_DefaultCommonLightStyleSheet", BindingFlags.Static | BindingFlags.NonPublic);

        if (darkField == null || lightField == null) return;

        //staticなフィールドとして値を取得
        defaultCommonDarkStyleSheet = (StyleSheet) darkField.GetValue(null);
        defaultCommonLightStyleSheet = (StyleSheet) lightField.GetValue(null);
    }

    private void OnEnable()
    {
        GetSkins();
    }
}
```

あとは取得したUSSをEditorWindowのrootVisualElementに適用してあげます。

```csharp:SkinFixedEditorWindow.cs
    private void OnEnable()
    {
        GetSkins();
        
        //Darkテーマに設定
        rootVisualElement.styleSheets.Clear();
        rootVisualElement.styleSheets.Add(defaultCommonDarkStyleSheet);
        
        //EditorWindowのデフォルトの背景色はUIElementsの色ではなく地の色なので、背景色だけはUIElements側に手動で設定する必要がある
        rootVisualElement.style.backgroundColor = new StyleColor(new Color(0.22f, 0.22f, 0.22f));
        rootVisualElement.style.flexGrow = 1f;

        //VisualElementを配置してみる
        var button = new Button();
        button.text = "ボタン";
        rootVisualElement.Add(button);
        
        var textField = new TextField("テキスト");
        rootVisualElement.Add(textField);

        var floatField = new FloatField("数値");
        rootVisualElement.Add(floatField);
    }
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124429/8a7e0079-d0a2-27d2-7e0a-45ef3d2e782d.png)

そんなわけで、LigthtテーマのUnityの上にDarkテーマ固定のEditorWindowを出現させることに成功しました。