From 597db17f9c6aa9a9193052236632c7a181d59bc8 Mon Sep 17 00:00:00 2001 From: Arnaud Jamin Date: Sat, 1 Feb 2025 02:40:56 -0500 Subject: [PATCH] CogEngine: Console improvements --- .../Private/CogEngineWindow_Console.cpp | 404 ++++++++++-------- .../Private/CogEngineWindow_Selection.cpp | 3 +- .../Private/CogEngineWindow_Stats.cpp | 3 +- .../Public/CogEngineWindow_Console.h | 42 +- .../Cog/Source/CogWindow/Public/CogWindow.h | 4 +- 5 files changed, 260 insertions(+), 196 deletions(-) diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Console.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Console.cpp index 6a34a55..fa251d2 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Console.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Console.cpp @@ -1,11 +1,8 @@ #include "CogEngineWindow_Console.h" -#include - #include "CogImguiHelper.h" #include "CogWindowManager.h" #include "CogWindowWidgets.h" -#include "GameFramework/PlayerController.h" #include "imgui.h" #include "imgui_internal.h" @@ -24,7 +21,8 @@ void FCogEngineWindow_Console::Initialize() bNoPadding = true; bHasMenu = true; - bHasWidget = 1; + bHasWidget = true; + bIsWidgetVisible = true; SelectedCommandIndex = -1; RefreshCommandList(); @@ -43,91 +41,148 @@ void FCogEngineWindow_Console::RenderContent() if (ImGui::BeginMenuBar()) { - if (ImGui::BeginMenu("Options")) - { - if (ImGui::Checkbox("Sort Commands", &Config->SortCommands)) - { - RefreshCommandList(); - } - - if (ImGui::Checkbox("Show Console Input In Menu Bar", &Config->ShowConsoleInputInMenuBar)) - { - RefreshCommandList(); - } - - if (ImGui::Checkbox("Use Clipper", &Config->UseClipper)) - { - RefreshCommandList(); - } - - FCogWindowWidgets::SetNextItemToShortWidth(); - if (ImGui::SliderInt("Num History Commands", &Config->NumHistoryCommands, 0, 100)) - { - RefreshCommandList(); - } - - FCogWindowWidgets::SetNextItemToShortWidth(); - if (ImGui::SliderInt("Completion Minimum Characters", &Config->CompletionMinimumCharacters, 0, 3)) - { - RefreshCommandList(); - } - - ImGui::ColorEdit4("History Color", (float*)&Config->HistoryColor, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_AlphaPreviewHalf); - - ImGui::EndMenu(); - } - - if (Config->ShowConsoleInputInMenuBar) - { - ImGui::SetNextItemWidth(-1); - RenderConsoleTextInput(); - } - - //ImGui::Text("%d", SelectedCommandIndex); - + RenderMenu(); ImGui::EndMenuBar(); } ImGui::Spacing(); - if (Config->ShowConsoleInputInMenuBar == false) + if (Config->DockInputInMenuBar == false) { ImGui::SetNextItemWidth(-1); - RenderConsoleTextInput(); + RenderInput(); } - const ImVec2 Size = IsWindowRenderedInMainMenu() ? ImVec2(0, ImGui::GetFontSize() * 20) : ImVec2(0.0f, -1.0f); - if (ImGui::BeginChild("Commands", Size, ImGuiChildFlags_NavFlattened)) - { - const float Indent = ImGui::GetFontSize() * 0.5f; - ImGui::Indent(Indent); - - RenderCommandList(); - - ImGui::Unindent(Indent); - } - - ImGui::EndChild(); - - // ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.2f, 0.2f, 0.2f, 0.5f)); - // if (ImGui::BeginChild("Description", ImVec2(0.0f, ImGui::GetContentRegionAvail().y))) - // { - // ImGui::Indent(Indent); - // ImGui::BeginDisabled(); - // - // const FString Help = GetConsoleCommandHelp(CurrentUserInput); - // const auto& HelpStr = StringCast(*Help); - // ImGui::TextWrapped(HelpStr.Get()); - // - // ImGui::EndDisabled(); - // ImGui::Unindent(Indent); - // } - // ImGui::EndChild(); - // ImGui::PopStyleColor(); + RenderCommandList(); } //-------------------------------------------------------------------------------------------------------------------------- -void FCogEngineWindow_Console::RenderConsoleTextInput() +void FCogEngineWindow_Console::RenderMainMenuWidget() +{ + bIsRenderingWidget = true; + + const ImGuiContext& g = *GImGui; + const ImGuiStyle& Style = g.Style; + const ImGuiWindow* Window = ImGui::GetCurrentWindow(); + ImVec2 TooltipPos = Window->DC.CursorPos; + TooltipPos.y += Window->MenuBarHeight; + + ImGui::SetNextItemWidth(Config->WidgetWidth); + RenderInput(); + + if (Config->FocusWidgetWhenAppearing && ImGui::IsWindowAppearing()) + { + SelectedCommandIndex = -1; + RefreshCommandList(); + ImGui::ActivateItemByID(InputIdOnWidgetMode); + } + + const bool IsTextInputActive = ImGui::IsItemActive(); + + if (bPopupCommandListOnWidgetMode) + { + ImGui::SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.90f); + ImGui::SetNextWindowSize(ImVec2(Config->WidgetWidth, ImGui::GetFontSize() * 30), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowPos(TooltipPos, ImGuiCond_Always); + + ImGuiWindowFlags flags = + ImGuiWindowFlags_NoTitleBar + | ImGuiWindowFlags_NoMove + | ImGuiWindowFlags_NoFocusOnAppearing; // We want the console input text to keep the focus. + + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + if (ImGui::Begin("ConsoleTooltip", nullptr, flags)) + { + RenderCommandList(); + + if (ImGui::BeginPopupContextWindow()) + { + RenderMenu(); + ImGui::EndPopup(); + } + + const bool IsWindowFocused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); + + if (IsTextInputActive == false && IsWindowFocused == false && bRequestInputFocus == false) + { + bPopupCommandListOnWidgetMode = false; + } + } + ImGui::End(); + ImGui::PopStyleVar(); + } + + if (ImGui::BeginPopupContextWindow()) + { + RenderMenu(); + ImGui::EndPopup(); + } + + bIsRenderingWidget = false; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Console::RenderMenu() +{ + if (ImGui::BeginMenu("Options")) + { + FCogWindowWidgets::ThinSeparatorText("General"); + + if (ImGui::Checkbox("Sort Commands", &Config->SortCommands)) + { + RefreshCommandList(); + } + + // if (ImGui::Checkbox("Use Clipper", &Config->UseClipper)) + // { + // RefreshCommandList(); + // } + + FCogWindowWidgets::SetNextItemToShortWidth(); + if (ImGui::SliderInt("Completion Minimum Characters", &Config->CompletionMinimumCharacters, 0, 3)) + { + RefreshCommandList(); + } + + FCogWindowWidgets::SetNextItemToShortWidth(); + if (ImGui::SliderInt("Num History Commands", &Config->NumHistoryCommands, 0, 100)) + { + RefreshCommandList(); + } + + ImGui::ColorEdit4("History Color", (float*)&Config->HistoryColor, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_AlphaPreviewHalf); + + FCogWindowWidgets::ThinSeparatorText("Window"); + + if (ImGui::Checkbox("Dock Input in Menu Bar", &Config->DockInputInMenuBar)) + { + RefreshCommandList(); + } + + FCogWindowWidgets::ThinSeparatorText("Widget"); + + if (ImGui::Checkbox("Focus Console Widget When Appearing", &Config->FocusWidgetWhenAppearing)) + { + RefreshCommandList(); + } + + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::SliderInt("Widget Width", &Config->WidgetWidth, 0, 1000); + + ImGui::EndMenu(); + } + + if (bIsRenderingWidget == false && Config->DockInputInMenuBar) + { + ImGui::SetNextItemWidth(-1); + RenderInput(); + } + + //ImGui::Text("%d", SelectedCommandIndex); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Console::RenderInput() { constexpr ImGuiInputTextFlags InputFlags = ImGuiInputTextFlags_EnterReturnsTrue @@ -140,9 +195,14 @@ void FCogEngineWindow_Console::RenderConsoleTextInput() if (FCogWindowWidgets::InputTextWithHint("##Command", "Command", CurrentUserInput, InputFlags, &OnTextInputCallbackStub, this)) { ExecuteCommand(CurrentUserInput); - bRequestTextInputFocus = true; + bRequestInputFocus = true; } + if (bIsRenderingWidget) + { + InputIdOnWidgetMode = ImGui::GetItemID(); + } + ImGui::SetItemDefaultFocus(); //------------------------------------------------------------------------------------------------- @@ -156,18 +216,14 @@ void FCogEngineWindow_Console::RenderConsoleTextInput() bPopupCommandListOnWidgetMode = true; } - if (ImGui::IsItemActive() == false - && bRequestTextInputFocus - /*&& ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)*/ - /*&& IsWindowRenderedInMainMenu() == false*/) + if (ImGui::IsItemActive() == false && bRequestInputFocus) { ImGui::SetKeyboardFocusHere(-1); - //bRequestTextInputFocus = false; } if (ImGui::IsItemActive()) { - bRequestTextInputFocus = false; + bRequestInputFocus = false; } } @@ -248,56 +304,99 @@ int FCogEngineWindow_Console::OnTextInputCallbackStub(ImGuiInputTextCallbackData return ConsoleWindow.OnTextInputCallback(InData); } +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Console::RenderCommandHelp() +{ + +} + //-------------------------------------------------------------------------------------------------------------------------- void FCogEngineWindow_Console::RenderCommandList() { - int32 Index = 0; + const float HelpHeight = ImGui::GetFontSize() * 5; + const float Indent = ImGui::GetFontSize() * 0.5f; - ImGuiListClipper Clipper; - Clipper.Begin(CommandList.Num()); - while (Clipper.Step()) + const ImVec2 Size = IsWindowRenderedInMainMenu() ? ImVec2(0, ImGui::GetFontSize() * 20) : ImVec2(0.0f, -HelpHeight); + if (ImGui::BeginChild("Commands", Size, ImGuiChildFlags_NavFlattened | ImGuiChildFlags_ResizeY)) { - const int32 Start = Config->UseClipper ? Clipper.DisplayStart : 0; - const int32 End = Config->UseClipper ? Clipper.DisplayEnd : CommandList.Num(); + ImGui::Indent(Indent); + + int32 Index = 0; + + ImGuiListClipper Clipper; + Clipper.Begin(CommandList.Num()); + while (Clipper.Step()) + { + const int32 Start = Config->UseClipper ? Clipper.DisplayStart : 0; + const int32 End = Config->UseClipper ? Clipper.DisplayEnd : CommandList.Num(); - for (Index = Start; Index < End; Index++) - { - if (CommandList.IsValidIndex(Index)) + for (Index = Start; Index < End; Index++) { - ImGui::PushID(Index); - const FString& CommandName = CommandList[Index]; - RenderCommand(CommandName, Index); - ImGui::PopID(); + if (CommandList.IsValidIndex(Index)) + { + ImGui::PushID(Index); + const FString& CommandName = CommandList[Index]; + RenderCommand(CommandName, Index); + ImGui::PopID(); + } } - } - if (Config->UseClipper == false) + if (Config->UseClipper == false) + { break; } + } + Clipper.End(); + + // If any is available, draw an additional command below the clipper to be able to scroll when pressing bottom + if (CommandList.IsValidIndex(Index + 1)) { - break; + const FString& Command = CommandList[Index + 1]; + RenderCommand(Command, Index); } - } - Clipper.End(); - // If any is available, draw an additional command below the clipper to be able to scroll when pressing bottom - if (CommandList.IsValidIndex(Index + 1)) - { - const FString& Command = CommandList[Index + 1]; - RenderCommand(Command, Index); + ImGui::Unindent(Indent); } + ImGui::EndChild(); + + //-------------------------------------------------------------------- + // Render Help + //-------------------------------------------------------------------- + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.2f, 0.2f, 0.2f, 0.5f)); + if (ImGui::BeginChild("Help", ImVec2(0.0f, ImGui::GetContentRegionAvail().y))) + { + ImGui::Spacing(); + ImGui::BeginDisabled(); + ImGui::Indent(Indent); + + if (CommandList.IsValidIndex(SelectedCommandIndex)) + { + const FString SelectedCommand = CommandList[SelectedCommandIndex]; + const FString Help = GetConsoleCommandHelp(SelectedCommand); + const auto& HelpStr = StringCast(*Help); + ImGui::TextWrapped(HelpStr.Get()); + } + + ImGui::Unindent(Indent); + ImGui::EndDisabled(); + } + ImGui::EndChild(); + ImGui::PopStyleColor(); } //-------------------------------------------------------------------------------------------------------------------------- FString FCogEngineWindow_Console::GetConsoleCommandHelp(const FString& InCommandName) { - TArray CommandSplitWithSpaces; - InCommandName.ParseIntoArrayWS(CommandSplitWithSpaces); - - if (CommandSplitWithSpaces.Num() > 0) + if (InCommandName.IsEmpty() == false) { - if (const IConsoleObject* ConsoleObject = IConsoleManager::Get().FindConsoleObject(*CommandSplitWithSpaces[0])) + TArray CommandSplitWithSpaces; + InCommandName.ParseIntoArrayWS(CommandSplitWithSpaces); + + if (CommandSplitWithSpaces.Num() > 0) { - return FString(ConsoleObject->GetHelp()); + if (const IConsoleObject* ConsoleObject = IConsoleManager::Get().FindConsoleObject(*CommandSplitWithSpaces[0])) + { + return FString(ConsoleObject->GetHelp()); + } } } @@ -326,7 +425,7 @@ void FCogEngineWindow_Console::RenderCommand(const FString& CommandName, const i if (ImGui::Selectable(CommandNameStr.Get(), &IsSelected, Flags)) { SelectedCommandIndex = Index; - bRequestTextInputFocus = true; + bRequestInputFocus = true; bSetBufferToSelectedCommand = true; if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) @@ -334,6 +433,17 @@ void FCogEngineWindow_Console::RenderCommand(const FString& CommandName, const i ExecuteCommand(CommandName); } } + + if (ImGui::BeginItemTooltip()) + { + const FString Help = GetConsoleCommandHelp(CommandName); + const auto& HelpStr = StringCast(*Help); + + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(HelpStr.Get()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } if (Index < NumHistoryCommands) { @@ -353,17 +463,6 @@ void FCogEngineWindow_Console::RenderCommand(const FString& CommandName, const i bScroll = false; } } - - if (ImGui::BeginItemTooltip()) - { - const FString Help = GetConsoleCommandHelp(CommandName); - const auto& HelpStr = StringCast(*Help); - - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextUnformatted(HelpStr.Get()); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); - } } //-------------------------------------------------------------------------------------------------------------------------- @@ -437,11 +536,7 @@ void FCogEngineWindow_Console::ExecuteCommand(const FString& InCommand) FString CleanupCommand = InCommand.TrimEnd(); if (CleanupCommand.IsEmpty() == false) { - //if (VisibleHistory.Num() == 0 || (VisibleHistory.Last() != CleanupCommand)) - { - IConsoleManager::Get().AddConsoleHistoryEntry(TEXT(""), *CleanupCommand); - } - + IConsoleManager::Get().AddConsoleHistoryEntry(TEXT(""), *CleanupCommand); GEngine->DeferredCommands.Add(CleanupCommand); } @@ -454,53 +549,4 @@ void FCogEngineWindow_Console::ExecuteCommand(const FString& InCommand) RefreshCommandList(); } -//-------------------------------------------------------------------------------------------------------------------------- -void FCogEngineWindow_Console::RenderMainMenuWidget() -{ - bIsRenderingWidget = true; - - const ImGuiContext& g = *GImGui; - const ImGuiStyle& Style = g.Style; - const ImGuiWindow* Window = ImGui::GetCurrentWindow(); - ImVec2 TooltipPos = Window->DC.CursorPos; - TooltipPos.y += Window->MenuBarHeight; - ImGui::SetNextItemWidth(-1); - RenderConsoleTextInput(); - const float Width = ImGui::GetItemRectSize().x; - - if (ImGui::IsWindowAppearing()) - { - bRequestTextInputFocus = true; - } - - const bool IsTextInputActive = ImGui::IsItemActive(); - - if (bPopupCommandListOnWidgetMode) - { - ImGui::SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.90f); - ImGui::SetNextWindowSize(ImVec2(Width, ImGui::GetFontSize() * 30), ImGuiCond_FirstUseEver); - ImGui::SetNextWindowPos(TooltipPos, ImGuiCond_Always); - - ImGuiWindowFlags flags = - ImGuiWindowFlags_NoTitleBar - | ImGuiWindowFlags_NoMove - | ImGuiWindowFlags_NoFocusOnAppearing; // We want the console input text to keep the focus. - - if (ImGui::Begin("ConsoleTooltip", nullptr, flags)) - { - RenderCommandList(); - - const bool IsWindowFocused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy); - - if (IsTextInputActive == false && IsWindowFocused == false && bRequestTextInputFocus == false) - { - bPopupCommandListOnWidgetMode = false; - } - } - ImGui::End(); - } - - bIsRenderingWidget = false; -} - diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp index dfde5c4..bbfa680 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp @@ -26,7 +26,8 @@ void FCogEngineWindow_Selection::Initialize() Super::Initialize(); bHasMenu = true; - bHasWidget = 2; + bHasWidget = true; + bIsWidgetVisible = true; ActorClasses = { AActor::StaticClass(), ACharacter::StaticClass() }; Config = GetConfig(); diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Stats.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Stats.cpp index f4fe046..e913edc 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Stats.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Stats.cpp @@ -17,7 +17,8 @@ void FCogEngineWindow_Stats::Initialize() { Super::Initialize(); - bHasWidget = 2; + bHasWidget = true; + bIsWidgetVisible = true; } //-------------------------------------------------------------------------------------------------------------------------- diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Console.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Console.h index 2aa416d..0748bca 100644 --- a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Console.h +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Console.h @@ -18,7 +18,6 @@ protected: virtual void RenderHelp() override; virtual void Initialize() override; - void RenderCommandList(); virtual void RenderMainMenuWidget() override; @@ -26,18 +25,25 @@ protected: private: - static int OnTextInputCallbackStub(ImGuiInputTextCallbackData* InData); static FString GetConsoleCommandHelp(const FString& InCommandName); - void RenderConsoleTextInput(); + void RenderMenu(); - void RenderCommand(const FString& CommandName, int32 Index); - - void RefreshCommandList(); + void RenderInput(); int OnTextInputCallback(ImGuiInputTextCallbackData* InData); + static int OnTextInputCallbackStub(ImGuiInputTextCallbackData* InData); + + void RenderCommandList(); + + void RenderCommand(const FString& CommandName, int32 Index); + + void RefreshCommandList(); + + void RenderCommandHelp(); + void ExecuteCommand(const FString& InCommand); int32 SelectedCommandIndex = -1; @@ -50,12 +56,14 @@ private: bool bScroll = false; - bool bRequestTextInputFocus = false; + bool bRequestInputFocus = false; bool bIsWindowFocused = false; bool bPopupCommandListOnWidgetMode = false; - + + ImGuiID InputIdOnWidgetMode = 0; + bool bIsRenderingWidget = false; bool bSetBufferToSelectedCommand = false; @@ -75,8 +83,14 @@ public: bool SortCommands = false; UPROPERTY(Config) - bool ShowConsoleInputInMenuBar = false; + bool DockInputInMenuBar = false; + UPROPERTY(Config) + bool FocusWidgetWhenAppearing = true; + + UPROPERTY(Config) + int32 WidgetWidth = 200; + UPROPERTY(Config) bool UseClipper = false; @@ -84,11 +98,11 @@ public: int32 NumHistoryCommands = 10; UPROPERTY(Config) - int32 CompletionMinimumCharacters = 0; - + int32 CompletionMinimumCharacters = 1; UPROPERTY(Config) FVector4f HistoryColor = FVector4f(1.0f, 1.0f, 1.0f, 0.5f); + UCogEngineConfig_Console() { @@ -100,9 +114,11 @@ public: Super::Reset(); SortCommands = false; + DockInputInMenuBar = false; + FocusWidgetWhenAppearing = true; + UseClipper = false; NumHistoryCommands = 10; - CompletionMinimumCharacters = 0; - ShowConsoleInputInMenuBar = false; + CompletionMinimumCharacters = 1; HistoryColor = FVector4f(1.0f, 1.0f, 1.0f, 0.5f); } }; \ No newline at end of file diff --git a/Plugins/Cog/Source/CogWindow/Public/CogWindow.h b/Plugins/Cog/Source/CogWindow/Public/CogWindow.h index d22f185..46e8d29 100644 --- a/Plugins/Cog/Source/CogWindow/Public/CogWindow.h +++ b/Plugins/Cog/Source/CogWindow/Public/CogWindow.h @@ -58,7 +58,7 @@ public: void SetIsVisible(bool Value); - int32 HasWidget() const { return bHasWidget; } + bool HasWidget() const { return bHasWidget; } bool GetIsWidgetVisible() const { return bIsWidgetVisible; } @@ -122,7 +122,7 @@ protected: bool bIsVisible = false; - int32 bHasWidget = 0; + bool bHasWidget = false; bool bIsWidgetVisible = false;