UE4の勉強記録

UE4の勉強の記録です。個人用です。

新しいツールバーボタンを作る(リバースエンジニア編)Part 4

<前文>

f:id:kazuhironagai77:20180225113310p:plain

で勉強しています。

今回も、ツールバーボタンのコードを分析していきます。UE4CookbookEditorクラスの分析の続きをやります。

<本文>

<個々の検証の続き>

前回、やっとStartupModule()が終りました。今回で、全部終わりにしたいです。ShutdownModule関数から見てみましょう。

f:id:kazuhironagai77:20180311120541p:plain

教科書のHow it works…から見ていきます。

f:id:kazuhironagai77:20180311120654p:plain

54.我々のextensionの初期化に相対するのは、勿論、我々のモジュールがアンロードされた時、それをremoveする事です。それをするためには、我々は、我々のextensionをextenderからremoveすることです。そして、メモリーの割り当てを再利用するために、extenderとextensionの両方のshared pointerをnullにします。

また、拙速な訳で、申し訳ないですが、一応、訳も載せておきました。もう、UE4APIを見る必要はないと思います。それくらい完璧な説明です。Remove してResetする。メモリーの開放が必要なToolbarExtenderとExtensionオブジェクト変数の正しい開放の仕方をここで、説明しています。

  • ExtensionをToolbarExtenderからremoveします。
  • Extensionをresetします。
  • ToolbarExtenderをresetします。

以上です。

次に残りの2つの関数、デリゲートとして、StartupModule()でパスした、2つの関数を見ていこうと思います。

f:id:kazuhironagai77:20180311121021p:plain

まず、初めにMyButton_Clicked関数です。ここのコードは、Packet Publish社のサンプルコードの丸写しなのですが、教科書に載っているコードより、量が多いです。その部分が余計な部分かどうかまだわかりません。その部分をとりあえず、除いてみます。

f:id:kazuhironagai77:20180311121056p:plain

ビルトして実行すると、

f:id:kazuhironagai77:20180311121123p:plain

少し、変化しましたが、普通に動きます。教科書のサンプルコードの方を一行ずつ見ていきます。まず、教科書のHow it works…を見てみたら、何処にもこの関数の説明がありません。仕方がないので、UE4のAPIを見てみましょう。

f:id:kazuhironagai77:20180311121204p:plain

APIのremarksによると、

f:id:kazuhironagai77:20180311121227p:plain

SWindowはトップレベルのウインドウのプラットホーム非依存型の表現である。

とあります。まあ、ふーんという感じの説明です。

ここはmyButtonがクリックされた時に、表示するウインドウの指定をしていると思われますが、UE4でウインドウ表示するためには、こんな手順が必要だよ、というものがあるはずです。その手順の第一歩がSWindowクラスのオブジェクトを初期化する事だと考えられます。

f:id:kazuhironagai77:20180311121511p:plain

残りのプロパティの説明はAPIにはなかったです。ただ、間違いなく、ウインドウのサイズの指定でしょうね。ちょっと、変えてみましょう。

f:id:kazuhironagai77:20180311121551p:plain

結果は、まあ予想通りでした。

f:id:kazuhironagai77:20180311121639p:plain

次の行を見てみましょう。

f:id:kazuhironagai77:20180311121710p:plain

Remarks:メインフレームモジュールのためのインターフェイス

とだけ書かれています。メインフレームモジュールは何のために、必要なのでしょうか?まだわかりません。

次に、FModuleManagerのAPIを見てみましょう。

f:id:kazuhironagai77:20180311121739p:plain

Remarks:モジュールマネージャーを実装する。

そのモジュールマネージャーは、モジュールをロードしたりアンロードしたりするのに使用される。更に、全ての現在ロードされているモジュールの記録を付ける。このシングルトンはFModuleManager::Get()を使用することで、アクセス出来る。

とあります。さらに、FModuleManager::LoadModuleCheckedAPIによると、

f:id:kazuhironagai77:20180311121808p:plain

Remarks:名前からモジュールをロードします。それが存在するかチェックします。

このメソッドは、モジュールが実際に存在するかどうかチェックします。もし、そのモジュールが存在しなければ、表明(assertion)が引き起こされます。もし、モジュールがすでにロードされていたら、存在するインスタンスが返ります。

特定のタイプネームにキャストした、モジュールインターファイスが返ります。

このRemarksによると、我々は、MainFrameという名前のモジュールをロードするみたいです。

f:id:kazuhironagai77:20180311121911p:plain

GetParentWindow()のAPIによると、

f:id:kazuhironagai77:20180311122016p:plain

Remarks:このメインフレームがいるウインドウをゲットします。ウインドウウィジット

となっています。SWindowクラスのCookbookWindowオブジェクト変数が返ってくるのでしょうか?

とりあえず、次の行を見てみましょう。

f:id:kazuhironagai77:20180311122136p:plain

Get()はシングルトンの場合にオブジェクトを得る方法であるはずなので、ここではスキップします。次に、AddWindowAsNativeChildのAPIを見てみます。

f:id:kazuhironagai77:20180311122210p:plain

Remarks:トップレベルのSlateウインドウをネイティブなウインドウに関連づけます。そしてそのウインドウを特定のSlateウインドウのネイティブな親にします。しかしそのウインドウは、Slateのトップレベルのウインドウであっても、オペレーティングシステムには、子のウインドウとなります。

つまり、ここで、もしMainFrameModuleのParentWIndowがあるならば、SWIndowを変わりにセットしてくださいと言っているようです。そして、もしなければ、

f:id:kazuhironagai77:20180311122317p:plain

そして、AddWindow()のAPIでは、

f:id:kazuhironagai77:20180311122342p:plain

Remarks:トップレベルのslateのウインドウとネイティブのウインドウを関連づけます。そしてアプリケーションによって正しく記録されることを保証します。このメソッドを呼ぶことで、(別な事を指定しない限り)そのウインドウは表示されます。だから、最初にあなたがパスしているウインドウのオブジェクトをコンテンツに関連づけることを、確実にしてください。

となっています。つまり、ここで、SWindowクラスのオブジェクト変数であるCookbookWindowを、メインフレームのウインドウにセットしたのです。MainFrameModuleに元から、ウインドウがあろうがなかろうか、CookbookWindowを、メインフレームのウインドウになったのです。

ここで、何故、このようなやり方でやるのかを考えるより、こういうやり方がUE4では、正しいと決められていると考えるべきだと思います。

最後の関数であるAddToolbarExtension()を見てみましょう。

f:id:kazuhironagai77:20180311122520p:plain

FSlateIconクラスが使われています。APIによると、

f:id:kazuhironagai77:20180311122553p:plain

Remarks:Slateのアイコンを表現するために使用される構造体

となっています。やはりここで、アイコンを指定しているのです。つぎに、初期化のAPIを見てみましょう。まず、ツールチップでどのコンストラクターを使用したかを確認します。

f:id:kazuhironagai77:20180311122644p:plain

3つパラメーターがあるオーバーロードです。Visual Studioと同じかもしれないですが、そのAPIを見ると、

f:id:kazuhironagai77:20180311122723p:plain

<Parameter>

InStyleSetName: アイコンが見つけられるスタイルセットの名前

StyleName:そのアイコンのためのスタイルの名前

InSmallStyleName: その小さいアイコンのためのスタイルの名前

となっています。アイコンが見つけられるスタイルセットの名前を見ると、FEditorStyle::GetStyleSetName()となっていて、じっさいの名前が分からないので、Break pointを置いて中身を見てみると、

f:id:kazuhironagai77:20180311122820p:plain

EditorStyleという名前だと、分かりました。つまり、EditorStyleというスタイルセットがあり、その中に、LevelEditor.ViewOptionsと、LevelEditor.ViewOption.Smallがあるので、それをアイコンとして使用してくださいと指定していると考えられます。探して見ましょう。

f:id:kazuhironagai77:20180311122852p:plain

SlateEditorStyle.cppファイルに上記の表示を見つけました。さらに同じファイルの中に、

f:id:kazuhironagai77:20180311122940p:plain

と言う上記の表示も発見しました。おそらく、このファイルのスタイルセットの名前をEditorStyleと設定しているのでしょう。更に、icon_view_40xと言う名前をUE_Slotフォルダー内で検索したら、

f:id:kazuhironagai77:20180311123052p:plain

もうそのものズバリのイメージがありました。Iconフォルダー内にある.pngは、左端のイメージ だけなので、これを使用していると考えられます。

f:id:kazuhironagai77:20180311123137p:plain

次の行は、

f:id:kazuhironagai77:20180311123202p:plain

となっています。まず、BuilderのクラスであるFToolBarBuilderのAPIを見てみましょう。Remarkには

f:id:kazuhironagai77:20180311123227p:plain

Remarks:ツールバービルダー

とだけあります。そのメンバー関数であるAddToolBarButton()のAPIは、

f:id:kazuhironagai77:20180311123312p:plain

Remarks: ツールバーボタンを加える。

とあります。それぞれのパラメーターの説明は、

f:id:kazuhironagai77:20180311123356p:plain

f:id:kazuhironagai77:20180311123410p:plain

パラメーター

InCommand: コマンドをツールバーボタンに関連づけます。

InLabelOverride: オーバーライドするためのオプショナルなラベルです。もし、省略された場合は、アクションラベルが変わりに使用されます。

InToolOverride:  オーバーライドするためのオプショナルなツールチップです。もし、省略された場合は、アクションラベルが変わりに使用されます。

InIconOverride: ツールバーイメージのために使用されるSlate brushのオプショナルな名前です。もし、省略された場合は、アクションアイコンが変わりに使用されます。

InTutorialHighlightName: このウィジィトを確認するための名前です。チュートリアルの時は、ハイライトされます。

一番目のパラメーターは、コマンドなので、MyButtonをパスするのは、納得出来ます。2番目のパラメーターは、NAME_Noneになっているので、アクションラベルが変わりに使用されるのでしょうか?三番目のパラメーターは、ツールチップで表示される文章だそうです。

f:id:kazuhironagai77:20180311123527p:plain

カーソルをMyButtonに重ねてみると、確かに、"Click me to display a message"と表示されています。ちょっとこれをいたずらしてみる事にして、"Test Test Test !!!"と変えてみました。結果は、

f:id:kazuhironagai77:20180311123555p:plain

見事に変わりました。日本語は表示できるのでしょうか?試してみます。“あいうえお”と変えてみます。

f:id:kazuhironagai77:20180311123628p:plain

流石に日本語には、対応していませんでした。三番目のパラメーターは、Syntaxに書かれているようにFSlateIcon クラスのオブジェクト変数であるIconBrushです。最後のパラメーターは、NAME_Noneとなっています。

ここまでやって、教科書のHow it works…を読むのを忘れてました。AddToolbarExtension関数はたしか、説明があったはずです。

f:id:kazuhironagai77:20180311123659p:plain

55.EditorModuleクラス内にあるAddToolBarExtension関数は、実際に我々のコマンドを呼ぶツールバーにUIエレメントを加える事を担当します。

56.(AddToolBarExtension)関数のパラメーターとしてパスされるFToolBarBuilderのインスタンスの関数を呼ぶ事でこれを行います。

57.最初に、我々は、我々の新しいツールバーボタンのための適切なアイコンをFSlateIconのコンストラクターを使用して、引き出します。

58.ロードされたアイコンとともに、我々は、BuilderインスタンスのAddToolBarButtonを呼びます。

59.AddToolbarButtonは、沢山のパラメーターがあります。

60.最初のパラメーターは、バインドするためのコマンドです。アクションをコマンドにバインドした時に、我々が前にアクセスしたMyButtonメンバーと同じである事に、あなたは気が付くでしょう。

61.次のパラメーターは、我々が先に特定した拡張フックのためのオーバーライドです。しかし我々は、これをオーバーライドしたくないので、Name_Noneを使用します。

62.三番目のパラメーターは、我々が作った新しいボタンのために、オーバーライドしたラベルです。

63.四番目のパラメーターは、新しいボタンのツールチップです。

64.最後から2番目のパラメーターは、ボタンのアイコンです。最後のパラメーターは、もしあなたがインエディターのチュートリアルフレームワークを使用したいと思った時に、このボタン要素をハイライトするための参照に使われる名前です。

こっちの方がはるかに分かり易いです。小さい事ですがここで注意しておきたい事は、61で拡張フック(extension hook)という言葉が使われている事です。この言葉は、UE4APIに一度使われていた言い方でしたが、特別な意味はないと解釈して拡張点と同じと解釈して訳していましたが、もしかしたら特別に何かを示す名称なのかもしれません。

<まとめ>

とうとう、新しいツールバーボタンを作るの全部のサンプルコードの検証が終りました。最初に今回のまとめを行い、その後で全体のまとめを行います。

<今回のまとめ>

今回は、ShutdownModule関数、MyButton_Clicked関数、さらにAddToolbarExtension関数の検証を行いました。特に、難しい事はなかったと思います。予測通りに、ShutdownModule関数は、EditorModuleクラス内で使用されるオブジェクト変数のメモリーの開放が目的でしたし、MyButton_Clicked関数、さらにAddToolbarExtension関数でも、前回の予測通りに、デリゲートとして、機能や形状をStartupModule関数にパスするためのものでした。それぞれの関数での機能や形状の設定のやり方は、独特な方法にも見えますが、これはこうやるものだと考えるべきだと思います。そしてその方法の中で、形状や機能を変化させる方法を身につけるべきと考えます。

 

ShutdownModule関数:EditorModuleクラス内で使用されるオブジェクト変数のメモリーの開放を行う。

MyButton_Clicked関数:新しいツールボタンがクリックされた場合、表示するウィンドウの形状を指定する。ここでそれ以外の機能を指定する場合の方法は、まだ分からない。表示するウィンドウのサイズの変更方法は判明した。

AddToolbarExtension関数:新しいツールボタンのアイコンの形状や、ツール内での表示する場所を指定する。

 

<全体のまとめ>

この検証を始める前に仮説を立て、その後、検証に基づきその仮説を改良しました。

f:id:kazuhironagai77:20180311123851p:plain

この仮説が基本的には正しい事が、検証によって支持されていたと思います。それぞれのやり方は、ここで、紹介されているサンプルコードの手順が正しいと仮定し、それに従う事とします。

<おまけ>

私独自のツールボタンアイコンを表示したいと思い、試してみました。

f:id:kazuhironagai77:20180311123932p:plain

f:id:kazuhironagai77:20180311123955p:plain

期待したほど、劇的ではなかったですが、一応独自のアイコンを表示させる事が出来ました。