Rework how replicators are spawned to simplify Cog integration

- Replicators are now automatically spawned
- Rework input management.
- Add input shortcuts in the TimeScale window to change the time scale.
This commit is contained in:
Arnaud Jamin
2025-03-19 12:59:37 -04:00
parent 3c2428ca8f
commit 810c51ac13
31 changed files with 880 additions and 436 deletions
Binary file not shown.
+167 -51
View File
@@ -8,6 +8,7 @@
#include "CogWindow_Settings.h"
#include "CogWindow_Spacing.h"
#include "CogConsoleCommandManager.h"
#include "CogDebugPluginSubsystem.h"
#include "CogHelper.h"
#include "CogWidgets.h"
#include "Engine/Engine.h"
@@ -44,12 +45,12 @@ void UCogSubsystem::Activate()
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::TryInitialize(UWorld* World)
void UCogSubsystem::TryInitialize(UWorld& World)
{
if (IsInitialized)
{ return; }
FWorldContext* WorldContext = GEngine->GetWorldContextFromWorld(World);
FWorldContext* WorldContext = GEngine->GetWorldContextFromWorld(&World);
if (WorldContext == nullptr)
{ return; }
@@ -77,7 +78,19 @@ void UCogSubsystem::TryInitialize(UWorld* World)
SpaceWindows.Add(AddWindow<FCogWindow_Spacing>("Spacing 4"));
Settings = GetConfig<UCogWindowConfig_Settings>();
OnShortcutsDefined();
UCogWindowConfig_Settings* SettingsPtr = Settings.Get();
AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_ToggleImguiInput).BindLambda([this] () { ToggleInputMode(); });
AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_ToggleSelection).BindLambda([this] (){ SetActivateSelectionMode(!GetActivateSelectionMode()); });
AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_LoadLayout1).BindLambda([this] (){ LoadLayout(1); });
AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_LoadLayout2).BindLambda([this] (){ LoadLayout(2); });
AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_LoadLayout3).BindLambda([this] (){ LoadLayout(3); });
AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_LoadLayout4).BindLambda([this] (){ LoadLayout(4); });
AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_SaveLayout1).BindLambda([this] (){ SaveLayout(1); });
AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_SaveLayout2).BindLambda([this] (){ SaveLayout(2); });
AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_SaveLayout3).BindLambda([this] (){ SaveLayout(3); });
AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_SaveLayout4).BindLambda([this] (){ SaveLayout(4); });
AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_ResetLayout).BindLambda([this] (){ ResetLayout(); });
LayoutsWindow = AddWindow<FCogWindow_Layouts>("Window.Layouts");
SettingsWindow = AddWindow<FCogWindow_Settings>("Window.Settings");
@@ -86,7 +99,7 @@ void UCogSubsystem::TryInitialize(UWorld* World)
{
InitializeWindow(Window);
}
FCogConsoleCommandManager::RegisterWorldConsoleCommand(
*ToggleInputCommand,
TEXT("Toggle the input focus between the Game and ImGui"),
@@ -217,7 +230,7 @@ void UCogSubsystem::Tick(UWorld* InTickedWorld, ELevelTick InTickType, float InD
//----------------------------------------------------------------------------------------------
if (World != CurrentWorld.Get())
{
NumExecBindingsChecked = INDEX_NONE;
RequestDisableCommandsConflictingWithShortcuts();
}
CurrentWorld = World;
@@ -226,30 +239,21 @@ void UCogSubsystem::Tick(UWorld* InTickedWorld, ELevelTick InTickType, float InD
if (IsInitialized == false)
{
TryInitialize(World);
TryInitialize(*World);
return;
}
FCogImGuiContextScope ImGuiContextScope(Context);
UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*World);
if (PlayerInput != nullptr)
UpdateServerPlayerControllers(*World);
if (UPlayerInput* PlayerInput = (LocalPlayerController != nullptr) ? LocalPlayerController->PlayerInput : nullptr)
{
HandleInputs(*PlayerInput);
//------------------------------------------------------------------
// We must wait for the player input to be valid to disable
// DebugExecBindings conflicting with our shortcuts.
//------------------------------------------------------------------
const int32 NewNumExecBindings = PlayerInput->DebugExecBindings.Num();
if (NumExecBindingsChecked != NewNumExecBindings)
{
if (Settings->bDisableConflictingCommands)
{
FCogImguiInputHelper::DisableCommandsConflictingWithShortcuts(*PlayerInput);
}
NumExecBindingsChecked = NewNumExecBindings;;
}
TryDisableCommandsConflictingWithShortcuts(PlayerInput);
}
if (LayoutToLoad != -1)
@@ -274,6 +278,77 @@ void UCogSubsystem::Tick(UWorld* InTickedWorld, ELevelTick InTickType, float InD
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::RequestDisableCommandsConflictingWithShortcuts()
{
NumExecBindingsChecked = INDEX_NONE;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::SetLocalPlayerController(APlayerController* PlayerController)
{
if (LocalPlayerController == PlayerController)
{ return; }
LocalPlayerController = PlayerController;
if (LocalPlayerController == nullptr)
{ return; }
UInputComponent* InputComponentPtr = NewObject<UInputComponent>(PlayerController, TEXT("Cog_Input"));
InputComponent = InputComponentPtr;
if (InputComponentPtr)
{
PlayerController->PushInputComponent(InputComponentPtr);
}
for (FCogShortcut& Shortcut : Shortcuts)
{
BindShortcut(Shortcut);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::UpdateServerPlayerControllers(UWorld& World)
{
TArray<UCogDebugPluginSubsystem*> PluginSubsystems;
ServerPlayerControllers.RemoveAll([] (TWeakObjectPtr<APlayerController> PlayerController)
{
return PlayerController.IsValid() == false;
});
for (FConstPlayerControllerIterator It = World.GetPlayerControllerIterator(); It; ++It)
{
APlayerController* PlayerController = It->Get();
if (PlayerController == nullptr)
{ continue; }
if (PlayerController->IsLocalController())
{
SetLocalPlayerController(PlayerController);
}
if (World.GetNetMode() != NM_Client)
{
if (ServerPlayerControllers.Contains(PlayerController))
{ continue; }
ServerPlayerControllers.Add(PlayerController);
if (PluginSubsystems.IsEmpty())
{
PluginSubsystems = GetOuterUGameInstance()->GetSubsystemArrayCopy<UCogDebugPluginSubsystem>();
}
for (UCogDebugPluginSubsystem* PluginSubsystem : PluginSubsystems)
{
PluginSubsystem->OnPlayerControllerReady(PlayerController);
}
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::Render(float DeltaTime)
{
@@ -938,30 +1013,6 @@ void UCogSubsystem::DisableInputMode()
Context.SetEnableInput(false);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::HandleInputs(const UPlayerInput& PlayerInput)
{
if (Settings->bDisableShortcutsWhenImGuiWantTextInput && ImGui::GetIO().WantTextInput)
{ return; }
if (FCogImguiInputHelper::IsKeyInfoPressed(PlayerInput, Settings->ToggleImGuiInputShortcut))
{
ToggleInputMode();
}
else if (FCogImguiInputHelper::IsKeyInfoPressed(PlayerInput, Settings->ToggleSelectionShortcut))
{
SetActivateSelectionMode(!GetActivateSelectionMode());
}
for (int i = 0; i < Settings->LoadLayoutShortcuts.Num(); ++i)
{
if (FCogImguiInputHelper::IsKeyInfoPressed(PlayerInput, Settings->LoadLayoutShortcuts[i]))
{
LoadLayout(i + 1);
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::SetActivateSelectionMode(const bool Value)
{
@@ -987,14 +1038,79 @@ bool UCogSubsystem::GetActivateSelectionMode() const
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::OnShortcutsDefined()
FInputActionHandlerSignature& UCogSubsystem::AddShortcut(const UObject& InInstance, const FProperty& InProperty)
{
TArray Shortcuts = { Settings->ToggleImGuiInputShortcut, Settings->ToggleSelectionShortcut };
Shortcuts.Append(Settings->LoadLayoutShortcuts);
Shortcuts.Append(Settings->SaveLayoutShortcuts);
FCogImguiInputHelper::SetShortcuts(Shortcuts);
NumExecBindingsChecked = INDEX_NONE;
FCogShortcut& Shortcut = Shortcuts.AddDefaulted_GetRef();
Shortcut.PropertyName = InProperty.GetFName();
Shortcut.Config = &InInstance;
return Shortcut.Delegate;
}
//--------------------------------------------------------------------------------------------------------------------------
bool UCogSubsystem::BindShortcut(FCogShortcut& InShortcut) const
{
UObject* Config = const_cast<UObject*>(InShortcut.Config.Get());
if (Config == nullptr)
{ return false; }
const FStructProperty* StructProperty = CastField<FStructProperty>(Config->GetClass()->FindPropertyByName(InShortcut.PropertyName));
if (StructProperty == nullptr)
{ return false; }
const FInputChord* InputChord = static_cast<FInputChord*>(StructProperty->ContainerPtrToValuePtr<void>(Config));
if (InputChord == nullptr)
{ return false; }
FInputKeyBinding InputBinding(*InputChord, IE_Pressed);
InputBinding.KeyDelegate.GetDelegateForManualSet() = InShortcut.Delegate;
InputComponent.Get()->KeyBindings.Add(InputBinding);
InShortcut.InputChord = *InputChord;
FCogImguiInputHelper::GetPrioritizedShortcuts().Add(*InputChord);
return true;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::RebindShortcut(const UCogCommonConfig& InConfig, const FProperty& InProperty)
{
// Ideally would unbind and rebind only the provided shortcut, but we currently rebind all shortcuts.
UInputComponent* InputComponentPtr = InputComponent.Get();
if (InputComponentPtr == nullptr)
{ return; }
for (auto& KeyBinding : InputComponentPtr->KeyBindings)
{
KeyBinding.KeyDelegate.Unbind();
}
InputComponent.Get()->KeyBindings.Empty();
for (FCogShortcut& Shortcut : Shortcuts)
{
BindShortcut(Shortcut);
}
RequestDisableCommandsConflictingWithShortcuts();
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::TryDisableCommandsConflictingWithShortcuts(UPlayerInput* PlayerInput)
{
const int32 NewNumExecBindings = PlayerInput->DebugExecBindings.Num();
if (NumExecBindingsChecked == NewNumExecBindings)
{ return; }
NumExecBindingsChecked = NewNumExecBindings;;
if (Settings->bDisableConflictingCommands == false)
{ return; }
TArray<FInputChord>& PrioritizedShortcuts = FCogImguiInputHelper::GetPrioritizedShortcuts();
for (const FCogShortcut& Shortcut : Shortcuts)
{
PrioritizedShortcuts.Add(Shortcut.InputChord);
}
FCogImguiInputHelper::DisableCommandsConflictingWithShortcuts(*PlayerInput);
}
+137 -38
View File
@@ -515,18 +515,18 @@ bool FCogWidgets::CheckBoxState(const char* Label, ECheckBoxState& State, bool S
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogWidgets::InputKey(const char* Label, FCogImGuiKeyInfo& KeyInfo)
bool FCogWidgets::InputChord(const char* Label, FInputChord& InInputChord)
{
ImGui::PushID(Label);
ImGui::AlignTextToFramePadding();
ImGui::BeginDisabled();
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 10);
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
ImGui::InputText("##Shortcut", const_cast<char*>(Label), IM_ARRAYSIZE(Label));
ImGui::EndDisabled();
ImGui::SameLine();
const bool HasChanged = InputKey(KeyInfo);
const bool HasChanged = InputChord(InInputChord);
ImGui::PopID();
@@ -534,18 +534,50 @@ bool FCogWidgets::InputKey(const char* Label, FCogImGuiKeyInfo& KeyInfo)
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogWidgets::InputKey(FCogImGuiKeyInfo& KeyInfo)
bool FCogWidgets::InputChord(FInputChord& InInputChord)
{
bool HasKeyChanged = false;
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 6);
if (ImGui::BeginCombo("##Key", TCHAR_TO_ANSI(*KeyInfo.Key.ToString()), ImGuiComboFlags_HeightLarge))
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
HasKeyChanged |= Key(InInputChord.Key);
bool Value = false;
ImGui::SameLine();
Value = static_cast<bool>(InInputChord.bCtrl);
HasKeyChanged |= ImGui::Selectable("Ctrl", &Value, ImGuiSelectableFlags_None, ImVec2(ImGui::GetFontSize() * 2, 0));
InInputChord.bCtrl = Value;
ImGui::SameLine();
Value = static_cast<bool>(InInputChord.bShift);
HasKeyChanged |= ImGui::Selectable("Shift", &Value, ImGuiSelectableFlags_None, ImVec2(ImGui::GetFontSize() * 3, 0));
InInputChord.bShift = Value;
ImGui::SameLine();
Value = static_cast<bool>(InInputChord.bAlt);
HasKeyChanged |= ImGui::Selectable("Alt", &Value, ImGuiSelectableFlags_None, ImVec2(ImGui::GetFontSize() * 2, 0));
InInputChord.bAlt = Value;
ImGui::SameLine();
Value = static_cast<bool>(InInputChord.bCmd);
HasKeyChanged |= ImGui::Selectable("Cmd", &Value, ImGuiSelectableFlags_None, ImVec2(ImGui::GetFontSize() * 2, 0));
InInputChord.bCmd = Value;
return HasKeyChanged;
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogWidgets::Key(FKey& InKey)
{
bool HasKeyChanged = false;
if (ImGui::BeginCombo("##Key", TCHAR_TO_ANSI(*InKey.ToString()), ImGuiComboFlags_HeightLarge))
{
{
bool IsSelected = KeyInfo.Key == FKey();
bool IsSelected = InKey == FKey();
if (ImGui::Selectable("None", IsSelected))
{
KeyInfo.Key = FKey();
InKey = FKey();
HasKeyChanged = true;
}
}
@@ -566,45 +598,33 @@ bool FCogWidgets::InputKey(FCogImGuiKeyInfo& KeyInfo)
continue;
}
bool IsSelected = KeyInfo.Key == Key;
bool IsSelected = InKey == Key;
if (ImGui::Selectable(TCHAR_TO_ANSI(*Key.ToString()), IsSelected))
{
KeyInfo.Key = Key;
InKey = Key;
HasKeyChanged = true;
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
HasKeyChanged |= CheckBoxState("Ctrl", KeyInfo.Ctrl);
ImGui::SameLine();
HasKeyChanged |= CheckBoxState("Shift", KeyInfo.Shift);
ImGui::SameLine();
HasKeyChanged |= CheckBoxState("Alt", KeyInfo.Alt);
ImGui::SameLine();
HasKeyChanged |= CheckBoxState("Cmd", KeyInfo.Cmd);
return HasKeyChanged;
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogWidgets::KeyBind(FKeyBind& KeyBind)
bool FCogWidgets::KeyBind(FKeyBind& InKeyBind)
{
static char Buffer[256] = "";
const auto Str = StringCast<ANSICHAR>(*KeyBind.Command);
const auto Str = StringCast<ANSICHAR>(*InKeyBind.Command);
ImStrncpy(Buffer, Str.Get(), IM_ARRAYSIZE(Buffer));
bool Disable = !KeyBind.bDisabled;
bool Disable = !InKeyBind.bDisabled;
if (ImGui::Checkbox("##Disable", &Disable))
{
KeyBind.bDisabled = !Disable;
InKeyBind.bDisabled = !Disable;
}
if (KeyBind.bDisabled)
if (InKeyBind.bDisabled)
{
ImGui::SetItemTooltip("Enable command");
}
@@ -613,7 +633,7 @@ bool FCogWidgets::KeyBind(FKeyBind& KeyBind)
ImGui::SetItemTooltip("Disable command");
}
if (KeyBind.bDisabled)
if (InKeyBind.bDisabled)
{
ImGui::BeginDisabled();
}
@@ -624,21 +644,43 @@ bool FCogWidgets::KeyBind(FKeyBind& KeyBind)
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
if (ImGui::InputText("##Command", Buffer, IM_ARRAYSIZE(Buffer)))
{
KeyBind.Command = FString(Buffer);
InKeyBind.Command = FString(Buffer);
HasChanged = true;
}
FCogImGuiKeyInfo KeyInfo;
FCogImguiInputHelper::KeyBindToKeyInfo(KeyBind, KeyInfo);
ImGui::SameLine();
if (InputKey(KeyInfo))
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 6);
HasChanged |= Key(InKeyBind.Key);
{
HasChanged = true;
FCogImguiInputHelper::KeyInfoToKeyBind(KeyInfo, KeyBind);
ImGui::SameLine();
ECheckBoxState State = FCogImguiInputHelper::MakeCheckBoxState(InKeyBind.Control, InKeyBind.bIgnoreCtrl);
HasChanged |= CheckBoxState("Ctrl", State);
BREAK_CHECKBOX_STATE(State, InKeyBind.Control, InKeyBind.bIgnoreCtrl);
}
if (KeyBind.bDisabled)
{
ImGui::SameLine();
ECheckBoxState State = FCogImguiInputHelper::MakeCheckBoxState(InKeyBind.Shift, InKeyBind.bIgnoreShift);
HasChanged |= CheckBoxState("Shift", State);
BREAK_CHECKBOX_STATE(State, InKeyBind.Shift, InKeyBind.bIgnoreShift);
}
{
ImGui::SameLine();
ECheckBoxState State = FCogImguiInputHelper::MakeCheckBoxState(InKeyBind.Alt, InKeyBind.bIgnoreAlt);
HasChanged |= CheckBoxState("Alt", State);
BREAK_CHECKBOX_STATE(State, InKeyBind.Alt, InKeyBind.bIgnoreAlt);
}
{
ImGui::SameLine();
ECheckBoxState State = FCogImguiInputHelper::MakeCheckBoxState(InKeyBind.Cmd, InKeyBind.bIgnoreCmd);
HasChanged |= CheckBoxState("Cmd", State);
BREAK_CHECKBOX_STATE(State, InKeyBind.Cmd, InKeyBind.bIgnoreCmd);
}
if (InKeyBind.bDisabled)
{
ImGui::EndDisabled();
}
@@ -746,7 +788,7 @@ FString FCogWidgets::FormatSmallFloat(float InValue)
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogWidgets::MultiChoiceButtonsFloat(TArray<float>& InValues, float& InValue, const ImVec2& InSize, bool InInline)
bool FCogWidgets::MultiChoiceButtonsFloat(TArray<float>& InValues, float& InValue, const ImVec2& InSize, bool InInline, float InTolerance)
{
ImGuiStyle& Style = ImGui::GetStyle();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(Style.WindowPadding.x * 0.40f, static_cast<int>(Style.WindowPadding.y * 0.60f)));
@@ -762,7 +804,7 @@ bool FCogWidgets::MultiChoiceButtonsFloat(TArray<float>& InValues, float& InValu
const auto Text = StringCast<ANSICHAR>(*FormatSmallFloat(ButtonValue));
ImGui::PushID(i);
if (MultiChoiceButton(Text.Get(), ButtonValue == InValue, InSize))
if (MultiChoiceButton(Text.Get(), FMath::IsNearlyEqual(ButtonValue, InValue, InTolerance) , InSize))
{
IsPressed = true;
InValue = ButtonValue;
@@ -1444,3 +1486,60 @@ ImVec2 FCogWidgets::ComputeScreenCornerLocation(const ImVec2& InAlignment, const
ImVec2 Position = Viewport->WorkPos + (InAlignment * Viewport->WorkSize) - Offset;
return Position;
}
//--------------------------------------------------------------------------------------------------------------------------
FString FCogWidgets::GetStringAfterCharacter(const FString& InString, const TCHAR InChar)
{
int32 Index = 0;
if (InString.FindChar(InChar, Index))
{
return InString.RightChop(Index + 1);
}
return FString();
}
//--------------------------------------------------------------------------------------------------------------------------
FString FCogWidgets::FormatConfigName(const FString& InConfigName)
{
return FName::NameToDisplayString(GetStringAfterCharacter(InConfigName, '_'), false);
}
//--------------------------------------------------------------------------------------------------------------------------
FString FCogWidgets::FormatShortcutName(const FString& InShortcutName)
{
return FName::NameToDisplayString(InShortcutName.Replace(TEXT("Shortcut_"), TEXT("")), false);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogWidgets::TextInputChordProperty(UObject& InConfig, const FProperty& InInputChordProperty)
{
const FInputChord* InputChord = InInputChordProperty.ContainerPtrToValuePtr<FInputChord>(&InConfig);
if (InputChord == nullptr)
{ return; }
const auto Name = StringCast<ANSICHAR>(*FormatShortcutName(InInputChordProperty.GetName()));
const auto Shortcut = StringCast<ANSICHAR>(*FCogImguiInputHelper::InputChordToString(*InputChord));
ImGui::Text("%s", Name.Get());
ImGui::SameLine();
if (BeginRightAlign(Name.Get()))
{
ImGui::TextDisabled("%s", Shortcut.Get());
EndRightAlign();
}
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogWidgets::InputChordProperty(UObject& InConfig, const FProperty& InInputChordProperty)
{
FInputChord* InputChord = InInputChordProperty.ContainerPtrToValuePtr<FInputChord>(&InConfig);
if (InputChord == nullptr)
{ return false; }
const auto Name = StringCast<ANSICHAR>(*FormatShortcutName(InInputChordProperty.GetName()));
return FCogWidgets::InputChord(Name.Get(), *InputChord);
}
@@ -254,4 +254,3 @@ float FCogWindow::GetDpiScale() const
{
return GetOwner()->GetContext().GetDpiScale();
}
@@ -27,45 +27,40 @@ void FCogWindow_Layouts::RenderContent()
}
ImGui::Separator();
for (int32 i = 0; i < 4; ++i)
{
RenderLoadLayoutMenuItem(PlayerInput, i);
}
UCogWindowConfig_Settings* Settings = GetOwner()->GetSettings();
RenderLoadLayoutMenuItem(1, Settings->Shortcut_LoadLayout1);
RenderLoadLayoutMenuItem(2, Settings->Shortcut_LoadLayout2);
RenderLoadLayoutMenuItem(3, Settings->Shortcut_LoadLayout3);
RenderLoadLayoutMenuItem(4, Settings->Shortcut_LoadLayout4);
ImGui::Separator();
for (int32 i = 0; i < 4; ++i)
{
RenderSaveLayoutMenuItem(PlayerInput, i);
}
RenderSaveLayoutMenuItem(1, Settings->Shortcut_SaveLayout1);
RenderSaveLayoutMenuItem(2, Settings->Shortcut_SaveLayout2);
RenderSaveLayoutMenuItem(3, Settings->Shortcut_SaveLayout3);
RenderSaveLayoutMenuItem(4, Settings->Shortcut_SaveLayout4);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Layouts::RenderLoadLayoutMenuItem(const UPlayerInput* PlayerInput, int LayoutIndex)
void FCogWindow_Layouts::RenderLoadLayoutMenuItem(int InLayoutIndex, const FInputChord& InInputChord)
{
FString Shortcut;
if (GetOwner()->GetSettings()->LoadLayoutShortcuts.IsValidIndex(LayoutIndex))
{
Shortcut = FCogImguiInputHelper::KeyInfoToString(GetOwner()->GetSettings()->LoadLayoutShortcuts[LayoutIndex]);
}
const auto Shortcut = StringCast<ANSICHAR>(*FCogImguiInputHelper::InputChordToString(InInputChord));
const auto Text = StringCast<ANSICHAR>(*FString::Printf(TEXT("Load Layout %d"), InLayoutIndex));
if (ImGui::MenuItem(TCHAR_TO_ANSI(*FString::Printf(TEXT("Load Layout %d"), LayoutIndex + 1)), TCHAR_TO_ANSI(*Shortcut)))
if (ImGui::MenuItem(Text.Get(), Shortcut.Get()))
{
GetOwner()->LoadLayout(LayoutIndex + 1);
GetOwner()->LoadLayout(InLayoutIndex + 1);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Layouts::RenderSaveLayoutMenuItem(const UPlayerInput* PlayerInput, int LayoutIndex)
void FCogWindow_Layouts::RenderSaveLayoutMenuItem(int InLayoutIndex, const FInputChord& InInputChord)
{
FString Shortcut;
if (GetOwner()->GetSettings()->LoadLayoutShortcuts.IsValidIndex(LayoutIndex))
{
Shortcut = FCogImguiInputHelper::KeyInfoToString(GetOwner()->GetSettings()->SaveLayoutShortcuts[LayoutIndex]);
}
const auto Shortcut = StringCast<ANSICHAR>(*FCogImguiInputHelper::InputChordToString(InInputChord));
const auto Text = StringCast<ANSICHAR>(*FString::Printf(TEXT("Save Layout %d"), InLayoutIndex));
if (ImGui::MenuItem(TCHAR_TO_ANSI(*FString::Printf(TEXT("Save Layout %d"), LayoutIndex + 1)), TCHAR_TO_ANSI(*Shortcut)))
if (ImGui::MenuItem(Text.Get(), Shortcut.Get()))
{
GetOwner()->SaveLayout(LayoutIndex + 1);
GetOwner()->SaveLayout(InLayoutIndex + 1);
}
}
@@ -80,7 +80,7 @@ void FCogWindow_Settings::RenderContent()
Context.SetEnableInput(bEnableInput);
}
FCogWidgets::ItemTooltipWrappedText("Enable ImGui inputs. When enabled the ImGui menu is shown and inputs are forwarded to ImGui.");
FCogWidgets::MenuItemShortcut("EnableInputShortcut", FCogImguiInputHelper::KeyInfoToString(Config->ToggleImGuiInputShortcut));
FCogWidgets::MenuItemShortcut("EnableInputShortcut", FCogImguiInputHelper::InputChordToString(Config->Shortcut_ToggleImguiInput));
//-------------------------------------------------------------------------------------------
bool bShareKeyboard = Context.GetShareKeyboard();
@@ -244,24 +244,34 @@ void FCogWindow_Settings::RenderContent()
//-------------------------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Shortcuts", ImGuiTreeNodeFlags_DefaultOpen))
{
RenderShortcut("Toggle ImGui Input", Config->ToggleImGuiInputShortcut);
RenderShortcut("Toggle Selection", Config->ToggleSelectionShortcut);
ImGui::Separator();
static char Buffer[32];
for (int32 i = 0; i < Config->LoadLayoutShortcuts.Num(); ++i)
TArray<TObjectPtr<UCogCommonConfig>>& Configs = GetOwner()->GetConfigs();
for (TObjectPtr<UCogCommonConfig> SomeConfig : Configs)
{
ImFormatString(Buffer, IM_ARRAYSIZE(Buffer), "Load Layout %d", i + 1);
RenderShortcut(Buffer, Config->LoadLayoutShortcuts[i]);
}
TArray<FProperty*> Properties;
for (TFieldIterator<FProperty> It(SomeConfig->GetClass()); It; ++It)
{
if (FStructProperty* StructProperty = CastField<FStructProperty>(*It))
{
if (StructProperty->Struct == FInputChord::StaticStruct())
{
Properties.Add(StructProperty);
}
}
}
ImGui::Separator();
for (int32 i = 0; i < Config->SaveLayoutShortcuts.Num(); ++i)
{
ImFormatString(Buffer, IM_ARRAYSIZE(Buffer), "Save Layout %d", i + 1);
RenderShortcut(Buffer, Config->SaveLayoutShortcuts[i]);
if (Properties.Num() > 0)
{
auto ConfigName = StringCast<ANSICHAR>(*FCogWidgets::FormatConfigName(SomeConfig->GetClass()->GetName()));
ImGui::SeparatorText(ConfigName.Get());
for (const FProperty* Property : Properties)
{
if (FCogWidgets::InputChordProperty(*SomeConfig, *Property))
{
GetOwner()->RebindShortcut(*SomeConfig, *Property);
}
}
}
}
}
@@ -311,14 +321,4 @@ void FCogWindow_Settings::SetDPIScale(float Value) const
{
Config->DPIScale = Value;
GetOwner()->GetContext().SetDPIScale(Config->DPIScale);
//COG_NOTIFY(TEXT("DPI Scale: %0.2f"), Value);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Settings::RenderShortcut(const char* Label, FCogImGuiKeyInfo& KeyInfo)
{
if (FCogWidgets::InputKey(Label, KeyInfo))
{
GetOwner()->OnShortcutsDefined();
}
}
+24
View File
@@ -19,6 +19,9 @@ public:
static const T* GetFirstAssetByClass();
static const UObject* GetFirstAssetByClass(const TSubclassOf<UObject>& AssetClass);
template<typename TCLass, typename TMember>
static FProperty* FindProperty(TCLass* Instance, TMember TCLass::*PointerToMember);
};
//----------------------------------------------------------------------------------------------------------------------
@@ -27,3 +30,24 @@ const T* FCogHelper::GetFirstAssetByClass()
{
return Cast<T>(GetFirstAssetByClass(T::StaticClass()));
}
//----------------------------------------------------------------------------------------------------------------------
template<typename TCLass, typename TMember>
FProperty* FCogHelper::FindProperty(TCLass* Instance, TMember TCLass::*PointerToMember)
{
for (TFieldIterator<FProperty> It(Instance->GetClass()); It; ++It)
{
FProperty* Property = *It;
if (Property == nullptr)
{ continue; }
const void* MemberAddress = &(Instance->*PointerToMember);
const void* PropertyAddress = Property->ContainerPtrToValuePtr<void>(Instance);
if (MemberAddress == PropertyAddress)
{ return Property; }
}
return nullptr;
}
@@ -0,0 +1,15 @@
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "CogPluginSubsystem.generated.h"
UCLASS(Abstract)
class COG_API UCogPluginSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
virtual void OnPlayerControllerSet(APlayerController* InController) {}
};
+60 -7
View File
@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "CogHelper.h"
#include "CogImguiContext.h"
#include "CogWindow_Settings.h"
#include "imgui.h"
@@ -19,6 +20,7 @@ struct ImGuiSettingsHandler;
struct ImGuiTextBuffer;
struct FKey;
//--------------------------------------------------------------------------------------------------------------------------
UCLASS()
class COG_API UCogSubsystem : public UGameInstanceSubsystem
{
@@ -55,7 +57,7 @@ public:
virtual void ResetAllWindowsConfig();
const UCogWindowConfig_Settings* GetSettings() const { return Settings.Get(); }
UCogWindowConfig_Settings* GetSettings() const { return Settings.Get(); }
UCogCommonConfig* GetConfig(const TSubclassOf<UCogCommonConfig>& ConfigClass);
@@ -67,17 +69,24 @@ public:
template<typename T>
T* GetAsset();
FInputActionHandlerSignature& AddShortcut(const UObject& InInstance, const FProperty& InProperty);
template<typename TCLass, typename TMember>
FInputActionHandlerSignature& AddShortcut(TCLass* InInstance, TMember TCLass::*InPointerToMember);
void RebindShortcut(const UCogCommonConfig& InConfig, const FProperty& InProperty);
const FCogImguiContext& GetContext() const { return Context; }
FCogImguiContext& GetContext() { return Context; }
void OnShortcutsDefined();
bool IsRenderingMainMenu() const { return IsRenderingInMainMenu; }
static void AddCommand(UPlayerInput* PlayerInput, const FString& Command, const FKey& Key);
static void SortCommands(UPlayerInput* PlayerInput);
TArray<TObjectPtr<UCogCommonConfig>>& GetConfigs() const { return Configs; };
protected:
@@ -91,11 +100,24 @@ protected:
TArray<FMenu> SubMenus;
};
struct FCogShortcut
{
FName PropertyName;
TWeakObjectPtr<const UObject> Config;
FInputActionHandlerSignature Delegate;
FInputChord InputChord;
};
virtual void Render(float DeltaTime);
virtual void Tick(UWorld* InTickedWorld, ELevelTick InTickType, float InDeltaTime);
virtual void TryInitialize(UWorld* World);
virtual void TryInitialize(UWorld& World);
virtual void UpdateServerPlayerControllers(UWorld& World);
virtual void InitializeWindow(FCogWindow* Window);
@@ -111,11 +133,17 @@ protected:
virtual void RenderMenuItemHelp(FCogWindow& Window);
void SetLocalPlayerController(APlayerController* PlayerController);
virtual void ToggleInputMode();
virtual void DisableInputMode();
virtual void TryDisableCommandsConflictingWithShortcuts(UPlayerInput* PlayerInput);
virtual void RequestDisableCommandsConflictingWithShortcuts();
virtual void HandleInputs(const UPlayerInput& PlayerInput);
virtual bool BindShortcut(FCogShortcut& InShortcut) const;
virtual void RenderWidgets();
@@ -154,12 +182,20 @@ protected:
UPROPERTY()
mutable TArray<TObjectPtr<const UObject>> Assets;
TArray<TWeakObjectPtr<APlayerController>> ServerPlayerControllers;
TWeakObjectPtr<APlayerController> LocalPlayerController;
TWeakObjectPtr<UInputComponent> InputComponent;
FCogImguiContext Context;
TArray<FCogWindow*> Windows;
TArray<FCogWindow*> Widgets;
TArray<FCogShortcut> Shortcuts;
int32 WidgetsOrderIndex = 0;
TArray<FCogWindow*> SpaceWindows;
@@ -187,7 +223,8 @@ protected:
bool IsRenderingInMainMenu = false;
int32 NumExecBindingsChecked = 0;
FInputActionHandlerSignature InvalidShortcutDelegate;
};
//--------------------------------------------------------------------------------------------------------------------------
@@ -212,4 +249,20 @@ template<typename T>
T* UCogSubsystem::GetAsset()
{
return Cast<T>(GetAsset(T::StaticClass()));
}
}
//--------------------------------------------------------------------------------------------------------------------------
template <typename TCLass, typename TMember>
FInputActionHandlerSignature& UCogSubsystem::AddShortcut(TCLass* InInstance, TMember TCLass::* InPointerToMember)
{
if (InInstance == nullptr)
{ return InvalidShortcutDelegate; }
const FProperty* Property = FCogHelper::FindProperty(InInstance, InPointerToMember);
if (Property == nullptr)
{ return InvalidShortcutDelegate; }
return AddShortcut(*InInstance, *Property);
}
+52 -6
View File
@@ -6,6 +6,8 @@
#include <Templates/SubclassOf.h>
#include "CogHelper.h"
class AActor;
class APawn;
class FEnumProperty;
@@ -14,7 +16,6 @@ class UEnum;
class UObject;
enum class ECheckBoxState : uint8;
enum ECollisionChannel : int;
struct FCogImGuiKeyInfo;
struct FKeyBind;
using FCogWindowActorContextMenuFunction = TFunction<void(AActor& Actor)>;
@@ -54,7 +55,7 @@ public:
static bool MultiChoiceButtonsInt(TArray<int32>& Values, int32& Value, const ImVec2& Size = ImVec2(0, 0), bool InInline = true);
static bool MultiChoiceButtonsFloat(TArray<float>& InValues, float& InValue, const ImVec2& InSize = ImVec2(0, 0), bool InInline = true);
static bool MultiChoiceButtonsFloat(TArray<float>& InValues, float& InValue, const ImVec2& InSize = ImVec2(0, 0), bool InInline = true, float InTolerance = UE_SMALL_NUMBER);
static void SliderWithReset(const char* Name, float* Value, float Min, float Max, const float& ResetValue, const char* Format);
@@ -93,18 +94,21 @@ public:
static bool ComboboxEnum(const char* Label, EnumType& Value);
static bool ComboboxEnum(const char* Label, const UEnum* Enum, int64 CurrentValue, int64& NewValue);
static bool ComboboxEnum(const char* Label, const UObject* Object, const char* FieldName, uint8* PointerToEnumValue);
static bool ComboboxEnum(const char* Label, const FEnumProperty* EnumProperty, uint8* PointerToEnumValue);
static bool CheckBoxState(const char* Label, ECheckBoxState& State, bool ShowTooltip = true);
static bool InputKey(const char* Label, FCogImGuiKeyInfo& KeyInfo);
static bool InputChord(const char* Label, FInputChord& InInputChord);
static bool InputKey(FCogImGuiKeyInfo& KeyInfo);
static bool InputChord(FInputChord& InInputChord);
static bool KeyBind(FKeyBind& KeyBind);
static bool Key(FKey& InKey);
static bool KeyBind(FKeyBind& InKeyBind);
static bool ButtonWithTooltip(const char* Text, const char* Tooltip);
@@ -140,6 +144,12 @@ public:
static void MenuItemShortcut(const char* Id, const FString& Text);
template <typename TCLass, typename TMember>
static void InputChordProperty(TCLass* InConfig, TMember TCLass::* InInputChordPointerToMember);
template <typename TCLass, typename TMember>
static void TextInputChordProperty(TCLass* InConfig, TMember TCLass::* InInputChordPointerToMember);
static bool BrowseToAssetButton(const UObject* InAsset, const ImVec2& InSize = ImVec2(0, 0));
static bool BrowseToAssetButton(const FAssetData& InAssetData, const ImVec2& InSize = ImVec2(0, 0));
@@ -168,6 +178,16 @@ public:
static ImVec2 ComputeScreenCornerLocation(const FVector2f& InAlignment, const FIntVector2& InPadding);
static ImVec2 ComputeScreenCornerLocation(const ImVec2& InAlignment, const ImVec2& InPadding);
static FString GetStringAfterCharacter(const FString& InString, TCHAR InChar);
static FString FormatConfigName(const FString& InConfigName);
static FString FormatShortcutName(const FString& InShortcutName);
static void TextInputChordProperty(UObject& InConfig, const FProperty& InInputChordProperty);
static bool InputChordProperty(UObject& InConfig, const FProperty& InInputChordProperty);
};
template<typename EnumType>
@@ -227,4 +247,30 @@ template<typename T>
ImGui::PopID();
return Result;
}
template <typename TCLass, typename TMember>
void FCogWidgets::InputChordProperty(TCLass* InConfig, TMember TCLass::* InInputChordPointerToMember)
{
if (InConfig == nullptr)
{ return; }
FProperty* Property = FCogHelper::FindProperty(InConfig, InInputChordPointerToMember);
if (Property == nullptr)
{ return; }
InputChordProperty(*InConfig, *Property);
}
template <typename TCLass, typename TMember>
void FCogWidgets::TextInputChordProperty(TCLass* InConfig, TMember TCLass::* InInputChordPointerToMember)
{
if (InConfig == nullptr)
{ return; }
FProperty* Property = FCogHelper::FindProperty(InConfig, InInputChordPointerToMember);
if (Property == nullptr)
{ return; }
TextInputChordProperty(*InConfig, *Property);
}
@@ -43,6 +43,8 @@ public:
virtual void RenderSettings();
virtual void BindInputs(UInputComponent* InputComponent) {}
ImGuiID GetID() const { return ID; }
/** The full name of the window, that contains the path in the main menu. For example "Gameplay.Character.Effect" */
@@ -87,6 +89,7 @@ public:
const UObject* GetAsset(const TSubclassOf<UObject>& AssetClass) const;
protected:
friend class UCogSubsystem;
@@ -17,7 +17,7 @@ protected:
virtual void RenderContent() override;
virtual void RenderLoadLayoutMenuItem(const UPlayerInput* PlayerInput, int LayoutIndex);
virtual void RenderLoadLayoutMenuItem(int InLayoutIndex, const FInputChord& InInputChord);
virtual void RenderSaveLayoutMenuItem(const UPlayerInput* PlayerInput, int LayoutIndex);
virtual void RenderSaveLayoutMenuItem(int InLayoutIndex, const FInputChord& InInputChord);
};
@@ -31,8 +31,6 @@ protected:
virtual void PreSaveConfig() override;
virtual void RenderShortcut(const char* Label, FCogImGuiKeyInfo& KeyInfo);
TObjectPtr<UCogWindowConfig_Settings> Config = nullptr;
};
@@ -98,19 +96,40 @@ public:
UPROPERTY(Config)
bool ShowWidgetBorders = false;
UPROPERTY(Config)
FInputChord Shortcut_ToggleImguiInput = FInputChord(EKeys::F1);
UPROPERTY(Config)
FInputChord Shortcut_ToggleSelection = FInputChord(EKeys::F5);
UPROPERTY(Config)
FInputChord Shortcut_LoadLayout1 = FInputChord(EKeys::F2);
UPROPERTY(Config)
FInputChord Shortcut_LoadLayout2 = FInputChord(EKeys::F3);
UPROPERTY(Config)
FInputChord Shortcut_LoadLayout3 = FInputChord(EKeys::F4);
UPROPERTY(Config)
FInputChord Shortcut_LoadLayout4 = FInputChord();
UPROPERTY(Config)
FInputChord Shortcut_SaveLayout1 = FInputChord();
UPROPERTY(Config)
FInputChord Shortcut_SaveLayout2 = FInputChord();
UPROPERTY(Config)
FInputChord Shortcut_SaveLayout3 = FInputChord();
UPROPERTY(Config)
FInputChord Shortcut_SaveLayout4 = FInputChord();
UPROPERTY(Config)
FCogImGuiKeyInfo ToggleImGuiInputShortcut = FCogImGuiKeyInfo(EKeys::F1);
FInputChord Shortcut_ResetLayout = FInputChord();
UPROPERTY(Config)
FCogImGuiKeyInfo ToggleSelectionShortcut = FCogImGuiKeyInfo(EKeys::F5);
UPROPERTY(Config)
TArray<FCogImGuiKeyInfo> LoadLayoutShortcuts = { FCogImGuiKeyInfo(EKeys::F2), FCogImGuiKeyInfo(EKeys::F3), FCogImGuiKeyInfo(EKeys::F4), FCogImGuiKeyInfo()};
UPROPERTY(Config)
TArray<FCogImGuiKeyInfo> SaveLayoutShortcuts = { FCogImGuiKeyInfo(), FCogImGuiKeyInfo(), FCogImGuiKeyInfo(), FCogImGuiKeyInfo()};
//UPROPERTY(Config)
//bool bNavEnableGamepad = false;
@@ -129,17 +148,23 @@ public:
bShowWindowsInMainMenu = true;
bEnableInput = false;
bShareMouse = false;
bShareMouseWithGameplay = false;
bShareKeyboard = false;
bNavEnableKeyboard = false;
bDisableConflictingCommands = true;
bDisableConflictingCommands = true;
bDisableShortcutsWhenImGuiWantTextInput = false;
//bNavEnableGamepad = false;
//bNavNoCaptureInput = true;
ToggleImGuiInputShortcut = FCogImGuiKeyInfo(EKeys::F1);
ToggleSelectionShortcut = FCogImGuiKeyInfo(EKeys::F5);
LoadLayoutShortcuts = { FCogImGuiKeyInfo(EKeys::F2), FCogImGuiKeyInfo(EKeys::F3), FCogImGuiKeyInfo(EKeys::F4), FCogImGuiKeyInfo()};
SaveLayoutShortcuts = { FCogImGuiKeyInfo(), FCogImGuiKeyInfo(), FCogImGuiKeyInfo(), FCogImGuiKeyInfo()};
WidgetAlignment = ECogWidgetAlignment::Right;
ShowWidgetBorders = false;
Shortcut_ToggleImguiInput = FInputChord(EKeys::F1);
Shortcut_ToggleSelection = FInputChord(EKeys::F5);
Shortcut_LoadLayout1 = FInputChord(EKeys::F2);
Shortcut_LoadLayout2 = FInputChord(EKeys::F3);
Shortcut_LoadLayout3 = FInputChord(EKeys::F4);
Shortcut_LoadLayout4 = FInputChord();
Shortcut_SaveLayout1 = FInputChord();
Shortcut_SaveLayout2 = FInputChord();
Shortcut_SaveLayout3 = FInputChord();
Shortcut_SaveLayout4 = FInputChord();
Shortcut_ResetLayout = FInputChord();
}
};
@@ -0,0 +1,15 @@
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "CogDebugPluginSubsystem.generated.h"
UCLASS(Abstract)
class COGDEBUG_API UCogDebugPluginSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
virtual void OnPlayerControllerReady(APlayerController* InController) {}
};
@@ -0,0 +1,22 @@
#pragma once
#include "CoreMinimal.h"
#include "CogDebugReplicator.h"
#include "CogDebugPluginSubsystem.h"
#include "CogDebugSubsystem.generated.h"
UCLASS()
class COGDEBUG_API UCogDebugSubsystem : public UCogDebugPluginSubsystem
{
GENERATED_BODY()
public:
virtual void OnPlayerControllerReady(APlayerController* InController) override
{
if (InController != nullptr)
{
ACogDebugReplicator::Spawn(InController);
}
}
};
@@ -30,7 +30,5 @@ struct COGDEBUG_API FCogDebugTrack
ECogDebugTrackType Type = ECogDebugTrackType::Value;
TWeakObjectPtr<const UWorld> World;
FCogDebugTracker* Owner = nullptr;
};
};
@@ -3,6 +3,7 @@
#include "CogCommon.h"
#include "CogCommonPossessorInterface.h"
#include "CogEngineDataAsset.h"
#include "CogSubsystem.h"
#include "Engine/EngineTypes.h"
#include "Engine/World.h"
#include "EngineUtils.h"
@@ -54,7 +54,7 @@ void FCogEngineWindow_CommandBindings::RenderContent()
"Disable the existing Unreal command shortcuts mapped to same shortcuts Cog is using. Typically, if the F1 shortcut is used to toggle Inputs, the Unreal wireframe command will get disabled."
))
{
GetOwner()->OnShortcutsDefined();
//GetOwner()->OnShortcutsDefined();
}
for (FKeyBind& KeyBind : PlayerInput->DebugExecBindings)
@@ -339,7 +339,7 @@ void FCogEngineWindow_Selection::RenderPickButtonTooltip()
{
if (FCogWidgets::BeginItemTooltipWrappedText())
{
const FString Shortcut = FCogImguiInputHelper::KeyInfoToString(GetOwner()->GetSettings()->ToggleSelectionShortcut);
const FString Shortcut = FCogImguiInputHelper::InputChordToString(GetOwner()->GetSettings()->Shortcut_ToggleSelection);
ImGui::Text("Enter selection mode to select an actor on screen. Change which actor type is selectable by clicking the selection combobox\n"
"%s", TCHAR_TO_ANSI(*Shortcut));
FCogWidgets::EndItemTooltipWrappedText();
@@ -2,10 +2,14 @@
#include "CogEngineReplicator.h"
#include "CogImguiHelper.h"
#include "CogImguiInputHelper.h"
#include "CogSubsystem.h"
#include "CogWidgets.h"
#include "Engine/Engine.h"
#include "Engine/World.h"
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_TimeScale::Initialize()
{
@@ -15,6 +19,12 @@ void FCogEngineWindow_TimeScale::Initialize()
bIsWidgetVisible = true;
Config = GetConfig<UCogEngineWindowConfig_TimeScale>();
UCogEngineWindowConfig_TimeScale* ConfigPtr = Config.Get();
GetOwner()->AddShortcut(ConfigPtr, &UCogEngineWindowConfig_TimeScale::Shortcut_FasterTimeScale).BindRaw(this, &FCogEngineWindow_TimeScale::FasterTimeScale);
GetOwner()->AddShortcut(ConfigPtr, &UCogEngineWindowConfig_TimeScale::Shortcut_SlowerTimeScale).BindRaw(this, &FCogEngineWindow_TimeScale::SlowerTimeScale);
GetOwner()->AddShortcut(ConfigPtr, &UCogEngineWindowConfig_TimeScale::Shortcut_ResetTimeScale).BindRaw(this, &FCogEngineWindow_TimeScale::ResetTimeScale);
GetOwner()->AddShortcut(ConfigPtr, &UCogEngineWindowConfig_TimeScale::Shortcut_ZeroTimeScale).BindRaw(this, &FCogEngineWindow_TimeScale::ZeroTimeScale);
}
//--------------------------------------------------------------------------------------------------------------------------
@@ -53,7 +63,14 @@ void FCogEngineWindow_TimeScale::RenderContextMenu()
ImGui::SetItemTooltip("Color of the current time scale, in widget mode, when the time scale in not 1.");
FCogWidgets::FloatArray("Time Scales", Config->TimeScales, 10, ImVec2(0, ImGui::GetFontSize() * 10));
if (ImGui::CollapsingHeader("Shortcuts", ImGuiTreeNodeFlags_DefaultOpen))
{
FCogWidgets::InputChord("Speed Up", Config->Shortcut_FasterTimeScale);
FCogWidgets::InputChord("Speed Down", Config->Shortcut_SlowerTimeScale);
FCogWidgets::InputChord("Reset Time", Config->Shortcut_ResetTimeScale);
}
ImGui::Separator();
FCogWindow::RenderContextMenu();
}
@@ -71,16 +88,21 @@ void FCogEngineWindow_TimeScale::RenderMainMenuWidget()
return;
}
const float CurrentValue = Replicator->GetTimeDilation();
if (CurrentValue != 1.0f)
float TimeDilation = GetTimeDilation();
if (TimeDilation != 1.0f)
{
ImGui::PushStyleColor(ImGuiCol_Text, FCogImguiHelper::ToImVec4(Config->TimeScaleModifiedColor));
}
if (FMath::IsNearlyZero(TimeDilation, 0.0001f))
{
TimeDilation = 0.0f;
}
const auto CurrentValueText = StringCast<ANSICHAR>(*FString::Printf(TEXT("x%g"), CurrentValue));
const bool Open = ImGui::BeginMenu(CurrentValueText.Get());
const auto Text = StringCast<ANSICHAR>(*FString::Printf(TEXT("x%g"), TimeDilation));
const bool Open = ImGui::BeginMenu(Text.Get());
if (CurrentValue != 1)
if (TimeDilation != 1)
{
ImGui::PopStyleColor();
}
@@ -90,16 +112,16 @@ void FCogEngineWindow_TimeScale::RenderMainMenuWidget()
RenderContextMenu();
ImGui::EndPopup();
}
if (Open)
{
for (int32 i = 0; i < Config->TimeScales.Num(); ++i)
{
const float Value = Config->TimeScales[i];
const auto ValueText = StringCast<ANSICHAR>(*FString::Printf(TEXT("%g"), Value));
if (ImGui::Selectable(ValueText.Get(), Value == Replicator->GetTimeDilation()))
if (ImGui::Selectable(ValueText.Get(), Value == TimeDilation))
{
Replicator->SetTimeDilation(Value);
SetCurrentTimeScale(*Replicator, Value);
}
}
@@ -107,16 +129,128 @@ void FCogEngineWindow_TimeScale::RenderMainMenuWidget()
}
else
{
ImGui::SetItemTooltip("Time Scale");
if (ImGui::BeginItemTooltip())
{
ImGui::Text("Time Scale: x%g", TimeDilation);
ImGui::Spacing();
ImGui::Separator();
FCogWidgets::TextInputChordProperty(Config.Get(), &UCogEngineWindowConfig_TimeScale::Shortcut_FasterTimeScale);
FCogWidgets::TextInputChordProperty(Config.Get(), &UCogEngineWindowConfig_TimeScale::Shortcut_SlowerTimeScale);
FCogWidgets::TextInputChordProperty(Config.Get(), &UCogEngineWindowConfig_TimeScale::Shortcut_ResetTimeScale);
FCogWidgets::TextInputChordProperty(Config.Get(), &UCogEngineWindowConfig_TimeScale::Shortcut_ZeroTimeScale);
ImGui::EndTooltip();
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
int32 FCogEngineWindow_TimeScale::GetCurrentTimeScaleIndex(const ACogEngineReplicator& Replicator) const
{
return GetTimeScaleIndex(Replicator.GetTimeDilation());
}
//--------------------------------------------------------------------------------------------------------------------------
int32 FCogEngineWindow_TimeScale::GetTimeScaleIndex(float InTimeScale) const
{
for (int32 i = 0; i < Config->TimeScales.Num(); ++i)
{
const float Value = Config->TimeScales[i];
if (FMath::IsNearlyEqual(Value, InTimeScale))
{ return i; }
}
return INDEX_NONE;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_TimeScale::SetCurrentTimeScale(ACogEngineReplicator& Replicator, const float Value) const
{
Replicator.SetTimeDilation(Value);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_TimeScale::SetCurrentTimeScaleIndex(ACogEngineReplicator& Replicator, int32 InTimeScaleIndex) const
{
if (Config->TimeScales.IsValidIndex(InTimeScaleIndex) == false)
{ return; }
const float Value = Config->TimeScales[InTimeScaleIndex];
SetCurrentTimeScale(Replicator, Value);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_TimeScale::FasterTimeScale()
{
ACogEngineReplicator* Replicator = ACogEngineReplicator::GetLocalReplicator(*GetWorld());
if (Replicator == nullptr)
{ return; }
const int32 TimeScaleIndex = GetCurrentTimeScaleIndex(*Replicator);
if (TimeScaleIndex == INDEX_NONE)
{ return; }
SetCurrentTimeScaleIndex(*Replicator, TimeScaleIndex + 1);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_TimeScale::SlowerTimeScale()
{
ACogEngineReplicator* Replicator = ACogEngineReplicator::GetLocalReplicator(*GetWorld());
if (Replicator == nullptr)
{ return; }
const int32 TimeScaleIndex = GetCurrentTimeScaleIndex(*Replicator);
if (TimeScaleIndex == INDEX_NONE)
{ return; }
SetCurrentTimeScaleIndex(*Replicator, TimeScaleIndex - 1);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_TimeScale::ResetTimeScale()
{
ACogEngineReplicator* Replicator = ACogEngineReplicator::GetLocalReplicator(*GetWorld());
if (Replicator == nullptr)
{ return; }
SetCurrentTimeScale(*Replicator, 1.0f);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_TimeScale::ZeroTimeScale()
{
ACogEngineReplicator* Replicator = ACogEngineReplicator::GetLocalReplicator(*GetWorld());
if (Replicator == nullptr)
{ return; }
SetCurrentTimeScale(*Replicator, 0.0f);
}
//--------------------------------------------------------------------------------------------------------------------------
float FCogEngineWindow_TimeScale::GetTimeDilation() const
{
const UWorld* World = GetWorld();
if (World == nullptr)
{
return 1.0f;
}
AWorldSettings* WorldSettings = World->GetWorldSettings();
if (WorldSettings == nullptr)
{
return 1.0f;
}
return WorldSettings->GetEffectiveTimeDilation();
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_TimeScale::RenderTimeScaleChoices(ACogEngineReplicator* Replicator)
{
float Value = Replicator->GetTimeDilation();
if (FCogWidgets::MultiChoiceButtonsFloat(Config->TimeScales, Value, ImVec2(3.5f * FCogWidgets::GetFontWidth(), 0), Config->Inline))
float TimeDilation = GetTimeDilation();
if (FCogWidgets::MultiChoiceButtonsFloat(Config->TimeScales, TimeDilation, ImVec2(3.5f * FCogWidgets::GetFontWidth(), 0), Config->Inline, 0.0001f))
{
Replicator->SetTimeDilation(Value);
Replicator->SetTimeDilation(TimeDilation);
}
}
}
@@ -0,0 +1,22 @@
#pragma once
#include "CoreMinimal.h"
#include "CogEngineReplicator.h"
#include "CogDebugPluginSubsystem.h"
#include "CogEngineSubsystem.generated.h"
UCLASS()
class COGENGINE_API UCogEngineSubsystem : public UCogDebugPluginSubsystem
{
GENERATED_BODY()
public:
virtual void OnPlayerControllerReady(APlayerController* InController) override
{
if (InController != nullptr)
{
ACogEngineReplicator::Spawn(InController);
}
}
};
@@ -123,7 +123,7 @@ public:
SortCommands = false;
DockInputInMenuBar = false;
FocusWidgetWhenAppearing = true;
FocusWidgetWhenAppearing = false;
UseClipper = false;
NumHistoryCommands = 10;
CompletionMinimumCharacters = 1;
@@ -2,6 +2,7 @@
#include "CoreMinimal.h"
#include "CogEngineReplicator.h"
#include "CogImguiKeyInfo.h"
#include "CogWindow.h"
#include "CogEngineWindow_TimeScale.generated.h"
@@ -27,6 +28,24 @@ protected:
virtual void RenderTimeScaleChoices(ACogEngineReplicator* Replicator);
virtual int32 GetCurrentTimeScaleIndex(const ACogEngineReplicator& Replicator) const;
virtual void SetCurrentTimeScaleIndex(ACogEngineReplicator& Replicator, int32 InTimeScaleIndex) const;
virtual void FasterTimeScale();
virtual void SlowerTimeScale();
virtual void ResetTimeScale();
virtual void ZeroTimeScale();
virtual float GetTimeDilation() const;
virtual int32 GetTimeScaleIndex(float InTimeScale) const;
virtual void SetCurrentTimeScale(ACogEngineReplicator& Replicator, float Value) const;
TWeakObjectPtr<UCogEngineWindowConfig_TimeScale> Config;
};
@@ -46,17 +65,34 @@ public:
Inline = true;
TimeScales = { 0.00f, 0.01f, 0.10f, 0.50f, 1.00f, 2.00f, 5.00f, 10.0f };
TimeScaleModifiedColor = FColor(255, 30, 210, 255);
Shortcut_ZeroTimeScale = FInputChord(EKeys::NumPadZero);
Shortcut_ResetTimeScale = FInputChord(EKeys::NumPadOne);
Shortcut_FasterTimeScale = FInputChord(EKeys::Add);
Shortcut_SlowerTimeScale = FInputChord(EKeys::Subtract);
}
UPROPERTY(Config)
float TimeScale = 1.0f;
UPROPERTY(Config)
TArray<float> TimeScales;
TArray<float> TimeScales = { 0.00f, 0.01f, 0.10f, 0.50f, 1.00f, 2.00f, 5.00f, 10.0f };
UPROPERTY(Config)
bool Inline = true;
UPROPERTY(Config)
FColor TimeScaleModifiedColor = FColor();
FColor TimeScaleModifiedColor = FColor(255, 30, 210, 255);
UPROPERTY(Config)
FInputChord Shortcut_ZeroTimeScale = FInputChord(EKeys::NumPadZero);
UPROPERTY(Config)
FInputChord Shortcut_ResetTimeScale = FInputChord(EKeys::NumPadOne);
UPROPERTY(Config)
FInputChord Shortcut_FasterTimeScale = FInputChord(EKeys::Add);
UPROPERTY(Config)
FInputChord Shortcut_SlowerTimeScale = FInputChord(EKeys::Subtract);
};
@@ -265,7 +265,7 @@ bool FCogImguiContext::BeginFrame(float InDeltaTime)
// Sometime the game can retake unaware that ImGui want to keep the focus and mouse unlock.
// This typically happens when switching level.
//-------------------------------------------------------------------------------------------------------
if (bRetakeFocus)
if (bRetakeFocus && IsConsoleOpened() == false)
{
SetEnableInput(true);
bRetakeFocus = false;
@@ -17,7 +17,7 @@
#endif //WITH_EDITOR
//--------------------------------------------------------------------------------------------------------------------------
TArray<FCogImGuiKeyInfo> FCogImguiInputHelper::CogShortcuts;
TArray<FInputChord> FCogImguiInputHelper::CogPrioritizedShortcuts;
//--------------------------------------------------------------------------------------------------------------------------
APlayerController* FCogImguiInputHelper::GetFirstLocalPlayerController(const UWorld& World)
@@ -60,9 +60,9 @@ bool FCogImguiInputHelper::IsTopPriorityKeyEvent(const UPlayerInput& PlayerInput
//------------------------------------------------------------------------------------------------
// We want the user to be able to use Cog shortcuts when imgui has the input.
//------------------------------------------------------------------------------------------------
for (const FCogImGuiKeyInfo& KeyInfo : CogShortcuts)
for (const FInputChord& InputChord : CogPrioritizedShortcuts)
{
if (IsKeyEventMatchingKeyInfo(InKeyEvent, KeyInfo))
if (IsInputChordMatchingKeyInfo(InKeyEvent, InputChord))
{ return true; }
}
@@ -117,39 +117,6 @@ bool FCogImguiInputHelper::IsCheckBoxStateMatchingKeyBindModifier(ECheckBoxState
return false;
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogImguiInputHelper::IsKeyEventMatchingKeyInfo(const FKeyEvent& InKeyEvent, const FCogImGuiKeyInfo& InKeyInfo)
{
const bool Result = (InKeyInfo.Key == InKeyEvent.GetKey())
&& IsCheckBoxStateMatchingValue(InKeyInfo.Shift, InKeyEvent.IsShiftDown())
&& IsCheckBoxStateMatchingValue(InKeyInfo.Ctrl, InKeyEvent.IsControlDown())
&& IsCheckBoxStateMatchingValue(InKeyInfo.Alt, InKeyEvent.IsAltDown())
&& IsCheckBoxStateMatchingValue(InKeyInfo.Cmd, InKeyEvent.IsCommandDown());
return Result;
}
//--------------------------------------------------------------------------------------------------------------------------
#define BREAK_CHECKBOX_STATE(CheckBoxState, RequireValue, IgnoreValue) \
{ \
if (CheckBoxState == ECheckBoxState::Checked) \
{ \
RequireValue = true; \
IgnoreValue = false; \
} \
else if (CheckBoxState == ECheckBoxState::Unchecked) \
{ \
RequireValue = false; \
IgnoreValue = true; \
} \
else if (CheckBoxState == ECheckBoxState::Undetermined) \
{ \
RequireValue = false; \
IgnoreValue = false; \
} \
} \
//--------------------------------------------------------------------------------------------------------------------------
ECheckBoxState FCogImguiInputHelper::MakeCheckBoxState(uint8 RequireValue, uint8 IgnoreValue)
{
@@ -167,57 +134,29 @@ ECheckBoxState FCogImguiInputHelper::MakeCheckBoxState(uint8 RequireValue, uint8
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiInputHelper::KeyBindToKeyInfo(const FKeyBind& KeyBind, FCogImGuiKeyInfo& KeyInfo)
bool FCogImguiInputHelper::IsInputChordMatchingKeyInfo(const FKeyEvent& InKeyEvent, const FInputChord& InInputChord)
{
KeyInfo.Key = KeyBind.Key;
KeyInfo.Shift = MakeCheckBoxState(KeyBind.Shift, KeyBind.bIgnoreShift);
KeyInfo.Ctrl = MakeCheckBoxState(KeyBind.Control, KeyBind.bIgnoreCtrl);
KeyInfo.Alt = MakeCheckBoxState(KeyBind.Alt, KeyBind.bIgnoreAlt);
KeyInfo.Alt = MakeCheckBoxState(KeyBind.Cmd, KeyBind.bIgnoreCmd);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiInputHelper::KeyInfoToKeyBind(const FCogImGuiKeyInfo& KeyInfo, FKeyBind& KeyBind)
{
KeyBind.Key = KeyInfo.Key;
BREAK_CHECKBOX_STATE(KeyInfo.Shift, KeyBind.Shift, KeyBind.bIgnoreShift);
BREAK_CHECKBOX_STATE(KeyInfo.Ctrl, KeyBind.Control, KeyBind.bIgnoreCtrl);
BREAK_CHECKBOX_STATE(KeyInfo.Alt, KeyBind.Alt, KeyBind.bIgnoreAlt);
BREAK_CHECKBOX_STATE(KeyInfo.Cmd, KeyBind.Cmd, KeyBind.bIgnoreCmd);
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogImguiInputHelper::IsKeyBindMatchingKeyInfo(const FKeyBind& InKeyBind, const FCogImGuiKeyInfo& InKeyInfo)
{
const bool Result =
InKeyBind.bDisabled == false
&& (InKeyInfo.Key == InKeyBind.Key)
&& IsCheckBoxStateMatchingKeyBindModifier(InKeyInfo.Shift, InKeyBind.Shift, InKeyBind.bIgnoreShift)
&& IsCheckBoxStateMatchingKeyBindModifier(InKeyInfo.Ctrl, InKeyBind.Control, InKeyBind.bIgnoreCtrl)
&& IsCheckBoxStateMatchingKeyBindModifier(InKeyInfo.Alt, InKeyBind.Alt, InKeyBind.bIgnoreAlt)
&& IsCheckBoxStateMatchingKeyBindModifier(InKeyInfo.Cmd, InKeyBind.Cmd, InKeyBind.bIgnoreCmd);
const bool Result = (InInputChord.Key == InKeyEvent.GetKey())
&& (InInputChord.bShift == InKeyEvent.IsShiftDown())
&& (InInputChord.bCtrl == InKeyEvent.IsControlDown())
&& (InInputChord.bAlt == InKeyEvent.IsAltDown())
&& (InInputChord.bCmd == InKeyEvent.IsCommandDown());
return Result;
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogImguiInputHelper::WasKeyInfoJustPressed(const APlayerController& PlayerController, const FCogImGuiKeyInfo& KeyInfo)
bool FCogImguiInputHelper::IsKeyBindMatchingInputChord(const FKeyBind& InKeyBind, const FInputChord& InInputChord)
{
if (PlayerController.WasInputKeyJustPressed(KeyInfo.Key))
{
const FModifierKeysState& ModifierKeys = FSlateApplication::Get().GetModifierKeys();
const bool Result =
InKeyBind.bDisabled == false
&& (InInputChord.Key == InKeyBind.Key)
&& (InInputChord.bShift == InKeyBind.Shift)
&& (InInputChord.bCtrl == InKeyBind.Control)
&& (InInputChord.bAlt == InKeyBind.Alt)
&& (InInputChord.bCmd == InKeyBind.Cmd);
const bool MatchCtrl = IsCheckBoxStateMatchingValue(KeyInfo.Ctrl, ModifierKeys.IsControlDown());
const bool MatchAlt = IsCheckBoxStateMatchingValue(KeyInfo.Alt, ModifierKeys.IsAltDown());
const bool MatchShift = IsCheckBoxStateMatchingValue(KeyInfo.Shift, ModifierKeys.IsShiftDown());
const bool MatchCmd = IsCheckBoxStateMatchingValue(KeyInfo.Cmd, ModifierKeys.IsCommandDown());
const bool Result = MatchCtrl && MatchAlt && MatchShift && MatchCmd;
return Result;
}
return false;
return Result;
}
//--------------------------------------------------------------------------------------------------------------------------
@@ -293,78 +232,35 @@ EMouseCursor::Type FCogImguiInputHelper::ToSlateMouseCursor(ImGuiMouseCursor Mou
}
//--------------------------------------------------------------------------------------------------------------------------
FString FCogImguiInputHelper::CommandToString(const UWorld& World, const FString& Command)
FString FCogImguiInputHelper::InputChordToString(const FInputChord& InInputChord)
{
const UPlayerInput* PlayerInput = GetPlayerInput(World);
if (PlayerInput == nullptr)
{
return FString();
}
const FKeyBind* Result = PlayerInput->DebugExecBindings.FindByPredicate([&](const FKeyBind& KeyBind) { return KeyBind.Command == Command; });
if (Result == nullptr)
{
return FString();
}
return KeyBindToString(*Result);
}
//--------------------------------------------------------------------------------------------------------------------------
FString FCogImguiInputHelper::CommandToString(const UPlayerInput* PlayerInput, const FString& Command)
{
if (PlayerInput == nullptr)
{
return FString();
}
const FKeyBind* Result = PlayerInput->DebugExecBindings.FindByPredicate([&](const FKeyBind& KeyBind) { return KeyBind.Command == Command; });
if (Result == nullptr)
{
return FString();
}
return KeyBindToString(*Result);
}
//--------------------------------------------------------------------------------------------------------------------------
FString FCogImguiInputHelper::KeyBindToString(const FKeyBind& InKeyBind)
{
FCogImGuiKeyInfo KeyInfo;
KeyBindToKeyInfo(InKeyBind, KeyInfo);
return KeyInfoToString(KeyInfo);
}
//--------------------------------------------------------------------------------------------------------------------------
FString FCogImguiInputHelper::KeyInfoToString(const FCogImGuiKeyInfo& InKeyInfo)
{
if (InKeyInfo == FKey())
if (InInputChord.Key == FKey())
{
return FString("");
}
FString Result = "[";
if (InKeyInfo.Alt == ECheckBoxState::Checked)
if (InInputChord.bAlt)
{
Result += FString("Alt ");
}
if (InKeyInfo.Shift == ECheckBoxState::Checked)
if (InInputChord.bShift)
{
Result += FString("Shift ");
}
if (InKeyInfo.Ctrl == ECheckBoxState::Checked)
if (InInputChord.bCtrl)
{
Result += FString("Ctrl ");
}
if (InKeyInfo.Cmd == ECheckBoxState::Checked)
if (InInputChord.bCmd)
{
Result += FString("Cmd ");
}
Result += InKeyInfo.Key.ToString();
Result += InInputChord.Key.ToString();
Result += FString("]");
return Result;
@@ -403,22 +299,6 @@ bool FCogImguiInputHelper::IsKeyEventMatchingKeyBind(const FKeyEvent& KeyEvent,
return false;
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogImguiInputHelper::IsKeyInfoPressed(const UPlayerInput& PlayerInput, const FCogImGuiKeyInfo& InKeyInfo)
{
const bool bKeyPressed = PlayerInput.WasJustPressed(InKeyInfo.Key);
if (bKeyPressed == false)
{ return false; }
if (IsCheckBoxStateMatchingValue(InKeyInfo.Ctrl, PlayerInput.IsCtrlPressed())
&& IsCheckBoxStateMatchingValue(InKeyInfo.Shift, PlayerInput.IsShiftPressed())
&& IsCheckBoxStateMatchingValue(InKeyInfo.Alt, PlayerInput.IsAltPressed())
&& IsCheckBoxStateMatchingValue(InKeyInfo.Cmd, PlayerInput.IsCmdPressed()))
{ return true; }
return false;
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogImguiInputHelper::IsKeyBoundToCommand(const UPlayerInput* InPlayerInput, const FKeyEvent& KeyEvent)
{
@@ -456,11 +336,11 @@ bool FCogImguiInputHelper::DisableCommandsConflictingWithShortcuts(UPlayerInput&
{
bool HasDisabled = false;
for (const FCogImGuiKeyInfo& Shortcut : CogShortcuts)
for (const FInputChord& Shortcut : CogPrioritizedShortcuts)
{
for (FKeyBind& KeyBind : PlayerInput.DebugExecBindings)
{
if (IsKeyBindMatchingKeyInfo(KeyBind, Shortcut))
if (IsKeyBindMatchingInputChord(KeyBind, Shortcut))
{
KeyBind.bDisabled = true;
HasDisabled = false;
@@ -476,12 +356,6 @@ bool FCogImguiInputHelper::DisableCommandsConflictingWithShortcuts(UPlayerInput&
return false;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiInputHelper::SetShortcuts(const TArray<FCogImGuiKeyInfo>& InShortcuts)
{
CogShortcuts = InShortcuts;
}
//--------------------------------------------------------------------------------------------------------------------------
ImGuiKey FCogImguiInputHelper::ToImKey(const FKey& Key)
{
@@ -8,12 +8,30 @@ class APlayerController;
class UPlayerInput;
class UWorld;
enum class ECheckBoxState : uint8;
struct FCogImGuiKeyInfo;
struct FCogImGuiKeyInfo;
struct FKey;
struct FKeyBind;
struct FKeyEvent;
//--------------------------------------------------------------------------------------------------------------------------
#define BREAK_CHECKBOX_STATE(CheckBoxState, RequireValue, IgnoreValue) \
{ \
if (CheckBoxState == ECheckBoxState::Checked) \
{ \
RequireValue = true; \
IgnoreValue = false; \
} \
else if (CheckBoxState == ECheckBoxState::Unchecked) \
{ \
RequireValue = false; \
IgnoreValue = true; \
} \
else if (CheckBoxState == ECheckBoxState::Undetermined) \
{ \
RequireValue = false; \
IgnoreValue = false; \
} \
} \
class COGIMGUI_API FCogImguiInputHelper
{
public:
@@ -26,25 +44,17 @@ public:
static bool IsTopPriorityKeyEvent(const UPlayerInput& PlayerInput, const FKeyEvent& InKeyEvent);
static bool WasKeyInfoJustPressed(const APlayerController& PlayerController, const FCogImGuiKeyInfo& KeyInfo);
static bool IsCheckBoxStateMatchingValue(ECheckBoxState CheckBoxState, bool bValue);
static bool IsCheckBoxStateMatchingKeyBindModifier(ECheckBoxState InCheckBoxState, bool InRequireModifier, bool InIgnoreModifier);
static bool IsKeyEventMatchingKeyInfo(const FKeyEvent& InKeyEvent, const FCogImGuiKeyInfo& InKeyInfo);
static bool IsKeyBindMatchingKeyInfo(const FKeyBind& InKeyBind, const FCogImGuiKeyInfo& InKeyInfo);
static bool IsKeyEventMatchingKeyBind(const FKeyEvent& KeyEvent, const FKeyBind& KeyBind);
static bool IsKeyInfoPressed(const UPlayerInput& PlayerInput, const FCogImGuiKeyInfo& InKeyInfo);
static ECheckBoxState MakeCheckBoxState(uint8 RequireValue, uint8 IgnoreValue);
static void KeyBindToKeyInfo(const FKeyBind& KeyBind, FCogImGuiKeyInfo& KeyInfo);
static bool IsInputChordMatchingKeyInfo(const FKeyEvent& InKeyEvent, const FInputChord& InInputChord);
static void KeyInfoToKeyBind(const FCogImGuiKeyInfo& KeyInfo, FKeyBind& KeyBind);
static bool IsKeyBindMatchingInputChord(const FKeyBind& InKeyBind, const FInputChord& InInputChord);
static bool IsConsoleEvent(const FKeyEvent& KeyEvent);
@@ -58,19 +68,13 @@ public:
static EMouseCursor::Type ToSlateMouseCursor(ImGuiMouseCursor MouseCursor);
static FString CommandToString(const UWorld& World, const FString& Command);
static FString CommandToString(const UPlayerInput* PlayerInput, const FString& Command);
static FString KeyBindToString(const FKeyBind& InKeyBind);
static FString KeyInfoToString(const FCogImGuiKeyInfo& InKeyInfo);
static FString InputChordToString(const FInputChord& InInputChord);
static bool IsMouseInsideMainViewport();
static bool IsKeyBoundToCommand(const UPlayerInput* InPlayerInput, const FKeyEvent& KeyEvent);
static void SetShortcuts(const TArray<FCogImGuiKeyInfo>& InShortcuts);
static TArray<FInputChord>& GetPrioritizedShortcuts() { return CogPrioritizedShortcuts; }
static bool DisableCommandsConflictingWithShortcuts(UPlayerInput& PlayerInput);
@@ -81,5 +85,5 @@ public:
}
private:
static TArray<FCogImGuiKeyInfo> CogShortcuts;
static TArray<FInputChord> CogPrioritizedShortcuts;
};
@@ -1,59 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "InputCoreTypes.h"
#include "Styling/SlateTypes.h"
#include "CogImguiKeyInfo.generated.h"
USTRUCT()
struct COGIMGUI_API FCogImGuiKeyInfo
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, Category = "Input")
FKey Key = EKeys::Invalid;
UPROPERTY(EditAnywhere, Category = "Input")
ECheckBoxState Shift = ECheckBoxState::Undetermined;
UPROPERTY(EditAnywhere, Category = "Input")
ECheckBoxState Ctrl = ECheckBoxState::Undetermined;
UPROPERTY(EditAnywhere, Category = "Input")
ECheckBoxState Alt = ECheckBoxState::Undetermined;
UPROPERTY(EditAnywhere, Category = "Input")
ECheckBoxState Cmd = ECheckBoxState::Undetermined;
FCogImGuiKeyInfo()
{
}
FCogImGuiKeyInfo(const FKey InKey,
const ECheckBoxState InShift = ECheckBoxState::Undetermined,
const ECheckBoxState InCtrl = ECheckBoxState::Undetermined,
const ECheckBoxState InAlt = ECheckBoxState::Undetermined,
const ECheckBoxState InCmd = ECheckBoxState::Undetermined)
: Key(InKey)
, Shift(InShift)
, Ctrl(InCtrl)
, Alt(InAlt)
, Cmd(InCmd)
{
}
friend bool operator==(const FCogImGuiKeyInfo& Lhs, const FCogImGuiKeyInfo& Rhs)
{
return Lhs.Key == Rhs.Key
&& Lhs.Shift == Rhs.Shift
&& Lhs.Ctrl == Rhs.Ctrl
&& Lhs.Alt == Rhs.Alt
&& Lhs.Cmd == Rhs.Cmd;
}
friend bool operator!=(const FCogImGuiKeyInfo& Lhs, const FCogImGuiKeyInfo& Rhs)
{
return !(Lhs == Rhs);
}
};
@@ -59,7 +59,7 @@ public:
TSharedPtr<const SWindow> GetWindow() const { return Window; }
void SetWindow(const TSharedPtr<SWindow>& Value) { Window = Value; }
protected:
FReply HandleKeyEvent(const FKeyEvent& KeyEvent, bool Down) const;
@@ -0,0 +1,22 @@
#pragma once
#include "CoreMinimal.h"
#include "CogAbilityReplicator.h"
#include "CogDebugPluginSubsystem.h"
#include "CogAbilitySubsystem.generated.h"
UCLASS()
class COGABILITY_API UCogAbilitySubsystem : public UCogDebugPluginSubsystem
{
GENERATED_BODY()
public:
virtual void OnPlayerControllerReady(APlayerController* InController) override
{
if (InController != nullptr)
{
ACogAbilityReplicator::Spawn(InController);
}
}
};
@@ -372,7 +372,7 @@ void FCogInputWindow_Gamepad::RenderContent()
const ImVec2 ContentMin = ImGui::GetCursorScreenPos();
const ImVec2 ContentSize = ImGui::GetContentRegionAvail();
const ImVec2 ContentMax = ContentMin + ContentSize;
const ImVec2 OverlayOffset = ImVec2(0.0f, Config->bShowAsOverlay ? ImGui::GetFrameHeight() : 0.0f);
const ImVec2 OverlayOffset = ImVec2(0.0f, Config->bShowAsOverlay && IsWindowRenderedInMainMenu() == false ? ImGui::GetFrameHeight() : 0.0f);
const ImVec2 Padding = ImVec2(Config->Border * 0.5f * ContentSize.x, Config->Border * 0.5f * ContentSize.x);
CanvasMin = ContentMin + OverlayOffset + Padding;