Created
November 15, 2024 06:36
-
-
Save iDevelopThings/9f0b3b213fe4ac63de128fe499709210 to your computer and use it in GitHub Desktop.
Slates SSplitter as a UMG Widget
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
#include "UI/UMGSplitter.h" | |
#include "Widgets/SWeakWidget.h" | |
#include UE_INLINE_GENERATED_CPP_BY_NAME(UMGSplitter) | |
#pragma region "Splitter Slot" | |
UUMGSplitterSlot::UUMGSplitterSlot(const FObjectInitializer& Oi): Super(Oi) { | |
Slot = nullptr; | |
} | |
void UUMGSplitterSlot::ReleaseSlateResources(bool bReleaseChildren) { | |
Super::ReleaseSlateResources(bReleaseChildren); | |
Slot = nullptr; | |
} | |
void UUMGSplitterSlot::BuildSlot(TSharedRef<SSplitter> Splitter) { | |
Splitter->AddSlot() | |
.Expose(Slot) | |
.SizeRule(SizeRule) | |
.Value(Value) | |
.MinSize(MinSize) | |
.Resizable(Resizable) | |
.OnSlotResized_UObject(this, &UUMGSplitterSlot::OnSlotResized) | |
[ | |
Content == nullptr ? SNullWidget::NullWidget : Content->TakeWidget() | |
]; | |
} | |
void UUMGSplitterSlot::ReplaceContent(UWidget* NewContent) { | |
if (Content != NewContent) { | |
if (NewContent) { | |
NewContent->RemoveFromParent(); | |
} | |
if (UWidget* PreviousWidget = Content) { | |
// Setting Slot=null before RemoveFromParent to prevent destroying this slot | |
PreviousWidget->Slot = nullptr; | |
PreviousWidget->RemoveFromParent(); | |
} | |
Content = NewContent; | |
if (Content) { | |
Content->Slot = this; | |
} | |
if (Slot) { | |
Slot->AttachWidget(Content == nullptr ? SNullWidget::NullWidget : Content->TakeWidget()); | |
} | |
} | |
} | |
void UUMGSplitterSlot::SynchronizeProperties() { | |
Super::SynchronizeProperties(); | |
SetSizeRule(SizeRule); | |
SetValue(Value); | |
SetMinSize(MinSize); | |
SetResizable(Resizable); | |
} | |
void UUMGSplitterSlot::SetSizeRule(EUMGSplitterSizeRule InSizeRule) { | |
SizeRule = InSizeRule; | |
if (Slot) { | |
Slot->SetSizingRule(GetSlateSizeRule(SizeRule)); | |
} | |
} | |
EUMGSplitterSizeRule UUMGSplitterSlot::GetSizeRule() const { return SizeRule; } | |
void UUMGSplitterSlot::SetValue(float InValue) { | |
Value = InValue; | |
if (Slot) { | |
Slot->SetSizeValue(Value); | |
} | |
} | |
float UUMGSplitterSlot::GetValue() const { return Value; } | |
void UUMGSplitterSlot::SetMinSize(float InMinSize) { | |
MinSize = InMinSize; | |
if (Slot) { | |
Slot->SetMinSize(MinSize); | |
} | |
} | |
float UUMGSplitterSlot::GetMinSize() const { return MinSize; } | |
void UUMGSplitterSlot::SetResizable(bool bInIsResizable) { | |
Resizable = bInIsResizable; | |
if (Slot) { | |
Slot->SetResizable(Resizable); | |
} | |
} | |
bool UUMGSplitterSlot::GetResizable() const { return Resizable; } | |
void UUMGSplitterSlot::OnSlotResized(float Size) { | |
UE_LOG(LogTemp, Warning, TEXT("Slot resized: %f"), Size); | |
Value = Size; | |
if (Slot) { | |
Slot->SetSizeValue(Size); | |
} | |
if (UUMGSplitter* Splitter = Cast<UUMGSplitter>(Parent)) { | |
Splitter->OnSlotResized(this, Size); | |
} | |
} | |
#pragma endregion | |
#pragma region "Splitter" | |
UUMGSplitter::UUMGSplitter(const FObjectInitializer& OI): Super(OI) { | |
Style = FAppStyle::Get().GetWidgetStyle<FSplitterStyle>("DetailsView.Splitter"); | |
} | |
void UUMGSplitter::OnSlotResized(UUMGSplitterSlot* InSlot, float Size) { | |
OnSlotResizedEvent.Broadcast(InSlot, Size); | |
} | |
void UUMGSplitter::SynchronizeProperties() { | |
Super::SynchronizeProperties(); | |
if (Splitter.IsValid()) { | |
Splitter->SetOrientation(Orientation); | |
} | |
} | |
TSharedRef<SWidget> UUMGSplitter::RebuildWidget() { | |
Splitter = SNew(SSplitter) | |
.Style(&Style) | |
.Orientation(Orientation) | |
.ResizeMode(GetSlateResizeMode(ResizeMode)) | |
.PhysicalSplitterHandleSize(PhysicalSplitterHandleSize) | |
.HitDetectionSplitterHandleSize(HitDetectionSplitterHandleSize) | |
.MinimumSlotHeight(MinimumSlotHeight) | |
// .PhysicalSplitterHandleSize(1.0f) | |
// .HitDetectionSplitterHandleSize(5.0f); | |
; | |
for (UPanelSlot* PanelSlot : Slots) { | |
if (UUMGSplitterSlot* TypedSlot = Cast<UUMGSplitterSlot>(PanelSlot)) { | |
TypedSlot->Parent = this; | |
TypedSlot->BuildSlot(Splitter.ToSharedRef()); | |
} | |
} | |
return Splitter.ToSharedRef(); | |
} | |
void UUMGSplitter::ReleaseSlateResources(bool bReleaseChildren) { | |
Super::ReleaseSlateResources(bReleaseChildren); | |
Splitter.Reset(); | |
} | |
void UUMGSplitter::OnSlotAdded(UPanelSlot* InSlot) { | |
if (Splitter.IsValid()) { | |
CastChecked<UUMGSplitterSlot>(InSlot)->BuildSlot(Splitter.ToSharedRef()); | |
} | |
} | |
void UUMGSplitter::OnSlotRemoved(UPanelSlot* InSlot) { | |
if (Splitter.IsValid() && InSlot->Content) { | |
TSharedPtr<SWidget> Widget = InSlot->Content->GetCachedWidget(); | |
if (Widget.IsValid()) { | |
TPanelChildren<SSplitter::FSlot>* SplitterChildren = static_cast<TPanelChildren<SSplitter::FSlot>*>(Splitter->GetChildren()); | |
SplitterChildren->Remove(Widget.ToSharedRef()); | |
} | |
} | |
} | |
#pragma endregion |
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
#pragma once | |
#include "CoreMinimal.h" | |
#include "Blueprint/UserWidget.h" | |
#include "Components/PanelWidget.h" | |
#include "Widgets/Layout/SSplitter.h" | |
#include "UMGSplitter.generated.h" | |
#define LOCTEXT_NAMESPACE "FontsAndIcons" | |
UENUM(BlueprintType) | |
enum class EUMGSplitterSizeRule: uint8 | |
{ | |
/** Get the DesiredSize() of the content */ | |
SizeToContent, | |
/** Use a fraction of the parent's size */ | |
FractionOfParent | |
}; | |
inline GFONTSANDICONSEDITOR_API SSplitter::ESizeRule GetSlateSizeRule(EUMGSplitterSizeRule InSizeRule) { | |
return static_cast<SSplitter::ESizeRule>(static_cast<uint8>(InSizeRule)); | |
} | |
UENUM(BlueprintType) | |
enum class EUMGSplitterResizeMode : uint8 | |
{ | |
/** Resize the selected slot. If space is needed, then resize the next resizable slot. */ | |
FixedPosition, | |
/** Resize the selected slot. If space is needed, then resize the last resizable slot. */ | |
FixedSize, | |
/** Resize the selected slot by redistributing the available space with the following resizable slots. */ | |
Fill, | |
}; | |
inline GFONTSANDICONSEDITOR_API ESplitterResizeMode::Type GetSlateResizeMode(EUMGSplitterResizeMode InResizeMode) { | |
return static_cast<ESplitterResizeMode::Type>(static_cast<uint8>(InResizeMode)); | |
} | |
UCLASS(BlueprintType) | |
class GFONTSANDICONSEDITOR_API UUMGSplitterSlot : public UPanelSlot | |
{ | |
GENERATED_BODY() | |
protected: | |
SSplitter::FSlot* Slot; | |
/** The size rule used by the slot. */ | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, BlueprintSetter=SetSizeRule, Category="Layout|Splitter Slot") | |
EUMGSplitterSizeRule SizeRule = EUMGSplitterSizeRule::FractionOfParent; | |
/** When the RuleSize is set to FractionOfParent, the size of the slot is the Value percentage of its parent size. */ | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, BlueprintSetter=SetValue, Category="Layout|Splitter Slot") | |
float Value = 1.0f; | |
/** Minimum slot size when resizing. */ | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, BlueprintSetter=SetMinSize, Category="Layout|Splitter Slot") | |
float MinSize = 0.0f; | |
/** Can the slot be resize by the user. */ | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, BlueprintSetter=SetResizable, Category="Layout|Splitter Slot") | |
bool Resizable = true; | |
public: | |
UUMGSplitterSlot(const FObjectInitializer& Oi = FObjectInitializer::Get()); | |
protected: | |
virtual void ReleaseSlateResources(bool bReleaseChildren) override; | |
public: | |
virtual void BuildSlot(TSharedRef<SSplitter> Splitter); | |
virtual void ReplaceContent(UWidget* NewContent); | |
virtual void SynchronizeProperties() override; | |
UFUNCTION(BlueprintCallable, Category="Layout|Splitter Slot") | |
void SetSizeRule(EUMGSplitterSizeRule InSizeRule); | |
UFUNCTION(BlueprintCallable, Category="Layout|Splitter Slot") | |
EUMGSplitterSizeRule GetSizeRule() const; | |
UFUNCTION(BlueprintCallable, Category="Layout|Splitter Slot") | |
void SetValue(float InValue); | |
UFUNCTION(BlueprintCallable, Category="Layout|Splitter Slot") | |
float GetValue() const; | |
UFUNCTION(BlueprintCallable, Category="Layout|Splitter Slot") | |
void SetMinSize(float InMinSize); | |
UFUNCTION(BlueprintCallable, Category="Layout|Splitter Slot") | |
float GetMinSize() const; | |
UFUNCTION(BlueprintCallable, Category="Layout|Splitter Slot") | |
void SetResizable(bool bInIsResizable); | |
UFUNCTION(BlueprintCallable, Category="Layout|Splitter Slot") | |
bool GetResizable() const; | |
void OnSlotResized(float Size); | |
}; | |
UCLASS(ClassGroup = UI, meta = (Category = "Editor|FontsAndIcons", DisableNativeTick)) | |
class GFONTSANDICONSEDITOR_API UUMGSplitter : public UPanelWidget | |
{ | |
GENERATED_BODY() | |
public: | |
TSharedPtr<SSplitter> Splitter; | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, BlueprintSetter=SetStyle, Category="Appearance") | |
FSplitterStyle Style; | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, BlueprintSetter=SetOrientation, Category="Appearance") | |
TEnumAsByte<EOrientation> Orientation = Orient_Horizontal; | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, BlueprintSetter=SetResizeMode, Category="Appearance") | |
EUMGSplitterResizeMode ResizeMode = EUMGSplitterResizeMode::FixedPosition; | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, BlueprintSetter=SetPhysicalSplitterHandleSize, Category="Appearance") | |
float PhysicalSplitterHandleSize = 5.0f; | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, BlueprintSetter=SetHitDetectionSplitterHandleSize, Category="Appearance") | |
float HitDetectionSplitterHandleSize = 5.0f; | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, BlueprintSetter=SetMinimumSlotHeight, Category="Appearance") | |
float MinimumSlotHeight = 20.f; | |
UUMGSplitter(const FObjectInitializer& OI = FObjectInitializer::Get()); | |
#if WITH_EDITOR | |
virtual const FText GetPaletteCategory() override { | |
static const FText Category = LOCTEXT("FontsAndIcons", "Fonts And Icons"); | |
return Category; | |
} | |
#endif | |
void OnSlotResized(UUMGSplitterSlot* InSlot, float Size); | |
UUMGSplitterSlot* SlotAt(int32 SlotIndex) { | |
return Cast<UUMGSplitterSlot>(GetSlots()[SlotIndex]); | |
} | |
DECLARE_MULTICAST_DELEGATE_TwoParams(FOnSlotResized, UUMGSplitterSlot*, float); | |
FOnSlotResized OnSlotResizedEvent; | |
virtual void SynchronizeProperties() override; | |
protected: | |
virtual TSharedRef<SWidget> RebuildWidget() override; | |
virtual void ReleaseSlateResources(bool bReleaseChildren) override; | |
virtual UClass* GetSlotClass() const override { | |
return UUMGSplitterSlot::StaticClass(); | |
} | |
virtual void OnSlotAdded(UPanelSlot* InSlot) override; | |
virtual void OnSlotRemoved(UPanelSlot* InSlot) override; | |
public: | |
UFUNCTION(BlueprintCallable, Category="Appearance") | |
FSplitterStyle GetStyle() const { return Style; } | |
UFUNCTION(BlueprintCallable, Category="Appearance") | |
void SetStyle(FSplitterStyle InStyle) { | |
Style = InStyle; | |
// Slate doesn't have setter... :| | |
} | |
UFUNCTION(BlueprintCallable, Category="Appearance") | |
EOrientation GetOrientation() const { return Orientation; } | |
UFUNCTION(BlueprintCallable, Category="Appearance") | |
void SetOrientation(EOrientation InOrientation) { | |
Orientation = InOrientation; | |
if (Splitter.IsValid()) { | |
Splitter->SetOrientation(Orientation); | |
} | |
} | |
UFUNCTION(BlueprintCallable, Category="Appearance") | |
EUMGSplitterResizeMode GetResizeMode() const { return ResizeMode; } | |
UFUNCTION(BlueprintCallable, Category="Appearance") | |
void SetResizeMode(EUMGSplitterResizeMode InResizeMode) { | |
ResizeMode = InResizeMode; | |
// Slate doesn't have setter... :| | |
} | |
UFUNCTION(BlueprintCallable, Category="Appearance") | |
float GetPhysicalSplitterHandleSize() const { return PhysicalSplitterHandleSize; } | |
UFUNCTION(BlueprintCallable, Category="Appearance") | |
void SetPhysicalSplitterHandleSize(float InPhysicalSplitterHandleSize) { | |
PhysicalSplitterHandleSize = InPhysicalSplitterHandleSize; | |
// Slate doesn't have setter... :| | |
} | |
UFUNCTION(BlueprintCallable, Category="Appearance") | |
float GetHitDetectionSplitterHandleSize() const { return HitDetectionSplitterHandleSize; } | |
UFUNCTION(BlueprintCallable, Category="Appearance") | |
void SetHitDetectionSplitterHandleSize(float InHitDetectionSplitterHandleSize) { | |
HitDetectionSplitterHandleSize = InHitDetectionSplitterHandleSize; | |
// Slate doesn't have setter... :| | |
} | |
UFUNCTION(BlueprintCallable, Category="Appearance") | |
float GetMinimumSlotHeight() const { return MinimumSlotHeight; } | |
UFUNCTION(BlueprintCallable, Category="Appearance") | |
void SetMinimumSlotHeight(float InMinimumSlotHeight) { | |
MinimumSlotHeight = InMinimumSlotHeight; | |
// Slate doesn't have setter... :| | |
} | |
}; | |
#undef LOCTEXT_NAMESPACE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment