Created
September 19, 2022 15:29
-
-
Save cgerchenhp/60fe6b83b46371fee308f4df1ecf4328 to your computer and use it in GitHub Desktop.
Apply color to nested array property rows. BlueprintCallable / Python Version
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void RecursivelyFindChildrenWidgetsOfType(TSharedPtr<SWidget> Widget, FString WidgetType, TArray<TSharedPtr<SWidget>>& OutFindedChildrenWidgets) | |
{ | |
if (!Widget.IsValid()) | |
{ | |
return; | |
} | |
FChildren* Children = Widget->GetChildren(); | |
if (Children) | |
{ | |
for (int32 i = 0; i < Children->Num(); i++) | |
{ | |
TSharedPtr<SWidget> Child = Children->GetChildAt(i); | |
if (Child.IsValid()) | |
{ | |
if (Child->GetTypeAsString().Equals(WidgetType)) | |
{ | |
OutFindedChildrenWidgets.AddUnique(Child); | |
} | |
RecursivelyFindChildrenWidgetsOfType(Child, WidgetType, OutFindedChildrenWidgets); | |
} | |
} | |
} | |
} | |
int32 GetGenBySize(TSharedPtr<SWidget> Widget) | |
{ | |
FVector2D Size = Widget->GetDesiredSize(); | |
return FMath::RoundToInt(Size.X/16); | |
} | |
void USomeBPLib::ApplyRainbowColor(float ColorMultiplier /*default = 1*/) | |
{ | |
// The code below is a quick and **dirty** snippet, for demonstrating how to find private widgets and apply colors by the nested struct's indent | |
// without change engine code. | |
// Call this function from BP or python, will apply the rainbow colors to current Details Window | |
// Only the generated row's color will be changed, once the DetailRow regenerated(Expand/Collapse), the color will dispared. So we need cache the widgets, and apply color when the Widget changed. | |
// call as py: unreal.SomeBPLib.apply_rainbow_color() | |
// The elegant and better way is change the Engine code, or implement a custom details panel | |
TSharedPtr<SWidget> DetailsView; | |
// 1. find the main window | |
TSharedPtr<SWindow> MainWindow = GetMainWindow(); | |
if (MainWindow == nullptr) | |
{ | |
UE_LOG(PythonTA, Log, TEXT("Can't find Main Window")); | |
return; | |
} | |
// 2. find the detail window | |
TArray<TSharedPtr<SWidget>> SActorDetailsWidgets; | |
RecursivelyFindChildrenWidgetsOfType(MainWindow, "SActorDetails", SActorDetailsWidgets); | |
TSharedPtr<SWidget> ActorDetail; | |
TArray<TSharedPtr<SWidget>> SDetailsViewWidgets; | |
if (SActorDetailsWidgets.Num() > 0) | |
{ | |
ActorDetail = SActorDetailsWidgets[0]; // assume only one actor Detail in window | |
RecursivelyFindChildrenWidgetsOfType(ActorDetail, "SDetailsView", SDetailsViewWidgets); | |
if (SDetailsViewWidgets.Num() > 0) { | |
UE_LOG(PythonTA, Log, TEXT("Found SDetailsView")); | |
DetailsView = SDetailsViewWidgets[0]; | |
} | |
} | |
TArray<FLinearColor> RainbowColors{ FLinearColor::Red, FLinearColor(1, 0.5, 0) | |
, FLinearColor::Yellow , FLinearColor::Green | |
, FLinearColor(0, 0.5, 1), FLinearColor(0.3, 0.3, 1) /*avoid too dark blue*/ | |
, FLinearColor(1, 0, 1) }; | |
if (DetailsView.IsValid()) | |
{ | |
FString WidgetTypeName = DetailsView->GetType().ToString(); | |
// 3. find the Row Indent | |
TArray<TSharedPtr<SWidget>> OutFindedChildrenWidgets; | |
RecursivelyFindChildrenWidgetsOfType(DetailsView, "SDetailRowIndent", OutFindedChildrenWidgets); | |
for (auto W : OutFindedChildrenWidgets) | |
{ | |
TSharedPtr<SCompoundWidget> AsTypeWidget = StaticCastSharedPtr<SCompoundWidget>(W); | |
// 4. Get the Row of the RowIndent, and apply colors | |
TSharedPtr<SWidget> Row = GetParentByType(W, "SDetailSingleItemRow"); | |
if (Row == nullptr) | |
continue; | |
int32 Gen = GetGenBySize(W); | |
if (Row != nullptr) { | |
if (ColorMultiplier == 0) { | |
StaticCastSharedPtr<SCompoundWidget>(Row)->SetColorAndOpacity(FLinearColor::White); | |
} | |
else { | |
if (Gen % 8 != 0) | |
StaticCastSharedPtr<SCompoundWidget>(Row)->SetColorAndOpacity(RainbowColors[Gen % 8 - 1] * ColorMultiplier); | |
} | |
} | |
} | |
} | |
} | |
TSharedPtr<SWindow> USomeBPLib::GetMainWindow() | |
{ | |
TSharedPtr<SWindow> MainWindow = nullptr; | |
TArray<TSharedRef<SWindow>> Windows = FSlateApplication::Get().GetTopLevelWindows(); | |
int32 MatchedCount = 0; | |
for (auto Window : Windows) | |
{ | |
UE_LOG(PythonTA, Log, TEXT("Window: %s"), *Window->GetTitle().ToString()); | |
FString Title = Window->GetTitle().ToString(); | |
if (Title.Find(TEXT(" - Unreal Editor")) != -1) // there should be a better way of get the main window. | |
{ | |
MainWindow = Window; | |
MatchedCount += 1; | |
} | |
} | |
if (MatchedCount > 1) | |
{ | |
UE_LOG(PythonTA, Error, TEXT("Multi Main-Window was founded. %d"), MatchedCount); | |
} | |
return MainWindow; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
UCLASS() | |
class USomeBPLib : public UBlueprintFunctionLibrary | |
{ | |
GENERATED_BODY() | |
UFUNCTION(BlueprintCallable, meta = (Keywords = "Python Editor"), Category = "PythonEditor") | |
static void ApplyRainbowColor(float ColorMultiplier=1); | |
static TSharedPtr<SWindow> GetMainWindow(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment