void FCreatureAnimStateMachineEditor::RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) { GraphEditorCommands = MakeShareable(new FUICommandList()); FAssetEditorToolkit::RegisterTabSpawners(TabManager); //蓝图编辑器命令绑定 GraphEditorCommands->MapAction(FGenericCommands::Get().Delete, FExecuteAction::CreateSP(this,&FCreatureAnimStateMachineEditor::OnDeleteNode) ); /*NodeAction.OnSelectionChanged.BindLambda( [&](const FGraphPanelSelectionSet& selection){ for (auto obj : selection) { if (UCreatureAnimStateNode* Node =Cast<UCreatureAnimStateNode>(obj)) { EditGraph->NotifyGraphChanged(); } } } );*/ EditGraph =SNew(SGraphEditor) .GraphToEdit(EditingStateMachine->StateMachineGraph) .IsEditable(true) .AdditionalCommands(GraphEditorCommands) .GraphEvents(NodeAction) ; //将细节面板放入左侧面板 TabManager->RegisterTabSpawner(FName(TEXT("Details")), FOnSpawnTab::CreateLambda( [&](const FSpawnTabArgs& Args){ TSharedPtr<FCreatureAnimStateMachineEditor> StateMechineEditorPtr = SharedThis(this); // Spawn the tab return SNew(SDockTab) .Icon(FEditorStyle::GetBrush("LevelEditor.Tabs.Details")) .Label(LOCTEXT("DetailsTab_Title", "Details")) [ SNew(SCreatureAnimStateMachinePropertiesTabBody,StateMechineEditorPtr) ]; } )) .SetDisplayName(LOCTEXT("DetailsTabLabel", "Details")) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Details")); TabManager->RegisterTabSpawner(FName(TEXT("BluePrint")), FOnSpawnTab::CreateLambda( //用于产生布局的Lambda表达式 [&](const FSpawnTabArgs& Args){ return SNew(SDockTab) .Icon(FEditorStyle::GetBrush("LevelEditor.Tabs.Details")) .Label(LOCTEXT("BlueprintTab_Title", "Blueprint")) [ EditGraph.ToSharedRef()//Slate允许提供一个sharedRef,不需要原地构建控件 ]; } )) .SetDisplayName(LOCTEXT("DetailsTabLabel", "Details")) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Details")); }
int32 FSequencerTimeSliderController::OnPaintTimeSlider( bool bMirrorLabels, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { const bool bEnabled = bParentEnabled; const ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; TRange<float> LocalViewRange = TimeSliderArgs.ViewRange.Get(); const float LocalViewRangeMin = LocalViewRange.GetLowerBoundValue(); const float LocalViewRangeMax = LocalViewRange.GetUpperBoundValue(); const float LocalSequenceLength = LocalViewRangeMax-LocalViewRangeMin; FVector2D Scale = FVector2D(1.0f,1.0f); if ( LocalSequenceLength > 0) { FScrubRangeToScreen RangeToScreen( LocalViewRange, AllottedGeometry.Size ); const float MajorTickHeight = 9.0f; FDrawTickArgs Args; Args.AllottedGeometry = AllottedGeometry; Args.bMirrorLabels = bMirrorLabels; Args.bOnlyDrawMajorTicks = false; Args.TickColor = FLinearColor::White; Args.ClippingRect = MyClippingRect; Args.DrawEffects = DrawEffects; Args.StartLayer = LayerId; Args.TickOffset = bMirrorLabels ? 0.0f : FMath::Abs( AllottedGeometry.Size.Y - MajorTickHeight ); Args.MajorTickHeight = MajorTickHeight; DrawTicks( OutDrawElements, RangeToScreen, Args ); FPaintPlaybackRangeArgs PlaybackRangeArgs( bMirrorLabels ? FEditorStyle::GetBrush("Sequencer.Timeline.PlayRange_Bottom_L") : FEditorStyle::GetBrush("Sequencer.Timeline.PlayRange_Top_L"), bMirrorLabels ? FEditorStyle::GetBrush("Sequencer.Timeline.PlayRange_Bottom_R") : FEditorStyle::GetBrush("Sequencer.Timeline.PlayRange_Top_R"), 6.f ); LayerId = DrawPlaybackRange(AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, RangeToScreen, PlaybackRangeArgs); float HalfSize = FMath::CeilToFloat(ScrubHandleSize/2.0f); // Draw the scrub handle float XPos = RangeToScreen.InputToLocalX( TimeSliderArgs.ScrubPosition.Get() ); // Should draw above the text const int32 ArrowLayer = LayerId + 2; FPaintGeometry MyGeometry = AllottedGeometry.ToPaintGeometry( FVector2D( XPos-HalfSize, 0 ), FVector2D( ScrubHandleSize, AllottedGeometry.Size.Y ) ); FLinearColor ScrubColor = InWidgetStyle.GetColorAndOpacityTint(); // @todo Sequencer this color should be specified in the style ScrubColor.A = ScrubColor.A*0.75f; ScrubColor.B *= 0.1f; ScrubColor.G *= 0.2f; FSlateDrawElement::MakeBox( OutDrawElements, ArrowLayer, MyGeometry, bMirrorLabels ? ScrubHandleUp : ScrubHandleDown, MyClippingRect, DrawEffects, ScrubColor ); // Draw the current time next to the scrub handle float Time = TimeSliderArgs.ScrubPosition.Get(); FString FrameString; if (SequencerSnapValues::IsTimeSnapIntervalFrameRate(TimeSliderArgs.Settings->GetTimeSnapInterval()) && TimeSliderArgs.Settings->GetShowFrameNumbers()) { float FrameRate = 1.0f/TimeSliderArgs.Settings->GetTimeSnapInterval(); float FrameTime = Time * FrameRate; int32 Frame = SequencerHelpers::TimeToFrame(Time, FrameRate); const float FrameTolerance = 0.001f; if (FMath::IsNearlyEqual(FrameTime, (float)Frame, FrameTolerance)) { FrameString = FString::Printf( TEXT("%d"), TimeToFrame(Time)); } else { FrameString = FString::Printf( TEXT("%.3f"), FrameTime); } } else { FrameString = FString::Printf( TEXT("%.2f"), Time ); } FSlateFontInfo SmallLayoutFont( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 10 ); const TSharedRef< FSlateFontMeasure > FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService(); FVector2D TextSize = FontMeasureService->Measure(FrameString, SmallLayoutFont); // Flip the text position if getting near the end of the view range if ((AllottedGeometry.Size.X - XPos) < (TextSize.X + 14.f)) { XPos = XPos - TextSize.X - 12.f; } else { XPos = XPos + 10.f; } FVector2D TextOffset( XPos, Args.bMirrorLabels ? TextSize.Y-6.f : Args.AllottedGeometry.Size.Y - (Args.MajorTickHeight+TextSize.Y) ); FSlateDrawElement::MakeText( OutDrawElements, Args.StartLayer+1, Args.AllottedGeometry.ToPaintGeometry( TextOffset, TextSize ), FrameString, SmallLayoutFont, Args.ClippingRect, Args.DrawEffects, Args.TickColor ); if (MouseDragType == DRAG_SETTING_RANGE) { float MouseStartPosX = RangeToScreen.InputToLocalX(MouseDownRange[0]); float MouseEndPosX = RangeToScreen.InputToLocalX(MouseDownRange[1]); float RangePosX = MouseStartPosX < MouseEndPosX ? MouseStartPosX : MouseEndPosX; float RangeSizeX = FMath::Abs(MouseStartPosX - MouseEndPosX); FSlateDrawElement::MakeBox( OutDrawElements, LayerId+1, AllottedGeometry.ToPaintGeometry( FVector2D(RangePosX, 0.f), FVector2D(RangeSizeX, AllottedGeometry.Size.Y) ), bMirrorLabels ? ScrubHandleDown : ScrubHandleUp, MyClippingRect, DrawEffects, MouseStartPosX < MouseEndPosX ? FLinearColor(0.5f, 0.5f, 0.5f) : FLinearColor(0.25f, 0.3f, 0.3f) ); } return ArrowLayer; } return LayerId; }
void TestUniqueIdRepl(UWorld* InWorld) { #if !UE_BUILD_SHIPPING bool bSuccess = true; TSharedPtr<const FUniqueNetId> UserId = UOnlineEngineInterface::Get()->GetUniquePlayerId(InWorld, 0); FUniqueNetIdRepl EmptyIdIn; if (EmptyIdIn.IsValid()) { UE_LOG(LogNet, Warning, TEXT("EmptyId is valid."), *EmptyIdIn->ToString()); bSuccess = false; } FUniqueNetIdRepl ValidIdIn(UserId); if (!ValidIdIn.IsValid() || UserId != ValidIdIn.GetUniqueNetId() || *UserId != *ValidIdIn) { UE_LOG(LogNet, Warning, TEXT("UserId input %s != UserId output %s"), *UserId->ToString(), *ValidIdIn->ToString()); bSuccess = false; } if (bSuccess) { TArray<uint8> Buffer; for (int32 i = 0; i < 2; i++) { Buffer.Empty(); FMemoryWriter TestWriteUniqueId(Buffer); if (i == 0) { // Normal serialize TestWriteUniqueId << EmptyIdIn; TestWriteUniqueId << ValidIdIn; } else { // Net serialize bool bOutSuccess = false; EmptyIdIn.NetSerialize(TestWriteUniqueId, NULL, bOutSuccess); ValidIdIn.NetSerialize(TestWriteUniqueId, NULL, bOutSuccess); } FMemoryReader TestReadUniqueId(Buffer); FUniqueNetIdRepl EmptyIdOut; TestReadUniqueId << EmptyIdOut; if (EmptyIdOut.GetUniqueNetId().IsValid()) { UE_LOG(LogNet, Warning, TEXT("EmptyId %s should have been invalid"), *EmptyIdOut->ToString()); bSuccess = false; } FUniqueNetIdRepl ValidIdOut; TestReadUniqueId << ValidIdOut; if (*UserId != *ValidIdOut.GetUniqueNetId()) { UE_LOG(LogNet, Warning, TEXT("UserId input %s != UserId output %s"), *ValidIdIn->ToString(), *ValidIdOut->ToString()); bSuccess = false; } } } if (bSuccess) { FString OutString; TSharedRef<FJsonValue> JsonValue = ValidIdIn.ToJson(); bSuccess = JsonValue->TryGetString(OutString); if (bSuccess) { FUniqueNetIdRepl NewIdOut; NewIdOut.FromJson(OutString); bSuccess = NewIdOut.IsValid(); } } if (!bSuccess) { UE_LOG(LogNet, Warning, TEXT("TestUniqueIdRepl test failure!")); } #endif }
void FWheeledVehicleMovementComponent4WDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) { DetailBuilder.GetObjectsBeingCustomized(SelectedObjects); //we only do fancy customization if we have one vehicle component selected if (SelectedObjects.Num() != 1) { return; } else if (UWheeledVehicleMovementComponent4W * VehicleComponent = Cast<UWheeledVehicleMovementComponent4W>(SelectedObjects[0].Get())) { SteeringCurveEditor = FSteeringCurveEditor(VehicleComponent); TorqueCurveEditor = FTorqueCurveEditor(VehicleComponent); } else { return; } //Torque curve { IDetailCategoryBuilder& MechanicalCategory = DetailBuilder.EditCategory("MechanicalSetup"); TSharedRef<IPropertyHandle> TorqueCurveHandle = DetailBuilder.GetProperty("EngineSetup.TorqueCurve"); MechanicalCategory.AddProperty(TorqueCurveHandle).CustomWidget() .NameContent() [ TorqueCurveHandle->CreatePropertyNameWidget() ] .ValueContent() .MinDesiredWidth(125.f * 3.f) [ SAssignNew(TorqueCurveWidget, SCurveEditor) .ViewMinInput(0.f) .ViewMaxInput(70000.f) .ViewMinOutput(0.f) .ViewMaxOutput(1.f) .TimelineLength(7000.f) .HideUI(false) .DesiredSize(FVector2D(512, 128)) ]; TorqueCurveWidget->SetCurveOwner(&TorqueCurveEditor); } //Steering curve { IDetailCategoryBuilder& SteeringCategory = DetailBuilder.EditCategory("SteeringSetup"); TSharedRef<IPropertyHandle> SteeringCurveHandle = DetailBuilder.GetProperty("SteeringCurve"); SteeringCategory.AddProperty(SteeringCurveHandle).CustomWidget() .NameContent() [ SteeringCurveHandle->CreatePropertyNameWidget() ] .ValueContent() .MinDesiredWidth(125.f * 3.f) [ SAssignNew(SteeringCurveWidget, SCurveEditor) .ViewMinInput(0.f) .ViewMaxInput(150.f) .ViewMinOutput(0.f) .ViewMaxOutput(1.f) .TimelineLength(150) .HideUI(false) .ZoomToFitVertical(false) .ZoomToFitHorizontal(false) .DesiredSize(FVector2D(512, 128)) ]; SteeringCurveWidget->SetCurveOwner(&SteeringCurveEditor); } }
void Construct( const FArguments& InArgs ) { OnCancelClickedDelegate = InArgs._OnCancelClickedDelegate; TSharedRef<SVerticalBox> VerticalBox = SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() .Padding( 14.0f, 4.0f, 14.0f, 10.0f ) [ SNew( STextBlock ) .Text( this, &SSlowTaskWidget::OnGetProgressText ) .ShadowOffset( FVector2D( 1.0f, 1.0f ) ) ]; if ( OnCancelClickedDelegate.IsBound() ) { VerticalBox->AddSlot() .AutoHeight() .Padding(10.0f, 7.0f) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .Padding(5,0,0,0) .FillWidth(0.8f) [ SNew(SProgressBar) .Percent( this, &SSlowTaskWidget::GetProgressFraction ) ] +SHorizontalBox::Slot() .Padding(5,0,0,0) .FillWidth(0.2f) [ SNew(SButton) .Text( NSLOCTEXT("FeedbackContextProgress", "Cancel", "Cancel") ) .HAlign(EHorizontalAlignment::HAlign_Center) .OnClicked(this, &SSlowTaskWidget::OnCancel) ] ]; } else { VerticalBox->AddSlot() .AutoHeight() .Padding(10.0f, 7.0f) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .Padding(5,0,0,0) .FillWidth(1.0f) [ SNew(SProgressBar) .Percent( this, &SSlowTaskWidget::GetProgressFraction ) ] ]; } SBorder::Construct( SBorder::FArguments() .BorderImage(FEditorStyle::GetBrush("Menu.Background")) .VAlign(VAlign_Center) [ VerticalBox ] ); }
void FCPPRichTextSyntaxHighlighterTextLayoutMarshaller::ParseTokens(const FString& SourceString, FTextLayout& TargetTextLayout, TArray<FSyntaxTokenizer::FTokenizedLine> TokenizedLines) { enum class EParseState : uint8 { None, LookingForString, LookingForCharacter, LookingForSingleLineComment, LookingForMultiLineComment, }; // Parse the tokens, generating the styled runs for each line EParseState ParseState = EParseState::None; for(const FSyntaxTokenizer::FTokenizedLine& TokenizedLine : TokenizedLines) { TSharedRef<FString> ModelString = MakeShareable(new FString()); TArray< TSharedRef< IRun > > Runs; if(ParseState == EParseState::LookingForSingleLineComment) { ParseState = EParseState::None; } for(const FSyntaxTokenizer::FToken& Token : TokenizedLine.Tokens) { const FString TokenText = SourceString.Mid(Token.Range.BeginIndex, Token.Range.Len()); const FTextRange ModelRange(ModelString->Len(), ModelString->Len() + TokenText.Len()); ModelString->Append(TokenText); FRunInfo RunInfo(TEXT("SyntaxHighlight.CPP.Normal")); FTextBlockStyle TextBlockStyle = SyntaxTextStyle.NormalTextStyle; const bool bIsWhitespace = FString(TokenText).TrimTrailing().IsEmpty(); if(!bIsWhitespace) { bool bHasMatchedSyntax = false; if(Token.Type == FSyntaxTokenizer::ETokenType::Syntax) { if(ParseState == EParseState::None && TokenText == TEXT("\"")) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.String"); TextBlockStyle = SyntaxTextStyle.StringTextStyle; ParseState = EParseState::LookingForString; bHasMatchedSyntax = true; } else if(ParseState == EParseState::LookingForString && TokenText == TEXT("\"")) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.Normal"); TextBlockStyle = SyntaxTextStyle.StringTextStyle; ParseState = EParseState::None; } else if(ParseState == EParseState::None && TokenText == TEXT("\'")) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.String"); TextBlockStyle = SyntaxTextStyle.StringTextStyle; ParseState = EParseState::LookingForCharacter; bHasMatchedSyntax = true; } else if(ParseState == EParseState::LookingForCharacter && TokenText == TEXT("\'")) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.Normal"); TextBlockStyle = SyntaxTextStyle.StringTextStyle; ParseState = EParseState::None; } else if(ParseState == EParseState::None && TokenText.StartsWith(TEXT("#"))) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.PreProcessorKeyword"); TextBlockStyle = SyntaxTextStyle.PreProcessorKeywordTextStyle; ParseState = EParseState::None; } else if(ParseState == EParseState::None && TokenText == TEXT("//")) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.Comment"); TextBlockStyle = SyntaxTextStyle.CommentTextStyle; ParseState = EParseState::LookingForSingleLineComment; } else if(ParseState == EParseState::None && TokenText == TEXT("/*")) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.Comment"); TextBlockStyle = SyntaxTextStyle.CommentTextStyle; ParseState = EParseState::LookingForMultiLineComment; } else if(ParseState == EParseState::LookingForMultiLineComment && TokenText == TEXT("*/")) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.Comment"); TextBlockStyle = SyntaxTextStyle.CommentTextStyle; ParseState = EParseState::None; } else if(ParseState == EParseState::None && TChar<WIDECHAR>::IsAlpha(TokenText[0])) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.Keyword"); TextBlockStyle = SyntaxTextStyle.KeywordTextStyle; ParseState = EParseState::None; } else if(ParseState == EParseState::None && !TChar<WIDECHAR>::IsAlpha(TokenText[0])) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.Operator"); TextBlockStyle = SyntaxTextStyle.OperatorTextStyle; ParseState = EParseState::None; } } // It's possible that we fail to match a syntax token if we're in a state where it isn't parsed // In this case, we treat it as a literal token if(Token.Type == FSyntaxTokenizer::ETokenType::Literal || !bHasMatchedSyntax) { if(ParseState == EParseState::LookingForString) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.String"); TextBlockStyle = SyntaxTextStyle.StringTextStyle; } else if(ParseState == EParseState::LookingForCharacter) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.String"); TextBlockStyle = SyntaxTextStyle.StringTextStyle; } else if(ParseState == EParseState::LookingForSingleLineComment) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.Comment"); TextBlockStyle = SyntaxTextStyle.CommentTextStyle; } else if(ParseState == EParseState::LookingForMultiLineComment) { RunInfo.Name = TEXT("SyntaxHighlight.CPP.Comment"); TextBlockStyle = SyntaxTextStyle.CommentTextStyle; } } TSharedRef< ISlateRun > Run = FSlateTextRun::Create(RunInfo, ModelString, TextBlockStyle, ModelRange); Runs.Add(Run); } else { RunInfo.Name = TEXT("SyntaxHighlight.CPP.WhiteSpace"); TSharedRef< ISlateRun > Run = FWhiteSpaceTextRun::Create(RunInfo, ModelString, TextBlockStyle, ModelRange, 4); Runs.Add(Run); } } TargetTextLayout.AddLine(ModelString, Runs); } }
bool FPerforceCheckInWorker::Execute(FPerforceSourceControlCommand& InCommand) { FScopedPerforceConnection ScopedConnection(InCommand); if (!InCommand.IsCanceled() && ScopedConnection.IsValid()) { FPerforceConnection& Connection = ScopedConnection.GetConnection(); check(InCommand.Operation->GetName() == GetName()); TSharedRef<FCheckIn, ESPMode::ThreadSafe> Operation = StaticCastSharedRef<FCheckIn>(InCommand.Operation); int32 ChangeList = Connection.CreatePendingChangelist(Operation->GetDescription(), FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.ErrorMessages); if (ChangeList > 0) { // Batch reopen into multiple commands, to avoid command line limits const int32 BatchedCount = 100; InCommand.bCommandSuccessful = true; for (int32 StartingIndex = 0; StartingIndex < InCommand.Files.Num() && InCommand.bCommandSuccessful; StartingIndex += BatchedCount) { FP4RecordSet Records; TArray< FString > ReopenParams; //Add changelist information to params ReopenParams.Insert(TEXT("-c"), 0); ReopenParams.Insert(FString::Printf(TEXT("%d"), ChangeList), 1); int32 NextIndex = FMath::Min(StartingIndex + BatchedCount, InCommand.Files.Num()); for (int32 FileIndex = StartingIndex; FileIndex < NextIndex; FileIndex++) { ReopenParams.Add(InCommand.Files[FileIndex]); } InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("reopen"), ReopenParams, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); } if (InCommand.bCommandSuccessful) { // Only submit if reopen was successful TArray<FString> SubmitParams; FP4RecordSet Records; SubmitParams.Insert(TEXT("-c"), 0); SubmitParams.Insert(FString::Printf(TEXT("%d"), ChangeList), 1); InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("submit"), SubmitParams, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); if (InCommand.ErrorMessages.Num() > 0) { InCommand.bCommandSuccessful = false; } if (InCommand.bCommandSuccessful) { // Remove any deleted files from status cache FPerforceSourceControlModule& PerforceSourceControl = FModuleManager::GetModuleChecked<FPerforceSourceControlModule>("PerforceSourceControl"); FPerforceSourceControlProvider& Provider = PerforceSourceControl.GetProvider(); TArray<TSharedRef<ISourceControlState, ESPMode::ThreadSafe>> States; Provider.GetState(InCommand.Files, States, EStateCacheUsage::Use); for (const auto& State : States) { if (State->IsDeleted()) { Provider.RemoveFileFromCache(State->GetFilename()); } } StaticCastSharedRef<FCheckIn>(InCommand.Operation)->SetSuccessMessage(ParseSubmitResults(Records)); for(auto Iter(InCommand.Files.CreateIterator()); Iter; Iter++) { OutResults.Add(*Iter, EPerforceState::ReadOnly); } } } } else { // Failed to create the changelist InCommand.bCommandSuccessful = false; } } return InCommand.bCommandSuccessful; }
void FAssetEditorToolkit::GenerateToolbar() { TSharedPtr<FExtender> Extender = FExtender::Combine(ToolbarExtenders); FToolBarBuilder ToolbarBuilder( GetToolkitCommands(), FMultiBoxCustomization::AllowCustomization( GetToolkitFName() ), Extender); ToolbarBuilder.SetIsFocusable(bIsToolbarFocusable); ToolbarBuilder.BeginSection("Asset"); { if( IsActuallyAnAsset() ) { ToolbarBuilder.AddToolBarButton(FAssetEditorCommonCommands::Get().SaveAsset); ToolbarBuilder.AddToolBarButton(FGlobalEditorCommonCommands::Get().FindInContentBrowser, NAME_None, LOCTEXT("FindInContentBrowserButton", "Find in CB")); } } ToolbarBuilder.EndSection(); TSharedRef<SHorizontalBox> MiscWidgets = SNew(SHorizontalBox); for (int32 WidgetIdx = 0; WidgetIdx < ToolbarWidgets.Num(); ++WidgetIdx) { MiscWidgets->AddSlot() .AutoWidth() .VAlign(VAlign_Center) .Padding(0.0f, 2.0f, 0.0f, 2.0f) [ ToolbarWidgets[WidgetIdx] ]; } Toolbar = SNew(SHorizontalBox) +SHorizontalBox::Slot() .HAlign(HAlign_Left) .VAlign(VAlign_Center) [ SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() .VAlign(VAlign_Bottom) [ ToolbarBuilder.MakeWidget() ] ] +SHorizontalBox::Slot() .HAlign(HAlign_Right) .VAlign(VAlign_Center) .AutoWidth() [ SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() .VAlign(VAlign_Bottom) [ SNew(SBorder) .BorderImage(FEditorStyle::GetBrush(TEXT("Toolbar.Background"))) .Visibility(ToolbarWidgets.Num() > 0 ? EVisibility::Visible : EVisibility::Collapsed) [ MiscWidgets ] ] ]; if (ToolbarWidgetContent.IsValid()) { ToolbarWidgetContent->SetContent(Toolbar.ToSharedRef()); } }
FReply HandleActionClicked(TSharedRef<IChatTip> ChatTip) { return ChatTip->ExecuteTip(); }
void FAssetEditorToolkit::UnregisterTabSpawners(const TSharedRef<class FTabManager>& InTabManager) { InTabManager->UnregisterTabSpawner( ToolbarTabId ); InTabManager->ClearLocalWorkspaceMenuCategories(); }
void FAssetEditorToolkit::InitAssetEditor( const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, const FName AppIdentifier, const TSharedRef<FTabManager::FLayout>& StandaloneDefaultLayout, const bool bCreateDefaultStandaloneMenu, const bool bCreateDefaultToolbar, const TArray<UObject*>& ObjectsToEdit, const bool bInIsToolbarFocusable ) { // Must not already be editing an object check( ObjectsToEdit.Num() > 0 ); check( EditingObjects.Num() == 0 ); bIsToolbarFocusable = bInIsToolbarFocusable; // cache reference to ToolkitManager; also ensure it was initialized. FToolkitManager& ToolkitManager = FToolkitManager::Get(); EditingObjects.Append( ObjectsToEdit ); // Store "previous" asset editing toolkit host, and clear it out PreviousWorldCentricToolkitHost = PreviousWorldCentricToolkitHostForNewAssetEditor; PreviousWorldCentricToolkitHostForNewAssetEditor.Reset(); ToolkitMode = Mode; TSharedPtr<SWindow> ParentWindow; TSharedPtr<SDockTab> NewMajorTab; TSharedPtr< SStandaloneAssetEditorToolkitHost > NewStandaloneHost; if( ToolkitMode == EToolkitMode::WorldCentric ) // @todo toolkit major: Do we need to remember this setting on a per-asset editor basis? Probably. { // Keep track of the level editor we're attached to (if any) ToolkitHost = InitToolkitHost; } else if( ensure( ToolkitMode == EToolkitMode::Standalone ) ) { // Open a standalone app to edit this asset. check( AppIdentifier != NAME_None ); // Create the label and the link for the toolkit documentation. TAttribute<FText> Label = TAttribute<FText>( this, &FAssetEditorToolkit::GetToolkitName ); TAttribute<FText> ToolTipText = TAttribute<FText>( this, &FAssetEditorToolkit::GetToolkitToolTipText ); FString DocLink = GetDocumentationLink(); if ( !DocLink.StartsWith( "Shared/" ) ) { DocLink = FString("Shared/") + DocLink; } // Create a new SlateToolkitHost NewMajorTab = SNew(SDockTab) .ContentPadding(0.0f) .TabRole(ETabRole::MajorTab) .ToolTip(IDocumentation::Get()->CreateToolTip(ToolTipText, nullptr, DocLink, GetToolkitFName().ToString())) .Icon( this, &FAssetEditorToolkit::GetDefaultTabIcon ) .Label( Label ); { static_assert(sizeof(EAssetEditorToolkitTabLocation) == sizeof(int32), "EAssetEditorToolkitTabLocation is the incorrect size"); const UEditorStyleSettings* StyleSettings = GetDefault<UEditorStyleSettings>(); // Work out where we should create this asset editor EAssetEditorToolkitTabLocation SavedAssetEditorToolkitTabLocation = StyleSettings->bOpenAssetEditorTabsInNewWindow ? EAssetEditorToolkitTabLocation::Standalone : EAssetEditorToolkitTabLocation::Docked; GConfig->GetInt( TEXT("AssetEditorToolkitTabLocation"), *ObjectsToEdit[0]->GetPathName(), reinterpret_cast<int32&>(SavedAssetEditorToolkitTabLocation), GEditorPerProjectIni ); const FName AssetEditorToolkitTab = (SavedAssetEditorToolkitTabLocation == EAssetEditorToolkitTabLocation::Docked) ? "DockedToolkit" : "StandaloneToolkit"; FGlobalTabmanager::Get()->InsertNewDocumentTab( AssetEditorToolkitTab, FTabManager::ESearchPreference::PreferLiveTab, NewMajorTab.ToSharedRef() ); } #if PLATFORM_MAC TSharedPtr< SEditableTextBox > ExposedEditableTextBox; TSharedRef<SWidget> SuperSearchWidget = FSuperSearchModule::Get().MakeSearchBox(ExposedEditableTextBox); #endif IUserFeedbackModule& UserFeedback = FModuleManager::LoadModuleChecked<IUserFeedbackModule>(TEXT("UserFeedback")); TSharedRef<SWidget> UserFeedbackWidget = UserFeedback.CreateFeedbackWidget(GetBaseToolkitName()); IIntroTutorials& IntroTutorials = FModuleManager::LoadModuleChecked<IIntroTutorials>(TEXT("IntroTutorials")); TSharedRef<SWidget> TutorialWidget = IntroTutorials.CreateTutorialsWidget(GetToolkitContextFName(), NewMajorTab->GetParentWindow()); NewMajorTab->SetRightContent( SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .Padding(8.0f, 0.0f, 0.0f, 0.0f) .VAlign(VAlign_Center) [ UserFeedbackWidget ] #if PLATFORM_MAC +SHorizontalBox::Slot() .AutoWidth() .Padding(16.0f, 0.0f, 0.0f, 0.0f) .VAlign(VAlign_Center) [ SuperSearchWidget ] #endif +SHorizontalBox::Slot() .AutoWidth() .Padding(8.0f, 0.0f, 8.0f, 0.0f) .VAlign(VAlign_Center) [ TutorialWidget ] ); const TSharedRef<FTabManager> NewTabManager = FGlobalTabmanager::Get()->NewTabManager( NewMajorTab.ToSharedRef() ); NewTabManager->SetOnPersistLayout(FTabManager::FOnPersistLayout::CreateRaw(this, &FAssetEditorToolkit::HandleTabManagerPersistLayout)); this->TabManager = NewTabManager; NewMajorTab->SetContent ( SAssignNew( NewStandaloneHost, SStandaloneAssetEditorToolkitHost, NewTabManager, AppIdentifier ) .OnRequestClose(this, &FAssetEditorToolkit::OnRequestClose) ); // Assign our toolkit host before we setup initial content. (Important: We must cache this pointer here as SetupInitialContent // will callback into the toolkit host.) ToolkitHost = NewStandaloneHost; } check( ToolkitHost.IsValid() ); ToolkitManager.RegisterNewToolkit( SharedThis( this ) ); if (ToolkitMode == EToolkitMode::Standalone) { TSharedRef<FTabManager::FLayout> LayoutToUse = FLayoutSaveRestore::LoadFromConfig(GEditorLayoutIni, StandaloneDefaultLayout); // Actually create the widget content NewStandaloneHost->SetupInitialContent( LayoutToUse, NewMajorTab, bCreateDefaultStandaloneMenu ); } StandaloneHost = NewStandaloneHost; if (bCreateDefaultToolbar) { GenerateToolbar(); } else { Toolbar = SNullWidget::NullWidget; } ToolkitCommands->MapAction( FAssetEditorCommonCommands::Get().SaveAsset, FExecuteAction::CreateSP( this, &FAssetEditorToolkit::SaveAsset_Execute ), FCanExecuteAction::CreateSP( this, &FAssetEditorToolkit::CanSaveAsset )); ToolkitCommands->MapAction( FGlobalEditorCommonCommands::Get().FindInContentBrowser, FExecuteAction::CreateSP( this, &FAssetEditorToolkit::FindInContentBrowser_Execute ) ); ToolkitCommands->MapAction( FGlobalEditorCommonCommands::Get().ViewReferences, FExecuteAction::CreateSP( this, &FAssetEditorToolkit::ViewReferences_Execute ), FCanExecuteAction::CreateSP( this, &FAssetEditorToolkit::CanViewReferences )); ToolkitCommands->MapAction( FGlobalEditorCommonCommands::Get().ViewSizeMap, FExecuteAction::CreateSP( this, &FAssetEditorToolkit::ViewSizeMap_Execute ), FCanExecuteAction::CreateSP( this, &FAssetEditorToolkit::CanViewSizeMap )); ToolkitCommands->MapAction( FGlobalEditorCommonCommands::Get().OpenDocumentation, FExecuteAction::CreateSP( this, &FAssetEditorToolkit::BrowseDocumentation_Execute ) ); ToolkitCommands->MapAction( FAssetEditorCommonCommands::Get().ReimportAsset, FExecuteAction::CreateSP( this, &FAssetEditorToolkit::Reimport_Execute ) ); FGlobalEditorCommonCommands::MapActions(ToolkitCommands); if( IsWorldCentricAssetEditor() ) { ToolkitCommands->MapAction( FAssetEditorCommonCommands::Get().SwitchToStandaloneEditor, FExecuteAction::CreateStatic( &FAssetEditorToolkit::SwitchToStandaloneEditor_Execute, TWeakPtr< FAssetEditorToolkit >( AsShared() ) ) ); } else { if( GetPreviousWorldCentricToolkitHost().IsValid() ) { ToolkitCommands->MapAction( FAssetEditorCommonCommands::Get().SwitchToWorldCentricEditor, FExecuteAction::CreateStatic( &FAssetEditorToolkit::SwitchToWorldCentricEditor_Execute, TWeakPtr< FAssetEditorToolkit >( AsShared() ) ) ); } } // NOTE: Currently, the AssetEditorManager will keep a hard reference to our object as we're editing it FAssetEditorManager::Get().NotifyAssetsOpened( EditingObjects, this ); }
// equality check bool operator==(const FReceivedPartyInvite& Other) const { return *Other.FromId == *FromId || *Other.PartyJoinInfo->GetPartyId() == *PartyJoinInfo->GetPartyId(); }
TSharedRef< FSlateStyleSet > FFriendsAndChatModuleStyle::Create(FFriendsAndChatStyle FriendStyle) { TSharedRef< FSlateStyleSet > Style = MakeShareable(new FSlateStyleSet("FriendsAndChatStyle")); const FTextBlockStyle DefaultText = FTextBlockStyle(FriendStyle.FriendsChatStyle.TextStyle) .SetFont(FriendStyle.FriendsNormalFontStyle.FriendsFontSmall); // Name Style const FTextBlockStyle GlobalChatFont = FTextBlockStyle(DefaultText) .SetFont(FriendStyle.FriendsNormalFontStyle.FriendsFontNormalBold) .SetColorAndOpacity(FriendStyle.FriendsChatStyle.GlobalChatColor); const FTextBlockStyle GameChatFont = FTextBlockStyle(DefaultText) .SetFont(FriendStyle.FriendsNormalFontStyle.FriendsFontNormalBold) .SetColorAndOpacity(FriendStyle.FriendsChatStyle.GameChatColor); const FTextBlockStyle PartyChatFont = FTextBlockStyle(DefaultText) .SetFont(FriendStyle.FriendsNormalFontStyle.FriendsFontNormalBold) .SetColorAndOpacity(FriendStyle.FriendsChatStyle.PartyChatColor); const FTextBlockStyle WhisperChatFont = FTextBlockStyle(DefaultText) .SetFont(FriendStyle.FriendsNormalFontStyle.FriendsFontNormalBold) .SetColorAndOpacity(FriendStyle.FriendsChatStyle.WhisplerChatColor); const FButtonStyle UserNameButton = FButtonStyle() .SetNormal(FSlateNoResource()) .SetPressed(FSlateNoResource()) .SetHovered(FSlateNoResource()); const FHyperlinkStyle GlobalChatHyperlink = FHyperlinkStyle() .SetUnderlineStyle(UserNameButton) .SetTextStyle(GlobalChatFont) .SetPadding(FMargin(0.0f)); const FHyperlinkStyle GameChatHyperlink = FHyperlinkStyle() .SetUnderlineStyle(UserNameButton) .SetTextStyle(GameChatFont) .SetPadding(FMargin(0.0f)); const FHyperlinkStyle PartyChatHyperlink = FHyperlinkStyle() .SetUnderlineStyle(UserNameButton) .SetTextStyle(PartyChatFont) .SetPadding(FMargin(0.0f)); const FHyperlinkStyle WhisperChatHyperlink = FHyperlinkStyle() .SetUnderlineStyle(UserNameButton) .SetTextStyle(WhisperChatFont) .SetPadding(FMargin(0.0f)); const FHyperlinkStyle DefaultChatHyperlink = FHyperlinkStyle() .SetUnderlineStyle(UserNameButton) .SetTextStyle(DefaultText) .SetPadding(FMargin(0.0f)); Style->Set("UserNameTextStyle.Default", DefaultText); Style->Set("UserNameTextStyle.GlobalHyperlink", GlobalChatHyperlink); Style->Set("UserNameTextStyle.GameHyperlink", GameChatHyperlink); Style->Set("UserNameTextStyle.PartyHyperlink", GameChatHyperlink); Style->Set("UserNameTextStyle.Whisperlink", WhisperChatHyperlink); Style->Set("UserNameTextStyle.DefaultHyperlink", DefaultChatHyperlink); Style->Set("UserNameTextStyle.GlobalTextStyle", GlobalChatFont); Style->Set("UserNameTextStyle.GameTextStyle", GameChatFont); Style->Set("UserNameTextStyle.PartyTextStyle", PartyChatFont); Style->Set("UserNameTextStyle.WhisperTextStyle", WhisperChatFont); Style->Set("MessageBreak", FTextBlockStyle(DefaultText) .SetFont(FSlateFontInfo( FriendStyle.FriendsNormalFontStyle.FriendsFontSmall.FontObject, 6, FriendStyle.FriendsNormalFontStyle.FriendsFontSmall.TypefaceFontName ))); Style->Set("GlobalChatIcon", FInlineTextImageStyle() .SetImage(FriendStyle.FriendsChatStyle.ChatGlobalBrush) .SetBaseline(0)); Style->Set("WhisperChatIcon", FInlineTextImageStyle() .SetImage(FriendStyle.FriendsChatStyle.ChatWhisperBrush) .SetBaseline(0)); Style->Set("PartyChatIcon", FInlineTextImageStyle() .SetImage(FriendStyle.FriendsChatStyle.ChatGameBrush) .SetBaseline(0)); return Style; }
FSkeletonEditorMode::FSkeletonEditorMode(TSharedRef<FWorkflowCentricApplication> InHostingApp, TSharedRef<ISkeletonTree> InSkeletonTree) : FApplicationMode(SkeletonEditorModes::SkeletonEditorMode) { HostingAppPtr = InHostingApp; TSharedRef<FSkeletonEditor> SkeletonEditor = StaticCastSharedRef<FSkeletonEditor>(InHostingApp); ISkeletonEditorModule& SkeletonEditorModule = FModuleManager::LoadModuleChecked<ISkeletonEditorModule>("SkeletonEditor"); TabFactories.RegisterFactory(SkeletonEditorModule.CreateSkeletonTreeTabFactory(InHostingApp, InSkeletonTree)); FPersonaModule& PersonaModule = FModuleManager::LoadModuleChecked<FPersonaModule>("Persona"); TabFactories.RegisterFactory(PersonaModule.CreateDetailsTabFactory(InHostingApp, FOnDetailsCreated::CreateSP(&SkeletonEditor.Get(), &FSkeletonEditor::HandleDetailsCreated))); TabFactories.RegisterFactory(PersonaModule.CreatePersonaViewportTabFactory(InHostingApp, InSkeletonTree, SkeletonEditor->GetPersonaToolkit()->GetPreviewScene(), SkeletonEditor->OnPostUndo, nullptr, FOnViewportCreated(), true, true)); TabFactories.RegisterFactory(PersonaModule.CreateAnimNotifiesTabFactory(InHostingApp, InSkeletonTree->GetEditableSkeleton(), SkeletonEditor->OnChangeAnimNotifies, SkeletonEditor->OnPostUndo, FOnObjectsSelected::CreateSP(&SkeletonEditor.Get(), &FSkeletonEditor::HandleObjectsSelected))); TabFactories.RegisterFactory(PersonaModule.CreateAdvancedPreviewSceneTabFactory(InHostingApp, SkeletonEditor->GetPersonaToolkit()->GetPreviewScene())); TabFactories.RegisterFactory(PersonaModule.CreateRetargetManagerTabFactory(InHostingApp, InSkeletonTree->GetEditableSkeleton(), SkeletonEditor->GetPersonaToolkit()->GetPreviewScene(), SkeletonEditor->OnPostUndo)); TabFactories.RegisterFactory(PersonaModule.CreateCurveViewerTabFactory(InHostingApp, InSkeletonTree->GetEditableSkeleton(), SkeletonEditor->GetPersonaToolkit()->GetPreviewScene(), SkeletonEditor->OnCurvesChanged, SkeletonEditor->OnPostUndo)); TabFactories.RegisterFactory(PersonaModule.CreateSkeletonSlotNamesTabFactory(InHostingApp, InSkeletonTree->GetEditableSkeleton(), SkeletonEditor->OnPostUndo, FOnObjectSelected::CreateSP(&SkeletonEditor.Get(), &FSkeletonEditor::HandleObjectSelected))); TabLayout = FTabManager::NewLayout("Standalone_SkeletonEditor_Layout_v1.1") ->AddArea ( FTabManager::NewPrimaryArea() ->SetOrientation(Orient_Vertical) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.1f) ->SetHideTabWell(true) ->AddTab(InHostingApp->GetToolbarTabId(), ETabState::OpenedTab) ) ->Split ( FTabManager::NewSplitter() ->SetSizeCoefficient(0.9f) ->SetOrientation(Orient_Horizontal) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.2f) ->SetHideTabWell(true) ->AddTab(SkeletonEditorTabs::SkeletonTreeTab, ETabState::OpenedTab) ->AddTab(SkeletonEditorTabs::RetargetManagerTab, ETabState::ClosedTab) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.6f) ->SetHideTabWell(true) ->AddTab(SkeletonEditorTabs::ViewportTab, ETabState::OpenedTab) ) ->Split ( FTabManager::NewSplitter() ->SetSizeCoefficient(0.2f) ->SetOrientation(Orient_Vertical) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.5f) ->SetHideTabWell(false) ->AddTab(SkeletonEditorTabs::DetailsTab, ETabState::OpenedTab) ->AddTab(SkeletonEditorTabs::AdvancedPreviewTab, ETabState::ClosedTab) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.5f) ->SetHideTabWell(false) ->AddTab(SkeletonEditorTabs::AnimNotifiesTab, ETabState::OpenedTab) ->AddTab(SkeletonEditorTabs::CurveNamesTab, ETabState::OpenedTab) ->AddTab(SkeletonEditorTabs::SlotNamesTab, ETabState::ClosedTab) ) ) ) ); }
static void LogGetPackageLinkerError(FArchiveUObject* LinkerArchive, const TCHAR* InFilename, const FText& InFullErrorMessage, const FText& InSummaryErrorMessage, UObject* InOuter, uint32 LoadFlags) { static FName NAME_LoadErrors("LoadErrors"); struct Local { /** Helper function to output more detailed error info if available */ static void OutputErrorDetail(FArchiveUObject* LinkerArchive, const FName& LogName) { if ( GSerializedObject && GSerializedImportLinker ) { FMessageLog LoadErrors(LogName); TSharedRef<FTokenizedMessage> Message = LoadErrors.Info(); Message->AddToken(FTextToken::Create(LOCTEXT("FailedLoad_Message", "Failed to load"))); Message->AddToken(FAssetNameToken::Create(GSerializedImportLinker->GetImportPathName(GSerializedImportIndex))); Message->AddToken(FTextToken::Create(LOCTEXT("FailedLoad_Referenced", "Referenced by"))); Message->AddToken(FUObjectToken::Create(GSerializedObject)); auto SerializedProperty = LinkerArchive ? LinkerArchive->GetSerializedProperty() : nullptr; if (SerializedProperty != nullptr) { FString PropertyPathName = SerializedProperty->GetPathName(); Message->AddToken(FTextToken::Create(LOCTEXT("FailedLoad_Property", "Property"))); Message->AddToken(FAssetNameToken::Create(PropertyPathName, FText::FromString( PropertyPathName) ) ); } } } }; FMessageLog LoadErrors(NAME_LoadErrors); // Display log error regardless LoadFlag settings SET_WARN_COLOR(COLOR_RED); if (LoadFlags & LOAD_NoWarn) { UE_LOG(LogLinker, Log, TEXT("%s"), *InFullErrorMessage.ToString()); } else { UE_LOG(LogLinker, Warning, TEXT("%s"), *InFullErrorMessage.ToString()); } CLEAR_WARN_COLOR(); if( GIsEditor && !IsRunningCommandlet() ) { // if we don't want to be warned, skip the load warning if (!(LoadFlags & LOAD_NoWarn)) { // we only want to output errors that content creators will be able to make sense of, // so any errors we cant get links out of we will just let be output to the output log (above) // rather than clog up the message log if(InFilename != NULL && InOuter != NULL) { // Output the summary error & the filename link. This might be something like "..\Content\Foo.upk Out of Memory" TSharedRef<FTokenizedMessage> Message = LoadErrors.Error(); Message->AddToken(FAssetNameToken::Create(FPackageName::FilenameToLongPackageName(InFilename))); Message->AddToken(FTextToken::Create(FText::FromString(TEXT(":")))); Message->AddToken(FTextToken::Create(InSummaryErrorMessage)); Message->AddToken(FAssetNameToken::Create(FPackageName::FilenameToLongPackageName(InOuter->GetPathName()))); } Local::OutputErrorDetail(LinkerArchive, NAME_LoadErrors); } } else { if (!(LoadFlags & LOAD_NoWarn)) { Local::OutputErrorDetail(LinkerArchive, NAME_LoadErrors); } FFormatNamedArguments Arguments; Arguments.Add(TEXT("FileName"), FText::FromString(InFilename ? InFilename : InOuter ? *InOuter->GetName() : TEXT("NULL"))); Arguments.Add(TEXT("ErrorMessage"), InFullErrorMessage); const FText Error = FText::Format(LOCTEXT("FailedLoad", "Failed to load '{FileName}': {ErrorMessage}"), Arguments); // @see ResavePackagesCommandlet if( FParse::Param(FCommandLine::Get(),TEXT("SavePackagesThatHaveFailedLoads")) == true ) { LoadErrors.Warning(Error); } else { // Gracefully handle missing packages SafeLoadError( InOuter, LoadFlags, *InFullErrorMessage.ToString(), *Error.ToString() ); } } }
/** * Construct the widget * * @param InDeclaration A declaration from which to construct the widget */ void Construct( const STableColumnHeader::FArguments& InArgs, const SHeaderRow::FColumn& Column, const FMargin DefaultHeaderContentPadding ) { check(InArgs._Style); SWidget::Construct( InArgs._ToolTipText, InArgs._ToolTip, InArgs._Cursor, InArgs._IsEnabled, InArgs._Visibility, InArgs._RenderTransform, InArgs._RenderTransformPivot, InArgs._Tag, InArgs._ForceVolatile, InArgs.MetaData ); Style = InArgs._Style; ColumnId = Column.ColumnId; SortMode = Column.SortMode; SortPriority = Column.SortPriority; OnSortModeChanged = Column.OnSortModeChanged; ContextMenuContent = Column.HeaderMenuContent.Widget; ComboVisibility = Column.HeaderComboVisibility; FMargin AdjustedDefaultHeaderContentPadding = DefaultHeaderContentPadding; TAttribute< FText > LabelText = Column.DefaultText; TAttribute< FText > TooltipText = Column.DefaultTooltip; if (Column.HeaderContent.Widget == SNullWidget::NullWidget) { if (!Column.DefaultText.IsSet()) { LabelText = FText::FromString( Column.ColumnId.ToString() + TEXT("[LabelMissing]") ); } if (!Column.DefaultTooltip.IsSet()) { TooltipText = LabelText; } } TSharedPtr< SHorizontalBox > Box; TSharedRef< SOverlay > Overlay = SNew( SOverlay ); Overlay->AddSlot( 0 ) [ SAssignNew( Box, SHorizontalBox ) ]; TSharedRef< SWidget > PrimaryContent = Column.HeaderContent.Widget; if ( PrimaryContent == SNullWidget::NullWidget ) { PrimaryContent = SNew( SBox ) .Padding( OnSortModeChanged.IsBound() ? FMargin( 0, 2, 0, 2 ) : FMargin( 0, 4, 0, 4 ) ) .VAlign( VAlign_Center ) [ SNew(STextBlock) .Text( LabelText ) .ToolTipText( TooltipText ) ]; } if ( OnSortModeChanged.IsBound() ) { //optional main button with the column's title. Used to toggle sorting modes. PrimaryContent = SNew(SButton) .ButtonStyle( FCoreStyle::Get(), "NoBorder" ) .ForegroundColor( FSlateColor::UseForeground() ) .ContentPadding( FMargin( 0, 2, 0, 2 ) ) .OnClicked(this, &STableColumnHeader::OnTitleClicked) [ PrimaryContent ]; } Box->AddSlot() .FillWidth(1.0f) [ PrimaryContent ]; if( Column.HeaderMenuContent.Widget != SNullWidget::NullWidget ) { // Add Drop down menu button (only if menu content has been specified) Box->AddSlot() .AutoWidth() [ SAssignNew( MenuOverlay, SOverlay ) .Visibility( this, &STableColumnHeader::GetMenuOverlayVisibility ) +SOverlay::Slot() [ SNew( SSpacer ) .Size( FVector2D( 12.0f, 0 ) ) ] +SOverlay::Slot() .Padding(FMargin(0,1,0,1)) [ SNew( SBorder ) .Padding( FMargin( 0, 0, AdjustedDefaultHeaderContentPadding.Right, 0 ) ) .BorderImage( this, &STableColumnHeader::GetComboButtonBorderBrush ) [ SAssignNew( ComboButton, SComboButton) .HasDownArrow(false) .ButtonStyle( FCoreStyle::Get(), "NoBorder" ) .ContentPadding( FMargin(0) ) .ButtonContent() [ SNew( SSpacer ) .Size( FVector2D( 14.0f, 0 ) ) ] .MenuContent() [ ContextMenuContent ] ] ] +SOverlay::Slot() .Padding(FMargin(0,0,0,2)) .HAlign( HAlign_Center ) .VAlign( VAlign_Bottom ) [ SNew(SImage) .Image( &Style->MenuDropdownImage ) .ColorAndOpacity( this, &STableColumnHeader::GetComboButtonTint ) .Visibility( EVisibility::HitTestInvisible ) ] ]; AdjustedDefaultHeaderContentPadding.Right = 0; } Overlay->AddSlot( 1 ) .HAlign(HAlign_Center) .VAlign( VAlign_Top ) .Padding( FMargin( 0, 2, 0, 0 ) ) [ SNew(SImage) .Image( this, &STableColumnHeader::GetSortingBrush ) .Visibility( this, &STableColumnHeader::GetSortModeVisibility ) ]; this->ChildSlot [ SNew( SBorder ) .BorderImage( this, &STableColumnHeader::GetHeaderBackgroundBrush ) .HAlign( Column.HeaderHAlignment ) .VAlign( Column.HeaderVAlignment ) .Padding( Column.HeaderContentPadding.Get( AdjustedDefaultHeaderContentPadding ) ) [ Overlay ] ]; }
TSharedRef< SWidget > FOutputLogModule::MakeConsoleInputBox( TSharedPtr< SEditableTextBox >& OutExposedEditableTextBox ) const { TSharedRef< SConsoleInputBox > NewConsoleInputBox = SNew( SConsoleInputBox ); OutExposedEditableTextBox = NewConsoleInputBox->GetEditableTextBox(); return NewConsoleInputBox; }
void FNiagaraEmitterPropertiesDetails::BuildScriptProperties(TSharedRef<IPropertyHandle> ScriptPropsHandle, FName Name, FText DisplayName) { DetailLayout->HideProperty(ScriptPropsHandle); IDetailCategoryBuilder& ScriptCategory = DetailLayout->EditCategory(Name, DisplayName); //Script TSharedPtr<IPropertyHandle> ScriptHandle = ScriptPropsHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraEmitterScriptProperties, Script)); ScriptCategory.AddProperty(ScriptHandle); //Constants bool bGenerateHeader = false; bool bDisplayResetToDefault = false; TSharedPtr<IPropertyHandle> Constants = ScriptPropsHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraEmitterScriptProperties, ExternalConstants)); DetailLayout->HideProperty(Constants); //Scalar Constants. TSharedPtr<IPropertyHandle> ScalarConstants = Constants->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstants, ScalarConstants)); TSharedRef<FDetailArrayBuilder> ScalarConstantsBuilder = MakeShareable(new FDetailArrayBuilder(ScalarConstants.ToSharedRef(), bGenerateHeader, bDisplayResetToDefault)); ScalarConstantsBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FNiagaraEmitterPropertiesDetails::OnGenerateScalarConstantEntry)); ScriptCategory.AddCustomBuilder(ScalarConstantsBuilder); //Vector Constants. TSharedPtr<IPropertyHandle> VectorConstants = Constants->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstants, VectorConstants)); TSharedRef<FDetailArrayBuilder> VectorConstantsBuilder = MakeShareable(new FDetailArrayBuilder(VectorConstants.ToSharedRef(), bGenerateHeader, bDisplayResetToDefault)); VectorConstantsBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FNiagaraEmitterPropertiesDetails::OnGenerateVectorConstantEntry)); ScriptCategory.AddCustomBuilder(VectorConstantsBuilder); //Matrix Constants. TSharedPtr<IPropertyHandle> MatrixConstants = Constants->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstants, MatrixConstants)); TSharedRef<FDetailArrayBuilder> MatrixConstantsBuilder = MakeShareable(new FDetailArrayBuilder(MatrixConstants.ToSharedRef(), bGenerateHeader, bDisplayResetToDefault)); MatrixConstantsBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FNiagaraEmitterPropertiesDetails::OnGenerateMatrixConstantEntry)); ScriptCategory.AddCustomBuilder(MatrixConstantsBuilder); //DataObject Constants. TSharedPtr<IPropertyHandle> DataObjectConstants = Constants->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstants, DataObjectConstants)); TSharedRef<FDetailArrayBuilder> DataObjectConstantsBuilder = MakeShareable(new FDetailArrayBuilder(DataObjectConstants.ToSharedRef(), bGenerateHeader, bDisplayResetToDefault)); DataObjectConstantsBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FNiagaraEmitterPropertiesDetails::OnGenerateDataObjectConstantEntry)); ScriptCategory.AddCustomBuilder(DataObjectConstantsBuilder); //Events bGenerateHeader = true; //Generators TSharedPtr<IPropertyHandle> EventGenerators = ScriptPropsHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraEmitterScriptProperties, EventGenerators)); TSharedRef<FDetailArrayBuilder> EventGeneratorsBuilder = MakeShareable(new FDetailArrayBuilder(EventGenerators.ToSharedRef(), bGenerateHeader, bDisplayResetToDefault)); EventGeneratorsBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FNiagaraEmitterPropertiesDetails::OnGenerateEventGeneratorEntry)); ScriptCategory.AddCustomBuilder(EventGeneratorsBuilder); //Receivers TSharedPtr<IPropertyHandle> EventReceivers = ScriptPropsHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraEmitterScriptProperties, EventReceivers)); TSharedRef<FDetailArrayBuilder> EventReceiversBuilder = MakeShareable(new FDetailArrayBuilder(EventReceivers.ToSharedRef(), bGenerateHeader, bDisplayResetToDefault)); EventReceiversBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FNiagaraEmitterPropertiesDetails::OnGenerateEventReceiverEntry)); ScriptCategory.AddCustomBuilder(EventReceiversBuilder); }
void SPropertyEditorText::Construct( const FArguments& InArgs, const TSharedRef< class FPropertyEditor >& InPropertyEditor ) { PropertyEditor = InPropertyEditor; const UProperty* Property = InPropertyEditor->GetProperty(); TSharedPtr<SHorizontalBox> HorizontalBox; bIsFNameProperty = Property->IsA<UNameProperty>(); bool bIsPassword = Property->GetBoolMetaData("PasswordField"); bIsMultiLine = Property->GetBoolMetaData("MultiLine"); if(bIsMultiLine) { ChildSlot [ SAssignNew(HorizontalBox, SHorizontalBox) +SHorizontalBox::Slot() .FillWidth(1.0f) [ SAssignNew(MultiLineWidget, SMultiLineEditableTextBox) .Text(InPropertyEditor, &FPropertyEditor::GetValueAsText) .Font(InArgs._Font) .SelectAllTextWhenFocused(false) .ClearKeyboardFocusOnCommit(false) .OnTextCommitted(this, &SPropertyEditorText::OnTextCommitted) .OnTextChanged(this, &SPropertyEditorText::OnMultiLineTextChanged) .SelectAllTextOnCommit(false) .IsReadOnly(this, &SPropertyEditorText::IsReadOnly) .AutoWrapText(true) .ModiferKeyForNewLine(EModifierKey::Shift) .IsPassword( bIsPassword ) ] ]; PrimaryWidget = MultiLineWidget; } else { ChildSlot [ SAssignNew(HorizontalBox, SHorizontalBox) +SHorizontalBox::Slot() .FillWidth(1.0f) [ SAssignNew( SingleLineWidget, SEditableTextBox ) .Text( InPropertyEditor, &FPropertyEditor::GetValueAsText ) .Font( InArgs._Font ) .SelectAllTextWhenFocused( true ) .ClearKeyboardFocusOnCommit(false) .OnTextCommitted( this, &SPropertyEditorText::OnTextCommitted ) .OnTextChanged( this, &SPropertyEditorText::OnSingleLineTextChanged ) .SelectAllTextOnCommit( true ) .IsReadOnly(this, &SPropertyEditorText::IsReadOnly) .IsPassword( bIsPassword ) ] ]; PrimaryWidget = SingleLineWidget; } if( InPropertyEditor->PropertyIsA( UObjectPropertyBase::StaticClass() ) ) { // Object properties should display their entire text in a tooltip PrimaryWidget->SetToolTipText( TAttribute<FText>( InPropertyEditor, &FPropertyEditor::GetValueAsText ) ); } SetEnabled( TAttribute<bool>( this, &SPropertyEditorText::CanEdit ) ); }
/** * Execute the Json test cases * * @return true if the test was successful, false otherwise */ bool FJsonAutomationTest::RunTest(const FString& Parameters) { // Null Case { const FString InputString = TEXT(""); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString ); TSharedPtr<FJsonObject> Object; check( FJsonSerializer::Deserialize( Reader, Object ) == false ); check( !Object.IsValid() ); } // Empty Object Case { const FString InputString = TEXT("{}"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString ); TSharedPtr<FJsonObject> Object; check( FJsonSerializer::Deserialize( Reader, Object ) ); check( Object.IsValid() ); FString OutputString; TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString ); check( FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ) ); check( InputString == OutputString ); } // Empty Array Case { const FString InputString = TEXT("[]"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString ); TArray< TSharedPtr<FJsonValue> > Array; check( FJsonSerializer::Deserialize( Reader, Array ) ); check( Array.Num() == 0 ); FString OutputString; TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString ); check( FJsonSerializer::Serialize( Array, Writer ) ); check( InputString == OutputString ); } // Simple Array Case { const FString InputString = TEXT("[") TEXT( "{") TEXT( "\"Value\":\"Some String\"") TEXT( "}") TEXT("]"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString ); TArray< TSharedPtr<FJsonValue> > Array; bool bSuccessful = FJsonSerializer::Deserialize(Reader, Array); check(bSuccessful); check( Array.Num() == 1 ); check( Array[0].IsValid() ); TSharedPtr< FJsonObject > Object = Array[0]->AsObject(); check( Object.IsValid() ); check( Object->GetStringField( TEXT("Value") ) == TEXT("Some String") ); FString OutputString; TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString ); check( FJsonSerializer::Serialize( Array, Writer ) ); check( InputString == OutputString ); } // Object Array Case { const FString InputString = TEXT("[") TEXT( "{") TEXT( "\"Value\":\"Some String1\"") TEXT( "},") TEXT( "{") TEXT( "\"Value\":\"Some String2\"") TEXT( "},") TEXT( "{") TEXT( "\"Value\":\"Some String3\"") TEXT( "}") TEXT("]"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(InputString); TArray< TSharedPtr<FJsonValue> > Array; bool bSuccessful = FJsonSerializer::Deserialize(Reader, Array); check(bSuccessful); check(Array.Num() == 3); check(Array[0].IsValid()); check(Array[1].IsValid()); check(Array[2].IsValid()); TSharedPtr< FJsonObject > Object = Array[0]->AsObject(); check(Object.IsValid()); check(Object->GetStringField(TEXT("Value")) == TEXT("Some String1")); Object = Array[1]->AsObject(); check(Object.IsValid()); check(Object->GetStringField(TEXT("Value")) == TEXT("Some String2")); Object = Array[2]->AsObject(); check(Object.IsValid()); check(Object->GetStringField(TEXT("Value")) == TEXT("Some String3")); FString OutputString; TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create(&OutputString); check(FJsonSerializer::Serialize(Array, Writer)); check(InputString == OutputString); } // Number Array Case { const FString InputString = TEXT("[") TEXT("10,") TEXT("20,") TEXT("30,") TEXT("40") TEXT("]"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(InputString); TArray< TSharedPtr<FJsonValue> > Array; bool bSuccessful = FJsonSerializer::Deserialize(Reader, Array); check(bSuccessful); check(Array.Num() == 4); check(Array[0].IsValid()); check(Array[1].IsValid()); check(Array[2].IsValid()); check(Array[3].IsValid()); double Number = Array[0]->AsNumber(); check(Number == 10); Number = Array[1]->AsNumber(); check(Number == 20); Number = Array[2]->AsNumber(); check(Number == 30); Number = Array[3]->AsNumber(); check(Number == 40); FString OutputString; TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create(&OutputString); check(FJsonSerializer::Serialize(Array, Writer)); check(InputString == OutputString); } // String Array Case { const FString InputString = TEXT("[") TEXT("\"Some String1\",") TEXT("\"Some String2\",") TEXT("\"Some String3\",") TEXT("\"Some String4\"") TEXT("]"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(InputString); TArray< TSharedPtr<FJsonValue> > Array; bool bSuccessful = FJsonSerializer::Deserialize(Reader, Array); check(bSuccessful); check(Array.Num() == 4); check(Array[0].IsValid()); check(Array[1].IsValid()); check(Array[2].IsValid()); check(Array[3].IsValid()); FString Text = Array[0]->AsString(); check(Text == TEXT("Some String1")); Text = Array[1]->AsString(); check(Text == TEXT("Some String2")); Text = Array[2]->AsString(); check(Text == TEXT("Some String3")); Text = Array[3]->AsString(); check(Text == TEXT("Some String4")); FString OutputString; TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create(&OutputString); check(FJsonSerializer::Serialize(Array, Writer)); check(InputString == OutputString); } // Complex Array Case { const FString InputString = TEXT("[") TEXT( "\"Some String1\",") TEXT( "10,") TEXT( "{") TEXT( "\"Value\":\"Some String3\"") TEXT( "},") TEXT( "[") TEXT( "\"Some String4\",") TEXT( "\"Some String5\"") TEXT( "],") TEXT( "true,") TEXT( "null") TEXT("]"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(InputString); TArray< TSharedPtr<FJsonValue> > Array; bool bSuccessful = FJsonSerializer::Deserialize(Reader, Array); check(bSuccessful); check(Array.Num() == 6); check(Array[0].IsValid()); check(Array[1].IsValid()); check(Array[2].IsValid()); check(Array[3].IsValid()); check(Array[4].IsValid()); check(Array[5].IsValid()); FString Text = Array[0]->AsString(); check(Text == TEXT("Some String1")); double Number = Array[1]->AsNumber(); check(Number == 10); TSharedPtr< FJsonObject > Object = Array[2]->AsObject(); check(Object.IsValid()); check(Object->GetStringField(TEXT("Value")) == TEXT("Some String3")); const TArray<TSharedPtr< FJsonValue >>& InnerArray = Array[3]->AsArray(); check(InnerArray.Num() == 2); check(Array[0].IsValid()); check(Array[1].IsValid()); Text = InnerArray[0]->AsString(); check(Text == TEXT("Some String4")); Text = InnerArray[1]->AsString(); check(Text == TEXT("Some String5")); bool Boolean = Array[4]->AsBool(); check(Boolean == true); check(Array[5]->IsNull() == true); FString OutputString; TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create(&OutputString); check(FJsonSerializer::Serialize(Array, Writer)); check(InputString == OutputString); } // String Test { const FString InputString = TEXT("{") TEXT( "\"Value\":\"Some String, Escape Chars: \\\\, \\\", \\/, \\b, \\f, \\n, \\r, \\t, \\u002B\"") TEXT("}"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString ); TSharedPtr<FJsonObject> Object; bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object); check(bSuccessful); check( Object.IsValid() ); const TSharedPtr<FJsonValue>* Value = Object->Values.Find(TEXT("Value")); check(Value && (*Value)->Type == EJson::String); const FString String = (*Value)->AsString(); check(String == TEXT("Some String, Escape Chars: \\, \", /, \b, \f, \n, \r, \t, +")); FString OutputString; TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString ); check( FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ) ); const FString TestOutput = TEXT("{") TEXT( "\"Value\":\"Some String, Escape Chars: \\\\, \\\", /, \\b, \\f, \\n, \\r, \\t, +\"") TEXT("}"); check(OutputString == TestOutput); } // Number Test { const FString InputString = TEXT("{") TEXT( "\"Value1\":2.544e+15,") TEXT( "\"Value2\":-0.544E-2,") TEXT( "\"Value3\":251e3,") TEXT( "\"Value4\":-0.0,") TEXT( "\"Value5\":843") TEXT("}"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString ); TSharedPtr<FJsonObject> Object; bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object); check(bSuccessful); check( Object.IsValid() ); double TestValues[] = {2.544e+15, -0.544e-2, 251e3, -0.0, 843}; for (int32 i = 0; i < 5; ++i) { const TSharedPtr<FJsonValue>* Value = Object->Values.Find(FString::Printf(TEXT("Value%i"), i + 1)); check(Value && (*Value)->Type == EJson::Number); const double Number = (*Value)->AsNumber(); check(Number == TestValues[i]); } FString OutputString; TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString ); check( FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ) ); // %g isn't standardized, so we use the same %g format that is used inside PrintJson instead of hardcoding the values here const FString TestOutput = FString::Printf( TEXT("{") TEXT( "\"Value1\":%.17g,") TEXT( "\"Value2\":%.17g,") TEXT( "\"Value3\":%.17g,") TEXT( "\"Value4\":%.17g,") TEXT( "\"Value5\":%.17g") TEXT("}"), TestValues[0], TestValues[1], TestValues[2], TestValues[3], TestValues[4]); check(OutputString == TestOutput); } // Boolean/Null Test { const FString InputString = TEXT("{") TEXT( "\"Value1\":true,") TEXT( "\"Value2\":true,") TEXT( "\"Value3\":faLsE,") TEXT( "\"Value4\":null,") TEXT( "\"Value5\":NULL") TEXT("}"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString ); TSharedPtr<FJsonObject> Object; bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object); check(bSuccessful); check( Object.IsValid() ); bool TestValues[] = {true, true, false}; for (int32 i = 0; i < 5; ++i) { const TSharedPtr<FJsonValue>* Value = Object->Values.Find(FString::Printf(TEXT("Value%i"), i + 1)); check(Value); if (i < 3) { check((*Value)->Type == EJson::Boolean); const bool Bool = (*Value)->AsBool(); check(Bool == TestValues[i]); } else { check((*Value)->Type == EJson::Null); check((*Value)->IsNull()); } } FString OutputString; TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString ); check( FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ) ); const FString TestOutput = TEXT("{") TEXT( "\"Value1\":true,") TEXT( "\"Value2\":true,") TEXT( "\"Value3\":false,") TEXT( "\"Value4\":null,") TEXT( "\"Value5\":null") TEXT("}"); check(OutputString == TestOutput); } // Object Test && extra whitespace test { const FString InputStringWithExtraWhitespace = TEXT(" \n\r\n {") TEXT( "\"Object\":") TEXT( "{") TEXT( "\"NestedValue\":null,") TEXT( "\"NestedObject\":{}") TEXT( "},") TEXT( "\"Value\":true") TEXT("} \n\r\n "); const FString InputString = TEXT("{") TEXT( "\"Object\":") TEXT( "{") TEXT( "\"NestedValue\":null,") TEXT( "\"NestedObject\":{}") TEXT( "},") TEXT( "\"Value\":true") TEXT("}"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputStringWithExtraWhitespace ); TSharedPtr<FJsonObject> Object; bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object); check(bSuccessful); check( Object.IsValid() ); const TSharedPtr<FJsonValue>* InnerValueFail = Object->Values.Find(TEXT("InnerValue")); check(!InnerValueFail); const TSharedPtr<FJsonValue>* ObjectValue = Object->Values.Find(TEXT("Object")); check(ObjectValue && (*ObjectValue)->Type == EJson::Object); const TSharedPtr<FJsonObject> InnerObject = (*ObjectValue)->AsObject(); check(InnerObject.IsValid()); { const TSharedPtr<FJsonValue>* NestedValueValue = InnerObject->Values.Find(TEXT("NestedValue")); check(NestedValueValue && (*NestedValueValue)->Type == EJson::Null); check((*NestedValueValue)->IsNull()); const TSharedPtr<FJsonValue>* NestedObjectValue = InnerObject->Values.Find(TEXT("NestedObject")); check(NestedObjectValue && (*NestedObjectValue)->Type == EJson::Object); const TSharedPtr<FJsonObject> InnerInnerObject = (*NestedObjectValue)->AsObject(); check(InnerInnerObject.IsValid()); { const TSharedPtr<FJsonValue>* NestedValueValueFail = InnerInnerObject->Values.Find(TEXT("NestedValue")); check(!NestedValueValueFail); } } const TSharedPtr<FJsonValue>* ValueValue = Object->Values.Find(TEXT("Value")); check(ValueValue && (*ValueValue)->Type == EJson::Boolean); const bool Bool = (*ValueValue)->AsBool(); check(Bool); FString OutputString; TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString ); check( FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ) ); check(OutputString == InputString); } // Array Test { const FString InputString = TEXT("{") TEXT( "\"Array\":") TEXT( "[") TEXT( "[],") TEXT( "\"Some String\",") TEXT( "\"Another String\",") TEXT( "null,") TEXT( "true,") TEXT( "false,") TEXT( "45,") TEXT( "{}") TEXT( "]") TEXT("}"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString ); TSharedPtr<FJsonObject> Object; bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object); check(bSuccessful); check( Object.IsValid() ); const TSharedPtr<FJsonValue>* InnerValueFail = Object->Values.Find(TEXT("InnerValue")); check(!InnerValueFail); const TSharedPtr<FJsonValue>* ArrayValue = Object->Values.Find(TEXT("Array")); check(ArrayValue && (*ArrayValue)->Type == EJson::Array); const TArray< TSharedPtr<FJsonValue> > Array = (*ArrayValue)->AsArray(); check(Array.Num() == 8); EJson ValueTypes[] = {EJson::Array, EJson::String, EJson::String, EJson::Null, EJson::Boolean, EJson::Boolean, EJson::Number, EJson::Object}; for (int32 i = 0; i < Array.Num(); ++i) { const TSharedPtr<FJsonValue>& Value = Array[i]; check(Value.IsValid()); check(Value->Type == ValueTypes[i]); } const TArray< TSharedPtr<FJsonValue> >& InnerArray = Array[0]->AsArray(); check(InnerArray.Num() == 0); check(Array[1]->AsString() == TEXT("Some String")); check(Array[2]->AsString() == TEXT("Another String")); check(Array[3]->IsNull()); check(Array[4]->AsBool()); check(!Array[5]->AsBool()); check(FMath::Abs(Array[6]->AsNumber() - 45.f) < KINDA_SMALL_NUMBER); const TSharedPtr<FJsonObject> InnerObject = Array[7]->AsObject(); check(InnerObject.IsValid()); FString OutputString; TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString ); check( FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ) ); check(OutputString == InputString); } // Pretty Print Test { const FString InputString = TEXT("{") LINE_TERMINATOR TEXT(" \"Data1\": \"value\",") LINE_TERMINATOR TEXT(" \"Data2\": \"value\",") LINE_TERMINATOR TEXT(" \"Array\": [") LINE_TERMINATOR TEXT(" {") LINE_TERMINATOR TEXT(" \"InnerData1\": \"value\"") LINE_TERMINATOR TEXT(" },") LINE_TERMINATOR TEXT(" [],") LINE_TERMINATOR TEXT(" [ 1, 2, 3, 4 ],") LINE_TERMINATOR TEXT(" {") LINE_TERMINATOR TEXT(" },") LINE_TERMINATOR TEXT(" \"value\",") LINE_TERMINATOR TEXT(" \"value\"") LINE_TERMINATOR TEXT(" ],") LINE_TERMINATOR TEXT(" \"Object\":") LINE_TERMINATOR TEXT(" {") LINE_TERMINATOR TEXT(" }") LINE_TERMINATOR TEXT("}"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString ); TSharedPtr<FJsonObject> Object; check( FJsonSerializer::Deserialize( Reader, Object ) ); check( Object.IsValid() ); FString OutputString; TSharedRef< FPrettyJsonStringWriter > Writer = FPrettyJsonStringWriterFactory::Create( &OutputString ); check( FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ) ); check(OutputString == InputString); } // Line and Character # test { const FString InputString = TEXT("{") LINE_TERMINATOR TEXT(" \"Data1\": \"value\",") LINE_TERMINATOR TEXT(" \"Array\":") LINE_TERMINATOR TEXT(" [") LINE_TERMINATOR TEXT(" 12345,") LINE_TERMINATOR TEXT(" True") LINE_TERMINATOR TEXT(" ],") LINE_TERMINATOR TEXT(" \"Object\":") LINE_TERMINATOR TEXT(" {") LINE_TERMINATOR TEXT(" }") LINE_TERMINATOR TEXT("}"); TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString ); EJsonNotation Notation = EJsonNotation::Null; check( Reader->ReadNext( Notation ) && Notation == EJsonNotation::ObjectStart ); check( Reader->GetLineNumber() == 1 && Reader->GetCharacterNumber() == 1 ); check( Reader->ReadNext( Notation ) && Notation == EJsonNotation::String ); check( Reader->GetLineNumber() == 2 && Reader->GetCharacterNumber() == 17 ); check( Reader->ReadNext( Notation ) && Notation == EJsonNotation::ArrayStart ); check( Reader->GetLineNumber() == 4 && Reader->GetCharacterNumber() == 2 ); check( Reader->ReadNext( Notation ) && Notation == EJsonNotation::Number ); check( Reader->GetLineNumber() == 5 && Reader->GetCharacterNumber() == 7 ); check( Reader->ReadNext( Notation ) && Notation == EJsonNotation::Boolean ); check( Reader->GetLineNumber() == 6 && Reader->GetCharacterNumber() == 6 ); } // Failure Cases TArray<FString> FailureInputs; // Unclosed Object FailureInputs.Add( TEXT("{")); // Values in Object without identifiers FailureInputs.Add( TEXT("{") TEXT( "\"Value1\",") TEXT( "\"Value2\",") TEXT( "43") TEXT("}")); // Unexpected End Of Input Found FailureInputs.Add( TEXT("{") TEXT( "\"Object\":") TEXT( "{") TEXT( "\"NestedValue\":null,")); // Missing first brace FailureInputs.Add( TEXT( "\"Object\":") TEXT( "{") TEXT( "\"NestedValue\":null,") TEXT( "\"NestedObject\":{}") TEXT( "},") TEXT( "\"Value\":true") TEXT("}")); // Missing last character FailureInputs.Add( TEXT("{") TEXT( "\"Object\":") TEXT( "{") TEXT( "\"NestedValue\":null,") TEXT( "\"NestedObject\":{}") TEXT( "},") TEXT( "\"Value\":true")); // Extra last character FailureInputs.Add( TEXT("{") TEXT( "\"Object\":") TEXT( "{") TEXT( "\"NestedValue\":null,") TEXT( "\"NestedObject\":{}") TEXT( "},") TEXT( "\"Value\":true") TEXT("}0")); // Missing comma FailureInputs.Add( TEXT("{") TEXT( "\"Value1\":null,") TEXT( "\"Value2\":\"string\"") TEXT( "\"Value3\":65.3") TEXT("}")); // Extra comma FailureInputs.Add( TEXT("{") TEXT( "\"Value1\":null,") TEXT( "\"Value2\":\"string\",") TEXT( "\"Value3\":65.3,") TEXT("}")); // Badly formed true/false/null FailureInputs.Add(TEXT("{\"Value\":tru}")); FailureInputs.Add(TEXT("{\"Value\":full}")); FailureInputs.Add(TEXT("{\"Value\":nulle}")); FailureInputs.Add(TEXT("{\"Value\":n%ll}")); // Floating Point Failures FailureInputs.Add(TEXT("{\"Value\":65.3e}")); FailureInputs.Add(TEXT("{\"Value\":65.}")); FailureInputs.Add(TEXT("{\"Value\":.7}")); FailureInputs.Add(TEXT("{\"Value\":+6}")); FailureInputs.Add(TEXT("{\"Value\":01}")); FailureInputs.Add(TEXT("{\"Value\":00.56}")); FailureInputs.Add(TEXT("{\"Value\":-1.e+4}")); FailureInputs.Add(TEXT("{\"Value\":2e+}")); // Bad Escape Characters FailureInputs.Add(TEXT("{\"Value\":\"Hello\\xThere\"}")); FailureInputs.Add(TEXT("{\"Value\":\"Hello\\u123There\"}")); FailureInputs.Add(TEXT("{\"Value\":\"Hello\\RThere\"}")); for (int32 i = 0; i < FailureInputs.Num(); ++i) { TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( FailureInputs[i] ); TSharedPtr<FJsonObject> Object; check( FJsonSerializer::Deserialize( Reader, Object ) == false ); check( !Object.IsValid() ); } return true; }
bool FPerforceUpdateStatusWorker::Execute(FPerforceSourceControlCommand& InCommand) { #if USE_P4_API FScopedPerforceConnection ScopedConnection(InCommand); if (!InCommand.IsCanceled() && ScopedConnection.IsValid()) { FPerforceConnection& Connection = ScopedConnection.GetConnection(); if(InCommand.Files.Num()) { // See http://www.perforce.com/perforce/doc.current/manuals/cmdref/p4_fstat.html // for full reference info on fstat command parameters... TArray<FString> Parameters; // We want to include integration record information: Parameters.Add(TEXT("-Or")); // Mandatory parameters (the list of files to stat): for (FString& File : InCommand.Files) { if (IFileManager::Get().DirectoryExists(*File)) { // If the file is a directory, do a recursive fstat on the contents File /= TEXT("..."); } Parameters.Add(File); } FP4RecordSet Records; InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("fstat"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); ParseUpdateStatusResults(Records, InCommand.ErrorMessages, OutStates); RemoveRedundantErrors(InCommand, TEXT(" - no such file(s).")); RemoveRedundantErrors(InCommand, TEXT("' is not under client's root '")); } else { InCommand.bCommandSuccessful = true; } // update using any special hints passed in via the operation check(InCommand.Operation->GetName() == GetName()); TSharedRef<FUpdateStatus, ESPMode::ThreadSafe> Operation = StaticCastSharedRef<FUpdateStatus>(InCommand.Operation); if(Operation->ShouldUpdateHistory()) { TArray<FString> Parameters; FP4RecordSet Records; // disregard non-contributory integrations Parameters.Add(TEXT("-s")); //include branching history Parameters.Add(TEXT("-i")); //include truncated change list descriptions Parameters.Add(TEXT("-L")); //include time stamps Parameters.Add(TEXT("-t")); //limit to last 100 changes Parameters.Add(TEXT("-m 100")); Parameters.Append(InCommand.Files); InCommand.bCommandSuccessful &= Connection.RunCommand(TEXT("filelog"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); ParseHistoryResults(Records, OutStates, OutHistory); RemoveRedundantErrors(InCommand, TEXT(" - no such file(s).")); RemoveRedundantErrors(InCommand, TEXT(" - file(s) not on client")); RemoveRedundantErrors(InCommand, TEXT("' is not under client's root '")); } if(Operation->ShouldGetOpenedOnly()) { const FString ContentFolder = FPaths::ConvertRelativePathToFull(FPaths::RootDir()); const FString FileQuery = FString::Printf(TEXT("%s..."), *ContentFolder); TArray<FString> Parameters = InCommand.Files; Parameters.Add(FileQuery); FP4RecordSet Records; InCommand.bCommandSuccessful &= Connection.RunCommand(TEXT("opened"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); ParseOpenedResults(Records, ANSI_TO_TCHAR(Connection.P4Client.GetClient().Text()), Connection.ClientRoot, OutStateMap); RemoveRedundantErrors(InCommand, TEXT(" - no such file(s).")); RemoveRedundantErrors(InCommand, TEXT("' is not under client's root '")); } if(Operation->ShouldUpdateModifiedState()) { TArray<FString> Parameters; FP4RecordSet Records; // Query for open files different than the versions stored in Perforce Parameters.Add(TEXT("-sa")); Parameters.Append(InCommand.Files); InCommand.bCommandSuccessful &= Connection.RunCommand(TEXT("diff"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); // Parse the results and store them in the command ParseDiffResults(Records, OutModifiedFiles); RemoveRedundantErrors(InCommand, TEXT(" - no such file(s).")); RemoveRedundantErrors(InCommand, TEXT(" - file(s) not opened for edit")); RemoveRedundantErrors(InCommand, TEXT("' is not under client's root '")); } } #endif return InCommand.bCommandSuccessful; }
void SAuthorizingPlugin::Construct(const FArguments& InArgs, const TSharedRef<SWindow>& InParentWindow, const FText& InPluginFriendlyName, const FString& InPluginItemId, const FString& InPluginOfferId, TFunction<void()> InAuthorizedCallback) { CurrentState = EPluginAuthorizationState::Initializing; WaitingTime = 0; ParentWindow = InParentWindow; PluginFriendlyName = InPluginFriendlyName; PluginItemId = InPluginItemId; PluginOfferId = InPluginOfferId; AuthorizedCallback = InAuthorizedCallback; InParentWindow->SetOnWindowClosed(FOnWindowClosed::CreateSP(this, &SAuthorizingPlugin::OnWindowClosed)); bUserInterrupted = true; RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &SAuthorizingPlugin::RefreshStatus)); ChildSlot [ SNew(SBox) .MinDesiredWidth(500) [ SNew(SBorder) .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) [ SNew(SVerticalBox) + SVerticalBox::Slot() .FillHeight(1.0f) .Padding(10, 30, 10, 20) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) [ SNew(SThrobber) ] + SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) .Padding(10, 0) [ SNew(STextBlock) .Text(this, &SAuthorizingPlugin::GetWaitingText) .Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 12)) ] ] + SVerticalBox::Slot() .AutoHeight() .HAlign(HAlign_Right) .Padding(10) [ SNew(SButton) .Text(LOCTEXT("CancelText", "Cancel")) .OnClicked(this, &SAuthorizingPlugin::OnCancel) ] ] ] ]; TSharedRef<IPortalServiceLocator> ServiceLocator = GEditor->GetServiceLocator(); PortalWindowService = ServiceLocator->GetServiceRef<IPortalApplicationWindow>(); PortalUserService = ServiceLocator->GetServiceRef<IPortalUser>(); PortalUserLoginService = ServiceLocator->GetServiceRef<IPortalUserLogin>(); }
bool SPropertyEditorBool::Supports( const TSharedRef< class FPropertyEditor >& PropertyEditor ) { return PropertyEditor->PropertyIsA( UBoolProperty::StaticClass() ); }
void SPropertyEditorAsset::Construct( const FArguments& InArgs, const TSharedPtr<FPropertyEditor>& InPropertyEditor ) { PropertyEditor = InPropertyEditor; PropertyHandle = InArgs._PropertyHandle; OnSetObject = InArgs._OnSetObject; OnShouldFilterAsset = InArgs._OnShouldFilterAsset; UProperty* Property = nullptr; if(PropertyEditor.IsValid()) { Property = PropertyEditor->GetPropertyNode()->GetProperty(); UObjectPropertyBase* ObjectProperty = Cast<UObjectPropertyBase>(Property); check(ObjectProperty); bAllowClear = !(Property->PropertyFlags & CPF_NoClear); ObjectClass = ObjectProperty->PropertyClass; bIsActor = ObjectProperty->PropertyClass->IsChildOf( AActor::StaticClass() ); } else { bAllowClear = InArgs._AllowClear; ObjectPath = InArgs._ObjectPath; ObjectClass = InArgs._Class; bIsActor = ObjectClass->IsChildOf( AActor::StaticClass() ); if (PropertyHandle.IsValid() && PropertyHandle->IsValidHandle()) { Property = PropertyHandle->GetProperty(); } else { CustomClassFilters.Add(ObjectClass); } } // Account for the allowed classes specified in the property metadata if (Property) { FString ClassFilterString; if (UArrayProperty* ArrayParent = Cast<UArrayProperty>(Property->GetOuter())) { ClassFilterString = ArrayParent->GetMetaData("AllowedClasses"); } else { ClassFilterString = Property->GetMetaData("AllowedClasses"); } if (ClassFilterString.IsEmpty()) { CustomClassFilters.Add(ObjectClass); } else { TArray<FString> CustomClassFilterNames; ClassFilterString.ParseIntoArray(CustomClassFilterNames, TEXT(","), true); for (auto It = CustomClassFilterNames.CreateConstIterator(); It; ++It) { const FString& ClassName = *It; UClass* Class = FindObject<UClass>(ANY_PACKAGE, *ClassName); if (!Class) { Class = LoadObject<UClass>(nullptr, *ClassName); } if (Class) { // If the class is an interface, expand it to be all classes in memory that implement the class. if (Class->HasAnyClassFlags(CLASS_Interface)) { for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt) { UClass* const ClassWithInterface = (*ClassIt); if (ClassWithInterface->ImplementsInterface(Class)) { CustomClassFilters.Add(ClassWithInterface); } } } else { CustomClassFilters.Add(Class); } } } } } if (InArgs._NewAssetFactories.IsSet()) { NewAssetFactories = InArgs._NewAssetFactories.GetValue(); } else if (CustomClassFilters.Num() > 1 || !CustomClassFilters.Contains(UObject::StaticClass())) { NewAssetFactories = PropertyCustomizationHelpers::GetNewAssetFactoriesForClasses(CustomClassFilters); } TSharedPtr<SHorizontalBox> ValueContentBox = NULL; ChildSlot [ SNew( SAssetDropTarget ) .OnIsAssetAcceptableForDrop( this, &SPropertyEditorAsset::OnAssetDraggedOver ) .OnAssetDropped( this, &SPropertyEditorAsset::OnAssetDropped ) [ SAssignNew( ValueContentBox, SHorizontalBox ) ] ]; TAttribute<bool> IsEnabledAttribute(this, &SPropertyEditorAsset::CanEdit); TAttribute<FText> TooltipAttribute(this, &SPropertyEditorAsset::OnGetToolTip); if (Property && Property->HasAllPropertyFlags(CPF_DisableEditOnTemplate)) { // There are some cases where editing an Actor Property is not allowed, such as when it is contained within a struct or a CDO TArray<UObject*> ObjectList; PropertyEditor->GetPropertyHandle()->GetOuterObjects(ObjectList); // If there is no objects, that means we must have a struct asset managing this property if (ObjectList.Num() == 0) { IsEnabledAttribute.Set(false); TooltipAttribute.Set(LOCTEXT("VariableHasDisableEditOnTemplate", "Editing this value in structure's defaults is not allowed")); } else { // Go through all the found objects and see if any are a CDO, we can't set an actor in a CDO default. for (UObject* Obj : ObjectList) { if (Obj->HasAllFlags(RF_ClassDefaultObject)) { IsEnabledAttribute.Set(false); TooltipAttribute.Set(LOCTEXT("VariableHasDisableEditOnTemplateTooltip", "Editing this value in a Class Default Object is not allowed")); break; } } } } AssetComboButton = SNew(SComboButton) .ToolTipText(TooltipAttribute) .ButtonStyle( FEditorStyle::Get(), "PropertyEditor.AssetComboStyle" ) .ForegroundColor(FEditorStyle::GetColor("PropertyEditor.AssetName.ColorAndOpacity")) .OnGetMenuContent( this, &SPropertyEditorAsset::OnGetMenuContent ) .OnMenuOpenChanged( this, &SPropertyEditorAsset::OnMenuOpenChanged ) .IsEnabled( IsEnabledAttribute ) .ContentPadding(2.0f) .ButtonContent() [ // Show the name of the asset or actor SNew(STextBlock) .TextStyle( FEditorStyle::Get(), "PropertyEditor.AssetClass" ) .Font( FEditorStyle::GetFontStyle( PropertyEditorConstants::PropertyFontStyle ) ) .Text(this,&SPropertyEditorAsset::OnGetAssetName) ]; TSharedRef<SHorizontalBox> ButtonBox = SNew( SHorizontalBox ); TSharedPtr<SVerticalBox> CustomContentBox; if( ShouldDisplayThumbnail(InArgs) ) { FObjectOrAssetData Value; GetValue( Value ); AssetThumbnail = MakeShareable( new FAssetThumbnail( Value.AssetData, InArgs._ThumbnailSize.X, InArgs._ThumbnailSize.Y, InArgs._ThumbnailPool ) ); ValueContentBox->AddSlot() .Padding( 0.0f, 0.0f, 2.0f, 0.0f ) .AutoWidth() [ SAssignNew( ThumbnailBorder, SBorder ) .Padding( 5.0f ) .BorderImage( this, &SPropertyEditorAsset::GetThumbnailBorder ) .OnMouseDoubleClick( this, &SPropertyEditorAsset::OnAssetThumbnailDoubleClick ) [ SNew( SBox ) .ToolTipText(TooltipAttribute) .WidthOverride( InArgs._ThumbnailSize.X ) .HeightOverride( InArgs._ThumbnailSize.Y ) [ AssetThumbnail->MakeThumbnailWidget() ] ] ]; ValueContentBox->AddSlot() [ SNew( SBox ) .VAlign( VAlign_Center ) [ SAssignNew( CustomContentBox, SVerticalBox ) + SVerticalBox::Slot() [ AssetComboButton.ToSharedRef() ] + SVerticalBox::Slot() .AutoHeight() .Padding( 0.0f, 2.0f, 4.0f, 2.0f ) [ ButtonBox ] ] ]; } else { ValueContentBox->AddSlot() [ SAssignNew( CustomContentBox, SVerticalBox ) +SVerticalBox::Slot() .VAlign( VAlign_Center ) [ SNew( SHorizontalBox ) + SHorizontalBox::Slot() [ AssetComboButton.ToSharedRef() ] + SHorizontalBox::Slot() .AutoWidth() .Padding( 4.f, 0.f ) [ ButtonBox ] ] ]; } if( InArgs._CustomContentSlot.Widget != SNullWidget::NullWidget ) { CustomContentBox->AddSlot() .VAlign( VAlign_Center ) .Padding( FMargin( 0.0f, 2.0f ) ) [ InArgs._CustomContentSlot.Widget ]; } if( !bIsActor && InArgs._DisplayUseSelected ) { ButtonBox->AddSlot() .VAlign(VAlign_Center) .AutoWidth() .Padding( 2.0f, 0.0f ) [ PropertyCustomizationHelpers::MakeUseSelectedButton( FSimpleDelegate::CreateSP( this, &SPropertyEditorAsset::OnUse ), FText(), IsEnabledAttribute ) ]; } if( InArgs._DisplayBrowse ) { ButtonBox->AddSlot() .Padding( 2.0f, 0.0f ) .AutoWidth() .VAlign(VAlign_Center) [ PropertyCustomizationHelpers::MakeBrowseButton( FSimpleDelegate::CreateSP( this, &SPropertyEditorAsset::OnBrowse ), TAttribute<FText>( this, &SPropertyEditorAsset::GetOnBrowseToolTip ) ) ]; } if( bIsActor ) { TSharedRef<SWidget> ActorPicker = PropertyCustomizationHelpers::MakeInteractiveActorPicker( FOnGetAllowedClasses::CreateSP(this, &SPropertyEditorAsset::OnGetAllowedClasses), FOnShouldFilterActor(), FOnActorSelected::CreateSP( this, &SPropertyEditorAsset::OnActorSelected ) ); ActorPicker->SetEnabled( IsEnabledAttribute ); ButtonBox->AddSlot() .Padding( 2.0f, 0.0f ) .AutoWidth() .VAlign(VAlign_Center) [ ActorPicker ]; } if( InArgs._ResetToDefaultSlot.Widget != SNullWidget::NullWidget ) { TSharedRef<SWidget> ResetToDefaultWidget = InArgs._ResetToDefaultSlot.Widget; ResetToDefaultWidget->SetEnabled( IsEnabledAttribute ); ButtonBox->AddSlot() .Padding( 4.0f, 0.0f ) .AutoWidth() .VAlign(VAlign_Center) [ ResetToDefaultWidget ]; } }
void FSequencerTimeSliderController::DrawTicks( FSlateWindowElementList& OutDrawElements, const struct FScrubRangeToScreen& RangeToScreen, FDrawTickArgs& InArgs ) const { float MinDisplayTickSpacing = ScrubConstants::MinDisplayTickSpacing; if (SequencerSnapValues::IsTimeSnapIntervalFrameRate(TimeSliderArgs.Settings->GetTimeSnapInterval()) && TimeSliderArgs.Settings->GetShowFrameNumbers()) { MinDisplayTickSpacing = TimeSliderArgs.Settings->GetTimeSnapInterval(); } const float Spacing = DetermineOptimalSpacing( RangeToScreen.PixelsPerInput, ScrubConstants::MinPixelsPerDisplayTick, MinDisplayTickSpacing ); // Sub divisions // @todo Sequencer may need more robust calculation const int32 Divider = 10; // For slightly larger halfway tick mark const int32 HalfDivider = Divider / 2; // Find out where to start from int32 OffsetNum = FMath::FloorToInt(RangeToScreen.ViewInput.GetLowerBoundValue() / Spacing); FSlateFontInfo SmallLayoutFont( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 8 ); TArray<FVector2D> LinePoints; LinePoints.AddUninitialized(2); float Seconds = 0; while( (Seconds = OffsetNum*Spacing) < RangeToScreen.ViewInput.GetUpperBoundValue() ) { // X position local to start of the widget area float XPos = RangeToScreen.InputToLocalX( Seconds ); uint32 AbsOffsetNum = FMath::Abs(OffsetNum); if ( AbsOffsetNum % Divider == 0 ) { FVector2D Offset( XPos, InArgs.TickOffset ); FVector2D TickSize( 0.0f, InArgs.MajorTickHeight ); LinePoints[0] = FVector2D( 0.0f,1.0f); LinePoints[1] = TickSize; // lines should not need anti-aliasing const bool bAntiAliasLines = false; // Draw each tick mark FSlateDrawElement::MakeLines( OutDrawElements, InArgs.StartLayer, InArgs.AllottedGeometry.ToPaintGeometry( Offset, TickSize ), LinePoints, InArgs.ClippingRect, InArgs.DrawEffects, InArgs.TickColor, bAntiAliasLines ); if( !InArgs.bOnlyDrawMajorTicks ) { FString FrameString; if (SequencerSnapValues::IsTimeSnapIntervalFrameRate(TimeSliderArgs.Settings->GetTimeSnapInterval()) && TimeSliderArgs.Settings->GetShowFrameNumbers()) { FrameString = FString::Printf( TEXT("%d"), TimeToFrame(Seconds)); } else { FrameString = Spacing == ScrubConstants::MinDisplayTickSpacing ? FString::Printf( TEXT("%.3f"), Seconds ) : FString::Printf( TEXT("%.2f"), Seconds ); } // Space the text between the tick mark but slightly above const TSharedRef< FSlateFontMeasure > FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService(); FVector2D TextSize = FontMeasureService->Measure(FrameString, SmallLayoutFont); FVector2D TextOffset( XPos + 5.f, InArgs.bMirrorLabels ? 3.f : FMath::Abs( InArgs.AllottedGeometry.Size.Y - (InArgs.MajorTickHeight+3.f) ) ); FSlateDrawElement::MakeText( OutDrawElements, InArgs.StartLayer+1, InArgs.AllottedGeometry.ToPaintGeometry( TextOffset, TextSize ), FrameString, SmallLayoutFont, InArgs.ClippingRect, InArgs.DrawEffects, InArgs.TickColor*0.65f ); } } else if( !InArgs.bOnlyDrawMajorTicks ) { // Compute the size of each tick mark. If we are half way between to visible values display a slightly larger tick mark const float MinorTickHeight = AbsOffsetNum % HalfDivider == 0 ? 6.0f : 2.0f; FVector2D Offset(XPos, InArgs.bMirrorLabels ? 0.0f : FMath::Abs( InArgs.AllottedGeometry.Size.Y - MinorTickHeight ) ); FVector2D TickSize(0.0f, MinorTickHeight); LinePoints[0] = FVector2D(0.0f,1.0f); LinePoints[1] = TickSize; const bool bAntiAlias = false; // Draw each sub mark FSlateDrawElement::MakeLines( OutDrawElements, InArgs.StartLayer, InArgs.AllottedGeometry.ToPaintGeometry( Offset, TickSize ), LinePoints, InArgs.ClippingRect, InArgs.DrawEffects, InArgs.TickColor, bAntiAlias ); } // Advance to next tick mark ++OffsetNum; } }
void FEpicSurvey::OnReadFileComplete( bool bSuccess, const FString& DLName ) { if ( bSuccess ) { if ( DLName == SurveyIndexCloudFile.DLName ) { LoadSurveyIndexFile(); } else { int32 FileHeaderIndex = INDEX_NONE; TArray< FCloudFileHeader > FileHeaders; TitleCloud->GetFileList( FileHeaders ); for (int Index = 0; Index < FileHeaders.Num(); Index++) { if ( FileHeaders[ Index ].DLName == DLName ) { FileHeaderIndex = Index; break; } } if ( FileHeaderIndex > INDEX_NONE ) { const FCloudFileHeader FileHeader = FileHeaders[ FileHeaderIndex ]; const FString FileExtension = FPaths::GetExtension( FileHeader.FileName ); if ( FileExtension == TEXT("json") ) { TArray< uint8 > FileContents; TitleCloud->GetFileContents( DLName, FileContents ); FString SurveyJson; FFileHelper::BufferToString( SurveyJson, FileContents.GetData(), FileContents.Num() ); TSharedPtr< FJsonObject > SurveyObject = NULL; TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<TCHAR>::Create( SurveyJson ); if ( FJsonSerializer::Deserialize( Reader, SurveyObject ) ) { TSharedPtr< FSurvey > NewSurvey = FSurvey::Create( SharedThis( this ), SurveyObject.ToSharedRef() ); if ( NewSurvey.IsValid() ) { switch( NewSurvey->GetSurveyType() ) { case ESurveyType::Normal: { auto* Settings = GetDefault<UEditorSettings>(); Surveys.Add( NewSurvey.ToSharedRef() ); const bool IsActiveSurveyInProgress = ActiveSurvey.IsValid() ? Settings->InProgressSurveys.Contains( ActiveSurvey->GetIdentifier() ) : false; if ( !IsActiveSurveyInProgress ) { const bool HasBeenCompleted = Settings->CompletedSurveys.Contains( NewSurvey->GetIdentifier() ); if ( !HasBeenCompleted ) { const bool IsInProgress = Settings->InProgressSurveys.Contains( NewSurvey->GetIdentifier() ); if ( NewSurvey->CanAutoPrompt() ) { SetActiveSurvey( NewSurvey ); } else if ( IsInProgress ) { SetActiveSurvey( NewSurvey ); } } } } break; case ESurveyType::Branch: BranchSurveys.Add( FileHeader.FileName, NewSurvey ); break; } } } else { UE_LOG(LogEpicSurvey, Verbose, TEXT("Parsing JSON survey failed. Filename: %s Message: %s"), *FileHeader.FileName, *Reader->GetErrorMessage()); } } else if ( FileExtension == TEXT("png") ) { TArray< FOnBrushLoaded > MapResults; FilenameToLoadCallbacks.MultiFind( FileHeaders[ FileHeaderIndex ].FileName, MapResults ); if ( MapResults.Num() > 0 ) { TArray< uint8 > FileContents; TitleCloud->GetFileContents( DLName, FileContents ); for (int Index = 0; Index < MapResults.Num(); Index++) { MapResults[ Index ].Execute( LoadRawDataAsBrush( *(FString(TEXT("EpicSurvey.")) + FileHeaders[ FileHeaderIndex ].FileName), FileContents ) ); } FilenameToLoadCallbacks.Remove( FileHeaders[ FileHeaderIndex ].FileName ); } } } } } else { InitializationState = EContentInitializationState::Failure; } }
/** * Open or close the popup * * @param InIsOpen If true, open the popup. Otherwise close it. */ void SMenuAnchor::SetIsOpen( bool InIsOpen, const bool bFocusMenu ) { // Prevent redundant opens/closes if ( IsOpen() != InIsOpen ) { if ( InIsOpen ) { TSharedPtr< SWidget > MenuContentPtr = OnGetMenuContent.IsBound() ? OnGetMenuContent.Execute() : MenuContent; if ( MenuContentPtr.IsValid() ) { // OPEN POPUP if ( OnMenuOpenChanged.IsBound() ) { OnMenuOpenChanged.Execute(true); } // This can be called at any time so we use the push menu override that explicitly allows us to specify our parent // Figure out where the menu anchor is on the screen, so we can set the initial position of our pop-up window SlatePrepass(); // NOTE: Careful, GeneratePathToWidget can be reentrant in that it can call visibility delegates and such FWidgetPath MyWidgetPath; FSlateApplication::Get().GeneratePathToWidgetChecked(AsShared(), MyWidgetPath); const FGeometry& MyGeometry = MyWidgetPath.Widgets.Last().Geometry; // @todo Slate: This code does not properly propagate the layout scale of the widget we are creating the popup for. // The popup instead has a scale of one, but a computed size as if the contents were scaled. This code should ideally // wrap the contents with an SFxWidget that applies the necessary layout scale. This is a very rare case right now. // Figure out how big the content widget is so we can set the window's initial size properly TSharedRef< SWidget > MenuContentRef = MenuContentPtr.ToSharedRef(); MenuContentRef->SlatePrepass(); // Combo-boxes never size down smaller than the widget that spawned them, but all // other pop-up menus are currently auto-sized const FVector2D DesiredContentSize = MenuContentRef->GetDesiredSize(); // @todo: This is ignoring any window border size! const EMenuPlacement PlacementMode = Placement.Get(); const FVector2D NewPosition = MyGeometry.AbsolutePosition; FVector2D NewWindowSize = DesiredContentSize; const FVector2D SummonLocationSize = MyGeometry.Size; FPopupTransitionEffect TransitionEffect(FPopupTransitionEffect::None); if ( PlacementMode == MenuPlacement_ComboBox || PlacementMode == MenuPlacement_ComboBoxRight ) { TransitionEffect = FPopupTransitionEffect(FPopupTransitionEffect::ComboButton); NewWindowSize = FVector2D(FMath::Max(MyGeometry.Size.X, DesiredContentSize.X), DesiredContentSize.Y); } else if ( PlacementMode == MenuPlacement_BelowAnchor ) { TransitionEffect = FPopupTransitionEffect(FPopupTransitionEffect::TopMenu); } else if ( PlacementMode == MenuPlacement_MenuRight ) { TransitionEffect = FPopupTransitionEffect(FPopupTransitionEffect::SubMenu); } if ( Method == CreateNewWindow ) { // Open the pop-up TSharedRef<SWindow> PopupWindow = FSlateApplication::Get().PushMenu(AsShared(), MenuContentRef, NewPosition, TransitionEffect, bFocusMenu, false, NewWindowSize, SummonLocationSize); PopupWindow->SetRequestDestroyWindowOverride(FRequestDestroyWindowOverride::CreateSP(this, &SMenuAnchor::RequestClosePopupWindow)); PopupWindowPtr = PopupWindow; } else { // We are re-using the current window instead of creating a new one. // The popup will be presented via an overlay service. ensure(Method == UseCurrentWindow); Children[1] [ MenuContentRef ]; // We want to support dismissing the popup widget when the user clicks outside it. FSlateApplication::Get().GetPopupSupport().RegisterClickNotification(MenuContentRef, FOnClickedOutside::CreateSP(this, &SMenuAnchor::OnClickedOutsidePopup)); } if ( bFocusMenu ) { FSlateApplication::Get().SetKeyboardFocus(MenuContentRef, EKeyboardFocusCause::SetDirectly); } } } else { // CLOSE POPUP if (Method == CreateNewWindow) { // Close the Popup window. TSharedPtr<SWindow> PopupWindow = PopupWindowPtr.Pin(); if ( PopupWindow.IsValid() ) { // Request that the popup be closed. PopupWindow->RequestDestroyWindow(); } } else { // Close the popup overlay ensure(Method==UseCurrentWindow); Children[1].DetachWidget(); } if (OnMenuOpenChanged.IsBound()) { OnMenuOpenChanged.Execute(false); } } } }
void FMainFrameHandler::ShutDownEditor() { FEditorDelegates::OnShutdownPostPackagesSaved.Broadcast(); // Any pending autosaves should not happen. A tick will go by before the editor shuts down and we want to avoid auto-saving during this time. GUnrealEd->GetPackageAutoSaver().ResetAutoSaveTimer(); GEditor->RequestEndPlayMap(); // End any play on console/PC games still happening GEditor->EndPlayOnLocalPc(); // Cancel any current Launch On in progress GEditor->CancelPlayingViaLauncher(); TSharedPtr<SWindow> RootWindow = RootWindowPtr.Pin(); // Save root window placement so we can restore it. if (RootWindow.IsValid()) { FSlateRect WindowRect = RootWindow->GetNonMaximizedRectInScreen(); FRootWindowLocation RootWindowLocation(FVector2D(WindowRect.Left, WindowRect.Top), WindowRect.GetSize(), RootWindow->IsWindowMaximized()); RootWindowLocation.SaveToIni(); } // Save the visual state of the editor before we even // ask whether we can shut down. TSharedRef<FGlobalTabmanager> GlobalTabManager = FGlobalTabmanager::Get(); if (FUnrealEdMisc::Get().IsSavingLayoutOnClosedAllowed()) { GlobalTabManager->SaveAllVisualState(); } else { GConfig->EmptySection(TEXT("EditorLayouts"), *GEditorLayoutIni); } // Clear the callback for destructionfrom the main tab; otherwise it will re-enter this shutdown function. if (MainTabPtr.IsValid()) { MainTabPtr.Pin()->SetOnTabClosed(SDockTab::FOnTabClosedCallback()); } // Inform the AssetEditorManager that the editor is exiting so that it may save open assets // and report usage stats FAssetEditorManager::Get().OnExit(); if (RootWindow.IsValid()) { RootWindow->SetRequestDestroyWindowOverride(FRequestDestroyWindowOverride()); RootWindow->RequestDestroyWindow(); } // Save out any config settings for the editor so they don't get lost GEditor->SaveConfig(); GLevelEditorModeTools().SaveConfig(); // Delete user settings, if requested if (FUnrealEdMisc::Get().IsDeletePreferences()) { IFileManager::Get().Delete(*GEditorPerProjectIni); } // Take a screenshot of this project for the project browser if (FApp::HasGameName()) { const FString ExistingBaseFilename = FString(FApp::GetGameName()) + TEXT(".png"); const FString ExistingScreenshotFilename = FPaths::Combine(*FPaths::GameDir(), *ExistingBaseFilename); // If there is already a screenshot, no need to take an auto screenshot if (!FPaths::FileExists(ExistingScreenshotFilename)) { const FString ScreenShotFilename = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("AutoScreenshot.png")); FViewport* Viewport = GEditor->GetActiveViewport(); if (Viewport) { UThumbnailManager::CaptureProjectThumbnail(Viewport, ScreenShotFilename, false); } } } // Shut down the editor // NOTE: We can't close the editor from within this stack frame as it will cause various DLLs // (such as MainFrame) to become unloaded out from underneath the code pointer. We'll shut down // as soon as it's safe to do so. // Note this is the only place in slate that should be calling QUIT_EDITOR GEngine->DeferredCommands.Add(TEXT("QUIT_EDITOR")); }
void SDockingArea::Construct( const FArguments& InArgs, const TSharedRef<FTabManager>& InTabManager, const TSharedRef<FTabManager::FArea>& PersistentNode ) { MyTabManager = InTabManager; InTabManager->GetPrivateApi().OnDockAreaCreated( SharedThis(this) ); bManageParentWindow = InArgs._ShouldManageParentWindow; bIsOverlayVisible = false; bIsCenterTargetVisible = false; const TAttribute<EVisibility> TargetCrossVisibility = TAttribute<EVisibility>(SharedThis(this), &SDockingArea::TargetCrossVisibility); const TAttribute<EVisibility> TargetCrossCenterVisibility = TAttribute<EVisibility>(SharedThis(this), &SDockingArea::TargetCrossCenterVisibility); // In DockSplitter mode we just act as a thin shell around a Splitter widget this->ChildSlot [ SNew(SOverlay) .Visibility( EVisibility::SelfHitTestInvisible ) +SOverlay::Slot() [ SAssignNew(Splitter, SSplitter) . Orientation( PersistentNode->GetOrientation() ) ] +SOverlay::Slot() .HAlign(HAlign_Left) .VAlign(VAlign_Fill) [ SNew(SDockingTarget) .Visibility(TargetCrossVisibility) .OwnerNode( SharedThis(this) ) .DockDirection( SDockingNode::LeftOf ) ] +SOverlay::Slot() .HAlign(HAlign_Right) .VAlign(VAlign_Fill) [ SNew(SDockingTarget) .Visibility(TargetCrossVisibility) .OwnerNode( SharedThis(this) ) .DockDirection( SDockingNode::RightOf ) ] +SOverlay::Slot() .HAlign(HAlign_Fill) .VAlign(VAlign_Top) [ SNew(SDockingTarget) .Visibility(TargetCrossVisibility) .OwnerNode( SharedThis(this) ) .DockDirection( SDockingNode::Above ) ] +SOverlay::Slot() .HAlign(HAlign_Fill) .VAlign(VAlign_Bottom) [ SNew(SDockingTarget) .Visibility(TargetCrossVisibility) .OwnerNode( SharedThis(this) ) .DockDirection( SDockingNode::Below ) ] +SOverlay::Slot() [ SNew(SDockingTarget) .Visibility(TargetCrossCenterVisibility) .OwnerNode( SharedThis(this) ) .DockDirection( SDockingNode::Center ) ] ]; bCleanUpUponTabRelocation = false; // If the owner window is set and bManageParentWindow is true, this docknode will close the window when its last tab is removed. if (InArgs._ParentWindow.IsValid()) { SetParentWindow(InArgs._ParentWindow.ToSharedRef()); } // Add initial content if it was provided if ( InArgs._InitialContent.IsValid() ) { AddChildNode( InArgs._InitialContent.ToSharedRef() ); } }
void FAnimMontageSegmentDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder ) { IDetailCategoryBuilder& SegmentCategory = DetailBuilder.EditCategory("Animation Segment", LOCTEXT("AnimationSegmentCategoryTitle", "Animation Segment") ); TSharedRef<IPropertyHandle> TargetPropertyHandle = DetailBuilder.GetProperty("AnimSegment.AnimReference"); UProperty* TargetProperty = TargetPropertyHandle->GetProperty(); const UObjectPropertyBase* ObjectProperty = CastChecked<const UObjectPropertyBase>(TargetProperty); IDetailPropertyRow& PropertyRow = SegmentCategory.AddProperty(TargetPropertyHandle); PropertyRow.DisplayName(LOCTEXT("AnimationReferenceLabel", "Animation Reference")); TSharedPtr<SWidget> NameWidget; TSharedPtr<SWidget> ValueWidget; FDetailWidgetRow Row; PropertyRow.GetDefaultWidgets(NameWidget, ValueWidget, Row); bool bAllowClear = !(ObjectProperty->PropertyFlags & CPF_NoClear); SAssignNew(ValueWidget, SObjectPropertyEntryBox) .PropertyHandle(TargetPropertyHandle) .AllowedClass(ObjectProperty->PropertyClass) .AllowClear(bAllowClear) .OnShouldFilterAsset(FOnShouldFilterAsset::CreateSP(this, &FAnimMontageSegmentDetails::OnShouldFilterAnimAsset)); PropertyRow.CustomWidget() .NameContent() .MinDesiredWidth(Row.NameWidget.MinWidth) .MaxDesiredWidth(Row.NameWidget.MaxWidth) [ NameWidget.ToSharedRef() ] .ValueContent() .MinDesiredWidth(Row.ValueWidget.MinWidth) .MaxDesiredWidth(Row.ValueWidget.MaxWidth) [ ValueWidget.ToSharedRef() ]; SegmentCategory.AddProperty("AnimSegment.AnimStartTime").DisplayName( LOCTEXT("StartTimeLabel", "Start Time") ); SegmentCategory.AddProperty("AnimSegment.AnimEndTime").DisplayName( LOCTEXT("EndTimeLabel", "End Time") ); SegmentCategory.AddProperty("AnimSegment.AnimPlayRate").DisplayName( LOCTEXT("PlayRateLabel", "Play Rate") ); SegmentCategory.AddProperty("AnimSegment.LoopingCount").DisplayName( LOCTEXT("LoopCountLabel", "Loop Count") ); TSharedPtr<IPropertyHandle> InPropertyHandle = DetailBuilder.GetProperty("AnimSegment.AnimReference"); UObject *Object = NULL; InPropertyHandle->GetValue(Object); UAnimSequenceBase *AnimRef = Cast<UAnimSequenceBase>(Object); USkeleton *Skeleton = NULL; if(AnimRef != NULL) { Skeleton = AnimRef->GetSkeleton(); } SegmentCategory.AddCustomRow(FText::GetEmpty(), false) [ SNew(SAnimationSegmentViewport) .Skeleton(Skeleton) .AnimRef(AnimRef) .AnimRefPropertyHandle(DetailBuilder.GetProperty("AnimSegment.AnimReference")) .StartTimePropertyHandle(DetailBuilder.GetProperty("AnimSegment.AnimStartTime")) .EndTimePropertyHandle(DetailBuilder.GetProperty("AnimSegment.AnimEndTime")) ]; }