今回からイベントループに入っていきますが、SDL2 を使った GUI プログラミングに不慣れなので少しずつ見ていきます。
イベントループ部分
int main(int Argc, char* Args[]) { // 略 //Main loop flag bool bQuit = false; //Event handler SDL_Event Event; //Enable text input SDL_StartTextInput(); //While application is running while (!bQuit) { //Handle events on queue while (SDL_PollEvent(&Event) != 0) { bQuit = ProcessSDLEvents(&Event); } Main->Tick(); //Update screen SDL_GL_SwapWindow(Main->GetWindow()); } //Disable text input SDL_StopTextInput();
上記は main のイベントループ部分のみ抜粋したものです。
ProcessSDLEvents メソッドがイベントハンドルをしているようです。
ProcessSDLEvents
bool ProcessSDLEvents(SDL_Event *Event) { FUIEvent InputEvent = FInput::ProcessSDLEvent(*Event); if (InputEvent.GetType() != EUIEventType::None) { FGame::Get().GetMenu()->OnUIEvent(InputEvent); } else { switch (Event->type) { case SDL_QUIT: { return true; } case SDL_WINDOWEVENT: { ProcessWindowEvent(&Event->window); break; } default: break; } } return false; }
FInput::ProcessSDLEvent
ここでは、 SDL_Event を FUIEvent に変換しています。詳細は省略しますが、 FUIEvent は以下の種類があり、 SDL_Event の特定の操作イベントが割り当てられます。
enum class EUIEventType : unsigned char { None, MousePressed, MouseReleased, MouseWheelScrolled, KeyPressed, KeyReleased, TextInput, CopyText, SelectAll, PasteText, FullscreenToggle, SearchText, FocusGained, FocusLost, FriendInviteSent, InviteToSession, Last = FriendInviteSent };
else 部分
else 部分は QUIT か Window 操作時に関するものです。 QUIT の場合は true が返却され、イベントループを抜けるようになっています。
InputEvent が None 以外のとき
FGame::Get().GetMenu()->OnUIEvent(InputEvent) が呼び出されています。
前回見たとおりで FGame は多くのゲームの要素を管理しており、 GetMenu では FMenu のインスタンスを取得します。
FMenu::OnUIEvent
実際には親クラスである FBaseMenu::OnUIEvent が呼び出されます。
void FBaseMenu::OnUIEvent(const FUIEvent& Event) { #ifdef EOS_DEMO_SDL // FullScreenToggle に関するコードがあるが省略 else #endif if (Event.GetType() == EUIEventType::MousePressed) { for (DialogPtr NextDialog : Dialogs) { if (NextDialog->CheckCollision(Event.GetVector())) { NextDialog->OnUIEvent(Event); } else { NextDialog->SetFocused(false); } } } else { for (DialogPtr NextDialog : Dialogs) { NextDialog->OnUIEvent(Event); } } if (AuthDialogs) AuthDialogs->OnUIEvent(Event); }
Dialogs 配列の内部
FBaseMenu の内部では以下が Dialogs 配列に追加されています。
- ConsoleDialog
- FriendsDialog
- ExitDialog (非表示)
- PopupDialog (非表示)
また FMenu の内部では以下が追加されています。
- CustomInvitesDialog
CheckCollision
NextDialog->CheckCollision は Dialog::CheckCollision に実装されており、Dialog 内部の Widgets (UI 要素) の座標とマウスポイントの座標がオーバーラップしているかどうかを判定しています。
AuthDialogs
AuthDialogs は Dialogs 配列に入っていないことからも、少し特別な扱いになっています。
void FBaseMenu::CreateAuthDialogs() { AuthDialogs = std::make_shared<FAuthDialogs>( FriendsDialog, L"Friends", BoldSmallFont->GetFont(), SmallFont->GetFont(), TinyFont->GetFont()); AuthDialogs->Create(); }
AuthDialogs は生成時に FriendsDialog も受け取るようになっています。
void FBaseMenu::Create() { BackgroundImage->Create(); TitleLabel->Create(); TitleLabel->SetFont(BoldLargeFont->GetFont()); FPSLabel->Create(); FPSLabel->SetFont(SmallFont->GetFont()); CreateConsoleDialog(); CreateAuthDialogs(); CreateExitDialog(); CreatePopupDialog(); }
void FMenu::Create() { CreateFriendsDialog(); // creates console dialog, which is needed for creating custom invites dialog FBaseMenu::Create(); CreateCustomInvitesDialog(); }
上記のように、FriendsDialog だけは FMenu で生成され、その後 FBaseMenu で AuthDialog を含む他の Dialog が生成されています。
まとめ
今日はイベントループに入り、イベントをまず受け取っている FMenu の構成要素を眺めました。
次は FMenu の構成要素がどのように UI にセットされているかなど見てみたいと思います。