├── .gitignore ├── Source ├── UEImgui │ ├── Private │ │ ├── Logging.cpp │ │ ├── Logging.h │ │ ├── Render │ │ │ ├── ImguiShader.cpp │ │ │ ├── ImguiDrawer.h │ │ │ ├── ImguiShader.h │ │ │ └── ImguiDrawer.cpp │ │ ├── Extension │ │ │ ├── UEImguiSceneOutline.cpp │ │ │ └── UEImguiDetail.cpp │ │ ├── UEImguiModule.cpp │ │ ├── Services │ │ │ ├── ImguiPerInstanceCtx.h │ │ │ ├── ImguiPerInstanceCtx.cpp │ │ │ └── ImguiGlobalContextService.cpp │ │ ├── Window │ │ │ ├── ImguiWindowWrapper.h │ │ │ └── ImguiWindowWrapper.cpp │ │ ├── ImguiWrap │ │ │ ├── ImguiGlobalInputHook.h │ │ │ ├── ImguiTextInputSystem.h │ │ │ ├── ImguiTextInputSystem.cpp │ │ │ ├── ImguiInputAdapterDeferred.cpp │ │ │ ├── ImguiGlobalInputHook.cpp │ │ │ ├── ImguiResourceManager.cpp │ │ │ └── ImguiInputAdapter.cpp │ │ ├── Widgets │ │ │ ├── SImguiWindow.h │ │ │ ├── SImguiWindow.cpp │ │ │ └── SImguiWidget.cpp │ │ └── Config │ │ │ └── ImguiConfig.cpp │ ├── Public │ │ ├── Lua │ │ │ └── imgui_lua_binding.h │ │ ├── Extension │ │ │ ├── UEImguiDetail.h │ │ │ ├── UEImguiSceneOutline.h │ │ │ └── SmallWidgets.h │ │ ├── ImguiWrap │ │ │ ├── ImguiInputAdapterDeferred.h │ │ │ ├── ImguiResourceManager.h │ │ │ ├── ImguiInputAdapter.h │ │ │ ├── ImguiUEWrap.h │ │ │ └── ImguiContext.h │ │ ├── Window │ │ │ └── IImguiViewport.h │ │ ├── Services │ │ │ ├── ImguiDetailCustomization.h │ │ │ └── ImguiGlobalContextService.h │ │ ├── Config │ │ │ └── ImguiConfig.h │ │ └── Widgets │ │ │ └── SImguiWidget.h │ └── UEImgui.Build.cs ├── UEImguiEditor │ ├── Private │ │ ├── Logging.cpp │ │ ├── Logging.h │ │ ├── Service │ │ │ ├── ImguiCustomDetailService.h │ │ │ └── ImguiCustomDetailService.cpp │ │ ├── Customize │ │ │ ├── ImguiDetailCustomization.h │ │ │ └── ImguiDetailCustomization.cpp │ │ └── UEImguiEditor.cpp │ ├── Public │ │ └── UEImguiEditor.h │ └── UEImguiEditor.Build.cs └── ThirdParty │ ├── ImPlot │ ├── ImPlotLibrary.tps │ ├── Private │ │ └── ImPlotModule.cpp │ ├── ImPlot.Build.cs │ ├── LICENSE │ └── README.md │ └── Imgui │ ├── ImGuiLibrary.tps │ ├── Private │ └── ImguiModule.cpp │ ├── Imgui.Build.cs │ ├── LICENSE.txt │ ├── Docs │ └── BACKENDS.md │ └── Public │ └── imconfig.h ├── README.md ├── Resources ├── Icon128.png ├── Icon500.png └── UEImgui.png ├── Shaders └── Private │ └── ImguiShader.usf ├── UEImgui.uplugin ├── LICENSE └── Examples ├── Example.h └── Example.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | Binaries/ 2 | Intermediate/ 3 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Logging.cpp: -------------------------------------------------------------------------------- 1 | #include "Logging.h" 2 | 3 | DEFINE_LOG_CATEGORY(LogUEImgui); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UEImgui 2 | 3 | 在UE4中使用Imgui 4 | 5 | ![UEImgui](./Resources/UEImgui.png) 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhuRong-HomoStation/UEImgui/HEAD/Resources/Icon128.png -------------------------------------------------------------------------------- /Resources/Icon500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhuRong-HomoStation/UEImgui/HEAD/Resources/Icon500.png -------------------------------------------------------------------------------- /Resources/UEImgui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhuRong-HomoStation/UEImgui/HEAD/Resources/UEImgui.png -------------------------------------------------------------------------------- /Source/UEImgui/Private/Logging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | 4 | DECLARE_LOG_CATEGORY_EXTERN(LogUEImgui, Log, All); -------------------------------------------------------------------------------- /Source/UEImgui/Public/Lua/imgui_lua_binding.h: -------------------------------------------------------------------------------- 1 | namespace slua 2 | { 3 | struct lua_State; 4 | } 5 | 6 | void UEIMGUI_API LoadImguiBindings(slua::lua_State* lState); -------------------------------------------------------------------------------- /Source/UEImguiEditor/Private/Logging.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #include "Logging.h" 4 | 5 | DEFINE_LOG_CATEGORY(UEImguiEditor); -------------------------------------------------------------------------------- /Source/UEImguiEditor/Private/Logging.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | DECLARE_LOG_CATEGORY_EXTERN(UEImguiEditor, Log, All); -------------------------------------------------------------------------------- /Source/UEImgui/Private/Render/ImguiShader.cpp: -------------------------------------------------------------------------------- 1 | #include "ImguiShader.h" 2 | 3 | IMPLEMENT_SHADER_TYPE(, FImguiShaderVs, TEXT("/Plugin/UEImgui/Private/ImguiShader.usf"), TEXT("ImguiShader_VS"), SF_Vertex); 4 | IMPLEMENT_SHADER_TYPE(, FImguiShaderPs, TEXT("/Plugin/UEImgui/Private/ImguiShader.usf"), TEXT("ImguiShader_PS"), SF_Pixel); -------------------------------------------------------------------------------- /Source/UEImgui/Public/Extension/UEImguiDetail.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class FUEImguiDetail 4 | { 5 | public: 6 | FUEImguiDetail(); 7 | bool MakeDetail(UScriptStruct* InStruct, void* InValue); 8 | bool MakeDetail(UClass* InClass, void* InValue); 9 | bool MakeDetail(FProperty* InProperty, void* InContainer); 10 | private: 11 | uint32 DetailDepth; 12 | }; 13 | 14 | 15 | -------------------------------------------------------------------------------- /Source/ThirdParty/ImPlot/ImPlotLibrary.tps: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ImPlot source files re-packaged to be included in Unreal Engine. Original Omar Cornut's repository can be found at https://github.com/epezent/implot. 5 | 6 | 7 | -------------------------------------------------------------------------------- /Source/ThirdParty/Imgui/ImGuiLibrary.tps: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dear ImGui source files re-packaged to be included in Unreal Engine. Original Omar Cornut's repository can be found at https://github.com/ocornut/imgui. 5 | 6 | 7 | -------------------------------------------------------------------------------- /Source/ThirdParty/Imgui/Private/ImguiModule.cpp: -------------------------------------------------------------------------------- 1 | #include "CoreMinimal.h" 2 | #include "Modules/ModuleManager.h" 3 | 4 | class IMGUI_API FImguiModule : public IModuleInterface 5 | { 6 | public: 7 | // ~Begin IModuleInterface API 8 | virtual void StartupModule() override {} 9 | virtual void ShutdownModule() override {} 10 | // ~End IModuleInterface API 11 | }; 12 | 13 | IMPLEMENT_MODULE(FImguiModule, Imgui) -------------------------------------------------------------------------------- /Source/ThirdParty/ImPlot/Private/ImPlotModule.cpp: -------------------------------------------------------------------------------- 1 | #include "CoreMinimal.h" 2 | #include "Modules/ModuleManager.h" 3 | #include "Modules/ModuleManager.h" 4 | 5 | #define LOCTEXT_NAMESPACE "FImPlot" 6 | 7 | class FImPlot : public IModuleInterface 8 | { 9 | public: 10 | void StartupModule() override 11 | { 12 | 13 | } 14 | void ShutdownModule() override 15 | { 16 | 17 | } 18 | }; 19 | 20 | #undef LOCTEXT_NAMESPACE 21 | 22 | IMPLEMENT_MODULE(FImPlot, ImPlot); -------------------------------------------------------------------------------- /Source/UEImgui/Private/Extension/UEImguiSceneOutline.cpp: -------------------------------------------------------------------------------- 1 | #include "Extension/UEImguiSceneOutline.h" 2 | 3 | FUEImguiSceneOutline::FUEImguiSceneOutline(UObject* InWorldContext) 4 | { 5 | // FWorldDelegates::LevelAddedToWorld; 6 | // FWorldDelegates::LevelRemovedFromWorld; 7 | // GWorld->AddOnActorSpawnedHandler(); 8 | // Destroyed 9 | } 10 | 11 | FUEImguiSceneOutline::~FUEImguiSceneOutline() 12 | { 13 | // FWorldDelegates::LevelAddedToWorld; 14 | // FWorldDelegates::LevelRemovedFromWorld; 15 | // GWorld->RemoveOnActorSpawnedHandler(); 16 | } 17 | -------------------------------------------------------------------------------- /Source/UEImguiEditor/Public/UEImguiEditor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "Modules/ModuleManager.h" 4 | 5 | struct ImPlotContext; 6 | 7 | class FUEImguiEditor : public IModuleInterface 8 | { 9 | public: 10 | // ~Begin IModuleInterface API 11 | void StartupModule() override; 12 | void ShutdownModule() override; 13 | // ~End IModuleInterface API 14 | 15 | private: 16 | void _InitDetailExtension(); 17 | void _ShutDownDetailExtension(); 18 | 19 | void _InitMenu(); 20 | void _ShutDownMenu(); 21 | 22 | void _ExtendMenu(FMenuBuilder& InBuilder); 23 | private: 24 | ImPlotContext* ImPlotCtx; 25 | }; 26 | -------------------------------------------------------------------------------- /Source/ThirdParty/ImPlot/ImPlot.Build.cs: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | using System.IO; 4 | using UnrealBuildTool; 5 | 6 | public class ImPlot : ModuleRules 7 | { 8 | public ImPlot(ReadOnlyTargetRules Target) : base(Target) 9 | { 10 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 11 | 12 | UnsafeTypeCastWarningLevel = WarningLevel.Off; 13 | 14 | PublicIncludePaths.AddRange( 15 | new string[] 16 | { 17 | Path.Combine(ModuleDirectory, "Public") 18 | }); 19 | 20 | PublicDependencyModuleNames.AddRange( 21 | new string[] 22 | { 23 | "Core" , 24 | "Imgui" , 25 | }); 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/ThirdParty/Imgui/Imgui.Build.cs: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | using System.IO; 4 | using UnrealBuildTool; 5 | 6 | public class Imgui : ModuleRules 7 | { 8 | public Imgui(ReadOnlyTargetRules Target) : base(Target) 9 | { 10 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 11 | 12 | PublicIncludePaths.AddRange( 13 | new string[] 14 | { 15 | Path.Combine(ModuleDirectory, "Public") 16 | }); 17 | 18 | PrivateDependencyModuleNames.AddRange( 19 | new string[] 20 | { 21 | "Core", 22 | }); 23 | 24 | PublicDefinitions.Add("IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); 25 | PublicDefinitions.Add("IMGUI_DEFINE_MATH_OPERATORS"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/UEImgui/Public/Extension/UEImguiSceneOutline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | DECLARE_DELEGATE_RetVal_OneParam(bool, FActorFilter, AActor*); 4 | 5 | struct FUEImguiSceneNode 6 | { 7 | AActor* Actor; 8 | bool bCulled; 9 | bool bDisabled; 10 | }; 11 | 12 | class FUEImguiSceneOutline 13 | { 14 | FUEImguiSceneOutline(UObject* InWorldContext = GWorld); 15 | ~FUEImguiSceneOutline(); 16 | 17 | public: 18 | // States 19 | FActorFilter Filter; 20 | TArray SceneNodes; 21 | TArray Entries; 22 | TArray SelectedActors; 23 | bool bNeedToUpdate; 24 | 25 | // Bound info 26 | TWeakObjectPtr BoundWorld; 27 | FDelegateHandle LevelAddedHandle; 28 | FDelegateHandle LevelRemovedHandle; 29 | FDelegateHandle ActorSpawnHandle; 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /Source/UEImguiEditor/UEImguiEditor.Build.cs: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | using System.IO; 4 | using UnrealBuildTool; 5 | 6 | public class UEImguiEditor : ModuleRules 7 | { 8 | public UEImguiEditor(ReadOnlyTargetRules Target) : base(Target) 9 | { 10 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 11 | 12 | PublicDependencyModuleNames.AddRange( 13 | new string[] 14 | { 15 | "Core", 16 | "Imgui", 17 | "UEImgui", 18 | "ImPlot", 19 | }); 20 | 21 | 22 | PrivateDependencyModuleNames.AddRange( 23 | new string[] 24 | { 25 | "Core", 26 | "CoreUObject", 27 | "Engine", 28 | "Slate", 29 | "SlateCore", 30 | "LevelEditor", 31 | "EditorSubsystem", 32 | "UnrealEd", 33 | "ImPlot", 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/UEImguiModule.cpp: -------------------------------------------------------------------------------- 1 | #include "Interfaces/IPluginManager.h" 2 | #include "CoreMinimal.h" 3 | #include "Modules/ModuleManager.h" 4 | #include "Services/ImguiGlobalContextService.h" 5 | 6 | #define LOCTEXT_NAMESPACE "FUEImguiModule" 7 | 8 | class UEIMGUI_API FUEImguiModule : public IModuleInterface 9 | { 10 | public: 11 | // ~Begin IModuleInterface API 12 | virtual void StartupModule() override 13 | { 14 | // register shader dictionary 15 | FString ShaderDir = FPaths::Combine(IPluginManager::Get().FindPlugin(TEXT("UEImgui"))->GetBaseDir(),TEXT("Shaders")); 16 | AddShaderSourceDirectoryMapping(TEXT("/Plugin/UEImgui"), ShaderDir); 17 | } 18 | virtual void ShutdownModule() override 19 | { 20 | 21 | } 22 | // ~End IModuleInterface API 23 | }; 24 | 25 | #undef LOCTEXT_NAMESPACE 26 | 27 | IMPLEMENT_MODULE(FUEImguiModule, UEImgui) -------------------------------------------------------------------------------- /Source/UEImguiEditor/Private/Service/ImguiCustomDetailService.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Editor.h" 3 | #include "EditorSubsystem.h" 4 | #include "Services/ImguiDetailCustomization.h" 5 | 6 | #include "ImguiCustomDetailService.generated.h" 7 | 8 | USTRUCT() 9 | struct FImguiDummy 10 | { 11 | GENERATED_BODY() 12 | 13 | }; 14 | 15 | UCLASS() 16 | class UImguiCustomDetailService : public UEditorSubsystem 17 | { 18 | GENERATED_BODY() 19 | public: 20 | static UImguiCustomDetailService& Get() { return *GEditor->GetEditorSubsystem(); } 21 | 22 | TArray GetAllDetailCustomizationOfClass(UClass* InClass); 23 | protected: 24 | // ~Begin USubsystem API 25 | virtual void Initialize(FSubsystemCollectionBase& Collection) override; 26 | virtual void Deinitialize() override; 27 | // ~End USubsystem API 28 | 29 | public: 30 | UPROPERTY() 31 | TArray AllDetailCustomization; 32 | }; 33 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Services/ImguiPerInstanceCtx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ImguiWrap/ImguiContext.h" 3 | #include "ImguiWrap/ImguiInputAdapterDeferred.h" 4 | #include "ImguiPerInstanceCtx.generated.h" 5 | 6 | UCLASS() 7 | class UImguiPerInstanceCtx : public UGameInstanceSubsystem 8 | { 9 | GENERATED_BODY() 10 | public: 11 | UImguiContext* GetGlobalContext() const { return GlobalContext; } 12 | UImguiInputAdapterDeferred* GetGlobalInputAdapter() const { return InputAdapter; } 13 | protected: 14 | // ~Begin UGameInstanceSubsystem API 15 | virtual void Initialize(FSubsystemCollectionBase& Collection) override; 16 | virtual void Deinitialize() override; 17 | // ~End UGameInstanceSubsystem API 18 | void Tick(float DeltaTime); 19 | 20 | virtual void BeginDestroy() override; 21 | private: 22 | UPROPERTY() 23 | UImguiContext* GlobalContext; 24 | 25 | UPROPERTY() 26 | UImguiInputAdapterDeferred* InputAdapter; 27 | 28 | FDelegateHandle PreSlateTick; 29 | }; 30 | -------------------------------------------------------------------------------- /Source/UEImguiEditor/Private/Customize/ImguiDetailCustomization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IDetailCustomization.h" 3 | 4 | class FImguiDetailCustomization : public IPropertyTypeCustomization 5 | { 6 | public: 7 | static TSharedRef MakeInstance(); 8 | 9 | protected: 10 | // Begin IDetailCustomization API 11 | virtual void CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils ) override; 12 | virtual void CustomizeChildren(TSharedRef PropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& CustomizationUtils ) override; 13 | // End IDetailCustomization API 14 | 15 | private: 16 | void _DrawMultObj(FName DetailName, const TArray& InObjs, IDetailChildrenBuilder& ChildBuilder, UClass* LowestClass); 17 | void _DrawSingleObj(FName DetailName, const TArray& InObjs, IDetailChildrenBuilder& ChildBuilder); 18 | }; 19 | -------------------------------------------------------------------------------- /Source/UEImguiEditor/Private/Service/ImguiCustomDetailService.cpp: -------------------------------------------------------------------------------- 1 | #include "ImguiCustomDetailService.h" 2 | #include "GenericPlatform/ITextInputMethodSystem.h" 3 | #include "Services/ImguiDetailCustomization.h" 4 | 5 | TArray UImguiCustomDetailService::GetAllDetailCustomizationOfClass(UClass* InClass) 6 | { 7 | TArray AllCustomization; 8 | for (UClass* Class : AllDetailCustomization) 9 | { 10 | UImguiDetailCustomization* CDO = (UImguiDetailCustomization*)Class->GetDefaultObject(true); 11 | if (InClass->IsChildOf(CDO->GetSupportClass()) || CDO->IsSupportClass(InClass)) 12 | { 13 | AllCustomization.Add(CDO); 14 | } 15 | } 16 | return AllCustomization; 17 | } 18 | 19 | void UImguiCustomDetailService::Initialize(FSubsystemCollectionBase& Collection) 20 | { 21 | GetDerivedClasses(UImguiDetailCustomization::StaticClass(), AllDetailCustomization); 22 | } 23 | 24 | void UImguiCustomDetailService::Deinitialize() 25 | { 26 | } 27 | -------------------------------------------------------------------------------- /Shaders/Private/ImguiShader.usf: -------------------------------------------------------------------------------- 1 | #include "/Engine/Public/Platform.ush" 2 | 3 | Texture2D InTexture; 4 | SamplerState InTextureSampler; 5 | float4x4 InTransform; 6 | int InHasTexture; 7 | 8 | struct InputVS 9 | { 10 | float2 Position : ATTRIBUTE0; 11 | float2 UV : ATTRIBUTE1; 12 | float4 Color : ATTRIBUTE2; 13 | }; 14 | 15 | struct OutputVS 16 | { 17 | float4 Position : SV_POSITION; 18 | float2 UV : TEXCOORD0; 19 | float4 Color : TEXCOORD1; 20 | }; 21 | 22 | struct OutputPS 23 | { 24 | float4 Color : SV_Target0; 25 | }; 26 | 27 | OutputVS ImguiShader_VS(InputVS In) 28 | { 29 | OutputVS Out; 30 | 31 | Out.Position = mul(float4(In.Position, 0, 1), InTransform); 32 | Out.UV = In.UV; 33 | Out.Color = In.Color; 34 | 35 | return Out; 36 | } 37 | 38 | OutputPS ImguiShader_PS(OutputVS In) 39 | { 40 | OutputPS Out; 41 | 42 | if (InHasTexture) 43 | { 44 | Out.Color = In.Color * InTexture.Sample(InTextureSampler, In.UV); 45 | } 46 | else 47 | { 48 | Out.Color = In.Color; 49 | } 50 | 51 | return Out; 52 | } -------------------------------------------------------------------------------- /UEImgui.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "1.0", 5 | "FriendlyName": "UEImgui", 6 | "Description": "use imgui in unreal engine", 7 | "Category": "Other", 8 | "CreatedBy": "ZhuRong", 9 | "CreatedByURL": "https://github.com/ZhuRong-HomoStation/UEImgui", 10 | "DocsURL": "", 11 | "MarketplaceURL": "", 12 | "SupportURL": "", 13 | "CanContainContent": false, 14 | "IsBetaVersion": true, 15 | "IsExperimentalVersion": false, 16 | "Installed": false, 17 | "Modules": [ 18 | { 19 | "Name": "Imgui", 20 | "Type": "Runtime", 21 | "LoadingPhase": "Default" 22 | }, 23 | { 24 | "Name": "UEImgui", 25 | "Type": "Runtime", 26 | "LoadingPhase": "PostConfigInit" 27 | }, 28 | { 29 | "Name": "UEImguiEditor", 30 | "Type": "Editor", 31 | "LoadingPhase": "Default" 32 | }, 33 | { 34 | "Name": "ImPlot", 35 | "Type": "Runtime", 36 | "LoadingPhase": "Default" 37 | } 38 | ], 39 | "Plugins": [ 40 | { 41 | "Name": "slua_unreal", 42 | "Enabled": false 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 zhurongjun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Source/ThirdParty/ImPlot/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Evan Pezent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Source/UEImgui/UEImgui.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class UEImgui : ModuleRules 6 | { 7 | public UEImgui(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicDependencyModuleNames.AddRange( 12 | new string[] 13 | { 14 | "Core", 15 | "Imgui" , 16 | }); 17 | 18 | 19 | PrivateDependencyModuleNames.AddRange( 20 | new string[] 21 | { 22 | #if UE_4_26_OR_LATER 23 | "DeveloperSettings", 24 | #endif 25 | "CoreUObject", 26 | "Engine", 27 | "Slate", 28 | "SlateCore", 29 | "InputCore", 30 | "ApplicationCore" , 31 | "Projects" , 32 | "RenderCore" , 33 | "RHI" , 34 | }); 35 | 36 | if (Target.Type == TargetType.Editor) 37 | { 38 | PrivateDependencyModuleNames.AddRange( 39 | new string[] 40 | { 41 | "MainFrame" , 42 | "LevelEditor" , 43 | "UnrealEd" , 44 | }); 45 | } 46 | 47 | // Enable if use SLua 48 | // PrivateDefinitions.Add("ENABLE_LUA_BINDING"); 49 | // PrivateDependencyModuleNames.Add("slua_unreal"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Source/ThirdParty/Imgui/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2021 Omar Cornut 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Window/ImguiWindowWrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "imgui.h" 4 | 5 | class UImguiContext; 6 | class UImguiInputAdapter; 7 | 8 | struct FImguiWindowWrapper 9 | { 10 | public: 11 | static void SetupPlatformInterface(ImGuiPlatformIO* PlatformIO); 12 | private: 13 | static void UE_CreateWindow(ImGuiViewport* viewport); 14 | static void UE_DestroyWindow(ImGuiViewport* viewport); 15 | static void UE_ShowWindow(ImGuiViewport* viewport); 16 | static void UE_UpdateWindow(ImGuiViewport* viewport); 17 | static ImVec2 UE_GetWindowPos(ImGuiViewport* viewport); 18 | static void UE_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos); 19 | static ImVec2 UE_GetWindowSize(ImGuiViewport* viewport); 20 | static void UE_SetWindowSize(ImGuiViewport* viewport, ImVec2 size); 21 | static void UE_SetWindowFocus(ImGuiViewport* viewport); 22 | static bool UE_GetWindowFocus(ImGuiViewport* viewport); 23 | static bool UE_GetWindowMinimized(ImGuiViewport* viewport); 24 | static void UE_SetWindowTitle(ImGuiViewport* viewport, const char* title); 25 | static void UE_SetWindowAlpha(ImGuiViewport* viewport, float alpha); 26 | static float UE_GetWindowDpiScale(ImGuiViewport* viewport); 27 | static void UE_OnChangedViewport(ImGuiViewport* viewport); 28 | static void UE_SetImeInputPos(ImGuiViewport* viewport, ImVec2 pos); 29 | public: 30 | static UImguiContext* CurContext; 31 | static UImguiInputAdapter* CurInputAdapter; 32 | }; 33 | -------------------------------------------------------------------------------- /Source/UEImgui/Public/ImguiWrap/ImguiInputAdapterDeferred.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "imgui.h" 4 | #include "ImguiInputAdapter.h" 5 | #include "ImguiInputAdapterDeferred.generated.h" 6 | 7 | UCLASS(CustomConstructor) 8 | class UEIMGUI_API UImguiInputAdapterDeferred : public UImguiInputAdapter 9 | { 10 | GENERATED_BODY() 11 | public: 12 | UImguiInputAdapterDeferred(const FObjectInitializer& InInitializer); 13 | 14 | // ~Begin UImguiInputAdapter API 15 | virtual void AddInputCharacter(TCHAR InChar) override; 16 | virtual void SetKeyState(uint32 InKeyNum, bool InState) override; 17 | virtual void SetCtrl(bool InState) override; 18 | virtual void SetAlt(bool InState) override; 19 | virtual void SetShift(bool InState) override; 20 | 21 | virtual void SetMouseBtnState(uint32 MouseBtnIndex, bool InState) override; 22 | virtual void SetMouseWheel(float InMouseWheel) override; 23 | virtual void SetMousePos(FVector2D InMousePos) override; 24 | 25 | virtual FCursorReply OnCursorQuery(const FPointerEvent& CursorEvent); 26 | // ~End UImguiInputAdapter API 27 | 28 | void ApplyInput(); 29 | void SaveTempData(); 30 | 31 | private: 32 | // Key chars 33 | ImVector InputQueueCharacters; 34 | 35 | // Modifier key 36 | bool KeyCtrl; 37 | bool KeyShift; 38 | bool KeyAlt; 39 | 40 | // Key downs 41 | bool KeysDown[512]; 42 | 43 | // Mouse downs 44 | bool MouseDown[5]; 45 | 46 | // Mouse wheel 47 | float MouseWheel; 48 | 49 | // Mouse pos 50 | ImVec2 MousePos; 51 | 52 | // Mouse cursor 53 | ImGuiMouseCursor Cursor; 54 | }; 55 | 56 | 57 | -------------------------------------------------------------------------------- /Source/UEImgui/Public/ImguiWrap/ImguiResourceManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "imgui.h" 4 | #include "ImguiResourceManager.generated.h" 5 | 6 | class UImguiContext; 7 | struct ImFontAtlas; 8 | 9 | enum class EGlobalImguiTextureId 10 | { 11 | DefaultFont = -1, 12 | }; 13 | 14 | USTRUCT() 15 | struct UEIMGUI_API FImguiResource 16 | { 17 | GENERATED_BODY() 18 | public: 19 | FImguiResource() = default; 20 | FImguiResource(const FName& InName, UTexture* SourceObject); 21 | 22 | UPROPERTY() 23 | FName Name; 24 | UPROPERTY() 25 | UTexture* Source; 26 | }; 27 | 28 | /** 29 | * @brief mange global imgui texture(for all context) 30 | */ 31 | UCLASS() 32 | class UEIMGUI_API UImguiResourceManager : public UObject 33 | { 34 | GENERATED_BODY() 35 | public: 36 | UImguiResourceManager(); 37 | static UImguiResourceManager& Get(); 38 | 39 | // Resource action 40 | ImTextureID AddResource(FName InResName, UTexture* SourceObj); 41 | bool IsResourceExist(FName InResName); 42 | bool IsResourceExist(ImTextureID InID); 43 | FImguiResource* FindResource(FName InResName); 44 | FImguiResource* FindResource(ImTextureID InResId); 45 | void ReleaseResource(FName InResName); 46 | void ReleaseResource(ImTextureID InID); 47 | 48 | // Default font 49 | ImFontAtlas* GetDefaultFont() const { return DefaultFont; } 50 | protected: 51 | // ~Begin UObject API 52 | virtual void BeginDestroy() override; 53 | // ~End UObject API 54 | private: 55 | // Font 56 | void _InitDefaultFont(); 57 | void _ShutDownDefaultFont(); 58 | private: 59 | UPROPERTY() 60 | TMap AllResource; 61 | TMap NamedResourceMap; 62 | int32 CurrentResIdx; 63 | 64 | ImFontAtlas* DefaultFont; 65 | }; 66 | 67 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/ImguiWrap/ImguiGlobalInputHook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "Framework/Application/IInputProcessor.h" 4 | 5 | class UImguiInputAdapter; 6 | 7 | // hook global input when we need 8 | class FImguiGlobalInputHook : public IInputProcessor, public FGCObject 9 | { 10 | public: 11 | static TSharedPtr Get(); 12 | 13 | void AddAdapter(UImguiInputAdapter* InInputAdapter); 14 | void RemoveAdapter(UImguiInputAdapter* InInputAdapter); 15 | protected: 16 | // ~Begin IInputProcessor API 17 | virtual void Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef Cursor) override; 18 | virtual bool HandleKeyDownEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent) override; 19 | virtual bool HandleKeyUpEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent) override; 20 | virtual bool HandleAnalogInputEvent(FSlateApplication& SlateApp, const FAnalogInputEvent& InAnalogInputEvent) override; 21 | virtual bool HandleMouseMoveEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) override; 22 | virtual bool HandleMouseButtonDownEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) override; 23 | virtual bool HandleMouseButtonUpEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) override; 24 | virtual bool HandleMouseButtonDoubleClickEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) override; 25 | virtual bool HandleMouseWheelOrGestureEvent(FSlateApplication& SlateApp, const FPointerEvent& InWheelEvent, const FPointerEvent* InGestureEvent) override; 26 | virtual bool HandleMotionDetectedEvent(FSlateApplication& SlateApp, const FMotionEvent& MotionEvent) override; 27 | // ~End IInputProcessor API 28 | 29 | // ~Begin FGCObject API 30 | virtual void AddReferencedObjects(FReferenceCollector& Collector) override; 31 | // ~End FGCObject API 32 | private: 33 | TArray TargetAdapters; 34 | }; 35 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Render/ImguiDrawer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Rendering/RenderingCommon.h" 3 | #include "imgui.h" 4 | 5 | class FImguiDrawer : public ICustomSlateElement 6 | { 7 | public: 8 | struct DrawElement 9 | { 10 | ImTextureID TextureID; 11 | uint32 VtxOffset; 12 | uint32 IdxOffset; 13 | uint32 NumIndices; 14 | FSlateRect ScissorRect; 15 | }; 16 | public: 17 | ~FImguiDrawer(); 18 | void SetDrawData(ImDrawData* InDrawData); 19 | void SetDrawData(const TArray& InDrawData); 20 | void SetDrawData(const TArray& InDrawData); 21 | 22 | void SetSlateTransform(FVector2D InVertexOffset, float InScale, const FMatrix& InOrthoMatrix) 23 | { 24 | Scale = InScale; 25 | VertexOffset = InVertexOffset; 26 | OrthoMatrix = InOrthoMatrix; 27 | } 28 | 29 | void SetClipRect(FSlateRect InRect) { ClippingRect = InRect; } 30 | 31 | static TSharedPtr AllocDrawer(); 32 | protected: 33 | // ~Begin ICustomSlateElement API 34 | virtual void DrawRenderThread(FRHICommandListImmediate& RHICmdList, const void* RenderTarget) override; 35 | // ~End ICustomSlateElement API 36 | private: 37 | FVertexDeclarationRHIRef _GetMeshDeclaration(); 38 | void _UpdateBufferSize(int32 InVtxNum, int32 InIdxNum); 39 | void _AppendDrawData(ImDrawData* InDrawData, ImDrawVert* InVtxBuf, ImDrawIdx* InIdxBuf, int32 BaseVtx = 0, int32 BaseIdx = 0); 40 | void _AppendDrawList(ImDrawList* InDrawList, ImDrawVert* InVtxBuf, ImDrawIdx* InIdxBuf, int32 BaseVtx = 0, int32 BaseIdx = 0); 41 | FRHITexture2D* _GetTextureFromID(ImTextureID InID); 42 | public: 43 | bool bIsFree = false; 44 | protected: 45 | FIndexBufferRHIRef IndexBufferRHI; 46 | FVertexBufferRHIRef VertexBufferRHI; 47 | int32 NumVertices = 0; 48 | int32 NumTriangles = 0; 49 | ImDrawVert* VtxBuf = nullptr; 50 | ImDrawIdx* IdxBuf = nullptr; 51 | 52 | FVector2D VertexOffset = FVector2D::ZeroVector; 53 | float Scale = 1.f; 54 | FMatrix OrthoMatrix = FMatrix::Identity; 55 | FSlateRect ClippingRect; 56 | TArray AllDrawElements; 57 | private: 58 | static TArray> GlobalPool; 59 | }; 60 | -------------------------------------------------------------------------------- /Source/UEImgui/Public/Window/IImguiViewport.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "imgui.h" 4 | 5 | class UImguiInputAdapter; 6 | class UImguiContext; 7 | 8 | /** 9 | * @brief Imgui viewport you can inherit it to customize your render proxy 10 | */ 11 | struct IImguiViewport 12 | { 13 | virtual ~IImguiViewport() {} 14 | 15 | // setup context 16 | virtual void SetupContext(UImguiContext* InCtx) = 0; 17 | 18 | // get the window that the viewport belong to 19 | virtual TSharedPtr GetWindow() = 0; 20 | 21 | // get persist window ID, which indicate proxy window 22 | virtual ImGuiID GetPersistWindowID() { return 0; } 23 | 24 | // is this window a render proxy? 25 | virtual bool IsPersist() { return false; } 26 | 27 | // show window, Input is the parent window of viewport 28 | virtual void Show(TSharedPtr InParent) = 0; 29 | 30 | // update viewport 31 | virtual void Update() = 0; 32 | 33 | // get viewport position in screen 34 | virtual FVector2D GetPos() = 0; 35 | 36 | // set viewport position in screen 37 | virtual void SetPos(FVector2D InPos) = 0; 38 | 39 | // get viewport absolute size 40 | virtual FVector2D GetSize() = 0; 41 | 42 | // set viewport absolute size 43 | virtual void SetSize(FVector2D InSize) = 0; 44 | 45 | // is viewport has focus? 46 | virtual bool GetFocus() = 0; 47 | 48 | // set viewport focus, may be you should bring window to front 49 | virtual void SetFocus() = 0; 50 | 51 | // is viewport window minimized 52 | virtual bool GetMinimized() = 0; 53 | 54 | // set viewport window title 55 | virtual void SetTitle(const char* InTitle) = 0; 56 | 57 | // set viewport alpha 58 | virtual void SetAlpha(float InAlpha) = 0; 59 | 60 | // get viewport DPI Scale, in Unreal, we always return 1 61 | virtual float GetDpiScale() = 0; 62 | 63 | // notify viewport changed, general, we needn't process it 64 | virtual void OnChangeViewport() {} 65 | 66 | // setup Imgui viewport that we bound 67 | virtual void SetupViewport(ImGuiViewport* InViewport) = 0; 68 | 69 | // setup Input adapter for message reroute 70 | virtual void SetupInputAdapter(UImguiInputAdapter* ImguiInputAdapter) = 0; 71 | }; 72 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/ImguiWrap/ImguiTextInputSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "GenericPlatform/ITextInputMethodSystem.h" 4 | #include "ImguiWrap/ImguiContext.h" 5 | 6 | struct ImGuiContext; 7 | struct ImGuiInputTextState; 8 | 9 | class FImguiTextInputSystem : public ITextInputMethodContext, public TSharedFromThis 10 | { 11 | public: 12 | static TSharedRef GetRef() 13 | { 14 | static TSharedRef StaticInstance = MakeShared(); 15 | return StaticInstance; 16 | } 17 | 18 | static FImguiTextInputSystem* Get() 19 | { 20 | return &GetRef().Get(); 21 | } 22 | 23 | bool IsEnable() { return bIsEnable; } 24 | void Enable(); 25 | void Disable(); 26 | protected: 27 | // ~Begin ITextInputMethodContext Interface 28 | 29 | // no composing 30 | virtual bool IsComposing() override; 31 | virtual void BeginComposition() override; 32 | virtual void UpdateCompositionRange(const int32 InBeginIndex, const uint32 InLength) override; 33 | virtual void EndComposition() override; 34 | 35 | virtual bool IsReadOnly() override; 36 | virtual uint32 GetTextLength() override; 37 | virtual void GetSelectionRange(uint32& OutBeginIndex, uint32& OutLength, ECaretPosition& OutCaretPosition) override; 38 | virtual void SetSelectionRange(const uint32 InBeginIndex, const uint32 InLength, const ECaretPosition InCaretPosition) override; 39 | virtual void GetTextInRange(const uint32 InBeginIndex, const uint32 InLength, FString& OutString) override; 40 | virtual void SetTextInRange(const uint32 InBeginIndex, const uint32 InLength, const FString& InString) override; 41 | virtual int32 GetCharacterIndexFromPoint(const FVector2D& InPoint) override; 42 | virtual bool GetTextBounds(const uint32 InBeginIndex, const uint32 InLength, FVector2D& OutPosition, FVector2D& OutSize) override; 43 | virtual void GetScreenBounds(FVector2D& OutPosition, FVector2D& OutSize) override; 44 | virtual TSharedPtr GetWindow() override; 45 | // ~End ITextInputMethodContext Interface 46 | public: 47 | FVector2D InputPos; 48 | TWeakPtr CurrentWindow; 49 | UImguiInputAdapter* CurrentInputAdapter; 50 | private: 51 | bool bIsEnable = false; 52 | }; 53 | -------------------------------------------------------------------------------- /Source/UEImgui/Public/Services/ImguiDetailCustomization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "ImguiDetailCustomization.generated.h" 4 | 5 | /** 6 | * @brief en. for imgui detail customization, inherit to customize your detail 7 | * ch. 用于使用Imgui扩展Detail, 继承这个类即可使用 8 | */ 9 | UCLASS(Abstract) 10 | class UEIMGUI_API UImguiDetailCustomization : public UObject 11 | { 12 | GENERATED_BODY() 13 | public: 14 | 15 | /** 16 | * @brief en. return class that we wan't to customize 17 | * ch. 返回我们希望定制的类 18 | * 19 | * @return en. class that we wan't to customize 20 | * ch. 我们期望定制的类 21 | */ 22 | UFUNCTION() 23 | virtual UClass* GetSupportClass() { return nullptr; } 24 | 25 | /** 26 | * @brief en. return does we support the class 27 | * ch. 返回我们是否支持某个类的定制 28 | * 29 | * @return en. does we support customize of the class 30 | * ch. 我们是否支持某个类的定制 31 | */ 32 | UFUNCTION() 33 | virtual bool IsSupportClass(UClass* InClass) { return false; } 34 | 35 | /** 36 | * @brief en. return does we support customize when editing single object 37 | * ch. 返回是否支持单物体编辑时候的定制 38 | * 39 | * @return en. does we support customize when editing single object 40 | * ch. 是否支持单物体编辑时候的定制 41 | */ 42 | UFUNCTION() 43 | virtual bool SupportSingleObjectEditing() { return false; } 44 | 45 | /** 46 | * @brief en. return does we support customize when editing multi object 47 | * ch. 返回是否支持多物体编辑时候的定制 48 | * 49 | * @return en. does we support customize when editing multi object 50 | * ch. 是否支持多物体编辑时候的定制 51 | */ 52 | UFUNCTION() 53 | virtual bool SupportMultiObjectEditing() { return false; } 54 | 55 | /** 56 | * @brief en. customize object's detail when editing single object, we can also use member function OnGui() in object 57 | * ch. 自定义单物体编辑时的detail, 我们还可以使用 OnGUI() 成员函数来实现这个功能 58 | * 59 | * @param InObject en. the object we are editing 60 | * ch. 我们当前正在编辑的物体 61 | */ 62 | UFUNCTION() 63 | virtual void OnEditSingleObject(UObject* InObject) { } 64 | 65 | /** 66 | * @brief en. customize object's detail when editing multi object 67 | * ch. 自定义多物体编辑时的detail 68 | * 69 | * @param InObjects en. the object we are editing 70 | * ch. 我们当前正在编辑的物体 71 | */ 72 | UFUNCTION() 73 | virtual void OnEditMultiObject(TArray InObjects) { } 74 | }; 75 | 76 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/ImguiWrap/ImguiTextInputSystem.cpp: -------------------------------------------------------------------------------- 1 | #include "ImguiTextInputSystem.h" 2 | #include "ImguiWrap/ImguiInputAdapter.h" 3 | #include "ImguiWrap/ImguiUEWrap.h" 4 | 5 | void FImguiTextInputSystem::Enable() 6 | { 7 | if (bIsEnable) return; 8 | FSlateApplication::Get().GetTextInputMethodSystem()->RegisterContext(AsShared()); 9 | FSlateApplication::Get().GetTextInputMethodSystem()->ActivateContext(AsShared()); 10 | bIsEnable = true; 11 | } 12 | 13 | void FImguiTextInputSystem::Disable() 14 | { 15 | if (!bIsEnable) return; 16 | FSlateApplication::Get().GetTextInputMethodSystem()->DeactivateContext(AsShared()); 17 | FSlateApplication::Get().GetTextInputMethodSystem()->UnregisterContext(AsShared()); 18 | bIsEnable = false; 19 | } 20 | 21 | bool FImguiTextInputSystem::IsComposing() 22 | { 23 | return false; 24 | } 25 | 26 | void FImguiTextInputSystem::BeginComposition() 27 | { 28 | } 29 | 30 | void FImguiTextInputSystem::UpdateCompositionRange(const int32 InBeginIndex, const uint32 InLength) 31 | { 32 | } 33 | 34 | void FImguiTextInputSystem::EndComposition() 35 | { 36 | } 37 | 38 | bool FImguiTextInputSystem::IsReadOnly() 39 | { 40 | return false; 41 | } 42 | 43 | uint32 FImguiTextInputSystem::GetTextLength() 44 | { 45 | return 1; 46 | } 47 | 48 | void FImguiTextInputSystem::GetSelectionRange(uint32& OutBeginIndex, uint32& OutLength, ECaretPosition& OutCaretPosition) 49 | { 50 | OutBeginIndex = 0; 51 | OutLength = 0; 52 | } 53 | 54 | void FImguiTextInputSystem::SetSelectionRange(const uint32 InBeginIndex, const uint32 InLength, const ECaretPosition InCaretPosition) 55 | { 56 | } 57 | 58 | void FImguiTextInputSystem::GetTextInRange(const uint32 InBeginIndex, const uint32 InLength, FString& OutString) 59 | { 60 | OutString.Append(TEXT(" "), InLength); 61 | } 62 | 63 | void FImguiTextInputSystem::SetTextInRange(const uint32 InBeginIndex, const uint32 InLength, const FString& InString) 64 | { 65 | if (InString.IsEmpty() || (InString.Len() == 1 && InString[0] == TEXT(' ')) || CurrentInputAdapter == nullptr) return; 66 | CurrentInputAdapter->AddInputIME(InString); 67 | } 68 | 69 | int32 FImguiTextInputSystem::GetCharacterIndexFromPoint(const FVector2D& InPoint) 70 | { 71 | return 0; 72 | } 73 | 74 | bool FImguiTextInputSystem::GetTextBounds( 75 | const uint32 InBeginIndex, 76 | const uint32 InLength, 77 | FVector2D& OutPosition, 78 | FVector2D& OutSize) 79 | { 80 | OutPosition = InputPos; 81 | OutSize = FVector2D::ZeroVector; 82 | return false; 83 | } 84 | 85 | void FImguiTextInputSystem::GetScreenBounds(FVector2D& OutPosition, FVector2D& OutSize) 86 | { 87 | OutPosition = InputPos; 88 | OutSize = FVector2D::ZeroVector; 89 | } 90 | 91 | TSharedPtr FImguiTextInputSystem::GetWindow() 92 | { 93 | return CurrentWindow.IsValid() ? CurrentWindow.Pin()->GetNativeWindow() : nullptr; 94 | } 95 | -------------------------------------------------------------------------------- /Source/UEImgui/Public/ImguiWrap/ImguiInputAdapter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "ImguiInputAdapter.generated.h" 4 | 5 | class UImguiContext; 6 | struct ImGuiIO; 7 | 8 | UCLASS(CustomConstructor) 9 | class UEIMGUI_API UImguiInputAdapter : public UObject 10 | { 11 | GENERATED_BODY() 12 | public: 13 | UImguiInputAdapter(const FObjectInitializer& InInitializer); 14 | 15 | // Key mapping 16 | static void CopyUnrealKeyMap(ImGuiIO* InIO); 17 | static uint32 MapKey(uint32 InKeyCode) 18 | { 19 | return InKeyCode < 512 ? InKeyCode : 256 + (InKeyCode % 256); 20 | } 21 | static uint32 MapKey(const FKey& InKey); 22 | static uint32 MapKey(const FKeyEvent& InKey) 23 | { 24 | return MapKey(InKey.GetKeyCode()); 25 | } 26 | 27 | // Mouse mapping 28 | static uint32 MapMouse(const FPointerEvent& InMouseEvent); 29 | 30 | // Key input 31 | FReply OnKeyChar(const FCharacterEvent& InCharacterEvent); 32 | FReply OnKeyDown(const FKeyEvent& InKeyEvent); 33 | FReply OnKeyUp(const FKeyEvent& InKeyEvent); 34 | 35 | // Mouse input 36 | FReply OnMouseButtonDown(const FPointerEvent& MouseEvent); 37 | FReply OnMouseButtonUp(const FPointerEvent& MouseEvent); 38 | FReply OnMouseButtonDoubleClick(const FPointerEvent& InMouseEvent); 39 | FReply OnMouseWheel(const FPointerEvent& MouseEvent); 40 | FReply OnMouseMove(SWidget* InWidget, const FGeometry& InGeometry, const FPointerEvent& MouseEvent); 41 | FReply OnMouseMove(FVector2D OffsetPos, const FPointerEvent& MouseEvent); 42 | 43 | // Cursor query 44 | virtual FCursorReply OnCursorQuery(const FPointerEvent& CursorEvent); 45 | 46 | // Set context 47 | UImguiContext* GetContext() const { return BoundContext; } 48 | void SetContext(UImguiContext* InContext) { BoundContext = InContext; } 49 | 50 | // Config 51 | bool CanBlockInput() const { return bBlockInput; } 52 | bool CanReceiveMouseInput() const { return bReceiveMouseInput; } 53 | bool CanReceiveKeyboardInput() const { return bReceiveKeyboardInput; } 54 | bool CanReceiveGamePadInput() const { return bReceiveGamePadInput; } 55 | 56 | void AddInputIME(const FString& InStr); 57 | protected: 58 | // Key 59 | virtual void AddInputCharacter(TCHAR InChar); 60 | virtual void SetKeyState(uint32 InKeyNum, bool InState); 61 | virtual void SetCtrl(bool InState); 62 | virtual void SetAlt(bool InState); 63 | virtual void SetShift(bool InState); 64 | 65 | // Mouse 66 | virtual void SetMouseBtnState(uint32 MouseBtnIndex, bool InState); 67 | virtual void SetMouseWheel(float MouseWheel); 68 | virtual void SetMousePos(FVector2D InMousePos); 69 | private: 70 | UPROPERTY() 71 | uint8 bBlockInput:1; 72 | UPROPERTY() 73 | uint8 bReceiveMouseInput:1; 74 | UPROPERTY() 75 | uint8 bReceiveKeyboardInput:1; 76 | UPROPERTY() 77 | uint8 bReceiveGamePadInput:1; 78 | UPROPERTY() 79 | UImguiContext* BoundContext; 80 | }; 81 | -------------------------------------------------------------------------------- /Source/UEImgui/Public/Extension/SmallWidgets.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "imgui.h" 3 | 4 | namespace ImGui 5 | { 6 | // ImGui Bezier widget. @r-lyeh, public domain 7 | // v1.03: improve grabbing, confine grabbers to area option, adaptive size, presets, preview. 8 | // v1.02: add BezierValue(); comments; usage 9 | // v1.01: out-of-bounds coord snapping; custom border width; spacing; cosmetics 10 | // v1.00: initial version 11 | // 12 | // [ref] http://robnapier.net/faster-bezier 13 | // [ref] http://easings.net/es#easeInSine 14 | // 15 | // Usage: 16 | // { static float v[5] = { 0.390f, 0.575f, 0.565f, 1.000f }; 17 | // ImGui::Bezier( "easeOutSine", v ); // draw 18 | // float y = ImGui::BezierValue( 0.5f, v ); // x delta in [0..1] range 19 | // } 20 | // 21 | // Source: https://github.com/ocornut/imgui/issues/786 22 | UEIMGUI_API int Bezier(const char* label, float P[5]); 23 | 24 | // Source: https://github.com/ocornut/imgui/issues/2718 25 | UEIMGUI_API bool SelectableInput(const char* str_id, bool selected, ImGuiSelectableFlags flags, char* buf, size_t buf_size); 26 | 27 | // Source: https://github.com/ocornut/imgui/issues/2718 28 | UEIMGUI_API bool SpinScaler(const char* label, ImGuiDataType data_type, void* data_ptr, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags flags); 29 | UEIMGUI_API bool SpinInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0); 30 | UEIMGUI_API bool SpinFloat(const char* label, float* v, float step = 1.0f, float step_fast = 100.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0); 31 | UEIMGUI_API bool SpinDouble(const char* label, double* v, double step = 1.0, double step_fast = 100.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0); 32 | 33 | // Source: https://github.com/ocornut/imgui/issues/1901 34 | UEIMGUI_API bool BufferingBar(const char* label, float value, const ImVec2& size_arg, const ImU32& bg_col, const ImU32& fg_col); 35 | UEIMGUI_API bool Spinner(const char* label, float radius, int thickness, const ImU32& color); 36 | UEIMGUI_API void LoadingIndicatorCircle(const char* label, const float indicator_radius, const ImVec4& main_color, const ImVec4& backdrop_color, const int circle_count, const float speed); 37 | 38 | // Source: https://github.com/ocornut/imgui/issues/1537 39 | UEIMGUI_API void ToggleButton(const char* str_id, bool* v); 40 | 41 | // Source: https://github.com/ocornut/imgui/issues/1496 42 | UEIMGUI_API void BeginGroupPanel(const char* name, const ImVec2& size = ImVec2(0, 0)); 43 | UEIMGUI_API void EndGroupPanel(); 44 | 45 | // Source: https://github.com/ocornut/imgui/issues/319 46 | UEIMGUI_API bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f); 47 | 48 | // =========================Demo========================= 49 | UEIMGUI_API void DrawSmallWidgetDemo(); 50 | UEIMGUI_API void DrawTextEditorDemo(bool* bIsOpen = nullptr); 51 | } 52 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Render/ImguiShader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "GlobalShader.h" 4 | #include "ShaderParameterUtils.h" 5 | #include "ShaderParameterStruct.h" 6 | 7 | class FImguiShaderVs : public FGlobalShader 8 | { 9 | DECLARE_SHADER_TYPE(FImguiShaderVs, Global) 10 | public: 11 | FImguiShaderVs() 12 | { } 13 | 14 | FImguiShaderVs(const ShaderMetaType::CompiledShaderInitializerType& Initializer) 15 | : FGlobalShader(Initializer) 16 | { 17 | InTransform.Bind(Initializer.ParameterMap, TEXT("InTransform")); 18 | } 19 | 20 | void SetParameters(FRHICommandList& RHICmdList, const FMatrix& TransformValue) 21 | { 22 | #if ENGINE_MAJOR_VERSION == 5 23 | SetShaderValue(RHICmdList, RHICmdList.GetBoundVertexShader(), InTransform, FMatrix44f(TransformValue)); 24 | #else 25 | SetShaderValue(RHICmdList, RHICmdList.GetBoundVertexShader(), InTransform, TransformValue); 26 | #endif 27 | } 28 | 29 | static bool ShouldCompilePermutation( 30 | const FGlobalShaderPermutationParameters& Parameters) 31 | { 32 | return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); 33 | } 34 | static void ModifyCompilationEnvironment( 35 | const FGlobalShaderPermutationParameters& Parameters, 36 | FShaderCompilerEnvironment& OutEnvironment) 37 | { 38 | FGlobalShader::ModifyCompilationEnvironment(Parameters,OutEnvironment); 39 | } 40 | private: 41 | LAYOUT_FIELD(FShaderParameter, InTransform) 42 | }; 43 | 44 | class FImguiShaderPs : public FGlobalShader 45 | { 46 | DECLARE_SHADER_TYPE(FImguiShaderPs, Global) 47 | public: 48 | FImguiShaderPs() 49 | { } 50 | 51 | FImguiShaderPs(const ShaderMetaType::CompiledShaderInitializerType& Initializer) 52 | : FGlobalShader(Initializer) 53 | { 54 | InTexture.Bind(Initializer.ParameterMap, TEXT("InTexture")); 55 | InTextureSampler.Bind(Initializer.ParameterMap, TEXT("InTextureSampler")); 56 | InHasTexture.Bind(Initializer.ParameterMap, TEXT("InHasTexture")); 57 | } 58 | 59 | static bool ShouldCompilePermutation( 60 | const FGlobalShaderPermutationParameters& Parameters) 61 | { 62 | return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); 63 | } 64 | static void ModifyCompilationEnvironment( 65 | const FGlobalShaderPermutationParameters& Parameters, 66 | FShaderCompilerEnvironment& OutEnvironment) 67 | { 68 | FGlobalShader::ModifyCompilationEnvironment(Parameters,OutEnvironment); 69 | } 70 | 71 | template 72 | void SetParameters(FRHICommandListImmediate& RHICmdList, const TShaderRHIParamRef ShaderRHI, FRHITexture2D* SourceTexture) 73 | { 74 | SetTextureParameter(RHICmdList, ShaderRHI, InTexture, SourceTexture); 75 | RHICmdList.SetShaderSampler(ShaderRHI, InTextureSampler.GetBaseIndex(), TStaticSamplerState::GetRHI()); 76 | } 77 | 78 | template 79 | void SetHasTexture(FRHICommandListImmediate& RHICmdList, const TShaderRHIParamRef ShaderRHI, bool bHasTexture) 80 | { 81 | SetShaderValue(RHICmdList, ShaderRHI, InHasTexture, int(bHasTexture)); 82 | } 83 | 84 | private: 85 | LAYOUT_FIELD(FShaderResourceParameter, InTexture) 86 | LAYOUT_FIELD(FShaderResourceParameter, InTextureSampler) 87 | LAYOUT_FIELD(FShaderParameter, InHasTexture); 88 | }; 89 | -------------------------------------------------------------------------------- /Source/UEImgui/Public/ImguiWrap/ImguiUEWrap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "imgui.h" 4 | #include 5 | 6 | struct ImDrawData; 7 | class SImguiRenderProxy; 8 | class FUEImguiDetail; 9 | 10 | enum ImguiWindowFlagUE 11 | { 12 | ImGuiWindowFlags_UEDetail = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking 13 | }; 14 | 15 | // Unreal draw functions 16 | namespace ImGui 17 | { 18 | // =============Unreal Style============= 19 | UEIMGUI_API void StyleColorUE(ImGuiStyle* dst = nullptr); // Unreal style 20 | UEIMGUI_API void StyleColorConfig(ImGuiStyle* dst = nullptr); // Config style 21 | UEIMGUI_API bool ShowUEStyleSelector(const char* Label); // Unreal style editor 22 | UEIMGUI_API void ShowUEStyleEditor(); // Unreal style editor 23 | 24 | // =============Detail============= 25 | UEIMGUI_API void SetCurrentDetail(FName InDetailName); // internal: used by detail customization 26 | UEIMGUI_API void SetCurrentDetailWidget(TWeakPtr InDetailWidget); // internal: used by detail customization 27 | UEIMGUI_API FName GetCurrentDetail(); // Get current detail name 28 | UEIMGUI_API void BeginDetail(); // Begin detail for detail customization 29 | UEIMGUI_API void EndDetail(); // End detail for detail customization 30 | 31 | // =============Text============= 32 | UEIMGUI_API void Text(const FString& InString); 33 | 34 | // =============InputText============= 35 | UEIMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 36 | UEIMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 37 | UEIMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 38 | 39 | // =============UETypeInput============= 40 | UEIMGUI_API bool UEColor(const char* InLabel, FColor* InColor, ImGuiColorEditFlags InFlags = 0); 41 | UEIMGUI_API bool UEColor(const char* InLabel, FLinearColor* InColor, ImGuiColorEditFlags InFlags = 0); 42 | 43 | // =============UEDetail============= 44 | UEIMGUI_API bool UEEnum(const char* InLabel ,UEnum* InEnumClass, int64* EnumSource); 45 | UEIMGUI_API bool UEStruct(UScriptStruct* InStruct, void* InValue); 46 | UEIMGUI_API bool UEObject(UClass* InClass, void* InValue); 47 | UEIMGUI_API bool UEProperty(FProperty* InProperty, void* InContainer); 48 | UEIMGUI_API FUEImguiDetail& GlobalDetailMaker(); 49 | } 50 | 51 | namespace ImGui 52 | { 53 | template 54 | FORCEINLINE bool UEEnum(const char* InLabel, T* InEnum) 55 | { 56 | int64 Value = (int64)*InEnum; 57 | bool bHasChanged = UEEnum(InLabel, StaticEnum(), &Value); 58 | *InEnum = (T)Value; 59 | return bHasChanged; 60 | } 61 | 62 | template 63 | FORCEINLINE bool UEStruct(T* InStruct) 64 | { 65 | return UEStruct(StaticStruct(), InStruct); 66 | } 67 | 68 | template 69 | FORCEINLINE bool UEObject(T* InObject) 70 | { 71 | return UEObject(StaticClass(), InObject); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Services/ImguiPerInstanceCtx.cpp: -------------------------------------------------------------------------------- 1 | #include "ImguiPerInstanceCtx.h" 2 | #include "imgui_internal.h" 3 | #include "ImguiWrap/ImguiGlobalInputHook.h" 4 | #include "ImguiWrap/ImguiInputAdapter.h" 5 | #include "ImguiWrap/ImguiResourceManager.h" 6 | 7 | void UImguiPerInstanceCtx::Initialize(FSubsystemCollectionBase& Collection) 8 | { 9 | // create global context 10 | GlobalContext = NewObject(); 11 | 12 | // create input adapter 13 | InputAdapter = NewObject(); 14 | InputAdapter->SetContext(GlobalContext); 15 | 16 | // setup default adapter 17 | GlobalContext->SetDefaultInputAdapter(InputAdapter); 18 | 19 | // add adapter 20 | FImguiGlobalInputHook::Get()->AddAdapter(InputAdapter); 21 | 22 | // add tick function 23 | PreSlateTick = FSlateApplication::Get().OnPreTick().AddUObject(this, &UImguiPerInstanceCtx::Tick); 24 | } 25 | 26 | void UImguiPerInstanceCtx::Deinitialize() 27 | { 28 | if (InputAdapter) 29 | { 30 | // remove adapter 31 | if (auto ImguiGlobalInputHook = FImguiGlobalInputHook::Get()) 32 | ImguiGlobalInputHook->RemoveAdapter(InputAdapter); 33 | InputAdapter = nullptr; 34 | } 35 | 36 | if (GlobalContext) 37 | { 38 | // shutdown global context 39 | GlobalContext->ShutDown(); 40 | GlobalContext = nullptr; 41 | } 42 | 43 | // remove tick function 44 | if (FSlateApplication::IsInitialized()) 45 | { 46 | FSlateApplication::Get().OnPreTick().Remove(PreSlateTick); 47 | } 48 | } 49 | 50 | void UImguiPerInstanceCtx::Tick(float DeltaTime) 51 | { 52 | if (!GlobalContext) return; 53 | if (!GlobalContext->IsInit()) 54 | { 55 | // find viewport client 56 | UGameViewportClient* ViewportClient = GetGameInstance()->GetGameViewportClient(); 57 | if (!ViewportClient) return; 58 | 59 | // create proxy 60 | TSharedPtr Proxy = SNew(SImguiRenderProxy) 61 | .InContext(GlobalContext) 62 | .InAdapter(InputAdapter) 63 | .HSizingRule(EImguiSizingRule::UESize) 64 | .VSizingRule(EImguiSizingRule::UESize) 65 | .BlockInput(true) 66 | .Visibility(EVisibility::HitTestInvisible); 67 | 68 | // add to viewport 69 | ViewportClient->AddViewportWidgetContent(Proxy->AsShared(), INT_MAX); 70 | 71 | // init context 72 | GlobalContext->Init(Proxy, UImguiResourceManager::Get().GetDefaultFont()); 73 | GlobalContext->EnableDocking(true); 74 | GlobalContext->EnableViewport(true); 75 | GlobalContext->EnableDPIScale(true); 76 | GlobalContext->EnableNoAutoMergeViewport(true); 77 | 78 | // set viewport manually 79 | StaticCastSharedPtr(Proxy)->SetupViewport(GlobalContext->GetContext()->Viewports[0]); 80 | 81 | return; 82 | } 83 | 84 | // update main viewport size 85 | GlobalContext->UpdateSize(); 86 | 87 | // apply context 88 | GlobalContext->ApplyContext(); 89 | 90 | // apply input 91 | InputAdapter->ApplyInput(); 92 | InputAdapter->SaveTempData(); 93 | 94 | // begin frame 95 | GlobalContext->NewFrame(DeltaTime); 96 | 97 | // draw global 98 | GlobalContext->DrawGlobal(); 99 | 100 | // render 101 | GlobalContext->Render(); 102 | 103 | // update viewport 104 | GlobalContext->UpdateViewport(InputAdapter); 105 | } 106 | 107 | void UImguiPerInstanceCtx::BeginDestroy() 108 | { 109 | Super::BeginDestroy(); 110 | 111 | Deinitialize(); 112 | } 113 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/ImguiWrap/ImguiInputAdapterDeferred.cpp: -------------------------------------------------------------------------------- 1 | #include "ImguiWrap/ImguiInputAdapterDeferred.h" 2 | #include "imgui_internal.h" 3 | #include "ImguiWrap/ImguiContext.h" 4 | 5 | UImguiInputAdapterDeferred::UImguiInputAdapterDeferred(const FObjectInitializer& InInitializer) 6 | : Super(InInitializer) 7 | , KeyCtrl(false) 8 | , KeyShift(false) 9 | , KeyAlt(false) 10 | , MouseWheel(false) 11 | , MousePos(0, 0) 12 | , Cursor(0) 13 | { 14 | FMemory::Memzero(KeysDown, sizeof(KeysDown)); 15 | FMemory::Memzero(MouseDown, sizeof(MouseDown)); 16 | } 17 | 18 | void UImguiInputAdapterDeferred::AddInputCharacter(TCHAR InChar) 19 | { 20 | if (InChar != 0) 21 | InputQueueCharacters.push_back(InChar <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)InChar : IM_UNICODE_CODEPOINT_INVALID); 22 | } 23 | 24 | void UImguiInputAdapterDeferred::SetKeyState(uint32 InKeyNum, bool InState) 25 | { 26 | KeysDown[InKeyNum] = InState; 27 | } 28 | 29 | void UImguiInputAdapterDeferred::SetCtrl(bool InState) 30 | { 31 | KeyCtrl = InState; 32 | } 33 | 34 | void UImguiInputAdapterDeferred::SetAlt(bool InState) 35 | { 36 | KeyAlt = InState; 37 | } 38 | 39 | void UImguiInputAdapterDeferred::SetShift(bool InState) 40 | { 41 | KeyShift = InState; 42 | } 43 | 44 | void UImguiInputAdapterDeferred::SetMouseBtnState(uint32 MouseBtnIndex, bool InState) 45 | { 46 | MouseDown[MouseBtnIndex] = InState; 47 | } 48 | 49 | void UImguiInputAdapterDeferred::SetMouseWheel(float InMouseWheel) 50 | { 51 | MouseWheel = InMouseWheel; 52 | } 53 | 54 | void UImguiInputAdapterDeferred::SetMousePos(FVector2D InMousePos) 55 | { 56 | MousePos.x = InMousePos.X; 57 | MousePos.y = InMousePos.Y; 58 | } 59 | 60 | FCursorReply UImguiInputAdapterDeferred::OnCursorQuery(const FPointerEvent& CursorEvent) 61 | { 62 | switch (Cursor) 63 | { 64 | case ImGuiMouseCursor_Arrow: return FCursorReply::Cursor(EMouseCursor::Default); 65 | case ImGuiMouseCursor_TextInput: return FCursorReply::Cursor(EMouseCursor::TextEditBeam); 66 | case ImGuiMouseCursor_ResizeAll: return FCursorReply::Cursor(EMouseCursor::CardinalCross); 67 | case ImGuiMouseCursor_ResizeEW: return FCursorReply::Cursor(EMouseCursor::ResizeLeftRight); 68 | case ImGuiMouseCursor_ResizeNS: return FCursorReply::Cursor(EMouseCursor::ResizeUpDown); 69 | case ImGuiMouseCursor_ResizeNESW: return FCursorReply::Cursor(EMouseCursor::ResizeSouthWest); 70 | case ImGuiMouseCursor_ResizeNWSE: return FCursorReply::Cursor(EMouseCursor::ResizeSouthEast); 71 | case ImGuiMouseCursor_Hand: return FCursorReply::Cursor(EMouseCursor::Hand); 72 | case ImGuiMouseCursor_NotAllowed: return FCursorReply::Cursor(EMouseCursor::SlashedCircle); 73 | } 74 | return FCursorReply::Cursor(EMouseCursor::Default); 75 | } 76 | 77 | void UImguiInputAdapterDeferred::ApplyInput() 78 | { 79 | if (!GetContext()) return; 80 | ImGuiIO* IO = GetContext()->GetIO(); 81 | 82 | // copy data 83 | IO->InputQueueCharacters = InputQueueCharacters; 84 | IO->KeyCtrl = KeyCtrl; 85 | IO->KeyShift = KeyShift; 86 | IO->KeyAlt = KeyAlt; 87 | FMemory::Memcpy(IO->KeysDown, KeysDown, sizeof(KeysDown)); 88 | FMemory::Memcpy(IO->MouseDown, MouseDown, sizeof(MouseDown)); 89 | IO->MousePos = MousePos; 90 | IO->MouseWheel = MouseWheel; 91 | 92 | // clean data 93 | InputQueueCharacters.clear(); 94 | MouseWheel = 0; 95 | } 96 | 97 | void UImguiInputAdapterDeferred::SaveTempData() 98 | { 99 | Cursor = GetContext()->GetContext()->MouseCursor; 100 | } 101 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Window/ImguiWindowWrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "ImguiWindowWrapper.h" 2 | #include "imgui.h" 3 | #include "Widgets/SImguiWindow.h" 4 | 5 | UImguiContext* FImguiWindowWrapper::CurContext = nullptr; 6 | UImguiInputAdapter* FImguiWindowWrapper::CurInputAdapter = nullptr; 7 | 8 | void FImguiWindowWrapper::SetupPlatformInterface(ImGuiPlatformIO* PlatformIO) 9 | { 10 | PlatformIO->Platform_CreateWindow = UE_CreateWindow; 11 | PlatformIO->Platform_DestroyWindow = UE_DestroyWindow; 12 | PlatformIO->Platform_ShowWindow = UE_ShowWindow; 13 | PlatformIO->Platform_SetWindowPos = UE_SetWindowPos; 14 | PlatformIO->Platform_GetWindowPos = UE_GetWindowPos; 15 | PlatformIO->Platform_SetWindowSize = UE_SetWindowSize; 16 | PlatformIO->Platform_GetWindowSize = UE_GetWindowSize; 17 | PlatformIO->Platform_SetWindowFocus = UE_SetWindowFocus; 18 | PlatformIO->Platform_GetWindowFocus = UE_GetWindowFocus; 19 | PlatformIO->Platform_GetWindowMinimized = UE_GetWindowMinimized; 20 | PlatformIO->Platform_SetWindowTitle = UE_SetWindowTitle; 21 | PlatformIO->Platform_SetWindowAlpha = UE_SetWindowAlpha; 22 | PlatformIO->Platform_UpdateWindow = UE_UpdateWindow; 23 | PlatformIO->Platform_GetWindowDpiScale = UE_GetWindowDpiScale; 24 | PlatformIO->Platform_OnChangedViewport = UE_OnChangedViewport; 25 | PlatformIO->Platform_SetImeInputPos = UE_SetImeInputPos; 26 | } 27 | 28 | void FImguiWindowWrapper::UE_CreateWindow(ImGuiViewport* viewport) 29 | { 30 | CurContext->_CreateWindow(viewport, CurInputAdapter); 31 | } 32 | 33 | void FImguiWindowWrapper::UE_DestroyWindow(ImGuiViewport* viewport) 34 | { 35 | CurContext->_DestroyWindow(viewport); 36 | } 37 | 38 | void FImguiWindowWrapper::UE_ShowWindow(ImGuiViewport* viewport) 39 | { 40 | CurContext->_ShowWindow(viewport); 41 | } 42 | 43 | void FImguiWindowWrapper::UE_UpdateWindow(ImGuiViewport* viewport) 44 | { 45 | CurContext->_UpdateWindow(viewport); 46 | } 47 | 48 | ImVec2 FImguiWindowWrapper::UE_GetWindowPos(ImGuiViewport* viewport) 49 | { 50 | return CurContext->_GetWindowPos(viewport); 51 | } 52 | 53 | void FImguiWindowWrapper::UE_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) 54 | { 55 | CurContext->_SetWindowPos(viewport, pos); 56 | } 57 | 58 | ImVec2 FImguiWindowWrapper::UE_GetWindowSize(ImGuiViewport* viewport) 59 | { 60 | return CurContext->_GetWindowSize(viewport); 61 | } 62 | 63 | void FImguiWindowWrapper::UE_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) 64 | { 65 | CurContext->_SetWindowSize(viewport, size); 66 | } 67 | 68 | void FImguiWindowWrapper::UE_SetWindowFocus(ImGuiViewport* viewport) 69 | { 70 | CurContext->_SetWindowFocus(viewport); 71 | } 72 | 73 | bool FImguiWindowWrapper::UE_GetWindowFocus(ImGuiViewport* viewport) 74 | { 75 | return CurContext->_GetWindowFocus(viewport); 76 | } 77 | 78 | bool FImguiWindowWrapper::UE_GetWindowMinimized(ImGuiViewport* viewport) 79 | { 80 | return CurContext->_GetWindowMinimized(viewport); 81 | } 82 | 83 | void FImguiWindowWrapper::UE_SetWindowTitle(ImGuiViewport* viewport, const char* title) 84 | { 85 | CurContext->_SetWindowTitle(viewport, title); 86 | } 87 | 88 | void FImguiWindowWrapper::UE_SetWindowAlpha(ImGuiViewport* viewport, float alpha) 89 | { 90 | CurContext->_SetWindowAlpha(viewport, alpha); 91 | } 92 | 93 | float FImguiWindowWrapper::UE_GetWindowDpiScale(ImGuiViewport* viewport) 94 | { 95 | return CurContext->_GetWindowDpiScale(viewport); 96 | } 97 | 98 | void FImguiWindowWrapper::UE_OnChangedViewport(ImGuiViewport* viewport) 99 | { 100 | CurContext->_OnChangedViewport(viewport); 101 | } 102 | 103 | void FImguiWindowWrapper::UE_SetImeInputPos(ImGuiViewport* viewport, ImVec2 pos) 104 | { 105 | CurContext->_SetImeInputPos(viewport, pos); 106 | } 107 | -------------------------------------------------------------------------------- /Source/UEImgui/Public/Config/ImguiConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "ImguiWrap/ImguiUEWrap.h" 4 | #include "Engine/DeveloperSettings.h" 5 | #include "ImguiConfig.generated.h" 6 | 7 | // Imgui setting wrap 8 | USTRUCT() 9 | struct FImguiStyle 10 | { 11 | GENERATED_BODY() 12 | public: 13 | UPROPERTY() 14 | float Alpha; 15 | UPROPERTY() 16 | FVector2D WindowPadding; 17 | UPROPERTY() 18 | float WindowRounding; 19 | UPROPERTY() 20 | float WindowBorderSize; 21 | UPROPERTY() 22 | FVector2D WindowMinSize; 23 | UPROPERTY() 24 | FVector2D WindowTitleAlign; 25 | // UPROPERTY() 26 | ImGuiDir WindowMenuButtonPosition = ImGuiDir_Left; 27 | UPROPERTY() 28 | float ChildRounding; 29 | UPROPERTY() 30 | float ChildBorderSize; 31 | UPROPERTY() 32 | float PopupRounding; 33 | UPROPERTY() 34 | float PopupBorderSize; 35 | UPROPERTY() 36 | FVector2D FramePadding; 37 | UPROPERTY() 38 | float FrameRounding; 39 | UPROPERTY() 40 | float FrameBorderSize; 41 | UPROPERTY() 42 | FVector2D ItemSpacing; 43 | UPROPERTY() 44 | FVector2D ItemInnerSpacing; 45 | UPROPERTY() 46 | FVector2D CellPadding; 47 | UPROPERTY() 48 | FVector2D TouchExtraPadding; 49 | UPROPERTY() 50 | float IndentSpacing; 51 | UPROPERTY() 52 | float ColumnsMinSpacing; 53 | UPROPERTY() 54 | float ScrollbarSize; 55 | UPROPERTY() 56 | float ScrollbarRounding; 57 | UPROPERTY() 58 | float GrabMinSize; 59 | UPROPERTY() 60 | float GrabRounding; 61 | UPROPERTY() 62 | float LogSliderDeadzone; 63 | UPROPERTY() 64 | float TabRounding; 65 | UPROPERTY() 66 | float TabBorderSize; 67 | UPROPERTY() 68 | float TabMinWidthForCloseButton; 69 | // UPROPERTY() 70 | ImGuiDir ColorButtonPosition = ImGuiDir_Right; 71 | UPROPERTY() 72 | FVector2D ButtonTextAlign; 73 | UPROPERTY() 74 | FVector2D SelectableTextAlign; 75 | UPROPERTY() 76 | FVector2D DisplayWindowPadding; 77 | UPROPERTY() 78 | FVector2D DisplaySafeAreaPadding; 79 | UPROPERTY() 80 | float MouseCursorScale; 81 | UPROPERTY() 82 | bool AntiAliasedLines; 83 | UPROPERTY() 84 | bool AntiAliasedLinesUseTex; 85 | UPROPERTY() 86 | bool AntiAliasedFill; 87 | UPROPERTY() 88 | float CurveTessellationTol; 89 | UPROPERTY() 90 | float CircleSegmentMaxError; 91 | }; 92 | 93 | UCLASS(Config=ImGui, DefaultConfig) 94 | class UImguiConfig : public UDeveloperSettings 95 | { 96 | GENERATED_BODY() 97 | public: 98 | UImguiConfig(); 99 | static UImguiConfig* Get() 100 | { 101 | static UImguiConfig* Config = nullptr; 102 | if (!Config) 103 | { 104 | Config = NewObject(); 105 | Config->LoadConfig(); 106 | Config->AddToRoot(); 107 | } 108 | return Config; 109 | } 110 | 111 | // set style 112 | void SetStyle(ImGuiStyle* InStyle); 113 | 114 | public: 115 | // Colors 116 | UPROPERTY(Config) 117 | TArray ImguiColors; 118 | 119 | // Style 120 | UPROPERTY(Config) 121 | FImguiStyle ImguiStyle; 122 | 123 | // Font 124 | UPROPERTY(EditAnywhere, Config) 125 | FString FontPath; 126 | 127 | // Save layout 128 | UPROPERTY(EditAnywhere, Config) 129 | bool bSaveLayout = true; 130 | 131 | // DPI Scale 132 | UPROPERTY(EditAnywhere, Config) 133 | bool bEnableDPIScale = false; 134 | }; -------------------------------------------------------------------------------- /Source/UEImgui/Private/Widgets/SImguiWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "imgui.h" 4 | #include "ImguiWrap/ImguiContext.h" 5 | #include "ImguiWrap/ImguiInputAdapter.h" 6 | #include "Widgets/SWindow.h" 7 | #include "Window/IImguiViewport.h" 8 | 9 | class UEIMGUI_API SImguiWindow : public SWindow, public IImguiViewport 10 | { 11 | using Super = SWindow; 12 | public: 13 | SLATE_BEGIN_ARGS(SImguiWindow) 14 | : _Context(nullptr) 15 | , _Viewport(nullptr) 16 | , _IsToolTip(false) 17 | {} 18 | SLATE_ARGUMENT(TWeakObjectPtr, Context) 19 | SLATE_ARGUMENT(TWeakObjectPtr, Adapter) 20 | SLATE_ARGUMENT(ImGuiViewport*, Viewport) 21 | SLATE_ARGUMENT(bool, IsToolTip) 22 | SLATE_ARGUMENT(bool, IsPopup) 23 | SLATE_ARGUMENT(bool, TakeFocusWhenShow) 24 | SLATE_END_ARGS() 25 | 26 | void Construct(const FArguments& InArgs); 27 | 28 | // Context action 29 | UImguiContext* GetContext() const { return BoundContext.Get(); } 30 | void SetContext(UImguiContext* InContext) { BoundContext = InContext; } 31 | 32 | UImguiInputAdapter* GetAdapter() const { return BoundAdapter.Get(); } 33 | void SetAdapter(UImguiInputAdapter* InAdapter) { BoundAdapter = InAdapter; } 34 | protected: 35 | // ~Begin SWidget API 36 | 37 | // receive key input 38 | virtual FReply OnKeyChar(const FGeometry& MyGeometry, const FCharacterEvent& InCharacterEvent) override; 39 | virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override; 40 | virtual FReply OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override; 41 | 42 | // receive mouse input 43 | virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; 44 | virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; 45 | virtual FReply OnMouseButtonDoubleClick(const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent) override; 46 | virtual FReply OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; 47 | virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; 48 | 49 | // Focus 50 | virtual bool SupportsKeyboardFocus() const override; 51 | virtual void OnFocusLost(const FFocusEvent& InFocusEvent) override; 52 | virtual FReply OnFocusReceived(const FGeometry& MyGeometry, const FFocusEvent& InFocusEvent) override; 53 | 54 | // cursor 55 | virtual FCursorReply OnCursorQuery(const FGeometry& MyGeometry, const FPointerEvent& CursorEvent) const override; 56 | 57 | // draw 58 | virtual FVector2D ComputeDesiredSize(float LayoutScaleMultiplier) const override; 59 | virtual int32 OnPaint( 60 | const FPaintArgs& Args, 61 | const FGeometry& AllottedGeometry, 62 | const FSlateRect& MyCullingRect, 63 | FSlateWindowElementList& OutDrawElements, 64 | int32 LayerId, 65 | const FWidgetStyle& InWidgetStyle, 66 | bool bParentEnabled) const override; 67 | // ~Begin SWidget API 68 | 69 | // ~Begin IImguiViewport API 70 | virtual void SetupContext(UImguiContext* InCtx) override { SetContext(InCtx); } 71 | virtual TSharedPtr GetWindow() override { return StaticCastSharedRef(AsShared()); } 72 | virtual void Show(TSharedPtr InParent) override; 73 | virtual void Update() override; 74 | virtual FVector2D GetPos() override; 75 | virtual void SetPos(FVector2D InPos) override; 76 | virtual FVector2D GetSize() override; 77 | virtual void SetSize(FVector2D InSize) override; 78 | virtual bool GetFocus() override; 79 | virtual void SetFocus() override; 80 | virtual bool GetMinimized() override; 81 | virtual void SetTitle(const char* InTitle) override; 82 | virtual void SetAlpha(float InAlpha) override; 83 | virtual void SetupViewport(ImGuiViewport* InViewport) override; 84 | virtual void SetupInputAdapter(UImguiInputAdapter* ImguiInputAdapter) override; 85 | virtual float GetDpiScale() override; 86 | // ~End IImguiViewport API 87 | private: 88 | ImGuiViewport* BoundViewport; 89 | TWeakObjectPtr BoundContext; 90 | TWeakObjectPtr BoundAdapter; 91 | bool bInFocus = false; 92 | }; 93 | -------------------------------------------------------------------------------- /Source/UEImgui/Public/ImguiWrap/ImguiContext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "imgui.h" 4 | #include "Widgets/SImguiWidget.h" 5 | #include "Window/IImguiViewport.h" 6 | #include "ImguiContext.generated.h" 7 | 8 | class UImguiInputAdapter; 9 | 10 | DECLARE_DELEGATE_RetVal(bool, FDrawGlobalImgui); 11 | 12 | /* 13 | * hold an imgui environment 14 | */ 15 | UCLASS(CustomConstructor) 16 | class UEIMGUI_API UImguiContext : public UObject 17 | { 18 | GENERATED_BODY() 19 | friend struct FImguiWindowWrapper; 20 | public: 21 | // init and shutdown 22 | void Init(TSharedPtr InMainViewPort, ImFontAtlas* InDefaultFontAtlas = nullptr); 23 | bool IsInit() const { return Context != nullptr; } 24 | void UpdateSize(); 25 | void ShutDown(); 26 | 27 | // context config 28 | void EnableDocking(bool bInEnable); 29 | bool EnableDocking(); 30 | void EnableViewport(bool bInEnable); 31 | bool EnableViewport(); 32 | void EnableDPIScale(bool bInEnable); 33 | bool EnableDPIScale(); 34 | void EnableNoAutoMergeViewport(bool bInIsEnable); 35 | bool EnableNoAutoMergeViewport(); 36 | 37 | // global draw 38 | int32 AddGlobalWindow(const FDrawGlobalImgui& InCallBack) { return AllDrawCallBack.Add(InCallBack); } 39 | void RemoveGlobalWindow(int32 InIndex) { AllDrawCallBack[InIndex].Unbind(); AllDrawCallBack.RemoveAt(InIndex);} 40 | 41 | // proxy 42 | void AddRenderProxy(TWeakPtr InRenderProxy); 43 | void RemoveRenderProxy(TWeakPtr InRenderProxy); 44 | 45 | // context operation 46 | ImGuiContext* GetContext() const { return Context; } 47 | ImGuiIO* GetIO() const; 48 | ImGuiStyle* GetStyle() const; 49 | UImguiInputAdapter* GetDefaultInputAdapter() const { return DefaultAdapter; } 50 | void SetDefaultInputAdapter(UImguiInputAdapter* InInputAdapter) { DefaultAdapter = InInputAdapter; } 51 | 52 | // life time function 53 | void ApplyContext(); 54 | void NewFrame(float DeltaTime); 55 | void DrawGlobal(); 56 | void Render(); 57 | void UpdateViewport(UImguiInputAdapter* InAdapter); 58 | protected: 59 | // ~Begin UObject API 60 | virtual void BeginDestroy() override; 61 | // ~End UObject API 62 | private: 63 | // window platform 64 | void _CreateWindow(ImGuiViewport* viewport, UImguiInputAdapter* InInputAdapter); 65 | void _DestroyWindow(ImGuiViewport* viewport); 66 | void _ShowWindow(ImGuiViewport* viewport); 67 | void _UpdateWindow(ImGuiViewport* viewport); 68 | ImVec2 _GetWindowPos(ImGuiViewport* viewport); 69 | void _SetWindowPos(ImGuiViewport* viewport, ImVec2 pos); 70 | ImVec2 _GetWindowSize(ImGuiViewport* viewport); 71 | void _SetWindowSize(ImGuiViewport* viewport, ImVec2 size); 72 | void _SetWindowFocus(ImGuiViewport* viewport); 73 | bool _GetWindowFocus(ImGuiViewport* viewport); 74 | bool _GetWindowMinimized(ImGuiViewport* viewport); 75 | void _SetWindowTitle(ImGuiViewport* viewport, const char* title); 76 | void _SetWindowAlpha(ImGuiViewport* viewport, float alpha); 77 | float _GetWindowDpiScale(ImGuiViewport* viewport); 78 | void _OnChangedViewport(ImGuiViewport* viewport); 79 | void _SetImeInputPos(ImGuiViewport* viewport, ImVec2 pos); 80 | 81 | // setup 82 | void _SetupImguiContext(); 83 | void _SetUpDefaultFont(); 84 | 85 | // help function 86 | TSharedPtr _SafeFindViewport(ImGuiViewport* InViewport, bool bNeedShow = true); 87 | TWeakPtr _DispatchProxy(ImGuiViewport* InViewport, UImguiInputAdapter* InInputAdapter); 88 | private: 89 | // main viewport of this context 90 | TSharedPtr MainViewPort; 91 | 92 | // all draw callback 93 | TSparseArray AllDrawCallBack; 94 | 95 | // render proxy, steal render data form window dispatch 96 | TArray> AllRenderProxy; 97 | 98 | // dispatched window, here keep reference to prevent GC 99 | TArray> AllDispatchedViewport; 100 | 101 | // imgui context 102 | ImGuiContext* Context; 103 | 104 | // default input adapter 105 | UImguiInputAdapter* DefaultAdapter; 106 | 107 | // imgui viewport map to UE viewport, for fast and safe search 108 | TMap> ImViewportToUE; 109 | }; 110 | -------------------------------------------------------------------------------- /Examples/Example.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "Services/ImguiDetailCustomization.h" 4 | #include "Example.generated.h" 5 | 6 | UENUM() 7 | enum class ETestEnum : uint8 8 | { 9 | A UMETA(DisplayName = "选项A"), 10 | B UMETA(DisplayName = "选项B"), 11 | C UMETA(DisplayName = "选项C"), 12 | D UMETA(DisplayName = "选项D"), 13 | E UMETA(DisplayName = "选项E"), 14 | F UMETA(DisplayName = "选项F"), 15 | }; 16 | 17 | USTRUCT() 18 | struct FSimpleStruct 19 | { 20 | GENERATED_BODY() 21 | public: 22 | UPROPERTY(EditAnywhere) 23 | int8 PropInt8; 24 | UPROPERTY(EditAnywhere) 25 | int16 PropInt16; 26 | UPROPERTY(EditAnywhere) 27 | int32 PropInt32; 28 | UPROPERTY(EditAnywhere) 29 | int64 PropInt64; 30 | }; 31 | 32 | USTRUCT() 33 | struct FTestStruct 34 | { 35 | GENERATED_BODY() 36 | public: 37 | UPROPERTY(EditAnywhere) 38 | int8 PropInt8; 39 | UPROPERTY(EditAnywhere) 40 | uint8 PropUInt8; 41 | UPROPERTY(EditAnywhere) 42 | int16 PropInt16; 43 | UPROPERTY(EditAnywhere) 44 | uint16 PropUInt16; 45 | UPROPERTY(EditAnywhere) 46 | int32 PropInt32; 47 | UPROPERTY(EditAnywhere) 48 | uint32 PropUInt32; 49 | UPROPERTY(EditAnywhere) 50 | int64 PropInt64; 51 | UPROPERTY(EditAnywhere) 52 | uint64 PropUInt64; 53 | UPROPERTY(EditAnywhere) 54 | float PropFloat; 55 | UPROPERTY(EditAnywhere) 56 | double PropDouble; 57 | UPROPERTY(EditAnywhere) 58 | bool PropBool; 59 | 60 | UPROPERTY(EditAnywhere) 61 | ETestEnum PropEnum; 62 | UPROPERTY(EditAnywhere) 63 | FSimpleStruct PropSimpleStruct; 64 | 65 | UPROPERTY(EditAnywhere) 66 | FName PropName; 67 | UPROPERTY(EditAnywhere) 68 | FText PropText; 69 | UPROPERTY(EditAnywhere) 70 | FString PropString; 71 | 72 | UPROPERTY(EditAnywhere) 73 | FVector2D PropVec2; 74 | UPROPERTY(EditAnywhere) 75 | FVector PropVec3; 76 | UPROPERTY(EditAnywhere) 77 | FVector PropVec4; 78 | UPROPERTY(EditAnywhere) 79 | FRotator PropRotator; 80 | UPROPERTY(EditAnywhere) 81 | FTransform PropTransform; 82 | UPROPERTY(EditAnywhere) 83 | FColor PropColor; 84 | UPROPERTY(EditAnywhere) 85 | FLinearColor PropColorHDR; 86 | 87 | UPROPERTY(EditAnywhere) 88 | TArray PropInt; 89 | UPROPERTY(EditAnywhere) 90 | TArray PropStruct; 91 | UPROPERTY(EditAnywhere) 92 | TMap PropMap; 93 | 94 | UPROPERTY(EditAnywhere) 95 | UObject* PropObject; 96 | UPROPERTY(EditAnywhere) 97 | TSoftObjectPtr PropSoftObject; 98 | UPROPERTY(EditAnywhere) 99 | TLazyObjectPtr PropLazyObject; 100 | UPROPERTY(EditAnywhere) 101 | TWeakObjectPtr PropWeakObject; 102 | 103 | UPROPERTY(EditAnywhere) 104 | UClass* PropClass; 105 | UPROPERTY(EditAnywhere) 106 | TSoftClassPtr PropSoftClassPtr; 107 | UPROPERTY(EditAnywhere) 108 | TSubclassOf PropSubClassOf; 109 | }; 110 | 111 | UCLASS() 112 | class AImguiExampleActor : public AActor 113 | { 114 | GENERATED_BODY() 115 | public: 116 | AImguiExampleActor(); 117 | 118 | // open imgui demo window(use global context) 119 | void OpenImguiDemoGlobal(); 120 | 121 | // open imgui demo dock window(use global context) 122 | void OpenImguiDemoDockGlobal(); 123 | 124 | // open imgui demo window(use stand alone context) 125 | void OpenImguiDemoStandAlone(); 126 | 127 | // use OnGUI function for customize detail panel 128 | UFUNCTION() 129 | void OnGUI(); 130 | 131 | protected: 132 | UPROPERTY(EditAnywhere) 133 | USceneComponent* Root; 134 | 135 | UPROPERTY(EditAnywhere, Category="0") 136 | FTestStruct StructValue; 137 | 138 | UPROPERTY(EditAnywhere, Category="0") 139 | ETestEnum EnumValue; 140 | 141 | bool bGlobalWndAdded = false; 142 | }; 143 | 144 | UCLASS() 145 | class UImguiDetailCustomizationExample : public UImguiDetailCustomization 146 | { 147 | GENERATED_BODY() 148 | public: 149 | // target class 150 | virtual UClass* GetSupportClass() override { return UObject::StaticClass(); } 151 | 152 | // support single object editing 153 | virtual bool SupportSingleObjectEditing() override { return true; } 154 | virtual void OnEditSingleObject(UObject* InObject) override; 155 | 156 | // support mult object editing 157 | virtual bool SupportMultiObjectEditing() override { return true; } 158 | virtual void OnEditMultiObject(TArray InObjects) override; 159 | }; 160 | 161 | -------------------------------------------------------------------------------- /Examples/Example.cpp: -------------------------------------------------------------------------------- 1 | #include "Example.h" 2 | #include "Misc/MessageDialog.h" 3 | #include "ImguiWrap/ImguiUEWrap.h" 4 | #include "Kismet/KismetSystemLibrary.h" 5 | #include "Services/ImguiGlobalContextService.h" 6 | #include "Widgets/SImguiWidget.h" 7 | #include "Widgets/Docking/SDockTab.h" 8 | 9 | AImguiExampleActor::AImguiExampleActor() 10 | { 11 | Root = CreateDefaultSubobject(TEXT("Root")); 12 | } 13 | 14 | void AImguiExampleActor::OpenImguiDemoGlobal() 15 | { 16 | if (!bGlobalWndAdded) 17 | { 18 | bGlobalWndAdded = true; 19 | UEImGui::AddGlobalWindow(FDrawGlobalImgui::CreateLambda([This=TWeakObjectPtr(this)] 20 | { 21 | AImguiExampleActor* Actor = This.Get(); 22 | if (!Actor) return false; 23 | ImGui::ShowDemoWindow(&Actor->bGlobalWndAdded); 24 | return Actor->bGlobalWndAdded; 25 | })); 26 | } 27 | } 28 | 29 | void AImguiExampleActor::OpenImguiDemoDockGlobal() 30 | { 31 | // Open Global Wnd 32 | OpenImguiDemoGlobal(); 33 | 34 | // create an global imgui widget 35 | auto GlobalImguiWidget = SNew(SImguiRenderProxy) 36 | .HSizingRule(EImguiSizingRule::UESize) 37 | .VSizingRule(EImguiSizingRule::UESize) 38 | .ProxyWndName("Dear ImGui Demo"); 39 | 40 | // register render proxy 41 | UEImGui::AddRenderProxy(GlobalImguiWidget, this); 42 | 43 | // create a dock tab 44 | TSharedPtr NewTab = SNew(SDockTab) 45 | .Label(FText::FromString(TEXT("Dear ImGui Demo"))) 46 | .TabRole(ETabRole::NomadTab) 47 | .OnTabClosed_Lambda([This=TWeakObjectPtr(this)](TSharedRef){ if (This.IsValid()) This->bGlobalWndAdded = false; }) 48 | [ 49 | GlobalImguiWidget 50 | ]; 51 | 52 | // register dock tab 53 | static FName PlaceholderId(TEXT("StandaloneToolkit")); 54 | static TSharedPtr SearchPreference = MakeShareable(new FTabManager::FRequireClosedTab()); 55 | FGlobalTabmanager::Get()->InsertNewDocumentTab(PlaceholderId, *SearchPreference, NewTab.ToSharedRef()); 56 | } 57 | 58 | void AImguiExampleActor::OpenImguiDemoStandAlone() 59 | { 60 | // InProgress 61 | } 62 | 63 | void AImguiExampleActor::OnGUI() 64 | { 65 | ImGui::BeginDetail(); 66 | 67 | ImGui::Columns(2); 68 | 69 | // simple functional 70 | ImGui::AlignTextToFramePadding(); 71 | ImGui::Text("Simple functional: "); 72 | ImGui::NextColumn(); 73 | if (ImGui::Button("SayHello")) 74 | { 75 | UKismetSystemLibrary::PrintString(GWorld); 76 | } 77 | ImGui::SameLine(); 78 | if (ImGui::Button("Print Location")) 79 | { 80 | UKismetSystemLibrary::PrintString(GWorld, GetActorLocation().ToString()); 81 | } 82 | ImGui::NextColumn(); 83 | 84 | // global context 85 | ImGui::AlignTextToFramePadding(); 86 | ImGui::Text("Global context: "); 87 | ImGui::NextColumn(); 88 | if (ImGui::Button("Open Demo")) 89 | { 90 | OpenImguiDemoGlobal(); 91 | } 92 | ImGui::SameLine(); 93 | if (ImGui::Button("Open Demo Dock")) 94 | { 95 | OpenImguiDemoDockGlobal(); 96 | } 97 | ImGui::NextColumn(); 98 | 99 | // stand alone context 100 | // ImGui::AlignTextToFramePadding(); 101 | // ImGui::Text("Stand alone context: "); 102 | // ImGui::NextColumn(); 103 | // if (ImGui::Button("Open Demo Window")) 104 | // { 105 | // OpenImguiDemoStandAlone(); 106 | // } 107 | // ImGui::NextColumn(); 108 | 109 | // resume 110 | ImGui::Columns(1); 111 | 112 | // enum 113 | ImGui::UEEnum("EnumExample" ,&EnumValue); 114 | 115 | // struct 116 | if (ImGui::Button("Open Struct Detail")) 117 | { 118 | UEImGui::AddGlobalWindow(FDrawGlobalImgui::CreateLambda([this]() 119 | { 120 | bool bOpen = true; 121 | ImGui::SetNextWindowSize(ImVec2(600,800), ImGuiCond_Appearing); 122 | ImGui::Begin("Example Struct Detail", &bOpen); 123 | ImGui::UEStruct(&StructValue); 124 | ImGui::End(); 125 | return bOpen; 126 | })); 127 | } 128 | 129 | ImGui::End(); 130 | } 131 | 132 | void UImguiDetailCustomizationExample::OnEditSingleObject(UObject* InObject) 133 | { 134 | ImGui::BeginDetail(); 135 | ImGui::Separator(); 136 | ImGui::Text("This is single object editor"); 137 | ImGui::EndDetail(); 138 | } 139 | 140 | void UImguiDetailCustomizationExample::OnEditMultiObject(TArray InObjects) 141 | { 142 | ImGui::BeginDetail(); 143 | ImGui::Text("Edit multi object here"); 144 | ImGui::Separator(); 145 | for (UObject* Object : InObjects) 146 | { 147 | ImGui::Text(Object->GetName()); 148 | } 149 | ImGui::EndDetail(); 150 | } 151 | -------------------------------------------------------------------------------- /Source/UEImgui/Public/Services/ImguiGlobalContextService.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "Window/IImguiViewport.h" 4 | 5 | DECLARE_DELEGATE_RetVal(bool, FDrawGlobalImgui); 6 | class UImguiContext; 7 | class UImguiInputAdapter; 8 | 9 | namespace UEImGui 10 | { 11 | /** 12 | * @brief en. Is it time to draw? before you call other global functions, you should check it 13 | * ch. 是否可以开始绘制,在调用其它函数之前,你需要验证它 14 | * 15 | * @param WorldContextObject en. Indicates the world to which the object calling this function belongs, by default, we use GWorld 16 | * ch. 指定调用此函数的对象所属的世界,默认情况下使用GWorld 17 | * 18 | * @return en. Is it time to draw, if true, you can call other global functions safe 19 | * ch. 是否可以开始绘制,如果返回True,你可以安全的调用其它全局函数 20 | */ 21 | UEIMGUI_API bool TimeToDraw(UObject* WorldContextObject = nullptr); 22 | 23 | /** 24 | * @brief en. get global context, which depends on the GameInstance to which the object belongs 25 | * ch. 得到全局的ImguiContext, 取决于对象所属的GameInstance 26 | * 27 | * @param WorldContextObject en. Indicates the world to which the object calling this function belongs, by default, we use GWorld 28 | * ch. 指定调用此函数的对象所属的世界,默认情况下使用GWorld 29 | * 30 | * @return en. current global context 31 | * ch. 当前的ImguiContext 32 | */ 33 | UEIMGUI_API UImguiContext* GetGlobalContext(UObject* WorldContextObject = nullptr); 34 | 35 | /** 36 | * @brief en. get global input adapter, which depends on the GameInstance to which the object belongs 37 | * ch. 得到全局的InputAdapter, 取决于对象所属的GameInstance 38 | * 39 | * @param WorldContextObject en. Indicates the world to which the object calling this function belongs, by default, we use GWorld 40 | * ch. 指定调用此函数的对象所属的世界,默认情况下使用GWorld 41 | * 42 | * @return en. current global context 43 | * ch. 当前的InputAdapter 44 | */ 45 | UEIMGUI_API UImguiInputAdapter* GetGlobalInputAdapter(UObject* WorldContextObject = nullptr); 46 | 47 | /** 48 | * @brief en. add and callback for draw imgui windows 49 | * ch. 添加一个用于绘制Imgui窗口的回调 50 | * 51 | * @param InGlobalContext en. Draw callback, return should the window draw next frame, if false, it will be removed 52 | * ch. 回调应返回一个bool用于指定下一帧窗口是否应当被渲染,如果返回false, 回调会被自动移除 53 | * 54 | * 55 | * @param WorldContextObject en. Indicates the world to which the object calling this function belongs, by default, we use GWorld 56 | * ch. 指定调用此函数的对象所属的世界,默认情况下使用GWorld 57 | * 58 | * @return en. the index of callback in current global context, for remove global window 59 | * ch. 当前CallBack在回调数组中的位置,可以用来移除callback 60 | */ 61 | UEIMGUI_API int32 AddGlobalWindow(const FDrawGlobalImgui& InGlobalContext, UObject* WorldContextObject = nullptr); 62 | 63 | /** 64 | * @brief en. remove callback from callback array 65 | * ch. 从回调数组中移除某个回调 66 | * 67 | * @param InIndex en. draw callback index, witch returned by AddGlobalWindow 68 | * ch. 绘制回调的位置,由AddGlobalWindow返回 69 | * 70 | * @param WorldContextObject en. Indicates the world to which the object calling this function belongs, by default, we use GWorld 71 | * ch. 指定调用此函数的对象所属的世界,默认情况下使用GWorld 72 | */ 73 | UEIMGUI_API void RemoveGlobalWindow(int32 InIndex, UObject* WorldContextObject = nullptr); 74 | 75 | /** 76 | * @brief en. add render proxy, about render proxy, see also IImguiViewport and SImguiRenderProxy 77 | * ch. 添加一个渲染代理, 关于渲染代理, 参见IImguiViewport和SImguiRenderProxy 78 | * 79 | * @param InRenderProxy en. the render proxy we want to add 80 | * ch. 期望添加的渲染代理 81 | * 82 | * @param WorldContextObject en. Indicates the world to which the object calling this function belongs, by default, we use GWorld 83 | * ch. 指定调用此函数的对象所属的世界,默认情况下使用GWorld 84 | */ 85 | UEIMGUI_API void AddRenderProxy(TWeakPtr InRenderProxy, UObject* WorldContextObject = nullptr); 86 | 87 | /** 88 | * @brief en. remove render proxy, about render proxy, see also IImguiViewport and SImguiRenderProxy 89 | * ch. 移除一个渲染代理, 关于渲染代理, 参见IImguiViewport和SImguiRenderProxy 90 | * 91 | * @param InRenderProxy en. the render proxy we want to remove 92 | * ch. 期望移除的渲染代理 93 | * 94 | * @param WorldContextObject en. Indicates the world to which the object calling this function belongs, by default, we use GWorld 95 | * ch. 指定调用此函数的对象所属的世界,默认情况下使用GWorld 96 | */ 97 | UEIMGUI_API void RemoveRenderProxy(TWeakPtr InRenderProxy, UObject* WorldContextObject = nullptr); 98 | } 99 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/ImguiWrap/ImguiGlobalInputHook.cpp: -------------------------------------------------------------------------------- 1 | #include "ImguiWrap/ImguiGlobalInputHook.h" 2 | 3 | #include "imgui.h" 4 | #include "imgui_internal.h" 5 | #include "ImguiWrap/ImguiContext.h" 6 | #include "ImguiWrap/ImguiInputAdapter.h" 7 | 8 | void FImguiGlobalInputHook::Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef Cursor) 9 | { 10 | } 11 | 12 | bool FImguiGlobalInputHook::HandleKeyDownEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent) 13 | { 14 | // for (UImguiInputAdapter* Adapter : TargetAdapters) 15 | // { 16 | // if (!Adapter->GetContext()) continue; 17 | // if (Adapter->GetContext()->GetIO()->WantCaptureMouse) 18 | // { 19 | // Adapter->OnKeyDown(InKeyEvent); 20 | // } 21 | // } 22 | return false; 23 | } 24 | 25 | bool FImguiGlobalInputHook::HandleKeyUpEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent) 26 | { 27 | for (UImguiInputAdapter* Adapter : TargetAdapters) 28 | { 29 | if (!Adapter->GetContext() || !Adapter->GetContext()->IsInit()) continue; 30 | // up event never block 31 | // if (Adapter->GetContext()->GetIO()->WantCaptureKeyboard) 32 | { 33 | Adapter->OnKeyUp(InKeyEvent); 34 | } 35 | } 36 | return false; 37 | } 38 | 39 | bool FImguiGlobalInputHook::HandleAnalogInputEvent(FSlateApplication& SlateApp, 40 | const FAnalogInputEvent& InAnalogInputEvent) 41 | { 42 | // for (UImguiInputAdapter* Adapter : TargetAdapters) 43 | // { 44 | // 45 | // } 46 | return false; 47 | } 48 | 49 | bool FImguiGlobalInputHook::HandleMouseMoveEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) 50 | { 51 | for (UImguiInputAdapter* Adapter : TargetAdapters) 52 | { 53 | if (!Adapter->GetContext() || !Adapter->GetContext()->IsInit()) continue; 54 | if (Adapter->GetContext()->GetIO()->WantCaptureMouse) 55 | { 56 | Adapter->OnMouseMove(FVector2D::ZeroVector, MouseEvent); 57 | } 58 | } 59 | return false; 60 | } 61 | 62 | bool FImguiGlobalInputHook::HandleMouseButtonDownEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) 63 | { 64 | for (UImguiInputAdapter* Adapter : TargetAdapters) 65 | { 66 | if (!Adapter->GetContext() || !Adapter->GetContext()->IsInit()) continue; 67 | if (Adapter->GetContext()->GetIO()->WantCaptureMouse) 68 | { 69 | Adapter->OnMouseButtonDown(MouseEvent); 70 | } 71 | } 72 | return false; 73 | } 74 | 75 | bool FImguiGlobalInputHook::HandleMouseButtonUpEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) 76 | { 77 | for (UImguiInputAdapter* Adapter : TargetAdapters) 78 | { 79 | if (!Adapter->GetContext() || !Adapter->GetContext()->IsInit()) continue; 80 | // up event never block 81 | // if (Adapter->GetContext()->GetIO()->WantCaptureMouse) 82 | { 83 | Adapter->OnMouseButtonUp(MouseEvent); 84 | } 85 | } 86 | return false; 87 | } 88 | 89 | bool FImguiGlobalInputHook::HandleMouseButtonDoubleClickEvent(FSlateApplication& SlateApp, 90 | const FPointerEvent& MouseEvent) 91 | { 92 | // for (UImguiInputAdapter* Adapter : TargetAdapters) 93 | // { 94 | // Adapter->OnMouseButtonDoubleClick(MouseEvent); 95 | // } 96 | return false; 97 | } 98 | 99 | bool FImguiGlobalInputHook::HandleMouseWheelOrGestureEvent(FSlateApplication& SlateApp, 100 | const FPointerEvent& InWheelEvent, const FPointerEvent* InGestureEvent) 101 | { 102 | // for (UImguiInputAdapter* Adapter : TargetAdapters) 103 | // { 104 | // Adapter->OnMouseWheel(InWheelEvent); 105 | // } 106 | return false; 107 | } 108 | 109 | bool FImguiGlobalInputHook::HandleMotionDetectedEvent(FSlateApplication& SlateApp, const FMotionEvent& MotionEvent) 110 | { 111 | // for (UImguiInputAdapter* Adapter : TargetAdapters) 112 | // { 113 | // 114 | // } 115 | return false; 116 | } 117 | 118 | void FImguiGlobalInputHook::AddReferencedObjects(FReferenceCollector& Collector) 119 | { 120 | Collector.AddReferencedObjects(TargetAdapters); 121 | } 122 | 123 | TSharedPtr FImguiGlobalInputHook::Get() 124 | { 125 | static TSharedPtr Instance; 126 | if (!FSlateApplication::IsInitialized()) return nullptr; 127 | if (!Instance.IsValid()) 128 | { 129 | Instance = MakeShared(); 130 | FSlateApplication::Get().RegisterInputPreProcessor(Instance); 131 | } 132 | return Instance; 133 | } 134 | 135 | void FImguiGlobalInputHook::AddAdapter(UImguiInputAdapter* InInputAdapter) 136 | { 137 | check(InInputAdapter); 138 | TargetAdapters.AddUnique(InInputAdapter); 139 | } 140 | 141 | void FImguiGlobalInputHook::RemoveAdapter(UImguiInputAdapter* InInputAdapter) 142 | { 143 | check(InInputAdapter); 144 | TargetAdapters.Remove(InInputAdapter); 145 | } -------------------------------------------------------------------------------- /Source/UEImgui/Private/ImguiWrap/ImguiResourceManager.cpp: -------------------------------------------------------------------------------- 1 | #include "ImguiWrap/ImguiResourceManager.h" 2 | #include "imgui.h" 3 | #include "Logging.h" 4 | #include "Config/ImguiConfig.h" 5 | #include "ImguiWrap/ImguiContext.h" 6 | #include "Slate/SlateTextureAtlasInterface.h" 7 | 8 | FImguiResource::FImguiResource(const FName& InName, UTexture* SourceObject) 9 | : Name(InName) 10 | , Source(SourceObject) 11 | { 12 | check(SourceObject != nullptr); 13 | } 14 | 15 | UImguiResourceManager::UImguiResourceManager() 16 | : CurrentResIdx(1) 17 | , DefaultFont(nullptr) 18 | { 19 | _InitDefaultFont(); 20 | } 21 | 22 | UImguiResourceManager& UImguiResourceManager::Get() 23 | { 24 | static UImguiResourceManager* Ins = nullptr; 25 | if (!Ins) 26 | { 27 | Ins = NewObject(); 28 | Ins->AddToRoot(); 29 | } 30 | 31 | return *Ins; 32 | } 33 | 34 | ImTextureID UImguiResourceManager::AddResource(FName InResName, UTexture* SourceObj) 35 | { 36 | // find resource 37 | auto FoundRes = NamedResourceMap.Find(InResName); 38 | if (FoundRes) 39 | { 40 | UE_LOG(LogUEImgui, Warning, TEXT("UImguiResourceManager::AddResource : resource %s has exist!!!"), *InResName.ToString()); 41 | return reinterpret_cast((SIZE_T)*FoundRes); 42 | } 43 | 44 | // add resource 45 | int32 GotId = CurrentResIdx++; 46 | AllResource.Add(GotId, FImguiResource(InResName, (UTexture*)SourceObj)); 47 | NamedResourceMap.Add(InResName, GotId); 48 | 49 | return reinterpret_cast((SIZE_T)GotId); 50 | } 51 | 52 | bool UImguiResourceManager::IsResourceExist(FName InResName) 53 | { 54 | return NamedResourceMap.Find(InResName) != nullptr; 55 | } 56 | 57 | bool UImguiResourceManager::IsResourceExist(ImTextureID InID) 58 | { 59 | return AllResource.Find((int32)reinterpret_cast(InID)) != nullptr; 60 | } 61 | 62 | FImguiResource* UImguiResourceManager::FindResource(FName InResName) 63 | { 64 | auto FoundID = NamedResourceMap.Find(InResName); 65 | if (!FoundID) return nullptr; 66 | return AllResource.Find(*FoundID); 67 | } 68 | 69 | FImguiResource* UImguiResourceManager::FindResource(ImTextureID InResId) 70 | { 71 | return AllResource.Find((int32)reinterpret_cast(InResId)); 72 | } 73 | 74 | void UImguiResourceManager::ReleaseResource(FName InResName) 75 | { 76 | auto FoundRes = NamedResourceMap.Find(InResName); 77 | if (FoundRes) 78 | { 79 | AllResource.Remove(*FoundRes); 80 | NamedResourceMap.Remove(InResName); 81 | } 82 | } 83 | 84 | void UImguiResourceManager::ReleaseResource(ImTextureID InID) 85 | { 86 | int32 UEId = (int32)reinterpret_cast(InID); 87 | auto FoundRes = AllResource.Find(UEId); 88 | if (FoundRes) 89 | { 90 | NamedResourceMap.Remove(FoundRes->Name); 91 | AllResource.Remove(UEId); 92 | } 93 | } 94 | 95 | void UImguiResourceManager::BeginDestroy() 96 | { 97 | Super::BeginDestroy(); 98 | _ShutDownDefaultFont(); 99 | } 100 | 101 | void UImguiResourceManager::_InitDefaultFont() 102 | { 103 | DefaultFont = IM_NEW(ImFontAtlas); 104 | 105 | // get unreal default font 106 | #if WITH_EDITOR 107 | const FCompositeFont* CompositeFont = FCoreStyle::Get(). 108 | GetWidgetStyle("NormalText").Font.GetCompositeFont(); 109 | FString FontPath = CompositeFont->DefaultTypeface.Fonts[0].Font.GetFontFilename(); 110 | FString FallbackPath = CompositeFont->FallbackTypeface.Typeface.Fonts[0].Font.GetFontFilename(); 111 | 112 | // add font 113 | DefaultFont->AddFontFromFileTTF( 114 | TCHAR_TO_UTF8(*FontPath), 15.0f, nullptr, DefaultFont->GetGlyphRangesDefault()); 115 | ImFontConfig FontConfig = {}; 116 | FontConfig.MergeMode = true; 117 | FontConfig.SizePixels = 15.0f; 118 | DefaultFont->AddFontFromFileTTF( 119 | TCHAR_TO_UTF8(*FallbackPath), 15.0f, &FontConfig, DefaultFont->GetGlyphRangesChineseFull()); 120 | #else 121 | if (UImguiConfig::Get()->FontPath.IsEmpty()) 122 | { 123 | DefaultFont->AddFontDefault(); 124 | } 125 | else 126 | { 127 | DefaultFont->AddFontFromFileTTF( 128 | TCHAR_TO_UTF8(*UImguiConfig::Get()->FontPath), 15.0f, nullptr, DefaultFont->GetGlyphRangesDefault()); 129 | ImFontConfig FontConfig = {}; 130 | FontConfig.MergeMode = true; 131 | FontConfig.SizePixels = 15.0f; 132 | DefaultFont->AddFontFromFileTTF( 133 | TCHAR_TO_UTF8(*UImguiConfig::Get()->FontPath), 15.0f, &FontConfig, DefaultFont->GetGlyphRangesChineseFull()); 134 | } 135 | #endif 136 | 137 | // get texture info 138 | unsigned char* Pixels; 139 | int Width, Height, Bpp; 140 | DefaultFont->GetTexDataAsRGBA32(&Pixels, &Width, &Height, &Bpp); 141 | 142 | // copy to UTexture2D 143 | UTexture2D* Texture = UTexture2D::CreateTransient(Width, Height, EPixelFormat::PF_B8G8R8A8, 144 | TEXT("Imgui_DefaultFont")); 145 | Texture->UpdateResource(); 146 | FUpdateTextureRegion2D* TextureRegion = new FUpdateTextureRegion2D(0, 0, 0, 0, Width, Height); 147 | auto DataCleanup = [](uint8* Data, const FUpdateTextureRegion2D* UpdateRegion) 148 | { 149 | delete UpdateRegion; 150 | }; 151 | Texture->UpdateTextureRegions(0, 1u, TextureRegion, Bpp * Width, Bpp, Pixels, DataCleanup); 152 | 153 | // add to resource map 154 | AllResource.Add((int32)EGlobalImguiTextureId::DefaultFont, FImguiResource("DefaultFont", Texture)); 155 | NamedResourceMap.Add("DefaultFont", (int32)EGlobalImguiTextureId::DefaultFont); 156 | 157 | // setup font 158 | DefaultFont->TexID = reinterpret_cast(EGlobalImguiTextureId::DefaultFont); 159 | } 160 | 161 | void UImguiResourceManager::_ShutDownDefaultFont() 162 | { 163 | IM_DELETE(DefaultFont); 164 | } 165 | -------------------------------------------------------------------------------- /Source/UEImguiEditor/Private/UEImguiEditor.cpp: -------------------------------------------------------------------------------- 1 | #include "UEImguiEditor.h" 2 | #include "imgui.h" 3 | #include "implot.h" 4 | #include "LevelEditor.h" 5 | #include "Logging.h" 6 | #include "Customize/ImguiDetailCustomization.h" 7 | #include "Extension/SmallWidgets.h" 8 | #include "ImguiWrap/ImguiUEWrap.h" 9 | #include "Modules/ModuleManager.h" 10 | #include "Service/ImguiCustomDetailService.h" 11 | #include "Services/ImguiGlobalContextService.h" 12 | #include "Widgets/SImguiWidget.h" 13 | #include "Widgets/Docking/SDockTab.h" 14 | #include "Widgets/Input/SEditableText.h" 15 | 16 | #define LOCTEXT_NAMESPACE "FUEImguiEditor" 17 | class FLevelEditorModule; 18 | 19 | void FUEImguiEditor::StartupModule() 20 | { 21 | _InitDetailExtension(); 22 | _InitMenu(); 23 | 24 | ImPlotCtx = ImPlot::CreateContext(); 25 | } 26 | 27 | void FUEImguiEditor::ShutdownModule() 28 | { 29 | _ShutDownDetailExtension(); 30 | _ShutDownMenu(); 31 | ImPlot::DestroyContext(ImPlotCtx); 32 | } 33 | 34 | void FUEImguiEditor::_InitDetailExtension() 35 | { 36 | if (!AActor::StaticClass()->FindPropertyByName(TEXT("ImguiDummy"))) 37 | { 38 | FStructProperty* DummyProperty = new FStructProperty(AActor::StaticClass() 39 | , TEXT("ImguiDummy"), EObjectFlags::RF_NoFlags); 40 | DummyProperty->Struct = FImguiDummy::StaticStruct(); 41 | DummyProperty->PropertyFlags |= EPropertyFlags::CPF_Transient; 42 | DummyProperty->PropertyFlags |= EPropertyFlags::CPF_EditConst; 43 | DummyProperty->PropertyFlags |= EPropertyFlags::CPF_Edit; 44 | DummyProperty->SetMetaData(TEXT("Category"), TEXT("Imgui")); 45 | AActor::StaticClass()->AddCppProperty(DummyProperty); 46 | } 47 | 48 | FPropertyEditorModule& PropertyEditorModule = FModuleManager::LoadModuleChecked("PropertyEditor"); 49 | PropertyEditorModule.RegisterCustomPropertyTypeLayout( 50 | TEXT("ImguiDummy"), 51 | FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FImguiDetailCustomization::MakeInstance)); 52 | 53 | PropertyEditorModule.NotifyCustomizationModuleChanged(); 54 | } 55 | 56 | void FUEImguiEditor::_ShutDownDetailExtension() 57 | { 58 | if (FModuleManager::Get().IsModuleLoaded("PropertyEditor")) 59 | { 60 | FPropertyEditorModule& PropertyEditorModule = FModuleManager::LoadModuleChecked("PropertyEditor"); 61 | PropertyEditorModule.UnregisterCustomPropertyTypeLayout("ImguiDummy"); 62 | } 63 | } 64 | 65 | void FUEImguiEditor::_InitMenu() 66 | { 67 | // Get level editor module 68 | FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); 69 | 70 | auto ExtendMenu = [](FMenuBuilder& InBuilder) 71 | { 72 | InBuilder.AddMenuEntry(FText::FromString(TEXT("Open ImGui Demo")), FText::GetEmpty(), FSlateIcon(), 73 | FUIAction(FExecuteAction::CreateLambda([] 74 | { 75 | UEImGui::AddGlobalWindow(FDrawGlobalImgui::CreateLambda([] 76 | { 77 | bool IsOpen = true; 78 | ImGui::ShowDemoWindow(&IsOpen); 79 | return IsOpen; 80 | })); 81 | }))); 82 | 83 | InBuilder.AddMenuEntry(FText::FromString(TEXT("Open ImPlot Demo")), FText::GetEmpty(), FSlateIcon(), 84 | FUIAction(FExecuteAction::CreateLambda([] 85 | { 86 | UEImGui::AddGlobalWindow(FDrawGlobalImgui::CreateLambda([] 87 | { 88 | bool IsOpen = true; 89 | ImPlot::ShowDemoWindow(&IsOpen); 90 | return IsOpen; 91 | })); 92 | }))); 93 | 94 | InBuilder.AddMenuEntry(FText::FromString(TEXT("Open Small Widget Demo")), FText::GetEmpty(), FSlateIcon(), 95 | FUIAction(FExecuteAction::CreateLambda([] 96 | { 97 | UEImGui::AddGlobalWindow(FDrawGlobalImgui::CreateLambda([] 98 | { 99 | bool IsOpen = true; 100 | ImGui::SetNextWindowSize(ImVec2(500, 800), ImGuiCond_Appearing); 101 | ImGui::Begin("Imgui Small Widget Demo", &IsOpen); 102 | ImGui::DrawSmallWidgetDemo(); 103 | ImGui::End(); 104 | return IsOpen; 105 | })); 106 | }))); 107 | 108 | InBuilder.AddMenuEntry(FText::FromString(TEXT("Open Text Editor Demo")), FText::GetEmpty(), FSlateIcon(), 109 | FUIAction(FExecuteAction::CreateLambda([] 110 | { 111 | UEImGui::AddGlobalWindow(FDrawGlobalImgui::CreateLambda([] 112 | { 113 | bool IsOpen = true; 114 | ImGui::SetNextWindowSize(ImVec2(500, 800), ImGuiCond_Appearing); 115 | ImGui::Begin("Imgui Text Editor Demo", &IsOpen, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoNav); 116 | ImGui::DrawTextEditorDemo(&IsOpen); 117 | ImGui::End(); 118 | return IsOpen; 119 | })); 120 | }))); 121 | 122 | InBuilder.AddMenuEntry(FText::FromString(TEXT("Open Style Editor")), FText::GetEmpty(), FSlateIcon(), 123 | FUIAction(FExecuteAction::CreateLambda([] 124 | { 125 | UEImGui::AddGlobalWindow(FDrawGlobalImgui::CreateLambda([] 126 | { 127 | bool IsOpen = true; 128 | ImGui::SetNextWindowSize(ImVec2(500, 800), ImGuiCond_Appearing); 129 | ImGui::Begin("ImguiStyleEditor", &IsOpen); 130 | ImGui::ShowUEStyleEditor(); 131 | ImGui::End(); 132 | return IsOpen; 133 | })); 134 | }))); 135 | }; 136 | 137 | auto ExtendMenuBar = [&](FMenuBarBuilder& InBuilder) 138 | { 139 | InBuilder.AddPullDownMenu( 140 | FText::FromString(TEXT("Imgui")), 141 | FText::FromString(TEXT("Imgui")), 142 | FNewMenuDelegate::CreateLambda(ExtendMenu)); 143 | }; 144 | 145 | TSharedPtr MenuExtender = MakeShareable(new FExtender()); 146 | MenuExtender->AddMenuBarExtension( 147 | "Help", 148 | EExtensionHook::After, 149 | nullptr, 150 | FMenuBarExtensionDelegate::CreateLambda(ExtendMenuBar)); 151 | LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender); 152 | } 153 | 154 | void FUEImguiEditor::_ShutDownMenu() 155 | { 156 | } 157 | 158 | 159 | #undef LOCTEXT_NAMESPACE 160 | 161 | IMPLEMENT_MODULE(FUEImguiEditor, UEImguiEditor); -------------------------------------------------------------------------------- /Source/UEImgui/Public/Widgets/SImguiWidget.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | #include "imgui.h" 4 | #include "ImguiWrap/ImguiInputAdapterDeferred.h" 5 | #include "Services/ImguiGlobalContextService.h" 6 | #include "Widgets/SWidget.h" 7 | #include "Window/IImguiViewport.h" 8 | 9 | class UImguiContext; 10 | class UImguiInputAdapter; 11 | 12 | DECLARE_DELEGATE(FOnImguiDraw); 13 | 14 | /** 15 | * @brief Imgui sizing rule, control the policy between UE widget size and Imgui widget size 16 | */ 17 | enum class EImguiSizingRule 18 | { 19 | // en. Desired size is zero, and we won't control imgui wnd size 20 | // ch. Desired size 是0(不占用空间), 并且我们不会改变Imgui window的大小 21 | NoSizing , 22 | 23 | // en. Desired size is zero, and we use UE Widget size as imgui wnd size 24 | // ch. Desired size 是0(不占用空间), 并且我们会根据控件的大小来决定Imgui window的大小 25 | UESize , 26 | 27 | // en. Desired is imgui wnd size 28 | // ch. Desired size 是imgui window的大小 29 | ImSize , 30 | 31 | // en. Desired is imgui size, and we will use wnd content size 32 | // ch. Desired size 是Imgui window内容的大小, 同时我们也会更新imgui window的大小以适应内容 33 | ImContentSize , 34 | }; 35 | 36 | /** 37 | * @brief en. Render proxy can steal render data that assigned by ProxyWndName or PersistWndID 38 | * ch. Render Proxy 可以从渲染数据中"偷"出对应窗口的Viewport来自己渲染,这个窗口由初始化传入的ProxyWndName计算的PersistWndID决定 39 | */ 40 | class UEIMGUI_API SImguiRenderProxy : public SLeafWidget, public FGCObject, public IImguiViewport 41 | { 42 | using Super = SLeafWidget; 43 | public: 44 | SLATE_BEGIN_ARGS(SImguiRenderProxy) 45 | : _InContext(nullptr) 46 | , _InAdapter(nullptr) 47 | , _HSizingRule(EImguiSizingRule::NoSizing) 48 | , _VSizingRule(EImguiSizingRule::NoSizing) 49 | , _ProxyWndName(nullptr) 50 | , _AutoSetWidgetPos(true) 51 | , _BlockInput(true) 52 | , _BlockWheel(false) 53 | {} 54 | SLATE_ARGUMENT(UImguiContext*, InContext) 55 | SLATE_ARGUMENT(UImguiInputAdapter*, InAdapter) 56 | SLATE_ARGUMENT(EImguiSizingRule, HSizingRule) 57 | SLATE_ARGUMENT(EImguiSizingRule, VSizingRule) 58 | SLATE_ARGUMENT(const char*, ProxyWndName) 59 | SLATE_ARGUMENT(bool, AutoSetWidgetPos) 60 | SLATE_ARGUMENT(bool, BlockInput) 61 | SLATE_ARGUMENT(bool, BlockWheel) 62 | SLATE_ATTRIBUTE(EVisibility, Visibility) 63 | SLATE_END_ARGS() 64 | 65 | void Construct(const FArguments& InArgs); 66 | 67 | UImguiContext* GetContext() const { return Context; } 68 | UImguiInputAdapter* GetAdapter() const { return Adapter; } 69 | void SetContext(UImguiContext* InContext); 70 | void SetAdapter(UImguiInputAdapter* InAdapter); 71 | 72 | ImGuiID GetPersistWndID() const { return PersistWndID; } 73 | void SetPersistWndID(ImGuiID InID) { PersistWndID = InID; } 74 | protected: 75 | // ~Begin FGCObject API 76 | virtual void AddReferencedObjects(FReferenceCollector& Collector) override; 77 | virtual FString GetReferencerName() const override; 78 | // ~End FGCObject API 79 | 80 | // ~Begin SWidget API 81 | // receive key input 82 | virtual FReply OnKeyChar(const FGeometry& MyGeometry, const FCharacterEvent& InCharacterEvent) override; 83 | virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override; 84 | virtual FReply OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override; 85 | 86 | // receive mouse input 87 | virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; 88 | virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; 89 | virtual FReply OnMouseButtonDoubleClick(const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent) override; 90 | virtual FReply OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; 91 | virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; 92 | 93 | // Focus 94 | virtual bool SupportsKeyboardFocus() const override; 95 | virtual void OnFocusLost(const FFocusEvent& InFocusEvent) override; 96 | virtual FReply OnFocusReceived(const FGeometry& MyGeometry, const FFocusEvent& InFocusEvent) override; 97 | 98 | // Cursor 99 | virtual FCursorReply OnCursorQuery(const FGeometry& MyGeometry, const FPointerEvent& CursorEvent) const override; 100 | 101 | // paint and size 102 | virtual int32 OnPaint( 103 | const FPaintArgs& Args, 104 | const FGeometry& AllottedGeometry, 105 | const FSlateRect& MyCullingRect, 106 | FSlateWindowElementList& OutDrawElements, 107 | int32 LayerId, 108 | const FWidgetStyle& InWidgetStyle, 109 | bool bParentEnabled) const override; 110 | virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override; 111 | virtual FVector2D ComputeDesiredSize(float) const override; 112 | // ~End SWidget API 113 | 114 | // ~Begin IImguiViewport API 115 | virtual void SetupContext(UImguiContext* InCtx) override { SetContext(InCtx); } 116 | virtual TSharedPtr GetWindow() override { return CachedWnd.Pin(); } 117 | virtual void Show(TSharedPtr InParent) override { } 118 | virtual bool IsPersist() override { return true; } 119 | virtual ImGuiID GetPersistWindowID() override { return PersistWndID; } 120 | virtual void Update() override {} 121 | virtual FVector2D GetPos() override { return GetPaintSpaceGeometry().GetAbsolutePosition(); } 122 | virtual void SetPos(FVector2D InPos) override {} 123 | virtual FVector2D GetSize() override { return GetPaintSpaceGeometry().GetAbsoluteSize(); } 124 | virtual void SetSize(FVector2D InSize) override {} 125 | virtual bool GetFocus() override { return bHasFocus; } 126 | virtual void SetFocus() override { FSlateApplication::Get().SetUserFocus(0, AsShared()); } 127 | virtual bool GetMinimized() override { return CachedWnd.IsValid() ? CachedWnd.Pin()->IsWindowMinimized() : false; } 128 | virtual void SetTitle(const char* InTitle) override { } 129 | virtual void SetAlpha(float InAlpha) override { } 130 | virtual void SetupViewport(ImGuiViewport* InViewport) override { BoundViewport = InViewport; } 131 | virtual void SetupInputAdapter(UImguiInputAdapter* ImguiInputAdapter) override { SetAdapter(ImguiInputAdapter); } 132 | virtual float GetDpiScale() override; 133 | // ~End IImguiViewport API 134 | private: 135 | EVisibility _GetVisibility() const; 136 | protected: 137 | // cached top side window 138 | mutable TWeakPtr CachedWnd; 139 | 140 | // imgui state 141 | UImguiContext* Context; 142 | UImguiInputAdapter* Adapter; 143 | ImGuiViewport* BoundViewport; 144 | 145 | // proxy settings 146 | ImGuiID PersistWndID; 147 | EImguiSizingRule HSizingRule; 148 | EImguiSizingRule VSizingRule; 149 | bool bAutoSetWidgetPos; 150 | bool bHasFocus; 151 | bool bBlockInput; 152 | bool bBlockWheel; 153 | }; 154 | -------------------------------------------------------------------------------- /Source/UEImguiEditor/Private/Customize/ImguiDetailCustomization.cpp: -------------------------------------------------------------------------------- 1 | #include "ImguiDetailCustomization.h" 2 | #include "DetailCategoryBuilder.h" 3 | #include "DetailLayoutBuilder.h" 4 | #include "DetailWidgetRow.h" 5 | #include "IDetailChildrenBuilder.h" 6 | #include "imgui.h" 7 | #include "imgui_internal.h" 8 | #include "ImguiWrap/ImguiUEWrap.h" 9 | #include "Service/ImguiCustomDetailService.h" 10 | #include "Services/ImguiGlobalContextService.h" 11 | #include "Widgets/SImguiWidget.h" 12 | 13 | TSharedRef FImguiDetailCustomization::MakeInstance() 14 | { 15 | return MakeShareable(new FImguiDetailCustomization); 16 | } 17 | 18 | void FImguiDetailCustomization::CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, 19 | IPropertyTypeCustomizationUtils& CustomizationUtils) 20 | { 21 | } 22 | 23 | void FImguiDetailCustomization::CustomizeChildren( 24 | TSharedRef PropertyHandle, 25 | IDetailChildrenBuilder& ChildBuilder, 26 | IPropertyTypeCustomizationUtils& CustomizationUtils) 27 | { 28 | // not time 29 | if (!UEImGui::TimeToDraw()) return; 30 | 31 | // get detail name 32 | FName DetailName = ChildBuilder.GetParentCategory().GetParentLayout().GetDetailsView()->GetIdentifier(); 33 | 34 | // find object and functions 35 | TArray Objs; 36 | PropertyHandle->GetOuterObjects(Objs); 37 | 38 | if (Objs.Num() == 0) return;; 39 | if (Objs.Num() == 1) 40 | { 41 | _DrawSingleObj(DetailName, Objs, ChildBuilder); 42 | } 43 | else 44 | { 45 | UClass* LowestClass = Objs[0]->GetClass(); 46 | for (UObject* Obj : Objs) 47 | { 48 | while (!Obj->GetClass()->IsChildOf(LowestClass)) 49 | { 50 | LowestClass = LowestClass->GetSuperClass(); 51 | } 52 | } 53 | _DrawMultObj(DetailName, Objs, ChildBuilder, LowestClass); 54 | } 55 | 56 | } 57 | 58 | void FImguiDetailCustomization::_DrawMultObj(FName DetailName, const TArray& InObjs, 59 | IDetailChildrenBuilder& ChildBuilder, UClass* LowestClass) 60 | { 61 | // cast weak ptr 62 | TArray> AllObjs; 63 | AllObjs.Reserve(InObjs.Num()); 64 | for (UObject* Obj : InObjs) 65 | { 66 | AllObjs.Emplace(Obj); 67 | } 68 | 69 | // find detail customization 70 | TArray AllCustomization = UImguiCustomDetailService::Get() 71 | .GetAllDetailCustomizationOfClass(LowestClass); 72 | 73 | // cull not support multi object items 74 | for (int32 i = 0; i < AllCustomization.Num();) 75 | { 76 | if (!AllCustomization[i]->SupportMultiObjectEditing()) 77 | { 78 | AllCustomization.RemoveAtSwap(i); 79 | } 80 | else 81 | { 82 | ++i; 83 | } 84 | } 85 | 86 | if (AllCustomization.Num() == 0) return; 87 | 88 | // edit category 89 | IDetailCategoryBuilder& CategoryBuilder = ChildBuilder.GetParentCategory().GetParentLayout() 90 | .EditCategory( 91 | FName(LowestClass->GetName() + TEXT("Imgui")), 92 | FText::FromString(LowestClass->GetName() + TEXT("Imgui")), 93 | ECategoryPriority::Important); 94 | 95 | // set widget 96 | TSharedPtr RenderProxy; 97 | CategoryBuilder.AddCustomRow(FText::FromString(TEXT("Imgui")), false) 98 | .WholeRowWidget 99 | [ 100 | SAssignNew(RenderProxy, SImguiRenderProxy) 101 | .InContext(UEImGui::GetGlobalContext()) 102 | .InAdapter(UEImGui::GetGlobalInputAdapter()) 103 | .HSizingRule(EImguiSizingRule::UESize) 104 | .VSizingRule(EImguiSizingRule::ImContentSize) 105 | ]; 106 | ImGuiID WndID = ImHashStr(TCHAR_TO_UTF8(*DetailName.ToString())); 107 | RenderProxy->SetPersistWndID(WndID); 108 | 109 | // add window 110 | UEImGui::AddGlobalWindow(FDrawGlobalImgui::CreateLambda( 111 | [DetailName, RenderProxy, AllCustomization, AllObjs] 112 | { 113 | if (RenderProxy.IsUnique()) return false; 114 | ImGui::SetCurrentDetail(DetailName); 115 | ImGui::SetCurrentDetailWidget(RenderProxy); 116 | for (UImguiDetailCustomization* Customization : AllCustomization) 117 | { 118 | static TArray Objs; 119 | Objs.Reset(); 120 | for (auto & Obj : AllObjs) 121 | { 122 | auto GotObj = Obj.Get(); 123 | if (GotObj) 124 | { 125 | Objs.Add(GotObj); 126 | } 127 | } 128 | Customization->OnEditMultiObject(Objs); 129 | } 130 | return true; 131 | })); 132 | UEImGui::AddRenderProxy(RenderProxy); 133 | } 134 | 135 | void FImguiDetailCustomization::_DrawSingleObj(FName DetailName, const TArray& InObjs, IDetailChildrenBuilder& ChildBuilder) 136 | { 137 | TWeakObjectPtr Obj = InObjs[0]; 138 | 139 | // find OnGUI 140 | UFunction* OnGUIFunc = Obj->GetClass()->FindFunctionByName(TEXT("OnGUI")); 141 | if (OnGUIFunc && (OnGUIFunc->NumParms != 0 || OnGUIFunc->ReturnValueOffset != 65535)) 142 | { 143 | OnGUIFunc = nullptr; 144 | } 145 | 146 | // find detail customization 147 | TArray AllCustomization = UImguiCustomDetailService::Get() 148 | .GetAllDetailCustomizationOfClass(Obj->GetClass()); 149 | 150 | // cull not support single object items 151 | for (int32 i = 0; i < AllCustomization.Num();) 152 | { 153 | if (!AllCustomization[i]->SupportSingleObjectEditing()) 154 | { 155 | AllCustomization.RemoveAtSwap(i); 156 | } 157 | else 158 | { 159 | ++i; 160 | } 161 | } 162 | 163 | if (!OnGUIFunc && AllCustomization.Num() == 0) return; 164 | 165 | // edit category 166 | IDetailCategoryBuilder& CategoryBuilder = ChildBuilder.GetParentCategory().GetParentLayout() 167 | .EditCategory( 168 | FName(Obj->GetClass()->GetName() + TEXT("Imgui")), 169 | FText::GetEmpty(), 170 | ECategoryPriority::Important); 171 | 172 | // set widget 173 | TSharedPtr RenderProxy; 174 | CategoryBuilder.AddCustomRow(FText::FromString(TEXT("Imgui")), false) 175 | .WholeRowWidget 176 | [ 177 | SAssignNew(RenderProxy, SImguiRenderProxy) 178 | .InContext(UEImGui::GetGlobalContext()) 179 | .InAdapter(UEImGui::GetGlobalInputAdapter()) 180 | .HSizingRule(EImguiSizingRule::UESize) 181 | .VSizingRule(EImguiSizingRule::ImContentSize) 182 | ]; 183 | ImGuiID WndID = ImHashStr(TCHAR_TO_UTF8(*DetailName.ToString())); 184 | RenderProxy->SetPersistWndID(WndID); 185 | 186 | // add window 187 | UEImGui::AddGlobalWindow(FDrawGlobalImgui::CreateLambda( 188 | [Obj, OnGUIFunc, DetailName, RenderProxy, AllCustomization] 189 | { 190 | if (RenderProxy.IsUnique()) return false; 191 | UObject* GotObj = Obj.Get(); 192 | if (!GotObj) return false; 193 | 194 | // set up detail info 195 | ImGui::SetCurrentDetail(DetailName); 196 | ImGui::SetCurrentDetailWidget(RenderProxy); 197 | 198 | // call on gui 199 | if (OnGUIFunc) 200 | { 201 | FFrame Stack(GotObj, OnGUIFunc, nullptr); 202 | OnGUIFunc->Invoke(GotObj, Stack, nullptr); 203 | } 204 | 205 | // call customization 206 | for (UImguiDetailCustomization* Customization : AllCustomization) 207 | { 208 | Customization->OnEditSingleObject(GotObj); 209 | } 210 | return true; 211 | })); 212 | UEImGui::AddRenderProxy(RenderProxy); 213 | } 214 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Services/ImguiGlobalContextService.cpp: -------------------------------------------------------------------------------- 1 | #include "Services/ImguiGlobalContextService.h" 2 | #include "ImguiPerInstanceCtx.h" 3 | #include "imgui_internal.h" 4 | #include "Logging.h" 5 | #include "Config/ImguiConfig.h" 6 | #include "ImguiWrap/ImguiContext.h" 7 | #include "ImguiWrap/ImguiGlobalInputHook.h" 8 | #include "ImguiWrap/ImguiInputAdapter.h" 9 | #include "ImguiWrap/ImguiInputAdapterDeferred.h" 10 | #include "ImguiWrap/ImguiResourceManager.h" 11 | 12 | #if WITH_EDITOR 13 | #define protected public 14 | #define private public 15 | #include "LevelEditorViewport.h" 16 | #include "LevelEditor.h" 17 | #include "ILevelEditor.h" 18 | #if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION <= 23 19 | #include "ILevelViewport.h" 20 | #endif 21 | #include "SEditorViewport.h" 22 | class FEditorGlobalContextGuard 23 | { 24 | public: 25 | FEditorGlobalContextGuard() 26 | { 27 | FCoreDelegates::OnPostEngineInit.AddLambda([this] 28 | { 29 | if(FSlateApplication::IsInitialized() && GEditor) 30 | { 31 | FSlateApplication::Get().OnPreTick().AddRaw(this, &FEditorGlobalContextGuard::Tick); 32 | } 33 | }); 34 | 35 | FCoreDelegates::OnEnginePreExit.AddLambda([this] 36 | { 37 | if (UImguiConfig::Get()->bSaveLayout && GEditor && !IsRunningCommandlet()) 38 | { 39 | SaveLayout(); 40 | } 41 | }); 42 | } 43 | 44 | void SaveLayout() 45 | { 46 | if (!Context || GIsBuildMachine || !GIsEditor) return; 47 | // save layout 48 | FString LayoutSettingDir = FPaths::ProjectConfigDir() / TEXT("ImguiLayout_Engine.ini"); 49 | auto OldContext = ImGui::GetCurrentContext(); 50 | Context->ApplyContext(); 51 | ImGui::SaveIniSettingsToDisk(TCHAR_TO_UTF8(*LayoutSettingDir)); 52 | ImGui::SetCurrentContext(OldContext); 53 | } 54 | 55 | void Tick(float DeltaTime) 56 | { 57 | if (!GEngine->IsInitialized()) return; 58 | 59 | // create imgui context 60 | if (!Context) 61 | { 62 | // create context 63 | Context = NewObject(); 64 | Context->AddToRoot(); 65 | 66 | // create input adapter 67 | InputAdapter = NewObject(); 68 | InputAdapter->AddToRoot(); 69 | InputAdapter->SetContext(Context); 70 | 71 | // setup default adapter 72 | Context->SetDefaultInputAdapter(InputAdapter); 73 | 74 | return; 75 | } 76 | 77 | // add global hook 78 | static bool bHookAdded = false; 79 | if (!bHookAdded) 80 | { 81 | auto GlobalHook = FImguiGlobalInputHook::Get(); 82 | if (!GlobalHook.IsValid()) return; 83 | GlobalHook->AddAdapter(InputAdapter); 84 | bHookAdded = true; 85 | } 86 | 87 | // try to init 88 | if (!Context->IsInit()) 89 | { 90 | // find viewport widget 91 | auto& AllViewportClients = GEditor->GetLevelViewportClients(); 92 | 93 | // create proxy 94 | TSharedPtr Proxy = SNew(SImguiRenderProxy) 95 | .InContext(Context) 96 | .InAdapter(InputAdapter) 97 | .HSizingRule(EImguiSizingRule::UESize) 98 | .VSizingRule(EImguiSizingRule::UESize) 99 | .BlockInput(true) 100 | .Visibility(EVisibility::HitTestInvisible); 101 | 102 | // add to viewport 103 | if (AllViewportClients.Num() != 0) 104 | { 105 | for (FLevelEditorViewportClient* Client : AllViewportClients) 106 | { 107 | Client->GetEditorViewportWidget()->ViewportOverlay->AddSlot() 108 | [ 109 | Proxy->AsShared() 110 | ]; 111 | } 112 | } 113 | 114 | // init context 115 | Context->Init(Proxy, UImguiResourceManager::Get().GetDefaultFont()); 116 | 117 | // enable docking and viewport 118 | Context->EnableDocking(true); 119 | Context->EnableViewport(true); 120 | Context->EnableDPIScale(UImguiConfig::Get()->bEnableDPIScale); 121 | Context->EnableNoAutoMergeViewport(true); 122 | 123 | // set viewport manually 124 | StaticCastSharedPtr(Proxy)->SetupViewport(Context->GetContext()->Viewports[0]); 125 | 126 | // load layout 127 | if (UImguiConfig::Get()->bSaveLayout) 128 | { 129 | FString LayoutSettingDir = FPaths::ProjectConfigDir() / TEXT("ImguiLayout_Engine.ini"); 130 | auto OldContext = ImGui::GetCurrentContext(); 131 | Context->ApplyContext(); 132 | ImGui::LoadIniSettingsFromDisk(TCHAR_TO_UTF8(*LayoutSettingDir)); 133 | ImGui::SetCurrentContext(OldContext); 134 | } 135 | 136 | return; 137 | } 138 | 139 | // update main viewport size 140 | Context->UpdateSize(); 141 | 142 | // set up context info 143 | Context->GetIO()->DeltaTime = DeltaTime; 144 | 145 | // apply context 146 | Context->ApplyContext(); 147 | 148 | // apply input 149 | InputAdapter->ApplyInput(); 150 | InputAdapter->SaveTempData(); 151 | 152 | // begin frame 153 | Context->NewFrame(DeltaTime); 154 | 155 | // draw global 156 | Context->DrawGlobal(); 157 | 158 | // render 159 | Context->Render(); 160 | 161 | // update viewport 162 | Context->UpdateViewport(InputAdapter); 163 | 164 | // save layout 165 | if (UImguiConfig::Get()->bSaveLayout) 166 | { 167 | static float AccumulateTime = 0.f; 168 | AccumulateTime += DeltaTime; 169 | if (AccumulateTime >= 30.f) 170 | { 171 | SaveLayout(); 172 | AccumulateTime -= 30.f; 173 | } 174 | } 175 | } 176 | 177 | UImguiContext* Context = nullptr; 178 | UImguiInputAdapterDeferred* InputAdapter = nullptr; 179 | }; 180 | 181 | static FEditorGlobalContextGuard Ins; 182 | static FEditorGlobalContextGuard* EngineGlobalCtxGuard() 183 | { 184 | return &Ins; 185 | } 186 | 187 | #undef protected 188 | #undef private 189 | #endif 190 | 191 | bool UEImGui::TimeToDraw(UObject* WorldContextObject) 192 | { 193 | UImguiContext* Ctx = GetGlobalContext(WorldContextObject); 194 | return Ctx ? Ctx->IsInit() : false; 195 | } 196 | 197 | UImguiContext* UEImGui::GetGlobalContext(UObject* WorldContextObject) 198 | { 199 | UWorld* FoundWorld = WorldContextObject ? WorldContextObject->GetWorld() : GWorld; 200 | if (!FoundWorld) return nullptr; 201 | UGameInstance* GameInst = FoundWorld->GetGameInstance(); 202 | if (GameInst) 203 | { 204 | auto PerInsCtx = GameInst->GetSubsystem(); 205 | if (!PerInsCtx) return nullptr; 206 | return PerInsCtx->GetGlobalContext(); 207 | } 208 | else 209 | { 210 | #if WITH_EDITOR 211 | return EngineGlobalCtxGuard()->Context; 212 | #else 213 | return nullptr; 214 | #endif 215 | } 216 | } 217 | 218 | UImguiInputAdapter* UEImGui::GetGlobalInputAdapter(UObject* WorldContextObject) 219 | { 220 | UWorld* FoundWorld = WorldContextObject ? WorldContextObject->GetWorld() : GWorld; 221 | if (!FoundWorld) return nullptr; 222 | UGameInstance* GameInst = FoundWorld->GetGameInstance(); 223 | if (GameInst) 224 | { 225 | auto PerInsCtx = GameInst->GetSubsystem(); 226 | if (!PerInsCtx) return nullptr; 227 | return PerInsCtx->GetGlobalInputAdapter(); 228 | } 229 | else 230 | { 231 | #if WITH_EDITOR 232 | return EngineGlobalCtxGuard()->InputAdapter; 233 | #else 234 | return nullptr; 235 | #endif 236 | } 237 | } 238 | 239 | int32 UEImGui::AddGlobalWindow(const FDrawGlobalImgui& InGlobalContext, UObject* WorldContextObject) 240 | { 241 | if (!TimeToDraw()) 242 | { 243 | UE_LOG(LogUEImgui, Error, TEXT("ImGui context invalid, AddGlobalWindow failed!!!")); 244 | return INDEX_NONE; 245 | } 246 | 247 | UImguiContext* Ctx = GetGlobalContext(WorldContextObject); 248 | return Ctx->AddGlobalWindow(InGlobalContext); 249 | } 250 | 251 | void UEImGui::RemoveGlobalWindow(int32 InIndex, UObject* WorldContextObject) 252 | { 253 | if (!TimeToDraw() || InIndex == INDEX_NONE) 254 | { 255 | UE_LOG(LogUEImgui, Error, TEXT("ImGui context invalid, RemoveGlobalWindow failed!!!")); 256 | return; 257 | } 258 | UImguiContext* Ctx = GetGlobalContext(WorldContextObject); 259 | Ctx->RemoveGlobalWindow(InIndex); 260 | } 261 | 262 | void UEImGui::AddRenderProxy(TWeakPtr InRenderProxy, UObject* WorldContextObject) 263 | { 264 | if (!TimeToDraw()) 265 | { 266 | UE_LOG(LogUEImgui, Error, TEXT("ImGui context invalid, AddRenderProxy failed!!!")); 267 | return; 268 | } 269 | UImguiContext* Ctx = GetGlobalContext(WorldContextObject); 270 | Ctx->AddRenderProxy(InRenderProxy); 271 | } 272 | 273 | void UEImGui::RemoveRenderProxy(TWeakPtr InRenderProxy, UObject* WorldContextObject) 274 | { 275 | if (!TimeToDraw()) 276 | { 277 | UE_LOG(LogUEImgui, Error, TEXT("ImGui context invalid, RemoveRenderProxy failed!!!")); 278 | return; 279 | } 280 | UImguiContext* Ctx = GetGlobalContext(WorldContextObject); 281 | Ctx->RemoveRenderProxy(InRenderProxy); 282 | } 283 | 284 | -------------------------------------------------------------------------------- /Source/ThirdParty/Imgui/Docs/BACKENDS.md: -------------------------------------------------------------------------------- 1 | _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md or view this file with any Markdown viewer)_ 2 | 3 | ## Dear ImGui: Backends 4 | 5 | **The backends/ folder contains backends for popular platforms/graphics API, which you can use in 6 | your application or engine to easily integrate Dear ImGui.** Each backend is typically self-contained in a pair of files: imgui_impl_XXXX.cpp + imgui_impl_XXXX.h. 7 | 8 | - The 'Platform' backends are in charge of: mouse/keyboard/gamepad inputs, cursor shape, timing, windowing.
9 | e.g. Windows ([imgui_impl_win32.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp)), GLFW ([imgui_impl_glfw.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_glfw.cpp)), SDL2 ([imgui_impl_sdl.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_sdl.cpp)), etc. 10 | 11 | - The 'Renderer' backends are in charge of: creating atlas texture, rendering imgui draw data.
12 | e.g. DirectX11 ([imgui_impl_dx11.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_dx11.cpp)), OpenGL/WebGL ([imgui_impl_opengl3.cpp]((https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_opengl3.cpp)), Vulkan ([imgui_impl_vulkan.cpp]((https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_vulkan.cpp)), etc. 13 | 14 | - For some high-level frameworks, a single backend usually handle both 'Platform' and 'Renderer' parts.
15 | e.g. Allegro 5 ([imgui_impl_allegro5.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_allegro5.cpp)), Marmalade ([imgui_impl_marmalade.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_marmalade.cpp)). If you end up creating a custom backend for your engine, you may want to do the same. 16 | 17 | An application usually combines 1 Platform backend + 1 Renderer backend + main Dear ImGui sources. 18 | For example, the [example_win32_directx11](https://github.com/ocornut/imgui/tree/master/examples/example_win32_directx11) application combines imgui_impl_win32.cpp + imgui_impl_dx11.cpp. See [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) for details. 19 | 20 | 21 | ### What are backends 22 | 23 | Dear ImGui is highly portable and only requires a few things to run and render, typically: 24 | 25 | - Required: providing mouse/keyboard inputs (fed into the `ImGuiIO` structure). 26 | - Required: uploading the font atlas texture into graphics memory. 27 | - Required: rendering indexed textured triangles with a clipping rectangle. 28 | 29 | Extra features are opt-in, our backends try to support as many as possible: 30 | 31 | - Optional: custom texture binding support. 32 | - Optional: clipboard support. 33 | - Optional: gamepad support. 34 | - Optional: mouse cursor shape support. 35 | - Optional: IME support. 36 | - Optional: multi-viewports support. 37 | etc. 38 | 39 | This is essentially what each backends are doing + obligatory portability cruft. 40 | 41 | It is important to understand the difference between the core Dear ImGui library (files in the root folder) 42 | and backends which we are describing here (backends/ folder). 43 | 44 | - Some issues may only be backend or platform specific. 45 | - You should be able to write backends for pretty much any platform and any 3D graphics API. 46 | e.g. you can get creative and use software rendering or render remotely on a different machine. 47 | 48 | 49 | ### List of backends 50 | 51 | In the [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder: 52 | 53 | List of Platforms Backends: 54 | 55 | imgui_impl_glfw.cpp ; GLFW (Windows, macOS, Linux, etc.) http://www.glfw.org/ 56 | imgui_impl_osx.mm ; macOS native API (not as feature complete as glfw/sdl backends) 57 | imgui_impl_sdl.cpp ; SDL2 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org 58 | imgui_impl_win32.cpp ; Win32 native API (Windows) 59 | imgui_impl_glut.cpp ; GLUT/FreeGLUT (this is prehistoric software and absolutely not recommended today!) 60 | 61 | List of Renderer Backends: 62 | 63 | imgui_impl_dx9.cpp ; DirectX9 64 | imgui_impl_dx10.cpp ; DirectX10 65 | imgui_impl_dx11.cpp ; DirectX11 66 | imgui_impl_dx12.cpp ; DirectX12 67 | imgui_impl_metal.mm ; Metal (with ObjC) 68 | imgui_impl_opengl2.cpp ; OpenGL 2 (legacy, fixed pipeline <- don't use with modern OpenGL context) 69 | imgui_impl_opengl3.cpp ; OpenGL 3/4, OpenGL ES 2, OpenGL ES 3 (modern programmable pipeline) 70 | imgui_impl_vulkan.cpp ; Vulkan 71 | 72 | List of high-level Frameworks Backends (combining Platform + Renderer): 73 | 74 | imgui_impl_allegro5.cpp 75 | imgui_impl_marmalade.cpp 76 | 77 | Emscripten is also supported. 78 | The [example_emscripten_opengl3](https://github.com/ocornut/imgui/tree/master/examples/example_emscripten_opengl3) app uses imgui_impl_sdl.cpp + imgui_impl_opengl3.cpp, but other combos are possible. 79 | 80 | ### Backends for third-party frameworks, graphics API or other languages 81 | 82 | See https://github.com/ocornut/imgui/wiki/Bindings 83 | - AGS/Adventure Game Studio 84 | - Amethyst 85 | - bsf 86 | - Cinder 87 | - Cocos2d-x 88 | - Diligent Engine 89 | - Flexium, 90 | - GML/Game Maker Studio2 91 | - GTK3+OpenGL3 92 | - Irrlicht Engine 93 | - LÖVE+LUA 94 | - Magnum 95 | - NanoRT 96 | - Nim Game Lib, 97 | - Ogre 98 | - openFrameworks 99 | - OSG/OpenSceneGraph 100 | - Orx 101 | - px_render 102 | - Qt/QtDirect3D 103 | - SFML 104 | - Sokol 105 | - Unity 106 | - Unreal Engine 4 107 | - vtk 108 | - Win32 GDI 109 | etc. 110 | 111 | 112 | ### Recommended Backends 113 | 114 | If you are not sure which backend to use, the recommended platform/frameworks for portable applications: 115 | 116 | |Library |Website |Backend |Note | 117 | |--------|--------|--------|-----| 118 | | GLFW | https://github.com/glfw/glfw | imgui_impl_glfw.cpp | | 119 | | SDL2 | https://www.libsdl.org | imgui_impl_sdl.cpp | | 120 | | Sokol | https://github.com/floooh/sokol | [util/sokol_imgui.h](https://github.com/floooh/sokol/blob/master/util/sokol_imgui.h) | Lower-level than GLFW/SDL | 121 | 122 | 123 | ### Using a custom engine? 124 | 125 | You will likely be tempted to start by rewrite your own backend using your own custom/high-level facilities...
126 | Think twice! 127 | 128 | If you are new to Dear ImGui, first try using the existing backends as-is. 129 | You will save lots of time integrating the library. 130 | You can LATER decide to rewrite yourself a custom backend if you really need to. 131 | In most situations, custom backends have less features and more bugs than the standard backends we provide. 132 | If you want portability, you can use multiple backends and choose between them either at compile time 133 | or at runtime. 134 | 135 | **Example A**: your engine is built over Windows + DirectX11 but you have your own high-level rendering 136 | system layered over DirectX11.
137 | Suggestion: try using imgui_impl_win32.cpp + imgui_impl_dx11.cpp first. 138 | Once it works, if you really need it you can replace the imgui_impl_dx11.cpp code with a 139 | custom renderer using your own rendering functions, and keep using the standard Win32 code etc. 140 | 141 | **Example B**: your engine runs on Windows, Mac, Linux and uses DirectX11, Metal, Vulkan respectively.
142 | Suggestion: use multiple generic backends! 143 | Once it works, if you really need it you can replace parts of backends with your own abstractions. 144 | 145 | **Example C**: your engine runs on platforms we can't provide public backends for (e.g. PS4/PS5, Switch), 146 | and you have high-level systems everywhere.
147 | Suggestion: try using a non-portable backend first (e.g. win32 + underlying graphics API) to get 148 | your desktop builds working first. This will get you running faster and get your acquainted with 149 | how Dear ImGui works and is setup. You can then rewrite a custom backend using your own engine API. 150 | 151 | Also: 152 | The [multi-viewports feature](https://github.com/ocornut/imgui/issues/1542) of the 'docking' branch allows 153 | Dear ImGui windows to be seamlessly detached from the main application window. This is achieved using an 154 | extra layer to the Platform and Renderer backends, which allows Dear ImGui to communicate platform-specific 155 | requests such as: "create an additional OS window", "create a render context", "get the OS position of this 156 | window" etc. See 'ImGuiPlatformIO' for details. 157 | Supporting the multi-viewports feature correctly using 100% of your own abstractions is more difficult 158 | than supporting single-viewport. 159 | If you decide to use unmodified imgui_impl_XXXX.cpp files, you can automatically benefit from 160 | improvements and fixes related to viewports and platform windows without extra work on your side. 161 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Widgets/SImguiWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "Widgets/SImguiWindow.h" 2 | #include "imgui_internal.h" 3 | #include "ImguiWrap/ImguiUEWrap.h" 4 | #include "Render/ImguiDrawer.h" 5 | #if WITH_EDITOR 6 | #include "Interfaces/IMainFrameModule.h" 7 | #endif 8 | 9 | class IMainFrameModule; 10 | 11 | void SImguiWindow::Construct(const FArguments& InArgs) 12 | { 13 | BoundContext = InArgs._Context; 14 | BoundAdapter = InArgs._Adapter; 15 | BoundViewport = InArgs._Viewport; 16 | 17 | RequestDestroyWindowOverride.BindLambda([this](const TSharedRef&) 18 | { 19 | if (!BoundViewport) 20 | { 21 | FSlateApplicationBase::Get().RequestDestroyWindow(SharedThis(this)); 22 | } 23 | BoundViewport->PlatformRequestClose = true; 24 | }); 25 | 26 | Super::Construct( Super::FArguments() 27 | .LayoutBorder(FMargin(0)) 28 | .HasCloseButton(false) 29 | .Type(InArgs._IsToolTip ? EWindowType::ToolTip : EWindowType::Normal) 30 | .IsTopmostWindow(InArgs._IsToolTip) 31 | .IsPopupWindow(InArgs._IsToolTip || InArgs._IsPopup) 32 | .SizingRule(ESizingRule::Autosized) 33 | .SupportsTransparency(FWindowTransparency(EWindowTransparency::PerWindow)) 34 | .HasCloseButton(false) 35 | .CreateTitleBar(false) 36 | .SupportsMaximize(false) 37 | .SupportsMinimize(false) 38 | .UserResizeBorder(FMargin(0)) 39 | .FocusWhenFirstShown(InArgs._TakeFocusWhenShow)); 40 | } 41 | 42 | FReply SImguiWindow::OnKeyChar(const FGeometry& MyGeometry, const FCharacterEvent& InCharacterEvent) 43 | { 44 | UImguiInputAdapter* Adapter = GetAdapter(); 45 | return Adapter ? Adapter->OnKeyChar(InCharacterEvent) : FReply::Unhandled(); 46 | } 47 | 48 | FReply SImguiWindow::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) 49 | { 50 | UImguiInputAdapter* Adapter = GetAdapter(); 51 | Super::OnKeyDown(MyGeometry, InKeyEvent); 52 | if (!Adapter) return FReply::Unhandled(); 53 | return Adapter->OnKeyDown(InKeyEvent); 54 | } 55 | 56 | FReply SImguiWindow::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) 57 | { 58 | UImguiInputAdapter* Adapter = GetAdapter(); 59 | Super::OnKeyUp(MyGeometry, InKeyEvent); 60 | if (!Adapter) return FReply::Unhandled(); 61 | return Adapter->OnKeyUp(InKeyEvent); 62 | } 63 | 64 | FReply SImguiWindow::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) 65 | { 66 | UImguiInputAdapter* Adapter = GetAdapter(); 67 | if (!Adapter) return FReply::Unhandled(); 68 | return Adapter->OnMouseButtonDown(MouseEvent); 69 | } 70 | 71 | FReply SImguiWindow::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) 72 | { 73 | UImguiInputAdapter* Adapter = GetAdapter(); 74 | if (!Adapter) return FReply::Unhandled(); 75 | return Adapter->OnMouseButtonUp(MouseEvent); 76 | } 77 | 78 | FReply SImguiWindow::OnMouseButtonDoubleClick(const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent) 79 | { 80 | UImguiInputAdapter* Adapter = GetAdapter(); 81 | if (!Adapter) return FReply::Unhandled(); 82 | return Adapter->OnMouseButtonDoubleClick(InMouseEvent); 83 | } 84 | 85 | FReply SImguiWindow::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) 86 | { 87 | UImguiInputAdapter* Adapter = GetAdapter(); 88 | if (!Adapter) return FReply::Unhandled(); 89 | return Adapter->OnMouseWheel(MouseEvent); 90 | } 91 | 92 | FReply SImguiWindow::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) 93 | { 94 | UImguiInputAdapter* Adapter = GetAdapter(); 95 | if (!Adapter) return FReply::Unhandled(); 96 | return Adapter->OnMouseMove(FVector2D::ZeroVector, MouseEvent); 97 | } 98 | 99 | bool SImguiWindow::SupportsKeyboardFocus() const 100 | { 101 | return true; 102 | } 103 | 104 | void SImguiWindow::OnFocusLost(const FFocusEvent& InFocusEvent) 105 | { 106 | bInFocus = false; 107 | } 108 | 109 | FReply SImguiWindow::OnFocusReceived(const FGeometry& MyGeometry, const FFocusEvent& InFocusEvent) 110 | { 111 | bInFocus = true; 112 | return FReply::Unhandled(); 113 | } 114 | 115 | FCursorReply SImguiWindow::OnCursorQuery(const FGeometry& MyGeometry, const FPointerEvent& CursorEvent) const 116 | { 117 | UImguiInputAdapter* Adapter = GetAdapter(); 118 | return Adapter ? Adapter->OnCursorQuery(CursorEvent) : FCursorReply::Cursor(EMouseCursor::Default); 119 | } 120 | 121 | FVector2D SImguiWindow::ComputeDesiredSize(float LayoutScaleMultiplier) const 122 | { 123 | if (!BoundViewport) return FVector2D::ZeroVector; 124 | return FVector2D(BoundViewport->Size.x, BoundViewport->Size.y); 125 | } 126 | 127 | int32 SImguiWindow::OnPaint( 128 | const FPaintArgs& Args, 129 | const FGeometry& AllottedGeometry, 130 | const FSlateRect& MyCullingRect, 131 | FSlateWindowElementList& OutDrawElements, 132 | int32 LayerId, 133 | const FWidgetStyle& InWidgetStyle, 134 | bool bParentEnabled) const 135 | { 136 | if (!BoundViewport) return LayerId; 137 | 138 | auto ScreenPos = GetPositionInScreen(); 139 | 140 | if (BoundViewport->DrawData->DisplaySize.x <= 0.0f || BoundViewport->DrawData->DisplaySize.y <= 0.0f) 141 | { 142 | return LayerId + 1; 143 | } 144 | 145 | auto RenderTargetSize = OutDrawElements.GetPaintWindow()->GetSizeInScreen(); 146 | auto Drawer = FImguiDrawer::AllocDrawer(); 147 | FMatrix OrthoMatrix( 148 | FPlane(2.0f / RenderTargetSize.X, 0.0f, 0.0f, 0.0f), 149 | FPlane(0.0f, -2.0f / RenderTargetSize.Y, 0.0f, 0.0f), 150 | FPlane(0.0f, 0.0f, 1.f / 5000.f, 0.0f), 151 | FPlane(-1, 1, 0.5f, 1.0f)); 152 | Drawer->SetSlateTransform(-ScreenPos, 1, OrthoMatrix); 153 | Drawer->SetClipRect(FSlateRect(0,0,RenderTargetSize.X, RenderTargetSize.Y)); 154 | Drawer->SetDrawData(BoundViewport->DrawData); 155 | FSlateDrawElement::MakeCustom(OutDrawElements, LayerId, Drawer); 156 | return LayerId + 1; 157 | } 158 | 159 | void SImguiWindow::Show(TSharedPtr InParent) 160 | { 161 | if (GetNativeWindow().IsValid()) 162 | { 163 | ShowWindow(); 164 | MoveWindowTo(GetInitialDesiredPositionInScreen()); 165 | return; 166 | } 167 | if (InParent.IsValid()) 168 | { 169 | FSlateApplication::Get().AddWindowAsNativeChild(StaticCastSharedRef(AsShared()), InParent.ToSharedRef()); 170 | MoveWindowTo(GetInitialDesiredPositionInScreen()); 171 | return; 172 | } 173 | #if WITH_EDITOR 174 | if (FModuleManager::Get().IsModuleLoaded("MainFrame")) 175 | { 176 | IMainFrameModule& MainFrame = FModuleManager::LoadModuleChecked("MainFrame"); 177 | const TSharedPtr MainFrameWindow = MainFrame.GetParentWindow(); 178 | FSlateApplication::Get().AddWindowAsNativeChild(StaticCastSharedRef(AsShared()), MainFrameWindow.ToSharedRef()); 179 | } 180 | else 181 | #endif 182 | { 183 | FSlateApplication::Get().AddWindow(StaticCastSharedRef(this->AsShared())); 184 | } 185 | MoveWindowTo(GetInitialDesiredPositionInScreen()); 186 | } 187 | 188 | void SImguiWindow::Update() 189 | { 190 | } 191 | 192 | FVector2D SImguiWindow::GetPos() 193 | { 194 | return ScreenPosition; 195 | } 196 | 197 | void SImguiWindow::SetPos(FVector2D InPos) 198 | { 199 | MoveWindowTo(InPos); 200 | } 201 | 202 | FVector2D SImguiWindow::GetSize() 203 | { 204 | return SWindow::Size; 205 | } 206 | 207 | void SImguiWindow::SetSize(FVector2D InSize) 208 | { 209 | Morpher.Sequence.JumpToEnd(); 210 | 211 | InSize.X = FMath::Max(SizeLimits.GetMinWidth().Get(InSize.X), InSize.X); 212 | InSize.X = FMath::Min(SizeLimits.GetMaxWidth().Get(InSize.X), InSize.X); 213 | 214 | InSize.Y = FMath::Max(SizeLimits.GetMinHeight().Get(InSize.Y), InSize.Y); 215 | InSize.Y = FMath::Min(SizeLimits.GetMaxHeight().Get(InSize.Y), InSize.Y); 216 | 217 | // ReshapeWindow W/H takes an int, so lets move our new W/H to int before checking if they are the same size 218 | FIntPoint CurrentIntSize = FIntPoint(FMath::CeilToInt(Size.X), FMath::CeilToInt(Size.Y)); 219 | FIntPoint NewIntSize = FIntPoint(FMath::CeilToInt(InSize.X), FMath::CeilToInt(InSize.Y)); 220 | 221 | if (CurrentIntSize != NewIntSize) 222 | { 223 | if (NativeWindow.IsValid()) 224 | { 225 | NativeWindow->ReshapeWindow(FMath::TruncToInt(ScreenPosition.X), FMath::TruncToInt(ScreenPosition.Y), NewIntSize.X, NewIntSize.Y); 226 | } 227 | else 228 | { 229 | InitialDesiredSize = InSize; 230 | } 231 | } 232 | SetCachedSize(InSize); 233 | } 234 | 235 | bool SImguiWindow::GetFocus() 236 | { 237 | return bInFocus; 238 | } 239 | 240 | void SImguiWindow::SetFocus() 241 | { 242 | if (!GetNativeWindow()) return; 243 | GetNativeWindow()->SetWindowFocus(); 244 | } 245 | 246 | bool SImguiWindow::GetMinimized() 247 | { 248 | return false; 249 | } 250 | 251 | void SImguiWindow::SetTitle(const char* InTitle) 252 | { 253 | Title = FText::FromString(InTitle); 254 | } 255 | 256 | void SImguiWindow::SetAlpha(float InAlpha) 257 | { 258 | SetOpacity(InAlpha); 259 | } 260 | 261 | void SImguiWindow::SetupViewport(ImGuiViewport* InViewport) 262 | { 263 | BoundViewport = InViewport; 264 | } 265 | 266 | void SImguiWindow::SetupInputAdapter(UImguiInputAdapter* ImguiInputAdapter) 267 | { 268 | SetAdapter(ImguiInputAdapter); 269 | } 270 | 271 | float SImguiWindow::GetDpiScale() 272 | { 273 | return GetDPIScaleFactor(); 274 | return 1.0f; 275 | } 276 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Widgets/SImguiWidget.cpp: -------------------------------------------------------------------------------- 1 | #include "Widgets/SImguiWidget.h" 2 | #include "imgui.h" 3 | #include "imgui_internal.h" 4 | #include "Logging.h" 5 | #include "ImguiWrap/ImguiInputAdapter.h" 6 | #include "ImguiWrap/ImguiContext.h" 7 | #include "ImguiWrap/ImguiResourceManager.h" 8 | #include "ImguiWrap/ImguiUEWrap.h" 9 | #include "Render/ImguiDrawer.h" 10 | #include "Widgets/Input/SEditableText.h" 11 | 12 | void SImguiRenderProxy::Construct(const FArguments& InArgs) 13 | { 14 | HSizingRule = InArgs._HSizingRule; 15 | VSizingRule = InArgs._VSizingRule; 16 | bAutoSetWidgetPos = InArgs._AutoSetWidgetPos; 17 | PersistWndID = InArgs._ProxyWndName ? ImHashStr(InArgs._ProxyWndName) : 0; 18 | Context = InArgs._InContext; 19 | Adapter = InArgs._InAdapter; 20 | bBlockInput = InArgs._BlockInput; 21 | bBlockWheel = InArgs._BlockWheel; 22 | 23 | Visibility = InArgs._Visibility; 24 | } 25 | 26 | void SImguiRenderProxy::SetContext(UImguiContext* InContext) 27 | { 28 | check(InContext != nullptr); 29 | Context = InContext; 30 | if (Adapter) Adapter->SetContext(Context); 31 | } 32 | 33 | void SImguiRenderProxy::SetAdapter(UImguiInputAdapter* InAdapter) 34 | { 35 | check(InAdapter != nullptr); 36 | Adapter = InAdapter; 37 | if (Context) Adapter->SetContext(Context); 38 | } 39 | 40 | void SImguiRenderProxy::AddReferencedObjects(FReferenceCollector& Collector) 41 | { 42 | Collector.AddReferencedObject(Context); 43 | Collector.AddReferencedObject(Adapter); 44 | } 45 | 46 | FString SImguiRenderProxy::GetReferencerName() const 47 | { 48 | return TEXT("ImguiRenderProxy"); 49 | } 50 | 51 | FReply SImguiRenderProxy::OnKeyChar(const FGeometry& MyGeometry, const FCharacterEvent& InCharacterEvent) 52 | { 53 | Super::OnKeyChar(MyGeometry, InCharacterEvent); 54 | if (!Adapter) return FReply::Unhandled(); 55 | FReply AdapterReply = Adapter->OnKeyChar(InCharacterEvent); 56 | return bBlockInput ? AdapterReply : FReply::Unhandled(); 57 | } 58 | 59 | FReply SImguiRenderProxy::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) 60 | { 61 | Super::OnKeyDown(MyGeometry, InKeyEvent); 62 | if (!Adapter) return FReply::Unhandled(); 63 | FReply AdapterReply = Adapter->OnKeyDown(InKeyEvent); 64 | return bBlockInput ? AdapterReply : FReply::Unhandled(); 65 | } 66 | 67 | FReply SImguiRenderProxy::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) 68 | { 69 | Super::OnKeyUp(MyGeometry, InKeyEvent); 70 | if (!Adapter) return FReply::Unhandled(); 71 | FReply AdapterReply = Adapter->OnKeyUp(InKeyEvent); 72 | return bBlockInput ? AdapterReply : FReply::Unhandled(); 73 | } 74 | 75 | FReply SImguiRenderProxy::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) 76 | { 77 | Super::OnMouseButtonDown(MyGeometry, MouseEvent); 78 | if (!Adapter) return FReply::Unhandled(); 79 | FReply AdapterReply = Adapter->OnMouseButtonDown(MouseEvent); 80 | return bBlockInput ? AdapterReply : FReply::Unhandled(); 81 | } 82 | 83 | FReply SImguiRenderProxy::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) 84 | { 85 | Super::OnMouseButtonDown(MyGeometry, MouseEvent); 86 | if (!Adapter) return FReply::Unhandled(); 87 | FReply AdapterReply = Adapter->OnMouseButtonUp(MouseEvent); 88 | return bBlockInput ? AdapterReply : FReply::Unhandled(); 89 | 90 | } 91 | 92 | FReply SImguiRenderProxy::OnMouseButtonDoubleClick(const FGeometry& InMyGeometry, 93 | const FPointerEvent& InMouseEvent) 94 | { 95 | Super::OnMouseButtonDoubleClick(InMyGeometry, InMouseEvent); 96 | if (!Adapter) return FReply::Unhandled(); 97 | FReply AdapterReply = Adapter->OnMouseButtonDoubleClick(InMouseEvent); 98 | return bBlockInput ? AdapterReply : FReply::Unhandled(); 99 | } 100 | 101 | FReply SImguiRenderProxy::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) 102 | { 103 | Super::OnMouseWheel(MyGeometry, MouseEvent); 104 | if (!Adapter) return FReply::Unhandled(); 105 | FReply AdapterReply = Adapter->OnMouseWheel(MouseEvent); 106 | return bBlockInput && bBlockWheel ? AdapterReply : FReply::Unhandled(); 107 | } 108 | 109 | FReply SImguiRenderProxy::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) 110 | { 111 | if (!GetAdapter()) return FReply::Unhandled(); 112 | FReply AdapterReply = Adapter->OnMouseMove(FVector2D::ZeroVector, MouseEvent); 113 | return bBlockInput ? AdapterReply : FReply::Unhandled(); 114 | } 115 | 116 | int32 SImguiRenderProxy::OnPaint( 117 | const FPaintArgs& Args, 118 | const FGeometry& AllottedGeometry, 119 | const FSlateRect& MyCullingRect, 120 | FSlateWindowElementList& OutDrawElements, 121 | int32 LayerId, 122 | const FWidgetStyle& InWidgetStyle, 123 | bool bParentEnabled) const 124 | { 125 | if (!BoundViewport || !BoundViewport->DrawData) return LayerId; 126 | 127 | if (BoundViewport->DrawData->DisplaySize.x <= 0.0f || BoundViewport->DrawData->DisplaySize.y <= 0.0f) 128 | { 129 | return LayerId + 1; 130 | } 131 | 132 | // get window 133 | CachedWnd = StaticCastSharedRef(OutDrawElements.GetPaintWindow()->AsShared()); 134 | 135 | // get vertex offset 136 | FVector2D ImguiVertexOffset = AllottedGeometry.GetAbsolutePosition() - *(FVector2D*)&BoundViewport->Pos; 137 | 138 | // build ortho matrix 139 | auto Size = OutDrawElements.GetPaintWindow()->GetSizeInScreen(); 140 | FMatrix OrthoMatrix( 141 | FPlane(2.0f / Size.X, 0.0f, 0.0f, 0.0f), 142 | FPlane(0.0f, -2.0f / Size.Y, 0.0f, 0.0f), 143 | FPlane(0.0f, 0.0f, 1.f / 5000.f, 0.0f), 144 | FPlane(-1, 1, 0.5f, 1.0f)); 145 | 146 | // setup drawer 147 | auto Drawer = FImguiDrawer::AllocDrawer(); 148 | Drawer->SetSlateTransform(ImguiVertexOffset, 1, OrthoMatrix); 149 | Drawer->SetClipRect(MyCullingRect); 150 | Drawer->SetDrawData(BoundViewport->DrawData); 151 | 152 | // add to draw list 153 | FSlateDrawElement::MakeCustom(OutDrawElements, LayerId, Drawer); 154 | 155 | // draw next layer 156 | return LayerId + 1; 157 | } 158 | 159 | void SImguiRenderProxy::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, 160 | const float InDeltaTime) 161 | { 162 | Super::Tick(AllottedGeometry, InCurrentTime, InDeltaTime); 163 | 164 | // get context 165 | UImguiContext* UECtx = GetContext(); 166 | if (!UECtx) return; 167 | ImGuiContext* Ctx = UECtx->GetContext(); 168 | 169 | // find window 170 | ImGuiWindow* Wnd = (ImGuiWindow*)Ctx->WindowsById.GetVoidPtr(PersistWndID); 171 | if (!Wnd) return; 172 | 173 | // update imgui wnd size 174 | FVector2D Size = AllottedGeometry.GetAbsoluteSize(); 175 | if (HSizingRule == EImguiSizingRule::UESize) 176 | { 177 | Wnd->Size.x = Size.X; 178 | } 179 | if (VSizingRule == EImguiSizingRule::UESize) 180 | { 181 | Wnd->Size.y = Size.Y; 182 | } 183 | 184 | // update imgui pos 185 | FVector2D Pos = AllottedGeometry.GetAbsolutePosition(); 186 | if (bAutoSetWidgetPos) 187 | { 188 | Wnd->Pos = *(ImVec2*)&Pos; 189 | } 190 | } 191 | 192 | FVector2D SImguiRenderProxy::ComputeDesiredSize(float) const 193 | { 194 | UImguiContext* UECtx = GetContext(); 195 | if (!UECtx) return FVector2D::ZeroVector; 196 | ImGuiContext* Ctx = UECtx->GetContext(); 197 | 198 | FVector2D OriginPoint = GetCachedGeometry().GetAccumulatedRenderTransform().GetTranslation(); 199 | FVector2D NewDesiredSize(0); 200 | 201 | ImGuiWindow* Wnd = (ImGuiWindow*)Ctx->WindowsById.GetVoidPtr(PersistWndID); 202 | if (!Wnd) return FVector2D::ZeroVector; 203 | 204 | // HSizing 205 | switch (HSizingRule) 206 | { 207 | case EImguiSizingRule::ImSize: 208 | NewDesiredSize.X = Wnd->Size.x; 209 | break; 210 | case EImguiSizingRule::ImContentSize: 211 | NewDesiredSize.X = Wnd->ContentSize.x + (Wnd->WindowBorderSize + Wnd->WindowPadding.x) * 2; 212 | break; 213 | default: ; 214 | } 215 | 216 | // VSizing 217 | switch (VSizingRule) 218 | { 219 | case EImguiSizingRule::ImSize: 220 | NewDesiredSize.Y = Wnd->Size.y; 221 | break; 222 | case EImguiSizingRule::ImContentSize: 223 | NewDesiredSize.Y = Wnd->ContentSize.y + (Wnd->WindowBorderSize + Wnd->WindowPadding.y) * 2; 224 | break; 225 | default: ; 226 | } 227 | 228 | return NewDesiredSize; 229 | } 230 | 231 | float SImguiRenderProxy::GetDpiScale() 232 | { 233 | return CachedWnd.IsValid() ? CachedWnd.Pin()->GetDPIScaleFactor() : 1.0f; 234 | return 1.0f; 235 | } 236 | 237 | EVisibility SImguiRenderProxy::_GetVisibility() const 238 | { 239 | return Context && Context->GetIO() && Context->GetIO()->WantCaptureMouse ? EVisibility::Visible : EVisibility::SelfHitTestInvisible; 240 | } 241 | 242 | bool SImguiRenderProxy::SupportsKeyboardFocus() const 243 | { 244 | return Adapter && Adapter->CanReceiveKeyboardInput(); 245 | } 246 | 247 | void SImguiRenderProxy::OnFocusLost(const FFocusEvent& InFocusEvent) 248 | { 249 | // if (!GetContext()) return; 250 | // // change context 251 | // ImGuiContext* LastCtx = ImGui::GetCurrentContext(); 252 | // ImGuiContext* Ctx = GetContext()->GetContext(); 253 | // GetContext()->ApplyContext(); 254 | // ImGuiWindow* Wnd = (ImGuiWindow*)Ctx->WindowsById.GetVoidPtr(PersistWndID); 255 | // 256 | // // remove focus 257 | // if (Ctx->ActiveIdWindow && Ctx->ActiveIdWindow->RootWindow != Wnd) 258 | // ImGui::FocusWindow(nullptr); 259 | // 260 | // // resume context 261 | // ImGui::SetCurrentContext(LastCtx); 262 | } 263 | 264 | FReply SImguiRenderProxy::OnFocusReceived(const FGeometry& MyGeometry, const FFocusEvent& InFocusEvent) 265 | { 266 | return FReply::Unhandled(); 267 | } 268 | 269 | FCursorReply SImguiRenderProxy::OnCursorQuery(const FGeometry& MyGeometry, const FPointerEvent& CursorEvent) const 270 | { 271 | Super::OnCursorQuery(MyGeometry, CursorEvent); 272 | if (!Adapter) return FCursorReply::Cursor(EMouseCursor::Default); 273 | return Adapter->OnCursorQuery(CursorEvent); 274 | } 275 | 276 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Extension/UEImguiDetail.cpp: -------------------------------------------------------------------------------- 1 | #include "Extension/UEImguiDetail.h" 2 | #include "imgui.h" 3 | #include "ImguiWrap/ImguiUEWrap.h" 4 | 5 | FUEImguiDetail::FUEImguiDetail() 6 | : DetailDepth(0) 7 | { 8 | } 9 | 10 | bool FUEImguiDetail::MakeDetail(UScriptStruct* InStruct, void* InValue) 11 | { 12 | bool bHasChanged = false; 13 | ++DetailDepth; 14 | if (ImGui::BeginTable("ImGuiDetail", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_SizingStretchSame)) 15 | { 16 | for (TFieldIterator It(InStruct); It; ++It) 17 | { 18 | bHasChanged |= MakeDetail(*It, InValue); 19 | } 20 | ImGui::EndTable(); 21 | } 22 | --DetailDepth; 23 | return bHasChanged; 24 | } 25 | 26 | bool FUEImguiDetail::MakeDetail(UClass* InClass, void* InValue) 27 | { 28 | bool bHasChanged = false; 29 | ++DetailDepth; 30 | 31 | --DetailDepth; 32 | return bHasChanged; 33 | } 34 | 35 | bool FUEImguiDetail::MakeDetail(FProperty* InProperty, void* InContainer) 36 | { 37 | ++DetailDepth; 38 | 39 | // constant 40 | const char s8_min = -128, s8_max = 127; 41 | const ImU8 u8_min = 0, u8_max = 255; 42 | const short s16_min = -32768, s16_max = 32767; 43 | const ImU16 u16_min = 0, u16_max = 65535; 44 | const ImS32 s32_min = INT_MIN, s32_max = INT_MAX; 45 | const ImU32 u32_min = 0, u32_max = UINT_MAX; 46 | const ImS64 s64_min = LLONG_MIN, s64_max = LLONG_MAX; 47 | const ImU64 u64_min = 0, u64_max = ULLONG_MAX; 48 | 49 | // string buffer 50 | static std::string StrBuffer; 51 | 52 | // get data 53 | void* PropertyData = InProperty->ContainerPtrToValuePtr(InContainer); 54 | bool bValueHasChanged = false; 55 | 56 | // draw label 57 | std::string PropertyName = TCHAR_TO_UTF8(*InProperty->GetName()); 58 | ImGui::TableNextRow(); 59 | ImGui::TableSetColumnIndex(0); 60 | ImGui::AlignTextToFramePadding(); 61 | ImGui::Text("%s", PropertyName.c_str()); 62 | ImGui::TableSetColumnIndex(1); 63 | 64 | // setup label 65 | PropertyName = "##" + PropertyName; 66 | 67 | // setup size 68 | ImGui::SetNextItemWidth(-FLT_MIN); 69 | 70 | // draw value 71 | switch ((EClassCastFlags)InProperty->GetClass()->GetId()) 72 | { 73 | // ========================Integer======================== 74 | case CASTCLASS_FInt8Property: 75 | bValueHasChanged = ImGui::DragScalar(PropertyName.c_str(), ImGuiDataType_S8, PropertyData, 1.f, &s8_min, &s8_max); 76 | break; 77 | case CASTCLASS_FByteProperty: 78 | bValueHasChanged = ImGui::DragScalar(PropertyName.c_str(), ImGuiDataType_U8, PropertyData, 1.f, &u8_min, &u8_max); 79 | break; 80 | case CASTCLASS_FInt16Property: 81 | bValueHasChanged = ImGui::DragScalar(PropertyName.c_str(), ImGuiDataType_S16, PropertyData, 1.f, &s16_min, &s16_max); 82 | break; 83 | case CASTCLASS_FUInt16Property: 84 | bValueHasChanged = ImGui::DragScalar(PropertyName.c_str(), ImGuiDataType_U16, PropertyData, 1.f, &u16_min, &u16_max); 85 | break; 86 | case CASTCLASS_FIntProperty: 87 | bValueHasChanged = ImGui::DragScalar(PropertyName.c_str(), ImGuiDataType_S32, PropertyData, 1.f, &s32_min, &s32_max); 88 | break; 89 | case CASTCLASS_FUInt32Property: 90 | bValueHasChanged = ImGui::DragScalar(PropertyName.c_str(), ImGuiDataType_U32, PropertyData, 1.f, &u32_min, &u32_max); 91 | break; 92 | case CASTCLASS_FInt64Property: 93 | bValueHasChanged = ImGui::DragScalar(PropertyName.c_str(), ImGuiDataType_S64, PropertyData, 1.f, &s64_min, &s64_max); 94 | break; 95 | case CASTCLASS_FUInt64Property: 96 | bValueHasChanged = ImGui::DragScalar(PropertyName.c_str(), ImGuiDataType_U64, PropertyData, 1.f, &u64_min, &u64_max); 97 | break; 98 | 99 | // ========================Floating======================== 100 | case CASTCLASS_FFloatProperty: 101 | bValueHasChanged = ImGui::DragScalar(PropertyName.c_str(), ImGuiDataType_Float, PropertyData, 1.f); 102 | break; 103 | case CASTCLASS_FDoubleProperty: 104 | bValueHasChanged = ImGui::DragScalar(PropertyName.c_str(), ImGuiDataType_Double, PropertyData, 1.f); 105 | break; 106 | 107 | // ========================Boolean======================== 108 | case CASTCLASS_FBoolProperty: 109 | bValueHasChanged = ImGui::Checkbox(PropertyName.c_str(), (bool*)PropertyData); 110 | break; 111 | 112 | // ========================String======================== 113 | case CASTCLASS_FNameProperty: 114 | { 115 | FName& NameValue = *(FName*)PropertyData; 116 | FString NameStr = NameValue.ToString(); 117 | int32 UTF8Len = FTCHARToUTF8_Convert::ConvertedLength(*NameStr, NameStr.Len()); 118 | StrBuffer.resize(UTF8Len + 1); 119 | StrBuffer.back() = 0; 120 | FTCHARToUTF8_Convert::Convert(const_cast(StrBuffer.data()), StrBuffer.length() + 1, *NameStr, NameStr.Len()); 121 | bValueHasChanged = ImGui::InputText(PropertyName.c_str(), &StrBuffer); 122 | if (bValueHasChanged) 123 | { 124 | NameValue = FName(UTF8_TO_TCHAR(StrBuffer.c_str())); 125 | } 126 | break; 127 | } 128 | case CASTCLASS_FTextProperty: 129 | { 130 | FText& TextValue = *(FText*)PropertyData; 131 | FString NameStr = TextValue.ToString(); 132 | int32 UTF8Len = FTCHARToUTF8_Convert::ConvertedLength(*NameStr, NameStr.Len()); 133 | StrBuffer.resize(UTF8Len + 1); 134 | StrBuffer.back() = 0; 135 | FTCHARToUTF8_Convert::Convert(const_cast(StrBuffer.data()), StrBuffer.length() + 1, *NameStr, NameStr.Len()); 136 | bValueHasChanged = ImGui::InputText(PropertyName.c_str(), &StrBuffer); 137 | if (bValueHasChanged) 138 | { 139 | int32 TCHARLen = FUTF8ToTCHAR_Convert::ConvertedLength(StrBuffer.c_str(), StrBuffer.length()); 140 | NameStr.GetCharArray().SetNumUninitialized(TCHARLen + 1); 141 | NameStr.GetCharArray().Top() = 0; 142 | FUTF8ToTCHAR_Convert::Convert(NameStr.GetCharArray().GetData(), NameStr.GetCharArray().Num(), StrBuffer.c_str(), StrBuffer.length()); 143 | TextValue = FText::FromString(NameStr); 144 | } 145 | break; 146 | } 147 | case CASTCLASS_FStrProperty: 148 | { 149 | FString& NameStr = *(FString*)PropertyData; 150 | int32 UTF8Len = FTCHARToUTF8_Convert::ConvertedLength(*NameStr, NameStr.Len()); 151 | StrBuffer.resize(UTF8Len + 1); 152 | StrBuffer.back() = 0; 153 | FTCHARToUTF8_Convert::Convert(const_cast(StrBuffer.data()), StrBuffer.length() + 1, *NameStr, NameStr.Len()); 154 | bValueHasChanged = ImGui::InputText(PropertyName.c_str(), &StrBuffer); 155 | if (bValueHasChanged) 156 | { 157 | int32 TCHARLen = FUTF8ToTCHAR_Convert::ConvertedLength(StrBuffer.c_str(), StrBuffer.length()); 158 | NameStr.GetCharArray().SetNumUninitialized(TCHARLen + 1); 159 | NameStr.GetCharArray().Top() = 0; 160 | FUTF8ToTCHAR_Convert::Convert(NameStr.GetCharArray().GetData(), NameStr.GetCharArray().Num(), StrBuffer.c_str(), StrBuffer.length()); 161 | } 162 | break; 163 | } 164 | 165 | // ========================Combo======================== 166 | case CASTCLASS_FEnumProperty: 167 | { 168 | FEnumProperty* EnumProperty = CastField(InProperty); 169 | EnumProperty->GetClass()->GetId(); 170 | FNumericProperty* LocalUnderlyingProp = EnumProperty->GetUnderlyingProperty(); 171 | int64 Value = LocalUnderlyingProp->GetSignedIntPropertyValue(PropertyData); 172 | bValueHasChanged = ImGui::UEEnum(PropertyName.c_str(), EnumProperty->GetEnum(), &Value); 173 | LocalUnderlyingProp->SetIntPropertyValue(PropertyData, Value); 174 | break; 175 | } 176 | case CASTCLASS_FStructProperty: 177 | { 178 | FStructProperty* StructProperty = CastField(InProperty); 179 | bValueHasChanged = ImGui::UEStruct(StructProperty->Struct, PropertyData); 180 | break; 181 | } 182 | 183 | // ========================Object======================== 184 | case CASTCLASS_FObjectProperty: 185 | case CASTCLASS_FWeakObjectProperty: 186 | case CASTCLASS_FLazyObjectProperty: 187 | case CASTCLASS_FSoftObjectProperty: 188 | // break; 189 | 190 | // ========================Class======================== 191 | case CASTCLASS_FClassProperty: 192 | case CASTCLASS_FSoftClassProperty: 193 | // break; 194 | 195 | // ========================Misc======================== 196 | case CASTCLASS_FArrayProperty: 197 | case CASTCLASS_FMapProperty: 198 | case CASTCLASS_FSetProperty: 199 | // break; 200 | 201 | // ========================AActor======================== 202 | case CASTCLASS_AActor: 203 | case CASTCLASS_APlayerController: 204 | case CASTCLASS_APawn: 205 | // break; 206 | 207 | // ========================Reflection[Unused]======================== 208 | case CASTCLASS_UField: 209 | case CASTCLASS_UStruct: 210 | case CASTCLASS_UScriptStruct: 211 | case CASTCLASS_UClass: 212 | case CASTCLASS_UEnum: 213 | case CASTCLASS_UFunction: 214 | 215 | // ========================BasicProperty[Unused]======================== 216 | case CASTCLASS_None: 217 | case CASTCLASS_FProperty: 218 | case CASTCLASS_FInterfaceProperty: 219 | case CASTCLASS_FNumericProperty: 220 | case CASTCLASS_FObjectPropertyBase: 221 | case CASTCLASS_FFieldPathProperty: 222 | 223 | // ========================Delegate[Unused]======================== 224 | case CASTCLASS_FDelegateProperty: 225 | case CASTCLASS_FMulticastDelegateProperty: 226 | case CASTCLASS_FMulticastInlineDelegateProperty: 227 | case CASTCLASS_FMulticastSparseDelegateProperty: 228 | 229 | // ========================EngineMisc[Unused]======================== 230 | case CASTCLASS_UPackage: 231 | case CASTCLASS_ULevel: 232 | case CASTCLASS_USceneComponent: 233 | case CASTCLASS_UPrimitiveComponent: 234 | case CASTCLASS_USkinnedMeshComponent: 235 | case CASTCLASS_USkeletalMeshComponent: 236 | case CASTCLASS_UBlueprint: 237 | case CASTCLASS_UDelegateFunction: 238 | case CASTCLASS_UStaticMeshComponent: 239 | case CASTCLASS_USparseDelegateFunction: 240 | default: 241 | ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1,0,0,1)); 242 | ImGui::Text("UnSupport"); 243 | ImGui::PopStyleColor(); 244 | break; 245 | } 246 | 247 | --DetailDepth; 248 | return bValueHasChanged; 249 | } 250 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/ImguiWrap/ImguiInputAdapter.cpp: -------------------------------------------------------------------------------- 1 | #include "ImguiWrap/ImguiInputAdapter.h" 2 | #include "imgui.h" 3 | #include "imgui_internal.h" 4 | #include "ImguiWrap/ImguiContext.h" 5 | 6 | UImguiInputAdapter::UImguiInputAdapter(const FObjectInitializer& InInitializer) 7 | : Super(InInitializer) 8 | , bBlockInput(true) 9 | , bReceiveMouseInput(true) 10 | , bReceiveKeyboardInput(true) 11 | , bReceiveGamePadInput(true) 12 | , BoundContext(nullptr) 13 | { 14 | 15 | } 16 | 17 | void UImguiInputAdapter::CopyUnrealKeyMap(ImGuiIO* InIO) 18 | { 19 | static int KeyMap[ImGuiKey_COUNT]; 20 | static bool bHasSetKeyMap = false; 21 | if (!bHasSetKeyMap) 22 | { 23 | KeyMap[ImGuiKey_Tab] = MapKey(EKeys::Tab); 24 | KeyMap[ImGuiKey_LeftArrow] = MapKey(EKeys::Left); 25 | KeyMap[ImGuiKey_RightArrow] = MapKey(EKeys::Right); 26 | KeyMap[ImGuiKey_UpArrow] = MapKey(EKeys::Up); 27 | KeyMap[ImGuiKey_DownArrow] = MapKey(EKeys::Down); 28 | KeyMap[ImGuiKey_PageUp] = MapKey(EKeys::PageUp); 29 | KeyMap[ImGuiKey_PageDown] = MapKey(EKeys::PageDown); 30 | KeyMap[ImGuiKey_Home] = MapKey(EKeys::Home); 31 | KeyMap[ImGuiKey_End] = MapKey(EKeys::End); 32 | KeyMap[ImGuiKey_Insert] = MapKey(EKeys::Insert); 33 | KeyMap[ImGuiKey_Delete] = MapKey(EKeys::Delete); 34 | KeyMap[ImGuiKey_Backspace] = MapKey(EKeys::BackSpace); 35 | KeyMap[ImGuiKey_Space] = MapKey(EKeys::SpaceBar); 36 | KeyMap[ImGuiKey_Enter] = MapKey(EKeys::Enter); 37 | KeyMap[ImGuiKey_Escape] = MapKey(EKeys::Escape); 38 | KeyMap[ImGuiKey_A] = MapKey(EKeys::A); 39 | KeyMap[ImGuiKey_C] = MapKey(EKeys::C); 40 | KeyMap[ImGuiKey_V] = MapKey(EKeys::V); 41 | KeyMap[ImGuiKey_X] = MapKey(EKeys::X); 42 | KeyMap[ImGuiKey_Y] = MapKey(EKeys::Y); 43 | KeyMap[ImGuiKey_Z] = MapKey(EKeys::Z); 44 | bHasSetKeyMap = true; 45 | } 46 | FMemory::Memcpy(InIO->KeyMap, KeyMap, sizeof(int) * ImGuiKey_COUNT); 47 | } 48 | 49 | uint32 UImguiInputAdapter::MapKey(const FKey& InKey) 50 | { 51 | const uint32* pKeyCode = nullptr; 52 | const uint32* pCharCode = nullptr; 53 | 54 | FInputKeyManager::Get().GetCodesFromKey(InKey, pKeyCode, pCharCode); 55 | 56 | const uint32 KeyCode = 57 | pKeyCode ? *pKeyCode 58 | : pCharCode ? *pCharCode 59 | : 0; 60 | 61 | return MapKey(KeyCode); 62 | } 63 | 64 | uint32 UImguiInputAdapter::MapMouse(const FPointerEvent& InMouseEvent) 65 | { 66 | if (InMouseEvent.GetEffectingButton() == EKeys::LeftMouseButton) 67 | { 68 | return ImGuiMouseButton_Left; 69 | } 70 | else if (InMouseEvent.GetEffectingButton() == EKeys::MiddleMouseButton) 71 | { 72 | return ImGuiMouseButton_Middle; 73 | } 74 | else if (InMouseEvent.GetEffectingButton() == EKeys::RightMouseButton) 75 | { 76 | return ImGuiMouseButton_Right; 77 | } 78 | else if (InMouseEvent.GetEffectingButton() == EKeys::ThumbMouseButton) 79 | { 80 | return ImGuiMouseButton_Right + 1; 81 | } 82 | else if (InMouseEvent.GetEffectingButton() == EKeys::ThumbMouseButton2) 83 | { 84 | return ImGuiMouseButton_Right + 2; 85 | } 86 | return INDEX_NONE; 87 | } 88 | 89 | FReply UImguiInputAdapter::OnKeyChar(const FCharacterEvent& InCharacterEvent) 90 | { 91 | if (!bReceiveKeyboardInput || !BoundContext) return FReply::Unhandled(); 92 | AddInputCharacter(InCharacterEvent.GetCharacter()); 93 | return bBlockInput && BoundContext->GetIO()->WantCaptureKeyboard ? FReply::Handled() : FReply::Unhandled(); 94 | } 95 | 96 | FReply UImguiInputAdapter::OnKeyDown(const FKeyEvent& InKeyEvent) 97 | { 98 | if (!bReceiveKeyboardInput || !BoundContext) return FReply::Unhandled(); 99 | 100 | // Modifier keys 101 | SetCtrl(InKeyEvent.IsControlDown()); 102 | SetShift(InKeyEvent.IsShiftDown()); 103 | SetAlt(InKeyEvent.IsAltDown()); 104 | 105 | // Add key down input 106 | if (InKeyEvent.GetKey().IsGamepadKey()) 107 | { 108 | 109 | } 110 | else if (InKeyEvent.GetKey().IsTouch()) 111 | { 112 | 113 | } 114 | else 115 | { 116 | SetKeyState(MapKey(InKeyEvent), true); 117 | } 118 | return bBlockInput && BoundContext->GetIO()->WantCaptureKeyboard ? FReply::Handled() : FReply::Unhandled(); 119 | } 120 | 121 | FReply UImguiInputAdapter::OnKeyUp(const FKeyEvent& InKeyEvent) 122 | { 123 | if (!bReceiveKeyboardInput || !BoundContext) return FReply::Unhandled(); 124 | 125 | // Modifier keys 126 | SetCtrl(InKeyEvent.IsControlDown()); 127 | SetShift(InKeyEvent.IsShiftDown()); 128 | SetAlt(InKeyEvent.IsAltDown()); 129 | 130 | // Add key down input 131 | if (InKeyEvent.GetKey().IsGamepadKey()) 132 | { 133 | 134 | } 135 | else if (InKeyEvent.GetKey().IsTouch()) 136 | { 137 | 138 | } 139 | else 140 | { 141 | SetKeyState(MapKey(InKeyEvent), false); 142 | } 143 | return bBlockInput && BoundContext->GetIO()->WantCaptureKeyboard ? FReply::Handled() : FReply::Unhandled(); 144 | } 145 | 146 | FReply UImguiInputAdapter::OnMouseButtonDown(const FPointerEvent& MouseEvent) 147 | { 148 | if (!bReceiveMouseInput || !BoundContext) return FReply::Unhandled(); 149 | 150 | uint32 Index = MapMouse(MouseEvent); 151 | if (Index == INDEX_NONE) return FReply::Unhandled(); 152 | 153 | SetMouseBtnState(Index, true); 154 | return bBlockInput && BoundContext->GetIO()->WantCaptureMouse ? FReply::Handled() : FReply::Unhandled(); 155 | } 156 | 157 | FReply UImguiInputAdapter::OnMouseButtonUp(const FPointerEvent& MouseEvent) 158 | { 159 | if (!bReceiveMouseInput || !BoundContext) return FReply::Unhandled(); 160 | 161 | uint32 Index = MapMouse(MouseEvent); 162 | if (Index == INDEX_NONE) return FReply::Unhandled(); 163 | 164 | SetMouseBtnState(Index, false); 165 | return bBlockInput && BoundContext->GetIO()->WantCaptureMouse ? FReply::Handled() : FReply::Unhandled(); 166 | } 167 | 168 | FReply UImguiInputAdapter::OnMouseButtonDoubleClick(const FPointerEvent& InMouseEvent) 169 | { 170 | if (!bReceiveMouseInput || !BoundContext) return FReply::Unhandled(); 171 | 172 | uint32 Index = MapMouse(InMouseEvent); 173 | if (Index == INDEX_NONE) return FReply::Unhandled(); 174 | 175 | SetMouseBtnState(Index, true); 176 | return bBlockInput && BoundContext->GetIO()->WantCaptureMouse ? FReply::Handled() : FReply::Unhandled(); 177 | } 178 | 179 | FReply UImguiInputAdapter::OnMouseWheel(const FPointerEvent& MouseEvent) 180 | { 181 | if (!bReceiveMouseInput || !BoundContext) return FReply::Unhandled(); 182 | 183 | SetMouseWheel(MouseEvent.GetWheelDelta()); 184 | return bBlockInput && BoundContext->GetIO()->WantCaptureMouse ? FReply::Handled() : FReply::Unhandled(); 185 | } 186 | 187 | FReply UImguiInputAdapter::OnMouseMove(SWidget* InWidget, const FGeometry& InGeometry, const FPointerEvent& MouseEvent) 188 | { 189 | if (!bReceiveMouseInput || !BoundContext) return FReply::Unhandled(); 190 | 191 | FVector2D Position = MouseEvent.GetScreenSpacePosition(); 192 | Position = InGeometry.GetAccumulatedRenderTransform().Inverse().TransformPoint(Position); 193 | 194 | SetMousePos(Position); 195 | 196 | return bBlockInput && BoundContext->GetIO()->WantCaptureMouse ? FReply::Handled() : FReply::Unhandled(); 197 | } 198 | 199 | FReply UImguiInputAdapter::OnMouseMove(FVector2D OffsetPos, const FPointerEvent& MouseEvent) 200 | { 201 | if (!bReceiveMouseInput || !BoundContext) return FReply::Unhandled(); 202 | 203 | SetMousePos(MouseEvent.GetScreenSpacePosition() - OffsetPos); 204 | 205 | return bBlockInput && BoundContext->GetIO()->WantCaptureMouse ? FReply::Handled() : FReply::Unhandled(); 206 | } 207 | 208 | FCursorReply UImguiInputAdapter::OnCursorQuery(const FPointerEvent& CursorEvent) 209 | { 210 | if (!BoundContext) return FCursorReply::Unhandled(); 211 | 212 | switch (BoundContext->GetContext()->MouseCursor) 213 | { 214 | case ImGuiMouseCursor_Arrow: return FCursorReply::Cursor(EMouseCursor::Default); 215 | case ImGuiMouseCursor_TextInput: return FCursorReply::Cursor(EMouseCursor::TextEditBeam); 216 | case ImGuiMouseCursor_ResizeAll: return FCursorReply::Cursor(EMouseCursor::CardinalCross); 217 | case ImGuiMouseCursor_ResizeEW: return FCursorReply::Cursor(EMouseCursor::ResizeLeftRight); 218 | case ImGuiMouseCursor_ResizeNS: return FCursorReply::Cursor(EMouseCursor::ResizeUpDown); 219 | case ImGuiMouseCursor_ResizeNESW: return FCursorReply::Cursor(EMouseCursor::ResizeSouthWest); 220 | case ImGuiMouseCursor_ResizeNWSE: return FCursorReply::Cursor(EMouseCursor::ResizeSouthEast); 221 | case ImGuiMouseCursor_Hand: return FCursorReply::Cursor(EMouseCursor::Hand); 222 | case ImGuiMouseCursor_NotAllowed: return FCursorReply::Cursor(EMouseCursor::SlashedCircle); 223 | } 224 | return FCursorReply::Cursor(EMouseCursor::Default); 225 | } 226 | 227 | void UImguiInputAdapter::AddInputIME(const FString& InStr) 228 | { 229 | for (TCHAR Ch : InStr) 230 | { 231 | AddInputCharacter(Ch); 232 | } 233 | } 234 | 235 | void UImguiInputAdapter::AddInputCharacter(TCHAR InChar) 236 | { 237 | BoundContext->GetIO()->AddInputCharacter(static_cast(InChar)); 238 | } 239 | 240 | void UImguiInputAdapter::SetKeyState(uint32 InKeyNum, bool InState) 241 | { 242 | BoundContext->GetIO()->KeysDown[InKeyNum] = InState; 243 | } 244 | 245 | void UImguiInputAdapter::SetCtrl(bool InState) 246 | { 247 | BoundContext->GetIO()->KeyCtrl = InState; 248 | } 249 | 250 | void UImguiInputAdapter::SetAlt(bool InState) 251 | { 252 | BoundContext->GetIO()->KeyAlt = InState; 253 | } 254 | 255 | void UImguiInputAdapter::SetShift(bool InState) 256 | { 257 | BoundContext->GetIO()->KeyShift = InState; 258 | } 259 | 260 | void UImguiInputAdapter::SetMouseBtnState(uint32 MouseBtnIndex, bool InState) 261 | { 262 | BoundContext->GetIO()->MouseDown[MouseBtnIndex] = InState; 263 | } 264 | 265 | void UImguiInputAdapter::SetMouseWheel(float MouseWheel) 266 | { 267 | BoundContext->GetIO()->MouseWheel = MouseWheel; 268 | } 269 | 270 | void UImguiInputAdapter::SetMousePos(FVector2D InMousePos) 271 | { 272 | BoundContext->GetIO()->MousePos.x = InMousePos.X; 273 | BoundContext->GetIO()->MousePos.y = InMousePos.Y; 274 | } 275 | -------------------------------------------------------------------------------- /Source/ThirdParty/Imgui/Public/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) 7 | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. 8 | //----------------------------------------------------------------------------- 9 | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp 10 | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 11 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 12 | // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. 13 | //----------------------------------------------------------------------------- 14 | 15 | #pragma once 16 | 17 | //---- Define assertion handler. Defaults to calling assert(). 18 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. 19 | #define IM_ASSERT(_EXPR) do {check(_EXPR)} while(0) 20 | // #define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 21 | 22 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 23 | // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 24 | // DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() 25 | // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. 26 | //#define IMGUI_API __declspec( dllexport ) 27 | //#define IMGUI_API __declspec( dllimport ) 28 | 29 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. 30 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 31 | 32 | //---- Disable all of Dear ImGui or don't implement standard windows. 33 | // It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp. 34 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 35 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended. 36 | //#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty. 37 | 38 | //---- Don't implement some functions to reduce linkage requirements. 39 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) 40 | //#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) 41 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) 42 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). 43 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). 44 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) 45 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. 46 | //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) 47 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. 48 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 49 | //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available 50 | 51 | //---- Include imgui_user.h at the end of imgui.h as a convenience 52 | //#define IMGUI_INCLUDE_IMGUI_USER_H 53 | 54 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 55 | //#define IMGUI_USE_BGRA_PACKED_COLOR 56 | 57 | //---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) 58 | //#define IMGUI_USE_WCHAR32 59 | 60 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 61 | // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. 62 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 63 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 64 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 65 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 66 | 67 | //---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) 68 | // Requires 'stb_sprintf.h' to be available in the include path. Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf. 69 | // #define IMGUI_USE_STB_SPRINTF 70 | 71 | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) 72 | // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). 73 | // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. 74 | //#define IMGUI_ENABLE_FREETYPE 75 | 76 | //---- Use stb_truetype to build and rasterize the font atlas (default) 77 | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. 78 | //#define IMGUI_ENABLE_STB_TRUETYPE 79 | 80 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 81 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 82 | /* 83 | #define IM_VEC2_CLASS_EXTRA \ 84 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 85 | operator MyVec2() const { return MyVec2(x,y); } 86 | 87 | #define IM_VEC4_CLASS_EXTRA \ 88 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 89 | operator MyVec4() const { return MyVec4(x,y,z,w); } 90 | */ 91 | 92 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 93 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). 94 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 95 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 96 | //#define ImDrawIdx unsigned int 97 | 98 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) 99 | //struct ImDrawList; 100 | //struct ImDrawCmd; 101 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 102 | //#define ImDrawCallback MyImDrawCallback 103 | 104 | //---- Debug Tools: Macro to break in Debugger 105 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 106 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 107 | //#define IM_DEBUG_BREAK __debugbreak() 108 | 109 | //---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(), 110 | // (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.) 111 | // This adds a small runtime cost which is why it is not enabled by default. 112 | //#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX 113 | 114 | //---- Debug Tools: Enable slower asserts 115 | //#define IMGUI_DEBUG_PARANOID 116 | 117 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 118 | /* 119 | namespace ImGui 120 | { 121 | void MyFunction(const char* name, const MyMatrix44& v); 122 | } 123 | */ 124 | -------------------------------------------------------------------------------- /Source/ThirdParty/ImPlot/README.md: -------------------------------------------------------------------------------- 1 | # ImPlot 2 | ImPlot is an immediate mode, GPU accelerated plotting library for [Dear ImGui](https://github.com/ocornut/imgui). It aims to provide a first-class API that ImGui fans will love. ImPlot is well suited for visualizing program data in real-time or creating interactive plots, and requires minimal code to integrate. Just like ImGui, it does not burden the end user with GUI state management, avoids STL containers and C++ headers, and has no external dependencies except for ImGui itself. 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ## Features 16 | 17 | - GPU accelerated rendering 18 | - multiple plot types: 19 | - line plots 20 | - shaded plots 21 | - scatter plots 22 | - vertical/horizontal bars graphs 23 | - vertical/horizontal error bars 24 | - stem plots 25 | - stair plots 26 | - pie charts 27 | - heatmap charts 28 | - images 29 | - and more likely to come 30 | - mix/match multiple plot items on a single plot 31 | - configurable axes ranges and scaling (linear/log) 32 | - time formatted x-axes (US formatted or ISO 8601) 33 | - reversible and lockable axes 34 | - up to three independent y-axes 35 | - controls for zooming, panning, box selection, and auto-fitting data 36 | - controls for creating persistent query ranges (see demo) 37 | - remappable input controls 38 | - several plot styling options: 10 marker types, adjustable marker sizes, line weights, outline colors, fill colors, etc. 39 | - 10 built-in and user definable colormaps 40 | - optional plot titles, axis labels, and grid labels 41 | - optional and configurable legends with toggle buttons to quickly show/hide plot items 42 | - default styling based on current ImGui theme, but most elements can be customized independently 43 | - customizable data getters and data striding (just like ImGui:PlotLine) 44 | - accepts data as float, double, and 8, 16, 32, and 64-bit signed/unsigned integral types 45 | - and more! (see Announcements [2020](https://github.com/epezent/implot/issues/48)/[2021](https://github.com/epezent/implot/issues/168)) 46 | 47 | ## Usage 48 | 49 | The API is used just like any other ImGui `BeginX`/`EndX` pair. First, start a new plot with `ImPlot::BeginPlot()`. Next, plot as many items as you want with the provided `PlotX` functions (e.g. `PlotLine()`, `PlotBars()`, `PlotScatter()`, etc). Finally, wrap things up with a call to `ImPlot::EndPlot()`. That's it! 50 | 51 | ```cpp 52 | int bar_data[11] = ...; 53 | float x_data[1000] = ...; 54 | float y_data[1000] = ...; 55 | 56 | ImGui::Begin("My Window"); 57 | if (ImPlot::BeginPlot("My Plot")) { 58 | ImPlot::PlotBars("My Bar Plot", bar_data, 11); 59 | ImPlot::PlotLine("My Line Plot", x_data, y_data, 1000); 60 | ... 61 | ImPlot::EndPlot(); 62 | } 63 | ImGui::End(); 64 | ``` 65 | 66 | ![Usage](https://raw.githubusercontent.com/wiki/epezent/implot/screenshots3/example.PNG) 67 | 68 | 69 | Of course, there's much more you can do with ImPlot. Consult `implot_demo.cpp` for a comprehensive example of ImPlot's features. 70 | 71 | ## Interactive Demo 72 | 73 | An online version of the demo is hosted [here](https://traineq.org/implot_demo/src/implot_demo.html). You can view the plots and the source code that generated them. Note that this demo may not always be up to date and is not as performant as a desktop implementation, but it should give you a general taste of what's possible with ImPlot. Special thanks to [pthom](https://github.com/pthom) for creating and hosting this! 74 | 75 | ## Integration 76 | 77 | 0) Set up an [ImGui](https://github.com/ocornut/imgui) environment if you don't already have one. 78 | 1) Add `implot.h`, `implot_internal.h`, `implot.cpp`, `implot_items.cpp` and optionally `implot_demo.cpp` to your sources. Alternatively, you can get ImPlot using [vcpkg](https://github.com/microsoft/vcpkg/tree/master/ports/implot). 79 | 2) Create and destroy an `ImPlotContext` wherever you do so for your `ImGuiContext`: 80 | 81 | ```cpp 82 | ImGui::CreateContext(); 83 | ImPlot::CreateContext(); 84 | ... 85 | ImPlot::DestroyContext(); 86 | ImGui::DestroyContext(); 87 | ``` 88 | 89 | You should be good to go! 90 | 91 | If you want to test ImPlot quickly, consider trying [mahi-gui](https://github.com/mahilab/mahi-gui), which bundles ImGui, ImPlot, and several other packages for you. 92 | 93 | ## Special Notes 94 | 95 | - If you experience data truncation and/or visual glitches, it is **HIGHLY** recommended that you EITHER: 96 | 1) Handle the `ImGuiBackendFlags_RendererHasVtxOffset` flag in your renderer when using 16-bit indices (the official OpenGL3 renderer supports this) and use an ImGui version with patch [imgui@f6120f8](https://github.com/ocornut/imgui/commit/f6120f8e16eefcdb37b63974e6915a3dd35414be), OR... 97 | 2) Enable 32-bit indices by uncommenting `#define ImDrawIdx unsigned int` in your ImGui `imconfig.h` file. 98 | - By default, no anti-aliasing is done on line plots for performance gains. If you use 4x MSAA, then you likely won't even notice. However, you can enable software AA per-plot with the `ImPlotFlags_AntiAliased` flag, or globally with `ImPlot::GetStyle().AntiAliasedLines = true;`. 99 | - Like ImGui, it is recommended that you compile and link ImPlot as a *static* library or directly as a part of your sources. However, if you are compiling ImPlot and ImGui as separate DLLs, make sure you set the current *ImGui* context with `ImPlot::SetImGuiContext(ImGuiContext* ctx)`. This ensures that global ImGui variables are correctly shared across the DLL boundary. 100 | 101 | ## FAQ 102 | 103 | **Q: Why?** 104 | 105 | A: ImGui is an incredibly powerful tool for rapid prototyping and development, but provides only limited mechanisms for data visualization. Two dimensional plots are ubiquitous and useful to almost any application. Being able to visualize your data in real-time will give you insight and better understanding of your application. 106 | 107 | **Q: Is ImPlot the right plotting library for me?** 108 | 109 | A: If you're looking to generate publication quality plots and/or export plots to a file, ImPlot is NOT the library for you. ImPlot is geared toward plotting application data at realtime speeds. ImPlot does its best to create pretty plots (indeed, there are quite a few styling options available), but it will always favor function over form. 110 | 111 | **Q: Where is the documentation?** 112 | 113 | A: The API is thoroughly commented in `implot.h`, and the demo in `implot_demo.cpp` should be more than enough to get you started. 114 | 115 | **Q: Is ImPlot suitable for plotting large datasets?** 116 | 117 | A: Yes, within reason. You can plot tens to hundreds of thousands of points without issue, but don't expect millions to be a buttery smooth experience. That said, you can always downsample extremely large datasets by telling ImPlot to stride your data at larger intervals if needed. 118 | 119 | **Q: What data types can I plot?** 120 | 121 | A: ImPlot plotting functions accept most scalar types: 122 | `float`, `double`, `int8`, `uint8`, `int16`, `uint16`, `int32`, `uint32`, `int64`, `uint64`. Arrays of custom structs or classes (e.g. `Vector2f` or similar) are easily passed to ImPlot functions using the built in striding features (see `implot.h` for documentation). 123 | 124 | **Q: Can plot styles be modified?** 125 | 126 | A: Yes. Data colormaps and various styling colors and variables can be pushed/popped or modified permanently on startup. Three default styles are available, as well as an automatic style that attempts to match you ImGui style. 127 | 128 | **Q: Does ImPlot support logarithmic scaling or time formatting?** 129 | 130 | A: Yep! Both logscale and timescale are supported. 131 | 132 | **Q: Does ImPlot support multiple y-axes? x-axes?** 133 | 134 | A: Yes. Up to three y-axes can be enabled. Multiple x-axes are not supported. 135 | 136 | **Q: Does ImPlot support [insert plot type]?** 137 | 138 | A: Maybe. Check the demo, gallery, or Announcements ([2020](https://github.com/epezent/implot/issues/48)/[2021](https://github.com/epezent/implot/issues/168))to see if your desired plot type is shown. If not, consider submitting an issue or better yet, a PR! 139 | 140 | **Q: Does ImPlot support 3D plots?** 141 | 142 | A: No, and likely never will since ImGui only deals in 2D rendering. 143 | 144 | **Q: My plot lines look like crap!** 145 | 146 | A: See the note about anti-aliasing under **Special Notes** above. 147 | 148 | **Q: Does ImPlot provide analytic tools?** 149 | 150 | A: Not exactly, but it does give you the ability to query plot sub-ranges, with which you can process your data however you like. 151 | 152 | **Q: Can plots be exported/saved to image?** 153 | 154 | A: Not currently. Use your OS's screen capturing mechanisms if you need to capture a plot. ImPlot is not suitable for rendering publication quality plots; it is only intended to be used as a visualization tool. Post-process your data with MATLAB or matplotlib for these purposes. 155 | 156 | **Q: Can ImPlot be used with other languages/bindings?** 157 | 158 | A: Yes, you can use the generated C binding, [cimplot](https://github.com/cimgui/cimplot) with most high level languages. [DearPyGui](https://github.com/hoffstadt/DearPyGui) provides a Python wrapper, among other things. A Rust binding, [implot-rs](https://github.com/4bb4/implot-rs), is currently in the works. An example using Emscripten can be found [here](https://github.com/pthom/implot_demo). 159 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Render/ImguiDrawer.cpp: -------------------------------------------------------------------------------- 1 | #include "ImguiDrawer.h" 2 | 3 | #include "ClearQuad.h" 4 | #include "ImguiShader.h" 5 | #include "ImguiWrap/ImguiResourceManager.h" 6 | 7 | TArray> FImguiDrawer::GlobalPool; 8 | 9 | FImguiDrawer::~FImguiDrawer() 10 | { 11 | if (VtxBuf) 12 | { 13 | FMemory::Free(VtxBuf); 14 | } 15 | if (IdxBuf) 16 | { 17 | FMemory::Free(IdxBuf); 18 | } 19 | } 20 | 21 | void FImguiDrawer::SetDrawData(ImDrawData* InDrawData) 22 | { 23 | // get vertex and index num 24 | int32 VtxNum = InDrawData->TotalVtxCount; 25 | int32 IdxNum = InDrawData->TotalIdxCount; 26 | 27 | // update buffer 28 | _UpdateBufferSize(VtxNum, IdxNum); 29 | 30 | // copy data 31 | _AppendDrawData(InDrawData, VtxBuf, IdxBuf); 32 | } 33 | 34 | void FImguiDrawer::SetDrawData(const TArray& InDrawData) 35 | { 36 | // get vertex and index num 37 | int32 VtxNum = 0; 38 | int32 IdxNum = 0; 39 | for (ImDrawData* DrawData : InDrawData) 40 | { 41 | VtxNum += DrawData->TotalVtxCount; 42 | IdxNum += DrawData->TotalIdxCount; 43 | } 44 | 45 | // update buffer 46 | _UpdateBufferSize(VtxNum, IdxNum); 47 | 48 | // copy data 49 | int32 BaseVtx = 0; 50 | int32 BaseIdx = 0; 51 | for (ImDrawData* DrawData : InDrawData) 52 | { 53 | _AppendDrawData(DrawData, VtxBuf, IdxBuf, BaseVtx, BaseIdx); 54 | BaseVtx += DrawData->TotalVtxCount; 55 | BaseIdx += DrawData->TotalIdxCount; 56 | } 57 | } 58 | 59 | void FImguiDrawer::SetDrawData(const TArray& InDrawData) 60 | { 61 | // reset draw elements 62 | AllDrawElements.Reset(); 63 | 64 | // get vertex and index num 65 | int32 VtxNum = 0; 66 | int32 IdxNum = 0; 67 | for (ImDrawList* DrawList : InDrawData) 68 | { 69 | VtxNum += DrawList->VtxBuffer.Size; 70 | IdxNum += DrawList->IdxBuffer.Size; 71 | } 72 | 73 | // update buffer 74 | _UpdateBufferSize(VtxNum, IdxNum); 75 | 76 | // copy data 77 | int32 BaseVtx = 0; 78 | int32 BaseIdx = 0; 79 | for (ImDrawList* DrawList : InDrawData) 80 | { 81 | _AppendDrawList(DrawList, VtxBuf, IdxBuf, BaseVtx, BaseIdx); 82 | BaseVtx += DrawList->VtxBuffer.Size; 83 | BaseIdx += DrawList->IdxBuffer.Size; 84 | } 85 | } 86 | 87 | FVertexDeclarationRHIRef FImguiDrawer::_GetMeshDeclaration() 88 | { 89 | static FVertexDeclarationRHIRef VertexDeclarationRHI; 90 | if (!VertexDeclarationRHI.IsValid()) 91 | { 92 | FVertexDeclarationElementList Elements; 93 | uint16 Stride = sizeof(ImDrawVert); 94 | Elements.Add(FVertexElement(0,STRUCT_OFFSET(ImDrawVert,pos),VET_Float2,0,Stride)); 95 | Elements.Add(FVertexElement(0,STRUCT_OFFSET(ImDrawVert,uv),VET_Float2,1,Stride)); 96 | Elements.Add(FVertexElement(0,STRUCT_OFFSET(ImDrawVert,col),VET_UByte4N,2,Stride)); 97 | VertexDeclarationRHI = PipelineStateCache::GetOrCreateVertexDeclaration(Elements); 98 | } 99 | return VertexDeclarationRHI; 100 | } 101 | 102 | void FImguiDrawer::_UpdateBufferSize(int32 InVtxNum, int32 InIdxNum) 103 | { 104 | #if ENGINE_MAJOR_VERSION == 5 105 | FRHIResourceCreateInfo CreateInfo(TEXT("IMGUI_BUFFER")); 106 | #else 107 | FRHIResourceCreateInfo CreateInfo; 108 | #endif 109 | if (InVtxNum > NumVertices) 110 | { 111 | auto VtxBufSize = sizeof(ImDrawVert) * InVtxNum; 112 | VertexBufferRHI = RHICreateVertexBuffer(VtxBufSize, BUF_Dynamic, CreateInfo); 113 | if (VtxBuf) 114 | { 115 | FMemory::Free(VtxBuf); 116 | } 117 | VtxBuf = (ImDrawVert*)FMemory::Malloc(VtxBufSize); 118 | NumVertices = InVtxNum; 119 | } 120 | if (InIdxNum > NumTriangles * 3) 121 | { 122 | auto IdxBufSize = sizeof(ImDrawIdx) * InIdxNum; 123 | check(InIdxNum % 3 == 0); 124 | IndexBufferRHI = RHICreateIndexBuffer(sizeof(ImDrawIdx), IdxBufSize, BUF_Dynamic, CreateInfo); 125 | if (IdxBuf) 126 | { 127 | FMemory::Free(IdxBuf); 128 | } 129 | IdxBuf = (ImDrawIdx*)FMemory::Malloc(IdxBufSize); 130 | NumTriangles = InIdxNum / 3; 131 | } 132 | } 133 | 134 | void FImguiDrawer::_AppendDrawData(ImDrawData* InDrawData, ImDrawVert* InVtxBuf, ImDrawIdx* InIdxBuf, int32 BaseVtx, 135 | int32 BaseIdx) 136 | { 137 | // offset vtx and idx 138 | InVtxBuf += BaseVtx; 139 | InIdxBuf += BaseIdx; 140 | 141 | uint32 GlobalVtxOffset = BaseVtx; 142 | uint32 GlobalIdxOffset = BaseIdx; 143 | for (int32 ListIdx = 0; ListIdx < InDrawData->CmdListsCount; ++ListIdx) 144 | { 145 | ImDrawList* DrawList = InDrawData->CmdLists[ListIdx]; 146 | 147 | _AppendDrawList(DrawList, InVtxBuf, InIdxBuf, GlobalVtxOffset, GlobalIdxOffset); 148 | 149 | GlobalVtxOffset += DrawList->VtxBuffer.Size; 150 | GlobalIdxOffset += DrawList->IdxBuffer.Size; 151 | } 152 | } 153 | 154 | void FImguiDrawer::_AppendDrawList(ImDrawList* InDrawList, ImDrawVert* InVtxBuf, ImDrawIdx* InIdxBuf, int32 BaseVtx, 155 | int32 BaseIdx) 156 | { 157 | // offset vtx and idx 158 | InVtxBuf += BaseVtx; 159 | InIdxBuf += BaseIdx; 160 | 161 | // copy vertices and indices 162 | FMemory::Memcpy(InVtxBuf, InDrawList->VtxBuffer.Data, InDrawList->VtxBuffer.Size * sizeof(ImDrawVert)); 163 | FMemory::Memcpy(InIdxBuf, InDrawList->IdxBuffer.Data, InDrawList->IdxBuffer.Size * sizeof(ImDrawIdx)); 164 | 165 | // copy draw commands 166 | for (int32 CmdIdx = 0; CmdIdx < InDrawList->CmdBuffer.Size; ++CmdIdx) 167 | { 168 | ImDrawCmd& DrawCmd = InDrawList->CmdBuffer[CmdIdx]; 169 | 170 | AllDrawElements.AddUninitialized(); 171 | auto& Element = AllDrawElements.Top(); 172 | Element.TextureID = DrawCmd.TextureId; 173 | Element.VtxOffset = DrawCmd.VtxOffset + BaseVtx; 174 | Element.IdxOffset = DrawCmd.IdxOffset + BaseIdx; 175 | Element.NumIndices = DrawCmd.ElemCount; 176 | FSlateRect Rect(*(FSlateRect*)&DrawCmd.ClipRect); 177 | Rect.Left += VertexOffset.X; 178 | Rect.Right += VertexOffset.X; 179 | Rect.Top += VertexOffset.Y; 180 | Rect.Bottom += VertexOffset.Y; 181 | Element.ScissorRect = ClippingRect.IntersectionWith(Rect); 182 | } 183 | } 184 | 185 | FRHITexture2D* FImguiDrawer::_GetTextureFromID(ImTextureID InID) 186 | { 187 | if (!InID) return nullptr; 188 | auto ImResource = UImguiResourceManager::Get().FindResource(InID); 189 | if (!ImResource || !ImResource->Source || !ImResource->Source->Resource) return nullptr; 190 | return ImResource->Source->Resource->TextureRHI->GetTexture2D(); 191 | } 192 | 193 | TSharedPtr FImguiDrawer::AllocDrawer() 194 | { 195 | // find free drawer 196 | for (TSharedPtr Drawer : GlobalPool) 197 | { 198 | if (Drawer->bIsFree) 199 | { 200 | Drawer->bIsFree = false; 201 | return Drawer; 202 | } 203 | } 204 | 205 | // create new 206 | GlobalPool.Emplace(MakeShared()); 207 | return GlobalPool.Top(); 208 | } 209 | 210 | void FImguiDrawer::DrawRenderThread(FRHICommandListImmediate& RHICmdList, const void* RenderTarget) 211 | { 212 | check(IsInRenderingThread()); 213 | 214 | // early out 215 | if (AllDrawElements.Num() == 0) 216 | { 217 | bIsFree = true; 218 | return; 219 | } 220 | 221 | // copy data 222 | auto VtxBufSize = NumVertices * sizeof(ImDrawVert); 223 | auto IdxBufSize = NumTriangles * 3 * sizeof(ImDrawIdx); 224 | ImDrawVert* RHIVtxBuf = (ImDrawVert*)RHILockVertexBuffer(VertexBufferRHI, 0, VtxBufSize, EResourceLockMode::RLM_WriteOnly); 225 | ImDrawIdx* RHIIdxBuf = (ImDrawIdx*)RHILockIndexBuffer(IndexBufferRHI, 0, IdxBufSize, EResourceLockMode::RLM_WriteOnly); 226 | 227 | FMemory::Memcpy(RHIVtxBuf, VtxBuf, VtxBufSize); 228 | FMemory::Memcpy(RHIIdxBuf, IdxBuf, IdxBufSize); 229 | 230 | RHIUnlockVertexBuffer(VertexBufferRHI); 231 | RHIUnlockIndexBuffer(IndexBufferRHI); 232 | 233 | // get render target 234 | FTexture2DRHIRef* RT = (FTexture2DRHIRef*)RenderTarget; 235 | 236 | // begin pass 237 | FRHIRenderPassInfo PassInfo(*RT, ERenderTargetActions::Load_Store); 238 | RHICmdList.BeginRenderPass(PassInfo, TEXT("DrawImguiMesh")); 239 | 240 | // get shader 241 | TShaderMapRef Vs(GetGlobalShaderMap(ERHIFeatureLevel::SM5)); 242 | TShaderMapRef Ps(GetGlobalShaderMap(ERHIFeatureLevel::SM5)); 243 | 244 | // setup PSO 245 | FGraphicsPipelineStateInitializer PSOInitializer; 246 | RHICmdList.ApplyCachedRenderTargets(PSOInitializer); 247 | PSOInitializer.BoundShaderState.VertexDeclarationRHI = _GetMeshDeclaration(); 248 | PSOInitializer.BoundShaderState.VertexShaderRHI = Vs.GetVertexShader(); 249 | PSOInitializer.BoundShaderState.PixelShaderRHI = Ps.GetPixelShader(); 250 | PSOInitializer.PrimitiveType = PT_TriangleList; 251 | PSOInitializer.BlendState = TStaticBlendState::GetRHI(); 252 | PSOInitializer.RasterizerState = TStaticRasterizerState<>::GetRHI(); 253 | PSOInitializer.DepthStencilState = TStaticDepthStencilState::GetRHI(); 254 | 255 | // init pso 256 | SetGraphicsPipelineState(RHICmdList, PSOInitializer); 257 | 258 | // init texture 259 | FRHITexture2D* CurTexture = _GetTextureFromID(AllDrawElements[0].TextureID); 260 | Ps->SetHasTexture(RHICmdList, Ps.GetPixelShader(), CurTexture != nullptr); 261 | if (CurTexture) 262 | { 263 | Ps->SetParameters(RHICmdList, Ps.GetPixelShader(), CurTexture); 264 | } 265 | 266 | // setup transform 267 | FMatrix RenderMatrix(FMatrix::Identity); 268 | RenderMatrix.M[0][0] = Scale; 269 | RenderMatrix.M[1][1] = Scale; 270 | RenderMatrix.M[3][0] = VertexOffset.X; 271 | RenderMatrix.M[3][1] = VertexOffset.Y; 272 | RenderMatrix *= OrthoMatrix; 273 | Vs->SetParameters(RHICmdList, RenderMatrix); 274 | 275 | // setup vertex buffer 276 | RHICmdList.SetStreamSource(0, VertexBufferRHI, 0); 277 | 278 | // draw items 279 | for (DrawElement& Element : AllDrawElements) 280 | { 281 | // early out 282 | if (!Element.NumIndices) continue; 283 | 284 | // get new texture 285 | FRHITexture2D* NewTexture = _GetTextureFromID(Element.TextureID); 286 | 287 | // change texture 288 | if (NewTexture != CurTexture) 289 | { 290 | // setup texture state 291 | Ps->SetHasTexture(RHICmdList, Ps.GetPixelShader(), NewTexture != nullptr); 292 | 293 | // change texture 294 | if (NewTexture) Ps->SetParameters(RHICmdList, Ps.GetPixelShader(), NewTexture); 295 | 296 | // update current texture 297 | CurTexture = NewTexture; 298 | } 299 | 300 | // setup scissor rect 301 | RHICmdList.SetScissorRect( 302 | true, 303 | Element.ScissorRect.Left, 304 | Element.ScissorRect.Top, 305 | Element.ScissorRect.Right, 306 | Element.ScissorRect.Bottom); 307 | 308 | // render mesh 309 | RHICmdList.DrawIndexedPrimitive( 310 | IndexBufferRHI, 311 | Element.VtxOffset, 312 | 0, 313 | NumVertices, 314 | Element.IdxOffset, 315 | Element.NumIndices / 3, 316 | 1); 317 | } 318 | 319 | // end pass 320 | RHICmdList.EndRenderPass(); 321 | 322 | // reset draw elements 323 | AllDrawElements.Reset(); 324 | 325 | // mark free 326 | bIsFree = true; 327 | } 328 | -------------------------------------------------------------------------------- /Source/UEImgui/Private/Config/ImguiConfig.cpp: -------------------------------------------------------------------------------- 1 | #include "Config/ImguiConfig.h" 2 | #include "imgui.h" 3 | 4 | UImguiConfig::UImguiConfig() 5 | { 6 | // setup category 7 | CategoryName = TEXT("Plugins"); 8 | 9 | // color settings 10 | ImguiColors.SetNumUninitialized(ImGuiCol_COUNT); 11 | ImguiColors[ImGuiCol_Text] = FLinearColor(1.00f, 1.00f, 1.00f, 1.00f); 12 | ImguiColors[ImGuiCol_TextDisabled] = FLinearColor(0.50f, 0.50f, 0.50f, 1.00f); 13 | ImguiColors[ImGuiCol_WindowBg] = FLinearColor(0.13f, 0.13f, 0.13f, 1.00f); 14 | ImguiColors[ImGuiCol_ChildBg] = FLinearColor(0.13f, 0.13f, 0.13f, 1.00f); 15 | ImguiColors[ImGuiCol_PopupBg] = FLinearColor(0.08f, 0.08f, 0.08f, 0.94f); 16 | ImguiColors[ImGuiCol_Border] = FLinearColor(0.43f, 0.43f, 0.50f, 0.50f); 17 | ImguiColors[ImGuiCol_BorderShadow] = FLinearColor(0.00f, 0.00f, 0.00f, 0.00f); 18 | ImguiColors[ImGuiCol_FrameBg] = FLinearColor(0.33f, 0.33f, 0.33f, 1.00f); 19 | ImguiColors[ImGuiCol_FrameBgHovered] = FLinearColor(0.19f, 0.19f, 0.19f, 1.00f); 20 | ImguiColors[ImGuiCol_FrameBgActive] = FLinearColor(0.56f, 0.56f, 0.56f, 1.00f); 21 | ImguiColors[ImGuiCol_TitleBg] = FLinearColor(0.13f, 0.13f, 0.13f, 1.00f); 22 | ImguiColors[ImGuiCol_TitleBgActive] = FLinearColor(0.33f, 0.33f, 0.33f, 1.00f); 23 | ImguiColors[ImGuiCol_TitleBgCollapsed] = FLinearColor(0.13f, 0.13f, 0.13f, 1.00f); 24 | ImguiColors[ImGuiCol_MenuBarBg] = FLinearColor(0.14f, 0.14f, 0.14f, 1.00f); 25 | ImguiColors[ImGuiCol_ScrollbarBg] = FLinearColor(0.02f, 0.02f, 0.02f, 0.53f); 26 | ImguiColors[ImGuiCol_ScrollbarGrab] = FLinearColor(0.31f, 0.31f, 0.31f, 1.00f); 27 | ImguiColors[ImGuiCol_ScrollbarGrabHovered] = FLinearColor(0.41f, 0.41f, 0.41f, 1.00f); 28 | ImguiColors[ImGuiCol_ScrollbarGrabActive] = FLinearColor(0.51f, 0.51f, 0.51f, 1.00f); 29 | ImguiColors[ImGuiCol_CheckMark] = FLinearColor(0.04f, 0.04f, 0.04f, 1.00f); 30 | ImguiColors[ImGuiCol_SliderGrab] = FLinearColor(0.80f, 0.80f, 0.80f, 1.00f); 31 | ImguiColors[ImGuiCol_SliderGrabActive] = FLinearColor(0.02f, 0.02f, 0.02f, 1.00f); 32 | ImguiColors[ImGuiCol_Button] = FLinearColor(0.33f, 0.33f, 0.33f, 1.00f); 33 | ImguiColors[ImGuiCol_ButtonHovered] = FLinearColor(0.27f, 0.27f, 0.27f, 1.00f); 34 | ImguiColors[ImGuiCol_ButtonActive] = FLinearColor(0.15f, 0.15f, 0.15f, 1.00f); 35 | ImguiColors[ImGuiCol_Header] = FLinearColor(0.28f, 0.28f, 0.28f, 1.00f); 36 | ImguiColors[ImGuiCol_HeaderHovered] = FLinearColor(0.50f, 0.50f, 0.50f, 0.80f); 37 | ImguiColors[ImGuiCol_HeaderActive] = FLinearColor(0.67f, 0.67f, 0.67f, 1.00f); 38 | ImguiColors[ImGuiCol_Separator] = FLinearColor(0.43f, 0.43f, 0.50f, 0.50f); 39 | ImguiColors[ImGuiCol_SeparatorHovered] = FLinearColor(0.10f, 0.40f, 0.75f, 0.78f); 40 | ImguiColors[ImGuiCol_SeparatorActive] = FLinearColor(0.10f, 0.40f, 0.75f, 1.00f); 41 | ImguiColors[ImGuiCol_ResizeGrip] = FLinearColor(0.80f, 0.80f, 0.80f, 1.00f); 42 | ImguiColors[ImGuiCol_ResizeGripHovered] = FLinearColor(0.87f, 0.87f, 0.87f, 1.00f); 43 | ImguiColors[ImGuiCol_ResizeGripActive] = FLinearColor(1.00f, 1.00f, 1.00f, 1.00f); 44 | ImguiColors[ImGuiCol_Tab] = FLinearColor(0.31f, 0.31f, 0.31f, 1.00f); 45 | ImguiColors[ImGuiCol_TabHovered] = FLinearColor(0.38f, 0.38f, 0.38f, 1.00f); 46 | ImguiColors[ImGuiCol_TabActive] = FLinearColor(0.47f, 0.47f, 0.47f, 1.00f); 47 | ImguiColors[ImGuiCol_TabUnfocused] = FLinearColor(0.07f, 0.10f, 0.15f, 0.97f); 48 | ImguiColors[ImGuiCol_TabUnfocusedActive] = FLinearColor(0.14f, 0.26f, 0.42f, 1.00f); 49 | ImguiColors[ImGuiCol_PlotLines] = FLinearColor(0.61f, 0.61f, 0.61f, 1.00f); 50 | ImguiColors[ImGuiCol_PlotLinesHovered] = FLinearColor(1.00f, 0.43f, 0.35f, 1.00f); 51 | ImguiColors[ImGuiCol_PlotHistogram] = FLinearColor(0.90f, 0.70f, 0.00f, 1.00f); 52 | ImguiColors[ImGuiCol_PlotHistogramHovered] = FLinearColor(1.00f, 0.60f, 0.00f, 1.00f); 53 | ImguiColors[ImGuiCol_TextSelectedBg] = FLinearColor(0.26f, 0.59f, 0.98f, 0.35f); 54 | ImguiColors[ImGuiCol_DragDropTarget] = FLinearColor(1.00f, 1.00f, 0.00f, 0.90f); 55 | ImguiColors[ImGuiCol_NavHighlight] = FLinearColor(0.26f, 0.59f, 0.98f, 1.00f); 56 | ImguiColors[ImGuiCol_NavWindowingHighlight] = FLinearColor(1.00f, 1.00f, 1.00f, 0.70f); 57 | ImguiColors[ImGuiCol_NavWindowingDimBg] = FLinearColor(0.80f, 0.80f, 0.80f, 0.20f); 58 | ImguiColors[ImGuiCol_ModalWindowDimBg] = FLinearColor(0.80f, 0.80f, 0.80f, 0.35f); 59 | ImguiColors[ImGuiCol_DockingPreview] = FLinearColor(1.00f, 1.00f, 1.00f, 0.50f); 60 | ImguiColors[ImGuiCol_TabUnfocused] = FLinearColor(0.50f, 0.50f, 0.50f, 1.00f); 61 | ImguiColors[ImGuiCol_TabUnfocusedActive] = FLinearColor(0.15f, 0.15f, 0.15f, 1.00f); 62 | 63 | // set up imgui style 64 | ImguiStyle.Alpha = 1.0f; // Global alpha applies to everything in ImGui 65 | ImguiStyle.WindowPadding = FVector2D(8,8); // Padding within a window 66 | ImguiStyle.WindowRounding = 0.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. 67 | ImguiStyle.WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested. 68 | ImguiStyle.WindowMinSize = FVector2D(32,32); // Minimum window size 69 | ImguiStyle.WindowTitleAlign = FVector2D(0.0f,0.5f); // Alignment for title bar text 70 | ImguiStyle.WindowMenuButtonPosition= ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left. 71 | ImguiStyle.ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows 72 | ImguiStyle.ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested. 73 | ImguiStyle.PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows 74 | ImguiStyle.PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested. 75 | ImguiStyle.FramePadding = FVector2D(4,3); // Padding within a framed rectangle (used by most widgets) 76 | ImguiStyle.FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). 77 | ImguiStyle.FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested. 78 | ImguiStyle.ItemSpacing = FVector2D(8,4); // Horizontal and vertical spacing between widgets/lines 79 | ImguiStyle.ItemInnerSpacing = FVector2D(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) 80 | ImguiStyle.CellPadding = FVector2D(4,2); // Padding within a table cell 81 | ImguiStyle.TouchExtraPadding = FVector2D(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! 82 | ImguiStyle.IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). 83 | ImguiStyle.ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). 84 | ImguiStyle.ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar 85 | ImguiStyle.ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar 86 | ImguiStyle.GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar 87 | ImguiStyle.GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. 88 | ImguiStyle.LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. 89 | ImguiStyle.TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. 90 | ImguiStyle.TabBorderSize = 0.0f; // Thickness of border around tabs. 91 | ImguiStyle.TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appears on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. 92 | ImguiStyle.ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. 93 | ImguiStyle.ButtonTextAlign = FVector2D(0.5f,0.5f); // Alignment of button text when button is larger than text. 94 | ImguiStyle.SelectableTextAlign = FVector2D(0.0f,0.0f); // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. 95 | ImguiStyle.DisplayWindowPadding = FVector2D(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. 96 | ImguiStyle.DisplaySafeAreaPadding = FVector2D(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. 97 | ImguiStyle.MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. 98 | ImguiStyle.AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. 99 | ImguiStyle.AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering. 100 | ImguiStyle.AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.). 101 | ImguiStyle.CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. 102 | ImguiStyle.CircleSegmentMaxError = 1.60f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. 103 | 104 | } 105 | 106 | void UImguiConfig::SetStyle(ImGuiStyle* InStyle) 107 | { 108 | FMemory::Memcpy(UImguiConfig::Get()->ImguiColors.GetData(), InStyle->Colors, ImGuiCol_COUNT * sizeof(ImVec4)); 109 | FMemory::Memcpy(&UImguiConfig::Get()->ImguiStyle, InStyle,sizeof(FImguiStyle)); 110 | } 111 | --------------------------------------------------------------------------------