// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreTypes.h" #include "Widgets/Layout/SBox.h" #include "Widgets/SNullWidget.h" #include "Widgets/SWidget.h" namespace UE::Editor::ContentBrowser::Private { /** Takes a single widget and two or more containing widgets (SBox) to switch between, depending on a custom condition. */ class FWidgetParentSwitcher { public: virtual ~FWidgetParentSwitcher() = default; FWidgetParentSwitcher( const TSharedPtr& InSubjectWidget, const TArray>& InParentWidgets) : SubjectWidget(InSubjectWidget) , ParentWidgets(InParentWidgets) { } /** Call to check and switch the widget's parent. Return true if switched. */ [[maybe_unused]] bool Update() { const int32 TargetParentIdx = GetParentIndex(); if (CurrentSubjectWidgetParentIdx == TargetParentIdx) { return false; } check(ParentWidgets.IsValidIndex(CurrentSubjectWidgetParentIdx)); check(ParentWidgets.IsValidIndex(TargetParentIdx)); ParentWidgets[CurrentSubjectWidgetParentIdx]->SetContent(SNullWidget::NullWidget); ParentWidgets[TargetParentIdx]->SetContent(SubjectWidget.ToSharedRef()); CurrentSubjectWidgetParentIdx = TargetParentIdx; return true; } TSharedPtr GetParentWidget() const { check(ParentWidgets.IsValidIndex(CurrentSubjectWidgetParentIdx)); return ParentWidgets[CurrentSubjectWidgetParentIdx]; } protected: virtual int32 GetParentIndex() const = 0; protected: TSharedPtr SubjectWidget; int32 CurrentSubjectWidgetParentIdx = 0; TArray> ParentWidgets; }; /** Switches parent widgets based on widget size */ template class TWidgetSizeParentSwitcher : public FWidgetParentSwitcher { public: virtual ~TWidgetSizeParentSwitcher() override = default; TWidgetSizeParentSwitcher( const TSharedPtr& InSubjectWidget, const TArray>& InParentWidgets, const TArray& InSwitchSizeRanges, TUniqueFunction&& InSizeGetter) : FWidgetParentSwitcher(InSubjectWidget, InParentWidgets) , SwitchSizeRanges(InSwitchSizeRanges) , SizeGetter(MoveTemp(InSizeGetter)) { check(SwitchSizeRanges.Num() == ParentWidgets.Num()); } protected: virtual int32 GetParentIndex() const override { const float CurrentSize = SizeGetter(); int32 TargetIdx = CurrentSubjectWidgetParentIdx; // Returns -1 if less, 0 if in range, 1 if greater auto InRange = [&](const int32 Idx, const int32 Value) { const FInt16Range& Range = SwitchSizeRanges[Idx]; if (Value <= Range.GetLowerBoundValue()) { return -1; } if (Value > Range.GetUpperBoundValue()) { return 1; } return 0; }; // Starting from the existing widget, check each size range for the matching parent int32 NumIterations = 0; while (NumIterations < SwitchSizeRanges.Num()) { const int32 InRangeResult = InRange(TargetIdx, FMath::FloorToInt(CurrentSize - UE_KINDA_SMALL_NUMBER)); if (InRangeResult <= 0) { // Effectively clamp to first widget if (TargetIdx == 0 || InRangeResult == 0) { return TargetIdx; } // Otherwise offset TargetIdx TargetIdx -= 1; } else { // Effectively clamp to last widget if (TargetIdx == SwitchSizeRanges.Num() - 1) { return TargetIdx; } // Otherwise offset TargetIdx TargetIdx += 1; } ++NumIterations; } checkNoEntry(); return INDEX_NONE; } private: TArray SwitchSizeRanges; TUniqueFunction SizeGetter; }; }