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());
	}
}
Пример #9
0
	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 );
}
Пример #12
0
	// equality check
	bool operator==(const FReceivedPartyInvite& Other) const
	{
		return *Other.FromId == *FromId || *Other.PartyJoinInfo->GetPartyId() == *PartyJoinInfo->GetPartyId();
	}
Пример #13
0
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)
					)
				)
			)
		);
}
Пример #15
0
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() );
		}
	}
}
Пример #16
0
    /**
     * 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
            ]
        ];
    }
Пример #17
0
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 ) );
}
Пример #20
0
/** 
 * 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>();
}
Пример #23
0
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;
	}
}
Пример #26
0
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;
	}
}
Пример #27
0
/**
 * 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"));
}
Пример #29
0
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"))
	];	
}