// Distributed under the MIT License (MIT) (see accompanying LICENSE file) #include "ImGuiPrivatePCH.h" #include "ImGuiModuleManager.h" #include "Utilities/WorldContext.h" #include "Utilities/WorldContextIndex.h" #if WITH_EDITOR #include "Editor/ImGuiEditor.h" #endif #include #define LOCTEXT_NAMESPACE "FImGuiModule" namespace CVars { extern TAutoConsoleVariable InputEnabled; extern TAutoConsoleVariable ShowDemo; } namespace Commands { const TCHAR* SwitchInputMode = TEXT("ImGui.SwitchInputMode"); } void SwitchImGuiInputMode() { FImGuiModule::Get().ToggleInputMode(); } FAutoConsoleCommand SwitchInputModeCommand = FAutoConsoleCommand( Commands::SwitchInputMode, TEXT("Changes ImGui input mode."), FConsoleCommandDelegate::CreateStatic(SwitchImGuiInputMode)); struct EDelegateCategory { enum { // Default per-context draw events. Default, // Multi-context draw event defined in context manager. MultiContext }; }; static FImGuiModuleManager* ImGuiModuleManager = nullptr; #if WITH_EDITOR static FImGuiEditor* ImGuiEditor = nullptr; #endif #if WITH_EDITOR FImGuiDelegateHandle FImGuiModule::AddEditorImGuiDelegate(const FImGuiDelegate& Delegate) { checkf(ImGuiModuleManager, TEXT("Null pointer to internal module implementation. Is module available?")); return { ImGuiModuleManager->GetContextManager().GetEditorContextProxy().OnDraw().Add(Delegate), EDelegateCategory::Default, Utilities::EDITOR_CONTEXT_INDEX }; } #endif FImGuiDelegateHandle FImGuiModule::AddWorldImGuiDelegate(const FImGuiDelegate& Delegate) { checkf(ImGuiModuleManager, TEXT("Null pointer to internal module implementation. Is module available?")); #if WITH_EDITOR checkf(GEngine, TEXT("Null GEngine. AddWorldImGuiDelegate should be only called with GEngine initialized.")); const FWorldContext* WorldContext = Utilities::GetWorldContext(GEngine->GameViewport); if (!WorldContext) { WorldContext = Utilities::GetWorldContextFromNetMode(ENetMode::NM_DedicatedServer); } checkf(WorldContext, TEXT("Couldn't find current world. AddWorldImGuiDelegate should be only called from a valid world.")); int32 Index; FImGuiContextProxy& Proxy = ImGuiModuleManager->GetContextManager().GetWorldContextProxy(*WorldContext->World(), Index); #else const int32 Index = Utilities::STANDALONE_GAME_CONTEXT_INDEX; FImGuiContextProxy& Proxy = ImGuiModuleManager->GetContextManager().GetWorldContextProxy(); #endif return{ Proxy.OnDraw().Add(Delegate), EDelegateCategory::Default, Index }; } FImGuiDelegateHandle FImGuiModule::AddMultiContextImGuiDelegate(const FImGuiDelegate& Delegate) { checkf(ImGuiModuleManager, TEXT("Null pointer to internal module implementation. Is module available?")); return { ImGuiModuleManager->GetContextManager().OnDrawMultiContext().Add(Delegate), EDelegateCategory::MultiContext }; } void FImGuiModule::RemoveImGuiDelegate(const FImGuiDelegateHandle& Handle) { if (ImGuiModuleManager) { if (Handle.Category == EDelegateCategory::MultiContext) { ImGuiModuleManager->GetContextManager().OnDrawMultiContext().Remove(Handle.Handle); } else if (auto* Proxy = ImGuiModuleManager->GetContextManager().GetContextProxy(Handle.Index)) { Proxy->OnDraw().Remove(Handle.Handle); } } } void FImGuiModule::StartupModule() { // Create managers that implements module logic. checkf(!ImGuiModuleManager, TEXT("Instance of the ImGui Module Manager already exists. Instance should be created only during module startup.")); ImGuiModuleManager = new FImGuiModuleManager(); #if WITH_EDITOR checkf(!ImGuiEditor, TEXT("Instance of the ImGui Editor already exists. Instance should be created only during module startup.")); ImGuiEditor = new FImGuiEditor(); #endif } void FImGuiModule::ShutdownModule() { // Before we shutdown we need to delete managers that will do all the necessary cleanup. #if WITH_EDITOR checkf(ImGuiEditor, TEXT("Null ImGui Editor. ImGui editor instance should be deleted during module shutdown.")); delete ImGuiEditor; ImGuiEditor = nullptr; #endif checkf(ImGuiModuleManager, TEXT("Null ImGui Module Manager. Module manager instance should be deleted during module shutdown.")); delete ImGuiModuleManager; ImGuiModuleManager = nullptr; } bool FImGuiModule::IsInputMode() const { return CVars::InputEnabled.GetValueOnAnyThread() > 0; } void FImGuiModule::SetInputMode(bool bEnabled) { // This function is for supporting shortcut or subsitiute for console command, so we are using the same priority. CVars::InputEnabled->Set(bEnabled ? 1 : 0, ECVF_SetByConsole); } void FImGuiModule::ToggleInputMode() { SetInputMode(!IsInputMode()); } bool FImGuiModule::IsShowingDemo() const { return CVars::ShowDemo.GetValueOnAnyThread() > 0; } void FImGuiModule::SetShowDemo(bool bShow) { // This function is for supporting shortcut or subsitiute for console command, so we are using the same priority. CVars::ShowDemo->Set(bShow ? 1 : 0, ECVF_SetByConsole); } void FImGuiModule::ToggleShowDemo() { SetShowDemo(!IsShowingDemo()); } #undef LOCTEXT_NAMESPACE IMPLEMENT_MODULE(FImGuiModule, ImGui)