[Unity][VFW]エディタ拡張用オリジナル属性（プロパティにも使えるHeaderAttributeを作る）

# はじめに
以前ご紹介した[Unityのエディター拡張VFW](https://qiita.com/Shinoda_Naoki/items/7a3205ae3e40d3fc58ab)ですが、私もReadme翻訳するまで勘違いしてたんですが、VFWは単なるカスタム属性のライブラリではなく、新しいエディター拡張用API群なんですね。

Unity標準でも[CustomEditor](https://docs.unity3d.com/ja/540/Manual/editor-CustomEditors.html)やら[PropertyDrawer](https://docs.unity3d.com/ja/540/Manual/editor-PropertyDrawers.html)やら使えば、特定のオブジェクト用のエディターGUIをカスタマイズできますが、VFWでも同等のクラスBaseEditor,ObjectDrawerなどがあります（機会があれば別途記事書きます）。
VFWのさらに進んだところは、**エディターの表示をカスタマイズするオリジナルのカスタム属性(CustomAttribute)を定義できる**ところ。

VFWには既存の[[Header]](https://docs.unity3d.com/ja/540/ScriptReference/HeaderAttribute.html)やら[[Tooltip]](https://docs.unity3d.com/ja/540/ScriptReference/TooltipAttribute.html)やらの属性が使えなくて、フォローが行き届いてないな〜なんて思ってましたが、**なければ作ればいい**んですね。なるほど、だからVexe **FrameWork** なんだ！

というわけで、今回はオリジナル属性の実装のサンプルとして、VFWで使える[Header]属性と同等の属性のコードを紹介してみたいと思います。

# VHeader の実装

まずはカスタム属性(CustomAttribute)です。「カスタム属性ってなんだよ？」って方は　[こちらのサイト](http://ufcpp.net/study/csharp/sp_attribute.html)を御覧ください。
オリジナルのHeaderAttributeはフィールドにしか付けられませんが、ここはVFWらしくプロパティーにも付けられるようにしてみました。
CompositeAttributeを継承して作ります。コンストラクタではベースクラスにidを渡すようにします。

```csharp:VHeaderAttribute.cs
using System;
using Vexe.Runtime.Types;

namespace VFWExample.Scripts.View
{
    /// <summary>
    /// Similar to Unity's HeaderAttribute
    /// </summary>
    [AttributeUsage(AttributeTargets.Field|AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
    public class VHeaderAttribute : CompositeAttribute
    {
        public string comment;

        public VHeaderAttribute(string comment) : this(-1, comment)
        {
        }

        public VHeaderAttribute(int id, string comment) : base(id)
        {
            this.comment = comment;
        }
    }
}
```

次に、対応するカスタムドロワーの実装です。CompositeDrawerを継承します。
CompositeDrawer\<Object,VHeaderAttribute\> というのは、VHeaderAttribute属性がついたObjectの派生オブジェクトに対して適用するドロワーであることを宣言するものです。
CompositeDrawer\<string,VHeaderAttribute\>, CompositeDrawer\<DateTime,VHeaderAttribute\> などのように対象の型ごとに違うドロワーを割り当てることもできます。

OnUpperGUI()は対象フィールドの上に追加要素を描画するために使います。他にOnLeftGUI(),OnRightGUI(),OnBottomGUI()などがオーバライドできます。
メソッド内では、RabbidGUIのAPIを使って、VHeaderAttributeで設定したコメントの内容をラベルに表示しています。

```csharp:VHwaderDrawer.cs
using System;
using VFWExample.Scripts.View;
using Vexe.Editor;
using Vexe.Editor.Drawers;

namespace VFWExample.Scripts.Editor
{
    public class VHeaderDrawer : CompositeDrawer<Object, VHeaderAttribute>
    {
        public override void OnUpperGUI()
        {
            base.OnUpperGUI();
            gui.Space(8f);
            gui.Label(attribute.comment,GUIStyles.BoldLabel);
        }
    }
}
```
最後に、ドロワーを登録するコードです。ここではVHeaderAttributeしか登録してませんが、他にも色々カスタマイズしたら登録するクラスは一箇所にまとめたほうがいいでしょう。

```csharp:VFWExtensions.cs
using VFWExample.Scripts.View;
using UnityEditor;
using Vexe.Editor;

namespace VFWExample.Scripts.Editor
{
    public static class VFWExtensions
    {
        [InitializeOnLoadMethod]
        public static void RegistorDrawers()
        {
            MemberDrawersHandler.Mapper.Insert<VHeaderAttribute, VHeaderDrawer>();
        }
    }
}

```

# 使用例

適当に作ったクラスをゲームオブジェクトにつけてみました。

```csharp:VHeaderSample.cs
using Vexe.Runtime.Types;

namespace VFWExamples.Scripts.View
{

    public class VHeaderSample : BaseBehaviour
    {
        [Show, VHeader("秘密の番号")]
        private int privateNumber;

        [Show, VHeader("名前")]
        public string Name { get; set; }
    }
}
```
####スクリーンショット
![ss_vheader_sample.jpg](https://qiita-image-store.s3.amazonaws.com/0/75035/46a3c63b-2a12-f258-d440-a127e30f8f71.jpeg)
ちゃんとプロパティにもヘッダーがついてますね！

# まとめ
以上のように、VFWでは比較的簡単に、エディターGUIをカスタマイズするためのカスタム属性を追加できます。またもちろん、特定のオブジェクトや特定の型のフィールド用のカスタマイズもできます。
まだ勉強中で、全てご紹介はできませんが、色々可能性を秘めたフレームワークだと思います。

次はToolTipの代わりになるようなカスタム属性作ってみますかね。