611 lines
16 KiB
C++
611 lines
16 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Widgets/SAtlasVisualizer.h"
|
|
#include "Textures/TextureAtlas.h"
|
|
#include "Widgets/Layout/SSpacer.h"
|
|
#include "Widgets/Images/SImage.h"
|
|
#include "Widgets/Input/SButton.h"
|
|
#include "Widgets/SViewport.h"
|
|
#include "Widgets/Input/SCheckBox.h"
|
|
#include "Framework/Layout/ScrollyZoomy.h"
|
|
#include "Styling/SlateStyleRegistry.h"
|
|
#include "Misc/FileHelper.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "AtlasVisualizer"
|
|
|
|
class SAtlasVisualizerPanel : public IScrollableZoomable, public SPanel
|
|
{
|
|
public:
|
|
using FAtlasVisualizerPanelSlot = FSingleWidgetChildrenWithSlot;
|
|
|
|
SLATE_BEGIN_ARGS(SAtlasVisualizerPanel)
|
|
{
|
|
_Visibility = EVisibility::Visible;
|
|
}
|
|
|
|
SLATE_DEFAULT_SLOT( FArguments, Content )
|
|
|
|
SLATE_END_ARGS()
|
|
|
|
SAtlasVisualizerPanel()
|
|
: PhysicalOffset(ForceInitToZero)
|
|
, CachedSize(ForceInitToZero)
|
|
, ZoomLevel(1.0f)
|
|
, bFitToWindow(true)
|
|
, ChildSlot(this)
|
|
, ScrollyZoomy(false)
|
|
{
|
|
}
|
|
|
|
void Construct( const FArguments& InArgs )
|
|
{
|
|
ChildSlot
|
|
[
|
|
InArgs._Content.Widget
|
|
];
|
|
}
|
|
|
|
virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const override
|
|
{
|
|
CachedSize = AllottedGeometry.GetLocalSize();
|
|
|
|
const TSharedRef<SWidget>& ChildWidget = ChildSlot.GetWidget();
|
|
if( ChildWidget->GetVisibility() != EVisibility::Collapsed )
|
|
{
|
|
const FVector2f& WidgetDesiredSize = ChildWidget->GetDesiredSize();
|
|
|
|
// Update the zoom level, and clamp the pan offset based on our current geometry
|
|
SAtlasVisualizerPanel* const NonConstThis = const_cast<SAtlasVisualizerPanel*>(this);
|
|
NonConstThis->UpdateFitToWindowZoom(WidgetDesiredSize, CachedSize);
|
|
NonConstThis->ClampViewOffset(WidgetDesiredSize, CachedSize);
|
|
|
|
ArrangedChildren.AddWidget(AllottedGeometry.MakeChild(ChildWidget, PhysicalOffset * ZoomLevel, WidgetDesiredSize * ZoomLevel));
|
|
}
|
|
}
|
|
|
|
virtual FVector2D ComputeDesiredSize(float) const override
|
|
{
|
|
FVector2D ThisDesiredSize = FVector2D::ZeroVector;
|
|
|
|
const TSharedRef<SWidget>& ChildWidget = ChildSlot.GetWidget();
|
|
if( ChildWidget->GetVisibility() != EVisibility::Collapsed )
|
|
{
|
|
ThisDesiredSize = ChildWidget->GetDesiredSize() * ZoomLevel;
|
|
}
|
|
|
|
return ThisDesiredSize;
|
|
}
|
|
|
|
virtual FChildren* GetChildren() override
|
|
{
|
|
return &ChildSlot;
|
|
}
|
|
|
|
virtual void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) override
|
|
{
|
|
ScrollyZoomy.Tick(InDeltaTime, *this);
|
|
}
|
|
|
|
virtual FReply OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override
|
|
{
|
|
return ScrollyZoomy.OnMouseButtonDown(MouseEvent);
|
|
}
|
|
|
|
virtual FReply OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override
|
|
{
|
|
return ScrollyZoomy.OnMouseButtonUp(AsShared(), MyGeometry, MouseEvent);
|
|
}
|
|
|
|
virtual FReply OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override
|
|
{
|
|
return ScrollyZoomy.OnMouseMove(AsShared(), *this, MyGeometry, MouseEvent);
|
|
}
|
|
|
|
virtual void OnMouseLeave( const FPointerEvent& MouseEvent ) override
|
|
{
|
|
ScrollyZoomy.OnMouseLeave(AsShared(), MouseEvent);
|
|
}
|
|
|
|
virtual FReply OnMouseWheel( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override
|
|
{
|
|
return ScrollyZoomy.OnMouseWheel(MouseEvent, *this);
|
|
}
|
|
|
|
virtual FCursorReply OnCursorQuery( const FGeometry& MyGeometry, const FPointerEvent& CursorEvent ) const override
|
|
{
|
|
return ScrollyZoomy.OnCursorQuery();
|
|
}
|
|
|
|
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override
|
|
{
|
|
LayerId = SPanel::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
|
|
LayerId = ScrollyZoomy.PaintSoftwareCursorIfNeeded(AllottedGeometry, MyCullingRect, OutDrawElements, LayerId);
|
|
return LayerId;
|
|
}
|
|
|
|
virtual bool ScrollBy( const FVector2D& Offset ) override
|
|
{
|
|
if( bFitToWindow )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const FVector2f PrevPhysicalOffset = PhysicalOffset;
|
|
const float InverseZoom = 1.0f / ZoomLevel;
|
|
PhysicalOffset += (UE::Slate::CastToVector2f(Offset) * InverseZoom);
|
|
|
|
const TSharedRef<SWidget>& ChildWidget = ChildSlot.GetWidget();
|
|
const FVector2f& WidgetDesiredSize = ChildWidget->GetDesiredSize();
|
|
ClampViewOffset(WidgetDesiredSize, CachedSize);
|
|
|
|
return PhysicalOffset != PrevPhysicalOffset;
|
|
}
|
|
|
|
virtual bool ZoomBy( const float Amount ) override
|
|
{
|
|
static const float MinZoomLevel = 0.2f;
|
|
static const float MaxZoomLevel = 4.0f;
|
|
|
|
bFitToWindow = false;
|
|
|
|
const float PrevZoomLevel = ZoomLevel;
|
|
ZoomLevel = FMath::Clamp(ZoomLevel + (Amount * 0.05f), MinZoomLevel, MaxZoomLevel);
|
|
return ZoomLevel != PrevZoomLevel;
|
|
}
|
|
|
|
float GetZoomLevel() const
|
|
{
|
|
return ZoomLevel;
|
|
}
|
|
|
|
void FitToWindow()
|
|
{
|
|
bFitToWindow = true;
|
|
PhysicalOffset = FVector2f::ZeroVector;
|
|
}
|
|
|
|
bool IsFitToWindow() const
|
|
{
|
|
return bFitToWindow;
|
|
}
|
|
|
|
void FitToSize()
|
|
{
|
|
bFitToWindow = false;
|
|
ZoomLevel = 1.0f;
|
|
PhysicalOffset = FVector2f::ZeroVector;
|
|
}
|
|
|
|
private:
|
|
void UpdateFitToWindowZoom( const FVector2f& ViewportSize, const FVector2f& LocalSize )
|
|
{
|
|
if( bFitToWindow )
|
|
{
|
|
const float ZoomHoriz = LocalSize.X / ViewportSize.X;
|
|
const float ZoomVert = LocalSize.Y / ViewportSize.Y;
|
|
ZoomLevel = FMath::Min(ZoomHoriz, ZoomVert);
|
|
}
|
|
}
|
|
|
|
void ClampViewOffset( const FVector2f& ViewportSize, const FVector2f& LocalSize )
|
|
{
|
|
PhysicalOffset.X = ClampViewOffsetAxis(ViewportSize.X, LocalSize.X, PhysicalOffset.X);
|
|
PhysicalOffset.Y = ClampViewOffsetAxis(ViewportSize.Y, LocalSize.Y, PhysicalOffset.Y);
|
|
}
|
|
|
|
float ClampViewOffsetAxis( const float ViewportSize, const float LocalSize, const float CurrentOffset )
|
|
{
|
|
const float ZoomedViewportSize = ViewportSize * ZoomLevel;
|
|
|
|
if( ZoomedViewportSize <= LocalSize )
|
|
{
|
|
// If the viewport is smaller than the available size, then we can't be scrolled
|
|
return 0.0f;
|
|
}
|
|
|
|
// Given the size of the viewport, and the current size of the window, work how far we can scroll
|
|
// Note: This number is negative since scrolling down/right moves the viewport up/left
|
|
const float MaxScrollOffset = (LocalSize - ZoomedViewportSize) / ZoomLevel;
|
|
|
|
// Clamp the left/top edge
|
|
if( CurrentOffset < MaxScrollOffset )
|
|
{
|
|
return MaxScrollOffset;
|
|
}
|
|
|
|
// Clamp the right/bottom edge
|
|
if( CurrentOffset > 0.0f )
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
return CurrentOffset;
|
|
}
|
|
|
|
FVector2f PhysicalOffset;
|
|
mutable FVector2f CachedSize;
|
|
float ZoomLevel;
|
|
bool bFitToWindow;
|
|
|
|
FAtlasVisualizerPanelSlot ChildSlot;
|
|
FScrollyZoomy ScrollyZoomy;
|
|
};
|
|
|
|
void SAtlasVisualizer::Construct( const FArguments& InArgs )
|
|
{
|
|
AtlasProvider = InArgs._AtlasProvider;
|
|
check(AtlasProvider);
|
|
|
|
SelectedAtlasPage = 0;
|
|
bDisplayCheckerboard = false;
|
|
|
|
HoveredSlotBorderBrush = FCoreStyle::Get().GetBrush("Debug.Border");
|
|
|
|
TSharedPtr<SViewport> Viewport;
|
|
ChildSlot
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage(FCoreStyle::Get().GetBrush("ToolPanel.GroupBorder"))
|
|
[
|
|
SNew( SVerticalBox )
|
|
+ SVerticalBox::Slot()
|
|
.Padding(4.0f)
|
|
.AutoHeight()
|
|
[
|
|
SNew( SHorizontalBox )
|
|
+ SHorizontalBox::Slot()
|
|
.VAlign( VAlign_Center )
|
|
.AutoWidth()
|
|
.Padding(0.0,2.0f,2.0f,2.0f)
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( LOCTEXT("SelectAPage", "Select a page") )
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(2.0f)
|
|
.VAlign( VAlign_Center )
|
|
[
|
|
SAssignNew( AtlasPageCombo, SComboBox< TSharedPtr<int32> > )
|
|
.OptionsSource( &AtlasPages )
|
|
.OnComboBoxOpening(this, &SAtlasVisualizer::OnComboOpening)
|
|
.OnGenerateWidget( this, &SAtlasVisualizer::OnGenerateWidgetForCombo )
|
|
.OnSelectionChanged( this, &SAtlasVisualizer::OnAtlasPageChanged )
|
|
.Content()
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( this, &SAtlasVisualizer::OnGetSelectedItemText )
|
|
]
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.VAlign( VAlign_Center )
|
|
.AutoWidth()
|
|
.Padding(0.0,2.0f,2.0f,2.0f)
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( this, &SAtlasVisualizer::GetViewportSizeText )
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(20.0f,2.0f)
|
|
.AutoWidth()
|
|
.VAlign( VAlign_Center )
|
|
[
|
|
SNew( SCheckBox )
|
|
.Visibility( this, &SAtlasVisualizer::OnGetDisplayCheckerboardVisibility )
|
|
.OnCheckStateChanged( this, &SAtlasVisualizer::OnDisplayCheckerboardStateChanged )
|
|
.IsChecked( this, &SAtlasVisualizer::OnGetCheckerboardState )
|
|
.Content()
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( LOCTEXT("DisplayCheckerboardCheckboxLabel", "Display Checkerboard") )
|
|
]
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(2.0f)
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( this, &SAtlasVisualizer::GetZoomLevelPercentText )
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(2.0f)
|
|
.AutoWidth()
|
|
.VAlign( VAlign_Center )
|
|
[
|
|
SNew( SCheckBox )
|
|
.OnCheckStateChanged( this, &SAtlasVisualizer::OnFitToWindowStateChanged )
|
|
.IsChecked( this, &SAtlasVisualizer::OnGetFitToWindowState )
|
|
.Content()
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( LOCTEXT("FitToWindow", "Fit to Window") )
|
|
]
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(2.0f)
|
|
.AutoWidth()
|
|
.VAlign( VAlign_Center )
|
|
[
|
|
SNew( SButton )
|
|
.Text( LOCTEXT("ActualSize", "Actual Size") )
|
|
.OnClicked( this, &SAtlasVisualizer::OnActualSizeClicked )
|
|
]
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.Padding(2.0f)
|
|
[
|
|
SAssignNew( ScrollPanel, SAtlasVisualizerPanel )
|
|
[
|
|
SNew( SOverlay )
|
|
+ SOverlay::Slot()
|
|
[
|
|
SNew( SImage )
|
|
.Visibility( this, &SAtlasVisualizer::OnGetCheckerboardVisibility )
|
|
.Image( FCoreStyle::Get().GetBrush("Checkerboard") )
|
|
]
|
|
+ SOverlay::Slot()
|
|
[
|
|
SAssignNew( Viewport, SViewport )
|
|
.ViewportSize(this, &SAtlasVisualizer::GetViewportWidgetSize)
|
|
.IgnoreTextureAlpha(false)
|
|
.EnableBlending(true)
|
|
.PreMultipliedAlpha(false)
|
|
]
|
|
]
|
|
]
|
|
]
|
|
];
|
|
|
|
Viewport->SetViewportInterface(SharedThis(this));
|
|
}
|
|
|
|
void SAtlasVisualizer::OnDrawViewport(const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, class FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled)
|
|
{
|
|
if (CurrentHoveredSlotInfo.AtlasSlotRect.IsValid())
|
|
{
|
|
FSlateRect CurrentSlotRect = CurrentHoveredSlotInfo.AtlasSlotRect;
|
|
|
|
FSlateDrawElement::MakeBox(
|
|
OutDrawElements,
|
|
LayerId+1,
|
|
AllottedGeometry.ToPaintGeometry((CurrentSlotRect.GetSize() * ScrollPanel->GetZoomLevel())+FVector2D(1, 1), FSlateLayoutTransform(FVector2D::Max((CurrentSlotRect.GetTopLeft()*ScrollPanel->GetZoomLevel())-FVector2D(1,1), FVector2D::ZeroVector))),
|
|
HoveredSlotBorderBrush,
|
|
ESlateDrawEffect::None,
|
|
FLinearColor::Yellow
|
|
);
|
|
}
|
|
}
|
|
|
|
FText SAtlasVisualizer::GetToolTipText() const
|
|
{
|
|
return HoveredAtlasSlotToolTip;
|
|
}
|
|
|
|
FIntPoint SAtlasVisualizer::GetSize() const
|
|
{
|
|
if (FSlateShaderResource* TargetTexture = GetViewportRenderTargetTexture())
|
|
{
|
|
return FIntPoint(TargetTexture->GetWidth(), TargetTexture->GetHeight());
|
|
}
|
|
|
|
return FIntPoint(0, 0);
|
|
}
|
|
|
|
bool SAtlasVisualizer::RequiresVsync() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
FSlateShaderResource* SAtlasVisualizer::GetViewportRenderTargetTexture() const
|
|
{
|
|
if( SelectedAtlasPage < AtlasProvider->GetNumAtlasPages() )
|
|
{
|
|
return AtlasProvider->GetAtlasPageResource(SelectedAtlasPage);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool SAtlasVisualizer::IsViewportTextureAlphaOnly() const
|
|
{
|
|
if (SelectedAtlasPage < AtlasProvider->GetNumAtlasPages())
|
|
{
|
|
return AtlasProvider->IsAtlasPageResourceAlphaOnly(SelectedAtlasPage);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void SAtlasVisualizer::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
|
{
|
|
CurrentHoveredSlotInfo = FAtlasSlotInfo();
|
|
}
|
|
|
|
void SAtlasVisualizer::OnMouseLeave(const FPointerEvent& MouseEvent)
|
|
{
|
|
CurrentHoveredSlotInfo = FAtlasSlotInfo();
|
|
}
|
|
|
|
FReply SAtlasVisualizer::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
|
{
|
|
#if WITH_ATLAS_DEBUGGING
|
|
if (!MouseEvent.GetCursorDelta().IsNearlyZero() && !HasMouseCapture() && !MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton))
|
|
{
|
|
FVector2D LocalPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()) / ScrollPanel->GetZoomLevel();
|
|
|
|
FAtlasSlotInfo PrevSlotInfo = CurrentHoveredSlotInfo;
|
|
|
|
CurrentHoveredSlotInfo = AtlasProvider->GetAtlasSlotInfoAtPosition(LocalPos.IntPoint(), SelectedAtlasPage);
|
|
|
|
if (CurrentHoveredSlotInfo != PrevSlotInfo)
|
|
{
|
|
RebuildToolTip(CurrentHoveredSlotInfo);
|
|
}
|
|
|
|
return FReply::Handled();
|
|
}
|
|
#endif
|
|
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
void SAtlasVisualizer::RebuildToolTip(const FAtlasSlotInfo& Info)
|
|
{
|
|
if(Info.TextureName != NAME_None)
|
|
{
|
|
FTextBuilder Builder;
|
|
Builder.AppendLine(FText::FromName(Info.TextureName));
|
|
|
|
TArray<FName> Resources = FSlateStyleRegistry::GetSylesUsingBrush(Info.TextureName);
|
|
|
|
if (!Resources.IsEmpty())
|
|
{
|
|
Builder.AppendLine(LOCTEXT("AtlasDebuggingToolTipTitle", "\nUsed by:"));
|
|
for (FName Name : Resources)
|
|
{
|
|
Builder.AppendLine(Name);
|
|
}
|
|
}
|
|
|
|
SetToolTipText(Builder.ToText());
|
|
}
|
|
else
|
|
{
|
|
SetToolTipText(FText::GetEmpty());
|
|
}
|
|
}
|
|
|
|
FText SAtlasVisualizer::GetViewportSizeText() const
|
|
{
|
|
const FIntPoint ViewportSize = GetSize();
|
|
return FText::Format(LOCTEXT("PageSizeXY", "({0} x {1})"), ViewportSize.X, ViewportSize.Y);
|
|
}
|
|
|
|
FVector2D SAtlasVisualizer::GetViewportWidgetSize() const
|
|
{
|
|
const FIntPoint ViewportSize = GetSize();
|
|
return FVector2D((float)ViewportSize.X, (float)ViewportSize.Y);
|
|
}
|
|
|
|
FText SAtlasVisualizer::GetZoomLevelPercentText() const
|
|
{
|
|
if( ScrollPanel.IsValid() )
|
|
{
|
|
return FText::Format( LOCTEXT("ZoomLevelPercent", "Zoom Level: {0}"), FText::AsPercent(ScrollPanel->GetZoomLevel()) );
|
|
}
|
|
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
void SAtlasVisualizer::OnFitToWindowStateChanged( ECheckBoxState NewState )
|
|
{
|
|
if( ScrollPanel.IsValid() )
|
|
{
|
|
if( NewState == ECheckBoxState::Checked )
|
|
{
|
|
ScrollPanel->FitToWindow();
|
|
}
|
|
else
|
|
{
|
|
ScrollPanel->FitToSize();
|
|
}
|
|
}
|
|
}
|
|
|
|
ECheckBoxState SAtlasVisualizer::OnGetFitToWindowState() const
|
|
{
|
|
if( ScrollPanel.IsValid() )
|
|
{
|
|
return (ScrollPanel->IsFitToWindow()) ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
|
|
return ECheckBoxState::Undetermined;
|
|
}
|
|
|
|
FReply SAtlasVisualizer::OnActualSizeClicked()
|
|
{
|
|
if( ScrollPanel.IsValid() )
|
|
{
|
|
ScrollPanel->FitToSize();
|
|
}
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
EVisibility SAtlasVisualizer::OnGetDisplayCheckerboardVisibility() const
|
|
{
|
|
return IsViewportTextureAlphaOnly() ? EVisibility::Collapsed : EVisibility::Visible;
|
|
}
|
|
|
|
void SAtlasVisualizer::OnDisplayCheckerboardStateChanged( ECheckBoxState NewState )
|
|
{
|
|
bDisplayCheckerboard = NewState == ECheckBoxState::Checked;
|
|
}
|
|
|
|
ECheckBoxState SAtlasVisualizer::OnGetCheckerboardState() const
|
|
{
|
|
return bDisplayCheckerboard ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
|
|
EVisibility SAtlasVisualizer::OnGetCheckerboardVisibility() const
|
|
{
|
|
return bDisplayCheckerboard && !IsViewportTextureAlphaOnly() ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
void SAtlasVisualizer::OnComboOpening()
|
|
{
|
|
const int32 NumAtlasPages = AtlasProvider->GetNumAtlasPages();
|
|
|
|
AtlasPages.Empty();
|
|
for( int32 AtlasIndex = 0; AtlasIndex < NumAtlasPages; ++AtlasIndex )
|
|
{
|
|
AtlasPages.Add( MakeShareable( new int32( AtlasIndex ) ) );
|
|
}
|
|
|
|
TSharedPtr<int32> SelectedComboEntry;
|
|
if( SelectedAtlasPage < NumAtlasPages )
|
|
{
|
|
SelectedComboEntry = AtlasPages[SelectedAtlasPage];
|
|
}
|
|
else if( AtlasPages.Num() > 0 )
|
|
{
|
|
SelectedAtlasPage = 0;
|
|
SelectedComboEntry = AtlasPages[0];
|
|
}
|
|
|
|
AtlasPageCombo->ClearSelection();
|
|
AtlasPageCombo->RefreshOptions();
|
|
AtlasPageCombo->SetSelectedItem(SelectedComboEntry);
|
|
}
|
|
|
|
FText SAtlasVisualizer::OnGetSelectedItemText() const
|
|
{
|
|
if( SelectedAtlasPage < AtlasProvider->GetNumAtlasPages() )
|
|
{
|
|
return FText::Format( LOCTEXT("PageX", "Page {0}"), FText::AsNumber(SelectedAtlasPage) );
|
|
}
|
|
|
|
return LOCTEXT("SelectAPage", "Select a page");
|
|
}
|
|
|
|
void SAtlasVisualizer::OnAtlasPageChanged( TSharedPtr<int32> AtlasPage, ESelectInfo::Type SelectionType )
|
|
{
|
|
if( AtlasPage.IsValid() )
|
|
{
|
|
SelectedAtlasPage = *AtlasPage;
|
|
}
|
|
}
|
|
|
|
TSharedRef<SWidget> SAtlasVisualizer::OnGenerateWidgetForCombo( TSharedPtr<int32> AtlasPage )
|
|
{
|
|
return
|
|
SNew( STextBlock )
|
|
.Text( FText::Format( LOCTEXT("PageX", "Page {0}"), FText::AsNumber(*AtlasPage) ) );
|
|
}
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|