bmh/FlightSimulation/Plugins/CesiumForUnreal_5.4/Source/CesiumRuntime/Private/ScreenCreditsWidget.cpp
2025-02-07 22:52:32 +08:00

283 lines
8.4 KiB
C++

// Copyright 2020-2024 CesiumGS, Inc. and Contributors
#include "ScreenCreditsWidget.h"
#include "Components/BackgroundBlur.h"
#include "Components/RichTextBlock.h"
#include "Engine/Font.h"
#include "Engine/Texture2D.h"
#include "Framework/Application/SlateApplication.h"
#include "HttpModule.h"
#include "ImageUtils.h"
#include "Interfaces/IHttpResponse.h"
#include "Math/UnrealMathUtility.h"
#include "Misc/Base64.h"
#include "Rendering/DrawElements.h"
#include "Runtime/Launch/Resources/Version.h"
#include "Slate/SlateGameResources.h"
#include "UObject/ConstructorHelpers.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/Images/SImage.h"
#include "Widgets/Input/SRichTextHyperlink.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/SCompoundWidget.h"
#include <string>
#include <vector>
class SCreditImage : public SCompoundWidget {
public:
SLATE_BEGIN_ARGS(SCreditImage) {}
SLATE_END_ARGS()
public:
void Construct(const FArguments& InArgs, const FSlateBrush* Brush) {
if (ensure(Brush)) {
ChildSlot[SNew(SBox).VAlign(VAlign_Center)[SNew(SImage).Image(Brush)]];
}
}
};
class SCreditHyperlinkImage : public SCompoundWidget {
public:
SLATE_BEGIN_ARGS(SCreditImage) {}
SLATE_END_ARGS()
public:
void Construct(
const FArguments& InArgs,
const FSlateBrush* Brush,
const FString& Url) {
if (ensure(Brush)) {
ButtonStyle.SetNormal(*Brush);
ButtonStyle.SetHovered(*Brush);
ButtonStyle.SetPressed(*Brush);
ChildSlot
[SNew(SButton).ButtonStyle(&ButtonStyle).OnClicked_Lambda([Url]() {
FPlatformProcess::LaunchURL(*Url, NULL, NULL);
return FReply::Handled();
})];
this->SetCursor(EMouseCursor::Hand);
}
}
private:
FButtonStyle ButtonStyle;
};
class SCreditHyperlink : public SCompoundWidget {
public:
SLATE_BEGIN_ARGS(SCreditImage) {}
SLATE_END_ARGS()
public:
void Construct(
const FArguments& InArgs,
const FString& Text,
const FString& Url,
const UCreditsDecorator* InDecorator) {
TSharedPtr<FSlateHyperlinkRun::FWidgetViewModel> model =
MakeShareable(new FSlateHyperlinkRun::FWidgetViewModel);
ChildSlot[SNew(SRichTextHyperlink, model.ToSharedRef())
.Text(FText::FromString(Text))
.OnNavigate_Lambda([Url, InDecorator]() {
if (Url.Equals("popup")) {
InDecorator->PopupClicked.Execute();
} else {
FPlatformProcess::LaunchURL(*Url, NULL, NULL);
}
})];
}
};
class FScreenCreditsDecorator : public FRichTextDecorator {
public:
FScreenCreditsDecorator(
URichTextBlock* InOwner,
UCreditsDecorator* InDecorator)
: FRichTextDecorator(InOwner), Decorator(InDecorator) {}
virtual bool Supports(
const FTextRunParseResults& RunParseResult,
const FString& Text) const override {
if (RunParseResult.Name == TEXT("credits") &&
(RunParseResult.MetaData.Contains(TEXT("id")) ||
RunParseResult.MetaData.Contains(TEXT("url")))) {
return true;
}
return false;
}
protected:
virtual TSharedPtr<SWidget> CreateDecoratorWidget(
const FTextRunInfo& RunInfo,
const FTextBlockStyle&) const override {
FString Text;
FString Url;
const FSlateBrush* Brush = nullptr;
if (RunInfo.MetaData.Contains(TEXT("url"))) {
Url = *RunInfo.MetaData[TEXT("url")];
}
if (RunInfo.MetaData.Contains(TEXT("text"))) {
Text = *RunInfo.MetaData[TEXT("text")];
}
if (RunInfo.MetaData.Contains(TEXT("id"))) {
int32 id = FCString::Atoi(*RunInfo.MetaData[TEXT("id")]);
Brush = Decorator->FindImageBrush(id);
}
if (Brush) {
if (Url.IsEmpty()) {
return SNew(SCreditImage, Brush);
} else {
return SNew(SCreditHyperlinkImage, Brush, Url);
}
} else
return SNew(SCreditHyperlink, Text, Url, Decorator);
}
private:
UCreditsDecorator* Decorator;
};
UCreditsDecorator::UCreditsDecorator(
const FObjectInitializer& ObjectInitializer)
: URichTextBlockDecorator(ObjectInitializer) {}
TSharedPtr<ITextDecorator>
UCreditsDecorator::CreateDecorator(URichTextBlock* InOwner) {
return MakeShareable(new FScreenCreditsDecorator(InOwner, this));
}
const FSlateBrush* UCreditsDecorator::FindImageBrush(int32 id) {
if (CreditsWidget->_creditImages.Num() > id) {
return CreditsWidget->_creditImages[id];
}
return nullptr;
}
UScreenCreditsWidget::UScreenCreditsWidget(
const FObjectInitializer& ObjectInitializer)
: UUserWidget(ObjectInitializer) {
static ConstructorHelpers::FObjectFinder<UFont> RobotoFontObj(
*UWidget::GetDefaultFontName());
_font = FSlateFontInfo(RobotoFontObj.Object, 8);
}
UScreenCreditsWidget::~UScreenCreditsWidget() {
for (int i = 0; i < _creditImages.Num(); i++) {
if (_creditImages[i]) {
delete _creditImages[i];
}
}
}
void UScreenCreditsWidget::OnPopupClicked() {
_showPopup = !_showPopup;
BackgroundBlur->SetVisibility(
_showPopup ? ESlateVisibility::Visible : ESlateVisibility::Hidden);
}
void UScreenCreditsWidget::NativeConstruct() {
Super::NativeConstruct();
if (RichTextOnScreen) {
RichTextOnScreen->SetDefaultFont(_font);
RichTextOnScreen->SetDefaultColorAndOpacity(
FSlateColor(FLinearColor(1.f, 1.f, 1.f, 1.f)));
_decoratorOnScreen =
static_cast<UCreditsDecorator*>(RichTextOnScreen->GetDecoratorByClass(
UCreditsDecorator::StaticClass()));
_decoratorOnScreen->PopupClicked.BindUObject(
this,
&UScreenCreditsWidget::OnPopupClicked);
_decoratorOnScreen->CreditsWidget = this;
}
if (RichTextPopup) {
RichTextPopup->SetDefaultFont(_font);
RichTextPopup->SetDefaultColorAndOpacity(
FSlateColor(FLinearColor(1.f, 1.f, 1.f, 1.f)));
_decoratorPopup = static_cast<UCreditsDecorator*>(
RichTextPopup->GetDecoratorByClass(UCreditsDecorator::StaticClass()));
_decoratorPopup->CreditsWidget = this;
}
}
void UScreenCreditsWidget::HandleImageRequest(
FHttpRequestPtr HttpRequest,
FHttpResponsePtr HttpResponse,
bool bSucceeded,
int32 id) {
UTexture2D* texture = nullptr;
if (bSucceeded && HttpResponse.IsValid() &&
HttpResponse->GetContentLength() > 0 &&
(texture = FImageUtils::ImportBufferAsTexture2D(
HttpResponse->GetContent())) != nullptr) {
texture->SRGB = true;
texture->UpdateResource();
_textures.Add(texture);
FTexturePlatformData* pPlatformData = texture->GetPlatformData();
int32 SizeX = pPlatformData->SizeX;
int32 SizeY = pPlatformData->SizeY;
_creditImages[id] = new FSlateImageBrush(texture, FVector2D(SizeX, SizeY));
}
// Only update credits after all of the images are done loading.
--_numImagesLoading;
if (_numImagesLoading == 0) {
SetCredits(_credits, _onScreenCredits);
}
}
std::string UScreenCreditsWidget::LoadImage(const std::string& url) {
const std::string base64Prefix = "data:image/png;base64,";
if (url.rfind(base64Prefix, 0) == 0) {
TArray<uint8> dataBuffer;
FString base64 = UTF8_TO_TCHAR(url.c_str() + base64Prefix.length());
if (FBase64::Decode(base64, dataBuffer)) {
UTexture2D* texture = FImageUtils::ImportBufferAsTexture2D(dataBuffer);
texture->SRGB = true;
texture->UpdateResource();
_textures.Add(texture);
FTexturePlatformData* pPlatformData = texture->GetPlatformData();
int32 SizeX = pPlatformData->SizeX;
int32 SizeY = pPlatformData->SizeY;
_creditImages.Add(new FSlateImageBrush(texture, FVector2D(SizeX, SizeY)));
}
} else {
++_numImagesLoading;
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> HttpRequest =
FHttpModule::Get().CreateRequest();
_creditImages.AddDefaulted();
HttpRequest->OnProcessRequestComplete().BindUObject(
this,
&UScreenCreditsWidget::HandleImageRequest,
_creditImages.Num() - 1);
HttpRequest->SetURL(UTF8_TO_TCHAR(url.c_str()));
HttpRequest->SetVerb(TEXT("GET"));
HttpRequest->ProcessRequest();
}
return std::to_string(_creditImages.Num() - 1);
}
void UScreenCreditsWidget::SetCredits(
const FString& InCredits,
const FString& InOnScreenCredits) {
if (_numImagesLoading != 0) {
_credits = InCredits;
_onScreenCredits = InOnScreenCredits;
return;
}
if (RichTextPopup) {
RichTextPopup->SetText(FText::FromString(InCredits));
}
if (RichTextOnScreen) {
RichTextOnScreen->SetText(FText::FromString(InOnScreenCredits));
}
}