Skip to content

Instantly share code, notes, and snippets.

@cgerchenhp
Created September 19, 2022 15:29
Show Gist options
  • Save cgerchenhp/60fe6b83b46371fee308f4df1ecf4328 to your computer and use it in GitHub Desktop.
Save cgerchenhp/60fe6b83b46371fee308f4df1ecf4328 to your computer and use it in GitHub Desktop.
Apply color to nested array property rows. BlueprintCallable / Python Version
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;
}
...
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