LifePlay-Revival/Source/LifePlayEditorTools/LPFixButtonPaddingCommandlet.cpp

184 lines
6.1 KiB
C++
Raw Normal View History

// Portage UE 5.5 - voir LPFixButtonPaddingCommandlet.h
#include "LPFixButtonPaddingCommandlet.h"
#include "AssetRegistry/AssetData.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "Blueprint/WidgetTree.h"
#include "Components/Button.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "Misc/PackageName.h"
#include "UObject/Package.h"
#include "UObject/SavePackage.h"
#include "WidgetBlueprint.h"
DEFINE_LOG_CATEGORY_STATIC(LogLPFixButton, Log, All);
namespace
{
// Valeurs de UE 4.27 : Engine/Source/Runtime/SlateCore/Private/Styling/CoreStyle.cpp
const FMargin UE4NormalPadding(2.f, 2.f, 2.f, 2.f);
const FMargin UE4PressedPadding(2.f, 3.f, 2.f, 1.f);
FString Str(const FMargin& M)
{
return FString::Printf(TEXT("(%g,%g,%g,%g)"), M.Left, M.Top, M.Right, M.Bottom);
}
/** Remplace par la valeur UE4 chaque composante egale au defaut UE5. Vrai si modifie. */
bool FixMargin(FMargin& M, const FMargin& UE5, const FMargin& UE4)
{
const FMargin Before = M;
if (M.Left == UE5.Left) { M.Left = UE4.Left; }
if (M.Top == UE5.Top) { M.Top = UE4.Top; }
if (M.Right == UE5.Right) { M.Right = UE4.Right; }
if (M.Bottom == UE5.Bottom) { M.Bottom = UE4.Bottom; }
return !(M == Before);
}
}
ULPFixButtonPaddingCommandlet::ULPFixButtonPaddingCommandlet()
{
IsClient = false;
IsServer = false;
IsEditor = true;
LogToConsole = true;
}
int32 ULPFixButtonPaddingCommandlet::Main(const FString& Params)
{
const bool bDryRun = Params.Contains(TEXT("DryRun"), ESearchCase::IgnoreCase);
// Defaut UE5 lu sur le CDO plutot que recopie : c'est lui que recoivent les boutons 4.27.
PRAGMA_DISABLE_DEPRECATION_WARNINGS
const FButtonStyle& UE5Style = GetDefault<UButton>()->WidgetStyle;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
const FMargin UE5Normal = UE5Style.NormalPadding;
const FMargin UE5Pressed = UE5Style.PressedPadding;
UE_LOG(LogLPFixButton, Warning, TEXT("=== Marges de UButton : defaut UE5 Normal=%s Pressed=%s -> UE4 Normal=%s Pressed=%s%s ==="),
*Str(UE5Normal), *Str(UE5Pressed), *Str(UE4NormalPadding), *Str(UE4PressedPadding),
bDryRun ? TEXT(" [DRY RUN]") : TEXT(""));
FAssetRegistryModule& AssetRegistryModule =
FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
AssetRegistryModule.Get().SearchAllAssets(true);
TArray<FAssetData> Assets;
AssetRegistryModule.Get().GetAssetsByClass(UWidgetBlueprint::StaticClass()->GetClassPathName(), Assets, true);
int32 ButtonsSeen = 0;
int32 ButtonsFixed = 0;
int32 ButtonsKept = 0;
int32 BlueprintsModified = 0;
int32 SaveFailures = 0;
for (const FAssetData& AssetData : Assets)
{
if (!AssetData.PackageName.ToString().StartsWith(TEXT("/Game/")))
{
continue;
}
UWidgetBlueprint* Blueprint = Cast<UWidgetBlueprint>(AssetData.GetAsset());
if (!Blueprint || !Blueprint->WidgetTree)
{
continue;
}
TArray<UWidget*> Widgets;
Blueprint->WidgetTree->GetAllWidgets(Widgets);
int32 FixedHere = 0;
for (UWidget* Widget : Widgets)
{
UButton* Button = Cast<UButton>(Widget);
if (!Button)
{
continue;
}
++ButtonsSeen;
PRAGMA_DISABLE_DEPRECATION_WARNINGS
FButtonStyle Style = Button->WidgetStyle;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
// Composante par composante : FMargin est serialise champ par champ, une marge 4.27
// partiellement modifiee (ex. Top/Bottom seuls) a recu les autres champs du defaut UE5.
const FMargin OldNormal = Style.NormalPadding;
const FMargin OldPressed = Style.PressedPadding;
const bool bNormal = FixMargin(Style.NormalPadding, UE5Normal, UE4NormalPadding);
const bool bPressed = FixMargin(Style.PressedPadding, UE5Pressed, UE4PressedPadding);
if (!bNormal && !bPressed)
{
++ButtonsKept;
UE_LOG(LogLPFixButton, Display, TEXT(" garde %s :: %s Normal=%s Pressed=%s"),
*Blueprint->GetName(), *Button->GetName(), *Str(OldNormal), *Str(OldPressed));
continue;
}
UE_LOG(LogLPFixButton, Warning, TEXT(" %s :: %s Normal %s -> %s | Pressed %s -> %s"),
*Blueprint->GetName(), *Button->GetName(),
*Str(OldNormal), *Str(Style.NormalPadding), *Str(OldPressed), *Str(Style.PressedPadding));
++ButtonsFixed;
++FixedHere;
if (bDryRun)
{
continue;
}
Button->Modify();
Button->SetStyle(Style);
}
if (FixedHere == 0)
{
continue;
}
if (bDryRun)
{
// Liste des paquets a sauvegarder (Snapshot) avant l'application reelle.
UE_LOG(LogLPFixButton, Warning, TEXT(" paquet %s (%d bouton(s))"), *Blueprint->GetOutermost()->GetName(), FixedHere);
continue;
}
++BlueprintsModified;
FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
FKismetEditorUtilities::CompileBlueprint(Blueprint);
UPackage* Package = Blueprint->GetOutermost();
FString Filename;
if (!FPackageName::TryConvertLongPackageNameToFilename(
Package->GetName(), Filename, FPackageName::GetAssetPackageExtension()))
{
++SaveFailures;
UE_LOG(LogLPFixButton, Error, TEXT(" chemin introuvable pour %s"), *Package->GetName());
continue;
}
ResetLoaders(Package);
FSavePackageArgs SaveArgs;
SaveArgs.TopLevelFlags = RF_Public | RF_Standalone;
SaveArgs.SaveFlags = SAVE_None;
SaveArgs.bWarnOfLongFilename = true;
// GWarn et non GError : en commandlet, GError rend toute erreur de save fatale.
SaveArgs.Error = GWarn;
if (UPackage::SavePackage(Package, nullptr, *Filename, SaveArgs))
{
UE_LOG(LogLPFixButton, Warning, TEXT(" -> %s sauvegarde (%d bouton(s))."), *Package->GetName(), FixedHere);
}
else
{
++SaveFailures;
UE_LOG(LogLPFixButton, Error, TEXT(" -> ECHEC de sauvegarde de %s"), *Package->GetName());
}
}
UE_LOG(LogLPFixButton, Warning,
TEXT("=== Termine : %d bouton(s) vu(s), %d a la marge UE5 %s, %d garde(s), %d Widget Blueprint(s) modifie(s), %d echec(s) de sauvegarde. ==="),
ButtonsSeen, ButtonsFixed, bDryRun ? TEXT("(a corriger)") : TEXT("corrige(s)"), ButtonsKept, BlueprintsModified, SaveFailures);
return SaveFailures > 0 ? 1 : 0;
}